summaryrefslogtreecommitdiff
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
parent889612fab092ec20463c886513b5cfde14cc8cb0 (diff)
parent5bf59d3f2baa0f98ab93ddb4ea8a3b37986db608 (diff)
downloadbarebox-ca922d6044e49b1ed9782aa8eb28d1ed70931978.tar.gz
Merge branch 'for-next/nvmem'
-rw-r--r--.gitignore1
-rw-r--r--Makefile2
-rw-r--r--arch/sandbox/Makefile7
-rw-r--r--arch/sandbox/board/Makefile2
-rw-r--r--arch/sandbox/board/env/init/state13
-rw-r--r--arch/sandbox/board/hostfile.c21
-rw-r--r--arch/sandbox/board/power.c33
-rw-r--r--arch/sandbox/board/stickypage.S26
-rw-r--r--arch/sandbox/board/watchdog.c20
-rw-r--r--arch/sandbox/configs/sandbox_defconfig2
-rw-r--r--arch/sandbox/dts/sandbox.dts36
-rw-r--r--arch/sandbox/mach-sandbox/include/mach/linux.h1
-rw-r--r--arch/sandbox/os/common.c83
-rw-r--r--commands/Kconfig7
-rw-r--r--commands/Makefile1
-rw-r--r--commands/nvmem.c24
-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
-rw-r--r--fs/devfs-core.c2
-rw-r--r--include/driver.h3
-rw-r--r--include/linux/nvmem-consumer.h2
-rw-r--r--include/linux/nvmem-provider.h8
-rw-r--r--include/of_net.h21
-rw-r--r--net/eth.c24
34 files changed, 548 insertions, 134 deletions
diff --git a/.gitignore b/.gitignore
index d7a37b3c9b..529bcfc212 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ Module.symvers
/TAGS
/barebox*
/System.map
+/stickypage.bin
#
# git files that we don't want to ignore even it they are dot-files
diff --git a/Makefile b/Makefile
index 3b915a6077..47ead62422 100644
--- a/Makefile
+++ b/Makefile
@@ -1123,7 +1123,7 @@ endif # CONFIG_MODULES
# Directories & files removed with 'make clean'
CLEAN_DIRS += $(MODVERDIR)
-CLEAN_FILES += barebox System.map include/generated/barebox_default_env.h \
+CLEAN_FILES += barebox System.map stickypage.bin include/generated/barebox_default_env.h \
.tmp_version .tmp_barebox* barebox.bin barebox.map \
.tmp_kallsyms* barebox.ldr compile_commands.json \
scripts/bareboxenv-target barebox-flash-image \
diff --git a/arch/sandbox/Makefile b/arch/sandbox/Makefile
index 5fc7e227be..ba2614ea5f 100644
--- a/arch/sandbox/Makefile
+++ b/arch/sandbox/Makefile
@@ -75,3 +75,10 @@ common-y += $(BOARD) arch/sandbox/os/ arch/sandbox/lib/
common-$(CONFIG_OFTREE) += arch/sandbox/dts/
CLEAN_FILES += $(BOARD)/barebox.lds
+
+OBJCOPYFLAGS_stickypage.bin = -O binary
+
+stickypage.bin: arch/sandbox/board/stickypage.o
+ $(call if_changed,objcopy)
+
+all: stickypage.bin
diff --git a/arch/sandbox/board/Makefile b/arch/sandbox/board/Makefile
index ffb1dbc21e..59fece60ef 100644
--- a/arch/sandbox/board/Makefile
+++ b/arch/sandbox/board/Makefile
@@ -10,3 +10,5 @@ obj-y += watchdog.o
obj-$(CONFIG_LED) += led.o
extra-y += barebox.lds
+
+extra-y += stickypage.o
diff --git a/arch/sandbox/board/env/init/state b/arch/sandbox/board/env/init/state
deleted file mode 100644
index b8a2b42a53..0000000000
--- a/arch/sandbox/board/env/init/state
+++ /dev/null
@@ -1,13 +0,0 @@
-if [ "x$state.dirty" != "x1" -o $global.system.reset != "POR" ]; then
- exit
-fi
-
-source /env/data/ansi-colors
-
-echo -e $CYAN
-echo "*******************************************************"
-echo "*** Inconsistent barebox state buckets detected ***"
-echo "*** This is normal for a first boot ***"
-echo "*** barebox will repair them on next poweroff/reset ***"
-echo "*******************************************************"
-echo -e -n $NC
diff --git a/arch/sandbox/board/hostfile.c b/arch/sandbox/board/hostfile.c
index 4fdf2b317d..f110621979 100644
--- a/arch/sandbox/board/hostfile.c
+++ b/arch/sandbox/board/hostfile.c
@@ -182,7 +182,7 @@ static struct driver_d hf_drv = {
.of_compatible = DRV_OF_COMPAT(hostfile_dt_ids),
.probe = hf_probe,
};
-device_platform_driver(hf_drv);
+postcore_platform_driver(hf_drv);
static int of_hostfile_fixup(struct device_node *root, void *ctx)
{
@@ -232,12 +232,21 @@ static int of_hostfile_map_fixup(struct device_node *root, void *ctx)
for_each_compatible_node_from(node, root, NULL, hostfile_dt_ids->compatible) {
struct hf_info hf = {};
uint64_t reg[2] = {};
- bool no_filename;
hf.devname = node->name;
ret = of_property_read_string(node, "barebox,filename", &hf.filename);
- no_filename = ret;
+ if (ret) {
+ pr_err("skipping nameless hostfile %s\n", hf.devname);
+ continue;
+ }
+
+ if (memcmp(hf.filename, "$build/", 7) == 0) {
+ char *fullpath = xasprintf("%s/%s", linux_get_builddir(),
+ hf.filename + sizeof "$build/" - 1);
+
+ hf.filename = fullpath;
+ }
hf.is_blockdev = of_property_read_bool(node, "barebox,blockdev");
hf.is_cdev = of_property_read_bool(node, "barebox,cdev");
@@ -263,12 +272,6 @@ static int of_hostfile_map_fixup(struct device_node *root, void *ctx)
if (ret)
goto out;
- if (no_filename) {
- ret = of_property_write_string(node, "barebox,filename", hf.filename);
- if (ret)
- goto out;
- }
-
ret = of_property_write_u32(node, "barebox,fd", hf.fd);
out:
if (ret)
diff --git a/arch/sandbox/board/power.c b/arch/sandbox/board/power.c
index 3cc9447958..3112c80348 100644
--- a/arch/sandbox/board/power.c
+++ b/arch/sandbox/board/power.c
@@ -4,11 +4,11 @@
#include <restart.h>
#include <mach/linux.h>
#include <reset_source.h>
-#include <mfd/syscon.h>
+#include <linux/nvmem-consumer.h>
struct sandbox_power {
struct restart_handler rst_hang, rst_reexec;
- struct regmap *src;
+ struct nvmem_cell *reset_source_cell;
u32 src_offset;
};
@@ -24,16 +24,20 @@ static void sandbox_rst_hang(struct restart_handler *rst)
static void sandbox_rst_reexec(struct restart_handler *rst)
{
+ u8 reason = RESET_RST;
struct sandbox_power *power = container_of(rst, struct sandbox_power, rst_reexec);
- regmap_update_bits(power->src, power->src_offset, 0xff, RESET_RST);
+
+ if (!IS_ERR(power->reset_source_cell))
+ WARN_ON(nvmem_cell_write(power->reset_source_cell, &reason, 1) <= 0);
+
linux_reexec();
}
static int sandbox_power_probe(struct device_d *dev)
{
struct sandbox_power *power = xzalloc(sizeof(*power));
- unsigned int rst;
- int ret;
+ size_t len = 1;
+ u8 *rst;
poweroff_handler_register_fn(sandbox_poweroff);
@@ -52,20 +56,19 @@ static int sandbox_power_probe(struct device_d *dev)
if (IS_ENABLED(CONFIG_SANDBOX_REEXEC))
restart_handler_register(&power->rst_reexec);
- power->src = syscon_regmap_lookup_by_phandle(dev->device_node, "barebox,reset-source");
- if (IS_ERR(power->src))
+ power->reset_source_cell = of_nvmem_cell_get(dev->device_node, "reset-source");
+ if (IS_ERR(power->reset_source_cell)) {
+ dev_warn(dev, "No reset source info available: %pe\n", power->reset_source_cell);
return 0;
+ }
- ret = of_property_read_u32_index(dev->device_node, "barebox,reset-source", 1,
- &power->src_offset);
- if (ret)
- return 0;
+ rst = nvmem_cell_read(power->reset_source_cell, &len);
+ if (!IS_ERR(rst)) {
+ reset_source_set_prinst(*rst, RESET_SOURCE_DEFAULT_PRIORITY, 0);
- ret = regmap_read(power->src, power->src_offset, &rst);
- if (ret == 0 && rst == 0)
- rst = RESET_POR;
+ free(rst);
+ }
- reset_source_set_prinst(rst, RESET_SOURCE_DEFAULT_PRIORITY, 0);
return 0;
}
diff --git a/arch/sandbox/board/stickypage.S b/arch/sandbox/board/stickypage.S
new file mode 100644
index 0000000000..f1915ab986
--- /dev/null
+++ b/arch/sandbox/board/stickypage.S
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+.globl stickypage;
+stickypage:
+
+/* nvmem */ .org 0x300
+.byte 0x01
+
+/* env */ .org 0x400
+.byte 0x79, 0xba, 0x8f, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+.byte 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x69, 0x9c, 0x7f, 0x00, 0x00, 0x00, 0x00
+
+/* state */ .org 0xC00
+.byte 0xf3, 0xfd, 0x54, 0x23, 0x18, 0x00, 0x00, 0x00, 0xa6, 0x86, 0x3b, 0xaa, 0x00, 0x00, 0x08, 0x00
+.byte 0x19, 0x70, 0x3d, 0xbb, 0x64, 0x89, 0x3b, 0x31, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
+.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+.byte 0xf3, 0xfd, 0x54, 0x23, 0x18, 0x00, 0x00, 0x00, 0xa6, 0x86, 0x3b, 0xaa, 0x00, 0x00, 0x08, 0x00
+.byte 0x19, 0x70, 0x3d, 0xbb, 0x64, 0x89, 0x3b, 0x31, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
+.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+.byte 0xf3, 0xfd, 0x54, 0x23, 0x18, 0x00, 0x00, 0x00, 0xa6, 0x86, 0x3b, 0xaa, 0x00, 0x00, 0x08, 0x00
+.byte 0x19, 0x70, 0x3d, 0xbb, 0x64, 0x89, 0x3b, 0x31, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00
+
+.fill 4096-(.-stickypage), 1, 0
+.size stickypage, 4096
diff --git a/arch/sandbox/board/watchdog.c b/arch/sandbox/board/watchdog.c
index e1cff7a0bf..ff26a2019f 100644
--- a/arch/sandbox/board/watchdog.c
+++ b/arch/sandbox/board/watchdog.c
@@ -6,7 +6,7 @@
#include <mach/linux.h>
#include <of.h>
#include <watchdog.h>
-#include <mfd/syscon.h>
+#include <linux/nvmem-consumer.h>
#include <reset_source.h>
struct sandbox_watchdog {
@@ -36,10 +36,9 @@ static int sandbox_watchdog_set_timeout(struct watchdog *wdd, unsigned int timeo
static int sandbox_watchdog_probe(struct device_d *dev)
{
struct device_node *np = dev->device_node;
+ struct nvmem_cell *reset_source_cell;
struct sandbox_watchdog *wd;
struct watchdog *wdd;
- struct regmap *src;
- u32 src_offset;
int ret;
wd = xzalloc(sizeof(*wd));
@@ -57,16 +56,17 @@ static int sandbox_watchdog_probe(struct device_d *dev)
return ret;
}
- src = syscon_regmap_lookup_by_phandle(np, "barebox,reset-source");
- if (IS_ERR(src))
- return 0;
+ reset_source_cell = of_nvmem_cell_get(dev->device_node, "reset-source");
+ if (IS_ERR(reset_source_cell)) {
+ dev_warn(dev, "No reset source info available: %pe\n", reset_source_cell);
+ goto out;
+ }
- ret = of_property_read_u32_index(np, "barebox,reset-source", 1, &src_offset);
- if (ret)
- return 0;
+ nvmem_cell_write(reset_source_cell, &(u8) { RESET_WDG }, 1);
- regmap_update_bits(src, src_offset, 0xff, RESET_WDG);
+ nvmem_cell_put(reset_source_cell);
+out:
dev_info(dev, "probed\n");
return 0;
}
diff --git a/arch/sandbox/configs/sandbox_defconfig b/arch/sandbox/configs/sandbox_defconfig
index d9d96d9481..881762444b 100644
--- a/arch/sandbox/configs/sandbox_defconfig
+++ b/arch/sandbox/configs/sandbox_defconfig
@@ -4,7 +4,6 @@ CONFIG_CMDLINE_EDITING=y
CONFIG_AUTO_COMPLETE=y
CONFIG_MENU=y
CONFIG_CONSOLE_ALLOW_COLOR=y
-CONFIG_PARTITION=y
CONFIG_PARTITION_DISK_EFI=y
CONFIG_DEFAULT_COMPRESSION_GZIP=y
CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
@@ -126,6 +125,7 @@ CONFIG_WATCHDOG_POLLER=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_DS1307=y
CONFIG_SYSCON_REBOOT_MODE=y
+CONFIG_NVMEM_REBOOT_MODE=y
CONFIG_FS_CRAMFS=y
CONFIG_FS_EXT4=y
CONFIG_FS_TFTP=y
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index e99986bb90..5b2cab219e 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -55,15 +55,17 @@
stickypage: stickypage {
compatible = "barebox,hostfile", "syscon", "simple-mfd";
+ barebox,filename = "$build/stickypage.bin";
reg = <0 0 0 4096>;
barebox,cdev; /* no caching allowed */
bmode: reboot-mode {
- compatible = "syscon-reboot-mode";
- offset = <0>;
- mask = <0xffffff00>;
- mode-normal = <0x00000000>;
- mode-loader = <0xbbbbbb00>;
+ compatible = "nvmem-reboot-mode";
+ nvmem-cells = <&reboot_mode>;
+ nvmem-cell-names = "reboot-mode";
+
+ mode-normal = <0x000000>;
+ mode-loader = <0xbbbbbb>;
};
partitions {
@@ -71,14 +73,28 @@
#address-cells = <1>;
#size-cells = <1>;
- /* 0x00+4 reserved for syscon use */
+ part_nvmem: nvmem@300 {
+ compatible = "nvmem-cells";
+ reg = <0x300 0x100>;
+ label = "nvmem";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ reset_source: reset-source@0 {
+ reg = <0x0 0x1>;
+ };
+
+ reboot_mode: reboot-mode@1 {
+ reg = <0x1 0x4>;
+ };
+ };
part_env: env@400 {
reg = <0x400 0x800>;
label = "env";
};
- part_state: state@800 {
+ part_state: state@c00 {
reg = <0xC00 0x400>;
label = "state";
};
@@ -87,12 +103,14 @@
power {
compatible = "barebox,sandbox-power";
- barebox,reset-source = <&stickypage 0>;
+ nvmem-cell-names = "reset-source";
+ nvmem-cells = <&reset_source>;
};
watchdog {
compatible = "barebox,sandbox-watchdog";
- barebox,reset-source = <&stickypage 0>;
+ nvmem-cell-names = "reset-source";
+ nvmem-cells = <&reset_source>;
};
sound {
diff --git a/arch/sandbox/mach-sandbox/include/mach/linux.h b/arch/sandbox/mach-sandbox/include/mach/linux.h
index 831e170d90..453813952e 100644
--- a/arch/sandbox/mach-sandbox/include/mach/linux.h
+++ b/arch/sandbox/mach-sandbox/include/mach/linux.h
@@ -13,6 +13,7 @@ int linux_register_device(const char *name, void *start, void *end);
int tap_alloc(const char *dev);
uint64_t linux_get_time(void);
int linux_open(const char *filename, int readwrite);
+const char *linux_get_builddir(void);
int linux_open_hostfile(struct hf_info *hf);
int linux_read(int fd, void *buf, size_t count);
int linux_read_nonblock(int fd, void *buf, size_t count);
diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
index 4eb6d37fff..e36e3972bc 100644
--- a/arch/sandbox/os/common.c
+++ b/arch/sandbox/os/common.c
@@ -127,9 +127,23 @@ void __attribute__((noreturn)) linux_exit(void)
exit(0);
}
-static size_t saved_argv_len;
static char **saved_argv;
+static int selfpath(char *buf, size_t len)
+{
+ int ret;
+
+ /* we must follow the symlink, so we can exec an updated executable */
+ ret = readlink("/proc/self/exe", buf, len - 1);
+ if (ret < 0)
+ return ret;
+
+ if (0 < ret && ret < len - 1)
+ buf[ret] = '\0';
+
+ return ret;
+}
+
void linux_reexec(void)
{
char buf[4097];
@@ -138,9 +152,8 @@ void linux_reexec(void)
cookmode();
/* we must follow the symlink, so we can exec an updated executable */
- ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
- if (0 < ret && ret < sizeof(buf) - 1) {
- buf[ret] = '\0';
+ ret = selfpath(buf, sizeof(buf));
+ if (ret > 0) {
execv(buf, saved_argv);
if (!strcmp(&buf[ret - DELETED_OFFSET], " (deleted)")) {
printf("barebox image on disk changed. Loading new.\n");
@@ -317,6 +330,21 @@ static int add_image(const char *_str, char *devname_template, int *devname_numb
return ret;
}
+const char *linux_get_builddir(void)
+{
+ static char path[4097];
+ int ret;
+
+ if (!path[0]) {
+ ret = selfpath(path, sizeof(path));
+ if (ret < 0)
+ return NULL;
+ dirname(path);
+ }
+
+ return path;
+}
+
int linux_open_hostfile(struct hf_info *hf)
{
char *buf = NULL;
@@ -327,45 +355,10 @@ int linux_open_hostfile(struct hf_info *hf)
hf->filename ? "" : "initially un", hf->filename ?: "",
hf->is_readonly ? "(ro)" : "");
- if (hf->filename) {
- fd = hf->fd = open(hf->filename, (hf->is_readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC);
- } else {
- char *filename;
- int ret;
-
- ret = asprintf(&buf, "--image=%s=/tmp/barebox-hostfileXXXXXX", hf->devname);
- if (ret < 0) {
- perror("asprintf");
- goto err_out;
- }
-
- filename = buf + strlen("--image==") + strlen(hf->devname);
-
- fd = hf->fd = mkstemp(filename);
- if (fd >= 0) {
- ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
- if (ret < 0) {
- perror("fcntl");
- goto err_out;
- }
-
- ret = ftruncate(fd, hf->size);
- if (ret < 0) {
- perror("ftruncate");
- goto err_out;
- }
-
- hf->filename = filename;
-
- saved_argv = realloc(saved_argv,
- ++saved_argv_len * sizeof(*saved_argv));
- if (!saved_argv)
- exit(1);
- saved_argv[saved_argv_len - 2] = buf;
- saved_argv[saved_argv_len - 1] = NULL;
- }
- }
+ if (!hf->filename)
+ return -ENOENT;
+ fd = hf->fd = open(hf->filename, (hf->is_readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC);
if (fd < 0) {
perror("open");
goto err_out;
@@ -517,11 +510,7 @@ int main(int argc, char *argv[])
}
}
- saved_argv_len = argc + 1;
- saved_argv = calloc(saved_argv_len, sizeof(*saved_argv));
- if (!saved_argv)
- exit(1);
- memcpy(saved_argv, argv, saved_argv_len * sizeof(*saved_argv));
+ saved_argv = argv;
ram = malloc(malloc_size);
if (!ram) {
diff --git a/commands/Kconfig b/commands/Kconfig
index 5ae3cb3dd1..7bb36d6e41 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -206,6 +206,13 @@ config CMD_REGULATOR
the regulator command lists the currently registered regulators and
their current state.
+config CMD_NVMEM
+ bool
+ depends on NVMEM
+ prompt "nvmem command"
+ help
+ the nvmem command lists the currently registered nvmem devices.
+
config CMD_LSPCI
bool
depends on PCI
diff --git a/commands/Makefile b/commands/Makefile
index 4b45d266fd..ba5ea19eb2 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_CMD_SAVEENV) += saveenv.o
obj-$(CONFIG_CMD_LOADENV) += loadenv.o
obj-$(CONFIG_CMD_NAND) += nand.o
obj-$(CONFIG_CMD_NANDTEST) += nandtest.o
+obj-$(CONFIG_CMD_NVMEM) += nvmem.o
obj-$(CONFIG_CMD_MEMTEST) += memtest.o
obj-$(CONFIG_CMD_MEMTESTER) += memtester/
obj-$(CONFIG_CMD_TRUE) += true.o
diff --git a/commands/nvmem.c b/commands/nvmem.c
new file mode 100644
index 0000000000..a0e3d092e3
--- /dev/null
+++ b/commands/nvmem.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: © 2021 Ahmad Fatoum, Pengutronix
+
+#include <common.h>
+#include <command.h>
+#include <linux/nvmem-consumer.h>
+
+static int do_nvmem(int argc, char *argv[])
+{
+ nvmem_devices_print();
+
+ return 0;
+}
+
+BAREBOX_CMD_HELP_START(nvmem)
+BAREBOX_CMD_HELP_TEXT("Usage: nvmem")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(nvmem)
+ .cmd = do_nvmem,
+ BAREBOX_CMD_DESC("list nvmem devices")
+ BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
+ BAREBOX_CMD_HELP(cmd_nvmem_help)
+BAREBOX_CMD_END
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);
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index f804f96974..30ad0e0508 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -529,7 +529,7 @@ void cdev_remove_loop(struct cdev *cdev)
free(cdev);
}
-static ssize_t mem_copy(struct device_d *dev, void *dst, const void *src,
+ssize_t mem_copy(struct device_d *dev, void *dst, const void *src,
resource_size_t count, resource_size_t offset,
unsigned long flags)
{
diff --git a/include/driver.h b/include/driver.h
index d84fe35d50..c7f5903fce 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -347,6 +347,9 @@ struct cdev;
/* These are used by drivers which work with direct memory accesses */
ssize_t mem_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags);
ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags);
+ssize_t mem_copy(struct device_d *dev, void *dst, const void *src,
+ resource_size_t count, resource_size_t offset,
+ unsigned long flags);
int generic_memmap_ro(struct cdev *dev, void **map, int flags);
int generic_memmap_rw(struct cdev *dev, void **map, int flags);
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
index 5f44cf00cd..b979f23372 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -49,6 +49,8 @@ ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
int nvmem_device_cell_write(struct nvmem_device *nvmem,
struct nvmem_cell_info *info, void *buf);
+void nvmem_devices_print(void);
+
#else
static inline struct nvmem_cell *nvmem_cell_get(struct device_d *dev,
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index 2d73898373..a293f60c1e 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -26,6 +26,7 @@ struct nvmem_config {
struct device_d *dev;
const char *name;
bool read_only;
+ struct cdev *cdev;
int stride;
int word_size;
int size;
@@ -34,11 +35,13 @@ struct nvmem_config {
};
struct regmap;
+struct cdev;
#if IS_ENABLED(CONFIG_NVMEM)
struct nvmem_device *nvmem_register(const struct nvmem_config *cfg);
struct nvmem_device *nvmem_regmap_register(struct regmap *regmap, const char *name);
+struct nvmem_device *nvmem_partition_register(struct cdev *cdev);
#else
@@ -52,5 +55,10 @@ static inline struct nvmem_device *nvmem_regmap_register(struct regmap *regmap,
return ERR_PTR(-ENOSYS);
}
+static inline struct nvmem_device *nvmem_partition_register(struct cdev *cdev)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
#endif /* CONFIG_NVMEM */
#endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
diff --git a/include/of_net.h b/include/of_net.h
index f37af58303..4e23deb28e 100644
--- a/include/of_net.h
+++ b/include/of_net.h
@@ -6,8 +6,27 @@
#ifndef __LINUX_OF_NET_H
#define __LINUX_OF_NET_H
+#include <linux/types.h>
#include <of.h>
+
+#ifdef CONFIG_OFTREE
+int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr);
+int of_get_mac_address(struct device_node *np, u8 *addr);
int of_get_phy_mode(struct device_node *np);
-const void *of_get_mac_address(struct device_node *np);
+#else
+static inline int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr)
+{
+ return -ENOSYS;
+}
+static inline int of_get_mac_address(struct device_node *np, u8 *addr)
+{
+ return -ENOSYS;
+}
+
+static inline int of_get_phy_mode(struct device_node *np)
+{
+ return -ENOSYS;
+}
+#endif
#endif /* __LINUX_OF_NET_H */
diff --git a/net/eth.c b/net/eth.c
index 84f99d3aa8..762c5dfb8a 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -11,6 +11,7 @@
#include <net.h>
#include <dma.h>
#include <of.h>
+#include <of_net.h>
#include <linux/phy.h>
#include <errno.h>
#include <malloc.h>
@@ -504,3 +505,26 @@ void led_trigger_network(enum led_trigger trigger)
led_trigger(trigger, TRIGGER_FLASH);
led_trigger(LED_TRIGGER_NET_TXRX, TRIGGER_FLASH);
}
+
+static int of_populate_ethaddr(void)
+{
+ char str[sizeof("xx:xx:xx:xx:xx:xx")];
+ struct eth_device *edev;
+ int ret;
+
+ list_for_each_entry(edev, &netdev_list, list) {
+ if (!edev->parent || is_valid_ether_addr(edev->ethaddr))
+ continue;
+
+ ret = of_get_mac_addr_nvmem(edev->parent->device_node, edev->ethaddr);
+ if (ret)
+ continue;
+
+ ethaddr_to_string(edev->ethaddr, str);
+ dev_info(&edev->dev, "Got preset MAC address from device tree: %s\n", str);
+ eth_set_ethaddr(edev, edev->ethaddr);
+ }
+
+ return 0;
+}
+postenvironment_initcall(of_populate_ethaddr);