⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand_base.c

📁 this is for nand controller
💻 C
📖 第 1 页 / 共 5 页
字号:
#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 + -