nand: lpc32xx: add SLC NAND controller support
[karo-tx-uboot.git] / drivers / mtd / nand / lpc32xx_nand_slc.c
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 }