diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-07-05 11:21:51 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-07-05 11:21:51 -0700 |
commit | da85e7ed6993144a9ca43a1106c7f898626390a3 (patch) | |
tree | a5fdbea1cfe8deb13bcbef1b6e102ad1ca965e34 /drivers/mtd/nand/raw/omap2.c | |
parent | Merge tag 'm68knommu-for-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu (diff) | |
parent | Merge tag 'spi-nor/for-5.14' into mtd/next (diff) | |
download | linux-dev-da85e7ed6993144a9ca43a1106c7f898626390a3.tar.xz linux-dev-da85e7ed6993144a9ca43a1106c7f898626390a3.zip |
Merge tag 'mtd/for-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull MTD updates from Richard Weinberger:
"MTD core changes:
- Convert list_for_each to entry variant
- Use MTD_DEVICE_ATTR_RO/RW() helper macros
- Remove unnecessary OOM messages
- Potential NULL dereference in mtd_otp_size()
- Fix freeing of otp_info buffer
- Create partname and partid debug files for child MTDs
- tests:
- Remove redundant assignment to err
- Fix error return code in mtd_oobtest_init()
- Add OTP NVMEM provider support
- Allow specifying of_node
- Convert sysfs sprintf/snprintf family to sysfs_emit
Bindings changes:
- Convert ti,am654-hbmc.txt to YAML schema
- spi-nor: add otp property
- Add OTP bindings
- add YAML schema for the generic MTD bindings
- Add brcm,trx-magic
MTD device drivers changes:
- Add support for microchip 48l640 EERAM
- Remove superfluous "break"
- sm_ftl:
- Fix alignment of block comment
- nftl:
- Return -ENOMEM when kmalloc failed
- nftlcore:
- Remove set but rewrite variables
- phram:
- Fix error return code in phram_setup()
- plat-ram:
- Remove redundant dev_err call in platram_probe()
MTD parsers changes:
- Qcom:
- Fix leaking of partition name
- Redboot:
- Fix style issues
- Seek fis-index-block in the right node
- trx:
- Allow to use TRX parser on Mediatek SoCs
- Allow to specify brcm, trx-magic in DT
Raw NAND core:
- Allow SDR timings to be nacked
- Bring support for NV-DDR timings which involved a number of small
preparation changes to bring new helpers, properly introduce NV-DDR
structures, fill them, differenciate them and pick the best timing
set.
- Add the necessary infrastructure to parse the new gpio-cs property
which aims at enlarging the number of available CS when a hardware
controller is too constrained.
- Update dead URL
- Silence static checker warning in nand_setup_interface()
- BBT:
- Fix corner case in bad block table handling
- onfi:
- Use more recent ONFI specification wording
- Use the BIT() macro when possible
Raw NAND controller drivers:
- Atmel:
- Ensure the data interface is supported.
- Arasan:
- Finer grain NV-DDR configuration
- Rename the data interface register
- Use the right DMA mask
- Leverage additional GPIO CS
- Ensure proper configuration for the asserted target
- Add support for the NV-DDR interface
- Fix a macro parameter
- brcmnand:
- Convert bindings to json-schema
- OMAP:
- Various fixes and style improvements
- Add larger page NAND chips support
- PL35X:
- New driver
- QCOM:
- Avoid writing to obsolete register
- Delete an unneeded bool conversion
- Allow override of partition parser
- Marvell:
- Minor documentation correction
- Add missing clk_disable_unprepare() on error in
marvell_nfc_resume()
- R852:
- Use DEVICE_ATTR_RO() helper macro
- MTK:
- Remove redundant dev_err call in mtk_ecc_probe()
- HISI504:
- Remove redundant dev_err call in probe
SPI-NAND core:
- Light reorganisation for the introduction of a core resume handler
- Fix double counting of ECC stats
SPI-NAND manufacturer drivers:
- Macronix:
- Add support for serial NAND flash
SPI NOR core changes:
- Ability to dump SFDP tables via sysfs
- Support for erasing OTP regions on Winbond and similar flashes
- Few API doc updates and fixes
- Locking support for MX25L12805D
SPI NOR controller drivers changes:
- Use SPI_MODE_X_MASK in nxp-spifi
- Intel Alder Lake-M SPI serial flash support"
* tag 'mtd/for-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (125 commits)
mtd: spi-nor: remove redundant continue statement
mtd: rawnand: omap: Add larger page NAND chips support
mtd: rawnand: omap: Various style fixes
mtd: rawnand: omap: Check return values
mtd: rawnand: omap: Rename a macro
mtd: rawnand: omap: Aggregate the HW configuration of the ELM
mtd: rawnand: pl353: Add support for the ARM PL353 SMC NAND controller
dt-bindings: mtd: pl353-nand: Describe this hardware controller
MAINTAINERS: Add PL353 NAND controller entry
mtd: rawnand: qcom: avoid writing to obsolete register
mtd: rawnand: marvell: Minor documentation correction
mtd: rawnand: r852: use DEVICE_ATTR_RO() helper macro
mtd: spinand: add SPI-NAND MTD resume handler
mtd: spinand: Add spinand_init_flash() helper
mtd: spinand: add spinand_read_cfg() helper
mtd: rawnand: marvell: add missing clk_disable_unprepare() on error in marvell_nfc_resume()
mtd: rawnand: arasan: Finer grain NV-DDR configuration
mtd: rawnand: arasan: Rename the data interface register
mtd: rawnand: onfi: Fix endianness when reading NV-DDR values
mtd: rawnand: arasan: Use the right DMA mask
...
Diffstat (limited to 'drivers/mtd/nand/raw/omap2.c')
-rw-r--r-- | drivers/mtd/nand/raw/omap2.c | 229 |
1 files changed, 141 insertions, 88 deletions
diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index c75e7a0b101f..b1839eef5b65 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -131,7 +131,7 @@ #define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */ #define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */ -#define BADBLOCK_MARKER_LENGTH 2 +#define BBM_LEN 2 static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, @@ -171,6 +171,10 @@ struct omap_nand_info { struct device *elm_dev; /* NAND ready gpio */ struct gpio_desc *ready_gpiod; + unsigned int neccpg; + unsigned int nsteps_per_eccpg; + unsigned int eccpg_size; + unsigned int eccpg_bytes; }; static inline struct omap_nand_info *mtd_to_omap(struct mtd_info *mtd) @@ -1355,7 +1359,7 @@ static int omap_elm_correct_data(struct nand_chip *chip, u_char *data, { struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(chip)); struct nand_ecc_ctrl *ecc = &info->nand.ecc; - int eccsteps = info->nand.ecc.steps; + int eccsteps = info->nsteps_per_eccpg; int i , j, stat = 0; int eccflag, actual_eccbytes; struct elm_errorvec err_vec[ERROR_VECTOR_MAX]; @@ -1525,24 +1529,37 @@ static int omap_write_page_bch(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); - int ret; + struct omap_nand_info *info = mtd_to_omap(mtd); uint8_t *ecc_calc = chip->ecc.calc_buf; + unsigned int eccpg; + int ret; - nand_prog_page_begin_op(chip, page, 0, NULL, 0); + ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0); + if (ret) + return ret; - /* Enable GPMC ecc engine */ - chip->ecc.hwctl(chip, NAND_ECC_WRITE); + for (eccpg = 0; eccpg < info->neccpg; eccpg++) { + /* Enable GPMC ecc engine */ + chip->ecc.hwctl(chip, NAND_ECC_WRITE); - /* Write data */ - chip->legacy.write_buf(chip, buf, mtd->writesize); + /* Write data */ + chip->legacy.write_buf(chip, buf + (eccpg * info->eccpg_size), + info->eccpg_size); - /* Update ecc vector from GPMC result registers */ - omap_calculate_ecc_bch_multi(mtd, buf, &ecc_calc[0]); + /* Update ecc vector from GPMC result registers */ + ret = omap_calculate_ecc_bch_multi(mtd, + buf + (eccpg * info->eccpg_size), + ecc_calc); + if (ret) + return ret; - ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, - chip->ecc.total); - if (ret) - return ret; + ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, + chip->oob_poi, + eccpg * info->eccpg_bytes, + info->eccpg_bytes); + if (ret) + return ret; + } /* Write ecc vector to OOB area */ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); @@ -1566,12 +1583,13 @@ static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); + struct omap_nand_info *info = mtd_to_omap(mtd); u8 *ecc_calc = chip->ecc.calc_buf; int ecc_size = chip->ecc.size; int ecc_bytes = chip->ecc.bytes; - int ecc_steps = chip->ecc.steps; u32 start_step = offset / ecc_size; u32 end_step = (offset + data_len - 1) / ecc_size; + unsigned int eccpg; int step, ret = 0; /* @@ -1580,36 +1598,48 @@ static int omap_write_subpage_bch(struct nand_chip *chip, u32 offset, * ECC is calculated for all subpages but we choose * only what we want. */ - nand_prog_page_begin_op(chip, page, 0, NULL, 0); - - /* Enable GPMC ECC engine */ - chip->ecc.hwctl(chip, NAND_ECC_WRITE); - - /* Write data */ - chip->legacy.write_buf(chip, buf, mtd->writesize); + ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0); + if (ret) + return ret; - for (step = 0; step < ecc_steps; step++) { - /* mask ECC of un-touched subpages by padding 0xFF */ - if (step < start_step || step > end_step) - memset(ecc_calc, 0xff, ecc_bytes); - else - ret = _omap_calculate_ecc_bch(mtd, buf, ecc_calc, step); + for (eccpg = 0; eccpg < info->neccpg; eccpg++) { + /* Enable GPMC ECC engine */ + chip->ecc.hwctl(chip, NAND_ECC_WRITE); + + /* Write data */ + chip->legacy.write_buf(chip, buf + (eccpg * info->eccpg_size), + info->eccpg_size); + + for (step = 0; step < info->nsteps_per_eccpg; step++) { + unsigned int base_step = eccpg * info->nsteps_per_eccpg; + const u8 *bufoffs = buf + (eccpg * info->eccpg_size); + + /* Mask ECC of un-touched subpages with 0xFFs */ + if ((step + base_step) < start_step || + (step + base_step) > end_step) + memset(ecc_calc + (step * ecc_bytes), 0xff, + ecc_bytes); + else + ret = _omap_calculate_ecc_bch(mtd, + bufoffs + (step * ecc_size), + ecc_calc + (step * ecc_bytes), + step); + + if (ret) + return ret; + } + /* + * Copy the calculated ECC for the whole page including the + * masked values (0xFF) corresponding to unwritten subpages. + */ + ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, + eccpg * info->eccpg_bytes, + info->eccpg_bytes); if (ret) return ret; - - buf += ecc_size; - ecc_calc += ecc_bytes; } - /* copy calculated ECC for whole page to chip->buffer->oob */ - /* this include masked-value(0xFF) for unwritten subpages */ - ecc_calc = chip->ecc.calc_buf; - ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, - chip->ecc.total); - if (ret) - return ret; - /* write OOB buffer to NAND device */ chip->legacy.write_buf(chip, chip->oob_poi, mtd->oobsize); @@ -1634,40 +1664,60 @@ static int omap_read_page_bch(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); + struct omap_nand_info *info = mtd_to_omap(mtd); uint8_t *ecc_calc = chip->ecc.calc_buf; uint8_t *ecc_code = chip->ecc.code_buf; + unsigned int max_bitflips = 0, eccpg; int stat, ret; - unsigned int max_bitflips = 0; - - nand_read_page_op(chip, page, 0, NULL, 0); - /* Enable GPMC ecc engine */ - chip->ecc.hwctl(chip, NAND_ECC_READ); + ret = nand_read_page_op(chip, page, 0, NULL, 0); + if (ret) + return ret; - /* Read data */ - chip->legacy.read_buf(chip, buf, mtd->writesize); + for (eccpg = 0; eccpg < info->neccpg; eccpg++) { + /* Enable GPMC ecc engine */ + chip->ecc.hwctl(chip, NAND_ECC_READ); - /* Read oob bytes */ - nand_change_read_column_op(chip, - mtd->writesize + BADBLOCK_MARKER_LENGTH, - chip->oob_poi + BADBLOCK_MARKER_LENGTH, - chip->ecc.total, false); + /* Read data */ + ret = nand_change_read_column_op(chip, eccpg * info->eccpg_size, + buf + (eccpg * info->eccpg_size), + info->eccpg_size, false); + if (ret) + return ret; - /* Calculate ecc bytes */ - omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc); + /* Read oob bytes */ + ret = nand_change_read_column_op(chip, + mtd->writesize + BBM_LEN + + (eccpg * info->eccpg_bytes), + chip->oob_poi + BBM_LEN + + (eccpg * info->eccpg_bytes), + info->eccpg_bytes, false); + if (ret) + return ret; - ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, - chip->ecc.total); - if (ret) - return ret; + /* Calculate ecc bytes */ + ret = omap_calculate_ecc_bch_multi(mtd, + buf + (eccpg * info->eccpg_size), + ecc_calc); + if (ret) + return ret; - stat = chip->ecc.correct(chip, buf, ecc_code, ecc_calc); + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, + chip->oob_poi, + eccpg * info->eccpg_bytes, + info->eccpg_bytes); + if (ret) + return ret; - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); + stat = chip->ecc.correct(chip, + buf + (eccpg * info->eccpg_size), + ecc_code, ecc_calc); + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } } return max_bitflips; @@ -1820,7 +1870,7 @@ static int omap_ooblayout_ecc(struct mtd_info *mtd, int section, { struct omap_nand_info *info = mtd_to_omap(mtd); struct nand_chip *chip = &info->nand; - int off = BADBLOCK_MARKER_LENGTH; + int off = BBM_LEN; if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW && !(chip->options & NAND_BUSWIDTH_16)) @@ -1840,7 +1890,7 @@ static int omap_ooblayout_free(struct mtd_info *mtd, int section, { struct omap_nand_info *info = mtd_to_omap(mtd); struct nand_chip *chip = &info->nand; - int off = BADBLOCK_MARKER_LENGTH; + int off = BBM_LEN; if (info->ecc_opt == OMAP_ECC_HAM1_CODE_HW && !(chip->options & NAND_BUSWIDTH_16)) @@ -1870,7 +1920,7 @@ static int omap_sw_ooblayout_ecc(struct mtd_info *mtd, int section, struct nand_device *nand = mtd_to_nanddev(mtd); unsigned int nsteps = nanddev_get_ecc_nsteps(nand); unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand); - int off = BADBLOCK_MARKER_LENGTH; + int off = BBM_LEN; if (section >= nsteps) return -ERANGE; @@ -1891,7 +1941,7 @@ static int omap_sw_ooblayout_free(struct mtd_info *mtd, int section, struct nand_device *nand = mtd_to_nanddev(mtd); unsigned int nsteps = nanddev_get_ecc_nsteps(nand); unsigned int ecc_bytes = nanddev_get_ecc_bytes_per_step(nand); - int off = BADBLOCK_MARKER_LENGTH; + int off = BBM_LEN; if (section) return -ERANGE; @@ -1920,7 +1970,8 @@ static int omap_nand_attach_chip(struct nand_chip *chip) struct mtd_info *mtd = nand_to_mtd(chip); struct omap_nand_info *info = mtd_to_omap(mtd); struct device *dev = &info->pdev->dev; - int min_oobbytes = BADBLOCK_MARKER_LENGTH; + int min_oobbytes = BBM_LEN; + int elm_bch_strength = -1; int oobbytes_per_step; dma_cap_mask_t mask; int err; @@ -2074,12 +2125,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip) chip->ecc.write_subpage = omap_write_subpage_bch; mtd_set_ooblayout(mtd, &omap_ooblayout_ops); oobbytes_per_step = chip->ecc.bytes; - - err = elm_config(info->elm_dev, BCH4_ECC, - mtd->writesize / chip->ecc.size, - chip->ecc.size, chip->ecc.bytes); - if (err < 0) - return err; + elm_bch_strength = BCH4_ECC; break; case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: @@ -2116,13 +2162,7 @@ static int omap_nand_attach_chip(struct nand_chip *chip) chip->ecc.write_subpage = omap_write_subpage_bch; mtd_set_ooblayout(mtd, &omap_ooblayout_ops); oobbytes_per_step = chip->ecc.bytes; - - err = elm_config(info->elm_dev, BCH8_ECC, - mtd->writesize / chip->ecc.size, - chip->ecc.size, chip->ecc.bytes); - if (err < 0) - return err; - + elm_bch_strength = BCH8_ECC; break; case OMAP_ECC_BCH16_CODE_HW: @@ -2138,19 +2178,32 @@ static int omap_nand_attach_chip(struct nand_chip *chip) chip->ecc.write_subpage = omap_write_subpage_bch; mtd_set_ooblayout(mtd, &omap_ooblayout_ops); oobbytes_per_step = chip->ecc.bytes; - - err = elm_config(info->elm_dev, BCH16_ECC, - mtd->writesize / chip->ecc.size, - chip->ecc.size, chip->ecc.bytes); - if (err < 0) - return err; - + elm_bch_strength = BCH16_ECC; break; default: dev_err(dev, "Invalid or unsupported ECC scheme\n"); return -EINVAL; } + if (elm_bch_strength >= 0) { + chip->ecc.steps = mtd->writesize / chip->ecc.size; + info->neccpg = chip->ecc.steps / ERROR_VECTOR_MAX; + if (info->neccpg) { + info->nsteps_per_eccpg = ERROR_VECTOR_MAX; + } else { + info->neccpg = 1; + info->nsteps_per_eccpg = chip->ecc.steps; + } + info->eccpg_size = info->nsteps_per_eccpg * chip->ecc.size; + info->eccpg_bytes = info->nsteps_per_eccpg * chip->ecc.bytes; + + err = elm_config(info->elm_dev, elm_bch_strength, + info->nsteps_per_eccpg, chip->ecc.size, + chip->ecc.bytes); + if (err < 0) + return err; + } + /* Check if NAND device's OOB is enough to store ECC signatures */ min_oobbytes += (oobbytes_per_step * (mtd->writesize / chip->ecc.size)); |