xref: /rk3399_rockchip-uboot/drivers/mtd/nand/raw/rockchip_nand.c (revision 3659eeb49eed0c0dc93838741e7a91207241cc14)
157e25cf7SYifeng Zhao /*
257e25cf7SYifeng Zhao  * Copyright (c) 2017 Yifeng Zhao <yifeng.zhao@rock-chips.com>
357e25cf7SYifeng Zhao  * Copyright (c) 2017 Paweł Jarosz <paweljarosz3691@gmail.com>
457e25cf7SYifeng Zhao  *
557e25cf7SYifeng Zhao  * SPDX-License-Identifier:     GPL-2.0+
657e25cf7SYifeng Zhao  */
757e25cf7SYifeng Zhao 
857e25cf7SYifeng Zhao #include <common.h>
957e25cf7SYifeng Zhao #include <dm.h>
1057e25cf7SYifeng Zhao #include <fdtdec.h>
1157e25cf7SYifeng Zhao #include <inttypes.h>
1257e25cf7SYifeng Zhao #include <nand.h>
1357e25cf7SYifeng Zhao #include <linux/io.h>
1457e25cf7SYifeng Zhao #include <linux/ioport.h>
1557e25cf7SYifeng Zhao #include <linux/kernel.h>
1657e25cf7SYifeng Zhao #include <linux/mtd/mtd.h>
1757e25cf7SYifeng Zhao #include <linux/mtd/rawnand.h>
1857e25cf7SYifeng Zhao #include <linux/mtd/partitions.h>
1957e25cf7SYifeng Zhao 
2057e25cf7SYifeng Zhao DECLARE_GLOBAL_DATA_PTR;
2157e25cf7SYifeng Zhao 
2257e25cf7SYifeng Zhao #define NANDC_V6_BOOTROM_ECC	24
2357e25cf7SYifeng Zhao #define	NANDC_V6_NUM_BANKS	8
2457e25cf7SYifeng Zhao #define NANDC_V6_DEF_TIMEOUT	20000
2557e25cf7SYifeng Zhao #define NANDC_V6_READ		0
2657e25cf7SYifeng Zhao #define NANDC_V6_WRITE		1
2757e25cf7SYifeng Zhao 
2857e25cf7SYifeng Zhao #define	NANDC_REG_V6_FMCTL	0x00
2957e25cf7SYifeng Zhao #define	NANDC_REG_V6_FMWAIT	0x04
3057e25cf7SYifeng Zhao #define	NANDC_REG_V6_FLCTL	0x08
3157e25cf7SYifeng Zhao #define	NANDC_REG_V6_BCHCTL	0x0c
3257e25cf7SYifeng Zhao #define	NANDC_REG_V6_DMA_CFG	0x10
3357e25cf7SYifeng Zhao #define	NANDC_REG_V6_DMA_BUF0	0x14
3457e25cf7SYifeng Zhao #define	NANDC_REG_V6_DMA_BUF1	0x18
3557e25cf7SYifeng Zhao #define	NANDC_REG_V6_DMA_ST	0x1C
3657e25cf7SYifeng Zhao #define	NANDC_REG_V6_BCHST	0x20
3757e25cf7SYifeng Zhao #define	NANDC_REG_V6_RANDMZ	0x150
3857e25cf7SYifeng Zhao #define	NANDC_REG_V6_VER	0x160
3957e25cf7SYifeng Zhao #define	NANDC_REG_V6_INTEN	0x16C
4057e25cf7SYifeng Zhao #define	NANDC_REG_V6_INTCLR 	0x170
4157e25cf7SYifeng Zhao #define	NANDC_REG_V6_INTST	0x174
4257e25cf7SYifeng Zhao #define	NANDC_REG_V6_SPARE0	0x200
4357e25cf7SYifeng Zhao #define	NANDC_REG_V6_SPARE1	0x230
4457e25cf7SYifeng Zhao #define	NANDC_REG_V6_BANK0	0x800
4557e25cf7SYifeng Zhao #define	NANDC_REG_V6_SRAM0	0x1000
4657e25cf7SYifeng Zhao #define	NANDC_REG_V6_SRAM_SIZE	0x400
4757e25cf7SYifeng Zhao 
4857e25cf7SYifeng Zhao #define NANDC_REG_V6_DATA	0x00
4957e25cf7SYifeng Zhao #define NANDC_REG_V6_ADDR	0x04
5057e25cf7SYifeng Zhao #define NANDC_REG_V6_CMD	0x08
5157e25cf7SYifeng Zhao 
5257e25cf7SYifeng Zhao /* FMCTL */
5357e25cf7SYifeng Zhao #define NANDC_V6_FM_WP		BIT(8)
5457e25cf7SYifeng Zhao #define NANDC_V6_FM_CE_SEL_M	0xFF
5557e25cf7SYifeng Zhao #define NANDC_V6_FM_CE_SEL(x)	(1 << (x))
5657e25cf7SYifeng Zhao #define NANDC_V6_FM_FREADY	BIT(9)
5757e25cf7SYifeng Zhao 
5857e25cf7SYifeng Zhao /* FLCTL */
5957e25cf7SYifeng Zhao #define NANDC_V6_FL_RST		BIT(0)
6057e25cf7SYifeng Zhao #define NANDC_V6_FL_DIR_S	0x1
6157e25cf7SYifeng Zhao #define NANDC_V6_FL_XFER_START	BIT(2)
6257e25cf7SYifeng Zhao #define NANDC_V6_FL_XFER_EN	BIT(3)
6357e25cf7SYifeng Zhao #define NANDC_V6_FL_ST_BUF_S	0x4
6457e25cf7SYifeng Zhao #define NANDC_V6_FL_XFER_COUNT	BIT(5)
6557e25cf7SYifeng Zhao #define NANDC_V6_FL_ACORRECT	BIT(10)
6657e25cf7SYifeng Zhao #define NANDC_V6_FL_XFER_READY	BIT(20)
6757e25cf7SYifeng Zhao 
6857e25cf7SYifeng Zhao /* BCHCTL */
6957e25cf7SYifeng Zhao #define NAND_V6_BCH_REGION_S	0x5
7057e25cf7SYifeng Zhao #define NAND_V6_BCH_REGION_M	0x7
7157e25cf7SYifeng Zhao 
7257e25cf7SYifeng Zhao /* BCHST */
7357e25cf7SYifeng Zhao #define NANDC_V6_BCH0_ST_ERR	BIT(2)
7457e25cf7SYifeng Zhao #define NANDC_V6_BCH1_ST_ERR	BIT(15)
7557e25cf7SYifeng Zhao #define NANDC_V6_ECC_ERR_CNT0(x) ((((x & (0x1F << 3)) >> 3) \
7657e25cf7SYifeng Zhao 				| ((x & (1 << 27)) >> 22)) & 0x3F)
7757e25cf7SYifeng Zhao #define NANDC_V6_ECC_ERR_CNT1(x) ((((x & (0x1F << 16)) >> 16) \
7857e25cf7SYifeng Zhao 				| ((x & (1 << 29)) >> 24)) & 0x3F)
7957e25cf7SYifeng Zhao 
8057e25cf7SYifeng Zhao struct rk_nand {
8157e25cf7SYifeng Zhao 	uint32_t banks[NANDC_V6_NUM_BANKS];
8257e25cf7SYifeng Zhao 	struct nand_hw_control controller;
8357e25cf7SYifeng Zhao 	uint32_t ecc_strength;
8457e25cf7SYifeng Zhao 	struct mtd_info mtd;
8557e25cf7SYifeng Zhao 	bool bootromblocks;
8657e25cf7SYifeng Zhao 	void __iomem *regs;
8757e25cf7SYifeng Zhao 	int selected_bank;
8857e25cf7SYifeng Zhao 	struct udevice *dev;
8957e25cf7SYifeng Zhao };
9057e25cf7SYifeng Zhao 
9157e25cf7SYifeng Zhao static struct nand_ecclayout nand_oob_fix = {
9257e25cf7SYifeng Zhao 	.eccbytes = 24,
9357e25cf7SYifeng Zhao 	.eccpos = {
9457e25cf7SYifeng Zhao 		   4, 5, 6, 7, 8, 9, 10},
9557e25cf7SYifeng Zhao 	.oobfree = {
9657e25cf7SYifeng Zhao 		{.offset = 0,
9757e25cf7SYifeng Zhao 		 .length = 4} }
9857e25cf7SYifeng Zhao };
9957e25cf7SYifeng Zhao 
to_rknand(struct nand_hw_control * ctrl)10057e25cf7SYifeng Zhao static inline struct rk_nand *to_rknand(struct nand_hw_control *ctrl)
10157e25cf7SYifeng Zhao {
10257e25cf7SYifeng Zhao 	return container_of(ctrl, struct rk_nand, controller);
10357e25cf7SYifeng Zhao }
10457e25cf7SYifeng Zhao 
rockchip_nand_init(struct rk_nand * rknand)10557e25cf7SYifeng Zhao static void rockchip_nand_init(struct rk_nand *rknand)
10657e25cf7SYifeng Zhao {
10757e25cf7SYifeng Zhao 	writel(0, rknand->regs + NANDC_REG_V6_RANDMZ);
10857e25cf7SYifeng Zhao 	writel(0, rknand->regs + NANDC_REG_V6_DMA_CFG);
10957e25cf7SYifeng Zhao 	writel(0, rknand->regs + NANDC_REG_V6_BCHCTL);
11057e25cf7SYifeng Zhao 	writel(NANDC_V6_FM_WP, rknand->regs + NANDC_REG_V6_FMCTL);
11157e25cf7SYifeng Zhao 	writel(0x1081, rknand->regs + NANDC_REG_V6_FMWAIT);
11257e25cf7SYifeng Zhao }
11357e25cf7SYifeng Zhao 
rockchip_nand_select_chip(struct mtd_info * mtd,int chipnr)11457e25cf7SYifeng Zhao static void rockchip_nand_select_chip(struct mtd_info *mtd, int chipnr)
11557e25cf7SYifeng Zhao {
11657e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
11757e25cf7SYifeng Zhao 	struct rk_nand *rknand = to_rknand(chip->controller);
11857e25cf7SYifeng Zhao 	void __iomem *bank_base;
11957e25cf7SYifeng Zhao 	uint32_t reg;
12057e25cf7SYifeng Zhao 	int banknr;
12157e25cf7SYifeng Zhao 
12257e25cf7SYifeng Zhao 	reg = readl(rknand->regs + NANDC_REG_V6_FMCTL);
12357e25cf7SYifeng Zhao 	reg &= ~NANDC_V6_FM_CE_SEL_M;
12457e25cf7SYifeng Zhao 
12557e25cf7SYifeng Zhao 	if (chipnr == -1) {
12657e25cf7SYifeng Zhao 		banknr = -1;
12757e25cf7SYifeng Zhao 	} else {
12857e25cf7SYifeng Zhao 		banknr = rknand->banks[chipnr];
12957e25cf7SYifeng Zhao 		bank_base = rknand->regs + NANDC_REG_V6_BANK0 + banknr * 0x100;
13057e25cf7SYifeng Zhao 
13157e25cf7SYifeng Zhao 		chip->IO_ADDR_R = bank_base;
13257e25cf7SYifeng Zhao 		chip->IO_ADDR_W = bank_base;
13357e25cf7SYifeng Zhao 
13457e25cf7SYifeng Zhao 		reg |= 1 << banknr;
13557e25cf7SYifeng Zhao 	}
13657e25cf7SYifeng Zhao 	writel(reg, rknand->regs + NANDC_REG_V6_FMCTL);
13757e25cf7SYifeng Zhao 
13857e25cf7SYifeng Zhao 	rknand->selected_bank = banknr;
13957e25cf7SYifeng Zhao }
14057e25cf7SYifeng Zhao 
rockchip_nand_cmd_ctrl(struct mtd_info * mtd,int dat,unsigned int ctrl)14157e25cf7SYifeng Zhao static void rockchip_nand_cmd_ctrl(struct mtd_info *mtd,
14257e25cf7SYifeng Zhao 				   int dat,
14357e25cf7SYifeng Zhao 				   unsigned int ctrl)
14457e25cf7SYifeng Zhao {
14557e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
14657e25cf7SYifeng Zhao 	struct rk_nand *rknand = to_rknand(chip->controller);
14757e25cf7SYifeng Zhao 	void __iomem *bank_base = rknand->regs + NANDC_REG_V6_BANK0
14857e25cf7SYifeng Zhao 				+ rknand->selected_bank * 0x100;
14957e25cf7SYifeng Zhao 
15057e25cf7SYifeng Zhao 	if (ctrl & NAND_CTRL_CHANGE) {
15157e25cf7SYifeng Zhao 		if (ctrl & NAND_ALE)
15257e25cf7SYifeng Zhao 			bank_base += NANDC_REG_V6_ADDR;
15357e25cf7SYifeng Zhao 		else if (ctrl & NAND_CLE)
15457e25cf7SYifeng Zhao 			bank_base += NANDC_REG_V6_CMD;
15557e25cf7SYifeng Zhao 		chip->IO_ADDR_W = bank_base;
15657e25cf7SYifeng Zhao 	}
15757e25cf7SYifeng Zhao 
15857e25cf7SYifeng Zhao 	if (dat != NAND_CMD_NONE)
15957e25cf7SYifeng Zhao 		writeb(dat & 0xFF, chip->IO_ADDR_W);
16057e25cf7SYifeng Zhao }
16157e25cf7SYifeng Zhao 
rockchip_nand_read_buf(struct mtd_info * mtd,uint8_t * buf,int len)16257e25cf7SYifeng Zhao static void rockchip_nand_read_buf(struct mtd_info *mtd,
16357e25cf7SYifeng Zhao 				   uint8_t *buf,
16457e25cf7SYifeng Zhao 				   int len)
16557e25cf7SYifeng Zhao {
16657e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
16757e25cf7SYifeng Zhao 	struct rk_nand *rknand = to_rknand(chip->controller);
16857e25cf7SYifeng Zhao 	int offs = 0;
16957e25cf7SYifeng Zhao 	void __iomem *bank_base = rknand->regs + NANDC_REG_V6_BANK0
17057e25cf7SYifeng Zhao 				+ rknand->selected_bank * 0x100;
17157e25cf7SYifeng Zhao 
17257e25cf7SYifeng Zhao 	for (offs = 0; offs < len; offs++)
17357e25cf7SYifeng Zhao 		buf[offs] = readb(bank_base);
17457e25cf7SYifeng Zhao }
17557e25cf7SYifeng Zhao 
rockchip_nand_write_buf(struct mtd_info * mtd,const uint8_t * buf,int len)17657e25cf7SYifeng Zhao static void rockchip_nand_write_buf(struct mtd_info *mtd,
17757e25cf7SYifeng Zhao 				    const uint8_t *buf,
17857e25cf7SYifeng Zhao 				    int len)
17957e25cf7SYifeng Zhao {
18057e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
18157e25cf7SYifeng Zhao 	struct rk_nand *rknand = to_rknand(chip->controller);
18257e25cf7SYifeng Zhao 	int offs = 0;
18357e25cf7SYifeng Zhao 	void __iomem *bank_base = rknand->regs + NANDC_REG_V6_BANK0
18457e25cf7SYifeng Zhao 				+ rknand->selected_bank * 0x100;
18557e25cf7SYifeng Zhao 
18657e25cf7SYifeng Zhao 	for (offs = 0; offs < len; offs++)
18757e25cf7SYifeng Zhao 		writeb(buf[offs], bank_base);
18857e25cf7SYifeng Zhao }
18957e25cf7SYifeng Zhao 
rockchip_nand_read_byte(struct mtd_info * mtd)19057e25cf7SYifeng Zhao static uint8_t rockchip_nand_read_byte(struct mtd_info *mtd)
19157e25cf7SYifeng Zhao {
19257e25cf7SYifeng Zhao 	uint8_t ret;
19357e25cf7SYifeng Zhao 
19457e25cf7SYifeng Zhao 	rockchip_nand_read_buf(mtd, &ret, 1);
19557e25cf7SYifeng Zhao 
19657e25cf7SYifeng Zhao 	return ret;
19757e25cf7SYifeng Zhao }
19857e25cf7SYifeng Zhao 
rockchip_nand_dev_ready(struct mtd_info * mtd)19957e25cf7SYifeng Zhao static int rockchip_nand_dev_ready(struct mtd_info *mtd)
20057e25cf7SYifeng Zhao {
20157e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
20257e25cf7SYifeng Zhao 	struct rk_nand *rknand = to_rknand(chip->controller);
20357e25cf7SYifeng Zhao 
20457e25cf7SYifeng Zhao 	if (readl(rknand->regs + NANDC_REG_V6_FMCTL) & NANDC_V6_FM_FREADY)
20557e25cf7SYifeng Zhao 		return 1;
20657e25cf7SYifeng Zhao 
20757e25cf7SYifeng Zhao 	return 0;
20857e25cf7SYifeng Zhao }
20957e25cf7SYifeng Zhao 
rockchip_nand_hw_ecc_setup(struct mtd_info * mtd,struct nand_ecc_ctrl * ecc,uint32_t strength)21057e25cf7SYifeng Zhao static int rockchip_nand_hw_ecc_setup(struct mtd_info *mtd,
21157e25cf7SYifeng Zhao 				      struct nand_ecc_ctrl *ecc,
21257e25cf7SYifeng Zhao 				      uint32_t strength)
21357e25cf7SYifeng Zhao {
21457e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
21557e25cf7SYifeng Zhao 	struct rk_nand *rknand = to_rknand(chip->controller);
21657e25cf7SYifeng Zhao 	u32 reg;
21757e25cf7SYifeng Zhao 
21857e25cf7SYifeng Zhao 	ecc->strength = strength;
21957e25cf7SYifeng Zhao 	ecc->bytes = DIV_ROUND_UP(ecc->strength * 14, 8);
22057e25cf7SYifeng Zhao 	ecc->bytes = ALIGN(ecc->bytes, 2);
22157e25cf7SYifeng Zhao 
22257e25cf7SYifeng Zhao 	switch (ecc->strength) {
22357e25cf7SYifeng Zhao 	case 60:
22457e25cf7SYifeng Zhao 		reg = 0x00040010;
22557e25cf7SYifeng Zhao 		break;
22657e25cf7SYifeng Zhao 	case 40:
22757e25cf7SYifeng Zhao 		reg = 0x00040000;
22857e25cf7SYifeng Zhao 		break;
22957e25cf7SYifeng Zhao 	case 24:
23057e25cf7SYifeng Zhao 		reg = 0x00000010;
23157e25cf7SYifeng Zhao 		break;
23257e25cf7SYifeng Zhao 	case 16:
23357e25cf7SYifeng Zhao 		reg = 0x00000000;
23457e25cf7SYifeng Zhao 		break;
23557e25cf7SYifeng Zhao 	default:
23657e25cf7SYifeng Zhao 		return -EINVAL;
23757e25cf7SYifeng Zhao 	}
23857e25cf7SYifeng Zhao 	writel(reg, rknand->regs + NANDC_REG_V6_BCHCTL);
23957e25cf7SYifeng Zhao 
24057e25cf7SYifeng Zhao 	return 0;
24157e25cf7SYifeng Zhao }
24257e25cf7SYifeng Zhao 
rockchip_nand_pio_xfer_start(struct rk_nand * rknand,u8 dir,u8 st_buf)24357e25cf7SYifeng Zhao static void rockchip_nand_pio_xfer_start(struct rk_nand *rknand,
24457e25cf7SYifeng Zhao 					 u8 dir,
24557e25cf7SYifeng Zhao 					 u8 st_buf)
24657e25cf7SYifeng Zhao {
24757e25cf7SYifeng Zhao 	u32 reg;
24857e25cf7SYifeng Zhao 
24957e25cf7SYifeng Zhao 	reg = readl(rknand->regs + NANDC_REG_V6_BCHCTL);
25057e25cf7SYifeng Zhao 	reg = (reg & (~(NAND_V6_BCH_REGION_M << NAND_V6_BCH_REGION_S))) |
25157e25cf7SYifeng Zhao 	      (rknand->selected_bank << NAND_V6_BCH_REGION_S);
25257e25cf7SYifeng Zhao 	writel(reg, rknand->regs + NANDC_REG_V6_BCHCTL);
25357e25cf7SYifeng Zhao 
25457e25cf7SYifeng Zhao 	reg = (dir << NANDC_V6_FL_DIR_S) | (st_buf << NANDC_V6_FL_ST_BUF_S) |
25557e25cf7SYifeng Zhao 	      NANDC_V6_FL_XFER_EN | NANDC_V6_FL_XFER_COUNT |
25657e25cf7SYifeng Zhao 	      NANDC_V6_FL_ACORRECT;
25757e25cf7SYifeng Zhao 	writel(reg, rknand->regs + NANDC_REG_V6_FLCTL);
25857e25cf7SYifeng Zhao 
25957e25cf7SYifeng Zhao 	reg |= NANDC_V6_FL_XFER_START;
26057e25cf7SYifeng Zhao 	writel(reg, rknand->regs + NANDC_REG_V6_FLCTL);
26157e25cf7SYifeng Zhao }
26257e25cf7SYifeng Zhao 
rockchip_nand_wait_pio_xfer_done(struct rk_nand * rknand)26357e25cf7SYifeng Zhao static int rockchip_nand_wait_pio_xfer_done(struct rk_nand *rknand)
26457e25cf7SYifeng Zhao {
26557e25cf7SYifeng Zhao 	int timeout = NANDC_V6_DEF_TIMEOUT;
26657e25cf7SYifeng Zhao 	int reg;
26757e25cf7SYifeng Zhao 
26857e25cf7SYifeng Zhao 	while (timeout--) {
26957e25cf7SYifeng Zhao 		reg = readl(rknand->regs + NANDC_REG_V6_FLCTL);
27057e25cf7SYifeng Zhao 
27157e25cf7SYifeng Zhao 		if ((reg & NANDC_V6_FL_XFER_READY) != 0)
27257e25cf7SYifeng Zhao 			break;
27357e25cf7SYifeng Zhao 
27457e25cf7SYifeng Zhao 		udelay(1);
27557e25cf7SYifeng Zhao 	}
27657e25cf7SYifeng Zhao 
27757e25cf7SYifeng Zhao 	if (timeout == 0)
27857e25cf7SYifeng Zhao 		return -1;
27957e25cf7SYifeng Zhao 
28057e25cf7SYifeng Zhao 	return 0;
28157e25cf7SYifeng Zhao }
28257e25cf7SYifeng Zhao 
rockchip_nand_read_extra_oob(struct mtd_info * mtd,u8 * oob)28357e25cf7SYifeng Zhao static void rockchip_nand_read_extra_oob(struct mtd_info *mtd, u8 *oob)
28457e25cf7SYifeng Zhao {
28557e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
28657e25cf7SYifeng Zhao 	struct nand_ecc_ctrl *ecc = &chip->ecc;
28757e25cf7SYifeng Zhao 	int offset = ((ecc->bytes + ecc->prepad) * ecc->steps);
28857e25cf7SYifeng Zhao 	int len = mtd->oobsize - offset;
28957e25cf7SYifeng Zhao 
29057e25cf7SYifeng Zhao 	if (len <= 0)
29157e25cf7SYifeng Zhao 		return;
29257e25cf7SYifeng Zhao 
29357e25cf7SYifeng Zhao 	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset + mtd->writesize, -1);
29457e25cf7SYifeng Zhao 
29557e25cf7SYifeng Zhao 	rockchip_nand_read_buf(mtd, oob + offset, len);
29657e25cf7SYifeng Zhao }
29757e25cf7SYifeng Zhao 
rockchip_nand_write_extra_oob(struct mtd_info * mtd,u8 * oob)29857e25cf7SYifeng Zhao static void rockchip_nand_write_extra_oob(struct mtd_info *mtd, u8 *oob)
29957e25cf7SYifeng Zhao {
30057e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
30157e25cf7SYifeng Zhao 	struct nand_ecc_ctrl *ecc = &chip->ecc;
30257e25cf7SYifeng Zhao 	int offset = ((ecc->bytes + ecc->prepad) * ecc->steps);
30357e25cf7SYifeng Zhao 	int len = mtd->oobsize - offset;
30457e25cf7SYifeng Zhao 
30557e25cf7SYifeng Zhao 	if (len <= 0)
30657e25cf7SYifeng Zhao 		return;
30757e25cf7SYifeng Zhao 
30857e25cf7SYifeng Zhao 	chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset + mtd->writesize, -1);
30957e25cf7SYifeng Zhao 
31057e25cf7SYifeng Zhao 	rockchip_nand_write_buf(mtd, oob + offset, len);
31157e25cf7SYifeng Zhao }
31257e25cf7SYifeng Zhao 
rockchip_nand_hw_syndrome_pio_read_page(struct mtd_info * mtd,struct nand_chip * chip,uint8_t * buf,int oob_required,int page)31357e25cf7SYifeng Zhao static int rockchip_nand_hw_syndrome_pio_read_page(struct mtd_info *mtd,
31457e25cf7SYifeng Zhao 						   struct nand_chip *chip,
31557e25cf7SYifeng Zhao 						   uint8_t *buf,
31657e25cf7SYifeng Zhao 						   int oob_required,
31757e25cf7SYifeng Zhao 						   int page)
31857e25cf7SYifeng Zhao {
31957e25cf7SYifeng Zhao 	struct rk_nand *rknand = to_rknand(chip->controller);
32057e25cf7SYifeng Zhao 	struct nand_ecc_ctrl *ecc = &chip->ecc;
32157e25cf7SYifeng Zhao 	void __iomem *sram_base = rknand->regs + NANDC_REG_V6_SRAM0;
32257e25cf7SYifeng Zhao 	unsigned int max_bitflips = 0;
32357e25cf7SYifeng Zhao 	int ret, step, bch_st;
32457e25cf7SYifeng Zhao 	int offset = page * mtd->writesize;
32557e25cf7SYifeng Zhao 
32657e25cf7SYifeng Zhao 	if (rknand->bootromblocks && (offset < (7 * mtd->erasesize)))
32757e25cf7SYifeng Zhao 		rockchip_nand_hw_ecc_setup(mtd, ecc, NANDC_V6_BOOTROM_ECC);
32857e25cf7SYifeng Zhao 
32957e25cf7SYifeng Zhao 	rockchip_nand_pio_xfer_start(rknand, NANDC_V6_READ, 0);
33057e25cf7SYifeng Zhao 
33157e25cf7SYifeng Zhao 	for (step = 0; step < ecc->steps; step++) {
33257e25cf7SYifeng Zhao 		int data_off = step * ecc->size;
33357e25cf7SYifeng Zhao 		int oob_off = step * (ecc->bytes + ecc->prepad);
33457e25cf7SYifeng Zhao 		u8 *data = buf + data_off;
33557e25cf7SYifeng Zhao 		u8 *oob = chip->oob_poi + oob_off;
33657e25cf7SYifeng Zhao 
33757e25cf7SYifeng Zhao 		ret = rockchip_nand_wait_pio_xfer_done(rknand);
33857e25cf7SYifeng Zhao 		if (ret)
33957e25cf7SYifeng Zhao 			return ret;
34057e25cf7SYifeng Zhao 
34157e25cf7SYifeng Zhao 		bch_st = readl(rknand->regs + NANDC_REG_V6_BCHST);
34257e25cf7SYifeng Zhao 
34357e25cf7SYifeng Zhao 		if (bch_st & NANDC_V6_BCH0_ST_ERR) {
34457e25cf7SYifeng Zhao 			mtd->ecc_stats.failed++;
34557e25cf7SYifeng Zhao 			max_bitflips = -1;
34657e25cf7SYifeng Zhao 		} else {
34757e25cf7SYifeng Zhao 			ret = NANDC_V6_ECC_ERR_CNT0(bch_st);
34857e25cf7SYifeng Zhao 			mtd->ecc_stats.corrected += ret;
34957e25cf7SYifeng Zhao 			max_bitflips = max_t(unsigned int, max_bitflips, ret);
35057e25cf7SYifeng Zhao 		}
35157e25cf7SYifeng Zhao 
35257e25cf7SYifeng Zhao 		if ((step + 1) < ecc->steps)
35357e25cf7SYifeng Zhao 			rockchip_nand_pio_xfer_start(rknand, NANDC_V6_READ,
35457e25cf7SYifeng Zhao 					      		(step + 1) & 0x1);
35557e25cf7SYifeng Zhao 
35657e25cf7SYifeng Zhao 		memcpy_fromio(data, sram_base + NANDC_REG_V6_SRAM_SIZE *
35757e25cf7SYifeng Zhao 			     				(step & 1), ecc->size);
35857e25cf7SYifeng Zhao 
35957e25cf7SYifeng Zhao 		if (step & 1)
36057e25cf7SYifeng Zhao 			memcpy_fromio(oob, rknand->regs + NANDC_REG_V6_SPARE1, 4);
36157e25cf7SYifeng Zhao 		else
36257e25cf7SYifeng Zhao 			memcpy_fromio(oob, rknand->regs + NANDC_REG_V6_SPARE0, 4);
36357e25cf7SYifeng Zhao 	}
36457e25cf7SYifeng Zhao 
36557e25cf7SYifeng Zhao 	rockchip_nand_read_extra_oob(mtd, chip->oob_poi);
36657e25cf7SYifeng Zhao 
36757e25cf7SYifeng Zhao 	if (rknand->bootromblocks)
36857e25cf7SYifeng Zhao 		rockchip_nand_hw_ecc_setup(mtd, ecc, rknand->ecc_strength);
36957e25cf7SYifeng Zhao 
37057e25cf7SYifeng Zhao 	return max_bitflips;
37157e25cf7SYifeng Zhao }
37257e25cf7SYifeng Zhao 
rockchip_nand_make_bootrom_compat(struct mtd_info * mtd,int page,const u8 * oob,bool bootromblocks)37357e25cf7SYifeng Zhao static uint32_t rockchip_nand_make_bootrom_compat(struct mtd_info *mtd,
37457e25cf7SYifeng Zhao 						  int page,
37557e25cf7SYifeng Zhao 						  const u8 *oob,
37657e25cf7SYifeng Zhao 						  bool bootromblocks)
37757e25cf7SYifeng Zhao {
37857e25cf7SYifeng Zhao 	int pages_per_block = mtd->erasesize / mtd->writesize;
37957e25cf7SYifeng Zhao 	int offset = page * mtd->writesize;
38057e25cf7SYifeng Zhao 
38157e25cf7SYifeng Zhao 	if ((offset < (2 * mtd->erasesize)) || !(page % 2) ||
38257e25cf7SYifeng Zhao 	    (offset >= (7 * mtd->erasesize)) || !bootromblocks)
38357e25cf7SYifeng Zhao 		return oob[3] | (oob[2] << 8) | (oob[1] << 16) | (oob[0] << 24);
38457e25cf7SYifeng Zhao 
38557e25cf7SYifeng Zhao 	return (page % pages_per_block + 1) * 4;
38657e25cf7SYifeng Zhao }
38757e25cf7SYifeng Zhao 
rockchip_nand_hw_syndrome_pio_write_page(struct mtd_info * mtd,struct nand_chip * chip,const uint8_t * buf,int oob_required,int page)38857e25cf7SYifeng Zhao static int rockchip_nand_hw_syndrome_pio_write_page(struct mtd_info *mtd,
38957e25cf7SYifeng Zhao 						    struct nand_chip *chip,
39057e25cf7SYifeng Zhao 						    const uint8_t *buf,
39157e25cf7SYifeng Zhao 						    int oob_required,
39257e25cf7SYifeng Zhao 						    int page)
39357e25cf7SYifeng Zhao {
39457e25cf7SYifeng Zhao 	struct rk_nand *rknand = to_rknand(chip->controller);
39557e25cf7SYifeng Zhao 	struct nand_ecc_ctrl *ecc = &chip->ecc;
39657e25cf7SYifeng Zhao 	void __iomem *sram_base = rknand->regs + NANDC_REG_V6_SRAM0;
39757e25cf7SYifeng Zhao 	int ret, index, step = 0;
39857e25cf7SYifeng Zhao 	int offset = page * mtd->writesize;
39957e25cf7SYifeng Zhao 	int data_off = step * ecc->size;
40057e25cf7SYifeng Zhao 	int oob_off = step * (ecc->bytes + ecc->prepad);
40157e25cf7SYifeng Zhao 	const u8 *data = buf + data_off;
40257e25cf7SYifeng Zhao 	const u8 *oob = chip->oob_poi + oob_off;
40357e25cf7SYifeng Zhao 
40457e25cf7SYifeng Zhao 	if (rknand->bootromblocks && (offset < (7 * mtd->erasesize)))
40557e25cf7SYifeng Zhao 		rockchip_nand_hw_ecc_setup(mtd, ecc, NANDC_V6_BOOTROM_ECC);
40657e25cf7SYifeng Zhao 
40757e25cf7SYifeng Zhao 	index = rockchip_nand_make_bootrom_compat(mtd, page, oob,
40857e25cf7SYifeng Zhao 					   rknand->bootromblocks);
40957e25cf7SYifeng Zhao 
41057e25cf7SYifeng Zhao 	memcpy_toio(sram_base, data, ecc->size);
41157e25cf7SYifeng Zhao 	memcpy_toio(rknand->regs + NANDC_REG_V6_SPARE0, &index, ecc->prepad);
41257e25cf7SYifeng Zhao 
41357e25cf7SYifeng Zhao 	for (step = 1; step <= ecc->steps; step++) {
41457e25cf7SYifeng Zhao 		rockchip_nand_pio_xfer_start(rknand, NANDC_V6_WRITE,
41557e25cf7SYifeng Zhao 					     (step - 1) & 0x1);
41657e25cf7SYifeng Zhao 
41757e25cf7SYifeng Zhao 		data_off = step * ecc->size;
41857e25cf7SYifeng Zhao 		oob_off = step * (ecc->bytes + ecc->prepad);
41957e25cf7SYifeng Zhao 		data = buf + data_off;
42057e25cf7SYifeng Zhao 		oob = chip->oob_poi + oob_off;
42157e25cf7SYifeng Zhao 
42257e25cf7SYifeng Zhao 		if (step < ecc->steps) {
42357e25cf7SYifeng Zhao 			memcpy_toio(sram_base + NANDC_REG_V6_SRAM_SIZE *
42457e25cf7SYifeng Zhao 				    (step & 1), data, ecc->size);
42557e25cf7SYifeng Zhao 			if (step & 1)
42657e25cf7SYifeng Zhao 				memcpy_toio(rknand->regs + NANDC_REG_V6_SPARE1,
42757e25cf7SYifeng Zhao 					    oob, ecc->prepad);
42857e25cf7SYifeng Zhao 			else
42957e25cf7SYifeng Zhao 				memcpy_toio(rknand->regs + NANDC_REG_V6_SPARE0,
43057e25cf7SYifeng Zhao 					    oob, ecc->prepad);
43157e25cf7SYifeng Zhao 		}
43257e25cf7SYifeng Zhao 
43357e25cf7SYifeng Zhao 		ret = rockchip_nand_wait_pio_xfer_done(rknand);
43457e25cf7SYifeng Zhao 		if (ret)
43557e25cf7SYifeng Zhao 			return ret;
43657e25cf7SYifeng Zhao 	}
43757e25cf7SYifeng Zhao 
43857e25cf7SYifeng Zhao 	rockchip_nand_write_extra_oob(mtd, chip->oob_poi);
43957e25cf7SYifeng Zhao 
44057e25cf7SYifeng Zhao 	rockchip_nand_hw_ecc_setup(mtd, ecc, rknand->ecc_strength);
44157e25cf7SYifeng Zhao 
44257e25cf7SYifeng Zhao 	return 0;
44357e25cf7SYifeng Zhao }
44457e25cf7SYifeng Zhao 
44557e25cf7SYifeng Zhao static const u8 strengths[] = {60, 40, 24, 16};
44657e25cf7SYifeng Zhao 
rockchip_nand_ecc_max_strength(struct mtd_info * mtd,struct nand_ecc_ctrl * ecc)44757e25cf7SYifeng Zhao static int rockchip_nand_ecc_max_strength(struct mtd_info *mtd,
44857e25cf7SYifeng Zhao 					  struct nand_ecc_ctrl *ecc)
44957e25cf7SYifeng Zhao {
45057e25cf7SYifeng Zhao 	uint32_t max_strength, index;
45157e25cf7SYifeng Zhao 
45257e25cf7SYifeng Zhao 	max_strength = ((mtd->oobsize / ecc->steps) - ecc->prepad) * 8 / 14;
45357e25cf7SYifeng Zhao 
45457e25cf7SYifeng Zhao 	for (index = 0; index < ARRAY_SIZE(strengths); index++)
45557e25cf7SYifeng Zhao 		if (max_strength >= strengths[index])
45657e25cf7SYifeng Zhao 			break;
45757e25cf7SYifeng Zhao 
45857e25cf7SYifeng Zhao 	if (index >= ARRAY_SIZE(strengths))
45957e25cf7SYifeng Zhao 		return -ENOTSUPP;
46057e25cf7SYifeng Zhao 
46157e25cf7SYifeng Zhao 	return strengths[index];
46257e25cf7SYifeng Zhao }
46357e25cf7SYifeng Zhao 
rockchip_nand_strength_is_valid(int strength)46457e25cf7SYifeng Zhao static bool rockchip_nand_strength_is_valid(int strength)
46557e25cf7SYifeng Zhao {
46657e25cf7SYifeng Zhao 	uint32_t index;
46757e25cf7SYifeng Zhao 
46857e25cf7SYifeng Zhao 	for (index = 0; index < ARRAY_SIZE(strengths); index++)
46957e25cf7SYifeng Zhao 		if (strength == strengths[index])
47057e25cf7SYifeng Zhao 			break;
47157e25cf7SYifeng Zhao 
47257e25cf7SYifeng Zhao 	if (index == ARRAY_SIZE(strengths))
47357e25cf7SYifeng Zhao 		return false;
47457e25cf7SYifeng Zhao 
47557e25cf7SYifeng Zhao 	return true;
47657e25cf7SYifeng Zhao }
47757e25cf7SYifeng Zhao 
rockchip_nand_hw_ecc_ctrl_init(struct mtd_info * mtd,struct nand_ecc_ctrl * ecc)47857e25cf7SYifeng Zhao static int rockchip_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
47957e25cf7SYifeng Zhao 					  struct nand_ecc_ctrl *ecc)
48057e25cf7SYifeng Zhao {
48157e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
48257e25cf7SYifeng Zhao 	struct rk_nand *rknand = to_rknand(chip->controller);
48357e25cf7SYifeng Zhao 	uint32_t strength;
48457e25cf7SYifeng Zhao 	int index;
48557e25cf7SYifeng Zhao 
48657e25cf7SYifeng Zhao 	ecc->prepad = 4;
48757e25cf7SYifeng Zhao 	ecc->steps = mtd->writesize / ecc->size;
48857e25cf7SYifeng Zhao 
48957e25cf7SYifeng Zhao 	if (fdtdec_get_bool(gd->fdt_blob, chip->flash_node,
49057e25cf7SYifeng Zhao 			    "rockchip,protect-bootrom-blocks"))
49157e25cf7SYifeng Zhao                 rknand->bootromblocks = true;
49257e25cf7SYifeng Zhao 	else
49357e25cf7SYifeng Zhao 		rknand->bootromblocks = false;
49457e25cf7SYifeng Zhao 
49557e25cf7SYifeng Zhao 	if (rockchip_nand_strength_is_valid(ecc->strength))
49657e25cf7SYifeng Zhao 		strength = ecc->strength;
49757e25cf7SYifeng Zhao 	else
49857e25cf7SYifeng Zhao 		strength = rockchip_nand_ecc_max_strength(mtd, ecc);
49957e25cf7SYifeng Zhao 
50057e25cf7SYifeng Zhao 	rockchip_nand_hw_ecc_setup(mtd, ecc, strength);
50157e25cf7SYifeng Zhao 
50257e25cf7SYifeng Zhao 	rknand->ecc_strength = ecc->strength;
50357e25cf7SYifeng Zhao 
50457e25cf7SYifeng Zhao 	nand_oob_fix.eccbytes = ecc->bytes * ecc->steps;
50557e25cf7SYifeng Zhao 	for (index = 0; index < ecc->bytes; index++)
50657e25cf7SYifeng Zhao 		nand_oob_fix.eccpos[index] = index + ecc->prepad;
50757e25cf7SYifeng Zhao 	ecc->layout = &nand_oob_fix;
50857e25cf7SYifeng Zhao 
50957e25cf7SYifeng Zhao 	if (mtd->oobsize < ((ecc->bytes + ecc->prepad) * ecc->steps)) {
51057e25cf7SYifeng Zhao 		return -EINVAL;
51157e25cf7SYifeng Zhao 	}
51257e25cf7SYifeng Zhao 
51357e25cf7SYifeng Zhao 	return 0;
51457e25cf7SYifeng Zhao }
51557e25cf7SYifeng Zhao 
rockchip_nand_ecc_init(struct mtd_info * mtd,struct nand_ecc_ctrl * ecc)51657e25cf7SYifeng Zhao static int rockchip_nand_ecc_init(struct mtd_info *mtd,
51757e25cf7SYifeng Zhao 				  struct nand_ecc_ctrl *ecc)
51857e25cf7SYifeng Zhao {
51957e25cf7SYifeng Zhao 	int ret;
52057e25cf7SYifeng Zhao 
52157e25cf7SYifeng Zhao 	switch (ecc->mode) {
522c23da6b7SJon Lin 	case NAND_ECC_HW:
52357e25cf7SYifeng Zhao 	case NAND_ECC_HW_SYNDROME:
52457e25cf7SYifeng Zhao 		ret = rockchip_nand_hw_ecc_ctrl_init(mtd, ecc);
52557e25cf7SYifeng Zhao 		if (ret)
52657e25cf7SYifeng Zhao 			return ret;
52757e25cf7SYifeng Zhao 		ecc->read_page =  rockchip_nand_hw_syndrome_pio_read_page;
52857e25cf7SYifeng Zhao 		ecc->write_page = rockchip_nand_hw_syndrome_pio_write_page;
52957e25cf7SYifeng Zhao 		break;
53057e25cf7SYifeng Zhao 	case NAND_ECC_SOFT_BCH:
53157e25cf7SYifeng Zhao 	case NAND_ECC_NONE:
53257e25cf7SYifeng Zhao 	case NAND_ECC_SOFT:
53357e25cf7SYifeng Zhao 		break;
53457e25cf7SYifeng Zhao 	default:
53557e25cf7SYifeng Zhao 		return -EINVAL;
53657e25cf7SYifeng Zhao 	}
53757e25cf7SYifeng Zhao 
53857e25cf7SYifeng Zhao 	return 0;
53957e25cf7SYifeng Zhao }
54057e25cf7SYifeng Zhao 
rockchip_nand_block_bad(struct mtd_info * mtd,loff_t ofs)54157e25cf7SYifeng Zhao static int rockchip_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
54257e25cf7SYifeng Zhao {
54357e25cf7SYifeng Zhao 	int page, res = 0;
54457e25cf7SYifeng Zhao 	struct nand_chip *chip = mtd_to_nand(mtd);
54557e25cf7SYifeng Zhao 	u16 bad = 0xff;
54657e25cf7SYifeng Zhao 	int chipnr = (int)(ofs >> chip->chip_shift);
54757e25cf7SYifeng Zhao 
54857e25cf7SYifeng Zhao 	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
54957e25cf7SYifeng Zhao 	chip->select_chip(mtd, chipnr);
55057e25cf7SYifeng Zhao 	chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
55157e25cf7SYifeng Zhao 	if(rockchip_nand_hw_syndrome_pio_read_page(mtd,
55257e25cf7SYifeng Zhao 	   chip, chip->buffers->databuf, 0, page) == -1) {
55357e25cf7SYifeng Zhao 		/* first page of the block*/
55457e25cf7SYifeng Zhao 		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
55557e25cf7SYifeng Zhao 		bad = chip->read_byte(mtd);
55657e25cf7SYifeng Zhao 		if (bad != 0xFF)
55757e25cf7SYifeng Zhao 			res = 1;
55857e25cf7SYifeng Zhao 		/* second page of the block*/
55957e25cf7SYifeng Zhao 		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
56057e25cf7SYifeng Zhao 			      page + 1);
56157e25cf7SYifeng Zhao 		bad = chip->read_byte(mtd);
56257e25cf7SYifeng Zhao 		if (bad != 0xFF)
56357e25cf7SYifeng Zhao 			res = 1;
56457e25cf7SYifeng Zhao 		/* last page of the block */
565*3659eeb4SJon Lin 		page += ((mtd->erasesize - mtd->writesize) >> chip->page_shift);
56657e25cf7SYifeng Zhao 		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
56757e25cf7SYifeng Zhao 		bad = chip->read_byte(mtd);
56857e25cf7SYifeng Zhao 		if (bad != 0xFF)
56957e25cf7SYifeng Zhao 			res = 1;
57057e25cf7SYifeng Zhao 	}
57157e25cf7SYifeng Zhao 	chip->select_chip(mtd, -1);
57257e25cf7SYifeng Zhao 	if (res)
57357e25cf7SYifeng Zhao 		printf("%s 0x%x %x %x\n", __func__, page, res, bad);
57457e25cf7SYifeng Zhao 	return res;
57557e25cf7SYifeng Zhao }
57657e25cf7SYifeng Zhao 
rockchip_nand_chip_init(int node,struct rk_nand * rknand,int devnum)57757e25cf7SYifeng Zhao static int rockchip_nand_chip_init(int node, struct rk_nand *rknand, int devnum)
57857e25cf7SYifeng Zhao {
57957e25cf7SYifeng Zhao 	const void *blob = gd->fdt_blob;
58057e25cf7SYifeng Zhao 	struct nand_chip *chip;
58157e25cf7SYifeng Zhao 	struct mtd_info *mtd;
58257e25cf7SYifeng Zhao 	int ret;
58357e25cf7SYifeng Zhao 
58457e25cf7SYifeng Zhao 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
58557e25cf7SYifeng Zhao 
58657e25cf7SYifeng Zhao 	chip->chip_delay = 50;
58757e25cf7SYifeng Zhao 	chip->flash_node = node;
58857e25cf7SYifeng Zhao 	chip->select_chip = rockchip_nand_select_chip;
58957e25cf7SYifeng Zhao 	chip->cmd_ctrl = rockchip_nand_cmd_ctrl;
59057e25cf7SYifeng Zhao 	chip->read_buf = rockchip_nand_read_buf;
59157e25cf7SYifeng Zhao 	chip->write_buf = rockchip_nand_write_buf;
59257e25cf7SYifeng Zhao 	chip->read_byte = rockchip_nand_read_byte;
59357e25cf7SYifeng Zhao 	chip->dev_ready = rockchip_nand_dev_ready;
59457e25cf7SYifeng Zhao 	chip->controller = &rknand->controller;
59557e25cf7SYifeng Zhao 	chip->block_bad = rockchip_nand_block_bad;
59657e25cf7SYifeng Zhao 	chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
59757e25cf7SYifeng Zhao 	chip->options = NAND_NO_SUBPAGE_WRITE;
59857e25cf7SYifeng Zhao 
59957e25cf7SYifeng Zhao 	rknand->banks[devnum] = fdtdec_get_int(blob, node, "reg", -1);
60057e25cf7SYifeng Zhao 
60157e25cf7SYifeng Zhao 	if (rknand->banks[devnum] < 0)
60257e25cf7SYifeng Zhao 		return -EINVAL;
60357e25cf7SYifeng Zhao 
60457e25cf7SYifeng Zhao 	mtd = nand_to_mtd(chip);
60557e25cf7SYifeng Zhao 	mtd->dev = rknand->dev;
60657e25cf7SYifeng Zhao 	if (rknand->dev)
60757e25cf7SYifeng Zhao 		rknand->dev->priv = mtd;
60857e25cf7SYifeng Zhao 
60957e25cf7SYifeng Zhao 	ret = nand_scan_ident(mtd, 1, NULL);
61057e25cf7SYifeng Zhao 	if (ret)
61157e25cf7SYifeng Zhao 		return ret;
61257e25cf7SYifeng Zhao 
61357e25cf7SYifeng Zhao 	ret = rockchip_nand_ecc_init(mtd, &chip->ecc);
61457e25cf7SYifeng Zhao 	if (ret) {
61557e25cf7SYifeng Zhao 		debug("rockchip_nand_ecc_init failed: %d\n", ret);
61657e25cf7SYifeng Zhao 		return ret;
61757e25cf7SYifeng Zhao 	}
61857e25cf7SYifeng Zhao 
61957e25cf7SYifeng Zhao 	ret = nand_scan_tail(mtd);
62057e25cf7SYifeng Zhao 	if (ret) {
62157e25cf7SYifeng Zhao 		debug("nand_scan_tail failed: %d\n", ret);
62257e25cf7SYifeng Zhao 		return ret;
62357e25cf7SYifeng Zhao 	}
62457e25cf7SYifeng Zhao 
62557e25cf7SYifeng Zhao 	ret = nand_register(devnum, mtd);
62657e25cf7SYifeng Zhao 	if (ret) {
62757e25cf7SYifeng Zhao 		debug("Failed to register mtd device: %d\n", ret);
62857e25cf7SYifeng Zhao 		return ret;
62957e25cf7SYifeng Zhao 	}
630b1758edaSJason Zhu 	memcpy(&rknand->mtd, mtd, sizeof(struct mtd_info));
631b1758edaSJason Zhu 
63257e25cf7SYifeng Zhao 	return 0;
63357e25cf7SYifeng Zhao }
63457e25cf7SYifeng Zhao 
rockchip_nand_chips_init(int node,struct rk_nand * rknand)63557e25cf7SYifeng Zhao static int rockchip_nand_chips_init(int node, struct rk_nand *rknand)
63657e25cf7SYifeng Zhao {
63757e25cf7SYifeng Zhao 	const void *blob = gd->fdt_blob;
63857e25cf7SYifeng Zhao 	int nand_node;
63957e25cf7SYifeng Zhao 	int ret, i = 0;
64057e25cf7SYifeng Zhao 
64157e25cf7SYifeng Zhao 	for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0;
64257e25cf7SYifeng Zhao 	     nand_node = fdt_next_subnode(blob, nand_node)) {
64357e25cf7SYifeng Zhao 		ret = rockchip_nand_chip_init(nand_node, rknand, i++);
64457e25cf7SYifeng Zhao 		if (ret)
64557e25cf7SYifeng Zhao 			return ret;
64657e25cf7SYifeng Zhao 	}
64757e25cf7SYifeng Zhao 
64857e25cf7SYifeng Zhao 	return 0;
64957e25cf7SYifeng Zhao }
65057e25cf7SYifeng Zhao 
65157e25cf7SYifeng Zhao #ifdef CONFIG_NAND_ROCKCHIP_DT
65257e25cf7SYifeng Zhao static const struct udevice_id rockchip_nandc_ids[] = {
65357e25cf7SYifeng Zhao 	{ .compatible = "rockchip,rk-nandc" },
65457e25cf7SYifeng Zhao 	{ }
65557e25cf7SYifeng Zhao };
65657e25cf7SYifeng Zhao 
rockchip_nandc_probe(struct udevice * dev)65757e25cf7SYifeng Zhao static int rockchip_nandc_probe(struct udevice *dev)
65857e25cf7SYifeng Zhao {
65957e25cf7SYifeng Zhao 	const void *blob = gd->fdt_blob;
66057e25cf7SYifeng Zhao 	struct rk_nand *rknand = dev_get_priv(dev);
661b1758edaSJason Zhu 	struct mtd_info *mtd = dev_get_uclass_priv(dev);
66257e25cf7SYifeng Zhao 	fdt_addr_t regs;
66357e25cf7SYifeng Zhao 	int ret = 0, node;
66457e25cf7SYifeng Zhao 
66557e25cf7SYifeng Zhao 	node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC);
66657e25cf7SYifeng Zhao 
66757e25cf7SYifeng Zhao 	rknand->dev = dev;
66857e25cf7SYifeng Zhao 
66957e25cf7SYifeng Zhao 	regs = dev_read_addr(dev);
67057e25cf7SYifeng Zhao 	if (regs == FDT_ADDR_T_NONE) {
67157e25cf7SYifeng Zhao 		debug("Nand address not found\n");
67257e25cf7SYifeng Zhao 		return ret;
67357e25cf7SYifeng Zhao 	}
67457e25cf7SYifeng Zhao 
67557e25cf7SYifeng Zhao 	rknand->regs = (void *)regs;
67657e25cf7SYifeng Zhao 
67757e25cf7SYifeng Zhao 	spin_lock_init(&rknand->controller.lock);
67857e25cf7SYifeng Zhao 	init_waitqueue_head(&rknand->controller.wq);
67957e25cf7SYifeng Zhao 
68057e25cf7SYifeng Zhao 	rockchip_nand_init(rknand);
68157e25cf7SYifeng Zhao 
68257e25cf7SYifeng Zhao 	ret = rockchip_nand_chips_init(node, rknand);
68357e25cf7SYifeng Zhao 	if (ret)
68457e25cf7SYifeng Zhao 		debug("Failed to init nand chips\n");
68557e25cf7SYifeng Zhao 
686b1758edaSJason Zhu 	memcpy(mtd, &rknand->mtd, sizeof(struct mtd_info));
687b1758edaSJason Zhu 
68857e25cf7SYifeng Zhao 	return ret;
68957e25cf7SYifeng Zhao }
69057e25cf7SYifeng Zhao 
rockchip_nandc_bind(struct udevice * udev)69157e25cf7SYifeng Zhao static int rockchip_nandc_bind(struct udevice *udev)
69257e25cf7SYifeng Zhao {
69357e25cf7SYifeng Zhao 	int ret = 0;
69457e25cf7SYifeng Zhao 
69557e25cf7SYifeng Zhao #ifdef CONFIG_MTD_BLK
69657e25cf7SYifeng Zhao 	struct udevice *bdev;
69757e25cf7SYifeng Zhao 
69857e25cf7SYifeng Zhao 	ret = blk_create_devicef(udev, "mtd_blk", "blk", IF_TYPE_MTD,
69933a3075bSJon Lin 				 BLK_MTD_NAND, 512, 0, &bdev);
70057e25cf7SYifeng Zhao 	if (ret)
70157e25cf7SYifeng Zhao 		printf("Cannot create block device\n");
70257e25cf7SYifeng Zhao #endif
70357e25cf7SYifeng Zhao 	return ret;
70457e25cf7SYifeng Zhao }
70557e25cf7SYifeng Zhao 
70657e25cf7SYifeng Zhao U_BOOT_DRIVER(rk_nandc_v6) = {
70757e25cf7SYifeng Zhao 	.name           = "rk_nandc_v6",
70857e25cf7SYifeng Zhao 	.id             = UCLASS_MTD,
70957e25cf7SYifeng Zhao 	.of_match       = rockchip_nandc_ids,
71057e25cf7SYifeng Zhao 	.bind		= rockchip_nandc_bind,
71157e25cf7SYifeng Zhao 	.probe          = rockchip_nandc_probe,
71257e25cf7SYifeng Zhao 	.priv_auto_alloc_size = sizeof(struct rk_nand),
71357e25cf7SYifeng Zhao };
71457e25cf7SYifeng Zhao 
board_nand_init(void)71557e25cf7SYifeng Zhao void board_nand_init(void)
71657e25cf7SYifeng Zhao {
71757e25cf7SYifeng Zhao 	struct udevice *dev;
71857e25cf7SYifeng Zhao 	int ret;
71957e25cf7SYifeng Zhao 
72057e25cf7SYifeng Zhao 	ret = uclass_get_device_by_driver(UCLASS_MTD,
72157e25cf7SYifeng Zhao 					  DM_GET_DRIVER(rk_nandc_v6),
72257e25cf7SYifeng Zhao 					  &dev);
72357e25cf7SYifeng Zhao 	if (ret && ret != -ENODEV)
72457e25cf7SYifeng Zhao 		pr_err("Failed to initialize NAND controller. (error %d)\n",
72557e25cf7SYifeng Zhao 		       ret);
72657e25cf7SYifeng Zhao }
72757e25cf7SYifeng Zhao #else
72857e25cf7SYifeng Zhao 
board_nand_init(void)72957e25cf7SYifeng Zhao void board_nand_init(void)
73057e25cf7SYifeng Zhao {
73157e25cf7SYifeng Zhao 	const void *blob = gd->fdt_blob;
73257e25cf7SYifeng Zhao 	struct rk_nand *rknand;
73357e25cf7SYifeng Zhao 	fdt_addr_t regs;
73457e25cf7SYifeng Zhao 	int node;
73557e25cf7SYifeng Zhao 	int ret;
73657e25cf7SYifeng Zhao 
73757e25cf7SYifeng Zhao 	rknand = kzalloc(sizeof(*rknand), GFP_KERNEL);
73857e25cf7SYifeng Zhao 
73957e25cf7SYifeng Zhao 	node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC);
74057e25cf7SYifeng Zhao 
74157e25cf7SYifeng Zhao 	if (node < 0) {
74257e25cf7SYifeng Zhao 		debug("Nand node not found\n");
74357e25cf7SYifeng Zhao 		goto err;
74457e25cf7SYifeng Zhao 	}
74557e25cf7SYifeng Zhao 
74657e25cf7SYifeng Zhao 	if (!fdtdec_get_is_enabled(blob, node)) {
74757e25cf7SYifeng Zhao 		debug("Nand disabled in device tree\n");
74857e25cf7SYifeng Zhao 		goto err;
74957e25cf7SYifeng Zhao 	}
75057e25cf7SYifeng Zhao 
75157e25cf7SYifeng Zhao 	regs = fdt_get_base_address(blob, node);
75257e25cf7SYifeng Zhao 	if (regs == FDT_ADDR_T_NONE) {
75357e25cf7SYifeng Zhao 		debug("Nand address not found\n");
75457e25cf7SYifeng Zhao 		goto err;
75557e25cf7SYifeng Zhao 	}
75657e25cf7SYifeng Zhao 
75757e25cf7SYifeng Zhao 	rknand->regs = (void *)regs;
75857e25cf7SYifeng Zhao 
75957e25cf7SYifeng Zhao 	spin_lock_init(&rknand->controller.lock);
76057e25cf7SYifeng Zhao 	init_waitqueue_head(&rknand->controller.wq);
76157e25cf7SYifeng Zhao 
76257e25cf7SYifeng Zhao 	rockchip_nand_init(rknand);
76357e25cf7SYifeng Zhao 
76457e25cf7SYifeng Zhao 	ret = rockchip_nand_chips_init(node, rknand);
76557e25cf7SYifeng Zhao 	if (ret) {
76657e25cf7SYifeng Zhao 		debug("Failed to init nand chips\n");
76757e25cf7SYifeng Zhao 		goto err;
76857e25cf7SYifeng Zhao 	}
76957e25cf7SYifeng Zhao 
77057e25cf7SYifeng Zhao 	return;
77157e25cf7SYifeng Zhao err:
77257e25cf7SYifeng Zhao 	kfree(rknand);
77357e25cf7SYifeng Zhao }
77457e25cf7SYifeng Zhao 
77557e25cf7SYifeng Zhao #endif
77657e25cf7SYifeng Zhao 
nand_spl_load_image(uint32_t offs,unsigned int size,void * dst)77757e25cf7SYifeng Zhao int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
77857e25cf7SYifeng Zhao {
77957e25cf7SYifeng Zhao 	struct mtd_info *mtd;
78057e25cf7SYifeng Zhao 	size_t length = size;
78157e25cf7SYifeng Zhao 
78257e25cf7SYifeng Zhao 	mtd = get_nand_dev_by_index(0);
78357e25cf7SYifeng Zhao 	return nand_read_skip_bad(mtd, offs, &length, NULL, size, (u_char *)dst);
78457e25cf7SYifeng Zhao }
78557e25cf7SYifeng Zhao 
nand_deselect(void)78657e25cf7SYifeng Zhao void nand_deselect(void) {}
787