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; }
/** * \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; }
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); }
/** * \brief This function check if the Nandflash has an embedded ECC controller. * \return 0: ONFI not compliant or internal ECC not supported. 1: Internal ECC enabled. */ uint8_t NandEnableInternalEcc (void) { OnfiPageParam *pOnfiPageParameter; pOnfiPageParameter = NandGetCurrentOnfiInstance(); if (pOnfiPageParameter->onfiCompatiable == 1) { /* Check if the Nandflash has an embedded ECC controller Known memories with this feature : - Manufacturer ID = 2Ch (Micron) - Number of bits ECC = 04h (4-bit ECC means process 34nm) - device size = 1Gb or 2Gb or 4Gb (Number of data bytes per page * Number of pages per block * Number of blocks per unit) */ if ( ((pOnfiPageParameter->manufacturerId & NAND_MFR_MICRON) == NAND_MFR_MICRON) && (pOnfiPageParameter->onfiEccCorrectability == 0x4) && ((pOnfiPageParameter->onfiDeviceModel == '1') // 1G, || (pOnfiPageParameter->onfiDeviceModel == '2') // 2G || (pOnfiPageParameter->onfiDeviceModel == '4'))) { // or 4G bits /* then activate the internal ECC controller */ WRITE_NAND_COMMAND(NAND_CMD_SET_FEATURE, EBI_NF_ADDR); WRITE_NAND_ADDRESS(0x90, EBI_NF_ADDR); WRITE_NAND(0x08, EBI_NF_ADDR); WRITE_NAND(0x00, EBI_NF_ADDR); WRITE_NAND(0x00, EBI_NF_ADDR); WRITE_NAND(0x00, EBI_NF_ADDR); NandSwitchEcc(ECC_INTERNAL); return 1; } } return 0; }
static void reset_nandflash(void) { NAND_ENABLE_CE(); WRITE_NAND_COMMAND(0xFF); NAND_WAIT_READY(); NAND_WAIT_READY(); NAND_DISABLE_CE(); }
/* 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; }
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'); }
bool onfi_embeddedecc(FAR const struct onfi_pgparam_s *onfi, uintptr_t cmdaddr, uintptr_t addraddr, uintptr_t dataaddr, bool enable) { /* Does the NAND supported the embedded ECC function? */ if (onfi_have_embeddedecc(onfi)) { /* Yes... enable or disable it */ /* Perform common setup */ WRITE_NAND_COMMAND(NAND_CMD_SET_FEATURE, cmdaddr); WRITE_NAND_ADDRESS(0x90, addraddr); if (enable) { /* Activate the internal ECC controller */ WRITE_NAND(0x08, dataaddr); WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); setSmcOpEccType(SMC_ECC_INTERNAL); } else { /* De-activate the internal ECC controller */ WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); } return true; } return false; }
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; }
/** * \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; } }
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; }