diff options
Diffstat (limited to 'drivers/spi/spi-qpic-snand.c')
-rw-r--r-- | drivers/spi/spi-qpic-snand.c | 166 |
1 files changed, 89 insertions, 77 deletions
diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 94948c8781e8..fd129650434f 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -116,7 +116,6 @@ struct qpic_spi_nand { struct nand_ecc_engine ecc_eng; u8 *data_buf; u8 *oob_buf; - u32 wlen; __le32 addr1; __le32 addr2; __le32 cmd; @@ -131,9 +130,9 @@ static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc, int is_last_read_loc) { __le32 locreg_val; - u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | - ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc) - << READ_LOCATION_LAST)); + u32 val = FIELD_PREP(READ_LOCATION_OFFSET_MASK, cw_offset) | + FIELD_PREP(READ_LOCATION_SIZE_MASK, read_size) | + FIELD_PREP(READ_LOCATION_LAST_MASK, is_last_read_loc); locreg_val = cpu_to_le32(val); @@ -152,9 +151,9 @@ static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc, int is_last_read_loc) { __le32 locreg_val; - u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | - ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc) - << READ_LOCATION_LAST)); + u32 val = FIELD_PREP(READ_LOCATION_OFFSET_MASK, cw_offset) | + FIELD_PREP(READ_LOCATION_SIZE_MASK, read_size) | + FIELD_PREP(READ_LOCATION_LAST_MASK, is_last_read_loc); locreg_val = cpu_to_le32(val); @@ -250,9 +249,11 @@ static const struct mtd_ooblayout_ops qcom_spi_ooblayout = { static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) { struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); + struct nand_ecc_props *reqs = &nand->ecc.requirements; + struct nand_ecc_props *user = &nand->ecc.user_conf; struct nand_ecc_props *conf = &nand->ecc.ctx.conf; struct mtd_info *mtd = nanddev_to_mtd(nand); - int cwperpage, bad_block_byte; + int cwperpage, bad_block_byte, ret; struct qpic_ecc *ecc_cfg; cwperpage = mtd->writesize / NANDC_STEP_SIZE; @@ -261,11 +262,39 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL); if (!ecc_cfg) return -ENOMEM; - snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize, + + if (user->step_size && user->strength) { + ecc_cfg->step_size = user->step_size; + ecc_cfg->strength = user->strength; + } else if (reqs->step_size && reqs->strength) { + ecc_cfg->step_size = reqs->step_size; + ecc_cfg->strength = reqs->strength; + } else { + /* use defaults */ + ecc_cfg->step_size = NANDC_STEP_SIZE; + ecc_cfg->strength = 4; + } + + if (ecc_cfg->step_size != NANDC_STEP_SIZE) { + dev_err(snandc->dev, + "only %u bytes ECC step size is supported\n", + NANDC_STEP_SIZE); + ret = -EOPNOTSUPP; + goto err_free_ecc_cfg; + } + + if (ecc_cfg->strength != 4) { + dev_err(snandc->dev, + "only 4 bits ECC strength is supported\n"); + ret = -EOPNOTSUPP; + goto err_free_ecc_cfg; + } + + snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); if (!snandc->qspi->oob_buf) { - kfree(ecc_cfg); - return -ENOMEM; + ret = -ENOMEM; + goto err_free_ecc_cfg; } memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize); @@ -280,8 +309,6 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size; ecc_cfg->steps = 4; - ecc_cfg->strength = 4; - ecc_cfg->step_size = 512; ecc_cfg->cw_data = 516; ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes; bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1; @@ -325,7 +352,7 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) FIELD_PREP(ECC_MODE_MASK, 0) | FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw); - ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS; + ecc_cfg->ecc_buf_cfg = FIELD_PREP(NUM_STEPS_MASK, 0x203); ecc_cfg->clrflashstatus = FS_READY_BSY_N; ecc_cfg->clrreadstatus = 0xc0; @@ -339,6 +366,10 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) ecc_cfg->strength, ecc_cfg->step_size); return 0; + +err_free_ecc_cfg: + kfree(ecc_cfg); + return ret; } static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand) @@ -452,7 +483,8 @@ static int qcom_spi_block_erase(struct qcom_nand_controller *snandc) snandc->regs->cmd = snandc->qspi->cmd; snandc->regs->addr0 = snandc->qspi->addr1; snandc->regs->addr1 = snandc->qspi->addr2; - snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE)); + snandc->regs->cfg0 = cpu_to_le32((ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) | + FIELD_PREP(CW_PER_PAGE_MASK, 0)); snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw); snandc->regs->exec = cpu_to_le32(1); @@ -493,6 +525,22 @@ static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *sna qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0); } +static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt) +{ + int i; + + qcom_nandc_dev_to_mem(snandc, true); + + for (i = 0; i < cw_cnt; i++) { + u32 flash = le32_to_cpu(snandc->reg_read_buf[i]); + + if (flash & (FS_OP_ERR | FS_MPU_ERR)) + return -EIO; + } + + return 0; +} + static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, const struct spi_mem_op *op) { @@ -513,8 +561,8 @@ static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); snandc->regs->addr1 = snandc->qspi->addr2; - cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | - 0 << CW_PER_PAGE; + cfg0 = (ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) | + FIELD_PREP(CW_PER_PAGE_MASK, 0); cfg1 = ecc_cfg->cfg1_raw; ecc_bch_cfg = ECC_CFG_ECC_DISABLE; @@ -538,11 +586,9 @@ static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, return ret; } - qcom_nandc_dev_to_mem(snandc, true); - u32 flash = le32_to_cpu(snandc->reg_read_buf[0]); - - if (flash & (FS_OP_ERR | FS_MPU_ERR)) - return -EIO; + ret = qcom_spi_check_raw_flash_errors(snandc, 1); + if (ret) + return ret; bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); @@ -556,7 +602,7 @@ static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, return ret; } -static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf) +static int qcom_spi_check_error(struct qcom_nand_controller *snandc) { struct snandc_read_status *buf; struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; @@ -573,15 +619,6 @@ static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_bu for (i = 0; i < num_cw; i++, buf++) { u32 flash, buffer, erased_cw; - int data_len, oob_len; - - if (i == (num_cw - 1)) { - data_len = NANDC_STEP_SIZE - ((num_cw - 1) << 2); - oob_len = num_cw << 2; - } else { - data_len = ecc_cfg->cw_data; - oob_len = 0; - } flash = le32_to_cpu(buf->snandc_flash); buffer = le32_to_cpu(buf->snandc_buffer); @@ -605,11 +642,6 @@ static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_bu snandc->qspi->ecc_stats.corrected += stat; max_bitflips = max(max_bitflips, stat); } - - if (data_buf) - data_buf += data_len; - if (oob_buf) - oob_buf += oob_len + ecc_cfg->bytes; } if (flash_op_err) @@ -623,22 +655,6 @@ static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_bu return 0; } -static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt) -{ - int i; - - qcom_nandc_dev_to_mem(snandc, true); - - for (i = 0; i < cw_cnt; i++) { - u32 flash = le32_to_cpu(snandc->reg_read_buf[i]); - - if (flash & (FS_OP_ERR | FS_MPU_ERR)) - return -EIO; - } - - return 0; -} - static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf, int cw) { @@ -656,8 +672,8 @@ static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_bu qcom_clear_bam_transaction(snandc); raw_cw = num_cw - 1; - cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | - 0 << CW_PER_PAGE; + cfg0 = (ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) | + FIELD_PREP(CW_PER_PAGE_MASK, 0); cfg1 = ecc_cfg->cfg1_raw; ecc_bch_cfg = ECC_CFG_ECC_DISABLE; @@ -763,22 +779,19 @@ static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc, const struct spi_mem_op *op) { struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; - u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start; + u8 *data_buf = NULL, *oob_buf = NULL; int ret, i; u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; data_buf = op->data.buf.in; - data_buf_start = data_buf; - oob_buf = snandc->qspi->oob_buf; - oob_buf_start = oob_buf; snandc->buf_count = 0; snandc->buf_start = 0; qcom_clear_read_regs(snandc); - cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | - (num_cw - 1) << CW_PER_PAGE; + cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) | + FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1); cfg1 = ecc_cfg->cfg1; ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; @@ -852,29 +865,26 @@ static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc, return ret; } - return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start); + return qcom_spi_check_error(snandc); } static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc, const struct spi_mem_op *op) { struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; - u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start; + u8 *oob_buf = NULL; int ret, i; u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; oob_buf = op->data.buf.in; - oob_buf_start = oob_buf; - - data_buf_start = data_buf; snandc->buf_count = 0; snandc->buf_start = 0; qcom_clear_read_regs(snandc); qcom_clear_bam_transaction(snandc); - cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | - (num_cw - 1) << CW_PER_PAGE; + cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) | + FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1); cfg1 = ecc_cfg->cfg1; ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; @@ -934,7 +944,7 @@ static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc, return ret; } - return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start); + return qcom_spi_check_error(snandc); } static int qcom_spi_read_page(struct qcom_nand_controller *snandc, @@ -984,8 +994,8 @@ static int qcom_spi_program_raw(struct qcom_nand_controller *snandc, int num_cw = snandc->qspi->num_cw; u32 cfg0, cfg1, ecc_bch_cfg; - cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | - (num_cw - 1) << CW_PER_PAGE; + cfg0 = (ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) | + FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1); cfg1 = ecc_cfg->cfg1_raw; ecc_bch_cfg = ECC_CFG_ECC_DISABLE; @@ -1067,8 +1077,8 @@ static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc, int num_cw = snandc->qspi->num_cw; u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg; - cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | - (num_cw - 1) << CW_PER_PAGE; + cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) | + FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1); cfg1 = ecc_cfg->cfg1; ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; ecc_buf_cfg = ecc_cfg->ecc_buf_cfg; @@ -1144,8 +1154,8 @@ static int qcom_spi_program_oob(struct qcom_nand_controller *snandc, int num_cw = snandc->qspi->num_cw; u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg; - cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | - (num_cw - 1) << CW_PER_PAGE; + cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) | + FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1); cfg1 = ecc_cfg->cfg1; ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; ecc_buf_cfg = ecc_cfg->ecc_buf_cfg; @@ -1374,8 +1384,10 @@ static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_ } ret = qcom_submit_descs(snandc); - if (ret) + if (ret) { dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode); + return ret; + } if (copy) { qcom_nandc_dev_to_mem(snandc, true); @@ -1389,7 +1401,7 @@ static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_ memcpy(op->data.buf.in, &val, snandc->buf_count); } - return ret; + return 0; } static bool qcom_spi_is_page_op(const struct spi_mem_op *op) |