From 59914786289033648db9bd5f4222978767e4d665 Mon Sep 17 00:00:00 2001 From: Rob Purchase Date: Fri, 25 Jan 2008 21:37:59 +0000 Subject: Read ID codes & raw page data from D2 NAND flash (work in progress; no logical->physical address translation yet) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16167 a1c6a512-1295-4272-9138-f99709370657 --- bootloader/telechips.c | 4 + firmware/export/tcc780x.h | 28 +- firmware/target/arm/tcc780x/ata-nand-tcc780x.c | 343 ++++++++++++++++++++++++- 3 files changed, 365 insertions(+), 10 deletions(-) diff --git a/bootloader/telechips.c b/bootloader/telechips.c index a51b6775a1..f5669d0bbf 100644 --- a/bootloader/telechips.c +++ b/bootloader/telechips.c @@ -68,6 +68,10 @@ void* main(void) _backlight_on(); +#if defined(COWON_D2) + ata_init(); +#endif + while(!do_power_off) { line = 0; printf("Hello World!"); diff --git a/firmware/export/tcc780x.h b/firmware/export/tcc780x.h index df55c6f03d..78211acf0a 100644 --- a/firmware/export/tcc780x.h +++ b/firmware/export/tcc780x.h @@ -85,6 +85,22 @@ #define CKSEL_PLL1 1 #define CKSEL_XIN 4 +/* Device bits for SWRESET & BCLKCTR */ + +#define DEV_LCDC (1<<2) +#define DEV_SDMMC (1<<6) +#define DEV_NAND (1<<9) +#define DEV_DAI (1<<14) +#define DEV_ECC (1<<16) +#define DEV_RTC (1<<21) +#define DEV_SDRAM (1<<22) +#define DEV_COP (1<<23) +#define DEV_ADC (1<<24) +#define DEV_TIMER (1<<26) +#define DEV_CPU (1<<27) +#define DEV_IRQ (1<<28) +#define DEV_MAIN (1<<31) + /* IRQ Controller */ #define IEN (*(volatile unsigned long *)0xF3001000) @@ -111,12 +127,12 @@ #define TREF1 (*(volatile unsigned long *)0xF3003018) #define TIREQ (*(volatile unsigned long *)0xF3003060) -/* ref. value reached */ -#define TF0 (1<<8) -#define TF1 (1<<9) -/* irq. status */ -#define TI0 (1<<0) -#define TI1 (1<<1) + +/* TIREQ flags */ +#define TF0 (1<<8) /* Timer 0 reference value reached */ +#define TF1 (1<<9) /* Timer 1 reference value reached */ +#define TI0 (1<<0) /* Timer 0 IRQ flag */ +#define TI1 (1<<1) /* Timer 1 IRQ flag */ #define TC32EN (*(volatile unsigned long *)0xF3003080) #define TC32LDV (*(volatile unsigned long *)0xF3003084) 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 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2007 Dave Chapman + * Copyright (C) 2008 Rob Purchase * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. @@ -32,12 +32,335 @@ int ata_spinup_time = 0; long last_disk_activity = -1; -/** static, private data **/ +/** static, private data **/ static bool initialized = false; static long next_yield = 0; #define MIN_YIELD_PERIOD 2000 + +/* TCC780x NAND Flash Controller */ + +#define NFC_CMD (*(volatile unsigned long *)0xF0053000) +#define NFC_SADDR (*(volatile unsigned long *)0xF005300C) +#define NFC_SDATA (*(volatile unsigned long *)0xF0053040) +#define NFC_WDATA (*(volatile unsigned long *)0xF0053010) +#define NFC_CTRL (*(volatile unsigned long *)0xF0053050) +#define NFC_IREQ (*(volatile unsigned long *)0xF0053060) +#define NFC_RST (*(volatile unsigned long *)0xF0053064) + +#define NFC_16BIT (1<<26) +#define NFC_CS0 (1<<23) +#define NFC_CS1 (1<<22) +#define NFC_READY (1<<20) + + +#if defined(COWON_D2) +/* + ===== Temporary D2 testing code ===== + + (assumes SAMSUNG K9LAG08UOM (2GB) in 1, 2 or 4 banks) + + Manufacturer Id: {0xec, 0xd5, 0x55, 0x25, 0x68} + +*/ +#define PAGE_SIZE 2048 +#define SPARE_SIZE 64 +#define PAGES_PER_BLOCK 128 +#define TOTAL_BLOCKS 8192 +#define TOTAL_PAGES (TOTAL_BLOCKS * PAGES_PER_BLOCK) +#define COL_CYCLES 2 +#define ROW_CYCLES 3 + +static int page_buf[PAGE_SIZE/4]; + +static void nand_chip_select(int chip) +{ + if (chip == -1) + { + /* Disable both chip selects */ + GPIOB_CLEAR = (1<<21); + NFC_CTRL |= NFC_CS0 | NFC_CS1; + } + else + { + /* NFC chip select */ + if (chip & 1) + { + NFC_CTRL &= ~NFC_CS0; + NFC_CTRL |= NFC_CS1; + } + else + { + NFC_CTRL |= NFC_CS0; + NFC_CTRL &= ~NFC_CS1; + } + + /* Secondary chip select */ + if (chip & 2) + { + GPIOB_SET = (1<<21); + } + else + { + GPIOB_CLEAR = (1<<21); + } + } +} + +static void nand_read_id(int chip, unsigned char* id_buf) +{ + int i; + + /* Enable NFC bus clock */ + BCLKCTR |= DEV_NAND; + + /* Reset NAND controller */ + NFC_RST = 0; + + /* Set slow cycle timings since the chip is as yet unidentified */ + NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x353; + + nand_chip_select(chip); + + /* Set write protect */ + GPIOB_CLEAR = (1<<19); + + /* Reset command */ + NFC_CMD = 0xFF; + + /* Set 8-bit data width */ + NFC_CTRL &= ~NFC_16BIT; + + /* Read ID command, single address cycle */ + NFC_CMD = 0x90; + NFC_SADDR = 0x00; + + /* Read the 5 single bytes */ + id_buf[0] = NFC_SDATA & 0xFF; + id_buf[1] = NFC_SDATA & 0xFF; + id_buf[2] = NFC_SDATA & 0xFF; + id_buf[3] = NFC_SDATA & 0xFF; + id_buf[4] = NFC_SDATA & 0xFF; + + nand_chip_select(-1); + + /* Disable NFC bus clock */ + BCLKCTR &= ~DEV_NAND; +} + + +static void nand_read_uid(int chip) +{ + int i; + + /* Enable NFC bus clock */ + BCLKCTR |= DEV_NAND; + + /* Set cycle timing (stp = 1, pw = 3, hold = 1) */ + NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131; + + nand_chip_select(chip); + + /* Set write protect */ + GPIOB_CLEAR = 1<<19; + + /* Set 8-bit data width */ + NFC_CTRL &= ~NFC_16BIT; + + /* Undocumented (SAMSUNG specific?) commands set the chip into a + special mode allowing a normally-hidden UID block to be read. */ + NFC_CMD = 0x30; + NFC_CMD = 0x65; + + /* Read command */ + NFC_CMD = 0x00; + + /* Write row/column address */ + for (i = 0; i < COL_CYCLES; i++) NFC_SADDR = 0; + for (i = 0; i < ROW_CYCLES; i++) NFC_SADDR = 0; + + /* End of read */ + NFC_CMD = 0x30; + + /* Wait until complete */ + while (!(NFC_CTRL & NFC_READY)) {}; + + /* Copy data to buffer (data repeats after 8 words) */ + for (i = 0; i < 8; i++) + { + page_buf[i] = NFC_WDATA; + } + + /* Reset the chip back to normal mode */ + NFC_CMD = 0xFF; + + nand_chip_select(-1); + + /* Disable NFC bus clock */ + BCLKCTR &= ~DEV_NAND; +} + + +/* NB: size must be divisible by 4 due to 32-bit read */ +static void nand_read(int chip, int row, int column, int size) +{ + int i; + + /* Enable NFC bus clock */ + BCLKCTR |= DEV_NAND; + + /* Set cycle timing (stp = 1, pw = 3, hold = 1) */ + NFC_CTRL = (NFC_CTRL &~0xFFF) | 0x131; + + nand_chip_select(chip); + + /* Set write protect */ + GPIOB_CLEAR = (1<<19); + + /* Set 8-bit data width */ + NFC_CTRL &= ~NFC_16BIT; + + /* Read command */ + NFC_CMD = 0x00; + + /* Write column address */ + for (i = 0; i < COL_CYCLES; i++) + { + NFC_SADDR = column & 0xFF; + column = column >> 8; + } + + /* Write row address */ + for (i = 0; i < ROW_CYCLES; i++) + { + NFC_SADDR = row & 0xFF; + row = row >> 8; + } + + /* End of read command */ + NFC_CMD = 0x30; + + /* Wait until complete */ + while (!(NFC_CTRL & NFC_READY)) {}; + + /* Read data into page buffer */ + for (i = 0; i < (size/4); i++) + { + page_buf[i] = NFC_WDATA; + } + + nand_chip_select(-1); + + /* Disable NFC bus clock */ + BCLKCTR &= ~DEV_NAND; +} + + +/* TEMP testing function */ +#include +#include "lcd.h" + +extern int line; + +static void nand_test(void) +{ + int i,j,row; + unsigned char id_buf[5]; + unsigned char str_buf[PAGE_SIZE]; + + /* Display ID codes & UID block for each bank */ + for (i = 0; i < 4; i++) + { + printf("NAND bank %d:", i); + + nand_read_id(i, id_buf); + + printf("ID: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", + id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]); + + nand_read_uid(i); + + for (j = 0; j < 8; j += 4) + { + printf("0x%08x 0x%08x 0x%08x 0x%08x", + page_buf[j],page_buf[j+1],page_buf[j+2],page_buf[j+3]); + } + + line++; + } + + while (!button_read_device()) {}; + + /* Now for fun, scan the raw pages for 'TAG' and display the contents */ + + row = 0; + while (row < TOTAL_PAGES) + { + bool found = false; + unsigned char* buf_ptr = (unsigned char*)page_buf; + + line = 0; + + /* Read a page from chip 0 */ + nand_read(0, row, 0, PAGE_SIZE); + + if (row % 512 == 0) printf("%dMb", row/512); + + for (j = 0; j < PAGE_SIZE; j++) + { + if (buf_ptr[j] == 'T' && buf_ptr[j+1] == 'A' && buf_ptr[j+2] == 'G') + found = true; + } + + if (found) + { + unsigned char* str_ptr = str_buf; + + printf("Row %d:", row); + + /* Copy ascii-readable parts out to a string */ + for (i = 0; i < PAGE_SIZE; i++) + { + str_buf[i] = ' '; + if (buf_ptr[i] > 31 && buf_ptr[i] < 128) + { + *str_ptr++ = buf_ptr[i]; + } + } + + str_ptr = str_buf; + + /* Nasty piece of code to display the text in a readable manner */ + for (i = 1; i < 30; i++) + { + for (j = 0; j < 48; j++) + { + /* In the absence of a putc() we have this mess... */ + unsigned char buf2[2]; + buf2[0] = *str_ptr++; + buf2[1] = '\0'; + lcd_puts(j,i,buf2); + } + } + + /* Alternate hex display code + for (i = 0; i<112; i+=4) + { + printf("0x%08x 0x%08x 0x%08x 0x%08x",buf[i],buf[i+1],buf[i+2],buf[i+3]); + } + */ + + while (!button_read_device()) {}; + + lcd_clear_display(); + } + row++; + } +} +#endif + + /* API Functions */ void ata_led(bool onoff) @@ -67,7 +390,7 @@ int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, void ata_spindown(int seconds) { - #warning function not implemented + /* null */ (void)seconds; } @@ -84,7 +407,7 @@ void ata_sleep(void) void ata_spin(void) { - #warning function not implemented + /* null */ } /* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */ @@ -109,5 +432,17 @@ void ata_enable(bool on) int ata_init(void) { #warning function not implemented + + /* This needs to: + a) establish how many banks are present + (using nand_read_id() and nand_read_uid() above) + b) scan all banks for bad blocks + c) use this info to build a physical->logical address translation + (using an as yet unknown scheme) + */ + + /* TEMP - print out some diagnostics */ + nand_test(); + return 0; } -- cgit v1.2.3