diff options
author | Richard Weinberger <richard@nod.at> | 2020-06-01 19:50:58 +0200 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2020-06-01 19:50:58 +0200 |
commit | a8dfb61d6349b7b7173ec6829b920449239c472f (patch) | |
tree | dffc9e88fcac2f30c731cbe9a0b6f3744d6fe2e1 /drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | |
parent | 3d77e6a8804abcc0504c904bd6e5cdf3a5cf8162 (diff) | |
parent | 86f2b225adf4ecd2edfdc8541a7342645556ac3b (diff) | |
download | linux-a8dfb61d6349b7b7173ec6829b920449239c472f.tar.bz2 |
Merge tag 'nand/for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux into mtd/next
Raw NAND core changes:
* Stop using nand_release(), patched all drivers.
* Give more information about the ECC weakness when not matching the
chip's requirement.
* MAINTAINERS updates.
* Support emulated SLC mode on MLC NANDs.
* Support "constrained" controllers, adapt the core and ONFI/JEDEC
table parsing and Micron's code.
* Take check_only into account.
* Add an invalid ECC mode to discriminate with valid ones.
* Return an enum from of_get_nand_ecc_algo().
* Drop OOB_FIRST placement scheme.
* Introduce nand_extract_bits().
* Ensure a consistent bitflips numbering.
* BCH lib:
- Allow easy bit swapping.
- Rework a little bit the exported function names.
* Fix nand_gpio_waitrdy().
* Propage CS selection to sub operations.
* Add a NAND_NO_BBM_QUIRK flag.
* Give the possibility to verify a read operation is supported.
* Add a helper to check supported operations.
* Avoid indirect access to ->data_buf().
* Rename the use_bufpoi variables.
* Fix comments about the use of bufpoi.
* Rename a NAND chip option.
* Reorder the nand_chip->options flags.
* Translate obscure bitfields into readable macros.
* Timings:
- Fix default values.
- Add mode information to the timings structure.
Raw NAND controller driver changes:
* Fixed many error paths.
* Arasan
- New driver
* Au1550nd:
- Various cleanups
- Migration to ->exec_op()
* brcmnand:
- Misc cleanup.
- Support v2.1-v2.2 controllers.
- Remove unused including <linux/version.h>.
- Correctly verify erased pages.
- Fix Hamming OOB layout.
* Cadence
- Make cadence_nand_attach_chip static.
* Cafe:
- Set the NAND_NO_BBM_QUIRK flag
* cmx270:
- Remove this controller driver.
* cs553x:
- Misc cleanup
- Migration to ->exec_op()
* Davinci:
- Misc cleanup.
- Migration to ->exec_op()
* Denali:
- Add more delays before latching incoming data
* Diskonchip:
- Misc cleanup
- Migration to ->exec_op()
* Fsmc:
- Change to non-atomic bit operations.
* GPMI:
- Use nand_extract_bits()
- Fix runtime PM imbalance.
* Ingenic:
- Migration to exec_op()
- Fix the RB gpio active-high property on qi, lb60
- Make qi_lb60_ooblayout_ops static.
* Marvell:
- Misc cleanup and small fixes
* Nandsim:
- Fix the error paths, driver wide.
* Omap_elm:
- Fix runtime PM imbalance.
* STM32_FMC2:
- Misc cleanups (error cases, comments, timeout valus, cosmetic
changes).
Diffstat (limited to 'drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c')
-rw-r--r-- | drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 189 |
1 files changed, 22 insertions, 167 deletions
diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 53b00c841aec..061a8ddda275 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -540,8 +540,10 @@ static int bch_set_geometry(struct gpmi_nand_data *this) return ret; ret = pm_runtime_get_sync(this->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_autosuspend(this->dev); return ret; + } /* * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this @@ -834,158 +836,6 @@ map_fail: return false; } -/** - * gpmi_copy_bits - copy bits from one memory region to another - * @dst: destination buffer - * @dst_bit_off: bit offset we're starting to write at - * @src: source buffer - * @src_bit_off: bit offset we're starting to read from - * @nbits: number of bits to copy - * - * This functions copies bits from one memory region to another, and is used by - * the GPMI driver to copy ECC sections which are not guaranteed to be byte - * aligned. - * - * src and dst should not overlap. - * - */ -static void gpmi_copy_bits(u8 *dst, size_t dst_bit_off, const u8 *src, - size_t src_bit_off, size_t nbits) -{ - size_t i; - size_t nbytes; - u32 src_buffer = 0; - size_t bits_in_src_buffer = 0; - - if (!nbits) - return; - - /* - * Move src and dst pointers to the closest byte pointer and store bit - * offsets within a byte. - */ - src += src_bit_off / 8; - src_bit_off %= 8; - - dst += dst_bit_off / 8; - dst_bit_off %= 8; - - /* - * Initialize the src_buffer value with bits available in the first - * byte of data so that we end up with a byte aligned src pointer. - */ - if (src_bit_off) { - src_buffer = src[0] >> src_bit_off; - if (nbits >= (8 - src_bit_off)) { - bits_in_src_buffer += 8 - src_bit_off; - } else { - src_buffer &= GENMASK(nbits - 1, 0); - bits_in_src_buffer += nbits; - } - nbits -= bits_in_src_buffer; - src++; - } - - /* Calculate the number of bytes that can be copied from src to dst. */ - nbytes = nbits / 8; - - /* Try to align dst to a byte boundary. */ - if (dst_bit_off) { - if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) { - src_buffer |= src[0] << bits_in_src_buffer; - bits_in_src_buffer += 8; - src++; - nbytes--; - } - - if (bits_in_src_buffer >= (8 - dst_bit_off)) { - dst[0] &= GENMASK(dst_bit_off - 1, 0); - dst[0] |= src_buffer << dst_bit_off; - src_buffer >>= (8 - dst_bit_off); - bits_in_src_buffer -= (8 - dst_bit_off); - dst_bit_off = 0; - dst++; - if (bits_in_src_buffer > 7) { - bits_in_src_buffer -= 8; - dst[0] = src_buffer; - dst++; - src_buffer >>= 8; - } - } - } - - if (!bits_in_src_buffer && !dst_bit_off) { - /* - * Both src and dst pointers are byte aligned, thus we can - * just use the optimized memcpy function. - */ - if (nbytes) - memcpy(dst, src, nbytes); - } else { - /* - * src buffer is not byte aligned, hence we have to copy each - * src byte to the src_buffer variable before extracting a byte - * to store in dst. - */ - for (i = 0; i < nbytes; i++) { - src_buffer |= src[i] << bits_in_src_buffer; - dst[i] = src_buffer; - src_buffer >>= 8; - } - } - /* Update dst and src pointers */ - dst += nbytes; - src += nbytes; - - /* - * nbits is the number of remaining bits. It should not exceed 8 as - * we've already copied as much bytes as possible. - */ - nbits %= 8; - - /* - * If there's no more bits to copy to the destination and src buffer - * was already byte aligned, then we're done. - */ - if (!nbits && !bits_in_src_buffer) - return; - - /* Copy the remaining bits to src_buffer */ - if (nbits) - src_buffer |= (*src & GENMASK(nbits - 1, 0)) << - bits_in_src_buffer; - bits_in_src_buffer += nbits; - - /* - * In case there were not enough bits to get a byte aligned dst buffer - * prepare the src_buffer variable to match the dst organization (shift - * src_buffer by dst_bit_off and retrieve the least significant bits - * from dst). - */ - if (dst_bit_off) - src_buffer = (src_buffer << dst_bit_off) | - (*dst & GENMASK(dst_bit_off - 1, 0)); - bits_in_src_buffer += dst_bit_off; - - /* - * Keep most significant bits from dst if we end up with an unaligned - * number of bits. - */ - nbytes = bits_in_src_buffer / 8; - if (bits_in_src_buffer % 8) { - src_buffer |= (dst[nbytes] & - GENMASK(7, bits_in_src_buffer % 8)) << - (nbytes * 8); - nbytes++; - } - - /* Copy the remaining bytes to dst */ - for (i = 0; i < nbytes; i++) { - dst[i] = src_buffer; - src_buffer >>= 8; - } -} - /* add our owner bbt descriptor */ static uint8_t scan_ff_pattern[] = { 0xff }; static struct nand_bbt_descr gpmi_bbt_descr = { @@ -1713,7 +1563,7 @@ static int gpmi_ecc_write_oob(struct nand_chip *chip, int page) * inline (interleaved with payload DATA), and do not align data chunk on * byte boundaries. * We thus need to take care moving the payload data and ECC bits stored in the - * page into the provided buffers, which is why we're using gpmi_copy_bits. + * page into the provided buffers, which is why we're using nand_extract_bits(). * * See set_geometry_by_ecc_info inline comments to have a full description * of the layout used by the GPMI controller. @@ -1762,9 +1612,8 @@ static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf, /* Extract interleaved payload data and ECC bits */ for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { if (buf) - gpmi_copy_bits(buf, step * eccsize * 8, - tmp_buf, src_bit_off, - eccsize * 8); + nand_extract_bits(buf, step * eccsize, tmp_buf, + src_bit_off, eccsize * 8); src_bit_off += eccsize * 8; /* Align last ECC block to align a byte boundary */ @@ -1773,9 +1622,8 @@ static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf, eccbits += 8 - ((oob_bit_off + eccbits) % 8); if (oob_required) - gpmi_copy_bits(oob, oob_bit_off, - tmp_buf, src_bit_off, - eccbits); + nand_extract_bits(oob, oob_bit_off, tmp_buf, + src_bit_off, eccbits); src_bit_off += eccbits; oob_bit_off += eccbits; @@ -1800,7 +1648,7 @@ static int gpmi_ecc_read_page_raw(struct nand_chip *chip, uint8_t *buf, * inline (interleaved with payload DATA), and do not align data chunk on * byte boundaries. * We thus need to take care moving the OOB area at the right place in the - * final page, which is why we're using gpmi_copy_bits. + * final page, which is why we're using nand_extract_bits(). * * See set_geometry_by_ecc_info inline comments to have a full description * of the layout used by the GPMI controller. @@ -1839,8 +1687,8 @@ static int gpmi_ecc_write_page_raw(struct nand_chip *chip, const uint8_t *buf, /* Interleave payload data and ECC bits */ for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { if (buf) - gpmi_copy_bits(tmp_buf, dst_bit_off, - buf, step * eccsize * 8, eccsize * 8); + nand_extract_bits(tmp_buf, dst_bit_off, buf, + step * eccsize * 8, eccsize * 8); dst_bit_off += eccsize * 8; /* Align last ECC block to align a byte boundary */ @@ -1849,8 +1697,8 @@ static int gpmi_ecc_write_page_raw(struct nand_chip *chip, const uint8_t *buf, eccbits += 8 - ((oob_bit_off + eccbits) % 8); if (oob_required) - gpmi_copy_bits(tmp_buf, dst_bit_off, - oob, oob_bit_off, eccbits); + nand_extract_bits(tmp_buf, dst_bit_off, oob, + oob_bit_off, eccbits); dst_bit_off += eccbits; oob_bit_off += eccbits; @@ -2408,6 +2256,9 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip, struct completion *completion; unsigned long to; + if (check_only) + return 0; + this->ntransfers = 0; for (i = 0; i < GPMI_MAX_TRANSFERS; i++) this->transfers[i].direction = DMA_NONE; @@ -2658,7 +2509,7 @@ static int gpmi_nand_probe(struct platform_device *pdev) ret = __gpmi_enable_clk(this, true); if (ret) - goto exit_nfc_init; + goto exit_acquire_resources; pm_runtime_set_autosuspend_delay(&pdev->dev, 500); pm_runtime_use_autosuspend(&pdev->dev); @@ -2693,11 +2544,15 @@ exit_acquire_resources: static int gpmi_nand_remove(struct platform_device *pdev) { struct gpmi_nand_data *this = platform_get_drvdata(pdev); + struct nand_chip *chip = &this->nand; + int ret; pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - nand_release(&this->nand); + ret = mtd_device_unregister(nand_to_mtd(chip)); + WARN_ON(ret); + nand_cleanup(chip); gpmi_free_dma_buffer(this); release_resources(this); return 0; |