diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2012-11-12 07:03:24 -0500 |
---|---|---|
committer | Artem Bityutskiy <artem.bityutskiy@linux.intel.com> | 2012-11-22 02:32:45 -0500 |
commit | 3c01d4cb7576ff79e13ba7d7fb884e63e6f07bbd (patch) | |
tree | 3235466e2bb387b2737be3f1355685a78adb0411 /drivers/mtd | |
parent | 0fbc5991551fa2024de7db79421e9a16ca9fe542 (diff) |
mtd: bcm47xxnflash: implement reading
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | 106 |
2 files changed, 107 insertions, 0 deletions
diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h index cc71400de116..264aec448fc4 100644 --- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h +++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h | |||
@@ -11,6 +11,7 @@ struct bcm47xxnflash { | |||
11 | struct mtd_info mtd; | 11 | struct mtd_info mtd; |
12 | 12 | ||
13 | unsigned curr_command; | 13 | unsigned curr_command; |
14 | int curr_page_addr; | ||
14 | int curr_column; | 15 | int curr_column; |
15 | 16 | ||
16 | u8 id_data[8]; | 17 | u8 id_data[8]; |
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index 7de190e9a788..e42e18208abc 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | |||
@@ -20,6 +20,8 @@ | |||
20 | * shown 164 retries as maxiumum. */ | 20 | * shown 164 retries as maxiumum. */ |
21 | #define NFLASH_READY_RETRIES 1000 | 21 | #define NFLASH_READY_RETRIES 1000 |
22 | 22 | ||
23 | #define NFLASH_SECTOR_SIZE 512 | ||
24 | |||
23 | /************************************************** | 25 | /************************************************** |
24 | * Various helpers | 26 | * Various helpers |
25 | **************************************************/ | 27 | **************************************************/ |
@@ -47,6 +49,80 @@ static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code) | |||
47 | return 0; | 49 | return 0; |
48 | } | 50 | } |
49 | 51 | ||
52 | static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc) | ||
53 | { | ||
54 | int i; | ||
55 | |||
56 | for (i = 0; i < NFLASH_READY_RETRIES; i++) { | ||
57 | if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & 0x04000000) { | ||
58 | if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & | ||
59 | BCMA_CC_NFLASH_CTL_ERR) { | ||
60 | pr_err("Error on polling\n"); | ||
61 | return -EBUSY; | ||
62 | } else { | ||
63 | return 0; | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | pr_err("Polling timeout!\n"); | ||
69 | return -EBUSY; | ||
70 | } | ||
71 | |||
72 | /************************************************** | ||
73 | * R/W | ||
74 | **************************************************/ | ||
75 | |||
76 | static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, | ||
77 | int len) | ||
78 | { | ||
79 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
80 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
81 | |||
82 | u32 ctlcode; | ||
83 | u32 *dest = (u32 *)buf; | ||
84 | int i; | ||
85 | int toread; | ||
86 | |||
87 | BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask); | ||
88 | /* Don't validate column using nand_chip->page_shift, it may be bigger | ||
89 | * when accessing OOB */ | ||
90 | |||
91 | while (len) { | ||
92 | /* We can read maximum of 0x200 bytes at once */ | ||
93 | toread = min(len, 0x200); | ||
94 | |||
95 | /* Set page and column */ | ||
96 | bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR, | ||
97 | b47n->curr_column); | ||
98 | bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR, | ||
99 | b47n->curr_page_addr); | ||
100 | |||
101 | /* Prepare to read */ | ||
102 | ctlcode = 0x40000000 | 0x00080000 | 0x00040000 | 0x00020000 | | ||
103 | 0x00010000; | ||
104 | ctlcode |= NAND_CMD_READSTART << 8; | ||
105 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) | ||
106 | return; | ||
107 | if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc)) | ||
108 | return; | ||
109 | |||
110 | /* Eventually read some data :) */ | ||
111 | for (i = 0; i < toread; i += 4, dest++) { | ||
112 | ctlcode = 0x40000000 | 0x30000000 | 0x00100000; | ||
113 | if (i == toread - 4) /* Last read goes without that */ | ||
114 | ctlcode &= ~0x40000000; | ||
115 | if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, | ||
116 | ctlcode)) | ||
117 | return; | ||
118 | *dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA); | ||
119 | } | ||
120 | |||
121 | b47n->curr_column += toread; | ||
122 | len -= toread; | ||
123 | } | ||
124 | } | ||
125 | |||
50 | /************************************************** | 126 | /************************************************** |
51 | * NAND chip ops | 127 | * NAND chip ops |
52 | **************************************************/ | 128 | **************************************************/ |
@@ -76,6 +152,8 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, | |||
76 | 152 | ||
77 | if (column != -1) | 153 | if (column != -1) |
78 | b47n->curr_column = column; | 154 | b47n->curr_column = column; |
155 | if (page_addr != -1) | ||
156 | b47n->curr_page_addr = page_addr; | ||
79 | 157 | ||
80 | switch (command) { | 158 | switch (command) { |
81 | case NAND_CMD_RESET: | 159 | case NAND_CMD_RESET: |
@@ -109,6 +187,12 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, | |||
109 | } | 187 | } |
110 | 188 | ||
111 | break; | 189 | break; |
190 | case NAND_CMD_READ0: | ||
191 | break; | ||
192 | case NAND_CMD_READOOB: | ||
193 | if (page_addr != -1) | ||
194 | b47n->curr_column += mtd->writesize; | ||
195 | break; | ||
112 | default: | 196 | default: |
113 | pr_err("Command 0x%X unsupported\n", command); | 197 | pr_err("Command 0x%X unsupported\n", command); |
114 | break; | 198 | break; |
@@ -120,6 +204,7 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) | |||
120 | { | 204 | { |
121 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | 205 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; |
122 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | 206 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; |
207 | u32 tmp = 0; | ||
123 | 208 | ||
124 | switch (b47n->curr_command) { | 209 | switch (b47n->curr_command) { |
125 | case NAND_CMD_READID: | 210 | case NAND_CMD_READID: |
@@ -129,12 +214,31 @@ static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd) | |||
129 | return 0; | 214 | return 0; |
130 | } | 215 | } |
131 | return b47n->id_data[b47n->curr_column++]; | 216 | return b47n->id_data[b47n->curr_column++]; |
217 | case NAND_CMD_READOOB: | ||
218 | bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4); | ||
219 | return tmp & 0xFF; | ||
132 | } | 220 | } |
133 | 221 | ||
134 | pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command); | 222 | pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command); |
135 | return 0; | 223 | return 0; |
136 | } | 224 | } |
137 | 225 | ||
226 | static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd, | ||
227 | uint8_t *buf, int len) | ||
228 | { | ||
229 | struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; | ||
230 | struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; | ||
231 | |||
232 | switch (b47n->curr_command) { | ||
233 | case NAND_CMD_READ0: | ||
234 | case NAND_CMD_READOOB: | ||
235 | bcm47xxnflash_ops_bcm4706_read(mtd, buf, len); | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command); | ||
240 | } | ||
241 | |||
138 | /************************************************** | 242 | /************************************************** |
139 | * Init | 243 | * Init |
140 | **************************************************/ | 244 | **************************************************/ |
@@ -153,6 +257,8 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) | |||
153 | b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; | 257 | b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; |
154 | b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; | 258 | b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; |
155 | b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; | 259 | b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; |
260 | b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; | ||
261 | b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; | ||
156 | b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ | 262 | b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ |
157 | 263 | ||
158 | /* Enable NAND flash access */ | 264 | /* Enable NAND flash access */ |