summaryrefslogtreecommitdiffstats
path: root/arch/sandbox/board
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sandbox/board')
-rw-r--r--arch/sandbox/board/.gitignore2
-rw-r--r--arch/sandbox/board/Makefile8
-rw-r--r--arch/sandbox/board/barebox.lds.S4
-rw-r--r--arch/sandbox/board/board.c25
-rw-r--r--arch/sandbox/board/clock.c4
-rw-r--r--arch/sandbox/board/console.c7
-rw-r--r--arch/sandbox/board/dev-random.c2
-rw-r--r--arch/sandbox/board/devices.c11
-rw-r--r--arch/sandbox/board/dtb.c33
-rw-r--r--arch/sandbox/board/env/nv/autoboot1
-rw-r--r--arch/sandbox/board/hostfile.c246
-rw-r--r--arch/sandbox/board/led.c68
-rw-r--r--arch/sandbox/board/power.c99
-rw-r--r--arch/sandbox/board/poweroff.c17
-rw-r--r--arch/sandbox/board/stickypage.S29
-rw-r--r--arch/sandbox/board/watchdog.c77
16 files changed, 512 insertions, 121 deletions
diff --git a/arch/sandbox/board/.gitignore b/arch/sandbox/board/.gitignore
index d1165788c9..03987a7009 100644
--- a/arch/sandbox/board/.gitignore
+++ b/arch/sandbox/board/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
barebox.lds
diff --git a/arch/sandbox/board/Makefile b/arch/sandbox/board/Makefile
index 26f6cb1922..b4bab02163 100644
--- a/arch/sandbox/board/Makefile
+++ b/arch/sandbox/board/Makefile
@@ -1,10 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
obj-y += board.o
obj-y += clock.o
obj-y += hostfile.o
obj-y += console.o
obj-y += devices.o
obj-y += dtb.o
-obj-y += poweroff.o
+obj-y += power.o
obj-y += dev-random.o
+obj-y += watchdog.o
+obj-$(CONFIG_LED) += led.o
extra-y += barebox.lds
+
+obj-y += stickypage.o
diff --git a/arch/sandbox/board/barebox.lds.S b/arch/sandbox/board/barebox.lds.S
index 7a5a8eb1e7..ab2801f3d2 100644
--- a/arch/sandbox/board/barebox.lds.S
+++ b/arch/sandbox/board/barebox.lds.S
@@ -1,4 +1,6 @@
-#include <asm-generic/barebox.lds.h>
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <asm/barebox.lds.h>
SECTIONS
{
diff --git a/arch/sandbox/board/board.c b/arch/sandbox/board/board.c
index ad2bc910c3..c8d1c99897 100644
--- a/arch/sandbox/board/board.c
+++ b/arch/sandbox/board/board.c
@@ -3,9 +3,6 @@
*
* Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
@@ -23,6 +20,7 @@
#include <mach/linux.h>
#include <init.h>
#include <errno.h>
+#include <deep-probe.h>
#include <fb.h>
struct fb_videomode mode = {
@@ -31,23 +29,23 @@ struct fb_videomode mode = {
.yres = 480,
};
-static struct device_d tap_device = {
+static struct device tap_device = {
.id = DEVICE_ID_DYNAMIC,
.name = "tap",
};
-static struct device_d sdl_device = {
+static struct device sdl_device = {
.id = DEVICE_ID_DYNAMIC,
.name = "sdlfb",
.platform_data = &mode,
};
-static struct device_d devrandom_device = {
+static struct device devrandom_device = {
.id = DEVICE_ID_DYNAMIC,
.name = "devrandom",
};
-static int devices_init(void)
+static int devices_init(struct device *dev)
{
platform_device_register(&tap_device);
@@ -64,4 +62,15 @@ static int devices_init(void)
return 0;
}
-device_initcall(devices_init);
+static struct of_device_id sandbox_dt_ids[] = {
+ { .compatible = "barebox,sandbox" },
+ { /* sentinel */ }
+};
+BAREBOX_DEEP_PROBE_ENABLE(sandbox_dt_ids);
+
+static struct driver sandbox_board_drv = {
+ .name = "sandbox-board",
+ .of_compatible = sandbox_dt_ids,
+ .probe = devices_init,
+};
+device_platform_driver(sandbox_board_drv);
diff --git a/arch/sandbox/board/clock.c b/arch/sandbox/board/clock.c
index bdea89f002..1787fb5786 100644
--- a/arch/sandbox/board/clock.c
+++ b/arch/sandbox/board/clock.c
@@ -3,9 +3,6 @@
*
* Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
@@ -31,6 +28,7 @@ static struct clocksource cs = {
.read = linux_clocksource_read,
.mask = CLOCKSOURCE_MASK(32),
.shift = 10,
+ .priority = 80,
};
static int clocksource_init (void)
diff --git a/arch/sandbox/board/console.c b/arch/sandbox/board/console.c
index 4b251e9087..274ef67aef 100644
--- a/arch/sandbox/board/console.c
+++ b/arch/sandbox/board/console.c
@@ -3,9 +3,6 @@
*
* Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
@@ -24,10 +21,10 @@
int barebox_register_console(int stdinfd, int stdoutfd)
{
- struct device_d *dev;
+ struct device *dev;
struct linux_console_data *data;
- dev = xzalloc(sizeof(struct device_d) + sizeof(struct linux_console_data));
+ dev = xzalloc(sizeof(struct device) + sizeof(struct linux_console_data));
data = (struct linux_console_data *)(dev + 1);
diff --git a/arch/sandbox/board/dev-random.c b/arch/sandbox/board/dev-random.c
index 60295e9fce..b62e8cc0d7 100644
--- a/arch/sandbox/board/dev-random.c
+++ b/arch/sandbox/board/dev-random.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <mach/linux.h>
diff --git a/arch/sandbox/board/devices.c b/arch/sandbox/board/devices.c
index 72e62552a3..ecd24e9207 100644
--- a/arch/sandbox/board/devices.c
+++ b/arch/sandbox/board/devices.c
@@ -6,13 +6,15 @@
#include <common.h>
#include <driver.h>
-#include <mach/linux.h>
#include <init.h>
#include <mach/linux.h>
+#include <asm/io.h>
+
+unsigned char __pci_iobase[IO_SPACE_LIMIT];
static LIST_HEAD(sandbox_device_list);
-int sandbox_add_device(struct device_d *dev)
+int sandbox_add_device(struct device *dev)
{
list_add(&dev->list, &sandbox_device_list);
@@ -21,10 +23,7 @@ int sandbox_add_device(struct device_d *dev)
static int sandbox_device_init(void)
{
- struct device_d *dev, *tmp;
-
- barebox_set_model("barebox sandbox");
- barebox_set_hostname("barebox");
+ struct device *dev, *tmp;
list_for_each_entry_safe(dev, tmp, &sandbox_device_list, list) {
/* reset the list_head before registering for real */
diff --git a/arch/sandbox/board/dtb.c b/arch/sandbox/board/dtb.c
index af4a64a9c7..98d2e774b8 100644
--- a/arch/sandbox/board/dtb.c
+++ b/arch/sandbox/board/dtb.c
@@ -2,9 +2,6 @@
* Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
* Copyright (c) 2015 Marc Kleine-Budde <mkl@pengutronix.de>, Pengutronix
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
@@ -35,33 +32,13 @@ int barebox_register_dtb(const void *new_dtb)
return 0;
}
+extern char __dtb_sandbox_start[];
+
static int of_sandbox_init(void)
{
- struct device_node *root;
- int ret;
-
- if (dtb) {
- root = of_unflatten_dtb(dtb);
- } else {
- root = of_new_node(NULL, NULL);
-
- ret = of_property_write_u32(root, "#address-cells", 2);
- if (ret)
- return ret;
+ if (!dtb)
+ dtb = __dtb_sandbox_start;
- ret = of_property_write_u32(root, "#size-cells", 1);
- if (ret)
- return ret;
- }
-
- if (IS_ERR(root))
- return PTR_ERR(root);
-
- of_set_root_node(root);
- of_fix_tree(root);
- if (IS_ENABLED(CONFIG_OFDEVICE))
- of_probe();
-
- return 0;
+ return barebox_register_fdt(dtb);
}
core_initcall(of_sandbox_init);
diff --git a/arch/sandbox/board/env/nv/autoboot b/arch/sandbox/board/env/nv/autoboot
new file mode 100644
index 0000000000..f7d13fd046
--- /dev/null
+++ b/arch/sandbox/board/env/nv/autoboot
@@ -0,0 +1 @@
+abort
diff --git a/arch/sandbox/board/hostfile.c b/arch/sandbox/board/hostfile.c
index e5a7580d07..7afad95b6d 100644
--- a/arch/sandbox/board/hostfile.c
+++ b/arch/sandbox/board/hostfile.c
@@ -3,9 +3,6 @@
*
* Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
@@ -19,25 +16,29 @@
#include <common.h>
#include <driver.h>
+#include <block.h>
+#include <disks.h>
#include <malloc.h>
#include <mach/linux.h>
#include <init.h>
#include <errno.h>
#include <linux/err.h>
#include <mach/hostfile.h>
+#include <featctrl.h>
#include <xfuncs.h>
-#include <linux/err.h>
-
struct hf_priv {
- struct cdev cdev;
+ union {
+ struct block_device blk;
+ struct cdev cdev;
+ };
const char *filename;
int fd;
+ struct feature_controller feat;
};
-static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags)
+static ssize_t hf_read(struct hf_priv *priv, void *buf, size_t count, loff_t offset, ulong flags)
{
- struct hf_priv *priv= cdev->priv;
int fd = priv->fd;
if (linux_lseek(fd, offset) != offset)
@@ -46,9 +47,8 @@ static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, loff_t offset
return linux_read(fd, buf, count);
}
-static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags)
+static ssize_t hf_write(struct hf_priv *priv, const void *buf, size_t count, loff_t offset, ulong flags)
{
- struct hf_priv *priv = cdev->priv;
int fd = priv->fd;
if (linux_lseek(fd, offset) != offset)
@@ -57,59 +57,135 @@ static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, loff_t
return linux_write(fd, buf, count);
}
-static void hf_info(struct device_d *dev)
+static ssize_t hf_cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags)
+{
+ return hf_read(cdev->priv, buf, count, offset, flags);
+}
+
+static ssize_t hf_cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags)
+{
+ return hf_write(cdev->priv, buf, count, offset, flags);
+}
+
+static struct cdev_operations hf_cdev_ops = {
+ .read = hf_cdev_read,
+ .write = hf_cdev_write,
+};
+
+static int hf_blk_read(struct block_device *blk, void *buf, sector_t block, blkcnt_t num_blocks)
+{
+ ssize_t ret = hf_read(container_of(blk, struct hf_priv, blk), buf,
+ num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0);
+ return ret > 0 ? 0 : ret;
+}
+
+static int hf_blk_write(struct block_device *blk, const void *buf, sector_t block, blkcnt_t num_blocks)
+{
+ ssize_t ret = hf_write(container_of(blk, struct hf_priv, blk), buf,
+ num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0);
+ return ret > 0 ? 0 : ret;
+}
+
+static struct block_device_ops hf_blk_ops = {
+ .read = hf_blk_read,
+ .write = hf_blk_write,
+};
+
+static void hf_info(struct device *dev)
{
struct hf_priv *priv = dev->priv;
printf("file: %s\n", priv->filename);
}
-static struct cdev_operations hf_fops = {
- .read = hf_read,
- .write = hf_write,
-};
+static int hostfile_feat_check(struct feature_controller *feat, int idx)
+{
+ struct hf_priv *priv = container_of(feat, struct hf_priv, feat);
-static int hf_probe(struct device_d *dev)
+ return priv->fd >= 0 ? FEATCTRL_OKAY : FEATCTRL_GATED;
+}
+
+static int hf_probe(struct device *dev)
{
+ struct device_node *np = dev->of_node;
struct hf_priv *priv = xzalloc(sizeof(*priv));
- struct resource *res;
+ struct cdev *cdev;
+ bool is_featctrl = false, is_blockdev;
+ u64 reg[2];
int err;
- res = dev_get_resource(dev, IORESOURCE_MEM, 0);
- if (IS_ERR(res))
- return PTR_ERR(res);
+ if (!np)
+ return -ENODEV;
+
+ dev->priv = priv;
+ priv->fd = -1;
- priv->cdev.size = resource_size(res);
+ if (IS_ENABLED(CONFIG_FEATURE_CONTROLLER) &&
+ of_property_read_bool(np, "barebox,feature-controller")) {
+ priv->feat.dev = dev;
+ priv->feat.check = hostfile_feat_check;
- if (!dev->device_node)
- return -ENODEV;
+ err = feature_controller_register(&priv->feat);
+ if (err)
+ return err;
- of_property_read_u32(dev->device_node, "barebox,fd", &priv->fd);
+ is_featctrl = true;
+ }
- err = of_property_read_string(dev->device_node, "barebox,filename",
- &priv->filename);
+
+ err = of_property_read_u64_array(np, "reg", reg, ARRAY_SIZE(reg));
if (err)
return err;
- if (!priv->fd)
- priv->fd = linux_open(priv->filename, true);
+ of_property_read_u32(np, "barebox,fd", &priv->fd);
+
+ err = of_property_read_string(np, "barebox,filename",
+ &priv->filename);
+ if (err)
+ return err;
- priv->cdev.name = dev->device_node->name;
- priv->cdev.dev = dev;
- priv->cdev.ops = &hf_fops;
- priv->cdev.priv = priv;
+ if (priv->fd < 0)
+ return is_featctrl ? 0 : priv->fd;
dev->info = hf_info;
- dev->priv = priv;
- err = devfs_create(&priv->cdev);
- if (err)
- return err;
+ is_blockdev = of_property_read_bool(np, "barebox,blockdev");
- of_parse_partitions(&priv->cdev, dev->device_node);
- of_partitions_register_fixup(&priv->cdev);
+ cdev = is_blockdev ? &priv->blk.cdev : &priv->cdev;
- return 0;
+ cdev_set_of_node(cdev, np);
+
+ if (is_blockdev) {
+ cdev->name = np->name;
+ priv->blk.dev = dev;
+ priv->blk.ops = &hf_blk_ops;
+ priv->blk.blockbits = SECTOR_SHIFT;
+ priv->blk.num_blocks = reg[1] / SECTOR_SIZE;
+ priv->blk.type = BLK_TYPE_VIRTUAL;
+
+ err = blockdevice_register(&priv->blk);
+ if (err)
+ return err;
+
+ dev_info(dev, "registered as block device\n");
+ } else {
+ cdev->name = np->name;
+ cdev->dev = dev;
+ cdev->ops = &hf_cdev_ops;
+ cdev->size = reg[1];
+ cdev->priv = priv;
+
+ err = devfs_create(cdev);
+ if (err)
+ return err;
+
+ dev_info(dev, "registered as character device\n");
+ }
+
+ of_parse_partitions(cdev, np);
+ of_partitions_register_fixup(cdev);
+
+ return of_platform_populate(np, NULL, dev);
}
static __maybe_unused struct of_device_id hostfile_dt_ids[] = {
@@ -119,45 +195,111 @@ static __maybe_unused struct of_device_id hostfile_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, hostfile_dt_ids);
-static struct driver_d hf_drv = {
+static struct driver hf_drv = {
.name = "hostfile",
.of_compatible = DRV_OF_COMPAT(hostfile_dt_ids),
.probe = hf_probe,
};
-coredevice_platform_driver(hf_drv);
+device_platform_driver(hf_drv);
static int of_hostfile_fixup(struct device_node *root, void *ctx)
{
struct hf_info *hf = ctx;
struct device_node *node;
- uint32_t reg[] = {
- hf->base >> 32,
- hf->base,
- hf->size
- };
+ bool name_only = false;
int ret;
- node = of_new_node(root, hf->devname);
+ node = of_get_child_by_name(root, hf->devname);
+ if (node)
+ name_only = true;
+ else
+ node = of_new_node(root, hf->devname);
- ret = of_property_write_string(node, "compatible", hostfile_dt_ids->compatible);
+ ret = of_property_write_string(node, "barebox,filename", hf->filename);
if (ret)
return ret;
- ret = of_property_write_u32_array(node, "reg", reg, ARRAY_SIZE(reg));
+ if (name_only)
+ return 0;
+
+ ret = of_property_write_string(node, "compatible", hostfile_dt_ids->compatible);
if (ret)
return ret;
- ret = of_property_write_u32(node, "barebox,fd", hf->fd);
+ ret = of_property_write_bool(node, "barebox,blockdev", hf->is_blockdev);
if (ret)
return ret;
- ret = of_property_write_string(node, "barebox,filename", hf->filename);
+ ret = of_property_write_bool(node, "barebox,cdev", hf->is_cdev);
+ if (ret)
+ return ret;
- return ret;
+ return of_property_write_bool(node, "barebox,read-only", hf->is_readonly);
}
int barebox_register_filedev(struct hf_info *hf)
{
return of_register_fixup(of_hostfile_fixup, hf);
}
+
+static int of_hostfile_map_fixup(struct device_node *root, void *ctx)
+{
+ struct device_node *node;
+ int ret;
+
+ for_each_compatible_node_from(node, root, NULL, "barebox,stickypage") {
+ char *filename;
+
+ filename = linux_get_stickypage_path();
+ if (!filename) {
+ pr_err("error allocating stickypage\n");
+ continue;
+ }
+
+ of_property_write_string(node, "barebox,filename", filename);
+ of_property_write_string(node, "compatible", "barebox,hostfile");
+ }
+
+ for_each_compatible_node_from(node, root, NULL, "barebox,hostfile") {
+ struct hf_info hf = {};
+ uint64_t reg[2] = {};
+
+ hf.devname = node->name;
+
+ ret = of_property_read_string(node, "barebox,filename", &hf.filename);
+ if (ret) {
+ pr_err("skipping nameless hostfile %s\n", hf.devname);
+ continue;
+ }
+
+ hf.is_blockdev = of_property_read_bool(node, "barebox,blockdev");
+ hf.is_cdev = of_property_read_bool(node, "barebox,cdev");
+ hf.is_readonly = of_property_read_bool(node, "barebox,read-only");
+
+ of_property_read_u64_array(node, "reg", reg, ARRAY_SIZE(reg));
+
+ hf.base = reg[0];
+ hf.size = reg[1];
+
+ ret = linux_open_hostfile(&hf);
+ if (ret)
+ continue;
+
+ reg[0] = hf.base;
+ reg[1] = hf.size;
+
+ of_property_write_u64_array(node, "reg", reg, ARRAY_SIZE(reg));
+ of_property_write_bool(node, "barebox,blockdev", hf.is_blockdev);
+ of_property_write_u32(node, "barebox,fd", hf.fd);
+ }
+
+ return 0;
+}
+
+static int barebox_fixup_filedevs(void)
+{
+ return of_register_fixup(of_hostfile_map_fixup, NULL);
+}
+pure_initcall(barebox_fixup_filedevs);
diff --git a/arch/sandbox/board/led.c b/arch/sandbox/board/led.c
new file mode 100644
index 0000000000..ced7e82f99
--- /dev/null
+++ b/arch/sandbox/board/led.c
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <common.h>
+#include <init.h>
+#include <led.h>
+#include <mach/linux.h>
+#include <of.h>
+
+static struct sandbox_led {
+ struct led led;
+ bool active;
+} sandbox_led;
+
+static inline void terminal_puts(const char *s)
+{
+ linux_write(1, s, strlen(s));
+}
+
+static void sandbox_led_set(struct led *led, unsigned int brightness)
+{
+ terminal_puts("\x1b]2;barebox ");
+ while (brightness--)
+ terminal_puts(".");
+ terminal_puts("\a");
+
+ sandbox_led.active = true;
+}
+
+static int sandbox_led_of_probe(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ if (sandbox_led.led.set)
+ return -EBUSY;
+
+ sandbox_led.led.name = xstrdup(np->name);
+ sandbox_led.led.max_value = 5;
+ sandbox_led.led.set = sandbox_led_set;
+
+ ret = led_register(&sandbox_led.led);
+ if (ret)
+ return ret;
+
+ led_of_parse_trigger(&sandbox_led.led, np);
+
+ return 0;
+}
+
+static void sandbox_led_of_remove(struct device *dev)
+{
+ if (sandbox_led.active)
+ sandbox_led_set(NULL, 0);
+}
+
+static struct of_device_id sandbox_led_of_ids[] = {
+ { .compatible = "barebox,sandbox-led", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sandbox_led_of_ids);
+
+static struct driver sandbox_led_of_driver = {
+ .name = "sandbox-led",
+ .probe = sandbox_led_of_probe,
+ .remove = sandbox_led_of_remove,
+ .of_compatible = sandbox_led_of_ids,
+};
+device_platform_driver(sandbox_led_of_driver);
diff --git a/arch/sandbox/board/power.c b/arch/sandbox/board/power.c
new file mode 100644
index 0000000000..8300c589c7
--- /dev/null
+++ b/arch/sandbox/board/power.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <driver.h>
+#include <poweroff.h>
+#include <restart.h>
+#include <mach/linux.h>
+#include <asm/reset_source.h>
+#include <linux/nvmem-consumer.h>
+
+struct sandbox_power {
+ struct restart_handler rst_hang, rst_reexec;
+ struct poweroff_handler poweroff;
+ struct nvmem_cell *reset_source_cell;
+};
+
+static void sandbox_poweroff(struct poweroff_handler *poweroff)
+{
+ struct sandbox_power *power = container_of(poweroff, struct sandbox_power, poweroff);
+
+ sandbox_save_reset_source(power->reset_source_cell, RESET_POR);
+
+ linux_exit();
+}
+
+static void sandbox_rst_hang(struct restart_handler *rst)
+{
+ linux_hang();
+}
+
+static void sandbox_rst_reexec(struct restart_handler *rst)
+{
+ struct sandbox_power *power = container_of(rst, struct sandbox_power, rst_reexec);
+
+ sandbox_save_reset_source(power->reset_source_cell, RESET_RST);
+
+ linux_reexec();
+}
+
+static int sandbox_power_probe(struct device *dev)
+{
+ struct sandbox_power *power = xzalloc(sizeof(*power));
+ size_t len;
+ u8 *rst;
+
+ power->poweroff = (struct poweroff_handler) {
+ .name = "exit",
+ .poweroff = sandbox_poweroff
+ };
+
+ poweroff_handler_register(&power->poweroff);
+
+ power->rst_hang = (struct restart_handler) {
+ .name = "hang",
+ .restart = sandbox_rst_hang
+ };
+
+ power->rst_reexec = (struct restart_handler) {
+ .name = "reexec", .priority = 200,
+ .restart = sandbox_rst_reexec,
+ };
+
+ restart_handler_register(&power->rst_hang);
+
+ if (IS_ENABLED(CONFIG_SANDBOX_REEXEC))
+ restart_handler_register(&power->rst_reexec);
+
+ power->reset_source_cell = of_nvmem_cell_get(dev->of_node,
+ "reset-source");
+ if (IS_ERR(power->reset_source_cell)) {
+ if (PTR_ERR(power->reset_source_cell) != -EPROBE_DEFER)
+ dev_warn(dev, "No reset source info available: %pe\n",
+ power->reset_source_cell);
+ power->reset_source_cell = NULL;
+ 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);
+
+ free(rst);
+ }
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id sandbox_power_dt_ids[] = {
+ { .compatible = "barebox,sandbox-power" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sandbox_power_dt_ids);
+
+static struct driver sandbox_power_drv = {
+ .name = "sandbox-power",
+ .of_compatible = sandbox_power_dt_ids,
+ .probe = sandbox_power_probe,
+};
+coredevice_platform_driver(sandbox_power_drv);
diff --git a/arch/sandbox/board/poweroff.c b/arch/sandbox/board/poweroff.c
deleted file mode 100644
index 6b5a6dff15..0000000000
--- a/arch/sandbox/board/poweroff.c
+++ /dev/null
@@ -1,17 +0,0 @@
-#include <common.h>
-#include <init.h>
-#include <poweroff.h>
-#include <mach/linux.h>
-
-static void sandbox_poweroff(struct poweroff_handler *poweroff)
-{
- linux_exit();
-}
-
-static int poweroff_register_feature(void)
-{
- poweroff_handler_register_fn(sandbox_poweroff);
-
- return 0;
-}
-coredevice_initcall(poweroff_register_feature);
diff --git a/arch/sandbox/board/stickypage.S b/arch/sandbox/board/stickypage.S
new file mode 100644
index 0000000000..1d3861c373
--- /dev/null
+++ b/arch/sandbox/board/stickypage.S
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+.section .note.GNU-stack,"",%progbits
+.section .rodata.stickypage,"a"
+
+.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
new file mode 100644
index 0000000000..074c96a8a9
--- /dev/null
+++ b/arch/sandbox/board/watchdog.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <errno.h>
+#include <driver.h>
+#include <mach/linux.h>
+#include <of.h>
+#include <watchdog.h>
+#include <linux/nvmem-consumer.h>
+#include <asm/reset_source.h>
+
+struct sandbox_watchdog {
+ struct watchdog wdd;
+ bool cant_disable :1;
+ struct nvmem_cell *reset_source_cell;
+};
+
+static inline struct sandbox_watchdog *to_sandbox_watchdog(struct watchdog *wdd)
+{
+ return container_of(wdd, struct sandbox_watchdog, wdd);
+}
+
+static int sandbox_watchdog_set_timeout(struct watchdog *wdd, unsigned int timeout)
+{
+ struct sandbox_watchdog *wd = to_sandbox_watchdog(wdd);
+
+ if (!timeout && wd->cant_disable)
+ return -ENOSYS;
+
+ if (timeout > wdd->timeout_max)
+ return -EINVAL;
+
+ sandbox_save_reset_source(wd->reset_source_cell, RESET_WDG);
+
+ linux_watchdog_set_timeout(timeout);
+ return 0;
+}
+
+static int sandbox_watchdog_probe(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct sandbox_watchdog *wd;
+ struct watchdog *wdd;
+
+ wd = xzalloc(sizeof(*wd));
+
+ wdd = &wd->wdd;
+ wdd->hwdev = dev;
+ wdd->set_timeout = sandbox_watchdog_set_timeout;
+ wdd->timeout_max = 1000;
+
+ wd->reset_source_cell = of_nvmem_cell_get(np, "reset-source");
+ if (IS_ERR(wd->reset_source_cell)) {
+ if (PTR_ERR(wd->reset_source_cell) != -EPROBE_DEFER)
+ dev_warn(dev, "No reset source info available: %pe\n",
+ wd->reset_source_cell);
+ wd->reset_source_cell = NULL;
+ }
+
+ wd->cant_disable = of_property_read_bool(np, "barebox,cant-disable");
+
+ return watchdog_register(wdd);
+}
+
+
+static __maybe_unused struct of_device_id sandbox_watchdog_dt_ids[] = {
+ { .compatible = "barebox,sandbox-watchdog" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sandbox_watchdog_dt_ids);
+
+static struct driver sandbox_watchdog_drv = {
+ .name = "sandbox-watchdog",
+ .of_compatible = sandbox_watchdog_dt_ids,
+ .probe = sandbox_watchdog_probe,
+};
+device_platform_driver(sandbox_watchdog_drv);