1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2017 Yifeng Zhao <yifeng.zhao@rock-chips.com>
3*4882a593Smuzhiyun * Copyright (c) 2017 Paweł Jarosz <paweljarosz3691@gmail.com>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <dm.h>
10*4882a593Smuzhiyun #include <fdtdec.h>
11*4882a593Smuzhiyun #include <inttypes.h>
12*4882a593Smuzhiyun #include <nand.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/ioport.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
17*4882a593Smuzhiyun #include <linux/mtd/nand.h>
18*4882a593Smuzhiyun #include <linux/mtd/partitions.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #ifdef CONFIG_ROCKCHIP_RK3568
23*4882a593Smuzhiyun #define NANDC_V9_BOOTROM_ECC 16
24*4882a593Smuzhiyun #else
25*4882a593Smuzhiyun #define NANDC_V9_BOOTROM_ECC 70
26*4882a593Smuzhiyun #endif
27*4882a593Smuzhiyun #define NANDC_V9_NUM_BANKS 4
28*4882a593Smuzhiyun #define NANDC_V9_DEF_TIMEOUT 20000
29*4882a593Smuzhiyun #define NANDC_V9_READ 0
30*4882a593Smuzhiyun #define NANDC_V9_WRITE 1
31*4882a593Smuzhiyun #define NANDC_REG_V9_FMCTL 0x00
32*4882a593Smuzhiyun #define NANDC_REG_V9_FMWAIT 0x04
33*4882a593Smuzhiyun #define NANDC_REG_V9_FLCTL 0x10
34*4882a593Smuzhiyun #define NANDC_REG_V9_BCHCTL 0x20
35*4882a593Smuzhiyun #define NANDC_REG_V9_DMA_CFG 0x30
36*4882a593Smuzhiyun #define NANDC_REG_V9_DMA_BUF0 0x34
37*4882a593Smuzhiyun #define NANDC_REG_V9_DMA_BUF1 0x38
38*4882a593Smuzhiyun #define NANDC_REG_V9_DMA_ST 0x40
39*4882a593Smuzhiyun #define NANDC_REG_V9_VER 0x80
40*4882a593Smuzhiyun #define NANDC_REG_V9_INTEN 0x120
41*4882a593Smuzhiyun #define NANDC_REG_V9_INTCLR 0x124
42*4882a593Smuzhiyun #define NANDC_REG_V9_INTST 0x128
43*4882a593Smuzhiyun #define NANDC_REG_V9_BCHST 0x150
44*4882a593Smuzhiyun #define NANDC_REG_V9_SPARE0 0x200
45*4882a593Smuzhiyun #define NANDC_REG_V9_SPARE1 0x204
46*4882a593Smuzhiyun #define NANDC_REG_V9_RANDMZ 0x208
47*4882a593Smuzhiyun #define NANDC_REG_V9_BANK0 0x800
48*4882a593Smuzhiyun #define NANDC_REG_V9_SRAM0 0x1000
49*4882a593Smuzhiyun #define NANDC_REG_V9_SRAM_SIZE 0x400
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun #define NANDC_REG_V9_DATA 0x00
52*4882a593Smuzhiyun #define NANDC_REG_V9_ADDR 0x04
53*4882a593Smuzhiyun #define NANDC_REG_V9_CMD 0x08
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /* FMCTL */
56*4882a593Smuzhiyun #define NANDC_V9_FM_WP BIT(8)
57*4882a593Smuzhiyun #define NANDC_V9_FM_CE_SEL_M 0xFF
58*4882a593Smuzhiyun #define NANDC_V9_FM_CE_SEL(x) (1 << (x))
59*4882a593Smuzhiyun #define NANDC_V9_FM_FREADY BIT(9)
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* FLCTL */
62*4882a593Smuzhiyun #define NANDC_V9_FL_RST BIT(0)
63*4882a593Smuzhiyun #define NANDC_V9_FL_DIR_S 0x1
64*4882a593Smuzhiyun #define NANDC_V9_FL_XFER_START BIT(2)
65*4882a593Smuzhiyun #define NANDC_V9_FL_XFER_EN BIT(3)
66*4882a593Smuzhiyun #define NANDC_V9_FL_ST_BUF_S 0x4
67*4882a593Smuzhiyun #define NANDC_V9_FL_XFER_COUNT BIT(5)
68*4882a593Smuzhiyun #define NANDC_V9_FL_ACORRECT BIT(10)
69*4882a593Smuzhiyun #define NANDC_V9_FL_XFER_READY BIT(20)
70*4882a593Smuzhiyun #define NANDC_V9_FL_ASYNC_TOG_MIX BIT(29)
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* BCHCTL */
73*4882a593Smuzhiyun #define NAND_V9_BCH_MODE_S 25
74*4882a593Smuzhiyun #define NAND_V9_BCH_MODE_M 0x7
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /* BCHST */
77*4882a593Smuzhiyun #define NANDC_V9_BCH0_ST_ERR BIT(2)
78*4882a593Smuzhiyun #define NANDC_V9_BCH1_ST_ERR BIT(18)
79*4882a593Smuzhiyun #define NANDC_V9_ECC_ERR_CNT0(x) (((x) & (0x7F << 3)) >> 3)
80*4882a593Smuzhiyun #define NANDC_V9_ECC_ERR_CNT1(x) (((x) & (0x7F << 19)) >> 19)
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun struct rk_nand {
83*4882a593Smuzhiyun uint32_t banks[NANDC_V9_NUM_BANKS];
84*4882a593Smuzhiyun struct nand_hw_control controller;
85*4882a593Smuzhiyun uint32_t ecc_strength;
86*4882a593Smuzhiyun struct mtd_info mtd;
87*4882a593Smuzhiyun bool bootromblocks;
88*4882a593Smuzhiyun void __iomem *regs;
89*4882a593Smuzhiyun int selected_bank;
90*4882a593Smuzhiyun struct udevice *dev;
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun static struct nand_ecclayout nand_oob_fix = {
94*4882a593Smuzhiyun .eccbytes = 24,
95*4882a593Smuzhiyun .eccpos = {
96*4882a593Smuzhiyun 4, 5, 6, 7, 8, 9, 10
97*4882a593Smuzhiyun },
98*4882a593Smuzhiyun .oobfree = {
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun .offset = 0,
101*4882a593Smuzhiyun .length = 4
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun };
105*4882a593Smuzhiyun
to_rknand(struct nand_hw_control * ctrl)106*4882a593Smuzhiyun static inline struct rk_nand *to_rknand(struct nand_hw_control *ctrl)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun return container_of(ctrl, struct rk_nand, controller);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
rockchip_nand_init(struct rk_nand * rknand)111*4882a593Smuzhiyun static void rockchip_nand_init(struct rk_nand *rknand)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun writel(0, rknand->regs + NANDC_REG_V9_RANDMZ);
114*4882a593Smuzhiyun writel(0, rknand->regs + NANDC_REG_V9_DMA_CFG);
115*4882a593Smuzhiyun writel(0, rknand->regs + NANDC_REG_V9_BCHCTL);
116*4882a593Smuzhiyun writel(NANDC_V9_FM_WP, rknand->regs + NANDC_REG_V9_FMCTL);
117*4882a593Smuzhiyun writel(0x1081, rknand->regs + NANDC_REG_V9_FMWAIT);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
rockchip_nand_select_chip(struct mtd_info * mtd,int chipnr)120*4882a593Smuzhiyun static void rockchip_nand_select_chip(struct mtd_info *mtd, int chipnr)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
123*4882a593Smuzhiyun struct rk_nand *rknand = to_rknand(chip->controller);
124*4882a593Smuzhiyun void __iomem *bank_base;
125*4882a593Smuzhiyun uint32_t reg;
126*4882a593Smuzhiyun int banknr;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun reg = readl(rknand->regs + NANDC_REG_V9_FMCTL);
129*4882a593Smuzhiyun reg &= ~NANDC_V9_FM_CE_SEL_M;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (chipnr == -1) {
132*4882a593Smuzhiyun banknr = -1;
133*4882a593Smuzhiyun } else {
134*4882a593Smuzhiyun banknr = rknand->banks[chipnr];
135*4882a593Smuzhiyun bank_base = rknand->regs + NANDC_REG_V9_BANK0 + banknr * 0x100;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun chip->IO_ADDR_R = bank_base;
138*4882a593Smuzhiyun chip->IO_ADDR_W = bank_base;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun reg |= 1 << banknr;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun writel(reg, rknand->regs + NANDC_REG_V9_FMCTL);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun rknand->selected_bank = banknr;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
rockchip_nand_cmd_ctrl(struct mtd_info * mtd,int dat,unsigned int ctrl)147*4882a593Smuzhiyun static void rockchip_nand_cmd_ctrl(struct mtd_info *mtd,
148*4882a593Smuzhiyun int dat,
149*4882a593Smuzhiyun unsigned int ctrl)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
152*4882a593Smuzhiyun struct rk_nand *rknand = to_rknand(chip->controller);
153*4882a593Smuzhiyun void __iomem *bank_base = rknand->regs + NANDC_REG_V9_BANK0
154*4882a593Smuzhiyun + rknand->selected_bank * 0x100;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun if (ctrl & NAND_CTRL_CHANGE) {
157*4882a593Smuzhiyun if (ctrl & NAND_ALE)
158*4882a593Smuzhiyun bank_base += NANDC_REG_V9_ADDR;
159*4882a593Smuzhiyun else if (ctrl & NAND_CLE)
160*4882a593Smuzhiyun bank_base += NANDC_REG_V9_CMD;
161*4882a593Smuzhiyun chip->IO_ADDR_W = bank_base;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (dat != NAND_CMD_NONE)
165*4882a593Smuzhiyun writeb(dat & 0xFF, chip->IO_ADDR_W);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
rockchip_nand_read_buf(struct mtd_info * mtd,uint8_t * buf,int len)168*4882a593Smuzhiyun static void rockchip_nand_read_buf(struct mtd_info *mtd,
169*4882a593Smuzhiyun uint8_t *buf,
170*4882a593Smuzhiyun int len)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
173*4882a593Smuzhiyun struct rk_nand *rknand = to_rknand(chip->controller);
174*4882a593Smuzhiyun int offs = 0;
175*4882a593Smuzhiyun void __iomem *bank_base = rknand->regs + NANDC_REG_V9_BANK0
176*4882a593Smuzhiyun + rknand->selected_bank * 0x100;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun for (offs = 0; offs < len; offs++)
179*4882a593Smuzhiyun buf[offs] = readb(bank_base);
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
rockchip_nand_write_buf(struct mtd_info * mtd,const uint8_t * buf,int len)182*4882a593Smuzhiyun static void rockchip_nand_write_buf(struct mtd_info *mtd,
183*4882a593Smuzhiyun const uint8_t *buf,
184*4882a593Smuzhiyun int len)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
187*4882a593Smuzhiyun struct rk_nand *rknand = to_rknand(chip->controller);
188*4882a593Smuzhiyun int offs = 0;
189*4882a593Smuzhiyun void __iomem *bank_base = rknand->regs + NANDC_REG_V9_BANK0
190*4882a593Smuzhiyun + rknand->selected_bank * 0x100;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun for (offs = 0; offs < len; offs++)
193*4882a593Smuzhiyun writeb(buf[offs], bank_base);
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
rockchip_nand_read_byte(struct mtd_info * mtd)196*4882a593Smuzhiyun static uint8_t rockchip_nand_read_byte(struct mtd_info *mtd)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun uint8_t ret;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun rockchip_nand_read_buf(mtd, &ret, 1);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun return ret;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
rockchip_nand_dev_ready(struct mtd_info * mtd)205*4882a593Smuzhiyun static int rockchip_nand_dev_ready(struct mtd_info *mtd)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
208*4882a593Smuzhiyun struct rk_nand *rknand = to_rknand(chip->controller);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if (readl(rknand->regs + NANDC_REG_V9_FMCTL) & NANDC_V9_FM_FREADY)
211*4882a593Smuzhiyun return 1;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
rockchip_nand_hw_ecc_setup(struct mtd_info * mtd,struct nand_ecc_ctrl * ecc,uint32_t strength)216*4882a593Smuzhiyun static int rockchip_nand_hw_ecc_setup(struct mtd_info *mtd,
217*4882a593Smuzhiyun struct nand_ecc_ctrl *ecc,
218*4882a593Smuzhiyun uint32_t strength)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
221*4882a593Smuzhiyun struct rk_nand *rknand = to_rknand(chip->controller);
222*4882a593Smuzhiyun u32 reg;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun ecc->strength = strength;
225*4882a593Smuzhiyun ecc->bytes = DIV_ROUND_UP(ecc->strength * 14, 8);
226*4882a593Smuzhiyun ecc->bytes = ALIGN(ecc->bytes, 2);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun switch (ecc->strength) {
229*4882a593Smuzhiyun case 70:
230*4882a593Smuzhiyun reg = 0x00000001;
231*4882a593Smuzhiyun break;
232*4882a593Smuzhiyun case 60:
233*4882a593Smuzhiyun reg = 0x06000001;
234*4882a593Smuzhiyun break;
235*4882a593Smuzhiyun case 40:
236*4882a593Smuzhiyun reg = 0x04000001;
237*4882a593Smuzhiyun break;
238*4882a593Smuzhiyun case 16:
239*4882a593Smuzhiyun reg = 0x02000001;
240*4882a593Smuzhiyun break;
241*4882a593Smuzhiyun default:
242*4882a593Smuzhiyun return -EINVAL;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun writel(reg, rknand->regs + NANDC_REG_V9_BCHCTL);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun return 0;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
rockchip_nand_pio_xfer_start(struct rk_nand * rknand,u8 dir,u8 st_buf)249*4882a593Smuzhiyun static void rockchip_nand_pio_xfer_start(struct rk_nand *rknand,
250*4882a593Smuzhiyun u8 dir,
251*4882a593Smuzhiyun u8 st_buf)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun u32 reg;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun reg = (dir << NANDC_V9_FL_DIR_S) | (st_buf << NANDC_V9_FL_ST_BUF_S) |
256*4882a593Smuzhiyun NANDC_V9_FL_XFER_EN | NANDC_V9_FL_XFER_COUNT |
257*4882a593Smuzhiyun NANDC_V9_FL_ACORRECT | NANDC_V9_FL_ASYNC_TOG_MIX;
258*4882a593Smuzhiyun writel(reg, rknand->regs + NANDC_REG_V9_FLCTL);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun reg |= NANDC_V9_FL_XFER_START;
261*4882a593Smuzhiyun writel(reg, rknand->regs + NANDC_REG_V9_FLCTL);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
rockchip_nand_wait_pio_xfer_done(struct rk_nand * rknand)264*4882a593Smuzhiyun static int rockchip_nand_wait_pio_xfer_done(struct rk_nand *rknand)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun int timeout = NANDC_V9_DEF_TIMEOUT;
267*4882a593Smuzhiyun int reg;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun while (timeout--) {
270*4882a593Smuzhiyun reg = readl(rknand->regs + NANDC_REG_V9_FLCTL);
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if ((reg & NANDC_V9_FL_XFER_READY) != 0)
273*4882a593Smuzhiyun break;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun udelay(1);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (timeout == 0)
279*4882a593Smuzhiyun return -1;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
rockchip_nand_read_extra_oob(struct mtd_info * mtd,u8 * oob)284*4882a593Smuzhiyun static void rockchip_nand_read_extra_oob(struct mtd_info *mtd, u8 *oob)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
287*4882a593Smuzhiyun struct nand_ecc_ctrl *ecc = &chip->ecc;
288*4882a593Smuzhiyun int offset = ((ecc->bytes + ecc->prepad) * ecc->steps);
289*4882a593Smuzhiyun int len = mtd->oobsize - offset;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (len <= 0)
292*4882a593Smuzhiyun return;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset + mtd->writesize, -1);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun rockchip_nand_read_buf(mtd, oob + offset, len);
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
rockchip_nand_write_extra_oob(struct mtd_info * mtd,u8 * oob)299*4882a593Smuzhiyun static void rockchip_nand_write_extra_oob(struct mtd_info *mtd, u8 *oob)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
302*4882a593Smuzhiyun struct nand_ecc_ctrl *ecc = &chip->ecc;
303*4882a593Smuzhiyun int offset = ((ecc->bytes + ecc->prepad) * ecc->steps);
304*4882a593Smuzhiyun int len = mtd->oobsize - offset;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun if (len <= 0)
307*4882a593Smuzhiyun return;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset + mtd->writesize, -1);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun rockchip_nand_write_buf(mtd, oob + offset, len);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
rockchip_nand_hw_syndrome_pio_read_page(struct mtd_info * mtd,struct nand_chip * chip,uint8_t * buf,int oob_required,int page)314*4882a593Smuzhiyun static int rockchip_nand_hw_syndrome_pio_read_page(struct mtd_info *mtd,
315*4882a593Smuzhiyun struct nand_chip *chip,
316*4882a593Smuzhiyun uint8_t *buf,
317*4882a593Smuzhiyun int oob_required,
318*4882a593Smuzhiyun int page)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun struct rk_nand *rknand = to_rknand(chip->controller);
321*4882a593Smuzhiyun struct nand_ecc_ctrl *ecc = &chip->ecc;
322*4882a593Smuzhiyun void __iomem *sram_base = rknand->regs + NANDC_REG_V9_SRAM0;
323*4882a593Smuzhiyun unsigned int max_bitflips = 0;
324*4882a593Smuzhiyun int ret, step, bch_st;
325*4882a593Smuzhiyun int offset = page * mtd->writesize;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun if (rknand->bootromblocks && (offset < (4 * mtd->erasesize)))
328*4882a593Smuzhiyun rockchip_nand_hw_ecc_setup(mtd, ecc, NANDC_V9_BOOTROM_ECC);
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun rockchip_nand_pio_xfer_start(rknand, NANDC_V9_READ, 0);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun for (step = 0; step < ecc->steps; step++) {
333*4882a593Smuzhiyun int data_off = step * ecc->size;
334*4882a593Smuzhiyun int oob_off = step * (ecc->bytes + ecc->prepad);
335*4882a593Smuzhiyun u8 *data = buf + data_off;
336*4882a593Smuzhiyun u8 *oob = chip->oob_poi + oob_off;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun ret = rockchip_nand_wait_pio_xfer_done(rknand);
339*4882a593Smuzhiyun if (ret)
340*4882a593Smuzhiyun return ret;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun bch_st = readl(rknand->regs + NANDC_REG_V9_BCHST);
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun if (bch_st & NANDC_V9_BCH0_ST_ERR) {
345*4882a593Smuzhiyun mtd->ecc_stats.failed++;
346*4882a593Smuzhiyun max_bitflips = -1;
347*4882a593Smuzhiyun } else {
348*4882a593Smuzhiyun ret = NANDC_V9_ECC_ERR_CNT0(bch_st);
349*4882a593Smuzhiyun mtd->ecc_stats.corrected += ret;
350*4882a593Smuzhiyun max_bitflips = max_t(unsigned int, max_bitflips, ret);
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun if ((step + 1) < ecc->steps)
354*4882a593Smuzhiyun rockchip_nand_pio_xfer_start(rknand, NANDC_V9_READ,
355*4882a593Smuzhiyun (step + 1) & 0x1);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun memcpy_fromio(data, sram_base + NANDC_REG_V9_SRAM_SIZE *
358*4882a593Smuzhiyun (step & 1), ecc->size);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun if (step & 1)
361*4882a593Smuzhiyun memcpy_fromio(oob, rknand->regs + NANDC_REG_V9_SPARE1, 4);
362*4882a593Smuzhiyun else
363*4882a593Smuzhiyun memcpy_fromio(oob, rknand->regs + NANDC_REG_V9_SPARE0, 4);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun rockchip_nand_read_extra_oob(mtd, chip->oob_poi);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (rknand->bootromblocks)
369*4882a593Smuzhiyun rockchip_nand_hw_ecc_setup(mtd, ecc, rknand->ecc_strength);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun return max_bitflips;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
rockchip_nand_make_bootrom_compat(struct mtd_info * mtd,int page,const u8 * oob,bool bootromblocks)374*4882a593Smuzhiyun static uint32_t rockchip_nand_make_bootrom_compat(struct mtd_info *mtd,
375*4882a593Smuzhiyun int page,
376*4882a593Smuzhiyun const u8 *oob,
377*4882a593Smuzhiyun bool bootromblocks)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun int pages_per_block = mtd->erasesize / mtd->writesize;
380*4882a593Smuzhiyun int offset = page * mtd->writesize;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun if ((offset < (2 * mtd->erasesize)) || !(page % 2) ||
383*4882a593Smuzhiyun (offset >= (7 * mtd->erasesize)) || !bootromblocks)
384*4882a593Smuzhiyun return oob[3] | (oob[2] << 8) | (oob[1] << 16) | (oob[0] << 24);
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun return (page % pages_per_block + 1) * 4;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
rockchip_nand_hw_syndrome_pio_write_page(struct mtd_info * mtd,struct nand_chip * chip,const uint8_t * buf,int oob_required,int page)389*4882a593Smuzhiyun static int rockchip_nand_hw_syndrome_pio_write_page(struct mtd_info *mtd,
390*4882a593Smuzhiyun struct nand_chip *chip,
391*4882a593Smuzhiyun const uint8_t *buf,
392*4882a593Smuzhiyun int oob_required,
393*4882a593Smuzhiyun int page)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun struct rk_nand *rknand = to_rknand(chip->controller);
396*4882a593Smuzhiyun struct nand_ecc_ctrl *ecc = &chip->ecc;
397*4882a593Smuzhiyun void __iomem *sram_base = rknand->regs + NANDC_REG_V9_SRAM0;
398*4882a593Smuzhiyun int ret, index, step = 0;
399*4882a593Smuzhiyun int offset = page * mtd->writesize;
400*4882a593Smuzhiyun int data_off = step * ecc->size;
401*4882a593Smuzhiyun int oob_off = step * (ecc->bytes + ecc->prepad);
402*4882a593Smuzhiyun const u8 *data = buf + data_off;
403*4882a593Smuzhiyun const u8 *oob = chip->oob_poi + oob_off;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun if (rknand->bootromblocks && (offset < (7 * mtd->erasesize)))
406*4882a593Smuzhiyun rockchip_nand_hw_ecc_setup(mtd, ecc, NANDC_V9_BOOTROM_ECC);
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun index = rockchip_nand_make_bootrom_compat(mtd, page, oob,
409*4882a593Smuzhiyun rknand->bootromblocks);
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun memcpy_toio(sram_base, data, ecc->size);
412*4882a593Smuzhiyun memcpy_toio(rknand->regs + NANDC_REG_V9_SPARE0, &index, ecc->prepad);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun for (step = 1; step <= ecc->steps; step++) {
415*4882a593Smuzhiyun rockchip_nand_pio_xfer_start(rknand, NANDC_V9_WRITE,
416*4882a593Smuzhiyun (step - 1) & 0x1);
417*4882a593Smuzhiyun data_off = step * ecc->size;
418*4882a593Smuzhiyun oob_off = step * (ecc->bytes + ecc->prepad);
419*4882a593Smuzhiyun data = buf + data_off;
420*4882a593Smuzhiyun oob = chip->oob_poi + oob_off;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun if (step < ecc->steps) {
423*4882a593Smuzhiyun memcpy_toio(sram_base + NANDC_REG_V9_SRAM_SIZE *
424*4882a593Smuzhiyun (step & 1), data, ecc->size);
425*4882a593Smuzhiyun if (step & 1)
426*4882a593Smuzhiyun memcpy_toio(rknand->regs + NANDC_REG_V9_SPARE1,
427*4882a593Smuzhiyun oob, ecc->prepad);
428*4882a593Smuzhiyun else
429*4882a593Smuzhiyun memcpy_toio(rknand->regs + NANDC_REG_V9_SPARE0,
430*4882a593Smuzhiyun oob, ecc->prepad);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun ret = rockchip_nand_wait_pio_xfer_done(rknand);
434*4882a593Smuzhiyun if (ret)
435*4882a593Smuzhiyun return ret;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun rockchip_nand_write_extra_oob(mtd, chip->oob_poi);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if (rknand->bootromblocks)
441*4882a593Smuzhiyun rockchip_nand_hw_ecc_setup(mtd, ecc, rknand->ecc_strength);
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun return 0;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun static const u8 strengths[] = {70, 60, 40, 16};
447*4882a593Smuzhiyun
rockchip_nand_ecc_max_strength(struct mtd_info * mtd,struct nand_ecc_ctrl * ecc)448*4882a593Smuzhiyun static int rockchip_nand_ecc_max_strength(struct mtd_info *mtd,
449*4882a593Smuzhiyun struct nand_ecc_ctrl *ecc)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun uint32_t max_strength, index;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun max_strength = ((mtd->oobsize / ecc->steps) - ecc->prepad) * 8 / 14;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun for (index = 0; index < ARRAY_SIZE(strengths); index++)
456*4882a593Smuzhiyun if (max_strength >= strengths[index])
457*4882a593Smuzhiyun break;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun if (index >= ARRAY_SIZE(strengths))
460*4882a593Smuzhiyun return -ENOTSUPP;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun return strengths[index];
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
rockchip_nand_strength_is_valid(int strength)465*4882a593Smuzhiyun static bool rockchip_nand_strength_is_valid(int strength)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun uint32_t index;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun for (index = 0; index < ARRAY_SIZE(strengths); index++)
470*4882a593Smuzhiyun if (strength == strengths[index])
471*4882a593Smuzhiyun break;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun if (index == ARRAY_SIZE(strengths))
474*4882a593Smuzhiyun return false;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun return true;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
rockchip_nand_hw_ecc_ctrl_init(struct mtd_info * mtd,struct nand_ecc_ctrl * ecc)479*4882a593Smuzhiyun static int rockchip_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
480*4882a593Smuzhiyun struct nand_ecc_ctrl *ecc)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
483*4882a593Smuzhiyun struct rk_nand *rknand = to_rknand(chip->controller);
484*4882a593Smuzhiyun uint32_t strength;
485*4882a593Smuzhiyun int index;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun ecc->prepad = 4;
488*4882a593Smuzhiyun ecc->steps = mtd->writesize / ecc->size;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun if (fdtdec_get_bool(gd->fdt_blob, chip->flash_node,
491*4882a593Smuzhiyun "rockchip,protect-bootrom-blocks"))
492*4882a593Smuzhiyun rknand->bootromblocks = true;
493*4882a593Smuzhiyun else
494*4882a593Smuzhiyun rknand->bootromblocks = false;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun if (rockchip_nand_strength_is_valid(ecc->strength))
497*4882a593Smuzhiyun strength = ecc->strength;
498*4882a593Smuzhiyun else
499*4882a593Smuzhiyun strength = rockchip_nand_ecc_max_strength(mtd, ecc);
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun rockchip_nand_hw_ecc_setup(mtd, ecc, strength);
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun rknand->ecc_strength = ecc->strength;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun nand_oob_fix.eccbytes = ecc->bytes * ecc->steps;
506*4882a593Smuzhiyun for (index = 0; index < ecc->bytes; index++)
507*4882a593Smuzhiyun nand_oob_fix.eccpos[index] = index + ecc->prepad;
508*4882a593Smuzhiyun ecc->layout = &nand_oob_fix;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (mtd->oobsize < ((ecc->bytes + ecc->prepad) * ecc->steps)) {
511*4882a593Smuzhiyun return -EINVAL;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun return 0;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun
rockchip_nand_ecc_init(struct mtd_info * mtd,struct nand_ecc_ctrl * ecc)517*4882a593Smuzhiyun static int rockchip_nand_ecc_init(struct mtd_info *mtd,
518*4882a593Smuzhiyun struct nand_ecc_ctrl *ecc)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun int ret;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun switch (ecc->mode) {
523*4882a593Smuzhiyun case NAND_ECC_HW:
524*4882a593Smuzhiyun case NAND_ECC_HW_SYNDROME:
525*4882a593Smuzhiyun ret = rockchip_nand_hw_ecc_ctrl_init(mtd, ecc);
526*4882a593Smuzhiyun if (ret)
527*4882a593Smuzhiyun return ret;
528*4882a593Smuzhiyun ecc->read_page = rockchip_nand_hw_syndrome_pio_read_page;
529*4882a593Smuzhiyun ecc->write_page = rockchip_nand_hw_syndrome_pio_write_page;
530*4882a593Smuzhiyun break;
531*4882a593Smuzhiyun case NAND_ECC_SOFT_BCH:
532*4882a593Smuzhiyun case NAND_ECC_NONE:
533*4882a593Smuzhiyun case NAND_ECC_SOFT:
534*4882a593Smuzhiyun break;
535*4882a593Smuzhiyun default:
536*4882a593Smuzhiyun return -EINVAL;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun return 0;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun
rockchip_nand_block_bad(struct mtd_info * mtd,loff_t ofs)542*4882a593Smuzhiyun static int rockchip_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun int page, res = 0;
545*4882a593Smuzhiyun struct nand_chip *chip = mtd_to_nand(mtd);
546*4882a593Smuzhiyun u16 bad = 0xff;
547*4882a593Smuzhiyun int chipnr = (int)(ofs >> chip->chip_shift);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun page = (int)(ofs >> chip->page_shift) & chip->pagemask;
550*4882a593Smuzhiyun chip->select_chip(mtd, chipnr);
551*4882a593Smuzhiyun chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
552*4882a593Smuzhiyun if(rockchip_nand_hw_syndrome_pio_read_page(mtd,
553*4882a593Smuzhiyun chip, chip->buffers->databuf, 0, page) == -1) {
554*4882a593Smuzhiyun /* first page of the block*/
555*4882a593Smuzhiyun chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
556*4882a593Smuzhiyun bad = chip->read_byte(mtd);
557*4882a593Smuzhiyun if (bad != 0xFF)
558*4882a593Smuzhiyun res = 1;
559*4882a593Smuzhiyun /* second page of the block*/
560*4882a593Smuzhiyun chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
561*4882a593Smuzhiyun page + 1);
562*4882a593Smuzhiyun bad = chip->read_byte(mtd);
563*4882a593Smuzhiyun if (bad != 0xFF)
564*4882a593Smuzhiyun res = 1;
565*4882a593Smuzhiyun /* last page of the block */
566*4882a593Smuzhiyun page += ((mtd->erasesize - mtd->writesize) >> chip->chip_shift);
567*4882a593Smuzhiyun page--;
568*4882a593Smuzhiyun chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
569*4882a593Smuzhiyun bad = chip->read_byte(mtd);
570*4882a593Smuzhiyun if (bad != 0xFF)
571*4882a593Smuzhiyun res = 1;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun chip->select_chip(mtd, -1);
574*4882a593Smuzhiyun if (res)
575*4882a593Smuzhiyun printf("%s 0x%x %x %x\n", __func__, page, res, bad);
576*4882a593Smuzhiyun return res;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
rockchip_nand_chip_init(int node,struct rk_nand * rknand,int devnum)579*4882a593Smuzhiyun static int rockchip_nand_chip_init(int node, struct rk_nand *rknand, int devnum)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun const void *blob = gd->fdt_blob;
582*4882a593Smuzhiyun struct nand_chip *chip;
583*4882a593Smuzhiyun struct mtd_info *mtd;
584*4882a593Smuzhiyun int ret;
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun chip = kzalloc(sizeof(*chip), GFP_KERNEL);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun chip->chip_delay = 50;
589*4882a593Smuzhiyun chip->flash_node = node;
590*4882a593Smuzhiyun chip->select_chip = rockchip_nand_select_chip;
591*4882a593Smuzhiyun chip->cmd_ctrl = rockchip_nand_cmd_ctrl;
592*4882a593Smuzhiyun chip->read_buf = rockchip_nand_read_buf;
593*4882a593Smuzhiyun chip->write_buf = rockchip_nand_write_buf;
594*4882a593Smuzhiyun chip->read_byte = rockchip_nand_read_byte;
595*4882a593Smuzhiyun chip->dev_ready = rockchip_nand_dev_ready;
596*4882a593Smuzhiyun chip->controller = &rknand->controller;
597*4882a593Smuzhiyun chip->block_bad = rockchip_nand_block_bad;
598*4882a593Smuzhiyun chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
599*4882a593Smuzhiyun chip->options = NAND_NO_SUBPAGE_WRITE;
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun rknand->banks[devnum] = fdtdec_get_int(blob, node, "reg", -1);
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun if (rknand->banks[devnum] < 0)
604*4882a593Smuzhiyun return -EINVAL;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun mtd = nand_to_mtd(chip);
607*4882a593Smuzhiyun mtd->dev = rknand->dev;
608*4882a593Smuzhiyun if (rknand->dev)
609*4882a593Smuzhiyun rknand->dev->priv = mtd;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun ret = nand_scan_ident(mtd, 1, NULL);
612*4882a593Smuzhiyun if (ret)
613*4882a593Smuzhiyun return ret;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun ret = rockchip_nand_ecc_init(mtd, &chip->ecc);
616*4882a593Smuzhiyun if (ret) {
617*4882a593Smuzhiyun debug("rockchip_nand_ecc_init failed: %d\n", ret);
618*4882a593Smuzhiyun return ret;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun ret = nand_scan_tail(mtd);
622*4882a593Smuzhiyun if (ret) {
623*4882a593Smuzhiyun debug("nand_scan_tail failed: %d\n", ret);
624*4882a593Smuzhiyun return ret;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun ret = nand_register(devnum, mtd);
628*4882a593Smuzhiyun if (ret) {
629*4882a593Smuzhiyun debug("Failed to register mtd device: %d\n", ret);
630*4882a593Smuzhiyun return ret;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun memcpy(&rknand->mtd, mtd, sizeof(struct mtd_info));
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun return 0;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun
rockchip_nand_chips_init(int node,struct rk_nand * rknand)637*4882a593Smuzhiyun static int rockchip_nand_chips_init(int node, struct rk_nand *rknand)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun const void *blob = gd->fdt_blob;
640*4882a593Smuzhiyun int nand_node;
641*4882a593Smuzhiyun int ret, i = 0;
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0;
644*4882a593Smuzhiyun nand_node = fdt_next_subnode(blob, nand_node)) {
645*4882a593Smuzhiyun ret = rockchip_nand_chip_init(nand_node, rknand, i++);
646*4882a593Smuzhiyun if (ret)
647*4882a593Smuzhiyun return ret;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun return 0;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun #ifdef CONFIG_NAND_ROCKCHIP_DT
654*4882a593Smuzhiyun static const struct udevice_id rockchip_nandc_ids[] = {
655*4882a593Smuzhiyun { .compatible = "rockchip,rk-nandc" },
656*4882a593Smuzhiyun { }
657*4882a593Smuzhiyun };
658*4882a593Smuzhiyun
rockchip_nandc_probe(struct udevice * dev)659*4882a593Smuzhiyun static int rockchip_nandc_probe(struct udevice *dev)
660*4882a593Smuzhiyun {
661*4882a593Smuzhiyun const void *blob = gd->fdt_blob;
662*4882a593Smuzhiyun struct rk_nand *rknand = dev_get_priv(dev);
663*4882a593Smuzhiyun struct mtd_info *mtd = dev_get_uclass_priv(dev);
664*4882a593Smuzhiyun fdt_addr_t regs;
665*4882a593Smuzhiyun int ret = 0, node;
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC);
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun rknand->dev = dev;
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun regs = dev_read_addr(dev);
672*4882a593Smuzhiyun if (regs == FDT_ADDR_T_NONE) {
673*4882a593Smuzhiyun debug("Nand address not found\n");
674*4882a593Smuzhiyun return ret;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun rknand->regs = (void *)regs;
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun spin_lock_init(&rknand->controller.lock);
680*4882a593Smuzhiyun init_waitqueue_head(&rknand->controller.wq);
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun rockchip_nand_init(rknand);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun ret = rockchip_nand_chips_init(node, rknand);
685*4882a593Smuzhiyun if (ret)
686*4882a593Smuzhiyun debug("Failed to init nand chips\n");
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun memcpy(mtd, &rknand->mtd, sizeof(struct mtd_info));
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun return ret;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
rockchip_nandc_bind(struct udevice * udev)693*4882a593Smuzhiyun static int rockchip_nandc_bind(struct udevice *udev)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun int ret = 0;
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun #ifdef CONFIG_MTD_BLK
698*4882a593Smuzhiyun struct udevice *bdev;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun ret = blk_create_devicef(udev, "mtd_blk", "blk", IF_TYPE_MTD,
701*4882a593Smuzhiyun BLK_MTD_NAND, 512, 0, &bdev);
702*4882a593Smuzhiyun if (ret)
703*4882a593Smuzhiyun printf("Cannot create block device\n");
704*4882a593Smuzhiyun #endif
705*4882a593Smuzhiyun return ret;
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun U_BOOT_DRIVER(rk_nandc_v9) = {
709*4882a593Smuzhiyun .name = "rk_nandc_v9",
710*4882a593Smuzhiyun .id = UCLASS_MTD,
711*4882a593Smuzhiyun .of_match = rockchip_nandc_ids,
712*4882a593Smuzhiyun .bind = rockchip_nandc_bind,
713*4882a593Smuzhiyun .probe = rockchip_nandc_probe,
714*4882a593Smuzhiyun .priv_auto_alloc_size = sizeof(struct rk_nand),
715*4882a593Smuzhiyun };
716*4882a593Smuzhiyun
board_nand_init(void)717*4882a593Smuzhiyun void board_nand_init(void)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun struct udevice *dev;
720*4882a593Smuzhiyun int ret;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun ret = uclass_get_device_by_driver(UCLASS_MTD,
723*4882a593Smuzhiyun DM_GET_DRIVER(rk_nandc_v9),
724*4882a593Smuzhiyun &dev);
725*4882a593Smuzhiyun if (ret && ret != -ENODEV)
726*4882a593Smuzhiyun pr_err("Failed to initialize NAND controller. (error %d)\n",
727*4882a593Smuzhiyun ret);
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun #else
730*4882a593Smuzhiyun
board_nand_init(void)731*4882a593Smuzhiyun void board_nand_init(void)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun const void *blob = gd->fdt_blob;
734*4882a593Smuzhiyun struct rk_nand *rknand;
735*4882a593Smuzhiyun fdt_addr_t regs;
736*4882a593Smuzhiyun int node;
737*4882a593Smuzhiyun int ret;
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun rknand = kzalloc(sizeof(*rknand), GFP_KERNEL);
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC);
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun if (node < 0) {
744*4882a593Smuzhiyun debug("Nand node not found\n");
745*4882a593Smuzhiyun goto err;
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun if (!fdtdec_get_is_enabled(blob, node)) {
749*4882a593Smuzhiyun debug("Nand disabled in device tree\n");
750*4882a593Smuzhiyun goto err;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun regs = fdt_get_base_address(blob, node);
754*4882a593Smuzhiyun if (regs == FDT_ADDR_T_NONE) {
755*4882a593Smuzhiyun debug("Nand address not found\n");
756*4882a593Smuzhiyun goto err;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun rknand->regs = (void *)regs;
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun spin_lock_init(&rknand->controller.lock);
762*4882a593Smuzhiyun init_waitqueue_head(&rknand->controller.wq);
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun rockchip_nand_init(rknand);
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun ret = rockchip_nand_chips_init(node, rknand);
767*4882a593Smuzhiyun if (ret) {
768*4882a593Smuzhiyun debug("Failed to init nand chips\n");
769*4882a593Smuzhiyun goto err;
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun return;
773*4882a593Smuzhiyun err:
774*4882a593Smuzhiyun kfree(rknand);
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun #endif
778*4882a593Smuzhiyun
nand_spl_load_image(uint32_t offs,unsigned int size,void * dst)779*4882a593Smuzhiyun int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun struct mtd_info *mtd;
782*4882a593Smuzhiyun size_t length = size;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun mtd = get_nand_dev_by_index(0);
785*4882a593Smuzhiyun return nand_read_skip_bad(mtd, offs, &length, NULL, size, (u_char *)dst);
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun
nand_deselect(void)788*4882a593Smuzhiyun void nand_deselect(void) {}
789