diff options
Diffstat (limited to 'firmware/target/arm/tcc780x/ata-nand-tcc780x.c')
-rw-r--r-- | firmware/target/arm/tcc780x/ata-nand-tcc780x.c | 343 |
1 files changed, 339 insertions, 4 deletions
diff --git a/firmware/target/arm/tcc780x/ata-nand-tcc780x.c b/firmware/target/arm/tcc780x/ata-nand-tcc780x.c index 5aed090d5c..813172f590 100644 --- a/firmware/target/arm/tcc780x/ata-nand-tcc780x.c +++ b/firmware/target/arm/tcc780x/ata-nand-tcc780x.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2007 Dave Chapman | 10 | * Copyright (C) 2008 Rob Purchase |
11 | * | 11 | * |
12 | * All files in this archive are subject to the GNU General Public License. | 12 | * All files in this archive are subject to the GNU General Public License. |
13 | * See the file COPYING in the source tree root for full license agreement. | 13 | * See the file COPYING in the source tree root for full license agreement. |
@@ -32,12 +32,335 @@ int ata_spinup_time = 0; | |||
32 | 32 | ||
33 | long last_disk_activity = -1; | 33 | long last_disk_activity = -1; |
34 | 34 | ||
35 | /** static, private data **/ | 35 | /** static, private data **/ |
36 | static bool initialized = false; | 36 | static bool initialized = false; |
37 | 37 | ||
38 | static long next_yield = 0; | 38 | static long next_yield = 0; |
39 | #define MIN_YIELD_PERIOD 2000 | 39 | #define MIN_YIELD_PERIOD 2000 |
40 | 40 | ||
41 | |||
42 | /* TCC780x NAND Flash Controller */ | ||
43 | |||
44 | #define NFC_CMD (*(volatile unsigned long *)0xF0053000) | ||
45 | #define NFC_SADDR (*(volatile unsigned long *)0xF005300C) | ||
46 | #define NFC_SDATA (*(volatile unsigned long *)0xF0053040) | ||
47 | #define NFC_WDATA (*(volatile unsigned long *)0xF0053010) | ||
48 | #define NFC_CTRL (*(volatile unsigned long *)0xF0053050) | ||
49 | #define NFC_IREQ (*(volatile unsigned long *)0xF0053060) | ||
50 | #define NFC_RST (*(volatile unsigned long *)0xF0053064) | ||
51 | |||
52 | #define NFC_16BIT (1<<26) | ||
53 | #define NFC_CS0 (1<<23) | ||
54 | #define NFC_CS1 (1<<22) | ||
55 | #define NFC_READY (1<<20) | ||
56 | |||
57 | |||
58 | #if defined(COWON_D2) | ||
59 | /* | ||
60 | ===== Temporary D2 testing code ===== | ||
61 | |||
62 | (assumes SAMSUNG K9LAG08UOM (2GB) in 1, 2 or 4 banks) | ||
63 | |||
64 | Manufacturer Id: {0xec, 0xd5, 0x55, 0x25, 0x68} | ||
65 | |||
66 | */ | ||
67 | #define PAGE_SIZE 2048 | ||
68 | #define SPARE_SIZE 64 | ||
69 | #define PAGES_PER_BLOCK 128 | ||
70 | #define TOTAL_BLOCKS 8192 | ||
71 | #define TOTAL_PAGES (TOTAL_BLOCKS * PAGES_PER_BLOCK) | ||
72 | #define COL_CYCLES 2 | ||
73 | #define ROW_CYCLES 3 | ||
74 | |||
75 | static int page_buf[PAGE_SIZE/4]; | ||
76 | |||
77 | static void nand_chip_select(int chip) | ||
78 | { | ||
79 | if (chip == -1) | ||
80 | { | ||
81 | /* Disable both chip selects */ | ||
82 | GPIOB_CLEAR = (1<<21); | ||
83 | NFC_CTRL |= NFC_CS0 | NFC_CS1; | ||
84 | } | ||
85 | else | ||
86 | { | ||
87 | /* NFC chip select */ | ||
88 | if (chip & 1) | ||
89 | { | ||
90 | NFC_CTRL &= ~NFC_CS0; | ||
91 | NFC_CTRL |= NFC_CS1; | ||
92 | } | ||
93 | else | ||
94 | { | ||
95 | NFC_CTRL |= NFC_CS0; | ||
96 | NFC_CTRL &= ~NFC_CS1; | ||
97 | } | ||
98 | |||
99 | /* Secondary chip select */ | ||
100 | if (chip & 2) | ||
101 | { | ||
102 | GPIOB_SET = (1<<21); | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | GPIOB_CLEAR = (1<<21); | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | |||
111 | static void nand_read_id(int chip, unsigned char* id_buf) | ||
112 | { | ||
113 | int i; | ||
114 | |||
115 | /* Enable NFC bus clock */ | ||
116 | BCLKCTR |= DEV_NAND; | ||
117 | |||
118 | /* Reset NAND controller */ | ||
119 | NFC_RST = 0; | ||
120 | |||
121 | /* Set slow cycle timings since the chip is as yet unidentified */ | ||
122 | NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x353; | ||
123 | |||
124 | nand_chip_select(chip); | ||
125 | |||
126 | /* Set write protect */ | ||
127 | GPIOB_CLEAR = (1<<19); | ||
128 | |||
129 | /* Reset command */ | ||
130 | NFC_CMD = 0xFF; | ||
131 | |||
132 | /* Set 8-bit data width */ | ||
133 | NFC_CTRL &= ~NFC_16BIT; | ||
134 | |||
135 | /* Read ID command, single address cycle */ | ||
136 | NFC_CMD = 0x90; | ||
137 | NFC_SADDR = 0x00; | ||
138 | |||
139 | /* Read the 5 single bytes */ | ||
140 | id_buf[0] = NFC_SDATA & 0xFF; | ||
141 | id_buf[1] = NFC_SDATA & 0xFF; | ||
142 | id_buf[2] = NFC_SDATA & 0xFF; | ||
143 | id_buf[3] = NFC_SDATA & 0xFF; | ||
144 | id_buf[4] = NFC_SDATA & 0xFF; | ||
145 | |||
146 | nand_chip_select(-1); | ||
147 | |||
148 | /* Disable NFC bus clock */ | ||
149 | BCLKCTR &= ~DEV_NAND; | ||
150 | } | ||
151 | |||
152 | |||
153 | static void nand_read_uid(int chip) | ||
154 | { | ||
155 | int i; | ||
156 | |||
157 | /* Enable NFC bus clock */ | ||
158 | BCLKCTR |= DEV_NAND; | ||
159 | |||
160 | /* Set cycle timing (stp = 1, pw = 3, hold = 1) */ | ||
161 | NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131; | ||
162 | |||
163 | nand_chip_select(chip); | ||
164 | |||
165 | /* Set write protect */ | ||
166 | GPIOB_CLEAR = 1<<19; | ||
167 | |||
168 | /* Set 8-bit data width */ | ||
169 | NFC_CTRL &= ~NFC_16BIT; | ||
170 | |||
171 | /* Undocumented (SAMSUNG specific?) commands set the chip into a | ||
172 | special mode allowing a normally-hidden UID block to be read. */ | ||
173 | NFC_CMD = 0x30; | ||
174 | NFC_CMD = 0x65; | ||
175 | |||
176 | /* Read command */ | ||
177 | NFC_CMD = 0x00; | ||
178 | |||
179 | /* Write row/column address */ | ||
180 | for (i = 0; i < COL_CYCLES; i++) NFC_SADDR = 0; | ||
181 | for (i = 0; i < ROW_CYCLES; i++) NFC_SADDR = 0; | ||
182 | |||
183 | /* End of read */ | ||
184 | NFC_CMD = 0x30; | ||
185 | |||
186 | /* Wait until complete */ | ||
187 | while (!(NFC_CTRL & NFC_READY)) {}; | ||
188 | |||
189 | /* Copy data to buffer (data repeats after 8 words) */ | ||
190 | for (i = 0; i < 8; i++) | ||
191 | { | ||
192 | page_buf[i] = NFC_WDATA; | ||
193 | } | ||
194 | |||
195 | /* Reset the chip back to normal mode */ | ||
196 | NFC_CMD = 0xFF; | ||
197 | |||
198 | nand_chip_select(-1); | ||
199 | |||
200 | /* Disable NFC bus clock */ | ||
201 | BCLKCTR &= ~DEV_NAND; | ||
202 | } | ||
203 | |||
204 | |||
205 | /* NB: size must be divisible by 4 due to 32-bit read */ | ||
206 | static void nand_read(int chip, int row, int column, int size) | ||
207 | { | ||
208 | int i; | ||
209 | |||
210 | /* Enable NFC bus clock */ | ||
211 | BCLKCTR |= DEV_NAND; | ||
212 | |||
213 | /* Set cycle timing (stp = 1, pw = 3, hold = 1) */ | ||
214 | NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131; | ||
215 | |||
216 | nand_chip_select(chip); | ||
217 | |||
218 | /* Set write protect */ | ||
219 | GPIOB_CLEAR = (1<<19); | ||
220 | |||
221 | /* Set 8-bit data width */ | ||
222 | NFC_CTRL &= ~NFC_16BIT; | ||
223 | |||
224 | /* Read command */ | ||
225 | NFC_CMD = 0x00; | ||
226 | |||
227 | /* Write column address */ | ||
228 | for (i = 0; i < COL_CYCLES; i++) | ||
229 | { | ||
230 | NFC_SADDR = column & 0xFF; | ||
231 | column = column >> 8; | ||
232 | } | ||
233 | |||
234 | /* Write row address */ | ||
235 | for (i = 0; i < ROW_CYCLES; i++) | ||
236 | { | ||
237 | NFC_SADDR = row & 0xFF; | ||
238 | row = row >> 8; | ||
239 | } | ||
240 | |||
241 | /* End of read command */ | ||
242 | NFC_CMD = 0x30; | ||
243 | |||
244 | /* Wait until complete */ | ||
245 | while (!(NFC_CTRL & NFC_READY)) {}; | ||
246 | |||
247 | /* Read data into page buffer */ | ||
248 | for (i = 0; i < (size/4); i++) | ||
249 | { | ||
250 | page_buf[i] = NFC_WDATA; | ||
251 | } | ||
252 | |||
253 | nand_chip_select(-1); | ||
254 | |||
255 | /* Disable NFC bus clock */ | ||
256 | BCLKCTR &= ~DEV_NAND; | ||
257 | } | ||
258 | |||
259 | |||
260 | /* TEMP testing function */ | ||
261 | #include <string.h> | ||
262 | #include "lcd.h" | ||
263 | |||
264 | extern int line; | ||
265 | |||
266 | static void nand_test(void) | ||
267 | { | ||
268 | int i,j,row; | ||
269 | unsigned char id_buf[5]; | ||
270 | unsigned char str_buf[PAGE_SIZE]; | ||
271 | |||
272 | /* Display ID codes & UID block for each bank */ | ||
273 | for (i = 0; i < 4; i++) | ||
274 | { | ||
275 | printf("NAND bank %d:", i); | ||
276 | |||
277 | nand_read_id(i, id_buf); | ||
278 | |||
279 | printf("ID: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", | ||
280 | id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]); | ||
281 | |||
282 | nand_read_uid(i); | ||
283 | |||
284 | for (j = 0; j < 8; j += 4) | ||
285 | { | ||
286 | printf("0x%08x 0x%08x 0x%08x 0x%08x", | ||
287 | page_buf[j],page_buf[j+1],page_buf[j+2],page_buf[j+3]); | ||
288 | } | ||
289 | |||
290 | line++; | ||
291 | } | ||
292 | |||
293 | while (!button_read_device()) {}; | ||
294 | |||
295 | /* Now for fun, scan the raw pages for 'TAG' and display the contents */ | ||
296 | |||
297 | row = 0; | ||
298 | while (row < TOTAL_PAGES) | ||
299 | { | ||
300 | bool found = false; | ||
301 | unsigned char* buf_ptr = (unsigned char*)page_buf; | ||
302 | |||
303 | line = 0; | ||
304 | |||
305 | /* Read a page from chip 0 */ | ||
306 | nand_read(0, row, 0, PAGE_SIZE); | ||
307 | |||
308 | if (row % 512 == 0) printf("%dMb", row/512); | ||
309 | |||
310 | for (j = 0; j < PAGE_SIZE; j++) | ||
311 | { | ||
312 | if (buf_ptr[j] == 'T' && buf_ptr[j+1] == 'A' && buf_ptr[j+2] == 'G') | ||
313 | found = true; | ||
314 | } | ||
315 | |||
316 | if (found) | ||
317 | { | ||
318 | unsigned char* str_ptr = str_buf; | ||
319 | |||
320 | printf("Row %d:", row); | ||
321 | |||
322 | /* Copy ascii-readable parts out to a string */ | ||
323 | for (i = 0; i < PAGE_SIZE; i++) | ||
324 | { | ||
325 | str_buf[i] = ' '; | ||
326 | if (buf_ptr[i] > 31 && buf_ptr[i] < 128) | ||
327 | { | ||
328 | *str_ptr++ = buf_ptr[i]; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | str_ptr = str_buf; | ||
333 | |||
334 | /* Nasty piece of code to display the text in a readable manner */ | ||
335 | for (i = 1; i < 30; i++) | ||
336 | { | ||
337 | for (j = 0; j < 48; j++) | ||
338 | { | ||
339 | /* In the absence of a putc() we have this mess... */ | ||
340 | unsigned char buf2[2]; | ||
341 | buf2[0] = *str_ptr++; | ||
342 | buf2[1] = '\0'; | ||
343 | lcd_puts(j,i,buf2); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | /* Alternate hex display code | ||
348 | for (i = 0; i<112; i+=4) | ||
349 | { | ||
350 | printf("0x%08x 0x%08x 0x%08x 0x%08x",buf[i],buf[i+1],buf[i+2],buf[i+3]); | ||
351 | } | ||
352 | */ | ||
353 | |||
354 | while (!button_read_device()) {}; | ||
355 | |||
356 | lcd_clear_display(); | ||
357 | } | ||
358 | row++; | ||
359 | } | ||
360 | } | ||
361 | #endif | ||
362 | |||
363 | |||
41 | /* API Functions */ | 364 | /* API Functions */ |
42 | 365 | ||
43 | void ata_led(bool onoff) | 366 | void ata_led(bool onoff) |
@@ -67,7 +390,7 @@ int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, | |||
67 | 390 | ||
68 | void ata_spindown(int seconds) | 391 | void ata_spindown(int seconds) |
69 | { | 392 | { |
70 | #warning function not implemented | 393 | /* null */ |
71 | (void)seconds; | 394 | (void)seconds; |
72 | } | 395 | } |
73 | 396 | ||
@@ -84,7 +407,7 @@ void ata_sleep(void) | |||
84 | 407 | ||
85 | void ata_spin(void) | 408 | void ata_spin(void) |
86 | { | 409 | { |
87 | #warning function not implemented | 410 | /* null */ |
88 | } | 411 | } |
89 | 412 | ||
90 | /* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */ | 413 | /* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */ |
@@ -109,5 +432,17 @@ void ata_enable(bool on) | |||
109 | int ata_init(void) | 432 | int ata_init(void) |
110 | { | 433 | { |
111 | #warning function not implemented | 434 | #warning function not implemented |
435 | |||
436 | /* This needs to: | ||
437 | a) establish how many banks are present | ||
438 | (using nand_read_id() and nand_read_uid() above) | ||
439 | b) scan all banks for bad blocks | ||
440 | c) use this info to build a physical->logical address translation | ||
441 | (using an as yet unknown scheme) | ||
442 | */ | ||
443 | |||
444 | /* TEMP - print out some diagnostics */ | ||
445 | nand_test(); | ||
446 | |||
112 | return 0; | 447 | return 0; |
113 | } | 448 | } |