D2: Add auto-detection of the SAMSUNG flash chips used in the 2/4/8Gb
[kugel-rb.git] / firmware / target / arm / tcc780x / ata-nand-tcc780x.c
blobbd7e9bb3360c2fcb074366f01815eb23cf9f29e0
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 Rob Purchase
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "ata.h"
20 #include "ata-target.h"
21 #include "ata_idle_notify.h"
22 #include "system.h"
23 #include <string.h>
24 #include "thread.h"
25 #include "led.h"
26 #include "disk.h"
27 #include "panic.h"
28 #include "usb.h"
30 /* for compatibility */
31 int ata_spinup_time = 0;
33 long last_disk_activity = -1;
35 /** static, private data **/
36 static bool initialized = false;
38 static long next_yield = 0;
39 #define MIN_YIELD_PERIOD 2000
41 /* TCC780x NAND Flash Controller */
43 #define NFC_CMD (*(volatile unsigned long *)0xF0053000)
44 #define NFC_SADDR (*(volatile unsigned long *)0xF005300C)
45 #define NFC_SDATA (*(volatile unsigned long *)0xF0053040)
46 #define NFC_WDATA (*(volatile unsigned long *)0xF0053010)
47 #define NFC_CTRL (*(volatile unsigned long *)0xF0053050)
48 #define NFC_IREQ (*(volatile unsigned long *)0xF0053060)
49 #define NFC_RST (*(volatile unsigned long *)0xF0053064)
51 /* NFC_CTRL flags */
52 #define NFC_16BIT (1<<26)
53 #define NFC_CS0 (1<<23)
54 #define NFC_CS1 (1<<22)
55 #define NFC_READY (1<<20)
57 /* Chip characteristics, initialised by nand_get_chip_info() */
59 static int page_size = 0;
60 static int spare_size = 0;
61 static int pages_per_block = 0;
62 static int total_blocks = 0;
63 static int total_pages = 0;
64 static int row_cycles = 0;
65 static int col_cycles = 0;
66 static int total_banks = 0;
68 /* Static page buffer */
70 #define MAX_PAGE_SIZE 4096
71 #define MAX_SPARE_SIZE 128
73 static int page_buf[(MAX_PAGE_SIZE+MAX_SPARE_SIZE)/4];
76 static void nand_chip_select(int chip)
78 if (chip == -1)
80 /* Disable both chip selects */
81 GPIOB_CLEAR = (1<<21);
82 NFC_CTRL |= NFC_CS0 | NFC_CS1;
84 else
86 /* NFC chip select */
87 if (chip & 1)
89 NFC_CTRL &= ~NFC_CS0;
90 NFC_CTRL |= NFC_CS1;
92 else
94 NFC_CTRL |= NFC_CS0;
95 NFC_CTRL &= ~NFC_CS1;
98 /* Secondary chip select */
99 if (chip & 2)
101 GPIOB_SET = (1<<21);
103 else
105 GPIOB_CLEAR = (1<<21);
111 static void nand_read_id(int chip, unsigned char* id_buf)
113 /* Enable NFC bus clock */
114 BCLKCTR |= DEV_NAND;
116 /* Reset NAND controller */
117 NFC_RST = 0;
119 /* Set slow cycle timings since the chip is as yet unidentified */
120 NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x353;
122 nand_chip_select(chip);
124 /* Set write protect */
125 GPIOB_CLEAR = (1<<19);
127 /* Reset command */
128 NFC_CMD = 0xFF;
130 /* Set 8-bit data width */
131 NFC_CTRL &= ~NFC_16BIT;
133 /* Read ID command, single address cycle */
134 NFC_CMD = 0x90;
135 NFC_SADDR = 0x00;
137 /* Read the 5 single bytes */
138 id_buf[0] = NFC_SDATA & 0xFF;
139 id_buf[1] = NFC_SDATA & 0xFF;
140 id_buf[2] = NFC_SDATA & 0xFF;
141 id_buf[3] = NFC_SDATA & 0xFF;
142 id_buf[4] = NFC_SDATA & 0xFF;
144 nand_chip_select(-1);
146 /* Disable NFC bus clock */
147 BCLKCTR &= ~DEV_NAND;
151 static void nand_read_uid(int chip, unsigned int* uid_buf)
153 int i;
155 /* Enable NFC bus clock */
156 BCLKCTR |= DEV_NAND;
158 /* Set cycle timing (stp = 1, pw = 3, hold = 1) */
159 NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131;
161 nand_chip_select(chip);
163 /* Set write protect */
164 GPIOB_CLEAR = 1<<19;
166 /* Set 8-bit data width */
167 NFC_CTRL &= ~NFC_16BIT;
169 /* Undocumented (SAMSUNG specific?) commands set the chip into a
170 special mode allowing a normally-hidden UID block to be read. */
171 NFC_CMD = 0x30;
172 NFC_CMD = 0x65;
174 /* Read command */
175 NFC_CMD = 0x00;
177 /* Write row/column address */
178 for (i = 0; i < col_cycles; i++) NFC_SADDR = 0;
179 for (i = 0; i < row_cycles; i++) NFC_SADDR = 0;
181 /* End of read */
182 NFC_CMD = 0x30;
184 /* Wait until complete */
185 while (!(NFC_CTRL & NFC_READY)) {};
187 /* Copy data to buffer (data repeats after 8 words) */
188 for (i = 0; i < 8; i++)
190 uid_buf[i] = NFC_WDATA;
193 /* Reset the chip back to normal mode */
194 NFC_CMD = 0xFF;
196 nand_chip_select(-1);
198 /* Disable NFC bus clock */
199 BCLKCTR &= ~DEV_NAND;
203 /* NB: size must be divisible by 4 due to 32-bit read */
204 static void nand_read(int chip, int row, int column, int size)
206 int i;
208 /* Enable NFC bus clock */
209 BCLKCTR |= DEV_NAND;
211 /* Set cycle timing (stp = 1, pw = 3, hold = 1) */
212 NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131;
214 nand_chip_select(chip);
216 /* Set write protect */
217 GPIOB_CLEAR = (1<<19);
219 /* Set 8-bit data width */
220 NFC_CTRL &= ~NFC_16BIT;
222 /* Read command */
223 NFC_CMD = 0x00;
225 /* Write column address */
226 for (i = 0; i < col_cycles; i++)
228 NFC_SADDR = column & 0xFF;
229 column = column >> 8;
232 /* Write row address */
233 for (i = 0; i < row_cycles; i++)
235 NFC_SADDR = row & 0xFF;
236 row = row >> 8;
239 /* End of read command */
240 NFC_CMD = 0x30;
242 /* Wait until complete */
243 while (!(NFC_CTRL & NFC_READY)) {};
245 /* Read data into page buffer */
246 for (i = 0; i < (size/4); i++)
248 page_buf[i] = NFC_WDATA;
251 nand_chip_select(-1);
253 /* Disable NFC bus clock */
254 BCLKCTR &= ~DEV_NAND;
258 /* TEMP testing function */
259 #include "lcd.h"
261 extern int line;
262 static unsigned char str_buf[MAX_PAGE_SIZE];
264 static void nand_test(void)
266 int i,j,row;
267 int pages_per_mb = 1048576/page_size;
269 printf("%d banks", total_banks);
270 printf("* %d pages", total_pages);
271 printf("* %d bytes per page", page_size);
273 while (!button_read_device()) {};
275 /* Now for fun, scan the raw pages for 'TAG' and display the contents */
277 row = 0;
278 while (row < total_pages)
280 bool found = false;
281 unsigned char* buf_ptr = (unsigned char*)page_buf;
283 line = 0;
285 if (row % pages_per_mb == 0) printf("%dMb", row/pages_per_mb);
287 /* Read a page from chip 0 */
288 nand_read(0, row, 0, page_size);
290 for (j = 0; j < page_size; j++)
292 if (buf_ptr[j] == 'T' && buf_ptr[j+1] == 'A' && buf_ptr[j+2] == 'G')
293 found = true;
296 if (found)
298 unsigned char* str_ptr = str_buf;
300 printf("Row %d:", row);
302 /* Copy ascii-readable parts out to a string */
303 for (i = 0; i < page_size; i++)
305 str_buf[i] = ' ';
306 if (buf_ptr[i] > 31 && buf_ptr[i] < 128)
308 *str_ptr++ = buf_ptr[i];
312 str_ptr = str_buf;
314 /* Nasty piece of code to display the text in a readable manner */
315 for (i = 1; i < 30; i++)
317 for (j = 0; j < 48; j++)
319 /* In the absence of a putc() we have this mess... */
320 unsigned char buf2[2];
321 buf2[0] = *str_ptr++;
322 buf2[1] = '\0';
323 lcd_puts(j,i,buf2);
327 /* Alternate hex display code
328 for (i = 0; i<112; i+=4)
330 printf("0x%08x 0x%08x 0x%08x 0x%08x",
331 page_buf[i],page_buf[i+1],page_buf[i+2],page_buf[i+3]);
335 while (!button_read_device()) {};
337 lcd_clear_display();
339 row++;
344 static void nand_get_chip_info(void)
346 bool found = false;
347 unsigned char manuf_id;
348 unsigned char id_buf[5];
350 /* Read chip id from bank 0 */
351 nand_read_id(0, id_buf);
353 manuf_id = id_buf[0];
355 switch (manuf_id)
357 case 0xEC: /* SAMSUNG */
359 switch(id_buf[1]) /* Chip Id */
361 case 0xD5: /* K9LAG08UOM */
363 page_size = 2048;
364 spare_size = 64;
365 pages_per_block = 128;
366 total_blocks = 8192;
367 col_cycles = 2;
368 row_cycles = 3;
370 found = true;
371 break;
373 case 0xD7: /* K9LBG08UOM */
375 page_size = 4096;
376 spare_size = 128;
377 pages_per_block = 128;
378 total_blocks = 8192;
379 col_cycles = 2;
380 row_cycles = 3;
382 found = true;
383 break;
385 break;
388 if (!found)
390 panicf("Unknown NAND: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
391 id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]);
394 total_pages = total_blocks * pages_per_block;
396 /* Establish how many banks are present */
398 nand_read_id(1, id_buf);
400 if (id_buf[0] == manuf_id)
402 /* Bank 1 is populated, now check if banks 2/3 are valid */
403 nand_read_id(2, id_buf);
405 if (id_buf[0] == manuf_id)
407 /* Bank 2 returned matching id - check if 2/3 are shadowing 0/1 */
408 unsigned int uid_buf0[8];
409 unsigned int uid_buf2[8];
411 nand_read_uid(0, uid_buf0);
412 nand_read_uid(2, uid_buf2);
414 if (memcmp(uid_buf0, uid_buf2, 32) == 0)
416 /* UIDs match, assume banks 2/3 are shadowing 0/1 */
417 total_banks = 2;
419 else
421 /* UIDs differ, assume banks 2/3 are valid */
422 total_banks = 4;
425 else
427 /* Bank 2 returned differing id - assume 2/3 are junk */
428 total_banks = 2;
431 else
433 /* Bank 1 returned differing id - assume it is junk */
434 total_banks = 1;
439 /* API Functions */
441 void ata_led(bool onoff)
443 led(onoff);
446 int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int incount,
447 void* inbuf)
449 #warning function not implemented
450 (void)start;
451 (void)incount;
452 (void)inbuf;
453 return 0;
456 int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count,
457 const void* outbuf)
459 #warning function not implemented
460 (void)start;
461 (void)count;
462 (void)outbuf;
463 return 0;
466 void ata_spindown(int seconds)
468 /* null */
469 (void)seconds;
472 bool ata_disk_is_active(void)
474 #warning function not implemented
475 return 0;
478 void ata_sleep(void)
480 #warning function not implemented
483 void ata_spin(void)
485 /* null */
488 /* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */
489 int ata_hard_reset(void)
491 #warning function not implemented
492 return 0;
495 int ata_soft_reset(void)
497 #warning function not implemented
498 return 0;
501 void ata_enable(bool on)
503 /* null - flash controller is enabled/disabled as needed. */
504 (void)on;
507 int ata_init(void)
509 if (!initialized)
511 /* Get chip characteristics and number of banks */
512 nand_get_chip_info();
514 /* TODO: Scan all banks for bad blocks */
516 /* TODO: Build physical->logical address translation */
518 initialized = true;
521 /* TEMP - print out some diagnostics */
522 nand_test();
524 return 0;