uint8_t * nand_read_id(nand_port *nandp) { nand_enable(nandp); NAND_COMMAND(nandp, 0x90); /* follow by address - 0 */ *(nandp->cont_port) |= NAND_CONT_ALE; NAND_IO_SET(nandp, 0x00); *(nandp->cont_port) &= ~NAND_CONT_ALE; NAND_IO_INPUT(nandp); NAND_IO_READ(nandp, device_id[0]); NAND_IO_READ(nandp, device_id[1]); /* hynix */ if (device_id[0] == 0xAD && device_id[1] == 0x73) { /* hynix flash device */ PAGE_SZ = 512; NBLOCKS = 1024; PAGES_PER_BLOCK = 32; PAGE_PLUS_RAS_SZ = PAGE_SZ+16; BLOCK_SZ = PAGES_PER_BLOCK * PAGE_SZ; return device_id; } /* samsung */ if (device_id[0] == 0xEC) { NAND_IO_READ(nandp, device_id[2]); NAND_IO_READ(nandp, device_id[3]); NBLOCKS = 1024; PAGE_SZ = (device_id[3] & 0x1) ? 2048 : 1024; /* !! 2048 */ switch ( ((device_id[3] >> 4) & 0x3) ) { case 0: BLOCK_SZ = (uint32_t)64 * (uint32_t)1024; break; case 1: BLOCK_SZ = (uint32_t)128 * (uint32_t)1024; /* should be 128 !! */ break; case 2: BLOCK_SZ = (uint32_t)256 * (uint32_t)1024; break; } // PAGE_PLUS_RAS_SZ = PAGE_SZ + ((device_id[3] & 4) ? (16 * (PAGE_SZ/512)) : (8 * (PAGE_SZ/512))); PAGE_PLUS_RAS_SZ = 2112; PAGES_PER_BLOCK = BLOCK_SZ / PAGE_SZ; /* !! 64 */ return device_id; }
//mtd子系统有对nand的请求时候调用 void nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) { struct nand_info *nand = container_of(mtd, struct nand_info, mtd); if(ctrl & NAND_CTRL_CHANGE){ if(ctrl & NAND_NCE) nand_enable(nand); else nand_disable(nand); } if(dat != NAND_CMD_NONE){ if(ctrl & NAND_CLE) writeb(dat, nand->virt + NFCMMD); else if(ctrl & NAND_ALE) writeb(dat, nand->virt + NFADDR); } }
void nand_init(struct nand_info *nand) { u32 tmp; //配置nand时序 tmp = TACLS | TWRPH0 | TWRPH1 | MUST1; writel(tmp, nand->virt + NFCONF); //打开nand控制器,并把nand芯片的片选无效 tmp = CSN2_DIS | CTROLLER_EN; writel(tmp, nand->virt + NFCONT); //打开nand片选 nand_enable(nand); //发送重启命令 writel(RESET_CMD, nand->virt + NFCMMD); while(!(nand_dev_ready(&nand->mtd))); //关掉nand芯片的片选 nand_disable(nand); }
/** * jz_nemc_ctrl_select - * @nand_nce: */ int jz_nemc_ctrl_select(NAND_BASE *host,void *pnand_io,int nand_nce) { JZ_IO *p_io = (JZ_IO *)pnand_io; unsigned int i=0,ret=0; if ((nand_nce >= g_maxchips) || (nand_nce == -1)) { nemc_writel(host->nemc_iomem,NEMC_NFCSR,0); return -1; /*bigger than support, or unselect all chips*/ } while(ret <= nand_nce && ret < NEMC_CS_COUNT) { if(g_chips_mark[i]) ret++; i++; } switch(i){ case 1: p_io->dataport = (void *)(host->nemc_cs6_iomem + 5 * 0x01000000); nand_enable(host,1); ret =1; break; case 2: p_io->dataport = (void *)(host->nemc_cs6_iomem + 4 * 0x01000000); nand_enable(host,2); ret =2; break; case 3: p_io->dataport = (void *)(host->nemc_cs6_iomem + 3 * 0x01000000); nand_enable(host,3); ret =3; break; case 4: p_io->dataport = (void *)(host->nemc_cs6_iomem + 2 * 0x01000000); nand_enable(host,4); ret =4; break; case 5: p_io->dataport = (void *)(host->nemc_cs6_iomem + 1 * 0x01000000); nand_enable(host,5); ret =5; break; case 6: p_io->dataport = (void *)(host->nemc_cs6_iomem + 0 * 0x01000000); nand_enable(host,6); ret =6; break; default: eprintf("error: no nand_nce 0x%x\n",nand_nce); ret = -1; break; } #ifdef CONFIG_TOGGLE_NAND switch(i){ case 1: tnand_enable(host,1); break; case 2: tnand_enable(host,2); break; case 3: tnand_enable(host,3); break; case 4: tnand_enable(host,4); break; case 5: tnand_enable(host,5); break; case 6: tnand_enable(host,6); break; default: eprintf(1,"error: no nand_nce 0x%x\n",nand_nce); break; } #endif p_io->cmdport = p_io->dataport + NAND_CMD_OFFSET; p_io->addrport = p_io->dataport + NAND_ADDR_OFFSET; // dprintf("DEBUG nand: jz_nemc_ctrl_select i = %d , p_io->dataport = 0x%x\n",i,(unsigned int)p_io->dataport); return ret; }