1058e0e84SYifeng Zhao // SPDX-License-Identifier: GPL-2.0 OR MIT 2058e0e84SYifeng Zhao /* 3058e0e84SYifeng Zhao * Rockchip NAND Flash controller driver. 4058e0e84SYifeng Zhao * Copyright (C) 2020 Rockchip Inc. 5058e0e84SYifeng Zhao * Author: Yifeng Zhao <yifeng.zhao@rock-chips.com> 6058e0e84SYifeng Zhao */ 7058e0e84SYifeng Zhao 8058e0e84SYifeng Zhao #include <linux/clk.h> 9058e0e84SYifeng Zhao #include <linux/delay.h> 10058e0e84SYifeng Zhao #include <linux/dma-mapping.h> 11058e0e84SYifeng Zhao #include <linux/dmaengine.h> 12058e0e84SYifeng Zhao #include <linux/interrupt.h> 13058e0e84SYifeng Zhao #include <linux/iopoll.h> 14058e0e84SYifeng Zhao #include <linux/module.h> 15058e0e84SYifeng Zhao #include <linux/mtd/mtd.h> 16058e0e84SYifeng Zhao #include <linux/mtd/rawnand.h> 17058e0e84SYifeng Zhao #include <linux/of.h> 18058e0e84SYifeng Zhao #include <linux/of_device.h> 19058e0e84SYifeng Zhao #include <linux/platform_device.h> 20058e0e84SYifeng Zhao #include <linux/slab.h> 21058e0e84SYifeng Zhao 22058e0e84SYifeng Zhao /* 23058e0e84SYifeng Zhao * NFC Page Data Layout: 24058e0e84SYifeng Zhao * 1024 bytes data + 4Bytes sys data + 28Bytes~124Bytes ECC data + 25058e0e84SYifeng Zhao * 1024 bytes data + 4Bytes sys data + 28Bytes~124Bytes ECC data + 26058e0e84SYifeng Zhao * ...... 27058e0e84SYifeng Zhao * NAND Page Data Layout: 28058e0e84SYifeng Zhao * 1024 * n data + m Bytes oob 29058e0e84SYifeng Zhao * Original Bad Block Mask Location: 30058e0e84SYifeng Zhao * First byte of oob(spare). 31058e0e84SYifeng Zhao * nand_chip->oob_poi data layout: 32058e0e84SYifeng Zhao * 4Bytes sys data + .... + 4Bytes sys data + ECC data. 33058e0e84SYifeng Zhao */ 34058e0e84SYifeng Zhao 35058e0e84SYifeng Zhao /* NAND controller register definition */ 36058e0e84SYifeng Zhao #define NFC_READ (0) 37058e0e84SYifeng Zhao #define NFC_WRITE (1) 38058e0e84SYifeng Zhao 39058e0e84SYifeng Zhao #define NFC_FMCTL (0x00) 40058e0e84SYifeng Zhao #define FMCTL_CE_SEL_M 0xFF 41058e0e84SYifeng Zhao #define FMCTL_CE_SEL(x) (1 << (x)) 42058e0e84SYifeng Zhao #define FMCTL_WP BIT(8) 43058e0e84SYifeng Zhao #define FMCTL_RDY BIT(9) 44058e0e84SYifeng Zhao 45058e0e84SYifeng Zhao #define NFC_FMWAIT (0x04) 46058e0e84SYifeng Zhao #define FLCTL_RST BIT(0) 47058e0e84SYifeng Zhao #define FLCTL_WR (1) /* 0: read, 1: write */ 48058e0e84SYifeng Zhao #define FLCTL_XFER_ST BIT(2) 49058e0e84SYifeng Zhao #define FLCTL_XFER_EN BIT(3) 50058e0e84SYifeng Zhao #define FLCTL_ACORRECT BIT(10) /* Auto correct error bits. */ 51058e0e84SYifeng Zhao #define FLCTL_XFER_READY BIT(20) 52058e0e84SYifeng Zhao #define FLCTL_XFER_SECTOR (22) 53058e0e84SYifeng Zhao #define FLCTL_TOG_FIX BIT(29) 54058e0e84SYifeng Zhao 55058e0e84SYifeng Zhao #define BCHCTL_BANK_M (7 << 5) 56058e0e84SYifeng Zhao #define BCHCTL_BANK (5) 57058e0e84SYifeng Zhao 58058e0e84SYifeng Zhao #define DMA_ST BIT(0) 59058e0e84SYifeng Zhao #define DMA_WR (1) /* 0: write, 1: read */ 60058e0e84SYifeng Zhao #define DMA_EN BIT(2) 61058e0e84SYifeng Zhao #define DMA_AHB_SIZE (3) /* 0: 1, 1: 2, 2: 4 */ 62058e0e84SYifeng Zhao #define DMA_BURST_SIZE (6) /* 0: 1, 3: 4, 5: 8, 7: 16 */ 63058e0e84SYifeng Zhao #define DMA_INC_NUM (9) /* 1 - 16 */ 64058e0e84SYifeng Zhao 65058e0e84SYifeng Zhao #define ECC_ERR_CNT(x, e) ((((x) >> (e).low) & (e).low_mask) |\ 66058e0e84SYifeng Zhao (((x) >> (e).high) & (e).high_mask) << (e).low_bn) 67058e0e84SYifeng Zhao #define INT_DMA BIT(0) 68058e0e84SYifeng Zhao #define NFC_BANK (0x800) 69058e0e84SYifeng Zhao #define NFC_BANK_STEP (0x100) 70058e0e84SYifeng Zhao #define BANK_DATA (0x00) 71058e0e84SYifeng Zhao #define BANK_ADDR (0x04) 72058e0e84SYifeng Zhao #define BANK_CMD (0x08) 73058e0e84SYifeng Zhao #define NFC_SRAM0 (0x1000) 74058e0e84SYifeng Zhao #define NFC_SRAM1 (0x1400) 75058e0e84SYifeng Zhao #define NFC_SRAM_SIZE (0x400) 76058e0e84SYifeng Zhao #define NFC_TIMEOUT (500000) 77058e0e84SYifeng Zhao #define NFC_MAX_OOB_PER_STEP 128 78058e0e84SYifeng Zhao #define NFC_MIN_OOB_PER_STEP 64 79058e0e84SYifeng Zhao #define MAX_DATA_SIZE 0xFFFC 80058e0e84SYifeng Zhao #define MAX_ADDRESS_CYC 6 81058e0e84SYifeng Zhao #define NFC_ECC_MAX_MODES 4 82058e0e84SYifeng Zhao #define NFC_MAX_NSELS (8) /* Some Socs only have 1 or 2 CSs. */ 83058e0e84SYifeng Zhao #define NFC_SYS_DATA_SIZE (4) /* 4 bytes sys data in oob pre 1024 data.*/ 84058e0e84SYifeng Zhao #define RK_DEFAULT_CLOCK_RATE (150 * 1000 * 1000) /* 150 Mhz */ 85058e0e84SYifeng Zhao #define ACCTIMING(csrw, rwpw, rwcs) ((csrw) << 12 | (rwpw) << 5 | (rwcs)) 86058e0e84SYifeng Zhao 87058e0e84SYifeng Zhao enum nfc_type { 88058e0e84SYifeng Zhao NFC_V6, 89058e0e84SYifeng Zhao NFC_V8, 90058e0e84SYifeng Zhao NFC_V9, 91058e0e84SYifeng Zhao }; 92058e0e84SYifeng Zhao 93058e0e84SYifeng Zhao /** 94058e0e84SYifeng Zhao * struct rk_ecc_cnt_status: represent a ecc status data. 95058e0e84SYifeng Zhao * @err_flag_bit: error flag bit index at register. 96058e0e84SYifeng Zhao * @low: ECC count low bit index at register. 97058e0e84SYifeng Zhao * @low_mask: mask bit. 98058e0e84SYifeng Zhao * @low_bn: ECC count low bit number. 99058e0e84SYifeng Zhao * @high: ECC count high bit index at register. 100058e0e84SYifeng Zhao * @high_mask: mask bit 101058e0e84SYifeng Zhao */ 102058e0e84SYifeng Zhao struct ecc_cnt_status { 103058e0e84SYifeng Zhao u8 err_flag_bit; 104058e0e84SYifeng Zhao u8 low; 105058e0e84SYifeng Zhao u8 low_mask; 106058e0e84SYifeng Zhao u8 low_bn; 107058e0e84SYifeng Zhao u8 high; 108058e0e84SYifeng Zhao u8 high_mask; 109058e0e84SYifeng Zhao }; 110058e0e84SYifeng Zhao 111058e0e84SYifeng Zhao /** 112058e0e84SYifeng Zhao * @type: NFC version 113058e0e84SYifeng Zhao * @ecc_strengths: ECC strengths 114058e0e84SYifeng Zhao * @ecc_cfgs: ECC config values 115058e0e84SYifeng Zhao * @flctl_off: FLCTL register offset 116058e0e84SYifeng Zhao * @bchctl_off: BCHCTL register offset 117058e0e84SYifeng Zhao * @dma_data_buf_off: DMA_DATA_BUF register offset 118058e0e84SYifeng Zhao * @dma_oob_buf_off: DMA_OOB_BUF register offset 119058e0e84SYifeng Zhao * @dma_cfg_off: DMA_CFG register offset 120058e0e84SYifeng Zhao * @dma_st_off: DMA_ST register offset 121058e0e84SYifeng Zhao * @bch_st_off: BCG_ST register offset 122058e0e84SYifeng Zhao * @randmz_off: RANDMZ register offset 123058e0e84SYifeng Zhao * @int_en_off: interrupt enable register offset 124058e0e84SYifeng Zhao * @int_clr_off: interrupt clean register offset 125058e0e84SYifeng Zhao * @int_st_off: interrupt status register offset 126058e0e84SYifeng Zhao * @oob0_off: oob0 register offset 127058e0e84SYifeng Zhao * @oob1_off: oob1 register offset 128058e0e84SYifeng Zhao * @ecc0: represent ECC0 status data 129058e0e84SYifeng Zhao * @ecc1: represent ECC1 status data 130058e0e84SYifeng Zhao */ 131058e0e84SYifeng Zhao struct nfc_cfg { 132058e0e84SYifeng Zhao enum nfc_type type; 133058e0e84SYifeng Zhao u8 ecc_strengths[NFC_ECC_MAX_MODES]; 134058e0e84SYifeng Zhao u32 ecc_cfgs[NFC_ECC_MAX_MODES]; 135058e0e84SYifeng Zhao u32 flctl_off; 136058e0e84SYifeng Zhao u32 bchctl_off; 137058e0e84SYifeng Zhao u32 dma_cfg_off; 138058e0e84SYifeng Zhao u32 dma_data_buf_off; 139058e0e84SYifeng Zhao u32 dma_oob_buf_off; 140058e0e84SYifeng Zhao u32 dma_st_off; 141058e0e84SYifeng Zhao u32 bch_st_off; 142058e0e84SYifeng Zhao u32 randmz_off; 143058e0e84SYifeng Zhao u32 int_en_off; 144058e0e84SYifeng Zhao u32 int_clr_off; 145058e0e84SYifeng Zhao u32 int_st_off; 146058e0e84SYifeng Zhao u32 oob0_off; 147058e0e84SYifeng Zhao u32 oob1_off; 148058e0e84SYifeng Zhao struct ecc_cnt_status ecc0; 149058e0e84SYifeng Zhao struct ecc_cnt_status ecc1; 150058e0e84SYifeng Zhao }; 151058e0e84SYifeng Zhao 152058e0e84SYifeng Zhao struct rk_nfc_nand_chip { 153058e0e84SYifeng Zhao struct list_head node; 154058e0e84SYifeng Zhao struct nand_chip chip; 155058e0e84SYifeng Zhao 156058e0e84SYifeng Zhao u16 boot_blks; 157058e0e84SYifeng Zhao u16 metadata_size; 158058e0e84SYifeng Zhao u32 boot_ecc; 159058e0e84SYifeng Zhao u32 timing; 160058e0e84SYifeng Zhao 161058e0e84SYifeng Zhao u8 nsels; 162*5c8a620aSZou Wei u8 sels[]; 163058e0e84SYifeng Zhao /* Nothing after this field. */ 164058e0e84SYifeng Zhao }; 165058e0e84SYifeng Zhao 166058e0e84SYifeng Zhao struct rk_nfc { 167058e0e84SYifeng Zhao struct nand_controller controller; 168058e0e84SYifeng Zhao const struct nfc_cfg *cfg; 169058e0e84SYifeng Zhao struct device *dev; 170058e0e84SYifeng Zhao 171058e0e84SYifeng Zhao struct clk *nfc_clk; 172058e0e84SYifeng Zhao struct clk *ahb_clk; 173058e0e84SYifeng Zhao void __iomem *regs; 174058e0e84SYifeng Zhao 175058e0e84SYifeng Zhao u32 selected_bank; 176058e0e84SYifeng Zhao u32 band_offset; 177058e0e84SYifeng Zhao u32 cur_ecc; 178058e0e84SYifeng Zhao u32 cur_timing; 179058e0e84SYifeng Zhao 180058e0e84SYifeng Zhao struct completion done; 181058e0e84SYifeng Zhao struct list_head chips; 182058e0e84SYifeng Zhao 183058e0e84SYifeng Zhao u8 *page_buf; 184058e0e84SYifeng Zhao u32 *oob_buf; 185058e0e84SYifeng Zhao u32 page_buf_size; 186058e0e84SYifeng Zhao u32 oob_buf_size; 187058e0e84SYifeng Zhao 188058e0e84SYifeng Zhao unsigned long assigned_cs; 189058e0e84SYifeng Zhao }; 190058e0e84SYifeng Zhao 191058e0e84SYifeng Zhao static inline struct rk_nfc_nand_chip *rk_nfc_to_rknand(struct nand_chip *chip) 192058e0e84SYifeng Zhao { 193058e0e84SYifeng Zhao return container_of(chip, struct rk_nfc_nand_chip, chip); 194058e0e84SYifeng Zhao } 195058e0e84SYifeng Zhao 196058e0e84SYifeng Zhao static inline u8 *rk_nfc_buf_to_data_ptr(struct nand_chip *chip, const u8 *p, int i) 197058e0e84SYifeng Zhao { 198058e0e84SYifeng Zhao return (u8 *)p + i * chip->ecc.size; 199058e0e84SYifeng Zhao } 200058e0e84SYifeng Zhao 201058e0e84SYifeng Zhao static inline u8 *rk_nfc_buf_to_oob_ptr(struct nand_chip *chip, int i) 202058e0e84SYifeng Zhao { 203058e0e84SYifeng Zhao u8 *poi; 204058e0e84SYifeng Zhao 205058e0e84SYifeng Zhao poi = chip->oob_poi + i * NFC_SYS_DATA_SIZE; 206058e0e84SYifeng Zhao 207058e0e84SYifeng Zhao return poi; 208058e0e84SYifeng Zhao } 209058e0e84SYifeng Zhao 210058e0e84SYifeng Zhao static inline u8 *rk_nfc_buf_to_oob_ecc_ptr(struct nand_chip *chip, int i) 211058e0e84SYifeng Zhao { 212058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 213058e0e84SYifeng Zhao u8 *poi; 214058e0e84SYifeng Zhao 215058e0e84SYifeng Zhao poi = chip->oob_poi + rknand->metadata_size + chip->ecc.bytes * i; 216058e0e84SYifeng Zhao 217058e0e84SYifeng Zhao return poi; 218058e0e84SYifeng Zhao } 219058e0e84SYifeng Zhao 220058e0e84SYifeng Zhao static inline int rk_nfc_data_len(struct nand_chip *chip) 221058e0e84SYifeng Zhao { 222058e0e84SYifeng Zhao return chip->ecc.size + chip->ecc.bytes + NFC_SYS_DATA_SIZE; 223058e0e84SYifeng Zhao } 224058e0e84SYifeng Zhao 225058e0e84SYifeng Zhao static inline u8 *rk_nfc_data_ptr(struct nand_chip *chip, int i) 226058e0e84SYifeng Zhao { 227058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 228058e0e84SYifeng Zhao 229058e0e84SYifeng Zhao return nfc->page_buf + i * rk_nfc_data_len(chip); 230058e0e84SYifeng Zhao } 231058e0e84SYifeng Zhao 232058e0e84SYifeng Zhao static inline u8 *rk_nfc_oob_ptr(struct nand_chip *chip, int i) 233058e0e84SYifeng Zhao { 234058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 235058e0e84SYifeng Zhao 236058e0e84SYifeng Zhao return nfc->page_buf + i * rk_nfc_data_len(chip) + chip->ecc.size; 237058e0e84SYifeng Zhao } 238058e0e84SYifeng Zhao 239058e0e84SYifeng Zhao static int rk_nfc_hw_ecc_setup(struct nand_chip *chip, u32 strength) 240058e0e84SYifeng Zhao { 241058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 242058e0e84SYifeng Zhao u32 reg, i; 243058e0e84SYifeng Zhao 244058e0e84SYifeng Zhao for (i = 0; i < NFC_ECC_MAX_MODES; i++) { 245058e0e84SYifeng Zhao if (strength == nfc->cfg->ecc_strengths[i]) { 246058e0e84SYifeng Zhao reg = nfc->cfg->ecc_cfgs[i]; 247058e0e84SYifeng Zhao break; 248058e0e84SYifeng Zhao } 249058e0e84SYifeng Zhao } 250058e0e84SYifeng Zhao 251058e0e84SYifeng Zhao if (i >= NFC_ECC_MAX_MODES) 252058e0e84SYifeng Zhao return -EINVAL; 253058e0e84SYifeng Zhao 254058e0e84SYifeng Zhao writel(reg, nfc->regs + nfc->cfg->bchctl_off); 255058e0e84SYifeng Zhao 256058e0e84SYifeng Zhao /* Save chip ECC setting */ 257058e0e84SYifeng Zhao nfc->cur_ecc = strength; 258058e0e84SYifeng Zhao 259058e0e84SYifeng Zhao return 0; 260058e0e84SYifeng Zhao } 261058e0e84SYifeng Zhao 262058e0e84SYifeng Zhao static void rk_nfc_select_chip(struct nand_chip *chip, int cs) 263058e0e84SYifeng Zhao { 264058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 265058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 266058e0e84SYifeng Zhao struct nand_ecc_ctrl *ecc = &chip->ecc; 267058e0e84SYifeng Zhao u32 val; 268058e0e84SYifeng Zhao 269058e0e84SYifeng Zhao if (cs < 0) { 270058e0e84SYifeng Zhao nfc->selected_bank = -1; 271058e0e84SYifeng Zhao /* Deselect the currently selected target. */ 272058e0e84SYifeng Zhao val = readl_relaxed(nfc->regs + NFC_FMCTL); 273058e0e84SYifeng Zhao val &= ~FMCTL_CE_SEL_M; 274058e0e84SYifeng Zhao writel(val, nfc->regs + NFC_FMCTL); 275058e0e84SYifeng Zhao return; 276058e0e84SYifeng Zhao } 277058e0e84SYifeng Zhao 278058e0e84SYifeng Zhao nfc->selected_bank = rknand->sels[cs]; 279058e0e84SYifeng Zhao nfc->band_offset = NFC_BANK + nfc->selected_bank * NFC_BANK_STEP; 280058e0e84SYifeng Zhao 281058e0e84SYifeng Zhao val = readl_relaxed(nfc->regs + NFC_FMCTL); 282058e0e84SYifeng Zhao val &= ~FMCTL_CE_SEL_M; 283058e0e84SYifeng Zhao val |= FMCTL_CE_SEL(nfc->selected_bank); 284058e0e84SYifeng Zhao 285058e0e84SYifeng Zhao writel(val, nfc->regs + NFC_FMCTL); 286058e0e84SYifeng Zhao 287058e0e84SYifeng Zhao /* 288058e0e84SYifeng Zhao * Compare current chip timing with selected chip timing and 289058e0e84SYifeng Zhao * change if needed. 290058e0e84SYifeng Zhao */ 291058e0e84SYifeng Zhao if (nfc->cur_timing != rknand->timing) { 292058e0e84SYifeng Zhao writel(rknand->timing, nfc->regs + NFC_FMWAIT); 293058e0e84SYifeng Zhao nfc->cur_timing = rknand->timing; 294058e0e84SYifeng Zhao } 295058e0e84SYifeng Zhao 296058e0e84SYifeng Zhao /* 297058e0e84SYifeng Zhao * Compare current chip ECC setting with selected chip ECC setting and 298058e0e84SYifeng Zhao * change if needed. 299058e0e84SYifeng Zhao */ 300058e0e84SYifeng Zhao if (nfc->cur_ecc != ecc->strength) 301058e0e84SYifeng Zhao rk_nfc_hw_ecc_setup(chip, ecc->strength); 302058e0e84SYifeng Zhao } 303058e0e84SYifeng Zhao 304058e0e84SYifeng Zhao static inline int rk_nfc_wait_ioready(struct rk_nfc *nfc) 305058e0e84SYifeng Zhao { 306058e0e84SYifeng Zhao int rc; 307058e0e84SYifeng Zhao u32 val; 308058e0e84SYifeng Zhao 309058e0e84SYifeng Zhao rc = readl_relaxed_poll_timeout(nfc->regs + NFC_FMCTL, val, 310058e0e84SYifeng Zhao val & FMCTL_RDY, 10, NFC_TIMEOUT); 311058e0e84SYifeng Zhao 312058e0e84SYifeng Zhao return rc; 313058e0e84SYifeng Zhao } 314058e0e84SYifeng Zhao 315058e0e84SYifeng Zhao static void rk_nfc_read_buf(struct rk_nfc *nfc, u8 *buf, int len) 316058e0e84SYifeng Zhao { 317058e0e84SYifeng Zhao int i; 318058e0e84SYifeng Zhao 319058e0e84SYifeng Zhao for (i = 0; i < len; i++) 320058e0e84SYifeng Zhao buf[i] = readb_relaxed(nfc->regs + nfc->band_offset + 321058e0e84SYifeng Zhao BANK_DATA); 322058e0e84SYifeng Zhao } 323058e0e84SYifeng Zhao 324058e0e84SYifeng Zhao static void rk_nfc_write_buf(struct rk_nfc *nfc, const u8 *buf, int len) 325058e0e84SYifeng Zhao { 326058e0e84SYifeng Zhao int i; 327058e0e84SYifeng Zhao 328058e0e84SYifeng Zhao for (i = 0; i < len; i++) 329058e0e84SYifeng Zhao writeb(buf[i], nfc->regs + nfc->band_offset + BANK_DATA); 330058e0e84SYifeng Zhao } 331058e0e84SYifeng Zhao 332058e0e84SYifeng Zhao static int rk_nfc_cmd(struct nand_chip *chip, 333058e0e84SYifeng Zhao const struct nand_subop *subop) 334058e0e84SYifeng Zhao { 335058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 336058e0e84SYifeng Zhao unsigned int i, j, remaining, start; 337058e0e84SYifeng Zhao int reg_offset = nfc->band_offset; 338058e0e84SYifeng Zhao u8 *inbuf = NULL; 339058e0e84SYifeng Zhao const u8 *outbuf; 340058e0e84SYifeng Zhao u32 cnt = 0; 341058e0e84SYifeng Zhao int ret = 0; 342058e0e84SYifeng Zhao 343058e0e84SYifeng Zhao for (i = 0; i < subop->ninstrs; i++) { 344058e0e84SYifeng Zhao const struct nand_op_instr *instr = &subop->instrs[i]; 345058e0e84SYifeng Zhao 346058e0e84SYifeng Zhao switch (instr->type) { 347058e0e84SYifeng Zhao case NAND_OP_CMD_INSTR: 348058e0e84SYifeng Zhao writeb(instr->ctx.cmd.opcode, 349058e0e84SYifeng Zhao nfc->regs + reg_offset + BANK_CMD); 350058e0e84SYifeng Zhao break; 351058e0e84SYifeng Zhao 352058e0e84SYifeng Zhao case NAND_OP_ADDR_INSTR: 353058e0e84SYifeng Zhao remaining = nand_subop_get_num_addr_cyc(subop, i); 354058e0e84SYifeng Zhao start = nand_subop_get_addr_start_off(subop, i); 355058e0e84SYifeng Zhao 356058e0e84SYifeng Zhao for (j = 0; j < 8 && j + start < remaining; j++) 357058e0e84SYifeng Zhao writeb(instr->ctx.addr.addrs[j + start], 358058e0e84SYifeng Zhao nfc->regs + reg_offset + BANK_ADDR); 359058e0e84SYifeng Zhao break; 360058e0e84SYifeng Zhao 361058e0e84SYifeng Zhao case NAND_OP_DATA_IN_INSTR: 362058e0e84SYifeng Zhao case NAND_OP_DATA_OUT_INSTR: 363058e0e84SYifeng Zhao start = nand_subop_get_data_start_off(subop, i); 364058e0e84SYifeng Zhao cnt = nand_subop_get_data_len(subop, i); 365058e0e84SYifeng Zhao 366058e0e84SYifeng Zhao if (instr->type == NAND_OP_DATA_OUT_INSTR) { 367058e0e84SYifeng Zhao outbuf = instr->ctx.data.buf.out + start; 368058e0e84SYifeng Zhao rk_nfc_write_buf(nfc, outbuf, cnt); 369058e0e84SYifeng Zhao } else { 370058e0e84SYifeng Zhao inbuf = instr->ctx.data.buf.in + start; 371058e0e84SYifeng Zhao rk_nfc_read_buf(nfc, inbuf, cnt); 372058e0e84SYifeng Zhao } 373058e0e84SYifeng Zhao break; 374058e0e84SYifeng Zhao 375058e0e84SYifeng Zhao case NAND_OP_WAITRDY_INSTR: 376058e0e84SYifeng Zhao if (rk_nfc_wait_ioready(nfc) < 0) { 377058e0e84SYifeng Zhao ret = -ETIMEDOUT; 378058e0e84SYifeng Zhao dev_err(nfc->dev, "IO not ready\n"); 379058e0e84SYifeng Zhao } 380058e0e84SYifeng Zhao break; 381058e0e84SYifeng Zhao } 382058e0e84SYifeng Zhao } 383058e0e84SYifeng Zhao 384058e0e84SYifeng Zhao return ret; 385058e0e84SYifeng Zhao } 386058e0e84SYifeng Zhao 387058e0e84SYifeng Zhao static const struct nand_op_parser rk_nfc_op_parser = NAND_OP_PARSER( 388058e0e84SYifeng Zhao NAND_OP_PARSER_PATTERN( 389058e0e84SYifeng Zhao rk_nfc_cmd, 390058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_CMD_ELEM(true), 391058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC), 392058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_CMD_ELEM(true), 393058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_WAITRDY_ELEM(true), 394058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, MAX_DATA_SIZE)), 395058e0e84SYifeng Zhao NAND_OP_PARSER_PATTERN( 396058e0e84SYifeng Zhao rk_nfc_cmd, 397058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_CMD_ELEM(true), 398058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC), 399058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, MAX_DATA_SIZE), 400058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_CMD_ELEM(true), 401058e0e84SYifeng Zhao NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), 402058e0e84SYifeng Zhao ); 403058e0e84SYifeng Zhao 404058e0e84SYifeng Zhao static int rk_nfc_exec_op(struct nand_chip *chip, 405058e0e84SYifeng Zhao const struct nand_operation *op, 406058e0e84SYifeng Zhao bool check_only) 407058e0e84SYifeng Zhao { 408058e0e84SYifeng Zhao if (!check_only) 409058e0e84SYifeng Zhao rk_nfc_select_chip(chip, op->cs); 410058e0e84SYifeng Zhao 411058e0e84SYifeng Zhao return nand_op_parser_exec_op(chip, &rk_nfc_op_parser, op, 412058e0e84SYifeng Zhao check_only); 413058e0e84SYifeng Zhao } 414058e0e84SYifeng Zhao 415058e0e84SYifeng Zhao static int rk_nfc_setup_interface(struct nand_chip *chip, int target, 416058e0e84SYifeng Zhao const struct nand_interface_config *conf) 417058e0e84SYifeng Zhao { 418058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 419058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 420058e0e84SYifeng Zhao const struct nand_sdr_timings *timings; 421058e0e84SYifeng Zhao u32 rate, tc2rw, trwpw, trw2c; 422058e0e84SYifeng Zhao u32 temp; 423058e0e84SYifeng Zhao 424058e0e84SYifeng Zhao if (target < 0) 425058e0e84SYifeng Zhao return 0; 426058e0e84SYifeng Zhao 427058e0e84SYifeng Zhao timings = nand_get_sdr_timings(conf); 428058e0e84SYifeng Zhao if (IS_ERR(timings)) 429058e0e84SYifeng Zhao return -EOPNOTSUPP; 430058e0e84SYifeng Zhao 431058e0e84SYifeng Zhao if (IS_ERR(nfc->nfc_clk)) 432058e0e84SYifeng Zhao rate = clk_get_rate(nfc->ahb_clk); 433058e0e84SYifeng Zhao else 434058e0e84SYifeng Zhao rate = clk_get_rate(nfc->nfc_clk); 435058e0e84SYifeng Zhao 436058e0e84SYifeng Zhao /* Turn clock rate into kHz. */ 437058e0e84SYifeng Zhao rate /= 1000; 438058e0e84SYifeng Zhao 439058e0e84SYifeng Zhao tc2rw = 1; 440058e0e84SYifeng Zhao trw2c = 1; 441058e0e84SYifeng Zhao 442058e0e84SYifeng Zhao trwpw = max(timings->tWC_min, timings->tRC_min) / 1000; 443058e0e84SYifeng Zhao trwpw = DIV_ROUND_UP(trwpw * rate, 1000000); 444058e0e84SYifeng Zhao 445058e0e84SYifeng Zhao temp = timings->tREA_max / 1000; 446058e0e84SYifeng Zhao temp = DIV_ROUND_UP(temp * rate, 1000000); 447058e0e84SYifeng Zhao 448058e0e84SYifeng Zhao if (trwpw < temp) 449058e0e84SYifeng Zhao trwpw = temp; 450058e0e84SYifeng Zhao 451058e0e84SYifeng Zhao /* 452058e0e84SYifeng Zhao * ACCON: access timing control register 453058e0e84SYifeng Zhao * ------------------------------------- 454058e0e84SYifeng Zhao * 31:18: reserved 455058e0e84SYifeng Zhao * 17:12: csrw, clock cycles from the falling edge of CSn to the 456058e0e84SYifeng Zhao * falling edge of RDn or WRn 457058e0e84SYifeng Zhao * 11:11: reserved 458058e0e84SYifeng Zhao * 10:05: rwpw, the width of RDn or WRn in processor clock cycles 459058e0e84SYifeng Zhao * 04:00: rwcs, clock cycles from the rising edge of RDn or WRn to the 460058e0e84SYifeng Zhao * rising edge of CSn 461058e0e84SYifeng Zhao */ 462058e0e84SYifeng Zhao 463058e0e84SYifeng Zhao /* Save chip timing */ 464058e0e84SYifeng Zhao rknand->timing = ACCTIMING(tc2rw, trwpw, trw2c); 465058e0e84SYifeng Zhao 466058e0e84SYifeng Zhao return 0; 467058e0e84SYifeng Zhao } 468058e0e84SYifeng Zhao 469058e0e84SYifeng Zhao static void rk_nfc_xfer_start(struct rk_nfc *nfc, u8 rw, u8 n_KB, 470058e0e84SYifeng Zhao dma_addr_t dma_data, dma_addr_t dma_oob) 471058e0e84SYifeng Zhao { 472058e0e84SYifeng Zhao u32 dma_reg, fl_reg, bch_reg; 473058e0e84SYifeng Zhao 474058e0e84SYifeng Zhao dma_reg = DMA_ST | ((!rw) << DMA_WR) | DMA_EN | (2 << DMA_AHB_SIZE) | 475058e0e84SYifeng Zhao (7 << DMA_BURST_SIZE) | (16 << DMA_INC_NUM); 476058e0e84SYifeng Zhao 477058e0e84SYifeng Zhao fl_reg = (rw << FLCTL_WR) | FLCTL_XFER_EN | FLCTL_ACORRECT | 478058e0e84SYifeng Zhao (n_KB << FLCTL_XFER_SECTOR) | FLCTL_TOG_FIX; 479058e0e84SYifeng Zhao 480058e0e84SYifeng Zhao if (nfc->cfg->type == NFC_V6 || nfc->cfg->type == NFC_V8) { 481058e0e84SYifeng Zhao bch_reg = readl_relaxed(nfc->regs + nfc->cfg->bchctl_off); 482058e0e84SYifeng Zhao bch_reg = (bch_reg & (~BCHCTL_BANK_M)) | 483058e0e84SYifeng Zhao (nfc->selected_bank << BCHCTL_BANK); 484058e0e84SYifeng Zhao writel(bch_reg, nfc->regs + nfc->cfg->bchctl_off); 485058e0e84SYifeng Zhao } 486058e0e84SYifeng Zhao 487058e0e84SYifeng Zhao writel(dma_reg, nfc->regs + nfc->cfg->dma_cfg_off); 488058e0e84SYifeng Zhao writel((u32)dma_data, nfc->regs + nfc->cfg->dma_data_buf_off); 489058e0e84SYifeng Zhao writel((u32)dma_oob, nfc->regs + nfc->cfg->dma_oob_buf_off); 490058e0e84SYifeng Zhao writel(fl_reg, nfc->regs + nfc->cfg->flctl_off); 491058e0e84SYifeng Zhao fl_reg |= FLCTL_XFER_ST; 492058e0e84SYifeng Zhao writel(fl_reg, nfc->regs + nfc->cfg->flctl_off); 493058e0e84SYifeng Zhao } 494058e0e84SYifeng Zhao 495058e0e84SYifeng Zhao static int rk_nfc_wait_for_xfer_done(struct rk_nfc *nfc) 496058e0e84SYifeng Zhao { 497058e0e84SYifeng Zhao void __iomem *ptr; 498058e0e84SYifeng Zhao u32 reg; 499058e0e84SYifeng Zhao 500058e0e84SYifeng Zhao ptr = nfc->regs + nfc->cfg->flctl_off; 501058e0e84SYifeng Zhao 502058e0e84SYifeng Zhao return readl_relaxed_poll_timeout(ptr, reg, 503058e0e84SYifeng Zhao reg & FLCTL_XFER_READY, 504058e0e84SYifeng Zhao 10, NFC_TIMEOUT); 505058e0e84SYifeng Zhao } 506058e0e84SYifeng Zhao 507058e0e84SYifeng Zhao static int rk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf, 508058e0e84SYifeng Zhao int oob_on, int page) 509058e0e84SYifeng Zhao { 510058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 511058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 512058e0e84SYifeng Zhao struct mtd_info *mtd = nand_to_mtd(chip); 513058e0e84SYifeng Zhao struct nand_ecc_ctrl *ecc = &chip->ecc; 514058e0e84SYifeng Zhao int i, pages_per_blk; 515058e0e84SYifeng Zhao 516058e0e84SYifeng Zhao pages_per_blk = mtd->erasesize / mtd->writesize; 517058e0e84SYifeng Zhao if ((chip->options & NAND_IS_BOOT_MEDIUM) && 518058e0e84SYifeng Zhao (page < (pages_per_blk * rknand->boot_blks)) && 519058e0e84SYifeng Zhao rknand->boot_ecc != ecc->strength) { 520058e0e84SYifeng Zhao /* 521058e0e84SYifeng Zhao * There's currently no method to notify the MTD framework that 522058e0e84SYifeng Zhao * a different ECC strength is in use for the boot blocks. 523058e0e84SYifeng Zhao */ 524058e0e84SYifeng Zhao return -EIO; 525058e0e84SYifeng Zhao } 526058e0e84SYifeng Zhao 527058e0e84SYifeng Zhao if (!buf) 528058e0e84SYifeng Zhao memset(nfc->page_buf, 0xff, mtd->writesize + mtd->oobsize); 529058e0e84SYifeng Zhao 530058e0e84SYifeng Zhao for (i = 0; i < ecc->steps; i++) { 531058e0e84SYifeng Zhao /* Copy data to the NFC buffer. */ 532058e0e84SYifeng Zhao if (buf) 533058e0e84SYifeng Zhao memcpy(rk_nfc_data_ptr(chip, i), 534058e0e84SYifeng Zhao rk_nfc_buf_to_data_ptr(chip, buf, i), 535058e0e84SYifeng Zhao ecc->size); 536058e0e84SYifeng Zhao /* 537058e0e84SYifeng Zhao * The first four bytes of OOB are reserved for the 538058e0e84SYifeng Zhao * boot ROM. In some debugging cases, such as with a 539058e0e84SYifeng Zhao * read, erase and write back test these 4 bytes stored 540058e0e84SYifeng Zhao * in OOB also need to be written back. 541058e0e84SYifeng Zhao * 542058e0e84SYifeng Zhao * The function nand_block_bad detects bad blocks like: 543058e0e84SYifeng Zhao * 544058e0e84SYifeng Zhao * bad = chip->oob_poi[chip->badblockpos]; 545058e0e84SYifeng Zhao * 546058e0e84SYifeng Zhao * chip->badblockpos == 0 for a large page NAND Flash, 547058e0e84SYifeng Zhao * so chip->oob_poi[0] is the bad block mask (BBM). 548058e0e84SYifeng Zhao * 549058e0e84SYifeng Zhao * The OOB data layout on the NFC is: 550058e0e84SYifeng Zhao * 551058e0e84SYifeng Zhao * PA0 PA1 PA2 PA3 | BBM OOB1 OOB2 OOB3 | ... 552058e0e84SYifeng Zhao * 553058e0e84SYifeng Zhao * or 554058e0e84SYifeng Zhao * 555058e0e84SYifeng Zhao * 0xFF 0xFF 0xFF 0xFF | BBM OOB1 OOB2 OOB3 | ... 556058e0e84SYifeng Zhao * 557058e0e84SYifeng Zhao * The code here just swaps the first 4 bytes with the last 558058e0e84SYifeng Zhao * 4 bytes without losing any data. 559058e0e84SYifeng Zhao * 560058e0e84SYifeng Zhao * The chip->oob_poi data layout: 561058e0e84SYifeng Zhao * 562058e0e84SYifeng Zhao * BBM OOB1 OOB2 OOB3 |......| PA0 PA1 PA2 PA3 563058e0e84SYifeng Zhao * 564058e0e84SYifeng Zhao * The rk_nfc_ooblayout_free() function already has reserved 565058e0e84SYifeng Zhao * these 4 bytes with: 566058e0e84SYifeng Zhao * 567058e0e84SYifeng Zhao * oob_region->offset = NFC_SYS_DATA_SIZE + 2; 568058e0e84SYifeng Zhao */ 569058e0e84SYifeng Zhao if (!i) 570058e0e84SYifeng Zhao memcpy(rk_nfc_oob_ptr(chip, i), 571058e0e84SYifeng Zhao rk_nfc_buf_to_oob_ptr(chip, ecc->steps - 1), 572058e0e84SYifeng Zhao NFC_SYS_DATA_SIZE); 573058e0e84SYifeng Zhao else 574058e0e84SYifeng Zhao memcpy(rk_nfc_oob_ptr(chip, i), 575058e0e84SYifeng Zhao rk_nfc_buf_to_oob_ptr(chip, i - 1), 576058e0e84SYifeng Zhao NFC_SYS_DATA_SIZE); 577058e0e84SYifeng Zhao /* Copy ECC data to the NFC buffer. */ 578058e0e84SYifeng Zhao memcpy(rk_nfc_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE, 579058e0e84SYifeng Zhao rk_nfc_buf_to_oob_ecc_ptr(chip, i), 580058e0e84SYifeng Zhao ecc->bytes); 581058e0e84SYifeng Zhao } 582058e0e84SYifeng Zhao 583058e0e84SYifeng Zhao nand_prog_page_begin_op(chip, page, 0, NULL, 0); 584058e0e84SYifeng Zhao rk_nfc_write_buf(nfc, buf, mtd->writesize + mtd->oobsize); 585058e0e84SYifeng Zhao return nand_prog_page_end_op(chip); 586058e0e84SYifeng Zhao } 587058e0e84SYifeng Zhao 588058e0e84SYifeng Zhao static int rk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf, 589058e0e84SYifeng Zhao int oob_on, int page) 590058e0e84SYifeng Zhao { 591058e0e84SYifeng Zhao struct mtd_info *mtd = nand_to_mtd(chip); 592058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 593058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 594058e0e84SYifeng Zhao struct nand_ecc_ctrl *ecc = &chip->ecc; 595058e0e84SYifeng Zhao int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP : 596058e0e84SYifeng Zhao NFC_MIN_OOB_PER_STEP; 597058e0e84SYifeng Zhao int pages_per_blk = mtd->erasesize / mtd->writesize; 598058e0e84SYifeng Zhao int ret = 0, i, boot_rom_mode = 0; 599058e0e84SYifeng Zhao dma_addr_t dma_data, dma_oob; 600058e0e84SYifeng Zhao u32 reg; 601058e0e84SYifeng Zhao u8 *oob; 602058e0e84SYifeng Zhao 603058e0e84SYifeng Zhao nand_prog_page_begin_op(chip, page, 0, NULL, 0); 604058e0e84SYifeng Zhao 605058e0e84SYifeng Zhao if (buf) 606058e0e84SYifeng Zhao memcpy(nfc->page_buf, buf, mtd->writesize); 607058e0e84SYifeng Zhao else 608058e0e84SYifeng Zhao memset(nfc->page_buf, 0xFF, mtd->writesize); 609058e0e84SYifeng Zhao 610058e0e84SYifeng Zhao /* 611058e0e84SYifeng Zhao * The first blocks (4, 8 or 16 depending on the device) are used 612058e0e84SYifeng Zhao * by the boot ROM and the first 32 bits of OOB need to link to 613058e0e84SYifeng Zhao * the next page address in the same block. We can't directly copy 614058e0e84SYifeng Zhao * OOB data from the MTD framework, because this page address 615058e0e84SYifeng Zhao * conflicts for example with the bad block marker (BBM), 616058e0e84SYifeng Zhao * so we shift all OOB data including the BBM with 4 byte positions. 617058e0e84SYifeng Zhao * As a consequence the OOB size available to the MTD framework is 618058e0e84SYifeng Zhao * also reduced with 4 bytes. 619058e0e84SYifeng Zhao * 620058e0e84SYifeng Zhao * PA0 PA1 PA2 PA3 | BBM OOB1 OOB2 OOB3 | ... 621058e0e84SYifeng Zhao * 622058e0e84SYifeng Zhao * If a NAND is not a boot medium or the page is not a boot block, 623058e0e84SYifeng Zhao * the first 4 bytes are left untouched by writing 0xFF to them. 624058e0e84SYifeng Zhao * 625058e0e84SYifeng Zhao * 0xFF 0xFF 0xFF 0xFF | BBM OOB1 OOB2 OOB3 | ... 626058e0e84SYifeng Zhao * 627058e0e84SYifeng Zhao * Configure the ECC algorithm supported by the boot ROM. 628058e0e84SYifeng Zhao */ 629058e0e84SYifeng Zhao if ((page < (pages_per_blk * rknand->boot_blks)) && 630058e0e84SYifeng Zhao (chip->options & NAND_IS_BOOT_MEDIUM)) { 631058e0e84SYifeng Zhao boot_rom_mode = 1; 632058e0e84SYifeng Zhao if (rknand->boot_ecc != ecc->strength) 633058e0e84SYifeng Zhao rk_nfc_hw_ecc_setup(chip, rknand->boot_ecc); 634058e0e84SYifeng Zhao } 635058e0e84SYifeng Zhao 636058e0e84SYifeng Zhao for (i = 0; i < ecc->steps; i++) { 637058e0e84SYifeng Zhao if (!i) { 638058e0e84SYifeng Zhao reg = 0xFFFFFFFF; 639058e0e84SYifeng Zhao } else { 640058e0e84SYifeng Zhao oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE; 641058e0e84SYifeng Zhao reg = oob[0] | oob[1] << 8 | oob[2] << 16 | 642058e0e84SYifeng Zhao oob[3] << 24; 643058e0e84SYifeng Zhao } 644058e0e84SYifeng Zhao 645058e0e84SYifeng Zhao if (!i && boot_rom_mode) 646058e0e84SYifeng Zhao reg = (page & (pages_per_blk - 1)) * 4; 647058e0e84SYifeng Zhao 648058e0e84SYifeng Zhao if (nfc->cfg->type == NFC_V9) 649058e0e84SYifeng Zhao nfc->oob_buf[i] = reg; 650058e0e84SYifeng Zhao else 651058e0e84SYifeng Zhao nfc->oob_buf[i * (oob_step / 4)] = reg; 652058e0e84SYifeng Zhao } 653058e0e84SYifeng Zhao 654058e0e84SYifeng Zhao dma_data = dma_map_single(nfc->dev, (void *)nfc->page_buf, 655058e0e84SYifeng Zhao mtd->writesize, DMA_TO_DEVICE); 656058e0e84SYifeng Zhao dma_oob = dma_map_single(nfc->dev, nfc->oob_buf, 657058e0e84SYifeng Zhao ecc->steps * oob_step, 658058e0e84SYifeng Zhao DMA_TO_DEVICE); 659058e0e84SYifeng Zhao 660058e0e84SYifeng Zhao reinit_completion(&nfc->done); 661058e0e84SYifeng Zhao writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off); 662058e0e84SYifeng Zhao 663058e0e84SYifeng Zhao rk_nfc_xfer_start(nfc, NFC_WRITE, ecc->steps, dma_data, 664058e0e84SYifeng Zhao dma_oob); 665058e0e84SYifeng Zhao ret = wait_for_completion_timeout(&nfc->done, 666058e0e84SYifeng Zhao msecs_to_jiffies(100)); 667058e0e84SYifeng Zhao if (!ret) 668058e0e84SYifeng Zhao dev_warn(nfc->dev, "write: wait dma done timeout.\n"); 669058e0e84SYifeng Zhao /* 670058e0e84SYifeng Zhao * Whether the DMA transfer is completed or not. The driver 671058e0e84SYifeng Zhao * needs to check the NFC`s status register to see if the data 672058e0e84SYifeng Zhao * transfer was completed. 673058e0e84SYifeng Zhao */ 674058e0e84SYifeng Zhao ret = rk_nfc_wait_for_xfer_done(nfc); 675058e0e84SYifeng Zhao 676058e0e84SYifeng Zhao dma_unmap_single(nfc->dev, dma_data, mtd->writesize, 677058e0e84SYifeng Zhao DMA_TO_DEVICE); 678058e0e84SYifeng Zhao dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step, 679058e0e84SYifeng Zhao DMA_TO_DEVICE); 680058e0e84SYifeng Zhao 681058e0e84SYifeng Zhao if (boot_rom_mode && rknand->boot_ecc != ecc->strength) 682058e0e84SYifeng Zhao rk_nfc_hw_ecc_setup(chip, ecc->strength); 683058e0e84SYifeng Zhao 684058e0e84SYifeng Zhao if (ret) { 685058e0e84SYifeng Zhao dev_err(nfc->dev, "write: wait transfer done timeout.\n"); 686058e0e84SYifeng Zhao return -ETIMEDOUT; 687058e0e84SYifeng Zhao } 688058e0e84SYifeng Zhao 689058e0e84SYifeng Zhao return nand_prog_page_end_op(chip); 690058e0e84SYifeng Zhao } 691058e0e84SYifeng Zhao 692058e0e84SYifeng Zhao static int rk_nfc_write_oob(struct nand_chip *chip, int page) 693058e0e84SYifeng Zhao { 694058e0e84SYifeng Zhao return rk_nfc_write_page_hwecc(chip, NULL, 1, page); 695058e0e84SYifeng Zhao } 696058e0e84SYifeng Zhao 697058e0e84SYifeng Zhao static int rk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on, 698058e0e84SYifeng Zhao int page) 699058e0e84SYifeng Zhao { 700058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 701058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 702058e0e84SYifeng Zhao struct mtd_info *mtd = nand_to_mtd(chip); 703058e0e84SYifeng Zhao struct nand_ecc_ctrl *ecc = &chip->ecc; 704058e0e84SYifeng Zhao int i, pages_per_blk; 705058e0e84SYifeng Zhao 706058e0e84SYifeng Zhao pages_per_blk = mtd->erasesize / mtd->writesize; 707058e0e84SYifeng Zhao if ((chip->options & NAND_IS_BOOT_MEDIUM) && 708058e0e84SYifeng Zhao (page < (pages_per_blk * rknand->boot_blks)) && 709058e0e84SYifeng Zhao rknand->boot_ecc != ecc->strength) { 710058e0e84SYifeng Zhao /* 711058e0e84SYifeng Zhao * There's currently no method to notify the MTD framework that 712058e0e84SYifeng Zhao * a different ECC strength is in use for the boot blocks. 713058e0e84SYifeng Zhao */ 714058e0e84SYifeng Zhao return -EIO; 715058e0e84SYifeng Zhao } 716058e0e84SYifeng Zhao 717058e0e84SYifeng Zhao nand_read_page_op(chip, page, 0, NULL, 0); 718058e0e84SYifeng Zhao rk_nfc_read_buf(nfc, nfc->page_buf, mtd->writesize + mtd->oobsize); 719058e0e84SYifeng Zhao for (i = 0; i < ecc->steps; i++) { 720058e0e84SYifeng Zhao /* 721058e0e84SYifeng Zhao * The first four bytes of OOB are reserved for the 722058e0e84SYifeng Zhao * boot ROM. In some debugging cases, such as with a read, 723058e0e84SYifeng Zhao * erase and write back test, these 4 bytes also must be 724058e0e84SYifeng Zhao * saved somewhere, otherwise this information will be 725058e0e84SYifeng Zhao * lost during a write back. 726058e0e84SYifeng Zhao */ 727058e0e84SYifeng Zhao if (!i) 728058e0e84SYifeng Zhao memcpy(rk_nfc_buf_to_oob_ptr(chip, ecc->steps - 1), 729058e0e84SYifeng Zhao rk_nfc_oob_ptr(chip, i), 730058e0e84SYifeng Zhao NFC_SYS_DATA_SIZE); 731058e0e84SYifeng Zhao else 732058e0e84SYifeng Zhao memcpy(rk_nfc_buf_to_oob_ptr(chip, i - 1), 733058e0e84SYifeng Zhao rk_nfc_oob_ptr(chip, i), 734058e0e84SYifeng Zhao NFC_SYS_DATA_SIZE); 735058e0e84SYifeng Zhao 736058e0e84SYifeng Zhao /* Copy ECC data from the NFC buffer. */ 737058e0e84SYifeng Zhao memcpy(rk_nfc_buf_to_oob_ecc_ptr(chip, i), 738058e0e84SYifeng Zhao rk_nfc_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE, 739058e0e84SYifeng Zhao ecc->bytes); 740058e0e84SYifeng Zhao 741058e0e84SYifeng Zhao /* Copy data from the NFC buffer. */ 742058e0e84SYifeng Zhao if (buf) 743058e0e84SYifeng Zhao memcpy(rk_nfc_buf_to_data_ptr(chip, buf, i), 744058e0e84SYifeng Zhao rk_nfc_data_ptr(chip, i), 745058e0e84SYifeng Zhao ecc->size); 746058e0e84SYifeng Zhao } 747058e0e84SYifeng Zhao 748058e0e84SYifeng Zhao return 0; 749058e0e84SYifeng Zhao } 750058e0e84SYifeng Zhao 751058e0e84SYifeng Zhao static int rk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *buf, int oob_on, 752058e0e84SYifeng Zhao int page) 753058e0e84SYifeng Zhao { 754058e0e84SYifeng Zhao struct mtd_info *mtd = nand_to_mtd(chip); 755058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 756058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 757058e0e84SYifeng Zhao struct nand_ecc_ctrl *ecc = &chip->ecc; 758058e0e84SYifeng Zhao int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP : 759058e0e84SYifeng Zhao NFC_MIN_OOB_PER_STEP; 760058e0e84SYifeng Zhao int pages_per_blk = mtd->erasesize / mtd->writesize; 761058e0e84SYifeng Zhao dma_addr_t dma_data, dma_oob; 762058e0e84SYifeng Zhao int ret = 0, i, cnt, boot_rom_mode = 0; 763058e0e84SYifeng Zhao int max_bitflips = 0, bch_st, ecc_fail = 0; 764058e0e84SYifeng Zhao u8 *oob; 765058e0e84SYifeng Zhao u32 tmp; 766058e0e84SYifeng Zhao 767058e0e84SYifeng Zhao nand_read_page_op(chip, page, 0, NULL, 0); 768058e0e84SYifeng Zhao 769058e0e84SYifeng Zhao dma_data = dma_map_single(nfc->dev, nfc->page_buf, 770058e0e84SYifeng Zhao mtd->writesize, 771058e0e84SYifeng Zhao DMA_FROM_DEVICE); 772058e0e84SYifeng Zhao dma_oob = dma_map_single(nfc->dev, nfc->oob_buf, 773058e0e84SYifeng Zhao ecc->steps * oob_step, 774058e0e84SYifeng Zhao DMA_FROM_DEVICE); 775058e0e84SYifeng Zhao 776058e0e84SYifeng Zhao /* 777058e0e84SYifeng Zhao * The first blocks (4, 8 or 16 depending on the device) 778058e0e84SYifeng Zhao * are used by the boot ROM. 779058e0e84SYifeng Zhao * Configure the ECC algorithm supported by the boot ROM. 780058e0e84SYifeng Zhao */ 781058e0e84SYifeng Zhao if ((page < (pages_per_blk * rknand->boot_blks)) && 782058e0e84SYifeng Zhao (chip->options & NAND_IS_BOOT_MEDIUM)) { 783058e0e84SYifeng Zhao boot_rom_mode = 1; 784058e0e84SYifeng Zhao if (rknand->boot_ecc != ecc->strength) 785058e0e84SYifeng Zhao rk_nfc_hw_ecc_setup(chip, rknand->boot_ecc); 786058e0e84SYifeng Zhao } 787058e0e84SYifeng Zhao 788058e0e84SYifeng Zhao reinit_completion(&nfc->done); 789058e0e84SYifeng Zhao writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off); 790058e0e84SYifeng Zhao rk_nfc_xfer_start(nfc, NFC_READ, ecc->steps, dma_data, 791058e0e84SYifeng Zhao dma_oob); 792058e0e84SYifeng Zhao ret = wait_for_completion_timeout(&nfc->done, 793058e0e84SYifeng Zhao msecs_to_jiffies(100)); 794058e0e84SYifeng Zhao if (!ret) 795058e0e84SYifeng Zhao dev_warn(nfc->dev, "read: wait dma done timeout.\n"); 796058e0e84SYifeng Zhao /* 797058e0e84SYifeng Zhao * Whether the DMA transfer is completed or not. The driver 798058e0e84SYifeng Zhao * needs to check the NFC`s status register to see if the data 799058e0e84SYifeng Zhao * transfer was completed. 800058e0e84SYifeng Zhao */ 801058e0e84SYifeng Zhao ret = rk_nfc_wait_for_xfer_done(nfc); 802058e0e84SYifeng Zhao 803058e0e84SYifeng Zhao dma_unmap_single(nfc->dev, dma_data, mtd->writesize, 804058e0e84SYifeng Zhao DMA_FROM_DEVICE); 805058e0e84SYifeng Zhao dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step, 806058e0e84SYifeng Zhao DMA_FROM_DEVICE); 807058e0e84SYifeng Zhao 808058e0e84SYifeng Zhao if (ret) { 809058e0e84SYifeng Zhao ret = -ETIMEDOUT; 810058e0e84SYifeng Zhao dev_err(nfc->dev, "read: wait transfer done timeout.\n"); 811058e0e84SYifeng Zhao goto timeout_err; 812058e0e84SYifeng Zhao } 813058e0e84SYifeng Zhao 814058e0e84SYifeng Zhao for (i = 1; i < ecc->steps; i++) { 815058e0e84SYifeng Zhao oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE; 816058e0e84SYifeng Zhao if (nfc->cfg->type == NFC_V9) 817058e0e84SYifeng Zhao tmp = nfc->oob_buf[i]; 818058e0e84SYifeng Zhao else 819058e0e84SYifeng Zhao tmp = nfc->oob_buf[i * (oob_step / 4)]; 820058e0e84SYifeng Zhao *oob++ = (u8)tmp; 821058e0e84SYifeng Zhao *oob++ = (u8)(tmp >> 8); 822058e0e84SYifeng Zhao *oob++ = (u8)(tmp >> 16); 823058e0e84SYifeng Zhao *oob++ = (u8)(tmp >> 24); 824058e0e84SYifeng Zhao } 825058e0e84SYifeng Zhao 826058e0e84SYifeng Zhao for (i = 0; i < (ecc->steps / 2); i++) { 827058e0e84SYifeng Zhao bch_st = readl_relaxed(nfc->regs + 828058e0e84SYifeng Zhao nfc->cfg->bch_st_off + i * 4); 829058e0e84SYifeng Zhao if (bch_st & BIT(nfc->cfg->ecc0.err_flag_bit) || 830058e0e84SYifeng Zhao bch_st & BIT(nfc->cfg->ecc1.err_flag_bit)) { 831058e0e84SYifeng Zhao mtd->ecc_stats.failed++; 832058e0e84SYifeng Zhao ecc_fail = 1; 833058e0e84SYifeng Zhao } else { 834058e0e84SYifeng Zhao cnt = ECC_ERR_CNT(bch_st, nfc->cfg->ecc0); 835058e0e84SYifeng Zhao mtd->ecc_stats.corrected += cnt; 836058e0e84SYifeng Zhao max_bitflips = max_t(u32, max_bitflips, cnt); 837058e0e84SYifeng Zhao 838058e0e84SYifeng Zhao cnt = ECC_ERR_CNT(bch_st, nfc->cfg->ecc1); 839058e0e84SYifeng Zhao mtd->ecc_stats.corrected += cnt; 840058e0e84SYifeng Zhao max_bitflips = max_t(u32, max_bitflips, cnt); 841058e0e84SYifeng Zhao } 842058e0e84SYifeng Zhao } 843058e0e84SYifeng Zhao 844058e0e84SYifeng Zhao if (buf) 845058e0e84SYifeng Zhao memcpy(buf, nfc->page_buf, mtd->writesize); 846058e0e84SYifeng Zhao 847058e0e84SYifeng Zhao timeout_err: 848058e0e84SYifeng Zhao if (boot_rom_mode && rknand->boot_ecc != ecc->strength) 849058e0e84SYifeng Zhao rk_nfc_hw_ecc_setup(chip, ecc->strength); 850058e0e84SYifeng Zhao 851058e0e84SYifeng Zhao if (ret) 852058e0e84SYifeng Zhao return ret; 853058e0e84SYifeng Zhao 854058e0e84SYifeng Zhao if (ecc_fail) { 855058e0e84SYifeng Zhao dev_err(nfc->dev, "read page: %x ecc error!\n", page); 856058e0e84SYifeng Zhao return 0; 857058e0e84SYifeng Zhao } 858058e0e84SYifeng Zhao 859058e0e84SYifeng Zhao return max_bitflips; 860058e0e84SYifeng Zhao } 861058e0e84SYifeng Zhao 862058e0e84SYifeng Zhao static int rk_nfc_read_oob(struct nand_chip *chip, int page) 863058e0e84SYifeng Zhao { 864058e0e84SYifeng Zhao return rk_nfc_read_page_hwecc(chip, NULL, 1, page); 865058e0e84SYifeng Zhao } 866058e0e84SYifeng Zhao 867058e0e84SYifeng Zhao static inline void rk_nfc_hw_init(struct rk_nfc *nfc) 868058e0e84SYifeng Zhao { 869058e0e84SYifeng Zhao /* Disable flash wp. */ 870058e0e84SYifeng Zhao writel(FMCTL_WP, nfc->regs + NFC_FMCTL); 871058e0e84SYifeng Zhao /* Config default timing 40ns at 150 Mhz NFC clock. */ 872058e0e84SYifeng Zhao writel(0x1081, nfc->regs + NFC_FMWAIT); 873058e0e84SYifeng Zhao nfc->cur_timing = 0x1081; 874058e0e84SYifeng Zhao /* Disable randomizer and DMA. */ 875058e0e84SYifeng Zhao writel(0, nfc->regs + nfc->cfg->randmz_off); 876058e0e84SYifeng Zhao writel(0, nfc->regs + nfc->cfg->dma_cfg_off); 877058e0e84SYifeng Zhao writel(FLCTL_RST, nfc->regs + nfc->cfg->flctl_off); 878058e0e84SYifeng Zhao } 879058e0e84SYifeng Zhao 880058e0e84SYifeng Zhao static irqreturn_t rk_nfc_irq(int irq, void *id) 881058e0e84SYifeng Zhao { 882058e0e84SYifeng Zhao struct rk_nfc *nfc = id; 883058e0e84SYifeng Zhao u32 sta, ien; 884058e0e84SYifeng Zhao 885058e0e84SYifeng Zhao sta = readl_relaxed(nfc->regs + nfc->cfg->int_st_off); 886058e0e84SYifeng Zhao ien = readl_relaxed(nfc->regs + nfc->cfg->int_en_off); 887058e0e84SYifeng Zhao 888058e0e84SYifeng Zhao if (!(sta & ien)) 889058e0e84SYifeng Zhao return IRQ_NONE; 890058e0e84SYifeng Zhao 891058e0e84SYifeng Zhao writel(sta, nfc->regs + nfc->cfg->int_clr_off); 892058e0e84SYifeng Zhao writel(~sta & ien, nfc->regs + nfc->cfg->int_en_off); 893058e0e84SYifeng Zhao 894058e0e84SYifeng Zhao complete(&nfc->done); 895058e0e84SYifeng Zhao 896058e0e84SYifeng Zhao return IRQ_HANDLED; 897058e0e84SYifeng Zhao } 898058e0e84SYifeng Zhao 899058e0e84SYifeng Zhao static int rk_nfc_enable_clks(struct device *dev, struct rk_nfc *nfc) 900058e0e84SYifeng Zhao { 901058e0e84SYifeng Zhao int ret; 902058e0e84SYifeng Zhao 903058e0e84SYifeng Zhao if (!IS_ERR(nfc->nfc_clk)) { 904058e0e84SYifeng Zhao ret = clk_prepare_enable(nfc->nfc_clk); 905058e0e84SYifeng Zhao if (ret) { 906058e0e84SYifeng Zhao dev_err(dev, "failed to enable NFC clk\n"); 907058e0e84SYifeng Zhao return ret; 908058e0e84SYifeng Zhao } 909058e0e84SYifeng Zhao } 910058e0e84SYifeng Zhao 911058e0e84SYifeng Zhao ret = clk_prepare_enable(nfc->ahb_clk); 912058e0e84SYifeng Zhao if (ret) { 913058e0e84SYifeng Zhao dev_err(dev, "failed to enable ahb clk\n"); 914058e0e84SYifeng Zhao if (!IS_ERR(nfc->nfc_clk)) 915058e0e84SYifeng Zhao clk_disable_unprepare(nfc->nfc_clk); 916058e0e84SYifeng Zhao return ret; 917058e0e84SYifeng Zhao } 918058e0e84SYifeng Zhao 919058e0e84SYifeng Zhao return 0; 920058e0e84SYifeng Zhao } 921058e0e84SYifeng Zhao 922058e0e84SYifeng Zhao static void rk_nfc_disable_clks(struct rk_nfc *nfc) 923058e0e84SYifeng Zhao { 924058e0e84SYifeng Zhao if (!IS_ERR(nfc->nfc_clk)) 925058e0e84SYifeng Zhao clk_disable_unprepare(nfc->nfc_clk); 926058e0e84SYifeng Zhao clk_disable_unprepare(nfc->ahb_clk); 927058e0e84SYifeng Zhao } 928058e0e84SYifeng Zhao 929058e0e84SYifeng Zhao static int rk_nfc_ooblayout_free(struct mtd_info *mtd, int section, 930058e0e84SYifeng Zhao struct mtd_oob_region *oob_region) 931058e0e84SYifeng Zhao { 932058e0e84SYifeng Zhao struct nand_chip *chip = mtd_to_nand(mtd); 933058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 934058e0e84SYifeng Zhao 935058e0e84SYifeng Zhao if (section) 936058e0e84SYifeng Zhao return -ERANGE; 937058e0e84SYifeng Zhao 938058e0e84SYifeng Zhao /* 939058e0e84SYifeng Zhao * The beginning of the OOB area stores the reserved data for the NFC, 940058e0e84SYifeng Zhao * the size of the reserved data is NFC_SYS_DATA_SIZE bytes. 941058e0e84SYifeng Zhao */ 942058e0e84SYifeng Zhao oob_region->length = rknand->metadata_size - NFC_SYS_DATA_SIZE - 2; 943058e0e84SYifeng Zhao oob_region->offset = NFC_SYS_DATA_SIZE + 2; 944058e0e84SYifeng Zhao 945058e0e84SYifeng Zhao return 0; 946058e0e84SYifeng Zhao } 947058e0e84SYifeng Zhao 948058e0e84SYifeng Zhao static int rk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section, 949058e0e84SYifeng Zhao struct mtd_oob_region *oob_region) 950058e0e84SYifeng Zhao { 951058e0e84SYifeng Zhao struct nand_chip *chip = mtd_to_nand(mtd); 952058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 953058e0e84SYifeng Zhao 954058e0e84SYifeng Zhao if (section) 955058e0e84SYifeng Zhao return -ERANGE; 956058e0e84SYifeng Zhao 957058e0e84SYifeng Zhao oob_region->length = mtd->oobsize - rknand->metadata_size; 958058e0e84SYifeng Zhao oob_region->offset = rknand->metadata_size; 959058e0e84SYifeng Zhao 960058e0e84SYifeng Zhao return 0; 961058e0e84SYifeng Zhao } 962058e0e84SYifeng Zhao 963058e0e84SYifeng Zhao static const struct mtd_ooblayout_ops rk_nfc_ooblayout_ops = { 964058e0e84SYifeng Zhao .free = rk_nfc_ooblayout_free, 965058e0e84SYifeng Zhao .ecc = rk_nfc_ooblayout_ecc, 966058e0e84SYifeng Zhao }; 967058e0e84SYifeng Zhao 968058e0e84SYifeng Zhao static int rk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd) 969058e0e84SYifeng Zhao { 970058e0e84SYifeng Zhao struct nand_chip *chip = mtd_to_nand(mtd); 971058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 972058e0e84SYifeng Zhao struct nand_ecc_ctrl *ecc = &chip->ecc; 973058e0e84SYifeng Zhao const u8 *strengths = nfc->cfg->ecc_strengths; 974058e0e84SYifeng Zhao u8 max_strength, nfc_max_strength; 975058e0e84SYifeng Zhao int i; 976058e0e84SYifeng Zhao 977058e0e84SYifeng Zhao nfc_max_strength = nfc->cfg->ecc_strengths[0]; 978058e0e84SYifeng Zhao /* If optional dt settings not present. */ 979058e0e84SYifeng Zhao if (!ecc->size || !ecc->strength || 980058e0e84SYifeng Zhao ecc->strength > nfc_max_strength) { 981058e0e84SYifeng Zhao chip->ecc.size = 1024; 982058e0e84SYifeng Zhao ecc->steps = mtd->writesize / ecc->size; 983058e0e84SYifeng Zhao 984058e0e84SYifeng Zhao /* 985058e0e84SYifeng Zhao * HW ECC always requests the number of ECC bytes per 1024 byte 986058e0e84SYifeng Zhao * blocks. The first 4 OOB bytes are reserved for sys data. 987058e0e84SYifeng Zhao */ 988058e0e84SYifeng Zhao max_strength = ((mtd->oobsize / ecc->steps) - 4) * 8 / 989058e0e84SYifeng Zhao fls(8 * 1024); 990058e0e84SYifeng Zhao if (max_strength > nfc_max_strength) 991058e0e84SYifeng Zhao max_strength = nfc_max_strength; 992058e0e84SYifeng Zhao 993058e0e84SYifeng Zhao for (i = 0; i < 4; i++) { 994058e0e84SYifeng Zhao if (max_strength >= strengths[i]) 995058e0e84SYifeng Zhao break; 996058e0e84SYifeng Zhao } 997058e0e84SYifeng Zhao 998058e0e84SYifeng Zhao if (i >= 4) { 999058e0e84SYifeng Zhao dev_err(nfc->dev, "unsupported ECC strength\n"); 1000058e0e84SYifeng Zhao return -EOPNOTSUPP; 1001058e0e84SYifeng Zhao } 1002058e0e84SYifeng Zhao 1003058e0e84SYifeng Zhao ecc->strength = strengths[i]; 1004058e0e84SYifeng Zhao } 1005058e0e84SYifeng Zhao ecc->steps = mtd->writesize / ecc->size; 1006058e0e84SYifeng Zhao ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * chip->ecc.size), 8); 1007058e0e84SYifeng Zhao 1008058e0e84SYifeng Zhao return 0; 1009058e0e84SYifeng Zhao } 1010058e0e84SYifeng Zhao 1011058e0e84SYifeng Zhao static int rk_nfc_attach_chip(struct nand_chip *chip) 1012058e0e84SYifeng Zhao { 1013058e0e84SYifeng Zhao struct mtd_info *mtd = nand_to_mtd(chip); 1014058e0e84SYifeng Zhao struct device *dev = mtd->dev.parent; 1015058e0e84SYifeng Zhao struct rk_nfc *nfc = nand_get_controller_data(chip); 1016058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip); 1017058e0e84SYifeng Zhao struct nand_ecc_ctrl *ecc = &chip->ecc; 1018058e0e84SYifeng Zhao int new_page_len, new_oob_len; 1019058e0e84SYifeng Zhao void *buf; 1020058e0e84SYifeng Zhao int ret; 1021058e0e84SYifeng Zhao 1022058e0e84SYifeng Zhao if (chip->options & NAND_BUSWIDTH_16) { 1023058e0e84SYifeng Zhao dev_err(dev, "16 bits bus width not supported"); 1024058e0e84SYifeng Zhao return -EINVAL; 1025058e0e84SYifeng Zhao } 1026058e0e84SYifeng Zhao 1027058e0e84SYifeng Zhao if (ecc->engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST) 1028058e0e84SYifeng Zhao return 0; 1029058e0e84SYifeng Zhao 1030058e0e84SYifeng Zhao ret = rk_nfc_ecc_init(dev, mtd); 1031058e0e84SYifeng Zhao if (ret) 1032058e0e84SYifeng Zhao return ret; 1033058e0e84SYifeng Zhao 1034058e0e84SYifeng Zhao rknand->metadata_size = NFC_SYS_DATA_SIZE * ecc->steps; 1035058e0e84SYifeng Zhao 1036058e0e84SYifeng Zhao if (rknand->metadata_size < NFC_SYS_DATA_SIZE + 2) { 1037058e0e84SYifeng Zhao dev_err(dev, 1038058e0e84SYifeng Zhao "driver needs at least %d bytes of meta data\n", 1039058e0e84SYifeng Zhao NFC_SYS_DATA_SIZE + 2); 1040058e0e84SYifeng Zhao return -EIO; 1041058e0e84SYifeng Zhao } 1042058e0e84SYifeng Zhao 1043058e0e84SYifeng Zhao /* Check buffer first, avoid duplicate alloc buffer. */ 1044058e0e84SYifeng Zhao new_page_len = mtd->writesize + mtd->oobsize; 1045058e0e84SYifeng Zhao if (nfc->page_buf && new_page_len > nfc->page_buf_size) { 1046058e0e84SYifeng Zhao buf = krealloc(nfc->page_buf, new_page_len, 1047058e0e84SYifeng Zhao GFP_KERNEL | GFP_DMA); 1048058e0e84SYifeng Zhao if (!buf) 1049058e0e84SYifeng Zhao return -ENOMEM; 1050058e0e84SYifeng Zhao nfc->page_buf = buf; 1051058e0e84SYifeng Zhao nfc->page_buf_size = new_page_len; 1052058e0e84SYifeng Zhao } 1053058e0e84SYifeng Zhao 1054058e0e84SYifeng Zhao new_oob_len = ecc->steps * NFC_MAX_OOB_PER_STEP; 1055058e0e84SYifeng Zhao if (nfc->oob_buf && new_oob_len > nfc->oob_buf_size) { 1056058e0e84SYifeng Zhao buf = krealloc(nfc->oob_buf, new_oob_len, 1057058e0e84SYifeng Zhao GFP_KERNEL | GFP_DMA); 1058058e0e84SYifeng Zhao if (!buf) { 1059058e0e84SYifeng Zhao kfree(nfc->page_buf); 1060058e0e84SYifeng Zhao nfc->page_buf = NULL; 1061058e0e84SYifeng Zhao return -ENOMEM; 1062058e0e84SYifeng Zhao } 1063058e0e84SYifeng Zhao nfc->oob_buf = buf; 1064058e0e84SYifeng Zhao nfc->oob_buf_size = new_oob_len; 1065058e0e84SYifeng Zhao } 1066058e0e84SYifeng Zhao 1067058e0e84SYifeng Zhao if (!nfc->page_buf) { 1068058e0e84SYifeng Zhao nfc->page_buf = kzalloc(new_page_len, GFP_KERNEL | GFP_DMA); 1069058e0e84SYifeng Zhao if (!nfc->page_buf) 1070058e0e84SYifeng Zhao return -ENOMEM; 1071058e0e84SYifeng Zhao nfc->page_buf_size = new_page_len; 1072058e0e84SYifeng Zhao } 1073058e0e84SYifeng Zhao 1074058e0e84SYifeng Zhao if (!nfc->oob_buf) { 1075058e0e84SYifeng Zhao nfc->oob_buf = kzalloc(new_oob_len, GFP_KERNEL | GFP_DMA); 1076058e0e84SYifeng Zhao if (!nfc->oob_buf) { 1077058e0e84SYifeng Zhao kfree(nfc->page_buf); 1078058e0e84SYifeng Zhao nfc->page_buf = NULL; 1079058e0e84SYifeng Zhao return -ENOMEM; 1080058e0e84SYifeng Zhao } 1081058e0e84SYifeng Zhao nfc->oob_buf_size = new_oob_len; 1082058e0e84SYifeng Zhao } 1083058e0e84SYifeng Zhao 1084058e0e84SYifeng Zhao chip->ecc.write_page_raw = rk_nfc_write_page_raw; 1085058e0e84SYifeng Zhao chip->ecc.write_page = rk_nfc_write_page_hwecc; 1086058e0e84SYifeng Zhao chip->ecc.write_oob = rk_nfc_write_oob; 1087058e0e84SYifeng Zhao 1088058e0e84SYifeng Zhao chip->ecc.read_page_raw = rk_nfc_read_page_raw; 1089058e0e84SYifeng Zhao chip->ecc.read_page = rk_nfc_read_page_hwecc; 1090058e0e84SYifeng Zhao chip->ecc.read_oob = rk_nfc_read_oob; 1091058e0e84SYifeng Zhao 1092058e0e84SYifeng Zhao return 0; 1093058e0e84SYifeng Zhao } 1094058e0e84SYifeng Zhao 1095058e0e84SYifeng Zhao static const struct nand_controller_ops rk_nfc_controller_ops = { 1096058e0e84SYifeng Zhao .attach_chip = rk_nfc_attach_chip, 1097058e0e84SYifeng Zhao .exec_op = rk_nfc_exec_op, 1098058e0e84SYifeng Zhao .setup_interface = rk_nfc_setup_interface, 1099058e0e84SYifeng Zhao }; 1100058e0e84SYifeng Zhao 1101058e0e84SYifeng Zhao static int rk_nfc_nand_chip_init(struct device *dev, struct rk_nfc *nfc, 1102058e0e84SYifeng Zhao struct device_node *np) 1103058e0e84SYifeng Zhao { 1104058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand; 1105058e0e84SYifeng Zhao struct nand_chip *chip; 1106058e0e84SYifeng Zhao struct mtd_info *mtd; 1107058e0e84SYifeng Zhao int nsels; 1108058e0e84SYifeng Zhao u32 tmp; 1109058e0e84SYifeng Zhao int ret; 1110058e0e84SYifeng Zhao int i; 1111058e0e84SYifeng Zhao 1112058e0e84SYifeng Zhao if (!of_get_property(np, "reg", &nsels)) 1113058e0e84SYifeng Zhao return -ENODEV; 1114058e0e84SYifeng Zhao nsels /= sizeof(u32); 1115058e0e84SYifeng Zhao if (!nsels || nsels > NFC_MAX_NSELS) { 1116058e0e84SYifeng Zhao dev_err(dev, "invalid reg property size %d\n", nsels); 1117058e0e84SYifeng Zhao return -EINVAL; 1118058e0e84SYifeng Zhao } 1119058e0e84SYifeng Zhao 1120058e0e84SYifeng Zhao rknand = devm_kzalloc(dev, sizeof(*rknand) + nsels * sizeof(u8), 1121058e0e84SYifeng Zhao GFP_KERNEL); 1122058e0e84SYifeng Zhao if (!rknand) 1123058e0e84SYifeng Zhao return -ENOMEM; 1124058e0e84SYifeng Zhao 1125058e0e84SYifeng Zhao rknand->nsels = nsels; 1126058e0e84SYifeng Zhao for (i = 0; i < nsels; i++) { 1127058e0e84SYifeng Zhao ret = of_property_read_u32_index(np, "reg", i, &tmp); 1128058e0e84SYifeng Zhao if (ret) { 1129058e0e84SYifeng Zhao dev_err(dev, "reg property failure : %d\n", ret); 1130058e0e84SYifeng Zhao return ret; 1131058e0e84SYifeng Zhao } 1132058e0e84SYifeng Zhao 1133058e0e84SYifeng Zhao if (tmp >= NFC_MAX_NSELS) { 1134058e0e84SYifeng Zhao dev_err(dev, "invalid CS: %u\n", tmp); 1135058e0e84SYifeng Zhao return -EINVAL; 1136058e0e84SYifeng Zhao } 1137058e0e84SYifeng Zhao 1138058e0e84SYifeng Zhao if (test_and_set_bit(tmp, &nfc->assigned_cs)) { 1139058e0e84SYifeng Zhao dev_err(dev, "CS %u already assigned\n", tmp); 1140058e0e84SYifeng Zhao return -EINVAL; 1141058e0e84SYifeng Zhao } 1142058e0e84SYifeng Zhao 1143058e0e84SYifeng Zhao rknand->sels[i] = tmp; 1144058e0e84SYifeng Zhao } 1145058e0e84SYifeng Zhao 1146058e0e84SYifeng Zhao chip = &rknand->chip; 1147058e0e84SYifeng Zhao chip->controller = &nfc->controller; 1148058e0e84SYifeng Zhao 1149058e0e84SYifeng Zhao nand_set_flash_node(chip, np); 1150058e0e84SYifeng Zhao 1151058e0e84SYifeng Zhao nand_set_controller_data(chip, nfc); 1152058e0e84SYifeng Zhao 1153058e0e84SYifeng Zhao chip->options |= NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE; 1154058e0e84SYifeng Zhao chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; 1155058e0e84SYifeng Zhao 1156058e0e84SYifeng Zhao /* Set default mode in case dt entry is missing. */ 1157058e0e84SYifeng Zhao chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; 1158058e0e84SYifeng Zhao 1159058e0e84SYifeng Zhao mtd = nand_to_mtd(chip); 1160058e0e84SYifeng Zhao mtd->owner = THIS_MODULE; 1161058e0e84SYifeng Zhao mtd->dev.parent = dev; 1162058e0e84SYifeng Zhao 1163058e0e84SYifeng Zhao if (!mtd->name) { 1164058e0e84SYifeng Zhao dev_err(nfc->dev, "NAND label property is mandatory\n"); 1165058e0e84SYifeng Zhao return -EINVAL; 1166058e0e84SYifeng Zhao } 1167058e0e84SYifeng Zhao 1168058e0e84SYifeng Zhao mtd_set_ooblayout(mtd, &rk_nfc_ooblayout_ops); 1169058e0e84SYifeng Zhao rk_nfc_hw_init(nfc); 1170058e0e84SYifeng Zhao ret = nand_scan(chip, nsels); 1171058e0e84SYifeng Zhao if (ret) 1172058e0e84SYifeng Zhao return ret; 1173058e0e84SYifeng Zhao 1174058e0e84SYifeng Zhao if (chip->options & NAND_IS_BOOT_MEDIUM) { 1175058e0e84SYifeng Zhao ret = of_property_read_u32(np, "rockchip,boot-blks", &tmp); 1176058e0e84SYifeng Zhao rknand->boot_blks = ret ? 0 : tmp; 1177058e0e84SYifeng Zhao 1178058e0e84SYifeng Zhao ret = of_property_read_u32(np, "rockchip,boot-ecc-strength", 1179058e0e84SYifeng Zhao &tmp); 1180058e0e84SYifeng Zhao rknand->boot_ecc = ret ? chip->ecc.strength : tmp; 1181058e0e84SYifeng Zhao } 1182058e0e84SYifeng Zhao 1183058e0e84SYifeng Zhao ret = mtd_device_register(mtd, NULL, 0); 1184058e0e84SYifeng Zhao if (ret) { 1185058e0e84SYifeng Zhao dev_err(dev, "MTD parse partition error\n"); 1186058e0e84SYifeng Zhao nand_cleanup(chip); 1187058e0e84SYifeng Zhao return ret; 1188058e0e84SYifeng Zhao } 1189058e0e84SYifeng Zhao 1190058e0e84SYifeng Zhao list_add_tail(&rknand->node, &nfc->chips); 1191058e0e84SYifeng Zhao 1192058e0e84SYifeng Zhao return 0; 1193058e0e84SYifeng Zhao } 1194058e0e84SYifeng Zhao 1195058e0e84SYifeng Zhao static void rk_nfc_chips_cleanup(struct rk_nfc *nfc) 1196058e0e84SYifeng Zhao { 1197058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand, *tmp; 1198058e0e84SYifeng Zhao struct nand_chip *chip; 1199058e0e84SYifeng Zhao int ret; 1200058e0e84SYifeng Zhao 1201058e0e84SYifeng Zhao list_for_each_entry_safe(rknand, tmp, &nfc->chips, node) { 1202058e0e84SYifeng Zhao chip = &rknand->chip; 1203058e0e84SYifeng Zhao ret = mtd_device_unregister(nand_to_mtd(chip)); 1204058e0e84SYifeng Zhao WARN_ON(ret); 1205058e0e84SYifeng Zhao nand_cleanup(chip); 1206058e0e84SYifeng Zhao list_del(&rknand->node); 1207058e0e84SYifeng Zhao } 1208058e0e84SYifeng Zhao } 1209058e0e84SYifeng Zhao 1210058e0e84SYifeng Zhao static int rk_nfc_nand_chips_init(struct device *dev, struct rk_nfc *nfc) 1211058e0e84SYifeng Zhao { 1212058e0e84SYifeng Zhao struct device_node *np = dev->of_node, *nand_np; 1213058e0e84SYifeng Zhao int nchips = of_get_child_count(np); 1214058e0e84SYifeng Zhao int ret; 1215058e0e84SYifeng Zhao 1216058e0e84SYifeng Zhao if (!nchips || nchips > NFC_MAX_NSELS) { 1217058e0e84SYifeng Zhao dev_err(nfc->dev, "incorrect number of NAND chips (%d)\n", 1218058e0e84SYifeng Zhao nchips); 1219058e0e84SYifeng Zhao return -EINVAL; 1220058e0e84SYifeng Zhao } 1221058e0e84SYifeng Zhao 1222058e0e84SYifeng Zhao for_each_child_of_node(np, nand_np) { 1223058e0e84SYifeng Zhao ret = rk_nfc_nand_chip_init(dev, nfc, nand_np); 1224058e0e84SYifeng Zhao if (ret) { 1225058e0e84SYifeng Zhao of_node_put(nand_np); 1226058e0e84SYifeng Zhao rk_nfc_chips_cleanup(nfc); 1227058e0e84SYifeng Zhao return ret; 1228058e0e84SYifeng Zhao } 1229058e0e84SYifeng Zhao } 1230058e0e84SYifeng Zhao 1231058e0e84SYifeng Zhao return 0; 1232058e0e84SYifeng Zhao } 1233058e0e84SYifeng Zhao 1234058e0e84SYifeng Zhao static struct nfc_cfg nfc_v6_cfg = { 1235058e0e84SYifeng Zhao .type = NFC_V6, 1236058e0e84SYifeng Zhao .ecc_strengths = {60, 40, 24, 16}, 1237058e0e84SYifeng Zhao .ecc_cfgs = { 1238058e0e84SYifeng Zhao 0x00040011, 0x00040001, 0x00000011, 0x00000001, 1239058e0e84SYifeng Zhao }, 1240058e0e84SYifeng Zhao .flctl_off = 0x08, 1241058e0e84SYifeng Zhao .bchctl_off = 0x0C, 1242058e0e84SYifeng Zhao .dma_cfg_off = 0x10, 1243058e0e84SYifeng Zhao .dma_data_buf_off = 0x14, 1244058e0e84SYifeng Zhao .dma_oob_buf_off = 0x18, 1245058e0e84SYifeng Zhao .dma_st_off = 0x1C, 1246058e0e84SYifeng Zhao .bch_st_off = 0x20, 1247058e0e84SYifeng Zhao .randmz_off = 0x150, 1248058e0e84SYifeng Zhao .int_en_off = 0x16C, 1249058e0e84SYifeng Zhao .int_clr_off = 0x170, 1250058e0e84SYifeng Zhao .int_st_off = 0x174, 1251058e0e84SYifeng Zhao .oob0_off = 0x200, 1252058e0e84SYifeng Zhao .oob1_off = 0x230, 1253058e0e84SYifeng Zhao .ecc0 = { 1254058e0e84SYifeng Zhao .err_flag_bit = 2, 1255058e0e84SYifeng Zhao .low = 3, 1256058e0e84SYifeng Zhao .low_mask = 0x1F, 1257058e0e84SYifeng Zhao .low_bn = 5, 1258058e0e84SYifeng Zhao .high = 27, 1259058e0e84SYifeng Zhao .high_mask = 0x1, 1260058e0e84SYifeng Zhao }, 1261058e0e84SYifeng Zhao .ecc1 = { 1262058e0e84SYifeng Zhao .err_flag_bit = 15, 1263058e0e84SYifeng Zhao .low = 16, 1264058e0e84SYifeng Zhao .low_mask = 0x1F, 1265058e0e84SYifeng Zhao .low_bn = 5, 1266058e0e84SYifeng Zhao .high = 29, 1267058e0e84SYifeng Zhao .high_mask = 0x1, 1268058e0e84SYifeng Zhao }, 1269058e0e84SYifeng Zhao }; 1270058e0e84SYifeng Zhao 1271058e0e84SYifeng Zhao static struct nfc_cfg nfc_v8_cfg = { 1272058e0e84SYifeng Zhao .type = NFC_V8, 1273058e0e84SYifeng Zhao .ecc_strengths = {16, 16, 16, 16}, 1274058e0e84SYifeng Zhao .ecc_cfgs = { 1275058e0e84SYifeng Zhao 0x00000001, 0x00000001, 0x00000001, 0x00000001, 1276058e0e84SYifeng Zhao }, 1277058e0e84SYifeng Zhao .flctl_off = 0x08, 1278058e0e84SYifeng Zhao .bchctl_off = 0x0C, 1279058e0e84SYifeng Zhao .dma_cfg_off = 0x10, 1280058e0e84SYifeng Zhao .dma_data_buf_off = 0x14, 1281058e0e84SYifeng Zhao .dma_oob_buf_off = 0x18, 1282058e0e84SYifeng Zhao .dma_st_off = 0x1C, 1283058e0e84SYifeng Zhao .bch_st_off = 0x20, 1284058e0e84SYifeng Zhao .randmz_off = 0x150, 1285058e0e84SYifeng Zhao .int_en_off = 0x16C, 1286058e0e84SYifeng Zhao .int_clr_off = 0x170, 1287058e0e84SYifeng Zhao .int_st_off = 0x174, 1288058e0e84SYifeng Zhao .oob0_off = 0x200, 1289058e0e84SYifeng Zhao .oob1_off = 0x230, 1290058e0e84SYifeng Zhao .ecc0 = { 1291058e0e84SYifeng Zhao .err_flag_bit = 2, 1292058e0e84SYifeng Zhao .low = 3, 1293058e0e84SYifeng Zhao .low_mask = 0x1F, 1294058e0e84SYifeng Zhao .low_bn = 5, 1295058e0e84SYifeng Zhao .high = 27, 1296058e0e84SYifeng Zhao .high_mask = 0x1, 1297058e0e84SYifeng Zhao }, 1298058e0e84SYifeng Zhao .ecc1 = { 1299058e0e84SYifeng Zhao .err_flag_bit = 15, 1300058e0e84SYifeng Zhao .low = 16, 1301058e0e84SYifeng Zhao .low_mask = 0x1F, 1302058e0e84SYifeng Zhao .low_bn = 5, 1303058e0e84SYifeng Zhao .high = 29, 1304058e0e84SYifeng Zhao .high_mask = 0x1, 1305058e0e84SYifeng Zhao }, 1306058e0e84SYifeng Zhao }; 1307058e0e84SYifeng Zhao 1308058e0e84SYifeng Zhao static struct nfc_cfg nfc_v9_cfg = { 1309058e0e84SYifeng Zhao .type = NFC_V9, 1310058e0e84SYifeng Zhao .ecc_strengths = {70, 60, 40, 16}, 1311058e0e84SYifeng Zhao .ecc_cfgs = { 1312058e0e84SYifeng Zhao 0x00000001, 0x06000001, 0x04000001, 0x02000001, 1313058e0e84SYifeng Zhao }, 1314058e0e84SYifeng Zhao .flctl_off = 0x10, 1315058e0e84SYifeng Zhao .bchctl_off = 0x20, 1316058e0e84SYifeng Zhao .dma_cfg_off = 0x30, 1317058e0e84SYifeng Zhao .dma_data_buf_off = 0x34, 1318058e0e84SYifeng Zhao .dma_oob_buf_off = 0x38, 1319058e0e84SYifeng Zhao .dma_st_off = 0x3C, 1320058e0e84SYifeng Zhao .bch_st_off = 0x150, 1321058e0e84SYifeng Zhao .randmz_off = 0x208, 1322058e0e84SYifeng Zhao .int_en_off = 0x120, 1323058e0e84SYifeng Zhao .int_clr_off = 0x124, 1324058e0e84SYifeng Zhao .int_st_off = 0x128, 1325058e0e84SYifeng Zhao .oob0_off = 0x200, 1326058e0e84SYifeng Zhao .oob1_off = 0x204, 1327058e0e84SYifeng Zhao .ecc0 = { 1328058e0e84SYifeng Zhao .err_flag_bit = 2, 1329058e0e84SYifeng Zhao .low = 3, 1330058e0e84SYifeng Zhao .low_mask = 0x7F, 1331058e0e84SYifeng Zhao .low_bn = 7, 1332058e0e84SYifeng Zhao .high = 0, 1333058e0e84SYifeng Zhao .high_mask = 0x0, 1334058e0e84SYifeng Zhao }, 1335058e0e84SYifeng Zhao .ecc1 = { 1336058e0e84SYifeng Zhao .err_flag_bit = 18, 1337058e0e84SYifeng Zhao .low = 19, 1338058e0e84SYifeng Zhao .low_mask = 0x7F, 1339058e0e84SYifeng Zhao .low_bn = 7, 1340058e0e84SYifeng Zhao .high = 0, 1341058e0e84SYifeng Zhao .high_mask = 0x0, 1342058e0e84SYifeng Zhao }, 1343058e0e84SYifeng Zhao }; 1344058e0e84SYifeng Zhao 1345058e0e84SYifeng Zhao static const struct of_device_id rk_nfc_id_table[] = { 1346058e0e84SYifeng Zhao { 1347058e0e84SYifeng Zhao .compatible = "rockchip,px30-nfc", 1348058e0e84SYifeng Zhao .data = &nfc_v9_cfg 1349058e0e84SYifeng Zhao }, 1350058e0e84SYifeng Zhao { 1351058e0e84SYifeng Zhao .compatible = "rockchip,rk2928-nfc", 1352058e0e84SYifeng Zhao .data = &nfc_v6_cfg 1353058e0e84SYifeng Zhao }, 1354058e0e84SYifeng Zhao { 1355058e0e84SYifeng Zhao .compatible = "rockchip,rv1108-nfc", 1356058e0e84SYifeng Zhao .data = &nfc_v8_cfg 1357058e0e84SYifeng Zhao }, 1358058e0e84SYifeng Zhao { /* sentinel */ } 1359058e0e84SYifeng Zhao }; 1360058e0e84SYifeng Zhao MODULE_DEVICE_TABLE(of, rk_nfc_id_table); 1361058e0e84SYifeng Zhao 1362058e0e84SYifeng Zhao static int rk_nfc_probe(struct platform_device *pdev) 1363058e0e84SYifeng Zhao { 1364058e0e84SYifeng Zhao struct device *dev = &pdev->dev; 1365058e0e84SYifeng Zhao struct rk_nfc *nfc; 1366058e0e84SYifeng Zhao int ret, irq; 1367058e0e84SYifeng Zhao 1368058e0e84SYifeng Zhao nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); 1369058e0e84SYifeng Zhao if (!nfc) 1370058e0e84SYifeng Zhao return -ENOMEM; 1371058e0e84SYifeng Zhao 1372058e0e84SYifeng Zhao nand_controller_init(&nfc->controller); 1373058e0e84SYifeng Zhao INIT_LIST_HEAD(&nfc->chips); 1374058e0e84SYifeng Zhao nfc->controller.ops = &rk_nfc_controller_ops; 1375058e0e84SYifeng Zhao 1376058e0e84SYifeng Zhao nfc->cfg = of_device_get_match_data(dev); 1377058e0e84SYifeng Zhao nfc->dev = dev; 1378058e0e84SYifeng Zhao 1379058e0e84SYifeng Zhao init_completion(&nfc->done); 1380058e0e84SYifeng Zhao 1381058e0e84SYifeng Zhao nfc->regs = devm_platform_ioremap_resource(pdev, 0); 1382058e0e84SYifeng Zhao if (IS_ERR(nfc->regs)) { 1383058e0e84SYifeng Zhao ret = PTR_ERR(nfc->regs); 1384058e0e84SYifeng Zhao goto release_nfc; 1385058e0e84SYifeng Zhao } 1386058e0e84SYifeng Zhao 1387058e0e84SYifeng Zhao nfc->nfc_clk = devm_clk_get(dev, "nfc"); 1388058e0e84SYifeng Zhao if (IS_ERR(nfc->nfc_clk)) { 1389058e0e84SYifeng Zhao dev_dbg(dev, "no NFC clk\n"); 1390058e0e84SYifeng Zhao /* Some earlier models, such as rk3066, have no NFC clk. */ 1391058e0e84SYifeng Zhao } 1392058e0e84SYifeng Zhao 1393058e0e84SYifeng Zhao nfc->ahb_clk = devm_clk_get(dev, "ahb"); 1394058e0e84SYifeng Zhao if (IS_ERR(nfc->ahb_clk)) { 1395058e0e84SYifeng Zhao dev_err(dev, "no ahb clk\n"); 1396058e0e84SYifeng Zhao ret = PTR_ERR(nfc->ahb_clk); 1397058e0e84SYifeng Zhao goto release_nfc; 1398058e0e84SYifeng Zhao } 1399058e0e84SYifeng Zhao 1400058e0e84SYifeng Zhao ret = rk_nfc_enable_clks(dev, nfc); 1401058e0e84SYifeng Zhao if (ret) 1402058e0e84SYifeng Zhao goto release_nfc; 1403058e0e84SYifeng Zhao 1404058e0e84SYifeng Zhao irq = platform_get_irq(pdev, 0); 1405058e0e84SYifeng Zhao if (irq < 0) { 1406058e0e84SYifeng Zhao dev_err(dev, "no NFC irq resource\n"); 1407058e0e84SYifeng Zhao ret = -EINVAL; 1408058e0e84SYifeng Zhao goto clk_disable; 1409058e0e84SYifeng Zhao } 1410058e0e84SYifeng Zhao 1411058e0e84SYifeng Zhao writel(0, nfc->regs + nfc->cfg->int_en_off); 1412058e0e84SYifeng Zhao ret = devm_request_irq(dev, irq, rk_nfc_irq, 0x0, "rk-nand", nfc); 1413058e0e84SYifeng Zhao if (ret) { 1414058e0e84SYifeng Zhao dev_err(dev, "failed to request NFC irq\n"); 1415058e0e84SYifeng Zhao goto clk_disable; 1416058e0e84SYifeng Zhao } 1417058e0e84SYifeng Zhao 1418058e0e84SYifeng Zhao platform_set_drvdata(pdev, nfc); 1419058e0e84SYifeng Zhao 1420058e0e84SYifeng Zhao ret = rk_nfc_nand_chips_init(dev, nfc); 1421058e0e84SYifeng Zhao if (ret) { 1422058e0e84SYifeng Zhao dev_err(dev, "failed to init NAND chips\n"); 1423058e0e84SYifeng Zhao goto clk_disable; 1424058e0e84SYifeng Zhao } 1425058e0e84SYifeng Zhao return 0; 1426058e0e84SYifeng Zhao 1427058e0e84SYifeng Zhao clk_disable: 1428058e0e84SYifeng Zhao rk_nfc_disable_clks(nfc); 1429058e0e84SYifeng Zhao release_nfc: 1430058e0e84SYifeng Zhao return ret; 1431058e0e84SYifeng Zhao } 1432058e0e84SYifeng Zhao 1433058e0e84SYifeng Zhao static int rk_nfc_remove(struct platform_device *pdev) 1434058e0e84SYifeng Zhao { 1435058e0e84SYifeng Zhao struct rk_nfc *nfc = platform_get_drvdata(pdev); 1436058e0e84SYifeng Zhao 1437058e0e84SYifeng Zhao kfree(nfc->page_buf); 1438058e0e84SYifeng Zhao kfree(nfc->oob_buf); 1439058e0e84SYifeng Zhao rk_nfc_chips_cleanup(nfc); 1440058e0e84SYifeng Zhao rk_nfc_disable_clks(nfc); 1441058e0e84SYifeng Zhao 1442058e0e84SYifeng Zhao return 0; 1443058e0e84SYifeng Zhao } 1444058e0e84SYifeng Zhao 1445058e0e84SYifeng Zhao static int __maybe_unused rk_nfc_suspend(struct device *dev) 1446058e0e84SYifeng Zhao { 1447058e0e84SYifeng Zhao struct rk_nfc *nfc = dev_get_drvdata(dev); 1448058e0e84SYifeng Zhao 1449058e0e84SYifeng Zhao rk_nfc_disable_clks(nfc); 1450058e0e84SYifeng Zhao 1451058e0e84SYifeng Zhao return 0; 1452058e0e84SYifeng Zhao } 1453058e0e84SYifeng Zhao 1454058e0e84SYifeng Zhao static int __maybe_unused rk_nfc_resume(struct device *dev) 1455058e0e84SYifeng Zhao { 1456058e0e84SYifeng Zhao struct rk_nfc *nfc = dev_get_drvdata(dev); 1457058e0e84SYifeng Zhao struct rk_nfc_nand_chip *rknand; 1458058e0e84SYifeng Zhao struct nand_chip *chip; 1459058e0e84SYifeng Zhao int ret; 1460058e0e84SYifeng Zhao u32 i; 1461058e0e84SYifeng Zhao 1462058e0e84SYifeng Zhao ret = rk_nfc_enable_clks(dev, nfc); 1463058e0e84SYifeng Zhao if (ret) 1464058e0e84SYifeng Zhao return ret; 1465058e0e84SYifeng Zhao 1466058e0e84SYifeng Zhao /* Reset NAND chip if VCC was powered off. */ 1467058e0e84SYifeng Zhao list_for_each_entry(rknand, &nfc->chips, node) { 1468058e0e84SYifeng Zhao chip = &rknand->chip; 1469058e0e84SYifeng Zhao for (i = 0; i < rknand->nsels; i++) 1470058e0e84SYifeng Zhao nand_reset(chip, i); 1471058e0e84SYifeng Zhao } 1472058e0e84SYifeng Zhao 1473058e0e84SYifeng Zhao return 0; 1474058e0e84SYifeng Zhao } 1475058e0e84SYifeng Zhao 1476058e0e84SYifeng Zhao static const struct dev_pm_ops rk_nfc_pm_ops = { 1477058e0e84SYifeng Zhao SET_SYSTEM_SLEEP_PM_OPS(rk_nfc_suspend, rk_nfc_resume) 1478058e0e84SYifeng Zhao }; 1479058e0e84SYifeng Zhao 1480058e0e84SYifeng Zhao static struct platform_driver rk_nfc_driver = { 1481058e0e84SYifeng Zhao .probe = rk_nfc_probe, 1482058e0e84SYifeng Zhao .remove = rk_nfc_remove, 1483058e0e84SYifeng Zhao .driver = { 1484058e0e84SYifeng Zhao .name = "rockchip-nfc", 1485058e0e84SYifeng Zhao .of_match_table = rk_nfc_id_table, 1486058e0e84SYifeng Zhao .pm = &rk_nfc_pm_ops, 1487058e0e84SYifeng Zhao }, 1488058e0e84SYifeng Zhao }; 1489058e0e84SYifeng Zhao 1490058e0e84SYifeng Zhao module_platform_driver(rk_nfc_driver); 1491058e0e84SYifeng Zhao 1492058e0e84SYifeng Zhao MODULE_LICENSE("Dual MIT/GPL"); 1493058e0e84SYifeng Zhao MODULE_AUTHOR("Yifeng Zhao <yifeng.zhao@rock-chips.com>"); 1494058e0e84SYifeng Zhao MODULE_DESCRIPTION("Rockchip Nand Flash Controller Driver"); 1495058e0e84SYifeng Zhao MODULE_ALIAS("platform:rockchip-nand-controller"); 1496