xref: /openbmc/linux/drivers/mtd/nand/raw/pl35x-nand-controller.c (revision f6176471542d991137543af2ef1c18dae3286079)
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