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