1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2017 Yifeng Zhao <yifeng.zhao@rock-chips.com>
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <dm.h>
9*4882a593Smuzhiyun #include <fdtdec.h>
10*4882a593Smuzhiyun #include <fdt_support.h>
11*4882a593Smuzhiyun #include <inttypes.h>
12*4882a593Smuzhiyun #include <nand.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
15*4882a593Smuzhiyun #include <linux/mtd/nand.h>
16*4882a593Smuzhiyun #include <linux/mtd/partitions.h>
17*4882a593Smuzhiyun #include <linux/io.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define NANDC_V6_BOOTROM_ECC 24
22*4882a593Smuzhiyun #define NANDC_V6_NUM_BANKS 4
23*4882a593Smuzhiyun #define NANDC_V6_DEF_TIMEOUT 20000
24*4882a593Smuzhiyun #define NANDC_V6_READ 0
25*4882a593Smuzhiyun #define NANDC_V6_WRITE 1
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define NANDC_REG_V6_FMCTL 0x00
28*4882a593Smuzhiyun #define NANDC_REG_V6_FMWAIT 0x04
29*4882a593Smuzhiyun #define NANDC_REG_V6_FLCTL 0x08
30*4882a593Smuzhiyun #define NANDC_REG_V6_BCHCTL 0x0c
31*4882a593Smuzhiyun #define NANDC_REG_V6_DMA_CFG 0x10
32*4882a593Smuzhiyun #define NANDC_REG_V6_DMA_BUF0 0x14
33*4882a593Smuzhiyun #define NANDC_REG_V6_DMA_BUF1 0x18
34*4882a593Smuzhiyun #define NANDC_REG_V6_DMA_ST 0x1C
35*4882a593Smuzhiyun #define NANDC_REG_V6_BCHST 0x20
36*4882a593Smuzhiyun #define NANDC_REG_V6_RANDMZ 0x150
37*4882a593Smuzhiyun #define NANDC_REG_V6_VER 0x160
38*4882a593Smuzhiyun #define NANDC_REG_V6_INTEN 0x16C
39*4882a593Smuzhiyun #define NANDC_REG_V6_INTCLR 0x170
40*4882a593Smuzhiyun #define NANDC_REG_V6_INTST 0x174
41*4882a593Smuzhiyun #define NANDC_REG_V6_SPARE0 0x200
42*4882a593Smuzhiyun #define NANDC_REG_V6_SPARE1 0x230
43*4882a593Smuzhiyun #define NANDC_REG_V6_BANK0 0x800
44*4882a593Smuzhiyun #define NANDC_REG_V6_SRAM0 0x1000
45*4882a593Smuzhiyun #define NANDC_REG_V6_SRAM_SIZE 0x400
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define NANDC_REG_V6_DATA 0x00
48*4882a593Smuzhiyun #define NANDC_REG_V6_ADDR 0x04
49*4882a593Smuzhiyun #define NANDC_REG_V6_CMD 0x08
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* FMCTL */
52*4882a593Smuzhiyun #define NANDC_V6_FM_WP BIT(8)
53*4882a593Smuzhiyun #define NANDC_V6_FM_CE_SEL_M 0xFF
54*4882a593Smuzhiyun #define NANDC_V6_FM_CE_SEL(x) (1 << (x))
55*4882a593Smuzhiyun #define NANDC_V6_FM_FREADY BIT(9)
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* FLCTL */
58*4882a593Smuzhiyun #define NANDC_V6_FL_RST BIT(0)
59*4882a593Smuzhiyun #define NANDC_V6_FL_DIR_S 0x1
60*4882a593Smuzhiyun #define NANDC_V6_FL_XFER_START BIT(2)
61*4882a593Smuzhiyun #define NANDC_V6_FL_XFER_EN BIT(3)
62*4882a593Smuzhiyun #define NANDC_V6_FL_ST_BUF_S 0x4
63*4882a593Smuzhiyun #define NANDC_V6_FL_XFER_COUNT BIT(5)
64*4882a593Smuzhiyun #define NANDC_V6_FL_ACORRECT BIT(10)
65*4882a593Smuzhiyun #define NANDC_V6_FL_XFER_READY BIT(20)
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* BCHCTL */
68*4882a593Smuzhiyun #define NAND_V6_BCH_REGION_S 0x5
69*4882a593Smuzhiyun #define NAND_V6_BCH_REGION_M 0x7
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* BCHST */
72*4882a593Smuzhiyun #define NANDC_V6_BCH0_ST_ERR BIT(2)
73*4882a593Smuzhiyun #define NANDC_V6_BCH1_ST_ERR BIT(15)
74*4882a593Smuzhiyun #define NANDC_V6_ECC_ERR_CNT0(x) ((((x & (0x1F << 3)) >> 3) \
75*4882a593Smuzhiyun | ((x & (1 << 27)) >> 22)) & 0x3F)
76*4882a593Smuzhiyun #define NANDC_V6_ECC_ERR_CNT1(x) ((((x & (0x1F << 16)) >> 16) \
77*4882a593Smuzhiyun | ((x & (1 << 29)) >> 24)) & 0x3F)
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun struct rk_nand {
80*4882a593Smuzhiyun void __iomem *regs;
81*4882a593Smuzhiyun u8 chipnr;
82*4882a593Smuzhiyun u8 id[5];
83*4882a593Smuzhiyun u8 *databuf;
84*4882a593Smuzhiyun struct udevice *dev;
85*4882a593Smuzhiyun struct mtd_info *mtd;
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun static struct rk_nand *g_rk_nand;
89*4882a593Smuzhiyun static u32 nand_page_size;
90*4882a593Smuzhiyun static u32 nand_page_num;
91*4882a593Smuzhiyun static u32 nand_block_num;
92*4882a593Smuzhiyun
nandc_init(struct rk_nand * rknand)93*4882a593Smuzhiyun static void nandc_init(struct rk_nand *rknand)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun writel(0x1081, rknand->regs + NANDC_REG_V6_FMWAIT);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
rockchip_nand_wait_dev_ready(void __iomem * regs)98*4882a593Smuzhiyun static void rockchip_nand_wait_dev_ready(void __iomem *regs)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun u32 reg;
101*4882a593Smuzhiyun u32 timeout = NANDC_V6_DEF_TIMEOUT;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun while (timeout--) {
104*4882a593Smuzhiyun udelay(1);
105*4882a593Smuzhiyun reg = readl(regs + NANDC_REG_V6_FMCTL);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if ((reg & NANDC_V6_FM_FREADY))
108*4882a593Smuzhiyun break;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
rockchip_nand_select_chip(void __iomem * regs,int chipnr)112*4882a593Smuzhiyun static void rockchip_nand_select_chip(void __iomem *regs, int chipnr)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun u32 reg;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun reg = readl(regs + NANDC_REG_V6_FMCTL);
117*4882a593Smuzhiyun reg &= ~NANDC_V6_FM_CE_SEL_M;
118*4882a593Smuzhiyun if (chipnr != -1)
119*4882a593Smuzhiyun reg |= 1 << chipnr;
120*4882a593Smuzhiyun writel(reg, regs + NANDC_REG_V6_FMCTL);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
rockchip_nand_read_page(void __iomem * regs,int page,int col)123*4882a593Smuzhiyun static void rockchip_nand_read_page(void __iomem *regs,
124*4882a593Smuzhiyun int page, int col)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun void __iomem *bank_base = regs + NANDC_REG_V6_BANK0;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun writeb(0x00, bank_base + NANDC_REG_V6_CMD);
129*4882a593Smuzhiyun writeb(col, bank_base + NANDC_REG_V6_ADDR);
130*4882a593Smuzhiyun writeb(col >> 8, bank_base + NANDC_REG_V6_ADDR);
131*4882a593Smuzhiyun writeb(page, bank_base + NANDC_REG_V6_ADDR);
132*4882a593Smuzhiyun writeb(page >> 8, bank_base + NANDC_REG_V6_ADDR);
133*4882a593Smuzhiyun writeb(page >> 16, bank_base + NANDC_REG_V6_ADDR);
134*4882a593Smuzhiyun writeb(0x30, bank_base + NANDC_REG_V6_CMD);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
rockchip_nand_pio_xfer_start(struct rk_nand * rknand,u8 dir,u8 st_buf)137*4882a593Smuzhiyun static void rockchip_nand_pio_xfer_start(struct rk_nand *rknand,
138*4882a593Smuzhiyun u8 dir,
139*4882a593Smuzhiyun u8 st_buf)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun u32 reg;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun reg = readl(rknand->regs + NANDC_REG_V6_BCHCTL);
144*4882a593Smuzhiyun reg = (reg & (~(NAND_V6_BCH_REGION_M << NAND_V6_BCH_REGION_S)));
145*4882a593Smuzhiyun writel(reg, rknand->regs + NANDC_REG_V6_BCHCTL);
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun reg = (dir << NANDC_V6_FL_DIR_S) | (st_buf << NANDC_V6_FL_ST_BUF_S) |
148*4882a593Smuzhiyun NANDC_V6_FL_XFER_EN | NANDC_V6_FL_XFER_COUNT |
149*4882a593Smuzhiyun NANDC_V6_FL_ACORRECT;
150*4882a593Smuzhiyun writel(reg, rknand->regs + NANDC_REG_V6_FLCTL);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun reg |= NANDC_V6_FL_XFER_START;
153*4882a593Smuzhiyun writel(reg, rknand->regs + NANDC_REG_V6_FLCTL);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
rockchip_nand_wait_pio_xfer_done(struct rk_nand * rknand)156*4882a593Smuzhiyun static int rockchip_nand_wait_pio_xfer_done(struct rk_nand *rknand)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun int timeout = NANDC_V6_DEF_TIMEOUT;
159*4882a593Smuzhiyun int reg;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun while (timeout--) {
162*4882a593Smuzhiyun reg = readl(rknand->regs + NANDC_REG_V6_FLCTL);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if ((reg & NANDC_V6_FL_XFER_READY) != 0)
165*4882a593Smuzhiyun break;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun udelay(1);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (timeout == 0)
171*4882a593Smuzhiyun return -1;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun return 0;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
nandc_read_page(unsigned int page,uint8_t * buf)176*4882a593Smuzhiyun static int nandc_read_page(unsigned int page, uint8_t *buf)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun void __iomem *sram_base = g_rk_nand->regs + NANDC_REG_V6_SRAM0;
179*4882a593Smuzhiyun unsigned int max_bitflips = 0;
180*4882a593Smuzhiyun int ret, step, bch_st, ecc_step;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun ecc_step = nand_page_size / 1024;
183*4882a593Smuzhiyun rockchip_nand_select_chip(g_rk_nand->regs, 0);
184*4882a593Smuzhiyun rockchip_nand_read_page(g_rk_nand->regs, page, 0);
185*4882a593Smuzhiyun rockchip_nand_wait_dev_ready(g_rk_nand->regs);
186*4882a593Smuzhiyun rockchip_nand_pio_xfer_start(g_rk_nand, NANDC_V6_READ, 0);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun for (step = 0; step < ecc_step; step++) {
189*4882a593Smuzhiyun int data_off = step * 1024;
190*4882a593Smuzhiyun u8 *data = buf + data_off;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun ret = rockchip_nand_wait_pio_xfer_done(g_rk_nand);
193*4882a593Smuzhiyun if (ret)
194*4882a593Smuzhiyun return ret;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun bch_st = readl(g_rk_nand->regs + NANDC_REG_V6_BCHST);
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if (bch_st & NANDC_V6_BCH0_ST_ERR) {
199*4882a593Smuzhiyun max_bitflips = -1;
200*4882a593Smuzhiyun } else {
201*4882a593Smuzhiyun ret = NANDC_V6_ECC_ERR_CNT0(bch_st);
202*4882a593Smuzhiyun max_bitflips = max_t(unsigned int, max_bitflips, ret);
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if ((step + 1) < ecc_step)
206*4882a593Smuzhiyun rockchip_nand_pio_xfer_start(g_rk_nand, NANDC_V6_READ,
207*4882a593Smuzhiyun (step + 1) & 0x1);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun memcpy_fromio(data, sram_base + NANDC_REG_V6_SRAM_SIZE *
210*4882a593Smuzhiyun (step & 1), 1024);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun rockchip_nand_select_chip(g_rk_nand->regs, -1);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun return max_bitflips;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
is_badblock(unsigned int page)217*4882a593Smuzhiyun static int is_badblock(unsigned int page)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun int res = 0, i;
220*4882a593Smuzhiyun u16 bad = 0xff;
221*4882a593Smuzhiyun void __iomem *regs = g_rk_nand->regs;
222*4882a593Smuzhiyun void __iomem *bank_base = regs + NANDC_REG_V6_BANK0;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (nandc_read_page(page, g_rk_nand->databuf) == -1) {
225*4882a593Smuzhiyun rockchip_nand_select_chip(regs, 0);
226*4882a593Smuzhiyun rockchip_nand_read_page(regs, page, nand_page_size);
227*4882a593Smuzhiyun rockchip_nand_wait_dev_ready(regs);
228*4882a593Smuzhiyun for (i = 0; i < 8; i++) {
229*4882a593Smuzhiyun bad = readb(bank_base);
230*4882a593Smuzhiyun if (bad)
231*4882a593Smuzhiyun break;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun if (i >= 8)
234*4882a593Smuzhiyun res = 1;
235*4882a593Smuzhiyun rockchip_nand_select_chip(regs, 0);
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun if (res)
238*4882a593Smuzhiyun printf("%s 0x%x %x %x\n", __func__, page, res, bad);
239*4882a593Smuzhiyun return res;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
read_flash_id(struct rk_nand * rknand,uint8_t * id)242*4882a593Smuzhiyun static void read_flash_id(struct rk_nand *rknand, uint8_t *id)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun void __iomem *bank_base = rknand->regs + NANDC_REG_V6_BANK0;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun rockchip_nand_wait_dev_ready(g_rk_nand->regs);
247*4882a593Smuzhiyun writeb(0x90, bank_base + NANDC_REG_V6_CMD);
248*4882a593Smuzhiyun writeb(0x00, bank_base + NANDC_REG_V6_ADDR);
249*4882a593Smuzhiyun udelay(1);
250*4882a593Smuzhiyun id[0] = readb(bank_base);
251*4882a593Smuzhiyun id[1] = readb(bank_base);
252*4882a593Smuzhiyun id[2] = readb(bank_base);
253*4882a593Smuzhiyun id[3] = readb(bank_base);
254*4882a593Smuzhiyun id[4] = readb(bank_base);
255*4882a593Smuzhiyun rockchip_nand_select_chip(rknand->regs, -1);
256*4882a593Smuzhiyun if (id[0] != 0xFF && id[0] != 0x00)
257*4882a593Smuzhiyun printf("NAND:%x %x\n", id[0], id[1]);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun #ifdef CONFIG_NAND_ROCKCHIP_DT
261*4882a593Smuzhiyun static const struct udevice_id rockchip_nandc_ids[] = {
262*4882a593Smuzhiyun { .compatible = "rockchip,rk-nandc" },
263*4882a593Smuzhiyun { }
264*4882a593Smuzhiyun };
265*4882a593Smuzhiyun
spl_nand_block_isbad(struct mtd_info * mtd,loff_t ofs)266*4882a593Smuzhiyun static int spl_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun return is_badblock((u32)ofs / nand_page_size);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
spl_nand_read_page(struct mtd_info * mtd,loff_t from,size_t len,size_t * retlen,u_char * buf)271*4882a593Smuzhiyun static int spl_nand_read_page(struct mtd_info *mtd, loff_t from, size_t len,
272*4882a593Smuzhiyun size_t *retlen, u_char *buf)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun int read_size, offset, read_len;
275*4882a593Smuzhiyun unsigned int page;
276*4882a593Smuzhiyun unsigned int max_pages = nand_page_num * nand_block_num;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /* Convert to page number */
279*4882a593Smuzhiyun page = (u32)from / nand_page_size;
280*4882a593Smuzhiyun offset = from & (nand_page_size - 1);
281*4882a593Smuzhiyun read_len = len;
282*4882a593Smuzhiyun *retlen = 0;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun while (read_len) {
285*4882a593Smuzhiyun read_size = nand_page_size - offset;
286*4882a593Smuzhiyun if (read_size > read_len)
287*4882a593Smuzhiyun read_size = read_len;
288*4882a593Smuzhiyun if (offset || read_size < nand_page_size) {
289*4882a593Smuzhiyun if (nandc_read_page(page, g_rk_nand->databuf) < 0)
290*4882a593Smuzhiyun return -EIO;
291*4882a593Smuzhiyun memcpy(buf, g_rk_nand->databuf + offset, read_size);
292*4882a593Smuzhiyun offset = 0;
293*4882a593Smuzhiyun } else {
294*4882a593Smuzhiyun if (nandc_read_page(page, buf) < 0)
295*4882a593Smuzhiyun return -EIO;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun page++;
298*4882a593Smuzhiyun read_len -= read_size;
299*4882a593Smuzhiyun buf += read_size;
300*4882a593Smuzhiyun if (page >= max_pages)
301*4882a593Smuzhiyun return -EIO;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun *retlen = len;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun return 0;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
rockchip_nandc_probe(struct udevice * dev)309*4882a593Smuzhiyun static int rockchip_nandc_probe(struct udevice *dev)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun const void *blob = gd->fdt_blob;
312*4882a593Smuzhiyun struct rk_nand *rknand = dev_get_priv(dev);
313*4882a593Smuzhiyun struct mtd_info *mtd = dev_get_uclass_priv(dev);
314*4882a593Smuzhiyun fdt_addr_t regs;
315*4882a593Smuzhiyun int ret = -ENODEV;
316*4882a593Smuzhiyun int node;
317*4882a593Smuzhiyun u8 *id;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun g_rk_nand = rknand;
320*4882a593Smuzhiyun rknand->dev = dev;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun if (node < 0) {
325*4882a593Smuzhiyun printf("Nand node not found\n");
326*4882a593Smuzhiyun return -ENODEV;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (!fdtdec_get_is_enabled(blob, node)) {
330*4882a593Smuzhiyun debug("Nand disabled in device tree\n");
331*4882a593Smuzhiyun return -ENODEV;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun regs = fdt_get_base_address(blob, node);
335*4882a593Smuzhiyun if (!regs) {
336*4882a593Smuzhiyun debug("Nand address not found\n");
337*4882a593Smuzhiyun return -ENODEV;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun rknand->regs = (void *)regs;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun nandc_init(g_rk_nand);
343*4882a593Smuzhiyun read_flash_id(g_rk_nand, g_rk_nand->id);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun id = g_rk_nand->id;
346*4882a593Smuzhiyun if (id[0] == id[1])
347*4882a593Smuzhiyun return -ENODEV;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun if (id[1] == 0xA1 || id[1] == 0xF1 ||
350*4882a593Smuzhiyun id[1] == 0xD1 || id[1] == 0xAA ||
351*4882a593Smuzhiyun id[1] == 0xDA || id[1] == 0xAC ||
352*4882a593Smuzhiyun id[1] == 0xDC || id[1] == 0xA3 ||
353*4882a593Smuzhiyun id[1] == 0xD3 || id[1] == 0x95 ||
354*4882a593Smuzhiyun id[1] == 0x48) {
355*4882a593Smuzhiyun nand_page_size = 2048;
356*4882a593Smuzhiyun nand_page_num = 64;
357*4882a593Smuzhiyun nand_block_num = 1024;
358*4882a593Smuzhiyun if (id[1] == 0xDC) {
359*4882a593Smuzhiyun if ((id[0] == 0x2C && id[3] == 0xA6) ||
360*4882a593Smuzhiyun (id[0] == 0xC2 && id[3] == 0xA2)) {
361*4882a593Smuzhiyun nand_page_size = 4096;
362*4882a593Smuzhiyun nand_block_num = 2048;
363*4882a593Smuzhiyun } else if (id[0] == 0x98 && id[3] == 0x26) {
364*4882a593Smuzhiyun nand_page_size = 4096;
365*4882a593Smuzhiyun nand_block_num = 2048;
366*4882a593Smuzhiyun } else {
367*4882a593Smuzhiyun nand_block_num = 4096;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun } else if (id[1] == 0xDA) {
370*4882a593Smuzhiyun nand_block_num = 2048;
371*4882a593Smuzhiyun } else if (id[1] == 0x48) {
372*4882a593Smuzhiyun nand_page_size = 4096;
373*4882a593Smuzhiyun nand_page_num = 128;
374*4882a593Smuzhiyun nand_block_num = 4096;
375*4882a593Smuzhiyun } else if (id[1] == 0xD3) {
376*4882a593Smuzhiyun if ((id[2] == 0xD1 && id[4] == 0x5a) || /* S34ML08G2 */
377*4882a593Smuzhiyun (id[3] == 0x05 && id[4] == 0x04)) { /* S34ML08G3 */
378*4882a593Smuzhiyun nand_block_num = 8192;
379*4882a593Smuzhiyun } else {
380*4882a593Smuzhiyun nand_page_size = 4096;
381*4882a593Smuzhiyun nand_block_num = 4096;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun g_rk_nand->chipnr = 1;
386*4882a593Smuzhiyun g_rk_nand->databuf = kzalloc(nand_page_size, GFP_KERNEL);
387*4882a593Smuzhiyun if (!g_rk_nand)
388*4882a593Smuzhiyun return -ENOMEM;
389*4882a593Smuzhiyun mtd->_block_isbad = spl_nand_block_isbad;
390*4882a593Smuzhiyun mtd->_read = spl_nand_read_page;
391*4882a593Smuzhiyun mtd->size = (size_t)nand_page_size * nand_page_num *
392*4882a593Smuzhiyun nand_block_num;
393*4882a593Smuzhiyun mtd->writesize = nand_page_size;
394*4882a593Smuzhiyun mtd->erasesize = nand_page_size * nand_page_num;
395*4882a593Smuzhiyun mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
396*4882a593Smuzhiyun mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
397*4882a593Smuzhiyun mtd->type = MTD_NANDFLASH;
398*4882a593Smuzhiyun mtd->dev = rknand->dev;
399*4882a593Smuzhiyun mtd->priv = rknand;
400*4882a593Smuzhiyun add_mtd_device(mtd);
401*4882a593Smuzhiyun rknand->mtd = mtd;
402*4882a593Smuzhiyun ret = 0;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun return ret;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
rockchip_nandc_bind(struct udevice * udev)408*4882a593Smuzhiyun static int rockchip_nandc_bind(struct udevice *udev)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun int ret = 0;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
413*4882a593Smuzhiyun struct udevice *bdev;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun ret = blk_create_devicef(udev, "mtd_blk", "blk", IF_TYPE_MTD,
416*4882a593Smuzhiyun BLK_MTD_NAND, 512, 0, &bdev);
417*4882a593Smuzhiyun if (ret)
418*4882a593Smuzhiyun printf("Cannot create block device\n");
419*4882a593Smuzhiyun #endif
420*4882a593Smuzhiyun return ret;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun U_BOOT_DRIVER(rk_nandc_v6) = {
424*4882a593Smuzhiyun .name = "rk_nandc_v6",
425*4882a593Smuzhiyun .id = UCLASS_MTD,
426*4882a593Smuzhiyun .of_match = rockchip_nandc_ids,
427*4882a593Smuzhiyun .bind = rockchip_nandc_bind,
428*4882a593Smuzhiyun .probe = rockchip_nandc_probe,
429*4882a593Smuzhiyun .priv_auto_alloc_size = sizeof(struct rk_nand),
430*4882a593Smuzhiyun };
431*4882a593Smuzhiyun
board_nand_init(void)432*4882a593Smuzhiyun void board_nand_init(void)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun struct udevice *dev;
435*4882a593Smuzhiyun int ret;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun ret = uclass_get_device_by_driver(UCLASS_MTD,
438*4882a593Smuzhiyun DM_GET_DRIVER(rk_nandc_v6),
439*4882a593Smuzhiyun &dev);
440*4882a593Smuzhiyun if (ret && ret != -ENODEV)
441*4882a593Smuzhiyun pr_err("Failed to initialize NAND controller. (error %d)\n",
442*4882a593Smuzhiyun ret);
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
nand_spl_load_image(u32 offs,u32 size,void * buf)445*4882a593Smuzhiyun int nand_spl_load_image(u32 offs, u32 size, void *buf)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun return -EIO;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
nand_init(void)450*4882a593Smuzhiyun void nand_init(void){};
451*4882a593Smuzhiyun
rk_nand_init(void)452*4882a593Smuzhiyun int rk_nand_init(void)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun return -ENODEV;
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun #else
board_nand_init(void)458*4882a593Smuzhiyun void board_nand_init(void)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun const void *blob = gd->fdt_blob;
461*4882a593Smuzhiyun static int initialized;
462*4882a593Smuzhiyun fdt_addr_t regs;
463*4882a593Smuzhiyun int node;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun if (initialized)
466*4882a593Smuzhiyun return;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun initialized = 1;
469*4882a593Smuzhiyun nand_page_size = CONFIG_SYS_NAND_PAGE_SIZE;
470*4882a593Smuzhiyun nand_page_num = CONFIG_SYS_NAND_PAGE_COUNT;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (g_rk_nand)
473*4882a593Smuzhiyun return;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun if (node < 0) {
478*4882a593Smuzhiyun printf("Nand node not found\n");
479*4882a593Smuzhiyun return;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun if (!fdtdec_get_is_enabled(blob, node)) {
483*4882a593Smuzhiyun debug("Nand disabled in device tree\n");
484*4882a593Smuzhiyun return;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun regs = fdt_get_base_address(blob, node);
488*4882a593Smuzhiyun if (!regs) {
489*4882a593Smuzhiyun debug("Nand address not found\n");
490*4882a593Smuzhiyun return;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun g_rk_nand = kzalloc(sizeof(*g_rk_nand), GFP_KERNEL);
494*4882a593Smuzhiyun g_rk_nand->regs = (void *)regs;
495*4882a593Smuzhiyun g_rk_nand->databuf = kzalloc(nand_page_size, GFP_KERNEL);
496*4882a593Smuzhiyun nandc_init(g_rk_nand);
497*4882a593Smuzhiyun read_flash_id(g_rk_nand, g_rk_nand->id);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun if (g_rk_nand->id[0] == g_rk_nand->id[1])
500*4882a593Smuzhiyun goto err;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun if (g_rk_nand->id[1] == 0xA1 || g_rk_nand->id[1] == 0xF1 ||
503*4882a593Smuzhiyun g_rk_nand->id[1] == 0xD1 || g_rk_nand->id[1] == 0xAA ||
504*4882a593Smuzhiyun g_rk_nand->id[1] == 0xDA || g_rk_nand->id[1] == 0xAC ||
505*4882a593Smuzhiyun g_rk_nand->id[1] == 0xDC || g_rk_nand->id[1] == 0xA3 ||
506*4882a593Smuzhiyun g_rk_nand->id[1] == 0xD3 || g_rk_nand->id[1] == 0x95 ||
507*4882a593Smuzhiyun g_rk_nand->id[1] == 0x48) {
508*4882a593Smuzhiyun g_rk_nand->chipnr = 1;
509*4882a593Smuzhiyun return;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun err:
513*4882a593Smuzhiyun kfree(g_rk_nand->databuf);
514*4882a593Smuzhiyun kfree(g_rk_nand);
515*4882a593Smuzhiyun g_rk_nand = NULL;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
nand_spl_load_image(u32 offs,u32 size,void * buf)518*4882a593Smuzhiyun int nand_spl_load_image(u32 offs, u32 size, void *buf)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun int i;
521*4882a593Smuzhiyun unsigned int page;
522*4882a593Smuzhiyun int force_bad_block_check = 1;
523*4882a593Smuzhiyun unsigned int maxpages = CONFIG_SYS_NAND_SIZE /
524*4882a593Smuzhiyun nand_page_size;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun /* Convert to page number */
527*4882a593Smuzhiyun page = offs / nand_page_size;
528*4882a593Smuzhiyun i = 0;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun size = roundup(size, nand_page_size);
531*4882a593Smuzhiyun while (i < size / nand_page_size) {
532*4882a593Smuzhiyun /*
533*4882a593Smuzhiyun * Check if we have crossed a block boundary, and if so
534*4882a593Smuzhiyun * check for bad block.
535*4882a593Smuzhiyun */
536*4882a593Smuzhiyun if (force_bad_block_check || !(page % nand_page_num)) {
537*4882a593Smuzhiyun /*
538*4882a593Smuzhiyun * Yes, new block. See if this block is good. If not,
539*4882a593Smuzhiyun * loop until we find a good block.
540*4882a593Smuzhiyun */
541*4882a593Smuzhiyun while (is_badblock(page)) {
542*4882a593Smuzhiyun page = page + nand_page_num;
543*4882a593Smuzhiyun /* Check i we've reached the end of flash. */
544*4882a593Smuzhiyun if (page >= maxpages)
545*4882a593Smuzhiyun return -EIO;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun force_bad_block_check = 0;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun if (nandc_read_page(page, buf) < 0)
552*4882a593Smuzhiyun return -EIO;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun page++;
555*4882a593Smuzhiyun i++;
556*4882a593Smuzhiyun buf = buf + nand_page_size;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun return 0;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
nand_init(void)561*4882a593Smuzhiyun void nand_init(void)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun board_nand_init();
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
rk_nand_init(void)566*4882a593Smuzhiyun int rk_nand_init(void)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun board_nand_init();
569*4882a593Smuzhiyun if (g_rk_nand && g_rk_nand->chipnr)
570*4882a593Smuzhiyun return 0;
571*4882a593Smuzhiyun else
572*4882a593Smuzhiyun return -ENODEV;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun #endif
575*4882a593Smuzhiyun
nand_deselect(void)576*4882a593Smuzhiyun void nand_deselect(void) {}
577*4882a593Smuzhiyun
578