summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2012-09-04 09:44:18 +0200
committerMarcin Bukat <marcin.bukat@gmail.com>2012-09-04 09:48:48 +0200
commit072badeafbf33b49cba38d4d837110a7766b5c8e (patch)
tree2b675d18a1393e115a422f58a9162b7c3bae8b42
parenta1b101b107900e0d163700fda0aab0efc429f55e (diff)
downloadrockbox-072badeafbf33b49cba38d4d837110a7766b5c8e.tar.gz
rockbox-072badeafbf33b49cba38d4d837110a7766b5c8e.zip
rk27xx: Put some nand handling functions for reference
The functions document my reverse engineer findings about nand controller. This code is commented out and is purely for reference as FTL scheme is still unknown. Change-Id: I70edeb4bfb0cbd51b6adc15afa7193dd8f71e8da
-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