All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nandor Han <nandor.han@vaisala.com>
To: u-boot@lists.denx.de, trini@konsulko.com, sjg@chromium.org
Cc: Nandor Han <nandor.han@vaisala.com>, vesa.jaaskelainen@vaisala.com
Subject: [PATCH v4 2/3] reboot-mode: read the boot mode from GPIOs status
Date: Thu, 10 Jun 2021 16:56:44 +0300	[thread overview]
Message-ID: <4e6d9194f7cdeaab9280d385d57bd39f2dae7534.1623332762.git.nandor.han@vaisala.com> (raw)
In-Reply-To: <cover.1623332762.git.nandor.han@vaisala.com>

A use case for controlling the boot mode is when the user wants
to control the device boot by pushing a button without needing to
go in user-space.

Add a new backed for reboot mode where GPIOs are used to control the
reboot-mode. The driver is able to scan a predefined list of GPIOs
and return the magic value. Having the modes associated with
the magic value generated based on the GPIO values, allows the
reboot mode uclass to select the proper mode.

Signed-off-by: Nandor Han <nandor.han@vaisala.com>
---
 arch/sandbox/dts/test.dts                     |   8 ++
 configs/sandbox_defconfig                     |   2 +
 .../reboot-mode/reboot-mode-gpio.txt          |  20 +++
 drivers/reboot-mode/Kconfig                   |   9 ++
 drivers/reboot-mode/Makefile                  |   1 +
 drivers/reboot-mode/reboot-mode-gpio.c        | 128 ++++++++++++++++++
 include/reboot-mode/reboot-mode-gpio.h        |  32 +++++
 test/dm/Makefile                              |   1 +
 test/dm/reboot-mode.c                         |  42 ++++++
 9 files changed, 243 insertions(+)
 create mode 100644 doc/device-tree-bindings/reboot-mode/reboot-mode-gpio.txt
 create mode 100644 drivers/reboot-mode/reboot-mode-gpio.c
 create mode 100644 include/reboot-mode/reboot-mode-gpio.h
 create mode 100644 test/dm/reboot-mode.c

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 5ca3bc502a..bd261818af 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 bdbf714e2b..fed187e2a0 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -287,3 +287,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 c9644617a1..0ebc373124 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);
-- 
2.26.3


  parent reply	other threads:[~2021-06-10 13:57 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-10 13:56 [PATCH v4 0/3] Add reboot mode support Nandor Han
2021-06-10 13:56 ` [PATCH v4 1/3] reboot-mode: add support for reboot mode control Nandor Han
2021-06-26 18:30   ` Simon Glass
2021-07-23 18:52   ` Tom Rini
2021-06-10 13:56 ` Nandor Han [this message]
2021-06-26 18:30   ` [PATCH v4 2/3] reboot-mode: read the boot mode from GPIOs status Simon Glass
2021-07-23 18:52   ` Tom Rini
2021-06-10 13:56 ` [PATCH v4 3/3] reboot-mode: read the boot mode from RTC memory Nandor Han
2021-06-26 18:30   ` Simon Glass
2021-06-28  9:44     ` Nandor Han
2021-07-05 15:29       ` Simon Glass
2021-07-14  9:55         ` Nandor Han
2021-07-23 18:52   ` Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4e6d9194f7cdeaab9280d385d57bd39f2dae7534.1623332762.git.nandor.han@vaisala.com \
    --to=nandor.han@vaisala.com \
    --cc=sjg@chromium.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=vesa.jaaskelainen@vaisala.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.