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