Merge https://gitlab.denx.de/u-boot/custodians/u-boot-spi
[platform/kernel/u-boot.git] / drivers / mtd / nand / raw / zynq_nand.c
index e932a58..3941297 100644 (file)
 #include <asm/io.h>
 #include <linux/errno.h>
 #include <nand.h>
+#include <linux/ioport.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand_ecc.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/sys_proto.h>
+#include <dm.h>
 
 /* The NAND flash driver defines */
 #define ZYNQ_NAND_CMD_PHASE            1
@@ -120,22 +122,31 @@ struct zynq_nand_smc_regs {
        u32 reserved2[2];
        u32 eval0r;             /* 0x418 */
 };
-#define zynq_nand_smc_base     ((struct zynq_nand_smc_regs __iomem *)\
-                               ZYNQ_SMC_BASEADDR)
 
 /*
- * struct zynq_nand_info - Defines the NAND flash driver instance
+ * struct nand_config - Defines the NAND flash driver instance
  * @parts:             Pointer to the mtd_partition structure
  * @nand_base:         Virtual address of the NAND flash device
  * @end_cmd_pending:   End command is pending
  * @end_cmd:           End command
  */
-struct zynq_nand_info {
+struct nand_config {
        void __iomem    *nand_base;
        u8              end_cmd_pending;
        u8              end_cmd;
 };
 
+struct nand_drv {
+       struct zynq_nand_smc_regs *reg;
+       struct nand_config config;
+};
+
+struct zynq_nand_info {
+       struct udevice *dev;
+       struct nand_drv nand_ctrl;
+       struct nand_chip nand_chip;
+};
+
 /*
  * struct zynq_nand_command_format - Defines NAND flash command format
  * @start_cmd:         First cycle command (Start command)
@@ -239,16 +250,18 @@ static struct nand_bbt_descr bbt_mirror_descr = {
  *
  * returns: status for command completion, -1 for Timeout
  */
-static int zynq_nand_waitfor_ecc_completion(void)
+static int zynq_nand_waitfor_ecc_completion(struct mtd_info *mtd)
 {
+       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct nand_drv *smc = nand_get_controller_data(nand_chip);
        unsigned long timeout;
        u32 status;
 
        /* Wait max 10us */
        timeout = 10;
-       status = readl(&zynq_nand_smc_base->esr);
+       status = readl(&smc->reg->esr);
        while (status & ZYNQ_NAND_ECC_BUSY) {
-               status = readl(&zynq_nand_smc_base->esr);
+               status = readl(&smc->reg->esr);
                if (timeout == 0)
                        return -1;
                timeout--;
@@ -266,33 +279,35 @@ static int zynq_nand_waitfor_ecc_completion(void)
  *
  * returns:    0 on success or error value on failure
  */
-static int zynq_nand_init_nand_flash(int option)
+static int zynq_nand_init_nand_flash(struct mtd_info *mtd, int option)
 {
+       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct nand_drv *smc = nand_get_controller_data(nand_chip);
        u32 status;
 
        /* disable interrupts */
-       writel(ZYNQ_NAND_CLR_CONFIG, &zynq_nand_smc_base->cfr);
+       writel(ZYNQ_NAND_CLR_CONFIG, &smc->reg->cfr);
 #ifndef CONFIG_NAND_ZYNQ_USE_BOOTLOADER1_TIMINGS
        /* Initialize the NAND interface by setting cycles and operation mode */
-       writel(ZYNQ_NAND_SET_CYCLES, &zynq_nand_smc_base->scr);
+       writel(ZYNQ_NAND_SET_CYCLES, &smc->reg->scr);
 #endif
        if (option & NAND_BUSWIDTH_16)
-               writel(ZYNQ_NAND_SET_OPMODE_16BIT, &zynq_nand_smc_base->sor);
+               writel(ZYNQ_NAND_SET_OPMODE_16BIT, &smc->reg->sor);
        else
-               writel(ZYNQ_NAND_SET_OPMODE_8BIT, &zynq_nand_smc_base->sor);
+               writel(ZYNQ_NAND_SET_OPMODE_8BIT, &smc->reg->sor);
 
-       writel(ZYNQ_NAND_DIRECT_CMD, &zynq_nand_smc_base->dcr);
+       writel(ZYNQ_NAND_DIRECT_CMD, &smc->reg->dcr);
 
        /* Wait till the ECC operation is complete */
-       status = zynq_nand_waitfor_ecc_completion();
+       status = zynq_nand_waitfor_ecc_completion(mtd);
        if (status < 0) {
                printf("%s: Timeout\n", __func__);
                return status;
        }
 
        /* Set the command1 and command2 register */
-       writel(ZYNQ_NAND_ECC_CMD1, &zynq_nand_smc_base->emcmd1r);
-       writel(ZYNQ_NAND_ECC_CMD2, &zynq_nand_smc_base->emcmd2r);
+       writel(ZYNQ_NAND_ECC_CMD1, &smc->reg->emcmd1r);
+       writel(ZYNQ_NAND_ECC_CMD2, &smc->reg->emcmd2r);
 
        return 0;
 }
@@ -311,12 +326,14 @@ static int zynq_nand_init_nand_flash(int option)
 static int zynq_nand_calculate_hwecc(struct mtd_info *mtd, const u8 *data,
                u8 *ecc_code)
 {
+       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct nand_drv *smc = nand_get_controller_data(nand_chip);
        u32 ecc_value = 0;
        u8 ecc_reg, ecc_byte;
        u32 ecc_status;
 
        /* Wait till the ECC operation is complete */
-       ecc_status = zynq_nand_waitfor_ecc_completion();
+       ecc_status = zynq_nand_waitfor_ecc_completion(mtd);
        if (ecc_status < 0) {
                printf("%s: Timeout\n", __func__);
                return ecc_status;
@@ -324,7 +341,7 @@ static int zynq_nand_calculate_hwecc(struct mtd_info *mtd, const u8 *data,
 
        for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) {
                /* Read ECC value for each block */
-               ecc_value = readl(&zynq_nand_smc_base->eval0r + ecc_reg);
+               ecc_value = readl(&smc->reg->eval0r + ecc_reg);
 
                /* Get the ecc status from ecc read value */
                ecc_status = (ecc_value >> 24) & 0xFF;
@@ -779,10 +796,11 @@ static void zynq_nand_select_chip(struct mtd_info *mtd, int chip)
 static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
                                 int column, int page_addr)
 {
-       struct nand_chip *chip = mtd->priv;
+       struct nand_chip *chip = mtd_to_nand(mtd);
+       struct nand_drv *smc = nand_get_controller_data(chip);
        const struct zynq_nand_command_format *curr_cmd = NULL;
        u8 addr_cycles = 0;
-       struct zynq_nand_info *xnand = (struct zynq_nand_info *)chip->priv;
+       struct nand_config *xnand = &smc->config;
        void *cmd_addr;
        unsigned long cmd_data = 0;
        unsigned long cmd_phase_addr = 0;
@@ -821,13 +839,13 @@ static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
        curr_cmd = &zynq_nand_commands[index];
 
        /* Clear interrupt */
-       writel(ZYNQ_MEMC_CLRCR_INT_CLR1, &zynq_nand_smc_base->cfr);
+       writel(ZYNQ_MEMC_CLRCR_INT_CLR1, &smc->reg->cfr);
 
        /* Get the command phase address */
        if (curr_cmd->end_cmd_valid == ZYNQ_NAND_CMD_PHASE)
                end_cmd_valid = 1;
 
-       if (curr_cmd->end_cmd == NAND_CMD_NONE)
+       if (curr_cmd->end_cmd == (u8)NAND_CMD_NONE)
                end_cmd = 0x0;
        else
                end_cmd = curr_cmd->end_cmd;
@@ -918,7 +936,7 @@ static void zynq_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
  */
 static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 {
-       struct nand_chip *chip = mtd->priv;
+       struct nand_chip *chip = mtd_to_nand(mtd);
 
        /* Make sure that buf is 32 bit aligned */
        if (((unsigned long)buf & 0x3) != 0) {
@@ -966,7 +984,7 @@ static void zynq_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
  */
 static void zynq_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
 {
-       struct nand_chip *chip = mtd->priv;
+       struct nand_chip *chip = mtd_to_nand(mtd);
        const u32 *nand = chip->IO_ADDR_W;
 
        /* Make sure that buf is 32 bit aligned */
@@ -1016,13 +1034,15 @@ static void zynq_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
  */
 static int zynq_nand_device_ready(struct mtd_info *mtd)
 {
+       struct nand_chip *nand_chip = mtd_to_nand(mtd);
+       struct nand_drv *smc = nand_get_controller_data(nand_chip);
        u32 csr_val;
 
-       csr_val = readl(&zynq_nand_smc_base->csr);
+       csr_val = readl(&smc->reg->csr);
        /* Check the raw_int_status1 bit */
        if (csr_val & ZYNQ_MEMC_SR_RAW_INT_ST1) {
                /* Clear the interrupt condition */
-               writel(ZYNQ_MEMC_SR_INT_ST1, &zynq_nand_smc_base->cfr);
+               writel(ZYNQ_MEMC_SR_INT_ST1, &smc->reg->cfr);
                return 1;
        }
 
@@ -1046,30 +1066,43 @@ static int zynq_nand_check_is_16bit_bw_flash(void)
        return is_16bit_bw;
 }
 
-static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
+static int zynq_nand_probe(struct udevice *dev)
 {
-       struct zynq_nand_info *xnand;
+       struct zynq_nand_info *zynq = dev_get_priv(dev);
+       struct nand_chip *nand_chip = &zynq->nand_chip;
+       struct nand_drv *smc = &zynq->nand_ctrl;
+       struct nand_config *xnand = &smc->config;
        struct mtd_info *mtd;
+       struct resource res;
+       ofnode of_nand;
        unsigned long ecc_page_size;
        u8 maf_id, dev_id, i;
        u8 get_feature[4];
        u8 set_feature[4] = {ONDIE_ECC_FEATURE_ENABLE, 0x00, 0x00, 0x00};
        unsigned long ecc_cfg;
        int ondie_ecc_enabled = 0;
-       int err = -1;
        int is_16bit_bw;
 
-       xnand = calloc(1, sizeof(struct zynq_nand_info));
-       if (!xnand) {
-               printf("%s: failed to allocate\n", __func__);
-               goto fail;
+       smc->reg = (struct zynq_nand_smc_regs *)dev_read_addr(dev);
+       of_nand = dev_read_subnode(dev, "flash@e1000000");
+       if (!ofnode_valid(of_nand)) {
+               printf("Failed to find nand node in dt\n");
+               return -ENODEV;
        }
 
-       xnand->nand_base = (void __iomem *)ZYNQ_NAND_BASEADDR;
-       mtd = nand_to_mtd(nand_chip);
+       if (!ofnode_is_available(of_nand)) {
+               debug("Nand node in dt disabled\n");
+               return dm_scan_fdt_dev(dev);
+       }
 
-       nand_chip->priv = xnand;
-       mtd->priv = nand_chip;
+       if (ofnode_read_resource(of_nand, 0, &res)) {
+               printf("Failed to get nand resource\n");
+               return -ENODEV;
+       }
+
+       xnand->nand_base = (void __iomem *)res.start;
+       mtd = nand_to_mtd(nand_chip);
+       nand_set_controller_data(nand_chip, &zynq->nand_ctrl);
 
        /* Set address of NAND IO lines */
        nand_chip->IO_ADDR_R = xnand->nand_base;
@@ -1091,7 +1124,7 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
        if (is_16bit_bw == NAND_BW_UNKNOWN) {
                printf("%s: Unable detect NAND based on MIO settings\n",
                       __func__);
-               goto fail;
+               return -EINVAL;
        }
 
        if (is_16bit_bw == NAND_BW_16BIT)
@@ -1100,15 +1133,15 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
        nand_chip->bbt_options = NAND_BBT_USE_FLASH;
 
        /* Initialize the NAND flash interface on NAND controller */
-       if (zynq_nand_init_nand_flash(nand_chip->options) < 0) {
+       if (zynq_nand_init_nand_flash(mtd, nand_chip->options) < 0) {
                printf("%s: nand flash init failed\n", __func__);
-               goto fail;
+               return -EINVAL;
        }
 
        /* first scan to find the device and get the page size */
        if (nand_scan_ident(mtd, 1, NULL)) {
                printf("%s: nand_scan_ident failed\n", __func__);
-               goto fail;
+               return -EINVAL;
        }
        /* Send the command for reading device ID */
        nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
@@ -1148,9 +1181,9 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
 
        if (ondie_ecc_enabled) {
                /* Bypass the controller ECC block */
-               ecc_cfg = readl(&zynq_nand_smc_base->emcr);
+               ecc_cfg = readl(&smc->reg->emcr);
                ecc_cfg &= ~ZYNQ_MEMC_NAND_ECC_MODE_MASK;
-               writel(ecc_cfg, &zynq_nand_smc_base->emcr);
+               writel(ecc_cfg, &smc->reg->emcr);
 
                /* The software ECC routines won't work
                 * with the SMC controller
@@ -1198,19 +1231,19 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
                        ecc_page_size = 0x1;
                        /* Set the ECC memory config register */
                        writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
-                              &zynq_nand_smc_base->emcr);
+                              &smc->reg->emcr);
                        break;
                case 1024:
                        ecc_page_size = 0x2;
                        /* Set the ECC memory config register */
                        writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
-                              &zynq_nand_smc_base->emcr);
+                              &smc->reg->emcr);
                        break;
                case 2048:
                        ecc_page_size = 0x3;
                        /* Set the ECC memory config register */
                        writel((ZYNQ_NAND_ECC_CONFIG | ecc_page_size),
-                              &zynq_nand_smc_base->emcr);
+                              &smc->reg->emcr);
                        break;
                default:
                        nand_chip->ecc.mode = NAND_ECC_SOFT;
@@ -1233,22 +1266,34 @@ static int zynq_nand_init(struct nand_chip *nand_chip, int devnum)
        /* Second phase scan */
        if (nand_scan_tail(mtd)) {
                printf("%s: nand_scan_tail failed\n", __func__);
-               goto fail;
+               return -EINVAL;
        }
-       if (nand_register(devnum, mtd))
-               goto fail;
+       if (nand_register(0, mtd))
+               return -EINVAL;
+
        return 0;
-fail:
-       free(xnand);
-       return err;
 }
 
-static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
+static const struct udevice_id zynq_nand_dt_ids[] = {
+       {.compatible = "arm,pl353-smc-r2p1",},
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(zynq_nand) = {
+       .name = "zynq-nand",
+       .id = UCLASS_MTD,
+       .of_match = zynq_nand_dt_ids,
+       .probe = zynq_nand_probe,
+       .priv_auto_alloc_size = sizeof(struct zynq_nand_info),
+};
 
 void board_nand_init(void)
 {
-       struct nand_chip *nand = &nand_chip[0];
+       struct udevice *dev;
+       int ret;
 
-       if (zynq_nand_init(nand, 0))
-               puts("ZYNQ NAND init failed\n");
+       ret = uclass_get_device_by_driver(UCLASS_MTD,
+                                         DM_GET_DRIVER(zynq_nand), &dev);
+       if (ret && ret != -ENODEV)
+               pr_err("Failed to initialize %s. (error %d)\n", dev->name, ret);
 }