157e25cf7SYifeng Zhao /* 257e25cf7SYifeng Zhao * Copyright (c) 2017 Yifeng Zhao <yifeng.zhao@rock-chips.com> 357e25cf7SYifeng Zhao * 457e25cf7SYifeng Zhao * SPDX-License-Identifier: GPL-2.0+ 557e25cf7SYifeng Zhao */ 657e25cf7SYifeng Zhao 757e25cf7SYifeng Zhao #include <common.h> 8*e65bf00aSYifeng Zhao #include <dm.h> 957e25cf7SYifeng Zhao #include <fdtdec.h> 103a692737SJason Zhu #include <fdt_support.h> 1157e25cf7SYifeng Zhao #include <inttypes.h> 1257e25cf7SYifeng Zhao #include <nand.h> 1357e25cf7SYifeng Zhao #include <linux/kernel.h> 1457e25cf7SYifeng Zhao #include <linux/mtd/mtd.h> 1557e25cf7SYifeng Zhao #include <linux/mtd/nand.h> 1657e25cf7SYifeng Zhao #include <linux/mtd/partitions.h> 1757e25cf7SYifeng Zhao #include <linux/io.h> 1857e25cf7SYifeng Zhao 1957e25cf7SYifeng Zhao DECLARE_GLOBAL_DATA_PTR; 2057e25cf7SYifeng Zhao 2157e25cf7SYifeng Zhao #define NANDC_V6_BOOTROM_ECC 24 2257e25cf7SYifeng Zhao #define NANDC_V6_NUM_BANKS 4 2357e25cf7SYifeng Zhao #define NANDC_V6_DEF_TIMEOUT 20000 2457e25cf7SYifeng Zhao #define NANDC_V6_READ 0 2557e25cf7SYifeng Zhao #define NANDC_V6_WRITE 1 2657e25cf7SYifeng Zhao 2757e25cf7SYifeng Zhao #define NANDC_REG_V6_FMCTL 0x00 2857e25cf7SYifeng Zhao #define NANDC_REG_V6_FMWAIT 0x04 2957e25cf7SYifeng Zhao #define NANDC_REG_V6_FLCTL 0x08 3057e25cf7SYifeng Zhao #define NANDC_REG_V6_BCHCTL 0x0c 3157e25cf7SYifeng Zhao #define NANDC_REG_V6_DMA_CFG 0x10 3257e25cf7SYifeng Zhao #define NANDC_REG_V6_DMA_BUF0 0x14 3357e25cf7SYifeng Zhao #define NANDC_REG_V6_DMA_BUF1 0x18 3457e25cf7SYifeng Zhao #define NANDC_REG_V6_DMA_ST 0x1C 3557e25cf7SYifeng Zhao #define NANDC_REG_V6_BCHST 0x20 3657e25cf7SYifeng Zhao #define NANDC_REG_V6_RANDMZ 0x150 3757e25cf7SYifeng Zhao #define NANDC_REG_V6_VER 0x160 3857e25cf7SYifeng Zhao #define NANDC_REG_V6_INTEN 0x16C 3957e25cf7SYifeng Zhao #define NANDC_REG_V6_INTCLR 0x170 4057e25cf7SYifeng Zhao #define NANDC_REG_V6_INTST 0x174 4157e25cf7SYifeng Zhao #define NANDC_REG_V6_SPARE0 0x200 4257e25cf7SYifeng Zhao #define NANDC_REG_V6_SPARE1 0x230 4357e25cf7SYifeng Zhao #define NANDC_REG_V6_BANK0 0x800 4457e25cf7SYifeng Zhao #define NANDC_REG_V6_SRAM0 0x1000 4557e25cf7SYifeng Zhao #define NANDC_REG_V6_SRAM_SIZE 0x400 4657e25cf7SYifeng Zhao 4757e25cf7SYifeng Zhao #define NANDC_REG_V6_DATA 0x00 4857e25cf7SYifeng Zhao #define NANDC_REG_V6_ADDR 0x04 4957e25cf7SYifeng Zhao #define NANDC_REG_V6_CMD 0x08 5057e25cf7SYifeng Zhao 5157e25cf7SYifeng Zhao /* FMCTL */ 5257e25cf7SYifeng Zhao #define NANDC_V6_FM_WP BIT(8) 5357e25cf7SYifeng Zhao #define NANDC_V6_FM_CE_SEL_M 0xFF 5457e25cf7SYifeng Zhao #define NANDC_V6_FM_CE_SEL(x) (1 << (x)) 5557e25cf7SYifeng Zhao #define NANDC_V6_FM_FREADY BIT(9) 5657e25cf7SYifeng Zhao 5757e25cf7SYifeng Zhao /* FLCTL */ 5857e25cf7SYifeng Zhao #define NANDC_V6_FL_RST BIT(0) 5957e25cf7SYifeng Zhao #define NANDC_V6_FL_DIR_S 0x1 6057e25cf7SYifeng Zhao #define NANDC_V6_FL_XFER_START BIT(2) 6157e25cf7SYifeng Zhao #define NANDC_V6_FL_XFER_EN BIT(3) 6257e25cf7SYifeng Zhao #define NANDC_V6_FL_ST_BUF_S 0x4 6357e25cf7SYifeng Zhao #define NANDC_V6_FL_XFER_COUNT BIT(5) 6457e25cf7SYifeng Zhao #define NANDC_V6_FL_ACORRECT BIT(10) 6557e25cf7SYifeng Zhao #define NANDC_V6_FL_XFER_READY BIT(20) 6657e25cf7SYifeng Zhao 6757e25cf7SYifeng Zhao /* BCHCTL */ 6857e25cf7SYifeng Zhao #define NAND_V6_BCH_REGION_S 0x5 6957e25cf7SYifeng Zhao #define NAND_V6_BCH_REGION_M 0x7 7057e25cf7SYifeng Zhao 7157e25cf7SYifeng Zhao /* BCHST */ 7257e25cf7SYifeng Zhao #define NANDC_V6_BCH0_ST_ERR BIT(2) 7357e25cf7SYifeng Zhao #define NANDC_V6_BCH1_ST_ERR BIT(15) 7457e25cf7SYifeng Zhao #define NANDC_V6_ECC_ERR_CNT0(x) ((((x & (0x1F << 3)) >> 3) \ 7557e25cf7SYifeng Zhao | ((x & (1 << 27)) >> 22)) & 0x3F) 7657e25cf7SYifeng Zhao #define NANDC_V6_ECC_ERR_CNT1(x) ((((x & (0x1F << 16)) >> 16) \ 7757e25cf7SYifeng Zhao | ((x & (1 << 29)) >> 24)) & 0x3F) 7857e25cf7SYifeng Zhao 7957e25cf7SYifeng Zhao struct rk_nand { 8057e25cf7SYifeng Zhao void __iomem *regs; 8157e25cf7SYifeng Zhao u8 chipnr; 8257e25cf7SYifeng Zhao u8 id[5]; 8357e25cf7SYifeng Zhao u8 *databuf; 84*e65bf00aSYifeng Zhao struct udevice *dev; 85*e65bf00aSYifeng Zhao struct mtd_info *mtd; 8657e25cf7SYifeng Zhao }; 8757e25cf7SYifeng Zhao 8857e25cf7SYifeng Zhao struct rk_nand *g_rk_nand; 8957e25cf7SYifeng Zhao 9057e25cf7SYifeng Zhao static void nandc_init(struct rk_nand *rknand) 9157e25cf7SYifeng Zhao { 9257e25cf7SYifeng Zhao writel(0x1081, rknand->regs + NANDC_REG_V6_FMWAIT); 9357e25cf7SYifeng Zhao } 9457e25cf7SYifeng Zhao 9557e25cf7SYifeng Zhao static void rockchip_nand_wait_dev_ready(void __iomem *regs) 9657e25cf7SYifeng Zhao { 9757e25cf7SYifeng Zhao u32 reg; 9857e25cf7SYifeng Zhao u32 timeout = NANDC_V6_DEF_TIMEOUT; 9957e25cf7SYifeng Zhao 10057e25cf7SYifeng Zhao while (timeout--) { 10157e25cf7SYifeng Zhao udelay(1); 10257e25cf7SYifeng Zhao reg = readl(regs + NANDC_REG_V6_FMCTL); 10357e25cf7SYifeng Zhao 10457e25cf7SYifeng Zhao if ((reg & NANDC_V6_FM_FREADY)) 10557e25cf7SYifeng Zhao break; 10657e25cf7SYifeng Zhao } 10757e25cf7SYifeng Zhao } 10857e25cf7SYifeng Zhao 10957e25cf7SYifeng Zhao static void rockchip_nand_select_chip(void __iomem *regs, int chipnr) 11057e25cf7SYifeng Zhao { 11157e25cf7SYifeng Zhao u32 reg; 11257e25cf7SYifeng Zhao 11357e25cf7SYifeng Zhao reg = readl(regs + NANDC_REG_V6_FMCTL); 11457e25cf7SYifeng Zhao reg &= ~NANDC_V6_FM_CE_SEL_M; 11557e25cf7SYifeng Zhao if (chipnr != -1) 11657e25cf7SYifeng Zhao reg |= 1 << chipnr; 11757e25cf7SYifeng Zhao writel(reg, regs + NANDC_REG_V6_FMCTL); 11857e25cf7SYifeng Zhao } 11957e25cf7SYifeng Zhao 12057e25cf7SYifeng Zhao static void rockchip_nand_read_page(void __iomem *regs, 12157e25cf7SYifeng Zhao int page, int col) 12257e25cf7SYifeng Zhao { 12357e25cf7SYifeng Zhao void __iomem *bank_base = regs + NANDC_REG_V6_BANK0; 12457e25cf7SYifeng Zhao 12557e25cf7SYifeng Zhao writeb(0x00, bank_base + NANDC_REG_V6_CMD); 12657e25cf7SYifeng Zhao writeb(col, bank_base + NANDC_REG_V6_ADDR); 12757e25cf7SYifeng Zhao writeb(col >> 8, bank_base + NANDC_REG_V6_ADDR); 12857e25cf7SYifeng Zhao writeb(page, bank_base + NANDC_REG_V6_ADDR); 12957e25cf7SYifeng Zhao writeb(page >> 8, bank_base + NANDC_REG_V6_ADDR); 13057e25cf7SYifeng Zhao writeb(page >> 16, bank_base + NANDC_REG_V6_ADDR); 13157e25cf7SYifeng Zhao writeb(0x30, bank_base + NANDC_REG_V6_CMD); 13257e25cf7SYifeng Zhao } 13357e25cf7SYifeng Zhao 13457e25cf7SYifeng Zhao static void rockchip_nand_pio_xfer_start(struct rk_nand *rknand, 13557e25cf7SYifeng Zhao u8 dir, 13657e25cf7SYifeng Zhao u8 st_buf) 13757e25cf7SYifeng Zhao { 13857e25cf7SYifeng Zhao u32 reg; 13957e25cf7SYifeng Zhao 14057e25cf7SYifeng Zhao reg = readl(rknand->regs + NANDC_REG_V6_BCHCTL); 14157e25cf7SYifeng Zhao reg = (reg & (~(NAND_V6_BCH_REGION_M << NAND_V6_BCH_REGION_S))); 14257e25cf7SYifeng Zhao writel(reg, rknand->regs + NANDC_REG_V6_BCHCTL); 14357e25cf7SYifeng Zhao 14457e25cf7SYifeng Zhao reg = (dir << NANDC_V6_FL_DIR_S) | (st_buf << NANDC_V6_FL_ST_BUF_S) | 14557e25cf7SYifeng Zhao NANDC_V6_FL_XFER_EN | NANDC_V6_FL_XFER_COUNT | 14657e25cf7SYifeng Zhao NANDC_V6_FL_ACORRECT; 14757e25cf7SYifeng Zhao writel(reg, rknand->regs + NANDC_REG_V6_FLCTL); 14857e25cf7SYifeng Zhao 14957e25cf7SYifeng Zhao reg |= NANDC_V6_FL_XFER_START; 15057e25cf7SYifeng Zhao writel(reg, rknand->regs + NANDC_REG_V6_FLCTL); 15157e25cf7SYifeng Zhao } 15257e25cf7SYifeng Zhao 15357e25cf7SYifeng Zhao static int rockchip_nand_wait_pio_xfer_done(struct rk_nand *rknand) 15457e25cf7SYifeng Zhao { 15557e25cf7SYifeng Zhao int timeout = NANDC_V6_DEF_TIMEOUT; 15657e25cf7SYifeng Zhao int reg; 15757e25cf7SYifeng Zhao 15857e25cf7SYifeng Zhao while (timeout--) { 15957e25cf7SYifeng Zhao reg = readl(rknand->regs + NANDC_REG_V6_FLCTL); 16057e25cf7SYifeng Zhao 16157e25cf7SYifeng Zhao if ((reg & NANDC_V6_FL_XFER_READY) != 0) 16257e25cf7SYifeng Zhao break; 16357e25cf7SYifeng Zhao 16457e25cf7SYifeng Zhao udelay(1); 16557e25cf7SYifeng Zhao } 16657e25cf7SYifeng Zhao 16757e25cf7SYifeng Zhao if (timeout == 0) 16857e25cf7SYifeng Zhao return -1; 16957e25cf7SYifeng Zhao 17057e25cf7SYifeng Zhao return 0; 17157e25cf7SYifeng Zhao } 17257e25cf7SYifeng Zhao 17357e25cf7SYifeng Zhao static int nandc_read_page(unsigned int page, uint8_t *buf) 17457e25cf7SYifeng Zhao { 17557e25cf7SYifeng Zhao void __iomem *sram_base = g_rk_nand->regs + NANDC_REG_V6_SRAM0; 17657e25cf7SYifeng Zhao unsigned int max_bitflips = 0; 17757e25cf7SYifeng Zhao int ret, step, bch_st, ecc_step; 17857e25cf7SYifeng Zhao 17957e25cf7SYifeng Zhao ecc_step = CONFIG_SYS_NAND_PAGE_SIZE / 1024; 18057e25cf7SYifeng Zhao rockchip_nand_select_chip(g_rk_nand->regs, 0); 18157e25cf7SYifeng Zhao rockchip_nand_read_page(g_rk_nand->regs, page, 0); 18257e25cf7SYifeng Zhao rockchip_nand_wait_dev_ready(g_rk_nand->regs); 18357e25cf7SYifeng Zhao rockchip_nand_pio_xfer_start(g_rk_nand, NANDC_V6_READ, 0); 18457e25cf7SYifeng Zhao 18557e25cf7SYifeng Zhao for (step = 0; step < ecc_step; step++) { 18657e25cf7SYifeng Zhao int data_off = step * 1024; 18757e25cf7SYifeng Zhao u8 *data = buf + data_off; 18857e25cf7SYifeng Zhao 18957e25cf7SYifeng Zhao ret = rockchip_nand_wait_pio_xfer_done(g_rk_nand); 19057e25cf7SYifeng Zhao if (ret) 19157e25cf7SYifeng Zhao return ret; 19257e25cf7SYifeng Zhao 19357e25cf7SYifeng Zhao bch_st = readl(g_rk_nand->regs + NANDC_REG_V6_BCHST); 19457e25cf7SYifeng Zhao 19557e25cf7SYifeng Zhao if (bch_st & NANDC_V6_BCH0_ST_ERR) { 19657e25cf7SYifeng Zhao max_bitflips = -1; 19757e25cf7SYifeng Zhao } else { 19857e25cf7SYifeng Zhao ret = NANDC_V6_ECC_ERR_CNT0(bch_st); 19957e25cf7SYifeng Zhao max_bitflips = max_t(unsigned int, max_bitflips, ret); 20057e25cf7SYifeng Zhao } 20157e25cf7SYifeng Zhao 20257e25cf7SYifeng Zhao if ((step + 1) < ecc_step) 20357e25cf7SYifeng Zhao rockchip_nand_pio_xfer_start(g_rk_nand, NANDC_V6_READ, 20457e25cf7SYifeng Zhao (step + 1) & 0x1); 20557e25cf7SYifeng Zhao 20657e25cf7SYifeng Zhao memcpy_fromio(data, sram_base + NANDC_REG_V6_SRAM_SIZE * 20757e25cf7SYifeng Zhao (step & 1), 1024); 20857e25cf7SYifeng Zhao } 20957e25cf7SYifeng Zhao rockchip_nand_select_chip(g_rk_nand->regs, -1); 21057e25cf7SYifeng Zhao 21157e25cf7SYifeng Zhao return max_bitflips; 21257e25cf7SYifeng Zhao } 21357e25cf7SYifeng Zhao 21457e25cf7SYifeng Zhao static int is_badblock(unsigned int page) 21557e25cf7SYifeng Zhao { 21657e25cf7SYifeng Zhao int res = 0, i; 21757e25cf7SYifeng Zhao u16 bad = 0xff; 21857e25cf7SYifeng Zhao void __iomem *regs = g_rk_nand->regs; 21957e25cf7SYifeng Zhao void __iomem *bank_base = regs + NANDC_REG_V6_BANK0; 22057e25cf7SYifeng Zhao 22157e25cf7SYifeng Zhao if (nandc_read_page(page, g_rk_nand->databuf) == -1) { 22257e25cf7SYifeng Zhao rockchip_nand_select_chip(regs, 0); 22357e25cf7SYifeng Zhao rockchip_nand_read_page(regs, page, 22457e25cf7SYifeng Zhao CONFIG_SYS_NAND_PAGE_SIZE); 22557e25cf7SYifeng Zhao rockchip_nand_wait_dev_ready(regs); 22657e25cf7SYifeng Zhao for (i = 0; i < 8; i++) { 22757e25cf7SYifeng Zhao bad = readb(bank_base); 22857e25cf7SYifeng Zhao if (bad) 22957e25cf7SYifeng Zhao break; 23057e25cf7SYifeng Zhao } 23157e25cf7SYifeng Zhao if (i >= 8) 23257e25cf7SYifeng Zhao res = 1; 23357e25cf7SYifeng Zhao rockchip_nand_select_chip(regs, 0); 23457e25cf7SYifeng Zhao } 23557e25cf7SYifeng Zhao if (res) 23657e25cf7SYifeng Zhao printf("%s 0x%x %x %x\n", __func__, page, res, bad); 23757e25cf7SYifeng Zhao return res; 23857e25cf7SYifeng Zhao } 23957e25cf7SYifeng Zhao 24057e25cf7SYifeng Zhao static void read_flash_id(struct rk_nand *rknand, uint8_t *id) 24157e25cf7SYifeng Zhao { 24257e25cf7SYifeng Zhao void __iomem *bank_base = rknand->regs + NANDC_REG_V6_BANK0; 24357e25cf7SYifeng Zhao 24457e25cf7SYifeng Zhao rockchip_nand_wait_dev_ready(g_rk_nand->regs); 24557e25cf7SYifeng Zhao writeb(0x90, bank_base + NANDC_REG_V6_CMD); 24657e25cf7SYifeng Zhao writeb(0x00, bank_base + NANDC_REG_V6_ADDR); 24757e25cf7SYifeng Zhao udelay(1); 24857e25cf7SYifeng Zhao id[0] = readb(bank_base); 24957e25cf7SYifeng Zhao id[1] = readb(bank_base); 25057e25cf7SYifeng Zhao id[2] = readb(bank_base); 25157e25cf7SYifeng Zhao id[3] = readb(bank_base); 25257e25cf7SYifeng Zhao id[4] = readb(bank_base); 25357e25cf7SYifeng Zhao rockchip_nand_select_chip(rknand->regs, -1); 254*e65bf00aSYifeng Zhao if (id[0] != 0xFF && id[0] != 0x00) 255*e65bf00aSYifeng Zhao printf("NAND:%x %x\n", id[0], id[1]); 25657e25cf7SYifeng Zhao } 25757e25cf7SYifeng Zhao 258*e65bf00aSYifeng Zhao #ifdef CONFIG_NAND_ROCKCHIP_DT 259*e65bf00aSYifeng Zhao static const struct udevice_id rockchip_nandc_ids[] = { 260*e65bf00aSYifeng Zhao { .compatible = "rockchip,rk-nandc" }, 261*e65bf00aSYifeng Zhao { } 262*e65bf00aSYifeng Zhao }; 263*e65bf00aSYifeng Zhao 264*e65bf00aSYifeng Zhao static int spl_nand_block_isbad(struct mtd_info *mtd, loff_t ofs) 265*e65bf00aSYifeng Zhao { 266*e65bf00aSYifeng Zhao return is_badblock(ofs / CONFIG_SYS_NAND_PAGE_SIZE); 267*e65bf00aSYifeng Zhao } 268*e65bf00aSYifeng Zhao 269*e65bf00aSYifeng Zhao static int spl_nand_read_page(struct mtd_info *mtd, loff_t from, size_t len, 270*e65bf00aSYifeng Zhao size_t *retlen, u_char *buf) 271*e65bf00aSYifeng Zhao { 272*e65bf00aSYifeng Zhao int read_size, offset, read_len; 273*e65bf00aSYifeng Zhao unsigned int page; 274*e65bf00aSYifeng Zhao unsigned int max_pages = CONFIG_SYS_NAND_SIZE / 275*e65bf00aSYifeng Zhao CONFIG_SYS_NAND_PAGE_SIZE; 276*e65bf00aSYifeng Zhao 277*e65bf00aSYifeng Zhao /* Convert to page number */ 278*e65bf00aSYifeng Zhao page = from / CONFIG_SYS_NAND_PAGE_SIZE; 279*e65bf00aSYifeng Zhao offset = from & (CONFIG_SYS_NAND_PAGE_SIZE - 1); 280*e65bf00aSYifeng Zhao read_len = len; 281*e65bf00aSYifeng Zhao *retlen = 0; 282*e65bf00aSYifeng Zhao 283*e65bf00aSYifeng Zhao while (read_len) { 284*e65bf00aSYifeng Zhao read_size = CONFIG_SYS_NAND_PAGE_SIZE - offset; 285*e65bf00aSYifeng Zhao if (read_size > read_len) 286*e65bf00aSYifeng Zhao read_size = read_len; 287*e65bf00aSYifeng Zhao if (offset || read_size < CONFIG_SYS_NAND_PAGE_SIZE) { 288*e65bf00aSYifeng Zhao if (nandc_read_page(page, g_rk_nand->databuf) < 0) 289*e65bf00aSYifeng Zhao return -EIO; 290*e65bf00aSYifeng Zhao memcpy(buf, g_rk_nand->databuf + offset, read_size); 291*e65bf00aSYifeng Zhao offset = 0; 292*e65bf00aSYifeng Zhao } else { 293*e65bf00aSYifeng Zhao if (nandc_read_page(page, buf) < 0) 294*e65bf00aSYifeng Zhao return -EIO; 295*e65bf00aSYifeng Zhao } 296*e65bf00aSYifeng Zhao page++; 297*e65bf00aSYifeng Zhao read_len -= read_size; 298*e65bf00aSYifeng Zhao buf += read_size; 299*e65bf00aSYifeng Zhao if (page >= max_pages) 300*e65bf00aSYifeng Zhao return -EIO; 301*e65bf00aSYifeng Zhao } 302*e65bf00aSYifeng Zhao 303*e65bf00aSYifeng Zhao *retlen = len; 304*e65bf00aSYifeng Zhao 305*e65bf00aSYifeng Zhao return 0; 306*e65bf00aSYifeng Zhao } 307*e65bf00aSYifeng Zhao 308*e65bf00aSYifeng Zhao static int rockchip_nandc_probe(struct udevice *dev) 309*e65bf00aSYifeng Zhao { 310*e65bf00aSYifeng Zhao const void *blob = gd->fdt_blob; 311*e65bf00aSYifeng Zhao struct rk_nand *rknand = dev_get_priv(dev); 312*e65bf00aSYifeng Zhao struct mtd_info *mtd = dev_get_uclass_priv(dev); 313*e65bf00aSYifeng Zhao fdt_addr_t regs; 314*e65bf00aSYifeng Zhao int ret = -ENODEV; 315*e65bf00aSYifeng Zhao int node; 316*e65bf00aSYifeng Zhao 317*e65bf00aSYifeng Zhao g_rk_nand = rknand; 318*e65bf00aSYifeng Zhao rknand->dev = dev; 319*e65bf00aSYifeng Zhao 320*e65bf00aSYifeng Zhao node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC); 321*e65bf00aSYifeng Zhao 322*e65bf00aSYifeng Zhao if (node < 0) { 323*e65bf00aSYifeng Zhao printf("Nand node not found\n"); 324*e65bf00aSYifeng Zhao return -ENODEV; 325*e65bf00aSYifeng Zhao } 326*e65bf00aSYifeng Zhao 327*e65bf00aSYifeng Zhao if (!fdtdec_get_is_enabled(blob, node)) { 328*e65bf00aSYifeng Zhao debug("Nand disabled in device tree\n"); 329*e65bf00aSYifeng Zhao return -ENODEV; 330*e65bf00aSYifeng Zhao } 331*e65bf00aSYifeng Zhao 332*e65bf00aSYifeng Zhao regs = fdt_get_base_address(blob, node); 333*e65bf00aSYifeng Zhao if (!regs) { 334*e65bf00aSYifeng Zhao debug("Nand address not found\n"); 335*e65bf00aSYifeng Zhao return -ENODEV; 336*e65bf00aSYifeng Zhao } 337*e65bf00aSYifeng Zhao 338*e65bf00aSYifeng Zhao rknand->regs = (void *)regs; 339*e65bf00aSYifeng Zhao 340*e65bf00aSYifeng Zhao nandc_init(g_rk_nand); 341*e65bf00aSYifeng Zhao read_flash_id(g_rk_nand, g_rk_nand->id); 342*e65bf00aSYifeng Zhao 343*e65bf00aSYifeng Zhao if (g_rk_nand->id[0] == g_rk_nand->id[1]) 344*e65bf00aSYifeng Zhao return -ENODEV; 345*e65bf00aSYifeng Zhao 346*e65bf00aSYifeng Zhao if (g_rk_nand->id[1] == 0xA1 || g_rk_nand->id[1] == 0xF1 || 347*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0xD1 || g_rk_nand->id[1] == 0xAA || 348*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0xDA || g_rk_nand->id[1] == 0xAC || 349*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0xDC || g_rk_nand->id[1] == 0xA3 || 350*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0xD3 || g_rk_nand->id[1] == 0x95 || 351*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0x48) { 352*e65bf00aSYifeng Zhao g_rk_nand->chipnr = 1; 353*e65bf00aSYifeng Zhao g_rk_nand->databuf = kzalloc(CONFIG_SYS_NAND_PAGE_SIZE, 354*e65bf00aSYifeng Zhao GFP_KERNEL); 355*e65bf00aSYifeng Zhao if (!g_rk_nand) 356*e65bf00aSYifeng Zhao return -ENOMEM; 357*e65bf00aSYifeng Zhao mtd->_block_isbad = spl_nand_block_isbad; 358*e65bf00aSYifeng Zhao mtd->_read = spl_nand_read_page; 359*e65bf00aSYifeng Zhao mtd->size = CONFIG_SYS_NAND_SIZE; 360*e65bf00aSYifeng Zhao mtd->writesize = CONFIG_SYS_NAND_PAGE_SIZE; 361*e65bf00aSYifeng Zhao mtd->type = MTD_NANDFLASH; 362*e65bf00aSYifeng Zhao mtd->dev = rknand->dev; 363*e65bf00aSYifeng Zhao mtd->priv = rknand; 364*e65bf00aSYifeng Zhao add_mtd_device(mtd); 365*e65bf00aSYifeng Zhao mtd->name = "rk-nand"; 366*e65bf00aSYifeng Zhao rknand->mtd = mtd; 367*e65bf00aSYifeng Zhao ret = 0; 368*e65bf00aSYifeng Zhao } 369*e65bf00aSYifeng Zhao 370*e65bf00aSYifeng Zhao return ret; 371*e65bf00aSYifeng Zhao } 372*e65bf00aSYifeng Zhao 373*e65bf00aSYifeng Zhao static int rockchip_nandc_bind(struct udevice *udev) 374*e65bf00aSYifeng Zhao { 375*e65bf00aSYifeng Zhao int ret = 0; 376*e65bf00aSYifeng Zhao 377*e65bf00aSYifeng Zhao #ifdef CONFIG_MTD_BLK 378*e65bf00aSYifeng Zhao struct udevice *bdev; 379*e65bf00aSYifeng Zhao 380*e65bf00aSYifeng Zhao ret = blk_create_devicef(udev, "mtd_blk", "blk", IF_TYPE_MTD, 381*e65bf00aSYifeng Zhao BLK_MTD_NAND, 512, 0, &bdev); 382*e65bf00aSYifeng Zhao if (ret) 383*e65bf00aSYifeng Zhao printf("Cannot create block device\n"); 384*e65bf00aSYifeng Zhao #endif 385*e65bf00aSYifeng Zhao return ret; 386*e65bf00aSYifeng Zhao } 387*e65bf00aSYifeng Zhao 388*e65bf00aSYifeng Zhao U_BOOT_DRIVER(rk_nandc_v6) = { 389*e65bf00aSYifeng Zhao .name = "rk_nandc_v6", 390*e65bf00aSYifeng Zhao .id = UCLASS_MTD, 391*e65bf00aSYifeng Zhao .of_match = rockchip_nandc_ids, 392*e65bf00aSYifeng Zhao .bind = rockchip_nandc_bind, 393*e65bf00aSYifeng Zhao .probe = rockchip_nandc_probe, 394*e65bf00aSYifeng Zhao .priv_auto_alloc_size = sizeof(struct rk_nand), 395*e65bf00aSYifeng Zhao }; 396*e65bf00aSYifeng Zhao 397*e65bf00aSYifeng Zhao void board_nand_init(void) 398*e65bf00aSYifeng Zhao { 399*e65bf00aSYifeng Zhao struct udevice *dev; 400*e65bf00aSYifeng Zhao int ret; 401*e65bf00aSYifeng Zhao 402*e65bf00aSYifeng Zhao ret = uclass_get_device_by_driver(UCLASS_MTD, 403*e65bf00aSYifeng Zhao DM_GET_DRIVER(rk_nandc_v6), 404*e65bf00aSYifeng Zhao &dev); 405*e65bf00aSYifeng Zhao if (ret && ret != -ENODEV) 406*e65bf00aSYifeng Zhao pr_err("Failed to initialize NAND controller. (error %d)\n", 407*e65bf00aSYifeng Zhao ret); 408*e65bf00aSYifeng Zhao } 409*e65bf00aSYifeng Zhao 410*e65bf00aSYifeng Zhao int nand_spl_load_image(u32 offs, u32 size, void *buf) 411*e65bf00aSYifeng Zhao { 412*e65bf00aSYifeng Zhao return -EIO; 413*e65bf00aSYifeng Zhao } 414*e65bf00aSYifeng Zhao 415*e65bf00aSYifeng Zhao void nand_init(void){}; 416*e65bf00aSYifeng Zhao 417*e65bf00aSYifeng Zhao int rk_nand_init(void) 418*e65bf00aSYifeng Zhao { 419*e65bf00aSYifeng Zhao return -ENODEV; 420*e65bf00aSYifeng Zhao } 421*e65bf00aSYifeng Zhao 422*e65bf00aSYifeng Zhao #else 42357e25cf7SYifeng Zhao void board_nand_init(void) 42457e25cf7SYifeng Zhao { 42557e25cf7SYifeng Zhao const void *blob = gd->fdt_blob; 4266c65ad50SJason Zhu static int initialized; 42757e25cf7SYifeng Zhao fdt_addr_t regs; 42857e25cf7SYifeng Zhao int node; 42957e25cf7SYifeng Zhao 4306c65ad50SJason Zhu if (initialized) 4316c65ad50SJason Zhu return; 4326c65ad50SJason Zhu 4336c65ad50SJason Zhu initialized = 1; 4346c65ad50SJason Zhu 43557e25cf7SYifeng Zhao if (g_rk_nand) 43657e25cf7SYifeng Zhao return; 43757e25cf7SYifeng Zhao 43857e25cf7SYifeng Zhao node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC); 43957e25cf7SYifeng Zhao 44057e25cf7SYifeng Zhao if (node < 0) { 44157e25cf7SYifeng Zhao printf("Nand node not found\n"); 442*e65bf00aSYifeng Zhao return; 44357e25cf7SYifeng Zhao } 44457e25cf7SYifeng Zhao 44557e25cf7SYifeng Zhao if (!fdtdec_get_is_enabled(blob, node)) { 44657e25cf7SYifeng Zhao debug("Nand disabled in device tree\n"); 447*e65bf00aSYifeng Zhao return; 44857e25cf7SYifeng Zhao } 44957e25cf7SYifeng Zhao 45057e25cf7SYifeng Zhao regs = fdt_get_base_address(blob, node); 451*e65bf00aSYifeng Zhao if (!regs) { 45257e25cf7SYifeng Zhao debug("Nand address not found\n"); 453*e65bf00aSYifeng Zhao return; 45457e25cf7SYifeng Zhao } 45557e25cf7SYifeng Zhao 45657e25cf7SYifeng Zhao g_rk_nand = kzalloc(sizeof(*g_rk_nand), GFP_KERNEL); 45757e25cf7SYifeng Zhao g_rk_nand->regs = (void *)regs; 45857e25cf7SYifeng Zhao g_rk_nand->databuf = kzalloc(CONFIG_SYS_NAND_PAGE_SIZE, GFP_KERNEL); 45957e25cf7SYifeng Zhao nandc_init(g_rk_nand); 46057e25cf7SYifeng Zhao read_flash_id(g_rk_nand, g_rk_nand->id); 461*e65bf00aSYifeng Zhao 462*e65bf00aSYifeng Zhao if (g_rk_nand->id[0] == g_rk_nand->id[1]) 463*e65bf00aSYifeng Zhao goto err; 464*e65bf00aSYifeng Zhao 465*e65bf00aSYifeng Zhao if (g_rk_nand->id[1] == 0xA1 || g_rk_nand->id[1] == 0xF1 || 466*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0xD1 || g_rk_nand->id[1] == 0xAA || 467*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0xDA || g_rk_nand->id[1] == 0xAC || 468*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0xDC || g_rk_nand->id[1] == 0xA3 || 469*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0xD3 || g_rk_nand->id[1] == 0x95 || 470*e65bf00aSYifeng Zhao g_rk_nand->id[1] == 0x48) { 47157e25cf7SYifeng Zhao g_rk_nand->chipnr = 1; 47257e25cf7SYifeng Zhao return; 473*e65bf00aSYifeng Zhao } 474*e65bf00aSYifeng Zhao 47557e25cf7SYifeng Zhao err: 476*e65bf00aSYifeng Zhao kfree(g_rk_nand->databuf); 47757e25cf7SYifeng Zhao kfree(g_rk_nand); 478*e65bf00aSYifeng Zhao g_rk_nand = NULL; 47957e25cf7SYifeng Zhao } 48057e25cf7SYifeng Zhao 48157e25cf7SYifeng Zhao int nand_spl_load_image(u32 offs, u32 size, void *buf) 48257e25cf7SYifeng Zhao { 48357e25cf7SYifeng Zhao int i; 48457e25cf7SYifeng Zhao unsigned int page; 48557e25cf7SYifeng Zhao unsigned int maxpages = CONFIG_SYS_NAND_SIZE / 48657e25cf7SYifeng Zhao CONFIG_SYS_NAND_PAGE_SIZE; 48757e25cf7SYifeng Zhao 48857e25cf7SYifeng Zhao /* Convert to page number */ 48957e25cf7SYifeng Zhao page = offs / CONFIG_SYS_NAND_PAGE_SIZE; 49057e25cf7SYifeng Zhao i = 0; 49157e25cf7SYifeng Zhao 49257e25cf7SYifeng Zhao size = roundup(size, CONFIG_SYS_NAND_PAGE_SIZE); 49357e25cf7SYifeng Zhao while (i < size / CONFIG_SYS_NAND_PAGE_SIZE) { 49457e25cf7SYifeng Zhao /* 49557e25cf7SYifeng Zhao * Check if we have crossed a block boundary, and if so 49657e25cf7SYifeng Zhao * check for bad block. 49757e25cf7SYifeng Zhao */ 49857e25cf7SYifeng Zhao if (!(page % CONFIG_SYS_NAND_PAGE_COUNT)) { 49957e25cf7SYifeng Zhao /* 50057e25cf7SYifeng Zhao * Yes, new block. See if this block is good. If not, 50157e25cf7SYifeng Zhao * loop until we find a good block. 50257e25cf7SYifeng Zhao */ 50357e25cf7SYifeng Zhao while (is_badblock(page)) { 50457e25cf7SYifeng Zhao page = page + CONFIG_SYS_NAND_PAGE_COUNT; 50557e25cf7SYifeng Zhao /* Check i we've reached the end of flash. */ 50657e25cf7SYifeng Zhao if (page >= maxpages) 50757e25cf7SYifeng Zhao return -EIO; 50857e25cf7SYifeng Zhao } 50957e25cf7SYifeng Zhao } 51057e25cf7SYifeng Zhao 51157e25cf7SYifeng Zhao if (nandc_read_page(page, buf) < 0) 51257e25cf7SYifeng Zhao return -EIO; 51357e25cf7SYifeng Zhao 51457e25cf7SYifeng Zhao page++; 51557e25cf7SYifeng Zhao i++; 51657e25cf7SYifeng Zhao buf = buf + CONFIG_SYS_NAND_PAGE_SIZE; 51757e25cf7SYifeng Zhao } 51857e25cf7SYifeng Zhao return 0; 51957e25cf7SYifeng Zhao } 52057e25cf7SYifeng Zhao 52157e25cf7SYifeng Zhao void nand_init(void) 52257e25cf7SYifeng Zhao { 52357e25cf7SYifeng Zhao board_nand_init(); 52457e25cf7SYifeng Zhao } 52557e25cf7SYifeng Zhao 52657e25cf7SYifeng Zhao int rk_nand_init(void) 52757e25cf7SYifeng Zhao { 52857e25cf7SYifeng Zhao board_nand_init(); 52957e25cf7SYifeng Zhao if (g_rk_nand && g_rk_nand->chipnr) 53057e25cf7SYifeng Zhao return 0; 53157e25cf7SYifeng Zhao else 53257e25cf7SYifeng Zhao return -ENODEV; 53357e25cf7SYifeng Zhao } 534*e65bf00aSYifeng Zhao #endif 53557e25cf7SYifeng Zhao 53657e25cf7SYifeng Zhao void nand_deselect(void) {} 537*e65bf00aSYifeng Zhao 538