/**************************************************************************//** * @file nandDrv.c * @version V3.00 * @brief N9H20 series SIC driver source file * * SPDX-License-Identifier: Apache-2.0 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. *****************************************************************************/ #include <stdlib.h> #include <string.h> #include "wbio.h" #include "N9H20_SIC.h" #include "wblib.h" #include "fmi.h" #include "GNAND_Global.h" #include "N9H20_GNAND.h" // define DATE CODE and show it when running to make maintaining easy. #define NAND_DATE_CODE FMI_DATE_CODE #define NAND_RESERVED_BLOCK 10 #define OPT_TWO_RB_PINS #define OPT_FIRST_4BLOCKS_ECC4 #define OPT_SUPPORT_H27UAG8T2A /* define DBG_DATA_CONFIRM to read back and compare data after page write. It is debug only. */ //#define DBG_DATA_CONFIRM #ifdef DBG_DATA_CONFIRM static INT sicSM_is_page_dirty(INT chipSel, INT PBA, INT page); __align(4096) UCHAR buffR[4096]; UCHAR *ptr_buffR; #endif #ifdef OPT_SW_WP #define SW_WP_DELAY_LOOP 3000 #endif BOOL volatile _fmi_bIsNandFirstAccess = TRUE; #ifdef _SIC_USE_INT_ extern BOOL volatile _fmi_bIsSMDataReady; #endif INT fmiSMCheckBootHeader(INT chipSel, FMI_SM_INFO_T *pSM); static int _nand_init0 = 0, _nand_init1 = 0; #if defined (__GNUC__) UCHAR _fmi_ucSMBuffer[4096] __attribute__((aligned (4096))); #else __align(4096) UCHAR _fmi_ucSMBuffer[4096]; #endif UINT8 *_fmi_pSMBuffer; /* functions */ INT fmiSMCheckRB(FMI_SM_INFO_T *pSM) { #if 0 // no timer in it UINT32 ii; for (ii=0; ii<100; ii++); while(1) { if(pSM == pSM0) { if (inpw(REG_SMISR) & SMISR_RB0_IF) { while(! (inpw(REG_SMISR) & SMISR_RB0) ); outpw(REG_SMISR, SMISR_RB0_IF); return 1; } } else { if (inpw(REG_SMISR) & SMISR_RB1_IF) { while(! (inpw(REG_SMISR) & SMISR_RB1) ); outpw(REG_SMISR, SMISR_RB1_IF); return 1; } } } return 0; #else unsigned int volatile tick; tick = sysGetTicks(TIMER0); while(1) { if(pSM == pSM0) { if (inpw(REG_SMISR) & SMISR_RB0_IF) { while(! (inpw(REG_SMISR) & SMISR_RB0) ); outpw(REG_SMISR, SMISR_RB0_IF); return 1; } } else { if (inpw(REG_SMISR) & SMISR_RB1_IF) { while(! (inpw(REG_SMISR) & SMISR_RB1) ); outpw(REG_SMISR, SMISR_RB1_IF); return 1; } } if ((sysGetTicks(TIMER0) - tick) > 1000) break; } return 0; #endif } INT fmiSMCheckStatus(FMI_SM_INFO_T *pSM) { UINT32 status, ret; ret = 0; outpw(REG_SMCMD, 0x70); // Status Read command for NAND flash status = inpw(REG_SMDATA); if (status & BIT0) // BIT0: Chip status: 1:fail; 0:pass { #ifdef DEBUG printf("NAND device status: FAIL!!\n"); #endif sysprintf("ERROR: NAND device status: FAIL!!\n"); ret = FMI_SM_STATUS_ERR; } if ((status & BIT7) == 0) // BIT7: Write Protect: 1:unprotected; 0:protected { #ifdef DEBUG printf("NAND device status: Write Protected!!\n"); #endif sysprintf("WARNING: NAND device status: Write Protected!!\n"); ret = FMI_SM_STATUS_ERR; } return ret; } // SM functions INT fmiSM_Reset(FMI_SM_INFO_T *pSM) { #ifdef OPT_TWO_RB_PINS UINT32 volatile i; if(pSM == pSM0) outpw(REG_SMISR, SMISR_RB0_IF); else outpw(REG_SMISR, SMISR_RB1_IF); outpw(REG_SMCMD, 0xff); for (i=100; i>0; i--); if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; return 0; #else UINT32 volatile i; outpw(REG_SMISR, SMISR_RB0_IF); outpw(REG_SMCMD, 0xff); for (i=100; i>0; i--); if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; return 0; #endif // OPT_TWO_RB_PINS } VOID fmiSM_Initial(FMI_SM_INFO_T *pSM) { if (pSM->nPageSize == NAND_PAGE_8KB) { outpw(REG_SMCSR, (inpw(REG_SMCSR)&(~SMCR_PSIZE))|PSIZE_8K); } else if (pSM->nPageSize == NAND_PAGE_4KB) { outpw(REG_SMCSR, (inpw(REG_SMCSR)&(~SMCR_PSIZE))|PSIZE_4K); } else if (pSM->nPageSize == NAND_PAGE_2KB) { outpw(REG_SMCSR, (inpw(REG_SMCSR)&(~SMCR_PSIZE))|PSIZE_2K); } else // pSM->nPageSize = NAND_PAGE_512B { outpw(REG_SMCSR, (inpw(REG_SMCSR)&(~SMCR_PSIZE))|PSIZE_512); } outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_ECC_EN); // enable ECC if (pSM->bIsCheckECC) outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_ECC_CHK); // enable ECC check else outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_ECC_CHK); // disable ECC check #ifdef _SIC_USE_INT_ if ((_nand_init0 == 0) && (_nand_init1 == 0)) outpw(REG_SMIER, SMIER_DMA_IE); #endif //_SIC_USE_INT_ // set BCH_Tx and redundant area size outpw(REG_SMREAREA_CTL, inpw(REG_SMREAREA_CTL) & ~SMRE_MECC); // Redundant area size if (pSM->nPageSize == NAND_PAGE_8KB) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T12); // BCH_12 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 376); // Redundant area size } else if (pSM->nPageSize == NAND_PAGE_4KB) { if (pSM->bIsNandECC12 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T12); // BCH_12 is selected #ifdef OPT_SUPPORT_H27UAG8T2A outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 224);; // Redundant area size #else outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 216);; // Redundant area size #endif } else if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 128); // Redundant area size } else { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 128); // Redundant area size } } else if (pSM->nPageSize == NAND_PAGE_2KB) { if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } else { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } } else { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 16); // Redundant area size } } /*----------------------------------------------------------------------------- * Read NAND chip ID from chip and then set pSM and NDISK by chip ID. *---------------------------------------------------------------------------*/ INT fmiSM_ReadID(FMI_SM_INFO_T *pSM, NDISK_T *NDISK_info) { UINT32 tempID[5]; fmiSM_Reset(pSM); outpw(REG_SMCMD, 0x90); // read ID command outpw(REG_SMADDR, EOA_SM); // address 0x00 tempID[0] = inpw(REG_SMDATA); tempID[1] = inpw(REG_SMDATA); tempID[2] = inpw(REG_SMDATA); tempID[3] = inpw(REG_SMDATA); tempID[4] = inpw(REG_SMDATA); NDISK_info->vendor_ID = tempID[0]; NDISK_info->device_ID = tempID[1]; if (((tempID[0] == 0xC2) && (tempID[1] == 0x79)) || ((tempID[0] == 0xC2) && (tempID[1] == 0x76))) // Don't support ECC for NAND Interface ROM pSM->bIsCheckECC = FALSE; else pSM->bIsCheckECC = TRUE; pSM->bIsNandECC4 = FALSE; pSM->bIsNandECC8 = FALSE; pSM->bIsNandECC12 = FALSE; pSM->bIsNandECC15 = FALSE; switch (tempID[1]) { /* page size 512B */ case 0x79: // 128M pSM->uSectorPerFlash = 255744; pSM->uBlockPerFlash = 8191; pSM->uPagePerBlock = 32; pSM->uSectorPerBlock = 32; pSM->bIsMulticycle = TRUE; pSM->nPageSize = NAND_PAGE_512B; pSM->bIsNandECC4 = TRUE; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nBlockPerZone = 8192; /* blocks per zone */ NDISK_info->nPagePerBlock = 32; /* pages per block */ NDISK_info->nLBPerZone = 8000; /* logical blocks per zone */ NDISK_info->nPageSize = 512; break; case 0x76: // 64M case 0x5A: // 64M XtraROM pSM->uSectorPerFlash = 127872; pSM->uBlockPerFlash = 4095; pSM->uPagePerBlock = 32; pSM->uSectorPerBlock = 32; pSM->bIsMulticycle = TRUE; pSM->nPageSize = NAND_PAGE_512B; pSM->bIsNandECC4 = TRUE; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nBlockPerZone = 4096; /* blocks per zone */ NDISK_info->nPagePerBlock = 32; /* pages per block */ NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */ NDISK_info->nPageSize = 512; break; case 0x75: // 32M pSM->uSectorPerFlash = 63936; pSM->uBlockPerFlash = 2047; pSM->uPagePerBlock = 32; pSM->uSectorPerBlock = 32; pSM->bIsMulticycle = FALSE; pSM->nPageSize = NAND_PAGE_512B; pSM->bIsNandECC4 = TRUE; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nBlockPerZone = 2048; /* blocks per zone */ NDISK_info->nPagePerBlock = 32; /* pages per block */ NDISK_info->nLBPerZone = 2000; /* logical blocks per zone */ NDISK_info->nPageSize = 512; break; case 0x73: // 16M pSM->uSectorPerFlash = 31968; // max. sector no. = 999 * 32 pSM->uBlockPerFlash = 1023; pSM->uPagePerBlock = 32; pSM->uSectorPerBlock = 32; pSM->bIsMulticycle = FALSE; pSM->nPageSize = NAND_PAGE_512B; pSM->bIsNandECC4 = TRUE; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nBlockPerZone = 1024; /* blocks per zone */ NDISK_info->nPagePerBlock = 32; /* pages per block */ NDISK_info->nLBPerZone = 1000; /* logical blocks per zone */ NDISK_info->nPageSize = 512; break; /* page size 2KB */ case 0xf1: // 128M case 0xd1: pSM->uBlockPerFlash = 1023; pSM->uPagePerBlock = 64; pSM->uSectorPerBlock = 256; pSM->uSectorPerFlash = 255744; pSM->bIsMulticycle = FALSE; pSM->nPageSize = NAND_PAGE_2KB; pSM->bIsNandECC8 = TRUE; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nBlockPerZone = 1024; /* blocks per zone */ NDISK_info->nPagePerBlock = 64; /* pages per block */ NDISK_info->nLBPerZone = 1000; /* logical blocks per zone */ NDISK_info->nPageSize = 2048; // 2013/10/22, support MXIC MX30LF1G08AA NAND flash // 2015/06/22, support MXIC MX30LF1G18AC NAND flash if ( ((tempID[0]==0xC2)&&(tempID[1]==0xF1)&&(tempID[2]==0x80)&&(tempID[3]==0x1D)) || ((tempID[0]==0xC2)&&(tempID[1]==0xF1)&&(tempID[2]==0x80)&&(tempID[3]==0x95)&&(tempID[4]==0x02)) ) { // The first ID of this NAND is 0xC2 BUT it is NOT NAND ROM (read only) // So, we MUST modify the configuration of it // 1. change pSM->bIsCheckECC to TRUE to enable ECC feature; // 2. assign a fake vendor_ID to make NVTFAT can write data to this NAND disk. // (GNAND will check vendor_ID and set disk to DISK_TYPE_READ_ONLY if it is 0xC2) pSM->bIsCheckECC = TRUE; NDISK_info->vendor_ID = 0xFF; // fake vendor_ID } // 2014/10/16, support Winbond W29N01GV NAND flash // 2017/09/14, support Samsung K9F1G08U0B NAND flash // 2017/09/19, support Winbond W29N01HV NAND flash if ( ((tempID[0]==0xEF)&&(tempID[1]==0xF1)&&(tempID[2]==0x80)&&(tempID[3]==0x95)) || ((tempID[0]==0xEC)&&(tempID[1]==0xF1)&&(tempID[2]==0x00)&&(tempID[3]==0x95)) || ((tempID[0]==0xEF)&&(tempID[1]==0xF1)&&(tempID[2]==0x00)&&(tempID[3]==0x95)) ) { NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; } break; case 0xda: // 256M if ((tempID[3] & 0x33) == 0x11) { pSM->uBlockPerFlash = 2047; pSM->uPagePerBlock = 64; pSM->uSectorPerBlock = 256; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 64; /* pages per block */ NDISK_info->nBlockPerZone = 2048; /* blocks per zone */ NDISK_info->nLBPerZone = 2000; /* logical blocks per zone */ } else if ((tempID[3] & 0x33) == 0x21) { pSM->uBlockPerFlash = 1023; pSM->uPagePerBlock = 128; pSM->uSectorPerBlock = 512; pSM->bIsMLCNand = TRUE; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 128; /* pages per block */ NDISK_info->nBlockPerZone = 1024; /* blocks per zone */ NDISK_info->nLBPerZone = 1000; /* logical blocks per zone */ } pSM->uSectorPerFlash = 511488; pSM->bIsMulticycle = TRUE; pSM->nPageSize = NAND_PAGE_2KB; pSM->bIsNandECC8 = TRUE; // 2018/10/29, support MXIC MX30LF2G18AC NAND flash if ((tempID[0]==0xC2)&&(tempID[1]==0xDA)&&(tempID[2]==0x90)&&(tempID[3]==0x95)&&(tempID[4]==0x06)) { // The first ID of this NAND is 0xC2 BUT it is NOT NAND ROM (read only) // So, we MUST modify the configuration of it // 1. change pSM->bIsCheckECC to TRUE to enable ECC feature; // 2. assign a fake vendor_ID to make NVTFAT can write data to this NAND disk. // (GNAND will check vendor_ID and set disk to DISK_TYPE_READ_ONLY if it is 0xC2) pSM->bIsCheckECC = TRUE; NDISK_info->vendor_ID = 0xFF; // fake vendor_ID } NDISK_info->nPageSize = 2048; break; case 0xdc: // 512M // 2020/10/08, support Micron MT29F4G08ABAEA 512MB NAND flash if ((tempID[0]==0x2C)&&(tempID[2]==0x90)&&(tempID[3]==0xA6)&&(tempID[4]==0x54)) { pSM->uBlockPerFlash = 2047; // block index with 0-base. = physical blocks - 1 pSM->uPagePerBlock = 64; pSM->nPageSize = NAND_PAGE_4KB; pSM->uSectorPerBlock = pSM->nPageSize / 512 * pSM->uPagePerBlock; pSM->bIsMLCNand = FALSE; pSM->bIsMulticycle = TRUE; //pSM->bIsNandECC24 = TRUE; // FA93 don't support ECC 24 pSM->bIsNandECC12 = TRUE; // FA93 use ECC 12 with OOB 224 bytes NDISK_info->NAND_type = (pSM->bIsMLCNand ? NAND_TYPE_MLC : NAND_TYPE_SLC); NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; // number of zones NDISK_info->nBlockPerZone = pSM->uBlockPerFlash + 1; // blocks per zone NDISK_info->nPagePerBlock = pSM->uPagePerBlock; NDISK_info->nPageSize = pSM->nPageSize; NDISK_info->nLBPerZone = 2000; // logical blocks per zone pSM->uSectorPerFlash = pSM->uSectorPerBlock * NDISK_info->nLBPerZone / 1000 * 999; break; } // 2017/9/19, To support both Maker Founder MP4G08JAA // and Toshiba TC58NVG2S0HTA00 512MB NAND flash if ((tempID[0]==0x98)&&(tempID[2]==0x90)&&(tempID[3]==0x26)&&(tempID[4]==0x76)) { pSM->uBlockPerFlash = 2047; // block index with 0-base. = physical blocks - 1 pSM->uPagePerBlock = 64; pSM->nPageSize = NAND_PAGE_4KB; pSM->uSectorPerBlock = pSM->nPageSize / 512 * pSM->uPagePerBlock; pSM->bIsMLCNand = FALSE; pSM->bIsMulticycle = TRUE; pSM->bIsNandECC8 = TRUE; NDISK_info->NAND_type = (pSM->bIsMLCNand ? NAND_TYPE_MLC : NAND_TYPE_SLC); NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; // number of zones NDISK_info->nBlockPerZone = pSM->uBlockPerFlash + 1; // blocks per zone NDISK_info->nPagePerBlock = pSM->uPagePerBlock; NDISK_info->nPageSize = pSM->nPageSize; NDISK_info->nLBPerZone = 2000; // logical blocks per zone pSM->uSectorPerFlash = pSM->uSectorPerBlock * NDISK_info->nLBPerZone / 1000 * 999; break; } if ((tempID[3] & 0x33) == 0x11) { pSM->uBlockPerFlash = 4095; pSM->uPagePerBlock = 64; pSM->uSectorPerBlock = 256; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 64; /* pages per block */ NDISK_info->nBlockPerZone = 4096; /* blocks per zone */ NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */ } else if ((tempID[3] & 0x33) == 0x21) { pSM->uBlockPerFlash = 2047; pSM->uPagePerBlock = 128; pSM->uSectorPerBlock = 512; pSM->bIsMLCNand = TRUE; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 128; /* pages per block */ NDISK_info->nBlockPerZone = 2048; /* blocks per zone */ NDISK_info->nLBPerZone = 2000; /* logical blocks per zone */ } pSM->uSectorPerFlash = 1022976; pSM->bIsMulticycle = TRUE; pSM->nPageSize = NAND_PAGE_2KB; pSM->bIsNandECC8 = TRUE; NDISK_info->nPageSize = 2048; // 2018/10/29, support MXIC MX30LF4G18AC NAND flash if ((tempID[0]==0xC2)&&(tempID[1]==0xDC)&&(tempID[2]==0x90)&&(tempID[3]==0x95)&&(tempID[4]==0x56)) { // The first ID of this NAND is 0xC2 BUT it is NOT NAND ROM (read only) // So, we MUST modify the configuration of it // 1. change pSM->bIsCheckECC to TRUE to enable ECC feature; // 2. assign a fake vendor_ID to make NVTFAT can write data to this NAND disk. // (GNAND will check vendor_ID and set disk to DISK_TYPE_READ_ONLY if it is 0xC2) pSM->bIsCheckECC = TRUE; NDISK_info->vendor_ID = 0xFF; // fake vendor_ID } break; case 0xd3: // 2014/4/2, To support Samsung K9WAG08U1D 512MB NAND flash if ((tempID[0]==0xEC)&&(tempID[2]==0x51)&&(tempID[3]==0x95)&&(tempID[4]==0x58)) { pSM->uBlockPerFlash = 4095; // block index with 0-base. = physical blocks - 1 pSM->uPagePerBlock = 64; pSM->nPageSize = NAND_PAGE_2KB; pSM->uSectorPerBlock = pSM->nPageSize / 512 * pSM->uPagePerBlock; pSM->bIsMLCNand = FALSE; pSM->bIsMulticycle = TRUE; pSM->bIsNandECC8 = TRUE; pSM->uSectorPerFlash = 1022976; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; // number of zones NDISK_info->nBlockPerZone = pSM->uBlockPerFlash + 1; // blocks per zone NDISK_info->nPagePerBlock = pSM->uPagePerBlock; NDISK_info->nPageSize = pSM->nPageSize; NDISK_info->nLBPerZone = 4000; // logical blocks per zone break; } // 2016/9/29, support MXIC MX60LF8G18AC NAND flash if ((tempID[0]==0xC2)&&(tempID[1]==0xD3)&&(tempID[2]==0xD1)&&(tempID[3]==0x95)&&(tempID[4]==0x5A)) { // The first ID of this NAND is 0xC2 BUT it is NOT NAND ROM (read only) // So, we MUST modify the configuration of it // 1. change pSM->bIsCheckECC to TRUE to enable ECC feature; // 2. assign a fake vendor_ID to make NVTFAT can write data to this NAND disk. // (GNAND will check vendor_ID and set disk to DISK_TYPE_READ_ONLY if it is 0xC2) pSM->bIsCheckECC = TRUE; NDISK_info->vendor_ID = 0xFF; // fake vendor_ID } if ((tempID[3] & 0x33) == 0x32) { pSM->uBlockPerFlash = 2047; pSM->uPagePerBlock = 128; pSM->uSectorPerBlock = 1024; /* 128x8 */ pSM->nPageSize = NAND_PAGE_4KB; pSM->bIsMLCNand = TRUE; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 128; /* pages per block */ NDISK_info->nPageSize = 4096; NDISK_info->nBlockPerZone = 2048; /* blocks per zone */ NDISK_info->nLBPerZone = 2000; /* logical blocks per zone */ } else if ((tempID[3] & 0x33) == 0x11) { pSM->uBlockPerFlash = 8191; pSM->uPagePerBlock = 64; pSM->uSectorPerBlock = 256; pSM->nPageSize = NAND_PAGE_2KB; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 64; /* pages per block */ NDISK_info->nPageSize = 2048; NDISK_info->nBlockPerZone = 8192; /* blocks per zone */ NDISK_info->nLBPerZone = 8000; /* logical blocks per zone */ } else if ((tempID[3] & 0x33) == 0x21) { pSM->uBlockPerFlash = 4095; pSM->uPagePerBlock = 128; pSM->uSectorPerBlock = 512; pSM->nPageSize = NAND_PAGE_2KB; pSM->bIsMLCNand = TRUE; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 128; /* pages per block */ NDISK_info->nPageSize = 2048; NDISK_info->nBlockPerZone = 4096; /* blocks per zone */ NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */ } else if ((tempID[3] & 0x33) == 0x22) { pSM->uBlockPerFlash = 4095; pSM->uPagePerBlock = 64; pSM->uSectorPerBlock = 512; /* 64x8 */ pSM->nPageSize = NAND_PAGE_4KB; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 64; /* pages per block */ NDISK_info->nPageSize = 4096; NDISK_info->nBlockPerZone = 4096; /* blocks per zone */ NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */ } pSM->uSectorPerFlash = 2045952; pSM->bIsMulticycle = TRUE; pSM->bIsNandECC8 = TRUE; break; case 0xd5: // 2048M #ifdef OPT_SUPPORT_H27UAG8T2A if ((tempID[0]==0xAD)&&(tempID[2] == 0x94)&&(tempID[3] == 0x25)) { pSM->uBlockPerFlash = 4095; pSM->uPagePerBlock = 128; pSM->uSectorPerBlock = 1024; /* 128x8 */ pSM->nPageSize = NAND_PAGE_4KB; pSM->bIsMLCNand = TRUE; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 128; /* pages per block */ NDISK_info->nPageSize = 4096; NDISK_info->nBlockPerZone = 4096; /* blocks per zone */ NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */ pSM->uSectorPerFlash = 4091904; pSM->bIsMulticycle = TRUE; pSM->bIsNandECC12 = TRUE; break; } else { if ((tempID[3] & 0x33) == 0x32) { pSM->uBlockPerFlash = 4095; pSM->uPagePerBlock = 128; pSM->uSectorPerBlock = 1024; /* 128x8 */ pSM->nPageSize = NAND_PAGE_4KB; pSM->bIsMLCNand = TRUE; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 128; /* pages per block */ NDISK_info->nPageSize = 4096; NDISK_info->nBlockPerZone = 4096; /* blocks per zone */ NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */ } else if ((tempID[3] & 0x33) == 0x11) { pSM->uBlockPerFlash = 16383; pSM->uPagePerBlock = 64; pSM->uSectorPerBlock = 256; pSM->nPageSize = NAND_PAGE_2KB; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 64; /* pages per block */ NDISK_info->nPageSize = 2048; NDISK_info->nBlockPerZone = 16384; /* blocks per zone */ NDISK_info->nLBPerZone = 16000; /* logical blocks per zone */ } else if ((tempID[3] & 0x33) == 0x21) { pSM->uBlockPerFlash = 8191; pSM->uPagePerBlock = 128; pSM->uSectorPerBlock = 512; pSM->nPageSize = NAND_PAGE_2KB; pSM->bIsMLCNand = TRUE; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 128; /* pages per block */ NDISK_info->nPageSize = 2048; NDISK_info->nBlockPerZone = 8192; /* blocks per zone */ NDISK_info->nLBPerZone = 8000; /* logical blocks per zone */ } pSM->uSectorPerFlash = 4091904; pSM->bIsMulticycle = TRUE; pSM->bIsNandECC8 = TRUE; break; } #else if ((tempID[3] & 0x33) == 0x32) { pSM->uBlockPerFlash = 4095; pSM->uPagePerBlock = 128; pSM->uSectorPerBlock = 1024; /* 128x8 */ pSM->nPageSize = NAND_PAGE_4KB; pSM->bIsMLCNand = TRUE; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 128; /* pages per block */ NDISK_info->nPageSize = 4096; NDISK_info->nBlockPerZone = 4096; /* blocks per zone */ NDISK_info->nLBPerZone = 4000; /* logical blocks per zone */ } else if ((tempID[3] & 0x33) == 0x11) { pSM->uBlockPerFlash = 16383; pSM->uPagePerBlock = 64; pSM->uSectorPerBlock = 256; pSM->nPageSize = NAND_PAGE_2KB; pSM->bIsMLCNand = FALSE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 64; /* pages per block */ NDISK_info->nPageSize = 2048; NDISK_info->nBlockPerZone = 16384; /* blocks per zone */ NDISK_info->nLBPerZone = 16000; /* logical blocks per zone */ } else if ((tempID[3] & 0x33) == 0x21) { pSM->uBlockPerFlash = 8191; pSM->uPagePerBlock = 128; pSM->uSectorPerBlock = 512; pSM->nPageSize = NAND_PAGE_2KB; pSM->bIsMLCNand = TRUE; NDISK_info->NAND_type = NAND_TYPE_MLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_IN_SEQ; NDISK_info->nZone = 1; /* number of zones */ NDISK_info->nPagePerBlock = 128; /* pages per block */ NDISK_info->nPageSize = 2048; NDISK_info->nBlockPerZone = 8192; /* blocks per zone */ NDISK_info->nLBPerZone = 8000; /* logical blocks per zone */ } pSM->uSectorPerFlash = 4091904; pSM->bIsMulticycle = TRUE; pSM->bIsNandECC8 = TRUE; break; #endif default: // 2013/9/25, support MXIC MX30LF1208AA NAND flash if ((tempID[0]==0xC2)&&(tempID[1]==0xF0)&&(tempID[2]==0x80)&&(tempID[3]==0x1D)) { pSM->uBlockPerFlash = 511; // block index with 0-base. = physical blocks - 1 pSM->uPagePerBlock = 64; pSM->nPageSize = NAND_PAGE_2KB; pSM->uSectorPerBlock = pSM->nPageSize / 512 * pSM->uPagePerBlock; pSM->bIsMLCNand = FALSE; pSM->bIsMulticycle = FALSE; pSM->bIsNandECC8 = TRUE; NDISK_info->NAND_type = NAND_TYPE_SLC; NDISK_info->write_page_in_seq = NAND_TYPE_PAGE_OUT_SEQ; NDISK_info->nZone = 1; // number of zones NDISK_info->nBlockPerZone = pSM->uBlockPerFlash + 1; // blocks per zone NDISK_info->nPagePerBlock = pSM->uPagePerBlock; NDISK_info->nPageSize = pSM->nPageSize; // why nLBPerZone is not 512 ? sicSMInit() had reserved %2 blocks for bad block base on this value. NDISK_info->nLBPerZone = 500; // logical blocks per zone pSM->uSectorPerFlash = pSM->uSectorPerBlock * NDISK_info->nLBPerZone / 1000 * 999; // The first ID of this NAND is 0xC2 BUT it is NOT NAND ROM (read only) // So, we MUST modify the configuration of it // 1. change pSM->bIsCheckECC to TRUE to enable ECC feature; // 2. assign a fake vendor_ID to make NVTFAT can write data to this NAND disk. // (GNAND will check vendor_ID and set disk to DISK_TYPE_READ_ONLY if it is 0xC2) pSM->bIsCheckECC = TRUE; NDISK_info->vendor_ID = 0xFF; // fake vendor_ID break; } printf("ERROR: SM ID not support!! [%02x][%02x][%02x][%02x][%02x]\n", tempID[0], tempID[1], tempID[2], tempID[3], tempID[4]); return FMI_SM_ID_ERR; } printf("NAND: Found %s NAND, ID [%02x][%02x][%02x][%02x][%02x], page size %d, BCH T%d\n", pSM->bIsMLCNand ? "MLC" : "SLC", tempID[0], tempID[1], tempID[2], tempID[3], tempID[4], pSM->nPageSize, pSM->bIsNandECC4*4 + pSM->bIsNandECC8*8 + pSM->bIsNandECC12*12 + pSM->bIsNandECC15*15 ); return 0; } INT fmiSM2BufferM(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT8 ucColAddr) { /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } outpw(REG_SMCMD, 0x00); // read command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; return 0; } INT fmiSM2BufferM_RA(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT8 ucColAddr) { /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } outpw(REG_SMCMD, 0x50); // read command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; return 0; } INT fmiSMECCErrCount(UINT32 ErrSt, BOOL bIsECC8) { unsigned int volatile errCount; if ((ErrSt & 0x02) || (ErrSt & 0x200) || (ErrSt & 0x20000) || (ErrSt & 0x2000000)) { #ifdef DEBUG printf("uncorrectable!![0x%x]\n", ErrSt); #endif return FMI_SM_ECC_ERROR; } if (ErrSt & 0x01) { errCount = (ErrSt >> 2) & 0xf; #ifdef DEBUG if (bIsECC8) printf("Field 5 have %d error!!\n", errCount); else printf("Field 1 have %d error!!\n", errCount); #endif } if (ErrSt & 0x100) { errCount = (ErrSt >> 10) & 0xf; #ifdef DEBUG if (bIsECC8) printf("Field 6 have %d error!!\n", errCount); else printf("Field 2 have %d error!!\n", errCount); #endif } if (ErrSt & 0x10000) { errCount = (ErrSt >> 18) & 0xf; #ifdef DEBUG if (bIsECC8) printf("Field 7 have %d error!!\n", errCount); else printf("Field 3 have %d error!!\n", errCount); #endif } if (ErrSt & 0x1000000) { errCount = (ErrSt >> 26) & 0xf; #ifdef DEBUG if (bIsECC8) printf("Field 8 have %d error!!\n", errCount); else printf("Field 4 have %d error!!\n", errCount); #endif } return errCount; } static VOID fmiSM_CorrectData_BCH(UINT8 ucFieidIndex, UINT8 ucErrorCnt, UINT8* pDAddr) { // ECC is based on 512+32, when ECC code error is encountered, we must coorect it by this base UINT32 uaData[16], uaAddr[16]; UINT32 uaErrorData[4]; UINT8 ii, jj; UINT32 uPageSize, spareSize; uPageSize = inpw(REG_SMCSR) & SMCR_PSIZE; jj = ucErrorCnt/4; jj ++; if (jj > 4) jj = 4; for(ii=0; ii<jj; ii++) { uaErrorData[ii] = inpw(REG_BCH_ECC_DATA0 + ii*4); } for(ii=0; ii<jj; ii++) { uaData[ii*4+0] = uaErrorData[ii] & 0xff; uaData[ii*4+1] = (uaErrorData[ii]>>8) & 0xff; uaData[ii*4+2] = (uaErrorData[ii]>>16) & 0xff; uaData[ii*4+3] = (uaErrorData[ii]>>24) & 0xff; } jj = ucErrorCnt/2; jj ++; if (jj > 8) jj = 8; for(ii=0; ii<jj; ii++) { uaAddr[ii*2+0] = inpw(REG_BCH_ECC_ADDR0 + ii*4) & 0x1fff; uaAddr[ii*2+1] = (inpw(REG_BCH_ECC_ADDR0 + ii*4)>>16) & 0x1fff; } pDAddr += (ucFieidIndex-1)*0x200; for(ii=0; ii<ucErrorCnt; ii++) { if (uPageSize == PSIZE_8K) { switch(inpw(REG_SMCSR) & SMCR_BCH_TSEL) { case BCH_T4: // 8K+256 default: if (uaAddr[ii] < 512) *(pDAddr+uaAddr[ii]) ^= uaData[ii]; else { if (uaAddr[ii] < 515) { uaAddr[ii] -= 512; uaAddr[ii] += 8*(ucFieidIndex-1); // field offset, only Field-0 *((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii]; } else { uaAddr[ii] = 543 - uaAddr[ii]; uaAddr[ii] = 7 - uaAddr[ii]; uaAddr[ii] += 8*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_32+uaAddr[ii]) ^= uaData[ii]; } } break; case BCH_T8: // 8K+256 if (uaAddr[ii] < 512) *(pDAddr+uaAddr[ii]) ^= uaData[ii]; else { if (uaAddr[ii] < 515) { uaAddr[ii] -= 512; uaAddr[ii] += 15*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii]; } else { uaAddr[ii] = 543 - uaAddr[ii]; uaAddr[ii] = 14 - uaAddr[ii]; uaAddr[ii] += 15*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_4+uaAddr[ii]) ^= uaData[ii]; } } break; case BCH_T12: // 8K+376 if (uaAddr[ii] < 512) *(pDAddr+uaAddr[ii]) ^= uaData[ii]; else { if (uaAddr[ii] < 515) { uaAddr[ii] -= 512; uaAddr[ii] += 23*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii]; } else { uaAddr[ii] = 543 - uaAddr[ii]; uaAddr[ii] = 22 - uaAddr[ii]; uaAddr[ii] += 23*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_2+uaAddr[ii]) ^= uaData[ii]; } } break; case BCH_T15: break; } } else if (uPageSize == PSIZE_4K) { switch(inpw(REG_SMCSR) & SMCR_BCH_TSEL) { case BCH_T4: // 4K+128 default: if (uaAddr[ii] < 512) *(pDAddr+uaAddr[ii]) ^= uaData[ii]; else { if (uaAddr[ii] < 515) { uaAddr[ii] -= 512; uaAddr[ii] += 8*(ucFieidIndex-1); // field offset, only Field-0 *((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii]; } else { uaAddr[ii] = 543 - uaAddr[ii]; uaAddr[ii] = 7 - uaAddr[ii]; uaAddr[ii] += 8*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_16+uaAddr[ii]) ^= uaData[ii]; } } break; case BCH_T8: // 4K+128 if (uaAddr[ii] < 512) *(pDAddr+uaAddr[ii]) ^= uaData[ii]; else { if (uaAddr[ii] < 515) { uaAddr[ii] -= 512; uaAddr[ii] += 15*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii]; } else { uaAddr[ii] = 543 - uaAddr[ii]; uaAddr[ii] = 14 - uaAddr[ii]; uaAddr[ii] += 15*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_2+uaAddr[ii]) ^= uaData[ii]; } } break; case BCH_T12: // 4K+216 if (uaAddr[ii] < 512) *(pDAddr+uaAddr[ii]) ^= uaData[ii]; else { if (uaAddr[ii] < 515) { uaAddr[ii] -= 512; uaAddr[ii] += 23*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii]; } else { uaAddr[ii] = 543 - uaAddr[ii]; uaAddr[ii] = 22 - uaAddr[ii]; uaAddr[ii] += 23*(ucFieidIndex-1); // field offset #ifdef OPT_SUPPORT_H27UAG8T2A // 4K+224 spareSize = inpw(REG_SMREAREA_CTL) & SMRE_REA128_EXT; // *((UINT8*)REG_SMRA_10+uaAddr[ii]) ^= uaData[ii]; *((UINT8*)REG_SMRA_0+(spareSize-184)+uaAddr[ii]) ^= uaData[ii]; #else // 4K+216 *((UINT8*)REG_SMRA_8+uaAddr[ii]) ^= uaData[ii]; #endif } } break; } } else if (uPageSize == PSIZE_2K) { switch(inpw(REG_SMCSR) & SMCR_BCH_TSEL) { case BCH_T4: default: if (uaAddr[ii] < 512) *(pDAddr+uaAddr[ii]) ^= uaData[ii]; else { if (uaAddr[ii] < 515) { uaAddr[ii] -= 512; uaAddr[ii] += 8*(ucFieidIndex-1); // field offset, only Field-0 *((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii]; } else { uaAddr[ii] = 543 - uaAddr[ii]; uaAddr[ii] = 7 - uaAddr[ii]; uaAddr[ii] += 8*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_8+uaAddr[ii]) ^= uaData[ii]; } } break; case BCH_T8: if (uaAddr[ii] < 512) *(pDAddr+uaAddr[ii]) ^= uaData[ii]; else { if (uaAddr[ii] < 515) { uaAddr[ii] -= 512; uaAddr[ii] += 15*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii]; } else { uaAddr[ii] = 543 - uaAddr[ii]; uaAddr[ii] = 14 - uaAddr[ii]; uaAddr[ii] += 15*(ucFieidIndex-1); // field offset *((UINT8*)REG_SMRA_1+uaAddr[ii]) ^= uaData[ii]; } } break; } } else { if (uaAddr[ii] < 512) *(pDAddr+uaAddr[ii]) ^= uaData[ii]; else { if (uaAddr[ii] < 515) { uaAddr[ii] -= 512; *((UINT8*)REG_SMRA_0+uaAddr[ii]) ^= uaData[ii]; } else { uaAddr[ii] = 543 - uaAddr[ii]; uaAddr[ii] = 7 - uaAddr[ii]; *((UINT8*)REG_SMRA_2+uaAddr[ii]) ^= uaData[ii]; } } } } } INT fmiSM_Read_512(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 uDAddr) { int volatile ret=0; UINT32 uStatus; UINT32 uErrorCnt; volatile UINT32 uError = 0; outpw(REG_DMACSAR, uDAddr); ret = fmiSM2BufferM(pSM, uSector, 0); if (ret < 0) return ret; #ifdef _SIC_USE_INT_ _fmi_bIsSMDataReady = FALSE; #endif //_SIC_USE_INT_ outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DRD_EN); #ifdef _SIC_USE_INT_ while(!_fmi_bIsSMDataReady); #else while(1) { if (!(inpw(REG_SMCSR) & SMCR_DRD_EN)) break; } #endif if (pSM->bIsCheckECC) { while(1) { if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) { if (inpw(REG_SMCSR) & BCH_T4) // BCH_ECC selected { uStatus = inpw(REG_SM_ECC_ST0); uStatus &= 0x3f; if ((uStatus & 0x03)==0x01) // correctable error in 1st field { uErrorCnt = uStatus >> 2; fmiSM_CorrectData_BCH(1, uErrorCnt, (UINT8*)uDAddr); #ifdef DEBUG printf("Field 1 have %d error!!\n", uErrorCnt); #endif } else if (((uStatus & 0x03)==0x02) ||((uStatus & 0x03)==0x03)) // uncorrectable error or ECC error { #ifdef DEBUG printf("SM uncorrectable error is encountered, %4x !!\n", uStatus); #endif uError = 1; } } else { #ifdef DEBUG printf("Wrong BCH setting for page-512 NAND !!\n"); #endif uError = 2; } outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FLD_Error } if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer. { if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) ) break; } } } else outpw(REG_SMISR, SMISR_ECC_FIELD_IF); outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag if (uError) return -1; return 0; } VOID fmiBuffer2SMM(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT8 ucColAddr) { // set the spare area configuration /* write byte 514, 515 as used page */ outpw(REG_SMRA_0, 0x0000FFFF); outpw(REG_SMRA_1, 0xFFFFFFFF); // send command outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } } INT fmiSM_Write_512(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 uSAddr) { /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_REDUN_AUTO_WEN); outpw(REG_DMACSAR, uSAddr); fmiBuffer2SMM(pSM, uSector, 0); #ifdef _SIC_USE_INT_ _fmi_bIsSMDataReady = FALSE; #endif // _SIC_USE_INT_ outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN); while(1) { #ifdef _SIC_USE_INT_ if (_fmi_bIsSMDataReady) #else if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer. #endif //_SIC_USE_INT_ break; } outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMCMD, 0x10); // auto program command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; if (fmiSMCheckStatus(pSM) != 0) { #ifdef DEBUG printf("fmiSM_Write_512: data error!!\n"); #endif return FMI_SM_STATE_ERROR; } return 0; } INT fmiSM_Read_2K(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 uDAddr) { UINT32 uStatus; UINT32 uErrorCnt, ii; volatile UINT32 uError = 0; // fmiSM_Reset(pSM); while(inpw(REG_DMACCSR) & FMI_BUSY); // wait DMAC FMI ready; outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_EN); outpw(REG_DMACSAR, uDAddr); // set DMA transfer starting address /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) /* ECC_FLD_IF */ { //printf("read: ECC error!!\n"); outpw(REG_SMISR, SMISR_ECC_FIELD_IF); } outpw(REG_SMCMD, 0x00); // read command outpw(REG_SMADDR, 0); // CA0 - CA7 outpw(REG_SMADDR, 0); // CA8 - CA11 outpw(REG_SMADDR, uPage & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uPage >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMCMD, 0x30); // read command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; #ifdef _SIC_USE_INT_ _fmi_bIsSMDataReady = FALSE; #endif //_SIC_USE_INT_ outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DRD_EN); // if ((pSM->bIsCheckECC) || (inpw(REG_SMCSR)&SMCR_ECC_CHK) ) if (pSM->bIsCheckECC) { while(1) { if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) { uStatus = inpw(REG_SM_ECC_ST0); for (ii=1; ii<5; ii++) { #if 0 if (!(uStatus & 0x03)) { uStatus >>= 8; continue; } #endif if ((uStatus & 0x03)==0x01) // correctable error in 1st field { uErrorCnt = uStatus >> 2; fmiSM_CorrectData_BCH(ii, uErrorCnt, (UINT8*)uDAddr); #ifdef DEBUG printf("Field %d have %d error!!\n", ii, uErrorCnt); #endif break; } else if (((uStatus & 0x03)==0x02) ||((uStatus & 0x03)==0x03)) // uncorrectable error or ECC error in 1st field { #ifdef DEBUG printf("SM uncorrectable error is encountered, %4x !!\n", uStatus); #endif uError = 1; break; } uStatus >>= 8; } outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FLD_Error } #ifdef _SIC_USE_INT_ if (_fmi_bIsSMDataReady) { if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) ) break; } #else if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer. { if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) ) break; } #endif //_SIC_USE_INT_ } } else { while(1) { outpw(REG_SMISR, SMISR_ECC_FIELD_IF); if (inpw(REG_SMISR) & SMISR_DMA_IF) { outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag break; } } } outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag if (uError) return -1; return 0; } INT fmiSM_Read_RA(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 ucColAddr) { /* clear R/B flag */ // fmiSM_Reset(pSM); if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } outpw(REG_SMCMD, 0x00); // read command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 // outpw(REG_SMADDR, (ucColAddr >> 8) & 0x1f); // CA8 - CA12 outpw(REG_SMADDR, (ucColAddr >> 8) & 0xFF); // CA8 - CA12 outpw(REG_SMADDR, uPage & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uPage >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMCMD, 0x30); // read command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; return 0; } INT fmiSM_Read_RA_512(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 uColumm) { /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } outpw(REG_SMCMD, 0x50); // read command outpw(REG_SMADDR, uColumm); outpw(REG_SMADDR, uPage & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uPage >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; return 0; } INT fmiSM_Write_2K(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr) { // fmiSM_Reset(pSM); /* enable DMAC */ while(inpw(REG_DMACCSR) & FMI_BUSY); // wait DMAC FMI ready; outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_EN); outpw(REG_DMACSAR, uSAddr); // set DMA transfer starting address // set the spare area configuration /* write byte 2050, 2051 as used page */ outpw(REG_SMRA_0, 0x0000FFFF); outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_REDUN_AUTO_WEN); /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) /* ECC_FLD_IF */ { //printf("error sector !!\n"); outpw(REG_SMISR, SMISR_ECC_FIELD_IF); } // send command outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 // outpw(REG_SMADDR, (ucColAddr >> 8) & 0x0f); // CA8 - CA11 outpw(REG_SMADDR, (ucColAddr >> 8) & 0xff); // CA8 - CA11 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } #ifdef _SIC_USE_INT_ _fmi_bIsSMDataReady = FALSE; #endif //_SIC_USE_INT_ outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN); while(1) { #ifdef _SIC_USE_INT_ if (_fmi_bIsSMDataReady) #else if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer. #endif //_SIC_USE_INT_ break; } outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMCMD, 0x10); // auto program command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; if (fmiSMCheckStatus(pSM) != 0) { #ifdef DEBUG printf("fmiSM_Write_2K: data error!!\n"); #endif sysprintf("ERROR: fmiSM_Write_2K() write data error on page %d since NAND status.\n", uSector); return FMI_SM_STATE_ERROR; } #if 1 if (inpw(REG_SMRA_0) != 0x0000FFFF) while(1); #endif return 0; } INT fmiSM_Write_2K_ALC(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr) { outpw(REG_DMACSAR, uSAddr); // set DMA transfer starting address // set the spare area configuration /* write byte 2050, 2051 as used page */ outpw(REG_SMRA_0, 0x0000FFFF); outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_REDUN_AUTO_WEN); /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } // send command outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 outpw(REG_SMADDR, (ucColAddr >> 8) & 0x0f); // CA8 - CA11 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|0x80000000); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|0x80000000); // PA16 - PA17 } #ifdef _SIC_USE_INT_ _fmi_bIsSMDataReady = FALSE; #endif // _SIC_USE_INT_ outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN); while(1) { #ifdef _SIC_USE_INT_ if (_fmi_bIsSMDataReady) #else if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer. #endif //_SIC_USE_INT_ break; } outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag { int i; UINT8 *u8pData; u8pData = (UINT8 *)REG_SMRA_0; for (i=0; i<64; i++) outpw(REG_SMDATA, *u8pData++); } outpw(REG_SMCMD, 0x10); // auto program command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; if (fmiSMCheckStatus(pSM) != 0) { #ifdef DEBUG printf("fmiSM_Write_2K: data error!!\n"); #endif return FMI_SM_STATE_ERROR; } return 0; } INT fmiSM_Read_4K(FMI_SM_INFO_T *pSM, UINT32 uPage, UINT32 uDAddr) { UINT32 uStatus; UINT32 uErrorCnt, ii, jj; volatile UINT32 uError = 0; outpw(REG_DMACSAR, uDAddr); // set DMA transfer starting address /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } outpw(REG_SMCMD, 0x00); // read command outpw(REG_SMADDR, 0); // CA0 - CA7 outpw(REG_SMADDR, 0); // CA8 - CA11 outpw(REG_SMADDR, uPage & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uPage >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uPage >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uPage >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMCMD, 0x30); // read command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; #ifdef _SIC_USE_INT_ _fmi_bIsSMDataReady = FALSE; #endif //_SIC_USE_INT_ outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DRD_EN); if ((pSM->bIsCheckECC) || (inpw(REG_SMCSR)&SMCR_ECC_CHK) ) { while(1) { if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) { for (jj=0; jj<2; jj++) { uStatus = inpw(REG_SM_ECC_ST0+jj*4); if (!uStatus) continue; for (ii=1; ii<5; ii++) { if (!(uStatus & 0x03)) { uStatus >>= 8; continue; } if ((uStatus & 0x03)==0x01) // correctable error in 1st field { uErrorCnt = uStatus >> 2; fmiSM_CorrectData_BCH(jj*4+ii, uErrorCnt, (UINT8*)uDAddr); #ifdef DEBUG printf("Field %d have %d error!!\n", jj*4+ii, uErrorCnt); #endif break; } else if (((uStatus & 0x03)==0x02) ||((uStatus & 0x03)==0x03)) // uncorrectable error or ECC error in 1st field { #ifdef _DEBUG printf("SM uncorrectable BCH error is encountered !!\n"); #endif uError = 1; break; } uStatus >>= 8; } } outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FLD_Error } #ifdef _SIC_USE_INT_ if (_fmi_bIsSMDataReady) { if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) ) break; } #else if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer. { if ( !(inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) ) break; } #endif //_SIC_USE_INT_ } } else { while(1) { outpw(REG_SMISR, SMISR_ECC_FIELD_IF); if (inpw(REG_SMISR) & SMISR_DMA_IF) { outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag break; } } } if (uError) return -1; return 0; } INT fmiSM_Write_4K(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr) { outpw(REG_DMACSAR, uSAddr); // set DMA transfer starting address // set the spare area configuration /* write byte 2050, 2051 as used page */ outpw(REG_SMRA_0, 0x0000FFFF); outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_REDUN_AUTO_WEN); /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } // send command outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 // outpw(REG_SMADDR, (ucColAddr >> 8) & 0x1f); // CA8 - CA12 outpw(REG_SMADDR, (ucColAddr >> 8) & 0xff); // CA8 - CA12 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } #ifdef _SIC_USE_INT_ _fmi_bIsSMDataReady = FALSE; #endif //_SIC_USE_INT_ outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN); while(1) { #ifdef _SIC_USE_INT_ if (_fmi_bIsSMDataReady) #else if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer. #endif //_SIC_USE_INT_ break; } outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMCMD, 0x10); // auto program command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; if (fmiSMCheckStatus(pSM) != 0) { #ifdef DEBUG printf("fmiSM_Write_4K: data error!!\n"); #endif return FMI_SM_STATE_ERROR; } return 0; } INT fmiSM_Write_4K_ALC(FMI_SM_INFO_T *pSM, UINT32 uSector, UINT32 ucColAddr, UINT32 uSAddr) { outpw(REG_DMACSAR, uSAddr); // set DMA transfer starting address // set the spare area configuration /* write byte 2050, 2051 as used page */ outpw(REG_SMRA_0, 0x0000FFFF); outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_REDUN_AUTO_WEN); /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } // send command outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 outpw(REG_SMADDR, (ucColAddr >> 8) & 0x1f); // CA8 - CA12 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } #ifdef _SIC_USE_INT_ _fmi_bIsSMDataReady = FALSE; #endif // _SIC_USE_INT_ outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag outpw(REG_SMISR, SMISR_ECC_FIELD_IF); // clear ECC_FIELD flag outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_DWR_EN); while(1) { #ifdef _SIC_USE_INT_ if (_fmi_bIsSMDataReady) #else if (inpw(REG_SMISR) & SMISR_DMA_IF) // wait to finish DMAC transfer. #endif //_SIC_USE_INT_ break; } outpw(REG_SMISR, SMISR_DMA_IF); // clear DMA flag { int i; UINT8 *u8pData; u8pData = (UINT8 *)REG_SMRA_0; for (i=0; i<218; i++) outpw(REG_SMDATA, *u8pData++); } outpw(REG_SMCMD, 0x10); // auto program command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; if (fmiSMCheckStatus(pSM) != 0) { #ifdef DEBUG printf("fmiSM_Write_2K: data error!!\n"); #endif return FMI_SM_STATE_ERROR; } return 0; } // mhkuo INT fmiCheckInvalidBlock(FMI_SM_INFO_T *pSM, UINT32 BlockNo) { int volatile status=0; unsigned int volatile sector; unsigned char volatile data512=0xff, data517=0xff, blockStatus=0xff; if (BlockNo == 0) return 0; sector = BlockNo * pSM->uPagePerBlock; if (pSM->nPageSize == NAND_PAGE_512B) status = fmiSM2BufferM_RA(pSM, sector, 0); else status = fmiSM_Read_RA(pSM, sector, pSM->nPageSize); if (status < 0) { #ifdef DEBUG printf("fmiCheckInvalidBlock 0x%x\n", status); #endif return 1; } if (pSM->nPageSize == NAND_PAGE_512B) { data512 = inpw(REG_SMDATA) & 0xff; data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA) & 0xff; // if ((data512 != 0xFF) || (data517 != 0xFF)) if ((data512 == 0xFF) && (data517 == 0xFF)) { fmiSM_Reset(pSM); status = fmiSM2BufferM_RA(pSM, sector+1, 0); if (status < 0) { #ifdef DEBUG printf("fmiCheckInvalidBlock 0x%x\n", status); #endif return 1; } data512 = inpw(REG_SMDATA) & 0xff; data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA) & 0xff; if ((data512 != 0xFF) || (data517 != 0xFF)) { fmiSM_Reset(pSM); return 1; // invalid block } } else { fmiSM_Reset(pSM); return 1; // invalid block } } else { blockStatus = inpw(REG_SMDATA) & 0xff; if (blockStatus == 0xFF) { fmiSM_Reset(pSM); if (pSM->bIsMLCNand == TRUE) sector = (BlockNo+1) * pSM->uPagePerBlock - 1; else sector++; status = fmiSM_Read_RA(pSM, sector, pSM->nPageSize); if (status < 0) { #ifdef DEBUG printf("fmiCheckInvalidBlock 0x%x\n", status); #endif return 1; } blockStatus = inpw(REG_SMDATA) & 0xff; if (blockStatus != 0xFF) { fmiSM_Reset(pSM); return 1; // invalid block } } else { fmiSM_Reset(pSM); return 1; // invalid block } } fmiSM_Reset(pSM); return 0; } static void sicSMselect(INT chipSel) { if (chipSel == 0) { outpw(REG_GPDFUN, inpw(REG_GPDFUN) | 0x0003CC00); // enable NAND NWR/NRD/RB0 pins outpw(REG_GPEFUN, inpw(REG_GPEFUN) | 0x00F30000); // enable NAND ALE/CLE/CS0 pins outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_CS0); outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_CS1); } else { outpw(REG_GPDFUN, inpw(REG_GPDFUN) | 0x0003F000); // enable NAND NWR/NRD/RB1 pins outpw(REG_GPEFUN, inpw(REG_GPEFUN) | 0x00FC0000); // enable NAND ALE/CLE/CS1 pins outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_CS1); outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_CS0); } //--- 2014/2/26, Reset SD controller and DMAC to keep clean status for next access. // Reset DMAC engine and interrupt satus outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_SWRST | DMAC_EN); while(inpw(REG_DMACCSR) & DMAC_SWRST); outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_EN); outpw(REG_DMACISR, WEOT_IF | TABORT_IF); // clear all interrupt flag // Reset FMI engine and interrupt status outpw(REG_FMICR, FMI_SWRST); while(inpw(REG_FMICR) & FMI_SWRST); outpw(REG_FMIISR, FMI_DAT_IF); // clear all interrupt flag // Reset NAND engine and interrupt status outpw(REG_FMICR, FMI_SM_EN); outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_SM_SWRST); while(inpw(REG_SMCSR) & SDCR_SWRST); outpw(REG_SMISR, 0xFFFFFFFF); // clear all interrupt flag } static INT fmiNormalCheckBlock(FMI_SM_INFO_T *pSM, UINT32 BlockNo) { int volatile status=0; unsigned int volatile sector; unsigned char data, data517; _fmi_pSMBuffer = (UINT8 *)((UINT32)_fmi_ucSMBuffer | 0x80000000); /* MLC check the 2048 byte of last page per block */ if (pSM->bIsMLCNand == TRUE) { if (pSM->nPageSize == NAND_PAGE_2KB) { sector = (BlockNo+1) * pSM->uPagePerBlock - 1; /* Read 2048 byte */ status = fmiSM_Read_RA(pSM, sector, 2048); if (status < 0) { #ifdef DEBUG printf("fmiNormalCheckBlock 0x%x\n", status); #endif return 1; } data = inpw(REG_SMDATA) & 0xff; if (data != 0xFF) return 1; // invalid block } else if (pSM->nPageSize == NAND_PAGE_4KB) { sector = (BlockNo+1) * pSM->uPagePerBlock - 1; /* Read 4096 byte */ status = fmiSM_Read_RA(pSM, sector, 4096); if (status < 0) { #ifdef DEBUG printf("fmiNormalCheckBlock 0x%x\n", status); #endif return 1; } data = inpw(REG_SMDATA) & 0xff; if (data != 0xFF) return 1; // invalid block } } /* SLC check the 2048 byte of 1st or 2nd page per block */ else // SLC { sector = BlockNo * pSM->uPagePerBlock; if (pSM->nPageSize == NAND_PAGE_4KB) { status = fmiSM_Read_RA(pSM, sector, 4096); if (status < 0) { #ifdef DEBUG printf("fmiNormalCheckBlock 0x%x\n", status); #endif return 1; } data = inpw(REG_SMDATA) & 0xff; if (data == 0xFF) { #ifdef DEBUG // printf("find bad block, check next page to confirm it.\n"); #endif status = fmiSM_Read_RA(pSM, sector+1, 4096); if (status < 0) { #ifdef DEBUG printf("fmiNormalCheckBlock 0x%x\n", status); #endif return 1; } data = inpw(REG_SMDATA) & 0xff; if (data != 0xFF) { #ifdef DEBUG printf("find bad block is conformed.\n"); #endif return 1; // invalid block } } else { #ifdef DEBUG printf("find bad block is conformed.\n"); #endif return 1; // invalid block } } else if (pSM->nPageSize == NAND_PAGE_2KB) { status = fmiSM_Read_RA(pSM, sector, 2048); if (status < 0) { #ifdef DEBUG printf("fmiNormalCheckBlock 0x%x\n", status); #endif return 1; } data = inpw(REG_SMDATA) & 0xff; if (data == 0xFF) { #ifdef DEBUG // printf("find bad block, check next page to confirm it.\n"); #endif status = fmiSM_Read_RA(pSM, sector+1, 2048); if (status < 0) { #ifdef DEBUG printf("fmiNormalCheckBlock 0x%x\n", status); #endif return 1; } data = inpw(REG_SMDATA) & 0xff; if (data != 0xFF) { #ifdef DEBUG printf("find bad block is conformed.\n"); #endif return 1; // invalid block } } else { #ifdef DEBUG printf("find bad block is conformed.\n"); #endif return 1; // invalid block } } else /* page size 512B */ { status = fmiSM2BufferM_RA(pSM, sector, 0); if (status < 0) { #ifdef DEBUG printf("fmiNormalCheckBlock 0x%x\n", status); #endif return 1; } data = inpw(REG_SMDATA) & 0xff; data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA) & 0xff; // if ((data != 0xFF) || (data517 != 0xFF)) if ((data == 0xFF) && (data517 == 0xFF)) { fmiSM_Reset(pSM); status = fmiSM2BufferM_RA(pSM, sector+1, 0); if (status < 0) { #ifdef DEBUG printf("fmiNormalCheckBlock 0x%x\n", status); #endif return 1; } data = inpw(REG_SMDATA) & 0xff; data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA); data517 = inpw(REG_SMDATA) & 0xff; if ((data != 0xFF) || (data517 != 0xFF)) { fmiSM_Reset(pSM); return 1; // invalid block } } else { #ifdef DEBUG printf("find bad block is conformed.\n"); #endif fmiSM_Reset(pSM); return 1; // invalid block } fmiSM_Reset(pSM); } } return 0; } /* function pointer */ FMI_SM_INFO_T *pSM0=0, *pSM1=0; static INT sicSMInit(INT chipSel, NDISK_T *NDISK_info) { int status=0, count; sysprintf("Initial NAND NonOS Driver (%s) for NAND port %d\n", NAND_DATE_CODE, chipSel); outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_EN); outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_SWRST); while(inpw(REG_DMACCSR) & DMAC_SWRST); outpw(REG_FMICR, FMI_SM_EN); if ((_nand_init0 == 0) && (_nand_init1 == 0)) { // enable SM /* select NAND control pin used */ // outpw(REG_SMTCR, 0x20304); // outpw(REG_SMTCR, 0x10205); outpw(REG_SMTCR, 0x20305); outpw(REG_SMCSR, (inpw(REG_SMCSR) & ~SMCR_PSIZE) | PSIZE_512); outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_ECC_3B_PROTECT); outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_ECC_CHK); /* init SM interface */ #ifdef _NAND_PAR_ALC_ outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_REDUN_AUTO_WEN); #ifdef DEBUG printf("Parity only written to SM registers but not NAND !!\n"); #endif #else outpw(REG_SMCSR, inpw(REG_SMCSR) | SMCR_REDUN_AUTO_WEN); #ifdef DEBUG printf("Parity written to SM registers and NAND !!\n"); #endif #endif // _NAND_PAR_ALC_ } sicSMselect(chipSel); if (chipSel == 0) { if (_nand_init0) return 0; pSM0 = malloc(sizeof(FMI_SM_INFO_T)); if (pSM0 == NULL) return FMI_NO_MEMORY; memset((char *)pSM0, 0, sizeof(FMI_SM_INFO_T)); if ((status = fmiSM_ReadID(pSM0, NDISK_info)) < 0) { if (pSM0 != NULL) { free(pSM0); pSM0 = 0; } return status; } fmiSM_Initial(pSM0); #ifdef OPT_SW_WP outpw(REG_GPAFUN, inpw(REG_GPAFUN) & ~MF_GPA7); // port A7 low (WP) outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~0x0080); // port A7 low (WP) outpw(REG_GPIOA_OMD, inpw(REG_GPIOA_OMD) | 0x0080); // port A7 output #endif // check NAND boot header fmiSMCheckBootHeader(0, pSM0); while(1) { if (!fmiNormalCheckBlock(pSM0, pSM0->uLibStartBlock)) break; else { #ifdef DEBUG printf("invalid start block %d\n", pSM0->uLibStartBlock); #endif pSM0->uLibStartBlock++; } } if (pSM0->bIsCheckECC) if (pSM0->uLibStartBlock == 0) pSM0->uLibStartBlock++; NDISK_info->nStartBlock = pSM0->uLibStartBlock; /* available start block */ pSM0->uBlockPerFlash -= pSM0->uLibStartBlock; count = NDISK_info->nBlockPerZone * 2 / 100 + NAND_RESERVED_BLOCK; NDISK_info->nBlockPerZone = (NDISK_info->nBlockPerZone * NDISK_info->nZone - NDISK_info->nStartBlock) / NDISK_info->nZone; NDISK_info->nLBPerZone = NDISK_info->nBlockPerZone - count; NDISK_info->nNandNo = chipSel; _nand_init0 = 1; } else if (chipSel == 1) { if (_nand_init1) return 0; pSM1 = malloc(sizeof(FMI_SM_INFO_T)); if (pSM1 == NULL) return FMI_NO_MEMORY; memset((char *)pSM1, 0, sizeof(FMI_SM_INFO_T)); if ((status = fmiSM_ReadID(pSM1, NDISK_info)) < 0) { if (pSM1 != NULL) { free(pSM1); pSM1 = 0; } return status; } fmiSM_Initial(pSM1); #ifdef OPT_SW_WP outpw(REG_GPAFUN, inpw(REG_GPAFUN) & ~MF_GPA7); // port A7 low (WP) outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~0x0080); // port A7 low (WP) outpw(REG_GPIOA_OMD, inpw(REG_GPIOA_OMD) | 0x0080); // port A7 output #endif // check NAND boot header fmiSMCheckBootHeader(1, pSM1); while(1) { if (!fmiNormalCheckBlock(pSM1, pSM1->uLibStartBlock)) break; else { #ifdef DEBUG printf("invalid start block %d\n", pSM1->uLibStartBlock); #endif pSM1->uLibStartBlock++; } } if (pSM1->bIsCheckECC) if (pSM1->uLibStartBlock == 0) pSM1->uLibStartBlock++; NDISK_info->nStartBlock = pSM1->uLibStartBlock; /* available start block */ pSM1->uBlockPerFlash -= pSM1->uLibStartBlock; count = NDISK_info->nBlockPerZone * 2 / 100 + NAND_RESERVED_BLOCK; NDISK_info->nBlockPerZone = (NDISK_info->nBlockPerZone * NDISK_info->nZone - NDISK_info->nStartBlock) / NDISK_info->nZone; NDISK_info->nLBPerZone = NDISK_info->nBlockPerZone - count; NDISK_info->nNandNo = chipSel; _nand_init1 = 1; } else return FMI_SM_INIT_ERROR; return 0; } //static INT sicSMpread(INT chipSel, INT PBA, INT page, UINT8 *buff) INT sicSMpread(INT chipSel, INT PBA, INT page, UINT8 *buff) { FMI_SM_INFO_T *pSM; int pageNo; int status=0; int i; char *ptr; #ifdef OPT_SUPPORT_H27UAG8T2A int spareSize; #endif sicSMselect(chipSel); if (chipSel == 0) pSM = pSM0; else pSM = pSM1; // enable SM outpw(REG_FMICR, FMI_SM_EN); fmiSM_Initial(pSM); //removed by mhuko PBA += pSM->uLibStartBlock; pageNo = PBA * pSM->uPagePerBlock + page; #ifdef OPT_FIRST_4BLOCKS_ECC4 if (PBA <= 3) { #ifdef OPT_SUPPORT_H27UAG8T2A // set to ECC8 for Block 0-3 if (pSM->nPageSize == NAND_PAGE_4KB) /* 4KB */ { if (pSM->bIsNandECC12 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 128); // Redundant area size } } // set to ECC4 for Block 0-3 else if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */ { if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } } #else // set to ECC4 for Block 0-3 if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */ { if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); // BCH_4 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } } #endif } #endif if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */ { ptr = (char *)REG_SMRA_0; fmiSM_Read_RA(pSM, pageNo, 2048); for (i=0; i<64; i++) *ptr++ = inpw(REG_SMDATA) & 0xff; status = fmiSM_Read_2K(pSM, pageNo, (UINT32)buff); } else if (pSM->nPageSize == NAND_PAGE_4KB) /* 4KB */ { #ifdef OPT_SUPPORT_H27UAG8T2A spareSize = inpw(REG_SMREAREA_CTL) & SMRE_REA128_EXT; ptr = (char *)REG_SMRA_0; fmiSM_Read_RA(pSM, pageNo, 4096); for (i=0; i<spareSize; i++) *ptr++ = inpw(REG_SMDATA) & 0xff; #else ptr = (char *)REG_SMRA_0; fmiSM_Read_RA(pSM, pageNo, 4096); // for (i=0; i<216; i++) for (i=0; i<128; i++) *ptr++ = inpw(REG_SMDATA) & 0xff; #endif status = fmiSM_Read_4K(pSM, pageNo, (UINT32)buff); } else /* 512B */ { ptr = (char *)REG_SMRA_0; fmiSM_Read_RA_512(pSM, pageNo, 0); for (i=0; i<16; i++) *ptr++ = inpw(REG_SMDATA) & 0xff; status = fmiSM_Read_512(pSM, pageNo, (UINT32)buff); } #ifdef DEBUG if (status) printf("read NAND page fail !!!\n"); #endif #ifdef OPT_FIRST_4BLOCKS_ECC4 if (PBA <= 3) { #ifdef OPT_SUPPORT_H27UAG8T2A // restore to ECC12 if (pSM->nPageSize == NAND_PAGE_4KB) /* 4KB */ { if (pSM->bIsNandECC12 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T12); // BCH_8 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 224); // Redundant area size } } // restore to ECC8 else if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */ { if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } } #else if (pSM->nPageSize == NAND_PAGE_2KB) /* 2KB */ { if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); // BCH_8 is selected outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } } #endif } #endif // sysFlushCache(I_D_CACHE); // sysInvalidCache(); return status; } //static INT sicSMpwrite(INT chipSel, INT PBA, INT page, UINT8 *buff) INT sicSMpwrite(INT chipSel, INT PBA, INT page, UINT8 *buff) { FMI_SM_INFO_T *pSM; int pageNo; int status=0; // sysFlushCache(D_CACHE); sicSMselect(chipSel); if (chipSel == 0) pSM = pSM0; else pSM = pSM1; // enable SM outpw(REG_FMICR, FMI_SM_EN); fmiSM_Initial(pSM); //removed by mhuko PBA += pSM->uLibStartBlock; pageNo = PBA * pSM->uPagePerBlock + page; #ifdef OPT_FIRST_4BLOCKS_ECC4 if (PBA <= 3) { #ifdef OPT_SUPPORT_H27UAG8T2A // set to ECC8 for Block 0-3 if (pSM->nPageSize == NAND_PAGE_4KB) { if (pSM->bIsNandECC12 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 128); // Redundant area size } } // set to ECC4 for Block 0-3 else if (pSM->nPageSize == NAND_PAGE_2KB) { if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } } #else // set to ECC4 for Block 0-3 if (pSM->nPageSize == NAND_PAGE_2KB) { if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T4); outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } } #endif } #endif if (pSM->nPageSize == NAND_PAGE_2KB) { #ifdef _NAND_PAR_ALC_ status = fmiSM_Write_2K_ALC(pSM, pageNo, 0, (UINT32)buff); #else status = fmiSM_Write_2K(pSM, pageNo, 0, (UINT32)buff); #ifdef DBG_DATA_CONFIRM /*--- Read back data and compare it for debug. ---*/ ptr_buffR = (UINT8 *)((UINT32)buffR | 0x80000000); // non-cache fmiSM_Read_2K(pSM, pageNo, (UINT32)ptr_buffR); // read back data if (memcmp(ptr_buffR, buff, pSM->nPageSize) != 0) { int i; sysprintf("--> NAND: Data confirm error at block %d page %d !! ", PBA, page); // If any page behind the current page is dirty, this page write is out of sequence. for (i=page+1; i<pSM->uPagePerBlock; i++) { if (sicSM_is_page_dirty(chipSel, PBA - pSM->uLibStartBlock, i)) { sysprintf(" (dirty page %d)", i); break; } } sysprintf("\n"); } #endif } #endif else if (pSM->nPageSize == NAND_PAGE_4KB) { #ifdef _NAND_PAR_ALC_ status = fmiSM_Write_4K_ALC(pSM, pageNo, 0, (UINT32)buff); #else status = fmiSM_Write_4K(pSM, pageNo, 0, (UINT32)buff); #endif } else /* 512B */ status = fmiSM_Write_512(pSM, pageNo, (UINT32)buff); #ifdef DEBUG if (status) printf("write NAND page fail !!!\n"); #endif #ifdef OPT_FIRST_4BLOCKS_ECC4 if (PBA <= 3) { #ifdef OPT_SUPPORT_H27UAG8T2A // restore to ECC12 if (pSM->nPageSize == NAND_PAGE_4KB) { if (pSM->bIsNandECC12 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T12); outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 224); // Redundant area size } } // restore to ECC8 else if (pSM->nPageSize == NAND_PAGE_2KB) { if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } } #else // restore to ECC8 if (pSM->nPageSize == NAND_PAGE_2KB) { if (pSM->bIsNandECC8 == TRUE) { outpw(REG_SMCSR, inpw(REG_SMCSR) & ~SMCR_BCH_TSEL); outpw(REG_SMCSR, inpw(REG_SMCSR) | BCH_T8); outpw(REG_SMREAREA_CTL, (inpw(REG_SMREAREA_CTL) & ~SMRE_REA128_EXT) | 64); // Redundant area size } } #endif } #endif return status; } static INT sicSM_is_page_dirty(INT chipSel, INT PBA, INT page) { FMI_SM_INFO_T *pSM; int pageNo; UINT8 data0, data1; sicSMselect(chipSel); if (chipSel == 0) pSM = pSM0; else pSM = pSM1; // enable SM outpw(REG_FMICR, FMI_SM_EN); fmiSM_Initial(pSM); //removed by mhuko PBA += pSM->uLibStartBlock; pageNo = PBA * pSM->uPagePerBlock + page; if (pSM->nPageSize == NAND_PAGE_2KB) fmiSM_Read_RA(pSM, pageNo, 2050); else if (pSM->nPageSize == NAND_PAGE_4KB) fmiSM_Read_RA(pSM, pageNo, 4098); else if (pSM->nPageSize == NAND_PAGE_8KB) fmiSM_Read_RA(pSM, pageNo, 8194); else /* 512B */ fmiSM_Read_RA_512(pSM, pageNo, 2); data0 = inpw(REG_SMDATA); data1 = inpw(REG_SMDATA); #if defined (__GNUC__) #else data1 = data1; // avoid compile warning message #endif if (pSM->nPageSize == NAND_PAGE_512B) fmiSM_Reset(pSM); if (data0 == 0x00) return 1; // used page else if (data0 != 0xff) return 1; // used page return 0; // un-used page } static INT sicSM_is_valid_block(INT chipSel, INT PBA) { FMI_SM_INFO_T *pSM; sicSMselect(chipSel); if (chipSel == 0) pSM = pSM0; else pSM = pSM1; PBA += pSM->uLibStartBlock; // enable SM outpw(REG_FMICR, FMI_SM_EN); fmiSM_Initial(pSM); if (fmiCheckInvalidBlock(pSM, PBA) == 1) // invalid block { #ifdef DEBUG printf("invalid block %d\n", PBA); #endif return 0; } else return 1; // valid block } #ifdef OPT_MARK_BAD_BLOCK_WHILE_ERASE_FAIL static INT sicSMMarkBadBlock_WhileEraseFail(FMI_SM_INFO_T *pSM, UINT32 BlockNo) { UINT32 uSector, ucColAddr; /* check if MLC NAND */ if (pSM->bIsMLCNand == TRUE) { uSector = (BlockNo+1) * pSM->uPagePerBlock - 1; // write last page if (pSM->nPageSize == NAND_PAGE_2KB) { ucColAddr = 2048; // write 2048th byte } else if (pSM->nPageSize == NAND_PAGE_4KB) { ucColAddr = 4096; // write 4096th byte } // send command outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 outpw(REG_SMADDR, (ucColAddr >> 8) & 0xff); // CA8 - CA11 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMDATA, 0xf0); // mark bad block (use 0xf0 instead of 0x00 to differ from Old (Factory) Bad Blcok Mark) outpw(REG_SMCMD, 0x10); if (! fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; fmiSM_Reset(pSM); return 0; } /* SLC check the 2048 byte of 1st or 2nd page per block */ else // SLC { uSector = BlockNo * pSM->uPagePerBlock; // write lst page if (pSM->nPageSize == NAND_PAGE_2KB) { ucColAddr = 2048; // write 2048th byte } else if (pSM->nPageSize == NAND_PAGE_4KB) { ucColAddr = 4096; // write 4096th byte } else if (pSM->nPageSize == NAND_PAGE_512B) { ucColAddr = 0; goto _mark_512; } // send command outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 outpw(REG_SMADDR, (ucColAddr >> 8) & 0xff); // CA8 - CA11 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMDATA, 0xf0); // mark bad block (use 0xf0 instead of 0x00 to differ from Old (Factory) Bad Blcok Mark) outpw(REG_SMCMD, 0x10); if (! fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; fmiSM_Reset(pSM); return 0; _mark_512: outpw(REG_SMCMD, 0x50); // point to redundant area outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, ucColAddr); // CA0 - CA7 outpw(REG_SMADDR, uSector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((uSector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (uSector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((uSector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMDATA, 0xf0); // 512 outpw(REG_SMDATA, 0xff); outpw(REG_SMDATA, 0xff); outpw(REG_SMDATA, 0xff); outpw(REG_SMDATA, 0xf0); // 516 outpw(REG_SMDATA, 0xf0); // 517 outpw(REG_SMCMD, 0x10); if (! fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; fmiSM_Reset(pSM); return 0; } } #endif // OPT_MARK_BAD_BLOCK_WHILE_ERASE_FAIL INT sicSMMarkBadBlock(FMI_SM_INFO_T *pSM, UINT32 BlockNo) { UINT32 sector, column; /* page 0 */ sector = BlockNo * pSM->uPagePerBlock; column = pSM->nPageSize; // set address to begin of spare area // send command outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, column); // CA0 - CA7 outpw(REG_SMADDR, (column >> 8) & 0x3f); // CA8 - CA12 outpw(REG_SMADDR, sector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((sector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (sector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((sector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMDATA, 0xf0); // 1st byte of spare area outpw(REG_SMDATA, 0xff); outpw(REG_SMDATA, 0xff); outpw(REG_SMDATA, 0xff); outpw(REG_SMDATA, 0xf0); outpw(REG_SMDATA, 0xf0); // 6th byte of spare area outpw(REG_SMCMD, 0x10); if (! fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; fmiSM_Reset(pSM); /* page 1 */ sector++; // send command outpw(REG_SMCMD, 0x80); // serial data input command outpw(REG_SMADDR, column); // CA0 - CA7 outpw(REG_SMADDR, (column >> 8) & 0x3f); // CA8 - CA12 outpw(REG_SMADDR, sector & 0xff); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((sector >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, (sector >> 8) & 0xff); // PA8 - PA15 outpw(REG_SMADDR, ((sector >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMDATA, 0xf0); // 512 outpw(REG_SMDATA, 0xff); outpw(REG_SMDATA, 0xff); outpw(REG_SMDATA, 0xff); outpw(REG_SMDATA, 0xf0); // 516 outpw(REG_SMDATA, 0xf0); // 517 outpw(REG_SMCMD, 0x10); if (! fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; fmiSM_Reset(pSM); return 0; } static INT sicSMChangeBadBlockMark(INT chipSel) { int status=0; FMI_SM_INFO_T *pSM; _fmi_pSMBuffer = (UINT8 *)((UINT32)_fmi_ucSMBuffer | 0x80000000); sicSMselect(chipSel); if (chipSel == 0) pSM = pSM0; else pSM = pSM1; // enable SM outpw(REG_FMICR, 0x08); fmiSM_Initial(pSM); #ifndef OPT_N9H20 // scan all nand chip for (i=1; i<=pSM->uBlockPerFlash; i++) { if (fmiNormalCheckBlock(pSM, i)) // bad block { if (sicSMMarkBadBlock(pSM, i) < 0) return FMI_SM_MARK_BAD_BLOCK_ERR; } } #endif /* read physical block 0 - image information */ status = sicSMpread(chipSel, 0, pSM->uPagePerBlock-1, _fmi_pSMBuffer); if (status < 0) return status; /* write specific mark */ _fmi_ucSMBuffer[pSM->nPageSize-6] = '5'; _fmi_ucSMBuffer[pSM->nPageSize-5] = '5'; _fmi_ucSMBuffer[pSM->nPageSize-4] = '0'; _fmi_ucSMBuffer[pSM->nPageSize-3] = '0'; _fmi_ucSMBuffer[pSM->nPageSize-2] = '9'; _fmi_ucSMBuffer[pSM->nPageSize-1] = '1'; // remove write "550091" in N9H20 // sicSMpwrite(chipSel, 0, pSM->uPagePerBlock-1, _fmi_ucSMBuffer); // status = sicSMpwrite(chipSel, 0, pSM->uPagePerBlock-1, _fmi_ucSMBuffer); //mhkuo@20100730 // status = sicSMpwrite(chipSel, 0, pSM->uPagePerBlock-1, _fmi_pSMBuffer); //mhkuo@20100730 return status; } //static INT sicSMblock_erase(INT chipSel, INT PBA) INT sicSMblock_erase(INT chipSel, INT PBA) { FMI_SM_INFO_T *pSM; UINT32 page_no; sicSMselect(chipSel); if (chipSel == 0) pSM = pSM0; else pSM = pSM1; PBA += pSM->uLibStartBlock; // enable SM outpw(REG_FMICR, FMI_SM_EN); fmiSM_Initial(pSM); if (fmiCheckInvalidBlock(pSM, PBA) != 1) { page_no = PBA * pSM->uPagePerBlock; // get page address /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) /* ECC_FLD_IF */ { #ifdef DEBUG printf("erase: error sector !!\n"); #endif outpw(REG_SMISR, SMISR_ECC_FIELD_IF); } outpw(REG_SMCMD, 0x60); // erase setup command outpw(REG_SMADDR, (page_no & 0xff)); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((page_no >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, ((page_no >> 8) & 0xff)); // PA8 - PA15 outpw(REG_SMADDR, ((page_no >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMCMD, 0xd0); // erase command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; if (fmiSMCheckStatus(pSM) != 0) { #ifdef DEBUG printf("sicSMblock_erase error!!\n"); #endif #ifdef OPT_MARK_BAD_BLOCK_WHILE_ERASE_FAIL sicSMMarkBadBlock_WhileEraseFail(pSM,PBA); #endif return FMI_SM_STATUS_ERR; } } else { sysprintf("Don't erase block PBA %d since it is bad block.\n", PBA); return FMI_SM_INVALID_BLOCK; } return 0; } /*----------------------------------------------------------------------------- * Force to erase a block even if it is a bad block. * INPUT: * chipSel: 0 for NAND0 port; 1 for NAND1 port. * PBA: physical block address include reserve area. * OUTPUT: * None. * RETURN: * 0 : erase successfully * -1: erase fail and return error code *---------------------------------------------------------------------------*/ INT sicSMblock_erase_test(INT chipSel, INT PBA) { FMI_SM_INFO_T *pSM; UINT32 page_no; sicSMselect(chipSel); if (chipSel == 0) pSM = pSM0; else pSM = pSM1; // enable SM outpw(REG_FMICR, 0x08); fmiSM_Initial(pSM); page_no = PBA * pSM->uPagePerBlock; // get page address /* clear R/B flag */ if (pSM == pSM0) { while(!(inpw(REG_SMISR) & SMISR_RB0)); outpw(REG_SMISR, SMISR_RB0_IF); } else { while(!(inpw(REG_SMISR) & SMISR_RB1)); outpw(REG_SMISR, SMISR_RB1_IF); } if (inpw(REG_SMISR) & SMISR_ECC_FIELD_IF) /* ECC_FLD_IF */ { #ifdef DEBUG printf("erase: error sector !!\n"); #endif outpw(REG_SMISR, SMISR_ECC_FIELD_IF); } outpw(REG_SMCMD, 0x60); // erase setup command outpw(REG_SMADDR, (page_no & 0xff)); // PA0 - PA7 if (!pSM->bIsMulticycle) outpw(REG_SMADDR, ((page_no >> 8) & 0xff)|EOA_SM); // PA8 - PA15 else { outpw(REG_SMADDR, ((page_no >> 8) & 0xff)); // PA8 - PA15 outpw(REG_SMADDR, ((page_no >> 16) & 0xff)|EOA_SM); // PA16 - PA17 } outpw(REG_SMCMD, 0xd0); // erase command if (!fmiSMCheckRB(pSM)) return FMI_SM_RB_ERR; if (fmiSMCheckStatus(pSM) != 0) { #ifdef DEBUG printf("sicSMblock_erase error!!\n"); #endif return FMI_SM_STATUS_ERR; } return 0; } static INT sicSMchip_erase(INT chipSel) { int i, status=0; FMI_SM_INFO_T *pSM; sicSMselect(chipSel); if (chipSel == 0) pSM = pSM0; else pSM = pSM1; // enable SM outpw(REG_FMICR, FMI_SM_EN); fmiSM_Initial(pSM); // erase all chip for (i=0; i<=pSM->uBlockPerFlash; i++) { status = sicSMblock_erase(chipSel, i); if (status < 0) printf("SM block erase fail <%d>!!\n", i); } return 0; } /* driver function */ INT nandInit0(NDISK_T *NDISK_info) { return (sicSMInit(0, NDISK_info)); } INT nandpread0(INT PBA, INT page, UINT8 *buff) { return (sicSMpread(0, PBA, page, buff)); } INT nandpwrite0(INT PBA, INT page, UINT8 *buff) { #ifdef OPT_SW_WP int status; UINT32 ii; outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP) for (ii=0; ii<SW_WP_DELAY_LOOP; ii++); status = sicSMpwrite(0, PBA, page, buff); outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP) return status; #else return (sicSMpwrite(0, PBA, page, buff)); #endif } INT nand_is_page_dirty0(INT PBA, INT page) { return (sicSM_is_page_dirty(0, PBA, page)); } INT nand_is_valid_block0(INT PBA) { return (sicSM_is_valid_block(0, PBA)); } INT nand_block_erase0(INT PBA) { #ifdef OPT_SW_WP int status; UINT32 ii; outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP) #if 0 sicSMselect(0); outpw(REG_SMCMD, 0x70); // status read command while(!(inpw(REG_SMDATA) & 0x80)) // 0: protected, 1: un-potected { outpw(REG_SMCMD, 0x70); // status read command } #endif for (ii=0; ii<SW_WP_DELAY_LOOP; ii++); status = sicSMblock_erase(0, PBA); outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP) return status; #else return (sicSMblock_erase(0, PBA)); #endif } INT nand_chip_erase0(void) { #ifdef OPT_SW_WP int status; UINT32 ii; outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP) for (ii=0; ii<SW_WP_DELAY_LOOP; ii++); status = sicSMchip_erase(0); outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP) return status; #else return (sicSMchip_erase(0)); #endif } INT nand_ioctl(INT param1, INT param2, INT param3, INT param4) { return 0; } INT fmiSMCheckBootHeader(INT chipSel, FMI_SM_INFO_T *pSM) { int fmiNandSysArea=0; int volatile status, imageCount, i, block; unsigned int *pImageList; volatile int ii; #define OPT_FOUR_BOOT_IMAGE _fmi_pSMBuffer = (UINT8 *)((UINT32)_fmi_ucSMBuffer | 0x80000000); pImageList = (UINT32 *)((UINT32)_fmi_ucSMBuffer | 0x80000000); /* read physical block 0 - image information */ #ifdef OPT_FOUR_BOOT_IMAGE for (ii=0; ii<4; ii++) { status = sicSMpread(chipSel, ii, pSM->uPagePerBlock-1, _fmi_pSMBuffer); if (!status) { if (((*(pImageList+0)) == 0x574255aa) && ((*(pImageList+3)) == 0x57425963)) break; } } #else status = sicSMpread(chipSel, 0, pSM->uPagePerBlock-1, _fmi_pSMBuffer); #endif if (status < 0) return status; /* check specific mark */ if (pSM->nPageSize != NAND_PAGE_512B) { if (((_fmi_ucSMBuffer[pSM->nPageSize-6]) == '5') && ((_fmi_ucSMBuffer[pSM->nPageSize-5]) == '5') && ((_fmi_ucSMBuffer[pSM->nPageSize-4]) == '0') && ((_fmi_ucSMBuffer[pSM->nPageSize-3]) == '0') && ((_fmi_ucSMBuffer[pSM->nPageSize-2]) == '9') && ((_fmi_ucSMBuffer[pSM->nPageSize-1]) == '1')) { _fmi_bIsNandFirstAccess = FALSE; } else { sicSMChangeBadBlockMark(chipSel); } } if (((*(pImageList+0)) == 0x574255aa) && ((*(pImageList+3)) == 0x57425963)) { fmiNandSysArea = *(pImageList+1); } if ((fmiNandSysArea != 0xFFFFFFFF) && (fmiNandSysArea != 0)) { pSM->uLibStartBlock = (fmiNandSysArea / pSM->uSectorPerBlock) + 1; } else { /* read physical block 0 - image information */ #ifdef OPT_FOUR_BOOT_IMAGE for (ii=0; ii<4; ii++) { status = sicSMpread(chipSel, ii, pSM->uPagePerBlock-2, _fmi_pSMBuffer); if (!status) { if (((*(pImageList+0)) == 0x574255aa) && ((*(pImageList+3)) == 0x57425963)) break; } } #else status = sicSMpread(chipSel, 0, pSM->uPagePerBlock-2, _fmi_pSMBuffer); #endif if (status < 0) return status; if (((*(pImageList+0)) == 0x574255aa) && ((*(pImageList+3)) == 0x57425963)) { imageCount = *(pImageList+1); /* pointer to image information */ pImageList = pImageList+4; for (i=0; i<imageCount; i++) { block = (*(pImageList + 1) & 0xFFFF0000) >> 16; if (block > pSM->uLibStartBlock) pSM->uLibStartBlock = block; /* pointer to next image */ pImageList = pImageList+12; } pSM->uLibStartBlock++; } } return 0; } VOID fmiSMClose(INT chipSel) { if (chipSel == 0) { _nand_init0 = 0; if (pSM0 != 0) { free(pSM0); pSM0 = 0; } } else { _nand_init1 = 0; if (pSM1 != 0) { free(pSM1); pSM1 = 0; } } if ((_nand_init0 == 0) && (_nand_init1 == 0)) { outpw(REG_SMCSR, inpw(REG_SMCSR)|0x06000000); // CS-0/CS-1 -> HIGH outpw(REG_SMISR, 0xfff); outpw(REG_FMICR, 0x00); outpw(REG_GPDFUN, inpw(REG_GPDFUN) & ~0x0003FC00); // enable NAND NWR/NRD/RB0/RB1 pins outpw(REG_GPEFUN, inpw(REG_GPEFUN) & ~0x00FF0000); // enable NAND ALE/CLE/CS0/CS1 pins } } INT nandInit1(NDISK_T *NDISK_info) { return (sicSMInit(1, NDISK_info)); } INT nandpread1(INT PBA, INT page, UINT8 *buff) { return (sicSMpread(1, PBA, page, buff)); } INT nandpwrite1(INT PBA, INT page, UINT8 *buff) { #ifdef OPT_SW_WP int status; UINT32 ii; outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP) for (ii=0; ii<SW_WP_DELAY_LOOP; ii++); #if 0 sicSMselect(1); outpw(REG_SMCMD, 0x70); // status read command while(!(inpw(REG_SMDATA) & 0x80)) // 0: protected, 1: un-potected { outpw(REG_SMCMD, 0x70); // status read command } #endif status = sicSMpwrite(1, PBA, page, buff); outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP) return status; #else return (sicSMpwrite(1, PBA, page, buff)); #endif } INT nand_is_page_dirty1(INT PBA, INT page) { return (sicSM_is_page_dirty(1, PBA, page)); } INT nand_is_valid_block1(INT PBA) { return (sicSM_is_valid_block(1, PBA)); } INT nand_block_erase1(INT PBA) { #ifdef OPT_SW_WP int status; UINT32 ii; outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP) for (ii=0; ii<SW_WP_DELAY_LOOP; ii++); #if 0 sicSMselect(1); outpw(REG_SMCMD, 0x70); // status read command while(!(inpw(REG_SMDATA) & 0x80)) // 0: protected, 1: un-potected { outpw(REG_SMCMD, 0x70); // status read command } #endif status = sicSMblock_erase(1, PBA); outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP) return status; #else return (sicSMblock_erase(1, PBA)); #endif } INT nand_chip_erase1(void) { #ifdef OPT_SW_WP int status; UINT32 ii; outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) | 0x0080); // port A7 high (WP) for (ii=0; ii<SW_WP_DELAY_LOOP; ii++); status = sicSMchip_erase(1); outpw(REG_GPIOA_DOUT, inpw(REG_GPIOA_DOUT) & ~ 0x0080); // port A7 low (WP) return status; #else return (sicSMchip_erase(1)); #endif }