162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Evatronix/Renesas R-Car Gen3, RZ/N1D, RZ/N1S, RZ/N1L NAND controller driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2021 Schneider Electric
662306a36Sopenharmony_ci * Author: Miquel RAYNAL <miquel.raynal@bootlin.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bitfield.h>
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/iopoll.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/mtd/mtd.h>
1662306a36Sopenharmony_ci#include <linux/mtd/rawnand.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define COMMAND_REG 0x00
2362306a36Sopenharmony_ci#define   COMMAND_SEQ(x) FIELD_PREP(GENMASK(5, 0), (x))
2462306a36Sopenharmony_ci#define     COMMAND_SEQ_10 COMMAND_SEQ(0x2A)
2562306a36Sopenharmony_ci#define     COMMAND_SEQ_12 COMMAND_SEQ(0x0C)
2662306a36Sopenharmony_ci#define     COMMAND_SEQ_18 COMMAND_SEQ(0x32)
2762306a36Sopenharmony_ci#define     COMMAND_SEQ_19 COMMAND_SEQ(0x13)
2862306a36Sopenharmony_ci#define     COMMAND_SEQ_GEN_IN COMMAND_SEQ_18
2962306a36Sopenharmony_ci#define     COMMAND_SEQ_GEN_OUT COMMAND_SEQ_19
3062306a36Sopenharmony_ci#define     COMMAND_SEQ_READ_PAGE COMMAND_SEQ_10
3162306a36Sopenharmony_ci#define     COMMAND_SEQ_WRITE_PAGE COMMAND_SEQ_12
3262306a36Sopenharmony_ci#define   COMMAND_INPUT_SEL_AHBS 0
3362306a36Sopenharmony_ci#define   COMMAND_INPUT_SEL_DMA BIT(6)
3462306a36Sopenharmony_ci#define   COMMAND_FIFO_SEL 0
3562306a36Sopenharmony_ci#define   COMMAND_DATA_SEL BIT(7)
3662306a36Sopenharmony_ci#define   COMMAND_0(x) FIELD_PREP(GENMASK(15, 8), (x))
3762306a36Sopenharmony_ci#define   COMMAND_1(x) FIELD_PREP(GENMASK(23, 16), (x))
3862306a36Sopenharmony_ci#define   COMMAND_2(x) FIELD_PREP(GENMASK(31, 24), (x))
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define CONTROL_REG 0x04
4162306a36Sopenharmony_ci#define   CONTROL_CHECK_RB_LINE 0
4262306a36Sopenharmony_ci#define   CONTROL_ECC_BLOCK_SIZE(x) FIELD_PREP(GENMASK(2, 1), (x))
4362306a36Sopenharmony_ci#define     CONTROL_ECC_BLOCK_SIZE_256 CONTROL_ECC_BLOCK_SIZE(0)
4462306a36Sopenharmony_ci#define     CONTROL_ECC_BLOCK_SIZE_512 CONTROL_ECC_BLOCK_SIZE(1)
4562306a36Sopenharmony_ci#define     CONTROL_ECC_BLOCK_SIZE_1024 CONTROL_ECC_BLOCK_SIZE(2)
4662306a36Sopenharmony_ci#define   CONTROL_INT_EN BIT(4)
4762306a36Sopenharmony_ci#define   CONTROL_ECC_EN BIT(5)
4862306a36Sopenharmony_ci#define   CONTROL_BLOCK_SIZE(x) FIELD_PREP(GENMASK(7, 6), (x))
4962306a36Sopenharmony_ci#define     CONTROL_BLOCK_SIZE_32P CONTROL_BLOCK_SIZE(0)
5062306a36Sopenharmony_ci#define     CONTROL_BLOCK_SIZE_64P CONTROL_BLOCK_SIZE(1)
5162306a36Sopenharmony_ci#define     CONTROL_BLOCK_SIZE_128P CONTROL_BLOCK_SIZE(2)
5262306a36Sopenharmony_ci#define     CONTROL_BLOCK_SIZE_256P CONTROL_BLOCK_SIZE(3)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define STATUS_REG 0x8
5562306a36Sopenharmony_ci#define   MEM_RDY(cs, reg) (FIELD_GET(GENMASK(3, 0), (reg)) & BIT(cs))
5662306a36Sopenharmony_ci#define   CTRL_RDY(reg) (FIELD_GET(BIT(8), (reg)) == 0)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define ECC_CTRL_REG 0x18
5962306a36Sopenharmony_ci#define   ECC_CTRL_CAP(x) FIELD_PREP(GENMASK(2, 0), (x))
6062306a36Sopenharmony_ci#define     ECC_CTRL_CAP_2B ECC_CTRL_CAP(0)
6162306a36Sopenharmony_ci#define     ECC_CTRL_CAP_4B ECC_CTRL_CAP(1)
6262306a36Sopenharmony_ci#define     ECC_CTRL_CAP_8B ECC_CTRL_CAP(2)
6362306a36Sopenharmony_ci#define     ECC_CTRL_CAP_16B ECC_CTRL_CAP(3)
6462306a36Sopenharmony_ci#define     ECC_CTRL_CAP_24B ECC_CTRL_CAP(4)
6562306a36Sopenharmony_ci#define     ECC_CTRL_CAP_32B ECC_CTRL_CAP(5)
6662306a36Sopenharmony_ci#define   ECC_CTRL_ERR_THRESHOLD(x) FIELD_PREP(GENMASK(13, 8), (x))
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define INT_MASK_REG 0x10
6962306a36Sopenharmony_ci#define INT_STATUS_REG 0x14
7062306a36Sopenharmony_ci#define   INT_CMD_END BIT(1)
7162306a36Sopenharmony_ci#define   INT_DMA_END BIT(3)
7262306a36Sopenharmony_ci#define   INT_MEM_RDY(cs) FIELD_PREP(GENMASK(11, 8), BIT(cs))
7362306a36Sopenharmony_ci#define   INT_DMA_ENDED BIT(3)
7462306a36Sopenharmony_ci#define   MEM_IS_RDY(cs, reg) (FIELD_GET(GENMASK(11, 8), (reg)) & BIT(cs))
7562306a36Sopenharmony_ci#define   DMA_HAS_ENDED(reg) FIELD_GET(BIT(3), (reg))
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define ECC_OFFSET_REG 0x1C
7862306a36Sopenharmony_ci#define   ECC_OFFSET(x) FIELD_PREP(GENMASK(15, 0), (x))
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#define ECC_STAT_REG 0x20
8162306a36Sopenharmony_ci#define   ECC_STAT_CORRECTABLE(cs, reg) (FIELD_GET(GENMASK(3, 0), (reg)) & BIT(cs))
8262306a36Sopenharmony_ci#define   ECC_STAT_UNCORRECTABLE(cs, reg) (FIELD_GET(GENMASK(11, 8), (reg)) & BIT(cs))
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define ADDR0_COL_REG 0x24
8562306a36Sopenharmony_ci#define   ADDR0_COL(x) FIELD_PREP(GENMASK(15, 0), (x))
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#define ADDR0_ROW_REG 0x28
8862306a36Sopenharmony_ci#define   ADDR0_ROW(x) FIELD_PREP(GENMASK(23, 0), (x))
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define ADDR1_COL_REG 0x2C
9162306a36Sopenharmony_ci#define   ADDR1_COL(x) FIELD_PREP(GENMASK(15, 0), (x))
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define ADDR1_ROW_REG 0x30
9462306a36Sopenharmony_ci#define   ADDR1_ROW(x) FIELD_PREP(GENMASK(23, 0), (x))
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define FIFO_DATA_REG 0x38
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define DATA_REG 0x3C
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define DATA_REG_SIZE_REG 0x40
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci#define DMA_ADDR_LOW_REG 0x64
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define DMA_ADDR_HIGH_REG 0x68
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define DMA_CNT_REG 0x6C
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define DMA_CTRL_REG 0x70
10962306a36Sopenharmony_ci#define   DMA_CTRL_INCREMENT_BURST_4 0
11062306a36Sopenharmony_ci#define   DMA_CTRL_REGISTER_MANAGED_MODE 0
11162306a36Sopenharmony_ci#define   DMA_CTRL_START BIT(7)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define MEM_CTRL_REG 0x80
11462306a36Sopenharmony_ci#define   MEM_CTRL_CS(cs) FIELD_PREP(GENMASK(1, 0), (cs))
11562306a36Sopenharmony_ci#define   MEM_CTRL_DIS_WP(cs) FIELD_PREP(GENMASK(11, 8), BIT((cs)))
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define DATA_SIZE_REG 0x84
11862306a36Sopenharmony_ci#define   DATA_SIZE(x) FIELD_PREP(GENMASK(14, 0), (x))
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define TIMINGS_ASYN_REG 0x88
12162306a36Sopenharmony_ci#define   TIMINGS_ASYN_TRWP(x) FIELD_PREP(GENMASK(3, 0), max((x), 1U) - 1)
12262306a36Sopenharmony_ci#define   TIMINGS_ASYN_TRWH(x) FIELD_PREP(GENMASK(7, 4), max((x), 1U) - 1)
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define TIM_SEQ0_REG 0x90
12562306a36Sopenharmony_ci#define   TIM_SEQ0_TCCS(x) FIELD_PREP(GENMASK(5, 0), max((x), 1U) - 1)
12662306a36Sopenharmony_ci#define   TIM_SEQ0_TADL(x) FIELD_PREP(GENMASK(13, 8), max((x), 1U) - 1)
12762306a36Sopenharmony_ci#define   TIM_SEQ0_TRHW(x) FIELD_PREP(GENMASK(21, 16), max((x), 1U) - 1)
12862306a36Sopenharmony_ci#define   TIM_SEQ0_TWHR(x) FIELD_PREP(GENMASK(29, 24), max((x), 1U) - 1)
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#define TIM_SEQ1_REG 0x94
13162306a36Sopenharmony_ci#define   TIM_SEQ1_TWB(x) FIELD_PREP(GENMASK(5, 0), max((x), 1U) - 1)
13262306a36Sopenharmony_ci#define   TIM_SEQ1_TRR(x) FIELD_PREP(GENMASK(13, 8), max((x), 1U) - 1)
13362306a36Sopenharmony_ci#define   TIM_SEQ1_TWW(x) FIELD_PREP(GENMASK(21, 16), max((x), 1U) - 1)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define TIM_GEN_SEQ0_REG 0x98
13662306a36Sopenharmony_ci#define   TIM_GEN_SEQ0_D0(x) FIELD_PREP(GENMASK(5, 0), max((x), 1U) - 1)
13762306a36Sopenharmony_ci#define   TIM_GEN_SEQ0_D1(x) FIELD_PREP(GENMASK(13, 8), max((x), 1U) - 1)
13862306a36Sopenharmony_ci#define   TIM_GEN_SEQ0_D2(x) FIELD_PREP(GENMASK(21, 16), max((x), 1U) - 1)
13962306a36Sopenharmony_ci#define   TIM_GEN_SEQ0_D3(x) FIELD_PREP(GENMASK(29, 24), max((x), 1U) - 1)
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#define TIM_GEN_SEQ1_REG 0x9c
14262306a36Sopenharmony_ci#define   TIM_GEN_SEQ1_D4(x) FIELD_PREP(GENMASK(5, 0), max((x), 1U) - 1)
14362306a36Sopenharmony_ci#define   TIM_GEN_SEQ1_D5(x) FIELD_PREP(GENMASK(13, 8), max((x), 1U) - 1)
14462306a36Sopenharmony_ci#define   TIM_GEN_SEQ1_D6(x) FIELD_PREP(GENMASK(21, 16), max((x), 1U) - 1)
14562306a36Sopenharmony_ci#define   TIM_GEN_SEQ1_D7(x) FIELD_PREP(GENMASK(29, 24), max((x), 1U) - 1)
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#define TIM_GEN_SEQ2_REG 0xA0
14862306a36Sopenharmony_ci#define   TIM_GEN_SEQ2_D8(x) FIELD_PREP(GENMASK(5, 0), max((x), 1U) - 1)
14962306a36Sopenharmony_ci#define   TIM_GEN_SEQ2_D9(x) FIELD_PREP(GENMASK(13, 8), max((x), 1U) - 1)
15062306a36Sopenharmony_ci#define   TIM_GEN_SEQ2_D10(x) FIELD_PREP(GENMASK(21, 16), max((x), 1U) - 1)
15162306a36Sopenharmony_ci#define   TIM_GEN_SEQ2_D11(x) FIELD_PREP(GENMASK(29, 24), max((x), 1U) - 1)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define FIFO_INIT_REG 0xB4
15462306a36Sopenharmony_ci#define   FIFO_INIT BIT(0)
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define FIFO_STATE_REG 0xB4
15762306a36Sopenharmony_ci#define   FIFO_STATE_R_EMPTY(reg) FIELD_GET(BIT(0), (reg))
15862306a36Sopenharmony_ci#define   FIFO_STATE_W_FULL(reg) FIELD_GET(BIT(1), (reg))
15962306a36Sopenharmony_ci#define   FIFO_STATE_C_EMPTY(reg) FIELD_GET(BIT(2), (reg))
16062306a36Sopenharmony_ci#define   FIFO_STATE_R_FULL(reg) FIELD_GET(BIT(6), (reg))
16162306a36Sopenharmony_ci#define   FIFO_STATE_W_EMPTY(reg) FIELD_GET(BIT(7), (reg))
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci#define GEN_SEQ_CTRL_REG 0xB8
16462306a36Sopenharmony_ci#define   GEN_SEQ_CMD0_EN BIT(0)
16562306a36Sopenharmony_ci#define   GEN_SEQ_CMD1_EN BIT(1)
16662306a36Sopenharmony_ci#define   GEN_SEQ_CMD2_EN BIT(2)
16762306a36Sopenharmony_ci#define   GEN_SEQ_CMD3_EN BIT(3)
16862306a36Sopenharmony_ci#define   GEN_SEQ_COL_A0(x) FIELD_PREP(GENMASK(5, 4), min((x), 2U))
16962306a36Sopenharmony_ci#define   GEN_SEQ_COL_A1(x) FIELD_PREP(GENMASK(7, 6), min((x), 2U))
17062306a36Sopenharmony_ci#define   GEN_SEQ_ROW_A0(x) FIELD_PREP(GENMASK(9, 8), min((x), 3U))
17162306a36Sopenharmony_ci#define   GEN_SEQ_ROW_A1(x) FIELD_PREP(GENMASK(11, 10), min((x), 3U))
17262306a36Sopenharmony_ci#define   GEN_SEQ_DATA_EN BIT(12)
17362306a36Sopenharmony_ci#define   GEN_SEQ_DELAY_EN(x) FIELD_PREP(GENMASK(14, 13), (x))
17462306a36Sopenharmony_ci#define     GEN_SEQ_DELAY0_EN GEN_SEQ_DELAY_EN(1)
17562306a36Sopenharmony_ci#define     GEN_SEQ_DELAY1_EN GEN_SEQ_DELAY_EN(2)
17662306a36Sopenharmony_ci#define   GEN_SEQ_IMD_SEQ BIT(15)
17762306a36Sopenharmony_ci#define   GEN_SEQ_COMMAND_3(x) FIELD_PREP(GENMASK(26, 16), (x))
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci#define DMA_TLVL_REG 0x114
18062306a36Sopenharmony_ci#define   DMA_TLVL(x) FIELD_PREP(GENMASK(7, 0), (x))
18162306a36Sopenharmony_ci#define   DMA_TLVL_MAX DMA_TLVL(0xFF)
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define TIM_GEN_SEQ3_REG 0x134
18462306a36Sopenharmony_ci#define   TIM_GEN_SEQ3_D12(x) FIELD_PREP(GENMASK(5, 0), max((x), 1U) - 1)
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci#define ECC_CNT_REG 0x14C
18762306a36Sopenharmony_ci#define   ECC_CNT(cs, reg) FIELD_GET(GENMASK(5, 0), (reg) >> ((cs) * 8))
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci#define RNANDC_CS_NUM 4
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci#define TO_CYCLES64(ps, period_ns) ((unsigned int)DIV_ROUND_UP_ULL(div_u64(ps, 1000), \
19262306a36Sopenharmony_ci								   period_ns))
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistruct rnand_chip_sel {
19562306a36Sopenharmony_ci	unsigned int cs;
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistruct rnand_chip {
19962306a36Sopenharmony_ci	struct nand_chip chip;
20062306a36Sopenharmony_ci	struct list_head node;
20162306a36Sopenharmony_ci	int selected_die;
20262306a36Sopenharmony_ci	u32 ctrl;
20362306a36Sopenharmony_ci	unsigned int nsels;
20462306a36Sopenharmony_ci	u32 control;
20562306a36Sopenharmony_ci	u32 ecc_ctrl;
20662306a36Sopenharmony_ci	u32 timings_asyn;
20762306a36Sopenharmony_ci	u32 tim_seq0;
20862306a36Sopenharmony_ci	u32 tim_seq1;
20962306a36Sopenharmony_ci	u32 tim_gen_seq0;
21062306a36Sopenharmony_ci	u32 tim_gen_seq1;
21162306a36Sopenharmony_ci	u32 tim_gen_seq2;
21262306a36Sopenharmony_ci	u32 tim_gen_seq3;
21362306a36Sopenharmony_ci	struct rnand_chip_sel sels[];
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistruct rnandc {
21762306a36Sopenharmony_ci	struct nand_controller controller;
21862306a36Sopenharmony_ci	struct device *dev;
21962306a36Sopenharmony_ci	void __iomem *regs;
22062306a36Sopenharmony_ci	unsigned long ext_clk_rate;
22162306a36Sopenharmony_ci	unsigned long assigned_cs;
22262306a36Sopenharmony_ci	struct list_head chips;
22362306a36Sopenharmony_ci	struct nand_chip *selected_chip;
22462306a36Sopenharmony_ci	struct completion complete;
22562306a36Sopenharmony_ci	bool use_polling;
22662306a36Sopenharmony_ci	u8 *buf;
22762306a36Sopenharmony_ci	unsigned int buf_sz;
22862306a36Sopenharmony_ci};
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistruct rnandc_op {
23162306a36Sopenharmony_ci	u32 command;
23262306a36Sopenharmony_ci	u32 addr0_col;
23362306a36Sopenharmony_ci	u32 addr0_row;
23462306a36Sopenharmony_ci	u32 addr1_col;
23562306a36Sopenharmony_ci	u32 addr1_row;
23662306a36Sopenharmony_ci	u32 data_size;
23762306a36Sopenharmony_ci	u32 ecc_offset;
23862306a36Sopenharmony_ci	u32 gen_seq_ctrl;
23962306a36Sopenharmony_ci	u8 *buf;
24062306a36Sopenharmony_ci	bool read;
24162306a36Sopenharmony_ci	unsigned int len;
24262306a36Sopenharmony_ci};
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic inline struct rnandc *to_rnandc(struct nand_controller *ctrl)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	return container_of(ctrl, struct rnandc, controller);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic inline struct rnand_chip *to_rnand(struct nand_chip *chip)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return container_of(chip, struct rnand_chip, chip);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic inline unsigned int to_rnandc_cs(struct rnand_chip *nand)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	return nand->sels[nand->selected_die].cs;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic void rnandc_dis_correction(struct rnandc *rnandc)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	u32 control;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	control = readl_relaxed(rnandc->regs + CONTROL_REG);
26462306a36Sopenharmony_ci	control &= ~CONTROL_ECC_EN;
26562306a36Sopenharmony_ci	writel_relaxed(control, rnandc->regs + CONTROL_REG);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic void rnandc_en_correction(struct rnandc *rnandc)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	u32 control;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	control = readl_relaxed(rnandc->regs + CONTROL_REG);
27362306a36Sopenharmony_ci	control |= CONTROL_ECC_EN;
27462306a36Sopenharmony_ci	writel_relaxed(control, rnandc->regs + CONTROL_REG);
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void rnandc_clear_status(struct rnandc *rnandc)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	writel_relaxed(0, rnandc->regs + INT_STATUS_REG);
28062306a36Sopenharmony_ci	writel_relaxed(0, rnandc->regs + ECC_STAT_REG);
28162306a36Sopenharmony_ci	writel_relaxed(0, rnandc->regs + ECC_CNT_REG);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic void rnandc_dis_interrupts(struct rnandc *rnandc)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	writel_relaxed(0, rnandc->regs + INT_MASK_REG);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic void rnandc_en_interrupts(struct rnandc *rnandc, u32 val)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	if (!rnandc->use_polling)
29262306a36Sopenharmony_ci		writel_relaxed(val, rnandc->regs + INT_MASK_REG);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic void rnandc_clear_fifo(struct rnandc *rnandc)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	writel_relaxed(FIFO_INIT, rnandc->regs + FIFO_INIT_REG);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic void rnandc_select_target(struct nand_chip *chip, int die_nr)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct rnand_chip *rnand = to_rnand(chip);
30362306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
30462306a36Sopenharmony_ci	unsigned int cs = rnand->sels[die_nr].cs;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (chip == rnandc->selected_chip && die_nr == rnand->selected_die)
30762306a36Sopenharmony_ci		return;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	rnandc_clear_status(rnandc);
31062306a36Sopenharmony_ci	writel_relaxed(MEM_CTRL_CS(cs) | MEM_CTRL_DIS_WP(cs), rnandc->regs + MEM_CTRL_REG);
31162306a36Sopenharmony_ci	writel_relaxed(rnand->control, rnandc->regs + CONTROL_REG);
31262306a36Sopenharmony_ci	writel_relaxed(rnand->ecc_ctrl, rnandc->regs + ECC_CTRL_REG);
31362306a36Sopenharmony_ci	writel_relaxed(rnand->timings_asyn, rnandc->regs + TIMINGS_ASYN_REG);
31462306a36Sopenharmony_ci	writel_relaxed(rnand->tim_seq0, rnandc->regs + TIM_SEQ0_REG);
31562306a36Sopenharmony_ci	writel_relaxed(rnand->tim_seq1, rnandc->regs + TIM_SEQ1_REG);
31662306a36Sopenharmony_ci	writel_relaxed(rnand->tim_gen_seq0, rnandc->regs + TIM_GEN_SEQ0_REG);
31762306a36Sopenharmony_ci	writel_relaxed(rnand->tim_gen_seq1, rnandc->regs + TIM_GEN_SEQ1_REG);
31862306a36Sopenharmony_ci	writel_relaxed(rnand->tim_gen_seq2, rnandc->regs + TIM_GEN_SEQ2_REG);
31962306a36Sopenharmony_ci	writel_relaxed(rnand->tim_gen_seq3, rnandc->regs + TIM_GEN_SEQ3_REG);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	rnandc->selected_chip = chip;
32262306a36Sopenharmony_ci	rnand->selected_die = die_nr;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic void rnandc_trigger_op(struct rnandc *rnandc, struct rnandc_op *rop)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	writel_relaxed(rop->addr0_col, rnandc->regs + ADDR0_COL_REG);
32862306a36Sopenharmony_ci	writel_relaxed(rop->addr0_row, rnandc->regs + ADDR0_ROW_REG);
32962306a36Sopenharmony_ci	writel_relaxed(rop->addr1_col, rnandc->regs + ADDR1_COL_REG);
33062306a36Sopenharmony_ci	writel_relaxed(rop->addr1_row, rnandc->regs + ADDR1_ROW_REG);
33162306a36Sopenharmony_ci	writel_relaxed(rop->ecc_offset, rnandc->regs + ECC_OFFSET_REG);
33262306a36Sopenharmony_ci	writel_relaxed(rop->gen_seq_ctrl, rnandc->regs + GEN_SEQ_CTRL_REG);
33362306a36Sopenharmony_ci	writel_relaxed(DATA_SIZE(rop->len), rnandc->regs + DATA_SIZE_REG);
33462306a36Sopenharmony_ci	writel_relaxed(rop->command, rnandc->regs + COMMAND_REG);
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic void rnandc_trigger_dma(struct rnandc *rnandc)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	writel_relaxed(DMA_CTRL_INCREMENT_BURST_4 |
34062306a36Sopenharmony_ci		       DMA_CTRL_REGISTER_MANAGED_MODE |
34162306a36Sopenharmony_ci		       DMA_CTRL_START, rnandc->regs + DMA_CTRL_REG);
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic irqreturn_t rnandc_irq_handler(int irq, void *private)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct rnandc *rnandc = private;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	rnandc_dis_interrupts(rnandc);
34962306a36Sopenharmony_ci	complete(&rnandc->complete);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return IRQ_HANDLED;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic int rnandc_wait_end_of_op(struct rnandc *rnandc,
35562306a36Sopenharmony_ci				 struct nand_chip *chip)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct rnand_chip *rnand = to_rnand(chip);
35862306a36Sopenharmony_ci	unsigned int cs = to_rnandc_cs(rnand);
35962306a36Sopenharmony_ci	u32 status;
36062306a36Sopenharmony_ci	int ret;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	ret = readl_poll_timeout(rnandc->regs + STATUS_REG, status,
36362306a36Sopenharmony_ci				 MEM_RDY(cs, status) && CTRL_RDY(status),
36462306a36Sopenharmony_ci				 1, 100000);
36562306a36Sopenharmony_ci	if (ret)
36662306a36Sopenharmony_ci		dev_err(rnandc->dev, "Operation timed out, status: 0x%08x\n",
36762306a36Sopenharmony_ci			status);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	return ret;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int rnandc_wait_end_of_io(struct rnandc *rnandc,
37362306a36Sopenharmony_ci				 struct nand_chip *chip)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	int timeout_ms = 1000;
37662306a36Sopenharmony_ci	int ret;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (rnandc->use_polling) {
37962306a36Sopenharmony_ci		struct rnand_chip *rnand = to_rnand(chip);
38062306a36Sopenharmony_ci		unsigned int cs = to_rnandc_cs(rnand);
38162306a36Sopenharmony_ci		u32 status;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		ret = readl_poll_timeout(rnandc->regs + INT_STATUS_REG, status,
38462306a36Sopenharmony_ci					 MEM_IS_RDY(cs, status) &
38562306a36Sopenharmony_ci					 DMA_HAS_ENDED(status),
38662306a36Sopenharmony_ci					 0, timeout_ms * 1000);
38762306a36Sopenharmony_ci	} else {
38862306a36Sopenharmony_ci		ret = wait_for_completion_timeout(&rnandc->complete,
38962306a36Sopenharmony_ci						  msecs_to_jiffies(timeout_ms));
39062306a36Sopenharmony_ci		if (!ret)
39162306a36Sopenharmony_ci			ret = -ETIMEDOUT;
39262306a36Sopenharmony_ci		else
39362306a36Sopenharmony_ci			ret = 0;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return ret;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic int rnandc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
40062306a36Sopenharmony_ci				   int oob_required, int page)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
40362306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
40462306a36Sopenharmony_ci	struct rnand_chip *rnand = to_rnand(chip);
40562306a36Sopenharmony_ci	unsigned int cs = to_rnandc_cs(rnand);
40662306a36Sopenharmony_ci	struct rnandc_op rop = {
40762306a36Sopenharmony_ci		.command = COMMAND_INPUT_SEL_DMA | COMMAND_0(NAND_CMD_READ0) |
40862306a36Sopenharmony_ci			   COMMAND_2(NAND_CMD_READSTART) | COMMAND_FIFO_SEL |
40962306a36Sopenharmony_ci			   COMMAND_SEQ_READ_PAGE,
41062306a36Sopenharmony_ci		.addr0_row = page,
41162306a36Sopenharmony_ci		.len = mtd->writesize,
41262306a36Sopenharmony_ci		.ecc_offset = ECC_OFFSET(mtd->writesize + 2),
41362306a36Sopenharmony_ci	};
41462306a36Sopenharmony_ci	unsigned int max_bitflips = 0;
41562306a36Sopenharmony_ci	dma_addr_t dma_addr;
41662306a36Sopenharmony_ci	u32 ecc_stat;
41762306a36Sopenharmony_ci	int bf, ret, i;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/* Prepare controller */
42062306a36Sopenharmony_ci	rnandc_select_target(chip, chip->cur_cs);
42162306a36Sopenharmony_ci	rnandc_clear_status(rnandc);
42262306a36Sopenharmony_ci	reinit_completion(&rnandc->complete);
42362306a36Sopenharmony_ci	rnandc_en_interrupts(rnandc, INT_DMA_ENDED);
42462306a36Sopenharmony_ci	rnandc_en_correction(rnandc);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* Configure DMA */
42762306a36Sopenharmony_ci	dma_addr = dma_map_single(rnandc->dev, rnandc->buf, mtd->writesize,
42862306a36Sopenharmony_ci				  DMA_FROM_DEVICE);
42962306a36Sopenharmony_ci	writel(dma_addr, rnandc->regs + DMA_ADDR_LOW_REG);
43062306a36Sopenharmony_ci	writel(mtd->writesize, rnandc->regs + DMA_CNT_REG);
43162306a36Sopenharmony_ci	writel(DMA_TLVL_MAX, rnandc->regs + DMA_TLVL_REG);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	rnandc_trigger_op(rnandc, &rop);
43462306a36Sopenharmony_ci	rnandc_trigger_dma(rnandc);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	ret = rnandc_wait_end_of_io(rnandc, chip);
43762306a36Sopenharmony_ci	dma_unmap_single(rnandc->dev, dma_addr, mtd->writesize, DMA_FROM_DEVICE);
43862306a36Sopenharmony_ci	rnandc_dis_correction(rnandc);
43962306a36Sopenharmony_ci	if (ret) {
44062306a36Sopenharmony_ci		dev_err(rnandc->dev, "Read page operation never ending\n");
44162306a36Sopenharmony_ci		return ret;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	ecc_stat = readl_relaxed(rnandc->regs + ECC_STAT_REG);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if (oob_required || ECC_STAT_UNCORRECTABLE(cs, ecc_stat)) {
44762306a36Sopenharmony_ci		ret = nand_change_read_column_op(chip, mtd->writesize,
44862306a36Sopenharmony_ci						 chip->oob_poi, mtd->oobsize,
44962306a36Sopenharmony_ci						 false);
45062306a36Sopenharmony_ci		if (ret)
45162306a36Sopenharmony_ci			return ret;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (ECC_STAT_UNCORRECTABLE(cs, ecc_stat)) {
45562306a36Sopenharmony_ci		for (i = 0; i < chip->ecc.steps; i++) {
45662306a36Sopenharmony_ci			unsigned int off = i * chip->ecc.size;
45762306a36Sopenharmony_ci			unsigned int eccoff = i * chip->ecc.bytes;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci			bf = nand_check_erased_ecc_chunk(rnandc->buf + off,
46062306a36Sopenharmony_ci							 chip->ecc.size,
46162306a36Sopenharmony_ci							 chip->oob_poi + 2 + eccoff,
46262306a36Sopenharmony_ci							 chip->ecc.bytes,
46362306a36Sopenharmony_ci							 NULL, 0,
46462306a36Sopenharmony_ci							 chip->ecc.strength);
46562306a36Sopenharmony_ci			if (bf < 0) {
46662306a36Sopenharmony_ci				mtd->ecc_stats.failed++;
46762306a36Sopenharmony_ci			} else {
46862306a36Sopenharmony_ci				mtd->ecc_stats.corrected += bf;
46962306a36Sopenharmony_ci				max_bitflips = max_t(unsigned int, max_bitflips, bf);
47062306a36Sopenharmony_ci			}
47162306a36Sopenharmony_ci		}
47262306a36Sopenharmony_ci	} else if (ECC_STAT_CORRECTABLE(cs, ecc_stat)) {
47362306a36Sopenharmony_ci		bf = ECC_CNT(cs, readl_relaxed(rnandc->regs + ECC_CNT_REG));
47462306a36Sopenharmony_ci		/*
47562306a36Sopenharmony_ci		 * The number of bitflips is an approximation given the fact
47662306a36Sopenharmony_ci		 * that this controller does not provide per-chunk details but
47762306a36Sopenharmony_ci		 * only gives statistics on the entire page.
47862306a36Sopenharmony_ci		 */
47962306a36Sopenharmony_ci		mtd->ecc_stats.corrected += bf;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	memcpy(buf, rnandc->buf, mtd->writesize);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	return 0;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic int rnandc_read_subpage_hw_ecc(struct nand_chip *chip, u32 req_offset,
48862306a36Sopenharmony_ci				      u32 req_len, u8 *bufpoi, int page)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
49162306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
49262306a36Sopenharmony_ci	struct rnand_chip *rnand = to_rnand(chip);
49362306a36Sopenharmony_ci	unsigned int cs = to_rnandc_cs(rnand);
49462306a36Sopenharmony_ci	unsigned int page_off = round_down(req_offset, chip->ecc.size);
49562306a36Sopenharmony_ci	unsigned int real_len = round_up(req_offset + req_len - page_off,
49662306a36Sopenharmony_ci					 chip->ecc.size);
49762306a36Sopenharmony_ci	unsigned int start_chunk = page_off / chip->ecc.size;
49862306a36Sopenharmony_ci	unsigned int nchunks = real_len / chip->ecc.size;
49962306a36Sopenharmony_ci	unsigned int ecc_off = 2 + (start_chunk * chip->ecc.bytes);
50062306a36Sopenharmony_ci	struct rnandc_op rop = {
50162306a36Sopenharmony_ci		.command = COMMAND_INPUT_SEL_AHBS | COMMAND_0(NAND_CMD_READ0) |
50262306a36Sopenharmony_ci			   COMMAND_2(NAND_CMD_READSTART) | COMMAND_FIFO_SEL |
50362306a36Sopenharmony_ci			   COMMAND_SEQ_READ_PAGE,
50462306a36Sopenharmony_ci		.addr0_row = page,
50562306a36Sopenharmony_ci		.addr0_col = page_off,
50662306a36Sopenharmony_ci		.len = real_len,
50762306a36Sopenharmony_ci		.ecc_offset = ECC_OFFSET(mtd->writesize + ecc_off),
50862306a36Sopenharmony_ci	};
50962306a36Sopenharmony_ci	unsigned int max_bitflips = 0, i;
51062306a36Sopenharmony_ci	u32 ecc_stat;
51162306a36Sopenharmony_ci	int bf, ret;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/* Prepare controller */
51462306a36Sopenharmony_ci	rnandc_select_target(chip, chip->cur_cs);
51562306a36Sopenharmony_ci	rnandc_clear_status(rnandc);
51662306a36Sopenharmony_ci	rnandc_en_correction(rnandc);
51762306a36Sopenharmony_ci	rnandc_trigger_op(rnandc, &rop);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	while (!FIFO_STATE_C_EMPTY(readl(rnandc->regs + FIFO_STATE_REG)))
52062306a36Sopenharmony_ci		cpu_relax();
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	while (FIFO_STATE_R_EMPTY(readl(rnandc->regs + FIFO_STATE_REG)))
52362306a36Sopenharmony_ci		cpu_relax();
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	ioread32_rep(rnandc->regs + FIFO_DATA_REG, bufpoi + page_off,
52662306a36Sopenharmony_ci		     real_len / 4);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (!FIFO_STATE_R_EMPTY(readl(rnandc->regs + FIFO_STATE_REG))) {
52962306a36Sopenharmony_ci		dev_err(rnandc->dev, "Clearing residual data in the read FIFO\n");
53062306a36Sopenharmony_ci		rnandc_clear_fifo(rnandc);
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	ret = rnandc_wait_end_of_op(rnandc, chip);
53462306a36Sopenharmony_ci	rnandc_dis_correction(rnandc);
53562306a36Sopenharmony_ci	if (ret) {
53662306a36Sopenharmony_ci		dev_err(rnandc->dev, "Read subpage operation never ending\n");
53762306a36Sopenharmony_ci		return ret;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	ecc_stat = readl_relaxed(rnandc->regs + ECC_STAT_REG);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (ECC_STAT_UNCORRECTABLE(cs, ecc_stat)) {
54362306a36Sopenharmony_ci		ret = nand_change_read_column_op(chip, mtd->writesize,
54462306a36Sopenharmony_ci						 chip->oob_poi, mtd->oobsize,
54562306a36Sopenharmony_ci						 false);
54662306a36Sopenharmony_ci		if (ret)
54762306a36Sopenharmony_ci			return ret;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		for (i = start_chunk; i < nchunks; i++) {
55062306a36Sopenharmony_ci			unsigned int dataoff = i * chip->ecc.size;
55162306a36Sopenharmony_ci			unsigned int eccoff = 2 + (i * chip->ecc.bytes);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci			bf = nand_check_erased_ecc_chunk(bufpoi + dataoff,
55462306a36Sopenharmony_ci							 chip->ecc.size,
55562306a36Sopenharmony_ci							 chip->oob_poi + eccoff,
55662306a36Sopenharmony_ci							 chip->ecc.bytes,
55762306a36Sopenharmony_ci							 NULL, 0,
55862306a36Sopenharmony_ci							 chip->ecc.strength);
55962306a36Sopenharmony_ci			if (bf < 0) {
56062306a36Sopenharmony_ci				mtd->ecc_stats.failed++;
56162306a36Sopenharmony_ci			} else {
56262306a36Sopenharmony_ci				mtd->ecc_stats.corrected += bf;
56362306a36Sopenharmony_ci				max_bitflips = max_t(unsigned int, max_bitflips, bf);
56462306a36Sopenharmony_ci			}
56562306a36Sopenharmony_ci		}
56662306a36Sopenharmony_ci	} else if (ECC_STAT_CORRECTABLE(cs, ecc_stat)) {
56762306a36Sopenharmony_ci		bf = ECC_CNT(cs, readl_relaxed(rnandc->regs + ECC_CNT_REG));
56862306a36Sopenharmony_ci		/*
56962306a36Sopenharmony_ci		 * The number of bitflips is an approximation given the fact
57062306a36Sopenharmony_ci		 * that this controller does not provide per-chunk details but
57162306a36Sopenharmony_ci		 * only gives statistics on the entire page.
57262306a36Sopenharmony_ci		 */
57362306a36Sopenharmony_ci		mtd->ecc_stats.corrected += bf;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	return 0;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic int rnandc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
58062306a36Sopenharmony_ci				    int oob_required, int page)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
58362306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
58462306a36Sopenharmony_ci	struct rnand_chip *rnand = to_rnand(chip);
58562306a36Sopenharmony_ci	unsigned int cs = to_rnandc_cs(rnand);
58662306a36Sopenharmony_ci	struct rnandc_op rop = {
58762306a36Sopenharmony_ci		.command = COMMAND_INPUT_SEL_DMA | COMMAND_0(NAND_CMD_SEQIN) |
58862306a36Sopenharmony_ci			   COMMAND_1(NAND_CMD_PAGEPROG) | COMMAND_FIFO_SEL |
58962306a36Sopenharmony_ci			   COMMAND_SEQ_WRITE_PAGE,
59062306a36Sopenharmony_ci		.addr0_row = page,
59162306a36Sopenharmony_ci		.len = mtd->writesize,
59262306a36Sopenharmony_ci		.ecc_offset = ECC_OFFSET(mtd->writesize + 2),
59362306a36Sopenharmony_ci	};
59462306a36Sopenharmony_ci	dma_addr_t dma_addr;
59562306a36Sopenharmony_ci	int ret;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	memcpy(rnandc->buf, buf, mtd->writesize);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* Prepare controller */
60062306a36Sopenharmony_ci	rnandc_select_target(chip, chip->cur_cs);
60162306a36Sopenharmony_ci	rnandc_clear_status(rnandc);
60262306a36Sopenharmony_ci	reinit_completion(&rnandc->complete);
60362306a36Sopenharmony_ci	rnandc_en_interrupts(rnandc, INT_MEM_RDY(cs));
60462306a36Sopenharmony_ci	rnandc_en_correction(rnandc);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	/* Configure DMA */
60762306a36Sopenharmony_ci	dma_addr = dma_map_single(rnandc->dev, (void *)rnandc->buf, mtd->writesize,
60862306a36Sopenharmony_ci				  DMA_TO_DEVICE);
60962306a36Sopenharmony_ci	writel(dma_addr, rnandc->regs + DMA_ADDR_LOW_REG);
61062306a36Sopenharmony_ci	writel(mtd->writesize, rnandc->regs + DMA_CNT_REG);
61162306a36Sopenharmony_ci	writel(DMA_TLVL_MAX, rnandc->regs + DMA_TLVL_REG);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	rnandc_trigger_op(rnandc, &rop);
61462306a36Sopenharmony_ci	rnandc_trigger_dma(rnandc);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	ret = rnandc_wait_end_of_io(rnandc, chip);
61762306a36Sopenharmony_ci	dma_unmap_single(rnandc->dev, dma_addr, mtd->writesize, DMA_TO_DEVICE);
61862306a36Sopenharmony_ci	rnandc_dis_correction(rnandc);
61962306a36Sopenharmony_ci	if (ret) {
62062306a36Sopenharmony_ci		dev_err(rnandc->dev, "Write page operation never ending\n");
62162306a36Sopenharmony_ci		return ret;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (!oob_required)
62562306a36Sopenharmony_ci		return 0;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	return nand_change_write_column_op(chip, mtd->writesize, chip->oob_poi,
62862306a36Sopenharmony_ci					   mtd->oobsize, false);
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic int rnandc_write_subpage_hw_ecc(struct nand_chip *chip, u32 req_offset,
63262306a36Sopenharmony_ci				       u32 req_len, const u8 *bufpoi,
63362306a36Sopenharmony_ci				       int oob_required, int page)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
63662306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
63762306a36Sopenharmony_ci	unsigned int page_off = round_down(req_offset, chip->ecc.size);
63862306a36Sopenharmony_ci	unsigned int real_len = round_up(req_offset + req_len - page_off,
63962306a36Sopenharmony_ci					 chip->ecc.size);
64062306a36Sopenharmony_ci	unsigned int start_chunk = page_off / chip->ecc.size;
64162306a36Sopenharmony_ci	unsigned int ecc_off = 2 + (start_chunk * chip->ecc.bytes);
64262306a36Sopenharmony_ci	struct rnandc_op rop = {
64362306a36Sopenharmony_ci		.command = COMMAND_INPUT_SEL_AHBS | COMMAND_0(NAND_CMD_SEQIN) |
64462306a36Sopenharmony_ci			   COMMAND_1(NAND_CMD_PAGEPROG) | COMMAND_FIFO_SEL |
64562306a36Sopenharmony_ci			   COMMAND_SEQ_WRITE_PAGE,
64662306a36Sopenharmony_ci		.addr0_row = page,
64762306a36Sopenharmony_ci		.addr0_col = page_off,
64862306a36Sopenharmony_ci		.len = real_len,
64962306a36Sopenharmony_ci		.ecc_offset = ECC_OFFSET(mtd->writesize + ecc_off),
65062306a36Sopenharmony_ci	};
65162306a36Sopenharmony_ci	int ret;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* Prepare controller */
65462306a36Sopenharmony_ci	rnandc_select_target(chip, chip->cur_cs);
65562306a36Sopenharmony_ci	rnandc_clear_status(rnandc);
65662306a36Sopenharmony_ci	rnandc_en_correction(rnandc);
65762306a36Sopenharmony_ci	rnandc_trigger_op(rnandc, &rop);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	while (FIFO_STATE_W_FULL(readl(rnandc->regs + FIFO_STATE_REG)))
66062306a36Sopenharmony_ci		cpu_relax();
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	iowrite32_rep(rnandc->regs + FIFO_DATA_REG, bufpoi + page_off,
66362306a36Sopenharmony_ci		      real_len / 4);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	while (!FIFO_STATE_W_EMPTY(readl(rnandc->regs + FIFO_STATE_REG)))
66662306a36Sopenharmony_ci		cpu_relax();
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	ret = rnandc_wait_end_of_op(rnandc, chip);
66962306a36Sopenharmony_ci	rnandc_dis_correction(rnandc);
67062306a36Sopenharmony_ci	if (ret) {
67162306a36Sopenharmony_ci		dev_err(rnandc->dev, "Write subpage operation never ending\n");
67262306a36Sopenharmony_ci		return ret;
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	return 0;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/*
67962306a36Sopenharmony_ci * This controller is simple enough and thus does not need to use the parser
68062306a36Sopenharmony_ci * provided by the core, instead, handle every situation here.
68162306a36Sopenharmony_ci */
68262306a36Sopenharmony_cistatic int rnandc_exec_op(struct nand_chip *chip,
68362306a36Sopenharmony_ci			  const struct nand_operation *op, bool check_only)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
68662306a36Sopenharmony_ci	const struct nand_op_instr *instr = NULL;
68762306a36Sopenharmony_ci	struct rnandc_op rop = {
68862306a36Sopenharmony_ci		.command = COMMAND_INPUT_SEL_AHBS,
68962306a36Sopenharmony_ci		.gen_seq_ctrl = GEN_SEQ_IMD_SEQ,
69062306a36Sopenharmony_ci	};
69162306a36Sopenharmony_ci	unsigned int cmd_phase = 0, addr_phase = 0, data_phase = 0,
69262306a36Sopenharmony_ci		delay_phase = 0, delays = 0;
69362306a36Sopenharmony_ci	unsigned int op_id, col_addrs, row_addrs, naddrs, remainder, words, i;
69462306a36Sopenharmony_ci	const u8 *addrs;
69562306a36Sopenharmony_ci	u32 last_bytes;
69662306a36Sopenharmony_ci	int ret;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (!check_only)
69962306a36Sopenharmony_ci		rnandc_select_target(chip, op->cs);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	for (op_id = 0; op_id < op->ninstrs; op_id++) {
70262306a36Sopenharmony_ci		instr = &op->instrs[op_id];
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		nand_op_trace("  ", instr);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci		switch (instr->type) {
70762306a36Sopenharmony_ci		case NAND_OP_CMD_INSTR:
70862306a36Sopenharmony_ci			switch (cmd_phase++) {
70962306a36Sopenharmony_ci			case 0:
71062306a36Sopenharmony_ci				rop.command |= COMMAND_0(instr->ctx.cmd.opcode);
71162306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_CMD0_EN;
71262306a36Sopenharmony_ci				break;
71362306a36Sopenharmony_ci			case 1:
71462306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_COMMAND_3(instr->ctx.cmd.opcode);
71562306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_CMD3_EN;
71662306a36Sopenharmony_ci				if (addr_phase == 0)
71762306a36Sopenharmony_ci					addr_phase = 1;
71862306a36Sopenharmony_ci				break;
71962306a36Sopenharmony_ci			case 2:
72062306a36Sopenharmony_ci				rop.command |= COMMAND_2(instr->ctx.cmd.opcode);
72162306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_CMD2_EN;
72262306a36Sopenharmony_ci				if (addr_phase <= 1)
72362306a36Sopenharmony_ci					addr_phase = 2;
72462306a36Sopenharmony_ci				break;
72562306a36Sopenharmony_ci			case 3:
72662306a36Sopenharmony_ci				rop.command |= COMMAND_1(instr->ctx.cmd.opcode);
72762306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_CMD1_EN;
72862306a36Sopenharmony_ci				if (addr_phase <= 1)
72962306a36Sopenharmony_ci					addr_phase = 2;
73062306a36Sopenharmony_ci				if (delay_phase == 0)
73162306a36Sopenharmony_ci					delay_phase = 1;
73262306a36Sopenharmony_ci				if (data_phase == 0)
73362306a36Sopenharmony_ci					data_phase = 1;
73462306a36Sopenharmony_ci				break;
73562306a36Sopenharmony_ci			default:
73662306a36Sopenharmony_ci				return -EOPNOTSUPP;
73762306a36Sopenharmony_ci			}
73862306a36Sopenharmony_ci			break;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci		case NAND_OP_ADDR_INSTR:
74162306a36Sopenharmony_ci			addrs = instr->ctx.addr.addrs;
74262306a36Sopenharmony_ci			naddrs = instr->ctx.addr.naddrs;
74362306a36Sopenharmony_ci			if (naddrs > 5)
74462306a36Sopenharmony_ci				return -EOPNOTSUPP;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci			col_addrs = min(2U, naddrs);
74762306a36Sopenharmony_ci			row_addrs = naddrs > 2 ? naddrs - col_addrs : 0;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci			switch (addr_phase++) {
75062306a36Sopenharmony_ci			case 0:
75162306a36Sopenharmony_ci				for (i = 0; i < col_addrs; i++)
75262306a36Sopenharmony_ci					rop.addr0_col |= addrs[i] << (i * 8);
75362306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_COL_A0(col_addrs);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci				for (i = 0; i < row_addrs; i++)
75662306a36Sopenharmony_ci					rop.addr0_row |= addrs[2 + i] << (i * 8);
75762306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_ROW_A0(row_addrs);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci				if (cmd_phase == 0)
76062306a36Sopenharmony_ci					cmd_phase = 1;
76162306a36Sopenharmony_ci				break;
76262306a36Sopenharmony_ci			case 1:
76362306a36Sopenharmony_ci				for (i = 0; i < col_addrs; i++)
76462306a36Sopenharmony_ci					rop.addr1_col |= addrs[i] << (i * 8);
76562306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_COL_A1(col_addrs);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci				for (i = 0; i < row_addrs; i++)
76862306a36Sopenharmony_ci					rop.addr1_row |= addrs[2 + i] << (i * 8);
76962306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_ROW_A1(row_addrs);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci				if (cmd_phase <= 1)
77262306a36Sopenharmony_ci					cmd_phase = 2;
77362306a36Sopenharmony_ci				break;
77462306a36Sopenharmony_ci			default:
77562306a36Sopenharmony_ci				return -EOPNOTSUPP;
77662306a36Sopenharmony_ci			}
77762306a36Sopenharmony_ci			break;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci		case NAND_OP_DATA_IN_INSTR:
78062306a36Sopenharmony_ci			rop.read = true;
78162306a36Sopenharmony_ci			fallthrough;
78262306a36Sopenharmony_ci		case NAND_OP_DATA_OUT_INSTR:
78362306a36Sopenharmony_ci			rop.gen_seq_ctrl |= GEN_SEQ_DATA_EN;
78462306a36Sopenharmony_ci			rop.buf = instr->ctx.data.buf.in;
78562306a36Sopenharmony_ci			rop.len = instr->ctx.data.len;
78662306a36Sopenharmony_ci			rop.command |= COMMAND_FIFO_SEL;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci			switch (data_phase++) {
78962306a36Sopenharmony_ci			case 0:
79062306a36Sopenharmony_ci				if (cmd_phase <= 2)
79162306a36Sopenharmony_ci					cmd_phase = 3;
79262306a36Sopenharmony_ci				if (addr_phase <= 1)
79362306a36Sopenharmony_ci					addr_phase = 2;
79462306a36Sopenharmony_ci				if (delay_phase == 0)
79562306a36Sopenharmony_ci					delay_phase = 1;
79662306a36Sopenharmony_ci				break;
79762306a36Sopenharmony_ci			default:
79862306a36Sopenharmony_ci				return -EOPNOTSUPP;
79962306a36Sopenharmony_ci			}
80062306a36Sopenharmony_ci			break;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci		case NAND_OP_WAITRDY_INSTR:
80362306a36Sopenharmony_ci			switch (delay_phase++) {
80462306a36Sopenharmony_ci			case 0:
80562306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_DELAY0_EN;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci				if (cmd_phase <= 2)
80862306a36Sopenharmony_ci					cmd_phase = 3;
80962306a36Sopenharmony_ci				break;
81062306a36Sopenharmony_ci			case 1:
81162306a36Sopenharmony_ci				rop.gen_seq_ctrl |= GEN_SEQ_DELAY1_EN;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci				if (cmd_phase <= 3)
81462306a36Sopenharmony_ci					cmd_phase = 4;
81562306a36Sopenharmony_ci				if (data_phase == 0)
81662306a36Sopenharmony_ci					data_phase = 1;
81762306a36Sopenharmony_ci				break;
81862306a36Sopenharmony_ci			default:
81962306a36Sopenharmony_ci				return -EOPNOTSUPP;
82062306a36Sopenharmony_ci			}
82162306a36Sopenharmony_ci			break;
82262306a36Sopenharmony_ci		}
82362306a36Sopenharmony_ci	}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	/*
82662306a36Sopenharmony_ci	 * Sequence 19 is generic and dedicated to write operations.
82762306a36Sopenharmony_ci	 * Sequence 18 is also generic and works for all other operations.
82862306a36Sopenharmony_ci	 */
82962306a36Sopenharmony_ci	if (rop.buf && !rop.read)
83062306a36Sopenharmony_ci		rop.command |= COMMAND_SEQ_GEN_OUT;
83162306a36Sopenharmony_ci	else
83262306a36Sopenharmony_ci		rop.command |= COMMAND_SEQ_GEN_IN;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	if (delays > 1) {
83562306a36Sopenharmony_ci		dev_err(rnandc->dev, "Cannot handle more than one wait delay\n");
83662306a36Sopenharmony_ci		return -EOPNOTSUPP;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if (check_only)
84062306a36Sopenharmony_ci		return 0;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	rnandc_trigger_op(rnandc, &rop);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	words = rop.len / sizeof(u32);
84562306a36Sopenharmony_ci	remainder = rop.len % sizeof(u32);
84662306a36Sopenharmony_ci	if (rop.buf && rop.read) {
84762306a36Sopenharmony_ci		while (!FIFO_STATE_C_EMPTY(readl(rnandc->regs + FIFO_STATE_REG)))
84862306a36Sopenharmony_ci			cpu_relax();
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		while (FIFO_STATE_R_EMPTY(readl(rnandc->regs + FIFO_STATE_REG)))
85162306a36Sopenharmony_ci			cpu_relax();
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci		ioread32_rep(rnandc->regs + FIFO_DATA_REG, rop.buf, words);
85462306a36Sopenharmony_ci		if (remainder) {
85562306a36Sopenharmony_ci			last_bytes = readl_relaxed(rnandc->regs + FIFO_DATA_REG);
85662306a36Sopenharmony_ci			memcpy(rop.buf + (words * sizeof(u32)), &last_bytes,
85762306a36Sopenharmony_ci			       remainder);
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci		if (!FIFO_STATE_R_EMPTY(readl(rnandc->regs + FIFO_STATE_REG))) {
86162306a36Sopenharmony_ci			dev_warn(rnandc->dev,
86262306a36Sopenharmony_ci				 "Clearing residual data in the read FIFO\n");
86362306a36Sopenharmony_ci			rnandc_clear_fifo(rnandc);
86462306a36Sopenharmony_ci		}
86562306a36Sopenharmony_ci	} else if (rop.len && !rop.read) {
86662306a36Sopenharmony_ci		while (FIFO_STATE_W_FULL(readl(rnandc->regs + FIFO_STATE_REG)))
86762306a36Sopenharmony_ci			cpu_relax();
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci		iowrite32_rep(rnandc->regs + FIFO_DATA_REG, rop.buf,
87062306a36Sopenharmony_ci			      DIV_ROUND_UP(rop.len, 4));
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		if (remainder) {
87362306a36Sopenharmony_ci			last_bytes = 0;
87462306a36Sopenharmony_ci			memcpy(&last_bytes, rop.buf + (words * sizeof(u32)), remainder);
87562306a36Sopenharmony_ci			writel_relaxed(last_bytes, rnandc->regs + FIFO_DATA_REG);
87662306a36Sopenharmony_ci		}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci		while (!FIFO_STATE_W_EMPTY(readl(rnandc->regs + FIFO_STATE_REG)))
87962306a36Sopenharmony_ci			cpu_relax();
88062306a36Sopenharmony_ci	}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	ret = rnandc_wait_end_of_op(rnandc, chip);
88362306a36Sopenharmony_ci	if (ret)
88462306a36Sopenharmony_ci		return ret;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	return 0;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic int rnandc_setup_interface(struct nand_chip *chip, int chipnr,
89062306a36Sopenharmony_ci				  const struct nand_interface_config *conf)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	struct rnand_chip *rnand = to_rnand(chip);
89362306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
89462306a36Sopenharmony_ci	unsigned int period_ns = 1000000000 / rnandc->ext_clk_rate;
89562306a36Sopenharmony_ci	const struct nand_sdr_timings *sdr;
89662306a36Sopenharmony_ci	unsigned int cyc, cle, ale, bef_dly, ca_to_data;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	sdr = nand_get_sdr_timings(conf);
89962306a36Sopenharmony_ci	if (IS_ERR(sdr))
90062306a36Sopenharmony_ci		return PTR_ERR(sdr);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (sdr->tRP_min != sdr->tWP_min || sdr->tREH_min != sdr->tWH_min) {
90362306a36Sopenharmony_ci		dev_err(rnandc->dev, "Read and write hold times must be identical\n");
90462306a36Sopenharmony_ci		return -EINVAL;
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	if (chipnr < 0)
90862306a36Sopenharmony_ci		return 0;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	rnand->timings_asyn =
91162306a36Sopenharmony_ci		TIMINGS_ASYN_TRWP(TO_CYCLES64(sdr->tRP_min, period_ns)) |
91262306a36Sopenharmony_ci		TIMINGS_ASYN_TRWH(TO_CYCLES64(sdr->tREH_min, period_ns));
91362306a36Sopenharmony_ci	rnand->tim_seq0 =
91462306a36Sopenharmony_ci		TIM_SEQ0_TCCS(TO_CYCLES64(sdr->tCCS_min, period_ns)) |
91562306a36Sopenharmony_ci		TIM_SEQ0_TADL(TO_CYCLES64(sdr->tADL_min, period_ns)) |
91662306a36Sopenharmony_ci		TIM_SEQ0_TRHW(TO_CYCLES64(sdr->tRHW_min, period_ns)) |
91762306a36Sopenharmony_ci		TIM_SEQ0_TWHR(TO_CYCLES64(sdr->tWHR_min, period_ns));
91862306a36Sopenharmony_ci	rnand->tim_seq1 =
91962306a36Sopenharmony_ci		TIM_SEQ1_TWB(TO_CYCLES64(sdr->tWB_max, period_ns)) |
92062306a36Sopenharmony_ci		TIM_SEQ1_TRR(TO_CYCLES64(sdr->tRR_min, period_ns)) |
92162306a36Sopenharmony_ci		TIM_SEQ1_TWW(TO_CYCLES64(sdr->tWW_min, period_ns));
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	cyc = sdr->tDS_min + sdr->tDH_min;
92462306a36Sopenharmony_ci	cle = sdr->tCLH_min + sdr->tCLS_min;
92562306a36Sopenharmony_ci	ale = sdr->tALH_min + sdr->tALS_min;
92662306a36Sopenharmony_ci	bef_dly = sdr->tWB_max - sdr->tDH_min;
92762306a36Sopenharmony_ci	ca_to_data = sdr->tWHR_min + sdr->tREA_max - sdr->tDH_min;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	/*
93062306a36Sopenharmony_ci	 * D0 = CMD -> ADDR = tCLH + tCLS - 1 cycle
93162306a36Sopenharmony_ci	 * D1 = CMD -> CMD = tCLH + tCLS - 1 cycle
93262306a36Sopenharmony_ci	 * D2 = CMD -> DLY = tWB - tDH
93362306a36Sopenharmony_ci	 * D3 = CMD -> DATA = tWHR + tREA - tDH
93462306a36Sopenharmony_ci	 */
93562306a36Sopenharmony_ci	rnand->tim_gen_seq0 =
93662306a36Sopenharmony_ci		TIM_GEN_SEQ0_D0(TO_CYCLES64(cle - cyc, period_ns)) |
93762306a36Sopenharmony_ci		TIM_GEN_SEQ0_D1(TO_CYCLES64(cle - cyc, period_ns)) |
93862306a36Sopenharmony_ci		TIM_GEN_SEQ0_D2(TO_CYCLES64(bef_dly, period_ns)) |
93962306a36Sopenharmony_ci		TIM_GEN_SEQ0_D3(TO_CYCLES64(ca_to_data, period_ns));
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	/*
94262306a36Sopenharmony_ci	 * D4 = ADDR -> CMD = tALH + tALS - 1 cyle
94362306a36Sopenharmony_ci	 * D5 = ADDR -> ADDR = tALH + tALS - 1 cyle
94462306a36Sopenharmony_ci	 * D6 = ADDR -> DLY = tWB - tDH
94562306a36Sopenharmony_ci	 * D7 = ADDR -> DATA = tWHR + tREA - tDH
94662306a36Sopenharmony_ci	 */
94762306a36Sopenharmony_ci	rnand->tim_gen_seq1 =
94862306a36Sopenharmony_ci		TIM_GEN_SEQ1_D4(TO_CYCLES64(ale - cyc, period_ns)) |
94962306a36Sopenharmony_ci		TIM_GEN_SEQ1_D5(TO_CYCLES64(ale - cyc, period_ns)) |
95062306a36Sopenharmony_ci		TIM_GEN_SEQ1_D6(TO_CYCLES64(bef_dly, period_ns)) |
95162306a36Sopenharmony_ci		TIM_GEN_SEQ1_D7(TO_CYCLES64(ca_to_data, period_ns));
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	/*
95462306a36Sopenharmony_ci	 * D8 = DLY -> DATA = tRR + tREA
95562306a36Sopenharmony_ci	 * D9 = DLY -> CMD = tRR
95662306a36Sopenharmony_ci	 * D10 = DATA -> CMD = tCLH + tCLS - 1 cycle
95762306a36Sopenharmony_ci	 * D11 = DATA -> DLY = tWB - tDH
95862306a36Sopenharmony_ci	 */
95962306a36Sopenharmony_ci	rnand->tim_gen_seq2 =
96062306a36Sopenharmony_ci		TIM_GEN_SEQ2_D8(TO_CYCLES64(sdr->tRR_min + sdr->tREA_max, period_ns)) |
96162306a36Sopenharmony_ci		TIM_GEN_SEQ2_D9(TO_CYCLES64(sdr->tRR_min, period_ns)) |
96262306a36Sopenharmony_ci		TIM_GEN_SEQ2_D10(TO_CYCLES64(cle - cyc, period_ns)) |
96362306a36Sopenharmony_ci		TIM_GEN_SEQ2_D11(TO_CYCLES64(bef_dly, period_ns));
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/* D12 = DATA -> END = tCLH - tDH */
96662306a36Sopenharmony_ci	rnand->tim_gen_seq3 =
96762306a36Sopenharmony_ci		TIM_GEN_SEQ3_D12(TO_CYCLES64(sdr->tCLH_min - sdr->tDH_min, period_ns));
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	return 0;
97062306a36Sopenharmony_ci}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_cistatic int rnandc_ooblayout_ecc(struct mtd_info *mtd, int section,
97362306a36Sopenharmony_ci				struct mtd_oob_region *oobregion)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	struct nand_chip *chip = mtd_to_nand(mtd);
97662306a36Sopenharmony_ci	unsigned int eccbytes = round_up(chip->ecc.bytes, 4) * chip->ecc.steps;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	if (section)
97962306a36Sopenharmony_ci		return -ERANGE;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	oobregion->offset = 2;
98262306a36Sopenharmony_ci	oobregion->length = eccbytes;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	return 0;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic int rnandc_ooblayout_free(struct mtd_info *mtd, int section,
98862306a36Sopenharmony_ci				 struct mtd_oob_region *oobregion)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	struct nand_chip *chip = mtd_to_nand(mtd);
99162306a36Sopenharmony_ci	unsigned int eccbytes = round_up(chip->ecc.bytes, 4) * chip->ecc.steps;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	if (section)
99462306a36Sopenharmony_ci		return -ERANGE;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	oobregion->offset = 2 + eccbytes;
99762306a36Sopenharmony_ci	oobregion->length = mtd->oobsize - oobregion->offset;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	return 0;
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_cistatic const struct mtd_ooblayout_ops rnandc_ooblayout_ops = {
100362306a36Sopenharmony_ci	.ecc = rnandc_ooblayout_ecc,
100462306a36Sopenharmony_ci	.free = rnandc_ooblayout_free,
100562306a36Sopenharmony_ci};
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_cistatic int rnandc_hw_ecc_controller_init(struct nand_chip *chip)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci	struct rnand_chip *rnand = to_rnand(chip);
101062306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
101162306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if (mtd->writesize > SZ_16K) {
101462306a36Sopenharmony_ci		dev_err(rnandc->dev, "Unsupported page size\n");
101562306a36Sopenharmony_ci		return -EINVAL;
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	switch (chip->ecc.size) {
101962306a36Sopenharmony_ci	case SZ_256:
102062306a36Sopenharmony_ci		rnand->control |= CONTROL_ECC_BLOCK_SIZE_256;
102162306a36Sopenharmony_ci		break;
102262306a36Sopenharmony_ci	case SZ_512:
102362306a36Sopenharmony_ci		rnand->control |= CONTROL_ECC_BLOCK_SIZE_512;
102462306a36Sopenharmony_ci		break;
102562306a36Sopenharmony_ci	case SZ_1K:
102662306a36Sopenharmony_ci		rnand->control |= CONTROL_ECC_BLOCK_SIZE_1024;
102762306a36Sopenharmony_ci		break;
102862306a36Sopenharmony_ci	default:
102962306a36Sopenharmony_ci		dev_err(rnandc->dev, "Unsupported ECC chunk size\n");
103062306a36Sopenharmony_ci		return -EINVAL;
103162306a36Sopenharmony_ci	}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	switch (chip->ecc.strength) {
103462306a36Sopenharmony_ci	case 2:
103562306a36Sopenharmony_ci		chip->ecc.bytes = 4;
103662306a36Sopenharmony_ci		rnand->ecc_ctrl |= ECC_CTRL_CAP_2B;
103762306a36Sopenharmony_ci		break;
103862306a36Sopenharmony_ci	case 4:
103962306a36Sopenharmony_ci		chip->ecc.bytes = 7;
104062306a36Sopenharmony_ci		rnand->ecc_ctrl |= ECC_CTRL_CAP_4B;
104162306a36Sopenharmony_ci		break;
104262306a36Sopenharmony_ci	case 8:
104362306a36Sopenharmony_ci		chip->ecc.bytes = 14;
104462306a36Sopenharmony_ci		rnand->ecc_ctrl |= ECC_CTRL_CAP_8B;
104562306a36Sopenharmony_ci		break;
104662306a36Sopenharmony_ci	case 16:
104762306a36Sopenharmony_ci		chip->ecc.bytes = 28;
104862306a36Sopenharmony_ci		rnand->ecc_ctrl |= ECC_CTRL_CAP_16B;
104962306a36Sopenharmony_ci		break;
105062306a36Sopenharmony_ci	case 24:
105162306a36Sopenharmony_ci		chip->ecc.bytes = 42;
105262306a36Sopenharmony_ci		rnand->ecc_ctrl |= ECC_CTRL_CAP_24B;
105362306a36Sopenharmony_ci		break;
105462306a36Sopenharmony_ci	case 32:
105562306a36Sopenharmony_ci		chip->ecc.bytes = 56;
105662306a36Sopenharmony_ci		rnand->ecc_ctrl |= ECC_CTRL_CAP_32B;
105762306a36Sopenharmony_ci		break;
105862306a36Sopenharmony_ci	default:
105962306a36Sopenharmony_ci		dev_err(rnandc->dev, "Unsupported ECC strength\n");
106062306a36Sopenharmony_ci		return -EINVAL;
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	rnand->ecc_ctrl |= ECC_CTRL_ERR_THRESHOLD(chip->ecc.strength);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	mtd_set_ooblayout(mtd, &rnandc_ooblayout_ops);
106662306a36Sopenharmony_ci	chip->ecc.steps = mtd->writesize / chip->ecc.size;
106762306a36Sopenharmony_ci	chip->ecc.read_page = rnandc_read_page_hw_ecc;
106862306a36Sopenharmony_ci	chip->ecc.read_subpage = rnandc_read_subpage_hw_ecc;
106962306a36Sopenharmony_ci	chip->ecc.write_page = rnandc_write_page_hw_ecc;
107062306a36Sopenharmony_ci	chip->ecc.write_subpage = rnandc_write_subpage_hw_ecc;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	return 0;
107362306a36Sopenharmony_ci}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_cistatic int rnandc_ecc_init(struct nand_chip *chip)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	struct nand_ecc_ctrl *ecc = &chip->ecc;
107862306a36Sopenharmony_ci	const struct nand_ecc_props *requirements =
107962306a36Sopenharmony_ci		nanddev_get_ecc_requirements(&chip->base);
108062306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
108162306a36Sopenharmony_ci	int ret;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (ecc->engine_type != NAND_ECC_ENGINE_TYPE_NONE &&
108462306a36Sopenharmony_ci	    (!ecc->size || !ecc->strength)) {
108562306a36Sopenharmony_ci		if (requirements->step_size && requirements->strength) {
108662306a36Sopenharmony_ci			ecc->size = requirements->step_size;
108762306a36Sopenharmony_ci			ecc->strength = requirements->strength;
108862306a36Sopenharmony_ci		} else {
108962306a36Sopenharmony_ci			dev_err(rnandc->dev, "No minimum ECC strength\n");
109062306a36Sopenharmony_ci			return -EINVAL;
109162306a36Sopenharmony_ci		}
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	switch (ecc->engine_type) {
109562306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_ON_HOST:
109662306a36Sopenharmony_ci		ret = rnandc_hw_ecc_controller_init(chip);
109762306a36Sopenharmony_ci		if (ret)
109862306a36Sopenharmony_ci			return ret;
109962306a36Sopenharmony_ci		break;
110062306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_NONE:
110162306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_SOFT:
110262306a36Sopenharmony_ci	case NAND_ECC_ENGINE_TYPE_ON_DIE:
110362306a36Sopenharmony_ci		break;
110462306a36Sopenharmony_ci	default:
110562306a36Sopenharmony_ci		return -EINVAL;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	return 0;
110962306a36Sopenharmony_ci}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic int rnandc_attach_chip(struct nand_chip *chip)
111262306a36Sopenharmony_ci{
111362306a36Sopenharmony_ci	struct rnand_chip *rnand = to_rnand(chip);
111462306a36Sopenharmony_ci	struct rnandc *rnandc = to_rnandc(chip->controller);
111562306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
111662306a36Sopenharmony_ci	struct nand_memory_organization *memorg = nanddev_get_memorg(&chip->base);
111762306a36Sopenharmony_ci	int ret;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	/* Do not store BBT bits in the OOB section as it is not protected */
112062306a36Sopenharmony_ci	if (chip->bbt_options & NAND_BBT_USE_FLASH)
112162306a36Sopenharmony_ci		chip->bbt_options |= NAND_BBT_NO_OOB;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	if (mtd->writesize <= 512) {
112462306a36Sopenharmony_ci		dev_err(rnandc->dev, "Small page devices not supported\n");
112562306a36Sopenharmony_ci		return -EINVAL;
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	rnand->control |= CONTROL_CHECK_RB_LINE | CONTROL_INT_EN;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	switch (memorg->pages_per_eraseblock) {
113162306a36Sopenharmony_ci	case 32:
113262306a36Sopenharmony_ci		rnand->control |= CONTROL_BLOCK_SIZE_32P;
113362306a36Sopenharmony_ci		break;
113462306a36Sopenharmony_ci	case 64:
113562306a36Sopenharmony_ci		rnand->control |= CONTROL_BLOCK_SIZE_64P;
113662306a36Sopenharmony_ci		break;
113762306a36Sopenharmony_ci	case 128:
113862306a36Sopenharmony_ci		rnand->control |= CONTROL_BLOCK_SIZE_128P;
113962306a36Sopenharmony_ci		break;
114062306a36Sopenharmony_ci	case 256:
114162306a36Sopenharmony_ci		rnand->control |= CONTROL_BLOCK_SIZE_256P;
114262306a36Sopenharmony_ci		break;
114362306a36Sopenharmony_ci	default:
114462306a36Sopenharmony_ci		dev_err(rnandc->dev, "Unsupported memory organization\n");
114562306a36Sopenharmony_ci		return -EINVAL;
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	chip->options |= NAND_SUBPAGE_READ;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	ret = rnandc_ecc_init(chip);
115162306a36Sopenharmony_ci	if (ret) {
115262306a36Sopenharmony_ci		dev_err(rnandc->dev, "ECC initialization failed (%d)\n", ret);
115362306a36Sopenharmony_ci		return ret;
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	/* Force an update of the configuration registers */
115762306a36Sopenharmony_ci	rnand->selected_die = -1;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	return 0;
116062306a36Sopenharmony_ci}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_cistatic const struct nand_controller_ops rnandc_ops = {
116362306a36Sopenharmony_ci	.attach_chip = rnandc_attach_chip,
116462306a36Sopenharmony_ci	.exec_op = rnandc_exec_op,
116562306a36Sopenharmony_ci	.setup_interface = rnandc_setup_interface,
116662306a36Sopenharmony_ci};
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic int rnandc_alloc_dma_buf(struct rnandc *rnandc,
116962306a36Sopenharmony_ci				struct mtd_info *new_mtd)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	unsigned int max_len = new_mtd->writesize + new_mtd->oobsize;
117262306a36Sopenharmony_ci	struct rnand_chip *entry, *temp;
117362306a36Sopenharmony_ci	struct nand_chip *chip;
117462306a36Sopenharmony_ci	struct mtd_info *mtd;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	list_for_each_entry_safe(entry, temp, &rnandc->chips, node) {
117762306a36Sopenharmony_ci		chip = &entry->chip;
117862306a36Sopenharmony_ci		mtd = nand_to_mtd(chip);
117962306a36Sopenharmony_ci		max_len = max(max_len, mtd->writesize + mtd->oobsize);
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (rnandc->buf && rnandc->buf_sz < max_len) {
118362306a36Sopenharmony_ci		devm_kfree(rnandc->dev, rnandc->buf);
118462306a36Sopenharmony_ci		rnandc->buf = NULL;
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	if (!rnandc->buf) {
118862306a36Sopenharmony_ci		rnandc->buf_sz = max_len;
118962306a36Sopenharmony_ci		rnandc->buf = devm_kmalloc(rnandc->dev, max_len,
119062306a36Sopenharmony_ci					   GFP_KERNEL | GFP_DMA);
119162306a36Sopenharmony_ci		if (!rnandc->buf)
119262306a36Sopenharmony_ci			return -ENOMEM;
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	return 0;
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_cistatic int rnandc_chip_init(struct rnandc *rnandc, struct device_node *np)
119962306a36Sopenharmony_ci{
120062306a36Sopenharmony_ci	struct rnand_chip *rnand;
120162306a36Sopenharmony_ci	struct mtd_info *mtd;
120262306a36Sopenharmony_ci	struct nand_chip *chip;
120362306a36Sopenharmony_ci	int nsels, ret, i;
120462306a36Sopenharmony_ci	u32 cs;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	nsels = of_property_count_elems_of_size(np, "reg", sizeof(u32));
120762306a36Sopenharmony_ci	if (nsels <= 0) {
120862306a36Sopenharmony_ci		ret = (nsels < 0) ? nsels : -EINVAL;
120962306a36Sopenharmony_ci		dev_err(rnandc->dev, "Invalid reg property (%d)\n", ret);
121062306a36Sopenharmony_ci		return ret;
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	/* Alloc the driver's NAND chip structure */
121462306a36Sopenharmony_ci	rnand = devm_kzalloc(rnandc->dev, struct_size(rnand, sels, nsels),
121562306a36Sopenharmony_ci			     GFP_KERNEL);
121662306a36Sopenharmony_ci	if (!rnand)
121762306a36Sopenharmony_ci		return -ENOMEM;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	rnand->nsels = nsels;
122062306a36Sopenharmony_ci	rnand->selected_die = -1;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	for (i = 0; i < nsels; i++) {
122362306a36Sopenharmony_ci		ret = of_property_read_u32_index(np, "reg", i, &cs);
122462306a36Sopenharmony_ci		if (ret) {
122562306a36Sopenharmony_ci			dev_err(rnandc->dev, "Incomplete reg property (%d)\n", ret);
122662306a36Sopenharmony_ci			return ret;
122762306a36Sopenharmony_ci		}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci		if (cs >= RNANDC_CS_NUM) {
123062306a36Sopenharmony_ci			dev_err(rnandc->dev, "Invalid reg property (%d)\n", cs);
123162306a36Sopenharmony_ci			return -EINVAL;
123262306a36Sopenharmony_ci		}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci		if (test_and_set_bit(cs, &rnandc->assigned_cs)) {
123562306a36Sopenharmony_ci			dev_err(rnandc->dev, "CS %d already assigned\n", cs);
123662306a36Sopenharmony_ci			return -EINVAL;
123762306a36Sopenharmony_ci		}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci		/*
124062306a36Sopenharmony_ci		 * No need to check for RB or WP properties, there is a 1:1
124162306a36Sopenharmony_ci		 * mandatory mapping with the CS.
124262306a36Sopenharmony_ci		 */
124362306a36Sopenharmony_ci		rnand->sels[i].cs = cs;
124462306a36Sopenharmony_ci	}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	chip = &rnand->chip;
124762306a36Sopenharmony_ci	chip->controller = &rnandc->controller;
124862306a36Sopenharmony_ci	nand_set_flash_node(chip, np);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	mtd = nand_to_mtd(chip);
125162306a36Sopenharmony_ci	mtd->dev.parent = rnandc->dev;
125262306a36Sopenharmony_ci	if (!mtd->name) {
125362306a36Sopenharmony_ci		dev_err(rnandc->dev, "Missing MTD label\n");
125462306a36Sopenharmony_ci		return -EINVAL;
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	ret = nand_scan(chip, rnand->nsels);
125862306a36Sopenharmony_ci	if (ret) {
125962306a36Sopenharmony_ci		dev_err(rnandc->dev, "Failed to scan the NAND chip (%d)\n", ret);
126062306a36Sopenharmony_ci		return ret;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	ret = rnandc_alloc_dma_buf(rnandc, mtd);
126462306a36Sopenharmony_ci	if (ret)
126562306a36Sopenharmony_ci		goto cleanup_nand;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	ret = mtd_device_register(mtd, NULL, 0);
126862306a36Sopenharmony_ci	if (ret) {
126962306a36Sopenharmony_ci		dev_err(rnandc->dev, "Failed to register MTD device (%d)\n", ret);
127062306a36Sopenharmony_ci		goto cleanup_nand;
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	list_add_tail(&rnand->node, &rnandc->chips);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	return 0;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cicleanup_nand:
127862306a36Sopenharmony_ci	nand_cleanup(chip);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	return ret;
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic void rnandc_chips_cleanup(struct rnandc *rnandc)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	struct rnand_chip *entry, *temp;
128662306a36Sopenharmony_ci	struct nand_chip *chip;
128762306a36Sopenharmony_ci	int ret;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	list_for_each_entry_safe(entry, temp, &rnandc->chips, node) {
129062306a36Sopenharmony_ci		chip = &entry->chip;
129162306a36Sopenharmony_ci		ret = mtd_device_unregister(nand_to_mtd(chip));
129262306a36Sopenharmony_ci		WARN_ON(ret);
129362306a36Sopenharmony_ci		nand_cleanup(chip);
129462306a36Sopenharmony_ci		list_del(&entry->node);
129562306a36Sopenharmony_ci	}
129662306a36Sopenharmony_ci}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cistatic int rnandc_chips_init(struct rnandc *rnandc)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	struct device_node *np;
130162306a36Sopenharmony_ci	int ret;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	for_each_child_of_node(rnandc->dev->of_node, np) {
130462306a36Sopenharmony_ci		ret = rnandc_chip_init(rnandc, np);
130562306a36Sopenharmony_ci		if (ret) {
130662306a36Sopenharmony_ci			of_node_put(np);
130762306a36Sopenharmony_ci			goto cleanup_chips;
130862306a36Sopenharmony_ci		}
130962306a36Sopenharmony_ci	}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	return 0;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_cicleanup_chips:
131462306a36Sopenharmony_ci	rnandc_chips_cleanup(rnandc);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	return ret;
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic int rnandc_probe(struct platform_device *pdev)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	struct rnandc *rnandc;
132262306a36Sopenharmony_ci	struct clk *eclk;
132362306a36Sopenharmony_ci	int irq, ret;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	rnandc = devm_kzalloc(&pdev->dev, sizeof(*rnandc), GFP_KERNEL);
132662306a36Sopenharmony_ci	if (!rnandc)
132762306a36Sopenharmony_ci		return -ENOMEM;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	rnandc->dev = &pdev->dev;
133062306a36Sopenharmony_ci	nand_controller_init(&rnandc->controller);
133162306a36Sopenharmony_ci	rnandc->controller.ops = &rnandc_ops;
133262306a36Sopenharmony_ci	INIT_LIST_HEAD(&rnandc->chips);
133362306a36Sopenharmony_ci	init_completion(&rnandc->complete);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	rnandc->regs = devm_platform_ioremap_resource(pdev, 0);
133662306a36Sopenharmony_ci	if (IS_ERR(rnandc->regs))
133762306a36Sopenharmony_ci		return PTR_ERR(rnandc->regs);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	devm_pm_runtime_enable(&pdev->dev);
134062306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(&pdev->dev);
134162306a36Sopenharmony_ci	if (ret < 0)
134262306a36Sopenharmony_ci		return ret;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	/* The external NAND bus clock rate is needed for computing timings */
134562306a36Sopenharmony_ci	eclk = clk_get(&pdev->dev, "eclk");
134662306a36Sopenharmony_ci	if (IS_ERR(eclk)) {
134762306a36Sopenharmony_ci		ret = PTR_ERR(eclk);
134862306a36Sopenharmony_ci		goto dis_runtime_pm;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	rnandc->ext_clk_rate = clk_get_rate(eclk);
135262306a36Sopenharmony_ci	clk_put(eclk);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	rnandc_dis_interrupts(rnandc);
135562306a36Sopenharmony_ci	irq = platform_get_irq_optional(pdev, 0);
135662306a36Sopenharmony_ci	if (irq == -EPROBE_DEFER) {
135762306a36Sopenharmony_ci		ret = irq;
135862306a36Sopenharmony_ci		goto dis_runtime_pm;
135962306a36Sopenharmony_ci	} else if (irq < 0) {
136062306a36Sopenharmony_ci		dev_info(&pdev->dev, "No IRQ found, fallback to polling\n");
136162306a36Sopenharmony_ci		rnandc->use_polling = true;
136262306a36Sopenharmony_ci	} else {
136362306a36Sopenharmony_ci		ret = devm_request_irq(&pdev->dev, irq, rnandc_irq_handler, 0,
136462306a36Sopenharmony_ci				       "renesas-nand-controller", rnandc);
136562306a36Sopenharmony_ci		if (ret < 0)
136662306a36Sopenharmony_ci			goto dis_runtime_pm;
136762306a36Sopenharmony_ci	}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
137062306a36Sopenharmony_ci	if (ret)
137162306a36Sopenharmony_ci		goto dis_runtime_pm;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	rnandc_clear_fifo(rnandc);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	platform_set_drvdata(pdev, rnandc);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	ret = rnandc_chips_init(rnandc);
137862306a36Sopenharmony_ci	if (ret)
137962306a36Sopenharmony_ci		goto dis_runtime_pm;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	return 0;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_cidis_runtime_pm:
138462306a36Sopenharmony_ci	pm_runtime_put(&pdev->dev);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	return ret;
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_cistatic void rnandc_remove(struct platform_device *pdev)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	struct rnandc *rnandc = platform_get_drvdata(pdev);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	rnandc_chips_cleanup(rnandc);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	pm_runtime_put(&pdev->dev);
139662306a36Sopenharmony_ci}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic const struct of_device_id rnandc_id_table[] = {
139962306a36Sopenharmony_ci	{ .compatible = "renesas,rcar-gen3-nandc" },
140062306a36Sopenharmony_ci	{ .compatible = "renesas,rzn1-nandc" },
140162306a36Sopenharmony_ci	{} /* sentinel */
140262306a36Sopenharmony_ci};
140362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rnandc_id_table);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_cistatic struct platform_driver rnandc_driver = {
140662306a36Sopenharmony_ci	.driver = {
140762306a36Sopenharmony_ci		.name = "renesas-nandc",
140862306a36Sopenharmony_ci		.of_match_table = rnandc_id_table,
140962306a36Sopenharmony_ci	},
141062306a36Sopenharmony_ci	.probe = rnandc_probe,
141162306a36Sopenharmony_ci	.remove_new = rnandc_remove,
141262306a36Sopenharmony_ci};
141362306a36Sopenharmony_cimodule_platform_driver(rnandc_driver);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ciMODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
141662306a36Sopenharmony_ciMODULE_DESCRIPTION("Renesas R-Car Gen3 & RZ/N1 NAND controller driver");
141762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1418