diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-17 01:58:35 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-17 01:58:35 +0300 |
commit | a701262c02cec71dc29b10fe910ba3c2298f5ba3 (patch) | |
tree | f1d9a0926440829cf3f04e96162899c5cee104ea /drivers/mtd/spi-nor/atmel.c | |
parent | 945433be3677955255fabecbf1076c17864ff9da (diff) | |
parent | 4c9e94dff65ca75b917ff0b5de2e44881062a8e8 (diff) | |
download | linux-a701262c02cec71dc29b10fe910ba3c2298f5ba3.tar.xz |
Merge tag 'mtd/for-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull MTD updates from Miquel Raynal:
"MTD core:
- Fix refcounting for unpartitioned MTDs
- Fix misspelled function parameter 'section'
- Remove unneeded break
- cmdline parser: Fix parsing of part-names with colons
- mtdpart: Fix misdocumented function parameter 'mtd'
MTD devices:
- phram:
- Allow the user to set the erase page size
- File headers are not good candidates for kernel-doc
- physmap-bt1-rom: Fix __iomem addrspace removal warning
- plat-ram: correctly free memory on error path in platram_probe()
- powernv_flash: Add function names to headers and fix 'dev'
- docg3: Fix kernel-doc 'bad line' and 'excessive doc' issues
UBI cleanup fixes:
- gluebi: Fix misnamed function parameter documentation
- wl: Fix a couple of kernel-doc issues
- eba: Fix a couple of misdocumentation issues
- kapi: Correct documentation for 'ubi_leb_read_sg's 'sgl' parameter
- Document 'ubi_num' in struct mtd_dev_param
Generic NAND core ECC management:
- Add an I/O request tweaking mechanism
- Entire rework of the software BCH ECC driver, creation of a real
ECC engine, getting rid of raw NAND structures, migration to more
generic prototypes, misc fixes and style cleanup. Moved now to the
Generic NAND layer.
- Entire rework of the software Hamming ECC driver, creation of a
real ECC engine, getting rid of raw NAND structures, misc renames,
comment updates, cleanup, and style fixes. Moved now to the generic
NAND layer.
- Necessary plumbing at the NAND level to retrieve generic NAND ECC
engines (softwares and on-die).
- Update of the bindings.
Raw NAND core:
- Geting rid of the chip->ecc.priv entry.
- Fix miscellaneous typos in kernel-doc
Raw NAND controller drivers:
- Arasan: Document 'anfc_op's 'buf' member
- AU1550: Ensure the presence of the right includes
- Brcmnand: Demote non-conformant kernel-doc headers
- Cafe: Remove superfluous param doc and add another
- Davinci: Do not use extra dereferencing
- Diskonchip: Marking unused variables as __always_unused
- GPMI:
- Fix the driver only sense CS0 R/B issue
- Fix the random DMA timeout issue
- Use a single line for of_device_id
- Use of_device_get_match_data()
- Fix reference count leak in gpmi ops
- Cleanup makefile
- Fix binding matching of clocks on different SoCs
- Ingenic: remove redundant get_device() in ingenic_ecc_get()
- Intel LGM: New NAND controller driver
- Marvell: Drop useless line
- Meson:
- Fix a resource leak in init
- Fix meson_nfc_dma_buffer_release() arguments
- mxc:
- Use device_get_match_data()
- Use a single line for of_device_id
- Remove platform data support
- Omap:
- Fix a bunch of kernel-doc misdemeanours
- Finish ELM half populated function header, demote empty ones
- s3c2410: Add documentation for 2 missing struct members
- Sunxi: Document 'sunxi_nfc's 'caps' member
- Qcom:
- Add support for SDX55
- Support for IPQ6018 QPIC NAND controller
- Fix DMA sync on FLASH_STATUS register read
- Rockchip: New NAND controller driver for RK3308, RK2928 and others
- Sunxi: Add MDMA support
ONENAND:
- bbt: Fix expected kernel-doc formatting
- Fix some kernel-doc misdemeanours
- Fix expected kernel-doc formatting
- Use mtd->oops_panic_write as condition
SPI-NAND core:
- Creation of a SPI-NAND on-die ECC engine
- Move ECC related definitions earlier in the driver
- Fix typo in comment
- Fill a default ECC provider/algorithm
- Remove outdated comment
- Fix OOB read
- Allow the case where there is no ECC engine
- Use the external ECC engine logic
SPI-NAND chip drivers:
- Micron:
- Add support for MT29F2G01AAAED
- Use more specific names
- Macronix:
- Add support for MX35LFxG24AD
- Add support for MX35LFxGE4AD
- Toshiba: Demote non-conformant kernel-doc header
SPI-NOR core:
- Initial support for stateful Octal DTR mode using volatile settings
- Preliminary support for JEDEC 251 (xSPI) and JEDEC 216D standards
- Support for Cypress Semper flash
- Support to specify ECC block size of SPI NOR flashes
- Fixes to avoid clearing of non-volatile Block Protection bits at
probe
- hisi-sfc: Demote non-conformant kernel-doc"
* tag 'mtd/for-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (120 commits)
mtd: spinand: macronix: Add support for MX35LFxG24AD
mtd: rawnand: rockchip: NFC driver for RK3308, RK2928 and others
dt-bindings: mtd: Describe Rockchip RK3xxx NAND flash controller
mtd: rawnand: gpmi: Use a single line for of_device_id
mtd: rawnand: gpmi: Fix the random DMA timeout issue
mtd: rawnand: gpmi: Fix the driver only sense CS0 R/B issue
mtd: rawnand: qcom: Add NAND controller support for SDX55
dt-bindings: qcom_nandc: Add SDX55 QPIC NAND documentation
mtd: rawnand: mxc: Use a single line for of_device_id
mtd: rawnand: mxc: Use device_get_match_data()
mtd: rawnand: meson: Fix a resource leak in init
mtd: rawnand: gpmi: Use of_device_get_match_data()
mtd: rawnand: Add NAND controller support on Intel LGM SoC
dt-bindings: mtd: Add Nand Flash Controller support for Intel LGM SoC
mtd: spinand: micron: Add support for MT29F2G01AAAED
mtd: spinand: micron: Use more specific names
mtd: rawnand: gpmi: fix reference count leak in gpmi ops
dt-bindings: mtd: gpmi-nand: Fix matching of clocks on different SoCs
mtd: spinand: macronix: Add support for MX35LFxGE4AD
mtd: plat-ram: correctly free memory on error path in platram_probe()
...
Diffstat (limited to 'drivers/mtd/spi-nor/atmel.c')
-rw-r--r-- | drivers/mtd/spi-nor/atmel.c | 191 |
1 files changed, 172 insertions, 19 deletions
diff --git a/drivers/mtd/spi-nor/atmel.c b/drivers/mtd/spi-nor/atmel.c index 3f5f21a473a6..1fea5cab492c 100644 --- a/drivers/mtd/spi-nor/atmel.c +++ b/drivers/mtd/spi-nor/atmel.c @@ -8,39 +8,192 @@ #include "core.h" +#define ATMEL_SR_GLOBAL_PROTECT_MASK GENMASK(5, 2) + +/* + * The Atmel AT25FS010/AT25FS040 parts have some weird configuration for the + * block protection bits. We don't support them. But legacy behavior in linux + * is to unlock the whole flash array on startup. Therefore, we have to support + * exactly this operation. + */ +static int atmel_at25fs_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + return -EOPNOTSUPP; +} + +static int atmel_at25fs_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + int ret; + + /* We only support unlocking the whole flash array */ + if (ofs || len != nor->params->size) + return -EINVAL; + + /* Write 0x00 to the status register to disable write protection */ + ret = spi_nor_write_sr_and_check(nor, 0); + if (ret) + dev_dbg(nor->dev, "unable to clear BP bits, WP# asserted?\n"); + + return ret; +} + +static int atmel_at25fs_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + return -EOPNOTSUPP; +} + +static const struct spi_nor_locking_ops atmel_at25fs_locking_ops = { + .lock = atmel_at25fs_lock, + .unlock = atmel_at25fs_unlock, + .is_locked = atmel_at25fs_is_locked, +}; + +static void atmel_at25fs_default_init(struct spi_nor *nor) +{ + nor->params->locking_ops = &atmel_at25fs_locking_ops; +} + +static const struct spi_nor_fixups atmel_at25fs_fixups = { + .default_init = atmel_at25fs_default_init, +}; + +/** + * atmel_set_global_protection - Do a Global Protect or Unprotect command + * @nor: pointer to 'struct spi_nor' + * @ofs: offset in bytes + * @len: len in bytes + * @is_protect: if true do a Global Protect otherwise it is a Global Unprotect + * + * Return: 0 on success, -error otherwise. + */ +static int atmel_set_global_protection(struct spi_nor *nor, loff_t ofs, + uint64_t len, bool is_protect) +{ + int ret; + u8 sr; + + /* We only support locking the whole flash array */ + if (ofs || len != nor->params->size) + return -EINVAL; + + ret = spi_nor_read_sr(nor, nor->bouncebuf); + if (ret) + return ret; + + sr = nor->bouncebuf[0]; + + /* SRWD bit needs to be cleared, otherwise the protection doesn't change */ + if (sr & SR_SRWD) { + sr &= ~SR_SRWD; + ret = spi_nor_write_sr_and_check(nor, sr); + if (ret) { + dev_dbg(nor->dev, "unable to clear SRWD bit, WP# asserted?\n"); + return ret; + } + } + + if (is_protect) { + sr |= ATMEL_SR_GLOBAL_PROTECT_MASK; + /* + * Set the SRWD bit again as soon as we are protecting + * anything. This will ensure that the WP# pin is working + * correctly. By doing this we also behave the same as + * spi_nor_sr_lock(), which sets SRWD if any block protection + * is active. + */ + sr |= SR_SRWD; + } else { + sr &= ~ATMEL_SR_GLOBAL_PROTECT_MASK; + } + + nor->bouncebuf[0] = sr; + + /* + * We cannot use the spi_nor_write_sr_and_check() because this command + * isn't really setting any bits, instead it is an pseudo command for + * "Global Unprotect" or "Global Protect" + */ + return spi_nor_write_sr(nor, nor->bouncebuf, 1); +} + +static int atmel_global_protect(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + return atmel_set_global_protection(nor, ofs, len, true); +} + +static int atmel_global_unprotect(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + return atmel_set_global_protection(nor, ofs, len, false); +} + +static int atmel_is_global_protected(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + int ret; + + if (ofs >= nor->params->size || (ofs + len) > nor->params->size) + return -EINVAL; + + ret = spi_nor_read_sr(nor, nor->bouncebuf); + if (ret) + return ret; + + return ((nor->bouncebuf[0] & ATMEL_SR_GLOBAL_PROTECT_MASK) == ATMEL_SR_GLOBAL_PROTECT_MASK); +} + +static const struct spi_nor_locking_ops atmel_global_protection_ops = { + .lock = atmel_global_protect, + .unlock = atmel_global_unprotect, + .is_locked = atmel_is_global_protected, +}; + +static void atmel_global_protection_default_init(struct spi_nor *nor) +{ + nor->params->locking_ops = &atmel_global_protection_ops; +} + +static const struct spi_nor_fixups atmel_global_protection_fixups = { + .default_init = atmel_global_protection_default_init, +}; + static const struct flash_info atmel_parts[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, - { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, + { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K | SPI_NOR_HAS_LOCK) + .fixups = &atmel_at25fs_fixups }, + { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_HAS_LOCK) + .fixups = &atmel_at25fs_fixups }, - { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, - { "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, - { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, - { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, + { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, + SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) + .fixups = &atmel_global_protection_fixups }, + { "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) + .fixups = &atmel_global_protection_fixups }, + { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) + .fixups = &atmel_global_protection_fixups }, + { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) + .fixups = &atmel_global_protection_fixups }, { "at25sl321", INFO(0x1f4216, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, - { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, - { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, - { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, + { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) + .fixups = &atmel_global_protection_fixups }, + { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) + .fixups = &atmel_global_protection_fixups }, + { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) + .fixups = &atmel_global_protection_fixups }, { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, }; -static void atmel_default_init(struct spi_nor *nor) -{ - nor->flags |= SNOR_F_HAS_LOCK; -} - -static const struct spi_nor_fixups atmel_fixups = { - .default_init = atmel_default_init, -}; - const struct spi_nor_manufacturer spi_nor_atmel = { .name = "atmel", .parts = atmel_parts, .nparts = ARRAY_SIZE(atmel_parts), - .fixups = &atmel_fixups, }; |