diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2021-07-18 07:13:26 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2021-07-18 07:13:26 +0200 |
commit | ca922d6044e49b1ed9782aa8eb28d1ed70931978 (patch) | |
tree | 6cac7b356b9fc9f4c152eafca0e38d14c311577b /drivers | |
parent | 889612fab092ec20463c886513b5cfde14cc8cb0 (diff) | |
parent | 5bf59d3f2baa0f98ab93ddb4ea8a3b37986db608 (diff) | |
download | barebox-ca922d6044e49b1ed9782aa8eb28d1ed70931978.tar.gz barebox-ca922d6044e49b1ed9782aa8eb28d1ed70931978.tar.xz |
Merge branch 'for-next/nvmem'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/nvmem/Kconfig | 6 | ||||
-rw-r--r-- | drivers/nvmem/Makefile | 4 | ||||
-rw-r--r-- | drivers/nvmem/bsec.c | 1 | ||||
-rw-r--r-- | drivers/nvmem/core.c | 25 | ||||
-rw-r--r-- | drivers/nvmem/partition.c | 40 | ||||
-rw-r--r-- | drivers/nvmem/rmem.c | 67 | ||||
-rw-r--r-- | drivers/of/base.c | 21 | ||||
-rw-r--r-- | drivers/of/of_net.c | 78 | ||||
-rw-r--r-- | drivers/of/partition.c | 7 | ||||
-rw-r--r-- | drivers/power/reset/Kconfig | 10 | ||||
-rw-r--r-- | drivers/power/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/reset/nvmem-reboot-mode.c | 83 |
12 files changed, 316 insertions, 27 deletions
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index e4a72b1431..0d7c0b7b9e 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -9,6 +9,12 @@ menuconfig NVMEM if NVMEM +config NVMEM_RMEM + bool "Reserved Memory Based Driver Support" + help + This driver maps reserved memory into an nvmem device. It might be + useful to expose information left by firmware in memory. + config NVMEM_SNVS_LPGPR tristate "Freescale SNVS LPGPR support" select MFD_SYSCON diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 617e3725a7..53c02dc785 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -3,7 +3,9 @@ # obj-$(CONFIG_NVMEM) += nvmem_core.o -nvmem_core-y := core.o regmap.o +nvmem_core-y := core.o regmap.o partition.o + +obj-$(CONFIG_NVMEM_RMEM) += rmem.o # Devices obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o diff --git a/drivers/nvmem/bsec.c b/drivers/nvmem/bsec.c index 509a5fa872..d9b38c8414 100644 --- a/drivers/nvmem/bsec.c +++ b/drivers/nvmem/bsec.c @@ -23,7 +23,6 @@ struct bsec_priv { u32 svc_id; struct regmap_config map_config; - struct nvmem_config config; }; struct stm32_bsec_data { diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 8f4b4646a9..4e558e1650 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -49,6 +49,15 @@ struct nvmem_cell { static LIST_HEAD(nvmem_cells); static LIST_HEAD(nvmem_devs); +void nvmem_devices_print(void) +{ + struct nvmem_device *dev; + + list_for_each_entry(dev, &nvmem_devs, node) { + printf("%s\n", dev_name(&dev->dev)); + } +} + static ssize_t nvmem_cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, unsigned long flags) { @@ -205,12 +214,12 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) nvmem->size = config->size; nvmem->dev.parent = config->dev; nvmem->bus = config->bus; - np = config->dev->device_node; + np = config->cdev ? config->cdev->device_node : config->dev->device_node; nvmem->dev.device_node = np; nvmem->priv = config->priv; - nvmem->read_only = of_property_read_bool(np, "read-only") | - config->read_only; + if (config->read_only || !config->bus->write || of_property_read_bool(np, "read-only")) + nvmem->read_only = true; dev_set_name(&nvmem->dev, config->name); nvmem->dev.id = DEVICE_ID_DYNAMIC; @@ -223,10 +232,12 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) return ERR_PTR(rval); } - rval = nvmem_register_cdev(nvmem, config->name); - if (rval) { - kfree(nvmem); - return ERR_PTR(rval); + if (!config->cdev) { + rval = nvmem_register_cdev(nvmem, config->name); + if (rval) { + kfree(nvmem); + return ERR_PTR(rval); + } } list_add_tail(&nvmem->node, &nvmem_devs); diff --git a/drivers/nvmem/partition.c b/drivers/nvmem/partition.c new file mode 100644 index 0000000000..3f0bdc58de --- /dev/null +++ b/drivers/nvmem/partition.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <common.h> +#include <driver.h> +#include <malloc.h> +#include <xfuncs.h> +#include <errno.h> +#include <init.h> +#include <io.h> +#include <linux/nvmem-provider.h> + +static int nvmem_cdev_write(void *ctx, unsigned offset, const void *val, size_t bytes) +{ + return cdev_write(ctx, val, bytes, offset, 0); +} + +static int nvmem_cdev_read(void *ctx, unsigned offset, void *buf, size_t bytes) +{ + return cdev_read(ctx, buf, bytes, offset, 0); +} + +static struct nvmem_bus nvmem_cdev_bus = { + .read = nvmem_cdev_read, + .write = nvmem_cdev_write, +}; + +struct nvmem_device *nvmem_partition_register(struct cdev *cdev) +{ + struct nvmem_config config = {}; + + config.name = cdev->name; + config.dev = cdev->dev; + config.cdev = cdev; + config.priv = cdev; + config.stride = 1; + config.word_size = 1; + config.size = cdev->size; + config.bus = &nvmem_cdev_bus; + + return nvmem_register(&config); +} diff --git a/drivers/nvmem/rmem.c b/drivers/nvmem/rmem.c new file mode 100644 index 0000000000..e103cec448 --- /dev/null +++ b/drivers/nvmem/rmem.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de> + */ + +#include <io.h> +#include <driver.h> +#include <linux/nvmem-provider.h> +#include <init.h> + +struct rmem { + struct device_d *dev; + const struct resource *mem; +}; + +static int rmem_read(void *context, unsigned int offset, + void *val, size_t bytes) +{ + struct rmem *rmem = context; + return mem_copy(rmem->dev, val, (void *)rmem->mem->start + offset, + bytes, offset, 0); +} + +static struct nvmem_bus rmem_nvmem_bus = { + .read = rmem_read, +}; + +static int rmem_probe(struct device_d *dev) +{ + struct nvmem_config config = { }; + struct resource *mem; + struct rmem *priv; + + mem = dev_request_mem_resource(dev, 0); + if (IS_ERR(mem)) + return PTR_ERR(mem); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->mem = mem; + + config.dev = priv->dev = dev; + config.priv = priv; + config.name = "rmem"; + config.size = resource_size(mem); + config.bus = &rmem_nvmem_bus; + + return PTR_ERR_OR_ZERO(nvmem_register(&config)); +} + +static const struct of_device_id rmem_match[] = { + { .compatible = "nvmem-rmem", }, + { /* sentinel */ }, +}; + +static struct driver_d rmem_driver = { + .name = "rmem", + .of_compatible = rmem_match, + .probe = rmem_probe, +}; +device_platform_driver(rmem_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>"); +MODULE_DESCRIPTION("Reserved Memory Based nvmem Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/of/base.c b/drivers/of/base.c index 0ae9a845a4..42b8d24874 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2354,16 +2354,29 @@ static void of_platform_device_create_root(struct device_node *np) free(dev); } +static const struct of_device_id reserved_mem_matches[] = { + { .compatible = "nvmem-rmem" }, + {} +}; + int of_probe(void) { - struct device_node *firmware; + struct device_node *node; if(!root_node) return -ENODEV; - firmware = of_find_node_by_path("/firmware"); - if (firmware) - of_platform_populate(firmware, NULL, NULL); + /* + * Handle certain compatibles explicitly, since we don't want to create + * platform_devices for every node in /reserved-memory with a + * "compatible", + */ + for_each_matching_node(node, reserved_mem_matches) + of_platform_device_create(node, NULL); + + node = of_find_node_by_path("/firmware"); + if (node) + of_platform_populate(node, NULL, NULL); of_platform_device_create_root(root_node); diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c index cee4597195..67015160e2 100644 --- a/drivers/of/of_net.c +++ b/drivers/of/of_net.c @@ -9,6 +9,7 @@ #include <net.h> #include <of_net.h> #include <linux/phy.h> +#include <linux/nvmem-consumer.h> /** * It maps 'enum phy_interface_t' found in include/linux/phy.h @@ -67,12 +68,55 @@ int of_get_phy_mode(struct device_node *np) } EXPORT_SYMBOL_GPL(of_get_phy_mode); +static int of_get_mac_addr(struct device_node *np, const char *name, u8 *addr) +{ + struct property *pp = of_find_property(np, name, NULL); + + if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value)) { + memcpy(addr, pp->value, ETH_ALEN); + return 0; + } + return -ENODEV; +} + +int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr) +{ + struct nvmem_cell *cell; + const void *mac; + size_t len; + + if (!IS_ENABLED(CONFIG_NVMEM)) + return -ENODEV; + + cell = of_nvmem_cell_get(np, "mac-address"); + if (IS_ERR(cell)) + return PTR_ERR(cell); + + mac = nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); + + if (IS_ERR(mac)) + return PTR_ERR(mac); + + if (len != ETH_ALEN || !is_valid_ether_addr(mac)) { + kfree(mac); + return -EINVAL; + } + + memcpy(addr, mac, ETH_ALEN); + kfree(mac); + + return 0; +} + /** * Search the device tree for the best MAC address to use. 'mac-address' is * checked first, because that is supposed to contain to "most recent" MAC * address. If that isn't set, then 'local-mac-address' is checked next, - * because that is the default address. If that isn't set, then the obsolete - * 'address' is checked, just in case we're using an old device tree. + * because that is the default address. If that isn't set, then the obsolete + * 'address' is checked, just in case we're using an old device tree. If any + * of the above isn't set, then try to get MAC address from nvmem cell named + * 'mac-address'. * * Note that the 'address' property is supposed to contain a virtual address of * the register set, but some DTS files have redefined that property to be the @@ -85,18 +129,24 @@ EXPORT_SYMBOL_GPL(of_get_phy_mode); * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists * but is all zeros. */ -const void *of_get_mac_address(struct device_node *np) +int of_get_mac_address(struct device_node *np, u8 *addr) { - const void *p; - int len, i; - const char *str[] = { "mac-address", "local-mac-address", "address" }; - - for (i = 0; i < ARRAY_SIZE(str); i++) { - p = of_get_property(np, str[i], &len); - if (p && (len == 6) && is_valid_ether_addr(p)) - return p; - } + int ret; + + if (!np) + return -ENODEV; + + ret = of_get_mac_addr(np, "mac-address", addr); + if (!ret) + return 0; + + ret = of_get_mac_addr(np, "local-mac-address", addr); + if (!ret) + return 0; + + ret = of_get_mac_addr(np, "address", addr); + if (!ret) + return 0; - return NULL; + return of_get_mac_addr_nvmem(np, addr); } -EXPORT_SYMBOL(of_get_mac_address); diff --git a/drivers/of/partition.c b/drivers/of/partition.c index b71716218b..b6d0523fd9 100644 --- a/drivers/of/partition.c +++ b/drivers/of/partition.c @@ -20,6 +20,7 @@ #include <linux/mtd/mtd.h> #include <linux/err.h> #include <nand.h> +#include <linux/nvmem-provider.h> #include <init.h> #include <globalvar.h> @@ -83,6 +84,12 @@ struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node) if (new) new->device_node = node;; + if (IS_ENABLED(CONFIG_NVMEM) && of_device_is_compatible(node, "nvmem-cells")) { + struct nvmem_device *nvmem = nvmem_partition_register(new); + if (IS_ERR(nvmem)) + dev_warn(cdev->dev, "nvmem registeration failed: %pe\n", nvmem); + } + free(filename); return new; diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index dec1482ccd..e4151d8bc6 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -13,6 +13,16 @@ config SYSCON_REBOOT_MODE Say y here will enable reboot mode driver. This will get reboot mode arguments and store it in SYSCON mapped register, then the bootloader can read it to take different + +config NVMEM_REBOOT_MODE + bool "Generic NVMEM reboot mode driver" + depends on OFDEVICE + depends on NVMEM + select REBOOT_MODE + help + Say y here will enable reboot mode driver. This will + get reboot mode arguments and store it in a NVMEM cell, + then the bootloader can read it and take different action according to the mode. config POWER_RESET_SYSCON diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 33d29d2d95..10d6f2a41e 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o +obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c new file mode 100644 index 0000000000..b82b37d642 --- /dev/null +++ b/drivers/power/reset/nvmem-reboot-mode.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) Vaisala Oyj. All rights reserved. + */ + +#include <common.h> +#include <init.h> +#include <of.h> +#include <linux/nvmem-consumer.h> +#include <linux/reboot-mode.h> + +struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; + struct nvmem_cell *cell; +}; + +static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + const u32 *_magic) +{ + struct nvmem_reboot_mode *nvmem_rbm; + u32 magic = *_magic; + int ret; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + + ret = nvmem_cell_write(nvmem_rbm->cell, &magic, sizeof(magic)); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed: %pe\n", ERR_PTR(ret)); + else if (ret != 4) + ret = -EIO; + else + ret = 0; + + return ret; +} + +static int nvmem_reboot_mode_probe(struct device_d *dev) +{ + struct nvmem_reboot_mode *nvmem_rbm; + struct nvmem_cell *cell; + void *magicbuf; + size_t len; + int ret; + + cell = nvmem_cell_get(dev, "reboot-mode"); + if (IS_ERR(cell)) { + ret = PTR_ERR(cell); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get the nvmem cell reboot-mode: %pe\n", cell); + return ret; + } + + nvmem_rbm = xzalloc(sizeof(*nvmem_rbm)); + + nvmem_rbm->cell = cell; + nvmem_rbm->reboot.dev = dev; + nvmem_rbm->reboot.write = nvmem_reboot_mode_write; + nvmem_rbm->reboot.priority = 200; + + magicbuf = nvmem_cell_read(nvmem_rbm->cell, &len); + if (IS_ERR(magicbuf) || len != 4) { + dev_err(dev, "error reading reboot mode: %pe\n", magicbuf); + return PTR_ERR(magicbuf); + } + + ret = reboot_mode_register(&nvmem_rbm->reboot, magicbuf, 1); + if (ret) + dev_err(dev, "can't register reboot mode\n"); + + return ret; +} + +static const struct of_device_id nvmem_reboot_mode_of_match[] = { + { .compatible = "nvmem-reboot-mode" }, + { /* sentinel */ } +}; + +static struct driver_d nvmem_reboot_mode_driver = { + .probe = nvmem_reboot_mode_probe, + .name = "nvmem-reboot-mode", + .of_compatible = nvmem_reboot_mode_of_match, +}; +coredevice_platform_driver(nvmem_reboot_mode_driver); |