diff options
author | Nandor Han <nandor.han@vaisala.com> | 2021-06-10 16:56:43 +0300 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2021-07-23 17:16:39 +0300 |
commit | 2541ce2c1af87f74a9feb35a1cbfc20ff8d04e4b (patch) | |
tree | 916abd832f987163a13630c9442fc3857f9aeb8f /drivers | |
parent | f534d93cbf34f1d1762b04eb5680e84bef5e1fe1 (diff) | |
download | u-boot-2541ce2c1af87f74a9feb35a1cbfc20ff8d04e4b.tar.xz |
reboot-mode: add support for reboot mode control
A new driver uclass is created to handle the reboot mode control.
The new uclass driver is updating an environment variable with the
configured reboot mode. The mode is extracted from a map provided
at initialization time. The map contains a list of modes
and associated ids.
Signed-off-by: Nandor Han <nandor.han@vaisala.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/reboot-mode/Kconfig | 18 | ||||
-rw-r--r-- | drivers/reboot-mode/Makefile | 7 | ||||
-rw-r--r-- | drivers/reboot-mode/reboot-mode-uclass.c | 134 |
5 files changed, 162 insertions, 0 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index c9c812b752..417d6f88c2 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -92,6 +92,8 @@ source "drivers/qe/Kconfig" source "drivers/ram/Kconfig" +source "drivers/reboot-mode/Kconfig" + source "drivers/remoteproc/Kconfig" source "drivers/reset/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 4081289104..82d3c98e06 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -95,6 +95,7 @@ obj-y += dfu/ obj-$(CONFIG_PCH) += pch/ obj-y += phy/allwinner/ obj-y += phy/marvell/ +obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode/ obj-y += phy/rockchip/ obj-y += phy/socionext/ obj-y += rtc/ diff --git a/drivers/reboot-mode/Kconfig b/drivers/reboot-mode/Kconfig new file mode 100644 index 0000000000..0edc3209d7 --- /dev/null +++ b/drivers/reboot-mode/Kconfig @@ -0,0 +1,18 @@ +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c), Vaisala Oyj +# + +menu "Reboot Mode Support" + +config DM_REBOOT_MODE + bool "Enable reboot mode using Driver Model" + depends on DM + default n + help + Enable support for reboot mode control. This will allow users to + adjust the boot process based on reboot mode parameter + passed to U-Boot. + +endmenu diff --git a/drivers/reboot-mode/Makefile b/drivers/reboot-mode/Makefile new file mode 100644 index 0000000000..2ab0fddac9 --- /dev/null +++ b/drivers/reboot-mode/Makefile @@ -0,0 +1,7 @@ +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c), Vaisala Oyj +# + +obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode-uclass.o diff --git a/drivers/reboot-mode/reboot-mode-uclass.c b/drivers/reboot-mode/reboot-mode-uclass.c new file mode 100644 index 0000000000..bb7a355fbf --- /dev/null +++ b/drivers/reboot-mode/reboot-mode-uclass.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c), Vaisala Oyj + */ + +#include <common.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <exports.h> +#include <reboot-mode/reboot-mode.h> + +DECLARE_GLOBAL_DATA_PTR; + +int dm_reboot_mode_update(struct udevice *dev) +{ + struct reboot_mode_ops *ops = reboot_mode_get_ops(dev); + u32 rebootmode; + int ret, i; + + assert(ops); + + if (!ops->get) + return -ENOSYS; + + ret = ops->get(dev, &rebootmode); + if (ret < 0) { + dev_err(dev, "Failed to retrieve the reboot mode value\n"); + return ret; + } + + const struct reboot_mode_uclass_platdata *plat_data = + dev_get_uclass_plat(dev); + + for (i = 0; i < plat_data->count; i++) { + if (plat_data->modes[i].mode_id == rebootmode) { + ret = env_set(plat_data->env_variable, + plat_data->modes[i].mode_name); + if (ret) { + dev_err(dev, "Failed to set env: %s\n", + plat_data->env_variable); + return ret; + } + } + } + + if (ops->set) { + /* Clear the value */ + rebootmode = 0; + ret = ops->set(dev, rebootmode); + if (ret) { + dev_err(dev, "Failed to clear the reboot mode\n"); + return ret; + } + } + + return 0; +} + +int dm_reboot_mode_pre_probe(struct udevice *dev) +{ + struct reboot_mode_uclass_platdata *plat_data; + + plat_data = dev_get_uclass_plat(dev); + if (!plat_data) + return -EINVAL; + +#if CONFIG_IS_ENABLED(OF_CONTROL) + const int node = dev_of_offset(dev); + const char *mode_prefix = "mode-"; + const int mode_prefix_len = strlen(mode_prefix); + int property; + const u32 *propvalue; + const char *propname; + + plat_data->env_variable = fdt_getprop(gd->fdt_blob, + node, + "u-boot,env-variable", + NULL); + if (!plat_data->env_variable) + plat_data->env_variable = "reboot-mode"; + + plat_data->count = 0; + + fdt_for_each_property_offset(property, gd->fdt_blob, node) { + propvalue = fdt_getprop_by_offset(gd->fdt_blob, + property, &propname, NULL); + if (!propvalue) { + dev_err(dev, "Could not get the value for property %s\n", + propname); + return -EINVAL; + } + + if (!strncmp(propname, mode_prefix, mode_prefix_len)) + plat_data->count++; + } + + plat_data->modes = devm_kcalloc(dev, plat_data->count, + sizeof(struct reboot_mode_mode), 0); + + struct reboot_mode_mode *next = plat_data->modes; + + fdt_for_each_property_offset(property, gd->fdt_blob, node) { + propvalue = fdt_getprop_by_offset(gd->fdt_blob, + property, &propname, NULL); + if (!propvalue) { + dev_err(dev, "Could not get the value for property %s\n", + propname); + return -EINVAL; + } + + if (!strncmp(propname, mode_prefix, mode_prefix_len)) { + next->mode_name = &propname[mode_prefix_len]; + next->mode_id = fdt32_to_cpu(*propvalue); + + next++; + } + } +#else + if (!plat_data->env_variable) + plat_data->env_variable = "reboot-mode"; + +#endif + + return 0; +} + +UCLASS_DRIVER(reboot_mode) = { + .name = "reboot-mode", + .id = UCLASS_REBOOT_MODE, + .pre_probe = dm_reboot_mode_pre_probe, + .per_device_plat_auto = + sizeof(struct reboot_mode_uclass_platdata), +}; |