📄 nand_base.c
字号:
#if CONFIG_MTD_NAND_VERSION <= CONFIG_MTD_NAND_VERS_0_1
uint32_t pAddr = offset + chip->pbase;
chip->ctrl_write(cmdEndAddr? BCHP_NAND_CMD_END_ADDRESS: BCHP_NAND_CMD_ADDRESS, pAddr);
#else
uint32_t udw, ldw, cs;
DIunion chipOffset;
//char msg[24];
// cs is the index into chip->CS[]
cs = (uint32_t) __ll_RightShift(offset, chip->chip_shift);
// chipOffset is offset into the current CS
#ifdef MTD_LARGE
chipOffset.ll = mtd64_and(offset, mtd64_sub32(chip->chipSize, 1));
#else
chipOffset.ll = __ll_and32(offset, chip->chipSize - 1);
#endif
if (cs >= chip->numchips) {
printk(KERN_ERR "%s: Offset=%s outside of chip range cs=%d, chip->CS[cs]=%d\n",
__FUNCTION__, __ll_sprintf(NandMsg, offset), cs, chip->CS[cs]);
BUG();
return;
}
if (gdebug) printk("CS=%d, chip->CS[cs]=%d\n", cs, chip->CS[cs]);
// ldw is lower 32 bit of chipOffset, need to add pbase when on CS0
if (chip->CS[cs] == 0) {
ldw = chipOffset.s.low + chip->pbase;
}
else {
ldw = chipOffset.s.low;
}
udw = chipOffset.s.high | (chip->CS[cs] << 16);
if (gdebug > 3) printk("%s: offset=%s cs=%d ldw = %08x, udw = %08x\n", __FUNCTION__, __ll_sprintf(NandMsg, offset), cs, ldw, udw);
chip->ctrl_write(cmdEndAddr? BCHP_NAND_CMD_END_ADDRESS: BCHP_NAND_CMD_ADDRESS, ldw);
chip->ctrl_write(BCHP_NAND_CMD_EXT_ADDRESS, udw);
#endif
}
#if 1
/* Dont delete, may be useful for debugging */
static void print_diagnostics(void)
{
uint32_t nand_acc_control = nand_ctrl_read(BCHP_NAND_ACC_CONTROL);
uint32_t nand_select = nand_ctrl_read(BCHP_NAND_CS_NAND_SELECT);
uint32_t nand_config = nand_ctrl_read(BCHP_NAND_CONFIG);
uint32_t flash_id = nand_ctrl_read(BCHP_NAND_FLASH_DEVICE_ID);
uint32_t pageAddr = nand_ctrl_read(BCHP_NAND_PROGRAM_PAGE_ADDR);
#if CONFIG_MTD_NAND_VERSION >= CONFIG_MTD_NAND_VERS_1_0
uint32_t pageAddrExt = nand_ctrl_read(BCHP_NAND_PROGRAM_PAGE_EXT_ADDR);
#endif
uint32_t ebiCSBase0 = * ((volatile unsigned long*) (0xb0000000|BCHP_EBI_CS_BASE_0));
//unsigned long nand_timing1 = nand_ctrl_read(BCHP_NAND_TIMING_1);
//unsigned long nand_timing2 = nand_ctrl_read(BCHP_NAND_TIMING_2);
printk("NAND_SELECT=%08x ACC_CONTROL=%08x, \tNAND_CONFIG=%08x, FLASH_ID=%08x\n",
nand_select, nand_acc_control, nand_config, flash_id);
#if CONFIG_MTD_NAND_VERSION >= CONFIG_MTD_NAND_VERS_1_0
printk("PAGE_EXT_ADDR=%08x\n", pageAddrExt);
#endif
printk("PAGE_ADDR=%08x, \tCS0_BASE=%08x\n", pageAddr, ebiCSBase0);
}
#endif
static void print_config_regs(void)
{
unsigned long nand_acc_control = nand_ctrl_read(BCHP_NAND_ACC_CONTROL);
unsigned long nand_config = nand_ctrl_read(BCHP_NAND_CONFIG);
unsigned long flash_id = nand_ctrl_read(BCHP_NAND_FLASH_DEVICE_ID);
unsigned long nand_timing1 = nand_ctrl_read(BCHP_NAND_TIMING_1);
unsigned long nand_timing2 = nand_ctrl_read(BCHP_NAND_TIMING_2);
printk("\nFound NAND: ACC=%08lx, cfg=%08lx, flashId=%08lx, tim1=%08lx, tim2=%08lx\n",
nand_acc_control, nand_config, flash_id, nand_timing1, nand_timing2);
}
#if 1
void print_oobbuf(const unsigned char* buf, int len)
{
int i;
if (!buf) {printk("NULL"); return;}
for (i=0; i<len; i++) {
if (i % 16 == 0) printk("\n");
else if (i % 4 == 0) printk(" ");
printk("%02x", buf[i]);
}
printk("\n");
}
void print_databuf(const unsigned char* buf, int len)
{
int i;
for (i=0; i<len; i++) {
if (i % 32 == 0) printk("\n%04x: ", i);
else if (i % 4 == 0) printk(" ");
printk("%02x", buf[i]);
}
printk("\n");
}
#endif
/*
* NAND controller always copies the data in 4 byte chunk, and in Big Endian mode
* from and to the flash.
* This routine assumes that dest and src are 4 byte aligned, and that len is a multiple of 4
(Restriction removed)
* TBD: 4/28/06: Remove restriction on count=512B, but do restrict the read from within a 512B section.
* Change nand_memcpy32 to be 2 functions, one to-flash, and one from-flash,
* enforcing reading from/writing to flash on a 4B boundary, but relaxing on the buffer being on 4 byte boundary.
*/
typedef union {
uint32_t u;
char c[4];
} u32_t;
#ifndef CONFIG_MTD_NAND_EDU
static int nand_from_flash_memcpy32(struct nand_chip* chip, void* dest, L_OFF_T offset, int len)
{
#if CONFIG_MTD_NAND_VERSION <= CONFIG_MTD_NAND_VERS_0_1
u_char* flash = chip->vbase + offset;
#else
volatile uint32_t* flash = (volatile uint32_t*) chip->vbase;
#endif
volatile uint32_t* pucDest = (volatile uint32_t*) dest;
volatile uint32_t* pucFlash = (volatile uint32_t*) flash;
int i;
#if 1
if (unlikely(((unsigned int) dest) & 0x3)) {
printk(KERN_ERR "nand_memcpy32 dest=%p not DW aligned\n", dest);
return -EINVAL;
}
if (unlikely(((unsigned int) flash) & 0x3)) {
printk(KERN_ERR "nand_memcpy32 src=%p not DW aligned\n", flash);
return -EINVAL;
}
if (unlikely(len & 0x3)) {
printk(KERN_ERR "nand_memcpy32 len=%d not DW aligned\n", len);
return -EINVAL;
}
#endif
#if 0
/*
* Take care of the leading odd bytes.
* Can't use memcpy here, because the flash contents are in BE order
*/
odd = (((unsigned long) pucFlash) & 0x3);
if (odd) {
printk("****** WARNING: leading odd bytes ************\n");
/* Guaranteed to be valid, since cache is on 512B boundary */
pSrc = (uint32_t*) (pucFlash - odd);
/* pSrc is now aligned on a DW boundary,
* no need to call cpu_to_be32 since we write and read from the same endian
*/
u32.u = /*cpu_to_be32 */(*pSrc);
for (i=0; i<odd; i++) {
pucDest[i] = u32.c[odd+i];
}
pucFlash += 4 - odd;
len += 4 - odd;
pucDest += 4 - odd;
}
/* Copy the aligned DWs */
pSrc = (uint32_t*) pucFlash;
pDest = (uint32_t*) pucDest;
#endif
#if 0
// THT 082808: FOr MLC, this codes still work, but for peace of mind, take it out.
// THT: Changed to use built-in kernel memcpy() to take advantage of Prefetch
if (gdebug) printk("%s: pucFlash=%p, len=%d\n", __FUNCTION__, pucFlash, len);
memcpy(pucDest, pucFlash, len);
#else
for (i=0; i< (len>>2); i++) {
pucDest[i] = /* THT 8/29/06 cpu_to_be32 */(pucFlash[i]);
}
#if 0
/*
* Take care of the trailing odd bytes.
* Can't use memcpy here, because the flash contents are in BE order
*/
odd = (len & 0x3);
if (odd) {
pucDest = (unsigned char*) pDest;
printk("****** WARNING: trailing odd bytes ************\n");
/* pSrc is now aligned on a DW boundary */
u32.u = /*cpu_to_be32 */ (*pSrc);
for (i=0; i<odd; i++) {
pucDest[i] = u32.c[odd+i];
}
}
#endif // Trailing odd bytes
#endif
return 0;
}
#endif // ifndef EDU
static int nand_to_flash_memcpy32(struct nand_chip* chip, L_OFF_T offset, const void* src, int len)
{
#if CONFIG_MTD_NAND_VERSION <= CONFIG_MTD_NAND_VERS_0_1
u_char* flash = chip->vbase + offset;
#else
u_char* flash = chip->vbase;
#endif
int i;
volatile uint32_t* pDest = (volatile uint32_t*) flash;
volatile uint32_t* pSrc = (volatile uint32_t*) src;
#if 1
if (unlikely((unsigned int) flash & 0x3)) {
printk(KERN_ERR "nand_memcpy32 dest=%p not DW aligned\n", flash);
return -EINVAL;
}
if (unlikely((unsigned int) src & 0x3)) {
printk(KERN_ERR "nand_memcpy32 src=%p not DW aligned\n", src);
return -EINVAL;
}
if (unlikely(len & 0x3)) {
printk(KERN_ERR "nand_memcpy32 len=%d not DW aligned\n", len);
return -EINVAL;
}
#endif
if (gdebug) printk("%s: flash=%p, len=%d, src=%p\n", __FUNCTION__, flash, len, src);
memcpy(flash, src, len);
#if 0
// THT Does not work for MLC when {FAST_PGM_RDIN, PARTIAL_PAGE_EN} = {0. 0}
// Use memcpy to take advantage of Prefetch
#else
for (i=0; i< (len>>2); i++) {
pDest[i] = /* THT: 8/29/06 cpu_to_be32 */ (pSrc[i]);
}
#endif
return 0;
}
#ifdef CONFIG_MTD_NAND_EDU
/*
* Returns 0: No errors
* 1: Correctable error
* -1: Uncorrectable error
*/
static int nand_verify_ecc(struct nand_chip* this, int state)
{
int err = 1; // 1 is no error, 2 is ECC correctable, 3 is EDU ECC correctable, -2 is ECC non-corr, -3 is EDU ECC non-corr
uint32_t intr;
uint32_t status = 0;
/* Only make sense on read */
if (state != FL_READING)
return 0;
intr = EDU_volatileRead(EDU_BASE_ADDRESS + BCHP_HIF_INTR2_CPU_STATUS);
#ifdef ECC_CORRECTABLE_SIMULATION
if(bEccCor)
{
intr |= BCHP_HIF_INTR2_CPU_STATUS_NAND_CORR_INTR_MASK;
}
#endif
#ifdef ECC_UNCORRECTABLE_SIMULATION
if(bEccUncor)
{
intr |= BCHP_HIF_INTR2_CPU_STATUS_NAND_UNC_INTR_MASK;
}
#endif
// Maybe an EDU BUG?
if ((intr & BCHP_HIF_INTR2_CPU_STATUS_EDU_ERR_INTR_MASK) != 0x00000000)
{
//Check EDU_ERR_STATUS:
status = EDU_volatileRead(EDU_BASE_ADDRESS + EDU_ERR_STATUS);
if((status & EDU_ERR_STATUS_NandECCuncor) != 0x00000000)
{
// EDU saw and NANDECCUNCORRERROR
err = EDU_UNCORRECTABLE_ECC_ERROR;
}
if((status & EDU_ERR_STATUS_NandECCcor) != 0x00000000)
{
err = EDU_CORRECTABLE_ECC_ERROR;
}
}
if ((intr & BCHP_HIF_INTR2_CPU_STATUS_NAND_CORR_INTR_MASK) != 0x00000000)
{
#if CONFIG_MTD_NAND_VERSION >= CONFIG_MTD_NAND_VERS_1_0
// Clear it
this->ctrl_write(BCHP_NAND_ECC_CORR_EXT_ADDR, 0);
#endif
// Clear it
this->ctrl_write(BCHP_NAND_ECC_CORR_ADDR, 0);
err = NAND_CORRECTABLE_ECC_ERROR;
// Clear the interrupt for next time
EDU_volatileWrite(EDU_BASE_ADDRESS + BCHP_HIF_INTR2_CPU_CLEAR, BCHP_HIF_INTR2_CPU_CLEAR_NAND_CORR_INTR_MASK);
}
if ((intr & BCHP_HIF_INTR2_CPU_STATUS_NAND_UNC_INTR_MASK) != 0x00000000)
{
#if CONFIG_MTD_NAND_VERSION >= CONFIG_MTD_NAND_VERS_1_0
// Clear it
this->ctrl_write(BCHP_NAND_ECC_UNC_EXT_ADDR, 0);
#endif
this->ctrl_write(BCHP_NAND_ECC_UNC_ADDR, 0);
/*
* If the block was just erased, and have not yet been written to, this will be flagged,
* so this could be a false alarm
*/
err = NAND_UNCORRECTABLE_ECC_ERROR;
// Clear the interrupt for next time
EDU_volatileWrite(EDU_BASE_ADDRESS + BCHP_HIF_INTR2_CPU_CLEAR, BCHP_HIF_INTR2_CPU_CLEAR_NAND_UNC_INTR_MASK);
}
return err;
}
#else
/*
* Returns 0: NAND_SUCCESS: No errors
* 1: Correctable error
* -1: Uncorrectable error
*/
static int nand_verify_ecc(struct nand_chip* chip, int state)
{
int err = 0;
uint32_t addr;
uint32_t extAddr = 0;
/* Only make sense on read */
if (state != FL_READING)
return NAND_SUCCESS;
addr = chip->ctrl_read(BCHP_NAND_ECC_CORR_ADDR);
if (addr) {
#if CONFIG_MTD_NAND_VERSION >= CONFIG_MTD_NAND_VERS_1_0
extAddr = chip->ctrl_read(BCHP_NAND_ECC_CORR_EXT_ADDR);
// Clear it
chip->ctrl_write(BCHP_NAND_ECC_CORR_EXT_ADDR, 0);
#endif
// Clear it
chip->ctrl_write(BCHP_NAND_ECC_CORR_ADDR, 0);
printk(KERN_WARNING "%s: Correctable ECC error at %08x:%08x\n", __FUNCTION__, extAddr, addr);
err = NAND_CORRECTABLE_ECC_ERROR;
}
addr = chip->ctrl_read(BCHP_NAND_ECC_UNC_ADDR);
if (addr) {
#if CONFIG_MTD_NAND_VERSION >= CONFIG_MTD_NAND_VERS_1_0
extAddr = chip->ctrl_read(BCHP_NAND_ECC_UNC_EXT_ADDR);
// Clear it
chip->ctrl_write(BCHP_NAND_ECC_UNC_EXT_ADDR, 0);
#endif
chip->ctrl_write(BCHP_NAND_ECC_UNC_ADDR, 0);
/*
* If the block was just erased, and have not yet been written to, this will be flagged,
* so this could be a false alarm
*/
err = NAND_UNCORRECTABLE_ECC_ERROR;
}
return err;
}
#endif //#ifdef CONFIG_MTD_NAND_EDU
/**
* nand_wait - [DEFAULT] wait until the command is done
* @param mtd MTD device structure
* @param state state to select the max. timeout value
*
* Wait for command done. This applies to all NAND command
* Read can take up to 53, erase up to ?s and program up to 30 clk cycle ()
* according to general NAND specs
*/
static int nand_wait(struct mtd_info *mtd, int state, uint32_t* pStatus)
{
struct nand_chip * chip = mtd->priv;
unsigned long timeout;
uint32_t ready;
/* The 20 msec is enough */
timeout = jiffies + msecs_to_jiffies(3000); // THT: 3secs, for now
while (time_before(jiffies, timeout)) {
PLATFORM_IOFLUSH_WAR();
ready = chip->ctrl_read(BCHP_NAND_INTFC_STATUS);
if (ready & BCHP_NAND_INTFC_STATUS_CTLR_READY_MASK) {
*pStatus = ready;
return 0;
}
if (state != FL_READING)
cond_resched();
//touch_softlockup_watchdog();
}
/*
* Get here on timeout
*/
return -ETIMEDOUT;
}
/*
* Returns 1: Success, correctable errors
* 0: Success
* -1: Uncorectable error
* -2: Block is bad, returned from flash Status.
* -3: Timed out
*/
static int nand_cache_is_valid(struct mtd_info* mtd, int state, L_OFF_T offset)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -