summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sandbox/dts/test.dts8
-rw-r--r--configs/sandbox_defconfig2
-rw-r--r--doc/device-tree-bindings/reboot-mode/reboot-mode-gpio.txt20
-rw-r--r--drivers/reboot-mode/Kconfig9
-rw-r--r--drivers/reboot-mode/Makefile1
-rw-r--r--drivers/reboot-mode/reboot-mode-gpio.c128
-rw-r--r--include/reboot-mode/reboot-mode-gpio.h32
-rw-r--r--test/dm/Makefile1
-rw-r--r--test/dm/reboot-mode.c42
9 files changed, 243 insertions, 0 deletions
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 0cee15a0ea..2347f4cbe4 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -59,6 +59,14 @@
};
};
+ reboot-mode0 {
+ compatible = "reboot-mode-gpio";
+ gpios = <&gpio_c 0 GPIO_ACTIVE_HIGH>, <&gpio_c 1 GPIO_ACTIVE_HIGH>;
+ u-boot,env-variable = "bootstatus";
+ mode-test = <0x01>;
+ mode-download = <0x03>;
+ };
+
audio: audio-codec {
compatible = "sandbox,audio-codec";
#sound-dai-cells = <1>;
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 1655bb1e8a..6931b176ed 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -290,3 +290,5 @@ CONFIG_TEST_FDTDEC=y
CONFIG_UNIT_TEST=y
CONFIG_UT_TIME=y
CONFIG_UT_DM=y
+CONFIG_DM_REBOOT_MODE=y
+CONFIG_DM_REBOOT_MODE_GPIO=y
diff --git a/doc/device-tree-bindings/reboot-mode/reboot-mode-gpio.txt b/doc/device-tree-bindings/reboot-mode/reboot-mode-gpio.txt
new file mode 100644
index 0000000000..bb209d2742
--- /dev/null
+++ b/doc/device-tree-bindings/reboot-mode/reboot-mode-gpio.txt
@@ -0,0 +1,20 @@
+GPIO Reboot Mode Configuration
+
+Required Properties:
+- compatible: must be "reboot-mode-gpio".
+- gpios: list of gpios that are used to calculate the reboot-mode magic value.
+ Every gpio represents a bit in the magic value in the same order
+ as defined in device tree.
+- modes: list of properties that define the modes and associated unique ids.
+
+Optional Properties:
+- u-boot,env-variable: used to save the reboot mode (default: reboot-mode).
+
+Example:
+ reboot-mode {
+ compatible = "reboot-mode-gpio";
+ gpios = <&gpio1 2 GPIO_ACTIVE_LOW>, <&gpio2 6 GPIO_ACTIVE_HIGH>;
+ u-boot,env-variable = "bootstatus";
+ mode-test = <0x00000001>;
+ mode-download = <0x00000002>;
+ };
diff --git a/drivers/reboot-mode/Kconfig b/drivers/reboot-mode/Kconfig
index 0edc3209d7..ff65e2031a 100644
--- a/drivers/reboot-mode/Kconfig
+++ b/drivers/reboot-mode/Kconfig
@@ -15,4 +15,13 @@ config DM_REBOOT_MODE
adjust the boot process based on reboot mode parameter
passed to U-Boot.
+config DM_REBOOT_MODE_GPIO
+ bool "Use GPIOs as reboot mode backend"
+ depends on DM_REBOOT_MODE
+ default n
+ help
+ Use GPIOs to control the reboot mode. This will allow users to boot
+ a device in a specific mode by using a GPIO that can be controlled
+ outside U-Boot.
+
endmenu
diff --git a/drivers/reboot-mode/Makefile b/drivers/reboot-mode/Makefile
index 2ab0fddac9..04917be4f4 100644
--- a/drivers/reboot-mode/Makefile
+++ b/drivers/reboot-mode/Makefile
@@ -5,3 +5,4 @@
#
obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode-uclass.o
+obj-$(CONFIG_DM_REBOOT_MODE_GPIO) += reboot-mode-gpio.o
diff --git a/drivers/reboot-mode/reboot-mode-gpio.c b/drivers/reboot-mode/reboot-mode-gpio.c
new file mode 100644
index 0000000000..305174736e
--- /dev/null
+++ b/drivers/reboot-mode/reboot-mode-gpio.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c), Vaisala Oyj
+ */
+
+#include <common.h>
+#include <asm/gpio.h>
+#include <dm.h>
+#include <dm/devres.h>
+#include <errno.h>
+#include <reboot-mode/reboot-mode-gpio.h>
+#include <reboot-mode/reboot-mode.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int reboot_mode_get(struct udevice *dev, u32 *buf)
+{
+ int ret;
+ struct reboot_mode_gpio_platdata *plat_data;
+
+ if (!buf)
+ return -EINVAL;
+
+ plat_data = dev_get_plat(dev);
+ if (!plat_data)
+ return -EINVAL;
+
+ ret = dm_gpio_get_values_as_int(plat_data->gpio_desc,
+ plat_data->gpio_count);
+ if (ret < 0)
+ return ret;
+
+ *buf = ret;
+
+ return 0;
+}
+
+static int reboot_mode_probe(struct udevice *dev)
+{
+ struct reboot_mode_gpio_platdata *plat_data;
+
+ plat_data = dev_get_plat(dev);
+ if (!plat_data)
+ return -EINVAL;
+
+ int ret;
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ ret = gpio_get_list_count(dev, "gpios");
+ if (ret < 0)
+ return ret;
+
+ plat_data->gpio_count = ret;
+#endif
+
+ if (plat_data->gpio_count <= 0)
+ return -EINVAL;
+
+ plat_data->gpio_desc = devm_kcalloc(dev, plat_data->gpio_count,
+ sizeof(struct gpio_desc), 0);
+ if (!plat_data->gpio_desc)
+ return -ENOMEM;
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ ret = gpio_request_list_by_name(dev, "gpios", plat_data->gpio_desc,
+ plat_data->gpio_count, GPIOD_IS_IN);
+ if (ret < 0)
+ return ret;
+#else
+ for (int i = 0; i < plat_data->gpio_count; i++) {
+ struct reboot_mode_gpio_config *gpio =
+ plat_data->gpios_config + i;
+ struct gpio_desc *desc = plat_data->gpio_desc + i;
+
+ ret = uclass_get_device_by_seq(UCLASS_GPIO,
+ gpio->gpio_dev_offset,
+ &desc->dev);
+ if (ret < 0)
+ return ret;
+
+ desc->flags = gpio->flags;
+ desc->offset = gpio->gpio_offset;
+
+ ret = dm_gpio_request(desc, "");
+ if (ret < 0)
+ return ret;
+
+ ret = dm_gpio_set_dir(desc);
+ if (ret < 0)
+ return ret;
+ }
+#endif
+ return 0;
+}
+
+static int reboot_mode_remove(struct udevice *dev)
+{
+ struct reboot_mode_gpio_platdata *plat_data;
+
+ plat_data = dev_get_plat(dev);
+ if (!plat_data)
+ return -EINVAL;
+
+ return gpio_free_list(dev, plat_data->gpio_desc, plat_data->gpio_count);
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static const struct udevice_id reboot_mode_ids[] = {
+ { .compatible = "reboot-mode-gpio", 0 },
+ { }
+};
+#endif
+
+static const struct reboot_mode_ops reboot_mode_gpio_ops = {
+ .get = reboot_mode_get,
+};
+
+U_BOOT_DRIVER(reboot_mode_gpio) = {
+ .name = "reboot-mode-gpio",
+ .id = UCLASS_REBOOT_MODE,
+ .probe = reboot_mode_probe,
+ .remove = reboot_mode_remove,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ .of_match = reboot_mode_ids,
+#endif
+ .plat_auto = sizeof(struct reboot_mode_gpio_platdata),
+ .ops = &reboot_mode_gpio_ops,
+};
diff --git a/include/reboot-mode/reboot-mode-gpio.h b/include/reboot-mode/reboot-mode-gpio.h
new file mode 100644
index 0000000000..16b1185c69
--- /dev/null
+++ b/include/reboot-mode/reboot-mode-gpio.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) Vaisala Oyj.
+ */
+
+#ifndef REBOOT_MODE_REBOOT_MODE_GPIO_H_
+#define REBOOT_MODE_REBOOT_MODE_GPIO_H_
+
+#include <asm/gpio.h>
+
+/*
+ * In case of initializing the driver statically (using U_BOOT_DEVICE macro),
+ * we can use this struct to declare the pins used.
+ */
+
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
+struct reboot_mode_gpio_config {
+ int gpio_dev_offset;
+ int gpio_offset;
+ int flags;
+};
+#endif
+
+struct reboot_mode_gpio_platdata {
+ struct gpio_desc *gpio_desc;
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
+ struct reboot_mode_gpio_config *gpios_config;
+#endif
+ int gpio_count;
+};
+
+#endif /* REBOOT_MODE_REBOOT_MODE_GPIO_H_ */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 9ef9171a1c..d5c42e7643 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_AXI) += axi.o
obj-$(CONFIG_BLK) += blk.o
obj-$(CONFIG_BUTTON) += button.o
obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o
+obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode.o
obj-$(CONFIG_CLK) += clk.o clk_ccf.o
obj-$(CONFIG_CPU) += cpu.o
obj-$(CONFIG_CROS_EC) += cros_ec.o
diff --git a/test/dm/reboot-mode.c b/test/dm/reboot-mode.c
new file mode 100644
index 0000000000..66aa4793f7
--- /dev/null
+++ b/test/dm/reboot-mode.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) 2018 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <reboot-mode/reboot-mode.h>
+#include <env.h>
+#include <log.h>
+#include <asm/gpio.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+static int dm_test_reboot_mode_gpio(struct unit_test_state *uts)
+{
+ struct udevice *gpio_dev;
+ struct udevice *rm_dev;
+ int gpio0_offset = 0;
+ int gpio1_offset = 1;
+
+ uclass_get_device_by_name(UCLASS_GPIO, "pinmux-gpios", &gpio_dev);
+
+ /* Prepare the GPIOs for "download" mode */
+ sandbox_gpio_set_direction(gpio_dev, gpio0_offset, 0);
+ sandbox_gpio_set_direction(gpio_dev, gpio1_offset, 0);
+ sandbox_gpio_set_value(gpio_dev, gpio0_offset, 1);
+ sandbox_gpio_set_value(gpio_dev, gpio1_offset, 1);
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_REBOOT_MODE,
+ "reboot-mode0", &rm_dev));
+ ut_assertok(dm_reboot_mode_update(rm_dev));
+
+ ut_asserteq_str("download", env_get("bootstatus"));
+
+ return 0;
+}
+
+DM_TEST(dm_test_reboot_mode_gpio,
+ UT_TESTF_PROBE_TEST | UT_TESTF_SCAN_FDT | UT_TESTF_FLAT_TREE);