diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-24 14:31:29 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-24 14:31:29 -0700 |
| commit | d335371940179318df97d66baef13987ee6e796b (patch) | |
| tree | aa7ee88e0b2f8c1eeaba662313ea37e58f9dc006 /drivers/mtd/devices/phram.c | |
| parent | 076f222a690e11b433d2b1e218dbd9bdb08fb190 (diff) | |
| parent | 2c51d0d88020b4d3c9bbe7d9df2796b2c2ce05b8 (diff) | |
Merge tag 'mtd/for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull mtd updates from Miquel Raynal:
"MTD core changes:
- Call of_platform_populate() for MTD partitions
- Check devicetree alias for index
- mtdoops:
- Add a timestamp to the mtdoops header.
- Create a header structure for the saved mtdoops.
- Fix the size of the header read buffer.
- mtdblock: Warn if opened on NAND
- Bindings:
- reserved-memory: Support MTD/block device
- jedec,spi-nor: remove unneeded properties
- Extend fixed-partitions binding
- Add Sercomm (Suzhou) Corporation vendor prefix
MTD driver changes:
- st_spi_fsm: add missing clk_disable_unprepare() in stfsm_remove()
- phram:
- Allow cached mappings
- Allow probing via reserved-memory
- maps: ixp4xx: Drop driver
- bcm47xxpart: Print correct offset on read error
CFI driver changes:
- Rename chip_ready variables
- Add S29GL064N ID definition
- Use chip_ready() for write on S29GL064N
- Move and rename chip_check/chip_ready/chip_good_for_write
NAND core changes:
- Print offset instead of page number for bad blocks
Raw NAND controller drivers:
- Cadence: Fix possible null-ptr-deref in cadence_nand_dt_probe()
- CS553X: simplify the return expression of cs553x_write_ctrl_byte()
- Davinci: Remove redundant unsigned comparison to zero
- Denali: Use managed device resources
- GPMI:
- Add large oob bch setting support
- Rename the variable ecc_chunk_size
- Uninline the gpmi_check_ecc function
- Add strict ecc strength check
- Refactor BCH geometry settings function
- Intel: Fix possible null-ptr-deref in ebu_nand_probe()
- MPC5121: Check before clk_disable_unprepare() not needed
- Mtk:
- MTD_NAND_ECC_MEDIATEK should depend on ARCH_MEDIATEK
- Also parse the default nand-ecc-engine property if available
- Make mtk_ecc.c a separated module
- OMAP ELM:
- Convert the bindings to yaml
- Describe the bindings for AM64 ELM
- Add support for its compatible
- Renesas: Use runtime PM instead of the raw clock API and update the
bindings accordingly
- Rockchip: Check before clk_disable_unprepare() not needed
- TMIO: Check return value after calling platform_get_resource()
Raw NAND chip driver:
- Kioxia: Add support for TH58NVG3S0HBAI4 and TC58NVG0S3HTA00
SPI-NAND chip drivers:
- Gigadevice:
- Add support for:
- GD5FxGM7xExxG
- GD5F{2,4}GQ5xExxG
- GD5F1GQ5RExxG
- GD5FxGQ4xExxG
- Fix Quad IO for GD5F1GQ5UExxG
- XTX: Add support for XT26G0xA
SPI NOR core changes:
- Read back written SR value to make sure the write was done
correctly.
- Introduce a common function for Read ID that manufacturer drivers
can use to verify the Octal DTR switch worked correctly.
- Add helpers for read/write any register commands so manufacturer
drivers don't open code it every time.
- Clarify rdsr dummy cycles documentation.
- Add debugfs entry to expose internal flash parameters and state.
SPI NOR manufacturer drivers changes:
- Add support for Winbond W25Q512NW-IM, and Eon EN25QH256A.
- Move spi_nor_write_ear() to Winbond module since only Winbond
flashes use it.
- Rework Micron and Cypress Octal DTR enable methods to improve
readability.
- Use the common Read ID function to verify switch to Octal DTR mode
for Micron and Cypress flashes.
- Skip polling status on volatile register writes for Micron and
Cypress flashes since the operation is instant"
* tag 'mtd/for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (68 commits)
mtd: st_spi_fsm: add missing clk_disable_unprepare() in stfsm_remove()
dt-bindings: mtd: partitions: Extend fixed-partitions binding
dt-bindings: Add Sercomm (Suzhou) Corporation vendor prefix
mtd: phram: Allow cached mappings
mtd: call of_platform_populate() for MTD partitions
mtd: rawnand: renesas: Use runtime PM instead of the raw clock API
dt-bindings: mtd: renesas: Fix the NAND controller description
mtd: rawnand: mpc5121: Check before clk_disable_unprepare() not needed
mtd: rawnand: rockchip: Check before clk_disable_unprepare() not needed
mtd: nand: MTD_NAND_ECC_MEDIATEK should depend on ARCH_MEDIATEK
mtd: rawnand: cs553x: simplify the return expression of cs553x_write_ctrl_byte()
mtd: rawnand: kioxia: Add support for TH58NVG3S0HBAI4
mtd: spi-nor: debugfs: fix format specifier
mtd: spi-nor: support eon en25qh256a variant
mtd: spi-nor: winbond: add support for W25Q512NW-IM
mtd: spi-nor: expose internal parameters via debugfs
mtd: spi-nor: export spi_nor_hwcaps_pp2cmd()
mtd: spi-nor: move spi_nor_write_ear() to winbond module
mtd: spi-nor: amend the rdsr dummy cycles documentation
mtd: cfi_cmdset_0002: Rename chip_ready variables
...
Diffstat (limited to 'drivers/mtd/devices/phram.c')
| -rw-r--r-- | drivers/mtd/devices/phram.c | 108 |
1 files changed, 99 insertions, 9 deletions
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index d503821a3e60..208bd4d871f4 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -27,10 +27,14 @@ #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <asm/div64.h> +#include <linux/platform_device.h> +#include <linux/of_address.h> +#include <linux/of.h> struct phram_mtd_list { struct mtd_info mtd; struct list_head list; + bool cached; }; static LIST_HEAD(phram_list); @@ -77,20 +81,51 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len, return 0; } +static int phram_map(struct phram_mtd_list *phram, phys_addr_t start, size_t len) +{ + void *addr = NULL; + + if (phram->cached) + addr = memremap(start, len, MEMREMAP_WB); + else + addr = (void __force *)ioremap(start, len); + if (!addr) + return -EIO; + + phram->mtd.priv = addr; + + return 0; +} + +static void phram_unmap(struct phram_mtd_list *phram) +{ + void *addr = phram->mtd.priv; + + if (phram->cached) { + memunmap(addr); + return; + } + + iounmap((void __iomem *)addr); +} + static void unregister_devices(void) { struct phram_mtd_list *this, *safe; list_for_each_entry_safe(this, safe, &phram_list, list) { mtd_device_unregister(&this->mtd); - iounmap(this->mtd.priv); + phram_unmap(this); kfree(this->mtd.name); kfree(this); } } -static int register_device(char *name, phys_addr_t start, size_t len, uint32_t erasesize) +static int register_device(struct platform_device *pdev, const char *name, + phys_addr_t start, size_t len, uint32_t erasesize) { + struct device_node *np = pdev ? pdev->dev.of_node : NULL; + bool cached = np ? !of_property_read_bool(np, "no-map") : false; struct phram_mtd_list *new; int ret = -ENOMEM; @@ -98,9 +133,10 @@ static int register_device(char *name, phys_addr_t start, size_t len, uint32_t e if (!new) goto out0; - ret = -EIO; - new->mtd.priv = ioremap(start, len); - if (!new->mtd.priv) { + new->cached = cached; + + ret = phram_map(new, start, len); + if (ret) { pr_err("ioremap failed\n"); goto out1; } @@ -119,17 +155,23 @@ static int register_device(char *name, phys_addr_t start, size_t len, uint32_t e new->mtd.erasesize = erasesize; new->mtd.writesize = 1; + mtd_set_of_node(&new->mtd, np); + ret = -EAGAIN; if (mtd_device_register(&new->mtd, NULL, 0)) { pr_err("Failed to register new device\n"); goto out2; } - list_add_tail(&new->list, &phram_list); + if (pdev) + platform_set_drvdata(pdev, new); + else + list_add_tail(&new->list, &phram_list); + return 0; out2: - iounmap(new->mtd.priv); + phram_unmap(new); out1: kfree(new); out0: @@ -278,7 +320,7 @@ static int phram_setup(const char *val) goto error; } - ret = register_device(name, start, len, (uint32_t)erasesize); + ret = register_device(NULL, name, start, len, (uint32_t)erasesize); if (ret) goto error; @@ -325,10 +367,54 @@ static int phram_param_call(const char *val, const struct kernel_param *kp) module_param_call(phram, phram_param_call, NULL, NULL, 0200); MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>[,<erasesize>]\""); +#ifdef CONFIG_OF +static const struct of_device_id phram_of_match[] = { + { .compatible = "phram" }, + {} +}; +MODULE_DEVICE_TABLE(of, phram_of_match); +#endif + +static int phram_probe(struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOMEM; + + /* mtd_set_of_node() reads name from "label" */ + return register_device(pdev, NULL, res->start, resource_size(res), + PAGE_SIZE); +} + +static int phram_remove(struct platform_device *pdev) +{ + struct phram_mtd_list *phram = platform_get_drvdata(pdev); + + mtd_device_unregister(&phram->mtd); + phram_unmap(phram); + kfree(phram); + + return 0; +} + +static struct platform_driver phram_driver = { + .probe = phram_probe, + .remove = phram_remove, + .driver = { + .name = "phram", + .of_match_table = of_match_ptr(phram_of_match), + }, +}; static int __init init_phram(void) { - int ret = 0; + int ret; + + ret = platform_driver_register(&phram_driver); + if (ret) + return ret; #ifndef MODULE if (phram_paramline[0]) @@ -336,12 +422,16 @@ static int __init init_phram(void) phram_init_called = 1; #endif + if (ret) + platform_driver_unregister(&phram_driver); + return ret; } static void __exit cleanup_phram(void) { unregister_devices(); + platform_driver_unregister(&phram_driver); } module_init(init_phram); |
