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