108d8c621SMiquel Raynal // SPDX-License-Identifier: GPL-2.0
208d8c621SMiquel Raynal /*
308d8c621SMiquel Raynal * ARM PL35X NAND flash controller driver
408d8c621SMiquel Raynal *
508d8c621SMiquel Raynal * Copyright (C) 2017 Xilinx, Inc
608d8c621SMiquel Raynal * Author:
708d8c621SMiquel Raynal * Miquel Raynal <miquel.raynal@bootlin.com>
808d8c621SMiquel Raynal * Original work (rewritten):
908d8c621SMiquel Raynal * Punnaiah Choudary Kalluri <punnaia@xilinx.com>
1008d8c621SMiquel Raynal * Naga Sureshkumar Relli <nagasure@xilinx.com>
1108d8c621SMiquel Raynal */
1208d8c621SMiquel Raynal
1308d8c621SMiquel Raynal #include <linux/amba/bus.h>
1408d8c621SMiquel Raynal #include <linux/err.h>
1508d8c621SMiquel Raynal #include <linux/delay.h>
1608d8c621SMiquel Raynal #include <linux/interrupt.h>
1708d8c621SMiquel Raynal #include <linux/io.h>
1808d8c621SMiquel Raynal #include <linux/ioport.h>
1908d8c621SMiquel Raynal #include <linux/iopoll.h>
2008d8c621SMiquel Raynal #include <linux/irq.h>
2108d8c621SMiquel Raynal #include <linux/module.h>
2208d8c621SMiquel Raynal #include <linux/moduleparam.h>
2308d8c621SMiquel Raynal #include <linux/mtd/mtd.h>
2408d8c621SMiquel Raynal #include <linux/mtd/rawnand.h>
2508d8c621SMiquel Raynal #include <linux/mtd/partitions.h>
26c2fc6b69SRob Herring #include <linux/of.h>
2708d8c621SMiquel Raynal #include <linux/platform_device.h>
2808d8c621SMiquel Raynal #include <linux/slab.h>
2908d8c621SMiquel Raynal #include <linux/clk.h>
3008d8c621SMiquel Raynal
3108d8c621SMiquel Raynal #define PL35X_NANDC_DRIVER_NAME "pl35x-nand-controller"
3208d8c621SMiquel Raynal
3308d8c621SMiquel Raynal /* SMC controller status register (RO) */
3408d8c621SMiquel Raynal #define PL35X_SMC_MEMC_STATUS 0x0
3508d8c621SMiquel Raynal #define PL35X_SMC_MEMC_STATUS_RAW_INT_STATUS1 BIT(6)
3608d8c621SMiquel Raynal /* SMC clear config register (WO) */
3708d8c621SMiquel Raynal #define PL35X_SMC_MEMC_CFG_CLR 0xC
3808d8c621SMiquel Raynal #define PL35X_SMC_MEMC_CFG_CLR_INT_DIS_1 BIT(1)
3908d8c621SMiquel Raynal #define PL35X_SMC_MEMC_CFG_CLR_INT_CLR_1 BIT(4)
4008d8c621SMiquel Raynal #define PL35X_SMC_MEMC_CFG_CLR_ECC_INT_DIS_1 BIT(6)
4108d8c621SMiquel Raynal /* SMC direct command register (WO) */
4208d8c621SMiquel Raynal #define PL35X_SMC_DIRECT_CMD 0x10
4308d8c621SMiquel Raynal #define PL35X_SMC_DIRECT_CMD_NAND_CS (0x4 << 23)
4408d8c621SMiquel Raynal #define PL35X_SMC_DIRECT_CMD_UPD_REGS (0x2 << 21)
4508d8c621SMiquel Raynal /* SMC set cycles register (WO) */
4608d8c621SMiquel Raynal #define PL35X_SMC_CYCLES 0x14
4708d8c621SMiquel Raynal #define PL35X_SMC_NAND_TRC_CYCLES(x) ((x) << 0)
4808d8c621SMiquel Raynal #define PL35X_SMC_NAND_TWC_CYCLES(x) ((x) << 4)
4908d8c621SMiquel Raynal #define PL35X_SMC_NAND_TREA_CYCLES(x) ((x) << 8)
5008d8c621SMiquel Raynal #define PL35X_SMC_NAND_TWP_CYCLES(x) ((x) << 11)
5108d8c621SMiquel Raynal #define PL35X_SMC_NAND_TCLR_CYCLES(x) ((x) << 14)
5208d8c621SMiquel Raynal #define PL35X_SMC_NAND_TAR_CYCLES(x) ((x) << 17)
5308d8c621SMiquel Raynal #define PL35X_SMC_NAND_TRR_CYCLES(x) ((x) << 20)
5408d8c621SMiquel Raynal /* SMC set opmode register (WO) */
5508d8c621SMiquel Raynal #define PL35X_SMC_OPMODE 0x18
5608d8c621SMiquel Raynal #define PL35X_SMC_OPMODE_BW_8 0
5708d8c621SMiquel Raynal #define PL35X_SMC_OPMODE_BW_16 1
5808d8c621SMiquel Raynal /* SMC ECC status register (RO) */
5908d8c621SMiquel Raynal #define PL35X_SMC_ECC_STATUS 0x400
6008d8c621SMiquel Raynal #define PL35X_SMC_ECC_STATUS_ECC_BUSY BIT(6)
6108d8c621SMiquel Raynal /* SMC ECC configuration register */
6208d8c621SMiquel Raynal #define PL35X_SMC_ECC_CFG 0x404
6308d8c621SMiquel Raynal #define PL35X_SMC_ECC_CFG_MODE_MASK 0xC
6408d8c621SMiquel Raynal #define PL35X_SMC_ECC_CFG_MODE_BYPASS 0
6508d8c621SMiquel Raynal #define PL35X_SMC_ECC_CFG_MODE_APB BIT(2)
6608d8c621SMiquel Raynal #define PL35X_SMC_ECC_CFG_MODE_MEM BIT(3)
6708d8c621SMiquel Raynal #define PL35X_SMC_ECC_CFG_PGSIZE_MASK 0x3
6808d8c621SMiquel Raynal /* SMC ECC command 1 register */
6908d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD1 0x408
7008d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD1_WRITE(x) ((x) << 0)
7108d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD1_READ(x) ((x) << 8)
7208d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD1_READ_END(x) ((x) << 16)
7308d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD1_READ_END_VALID(x) ((x) << 24)
7408d8c621SMiquel Raynal /* SMC ECC command 2 register */
7508d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD2 0x40C
7608d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD2_WRITE_COL_CHG(x) ((x) << 0)
7708d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD2_READ_COL_CHG(x) ((x) << 8)
7808d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD2_READ_COL_CHG_END(x) ((x) << 16)
7908d8c621SMiquel Raynal #define PL35X_SMC_ECC_CMD2_READ_COL_CHG_END_VALID(x) ((x) << 24)
8008d8c621SMiquel Raynal /* SMC ECC value registers (RO) */
8108d8c621SMiquel Raynal #define PL35X_SMC_ECC_VALUE(x) (0x418 + (4 * (x)))
8208d8c621SMiquel Raynal #define PL35X_SMC_ECC_VALUE_IS_CORRECTABLE(x) ((x) & BIT(27))
8308d8c621SMiquel Raynal #define PL35X_SMC_ECC_VALUE_HAS_FAILED(x) ((x) & BIT(28))
8408d8c621SMiquel Raynal #define PL35X_SMC_ECC_VALUE_IS_VALID(x) ((x) & BIT(30))
8508d8c621SMiquel Raynal
8608d8c621SMiquel Raynal /* NAND AXI interface */
8708d8c621SMiquel Raynal #define PL35X_SMC_CMD_PHASE 0
8808d8c621SMiquel Raynal #define PL35X_SMC_CMD_PHASE_CMD0(x) ((x) << 3)
8908d8c621SMiquel Raynal #define PL35X_SMC_CMD_PHASE_CMD1(x) ((x) << 11)
9008d8c621SMiquel Raynal #define PL35X_SMC_CMD_PHASE_CMD1_VALID BIT(20)
9108d8c621SMiquel Raynal #define PL35X_SMC_CMD_PHASE_ADDR(pos, x) ((x) << (8 * (pos)))
9208d8c621SMiquel Raynal #define PL35X_SMC_CMD_PHASE_NADDRS(x) ((x) << 21)
9308d8c621SMiquel Raynal #define PL35X_SMC_DATA_PHASE BIT(19)
9408d8c621SMiquel Raynal #define PL35X_SMC_DATA_PHASE_ECC_LAST BIT(10)
9508d8c621SMiquel Raynal #define PL35X_SMC_DATA_PHASE_CLEAR_CS BIT(21)
9608d8c621SMiquel Raynal
9708d8c621SMiquel Raynal #define PL35X_NAND_MAX_CS 1
9808d8c621SMiquel Raynal #define PL35X_NAND_LAST_XFER_SZ 4
9908d8c621SMiquel Raynal #define TO_CYCLES(ps, period_ns) (DIV_ROUND_UP((ps) / 1000, period_ns))
10008d8c621SMiquel Raynal
10108d8c621SMiquel Raynal #define PL35X_NAND_ECC_BITS_MASK 0xFFF
10208d8c621SMiquel Raynal #define PL35X_NAND_ECC_BYTE_OFF_MASK 0x1FF
10308d8c621SMiquel Raynal #define PL35X_NAND_ECC_BIT_OFF_MASK 0x7
10408d8c621SMiquel Raynal
10508d8c621SMiquel Raynal struct pl35x_nand_timings {
10608d8c621SMiquel Raynal unsigned int t_rc:4;
10708d8c621SMiquel Raynal unsigned int t_wc:4;
10808d8c621SMiquel Raynal unsigned int t_rea:3;
10908d8c621SMiquel Raynal unsigned int t_wp:3;
11008d8c621SMiquel Raynal unsigned int t_clr:3;
11108d8c621SMiquel Raynal unsigned int t_ar:3;
11208d8c621SMiquel Raynal unsigned int t_rr:4;
11308d8c621SMiquel Raynal unsigned int rsvd:8;
11408d8c621SMiquel Raynal };
11508d8c621SMiquel Raynal
11608d8c621SMiquel Raynal struct pl35x_nand {
11708d8c621SMiquel Raynal struct list_head node;
11808d8c621SMiquel Raynal struct nand_chip chip;
11908d8c621SMiquel Raynal unsigned int cs;
12008d8c621SMiquel Raynal unsigned int addr_cycles;
12108d8c621SMiquel Raynal u32 ecc_cfg;
12208d8c621SMiquel Raynal u32 timings;
12308d8c621SMiquel Raynal };
12408d8c621SMiquel Raynal
12508d8c621SMiquel Raynal /**
12608d8c621SMiquel Raynal * struct pl35x_nandc - NAND flash controller driver structure
12708d8c621SMiquel Raynal * @dev: Kernel device
12808d8c621SMiquel Raynal * @conf_regs: SMC configuration registers for command phase
12908d8c621SMiquel Raynal * @io_regs: NAND data registers for data phase
13008d8c621SMiquel Raynal * @controller: Core NAND controller structure
13108d8c621SMiquel Raynal * @chip: NAND chip information structure
13208d8c621SMiquel Raynal * @selected_chip: NAND chip currently selected by the controller
13308d8c621SMiquel Raynal * @assigned_cs: List of assigned CS
13408d8c621SMiquel Raynal * @ecc_buf: Temporary buffer to extract ECC bytes
13508d8c621SMiquel Raynal */
13608d8c621SMiquel Raynal struct pl35x_nandc {
13708d8c621SMiquel Raynal struct device *dev;
13808d8c621SMiquel Raynal void __iomem *conf_regs;
13908d8c621SMiquel Raynal void __iomem *io_regs;
14008d8c621SMiquel Raynal struct nand_controller controller;
14108d8c621SMiquel Raynal struct list_head chips;
14208d8c621SMiquel Raynal struct nand_chip *selected_chip;
14308d8c621SMiquel Raynal unsigned long assigned_cs;
14408d8c621SMiquel Raynal u8 *ecc_buf;
14508d8c621SMiquel Raynal };
14608d8c621SMiquel Raynal
to_pl35x_nandc(struct nand_controller * ctrl)14708d8c621SMiquel Raynal static inline struct pl35x_nandc *to_pl35x_nandc(struct nand_controller *ctrl)
14808d8c621SMiquel Raynal {
14908d8c621SMiquel Raynal return container_of(ctrl, struct pl35x_nandc, controller);
15008d8c621SMiquel Raynal }
15108d8c621SMiquel Raynal
to_pl35x_nand(struct nand_chip * chip)15208d8c621SMiquel Raynal static inline struct pl35x_nand *to_pl35x_nand(struct nand_chip *chip)
15308d8c621SMiquel Raynal {
15408d8c621SMiquel Raynal return container_of(chip, struct pl35x_nand, chip);
15508d8c621SMiquel Raynal }
15608d8c621SMiquel Raynal
pl35x_ecc_ooblayout16_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)15708d8c621SMiquel Raynal static int pl35x_ecc_ooblayout16_ecc(struct mtd_info *mtd, int section,
15808d8c621SMiquel Raynal struct mtd_oob_region *oobregion)
15908d8c621SMiquel Raynal {
16008d8c621SMiquel Raynal struct nand_chip *chip = mtd_to_nand(mtd);
16108d8c621SMiquel Raynal
16208d8c621SMiquel Raynal if (section >= chip->ecc.steps)
16308d8c621SMiquel Raynal return -ERANGE;
16408d8c621SMiquel Raynal
16508d8c621SMiquel Raynal oobregion->offset = (section * chip->ecc.bytes);
16608d8c621SMiquel Raynal oobregion->length = chip->ecc.bytes;
16708d8c621SMiquel Raynal
16808d8c621SMiquel Raynal return 0;
16908d8c621SMiquel Raynal }
17008d8c621SMiquel Raynal
pl35x_ecc_ooblayout16_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)17108d8c621SMiquel Raynal static int pl35x_ecc_ooblayout16_free(struct mtd_info *mtd, int section,
17208d8c621SMiquel Raynal struct mtd_oob_region *oobregion)
17308d8c621SMiquel Raynal {
17408d8c621SMiquel Raynal struct nand_chip *chip = mtd_to_nand(mtd);
17508d8c621SMiquel Raynal
17608d8c621SMiquel Raynal if (section >= chip->ecc.steps)
17708d8c621SMiquel Raynal return -ERANGE;
17808d8c621SMiquel Raynal
17908d8c621SMiquel Raynal oobregion->offset = (section * chip->ecc.bytes) + 8;
18008d8c621SMiquel Raynal oobregion->length = 8;
18108d8c621SMiquel Raynal
18208d8c621SMiquel Raynal return 0;
18308d8c621SMiquel Raynal }
18408d8c621SMiquel Raynal
18508d8c621SMiquel Raynal static const struct mtd_ooblayout_ops pl35x_ecc_ooblayout16_ops = {
18608d8c621SMiquel Raynal .ecc = pl35x_ecc_ooblayout16_ecc,
18708d8c621SMiquel Raynal .free = pl35x_ecc_ooblayout16_free,
18808d8c621SMiquel Raynal };
18908d8c621SMiquel Raynal
19008d8c621SMiquel Raynal /* Generic flash bbt decriptors */
19108d8c621SMiquel Raynal static u8 bbt_pattern[] = { 'B', 'b', 't', '0' };
19208d8c621SMiquel Raynal static u8 mirror_pattern[] = { '1', 't', 'b', 'B' };
19308d8c621SMiquel Raynal
19408d8c621SMiquel Raynal static struct nand_bbt_descr bbt_main_descr = {
19508d8c621SMiquel Raynal .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
19608d8c621SMiquel Raynal | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
19708d8c621SMiquel Raynal .offs = 4,
19808d8c621SMiquel Raynal .len = 4,
19908d8c621SMiquel Raynal .veroffs = 20,
20008d8c621SMiquel Raynal .maxblocks = 4,
20108d8c621SMiquel Raynal .pattern = bbt_pattern
20208d8c621SMiquel Raynal };
20308d8c621SMiquel Raynal
20408d8c621SMiquel Raynal static struct nand_bbt_descr bbt_mirror_descr = {
20508d8c621SMiquel Raynal .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
20608d8c621SMiquel Raynal | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
20708d8c621SMiquel Raynal .offs = 4,
20808d8c621SMiquel Raynal .len = 4,
20908d8c621SMiquel Raynal .veroffs = 20,
21008d8c621SMiquel Raynal .maxblocks = 4,
21108d8c621SMiquel Raynal .pattern = mirror_pattern
21208d8c621SMiquel Raynal };
21308d8c621SMiquel Raynal
pl35x_smc_update_regs(struct pl35x_nandc * nfc)21408d8c621SMiquel Raynal static void pl35x_smc_update_regs(struct pl35x_nandc *nfc)
21508d8c621SMiquel Raynal {
21608d8c621SMiquel Raynal writel(PL35X_SMC_DIRECT_CMD_NAND_CS |
21708d8c621SMiquel Raynal PL35X_SMC_DIRECT_CMD_UPD_REGS,
21808d8c621SMiquel Raynal nfc->conf_regs + PL35X_SMC_DIRECT_CMD);
21908d8c621SMiquel Raynal }
22008d8c621SMiquel Raynal
pl35x_smc_set_buswidth(struct pl35x_nandc * nfc,unsigned int bw)22108d8c621SMiquel Raynal static int pl35x_smc_set_buswidth(struct pl35x_nandc *nfc, unsigned int bw)
22208d8c621SMiquel Raynal {
22308d8c621SMiquel Raynal if (bw != PL35X_SMC_OPMODE_BW_8 && bw != PL35X_SMC_OPMODE_BW_16)
22408d8c621SMiquel Raynal return -EINVAL;
22508d8c621SMiquel Raynal
22608d8c621SMiquel Raynal writel(bw, nfc->conf_regs + PL35X_SMC_OPMODE);
22708d8c621SMiquel Raynal pl35x_smc_update_regs(nfc);
22808d8c621SMiquel Raynal
22908d8c621SMiquel Raynal return 0;
23008d8c621SMiquel Raynal }
23108d8c621SMiquel Raynal
pl35x_smc_clear_irq(struct pl35x_nandc * nfc)23208d8c621SMiquel Raynal static void pl35x_smc_clear_irq(struct pl35x_nandc *nfc)
23308d8c621SMiquel Raynal {
23408d8c621SMiquel Raynal writel(PL35X_SMC_MEMC_CFG_CLR_INT_CLR_1,
23508d8c621SMiquel Raynal nfc->conf_regs + PL35X_SMC_MEMC_CFG_CLR);
23608d8c621SMiquel Raynal }
23708d8c621SMiquel Raynal
pl35x_smc_wait_for_irq(struct pl35x_nandc * nfc)23808d8c621SMiquel Raynal static int pl35x_smc_wait_for_irq(struct pl35x_nandc *nfc)
23908d8c621SMiquel Raynal {
24008d8c621SMiquel Raynal u32 reg;
24108d8c621SMiquel Raynal int ret;
24208d8c621SMiquel Raynal
24308d8c621SMiquel Raynal ret = readl_poll_timeout(nfc->conf_regs + PL35X_SMC_MEMC_STATUS, reg,
24408d8c621SMiquel Raynal reg & PL35X_SMC_MEMC_STATUS_RAW_INT_STATUS1,
24508d8c621SMiquel Raynal 10, 1000000);
24608d8c621SMiquel Raynal if (ret)
24708d8c621SMiquel Raynal dev_err(nfc->dev,
24808d8c621SMiquel Raynal "Timeout polling on NAND controller interrupt (0x%x)\n",
24908d8c621SMiquel Raynal reg);
25008d8c621SMiquel Raynal
25108d8c621SMiquel Raynal pl35x_smc_clear_irq(nfc);
25208d8c621SMiquel Raynal
25308d8c621SMiquel Raynal return ret;
25408d8c621SMiquel Raynal }
25508d8c621SMiquel Raynal
pl35x_smc_wait_for_ecc_done(struct pl35x_nandc * nfc)25608d8c621SMiquel Raynal static int pl35x_smc_wait_for_ecc_done(struct pl35x_nandc *nfc)
25708d8c621SMiquel Raynal {
25808d8c621SMiquel Raynal u32 reg;
25908d8c621SMiquel Raynal int ret;
26008d8c621SMiquel Raynal
26108d8c621SMiquel Raynal ret = readl_poll_timeout(nfc->conf_regs + PL35X_SMC_ECC_STATUS, reg,
26208d8c621SMiquel Raynal !(reg & PL35X_SMC_ECC_STATUS_ECC_BUSY),
26308d8c621SMiquel Raynal 10, 1000000);
26408d8c621SMiquel Raynal if (ret)
26508d8c621SMiquel Raynal dev_err(nfc->dev,
26608d8c621SMiquel Raynal "Timeout polling on ECC controller interrupt\n");
26708d8c621SMiquel Raynal
26808d8c621SMiquel Raynal return ret;
26908d8c621SMiquel Raynal }
27008d8c621SMiquel Raynal
pl35x_smc_set_ecc_mode(struct pl35x_nandc * nfc,struct nand_chip * chip,unsigned int mode)27108d8c621SMiquel Raynal static int pl35x_smc_set_ecc_mode(struct pl35x_nandc *nfc,
27208d8c621SMiquel Raynal struct nand_chip *chip,
27308d8c621SMiquel Raynal unsigned int mode)
27408d8c621SMiquel Raynal {
27508d8c621SMiquel Raynal struct pl35x_nand *plnand;
27608d8c621SMiquel Raynal u32 ecc_cfg;
27708d8c621SMiquel Raynal
27808d8c621SMiquel Raynal ecc_cfg = readl(nfc->conf_regs + PL35X_SMC_ECC_CFG);
27908d8c621SMiquel Raynal ecc_cfg &= ~PL35X_SMC_ECC_CFG_MODE_MASK;
28008d8c621SMiquel Raynal ecc_cfg |= mode;
28108d8c621SMiquel Raynal writel(ecc_cfg, nfc->conf_regs + PL35X_SMC_ECC_CFG);
28208d8c621SMiquel Raynal
28308d8c621SMiquel Raynal if (chip) {
28408d8c621SMiquel Raynal plnand = to_pl35x_nand(chip);
28508d8c621SMiquel Raynal plnand->ecc_cfg = ecc_cfg;
28608d8c621SMiquel Raynal }
28708d8c621SMiquel Raynal
28808d8c621SMiquel Raynal if (mode != PL35X_SMC_ECC_CFG_MODE_BYPASS)
28908d8c621SMiquel Raynal return pl35x_smc_wait_for_ecc_done(nfc);
29008d8c621SMiquel Raynal
29108d8c621SMiquel Raynal return 0;
29208d8c621SMiquel Raynal }
29308d8c621SMiquel Raynal
pl35x_smc_force_byte_access(struct nand_chip * chip,bool force_8bit)29408d8c621SMiquel Raynal static void pl35x_smc_force_byte_access(struct nand_chip *chip,
29508d8c621SMiquel Raynal bool force_8bit)
29608d8c621SMiquel Raynal {
29708d8c621SMiquel Raynal struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
29808d8c621SMiquel Raynal int ret;
29908d8c621SMiquel Raynal
30008d8c621SMiquel Raynal if (!(chip->options & NAND_BUSWIDTH_16))
30108d8c621SMiquel Raynal return;
30208d8c621SMiquel Raynal
30308d8c621SMiquel Raynal if (force_8bit)
30408d8c621SMiquel Raynal ret = pl35x_smc_set_buswidth(nfc, PL35X_SMC_OPMODE_BW_8);
30508d8c621SMiquel Raynal else
30608d8c621SMiquel Raynal ret = pl35x_smc_set_buswidth(nfc, PL35X_SMC_OPMODE_BW_16);
30708d8c621SMiquel Raynal
30808d8c621SMiquel Raynal if (ret)
30908d8c621SMiquel Raynal dev_err(nfc->dev, "Error in Buswidth\n");
31008d8c621SMiquel Raynal }
31108d8c621SMiquel Raynal
pl35x_nand_select_target(struct nand_chip * chip,unsigned int die_nr)31208d8c621SMiquel Raynal static void pl35x_nand_select_target(struct nand_chip *chip,
31308d8c621SMiquel Raynal unsigned int die_nr)
31408d8c621SMiquel Raynal {
31508d8c621SMiquel Raynal struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
31608d8c621SMiquel Raynal struct pl35x_nand *plnand = to_pl35x_nand(chip);
31708d8c621SMiquel Raynal
31808d8c621SMiquel Raynal if (chip == nfc->selected_chip)
31908d8c621SMiquel Raynal return;
32008d8c621SMiquel Raynal
32108d8c621SMiquel Raynal /* Setup the timings */
32208d8c621SMiquel Raynal writel(plnand->timings, nfc->conf_regs + PL35X_SMC_CYCLES);
32308d8c621SMiquel Raynal pl35x_smc_update_regs(nfc);
32408d8c621SMiquel Raynal
32508d8c621SMiquel Raynal /* Configure the ECC engine */
32608d8c621SMiquel Raynal writel(plnand->ecc_cfg, nfc->conf_regs + PL35X_SMC_ECC_CFG);
32708d8c621SMiquel Raynal
32808d8c621SMiquel Raynal nfc->selected_chip = chip;
32908d8c621SMiquel Raynal }
33008d8c621SMiquel Raynal
pl35x_nand_read_data_op(struct nand_chip * chip,u8 * in,unsigned int len,bool force_8bit,unsigned int flags,unsigned int last_flags)33108d8c621SMiquel Raynal static void pl35x_nand_read_data_op(struct nand_chip *chip, u8 *in,
33208d8c621SMiquel Raynal unsigned int len, bool force_8bit,
33308d8c621SMiquel Raynal unsigned int flags, unsigned int last_flags)
33408d8c621SMiquel Raynal {
33508d8c621SMiquel Raynal struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
33608d8c621SMiquel Raynal unsigned int buf_end = len / 4;
33708d8c621SMiquel Raynal unsigned int in_start = round_down(len, 4);
33808d8c621SMiquel Raynal unsigned int data_phase_addr;
33908d8c621SMiquel Raynal u32 *buf32 = (u32 *)in;
34008d8c621SMiquel Raynal u8 *buf8 = (u8 *)in;
34108d8c621SMiquel Raynal int i;
34208d8c621SMiquel Raynal
34308d8c621SMiquel Raynal if (force_8bit)
34408d8c621SMiquel Raynal pl35x_smc_force_byte_access(chip, true);
34508d8c621SMiquel Raynal
34608d8c621SMiquel Raynal for (i = 0; i < buf_end; i++) {
34708d8c621SMiquel Raynal data_phase_addr = PL35X_SMC_DATA_PHASE + flags;
34808d8c621SMiquel Raynal if (i + 1 == buf_end)
34908d8c621SMiquel Raynal data_phase_addr = PL35X_SMC_DATA_PHASE + last_flags;
35008d8c621SMiquel Raynal
35108d8c621SMiquel Raynal buf32[i] = readl(nfc->io_regs + data_phase_addr);
35208d8c621SMiquel Raynal }
35308d8c621SMiquel Raynal
35408d8c621SMiquel Raynal /* No working extra flags on unaligned data accesses */
35508d8c621SMiquel Raynal for (i = in_start; i < len; i++)
35608d8c621SMiquel Raynal buf8[i] = readb(nfc->io_regs + PL35X_SMC_DATA_PHASE);
35708d8c621SMiquel Raynal
35808d8c621SMiquel Raynal if (force_8bit)
35908d8c621SMiquel Raynal pl35x_smc_force_byte_access(chip, false);
36008d8c621SMiquel Raynal }
36108d8c621SMiquel Raynal
pl35x_nand_write_data_op(struct nand_chip * chip,const u8 * out,int len,bool force_8bit,unsigned int flags,unsigned int last_flags)36208d8c621SMiquel Raynal static void pl35x_nand_write_data_op(struct nand_chip *chip, const u8 *out,
36308d8c621SMiquel Raynal int len, bool force_8bit,
36408d8c621SMiquel Raynal unsigned int flags,
36508d8c621SMiquel Raynal unsigned int last_flags)
36608d8c621SMiquel Raynal {
36708d8c621SMiquel Raynal struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
36808d8c621SMiquel Raynal unsigned int buf_end = len / 4;
36908d8c621SMiquel Raynal unsigned int in_start = round_down(len, 4);
37008d8c621SMiquel Raynal const u32 *buf32 = (const u32 *)out;
37108d8c621SMiquel Raynal const u8 *buf8 = (const u8 *)out;
37208d8c621SMiquel Raynal unsigned int data_phase_addr;
37308d8c621SMiquel Raynal int i;
37408d8c621SMiquel Raynal
37508d8c621SMiquel Raynal if (force_8bit)
37608d8c621SMiquel Raynal pl35x_smc_force_byte_access(chip, true);
37708d8c621SMiquel Raynal
37808d8c621SMiquel Raynal for (i = 0; i < buf_end; i++) {
37908d8c621SMiquel Raynal data_phase_addr = PL35X_SMC_DATA_PHASE + flags;
38008d8c621SMiquel Raynal if (i + 1 == buf_end)
38108d8c621SMiquel Raynal data_phase_addr = PL35X_SMC_DATA_PHASE + last_flags;
38208d8c621SMiquel Raynal
38308d8c621SMiquel Raynal writel(buf32[i], nfc->io_regs + data_phase_addr);
38408d8c621SMiquel Raynal }
38508d8c621SMiquel Raynal
38608d8c621SMiquel Raynal /* No working extra flags on unaligned data accesses */
38708d8c621SMiquel Raynal for (i = in_start; i < len; i++)
38808d8c621SMiquel Raynal writeb(buf8[i], nfc->io_regs + PL35X_SMC_DATA_PHASE);
38908d8c621SMiquel Raynal
39008d8c621SMiquel Raynal if (force_8bit)
39108d8c621SMiquel Raynal pl35x_smc_force_byte_access(chip, false);
39208d8c621SMiquel Raynal }
39308d8c621SMiquel Raynal
pl35x_nand_correct_data(struct pl35x_nandc * nfc,unsigned char * buf,unsigned char * read_ecc,unsigned char * calc_ecc)39408d8c621SMiquel Raynal static int pl35x_nand_correct_data(struct pl35x_nandc *nfc, unsigned char *buf,
39508d8c621SMiquel Raynal unsigned char *read_ecc,
39608d8c621SMiquel Raynal unsigned char *calc_ecc)
39708d8c621SMiquel Raynal {
39808d8c621SMiquel Raynal unsigned short ecc_odd, ecc_even, read_ecc_lower, read_ecc_upper;
39908d8c621SMiquel Raynal unsigned short calc_ecc_lower, calc_ecc_upper;
40008d8c621SMiquel Raynal unsigned short byte_addr, bit_addr;
40108d8c621SMiquel Raynal
40208d8c621SMiquel Raynal read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) &
40308d8c621SMiquel Raynal PL35X_NAND_ECC_BITS_MASK;
40408d8c621SMiquel Raynal read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) &
40508d8c621SMiquel Raynal PL35X_NAND_ECC_BITS_MASK;
40608d8c621SMiquel Raynal
40708d8c621SMiquel Raynal calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) &
40808d8c621SMiquel Raynal PL35X_NAND_ECC_BITS_MASK;
40908d8c621SMiquel Raynal calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) &
41008d8c621SMiquel Raynal PL35X_NAND_ECC_BITS_MASK;
41108d8c621SMiquel Raynal
41208d8c621SMiquel Raynal ecc_odd = read_ecc_lower ^ calc_ecc_lower;
41308d8c621SMiquel Raynal ecc_even = read_ecc_upper ^ calc_ecc_upper;
41408d8c621SMiquel Raynal
41508d8c621SMiquel Raynal /* No error */
41608d8c621SMiquel Raynal if (likely(!ecc_odd && !ecc_even))
41708d8c621SMiquel Raynal return 0;
41808d8c621SMiquel Raynal
41908d8c621SMiquel Raynal /* One error in the main data; to be corrected */
42008d8c621SMiquel Raynal if (ecc_odd == (~ecc_even & PL35X_NAND_ECC_BITS_MASK)) {
42108d8c621SMiquel Raynal /* Bits [11:3] of error code give the byte offset */
42208d8c621SMiquel Raynal byte_addr = (ecc_odd >> 3) & PL35X_NAND_ECC_BYTE_OFF_MASK;
42308d8c621SMiquel Raynal /* Bits [2:0] of error code give the bit offset */
42408d8c621SMiquel Raynal bit_addr = ecc_odd & PL35X_NAND_ECC_BIT_OFF_MASK;
42508d8c621SMiquel Raynal /* Toggle the faulty bit */
42608d8c621SMiquel Raynal buf[byte_addr] ^= (BIT(bit_addr));
42708d8c621SMiquel Raynal
42808d8c621SMiquel Raynal return 1;
42908d8c621SMiquel Raynal }
43008d8c621SMiquel Raynal
43108d8c621SMiquel Raynal /* One error in the ECC data; no action needed */
43208d8c621SMiquel Raynal if (hweight32(ecc_odd | ecc_even) == 1)
43308d8c621SMiquel Raynal return 1;
43408d8c621SMiquel Raynal
43508d8c621SMiquel Raynal return -EBADMSG;
43608d8c621SMiquel Raynal }
43708d8c621SMiquel Raynal
pl35x_nand_ecc_reg_to_array(struct nand_chip * chip,u32 ecc_reg,u8 * ecc_array)43808d8c621SMiquel Raynal static void pl35x_nand_ecc_reg_to_array(struct nand_chip *chip, u32 ecc_reg,
43908d8c621SMiquel Raynal u8 *ecc_array)
44008d8c621SMiquel Raynal {
44108d8c621SMiquel Raynal u32 ecc_value = ~ecc_reg;
44208d8c621SMiquel Raynal unsigned int ecc_byte;
44308d8c621SMiquel Raynal
44408d8c621SMiquel Raynal for (ecc_byte = 0; ecc_byte < chip->ecc.bytes; ecc_byte++)
44508d8c621SMiquel Raynal ecc_array[ecc_byte] = ecc_value >> (8 * ecc_byte);
44608d8c621SMiquel Raynal }
44708d8c621SMiquel Raynal
pl35x_nand_read_eccbytes(struct pl35x_nandc * nfc,struct nand_chip * chip,u8 * read_ecc)44808d8c621SMiquel Raynal static int pl35x_nand_read_eccbytes(struct pl35x_nandc *nfc,
44908d8c621SMiquel Raynal struct nand_chip *chip, u8 *read_ecc)
45008d8c621SMiquel Raynal {
45108d8c621SMiquel Raynal u32 ecc_value;
45208d8c621SMiquel Raynal int chunk;
45308d8c621SMiquel Raynal
45408d8c621SMiquel Raynal for (chunk = 0; chunk < chip->ecc.steps;
45508d8c621SMiquel Raynal chunk++, read_ecc += chip->ecc.bytes) {
45608d8c621SMiquel Raynal ecc_value = readl(nfc->conf_regs + PL35X_SMC_ECC_VALUE(chunk));
45708d8c621SMiquel Raynal if (!PL35X_SMC_ECC_VALUE_IS_VALID(ecc_value))
45808d8c621SMiquel Raynal return -EINVAL;
45908d8c621SMiquel Raynal
46008d8c621SMiquel Raynal pl35x_nand_ecc_reg_to_array(chip, ecc_value, read_ecc);
46108d8c621SMiquel Raynal }
46208d8c621SMiquel Raynal
46308d8c621SMiquel Raynal return 0;
46408d8c621SMiquel Raynal }
46508d8c621SMiquel Raynal
pl35x_nand_recover_data_hwecc(struct pl35x_nandc * nfc,struct nand_chip * chip,u8 * data,u8 * read_ecc)46608d8c621SMiquel Raynal static int pl35x_nand_recover_data_hwecc(struct pl35x_nandc *nfc,
46708d8c621SMiquel Raynal struct nand_chip *chip, u8 *data,
46808d8c621SMiquel Raynal u8 *read_ecc)
46908d8c621SMiquel Raynal {
47008d8c621SMiquel Raynal struct mtd_info *mtd = nand_to_mtd(chip);
47108d8c621SMiquel Raynal unsigned int max_bitflips = 0, chunk;
47208d8c621SMiquel Raynal u8 calc_ecc[3];
47308d8c621SMiquel Raynal u32 ecc_value;
47408d8c621SMiquel Raynal int stats;
47508d8c621SMiquel Raynal
47608d8c621SMiquel Raynal for (chunk = 0; chunk < chip->ecc.steps;
47708d8c621SMiquel Raynal chunk++, data += chip->ecc.size, read_ecc += chip->ecc.bytes) {
47808d8c621SMiquel Raynal /* Read ECC value for each chunk */
47908d8c621SMiquel Raynal ecc_value = readl(nfc->conf_regs + PL35X_SMC_ECC_VALUE(chunk));
48008d8c621SMiquel Raynal
48108d8c621SMiquel Raynal if (!PL35X_SMC_ECC_VALUE_IS_VALID(ecc_value))
48208d8c621SMiquel Raynal return -EINVAL;
48308d8c621SMiquel Raynal
48408d8c621SMiquel Raynal if (PL35X_SMC_ECC_VALUE_HAS_FAILED(ecc_value)) {
48508d8c621SMiquel Raynal mtd->ecc_stats.failed++;
48608d8c621SMiquel Raynal continue;
48708d8c621SMiquel Raynal }
48808d8c621SMiquel Raynal
48908d8c621SMiquel Raynal pl35x_nand_ecc_reg_to_array(chip, ecc_value, calc_ecc);
49008d8c621SMiquel Raynal stats = pl35x_nand_correct_data(nfc, data, read_ecc, calc_ecc);
49108d8c621SMiquel Raynal if (stats < 0) {
49208d8c621SMiquel Raynal mtd->ecc_stats.failed++;
49308d8c621SMiquel Raynal } else {
49408d8c621SMiquel Raynal mtd->ecc_stats.corrected += stats;
49508d8c621SMiquel Raynal max_bitflips = max_t(unsigned int, max_bitflips, stats);
49608d8c621SMiquel Raynal }
49708d8c621SMiquel Raynal }
49808d8c621SMiquel Raynal
49908d8c621SMiquel Raynal return max_bitflips;
50008d8c621SMiquel Raynal }
50108d8c621SMiquel Raynal
pl35x_nand_write_page_hwecc(struct nand_chip * chip,const u8 * buf,int oob_required,int page)50208d8c621SMiquel Raynal static int pl35x_nand_write_page_hwecc(struct nand_chip *chip,
50308d8c621SMiquel Raynal const u8 *buf, int oob_required,
50408d8c621SMiquel Raynal int page)
50508d8c621SMiquel Raynal {
50608d8c621SMiquel Raynal struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
50708d8c621SMiquel Raynal struct pl35x_nand *plnand = to_pl35x_nand(chip);
50808d8c621SMiquel Raynal struct mtd_info *mtd = nand_to_mtd(chip);
50908d8c621SMiquel Raynal unsigned int first_row = (mtd->writesize <= 512) ? 1 : 2;
51008d8c621SMiquel Raynal unsigned int nrows = plnand->addr_cycles;
51108d8c621SMiquel Raynal u32 addr1 = 0, addr2 = 0, row;
51208d8c621SMiquel Raynal u32 cmd_addr;
51308d8c621SMiquel Raynal int i, ret;
514*9777cc13SMiquel Raynal u8 status;
51508d8c621SMiquel Raynal
51608d8c621SMiquel Raynal ret = pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_APB);
51708d8c621SMiquel Raynal if (ret)
51808d8c621SMiquel Raynal return ret;
51908d8c621SMiquel Raynal
52008d8c621SMiquel Raynal cmd_addr = PL35X_SMC_CMD_PHASE |
52108d8c621SMiquel Raynal PL35X_SMC_CMD_PHASE_NADDRS(plnand->addr_cycles) |
52208d8c621SMiquel Raynal PL35X_SMC_CMD_PHASE_CMD0(NAND_CMD_SEQIN);
52308d8c621SMiquel Raynal
52408d8c621SMiquel Raynal for (i = 0, row = first_row; row < nrows; i++, row++) {
52508d8c621SMiquel Raynal u8 addr = page >> ((i * 8) & 0xFF);
52608d8c621SMiquel Raynal
52708d8c621SMiquel Raynal if (row < 4)
52808d8c621SMiquel Raynal addr1 |= PL35X_SMC_CMD_PHASE_ADDR(row, addr);
52908d8c621SMiquel Raynal else
53008d8c621SMiquel Raynal addr2 |= PL35X_SMC_CMD_PHASE_ADDR(row - 4, addr);
53108d8c621SMiquel Raynal }
53208d8c621SMiquel Raynal
53308d8c621SMiquel Raynal /* Send the command and address cycles */
53408d8c621SMiquel Raynal writel(addr1, nfc->io_regs + cmd_addr);
53508d8c621SMiquel Raynal if (plnand->addr_cycles > 4)
53608d8c621SMiquel Raynal writel(addr2, nfc->io_regs + cmd_addr);
53708d8c621SMiquel Raynal
53808d8c621SMiquel Raynal /* Write the data with the engine enabled */
53908d8c621SMiquel Raynal pl35x_nand_write_data_op(chip, buf, mtd->writesize, false,
54008d8c621SMiquel Raynal 0, PL35X_SMC_DATA_PHASE_ECC_LAST);
54108d8c621SMiquel Raynal ret = pl35x_smc_wait_for_ecc_done(nfc);
54208d8c621SMiquel Raynal if (ret)
54308d8c621SMiquel Raynal goto disable_ecc_engine;
54408d8c621SMiquel Raynal
54508d8c621SMiquel Raynal /* Copy the HW calculated ECC bytes in the OOB buffer */
54608d8c621SMiquel Raynal ret = pl35x_nand_read_eccbytes(nfc, chip, nfc->ecc_buf);
54708d8c621SMiquel Raynal if (ret)
54808d8c621SMiquel Raynal goto disable_ecc_engine;
54908d8c621SMiquel Raynal
55008d8c621SMiquel Raynal if (!oob_required)
55108d8c621SMiquel Raynal memset(chip->oob_poi, 0xFF, mtd->oobsize);
55208d8c621SMiquel Raynal
55308d8c621SMiquel Raynal ret = mtd_ooblayout_set_eccbytes(mtd, nfc->ecc_buf, chip->oob_poi,
55408d8c621SMiquel Raynal 0, chip->ecc.total);
55508d8c621SMiquel Raynal if (ret)
55608d8c621SMiquel Raynal goto disable_ecc_engine;
55708d8c621SMiquel Raynal
55808d8c621SMiquel Raynal /* Write the spare area with ECC bytes */
55908d8c621SMiquel Raynal pl35x_nand_write_data_op(chip, chip->oob_poi, mtd->oobsize, false, 0,
56008d8c621SMiquel Raynal PL35X_SMC_CMD_PHASE_CMD1(NAND_CMD_PAGEPROG) |
56108d8c621SMiquel Raynal PL35X_SMC_CMD_PHASE_CMD1_VALID |
56208d8c621SMiquel Raynal PL35X_SMC_DATA_PHASE_CLEAR_CS);
56308d8c621SMiquel Raynal ret = pl35x_smc_wait_for_irq(nfc);
56408d8c621SMiquel Raynal if (ret)
56508d8c621SMiquel Raynal goto disable_ecc_engine;
56608d8c621SMiquel Raynal
567*9777cc13SMiquel Raynal /* Check write status on the chip side */
568*9777cc13SMiquel Raynal ret = nand_status_op(chip, &status);
569*9777cc13SMiquel Raynal if (ret)
570*9777cc13SMiquel Raynal goto disable_ecc_engine;
571*9777cc13SMiquel Raynal
572*9777cc13SMiquel Raynal if (status & NAND_STATUS_FAIL)
573*9777cc13SMiquel Raynal ret = -EIO;
574*9777cc13SMiquel Raynal
57508d8c621SMiquel Raynal disable_ecc_engine:
57608d8c621SMiquel Raynal pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_BYPASS);
57708d8c621SMiquel Raynal
57808d8c621SMiquel Raynal return ret;
57908d8c621SMiquel Raynal }
58008d8c621SMiquel Raynal
58108d8c621SMiquel Raynal /*
58208d8c621SMiquel Raynal * This functions reads data and checks the data integrity by comparing hardware
58308d8c621SMiquel Raynal * generated ECC values and read ECC values from spare area.
58408d8c621SMiquel Raynal *
58508d8c621SMiquel Raynal * There is a limitation with SMC controller: ECC_LAST must be set on the
58608d8c621SMiquel Raynal * last data access to tell the ECC engine not to expect any further data.
58708d8c621SMiquel Raynal * In practice, this implies to shrink the last data transfert by eg. 4 bytes,
58808d8c621SMiquel Raynal * and doing a last 4-byte transfer with the additional bit set. The last block
58908d8c621SMiquel Raynal * should be aligned with the end of an ECC block. Because of this limitation,
59008d8c621SMiquel Raynal * it is not possible to use the core routines.
59108d8c621SMiquel Raynal */
pl35x_nand_read_page_hwecc(struct nand_chip * chip,u8 * buf,int oob_required,int page)59208d8c621SMiquel Raynal static int pl35x_nand_read_page_hwecc(struct nand_chip *chip,
59308d8c621SMiquel Raynal u8 *buf, int oob_required, int page)
59408d8c621SMiquel Raynal {
59508d8c621SMiquel Raynal const struct nand_sdr_timings *sdr =
59608d8c621SMiquel Raynal nand_get_sdr_timings(nand_get_interface_config(chip));
59708d8c621SMiquel Raynal struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
59808d8c621SMiquel Raynal struct pl35x_nand *plnand = to_pl35x_nand(chip);
59908d8c621SMiquel Raynal struct mtd_info *mtd = nand_to_mtd(chip);
60008d8c621SMiquel Raynal unsigned int first_row = (mtd->writesize <= 512) ? 1 : 2;
60108d8c621SMiquel Raynal unsigned int nrows = plnand->addr_cycles;
60208d8c621SMiquel Raynal unsigned int addr1 = 0, addr2 = 0, row;
60308d8c621SMiquel Raynal u32 cmd_addr;
60408d8c621SMiquel Raynal int i, ret;
60508d8c621SMiquel Raynal
60608d8c621SMiquel Raynal ret = pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_APB);
60708d8c621SMiquel Raynal if (ret)
60808d8c621SMiquel Raynal return ret;
60908d8c621SMiquel Raynal
61008d8c621SMiquel Raynal cmd_addr = PL35X_SMC_CMD_PHASE |
61108d8c621SMiquel Raynal PL35X_SMC_CMD_PHASE_NADDRS(plnand->addr_cycles) |
61208d8c621SMiquel Raynal PL35X_SMC_CMD_PHASE_CMD0(NAND_CMD_READ0) |
61308d8c621SMiquel Raynal PL35X_SMC_CMD_PHASE_CMD1(NAND_CMD_READSTART) |
61408d8c621SMiquel Raynal PL35X_SMC_CMD_PHASE_CMD1_VALID;
61508d8c621SMiquel Raynal
61608d8c621SMiquel Raynal for (i = 0, row = first_row; row < nrows; i++, row++) {
61708d8c621SMiquel Raynal u8 addr = page >> ((i * 8) & 0xFF);
61808d8c621SMiquel Raynal
61908d8c621SMiquel Raynal if (row < 4)
62008d8c621SMiquel Raynal addr1 |= PL35X_SMC_CMD_PHASE_ADDR(row, addr);
62108d8c621SMiquel Raynal else
62208d8c621SMiquel Raynal addr2 |= PL35X_SMC_CMD_PHASE_ADDR(row - 4, addr);
62308d8c621SMiquel Raynal }
62408d8c621SMiquel Raynal
62508d8c621SMiquel Raynal /* Send the command and address cycles */
62608d8c621SMiquel Raynal writel(addr1, nfc->io_regs + cmd_addr);
62708d8c621SMiquel Raynal if (plnand->addr_cycles > 4)
62808d8c621SMiquel Raynal writel(addr2, nfc->io_regs + cmd_addr);
62908d8c621SMiquel Raynal
63008d8c621SMiquel Raynal /* Wait the data to be available in the NAND cache */
63108d8c621SMiquel Raynal ndelay(PSEC_TO_NSEC(sdr->tRR_min));
63208d8c621SMiquel Raynal ret = pl35x_smc_wait_for_irq(nfc);
63308d8c621SMiquel Raynal if (ret)
63408d8c621SMiquel Raynal goto disable_ecc_engine;
63508d8c621SMiquel Raynal
63608d8c621SMiquel Raynal /* Retrieve the raw data with the engine enabled */
63708d8c621SMiquel Raynal pl35x_nand_read_data_op(chip, buf, mtd->writesize, false,
63808d8c621SMiquel Raynal 0, PL35X_SMC_DATA_PHASE_ECC_LAST);
63908d8c621SMiquel Raynal ret = pl35x_smc_wait_for_ecc_done(nfc);
64008d8c621SMiquel Raynal if (ret)
64108d8c621SMiquel Raynal goto disable_ecc_engine;
64208d8c621SMiquel Raynal
64308d8c621SMiquel Raynal /* Retrieve the stored ECC bytes */
64408d8c621SMiquel Raynal pl35x_nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false,
64508d8c621SMiquel Raynal 0, PL35X_SMC_DATA_PHASE_CLEAR_CS);
64608d8c621SMiquel Raynal ret = mtd_ooblayout_get_eccbytes(mtd, nfc->ecc_buf, chip->oob_poi, 0,
64708d8c621SMiquel Raynal chip->ecc.total);
64808d8c621SMiquel Raynal if (ret)
64908d8c621SMiquel Raynal goto disable_ecc_engine;
65008d8c621SMiquel Raynal
65108d8c621SMiquel Raynal pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_BYPASS);
65208d8c621SMiquel Raynal
65308d8c621SMiquel Raynal /* Correct the data and report failures */
65408d8c621SMiquel Raynal return pl35x_nand_recover_data_hwecc(nfc, chip, buf, nfc->ecc_buf);
65508d8c621SMiquel Raynal
65608d8c621SMiquel Raynal disable_ecc_engine:
65708d8c621SMiquel Raynal pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_BYPASS);
65808d8c621SMiquel Raynal
65908d8c621SMiquel Raynal return ret;
66008d8c621SMiquel Raynal }
66108d8c621SMiquel Raynal
pl35x_nand_exec_op(struct nand_chip * chip,const struct nand_subop * subop)66208d8c621SMiquel Raynal static int pl35x_nand_exec_op(struct nand_chip *chip,
66308d8c621SMiquel Raynal const struct nand_subop *subop)
66408d8c621SMiquel Raynal {
66508d8c621SMiquel Raynal struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
66608d8c621SMiquel Raynal const struct nand_op_instr *instr, *data_instr = NULL;
66708d8c621SMiquel Raynal unsigned int rdy_tim_ms = 0, naddrs = 0, cmds = 0, last_flags = 0;
66808d8c621SMiquel Raynal u32 addr1 = 0, addr2 = 0, cmd0 = 0, cmd1 = 0, cmd_addr = 0;
66908d8c621SMiquel Raynal unsigned int op_id, len, offset, rdy_del_ns;
67008d8c621SMiquel Raynal int last_instr_type = -1;
67108d8c621SMiquel Raynal bool cmd1_valid = false;
67208d8c621SMiquel Raynal const u8 *addrs;
67308d8c621SMiquel Raynal int i, ret;
67408d8c621SMiquel Raynal
67508d8c621SMiquel Raynal for (op_id = 0; op_id < subop->ninstrs; op_id++) {
67608d8c621SMiquel Raynal instr = &subop->instrs[op_id];
67708d8c621SMiquel Raynal
67808d8c621SMiquel Raynal switch (instr->type) {
67908d8c621SMiquel Raynal case NAND_OP_CMD_INSTR:
68008d8c621SMiquel Raynal if (!cmds) {
68108d8c621SMiquel Raynal cmd0 = PL35X_SMC_CMD_PHASE_CMD0(instr->ctx.cmd.opcode);
68208d8c621SMiquel Raynal } else {
68308d8c621SMiquel Raynal cmd1 = PL35X_SMC_CMD_PHASE_CMD1(instr->ctx.cmd.opcode);
68408d8c621SMiquel Raynal if (last_instr_type != NAND_OP_DATA_OUT_INSTR)
68508d8c621SMiquel Raynal cmd1_valid = true;
68608d8c621SMiquel Raynal }
68708d8c621SMiquel Raynal cmds++;
68808d8c621SMiquel Raynal break;
68908d8c621SMiquel Raynal
69008d8c621SMiquel Raynal case NAND_OP_ADDR_INSTR:
69108d8c621SMiquel Raynal offset = nand_subop_get_addr_start_off(subop, op_id);
69208d8c621SMiquel Raynal naddrs = nand_subop_get_num_addr_cyc(subop, op_id);
69308d8c621SMiquel Raynal addrs = &instr->ctx.addr.addrs[offset];
69408d8c621SMiquel Raynal cmd_addr |= PL35X_SMC_CMD_PHASE_NADDRS(naddrs);
69508d8c621SMiquel Raynal
69608d8c621SMiquel Raynal for (i = offset; i < naddrs; i++) {
69708d8c621SMiquel Raynal if (i < 4)
69808d8c621SMiquel Raynal addr1 |= PL35X_SMC_CMD_PHASE_ADDR(i, addrs[i]);
69908d8c621SMiquel Raynal else
70008d8c621SMiquel Raynal addr2 |= PL35X_SMC_CMD_PHASE_ADDR(i - 4, addrs[i]);
70108d8c621SMiquel Raynal }
70208d8c621SMiquel Raynal break;
70308d8c621SMiquel Raynal
70408d8c621SMiquel Raynal case NAND_OP_DATA_IN_INSTR:
70508d8c621SMiquel Raynal case NAND_OP_DATA_OUT_INSTR:
70608d8c621SMiquel Raynal data_instr = instr;
70708d8c621SMiquel Raynal len = nand_subop_get_data_len(subop, op_id);
70808d8c621SMiquel Raynal break;
70908d8c621SMiquel Raynal
71008d8c621SMiquel Raynal case NAND_OP_WAITRDY_INSTR:
71108d8c621SMiquel Raynal rdy_tim_ms = instr->ctx.waitrdy.timeout_ms;
71208d8c621SMiquel Raynal rdy_del_ns = instr->delay_ns;
71308d8c621SMiquel Raynal break;
71408d8c621SMiquel Raynal }
71508d8c621SMiquel Raynal
71608d8c621SMiquel Raynal last_instr_type = instr->type;
71708d8c621SMiquel Raynal }
71808d8c621SMiquel Raynal
71908d8c621SMiquel Raynal /* Command phase */
72008d8c621SMiquel Raynal cmd_addr |= PL35X_SMC_CMD_PHASE | cmd0 | cmd1 |
72108d8c621SMiquel Raynal (cmd1_valid ? PL35X_SMC_CMD_PHASE_CMD1_VALID : 0);
72208d8c621SMiquel Raynal writel(addr1, nfc->io_regs + cmd_addr);
72308d8c621SMiquel Raynal if (naddrs > 4)
72408d8c621SMiquel Raynal writel(addr2, nfc->io_regs + cmd_addr);
72508d8c621SMiquel Raynal
72608d8c621SMiquel Raynal /* Data phase */
72708d8c621SMiquel Raynal if (data_instr && data_instr->type == NAND_OP_DATA_OUT_INSTR) {
72808d8c621SMiquel Raynal last_flags = PL35X_SMC_DATA_PHASE_CLEAR_CS;
72908d8c621SMiquel Raynal if (cmds == 2)
73008d8c621SMiquel Raynal last_flags |= cmd1 | PL35X_SMC_CMD_PHASE_CMD1_VALID;
73108d8c621SMiquel Raynal
73208d8c621SMiquel Raynal pl35x_nand_write_data_op(chip, data_instr->ctx.data.buf.out,
73308d8c621SMiquel Raynal len, data_instr->ctx.data.force_8bit,
73408d8c621SMiquel Raynal 0, last_flags);
73508d8c621SMiquel Raynal }
73608d8c621SMiquel Raynal
73708d8c621SMiquel Raynal if (rdy_tim_ms) {
73808d8c621SMiquel Raynal ndelay(rdy_del_ns);
73908d8c621SMiquel Raynal ret = pl35x_smc_wait_for_irq(nfc);
74008d8c621SMiquel Raynal if (ret)
74108d8c621SMiquel Raynal return ret;
74208d8c621SMiquel Raynal }
74308d8c621SMiquel Raynal
74408d8c621SMiquel Raynal if (data_instr && data_instr->type == NAND_OP_DATA_IN_INSTR)
74508d8c621SMiquel Raynal pl35x_nand_read_data_op(chip, data_instr->ctx.data.buf.in,
74608d8c621SMiquel Raynal len, data_instr->ctx.data.force_8bit,
74708d8c621SMiquel Raynal 0, PL35X_SMC_DATA_PHASE_CLEAR_CS);
74808d8c621SMiquel Raynal
74908d8c621SMiquel Raynal return 0;
75008d8c621SMiquel Raynal }
75108d8c621SMiquel Raynal
75208d8c621SMiquel Raynal static const struct nand_op_parser pl35x_nandc_op_parser = NAND_OP_PARSER(
75308d8c621SMiquel Raynal NAND_OP_PARSER_PATTERN(pl35x_nand_exec_op,
75408d8c621SMiquel Raynal NAND_OP_PARSER_PAT_CMD_ELEM(true),
75508d8c621SMiquel Raynal NAND_OP_PARSER_PAT_ADDR_ELEM(true, 7),
75608d8c621SMiquel Raynal NAND_OP_PARSER_PAT_CMD_ELEM(true),
75708d8c621SMiquel Raynal NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
75808d8c621SMiquel Raynal NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 2112)),
75908d8c621SMiquel Raynal NAND_OP_PARSER_PATTERN(pl35x_nand_exec_op,
76008d8c621SMiquel Raynal NAND_OP_PARSER_PAT_CMD_ELEM(false),
76108d8c621SMiquel Raynal NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7),
76208d8c621SMiquel Raynal NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 2112),
76308d8c621SMiquel Raynal NAND_OP_PARSER_PAT_CMD_ELEM(false),
76408d8c621SMiquel Raynal NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
76508d8c621SMiquel Raynal NAND_OP_PARSER_PATTERN(pl35x_nand_exec_op,
76608d8c621SMiquel Raynal NAND_OP_PARSER_PAT_CMD_ELEM(false),
76708d8c621SMiquel Raynal NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7),
76808d8c621SMiquel Raynal NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 2112),
76908d8c621SMiquel Raynal NAND_OP_PARSER_PAT_CMD_ELEM(true),
77008d8c621SMiquel Raynal NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
77108d8c621SMiquel Raynal );
77208d8c621SMiquel Raynal
pl35x_nfc_exec_op(struct nand_chip * chip,const struct nand_operation * op,bool check_only)77308d8c621SMiquel Raynal static int pl35x_nfc_exec_op(struct nand_chip *chip,
77408d8c621SMiquel Raynal const struct nand_operation *op,
77508d8c621SMiquel Raynal bool check_only)
77608d8c621SMiquel Raynal {
77708d8c621SMiquel Raynal if (!check_only)
77808d8c621SMiquel Raynal pl35x_nand_select_target(chip, op->cs);
77908d8c621SMiquel Raynal
78008d8c621SMiquel Raynal return nand_op_parser_exec_op(chip, &pl35x_nandc_op_parser,
78108d8c621SMiquel Raynal op, check_only);
78208d8c621SMiquel Raynal }
78308d8c621SMiquel Raynal
pl35x_nfc_setup_interface(struct nand_chip * chip,int cs,const struct nand_interface_config * conf)78408d8c621SMiquel Raynal static int pl35x_nfc_setup_interface(struct nand_chip *chip, int cs,
78508d8c621SMiquel Raynal const struct nand_interface_config *conf)
78608d8c621SMiquel Raynal {
78708d8c621SMiquel Raynal struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
78808d8c621SMiquel Raynal struct pl35x_nand *plnand = to_pl35x_nand(chip);
78908d8c621SMiquel Raynal struct pl35x_nand_timings tmgs = {};
79008d8c621SMiquel Raynal const struct nand_sdr_timings *sdr;
79108d8c621SMiquel Raynal unsigned int period_ns, val;
79208d8c621SMiquel Raynal struct clk *mclk;
79308d8c621SMiquel Raynal
79408d8c621SMiquel Raynal sdr = nand_get_sdr_timings(conf);
79508d8c621SMiquel Raynal if (IS_ERR(sdr))
79608d8c621SMiquel Raynal return PTR_ERR(sdr);
79708d8c621SMiquel Raynal
79808d8c621SMiquel Raynal mclk = of_clk_get_by_name(nfc->dev->parent->of_node, "memclk");
79908d8c621SMiquel Raynal if (IS_ERR(mclk)) {
80008d8c621SMiquel Raynal dev_err(nfc->dev, "Failed to retrieve SMC memclk\n");
80108d8c621SMiquel Raynal return PTR_ERR(mclk);
80208d8c621SMiquel Raynal }
80308d8c621SMiquel Raynal
80408d8c621SMiquel Raynal /*
80508d8c621SMiquel Raynal * SDR timings are given in pico-seconds while NFC timings must be
80608d8c621SMiquel Raynal * expressed in NAND controller clock cycles. We use the TO_CYCLE()
80708d8c621SMiquel Raynal * macro to convert from one to the other.
80808d8c621SMiquel Raynal */
80908d8c621SMiquel Raynal period_ns = NSEC_PER_SEC / clk_get_rate(mclk);
81008d8c621SMiquel Raynal
81108d8c621SMiquel Raynal /*
81208d8c621SMiquel Raynal * PL35X SMC needs one extra read cycle in SDR Mode 5. This is not
81308d8c621SMiquel Raynal * written anywhere in the datasheet but is an empirical observation.
81408d8c621SMiquel Raynal */
81508d8c621SMiquel Raynal val = TO_CYCLES(sdr->tRC_min, period_ns);
81608d8c621SMiquel Raynal if (sdr->tRC_min <= 20000)
81708d8c621SMiquel Raynal val++;
81808d8c621SMiquel Raynal
81908d8c621SMiquel Raynal tmgs.t_rc = val;
82008d8c621SMiquel Raynal if (tmgs.t_rc != val || tmgs.t_rc < 2)
82108d8c621SMiquel Raynal return -EINVAL;
82208d8c621SMiquel Raynal
82308d8c621SMiquel Raynal val = TO_CYCLES(sdr->tWC_min, period_ns);
82408d8c621SMiquel Raynal tmgs.t_wc = val;
82508d8c621SMiquel Raynal if (tmgs.t_wc != val || tmgs.t_wc < 2)
82608d8c621SMiquel Raynal return -EINVAL;
82708d8c621SMiquel Raynal
82808d8c621SMiquel Raynal /*
82908d8c621SMiquel Raynal * For all SDR modes, PL35X SMC needs tREA_max being 1,
83008d8c621SMiquel Raynal * this is also an empirical result.
83108d8c621SMiquel Raynal */
83208d8c621SMiquel Raynal tmgs.t_rea = 1;
83308d8c621SMiquel Raynal
83408d8c621SMiquel Raynal val = TO_CYCLES(sdr->tWP_min, period_ns);
83508d8c621SMiquel Raynal tmgs.t_wp = val;
83608d8c621SMiquel Raynal if (tmgs.t_wp != val || tmgs.t_wp < 1)
83708d8c621SMiquel Raynal return -EINVAL;
83808d8c621SMiquel Raynal
83908d8c621SMiquel Raynal val = TO_CYCLES(sdr->tCLR_min, period_ns);
84008d8c621SMiquel Raynal tmgs.t_clr = val;
84108d8c621SMiquel Raynal if (tmgs.t_clr != val)
84208d8c621SMiquel Raynal return -EINVAL;
84308d8c621SMiquel Raynal
84408d8c621SMiquel Raynal val = TO_CYCLES(sdr->tAR_min, period_ns);
84508d8c621SMiquel Raynal tmgs.t_ar = val;
84608d8c621SMiquel Raynal if (tmgs.t_ar != val)
84708d8c621SMiquel Raynal return -EINVAL;
84808d8c621SMiquel Raynal
84908d8c621SMiquel Raynal val = TO_CYCLES(sdr->tRR_min, period_ns);
85008d8c621SMiquel Raynal tmgs.t_rr = val;
85108d8c621SMiquel Raynal if (tmgs.t_rr != val)
85208d8c621SMiquel Raynal return -EINVAL;
85308d8c621SMiquel Raynal
85408d8c621SMiquel Raynal if (cs == NAND_DATA_IFACE_CHECK_ONLY)
85508d8c621SMiquel Raynal return 0;
85608d8c621SMiquel Raynal
85708d8c621SMiquel Raynal plnand->timings = PL35X_SMC_NAND_TRC_CYCLES(tmgs.t_rc) |
85808d8c621SMiquel Raynal PL35X_SMC_NAND_TWC_CYCLES(tmgs.t_wc) |
85908d8c621SMiquel Raynal PL35X_SMC_NAND_TREA_CYCLES(tmgs.t_rea) |
86008d8c621SMiquel Raynal PL35X_SMC_NAND_TWP_CYCLES(tmgs.t_wp) |
86108d8c621SMiquel Raynal PL35X_SMC_NAND_TCLR_CYCLES(tmgs.t_clr) |
86208d8c621SMiquel Raynal PL35X_SMC_NAND_TAR_CYCLES(tmgs.t_ar) |
86308d8c621SMiquel Raynal PL35X_SMC_NAND_TRR_CYCLES(tmgs.t_rr);
86408d8c621SMiquel Raynal
86508d8c621SMiquel Raynal return 0;
86608d8c621SMiquel Raynal }
86708d8c621SMiquel Raynal
pl35x_smc_set_ecc_pg_size(struct pl35x_nandc * nfc,struct nand_chip * chip,unsigned int pg_sz)86808d8c621SMiquel Raynal static void pl35x_smc_set_ecc_pg_size(struct pl35x_nandc *nfc,
86908d8c621SMiquel Raynal struct nand_chip *chip,
87008d8c621SMiquel Raynal unsigned int pg_sz)
87108d8c621SMiquel Raynal {
87208d8c621SMiquel Raynal struct pl35x_nand *plnand = to_pl35x_nand(chip);
87308d8c621SMiquel Raynal u32 sz;
87408d8c621SMiquel Raynal
87508d8c621SMiquel Raynal switch (pg_sz) {
87608d8c621SMiquel Raynal case SZ_512:
87708d8c621SMiquel Raynal sz = 1;
87808d8c621SMiquel Raynal break;
87908d8c621SMiquel Raynal case SZ_1K:
88008d8c621SMiquel Raynal sz = 2;
88108d8c621SMiquel Raynal break;
88208d8c621SMiquel Raynal case SZ_2K:
88308d8c621SMiquel Raynal sz = 3;
88408d8c621SMiquel Raynal break;
88508d8c621SMiquel Raynal default:
88608d8c621SMiquel Raynal sz = 0;
88708d8c621SMiquel Raynal break;
88808d8c621SMiquel Raynal }
88908d8c621SMiquel Raynal
89008d8c621SMiquel Raynal plnand->ecc_cfg = readl(nfc->conf_regs + PL35X_SMC_ECC_CFG);
89108d8c621SMiquel Raynal plnand->ecc_cfg &= ~PL35X_SMC_ECC_CFG_PGSIZE_MASK;
89208d8c621SMiquel Raynal plnand->ecc_cfg |= sz;
89308d8c621SMiquel Raynal writel(plnand->ecc_cfg, nfc->conf_regs + PL35X_SMC_ECC_CFG);
89408d8c621SMiquel Raynal }
89508d8c621SMiquel Raynal
pl35x_nand_init_hw_ecc_controller(struct pl35x_nandc * nfc,struct nand_chip * chip)89608d8c621SMiquel Raynal static int pl35x_nand_init_hw_ecc_controller(struct pl35x_nandc *nfc,
89708d8c621SMiquel Raynal struct nand_chip *chip)
89808d8c621SMiquel Raynal {
89908d8c621SMiquel Raynal struct mtd_info *mtd = nand_to_mtd(chip);
90008d8c621SMiquel Raynal int ret = 0;
90108d8c621SMiquel Raynal
90208d8c621SMiquel Raynal if (mtd->writesize < SZ_512 || mtd->writesize > SZ_2K) {
90308d8c621SMiquel Raynal dev_err(nfc->dev,
90408d8c621SMiquel Raynal "The hardware ECC engine is limited to pages up to 2kiB\n");
90508d8c621SMiquel Raynal return -EOPNOTSUPP;
90608d8c621SMiquel Raynal }
90708d8c621SMiquel Raynal
90808d8c621SMiquel Raynal chip->ecc.strength = 1;
90908d8c621SMiquel Raynal chip->ecc.bytes = 3;
91008d8c621SMiquel Raynal chip->ecc.size = SZ_512;
91108d8c621SMiquel Raynal chip->ecc.steps = mtd->writesize / chip->ecc.size;
91208d8c621SMiquel Raynal chip->ecc.read_page = pl35x_nand_read_page_hwecc;
91308d8c621SMiquel Raynal chip->ecc.write_page = pl35x_nand_write_page_hwecc;
91408d8c621SMiquel Raynal chip->ecc.write_page_raw = nand_monolithic_write_page_raw;
91508d8c621SMiquel Raynal pl35x_smc_set_ecc_pg_size(nfc, chip, mtd->writesize);
91608d8c621SMiquel Raynal
91708d8c621SMiquel Raynal nfc->ecc_buf = devm_kmalloc(nfc->dev, chip->ecc.bytes * chip->ecc.steps,
91808d8c621SMiquel Raynal GFP_KERNEL);
91908d8c621SMiquel Raynal if (!nfc->ecc_buf)
92008d8c621SMiquel Raynal return -ENOMEM;
92108d8c621SMiquel Raynal
92208d8c621SMiquel Raynal switch (mtd->oobsize) {
92308d8c621SMiquel Raynal case 16:
92408d8c621SMiquel Raynal /* Legacy Xilinx layout */
92508d8c621SMiquel Raynal mtd_set_ooblayout(mtd, &pl35x_ecc_ooblayout16_ops);
92608d8c621SMiquel Raynal chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
92708d8c621SMiquel Raynal break;
92808d8c621SMiquel Raynal case 64:
92908d8c621SMiquel Raynal mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
93008d8c621SMiquel Raynal break;
93108d8c621SMiquel Raynal default:
93208d8c621SMiquel Raynal dev_err(nfc->dev, "Unsupported OOB size\n");
93308d8c621SMiquel Raynal return -EOPNOTSUPP;
93408d8c621SMiquel Raynal }
93508d8c621SMiquel Raynal
93608d8c621SMiquel Raynal return ret;
93708d8c621SMiquel Raynal }
93808d8c621SMiquel Raynal
pl35x_nand_attach_chip(struct nand_chip * chip)93908d8c621SMiquel Raynal static int pl35x_nand_attach_chip(struct nand_chip *chip)
94008d8c621SMiquel Raynal {
94108d8c621SMiquel Raynal const struct nand_ecc_props *requirements =
94208d8c621SMiquel Raynal nanddev_get_ecc_requirements(&chip->base);
94308d8c621SMiquel Raynal struct pl35x_nandc *nfc = to_pl35x_nandc(chip->controller);
94408d8c621SMiquel Raynal struct pl35x_nand *plnand = to_pl35x_nand(chip);
94508d8c621SMiquel Raynal struct mtd_info *mtd = nand_to_mtd(chip);
94608d8c621SMiquel Raynal int ret;
94708d8c621SMiquel Raynal
94808d8c621SMiquel Raynal if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
94908d8c621SMiquel Raynal (!chip->ecc.size || !chip->ecc.strength)) {
95008d8c621SMiquel Raynal if (requirements->step_size && requirements->strength) {
95108d8c621SMiquel Raynal chip->ecc.size = requirements->step_size;
95208d8c621SMiquel Raynal chip->ecc.strength = requirements->strength;
95308d8c621SMiquel Raynal } else {
95408d8c621SMiquel Raynal dev_info(nfc->dev,
95508d8c621SMiquel Raynal "No minimum ECC strength, using 1b/512B\n");
95608d8c621SMiquel Raynal chip->ecc.size = 512;
95708d8c621SMiquel Raynal chip->ecc.strength = 1;
95808d8c621SMiquel Raynal }
95908d8c621SMiquel Raynal }
96008d8c621SMiquel Raynal
96108d8c621SMiquel Raynal if (mtd->writesize <= SZ_512)
96208d8c621SMiquel Raynal plnand->addr_cycles = 1;
96308d8c621SMiquel Raynal else
96408d8c621SMiquel Raynal plnand->addr_cycles = 2;
96508d8c621SMiquel Raynal
96608d8c621SMiquel Raynal if (chip->options & NAND_ROW_ADDR_3)
96708d8c621SMiquel Raynal plnand->addr_cycles += 3;
96808d8c621SMiquel Raynal else
96908d8c621SMiquel Raynal plnand->addr_cycles += 2;
97008d8c621SMiquel Raynal
97108d8c621SMiquel Raynal switch (chip->ecc.engine_type) {
97208d8c621SMiquel Raynal case NAND_ECC_ENGINE_TYPE_ON_DIE:
97308d8c621SMiquel Raynal /* Keep these legacy BBT descriptors for ON_DIE situations */
97408d8c621SMiquel Raynal chip->bbt_td = &bbt_main_descr;
97508d8c621SMiquel Raynal chip->bbt_md = &bbt_mirror_descr;
97608d8c621SMiquel Raynal fallthrough;
97708d8c621SMiquel Raynal case NAND_ECC_ENGINE_TYPE_NONE:
97808d8c621SMiquel Raynal case NAND_ECC_ENGINE_TYPE_SOFT:
97908d8c621SMiquel Raynal break;
98008d8c621SMiquel Raynal case NAND_ECC_ENGINE_TYPE_ON_HOST:
98108d8c621SMiquel Raynal ret = pl35x_nand_init_hw_ecc_controller(nfc, chip);
98208d8c621SMiquel Raynal if (ret)
98308d8c621SMiquel Raynal return ret;
98408d8c621SMiquel Raynal break;
98508d8c621SMiquel Raynal default:
98608d8c621SMiquel Raynal dev_err(nfc->dev, "Unsupported ECC mode: %d\n",
98708d8c621SMiquel Raynal chip->ecc.engine_type);
98808d8c621SMiquel Raynal return -EINVAL;
98908d8c621SMiquel Raynal }
99008d8c621SMiquel Raynal
99108d8c621SMiquel Raynal return 0;
99208d8c621SMiquel Raynal }
99308d8c621SMiquel Raynal
99408d8c621SMiquel Raynal static const struct nand_controller_ops pl35x_nandc_ops = {
99508d8c621SMiquel Raynal .attach_chip = pl35x_nand_attach_chip,
99608d8c621SMiquel Raynal .exec_op = pl35x_nfc_exec_op,
99708d8c621SMiquel Raynal .setup_interface = pl35x_nfc_setup_interface,
99808d8c621SMiquel Raynal };
99908d8c621SMiquel Raynal
pl35x_nand_reset_state(struct pl35x_nandc * nfc)100008d8c621SMiquel Raynal static int pl35x_nand_reset_state(struct pl35x_nandc *nfc)
100108d8c621SMiquel Raynal {
100208d8c621SMiquel Raynal int ret;
100308d8c621SMiquel Raynal
100408d8c621SMiquel Raynal /* Disable interrupts and clear their status */
100508d8c621SMiquel Raynal writel(PL35X_SMC_MEMC_CFG_CLR_INT_CLR_1 |
100608d8c621SMiquel Raynal PL35X_SMC_MEMC_CFG_CLR_ECC_INT_DIS_1 |
100708d8c621SMiquel Raynal PL35X_SMC_MEMC_CFG_CLR_INT_DIS_1,
100808d8c621SMiquel Raynal nfc->conf_regs + PL35X_SMC_MEMC_CFG_CLR);
100908d8c621SMiquel Raynal
101008d8c621SMiquel Raynal /* Set default bus width to 8-bit */
101108d8c621SMiquel Raynal ret = pl35x_smc_set_buswidth(nfc, PL35X_SMC_OPMODE_BW_8);
101208d8c621SMiquel Raynal if (ret)
101308d8c621SMiquel Raynal return ret;
101408d8c621SMiquel Raynal
101508d8c621SMiquel Raynal /* Ensure the ECC controller is bypassed by default */
101608d8c621SMiquel Raynal ret = pl35x_smc_set_ecc_mode(nfc, NULL, PL35X_SMC_ECC_CFG_MODE_BYPASS);
101708d8c621SMiquel Raynal if (ret)
101808d8c621SMiquel Raynal return ret;
101908d8c621SMiquel Raynal
102008d8c621SMiquel Raynal /*
102108d8c621SMiquel Raynal * Configure the commands that the ECC block uses to detect the
102208d8c621SMiquel Raynal * operations it should start/end.
102308d8c621SMiquel Raynal */
102408d8c621SMiquel Raynal writel(PL35X_SMC_ECC_CMD1_WRITE(NAND_CMD_SEQIN) |
102508d8c621SMiquel Raynal PL35X_SMC_ECC_CMD1_READ(NAND_CMD_READ0) |
102608d8c621SMiquel Raynal PL35X_SMC_ECC_CMD1_READ_END(NAND_CMD_READSTART) |
102708d8c621SMiquel Raynal PL35X_SMC_ECC_CMD1_READ_END_VALID(NAND_CMD_READ1),
102808d8c621SMiquel Raynal nfc->conf_regs + PL35X_SMC_ECC_CMD1);
102908d8c621SMiquel Raynal writel(PL35X_SMC_ECC_CMD2_WRITE_COL_CHG(NAND_CMD_RNDIN) |
103008d8c621SMiquel Raynal PL35X_SMC_ECC_CMD2_READ_COL_CHG(NAND_CMD_RNDOUT) |
103108d8c621SMiquel Raynal PL35X_SMC_ECC_CMD2_READ_COL_CHG_END(NAND_CMD_RNDOUTSTART) |
103208d8c621SMiquel Raynal PL35X_SMC_ECC_CMD2_READ_COL_CHG_END_VALID(NAND_CMD_READ1),
103308d8c621SMiquel Raynal nfc->conf_regs + PL35X_SMC_ECC_CMD2);
103408d8c621SMiquel Raynal
103508d8c621SMiquel Raynal return 0;
103608d8c621SMiquel Raynal }
103708d8c621SMiquel Raynal
pl35x_nand_chip_init(struct pl35x_nandc * nfc,struct device_node * np)103808d8c621SMiquel Raynal static int pl35x_nand_chip_init(struct pl35x_nandc *nfc,
103908d8c621SMiquel Raynal struct device_node *np)
104008d8c621SMiquel Raynal {
104108d8c621SMiquel Raynal struct pl35x_nand *plnand;
104208d8c621SMiquel Raynal struct nand_chip *chip;
104308d8c621SMiquel Raynal struct mtd_info *mtd;
104408d8c621SMiquel Raynal int cs, ret;
104508d8c621SMiquel Raynal
104608d8c621SMiquel Raynal plnand = devm_kzalloc(nfc->dev, sizeof(*plnand), GFP_KERNEL);
104708d8c621SMiquel Raynal if (!plnand)
104808d8c621SMiquel Raynal return -ENOMEM;
104908d8c621SMiquel Raynal
105008d8c621SMiquel Raynal ret = of_property_read_u32(np, "reg", &cs);
105108d8c621SMiquel Raynal if (ret)
105208d8c621SMiquel Raynal return ret;
105308d8c621SMiquel Raynal
105408d8c621SMiquel Raynal if (cs >= PL35X_NAND_MAX_CS) {
105508d8c621SMiquel Raynal dev_err(nfc->dev, "Wrong CS %d\n", cs);
105608d8c621SMiquel Raynal return -EINVAL;
105708d8c621SMiquel Raynal }
105808d8c621SMiquel Raynal
105908d8c621SMiquel Raynal if (test_and_set_bit(cs, &nfc->assigned_cs)) {
106008d8c621SMiquel Raynal dev_err(nfc->dev, "Already assigned CS %d\n", cs);
106108d8c621SMiquel Raynal return -EINVAL;
106208d8c621SMiquel Raynal }
106308d8c621SMiquel Raynal
106408d8c621SMiquel Raynal plnand->cs = cs;
106508d8c621SMiquel Raynal
106608d8c621SMiquel Raynal chip = &plnand->chip;
106708d8c621SMiquel Raynal chip->options = NAND_BUSWIDTH_AUTO | NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE;
106808d8c621SMiquel Raynal chip->bbt_options = NAND_BBT_USE_FLASH;
106908d8c621SMiquel Raynal chip->controller = &nfc->controller;
107008d8c621SMiquel Raynal mtd = nand_to_mtd(chip);
107108d8c621SMiquel Raynal mtd->dev.parent = nfc->dev;
1072a1fe2aceSAmit Kumar Mahapatra nand_set_flash_node(chip, np);
107308d8c621SMiquel Raynal if (!mtd->name) {
107408d8c621SMiquel Raynal mtd->name = devm_kasprintf(nfc->dev, GFP_KERNEL,
107508d8c621SMiquel Raynal "%s", PL35X_NANDC_DRIVER_NAME);
107608d8c621SMiquel Raynal if (!mtd->name) {
107708d8c621SMiquel Raynal dev_err(nfc->dev, "Failed to allocate mtd->name\n");
107808d8c621SMiquel Raynal return -ENOMEM;
107908d8c621SMiquel Raynal }
108008d8c621SMiquel Raynal }
108108d8c621SMiquel Raynal
108208d8c621SMiquel Raynal ret = nand_scan(chip, 1);
108308d8c621SMiquel Raynal if (ret)
108408d8c621SMiquel Raynal return ret;
108508d8c621SMiquel Raynal
108608d8c621SMiquel Raynal ret = mtd_device_register(mtd, NULL, 0);
108708d8c621SMiquel Raynal if (ret) {
108808d8c621SMiquel Raynal nand_cleanup(chip);
108908d8c621SMiquel Raynal return ret;
109008d8c621SMiquel Raynal }
109108d8c621SMiquel Raynal
109208d8c621SMiquel Raynal list_add_tail(&plnand->node, &nfc->chips);
109308d8c621SMiquel Raynal
109408d8c621SMiquel Raynal return ret;
109508d8c621SMiquel Raynal }
109608d8c621SMiquel Raynal
pl35x_nand_chips_cleanup(struct pl35x_nandc * nfc)109708d8c621SMiquel Raynal static void pl35x_nand_chips_cleanup(struct pl35x_nandc *nfc)
109808d8c621SMiquel Raynal {
109908d8c621SMiquel Raynal struct pl35x_nand *plnand, *tmp;
110008d8c621SMiquel Raynal struct nand_chip *chip;
110108d8c621SMiquel Raynal int ret;
110208d8c621SMiquel Raynal
110308d8c621SMiquel Raynal list_for_each_entry_safe(plnand, tmp, &nfc->chips, node) {
110408d8c621SMiquel Raynal chip = &plnand->chip;
110508d8c621SMiquel Raynal ret = mtd_device_unregister(nand_to_mtd(chip));
110608d8c621SMiquel Raynal WARN_ON(ret);
110708d8c621SMiquel Raynal nand_cleanup(chip);
110808d8c621SMiquel Raynal list_del(&plnand->node);
110908d8c621SMiquel Raynal }
111008d8c621SMiquel Raynal }
111108d8c621SMiquel Raynal
pl35x_nand_chips_init(struct pl35x_nandc * nfc)111208d8c621SMiquel Raynal static int pl35x_nand_chips_init(struct pl35x_nandc *nfc)
111308d8c621SMiquel Raynal {
111408d8c621SMiquel Raynal struct device_node *np = nfc->dev->of_node, *nand_np;
111508d8c621SMiquel Raynal int nchips = of_get_child_count(np);
111608d8c621SMiquel Raynal int ret;
111708d8c621SMiquel Raynal
111808d8c621SMiquel Raynal if (!nchips || nchips > PL35X_NAND_MAX_CS) {
111908d8c621SMiquel Raynal dev_err(nfc->dev, "Incorrect number of NAND chips (%d)\n",
112008d8c621SMiquel Raynal nchips);
112108d8c621SMiquel Raynal return -EINVAL;
112208d8c621SMiquel Raynal }
112308d8c621SMiquel Raynal
112408d8c621SMiquel Raynal for_each_child_of_node(np, nand_np) {
112508d8c621SMiquel Raynal ret = pl35x_nand_chip_init(nfc, nand_np);
112608d8c621SMiquel Raynal if (ret) {
112708d8c621SMiquel Raynal of_node_put(nand_np);
112808d8c621SMiquel Raynal pl35x_nand_chips_cleanup(nfc);
112908d8c621SMiquel Raynal break;
113008d8c621SMiquel Raynal }
113108d8c621SMiquel Raynal }
113208d8c621SMiquel Raynal
113308d8c621SMiquel Raynal return ret;
113408d8c621SMiquel Raynal }
113508d8c621SMiquel Raynal
pl35x_nand_probe(struct platform_device * pdev)113608d8c621SMiquel Raynal static int pl35x_nand_probe(struct platform_device *pdev)
113708d8c621SMiquel Raynal {
113808d8c621SMiquel Raynal struct device *smc_dev = pdev->dev.parent;
113908d8c621SMiquel Raynal struct amba_device *smc_amba = to_amba_device(smc_dev);
114008d8c621SMiquel Raynal struct pl35x_nandc *nfc;
114108d8c621SMiquel Raynal u32 ret;
114208d8c621SMiquel Raynal
114308d8c621SMiquel Raynal nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL);
114408d8c621SMiquel Raynal if (!nfc)
114508d8c621SMiquel Raynal return -ENOMEM;
114608d8c621SMiquel Raynal
114708d8c621SMiquel Raynal nfc->dev = &pdev->dev;
114808d8c621SMiquel Raynal nand_controller_init(&nfc->controller);
114908d8c621SMiquel Raynal nfc->controller.ops = &pl35x_nandc_ops;
115008d8c621SMiquel Raynal INIT_LIST_HEAD(&nfc->chips);
115108d8c621SMiquel Raynal
115208d8c621SMiquel Raynal nfc->conf_regs = devm_ioremap_resource(&smc_amba->dev, &smc_amba->res);
115308d8c621SMiquel Raynal if (IS_ERR(nfc->conf_regs))
115408d8c621SMiquel Raynal return PTR_ERR(nfc->conf_regs);
115508d8c621SMiquel Raynal
115608d8c621SMiquel Raynal nfc->io_regs = devm_platform_ioremap_resource(pdev, 0);
115708d8c621SMiquel Raynal if (IS_ERR(nfc->io_regs))
115808d8c621SMiquel Raynal return PTR_ERR(nfc->io_regs);
115908d8c621SMiquel Raynal
116008d8c621SMiquel Raynal ret = pl35x_nand_reset_state(nfc);
116108d8c621SMiquel Raynal if (ret)
116208d8c621SMiquel Raynal return ret;
116308d8c621SMiquel Raynal
116408d8c621SMiquel Raynal ret = pl35x_nand_chips_init(nfc);
116508d8c621SMiquel Raynal if (ret)
116608d8c621SMiquel Raynal return ret;
116708d8c621SMiquel Raynal
116808d8c621SMiquel Raynal platform_set_drvdata(pdev, nfc);
116908d8c621SMiquel Raynal
117008d8c621SMiquel Raynal return 0;
117108d8c621SMiquel Raynal }
117208d8c621SMiquel Raynal
pl35x_nand_remove(struct platform_device * pdev)1173ec185b18SUwe Kleine-König static void pl35x_nand_remove(struct platform_device *pdev)
117408d8c621SMiquel Raynal {
117508d8c621SMiquel Raynal struct pl35x_nandc *nfc = platform_get_drvdata(pdev);
117608d8c621SMiquel Raynal
117708d8c621SMiquel Raynal pl35x_nand_chips_cleanup(nfc);
117808d8c621SMiquel Raynal }
117908d8c621SMiquel Raynal
118008d8c621SMiquel Raynal static const struct of_device_id pl35x_nand_of_match[] = {
118108d8c621SMiquel Raynal { .compatible = "arm,pl353-nand-r2p1" },
118208d8c621SMiquel Raynal {},
118308d8c621SMiquel Raynal };
118408d8c621SMiquel Raynal MODULE_DEVICE_TABLE(of, pl35x_nand_of_match);
118508d8c621SMiquel Raynal
118608d8c621SMiquel Raynal static struct platform_driver pl35x_nandc_driver = {
118708d8c621SMiquel Raynal .probe = pl35x_nand_probe,
1188ec185b18SUwe Kleine-König .remove_new = pl35x_nand_remove,
118908d8c621SMiquel Raynal .driver = {
119008d8c621SMiquel Raynal .name = PL35X_NANDC_DRIVER_NAME,
119108d8c621SMiquel Raynal .of_match_table = pl35x_nand_of_match,
119208d8c621SMiquel Raynal },
119308d8c621SMiquel Raynal };
119408d8c621SMiquel Raynal module_platform_driver(pl35x_nandc_driver);
119508d8c621SMiquel Raynal
119608d8c621SMiquel Raynal MODULE_AUTHOR("Xilinx, Inc.");
119708d8c621SMiquel Raynal MODULE_ALIAS("platform:" PL35X_NANDC_DRIVER_NAME);
119808d8c621SMiquel Raynal MODULE_DESCRIPTION("ARM PL35X NAND controller driver");
119908d8c621SMiquel Raynal MODULE_LICENSE("GPL");
1200