summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-07-18 07:13:26 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-07-18 07:13:26 +0200
commitca922d6044e49b1ed9782aa8eb28d1ed70931978 (patch)
tree6cac7b356b9fc9f4c152eafca0e38d14c311577b /drivers
parent889612fab092ec20463c886513b5cfde14cc8cb0 (diff)
parent5bf59d3f2baa0f98ab93ddb4ea8a3b37986db608 (diff)
downloadbarebox-ca922d6044e49b1ed9782aa8eb28d1ed70931978.tar.gz
barebox-ca922d6044e49b1ed9782aa8eb28d1ed70931978.tar.xz
Merge branch 'for-next/nvmem'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/nvmem/Kconfig6
-rw-r--r--drivers/nvmem/Makefile4
-rw-r--r--drivers/nvmem/bsec.c1
-rw-r--r--drivers/nvmem/core.c25
-rw-r--r--drivers/nvmem/partition.c40
-rw-r--r--drivers/nvmem/rmem.c67
-rw-r--r--drivers/of/base.c21
-rw-r--r--drivers/of/of_net.c78
-rw-r--r--drivers/of/partition.c7
-rw-r--r--drivers/power/reset/Kconfig10
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/nvmem-reboot-mode.c83
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);