/* read chip mfr and id * return 0 if they match board config * return 1 if not */ int nand_chip() { int mfr, id; NAND_ENABLE_CE(); if (NanD_Command(NAND_CMD_RESET)) { printf("Err: RESET\n"); NAND_DISABLE_CE(); return 1; } if (NanD_Command(NAND_CMD_READID)) { printf("Err: READID\n"); NAND_DISABLE_CE(); return 1; } NanD_Address(ADDR_COLUMN, 0); mfr = READ_NAND(NAND_ADDR); id = READ_NAND(NAND_ADDR); NAND_DISABLE_CE(); return (mfr != K9F5616_MFR || id != K9F5616_ID); }
static PSNandInitInfo AT91F_NandReadID(void) { unsigned int uChipID; unsigned char bManufacturerID, bDeviceID; /* * Enable chipset */ NAND_ENABLE_CE(); /* * Ask the Nand its IDs */ WRITE_NAND_COMMAND(CMD_READID); WRITE_NAND_ADDRESS(0x00); /* * Read answer */ bManufacturerID = READ_NAND(); bDeviceID = READ_NAND(); /* * Disable chipset before returning */ NAND_DISABLE_CE(); uChipID = (bManufacturerID << 8) | bDeviceID; return AT91F_GetNandInitInfo(uChipID); }
bool onfi_ebidetect(uintptr_t cmdaddr, uintptr_t addraddr, uintptr_t dataaddr) { uint32_t timer; uint8_t rc; bool found = false; uint8_t ids[4]; uint8_t i; finfo("cmdaddr=%08x addraddr=%08x dataaddr=%08x\n", (int)cmdaddr, (int)addraddr, (int)dataaddr); /* Send Reset command */ WRITE_NAND_COMMAND(NAND_CMD_RESET, cmdaddr); /* If a Nandflash is connected, it should answer to a read status command */ for (timer = 0; timer < 60; timer++) { rc = onfi_readstatus(cmdaddr, dataaddr); if (rc == OK) { WRITE_NAND_COMMAND(NAND_CMD_READID, cmdaddr); WRITE_NAND_ADDRESS(0, addraddr); ids[0] = READ_NAND(dataaddr); ids[1] = READ_NAND(dataaddr); ids[2] = READ_NAND(dataaddr); ids[3] = READ_NAND(dataaddr); for (i = 0; i < NAND_NMODELS ; i++) { if (g_nandmodels[i].devid == ids[1]) { found = true; break; } } break; } } if (!found) { if (onfi_compatible(cmdaddr, addraddr, dataaddr)) { /* Report true if it is an ONFI device that is not in device * list (perhaps it is a new device that is ONFI campatible */ found = true; } } return found; }
/* read a page with ECC */ static int nand_read_page(u_char *buf, ulong page_addr) { u_char ecc_code[6]; u_char ecc_calc[3]; u_char oob_buf[16]; u_char *p; u16 val; int cntr; NAND_ENABLE_CE(); NanD_Command(NAND_CMD_READ0); NanD_Address(ADDR_COLUMN_PAGE, page_addr>>1); NAND_WAIT_READY(); p = buf; for (cntr = 0; cntr < 256; cntr++){ val = READ_NAND(NAND_ADDR); *p++ = val & 0xff; *p++ = val >> 8; } p = oob_buf; for (cntr = 0; cntr < 8; cntr++){ val = READ_NAND(NAND_ADDR); *p++ = val & 0xff; *p++ = val >> 8; } NAND_DISABLE_CE(); /* set pin high */ /* Pick the ECC bytes out of the oob data */ for (cntr = 0; cntr < 6; cntr++) ecc_code[cntr] = oob_buf[ecc_pos[cntr]]; if ((oob_buf[eccvalid_pos] & 0x0f) != 0x0f) { nand_calculate_ecc (buf, &ecc_calc[0]); if (nand_correct_data (buf, &ecc_code[0], &ecc_calc[0]) == -1) { printf ("ECC Failed, page 0x%08x\n", page_addr); return 1; } } if ((oob_buf[eccvalid_pos] & 0xf0) != 0xf0) { nand_calculate_ecc (buf + 256, &ecc_calc[0]); if (nand_correct_data (buf + 256, &ecc_code[3], &ecc_calc[0]) == -1) { printf ("ECC Failed, page 0x%08x\n", page_addr+0x100); return 1; } } return 0; }
static u_char upmnand_read_byte(struct mtd_info *mtdinfo) { struct nand_chip *this = mtdinfo->priv; ulong base = (ulong) (this->IO_ADDR_W + chipsel * CONFIG_SYS_NAND_CS_DIST); return READ_NAND(base); }
bool onfi_compatible(uintptr_t cmdaddr, uintptr_t addraddr, uintptr_t dataaddr) { uint8_t parmtab[ONFI_PARAM_TABLE_SIZE]; /* Check if the Nandflash is ONFI compliant */ WRITE_NAND_COMMAND(NAND_CMD_READID, cmdaddr); WRITE_NAND_ADDRESS(0x20, addraddr); parmtab[0] = READ_NAND(dataaddr); parmtab[1] = READ_NAND(dataaddr); parmtab[2] = READ_NAND(dataaddr); parmtab[3] = READ_NAND(dataaddr); return (parmtab[0] == 'O' && parmtab[1] == 'N' && parmtab[2] == 'F' && parmtab[3] == 'I'); }
/** * \brief This function retrieves the data structure that describes the target¡®s * organization, features, timings and other behavioral parameters. * \param pOnfiPageParameter Pointer to a PmeccDescriptor instance. * \return 0: ONFI not compliant or not supported. 1: ONFI compliant */ uint8_t NandGetOnfiPageParam (OnfiPageParam *pOnfiPageParameter) { uint8_t i; uint8_t rc; uint8_t onfi_param_table[ONFI_PARAM_TABLE_SIZE]; if (NandIsOnficompatible()) { pCurrentOnfiPageParam = pOnfiPageParameter; pOnfiPageParameter->onfiCompatiable = 1; for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++) { onfi_param_table[i] = 0xFF; } /* Perform Read Parameter Page command */ WRITE_NAND_COMMAND(NAND_CMD_READ_PARAM_PAGE, EBI_NF_ADDR); WRITE_NAND_ADDRESS(0x0, EBI_NF_ADDR); /* Wait NF ready */ _NandReadStatus(); /* Re-enable data output mode required after Read Status command */ WRITE_NAND_COMMAND(NAND_CMD_READ0, EBI_NF_ADDR); /* Read the parameter table */ for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++) { onfi_param_table[i] = READ_NAND(EBI_NF_ADDR); } for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++) { if ( onfi_param_table[i] != 0xFF ) break; } if ( i == ONFI_PARAM_TABLE_SIZE) { pOnfiPageParameter->onfiCompatiable = 0; return 0; } /* JEDEC manufacturer ID */ pOnfiPageParameter->manufacturerId = *(uint8_t *)(onfi_param_table + 64); /* Bus width */ pOnfiPageParameter->onfiBusWidth = (*(uint8_t *)(onfi_param_table + 6)) & 0x01; /* Get number of data bytes per page (bytes 80-83 in the param table) */ pOnfiPageParameter->onfiPageSize = *(uint32_t *)(void*)(onfi_param_table + 80); /* Get number of spare bytes per page (bytes 84-85 in the param table) */ pOnfiPageParameter->onfiSpareSize = *(uint16_t *)(void*)(onfi_param_table + 84); /* Number of pages per block. */ pOnfiPageParameter->onfiPagesPerBlock = *(uint32_t *)(void*)(onfi_param_table + 92); /* Number of blocks per logical unit (LUN). */ pOnfiPageParameter->onfiBlocksPerLun = *(uint32_t *)(void*)(onfi_param_table + 96); /* Number of logical units. */ pOnfiPageParameter->onfiLogicalUnits = *(uint8_t *)(onfi_param_table + 100); /* Number of bits of ECC correction */ pOnfiPageParameter->onfiEccCorrectability = *(uint8_t *)(onfi_param_table + 112); /* Device model */ pOnfiPageParameter->onfiDeviceModel= *(uint8_t *)(onfi_param_table + 49); return 1; } return 0; }
/** * \brief This function read an the ONFI signature at address of 20h to detect * if the device is ONFI compatiable. * \return 0: ONFI not compliant or not supported. 1: ONFI compliant */ uint8_t NandIsOnficompatible (void) { uint8_t onfi_param_table[ONFI_PARAM_TABLE_SIZE]; // Check if the Nandflash is ONFI compliant WRITE_NAND_COMMAND(NAND_CMD_READID, EBI_NF_ADDR); WRITE_NAND_ADDRESS(0x20, EBI_NF_ADDR); onfi_param_table[0] = READ_NAND(EBI_NF_ADDR); onfi_param_table[1] = READ_NAND(EBI_NF_ADDR); onfi_param_table[2] = READ_NAND(EBI_NF_ADDR); onfi_param_table[3] = READ_NAND(EBI_NF_ADDR); if ((onfi_param_table[0] == 'O') && (onfi_param_table[1] == 'N') && (onfi_param_table[2] == 'F') && (onfi_param_table[3] == 'I')) { return 1; } else { return 0; } }
/* NanD_Command: Send a flash command to the flash chip */ static int NanD_Command(unsigned char command) { NAND_CTL_SETCLE(NAND_ADDR); WRITE_NAND_COMMAND(command, NAND_ADDR); NAND_CTL_CLRCLE(NAND_ADDR); if(command == NAND_CMD_RESET){ unsigned char ret_val; NanD_Command(NAND_CMD_STATUS); do{ ret_val = READ_NAND(NAND_ADDR);/* wait till ready */ } while((ret_val & 0x40) != 0x40); } NAND_WAIT_READY(); return 0; }
/* read from the 16 bytes of oob data that correspond to a 512 byte page. */ static int nand_read_oob(u_char *buf, ulong page_addr) { u16 val; int cntr; NAND_ENABLE_CE(); /* set pin low */ NanD_Command(NAND_CMD_READOOB); NanD_Address(ADDR_COLUMN_PAGE, page_addr>>1); NAND_WAIT_READY(); for (cntr = 0; cntr < 8; cntr++){ val = READ_NAND(NAND_ADDR); *buf++ = val & 0xff; *buf++ = val >> 8; } NAND_WAIT_READY(); NAND_DISABLE_CE(); /* set pin high */ return 0; }
static int onfi_readstatus(uintptr_t cmdaddr, uintptr_t dataaddr) { uint32_t timeout; uint8_t status; /* Issue command */ WRITE_NAND_COMMAND(NAND_CMD_STATUS, cmdaddr); timeout = 0; while (timeout < MAX_READ_STATUS_COUNT) { /* Read status byte */ status = READ_NAND(dataaddr); /* Check status. If status bit 6 = 1 device is ready */ if ((status & STATUS_BIT_6) == STATUS_BIT_6) { /* If status bit 0 = 0 the last operation was successful */ if ((status & STATUS_BIT_0) == 0) { return OK; } else { return -EIO; } } timeout++; } return -ETIMEDOUT; }
/** * \brief This function Reads the status register of the NAND device by * issuing a 0x70 command. * \return NAND_IO_RC_PASS =0 : The function completes operation successfully. NAND_IO_RC_FAIL =1 : The function does not complete operation successfully. NAND_IO_RC_TIMEOUT =2 : The function times out before operation completes. */ static uint32_t _NandReadStatus(void) { uint32_t nReadStatusCount; uint8_t ucStatus; /* Issue command */ WRITE_NAND_COMMAND(NAND_CMD_STATUS, EBI_NF_ADDR); nReadStatusCount = 0; while (nReadStatusCount < MAX_READ_STATUS_COUNT) { /* Read status byte */ ucStatus = READ_NAND(EBI_NF_ADDR); /* Check status */ /* If status bit 6 = 1 device is ready */ if ((ucStatus & STATUS_BIT_6) == STATUS_BIT_6) { if ((ucStatus & STATUS_BIT_0) == 0) /* If status bit 0 = 0 the last operation was succesful */ return NAND_IO_RC_PASS; else return NAND_IO_RC_FAIL; } nReadStatusCount++; } return NAND_IO_RC_TIMEOUT; }
uint8_t NandEbiDetect(void) { uint32_t timer; uint8_t rc; uint8_t chip_found = 0; uint8_t ids[4]; uint8_t i; *ADDR_CCFG_EBICSA |= EBICSA_EBI_DBPDC; /* Try to detect a bootable Nand connected on D16 */ *ADDR_CCFG_EBICSA |= (EBICSA_NAND_D0_ON_D16 ); /* Send Reset command */ WRITE_NAND_COMMAND(NAND_CMD_RESET, EBI_NF_ADDR); /* If a Nandflash is connected, it should answer to a read status command */ for (timer = 0; timer < 60; timer++) { rc = _NandReadStatus(); if (rc == NAND_IO_RC_PASS) { WRITE_NAND_COMMAND(NAND_CMD_READID, EBI_NF_ADDR); WRITE_NAND_ADDRESS(0, EBI_NF_ADDR); ids[0] = READ_NAND(EBI_NF_ADDR); ids[1] = READ_NAND(EBI_NF_ADDR); ids[2] = READ_NAND(EBI_NF_ADDR); ids[3] = READ_NAND(EBI_NF_ADDR); for(i = 0; i< NandFlashModelList_SIZE ; i++) { if(nandFlashModelList[i].deviceId == ids[1]) { chip_found = 1; break; } } break; } } if (chip_found == 0) { /* Then try Nand connected on D0 */ *ADDR_CCFG_EBICSA &= (uint32_t)(~ EBICSA_NAND_D0_ON_D16 ); /* Send Reset command */ WRITE_NAND_COMMAND(NAND_CMD_RESET, EBI_NF_ADDR); /* If a Nandflash is connected, it should answer to a read status command */ for (timer = 0; timer < 60; timer++) { rc = _NandReadStatus(); if (rc == NAND_IO_RC_PASS) { WRITE_NAND_COMMAND(NAND_CMD_READID, EBI_NF_ADDR); WRITE_NAND_ADDRESS(0, EBI_NF_ADDR); ids[0] = READ_NAND(EBI_NF_ADDR); ids[1] = READ_NAND(EBI_NF_ADDR); ids[2] = READ_NAND(EBI_NF_ADDR); ids[3] = READ_NAND(EBI_NF_ADDR); for( i = 0; i< NandFlashModelList_SIZE ; i++) { if(nandFlashModelList[i].deviceId == ids[1]) { chip_found = 1; break; } } } break; } } return chip_found; }
int onfi_read(uintptr_t cmdaddr, uintptr_t addraddr, uintptr_t dataaddr, FAR struct onfi_pgparam_s *onfi) { uint8_t parmtab[ONFI_PARAM_TABLE_SIZE]; int i; finfo("cmdaddr=%08x addraddr=%08x dataaddr=%08x\n", (int)cmdaddr, (int)addraddr, (int)dataaddr); if (!onfi_compatible(cmdaddr, addraddr, dataaddr)) { ferr("ERROR: No ONFI compatible device detected\n"); return -ENODEV; } /* Initialize the ONFI parameter table */ memset(parmtab, 0xff, ONFI_PARAM_TABLE_SIZE); /* Perform Read Parameter Page command */ WRITE_NAND_COMMAND(NAND_CMD_READ_PARAM_PAGE, cmdaddr); WRITE_NAND_ADDRESS(0x0, addraddr); /* Wait NF ready */ onfi_readstatus(cmdaddr, dataaddr); /* Re-enable data output mode required after Read Status command */ WRITE_NAND_COMMAND(NAND_CMD_READ0, cmdaddr); /* Read the parameter table */ for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++) { parmtab[i] = READ_NAND(dataaddr); } for (i = 0; i < ONFI_PARAM_TABLE_SIZE; i++) { if (parmtab[i] != 0xff) { break; } } if (i == ONFI_PARAM_TABLE_SIZE) { ferr("ERROR: Failed to read ONFI parameter table\n"); return -EIO; } /* JEDEC manufacturer ID */ onfi->manufacturer = *(FAR uint8_t *)(parmtab + 64); /* Bus width */ onfi->buswidth = (*(FAR uint8_t *)(parmtab + 6)) & 0x01; /* Get number of data bytes per page (bytes 80-83 in the param table) */ onfi->pagesize = *(FAR uint32_t *)(FAR void *)(parmtab + 80); /* Get number of spare bytes per page (bytes 84-85 in the param table) */ onfi->sparesize = *(FAR uint16_t *)(FAR void *)(parmtab + 84); /* Number of pages per block. */ onfi->pagesperblock = *(FAR uint32_t *)(FAR void *)(parmtab + 92); /* Number of blocks per logical unit (LUN). */ onfi->blocksperlun = *(FAR uint32_t *)(FAR void *)(parmtab + 96); /* Number of logical units. */ onfi->luns = *(FAR uint8_t *)(parmtab + 100); /* Number of bits of ECC correction */ onfi->eccsize = *(FAR uint8_t *)(parmtab + 112); /* Device model */ onfi->model = *(FAR uint8_t *)(parmtab + 49); finfo("Returning:\n"); finfo(" manufacturer: 0x%02x\n", onfi->manufacturer); finfo(" buswidth: %d\n", onfi->buswidth); finfo(" luns: %d\n", onfi->luns); finfo(" eccsize: %d\n", onfi->eccsize); finfo(" model: 0x%02s\n", onfi->model); finfo(" sparesize: %d\n", onfi->sparesize); finfo(" pagesperblock: %d\n", onfi->pagesperblock); finfo(" blocksperlun: %d\n", onfi->blocksperlun); finfo(" pagesize: %d\n", onfi->pagesize); return OK; }
//----------------------------------------------------------------------------- HANDLE NAND_Initialize( LPCTSTR szContext, PCI_REG_INFO *pRegIn, PCI_REG_INFO *pRegOut ) { DWORD chipSelect = BSPGetNandCS(); const NAND_INFO * pBSPNandInfo; HANDLE hDevice = NULL; UINT ffPrefetchMode = 0; UINT8 manufacturer, device; NandDevice_t *pDevice = &s_Device; #ifndef BOOT_MODE DWORD dwKernelRet; #endif UNREFERENCED_PARAMETER(pRegOut); UNREFERENCED_PARAMETER(szContext); // initialize structure memset(pDevice, 0, sizeof(NandDevice_t)); #ifdef BOOT_MODE pDevice->pGpmcRegs = (OMAP_GPMC_REGS*)OALPAtoUA(SOCGetGPMCAddress(0)); pDevice->pFifo = (NANDREG*)OALPAtoUA(pRegIn->MemBase.Reg[0]); /* Get ECC mode from BootCfg */ pDevice->ECCtype = g_ecctype; if((pDevice->ECCtype > BCH8bit) || (pDevice->ECCtype < Hamming1bit)) { pDevice->ECCtype = Hamming1bit; RETAILMSG(TRUE, (L"Incorrect ECC type setting\r\n")); } #else if (szContext != NULL) { if (InitializePointers(szContext, pDevice) == FALSE) goto cleanUp; } else { PHYSICAL_ADDRESS pa; // if there's not context string then use global macros pa.QuadPart = pRegIn->MemBase.Reg[0]; pDevice->memLen[0] = pRegIn->MemLen.Reg[0]; pDevice->pGpmcRegs = MmMapIoSpace(pa, pDevice->memLen[0], FALSE); if (pDevice->pGpmcRegs == NULL) goto cleanUp; pa.QuadPart = pRegIn->MemBase.Reg[1]; pDevice->memLen[1] = pRegIn->MemLen.Reg[1]; pDevice->pFifo = MmMapIoSpace(pa, pDevice->memLen[1], FALSE); if (pDevice->pGpmcRegs == NULL) goto cleanUp; } if (!KernelIoControl(IOCTL_HAL_GET_ECC_TYPE, NULL, 0, &pDevice->ECCtype, sizeof(DWORD), &dwKernelRet)) { RETAILMSG( TRUE,(TEXT("Failed to read Ecc type\r\n"))); pDevice->ECCtype = Hamming1bit; } RETAILMSG(TRUE, (L"ECC TYPE is %s\r\n", (pDevice->ECCtype==Hamming1bit)? L"Hamming 1 bit" : (pDevice->ECCtype==BCH4bit)? L"BCH 4 bit" : L"BCH 8 bit")); #endif pDevice->pNandCmd = (NANDREG*)((UINT32)pDevice->pGpmcRegs + offset(OMAP_GPMC_REGS, GPMC_NAND_COMMAND_0) + (0x30 * chipSelect)); pDevice->pNandAddress= (NANDREG*)((UINT32)pDevice->pGpmcRegs + offset(OMAP_GPMC_REGS, GPMC_NAND_ADDRESS_0) + (0x30 * chipSelect)); pDevice->pNandData= (NANDREG*)((UINT32)pDevice->pGpmcRegs + offset(OMAP_GPMC_REGS, GPMC_NAND_DATA_0) + (0x30 * chipSelect)); // Enable GPMC wait-to-nowait edge detection mechanism on NAND R/B pin NAND_Enable(pDevice, TRUE); // Write RESET command // (a reset aborts any current READ, WRITE (PROGRAM) or ERASE operation) NAND_SendCommand(pDevice, NAND_CMD_RESET); // Wait for NAND while ((NAND_GetStatus(pDevice) & NAND_STATUS_READY) == 0); // Send Read ID Command NAND_SendCommand(pDevice, NAND_CMD_READID); // Send Address 00h WRITE_NAND(pDevice->pNandAddress, 0); // Read the manufacturer ID & device code manufacturer = (UINT8)READ_NAND(pDevice->pNandData); device = (UINT8)READ_NAND(pDevice->pNandData); if ((pBSPNandInfo = BSPGetNandInfo(manufacturer,device))==NULL) { goto cleanUp; } if ((pBSPNandInfo->sectorSize != 2048) && (pBSPNandInfo->wordData != 2)) { ERRORMSG(1,(TEXT("FMD driver supports only 16bits large page (2KB) devices\r\n"))); goto cleanUp; } pDevice->nandInfo = *pBSPNandInfo; pDevice->IrqWait = BSPGetNandIrqWait(); /* ECCCfg: 16bit bus width, cs0, 4 - 512 bytes blocks per page */ pDevice->ECCCfg = (GPMC_ECC_CONFIG_16BIT | (chipSelect << 1) | (0x3<<4)); pDevice->ECCsize = (pDevice->ECCtype == Hamming1bit ) ? ECC_BYTES_HAMMING : (pDevice->ECCtype == BCH4bit ) ? ECC_BYTES_BCH4 : ECC_BYTES_BCH8; // Enable and reset ECC engine (workaround for engine giving 0s first time) ECC_Init(pDevice->pGpmcRegs, pDevice->ECCCfg, pDevice->ECCtype, NAND_ECC_READ); ECC_Reset(pDevice->pGpmcRegs); // Only enable during NAND read/write/erase operations NAND_Enable(pDevice, FALSE); // configure the prefetch engine pDevice->prefetchMode = kPrefetchOff; OUTREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONTROL, 0); // set prefetch mask ffPrefetchMode = GPMC_PREFETCH_CONFIG_SYNCHROMODE | GPMC_PREFETCH_CONFIG_PFPWENROUNDROBIN | GPMC_PREFETCH_CONFIG_ENABLEOPTIMIZEDACCESS | GPMC_PREFETCH_CONFIG_WAITPINSELECTOR(chipSelect) | GPMC_PREFETCH_CONFIG_FIFOTHRESHOLD(FIFO_THRESHOLD) | GPMC_PREFETCH_CONFIG_ENGINECSSELECTOR(chipSelect); OUTREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONFIG1, ffPrefetchMode); // configure prefetch engine OUTREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONFIG2, pBSPNandInfo->sectorSize ); SETREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONFIG1, GPMC_PREFETCH_CONFIG_ENABLEENGINE ); // We are done hDevice = pDevice; cleanUp: return hDevice; }