#include struct NAND_Setup { uint32_t ddrMode; uint32_t ddrSetupA; uint32_t ddrSetupB; uint32_t pageSize; /* in kB */ uint32_t addrBytes; uint32_t eccBits; uint32_t smallEccPage; /* 1 - use 512-byte ECC */ }; static struct CCU_regs { uint32_t _rsvd1[24]; uint32_t AHB_GATING0; /* 0x060 */ uint32_t _rsvd2[7]; uint32_t NAND_SCLK_CFG; /* 0x080 */ } *CCU = (struct CCU_regs *)0x01C20000; static struct NFC_regs { uint32_t CTL; /* 0x00 */ uint32_t ST; /* 0x04 */ uint32_t INT; /* 0x08 */ uint32_t TIMING_CTL; /* 0x0c */ uint32_t TIMING_CFG; /* 0x10 */ uint32_t ADDR_LOW; /* 0x14 */ uint32_t ADDR_HIGH; /* 0x18 */ uint32_t SECTOR_NUM; /* 0x1c */ uint32_t CNT; /* 0x20 */ uint32_t CMD; /* 0x24 */ uint32_t READ_CMD_SET; /* 0x28 */ uint32_t WRITE_CMD_SET; /* 0x2c */ uint32_t IO_DATA; /* 0x30 */ uint32_t ECC_CTL; /* 0x34 */ uint32_t ECC_ST; /* 0x38 */ uint32_t DEBUG; /* 0x3c */ uint32_t ECC_COUNT[4]; /* 0x40 */ uint32_t ECC_USER_DB[16]; /* 0x50 */ uint32_t _rsvd[4]; uint32_t SPARE_AREA; /* 0xA0 */ } *NFC = (struct NFC_regs *)0x01C03000; static struct DMA_regs { uint32_t IRQ_EN; /* 0x000 */ uint32_t IRQ_PEND_STA; /* 0x004 */ uint32_t NDMA_AUTO_GAT; /* 0x008 */ uint32_t _rsvd1[61]; struct { uint32_t CTRL; /* 0x100 + 0x20*i */ uint32_t SRC; /* 0x104 + 0x20*i */ uint32_t DEST; /* 0x108 + 0x20*i */ uint32_t BC; /* 0x10C + 0x20*i */ uint32_t _rsvd[4]; } NDMA[8]; uint32_t _rsvd2[64]; struct { uint32_t CFG; /* 0x300 + 0x20*i */ uint32_t SRC; /* 0x304 + 0x20*i */ uint32_t DEST; /* 0x308 + 0x20*i */ uint32_t BC; /* 0x30C + 0x20*i */ uint32_t _rsvd1[2]; uint32_t PARA; /* 0x318 + 0x20*i */ uint32_t _rsvd2; } DDMA[8]; } *DMA = (struct DMA_regs *)0x01C02000; #define DDMA_CFG_LOADING (1 << 31) #define NFC_CTL_EN (1 << 0) #define NFC_CTL_RESET (1 << 1) #define NFC_CTL_BUS_WIDTH (1 << 2) #define NFC_CTL_RB_SEL (1 << 3) #define NFC_CTL_CE0 (1 << 6) #define NFC_CTL_CE1 (1 << 7) #define NFC_CTL_PAGE(x) ((x) << 8) #define NFC_CTL_PAGE_BITS (15 << 8) #define NFC_CTL_SAM (1 << 12) #define NFC_CTL_RAM_METHOD (1 << 14) #define NFC_CTL_DDR_TYPE(x) ((x) << 18) #define NFC_CTL_DDR_TYPE_BITS (3 << 18) #define NFC_CTL_REPEAT_MODE (1 << 20) #define NFC_CTL_CE_SEL(x) ((x) << 24) #define NFC_CMD_TYPE(x) ((x) << 30) #define NFC_SEND_CMD3 (1 << 29) #define NFC_SEND_CMD2 (1 << 28) #define NFC_ROW_AUTO_INC (1 << 27) #define NFC_DATA_SWAP_METHOD (1 << 26) #define NFC_SEQ (1 << 25) #define NFC_SEND_CMD1 (1 << 24) #define NFC_WAIT_FLAG (1 << 23) #define NFC_SEND_CMD0 (1 << 22) #define NFC_DATA_TRANS (1 << 21) #define NFC_XS_DIR (1 << 20) #define NFC_SEND_ADDR (1 << 19) #define NFC_ADDR_NUM(x) ((x) << 16) #define NFC_CMD_HIGH(x) ((x) << 8) #define NFC_CMD_LOW(x) ((x) << 0) #define NFC_CMD_INT_FLAG (1 << 1) #define NFC_DMA_INT_FLAG (1 << 2) #define NFC_CMD_FIFO_STAT (1 << 3) #define NFC_ECC_ENABLE (1 << 0) #define NFC_ECC_PIPELINE (1 << 3) #define NFC_ECC_EXCEPTION (1 << 4) #define NFC_ECC_BLOCK_SIZE(x) ((x) << 5) #define NFC_ECC_RANDOM (1 << 9) #define NFC_ECC_RANDOM_DIR (1 << 10) #define NFC_ECC_MODE(x) ((x) << 12) #define NFC_ECC_RANDOM_SEED(x) ((x) << 16) #define AHB_GATING0_NAND (1 << 13) #define AHB_GATING0_DMA (1 << 6) #define SCLK_CFG_GATING (1 << 31) #define SCLK_CFG_SRC_SEL_BITS (3 << 24) #define SCLK_CFG_DIV_N_BITS (3 << 16) #define SCLK_CFG_DIV_M_BITS (15 << 0) #define SCLK_CFG_DIV_M(x) ((x) - 1) #define BROM_ECC_SEED 0x4A80 static unsigned ilog2(unsigned a) { unsigned i = 0; for(i=0; i<16; i++) if((a >> i) & 1) return i; return 31; } static void delay_loop(unsigned loops) { while(loops--) asm ("nop\n"); } static inline void iormw32(void *ptr, uint32_t clear, uint32_t set) { uint32_t tmp = *(volatile uint32_t *)ptr; tmp = (tmp & ~clear) | set; *(volatile uint32_t *)ptr = tmp; } static inline void iowrite32(void *ptr, uint32_t data) { *(volatile uint32_t *)ptr = data; } static inline uint32_t ioread32(void *ptr) { return *(volatile uint32_t *)ptr; } void NAND_PrepareChip(void) { /* initialize I/Os here */ /* clock setup */ iormw32(&(CCU->AHB_GATING0), 0, AHB_GATING0_NAND | AHB_GATING0_DMA); iormw32(&(CCU->NAND_SCLK_CFG), SCLK_CFG_GATING | SCLK_CFG_SRC_SEL_BITS | SCLK_CFG_DIV_N_BITS | SCLK_CFG_DIV_M_BITS, SCLK_CFG_DIV_M(2)); iormw32(&(CCU->NAND_SCLK_CFG), 0, SCLK_CFG_GATING); iowrite32(&(NFC->CTL), NFC_CTL_EN | NFC_CTL_RESET); delay_loop(240); iowrite32(&(NFC->CTL), NFC_CTL_EN); } static int NAND_WaitFIFOBusy(unsigned loops) { while(loops--) if(!(ioread32(&(DMA->DDMA[0].CFG)) & DDMA_CFG_LOADING)) return 0; return 1; } static int NAND_WaitDMABusy(unsigned loops) { while(loops--) if(!(ioread32(&(NFC->ST)) & NFC_CMD_FIFO_STAT)) return 0; return 1; } static int NAND_WaitCmdBusy(unsigned loops) { while(loops--) if(ioread32(&(NFC->ST)) & NFC_CMD_INT_FLAG) return 0; return 1; } static int NAND_ResetController(void) { iowrite32(&(NFC->CMD), NFC_WAIT_FLAG | NFC_SEND_CMD0 | NFC_CMD_LOW(0xFF)); if(NAND_WaitFIFOBusy(4800)) return 1; if(NAND_WaitCmdBusy(4920)) return 1; return 0; } int NAND_SetupController(struct NAND_Setup *setup) { static const char eccModeMap[] = { 9, 9, 9, 9, 0, 9, 1, 2, 3, 9, 4, 9, 5, 9, 6, 7, 8 }; /* 16 24 28 32 40 48 56 60 64 */ if((setup->eccBits & 3) || (setup->eccBits > 64) || (eccModeMap[setup->eccBits >> 2] > 8)) return 1; if(NAND_ResetController()) return 1; iowrite32(&(NFC->ECC_CTL), NFC_ECC_RANDOM_SEED(BROM_ECC_SEED) | NFC_ECC_RANDOM | NFC_ECC_ENABLE | NFC_ECC_BLOCK_SIZE(setup->smallEccPage) | NFC_ECC_MODE(eccModeMap[setup->eccBits >> 2])); iormw32(&(NFC->CTL), NFC_CTL_BUS_WIDTH | NFC_CTL_PAGE_BITS | NFC_CTL_DDR_TYPE_BITS, NFC_CTL_DDR_TYPE(setup->ddrMode) | NFC_CTL_PAGE(ilog2(setup->pageSize)) | NFC_CTL_RAM_METHOD); iormw32(&(NFC->TIMING_CTL), 0xF3F, setup->ddrMode ? ((setup->ddrSetupA << 8) | setup->ddrSetupB) : 0); iowrite32(&(NFC->SPARE_AREA), setup->pageSize << 10); return 0; } static void NAND_SetupDMA(void *dstBuf, unsigned bytes) { iowrite32(&(DMA->DDMA[0].SRC), (uint32_t)&(NFC->IO_DATA)); iowrite32(&(DMA->DDMA[0].DEST), (uint32_t)dstBuf); iowrite32(&(DMA->DDMA[0].PARA), 0x7F0F); iowrite32(&(DMA->DDMA[0].BC), bytes); iowrite32(&(DMA->DDMA[0].CFG), DDMA_CFG_LOADING | 0x4000423); } static int NAND_WaitBusy(unsigned loops) { if(NAND_WaitFIFOBusy(loops)) return 1; if(NAND_WaitCmdBusy(loops)) return 1; return NAND_WaitDMABusy(loops); } int NAND_LoadPage(uint32_t pageAddr, void *dstBuf, int addrBytes, int pageSize, int smallEccPage) { int err = 1; iowrite32(&(NFC->READ_CMD_SET), 0xE00530); NAND_SetupDMA(dstBuf, pageSize << 10); iowrite32(&(NFC->SECTOR_NUM), pageSize << smallEccPage); if(NAND_WaitFIFOBusy(4888)) goto failure; iowrite32(&(NFC->ADDR_LOW), pageAddr << 16); iowrite32(&(NFC->ADDR_HIGH), pageAddr >> 16); iowrite32(&(NFC->CMD), NFC_CMD_TYPE(2) | NFC_SEND_ADDR | NFC_DATA_TRANS | NFC_SEND_CMD0 | NFC_WAIT_FLAG | NFC_DATA_SWAP_METHOD | NFC_SEQ | NFC_SEND_CMD1 | NFC_ADDR_NUM(addrBytes - 1)); if(NAND_WaitBusy(4800 + 22*pageSize)) goto failure; if(ioread32(&(NFC->ECC_ST)) & ((1 << (pageSize << smallEccPage)) - 1)) { err = 2; goto failure; } err = 0; failure: iormw32(&(DMA->DDMA[0].CFG), DDMA_CFG_LOADING, 0); return err; }