/*------------------------------------------------------------------------------------------*\ * * Copyright (C) 2007 AVM GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \*------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------*\ * Direkte Ansteuerung des SPI-Flash im Panic Mode (Urlader-Routinen) \*------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include "tffs_direct_nand.h" #include "tffs_direct_nand_ebu.h" #define DEBUG_NAND #ifdef DEBUG_NAND #define DebugPrintf(...) printk(__VA_ARGS__) #define DBG_NAND(...) printk(__VA_ARGS__) #else #define DebugPrintf(...) #define DBG_NAND(...) #endif #define NAND_BASE_ADDRESS 0xB4000000 struct ebu_register * const ar9_ebu = (struct ebu_register *)&(*(volatile unsigned int *)(IFX_EBU)); struct tffs_nand_flash_device_ tffs_nand_device; #define ECC_HW_BLOCK_SIZE 512 #define ECC_BLOCK_SIZE 256 #define ECC_STEPS 3 extern struct mtd_partition ifx_nand_partitions[]; /* JFFS2 large page layout for 3-byte ECC per 256 bytes ECC layout * This is the only SW ECC supported by u-boot. * So to load u-boot this should be supported */ static unsigned char ecc_pos_64[] = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }; static unsigned int LastScannedBlock = (unsigned int)(-1); static int LastScannedBlockResult = (unsigned int)(-1); static unsigned int NandForceErase = 0; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void nand_wait(unsigned int instanz) { while (!ar9_ebu->nand_wait.Bits.rd_by); } static void delay(unsigned int units) { volatile unsigned int ii; for (ii = 0; ii < units; ii++); } #define WRITE_CMD 0x18 #define WRITE_ADDR 0x14 #define WRITE_LADDR 0x10 #define READ_LDATA 0x00 #define WRITE_DATA 0x10 #define READ_DATA 0x10 #define NAND_WRITE(addr, val) #define READ_NAND(adr) *((volatile u8 *)(NAND_BASE_ADDRESS | (READ_DATA))) #define WRITE_NAND(d, adr) *((volatile u8 *)(NAND_BASE_ADDRESS | (WRITE_DATA))) = d; \ while(!ar9_ebu->nand_wait.Bits.wr_c); #define WRITE_NAND_COMMAND(d, instanz) \ *((volatile u8 *)(NAND_BASE_ADDRESS | (WRITE_CMD))) = d; \ while(!ar9_ebu->nand_wait.Bits.wr_c); #define WRITE_NAND_ADDRESS(d, instanz) \ *((volatile u8 *)(NAND_BASE_ADDRESS | (WRITE_ADDR))) = d; \ while(!ar9_ebu->nand_wait.Bits.wr_c); #define NAND_DISABLE_CE(nand) ar9_ebu->nand_con.Register &= ~(1<<20); #define NAND_ENABLE_CE(nand) ar9_ebu->nand_con.Register |= (1<<20); #define NAND_CTL_CLRCLE(a) #define NAND_CTL_SETCLE(a) /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void tffs_nand_read_buffer(unsigned int instanz, unsigned char *buffer, unsigned int len) { #if defined(NAND_16BIT) unsigned short *pbuffer = (unsigned short *)buffer; len =>> 1; #else unsigned char *pbuffer = buffer; #endif /*--- DBG_NAND("[%s] len %d ", __FUNCTION__, len); ---*/ while (len--) { *pbuffer++ = READ_NAND(instanz); } /*--- DBG_NAND("done\n"); ---*/ } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void tffs_nand_write_buffer(unsigned int instanz, unsigned char *buffer, unsigned int len) { #if defined(NAND_16BIT) unsigned short *pbuffer = (unsigned short *)buffer; len =>> 1; #else unsigned char *pbuffer = buffer; #endif /*--- DBG_NAND("[%s] len %d\n", __FUNCTION__, len); ---*/ while (len--) { WRITE_NAND(*pbuffer++, instanz); } /*--- DBG_NAND("done\n"); ---*/ } /*------------------------------------------------------------------------------------------*\ * wir bekommen die page übergeben - wir brauchen ein Command für den OOB \*------------------------------------------------------------------------------------------*/ static int NanD_Command(unsigned int command, unsigned int page, unsigned int instanz) { int i, bytes = 0; unsigned char offset = 0; /*--- DBG_NAND("[%s] Cmd 0x%x %d page 0x%x\n", __FUNCTION__, command, instanz, page); ---*/ NAND_CTL_SETCLE(instanz); switch (command) { /*--- NAND_CMD_READOOB ist nur ein Hilfskommando ---*/ case NAND_CMD_READOOB: WRITE_NAND_COMMAND(NAND_CMD_READ, instanz); break; /*--- NAND_CMD_PROGRAMOOB ist nur ein Hilfskommando ---*/ case NAND_CMD_PROGRAMOOB: WRITE_NAND_COMMAND(NAND_CMD_PROGRAM, instanz); break; default: WRITE_NAND_COMMAND(command, instanz); break; } NAND_CTL_CLRCLE(instanz); switch (command) { case NAND_CMD_STATUS: break; case NAND_CMD_PROGRAMOOB: case NAND_CMD_READOOB: offset = (tffs_nand_device.nand_Geometry.pagesize >> 8) & 0xFF; /*--- DebugPrintf("[%s] offset 0x%x\n", __FUNCTION__, offset); ---*/ /*--- kein break; ---*/ case NAND_CMD_PROGRAM: case NAND_CMD_READ: WRITE_NAND_ADDRESS(0, instanz); WRITE_NAND_ADDRESS(offset, instanz); bytes = 3; /*--- die Devicesize berücksichtigen ---*/ break; case NAND_CMD_READID: bytes = 1; break; case NAND_CMD_RESET: break; case NAND_CMD_ERASE: bytes = 3; /*--- die Devicesize berücksichtigen ---*/ break; case NAND_CMD_PROGRAM_START: break; default: /*--- DebugPrintf("[%s] unknown Command 0x%x\n", __FUNCTION__, command); ---*/ return -1; } page = page >> 11; /*--- beim AR9 ist page die Adresse, es soll eine Page werden ---*/ for (i=0;i> (i * 8)) & 0xFF; /*--- DebugPrintf("[%s] tmp 0x%x\n",__FUNCTION__, tmp); ---*/ WRITE_NAND_ADDRESS(tmp, instanz); } switch (command) { case NAND_CMD_READ: case NAND_CMD_READOOB: WRITE_NAND_COMMAND(NAND_CMD_READ_START, instanz); break; case NAND_CMD_ERASE: WRITE_NAND_COMMAND(NAND_CMD_ERASE_START, instanz); break; case NAND_CMD_PROGRAM: return FLASH_SUCCESS; } delay(100); nand_wait(instanz); return FLASH_SUCCESS; } /*------------------------------------------------------------------------------------------*\ * gibt das Chipselect zur Page zurück \*------------------------------------------------------------------------------------------*/ static unsigned int get_chip_instanz(unsigned int page) { return 0; /*--- wir haben hier nur eine Instanz ---*/ } /*------------------------------------------------------------------------------------------*\ * ACHTUNG: block_addr - wir rechnen Pageweise d.h. 1,2,3 - ein Block hat dann z.B. 128Pages \*------------------------------------------------------------------------------------------*/ int tffs_nand_block_is_bad(unsigned int page) { unsigned int oobsize = tffs_nand_device.nand_Geometry.oobsize; unsigned char oob_buf[tffs_nand_device.nand_Geometry.oobsize]; unsigned int instanz; unsigned char *p; unsigned int i,len,block; instanz = get_chip_instanz(page); block = page & ~(tffs_nand_device.nand_Geometry.blocksize - 1); DBG_NAND("[%s] instanz %d page 0x%x block 0x%x\n", __FUNCTION__, instanz, page, block); if (LastScannedBlock != block) { LastScannedBlock = block; /*--- DBG_NAND("[%s] page 0x%x instanz %d\n", __FUNCTION__, block, instanz); ---*/ NAND_ENABLE_CE(instanz); NanD_Command(NAND_CMD_READOOB, block, instanz); #if defined(NAND_16BIT) len = oobsize >> 1; p = (unsigned short *)oob_buf; #else len = oobsize; p = oob_buf; #endif for (i = 0; i < len; i++){ *p++ = READ_NAND(instanz); delay(10); } NAND_DISABLE_CE(); /* set pin high */ #if 0 p = oob_buf; for (i = 0; i < len; i++){ DebugPrintf("0x%02x ", *p++); } DebugPrintf("\n"); #endif if (oob_buf[0] != 0xFF) { DebugPrintf("[%s]\n", __FUNCTION__, block); LastScannedBlockResult = -FLASH_BAD_BLOCK; } else LastScannedBlockResult = FLASH_NO_ERROR; } return LastScannedBlockResult; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int tffs_nand_read_page(unsigned int page, unsigned char *buffer) { struct tffs_nand_flash_device_ *flash_device = &tffs_nand_device; int i, pagesize, oobsize, eccsteps, error = FLASH_NO_ERROR; unsigned int instanz; unsigned char *pdata = buffer; enum ecc_errors ecc_error; unsigned char oob_buf[flash_device->nand_Geometry.oobsize]; unsigned char ecc_code[flash_device->nand_Geometry.eccsize]; unsigned char ecc_calc[flash_device->nand_Geometry.eccsize]; instanz = get_chip_instanz(page); pagesize = flash_device->nand_Geometry.pagesize; oobsize = flash_device->nand_Geometry.oobsize; eccsteps = flash_device->nand_Geometry.pagesize/flash_device->nand_Geometry.eccblocksize; NAND_ENABLE_CE(instanz); NanD_Command(NAND_CMD_READ, page, instanz); DBG_NAND("[%s] page 0x%x\n", __FUNCTION__, page); /*--- page lesen und ECC berechnen ---*/ for (i=0; iecc_enable(instanz); /*--- enable HW-ECC ---*/ tffs_nand_read_buffer(instanz, pdata, flash_device->nand_Geometry.eccblocksize); flash_device->ecc_calculate(pdata, &ecc_calc[i*ECC_STEPS]); /*--- HW-ECC auslesen ---*/ pdata += flash_device->nand_Geometry.eccblocksize; } /*--- oob-Daten lesen ---*/ tffs_nand_read_buffer(instanz, oob_buf, oobsize); NAND_DISABLE_CE(); /* set pin high */ /*--- ECC umkopieren ---*/ for (i = 0; i < flash_device->nand_Geometry.eccsize; i++) ecc_code[i] = oob_buf[flash_device->nand_Geometry.ecc_layout[i]]; /*--- ECC vergleichen ---*/ #if defined(DEBUG_NAND) pdata = buffer; #endif for (i=0; iecc_correct(pdata, &ecc_code[i*ECC_STEPS], &ecc_calc[i*ECC_STEPS]); switch (ecc_error) { case no: DBG_NAND ("[%s] no Error page 0x%08x\n", __FUNCTION__, page); break; case onebit: DebugPrintf ("[%s] \n", __FUNCTION__, page); error = -FLASH_SINGLEBIT_ERROR; break; case multibit: DebugPrintf ("[%s] \n", __FUNCTION__, page); #if defined(DEBUG_NAND) && 0 { unsigned int val; for (val = 0; val < flash_device->nand_Geometry.eccblocksize; val++) DebugPrintf("0x%02x ", pdata[val]); DebugPrintf("\n"); } #endif return -FLASH_MULTIBIT_ERROR; } #if defined(DEBUG_NAND) pdata += flash_device->nand_Geometry.eccblocksize; #endif } return error; } /*------------------------------------------------------------------------------------------*\ * read a page with ECC * ueberspringt defekte Bloecke * * returns * FLASH_NO_ERROR * -FLASH_PARAMETER_ERROR * -FLASH_SINGLEBIT_ERROR * -FLASH_MULTIBIT_ERROR * Bytes read \*------------------------------------------------------------------------------------------*/ int tffs_nand_read(unsigned int page, unsigned char *buffer, unsigned int len) { struct tffs_nand_flash_device_ *flash_device = &tffs_nand_device; int status, readlen, pagesize; unsigned char *pdata = buffer; unsigned int offset; int Bytes = 0; /*--------------------------------------------------------------------------------------*\ * Wir schreiben das PANIC-LOG in den letzten NAND-Block der Kernel-Partition \*--------------------------------------------------------------------------------------*/ page = ifx_nand_partitions[0].size - tffs_nand_device.nand_Geometry.blocksize; /*--- DebugPrintf("[%s] p=%#x, o=%#x, b=%#x, len=%d\n",__FUNCTION__, page, offset, (unsigned int)buffer, len); ---*/ pagesize = flash_device->nand_Geometry.pagesize; offset = page % pagesize; if (offset > pagesize) return -FLASH_PARAMETER_ERROR; page -= offset; while (len) { DBG_NAND("[%s] len %d offset %d\n", __FUNCTION__, len, offset); while(tffs_nand_block_is_bad(page)) { /*--- es können mehrere Blöcke hintereinander defekt sein ---*/ #if defined(DEBUG_NAND) unsigned int block; block = page & ~(flash_device->nand_Geometry.blocksize - 1); DebugPrintf("[%s] Block 0x%x Page 0x%x not valid\n", __FUNCTION__, block, page); #endif page += flash_device->nand_Geometry.blocksize; } if ((len < pagesize) || offset) { unsigned char pagesize_buf[pagesize]; DBG_NAND("[%s] use internal buffer on page 0x%x len %d\n", __FUNCTION__, page, len); status = tffs_nand_read_page(page, pagesize_buf); if ((len + offset) < pagesize) readlen = len; else readlen = pagesize - offset; memcpy(pdata, &pagesize_buf[offset], readlen); offset = 0; /*--- DBG_NAND("[%s] readlen %d\n", __FUNCTION__, readlen); ---*/ } else { status = tffs_nand_read_page(page, pdata); readlen = pagesize; } switch (status) { case FLASH_NO_ERROR: case -FLASH_SINGLEBIT_ERROR: break; case -FLASH_MULTIBIT_ERROR: DebugPrintf("[%s]\n", __FUNCTION__, page, status); return status; } pdata += readlen; page += readlen; len -= readlen; Bytes += readlen; } return Bytes; } /*------------------------------------------------------------------------------------------*\ * liefert folgende Fehler * FLASH_NO_ERROR * -FLASH_VERIFY_ERROR * -FLASH_SINGLE_BIT_ERROR * -FLASH_MULTI_BIT_ERROR * \*------------------------------------------------------------------------------------------*/ static int nand_verify(unsigned int page, unsigned char *buffer) { struct tffs_nand_flash_device_ *flash_device = &tffs_nand_device; unsigned char verify_buffer[flash_device->nand_Geometry.pagesize]; int i, pagesize; int status; pagesize = flash_device->nand_Geometry.pagesize; DBG_NAND("[%s] page 0x%x\n", __FUNCTION__, page); status = tffs_nand_read_page(page, verify_buffer); if (status == -FLASH_MULTIBIT_ERROR) { DebugPrintf("[%s] \n", __FUNCTION__, page, status); return status; } for (i=0; i < pagesize; i++) { if (buffer[i] != verify_buffer[i]) { DebugPrintf("[%s] \n", __FUNCTION__, page); return -FLASH_VERIFY_ERROR; } } return status; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int tffs_nand_write_page(unsigned int page, unsigned char *buffer) { struct tffs_nand_flash_device_ *flash_device = &tffs_nand_device; int i, pagesize, oobsize, eccsteps, status; unsigned char ecc_calc[flash_device->nand_Geometry.eccsize]; unsigned char oob_buf[flash_device->nand_Geometry.oobsize]; unsigned int instanz; unsigned char *pdata = buffer; instanz = get_chip_instanz(page); pagesize = flash_device->nand_Geometry.pagesize; oobsize = flash_device->nand_Geometry.oobsize; eccsteps = flash_device->nand_Geometry.pagesize/flash_device->nand_Geometry.eccblocksize; memset(oob_buf, 0xFF, oobsize); DBG_NAND("[%s] page 0x%x\n", __FUNCTION__, page); NAND_ENABLE_CE(instanz); NanD_Command(NAND_CMD_PROGRAM, page, instanz); /*--- page schreiben und ECC berechnen ---*/ for (i=0; iecc_enable(instanz); /*--- enable HW-ECC ---*/ tffs_nand_write_buffer(instanz, pdata, flash_device->nand_Geometry.eccblocksize); flash_device->ecc_calculate(pdata, &ecc_calc[i*ECC_STEPS]) ; /*--- HW-ECC auslesen ---*/ pdata += flash_device->nand_Geometry.eccblocksize; } /*--- ECC umkopieren ---*/ for (i = 0; i < flash_device->nand_Geometry.eccsize; i++) { oob_buf[flash_device->nand_Geometry.ecc_layout[i]] = ecc_calc[i]; } /*--- oob-Daten schreiben ---*/ tffs_nand_write_buffer(instanz, oob_buf, oobsize); NanD_Command(NAND_CMD_PROGRAM_START, page, instanz); status = NanD_Command(NAND_CMD_STATUS, 0, instanz); NAND_DISABLE_CE(); /* set pin high */ if (status & NAND_STATUS_MASK_ERROR) { DebugPrintf("[%s] page 0x%x Status 0x%x\n", __FUNCTION__, page, status); return -FLASH_WRITE_ERROR; } else { return FLASH_NO_ERROR; } } /*------------------------------------------------------------------------------------------*\ * es kann nur Blockweise geschrieben werden * returns * FLASH_NO_ERROR * -FLASH_BAD_BLOCK * -FLASH_VERIFY_ERROR * -FLASH_SINGLEBIT_ERROR * -FLASH_MULTIBIT_ERROR * \*------------------------------------------------------------------------------------------*/ int tffs_nand_write(unsigned int page, unsigned char *pdata, unsigned int len) { struct tffs_nand_flash_device_ *flash_device = &tffs_nand_device; /*--- int pagesize, retry = 3; ---*/ int pagesize; unsigned char *pbuffer = pdata; int status, verify_status; int Bytes = 0; /*--------------------------------------------------------------------------------------*\ * Wir schreiben das PANIC-LOG in den letzten NAND-Block der Kernel-Partition \*--------------------------------------------------------------------------------------*/ page = ifx_nand_partitions[0].size - tffs_nand_device.nand_Geometry.blocksize; pagesize = flash_device->nand_Geometry.pagesize; /*--- den Block auf Gültigkeit checken ---*/ if (tffs_nand_block_is_bad(page)) { #if defined(DEBUG_NAND) unsigned int block = page & ~(tffs_nand_device.nand_Geometry.blocksize - 1); DebugPrintf("[%s]\n", __FUNCTION__, block, page); #endif return -FLASH_BAD_BLOCK; } while (Bytes < len) { DBG_NAND("[%s] write page 0x%x len %d\n", __FUNCTION__, page, len); status = tffs_nand_write_page(page, pbuffer); if (status) { DebugPrintf("\n", page); return status; } verify_status = nand_verify(page, pbuffer); switch (verify_status) { case FLASH_NO_ERROR: break; case -FLASH_VERIFY_ERROR: DebugPrintf("[%s]\n", __FUNCTION__, page); return verify_status; case -FLASH_SINGLEBIT_ERROR: DebugPrintf("[%s]\n", __FUNCTION__, page); return verify_status; case -FLASH_MULTIBIT_ERROR: DebugPrintf("[%s]\n", __FUNCTION__, page); return verify_status; default: DebugPrintf("[%s]\n", __FUNCTION__, page, verify_status); return verify_status; } pbuffer += pagesize; Bytes += pagesize; page += pagesize; } return len; } /*------------------------------------------------------------------------------------------*\ * returns * FLASH_NO_ERROR * -FLASH_ERASE_ERROR * -FLASH_BAD_BLOCK \*------------------------------------------------------------------------------------------*/ int tffs_nand_erase(unsigned int page) { unsigned int status, block, instanz; struct tffs_nand_flash_device_ *flash_device = &tffs_nand_device; instanz = get_chip_instanz(page); block = page & ~(flash_device->nand_Geometry.blocksize - 1); DBG_NAND("[%s] page 0x%x block 0x%x instanz %d\n", __FUNCTION__, page, block, instanz); if (!NandForceErase && tffs_nand_block_is_bad(block)) { return -FLASH_BAD_BLOCK; } NanD_Command(NAND_CMD_ERASE, block, instanz); status = NanD_Command(NAND_CMD_STATUS, 0, instanz); if (status) return -FLASH_ERASE_ERROR; return FLASH_NO_ERROR; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void amazon_s_nand_chip_init(void) { *IFX_GPIO_P1_ALTSEL0 |= (1<<7) | (1<<8); *IFX_GPIO_P1_ALTSEL1 &= ~((1<<7) | (1<<8)); *IFX_GPIO_P1_DIR |= (1<<7) | (1<<8); *IFX_GPIO_P1_OD |= (1<<7) | (1<<8); (*IFX_GPIO_P0_ALTSEL0) |= (1<<13); //Set GPIO 13 to ND_ALE (*IFX_GPIO_P0_ALTSEL1) &= ~(1<<13); (*IFX_GPIO_P0_OD) |= (1<<13); (*IFX_GPIO_P0_DIR) |= (1<<13); // set GPIO 13 to output //USE GPIO48 and 49 for FL_RD and and NAND_READY *IFX_GPIO_P3_ALTSEL0 |= (3<<0) ; *IFX_GPIO_P3_ALTSEL1 &= ~(3<<0); *IFX_GPIO_P3_DIR |= (1<<1); *IFX_GPIO_P3_DIR &= ~(1<<0); *IFX_GPIO_P3_OD |= (1<<1); ar9_ebu->addr_sel0.Register = (NAND_BASE_ADDRESS & 0x1fffff00) | 0x31; /* byte swap;minimum delay*/ ar9_ebu->con0.Register = (1<<22)|(1<<15)|(0xE<<11)|(0x4<<7)|(4<<5)|(2<<3)|(2<<1)|(1<<0); ar9_ebu->nand_con.Register = (0xF<<4)|(1<<1)|(1<<0); asm("sync"); /* Set bus signals to inactive */ NAND_WRITE(WRITE_CMD, 0xff); // Reset nand chip } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int tffs_nand_init(void) { int ID[5], i; unsigned int planesize, planecnt, chipcnt; unsigned int cs; cs = 0; /*--- wir prüfen nur 1 Chipselect ---*/ amazon_s_nand_chip_init(); DBG_NAND("[%s] CS %d ",__FUNCTION__, cs); NAND_ENABLE_CE(); if (NanD_Command(NAND_CMD_RESET, 0, cs)) { DebugPrintf("[%s] Err: RESET\n", __FUNCTION__); NAND_DISABLE_CE(); return 1; } if (NanD_Command(NAND_CMD_READID, 0, cs)) { DebugPrintf("[%s] Err: READID\n", __FUNCTION__ ); NAND_DISABLE_CE(); return 1; } DBG_NAND("ID"); for( i=0 ; i>4) & 0x03))<<10; tffs_nand_device.nand_Geometry.interface_size = ID[3] & 0x40 ? 16 : 8; tffs_nand_device.nand_Geometry.oobsize = (8 << ((ID[3]>>2) & 0x01)) * (tffs_nand_device.nand_Geometry.pagesize >> 9); DBG_NAND("Pagesize 0x%x\n", tffs_nand_device.nand_Geometry.pagesize); DBG_NAND("Blocksize 0x%x\n", tffs_nand_device.nand_Geometry.blocksize); DBG_NAND("Interfacesize 0x%x\n", tffs_nand_device.nand_Geometry.interface_size); DBG_NAND("oobsize 0x%x\n", tffs_nand_device.nand_Geometry.oobsize); planesize = 64 << ((ID[4] >> 4) & 0x7); planecnt = 1 << ((ID[4] >> 2) & 0x3); chipcnt = 1 << ( ID[2] & 0x3); /* Check Micron part or Samsung part */ switch (tffs_nand_device.Manufacturer) { case MANUFACTURE_MICRON: switch (tffs_nand_device.ID) { case MICRON_29F1G_ID_3_3: // Auslesen der planesize aus dem Byte 4 ist mit dem NAND nicht moeglichm da dieses einen // falschen Wert zurueckgibt (000 statt 100) planesize = 1024; tffs_nand_device.nand_Geometry.chipcnt = chipcnt; break; case MICRON_29F1G_ID: case MICRON_29F2G_ID: case MICRON_29F4G_ID: case MICRON_29F16G_ID: case MICRON_29F64G_ID: tffs_nand_device.nand_Geometry.chipcnt = chipcnt; break; default: goto error; } break; case MANUFACTURE_SAMSUNG: switch (tffs_nand_device.ID) { case SAMSUNG_K9F1G08R0A_ID: case SAMSUNG_K9F_ID: tffs_nand_device.nand_Geometry.chipcnt = 1; break; case SAMSUNG_K9F64G08R0A_ID: tffs_nand_device.nand_Geometry.chipcnt = 1; break; default: goto error; } break; case MANUFACTURE_NUMONYX: switch (tffs_nand_device.ID) { case NUMONYX_08GW3x_ID: tffs_nand_device.nand_Geometry.chipcnt = chipcnt = 1; break; case NUMONYX_01GW3B_ID: planesize = 128<<3; /*--- 1GBit - 128MByte ---*/ planecnt = 1; tffs_nand_device.nand_Geometry.chipcnt = chipcnt; break; case NUMONYX_04GW3B_ID: if (ID[2] == 0x80) { /*--- bei dieser Variante gibt es kein ID[4] ---*/ planesize = 512<<3; /*--- 4GBit - 512MByte ---*/ planecnt = 1; } tffs_nand_device.nand_Geometry.chipcnt = chipcnt; break; default: goto error; } break; default: goto error; } /*--- ausgerechnet werden MBit - tffs_nand_device.Size ist MByte also >> 3 ---*/ tffs_nand_device.Size = (planesize * planecnt * chipcnt) >> 3; tffs_nand_device.nand_Geometry.blk_num = (tffs_nand_device.Size << 10)/(tffs_nand_device.nand_Geometry.blocksize >> 10); /*--- XXX tffs_nand_device.nand_Geometry.pageshift = nand_calc_pageshift(tffs_nand_device.nand_Geometry.pagesize); ---*/ if( (MANUFACTURE_MICRON == tffs_nand_device.Manufacturer) && (MICRON_29F1G_ID_3_3 == tffs_nand_device.ID)) { unsigned char result; tffs_nand_device.ecc_calculate = tffs_nand_calculate_hwecc; tffs_nand_device.ecc_correct = tffs_nand_hwecc_correct_data; tffs_nand_device.ecc_enable = tffs_nand_hwecc_enable; // HW-Ecc des Nands einschalten WRITE_NAND_COMMAND(0xEF, cs); // getFeature WRITE_NAND_ADDRESS(0x90, cs); // array operation mode WRITE_NAND(0x08, cs); WRITE_NAND(0x00, cs); WRITE_NAND(0x00, cs); WRITE_NAND(0x00, cs); nand_wait(cs); // read result WRITE_NAND_COMMAND(0xEE, cs); // getFeature WRITE_NAND_ADDRESS(0x90, cs); // array operation mode nand_wait(cs); // read 4 bytes... result = READ_NAND(cs); DBG_NAND("[%s:%d] ::NAND feature bytes:: b1:%u|b2:%u|b3:%u|b4:%u\n", __FUNCTION__, __LINE__, result, READ_NAND(cs), READ_NAND(cs), READ_NAND(cs)); if(!(result & 0x08)) { DebugPrintf("!!! NAND with onchip-Ecc identified, but could not activate this feature !!!"); } } else { tffs_nand_device.ecc_calculate = tffs_nand_calculate_ecc; tffs_nand_device.ecc_correct = tffs_nand_correct_data; tffs_nand_device.ecc_enable = tffs_nand_ecc_enable; } tffs_nand_device.nand_Geometry.ecc_layout = ecc_pos_64; tffs_nand_device.nand_Geometry.eccsize = (tffs_nand_device.nand_Geometry.pagesize / ECC_BLOCK_SIZE) * ECC_STEPS; tffs_nand_device.nand_Geometry.eccblocksize = ECC_BLOCK_SIZE; DBG_NAND("[%s] planesize %d planecnt %d chipcnt %d blk_num %d\n", __FUNCTION__, planesize, planecnt, tffs_nand_device.nand_Geometry.chipcnt, tffs_nand_device.nand_Geometry.blk_num); NAND_DISABLE_CE(); DBG_NAND("[%s] mfr:%x id=%x pagesize=%d blocksize=%dKB %dbit\n", __FUNCTION__, tffs_nand_device.Manufacturer, tffs_nand_device.ID, tffs_nand_device.nand_Geometry.pagesize, tffs_nand_device.nand_Geometry.blocksize >> 10, tffs_nand_device.nand_Geometry.interface_size); DBG_NAND("[%s] ECC_SIZE %d ECC_BLOCK_SIZE %d OOB_SIZE %d ECC_STEPS %d ecc_layout %d\n", __FUNCTION__, tffs_nand_device.nand_Geometry.eccsize, ECC_BLOCK_SIZE, tffs_nand_device.nand_Geometry.oobsize, ECC_STEPS, (tffs_nand_device.nand_Geometry.pagesize == 2048) ? 64 : 128); tffs_nand_device.Erase_Cmd = tffs_nand_erase; return FLASH_SUCCESS; error: DebugPrintf("\n", tffs_nand_device.ID); return FLASH_ID_FAILED; }