Vladimir Zapolskiy | 78f04f0 | 2015-07-18 03:07:52 +0300 | [diff] [blame] | 1 | /* |
| 2 | * LPC32xx SLC NAND flash controller driver |
| 3 | * |
| 4 | * (C) Copyright 2015 Vladimir Zapolskiy <vz@mleia.com> |
| 5 | * |
| 6 | * SPDX-License-Identifier: GPL-2.0+ |
| 7 | */ |
| 8 | |
| 9 | #include <common.h> |
| 10 | #include <nand.h> |
| 11 | #include <asm/errno.h> |
| 12 | #include <asm/io.h> |
| 13 | #include <asm/arch/clk.h> |
| 14 | #include <asm/arch/sys_proto.h> |
| 15 | |
| 16 | struct lpc32xx_nand_slc_regs { |
| 17 | u32 data; |
| 18 | u32 addr; |
| 19 | u32 cmd; |
| 20 | u32 stop; |
| 21 | u32 ctrl; |
| 22 | u32 cfg; |
| 23 | u32 stat; |
| 24 | u32 int_stat; |
| 25 | u32 ien; |
| 26 | u32 isr; |
| 27 | u32 icr; |
| 28 | u32 tac; |
| 29 | u32 tc; |
| 30 | u32 ecc; |
| 31 | u32 dma_data; |
| 32 | }; |
| 33 | |
| 34 | /* CFG register */ |
| 35 | #define CFG_CE_LOW (1 << 5) |
| 36 | |
| 37 | /* CTRL register */ |
| 38 | #define CTRL_SW_RESET (1 << 2) |
| 39 | |
| 40 | /* STAT register */ |
| 41 | #define STAT_NAND_READY (1 << 0) |
| 42 | |
| 43 | /* INT_STAT register */ |
| 44 | #define INT_STAT_TC (1 << 1) |
| 45 | #define INT_STAT_RDY (1 << 0) |
| 46 | |
| 47 | /* TAC register bits, be aware of overflows */ |
| 48 | #define TAC_W_RDY(n) (max_t(uint32_t, (n), 0xF) << 28) |
| 49 | #define TAC_W_WIDTH(n) (max_t(uint32_t, (n), 0xF) << 24) |
| 50 | #define TAC_W_HOLD(n) (max_t(uint32_t, (n), 0xF) << 20) |
| 51 | #define TAC_W_SETUP(n) (max_t(uint32_t, (n), 0xF) << 16) |
| 52 | #define TAC_R_RDY(n) (max_t(uint32_t, (n), 0xF) << 12) |
| 53 | #define TAC_R_WIDTH(n) (max_t(uint32_t, (n), 0xF) << 8) |
| 54 | #define TAC_R_HOLD(n) (max_t(uint32_t, (n), 0xF) << 4) |
| 55 | #define TAC_R_SETUP(n) (max_t(uint32_t, (n), 0xF) << 0) |
| 56 | |
| 57 | static struct lpc32xx_nand_slc_regs __iomem *lpc32xx_nand_slc_regs |
| 58 | = (struct lpc32xx_nand_slc_regs __iomem *)SLC_NAND_BASE; |
| 59 | |
| 60 | static void lpc32xx_nand_init(void) |
| 61 | { |
| 62 | uint32_t hclk = get_hclk_clk_rate(); |
| 63 | |
| 64 | /* Reset SLC NAND controller */ |
| 65 | writel(CTRL_SW_RESET, &lpc32xx_nand_slc_regs->ctrl); |
| 66 | |
| 67 | /* 8-bit bus, no DMA, no ECC, ordinary CE signal */ |
| 68 | writel(0, &lpc32xx_nand_slc_regs->cfg); |
| 69 | |
| 70 | /* Interrupts disabled and cleared */ |
| 71 | writel(0, &lpc32xx_nand_slc_regs->ien); |
| 72 | writel(INT_STAT_TC | INT_STAT_RDY, |
| 73 | &lpc32xx_nand_slc_regs->icr); |
| 74 | |
| 75 | /* Configure NAND flash timings */ |
| 76 | writel(TAC_W_RDY(CONFIG_LPC32XX_NAND_SLC_WDR_CLKS) | |
| 77 | TAC_W_WIDTH(hclk / CONFIG_LPC32XX_NAND_SLC_WWIDTH) | |
| 78 | TAC_W_HOLD(hclk / CONFIG_LPC32XX_NAND_SLC_WHOLD) | |
| 79 | TAC_W_SETUP(hclk / CONFIG_LPC32XX_NAND_SLC_WSETUP) | |
| 80 | TAC_R_RDY(CONFIG_LPC32XX_NAND_SLC_RDR_CLKS) | |
| 81 | TAC_R_WIDTH(hclk / CONFIG_LPC32XX_NAND_SLC_RWIDTH) | |
| 82 | TAC_R_HOLD(hclk / CONFIG_LPC32XX_NAND_SLC_RHOLD) | |
| 83 | TAC_R_SETUP(hclk / CONFIG_LPC32XX_NAND_SLC_RSETUP), |
| 84 | &lpc32xx_nand_slc_regs->tac); |
| 85 | } |
| 86 | |
| 87 | static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, |
| 88 | int cmd, unsigned int ctrl) |
| 89 | { |
| 90 | debug("ctrl: 0x%08x, cmd: 0x%08x\n", ctrl, cmd); |
| 91 | |
| 92 | if (ctrl & NAND_NCE) |
| 93 | setbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_CE_LOW); |
| 94 | else |
| 95 | clrbits_le32(&lpc32xx_nand_slc_regs->cfg, CFG_CE_LOW); |
| 96 | |
| 97 | if (cmd == NAND_CMD_NONE) |
| 98 | return; |
| 99 | |
| 100 | if (ctrl & NAND_CLE) |
| 101 | writel(cmd & 0xFF, &lpc32xx_nand_slc_regs->cmd); |
| 102 | else if (ctrl & NAND_ALE) |
| 103 | writel(cmd & 0xFF, &lpc32xx_nand_slc_regs->addr); |
| 104 | } |
| 105 | |
| 106 | static int lpc32xx_nand_dev_ready(struct mtd_info *mtd) |
| 107 | { |
| 108 | return readl(&lpc32xx_nand_slc_regs->stat) & STAT_NAND_READY; |
| 109 | } |
| 110 | |
| 111 | static void lpc32xx_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
| 112 | { |
| 113 | while (len-- > 0) |
| 114 | *buf++ = readl(&lpc32xx_nand_slc_regs->data); |
| 115 | } |
| 116 | |
| 117 | static uint8_t lpc32xx_read_byte(struct mtd_info *mtd) |
| 118 | { |
| 119 | return readl(&lpc32xx_nand_slc_regs->data); |
| 120 | } |
| 121 | |
| 122 | static void lpc32xx_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
| 123 | { |
| 124 | while (len-- > 0) |
| 125 | writel(*buf++, &lpc32xx_nand_slc_regs->data); |
| 126 | } |
| 127 | |
| 128 | static void lpc32xx_write_byte(struct mtd_info *mtd, uint8_t byte) |
| 129 | { |
| 130 | writel(byte, &lpc32xx_nand_slc_regs->data); |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | * LPC32xx has only one SLC NAND controller, don't utilize |
| 135 | * CONFIG_SYS_NAND_SELF_INIT to be able to reuse this function |
| 136 | * both in SPL NAND and U-boot images. |
| 137 | */ |
| 138 | int board_nand_init(struct nand_chip *lpc32xx_chip) |
| 139 | { |
| 140 | lpc32xx_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; |
| 141 | lpc32xx_chip->dev_ready = lpc32xx_nand_dev_ready; |
| 142 | |
| 143 | /* |
| 144 | * Hardware ECC calculation is not supported by the driver, |
| 145 | * because it requires DMA support, see LPC32x0 User Manual, |
| 146 | * note after SLC_ECC register description (UM10326, p.198) |
| 147 | */ |
| 148 | lpc32xx_chip->ecc.mode = NAND_ECC_SOFT; |
| 149 | |
| 150 | /* |
| 151 | * The implementation of these functions is quite common, but |
| 152 | * they MUST be defined, because access to data register |
| 153 | * is strictly 32-bit aligned. |
| 154 | */ |
| 155 | lpc32xx_chip->read_buf = lpc32xx_read_buf; |
| 156 | lpc32xx_chip->read_byte = lpc32xx_read_byte; |
| 157 | lpc32xx_chip->write_buf = lpc32xx_write_buf; |
| 158 | lpc32xx_chip->write_byte = lpc32xx_write_byte; |
| 159 | |
| 160 | /* |
| 161 | * Use default ECC layout, but these values are predefined |
| 162 | * for both small and large page NAND flash devices. |
| 163 | */ |
| 164 | lpc32xx_chip->ecc.size = 256; |
| 165 | lpc32xx_chip->ecc.bytes = 3; |
| 166 | lpc32xx_chip->ecc.strength = 1; |
| 167 | |
| 168 | #if defined(CONFIG_SYS_NAND_USE_FLASH_BBT) |
| 169 | lpc32xx_chip->bbt_options |= NAND_BBT_USE_FLASH; |
| 170 | #endif |
| 171 | |
| 172 | /* Initialize NAND interface */ |
| 173 | lpc32xx_nand_init(); |
| 174 | |
| 175 | return 0; |
| 176 | } |