The reboot-mode framework so far only reads a value from a backing store
on boot (get/set) and maps it to an environment variable. Triggering a
reset into a specific mode on demand - e.g. rebooting a Qualcomm SoC into
EDL via a PSCI SYSTEM_RESET2 vendor reset - needs a different approach.
Add an trigger() op to struct reboot_mode_ops. It takes the
decoded magic cells for a mode and resets the system immediately; on
success it does not return. Backing-store drivers (nvmem, gpio, rtc)
leave it NULL and are unaffected.
Add two uclass helpers built on top of it:
- reboot_mode_request(name) looks up a mode by name across all
UCLASS_REBOOT_MODE devices and, if the owning device can trigger,
resets into it. Returns -ENOENT if no triggerable mode matches.
- reboot_mode_list() enumerates every triggerable mode registered with
the framework, so a command can present the available modes to the
user rather than hard-coding them.
Signed-off-by: Balaji Selvanathan <[email protected]>
---
drivers/reboot-mode/reboot-mode-uclass.c | 48 ++++++++++++++++++++++++++++++++
include/reboot-mode/reboot-mode.h | 40 ++++++++++++++++++++++++++
2 files changed, 88 insertions(+)
diff --git a/drivers/reboot-mode/reboot-mode-uclass.c
b/drivers/reboot-mode/reboot-mode-uclass.c
index 80aabf54750..866a56ecb7b 100644
--- a/drivers/reboot-mode/reboot-mode-uclass.c
+++ b/drivers/reboot-mode/reboot-mode-uclass.c
@@ -54,6 +54,54 @@ int dm_reboot_mode_update(struct udevice *dev)
return 0;
}
+int reboot_mode_request(const char *name)
+{
+ const struct reboot_mode_uclass_platdata *plat_data;
+ struct reboot_mode_ops *ops;
+ struct udevice *dev;
+ int i;
+
+ uclass_foreach_dev_probe(UCLASS_REBOOT_MODE, dev) {
+ ops = reboot_mode_get_ops(dev);
+ if (!ops || !ops->trigger)
+ continue;
+
+ plat_data = dev_get_uclass_plat(dev);
+ for (i = 0; i < plat_data->count; i++) {
+ if (strcmp(plat_data->modes[i].mode_name, name))
+ continue;
+
+ /* Does not return on success. */
+ return ops->trigger(dev, plat_data->modes[i].magic,
+ plat_data->modes[i].count);
+ }
+ }
+
+ return -ENOENT;
+}
+
+int reboot_mode_list(void)
+{
+ const struct reboot_mode_uclass_platdata *plat_data;
+ struct reboot_mode_ops *ops;
+ struct udevice *dev;
+ int i;
+
+ printf("Available reset modes:\n");
+
+ uclass_foreach_dev_probe(UCLASS_REBOOT_MODE, dev) {
+ ops = reboot_mode_get_ops(dev);
+ if (!ops || !ops->trigger)
+ continue;
+
+ plat_data = dev_get_uclass_plat(dev);
+ for (i = 0; i < plat_data->count; i++)
+ printf(" %s\n", plat_data->modes[i].mode_name);
+ }
+
+ return 0;
+}
+
int dm_reboot_mode_pre_probe(struct udevice *dev)
{
struct reboot_mode_uclass_platdata *plat_data;
diff --git a/include/reboot-mode/reboot-mode.h
b/include/reboot-mode/reboot-mode.h
index 54a8c09650e..67be5e4b3eb 100644
--- a/include/reboot-mode/reboot-mode.h
+++ b/include/reboot-mode/reboot-mode.h
@@ -46,6 +46,22 @@ struct reboot_mode_ops {
* @rebootmode: New reboot mode value to store
*/
int (*set)(struct udevice *dev, u32 rebootmode);
+
+ /**
+ * trigger() - reset the system into the given mode now
+ *
+ * Unlike get()/set(), which persist a value for the next boot to
+ * consume, trigger() performs the reset immediately. On success it
+ * does not return. Drivers with a backing store (nvmem, gpio, rtc)
+ * leave this NULL.
+ *
+ * @dev: Device to trigger
+ * @magic: Array of @count 32-bit magic cells describing the mode
+ * @count: Number of valid cells in @magic (1 to
+ * REBOOT_MODE_MAX_MAGIC)
+ * Return: does not return on success; -ve on error
+ */
+ int (*trigger)(struct udevice *dev, const u32 *magic, int count);
};
/* Access the operations for a reboot mode device */
@@ -59,4 +75,28 @@ struct reboot_mode_ops {
*/
int dm_reboot_mode_update(struct udevice *dev);
+/**
+ * reboot_mode_request() - reset the system into a named mode
+ *
+ * Search every UCLASS_REBOOT_MODE device for a mode named @name and, if the
+ * owning device supports triggering, reset into it. On success this does not
+ * return.
+ *
+ * @name: Mode name (without the device tree "mode-" prefix)
+ * Return: does not return on success; -ENOENT if no device declares a
+ * triggerable mode called @name; other -ve on error
+ */
+int reboot_mode_request(const char *name);
+
+/**
+ * reboot_mode_list() - print all triggerable reboot modes
+ *
+ * Enumerate every UCLASS_REBOOT_MODE device and print the name of each mode
+ * that can be triggered (i.e. whose device implements the trigger op). Modes
+ * that only exist to be read from a backing store on boot are not listed.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int reboot_mode_list(void);
+
#endif /* REBOOT_MODE_REBOOT_MODE_H__ */
--
2.34.1