diff options
-rw-r--r-- | drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h | 5 | ||||
-rw-r--r-- | drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | 101 |
2 files changed, 106 insertions, 0 deletions
diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h index 2e8864a891e2..cc71400de116 100644 --- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h +++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h | |||
@@ -9,6 +9,11 @@ struct bcm47xxnflash { | |||
9 | 9 | ||
10 | struct nand_chip nand_chip; | 10 | struct nand_chip nand_chip; |
11 | struct mtd_info mtd; | 11 | struct mtd_info mtd; |
12 | |||
13 | unsigned curr_command; | ||
14 | int curr_column; | ||
15 | |||
16 | u8 id_data[8]; | ||
12 | }; | 17 | }; |
13 | 18 | ||
14 | #endif /* BCM47XXNFLASH */ | 19 | #endif /* BCM47XXNFLASH */ |
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index ae8a79387c27..7de190e9a788 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | |||
@@ -16,6 +16,10 @@ | |||
16 | 16 | ||
17 | #include "bcm47xxnflash.h" | 17 | #include "bcm47xxnflash.h" |
18 | 18 | ||
19 | /* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has | ||
20 | * shown 164 retries as maxiumum. */ | ||
21 | #define NFLASH_READY_RETRIES 1000 | ||
22 | |||
19 | /************************************************** | 23 | /************************************************** |
20 | * Various helpers | 24 | * Various helpers |
21 | **************************************************/ | 25 | **************************************************/ |
@@ -25,6 +29,24 @@ static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock) | |||
25 | return ((ns * 1000 * clock) / 1000000) + 1; | 29 | return ((ns * 1000 * clock) / 1000000) + 1; |
26 | } | 30 | } |
27 | 31 | ||
32 | static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code) | ||
33 | { | ||
34 | int i = 0; | ||
35 | |||
36 | bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, 0x80000000 | code); | ||
37 | for (i = 0; i < NFLASH_READY_RETRIES; i++) { | ||
38 | if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & 0x80000000)) { | ||
39 | i = 0; | ||
40 | break; | ||
41 | } | ||
42 | } | ||
43 | if (i) { | ||
44 | pr_err("NFLASH control command not ready!\n"); | ||
45 | return -EBUSY; | ||
46 | } | ||
47 | return 0; | ||
48 | } | ||
49 | |||
28 | /************************************************** | 50 | /************************************************** |
29 | * NAND chip ops | 51 | * NAND chip ops |
30 | **************************************************/ | 52 | **************************************************/ |
@@ -36,6 +58,83 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, | |||
36 | return; | 58 | return; |
37 | } | 59 | } |
38 | 60 | ||
61 | /* | ||
62 | * Default nand_command and nand_command_lp don't match BCM4706 hardware layout. | ||
63 | * For example, reading chip id is performed in a non-standard way. | ||
64 | * Setting column and page is also handled differently, we use a special | ||
65 | * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert | ||
66 | * standard commands would be much more complicated. | ||
67 | */ | ||
68 | static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, | ||
69 | unsigned command, int column, | ||
70 | int page_addr) | ||
71 | { | ||
72 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
73 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
74 | u32 ctlcode; | ||
75 | int i; | ||
76 | |||
77 | if (column != -1) | ||
78 | b47n->curr_column = column; | ||
79 | |||
80 | switch (command) { | ||
81 | case NAND_CMD_RESET: | ||
82 | pr_warn("Chip reset not implemented yet\n"); | ||
83 | break; | ||
84 | case NAND_CMD_READID: | ||
85 | ctlcode = 0x40000000 | 0x01000000 | 0x00080000 | 0x00010000; | ||
86 | ctlcode |= NAND_CMD_READID; | ||
87 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) { | ||
88 | pr_err("READID error\n"); | ||
89 | break; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Reading is specific, last one has to go without 0x40000000 | ||
94 | * bit. We don't know how many reads NAND subsystem is going | ||
95 | * to perform, so cache everything. | ||
96 | */ | ||
97 | for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) { | ||
98 | ctlcode = 0x40000000 | 0x00100000; | ||
99 | if (i == ARRAY_SIZE(b47n->id_data) - 1) | ||
100 | ctlcode &= ~0x40000000; | ||
101 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, | ||
102 | ctlcode)) { | ||
103 | pr_err("READID error\n"); | ||
104 | break; | ||
105 | } | ||
106 | b47n->id_data[i] = | ||
107 | bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA) | ||
108 | & 0xFF; | ||
109 | } | ||
110 | |||
111 | break; | ||
112 | default: | ||
113 | pr_err("Command 0x%X unsupported\n", command); | ||
114 | break; | ||
115 | } | ||
116 | b47n->curr_command = command; | ||
117 | } | ||
118 | |||
119 | static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) | ||
120 | { | ||
121 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
122 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
123 | |||
124 | switch (b47n->curr_command) { | ||
125 | case NAND_CMD_READID: | ||
126 | if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) { | ||
127 | pr_err("Requested invalid id_data: %d\n", | ||
128 | b47n->curr_column); | ||
129 | return 0; | ||
130 | } | ||
131 | return b47n->id_data[b47n->curr_column++]; | ||
132 | } | ||
133 | |||
134 | pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
39 | /************************************************** | 138 | /************************************************** |
40 | * Init | 139 | * Init |
41 | **************************************************/ | 140 | **************************************************/ |
@@ -52,6 +151,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) | |||
52 | u32 val; | 151 | u32 val; |
53 | 152 | ||
54 | b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; | 153 | b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; |
154 | b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; | ||
155 | b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; | ||
55 | b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ | 156 | b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ |
56 | 157 | ||
57 | /* Enable NAND flash access */ | 158 | /* Enable NAND flash access */ |