diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index ad9316e418fd..eb9540ce8786 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -17,6 +17,7 @@ #define MAX_DESC 16 #define SMEM_AARM_PARTITION_TABLE 9 #define SMEM_APPS 0 +#define ONE_CODEWORD_SIZE 516 /* * Get the DMA memory for requested amount of size. It returns the pointer @@ -1076,10 +1077,16 @@ static int msm_nand_validate_mtd_params(struct mtd_info *mtd, bool read, err = -EINVAL; goto out; } - args->page_count = ops->len / (mtd->writesize + mtd->oobsize); + if (ops->len <= ONE_CODEWORD_SIZE) + args->page_count = 1; + else + args->page_count = ops->len / + (mtd->writesize + mtd->oobsize); } else if (ops->mode == MTD_OPS_AUTO_OOB) { - if (ops->datbuf && (ops->len % mtd->writesize) != 0) { + if (ops->datbuf && (ops->len % + ((ops->len <= ONE_CODEWORD_SIZE) ? + ONE_CODEWORD_SIZE : mtd->writesize)) != 0) { /* when ops->datbuf is NULL, ops->len can be ooblen */ pr_err("unsupported data len %d for AUTO mode\n", ops->len); @@ -1092,7 +1099,10 @@ static int msm_nand_validate_mtd_params(struct mtd_info *mtd, bool read, if ((args->page_count == 0) && (ops->ooblen)) args->page_count = 1; } else if (ops->datbuf) { - args->page_count = ops->len / mtd->writesize; + if (ops->len <= ONE_CODEWORD_SIZE) + args->page_count = 1; + else + args->page_count = ops->len / mtd->writesize; } } @@ -1138,12 +1148,20 @@ static void msm_nand_update_rw_reg_data(struct msm_nand_chip *chip, struct msm_nand_rw_params *args, struct msm_nand_rw_reg_data *data) { + /* + * While reading one codeword, CW_PER_PAGE bits of QPIC_NAND_DEV0_CFG0 + * should be set to 0, which implies 1 codeword per page. 'n' below, + * is used to configure cfg0 for reading one full page or one single + * codeword. + */ + int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1; + if (args->read) { if (ops->mode != MTD_OPS_RAW) { data->cmd = MSM_NAND_CMD_PAGE_READ_ECC; data->cfg0 = (chip->cfg0 & ~(7U << CW_PER_PAGE)) | - (((args->cwperpage-1) - args->start_sector) + (((args->cwperpage-n) - args->start_sector) << CW_PER_PAGE); data->cfg1 = chip->cfg1; data->ecc_bch_cfg = chip->ecc_bch_cfg; @@ -1151,7 +1169,7 @@ static void msm_nand_update_rw_reg_data(struct msm_nand_chip *chip, data->cmd = MSM_NAND_CMD_PAGE_READ_ALL; data->cfg0 = (chip->cfg0_raw & ~(7U << CW_PER_PAGE)) | - (((args->cwperpage-1) - args->start_sector) + (((args->cwperpage-n) - args->start_sector) << CW_PER_PAGE); data->cfg1 = chip->cfg1_raw; data->ecc_bch_cfg = chip->ecc_cfg_raw; @@ -1195,6 +1213,11 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops, uint32_t offset, size, last_read; struct sps_command_element *curr_ce, *start_ce; uint32_t *flags_ptr, *num_ce_ptr; + /* + * Variable to configure read_location register parameters + * while reading one codeword or one full page + */ + int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1; if (curr_cw == args->start_sector) { curr_ce = start_ce = &cmd_list->setup_desc.ce[0]; @@ -1287,10 +1310,15 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops, if (ops->mode == MTD_OPS_AUTO_OOB) { if (ops->datbuf) { offset = 0; - size = (curr_cw < (args->cwperpage - 1)) ? 516 : - (512 - ((args->cwperpage - 1) << 2)); - last_read = (curr_cw < (args->cwperpage - 1)) ? 1 : - (ops->oobbuf ? 0 : 1); + if (ops->len <= ONE_CODEWORD_SIZE) { + size = ONE_CODEWORD_SIZE; + last_read = 1; + } else { + size = (curr_cw < (args->cwperpage - 1)) ? 516 : + (512 - ((args->cwperpage - 1) << 2)); + last_read = (curr_cw < (args->cwperpage - 1)) ? + 1 : (ops->oobbuf ? 0 : 1); + } rdata = (offset << 0) | (size << 16) | (last_read << 31); @@ -1306,7 +1334,7 @@ static void msm_nand_prep_rw_cmd_desc(struct mtd_oob_ops *ops, curr_ce++; } } - if (curr_cw == (args->cwperpage - 1) && ops->oobbuf) { + if (curr_cw == (args->cwperpage - n) && ops->oobbuf) { offset = 512 - ((args->cwperpage - 1) << 2); size = (args->cwperpage) << 2; if (size > args->oob_len_cmd) @@ -1364,6 +1392,11 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, uint32_t sectordatasize, sectoroobsize; uint32_t sps_flags = 0; int err = 0; + /* + * Variable to configure sectordatasize and sectoroobsize + * while reading one codeword or one full page. + */ + int n = (ops->len <= ONE_CODEWORD_SIZE) ? args->cwperpage : 1; if (args->read) data_pipe_handle = info->sps.data_prod.handle; @@ -1372,7 +1405,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, if (ops->mode == MTD_OPS_RAW) { if (ecc_parity_bytes && args->read) { - if (curr_cw == (args->cwperpage - 1)) + if (curr_cw == (args->cwperpage - n)) sps_flags |= SPS_IOVEC_FLAG_INT; /* read only ecc bytes */ @@ -1387,7 +1420,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, sectordatasize = chip->cw_size; if (!args->read) sps_flags = SPS_IOVEC_FLAG_EOT; - if (curr_cw == (args->cwperpage - 1)) + if (curr_cw == (args->cwperpage - n)) sps_flags |= SPS_IOVEC_FLAG_INT; err = sps_transfer_one(data_pipe_handle, @@ -1400,8 +1433,13 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, } } else if (ops->mode == MTD_OPS_AUTO_OOB) { if (ops->datbuf) { - sectordatasize = (curr_cw < (args->cwperpage - 1)) - ? 516 : (512 - ((args->cwperpage - 1) << 2)); + if (ops->len <= ONE_CODEWORD_SIZE) + sectordatasize = ONE_CODEWORD_SIZE; + else + sectordatasize = + (curr_cw < (args->cwperpage - 1)) + ? 516 : + (512 - ((args->cwperpage - 1) << 2)); if (!args->read) { sps_flags = SPS_IOVEC_FLAG_EOT; @@ -1409,7 +1447,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, ops->oobbuf) sps_flags = 0; } - if ((curr_cw == (args->cwperpage - 1)) && !ops->oobbuf) + if ((curr_cw == (args->cwperpage - n)) && !ops->oobbuf) sps_flags |= SPS_IOVEC_FLAG_INT; err = sps_transfer_one(data_pipe_handle, @@ -1421,7 +1459,7 @@ static int msm_nand_submit_rw_data_desc(struct mtd_oob_ops *ops, args->data_dma_addr_curr += sectordatasize; } - if (ops->oobbuf && (curr_cw == (args->cwperpage - 1))) { + if (ops->oobbuf && (curr_cw == (args->cwperpage - n))) { sectoroobsize = args->cwperpage << 2; if (sectoroobsize > args->oob_len_data) sectoroobsize = args->oob_len_data; @@ -2590,6 +2628,9 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, data.addr0 = (rw_params.page << 16) | rw_params.oob_col; data.addr1 = (rw_params.page >> 16) & 0xff; + if (ops->len <= ONE_CODEWORD_SIZE) + cwperpage = 1; + for (n = rw_params.start_sector; n < cwperpage; n++) { struct sps_command_element *curr_ce, *start_ce; @@ -2667,7 +2708,7 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, } else if (ops->mode == MTD_OPS_AUTO_OOB) { if (ops->datbuf) submitted_num_desc = cwperpage - - rw_params.start_sector; + rw_params.start_sector; if (ops->oobbuf) submitted_num_desc++; } @@ -2846,7 +2887,10 @@ free_dma: } validate_mtd_params_failed: if (ops->mode != MTD_OPS_RAW) - ops->retlen = mtd->writesize * pages_read; + if (ops->len <= ONE_CODEWORD_SIZE) + ops->retlen = ONE_CODEWORD_SIZE; + else + ops->retlen = mtd->writesize * pages_read; else ops->retlen = (mtd->writesize + mtd->oobsize) * pages_read; ops->oobretlen = ops->ooblen - rw_params.oob_len_data; @@ -2917,8 +2961,11 @@ static int msm_nand_read_partial_page(struct mtd_info *mtd, ops->datbuf = no_copy ? actual_buf : bounce_buf; if (info->nand_chip.caps & MSM_NAND_CAP_PAGE_SCOPE_READ) err = msm_nand_read_pagescope(mtd, aligned_from, ops); - else + else { + if ((len <= ONE_CODEWORD_SIZE) && (offset == 0)) + ops->len = ONE_CODEWORD_SIZE; err = msm_nand_read_oob(mtd, aligned_from, ops); + } if (err == -EUCLEAN) { is_euclean = 1; err = 0;