summaryrefslogtreecommitdiff
path: root/firmware/target/arm/rk27xx/nand-rk27xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/rk27xx/nand-rk27xx.c')
-rw-r--r--firmware/target/arm/rk27xx/nand-rk27xx.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/firmware/target/arm/rk27xx/nand-rk27xx.c b/firmware/target/arm/rk27xx/nand-rk27xx.c
index c2c855efee..84e60a47e1 100644
--- a/firmware/target/arm/rk27xx/nand-rk27xx.c
+++ b/firmware/target/arm/rk27xx/nand-rk27xx.c
@@ -22,6 +22,400 @@
22 #include "config.h" 22 #include "config.h"
23 #include "nand-target.h" 23 #include "nand-target.h"
24 24
25#if 0
26/* This is for documentation purpose as FTL has not been reverse engineered yet
27 * Raw nand handling functions based on OF disassembly and partially inspired
28 * by Rockchip patent
29 */
30
31#define MAX_FLASH_NUM 4
32#define CMD_READ_STATUS 0x70
33#define CMD_RESET 0xFF
34#define CMD_READ_ID 0x90
35#define READ_PAGE_CMD 0x30
36
37/* this is the struct OF uses */
38struct flashspec_t
39{
40 uint8_t cache_prog;
41 uint8_t mul_plane;
42 uint8_t interleave;
43 uint8_t large;
44 uint8_t five;
45 uint8_t mlc;
46 uint8_t vendor;
47 uint8_t access_time;
48 uint8_t sec_per_page;
49 uint8_t sec_per_page_raw;
50 uint16_t sec_per_block;
51 uint16_t sec_per_block_raw;
52 uint16_t page_per_block;
53 uint16_t page_per_block_raw;
54
55 uint32_t tot_logic_sec;
56 uint32_t total_phy_sec;
57 uint32_t total_bloks;
58
59 uint32_t cmd;
60 uint32_t addr;
61 uint32_t data;
62};
63
64/* holds nand chips characteristics */
65struct flashspec_t flash_spec[MAX_FLASH_NUM];
66
67/* sum of all phy sectors in all chips */
68uint32_t total_phy_sec;
69
70enum vendor_t {
71 SAMSUNG,
72 TOSHIBA,
73 HYNIX,
74 INFINEON,
75 MICRON,
76 RENESAS,
77 ST
78};
79
80/* taken from OF */
81const uint8_t device_code[] = {
82 0x76,
83 0x79,
84 0xf1,
85 0xda,
86 0xdc,
87 0xd3,
88 0xd7
89};
90
91const uint8_t manufacture_id_tbl[] =
92{
93 0xec, /* SAMSUNG */
94 0x98, /* TOSHIBA */
95 0xad, /* HYNIX */
96 0xc1, /* INFINEON */
97 0x2c, /* MICRON */
98 0x07, /* RENESAS */
99 0x20 /* ST */
100};
101
102/* phisical sectors */
103const uint32_t device_info[] =
104{
105 0x20000, /* 64M, small page */
106 0x40000, /* 128M, small page */
107 0x40000, /* 128M, large page */
108 0x80000, /* 256M, large page */
109 0x100000, /* 512M, large page */
110 0x200000, /* 1G, large page */
111 0x400000, /* 2G, large page */
112 0x800000 /* 4G, large page */
113};
114
115static int flash_delay(int n)
116{
117 volatile int cnt, i, j;
118
119 for (j=0; j<n; j++)
120 for (i=0; i<10000; i++)
121 cnt++;
122
123 return cnt;
124}
125
126
127static void flash_wait_busy(void)
128{
129 unsigned int i;
130
131 for (i=0; i<0x2000; i++)
132 {
133 if (FMCTL & FM_RDY)
134 break;
135
136 flash_delay(1);
137 }
138}
139
140void flash_chip_deselect(void)
141{
142 uint32_t tmp;
143 tmp = FMCTL;
144 tmp &= 0xf0;
145 FMCTL = tmp;
146}
147
148void flash_chip_select(uint8_t chip)
149{
150 uint32_t tmp;
151
152 /* Maybe we should handle IOMUX here as well?
153 * for chip == 0,1 it is not needed
154 */
155 tmp = FMCTL;
156 tmp &= 0xf0;
157 tmp |= 1<<chip;
158 FMCTL = tmp;
159}
160
161void flash_init(void)
162{
163 uint8_t buff[5]; /* buff for CMD_READ_ID response */
164 uint32_t i,j;
165
166 mlc_refresh_row = 0xffffffff;
167 total_phy_sec = 0;
168 flash_pend_cmd.valid = 0;
169 flash_read_status_cmd = CMD_READ_STATUS;
170
171 FMWAIT = 0x1081;
172 FLCTL = FL_RST;
173
174 for (i=0; i< MAX_FLASH_NUM; i++)
175 {
176 /* Redundat - we will use special macros
177 * just for reference what OF does
178 */
179 flash_spec[i].cmd = 0x180E8200 + (i<<9);
180 flash_spec[i].addr = 0x180E204 + (i<<9);
181 flash_spec[i].data = 0x180E208 + (i<<9);
182
183 flash_chip_select(i);
184 FLASH_CMD(i) = CMD_RESET; /* write cmd to flash chip */
185 flash_delay(2);
186 flash_wait_busy();
187 FLASH_CMD(i) = CMD_READ_ID; /* write cmd to flash chip */
188 FLASH_ADDR(i) = 0x00;
189
190 /* read 5 bytes of CMD_READ_ID response */
191 for (j=0; j<5; j++)
192 buff[j] = FLASH_DATA(i);
193
194 flash_chip_deselect();
195
196 /* Get the vendor of the chip */
197 for (j=0; j<sizeof(manufacture_id_tbl); j++)
198 {
199 /* store Manufacturer index */
200 if (ManufactureIDTbl[j] == buff[0])
201 {
202 flash_spec[i].vendor = j;
203 }
204 }
205
206 for (j=0; j<sizeof(device_code); j++)
207 {
208 /* look for matching device code
209 * and store total phys sectors
210 */
211 if (DeviceCode[j] == buff[1])
212 {
213 flash_spec[i].total_phy_sec = device_info[j];
214 break;
215 }
216 }
217
218 /* div zero is fatal for us (not for OF :P) */
219 if (flash_spec[i].total_phy_sec == 0)
220 continue;
221
222 /* loc_7e8 */
223 flash_spec[i].mlc = 0;
224 flash_spec[i].large = 0;
225 flash_spec[i].five = 1;
226 flash_spec[i].mul_plane = 1;
227 flash_spec[i].interleave = 0;
228
229 flash_spec[i].cache_prog = buff[2] & 0x80;
230
231 /* flash access time (ns) */
232 switch (buff[3] & 0x88)
233 {
234 case 0:
235 flash_spec[i].access_time = 50;
236 break;
237 case 0x80:
238 flash_spec[i].access_time = 25;
239 break;
240 case 0x08:
241 flash_spec[i].access_time = 20;
242 break;
243 default:
244 flash_spec[i].access_time = 60;
245 }
246
247 /* set_large
248 * j is index in device_code table
249 */
250 if (j < 2)
251 {
252 /* small block */
253 flash_spec[i].large = 0;
254 flash_spec[i].sec_per_page_raw = 1;
255 flash_spec[i].sec_per_block_raw = 32;
256 }
257 else
258 {
259 flash_spec[i].large = 1;
260 if (j == 2)
261 flash_spec[i].five = 0;
262
263
264 /* cell type */
265 flash_spec[i].mlc = (buff[2] >> 2) & 0x03;
266
267 flash_spec[i].sec_per_page_raw = 2; /* 1KB~8KB */
268
269 /* set_sec_per_page_raw */
270 flash_spec[i].sec_per_page_raw <<= (buff[3] & 3);
271
272 flash_spec[i].sec_per_block_raw = 128; /* 64KB~512KB */
273
274 /* set_sec_per_block_raw */
275 flash_spec[i].sec_per_block_raw <<= ((buff[3]>>4) & 3);
276
277 /* simult_prog */
278 if (buff[2] & 0x30)
279 {
280 /* buff4_mulplane */
281 flash_spec[i].mul_plane <<= ((buff[4]>>2) & 3);
282 }
283
284 /* set_interleave */
285 if (flash_spec[i].vendor == TOSHIBA)
286 {
287 flash_spec[i].mul_plane = 2;
288 if (buff[2] & 3)
289 flash_spec[i].interleave = 1;
290 }
291
292 } /* large block */
293
294 if (flash_spec[i].mul_plane > 2)
295 {
296 flash_spec[i].mul_plane = 2;
297 flash_spec[i].interleave = 1;
298 }
299
300 flash_spec[i].page_per_block_raw = flash_spec[i].sec_per_block_raw/flash_spec[i].sec_per_page_raw;
301 flash_spec[i].page_per_block = flash_spec[i].page_per_block_raw * flash_spec[i].mul_plane;
302 flash_spec[i].sec_per_block = flash_spec[i].sec_per_block_raw * flash_spec[i].mul_plane;
303 flash_spec[i].sec_per_page = flash_spec[i].sec_per_page_raw * flash_spec[i].mul_plane;
304 flash_spec[i].total_bloks = flash_spec[i].total_phy_sec / flash_spec[i].sec_per_block;
305
306 total_phy_sec += flash_spec[i].total_phy_sec;
307 }
308
309 /* read ID block and propagate SysDiskCapacity and SysResBlocks */
310}
311
312/* read single page in unbuffered mode */
313void flash_read_page(int page, unsigned char *pgbuff)
314{
315 unsigned int i;
316
317 flash_chip_select(0);
318 flash_delay(2);
319 flash_wait_busy();
320
321 /* setup transfer */
322 FLASH_CMD(0) = 0x00;
323 FLASH_ADDR(0) = 0x00; /* column */
324 FLASH_ADDR(0) = 0x00; /* column */
325 FLASH_ADDR(0) = page & 0xff; /* row */
326 FLASH_ADDR(0) = (page >> 8) & 0xff; /* row */
327 FLASH_ADDR(0) = (page >> 16) & 0xff; /* row */
328 FLASH_CMD(0) = READ_PAGE_CMD;
329
330 /* wait for operation complete */
331 flash_wait_busy();
332
333 /* copy data from page register
334 * WARNING flash page size can be different
335 * for different chips. This value should be set
336 * based on initialization.
337 */
338 for (i=0; i<(4096+218); i++)
339 pgbuff[i] = FLASH_DATA(0);
340
341 flash_chip_deselect();
342}
343
344void flash_read_sector(int page, unsigned char *secbuf, int nsec)
345{
346 int i = 0;
347 int j = 0;
348
349 /* WARNING this code assumes only one nand chip
350 * it does not handle data split across different nand chips
351 */
352 flash_chip_select(0);
353 flash_delay(2);
354 flash_wait_busy();
355
356 FLASH_CMD(0) = 0x00;
357 FLASH_ADDR(0) = 0x00;
358 FLASH_ADDR(0) = 0x00;
359 FLASH_ADDR(0) = page & 0xff;
360 FLASH_ADDR(0) = (page >> 8) & 0xff;
361 FLASH_ADDR(0) = (page >> 16) & 0xff;
362 FLASH_CMD(0) = READ_PAGE_CMD;
363
364 flash_delay(1);
365
366 /* wait for operation to complete */
367 flash_wait_busy();
368
369 /* enables hw checksum control most probably */
370 BCHCTL = 1;
371
372 /* This initializes the transfer from the nand to the buffer
373 * There are 4 consecutive hw buffers 512 bytes long for data (PAGE_BUF)
374 * and 4 16 bytes long for metadata (BCH code checksum) (SPARE_BUF)
375 */
376 FLCTL = 0xA24;
377
378 /* This scheme utilizes some overlap in data transfers -
379 * data are copied from buffer to the mem and from nand to the buf
380 * at the same time.
381 */
382 while (++j < nsec)
383 {
384 /* wait for transfer to complete */
385 while(! (FLCTL & FL_RDY));
386
387 /* initialize next transfer to the next buffer */
388 FLCTL = 0xA24 | (j&3)<<3;
389
390 /* copy data chunk */
391 memcpy(secbuf, (((unsigned char *)&PAGE_BUF)+((i&3)<<9)), 0x200);
392 secbuf += 0x200;
393
394 /* copy metadata chunk (BCH)
395 * in real application this can be discarded
396 */
397 memcpy(secbuf, (((unsigned char *)&SPARE_BUF)+((i&3)<<4)), 0x10);
398 secbuf += 0x10;
399 i++;
400 }
401
402 /* wait for transfer to complete */
403 while(! (FLCTL & FL_RDY));
404
405 /* copy data chunk */
406 memcpy(secbuf, (((unsigned char *)&PAGE_BUF)+((i&3)<<9)), 0x200);
407 secbuf += 0x200;
408
409 /* copy metadata chunk (BCH)
410 * in real application this can be discarded
411 */
412 memcpy(secbuf, (((unsigned char *)&SPARE_BUF)+((i&3)<<4)), 0x10);
413 secbuf += 0x10;
414
415 flash_chip_deselect();
416}
417
418#endif
25const struct nand_device_info_type* nand_get_device_type(uint32_t bank); 419const struct nand_device_info_type* nand_get_device_type(uint32_t bank);
26 420
27 421