17304d190SMd Sadre Alam /* 27304d190SMd Sadre Alam * SPDX-License-Identifier: GPL-2.0 37304d190SMd Sadre Alam * 47304d190SMd Sadre Alam * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. 57304d190SMd Sadre Alam * 67304d190SMd Sadre Alam * Authors: 77304d190SMd Sadre Alam * Md Sadre Alam <quic_mdalam@quicinc.com> 87304d190SMd Sadre Alam * Sricharan R <quic_srichara@quicinc.com> 97304d190SMd Sadre Alam * Varadarajan Narayanan <quic_varada@quicinc.com> 107304d190SMd Sadre Alam */ 117304d190SMd Sadre Alam #include <linux/bitops.h> 127304d190SMd Sadre Alam #include <linux/clk.h> 137304d190SMd Sadre Alam #include <linux/delay.h> 147304d190SMd Sadre Alam #include <linux/dmaengine.h> 157304d190SMd Sadre Alam #include <linux/dma-mapping.h> 167304d190SMd Sadre Alam #include <linux/dma/qcom_adm.h> 177304d190SMd Sadre Alam #include <linux/dma/qcom_bam_dma.h> 187304d190SMd Sadre Alam #include <linux/module.h> 197304d190SMd Sadre Alam #include <linux/of.h> 207304d190SMd Sadre Alam #include <linux/platform_device.h> 217304d190SMd Sadre Alam #include <linux/slab.h> 227304d190SMd Sadre Alam #include <linux/mtd/nand-qpic-common.h> 237304d190SMd Sadre Alam #include <linux/mtd/spinand.h> 247304d190SMd Sadre Alam #include <linux/bitfield.h> 257304d190SMd Sadre Alam 267304d190SMd Sadre Alam #define NAND_FLASH_SPI_CFG 0xc0 277304d190SMd Sadre Alam #define NAND_NUM_ADDR_CYCLES 0xc4 287304d190SMd Sadre Alam #define NAND_BUSY_CHECK_WAIT_CNT 0xc8 297304d190SMd Sadre Alam #define NAND_FLASH_FEATURES 0xf64 307304d190SMd Sadre Alam 317304d190SMd Sadre Alam /* QSPI NAND config reg bits */ 327304d190SMd Sadre Alam #define LOAD_CLK_CNTR_INIT_EN BIT(28) 337304d190SMd Sadre Alam #define CLK_CNTR_INIT_VAL_VEC 0x924 347304d190SMd Sadre Alam #define CLK_CNTR_INIT_VAL_VEC_MASK GENMASK(27, 16) 357304d190SMd Sadre Alam #define FEA_STATUS_DEV_ADDR 0xc0 367304d190SMd Sadre Alam #define FEA_STATUS_DEV_ADDR_MASK GENMASK(15, 8) 377304d190SMd Sadre Alam #define SPI_CFG BIT(0) 387304d190SMd Sadre Alam #define SPI_NUM_ADDR 0xDA4DB 397304d190SMd Sadre Alam #define SPI_WAIT_CNT 0x10 407304d190SMd Sadre Alam #define QPIC_QSPI_NUM_CS 1 417304d190SMd Sadre Alam #define SPI_TRANSFER_MODE_x1 BIT(29) 427304d190SMd Sadre Alam #define SPI_TRANSFER_MODE_x4 (3 << 29) 437304d190SMd Sadre Alam #define SPI_WP BIT(28) 447304d190SMd Sadre Alam #define SPI_HOLD BIT(27) 457304d190SMd Sadre Alam #define QPIC_SET_FEATURE BIT(31) 467304d190SMd Sadre Alam 477304d190SMd Sadre Alam #define SPINAND_RESET 0xff 487304d190SMd Sadre Alam #define SPINAND_READID 0x9f 497304d190SMd Sadre Alam #define SPINAND_GET_FEATURE 0x0f 507304d190SMd Sadre Alam #define SPINAND_SET_FEATURE 0x1f 517304d190SMd Sadre Alam #define SPINAND_READ 0x13 527304d190SMd Sadre Alam #define SPINAND_ERASE 0xd8 537304d190SMd Sadre Alam #define SPINAND_WRITE_EN 0x06 547304d190SMd Sadre Alam #define SPINAND_PROGRAM_EXECUTE 0x10 557304d190SMd Sadre Alam #define SPINAND_PROGRAM_LOAD 0x84 567304d190SMd Sadre Alam 577304d190SMd Sadre Alam #define ACC_FEATURE 0xe 587304d190SMd Sadre Alam #define BAD_BLOCK_MARKER_SIZE 0x2 597304d190SMd Sadre Alam #define OOB_BUF_SIZE 128 607304d190SMd Sadre Alam #define ecceng_to_qspi(eng) container_of(eng, struct qpic_spi_nand, ecc_eng) 617304d190SMd Sadre Alam 627304d190SMd Sadre Alam struct qpic_snand_op { 637304d190SMd Sadre Alam u32 cmd_reg; 647304d190SMd Sadre Alam u32 addr1_reg; 657304d190SMd Sadre Alam u32 addr2_reg; 667304d190SMd Sadre Alam }; 677304d190SMd Sadre Alam 687304d190SMd Sadre Alam struct snandc_read_status { 697304d190SMd Sadre Alam __le32 snandc_flash; 707304d190SMd Sadre Alam __le32 snandc_buffer; 717304d190SMd Sadre Alam __le32 snandc_erased_cw; 727304d190SMd Sadre Alam }; 737304d190SMd Sadre Alam 747304d190SMd Sadre Alam /* 757304d190SMd Sadre Alam * ECC state struct 767304d190SMd Sadre Alam * @corrected: ECC corrected 777304d190SMd Sadre Alam * @bitflips: Max bit flip 787304d190SMd Sadre Alam * @failed: ECC failed 797304d190SMd Sadre Alam */ 807304d190SMd Sadre Alam struct qcom_ecc_stats { 817304d190SMd Sadre Alam u32 corrected; 827304d190SMd Sadre Alam u32 bitflips; 837304d190SMd Sadre Alam u32 failed; 847304d190SMd Sadre Alam }; 857304d190SMd Sadre Alam 867304d190SMd Sadre Alam struct qpic_ecc { 877304d190SMd Sadre Alam struct device *dev; 887304d190SMd Sadre Alam int ecc_bytes_hw; 897304d190SMd Sadre Alam int spare_bytes; 907304d190SMd Sadre Alam int bbm_size; 917304d190SMd Sadre Alam int ecc_mode; 927304d190SMd Sadre Alam int bytes; 937304d190SMd Sadre Alam int steps; 947304d190SMd Sadre Alam int step_size; 957304d190SMd Sadre Alam int strength; 967304d190SMd Sadre Alam int cw_size; 977304d190SMd Sadre Alam int cw_data; 987304d190SMd Sadre Alam u32 cfg0; 997304d190SMd Sadre Alam u32 cfg1; 1007304d190SMd Sadre Alam u32 cfg0_raw; 1017304d190SMd Sadre Alam u32 cfg1_raw; 1027304d190SMd Sadre Alam u32 ecc_buf_cfg; 1037304d190SMd Sadre Alam u32 ecc_bch_cfg; 1047304d190SMd Sadre Alam u32 clrflashstatus; 1057304d190SMd Sadre Alam u32 clrreadstatus; 1067304d190SMd Sadre Alam bool bch_enabled; 1077304d190SMd Sadre Alam }; 1087304d190SMd Sadre Alam 1097304d190SMd Sadre Alam struct qpic_spi_nand { 1107304d190SMd Sadre Alam struct qcom_nand_controller *snandc; 1117304d190SMd Sadre Alam struct spi_controller *ctlr; 1127304d190SMd Sadre Alam struct mtd_info *mtd; 1137304d190SMd Sadre Alam struct clk *iomacro_clk; 1147304d190SMd Sadre Alam struct qpic_ecc *ecc; 1157304d190SMd Sadre Alam struct qcom_ecc_stats ecc_stats; 1167304d190SMd Sadre Alam struct nand_ecc_engine ecc_eng; 1177304d190SMd Sadre Alam u8 *data_buf; 1187304d190SMd Sadre Alam u8 *oob_buf; 1197304d190SMd Sadre Alam u32 wlen; 1207304d190SMd Sadre Alam __le32 addr1; 1217304d190SMd Sadre Alam __le32 addr2; 1227304d190SMd Sadre Alam __le32 cmd; 1237304d190SMd Sadre Alam u32 num_cw; 1247304d190SMd Sadre Alam bool oob_rw; 1257304d190SMd Sadre Alam bool page_rw; 1267304d190SMd Sadre Alam bool raw_rw; 1277304d190SMd Sadre Alam }; 1287304d190SMd Sadre Alam 1297304d190SMd Sadre Alam static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc, 1307304d190SMd Sadre Alam int reg, int cw_offset, int read_size, 1317304d190SMd Sadre Alam int is_last_read_loc) 1327304d190SMd Sadre Alam { 1337304d190SMd Sadre Alam __le32 locreg_val; 1347304d190SMd Sadre Alam u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | 1357304d190SMd Sadre Alam ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc) 1367304d190SMd Sadre Alam << READ_LOCATION_LAST)); 1377304d190SMd Sadre Alam 1387304d190SMd Sadre Alam locreg_val = cpu_to_le32(val); 1397304d190SMd Sadre Alam 1407304d190SMd Sadre Alam if (reg == NAND_READ_LOCATION_0) 1417304d190SMd Sadre Alam snandc->regs->read_location0 = locreg_val; 1427304d190SMd Sadre Alam else if (reg == NAND_READ_LOCATION_1) 1437304d190SMd Sadre Alam snandc->regs->read_location1 = locreg_val; 1447304d190SMd Sadre Alam else if (reg == NAND_READ_LOCATION_2) 1457304d190SMd Sadre Alam snandc->regs->read_location1 = locreg_val; 1467304d190SMd Sadre Alam else if (reg == NAND_READ_LOCATION_3) 1477304d190SMd Sadre Alam snandc->regs->read_location3 = locreg_val; 1487304d190SMd Sadre Alam } 1497304d190SMd Sadre Alam 1507304d190SMd Sadre Alam static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc, 1517304d190SMd Sadre Alam int reg, int cw_offset, int read_size, 1527304d190SMd Sadre Alam int is_last_read_loc) 1537304d190SMd Sadre Alam { 1547304d190SMd Sadre Alam __le32 locreg_val; 1557304d190SMd Sadre Alam u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | 1567304d190SMd Sadre Alam ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc) 1577304d190SMd Sadre Alam << READ_LOCATION_LAST)); 1587304d190SMd Sadre Alam 1597304d190SMd Sadre Alam locreg_val = cpu_to_le32(val); 1607304d190SMd Sadre Alam 1617304d190SMd Sadre Alam if (reg == NAND_READ_LOCATION_LAST_CW_0) 1627304d190SMd Sadre Alam snandc->regs->read_location_last0 = locreg_val; 1637304d190SMd Sadre Alam else if (reg == NAND_READ_LOCATION_LAST_CW_1) 1647304d190SMd Sadre Alam snandc->regs->read_location_last1 = locreg_val; 1657304d190SMd Sadre Alam else if (reg == NAND_READ_LOCATION_LAST_CW_2) 1667304d190SMd Sadre Alam snandc->regs->read_location_last2 = locreg_val; 1677304d190SMd Sadre Alam else if (reg == NAND_READ_LOCATION_LAST_CW_3) 1687304d190SMd Sadre Alam snandc->regs->read_location_last3 = locreg_val; 1697304d190SMd Sadre Alam } 1707304d190SMd Sadre Alam 1717304d190SMd Sadre Alam static struct qcom_nand_controller *nand_to_qcom_snand(struct nand_device *nand) 1727304d190SMd Sadre Alam { 1737304d190SMd Sadre Alam struct nand_ecc_engine *eng = nand->ecc.engine; 1747304d190SMd Sadre Alam struct qpic_spi_nand *qspi = ecceng_to_qspi(eng); 1757304d190SMd Sadre Alam 1767304d190SMd Sadre Alam return qspi->snandc; 1777304d190SMd Sadre Alam } 1787304d190SMd Sadre Alam 1797304d190SMd Sadre Alam static int qcom_spi_init(struct qcom_nand_controller *snandc) 1807304d190SMd Sadre Alam { 1817304d190SMd Sadre Alam u32 snand_cfg_val = 0x0; 1827304d190SMd Sadre Alam int ret; 1837304d190SMd Sadre Alam 1847304d190SMd Sadre Alam snand_cfg_val = FIELD_PREP(CLK_CNTR_INIT_VAL_VEC_MASK, CLK_CNTR_INIT_VAL_VEC) | 1857304d190SMd Sadre Alam FIELD_PREP(LOAD_CLK_CNTR_INIT_EN, 0) | 1867304d190SMd Sadre Alam FIELD_PREP(FEA_STATUS_DEV_ADDR_MASK, FEA_STATUS_DEV_ADDR) | 1877304d190SMd Sadre Alam FIELD_PREP(SPI_CFG, 0); 1887304d190SMd Sadre Alam 1897304d190SMd Sadre Alam snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val); 1907304d190SMd Sadre Alam snandc->regs->num_addr_cycle = cpu_to_le32(SPI_NUM_ADDR); 1917304d190SMd Sadre Alam snandc->regs->busy_wait_cnt = cpu_to_le32(SPI_WAIT_CNT); 1927304d190SMd Sadre Alam 1937304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0); 1947304d190SMd Sadre Alam 1957304d190SMd Sadre Alam snand_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN; 1967304d190SMd Sadre Alam snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val); 1977304d190SMd Sadre Alam 1987304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0); 1997304d190SMd Sadre Alam 2007304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->num_addr_cycle, NAND_NUM_ADDR_CYCLES, 1, 0); 2017304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->busy_wait_cnt, NAND_BUSY_CHECK_WAIT_CNT, 1, 2027304d190SMd Sadre Alam NAND_BAM_NEXT_SGL); 2037304d190SMd Sadre Alam 2047304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 2057304d190SMd Sadre Alam if (ret) { 2067304d190SMd Sadre Alam dev_err(snandc->dev, "failure in submitting spi init descriptor\n"); 2077304d190SMd Sadre Alam return ret; 2087304d190SMd Sadre Alam } 2097304d190SMd Sadre Alam 2107304d190SMd Sadre Alam return ret; 2117304d190SMd Sadre Alam } 2127304d190SMd Sadre Alam 2137304d190SMd Sadre Alam static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section, 2147304d190SMd Sadre Alam struct mtd_oob_region *oobregion) 2157304d190SMd Sadre Alam { 2167304d190SMd Sadre Alam struct nand_device *nand = mtd_to_nanddev(mtd); 2177304d190SMd Sadre Alam struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); 2187304d190SMd Sadre Alam struct qpic_ecc *qecc = snandc->qspi->ecc; 2197304d190SMd Sadre Alam 2207304d190SMd Sadre Alam if (section > 1) 2217304d190SMd Sadre Alam return -ERANGE; 2227304d190SMd Sadre Alam 2237304d190SMd Sadre Alam oobregion->length = qecc->ecc_bytes_hw + qecc->spare_bytes; 2247304d190SMd Sadre Alam oobregion->offset = mtd->oobsize - oobregion->length; 2257304d190SMd Sadre Alam 2267304d190SMd Sadre Alam return 0; 2277304d190SMd Sadre Alam } 2287304d190SMd Sadre Alam 2297304d190SMd Sadre Alam static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section, 2307304d190SMd Sadre Alam struct mtd_oob_region *oobregion) 2317304d190SMd Sadre Alam { 2327304d190SMd Sadre Alam struct nand_device *nand = mtd_to_nanddev(mtd); 2337304d190SMd Sadre Alam struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); 2347304d190SMd Sadre Alam struct qpic_ecc *qecc = snandc->qspi->ecc; 2357304d190SMd Sadre Alam 2367304d190SMd Sadre Alam if (section) 2377304d190SMd Sadre Alam return -ERANGE; 2387304d190SMd Sadre Alam 2397304d190SMd Sadre Alam oobregion->length = qecc->steps * 4; 2407304d190SMd Sadre Alam oobregion->offset = ((qecc->steps - 1) * qecc->bytes) + qecc->bbm_size; 2417304d190SMd Sadre Alam 2427304d190SMd Sadre Alam return 0; 2437304d190SMd Sadre Alam } 2447304d190SMd Sadre Alam 2457304d190SMd Sadre Alam static const struct mtd_ooblayout_ops qcom_spi_ooblayout = { 2467304d190SMd Sadre Alam .ecc = qcom_spi_ooblayout_ecc, 2477304d190SMd Sadre Alam .free = qcom_spi_ooblayout_free, 2487304d190SMd Sadre Alam }; 2497304d190SMd Sadre Alam 2507304d190SMd Sadre Alam static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) 2517304d190SMd Sadre Alam { 2527304d190SMd Sadre Alam struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); 2537304d190SMd Sadre Alam struct nand_ecc_props *conf = &nand->ecc.ctx.conf; 2547304d190SMd Sadre Alam struct mtd_info *mtd = nanddev_to_mtd(nand); 2557304d190SMd Sadre Alam int cwperpage, bad_block_byte; 2567304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg; 2577304d190SMd Sadre Alam 2587304d190SMd Sadre Alam cwperpage = mtd->writesize / NANDC_STEP_SIZE; 2597304d190SMd Sadre Alam snandc->qspi->num_cw = cwperpage; 2607304d190SMd Sadre Alam 2617304d190SMd Sadre Alam ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL); 2627304d190SMd Sadre Alam if (!ecc_cfg) 2637304d190SMd Sadre Alam return -ENOMEM; 2647304d190SMd Sadre Alam snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize, 2657304d190SMd Sadre Alam GFP_KERNEL); 266*d450cdd9SGabor Juhos if (!snandc->qspi->oob_buf) { 267*d450cdd9SGabor Juhos kfree(ecc_cfg); 2687304d190SMd Sadre Alam return -ENOMEM; 269*d450cdd9SGabor Juhos } 2707304d190SMd Sadre Alam 2717304d190SMd Sadre Alam memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize); 2727304d190SMd Sadre Alam 2737304d190SMd Sadre Alam nand->ecc.ctx.priv = ecc_cfg; 2747304d190SMd Sadre Alam snandc->qspi->mtd = mtd; 2757304d190SMd Sadre Alam 2767304d190SMd Sadre Alam ecc_cfg->ecc_bytes_hw = 7; 2777304d190SMd Sadre Alam ecc_cfg->spare_bytes = 4; 2787304d190SMd Sadre Alam ecc_cfg->bbm_size = 1; 2797304d190SMd Sadre Alam ecc_cfg->bch_enabled = true; 2807304d190SMd Sadre Alam ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size; 2817304d190SMd Sadre Alam 2827304d190SMd Sadre Alam ecc_cfg->steps = 4; 2837304d190SMd Sadre Alam ecc_cfg->strength = 4; 2847304d190SMd Sadre Alam ecc_cfg->step_size = 512; 2857304d190SMd Sadre Alam ecc_cfg->cw_data = 516; 2867304d190SMd Sadre Alam ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes; 2877304d190SMd Sadre Alam bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1; 2887304d190SMd Sadre Alam 2897304d190SMd Sadre Alam mtd_set_ooblayout(mtd, &qcom_spi_ooblayout); 2907304d190SMd Sadre Alam 2917304d190SMd Sadre Alam ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | 2927304d190SMd Sadre Alam FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) | 2937304d190SMd Sadre Alam FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) | 2947304d190SMd Sadre Alam FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) | 2957304d190SMd Sadre Alam FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, ecc_cfg->ecc_bytes_hw) | 2967304d190SMd Sadre Alam FIELD_PREP(STATUS_BFR_READ, 0) | 2977304d190SMd Sadre Alam FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) | 2987304d190SMd Sadre Alam FIELD_PREP(SPARE_SIZE_BYTES_MASK, ecc_cfg->spare_bytes); 2997304d190SMd Sadre Alam 3007304d190SMd Sadre Alam ecc_cfg->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) | 3017304d190SMd Sadre Alam FIELD_PREP(CS_ACTIVE_BSY, 0) | 3027304d190SMd Sadre Alam FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) | 3037304d190SMd Sadre Alam FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) | 3047304d190SMd Sadre Alam FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) | 3057304d190SMd Sadre Alam FIELD_PREP(WIDE_FLASH, 0) | 3067304d190SMd Sadre Alam FIELD_PREP(ENABLE_BCH_ECC, ecc_cfg->bch_enabled); 3077304d190SMd Sadre Alam 3087304d190SMd Sadre Alam ecc_cfg->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | 3097304d190SMd Sadre Alam FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) | 3107304d190SMd Sadre Alam FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_size) | 3117304d190SMd Sadre Alam FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); 3127304d190SMd Sadre Alam 3137304d190SMd Sadre Alam ecc_cfg->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) | 3147304d190SMd Sadre Alam FIELD_PREP(CS_ACTIVE_BSY, 0) | 3157304d190SMd Sadre Alam FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | 3167304d190SMd Sadre Alam FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | 3177304d190SMd Sadre Alam FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) | 3187304d190SMd Sadre Alam FIELD_PREP(WIDE_FLASH, 0) | 3197304d190SMd Sadre Alam FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); 3207304d190SMd Sadre Alam 3217304d190SMd Sadre Alam ecc_cfg->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !ecc_cfg->bch_enabled) | 3227304d190SMd Sadre Alam FIELD_PREP(ECC_SW_RESET, 0) | 3237304d190SMd Sadre Alam FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) | 3247304d190SMd Sadre Alam FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) | 3257304d190SMd Sadre Alam FIELD_PREP(ECC_MODE_MASK, 0) | 3267304d190SMd Sadre Alam FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw); 3277304d190SMd Sadre Alam 3287304d190SMd Sadre Alam ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS; 3297304d190SMd Sadre Alam ecc_cfg->clrflashstatus = FS_READY_BSY_N; 3307304d190SMd Sadre Alam ecc_cfg->clrreadstatus = 0xc0; 3317304d190SMd Sadre Alam 3327304d190SMd Sadre Alam conf->step_size = ecc_cfg->step_size; 3337304d190SMd Sadre Alam conf->strength = ecc_cfg->strength; 3347304d190SMd Sadre Alam 3357304d190SMd Sadre Alam snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET); 3367304d190SMd Sadre Alam snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET); 3377304d190SMd Sadre Alam 3387304d190SMd Sadre Alam dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n", 3397304d190SMd Sadre Alam ecc_cfg->strength, ecc_cfg->step_size); 3407304d190SMd Sadre Alam 3417304d190SMd Sadre Alam return 0; 3427304d190SMd Sadre Alam } 3437304d190SMd Sadre Alam 3447304d190SMd Sadre Alam static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand) 3457304d190SMd Sadre Alam { 3467304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand); 3477304d190SMd Sadre Alam 3487304d190SMd Sadre Alam kfree(ecc_cfg); 3497304d190SMd Sadre Alam } 3507304d190SMd Sadre Alam 3517304d190SMd Sadre Alam static int qcom_spi_ecc_prepare_io_req_pipelined(struct nand_device *nand, 3527304d190SMd Sadre Alam struct nand_page_io_req *req) 3537304d190SMd Sadre Alam { 3547304d190SMd Sadre Alam struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); 3557304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand); 3567304d190SMd Sadre Alam 3577304d190SMd Sadre Alam snandc->qspi->ecc = ecc_cfg; 3587304d190SMd Sadre Alam snandc->qspi->raw_rw = false; 3597304d190SMd Sadre Alam snandc->qspi->oob_rw = false; 3607304d190SMd Sadre Alam snandc->qspi->page_rw = false; 3617304d190SMd Sadre Alam 3627304d190SMd Sadre Alam if (req->datalen) 3637304d190SMd Sadre Alam snandc->qspi->page_rw = true; 3647304d190SMd Sadre Alam 3657304d190SMd Sadre Alam if (req->ooblen) 3667304d190SMd Sadre Alam snandc->qspi->oob_rw = true; 3677304d190SMd Sadre Alam 3687304d190SMd Sadre Alam if (req->mode == MTD_OPS_RAW) 3697304d190SMd Sadre Alam snandc->qspi->raw_rw = true; 3707304d190SMd Sadre Alam 3717304d190SMd Sadre Alam return 0; 3727304d190SMd Sadre Alam } 3737304d190SMd Sadre Alam 3747304d190SMd Sadre Alam static int qcom_spi_ecc_finish_io_req_pipelined(struct nand_device *nand, 3757304d190SMd Sadre Alam struct nand_page_io_req *req) 3767304d190SMd Sadre Alam { 3777304d190SMd Sadre Alam struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); 3787304d190SMd Sadre Alam struct mtd_info *mtd = nanddev_to_mtd(nand); 3797304d190SMd Sadre Alam 3807304d190SMd Sadre Alam if (req->mode == MTD_OPS_RAW || req->type != NAND_PAGE_READ) 3817304d190SMd Sadre Alam return 0; 3827304d190SMd Sadre Alam 3837304d190SMd Sadre Alam if (snandc->qspi->ecc_stats.failed) 3847304d190SMd Sadre Alam mtd->ecc_stats.failed += snandc->qspi->ecc_stats.failed; 3857304d190SMd Sadre Alam else 3867304d190SMd Sadre Alam mtd->ecc_stats.corrected += snandc->qspi->ecc_stats.corrected; 3877304d190SMd Sadre Alam 3887304d190SMd Sadre Alam if (snandc->qspi->ecc_stats.failed) 3897304d190SMd Sadre Alam return -EBADMSG; 3907304d190SMd Sadre Alam else 3917304d190SMd Sadre Alam return snandc->qspi->ecc_stats.bitflips; 3927304d190SMd Sadre Alam } 3937304d190SMd Sadre Alam 3947304d190SMd Sadre Alam static struct nand_ecc_engine_ops qcom_spi_ecc_engine_ops_pipelined = { 3957304d190SMd Sadre Alam .init_ctx = qcom_spi_ecc_init_ctx_pipelined, 3967304d190SMd Sadre Alam .cleanup_ctx = qcom_spi_ecc_cleanup_ctx_pipelined, 3977304d190SMd Sadre Alam .prepare_io_req = qcom_spi_ecc_prepare_io_req_pipelined, 3987304d190SMd Sadre Alam .finish_io_req = qcom_spi_ecc_finish_io_req_pipelined, 3997304d190SMd Sadre Alam }; 4007304d190SMd Sadre Alam 4017304d190SMd Sadre Alam /* helper to configure location register values */ 4027304d190SMd Sadre Alam static void qcom_spi_set_read_loc(struct qcom_nand_controller *snandc, int cw, int reg, 4037304d190SMd Sadre Alam int cw_offset, int read_size, int is_last_read_loc) 4047304d190SMd Sadre Alam { 4057304d190SMd Sadre Alam int reg_base = NAND_READ_LOCATION_0; 4067304d190SMd Sadre Alam int num_cw = snandc->qspi->num_cw; 4077304d190SMd Sadre Alam 4087304d190SMd Sadre Alam if (cw == (num_cw - 1)) 4097304d190SMd Sadre Alam reg_base = NAND_READ_LOCATION_LAST_CW_0; 4107304d190SMd Sadre Alam 4117304d190SMd Sadre Alam reg_base += reg * 4; 4127304d190SMd Sadre Alam 4137304d190SMd Sadre Alam if (cw == (num_cw - 1)) 4147304d190SMd Sadre Alam return qcom_spi_set_read_loc_last(snandc, reg_base, cw_offset, 4157304d190SMd Sadre Alam read_size, is_last_read_loc); 4167304d190SMd Sadre Alam else 4177304d190SMd Sadre Alam return qcom_spi_set_read_loc_first(snandc, reg_base, cw_offset, 4187304d190SMd Sadre Alam read_size, is_last_read_loc); 4197304d190SMd Sadre Alam } 4207304d190SMd Sadre Alam 4217304d190SMd Sadre Alam static void 4227304d190SMd Sadre Alam qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int cw) 4237304d190SMd Sadre Alam { 4247304d190SMd Sadre Alam __le32 *reg = &snandc->regs->read_location0; 4257304d190SMd Sadre Alam int num_cw = snandc->qspi->num_cw; 4267304d190SMd Sadre Alam 4277304d190SMd Sadre Alam qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); 4287304d190SMd Sadre Alam if (cw == (num_cw - 1)) { 4297304d190SMd Sadre Alam reg = &snandc->regs->read_location_last0; 4307304d190SMd Sadre Alam qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, 4317304d190SMd Sadre Alam NAND_BAM_NEXT_SGL); 4327304d190SMd Sadre Alam } 4337304d190SMd Sadre Alam 4347304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); 4357304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); 4367304d190SMd Sadre Alam 4377304d190SMd Sadre Alam qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0); 4387304d190SMd Sadre Alam qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1, 4397304d190SMd Sadre Alam NAND_BAM_NEXT_SGL); 4407304d190SMd Sadre Alam } 4417304d190SMd Sadre Alam 4427304d190SMd Sadre Alam static int qcom_spi_block_erase(struct qcom_nand_controller *snandc) 4437304d190SMd Sadre Alam { 4447304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 4457304d190SMd Sadre Alam int ret; 4467304d190SMd Sadre Alam 4477304d190SMd Sadre Alam snandc->buf_count = 0; 4487304d190SMd Sadre Alam snandc->buf_start = 0; 4497304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 4507304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 4517304d190SMd Sadre Alam 4527304d190SMd Sadre Alam snandc->regs->cmd = snandc->qspi->cmd; 4537304d190SMd Sadre Alam snandc->regs->addr0 = snandc->qspi->addr1; 4547304d190SMd Sadre Alam snandc->regs->addr1 = snandc->qspi->addr2; 4557304d190SMd Sadre Alam snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE)); 4567304d190SMd Sadre Alam snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw); 4577304d190SMd Sadre Alam snandc->regs->exec = cpu_to_le32(1); 4587304d190SMd Sadre Alam 4597304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); 4607304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); 4617304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); 4627304d190SMd Sadre Alam 4637304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 4647304d190SMd Sadre Alam if (ret) { 4657304d190SMd Sadre Alam dev_err(snandc->dev, "failure to erase block\n"); 4667304d190SMd Sadre Alam return ret; 4677304d190SMd Sadre Alam } 4687304d190SMd Sadre Alam 4697304d190SMd Sadre Alam return 0; 4707304d190SMd Sadre Alam } 4717304d190SMd Sadre Alam 4727304d190SMd Sadre Alam static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *snandc, 4737304d190SMd Sadre Alam bool use_ecc, int cw) 4747304d190SMd Sadre Alam { 4757304d190SMd Sadre Alam __le32 *reg = &snandc->regs->read_location0; 4767304d190SMd Sadre Alam int num_cw = snandc->qspi->num_cw; 4777304d190SMd Sadre Alam 4787304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); 4797304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); 4807304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, 4817304d190SMd Sadre Alam NAND_ERASED_CW_DETECT_CFG, 1, 0); 4827304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, 4837304d190SMd Sadre Alam NAND_ERASED_CW_DETECT_CFG, 1, 4847304d190SMd Sadre Alam NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); 4857304d190SMd Sadre Alam 4867304d190SMd Sadre Alam if (cw == (num_cw - 1)) { 4877304d190SMd Sadre Alam reg = &snandc->regs->read_location_last0; 4887304d190SMd Sadre Alam qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, NAND_BAM_NEXT_SGL); 4897304d190SMd Sadre Alam } 4907304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); 4917304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); 4927304d190SMd Sadre Alam 4937304d190SMd Sadre Alam qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0); 4947304d190SMd Sadre Alam } 4957304d190SMd Sadre Alam 4967304d190SMd Sadre Alam static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, 4977304d190SMd Sadre Alam const struct spi_mem_op *op) 4987304d190SMd Sadre Alam { 4997304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 5007304d190SMd Sadre Alam struct mtd_info *mtd = snandc->qspi->mtd; 5017304d190SMd Sadre Alam int size, ret = 0; 5027304d190SMd Sadre Alam int col, bbpos; 5037304d190SMd Sadre Alam u32 cfg0, cfg1, ecc_bch_cfg; 5047304d190SMd Sadre Alam u32 num_cw = snandc->qspi->num_cw; 5057304d190SMd Sadre Alam 5067304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 5077304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 5087304d190SMd Sadre Alam 5097304d190SMd Sadre Alam size = ecc_cfg->cw_size; 5107304d190SMd Sadre Alam col = ecc_cfg->cw_size * (num_cw - 1); 5117304d190SMd Sadre Alam 5127304d190SMd Sadre Alam memset(snandc->data_buffer, 0xff, size); 5137304d190SMd Sadre Alam snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); 5147304d190SMd Sadre Alam snandc->regs->addr1 = snandc->qspi->addr2; 5157304d190SMd Sadre Alam 5167304d190SMd Sadre Alam cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | 5177304d190SMd Sadre Alam 0 << CW_PER_PAGE; 5187304d190SMd Sadre Alam cfg1 = ecc_cfg->cfg1_raw; 519cf1ba3cbSDan Carpenter ecc_bch_cfg = ECC_CFG_ECC_DISABLE; 5207304d190SMd Sadre Alam 5217304d190SMd Sadre Alam snandc->regs->cmd = snandc->qspi->cmd; 5227304d190SMd Sadre Alam snandc->regs->cfg0 = cpu_to_le32(cfg0); 5237304d190SMd Sadre Alam snandc->regs->cfg1 = cpu_to_le32(cfg1); 5247304d190SMd Sadre Alam snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); 5257304d190SMd Sadre Alam snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); 5267304d190SMd Sadre Alam snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); 5277304d190SMd Sadre Alam snandc->regs->exec = cpu_to_le32(1); 5287304d190SMd Sadre Alam 5297304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1); 5307304d190SMd Sadre Alam 5317304d190SMd Sadre Alam qcom_spi_config_single_cw_page_read(snandc, false, num_cw - 1); 5327304d190SMd Sadre Alam 5337304d190SMd Sadre Alam qcom_read_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, size, 0); 5347304d190SMd Sadre Alam 5357304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 5367304d190SMd Sadre Alam if (ret) { 5377304d190SMd Sadre Alam dev_err(snandc->dev, "failed to read last cw\n"); 5387304d190SMd Sadre Alam return ret; 5397304d190SMd Sadre Alam } 5407304d190SMd Sadre Alam 5417304d190SMd Sadre Alam qcom_nandc_dev_to_mem(snandc, true); 5427304d190SMd Sadre Alam u32 flash = le32_to_cpu(snandc->reg_read_buf[0]); 5437304d190SMd Sadre Alam 5447304d190SMd Sadre Alam if (flash & (FS_OP_ERR | FS_MPU_ERR)) 5457304d190SMd Sadre Alam return -EIO; 5467304d190SMd Sadre Alam 5477304d190SMd Sadre Alam bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); 5487304d190SMd Sadre Alam 5497304d190SMd Sadre Alam if (snandc->data_buffer[bbpos] == 0xff) 5507304d190SMd Sadre Alam snandc->data_buffer[bbpos + 1] = 0xff; 5517304d190SMd Sadre Alam if (snandc->data_buffer[bbpos] != 0xff) 5527304d190SMd Sadre Alam snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos]; 5537304d190SMd Sadre Alam 5547304d190SMd Sadre Alam memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes); 5557304d190SMd Sadre Alam 5567304d190SMd Sadre Alam return ret; 5577304d190SMd Sadre Alam } 5587304d190SMd Sadre Alam 5597304d190SMd Sadre Alam static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf) 5607304d190SMd Sadre Alam { 5617304d190SMd Sadre Alam struct snandc_read_status *buf; 5627304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 5637304d190SMd Sadre Alam int i, num_cw = snandc->qspi->num_cw; 5647304d190SMd Sadre Alam bool flash_op_err = false, erased; 5657304d190SMd Sadre Alam unsigned int max_bitflips = 0; 5667304d190SMd Sadre Alam unsigned int uncorrectable_cws = 0; 5677304d190SMd Sadre Alam 5687304d190SMd Sadre Alam snandc->qspi->ecc_stats.failed = 0; 5697304d190SMd Sadre Alam snandc->qspi->ecc_stats.corrected = 0; 5707304d190SMd Sadre Alam 5717304d190SMd Sadre Alam qcom_nandc_dev_to_mem(snandc, true); 5727304d190SMd Sadre Alam buf = (struct snandc_read_status *)snandc->reg_read_buf; 5737304d190SMd Sadre Alam 5747304d190SMd Sadre Alam for (i = 0; i < num_cw; i++, buf++) { 5757304d190SMd Sadre Alam u32 flash, buffer, erased_cw; 5767304d190SMd Sadre Alam int data_len, oob_len; 5777304d190SMd Sadre Alam 5787304d190SMd Sadre Alam if (i == (num_cw - 1)) { 5797304d190SMd Sadre Alam data_len = NANDC_STEP_SIZE - ((num_cw - 1) << 2); 5807304d190SMd Sadre Alam oob_len = num_cw << 2; 5817304d190SMd Sadre Alam } else { 5827304d190SMd Sadre Alam data_len = ecc_cfg->cw_data; 5837304d190SMd Sadre Alam oob_len = 0; 5847304d190SMd Sadre Alam } 5857304d190SMd Sadre Alam 5867304d190SMd Sadre Alam flash = le32_to_cpu(buf->snandc_flash); 5877304d190SMd Sadre Alam buffer = le32_to_cpu(buf->snandc_buffer); 5887304d190SMd Sadre Alam erased_cw = le32_to_cpu(buf->snandc_erased_cw); 5897304d190SMd Sadre Alam 5907304d190SMd Sadre Alam if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) { 5917304d190SMd Sadre Alam if (ecc_cfg->bch_enabled) 5927304d190SMd Sadre Alam erased = (erased_cw & ERASED_CW) == ERASED_CW; 5937304d190SMd Sadre Alam else 5947304d190SMd Sadre Alam erased = false; 5957304d190SMd Sadre Alam 5967304d190SMd Sadre Alam if (!erased) 5977304d190SMd Sadre Alam uncorrectable_cws |= BIT(i); 5987304d190SMd Sadre Alam 5997304d190SMd Sadre Alam } else if (flash & (FS_OP_ERR | FS_MPU_ERR)) { 6007304d190SMd Sadre Alam flash_op_err = true; 6017304d190SMd Sadre Alam } else { 6027304d190SMd Sadre Alam unsigned int stat; 6037304d190SMd Sadre Alam 6047304d190SMd Sadre Alam stat = buffer & BS_CORRECTABLE_ERR_MSK; 6057304d190SMd Sadre Alam snandc->qspi->ecc_stats.corrected += stat; 6067304d190SMd Sadre Alam max_bitflips = max(max_bitflips, stat); 6077304d190SMd Sadre Alam } 6087304d190SMd Sadre Alam 6097304d190SMd Sadre Alam if (data_buf) 6107304d190SMd Sadre Alam data_buf += data_len; 6117304d190SMd Sadre Alam if (oob_buf) 6127304d190SMd Sadre Alam oob_buf += oob_len + ecc_cfg->bytes; 6137304d190SMd Sadre Alam } 6147304d190SMd Sadre Alam 6157304d190SMd Sadre Alam if (flash_op_err) 6167304d190SMd Sadre Alam return -EIO; 6177304d190SMd Sadre Alam 6187304d190SMd Sadre Alam if (!uncorrectable_cws) 6197304d190SMd Sadre Alam snandc->qspi->ecc_stats.bitflips = max_bitflips; 6207304d190SMd Sadre Alam else 6217304d190SMd Sadre Alam snandc->qspi->ecc_stats.failed++; 6227304d190SMd Sadre Alam 6237304d190SMd Sadre Alam return 0; 6247304d190SMd Sadre Alam } 6257304d190SMd Sadre Alam 6267304d190SMd Sadre Alam static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt) 6277304d190SMd Sadre Alam { 6287304d190SMd Sadre Alam int i; 6297304d190SMd Sadre Alam 6307304d190SMd Sadre Alam qcom_nandc_dev_to_mem(snandc, true); 6317304d190SMd Sadre Alam 6327304d190SMd Sadre Alam for (i = 0; i < cw_cnt; i++) { 6337304d190SMd Sadre Alam u32 flash = le32_to_cpu(snandc->reg_read_buf[i]); 6347304d190SMd Sadre Alam 6357304d190SMd Sadre Alam if (flash & (FS_OP_ERR | FS_MPU_ERR)) 6367304d190SMd Sadre Alam return -EIO; 6377304d190SMd Sadre Alam } 6387304d190SMd Sadre Alam 6397304d190SMd Sadre Alam return 0; 6407304d190SMd Sadre Alam } 6417304d190SMd Sadre Alam 6427304d190SMd Sadre Alam static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf, 6437304d190SMd Sadre Alam u8 *oob_buf, int cw) 6447304d190SMd Sadre Alam { 6457304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 6467304d190SMd Sadre Alam struct mtd_info *mtd = snandc->qspi->mtd; 6477304d190SMd Sadre Alam int data_size1, data_size2, oob_size1, oob_size2; 6487304d190SMd Sadre Alam int ret, reg_off = FLASH_BUF_ACC, read_loc = 0; 6497304d190SMd Sadre Alam int raw_cw = cw; 6507304d190SMd Sadre Alam u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; 6517304d190SMd Sadre Alam int col; 6527304d190SMd Sadre Alam 6537304d190SMd Sadre Alam snandc->buf_count = 0; 6547304d190SMd Sadre Alam snandc->buf_start = 0; 6557304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 6567304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 6577304d190SMd Sadre Alam raw_cw = num_cw - 1; 6587304d190SMd Sadre Alam 6597304d190SMd Sadre Alam cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | 6607304d190SMd Sadre Alam 0 << CW_PER_PAGE; 6617304d190SMd Sadre Alam cfg1 = ecc_cfg->cfg1_raw; 6627304d190SMd Sadre Alam ecc_bch_cfg = ECC_CFG_ECC_DISABLE; 6637304d190SMd Sadre Alam 6647304d190SMd Sadre Alam col = ecc_cfg->cw_size * cw; 6657304d190SMd Sadre Alam 6667304d190SMd Sadre Alam snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); 6677304d190SMd Sadre Alam snandc->regs->addr1 = snandc->qspi->addr2; 6687304d190SMd Sadre Alam snandc->regs->cmd = snandc->qspi->cmd; 6697304d190SMd Sadre Alam snandc->regs->cfg0 = cpu_to_le32(cfg0); 6707304d190SMd Sadre Alam snandc->regs->cfg1 = cpu_to_le32(cfg1); 6717304d190SMd Sadre Alam snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); 6727304d190SMd Sadre Alam snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); 6737304d190SMd Sadre Alam snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); 6747304d190SMd Sadre Alam snandc->regs->exec = cpu_to_le32(1); 6757304d190SMd Sadre Alam 6767304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1); 6777304d190SMd Sadre Alam 6787304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); 6797304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); 6807304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); 6817304d190SMd Sadre Alam 6827304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, 6837304d190SMd Sadre Alam NAND_ERASED_CW_DETECT_CFG, 1, 0); 6847304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, 6857304d190SMd Sadre Alam NAND_ERASED_CW_DETECT_CFG, 1, 6867304d190SMd Sadre Alam NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); 6877304d190SMd Sadre Alam 6887304d190SMd Sadre Alam data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); 6897304d190SMd Sadre Alam oob_size1 = ecc_cfg->bbm_size; 6907304d190SMd Sadre Alam 6917304d190SMd Sadre Alam if (cw == (num_cw - 1)) { 6927304d190SMd Sadre Alam data_size2 = NANDC_STEP_SIZE - data_size1 - 6937304d190SMd Sadre Alam ((num_cw - 1) * 4); 6947304d190SMd Sadre Alam oob_size2 = (num_cw * 4) + ecc_cfg->ecc_bytes_hw + 6957304d190SMd Sadre Alam ecc_cfg->spare_bytes; 6967304d190SMd Sadre Alam } else { 6977304d190SMd Sadre Alam data_size2 = ecc_cfg->cw_data - data_size1; 6987304d190SMd Sadre Alam oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; 6997304d190SMd Sadre Alam } 7007304d190SMd Sadre Alam 7017304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, cw, 0, read_loc, data_size1, 0); 7027304d190SMd Sadre Alam read_loc += data_size1; 7037304d190SMd Sadre Alam 7047304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, cw, 1, read_loc, oob_size1, 0); 7057304d190SMd Sadre Alam read_loc += oob_size1; 7067304d190SMd Sadre Alam 7077304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, cw, 2, read_loc, data_size2, 0); 7087304d190SMd Sadre Alam read_loc += data_size2; 7097304d190SMd Sadre Alam 7107304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, cw, 3, read_loc, oob_size2, 1); 7117304d190SMd Sadre Alam 7127304d190SMd Sadre Alam qcom_spi_config_cw_read(snandc, false, raw_cw); 7137304d190SMd Sadre Alam 7147304d190SMd Sadre Alam qcom_read_data_dma(snandc, reg_off, data_buf, data_size1, 0); 7157304d190SMd Sadre Alam reg_off += data_size1; 7167304d190SMd Sadre Alam 7177304d190SMd Sadre Alam qcom_read_data_dma(snandc, reg_off, oob_buf, oob_size1, 0); 7187304d190SMd Sadre Alam reg_off += oob_size1; 7197304d190SMd Sadre Alam 7207304d190SMd Sadre Alam qcom_read_data_dma(snandc, reg_off, data_buf + data_size1, data_size2, 0); 7217304d190SMd Sadre Alam reg_off += data_size2; 7227304d190SMd Sadre Alam 7237304d190SMd Sadre Alam qcom_read_data_dma(snandc, reg_off, oob_buf + oob_size1, oob_size2, 0); 7247304d190SMd Sadre Alam 7257304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 7267304d190SMd Sadre Alam if (ret) { 7277304d190SMd Sadre Alam dev_err(snandc->dev, "failure to read raw cw %d\n", cw); 7287304d190SMd Sadre Alam return ret; 7297304d190SMd Sadre Alam } 7307304d190SMd Sadre Alam 7317304d190SMd Sadre Alam return qcom_spi_check_raw_flash_errors(snandc, 1); 7327304d190SMd Sadre Alam } 7337304d190SMd Sadre Alam 7347304d190SMd Sadre Alam static int qcom_spi_read_page_raw(struct qcom_nand_controller *snandc, 7357304d190SMd Sadre Alam const struct spi_mem_op *op) 7367304d190SMd Sadre Alam { 7377304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 7387304d190SMd Sadre Alam u8 *data_buf = NULL, *oob_buf = NULL; 7397304d190SMd Sadre Alam int ret, cw; 7407304d190SMd Sadre Alam u32 num_cw = snandc->qspi->num_cw; 7417304d190SMd Sadre Alam 7427304d190SMd Sadre Alam if (snandc->qspi->page_rw) 7437304d190SMd Sadre Alam data_buf = op->data.buf.in; 7447304d190SMd Sadre Alam 7457304d190SMd Sadre Alam oob_buf = snandc->qspi->oob_buf; 7467304d190SMd Sadre Alam memset(oob_buf, 0xff, OOB_BUF_SIZE); 7477304d190SMd Sadre Alam 7487304d190SMd Sadre Alam for (cw = 0; cw < num_cw; cw++) { 7497304d190SMd Sadre Alam ret = qcom_spi_read_cw_raw(snandc, data_buf, oob_buf, cw); 7507304d190SMd Sadre Alam if (ret) 7517304d190SMd Sadre Alam return ret; 7527304d190SMd Sadre Alam 7537304d190SMd Sadre Alam if (data_buf) 7547304d190SMd Sadre Alam data_buf += ecc_cfg->cw_data; 7557304d190SMd Sadre Alam if (oob_buf) 7567304d190SMd Sadre Alam oob_buf += ecc_cfg->bytes; 7577304d190SMd Sadre Alam } 7587304d190SMd Sadre Alam 7597304d190SMd Sadre Alam return 0; 7607304d190SMd Sadre Alam } 7617304d190SMd Sadre Alam 7627304d190SMd Sadre Alam static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc, 7637304d190SMd Sadre Alam const struct spi_mem_op *op) 7647304d190SMd Sadre Alam { 7657304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 7667304d190SMd Sadre Alam u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start; 7677304d190SMd Sadre Alam int ret, i; 7687304d190SMd Sadre Alam u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; 7697304d190SMd Sadre Alam 7707304d190SMd Sadre Alam data_buf = op->data.buf.in; 7717304d190SMd Sadre Alam data_buf_start = data_buf; 7727304d190SMd Sadre Alam 7737304d190SMd Sadre Alam oob_buf = snandc->qspi->oob_buf; 7747304d190SMd Sadre Alam oob_buf_start = oob_buf; 7757304d190SMd Sadre Alam 7767304d190SMd Sadre Alam snandc->buf_count = 0; 7777304d190SMd Sadre Alam snandc->buf_start = 0; 7787304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 7797304d190SMd Sadre Alam 7807304d190SMd Sadre Alam cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | 7817304d190SMd Sadre Alam (num_cw - 1) << CW_PER_PAGE; 7827304d190SMd Sadre Alam cfg1 = ecc_cfg->cfg1; 7837304d190SMd Sadre Alam ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; 7847304d190SMd Sadre Alam 7857304d190SMd Sadre Alam snandc->regs->addr0 = snandc->qspi->addr1; 7867304d190SMd Sadre Alam snandc->regs->addr1 = snandc->qspi->addr2; 7877304d190SMd Sadre Alam snandc->regs->cmd = snandc->qspi->cmd; 7887304d190SMd Sadre Alam snandc->regs->cfg0 = cpu_to_le32(cfg0); 7897304d190SMd Sadre Alam snandc->regs->cfg1 = cpu_to_le32(cfg1); 7907304d190SMd Sadre Alam snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); 7917304d190SMd Sadre Alam snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); 7927304d190SMd Sadre Alam snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); 7937304d190SMd Sadre Alam snandc->regs->exec = cpu_to_le32(1); 7947304d190SMd Sadre Alam 7957304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1); 7967304d190SMd Sadre Alam 7977304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 7987304d190SMd Sadre Alam 7997304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); 8007304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); 8017304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, 8027304d190SMd Sadre Alam NAND_ERASED_CW_DETECT_CFG, 1, 0); 8037304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, 8047304d190SMd Sadre Alam NAND_ERASED_CW_DETECT_CFG, 1, 8057304d190SMd Sadre Alam NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); 8067304d190SMd Sadre Alam 8077304d190SMd Sadre Alam for (i = 0; i < num_cw; i++) { 8087304d190SMd Sadre Alam int data_size, oob_size; 8097304d190SMd Sadre Alam 8107304d190SMd Sadre Alam if (i == (num_cw - 1)) { 8117304d190SMd Sadre Alam data_size = 512 - ((num_cw - 1) << 2); 8127304d190SMd Sadre Alam oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + 8137304d190SMd Sadre Alam ecc_cfg->spare_bytes; 8147304d190SMd Sadre Alam } else { 8157304d190SMd Sadre Alam data_size = ecc_cfg->cw_data; 8167304d190SMd Sadre Alam oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; 8177304d190SMd Sadre Alam } 8187304d190SMd Sadre Alam 8197304d190SMd Sadre Alam if (data_buf && oob_buf) { 8207304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 0); 8217304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, i, 1, data_size, oob_size, 1); 8227304d190SMd Sadre Alam } else if (data_buf) { 8237304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 1); 8247304d190SMd Sadre Alam } else { 8257304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1); 8267304d190SMd Sadre Alam } 8277304d190SMd Sadre Alam 8287304d190SMd Sadre Alam qcom_spi_config_cw_read(snandc, true, i); 8297304d190SMd Sadre Alam 8307304d190SMd Sadre Alam if (data_buf) 8317304d190SMd Sadre Alam qcom_read_data_dma(snandc, FLASH_BUF_ACC, data_buf, 8327304d190SMd Sadre Alam data_size, 0); 8337304d190SMd Sadre Alam if (oob_buf) { 8347304d190SMd Sadre Alam int j; 8357304d190SMd Sadre Alam 8367304d190SMd Sadre Alam for (j = 0; j < ecc_cfg->bbm_size; j++) 8377304d190SMd Sadre Alam *oob_buf++ = 0xff; 8387304d190SMd Sadre Alam 8397304d190SMd Sadre Alam qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size, 8407304d190SMd Sadre Alam oob_buf, oob_size, 0); 8417304d190SMd Sadre Alam } 8427304d190SMd Sadre Alam 8437304d190SMd Sadre Alam if (data_buf) 8447304d190SMd Sadre Alam data_buf += data_size; 8457304d190SMd Sadre Alam if (oob_buf) 8467304d190SMd Sadre Alam oob_buf += oob_size; 8477304d190SMd Sadre Alam } 8487304d190SMd Sadre Alam 8497304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 8507304d190SMd Sadre Alam if (ret) { 8517304d190SMd Sadre Alam dev_err(snandc->dev, "failure to read page\n"); 8527304d190SMd Sadre Alam return ret; 8537304d190SMd Sadre Alam } 8547304d190SMd Sadre Alam 8557304d190SMd Sadre Alam return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start); 8567304d190SMd Sadre Alam } 8577304d190SMd Sadre Alam 8587304d190SMd Sadre Alam static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc, 8597304d190SMd Sadre Alam const struct spi_mem_op *op) 8607304d190SMd Sadre Alam { 8617304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 8627304d190SMd Sadre Alam u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start; 8637304d190SMd Sadre Alam int ret, i; 8647304d190SMd Sadre Alam u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; 8657304d190SMd Sadre Alam 8667304d190SMd Sadre Alam oob_buf = op->data.buf.in; 8677304d190SMd Sadre Alam oob_buf_start = oob_buf; 8687304d190SMd Sadre Alam 8697304d190SMd Sadre Alam data_buf_start = data_buf; 8707304d190SMd Sadre Alam 8717304d190SMd Sadre Alam snandc->buf_count = 0; 8727304d190SMd Sadre Alam snandc->buf_start = 0; 8737304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 8747304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 8757304d190SMd Sadre Alam 8767304d190SMd Sadre Alam cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | 8777304d190SMd Sadre Alam (num_cw - 1) << CW_PER_PAGE; 8787304d190SMd Sadre Alam cfg1 = ecc_cfg->cfg1; 8797304d190SMd Sadre Alam ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; 8807304d190SMd Sadre Alam 8817304d190SMd Sadre Alam snandc->regs->addr0 = snandc->qspi->addr1; 8827304d190SMd Sadre Alam snandc->regs->addr1 = snandc->qspi->addr2; 8837304d190SMd Sadre Alam snandc->regs->cmd = snandc->qspi->cmd; 8847304d190SMd Sadre Alam snandc->regs->cfg0 = cpu_to_le32(cfg0); 8857304d190SMd Sadre Alam snandc->regs->cfg1 = cpu_to_le32(cfg1); 8867304d190SMd Sadre Alam snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); 8877304d190SMd Sadre Alam snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); 8887304d190SMd Sadre Alam snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); 8897304d190SMd Sadre Alam snandc->regs->exec = cpu_to_le32(1); 8907304d190SMd Sadre Alam 8917304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1); 8927304d190SMd Sadre Alam 8937304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); 8947304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); 8957304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, 8967304d190SMd Sadre Alam NAND_ERASED_CW_DETECT_CFG, 1, 0); 8977304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, 8987304d190SMd Sadre Alam NAND_ERASED_CW_DETECT_CFG, 1, 8997304d190SMd Sadre Alam NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); 9007304d190SMd Sadre Alam 9017304d190SMd Sadre Alam for (i = 0; i < num_cw; i++) { 9027304d190SMd Sadre Alam int data_size, oob_size; 9037304d190SMd Sadre Alam 9047304d190SMd Sadre Alam if (i == (num_cw - 1)) { 9057304d190SMd Sadre Alam data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2); 9067304d190SMd Sadre Alam oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + 9077304d190SMd Sadre Alam ecc_cfg->spare_bytes; 9087304d190SMd Sadre Alam } else { 9097304d190SMd Sadre Alam data_size = ecc_cfg->cw_data; 9107304d190SMd Sadre Alam oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; 9117304d190SMd Sadre Alam } 9127304d190SMd Sadre Alam 9137304d190SMd Sadre Alam qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1); 9147304d190SMd Sadre Alam 9157304d190SMd Sadre Alam qcom_spi_config_cw_read(snandc, true, i); 9167304d190SMd Sadre Alam 9177304d190SMd Sadre Alam if (oob_buf) { 9187304d190SMd Sadre Alam int j; 9197304d190SMd Sadre Alam 9207304d190SMd Sadre Alam for (j = 0; j < ecc_cfg->bbm_size; j++) 9217304d190SMd Sadre Alam *oob_buf++ = 0xff; 9227304d190SMd Sadre Alam 9237304d190SMd Sadre Alam qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size, 9247304d190SMd Sadre Alam oob_buf, oob_size, 0); 9257304d190SMd Sadre Alam } 9267304d190SMd Sadre Alam 9277304d190SMd Sadre Alam if (oob_buf) 9287304d190SMd Sadre Alam oob_buf += oob_size; 9297304d190SMd Sadre Alam } 9307304d190SMd Sadre Alam 9317304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 9327304d190SMd Sadre Alam if (ret) { 9337304d190SMd Sadre Alam dev_err(snandc->dev, "failure to read oob\n"); 9347304d190SMd Sadre Alam return ret; 9357304d190SMd Sadre Alam } 9367304d190SMd Sadre Alam 9377304d190SMd Sadre Alam return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start); 9387304d190SMd Sadre Alam } 9397304d190SMd Sadre Alam 9407304d190SMd Sadre Alam static int qcom_spi_read_page(struct qcom_nand_controller *snandc, 9417304d190SMd Sadre Alam const struct spi_mem_op *op) 9427304d190SMd Sadre Alam { 9437304d190SMd Sadre Alam if (snandc->qspi->page_rw && snandc->qspi->raw_rw) 9447304d190SMd Sadre Alam return qcom_spi_read_page_raw(snandc, op); 9457304d190SMd Sadre Alam 9467304d190SMd Sadre Alam if (snandc->qspi->page_rw) 9477304d190SMd Sadre Alam return qcom_spi_read_page_ecc(snandc, op); 9487304d190SMd Sadre Alam 9497304d190SMd Sadre Alam if (snandc->qspi->oob_rw && snandc->qspi->raw_rw) 9507304d190SMd Sadre Alam return qcom_spi_read_last_cw(snandc, op); 9517304d190SMd Sadre Alam 9527304d190SMd Sadre Alam if (snandc->qspi->oob_rw) 9537304d190SMd Sadre Alam return qcom_spi_read_page_oob(snandc, op); 9547304d190SMd Sadre Alam 9557304d190SMd Sadre Alam return 0; 9567304d190SMd Sadre Alam } 9577304d190SMd Sadre Alam 9587304d190SMd Sadre Alam static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc) 9597304d190SMd Sadre Alam { 9607304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); 9617304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); 9627304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 9637304d190SMd Sadre Alam 1, NAND_BAM_NEXT_SGL); 9647304d190SMd Sadre Alam } 9657304d190SMd Sadre Alam 9667304d190SMd Sadre Alam static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc) 9677304d190SMd Sadre Alam { 9687304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); 9697304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); 9707304d190SMd Sadre Alam qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); 9717304d190SMd Sadre Alam 9727304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0); 9737304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->clrreadstatus, NAND_READ_STATUS, 1, 9747304d190SMd Sadre Alam NAND_BAM_NEXT_SGL); 9757304d190SMd Sadre Alam } 9767304d190SMd Sadre Alam 9777304d190SMd Sadre Alam static int qcom_spi_program_raw(struct qcom_nand_controller *snandc, 9787304d190SMd Sadre Alam const struct spi_mem_op *op) 9797304d190SMd Sadre Alam { 9807304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 9817304d190SMd Sadre Alam struct mtd_info *mtd = snandc->qspi->mtd; 9827304d190SMd Sadre Alam u8 *data_buf = NULL, *oob_buf = NULL; 9837304d190SMd Sadre Alam int i, ret; 9847304d190SMd Sadre Alam int num_cw = snandc->qspi->num_cw; 9857304d190SMd Sadre Alam u32 cfg0, cfg1, ecc_bch_cfg; 9867304d190SMd Sadre Alam 9877304d190SMd Sadre Alam cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | 9887304d190SMd Sadre Alam (num_cw - 1) << CW_PER_PAGE; 9897304d190SMd Sadre Alam cfg1 = ecc_cfg->cfg1_raw; 9907304d190SMd Sadre Alam ecc_bch_cfg = ECC_CFG_ECC_DISABLE; 9917304d190SMd Sadre Alam 9927304d190SMd Sadre Alam data_buf = snandc->qspi->data_buf; 9937304d190SMd Sadre Alam 9947304d190SMd Sadre Alam oob_buf = snandc->qspi->oob_buf; 9957304d190SMd Sadre Alam memset(oob_buf, 0xff, OOB_BUF_SIZE); 9967304d190SMd Sadre Alam 9977304d190SMd Sadre Alam snandc->buf_count = 0; 9987304d190SMd Sadre Alam snandc->buf_start = 0; 9997304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 10007304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 10017304d190SMd Sadre Alam 10027304d190SMd Sadre Alam snandc->regs->addr0 = snandc->qspi->addr1; 10037304d190SMd Sadre Alam snandc->regs->addr1 = snandc->qspi->addr2; 10047304d190SMd Sadre Alam snandc->regs->cmd = snandc->qspi->cmd; 10057304d190SMd Sadre Alam snandc->regs->cfg0 = cpu_to_le32(cfg0); 10067304d190SMd Sadre Alam snandc->regs->cfg1 = cpu_to_le32(cfg1); 10077304d190SMd Sadre Alam snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); 10087304d190SMd Sadre Alam snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); 10097304d190SMd Sadre Alam snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); 10107304d190SMd Sadre Alam snandc->regs->exec = cpu_to_le32(1); 10117304d190SMd Sadre Alam 10127304d190SMd Sadre Alam qcom_spi_config_page_write(snandc); 10137304d190SMd Sadre Alam 10147304d190SMd Sadre Alam for (i = 0; i < num_cw; i++) { 10157304d190SMd Sadre Alam int data_size1, data_size2, oob_size1, oob_size2; 10167304d190SMd Sadre Alam int reg_off = FLASH_BUF_ACC; 10177304d190SMd Sadre Alam 10187304d190SMd Sadre Alam data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); 10197304d190SMd Sadre Alam oob_size1 = ecc_cfg->bbm_size; 10207304d190SMd Sadre Alam 10217304d190SMd Sadre Alam if (i == (num_cw - 1)) { 10227304d190SMd Sadre Alam data_size2 = NANDC_STEP_SIZE - data_size1 - 10237304d190SMd Sadre Alam ((num_cw - 1) << 2); 10247304d190SMd Sadre Alam oob_size2 = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + 10257304d190SMd Sadre Alam ecc_cfg->spare_bytes; 10267304d190SMd Sadre Alam } else { 10277304d190SMd Sadre Alam data_size2 = ecc_cfg->cw_data - data_size1; 10287304d190SMd Sadre Alam oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; 10297304d190SMd Sadre Alam } 10307304d190SMd Sadre Alam 10317304d190SMd Sadre Alam qcom_write_data_dma(snandc, reg_off, data_buf, data_size1, 10327304d190SMd Sadre Alam NAND_BAM_NO_EOT); 10337304d190SMd Sadre Alam reg_off += data_size1; 10347304d190SMd Sadre Alam data_buf += data_size1; 10357304d190SMd Sadre Alam 10367304d190SMd Sadre Alam qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size1, 10377304d190SMd Sadre Alam NAND_BAM_NO_EOT); 10387304d190SMd Sadre Alam oob_buf += oob_size1; 10397304d190SMd Sadre Alam reg_off += oob_size1; 10407304d190SMd Sadre Alam 10417304d190SMd Sadre Alam qcom_write_data_dma(snandc, reg_off, data_buf, data_size2, 10427304d190SMd Sadre Alam NAND_BAM_NO_EOT); 10437304d190SMd Sadre Alam reg_off += data_size2; 10447304d190SMd Sadre Alam data_buf += data_size2; 10457304d190SMd Sadre Alam 10467304d190SMd Sadre Alam qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size2, 0); 10477304d190SMd Sadre Alam oob_buf += oob_size2; 10487304d190SMd Sadre Alam 10497304d190SMd Sadre Alam qcom_spi_config_cw_write(snandc); 10507304d190SMd Sadre Alam } 10517304d190SMd Sadre Alam 10527304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 10537304d190SMd Sadre Alam if (ret) { 10547304d190SMd Sadre Alam dev_err(snandc->dev, "failure to write raw page\n"); 10557304d190SMd Sadre Alam return ret; 10567304d190SMd Sadre Alam } 10577304d190SMd Sadre Alam 10587304d190SMd Sadre Alam return 0; 10597304d190SMd Sadre Alam } 10607304d190SMd Sadre Alam 10617304d190SMd Sadre Alam static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc, 10627304d190SMd Sadre Alam const struct spi_mem_op *op) 10637304d190SMd Sadre Alam { 10647304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 10657304d190SMd Sadre Alam u8 *data_buf = NULL, *oob_buf = NULL; 10667304d190SMd Sadre Alam int i, ret; 10677304d190SMd Sadre Alam int num_cw = snandc->qspi->num_cw; 10687304d190SMd Sadre Alam u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg; 10697304d190SMd Sadre Alam 10707304d190SMd Sadre Alam cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | 10717304d190SMd Sadre Alam (num_cw - 1) << CW_PER_PAGE; 10727304d190SMd Sadre Alam cfg1 = ecc_cfg->cfg1; 10737304d190SMd Sadre Alam ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; 10747304d190SMd Sadre Alam ecc_buf_cfg = ecc_cfg->ecc_buf_cfg; 10757304d190SMd Sadre Alam 10767304d190SMd Sadre Alam if (snandc->qspi->data_buf) 10777304d190SMd Sadre Alam data_buf = snandc->qspi->data_buf; 10787304d190SMd Sadre Alam 10797304d190SMd Sadre Alam oob_buf = snandc->qspi->oob_buf; 10807304d190SMd Sadre Alam 10817304d190SMd Sadre Alam snandc->buf_count = 0; 10827304d190SMd Sadre Alam snandc->buf_start = 0; 10837304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 10847304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 10857304d190SMd Sadre Alam 10867304d190SMd Sadre Alam snandc->regs->addr0 = snandc->qspi->addr1; 10877304d190SMd Sadre Alam snandc->regs->addr1 = snandc->qspi->addr2; 10887304d190SMd Sadre Alam snandc->regs->cmd = snandc->qspi->cmd; 10897304d190SMd Sadre Alam snandc->regs->cfg0 = cpu_to_le32(cfg0); 10907304d190SMd Sadre Alam snandc->regs->cfg1 = cpu_to_le32(cfg1); 10917304d190SMd Sadre Alam snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); 10927304d190SMd Sadre Alam snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg); 10937304d190SMd Sadre Alam snandc->regs->exec = cpu_to_le32(1); 10947304d190SMd Sadre Alam 10957304d190SMd Sadre Alam qcom_spi_config_page_write(snandc); 10967304d190SMd Sadre Alam 10977304d190SMd Sadre Alam for (i = 0; i < num_cw; i++) { 10987304d190SMd Sadre Alam int data_size, oob_size; 10997304d190SMd Sadre Alam 11007304d190SMd Sadre Alam if (i == (num_cw - 1)) { 11017304d190SMd Sadre Alam data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2); 11027304d190SMd Sadre Alam oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + 11037304d190SMd Sadre Alam ecc_cfg->spare_bytes; 11047304d190SMd Sadre Alam } else { 11057304d190SMd Sadre Alam data_size = ecc_cfg->cw_data; 11067304d190SMd Sadre Alam oob_size = ecc_cfg->bytes; 11077304d190SMd Sadre Alam } 11087304d190SMd Sadre Alam 11097304d190SMd Sadre Alam if (data_buf) 11107304d190SMd Sadre Alam qcom_write_data_dma(snandc, FLASH_BUF_ACC, data_buf, data_size, 11117304d190SMd Sadre Alam i == (num_cw - 1) ? NAND_BAM_NO_EOT : 0); 11127304d190SMd Sadre Alam 11137304d190SMd Sadre Alam if (i == (num_cw - 1)) { 11147304d190SMd Sadre Alam if (oob_buf) { 11157304d190SMd Sadre Alam oob_buf += ecc_cfg->bbm_size; 11167304d190SMd Sadre Alam qcom_write_data_dma(snandc, FLASH_BUF_ACC + data_size, 11177304d190SMd Sadre Alam oob_buf, oob_size, 0); 11187304d190SMd Sadre Alam } 11197304d190SMd Sadre Alam } 11207304d190SMd Sadre Alam 11217304d190SMd Sadre Alam qcom_spi_config_cw_write(snandc); 11227304d190SMd Sadre Alam 11237304d190SMd Sadre Alam if (data_buf) 11247304d190SMd Sadre Alam data_buf += data_size; 11257304d190SMd Sadre Alam if (oob_buf) 11267304d190SMd Sadre Alam oob_buf += oob_size; 11277304d190SMd Sadre Alam } 11287304d190SMd Sadre Alam 11297304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 11307304d190SMd Sadre Alam if (ret) { 11317304d190SMd Sadre Alam dev_err(snandc->dev, "failure to write page\n"); 11327304d190SMd Sadre Alam return ret; 11337304d190SMd Sadre Alam } 11347304d190SMd Sadre Alam 11357304d190SMd Sadre Alam return 0; 11367304d190SMd Sadre Alam } 11377304d190SMd Sadre Alam 11387304d190SMd Sadre Alam static int qcom_spi_program_oob(struct qcom_nand_controller *snandc, 11397304d190SMd Sadre Alam const struct spi_mem_op *op) 11407304d190SMd Sadre Alam { 11417304d190SMd Sadre Alam struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; 11427304d190SMd Sadre Alam u8 *oob_buf = NULL; 11437304d190SMd Sadre Alam int ret, col, data_size, oob_size; 11447304d190SMd Sadre Alam int num_cw = snandc->qspi->num_cw; 11457304d190SMd Sadre Alam u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg; 11467304d190SMd Sadre Alam 11477304d190SMd Sadre Alam cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | 11487304d190SMd Sadre Alam (num_cw - 1) << CW_PER_PAGE; 11497304d190SMd Sadre Alam cfg1 = ecc_cfg->cfg1; 11507304d190SMd Sadre Alam ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; 11517304d190SMd Sadre Alam ecc_buf_cfg = ecc_cfg->ecc_buf_cfg; 11527304d190SMd Sadre Alam 11537304d190SMd Sadre Alam col = ecc_cfg->cw_size * (num_cw - 1); 11547304d190SMd Sadre Alam 11557304d190SMd Sadre Alam oob_buf = snandc->qspi->data_buf; 11567304d190SMd Sadre Alam 11577304d190SMd Sadre Alam snandc->buf_count = 0; 11587304d190SMd Sadre Alam snandc->buf_start = 0; 11597304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 11607304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 11617304d190SMd Sadre Alam snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); 11627304d190SMd Sadre Alam snandc->regs->addr1 = snandc->qspi->addr2; 11637304d190SMd Sadre Alam snandc->regs->cmd = snandc->qspi->cmd; 11647304d190SMd Sadre Alam snandc->regs->cfg0 = cpu_to_le32(cfg0); 11657304d190SMd Sadre Alam snandc->regs->cfg1 = cpu_to_le32(cfg1); 11667304d190SMd Sadre Alam snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); 11677304d190SMd Sadre Alam snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg); 11687304d190SMd Sadre Alam snandc->regs->exec = cpu_to_le32(1); 11697304d190SMd Sadre Alam 11707304d190SMd Sadre Alam /* calculate the data and oob size for the last codeword/step */ 11717304d190SMd Sadre Alam data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2); 11727304d190SMd Sadre Alam oob_size = snandc->qspi->mtd->oobavail; 11737304d190SMd Sadre Alam 11747304d190SMd Sadre Alam memset(snandc->data_buffer, 0xff, ecc_cfg->cw_data); 11757304d190SMd Sadre Alam /* override new oob content to last codeword */ 11767304d190SMd Sadre Alam mtd_ooblayout_get_databytes(snandc->qspi->mtd, snandc->data_buffer + data_size, 11777304d190SMd Sadre Alam oob_buf, 0, snandc->qspi->mtd->oobavail); 11787304d190SMd Sadre Alam qcom_spi_config_page_write(snandc); 11797304d190SMd Sadre Alam qcom_write_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, data_size + oob_size, 0); 11807304d190SMd Sadre Alam qcom_spi_config_cw_write(snandc); 11817304d190SMd Sadre Alam 11827304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 11837304d190SMd Sadre Alam if (ret) { 11847304d190SMd Sadre Alam dev_err(snandc->dev, "failure to write oob\n"); 11857304d190SMd Sadre Alam return ret; 11867304d190SMd Sadre Alam } 11877304d190SMd Sadre Alam 11887304d190SMd Sadre Alam return 0; 11897304d190SMd Sadre Alam } 11907304d190SMd Sadre Alam 11917304d190SMd Sadre Alam static int qcom_spi_program_execute(struct qcom_nand_controller *snandc, 11927304d190SMd Sadre Alam const struct spi_mem_op *op) 11937304d190SMd Sadre Alam { 11947304d190SMd Sadre Alam if (snandc->qspi->page_rw && snandc->qspi->raw_rw) 11957304d190SMd Sadre Alam return qcom_spi_program_raw(snandc, op); 11967304d190SMd Sadre Alam 11977304d190SMd Sadre Alam if (snandc->qspi->page_rw) 11987304d190SMd Sadre Alam return qcom_spi_program_ecc(snandc, op); 11997304d190SMd Sadre Alam 12007304d190SMd Sadre Alam if (snandc->qspi->oob_rw) 12017304d190SMd Sadre Alam return qcom_spi_program_oob(snandc, op); 12027304d190SMd Sadre Alam 12037304d190SMd Sadre Alam return 0; 12047304d190SMd Sadre Alam } 12057304d190SMd Sadre Alam 12067304d190SMd Sadre Alam static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd) 12077304d190SMd Sadre Alam { 12087304d190SMd Sadre Alam switch (opcode) { 12097304d190SMd Sadre Alam case SPINAND_RESET: 12107304d190SMd Sadre Alam *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE); 12117304d190SMd Sadre Alam break; 12127304d190SMd Sadre Alam case SPINAND_READID: 12137304d190SMd Sadre Alam *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID); 12147304d190SMd Sadre Alam break; 12157304d190SMd Sadre Alam case SPINAND_GET_FEATURE: 12167304d190SMd Sadre Alam *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE); 12177304d190SMd Sadre Alam break; 12187304d190SMd Sadre Alam case SPINAND_SET_FEATURE: 12197304d190SMd Sadre Alam *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE | 12207304d190SMd Sadre Alam QPIC_SET_FEATURE); 12217304d190SMd Sadre Alam break; 12227304d190SMd Sadre Alam case SPINAND_READ: 12237304d190SMd Sadre Alam if (snandc->qspi->raw_rw) { 12247304d190SMd Sadre Alam *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 | 12257304d190SMd Sadre Alam SPI_WP | SPI_HOLD | OP_PAGE_READ); 12267304d190SMd Sadre Alam } else { 12277304d190SMd Sadre Alam *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 | 12287304d190SMd Sadre Alam SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC); 12297304d190SMd Sadre Alam } 12307304d190SMd Sadre Alam 12317304d190SMd Sadre Alam break; 12327304d190SMd Sadre Alam case SPINAND_ERASE: 12337304d190SMd Sadre Alam *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP | 12347304d190SMd Sadre Alam SPI_HOLD | SPI_TRANSFER_MODE_x1; 12357304d190SMd Sadre Alam break; 12367304d190SMd Sadre Alam case SPINAND_WRITE_EN: 12377304d190SMd Sadre Alam *cmd = SPINAND_WRITE_EN; 12387304d190SMd Sadre Alam break; 12397304d190SMd Sadre Alam case SPINAND_PROGRAM_EXECUTE: 12407304d190SMd Sadre Alam *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 | 12417304d190SMd Sadre Alam SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE); 12427304d190SMd Sadre Alam break; 12437304d190SMd Sadre Alam case SPINAND_PROGRAM_LOAD: 12447304d190SMd Sadre Alam *cmd = SPINAND_PROGRAM_LOAD; 12457304d190SMd Sadre Alam break; 12467304d190SMd Sadre Alam default: 12477304d190SMd Sadre Alam dev_err(snandc->dev, "Opcode not supported: %u\n", opcode); 12487304d190SMd Sadre Alam return -EOPNOTSUPP; 12497304d190SMd Sadre Alam } 12507304d190SMd Sadre Alam 12517304d190SMd Sadre Alam return 0; 12527304d190SMd Sadre Alam } 12537304d190SMd Sadre Alam 12547304d190SMd Sadre Alam static int qcom_spi_write_page(struct qcom_nand_controller *snandc, 12557304d190SMd Sadre Alam const struct spi_mem_op *op) 12567304d190SMd Sadre Alam { 12577304d190SMd Sadre Alam int ret; 12587304d190SMd Sadre Alam u32 cmd; 12597304d190SMd Sadre Alam 12607304d190SMd Sadre Alam ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd); 12617304d190SMd Sadre Alam if (ret < 0) 12627304d190SMd Sadre Alam return ret; 12637304d190SMd Sadre Alam 12647304d190SMd Sadre Alam if (op->cmd.opcode == SPINAND_PROGRAM_LOAD) 12657304d190SMd Sadre Alam snandc->qspi->data_buf = (u8 *)op->data.buf.out; 12667304d190SMd Sadre Alam 12677304d190SMd Sadre Alam return 0; 12687304d190SMd Sadre Alam } 12697304d190SMd Sadre Alam 12707304d190SMd Sadre Alam static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc, 12717304d190SMd Sadre Alam const struct spi_mem_op *op) 12727304d190SMd Sadre Alam { 12737304d190SMd Sadre Alam struct qpic_snand_op s_op = {}; 12747304d190SMd Sadre Alam u32 cmd; 12757304d190SMd Sadre Alam int ret, opcode; 12767304d190SMd Sadre Alam 12777304d190SMd Sadre Alam ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd); 12787304d190SMd Sadre Alam if (ret < 0) 12797304d190SMd Sadre Alam return ret; 12807304d190SMd Sadre Alam 12817304d190SMd Sadre Alam s_op.cmd_reg = cmd; 12827304d190SMd Sadre Alam s_op.addr1_reg = op->addr.val; 12837304d190SMd Sadre Alam s_op.addr2_reg = 0; 12847304d190SMd Sadre Alam 12857304d190SMd Sadre Alam opcode = op->cmd.opcode; 12867304d190SMd Sadre Alam 12877304d190SMd Sadre Alam switch (opcode) { 12887304d190SMd Sadre Alam case SPINAND_WRITE_EN: 12897304d190SMd Sadre Alam return 0; 12907304d190SMd Sadre Alam case SPINAND_PROGRAM_EXECUTE: 12917304d190SMd Sadre Alam s_op.addr1_reg = op->addr.val << 16; 12927304d190SMd Sadre Alam s_op.addr2_reg = op->addr.val >> 16 & 0xff; 12937304d190SMd Sadre Alam snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg); 12947304d190SMd Sadre Alam snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); 12957304d190SMd Sadre Alam snandc->qspi->cmd = cpu_to_le32(cmd); 12967304d190SMd Sadre Alam return qcom_spi_program_execute(snandc, op); 12977304d190SMd Sadre Alam case SPINAND_READ: 12987304d190SMd Sadre Alam s_op.addr1_reg = (op->addr.val << 16); 12997304d190SMd Sadre Alam s_op.addr2_reg = op->addr.val >> 16 & 0xff; 13007304d190SMd Sadre Alam snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg); 13017304d190SMd Sadre Alam snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); 13027304d190SMd Sadre Alam snandc->qspi->cmd = cpu_to_le32(cmd); 13037304d190SMd Sadre Alam return 0; 13047304d190SMd Sadre Alam case SPINAND_ERASE: 13057304d190SMd Sadre Alam s_op.addr2_reg = (op->addr.val >> 16) & 0xffff; 13067304d190SMd Sadre Alam s_op.addr1_reg = op->addr.val; 13077304d190SMd Sadre Alam snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16); 13087304d190SMd Sadre Alam snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); 13097304d190SMd Sadre Alam snandc->qspi->cmd = cpu_to_le32(cmd); 13107304d190SMd Sadre Alam qcom_spi_block_erase(snandc); 13117304d190SMd Sadre Alam return 0; 13127304d190SMd Sadre Alam default: 13137304d190SMd Sadre Alam break; 13147304d190SMd Sadre Alam } 13157304d190SMd Sadre Alam 13167304d190SMd Sadre Alam snandc->buf_count = 0; 13177304d190SMd Sadre Alam snandc->buf_start = 0; 13187304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 13197304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 13207304d190SMd Sadre Alam 13217304d190SMd Sadre Alam snandc->regs->cmd = cpu_to_le32(s_op.cmd_reg); 13227304d190SMd Sadre Alam snandc->regs->exec = cpu_to_le32(1); 13237304d190SMd Sadre Alam snandc->regs->addr0 = cpu_to_le32(s_op.addr1_reg); 13247304d190SMd Sadre Alam snandc->regs->addr1 = cpu_to_le32(s_op.addr2_reg); 13257304d190SMd Sadre Alam 13267304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); 13277304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); 13287304d190SMd Sadre Alam 13297304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 13307304d190SMd Sadre Alam if (ret) 13317304d190SMd Sadre Alam dev_err(snandc->dev, "failure in submitting cmd descriptor\n"); 13327304d190SMd Sadre Alam 13337304d190SMd Sadre Alam return ret; 13347304d190SMd Sadre Alam } 13357304d190SMd Sadre Alam 13367304d190SMd Sadre Alam static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_mem_op *op) 13377304d190SMd Sadre Alam { 13387304d190SMd Sadre Alam int ret, val, opcode; 13397304d190SMd Sadre Alam bool copy = false, copy_ftr = false; 13407304d190SMd Sadre Alam 13417304d190SMd Sadre Alam ret = qcom_spi_send_cmdaddr(snandc, op); 13427304d190SMd Sadre Alam if (ret) 13437304d190SMd Sadre Alam return ret; 13447304d190SMd Sadre Alam 13457304d190SMd Sadre Alam snandc->buf_count = 0; 13467304d190SMd Sadre Alam snandc->buf_start = 0; 13477304d190SMd Sadre Alam qcom_clear_read_regs(snandc); 13487304d190SMd Sadre Alam qcom_clear_bam_transaction(snandc); 13497304d190SMd Sadre Alam opcode = op->cmd.opcode; 13507304d190SMd Sadre Alam 13517304d190SMd Sadre Alam switch (opcode) { 13527304d190SMd Sadre Alam case SPINAND_READID: 13537304d190SMd Sadre Alam snandc->buf_count = 4; 13547304d190SMd Sadre Alam qcom_read_reg_dma(snandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); 13557304d190SMd Sadre Alam copy = true; 13567304d190SMd Sadre Alam break; 13577304d190SMd Sadre Alam case SPINAND_GET_FEATURE: 13587304d190SMd Sadre Alam snandc->buf_count = 4; 13597304d190SMd Sadre Alam qcom_read_reg_dma(snandc, NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL); 13607304d190SMd Sadre Alam copy_ftr = true; 13617304d190SMd Sadre Alam break; 13627304d190SMd Sadre Alam case SPINAND_SET_FEATURE: 13637304d190SMd Sadre Alam snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out); 13647304d190SMd Sadre Alam qcom_write_reg_dma(snandc, &snandc->regs->flash_feature, 13657304d190SMd Sadre Alam NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL); 13667304d190SMd Sadre Alam break; 13677304d190SMd Sadre Alam case SPINAND_PROGRAM_EXECUTE: 13687304d190SMd Sadre Alam case SPINAND_WRITE_EN: 13697304d190SMd Sadre Alam case SPINAND_RESET: 13707304d190SMd Sadre Alam case SPINAND_ERASE: 13717304d190SMd Sadre Alam case SPINAND_READ: 13727304d190SMd Sadre Alam return 0; 13737304d190SMd Sadre Alam default: 13747304d190SMd Sadre Alam return -EOPNOTSUPP; 13757304d190SMd Sadre Alam } 13767304d190SMd Sadre Alam 13777304d190SMd Sadre Alam ret = qcom_submit_descs(snandc); 13787304d190SMd Sadre Alam if (ret) 13797304d190SMd Sadre Alam dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode); 13807304d190SMd Sadre Alam 13817304d190SMd Sadre Alam if (copy) { 13827304d190SMd Sadre Alam qcom_nandc_dev_to_mem(snandc, true); 13837304d190SMd Sadre Alam memcpy(op->data.buf.in, snandc->reg_read_buf, snandc->buf_count); 13847304d190SMd Sadre Alam } 13857304d190SMd Sadre Alam 13867304d190SMd Sadre Alam if (copy_ftr) { 13877304d190SMd Sadre Alam qcom_nandc_dev_to_mem(snandc, true); 13887304d190SMd Sadre Alam val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf); 13897304d190SMd Sadre Alam val >>= 8; 13907304d190SMd Sadre Alam memcpy(op->data.buf.in, &val, snandc->buf_count); 13917304d190SMd Sadre Alam } 13927304d190SMd Sadre Alam 13937304d190SMd Sadre Alam return ret; 13947304d190SMd Sadre Alam } 13957304d190SMd Sadre Alam 13967304d190SMd Sadre Alam static bool qcom_spi_is_page_op(const struct spi_mem_op *op) 13977304d190SMd Sadre Alam { 13987304d190SMd Sadre Alam if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && op->addr.buswidth != 4) 13997304d190SMd Sadre Alam return false; 14007304d190SMd Sadre Alam 14017304d190SMd Sadre Alam if (op->data.dir == SPI_MEM_DATA_IN) { 14027304d190SMd Sadre Alam if (op->addr.buswidth == 4 && op->data.buswidth == 4) 14037304d190SMd Sadre Alam return true; 14047304d190SMd Sadre Alam 14057304d190SMd Sadre Alam if (op->addr.nbytes == 2 && op->addr.buswidth == 1) 14067304d190SMd Sadre Alam return true; 14077304d190SMd Sadre Alam 14087304d190SMd Sadre Alam } else if (op->data.dir == SPI_MEM_DATA_OUT) { 14097304d190SMd Sadre Alam if (op->data.buswidth == 4) 14107304d190SMd Sadre Alam return true; 14117304d190SMd Sadre Alam if (op->addr.nbytes == 2 && op->addr.buswidth == 1) 14127304d190SMd Sadre Alam return true; 14137304d190SMd Sadre Alam } 14147304d190SMd Sadre Alam 14157304d190SMd Sadre Alam return false; 14167304d190SMd Sadre Alam } 14177304d190SMd Sadre Alam 14187304d190SMd Sadre Alam static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) 14197304d190SMd Sadre Alam { 14207304d190SMd Sadre Alam if (!spi_mem_default_supports_op(mem, op)) 14217304d190SMd Sadre Alam return false; 14227304d190SMd Sadre Alam 14237304d190SMd Sadre Alam if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1) 14247304d190SMd Sadre Alam return false; 14257304d190SMd Sadre Alam 14267304d190SMd Sadre Alam if (qcom_spi_is_page_op(op)) 14277304d190SMd Sadre Alam return true; 14287304d190SMd Sadre Alam 14297304d190SMd Sadre Alam return ((!op->addr.nbytes || op->addr.buswidth == 1) && 14307304d190SMd Sadre Alam (!op->dummy.nbytes || op->dummy.buswidth == 1) && 14317304d190SMd Sadre Alam (!op->data.nbytes || op->data.buswidth == 1)); 14327304d190SMd Sadre Alam } 14337304d190SMd Sadre Alam 14347304d190SMd Sadre Alam static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) 14357304d190SMd Sadre Alam { 14367304d190SMd Sadre Alam struct qcom_nand_controller *snandc = spi_controller_get_devdata(mem->spi->controller); 14377304d190SMd Sadre Alam 14387304d190SMd Sadre Alam dev_dbg(snandc->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode, 14397304d190SMd Sadre Alam op->addr.val, op->addr.buswidth, op->addr.nbytes, 14407304d190SMd Sadre Alam op->data.buswidth, op->data.nbytes); 14417304d190SMd Sadre Alam 14427304d190SMd Sadre Alam if (qcom_spi_is_page_op(op)) { 14437304d190SMd Sadre Alam if (op->data.dir == SPI_MEM_DATA_IN) 14447304d190SMd Sadre Alam return qcom_spi_read_page(snandc, op); 14457304d190SMd Sadre Alam if (op->data.dir == SPI_MEM_DATA_OUT) 14467304d190SMd Sadre Alam return qcom_spi_write_page(snandc, op); 14477304d190SMd Sadre Alam } else { 14487304d190SMd Sadre Alam return qcom_spi_io_op(snandc, op); 14497304d190SMd Sadre Alam } 14507304d190SMd Sadre Alam 14517304d190SMd Sadre Alam return 0; 14527304d190SMd Sadre Alam } 14537304d190SMd Sadre Alam 14547304d190SMd Sadre Alam static const struct spi_controller_mem_ops qcom_spi_mem_ops = { 14557304d190SMd Sadre Alam .supports_op = qcom_spi_supports_op, 14567304d190SMd Sadre Alam .exec_op = qcom_spi_exec_op, 14577304d190SMd Sadre Alam }; 14587304d190SMd Sadre Alam 14597304d190SMd Sadre Alam static const struct spi_controller_mem_caps qcom_spi_mem_caps = { 14607304d190SMd Sadre Alam .ecc = true, 14617304d190SMd Sadre Alam }; 14627304d190SMd Sadre Alam 14637304d190SMd Sadre Alam static int qcom_spi_probe(struct platform_device *pdev) 14647304d190SMd Sadre Alam { 14657304d190SMd Sadre Alam struct device *dev = &pdev->dev; 14667304d190SMd Sadre Alam struct spi_controller *ctlr; 14677304d190SMd Sadre Alam struct qcom_nand_controller *snandc; 14687304d190SMd Sadre Alam struct qpic_spi_nand *qspi; 14697304d190SMd Sadre Alam struct qpic_ecc *ecc; 14707304d190SMd Sadre Alam struct resource *res; 14717304d190SMd Sadre Alam const void *dev_data; 14727304d190SMd Sadre Alam int ret; 14737304d190SMd Sadre Alam 14747304d190SMd Sadre Alam ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL); 14757304d190SMd Sadre Alam if (!ecc) 14767304d190SMd Sadre Alam return -ENOMEM; 14777304d190SMd Sadre Alam 14787304d190SMd Sadre Alam qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL); 14797304d190SMd Sadre Alam if (!qspi) 14807304d190SMd Sadre Alam return -ENOMEM; 14817304d190SMd Sadre Alam 14827304d190SMd Sadre Alam ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false); 14837304d190SMd Sadre Alam if (!ctlr) 14847304d190SMd Sadre Alam return -ENOMEM; 14857304d190SMd Sadre Alam 14867304d190SMd Sadre Alam platform_set_drvdata(pdev, ctlr); 14877304d190SMd Sadre Alam 14887304d190SMd Sadre Alam snandc = spi_controller_get_devdata(ctlr); 14897304d190SMd Sadre Alam qspi->snandc = snandc; 14907304d190SMd Sadre Alam 14917304d190SMd Sadre Alam snandc->dev = dev; 14927304d190SMd Sadre Alam snandc->qspi = qspi; 14937304d190SMd Sadre Alam snandc->qspi->ctlr = ctlr; 14947304d190SMd Sadre Alam snandc->qspi->ecc = ecc; 14957304d190SMd Sadre Alam 14967304d190SMd Sadre Alam dev_data = of_device_get_match_data(dev); 14977304d190SMd Sadre Alam if (!dev_data) { 14987304d190SMd Sadre Alam dev_err(&pdev->dev, "failed to get device data\n"); 14997304d190SMd Sadre Alam return -ENODEV; 15007304d190SMd Sadre Alam } 15017304d190SMd Sadre Alam 15027304d190SMd Sadre Alam snandc->props = dev_data; 15037304d190SMd Sadre Alam snandc->dev = &pdev->dev; 15047304d190SMd Sadre Alam 15057304d190SMd Sadre Alam snandc->core_clk = devm_clk_get(dev, "core"); 15067304d190SMd Sadre Alam if (IS_ERR(snandc->core_clk)) 15077304d190SMd Sadre Alam return PTR_ERR(snandc->core_clk); 15087304d190SMd Sadre Alam 15097304d190SMd Sadre Alam snandc->aon_clk = devm_clk_get(dev, "aon"); 15107304d190SMd Sadre Alam if (IS_ERR(snandc->aon_clk)) 15117304d190SMd Sadre Alam return PTR_ERR(snandc->aon_clk); 15127304d190SMd Sadre Alam 15137304d190SMd Sadre Alam snandc->qspi->iomacro_clk = devm_clk_get(dev, "iom"); 15147304d190SMd Sadre Alam if (IS_ERR(snandc->qspi->iomacro_clk)) 15157304d190SMd Sadre Alam return PTR_ERR(snandc->qspi->iomacro_clk); 15167304d190SMd Sadre Alam 15177304d190SMd Sadre Alam snandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 15187304d190SMd Sadre Alam if (IS_ERR(snandc->base)) 15197304d190SMd Sadre Alam return PTR_ERR(snandc->base); 15207304d190SMd Sadre Alam 15217304d190SMd Sadre Alam snandc->base_phys = res->start; 15227304d190SMd Sadre Alam snandc->base_dma = dma_map_resource(dev, res->start, resource_size(res), 15237304d190SMd Sadre Alam DMA_BIDIRECTIONAL, 0); 15247304d190SMd Sadre Alam if (dma_mapping_error(dev, snandc->base_dma)) 15257304d190SMd Sadre Alam return -ENXIO; 15267304d190SMd Sadre Alam 15277304d190SMd Sadre Alam ret = clk_prepare_enable(snandc->core_clk); 15287304d190SMd Sadre Alam if (ret) 15297304d190SMd Sadre Alam goto err_dis_core_clk; 15307304d190SMd Sadre Alam 15317304d190SMd Sadre Alam ret = clk_prepare_enable(snandc->aon_clk); 15327304d190SMd Sadre Alam if (ret) 15337304d190SMd Sadre Alam goto err_dis_aon_clk; 15347304d190SMd Sadre Alam 15357304d190SMd Sadre Alam ret = clk_prepare_enable(snandc->qspi->iomacro_clk); 15367304d190SMd Sadre Alam if (ret) 15377304d190SMd Sadre Alam goto err_dis_iom_clk; 15387304d190SMd Sadre Alam 15397304d190SMd Sadre Alam ret = qcom_nandc_alloc(snandc); 15407304d190SMd Sadre Alam if (ret) 15417304d190SMd Sadre Alam goto err_snand_alloc; 15427304d190SMd Sadre Alam 15437304d190SMd Sadre Alam ret = qcom_spi_init(snandc); 15447304d190SMd Sadre Alam if (ret) 15457304d190SMd Sadre Alam goto err_spi_init; 15467304d190SMd Sadre Alam 15477304d190SMd Sadre Alam /* setup ECC engine */ 15487304d190SMd Sadre Alam snandc->qspi->ecc_eng.dev = &pdev->dev; 15497304d190SMd Sadre Alam snandc->qspi->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED; 15507304d190SMd Sadre Alam snandc->qspi->ecc_eng.ops = &qcom_spi_ecc_engine_ops_pipelined; 15517304d190SMd Sadre Alam snandc->qspi->ecc_eng.priv = snandc; 15527304d190SMd Sadre Alam 15537304d190SMd Sadre Alam ret = nand_ecc_register_on_host_hw_engine(&snandc->qspi->ecc_eng); 15547304d190SMd Sadre Alam if (ret) { 15557304d190SMd Sadre Alam dev_err(&pdev->dev, "failed to register ecc engine:%d\n", ret); 15567304d190SMd Sadre Alam goto err_spi_init; 15577304d190SMd Sadre Alam } 15587304d190SMd Sadre Alam 15597304d190SMd Sadre Alam ctlr->num_chipselect = QPIC_QSPI_NUM_CS; 15607304d190SMd Sadre Alam ctlr->mem_ops = &qcom_spi_mem_ops; 15617304d190SMd Sadre Alam ctlr->mem_caps = &qcom_spi_mem_caps; 15627304d190SMd Sadre Alam ctlr->dev.of_node = pdev->dev.of_node; 15637304d190SMd Sadre Alam ctlr->mode_bits = SPI_TX_DUAL | SPI_RX_DUAL | 15647304d190SMd Sadre Alam SPI_TX_QUAD | SPI_RX_QUAD; 15657304d190SMd Sadre Alam 15667304d190SMd Sadre Alam ret = spi_register_controller(ctlr); 15677304d190SMd Sadre Alam if (ret) { 15687304d190SMd Sadre Alam dev_err(&pdev->dev, "spi_register_controller failed.\n"); 15697304d190SMd Sadre Alam goto err_spi_init; 15707304d190SMd Sadre Alam } 15717304d190SMd Sadre Alam 15727304d190SMd Sadre Alam return 0; 15737304d190SMd Sadre Alam 15747304d190SMd Sadre Alam err_spi_init: 15757304d190SMd Sadre Alam qcom_nandc_unalloc(snandc); 15767304d190SMd Sadre Alam err_snand_alloc: 15777304d190SMd Sadre Alam clk_disable_unprepare(snandc->qspi->iomacro_clk); 15787304d190SMd Sadre Alam err_dis_iom_clk: 15797304d190SMd Sadre Alam clk_disable_unprepare(snandc->aon_clk); 15807304d190SMd Sadre Alam err_dis_aon_clk: 15817304d190SMd Sadre Alam clk_disable_unprepare(snandc->core_clk); 15827304d190SMd Sadre Alam err_dis_core_clk: 15837304d190SMd Sadre Alam dma_unmap_resource(dev, res->start, resource_size(res), 15847304d190SMd Sadre Alam DMA_BIDIRECTIONAL, 0); 15857304d190SMd Sadre Alam return ret; 15867304d190SMd Sadre Alam } 15877304d190SMd Sadre Alam 15887304d190SMd Sadre Alam static void qcom_spi_remove(struct platform_device *pdev) 15897304d190SMd Sadre Alam { 15907304d190SMd Sadre Alam struct spi_controller *ctlr = platform_get_drvdata(pdev); 15917304d190SMd Sadre Alam struct qcom_nand_controller *snandc = spi_controller_get_devdata(ctlr); 15927304d190SMd Sadre Alam struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 15937304d190SMd Sadre Alam 15947304d190SMd Sadre Alam spi_unregister_controller(ctlr); 15957304d190SMd Sadre Alam 15967304d190SMd Sadre Alam qcom_nandc_unalloc(snandc); 15977304d190SMd Sadre Alam 15987304d190SMd Sadre Alam clk_disable_unprepare(snandc->aon_clk); 15997304d190SMd Sadre Alam clk_disable_unprepare(snandc->core_clk); 16007304d190SMd Sadre Alam clk_disable_unprepare(snandc->qspi->iomacro_clk); 16017304d190SMd Sadre Alam 16027304d190SMd Sadre Alam dma_unmap_resource(&pdev->dev, snandc->base_dma, resource_size(res), 16037304d190SMd Sadre Alam DMA_BIDIRECTIONAL, 0); 16047304d190SMd Sadre Alam } 16057304d190SMd Sadre Alam 16067304d190SMd Sadre Alam static const struct qcom_nandc_props ipq9574_snandc_props = { 16077304d190SMd Sadre Alam .dev_cmd_reg_start = 0x7000, 16087304d190SMd Sadre Alam .supports_bam = true, 16097304d190SMd Sadre Alam }; 16107304d190SMd Sadre Alam 16117304d190SMd Sadre Alam static const struct of_device_id qcom_snandc_of_match[] = { 16127304d190SMd Sadre Alam { 16137304d190SMd Sadre Alam .compatible = "qcom,ipq9574-snand", 16147304d190SMd Sadre Alam .data = &ipq9574_snandc_props, 16157304d190SMd Sadre Alam }, 16167304d190SMd Sadre Alam {} 16177304d190SMd Sadre Alam } 16187304d190SMd Sadre Alam MODULE_DEVICE_TABLE(of, qcom_snandc_of_match); 16197304d190SMd Sadre Alam 16207304d190SMd Sadre Alam static struct platform_driver qcom_spi_driver = { 16217304d190SMd Sadre Alam .driver = { 16227304d190SMd Sadre Alam .name = "qcom_snand", 16237304d190SMd Sadre Alam .of_match_table = qcom_snandc_of_match, 16247304d190SMd Sadre Alam }, 16257304d190SMd Sadre Alam .probe = qcom_spi_probe, 16267304d190SMd Sadre Alam .remove = qcom_spi_remove, 16277304d190SMd Sadre Alam }; 16287304d190SMd Sadre Alam module_platform_driver(qcom_spi_driver); 16297304d190SMd Sadre Alam 16307304d190SMd Sadre Alam MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores"); 16317304d190SMd Sadre Alam MODULE_AUTHOR("Md Sadre Alam <quic_mdalam@quicinc.com>"); 16327304d190SMd Sadre Alam MODULE_LICENSE("GPL"); 16337304d190SMd Sadre Alam 1634