
On Thu, 17 Aug 2017, Paweł Jarosz wrote:
Add basic Rockchip nand driver.
Driver in current state has 16, 24, 40, 60 per 1024B BCH/ECC ability and 8 bit asynchronous flash interface support. Other features will come later.
Signed-off-by: Paweł Jarosz paweljarosz3691@gmail.com
Changes since v1:
- none
Changes since v2:
- fixed correct ecc checking
Changes since v3:
- none
drivers/mtd/nand/Kconfig | 6 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/rockchip_nand.c | 660 +++++++++++++++++++++++++++++++++++++++ include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 5 files changed, 669 insertions(+) create mode 100644 drivers/mtd/nand/rockchip_nand.c
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 71d678f..c308497 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -69,6 +69,12 @@ config NAND_PXA3XX This enables the driver for the NAND flash device found on PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
+config NAND_ROCKCHIP
- bool "Support for NAND on Rockchip SoCs"
- select SYS_NAND_SELF_INIT
- ---help---
- Enable support for Rockchip nand.
config NAND_SUNXI bool "Support for NAND on Allwinner SoCs" depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index c3d4a99..0659253 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o obj-$(CONFIG_NAND_PLAT) += nand_plat.o obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o +obj-$(CONFIG_NAND_ROCKCHIP) += rockchip_nand.o
else # minimal SPL drivers
diff --git a/drivers/mtd/nand/rockchip_nand.c b/drivers/mtd/nand/rockchip_nand.c new file mode 100644 index 0000000..d8f4439 --- /dev/null +++ b/drivers/mtd/nand/rockchip_nand.c @@ -0,0 +1,660 @@ +/*
- Copyright (c) 2017 Yifeng Zhao yifeng.zhao@rock-chips.com
- Copyright (c) 2017 Paweł Jarosz paweljarosz3691@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <inttypes.h> +#include <nand.h> +#include <linux/kernel.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/io.h>
+DECLARE_GLOBAL_DATA_PTR;
+#define NANDC_V6_BOOTROM_ECC 24 +#define NANDC_V6_NUM_BANKS 8 +#define NANDC_V6_DEF_TIMEOUT 20000 +#define NANDC_V6_READ 0 +#define NANDC_V6_WRITE 1
+#define NANDC_REG_V6_FMCTL 0x00 +#define NANDC_REG_V6_FMWAIT 0x04 +#define NANDC_REG_V6_FLCTL 0x08 +#define NANDC_REG_V6_BCHCTL 0x0c +#define NANDC_REG_V6_DMA_CFG 0x10 +#define NANDC_REG_V6_DMA_BUF0 0x14 +#define NANDC_REG_V6_DMA_BUF1 0x18 +#define NANDC_REG_V6_DMA_ST 0x1C +#define NANDC_REG_V6_BCHST 0x20 +#define NANDC_REG_V6_RANDMZ 0x150 +#define NANDC_REG_V6_VER 0x160 +#define NANDC_REG_V6_INTEN 0x16C +#define NANDC_REG_V6_INTCLR 0x170 +#define NANDC_REG_V6_INTST 0x174 +#define NANDC_REG_V6_SPARE0 0x200 +#define NANDC_REG_V6_SPARE1 0x230 +#define NANDC_REG_V6_BANK0 0x800 +#define NANDC_REG_V6_SRAM0 0x1000 +#define NANDC_REG_V6_SRAM_SIZE 0x400
For the Rockchip drivers we have usually used structures to represent the layout. I know that this will be very sparse for this particular case, but it seems to be worth this for consistency.
+#define NANDC_REG_V6_DATA 0x00 +#define NANDC_REG_V6_ADDR 0x04 +#define NANDC_REG_V6_CMD 0x08
+/* FMCTL */ +#define NANDC_V6_FM_WP BIT(8) +#define NANDC_V6_FM_CE_SEL_M 0xFF +#define NANDC_V6_FM_CE_SEL(x) (1 << (x))
BIT(x) ?
+#define NANDC_V6_FM_FREADY BIT(9)
+/* FLCTL */ +#define NANDC_V6_FL_RST BIT(0) +#define NANDC_V6_FL_DIR_S 0x1 +#define NANDC_V6_FL_XFER_START BIT(2) +#define NANDC_V6_FL_XFER_EN BIT(3) +#define NANDC_V6_FL_ST_BUF_S 0x4 +#define NANDC_V6_FL_XFER_COUNT BIT(5) +#define NANDC_V6_FL_ACORRECT BIT(10) +#define NANDC_V6_FL_XFER_READY BIT(20)
+/* BCHCTL */ +#define NAND_V6_BCH_REGION_S 0x5 +#define NAND_V6_BCH_REGION_M 0x7
+/* BCHST */ +#define NANDC_V6_BCH0_ST_ERR BIT(2) +#define NANDC_V6_BCH1_ST_ERR BIT(15) +#define NANDC_V6_ECC_ERR_CNT0(x) ((((x & (0x1F << 3)) >> 3) \
| ((x & (1 << 27)) >> 22)) & 0x3F)
+#define NANDC_V6_ECC_ERR_CNT1(x) ((((x & (0x1F << 16)) >> 16) \
| ((x & (1 << 29)) >> 24)) & 0x3F)
This might benefit from using functions from bitfield.h?
+struct rk_nand {
- uint32_t banks[NANDC_V6_NUM_BANKS];
Is the number of banks fixed or should this be dynamically allocated based on a device-tree property (or driver-data, if it is dependent on how the controller was synthesized)?
- struct nand_hw_control controller;
- uint32_t ecc_strength;
- struct mtd_info mtd;
- bool bootromblocks;
- void __iomem *regs;
- int selected_bank;
+};
+static struct nand_ecclayout nand_oob_fix = {
- .eccbytes = 24,
- .eccpos = {
4, 5, 6, 7, 8, 9, 10},
- .oobfree = {
{.offset = 0,
.length = 4} }
The indentation looks odd on those.
+};
+static inline struct rk_nand *to_rknand(struct nand_hw_control *ctrl) +{
- return container_of(ctrl, struct rk_nand, controller);
+}
+static void rockchip_nand_init(struct rk_nand *rknand) +{
- writel(0, rknand->regs + NANDC_REG_V6_RANDMZ);
- writel(0, rknand->regs + NANDC_REG_V6_DMA_CFG);
- writel(0, rknand->regs + NANDC_REG_V6_BCHCTL);
- writel(NANDC_V6_FM_WP, rknand->regs + NANDC_REG_V6_FMCTL);
- writel(0x1081, rknand->regs + NANDC_REG_V6_FMWAIT);
Why the 0x1081?
+}
+static void rockchip_nand_select_chip(struct mtd_info *mtd, int chipnr) +{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct rk_nand *rknand = to_rknand(chip->controller);
- void __iomem *bank_base;
- uint32_t reg;
- int banknr;
- reg = readl(rknand->regs + NANDC_REG_V6_FMCTL);
- reg &= ~NANDC_V6_FM_CE_SEL_M;
- if (chipnr == -1) {
banknr = -1;
- } else {
banknr = rknand->banks[chipnr];
bank_base = rknand->regs + NANDC_REG_V6_BANK0 + banknr * 0x100;
Once converted to a structure, this could be as simple to read as bank_base = &rknand->bank[banknr];
chip->IO_ADDR_R = bank_base;
chip->IO_ADDR_W = bank_base;
reg |= 1 << banknr;
- }
- writel(reg, rknand->regs + NANDC_REG_V6_FMCTL);
Why not a clrsetbits?
- rknand->selected_bank = banknr;
+}
+static void rockchip_nand_cmd_ctrl(struct mtd_info *mtd,
int dat,
unsigned int ctrl)
+{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct rk_nand *rknand = to_rknand(chip->controller);
- void __iomem *bank_base = rknand->regs + NANDC_REG_V6_BANK0
+ rknand->selected_bank * 0x100;
See above.
- if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_ALE)
bank_base += NANDC_REG_V6_ADDR;
This is not the bank_base you are modifying. So this really is if (ctrl & NAND_ALE) chip->IO_ADDR_W = &rknand->bank[i].addr; else if (ctrl & NAND_CLE) chip->IO_ADDR_W = &rknand->bank[i].cmd; else chip->IO_ADDR_W = &rknand->bank[i];
else if (ctrl & NAND_CLE)
bank_base += NANDC_REG_V6_CMD;
chip->IO_ADDR_W = bank_base;
- }
- if (dat != NAND_CMD_NONE)
writeb(dat & 0xFF, chip->IO_ADDR_W);
+}
+static void rockchip_nand_read_buf(struct mtd_info *mtd,
uint8_t *buf,
int len)
+{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct rk_nand *rknand = to_rknand(chip->controller);
- int offs = 0;
- void __iomem *bank_base = rknand->regs + NANDC_REG_V6_BANK0
+ rknand->selected_bank * 0x100;
- for (offs = 0; offs < len; offs++)
buf[offs] = readb(bank_base);
+}
+static void rockchip_nand_write_buf(struct mtd_info *mtd,
const uint8_t *buf,
int len)
+{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct rk_nand *rknand = to_rknand(chip->controller);
- int offs = 0;
- void __iomem *bank_base = rknand->regs + NANDC_REG_V6_BANK0
+ rknand->selected_bank * 0x100;
- for (offs = 0; offs < len; offs++)
writeb(buf[offs], bank_base);
+}
See above.
+static uint8_t rockchip_nand_read_byte(struct mtd_info *mtd) +{
- uint8_t ret;
- rockchip_nand_read_buf(mtd, &ret, 1);
- return ret;
+}
+static int rockchip_nand_dev_ready(struct mtd_info *mtd) +{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct rk_nand *rknand = to_rknand(chip->controller);
- if (readl(rknand->regs + NANDC_REG_V6_FMCTL) & NANDC_V6_FM_FREADY)
return 1;
- return 0;
+}
+static int rockchip_nand_hw_ecc_setup(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc,
uint32_t strength)
+{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct rk_nand *rknand = to_rknand(chip->controller);
- u32 reg;
- ecc->strength = strength;
- ecc->bytes = DIV_ROUND_UP(ecc->strength * 14, 8);
- ecc->bytes = ALIGN(ecc->bytes, 2);
- switch (ecc->strength) {
- case 60:
reg = 0x00040010;
break;
- case 40:
reg = 0x00040000;
break;
- case 24:
reg = 0x00000010;
break;
- case 16:
reg = 0x00000000;
break;
- default:
return -EINVAL;
- }
Could you use symbolic constants?
- writel(reg, rknand->regs + NANDC_REG_V6_BCHCTL);
- return 0;
+}
+static void rockchip_nand_pio_xfer_start(struct rk_nand *rknand,
u8 dir,
u8 st_buf)
+{
- u32 reg;
- reg = readl(rknand->regs + NANDC_REG_V6_BCHCTL);
- reg = (reg & (~(NAND_V6_BCH_REGION_M << NAND_V6_BCH_REGION_S))) |
(rknand->selected_bank << NAND_V6_BCH_REGION_S);
- writel(reg, rknand->regs + NANDC_REG_V6_BCHCTL);
clrsetbits?
- reg = (dir << NANDC_V6_FL_DIR_S) | (st_buf << NANDC_V6_FL_ST_BUF_S) |
NANDC_V6_FL_XFER_EN | NANDC_V6_FL_XFER_COUNT |
NANDC_V6_FL_ACORRECT;
- writel(reg, rknand->regs + NANDC_REG_V6_FLCTL);
- reg |= NANDC_V6_FL_XFER_START;
- writel(reg, rknand->regs + NANDC_REG_V6_FLCTL);
setbits?
+}
+static int rockchip_nand_wait_pio_xfer_done(struct rk_nand *rknand) +{
- int timeout = NANDC_V6_DEF_TIMEOUT;
- int reg;
- while (timeout--) {
reg = readl(rknand->regs + NANDC_REG_V6_FLCTL);
if ((reg & NANDC_V6_FL_XFER_READY) != 0)
break;
udelay(1);
- }
- if (timeout == 0)
return -1;
- return 0;
+}
+static void rockchip_nand_read_extra_oob(struct mtd_info *mtd, u8 *oob) +{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- int offset = ((ecc->bytes + ecc->prepad) * ecc->steps);
- int len = mtd->oobsize - offset;
- if (len <= 0)
return;
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset + mtd->writesize, -1);
- rockchip_nand_read_buf(mtd, oob + offset, len);
+}
+static void rockchip_nand_write_extra_oob(struct mtd_info *mtd, u8 *oob) +{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- int offset = ((ecc->bytes + ecc->prepad) * ecc->steps);
- int len = mtd->oobsize - offset;
- if (len <= 0)
return;
- chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset + mtd->writesize, -1);
- rockchip_nand_write_buf(mtd, oob + offset, len);
+}
+static int rockchip_nand_hw_syndrome_pio_read_page(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf,
int oob_required,
int page)
+{
- struct rk_nand *rknand = to_rknand(chip->controller);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- void __iomem *sram_base = rknand->regs + NANDC_REG_V6_SRAM0;
- unsigned int max_bitflips = 0;
- int ret, step, bch_st;
- int offset = page * mtd->writesize;
- if (rknand->bootromblocks && (offset < (7 * mtd->erasesize)))
rockchip_nand_hw_ecc_setup(mtd, ecc, NANDC_V6_BOOTROM_ECC);
- rockchip_nand_pio_xfer_start(rknand, NANDC_V6_READ, 0);
- for (step = 0; step < ecc->steps; step++) {
int data_off = step * ecc->size;
int oob_off = step * (ecc->bytes + ecc->prepad);
u8 *data = buf + data_off;
u8 *oob = chip->oob_poi + oob_off;
ret = rockchip_nand_wait_pio_xfer_done(rknand);
if (ret)
return ret;
bch_st = readl(rknand->regs + NANDC_REG_V6_BCHST);
if (bch_st & NANDC_V6_BCH0_ST_ERR) {
mtd->ecc_stats.failed++;
max_bitflips = -1;
} else {
ret = NANDC_V6_ECC_ERR_CNT0(bch_st);
mtd->ecc_stats.corrected += ret;
max_bitflips = max_t(unsigned int, max_bitflips, ret);
}
if ((step + 1) < ecc->steps)
rockchip_nand_pio_xfer_start(rknand, NANDC_V6_READ,
(step + 1) & 0x1);
memcpy_fromio(data, sram_base + NANDC_REG_V6_SRAM_SIZE *
(step & 1), ecc->size);
if (step & 1)
memcpy_fromio(oob, rknand->regs + NANDC_REG_V6_SPARE1, 4);
else
memcpy_fromio(oob, rknand->regs + NANDC_REG_V6_SPARE0, 4);
- }
- rockchip_nand_read_extra_oob(mtd, chip->oob_poi);
- if (rknand->bootromblocks)
rockchip_nand_hw_ecc_setup(mtd, ecc, rknand->ecc_strength);
- return max_bitflips;
+}
+static uint32_t rockchip_nand_make_bootrom_compat(struct mtd_info *mtd,
int page,
const u8 *oob,
bool bootromblocks)
+{
- int pages_per_block = mtd->erasesize / mtd->writesize;
- int offset = page * mtd->writesize;
- if ((offset < (2 * mtd->erasesize)) || !(page % 2) ||
(offset >= (7 * mtd->erasesize)) || !bootromblocks)
return oob[3] | (oob[2] << 8) | (oob[1] << 16) | (oob[0] << 24);
- return (page % pages_per_block + 1) * 4;
+}
+static int rockchip_nand_hw_syndrome_pio_write_page(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf,
int oob_required,
int page)
+{
- struct rk_nand *rknand = to_rknand(chip->controller);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- void __iomem *sram_base = rknand->regs + NANDC_REG_V6_SRAM0;
- int ret, index, step = 0;
- int offset = page * mtd->writesize;
- int data_off = step * ecc->size;
- int oob_off = step * (ecc->bytes + ecc->prepad);
- const u8 *data = buf + data_off;
- const u8 *oob = chip->oob_poi + oob_off;
- if (rknand->bootromblocks && (offset < (7 * mtd->erasesize)))
rockchip_nand_hw_ecc_setup(mtd, ecc, NANDC_V6_BOOTROM_ECC);
- index = rockchip_nand_make_bootrom_compat(mtd, page, oob,
rknand->bootromblocks);
- memcpy_toio(sram_base, data, ecc->size);
- memcpy_toio(rknand->regs + NANDC_REG_V6_SPARE0, &index, ecc->prepad);
- for (step = 1; step <= ecc->steps; step++) {
rockchip_nand_pio_xfer_start(rknand, NANDC_V6_WRITE,
(step - 1) & 0x1);
data_off = step * ecc->size;
oob_off = step * (ecc->bytes + ecc->prepad);
data = buf + data_off;
oob = chip->oob_poi + oob_off;
if (step < ecc->steps) {
memcpy_toio(sram_base + NANDC_REG_V6_SRAM_SIZE *
(step & 1), data, ecc->size);
if (step & 1)
memcpy_toio(rknand->regs + NANDC_REG_V6_SPARE1,
oob, ecc->prepad);
else
memcpy_toio(rknand->regs + NANDC_REG_V6_SPARE0,
oob, ecc->prepad);
}
ret = rockchip_nand_wait_pio_xfer_done(rknand);
if (ret)
return ret;
- }
- rockchip_nand_write_extra_oob(mtd, chip->oob_poi);
- rockchip_nand_hw_ecc_setup(mtd, ecc, rknand->ecc_strength);
- return 0;
+}
+static const u8 strengths[] = {60, 40, 24, 16};
+static int rockchip_nand_ecc_max_strength(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc)
+{
- uint32_t max_strength, index;
- max_strength = ((mtd->oobsize / ecc->steps) - ecc->prepad) * 8 / 14;
- for (index = 0; index < ARRAY_SIZE(strengths); index++)
if (max_strength >= strengths[index])
break;
- if (index >= ARRAY_SIZE(strengths))
return -ENOTSUPP;
- return strengths[index];
+}
+static bool rockchip_nand_strength_is_valid(int strength) +{
- uint32_t index;
- for (index = 0; index < ARRAY_SIZE(strengths); index++)
if (strength == strengths[index])
break;
- if (index == ARRAY_SIZE(strengths))
return false;
- return true;
+}
+static int rockchip_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc)
+{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct rk_nand *rknand = to_rknand(chip->controller);
- uint32_t strength;
- int index;
- ecc->prepad = 4;
- ecc->steps = mtd->writesize / ecc->size;
- if (fdtdec_get_bool(gd->fdt_blob, chip->flash_node,
"rockchip,protect-bootrom-blocks"))
rknand->bootromblocks = true;
- else
rknand->bootromblocks = false;
- if (rockchip_nand_strength_is_valid(ecc->strength))
strength = ecc->strength;
- else
strength = rockchip_nand_ecc_max_strength(mtd, ecc);
- rockchip_nand_hw_ecc_setup(mtd, ecc, strength);
- rknand->ecc_strength = ecc->strength;
- nand_oob_fix.eccbytes = ecc->bytes * ecc->steps;
- for (index = 0; index < ecc->bytes; index++)
nand_oob_fix.eccpos[index] = index + ecc->prepad;
- ecc->layout = &nand_oob_fix;
- if (mtd->oobsize < ((ecc->bytes + ecc->prepad) * ecc->steps)) {
return -EINVAL;
- }
- return 0;
+}
+static int rockchip_nand_ecc_init(struct mtd_info *mtd,
struct nand_ecc_ctrl *ecc)
+{
- int ret;
- switch (ecc->mode) {
- case NAND_ECC_HW_SYNDROME:
ret = rockchip_nand_hw_ecc_ctrl_init(mtd, ecc);
if (ret)
return ret;
ecc->read_page = rockchip_nand_hw_syndrome_pio_read_page;
ecc->write_page = rockchip_nand_hw_syndrome_pio_write_page;
break;
- case NAND_ECC_SOFT_BCH:
- case NAND_ECC_NONE:
- case NAND_ECC_SOFT:
break;
- default:
return -EINVAL;
- }
- return 0;
+}
+static int rockchip_nand_chip_init(int node, struct rk_nand *rknand, int devnum) +{
- const void *blob = gd->fdt_blob;
- struct nand_chip *chip;
- struct mtd_info *mtd;
- int ret;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- chip->chip_delay = 50;
- chip->flash_node = node;
- chip->select_chip = rockchip_nand_select_chip;
- chip->cmd_ctrl = rockchip_nand_cmd_ctrl;
- chip->read_buf = rockchip_nand_read_buf;
- chip->write_buf = rockchip_nand_write_buf;
- chip->read_byte = rockchip_nand_read_byte;
- chip->dev_ready = rockchip_nand_dev_ready;
- chip->controller = &rknand->controller;
- rknand->banks[devnum] = fdtdec_get_int(blob, node, "reg", -1);
- if (rknand->banks[devnum] < 0)
return -EINVAL;
- mtd = nand_to_mtd(chip);
- mtd->name = "rknand";
- ret = nand_scan_ident(mtd, 1, NULL);
- if (ret)
return ret;
- ret = rockchip_nand_ecc_init(mtd, &chip->ecc);
- if (ret) {
debug("rockchip_nand_ecc_init failed: %d\n", ret);
return ret;
- }
- ret = nand_scan_tail(mtd);
- if (ret) {
debug("nand_scan_tail failed: %d\n", ret);
return ret;
- }
- ret = nand_register(devnum, mtd);
- if (ret) {
debug("Failed to register mtd device: %d\n", ret);
return ret;
- }
- return 0;
+}
+static int rockchip_nand_chips_init(int node, struct rk_nand *rknand) +{
- const void *blob = gd->fdt_blob;
- int nand_node;
- int ret, i = 0;
- for (nand_node = fdt_first_subnode(blob, node); nand_node >= 0;
nand_node = fdt_next_subnode(blob, nand_node)) {
ret = rockchip_nand_chip_init(nand_node, rknand, i++);
if (ret)
return ret;
- }
- return 0;
+}
+void board_nand_init(void) +{
- const void *blob = gd->fdt_blob;
- struct rk_nand *rknand;
- fdt_addr_t regs;
- int node;
- int ret;
- rknand = kzalloc(sizeof(*rknand), GFP_KERNEL);
- node = fdtdec_next_compatible(blob, 0, COMPAT_ROCKCHIP_NANDC);
- if (node < 0) {
debug("Nand node not found\n");
goto err;
- }
- if (!fdtdec_get_is_enabled(blob, node)) {
debug("Nand disabled in device tree\n");
goto err;
- }
- regs = fdtdec_get_addr(blob, node, "reg");
- if (regs == FDT_ADDR_T_NONE) {
debug("Nand address not found\n");
goto err;
- }
- rknand->regs = (void *)regs;
- spin_lock_init(&rknand->controller.lock);
- init_waitqueue_head(&rknand->controller.wq);
- rockchip_nand_init(rknand);
- ret = rockchip_nand_chips_init(node, rknand);
- if (ret) {
debug("Failed to init nand chips\n");
goto err;
- }
- return;
+err:
- kfree(rknand);
+}
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) +{
- struct mtd_info *mtd;
- mtd = get_nand_dev_by_index(0);
- return nand_read_skip_bad(mtd, offs, &size, NULL, size, (u_char *)dst);
+}
+void nand_deselect(void) {} diff --git a/include/fdtdec.h b/include/fdtdec.h index 4a0947c..0e68788 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -157,6 +157,7 @@ enum fdt_compat_id { COMPAT_ALTERA_SOCFPGA_F2SDR0, /* SoCFPGA fpga2SDRAM0 bridge */ COMPAT_ALTERA_SOCFPGA_F2SDR1, /* SoCFPGA fpga2SDRAM1 bridge */ COMPAT_ALTERA_SOCFPGA_F2SDR2, /* SoCFPGA fpga2SDRAM2 bridge */
COMPAT_ROCKCHIP_NANDC, /* Rockchip NAND controller */
COMPAT_COUNT,
}; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 107a892..4a8a8d7 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -70,6 +70,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(ALTERA_SOCFPGA_F2SDR0, "altr,socfpga-fpga2sdram0-bridge"), COMPAT(ALTERA_SOCFPGA_F2SDR1, "altr,socfpga-fpga2sdram1-bridge"), COMPAT(ALTERA_SOCFPGA_F2SDR2, "altr,socfpga-fpga2sdram2-bridge"),
- COMPAT(ROCKCHIP_NANDC, "rockchip,nandc"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)