最近在升级u-boot,从1.1.4升级到1.3.3,原因是想用Linux的MTD层和nand驱动,方便管理坏块。 可是一个问题困扰了一整天,NAND初始化总是不正确,经过排查,定位到读ID不正确。 4020这颗芯片读ID应该很简单的,只要发送0x80000090命令,再读取EMI的NAND_ID寄存器就行了,可我怎么用了一整天都读不正确呢?于是写了一段最简单的代码来验证: 首先是ADS的代码: tempnand = (*(volatile unsigned long*)EMI_NAND_ID)>>8; 发现读取是正确的。 然后是Linux下的代码: *(unsigned long*)INTC_IMR_V = 0XFFFFFFFF; *(unsigned long*)INTC_IMR_V = 0X00000000; *(unsigned long*)EMI_NAND_CONF1_V = 0x06302857; *(unsigned long*)EMI_NAND_CONF2_V = 0x00514353;
*(unsigned long*)GPIO_PORTG_SEL_V |= 0x0080; *(unsigned long*)GPIO_PORTG_DATA_V |= 0x0080; *(unsigned long*)GPIO_PORTG_DIR_V &= ~0x0080;
*(unsigned long*)EMI_NAND_COM_V = 0X00000090; *(unsigned long*)EMI_NAND_COM_V |= 0X80000000; unsigned int tempnand = (*(volatile unsigned long*)EMI_NAND_ID_V)>>8; printk("read id! id is 0x%x,0x%x\n\n",tempnand,EMI_NAND_ID_V ); 启动时发现,tempnand的值为0; 最后是u-boot的代码: *(unsigned long*)INTC_IMR_V = 0XFFFFFFFF; *(unsigned long*)INTC_IMR_V = 0X00000000; *(unsigned long*)EMI_NAND_CONF1_V = 0x06302857; *(unsigned long*)EMI_NAND_CONF2_V = 0x00514353;
*(unsigned long*)GPIO_PORTG_SEL_V |= 0x0080; *(unsigned long*)GPIO_PORTG_DATA_V |= 0x0080; *(unsigned long*)GPIO_PORTG_DIR_V &= ~0x0080;
*(unsigned long*)EMI_NAND_COM_V = 0X00000090; *(unsigned long*)EMI_NAND_COM_V |= 0X80000000; unsigned int tempnand = (EMI_NAND_ID)>>8; 打印的值更诡异,竟然是0x800000。
奇怪吧,容我解释逐条解释原因: 1)Linux的代码,在加上volatile后,顺利的读出了ID,难道这就是传说中的因为没加volatile,同一个寄存器赋值两次,被优化掉了!!!??? 2)怀疑u-boot代码也是volatile原因,在添加后,依然不成功? 3)仔细看u-boot的寄存器定义: #define EMI_NAND_ID (REGW(EMI_BASE+0X130)) 比Linux多了个REGW,这个REGW是什么东西??? 翻到上面,赫然看到: #define REGW(addr) (*(volatile unsigned int *)(addr)) 晕,人家都加好了,再加一遍,数据能对就怪了! 附修改后的代码: Linux: *(volatile unsigned long*)INTC_IMR_V = 0XFFFFFFFF; *(volatile unsigned long*)INTC_IMR_V = 0X00000000; *(volatile unsigned long*)EMI_NAND_CONF1_V = 0x06302857; *(volatile unsigned long*)EMI_NAND_CONF2_V = 0x00514353; *(volatile unsigned long*)GPIO_PORTG_SEL_V |= 0x0080; *(volatile unsigned long*)GPIO_PORTG_DATA_V |= 0x0080; *(volatile unsigned long*)GPIO_PORTG_DIR_V &= ~0x0080;
*(volatile unsigned long*)EMI_NAND_COM_V = 0X00000090; *(volatile unsigned long*)EMI_NAND_COM_V |= 0X80000000; printk("read id! id is 0x%x,0x%x\n\n",tempnand,EMI_NAND_ID_V );
u-boot: INTC_IMR = 0XFFFFFFFF; INTC_IMR = 0X00000000; EMI_NAND_CONF1 = 0x06302857; EMI_NAND_CONF2 = 0x00514353; GPIO_PORTG_SEL |= 0x0080; GPIO_PORTG_DATA |= 0x0080; GPIO_PORTG_DIR &= ~0x0080; EMI_NAND_COM = 0X00000090;
|