Merge tag 'tpm-030822' of https://source.denx.de/u-boot/custodians/u-boot-tpm
[platform/kernel/u-boot.git] / drivers / reboot-mode / reboot-mode-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c), Vaisala Oyj
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <dm/device_compat.h>
9 #include <dm/devres.h>
10 #include <exports.h>
11 #include <reboot-mode/reboot-mode.h>
12
13 int dm_reboot_mode_update(struct udevice *dev)
14 {
15         struct reboot_mode_ops *ops = reboot_mode_get_ops(dev);
16         u32 rebootmode;
17         int ret, i;
18
19         assert(ops);
20
21         if (!ops->get)
22                 return -ENOSYS;
23
24         ret = ops->get(dev, &rebootmode);
25         if (ret < 0) {
26                 dev_err(dev, "Failed to retrieve the reboot mode value\n");
27                 return ret;
28         }
29
30         const struct reboot_mode_uclass_platdata *plat_data =
31                 dev_get_uclass_plat(dev);
32
33         for (i = 0; i < plat_data->count; i++) {
34                 if (plat_data->modes[i].mode_id == rebootmode) {
35                         ret = env_set(plat_data->env_variable,
36                                       plat_data->modes[i].mode_name);
37                         if (ret) {
38                                 dev_err(dev, "Failed to set env: %s\n",
39                                         plat_data->env_variable);
40                                 return ret;
41                         }
42                 }
43         }
44
45         if (ops->set) {
46                 /* Clear the value */
47                 rebootmode = 0;
48                 ret = ops->set(dev, rebootmode);
49                 if (ret) {
50                         dev_err(dev, "Failed to clear the reboot mode\n");
51                         return ret;
52                 }
53         }
54
55         return 0;
56 }
57
58 int dm_reboot_mode_pre_probe(struct udevice *dev)
59 {
60         struct reboot_mode_uclass_platdata *plat_data;
61
62         plat_data = dev_get_uclass_plat(dev);
63         if (!plat_data)
64                 return -EINVAL;
65
66 #if CONFIG_IS_ENABLED(OF_CONTROL)
67         const char *mode_prefix = "mode-";
68         const int mode_prefix_len = strlen(mode_prefix);
69         struct ofprop property;
70         const u32 *propvalue;
71         const char *propname;
72
73         plat_data->env_variable = dev_read_string(dev, "u-boot,env-variable");
74         if (!plat_data->env_variable)
75                 plat_data->env_variable = "reboot-mode";
76
77         plat_data->count = 0;
78
79         dev_for_each_property(property, dev) {
80                 propvalue = dev_read_prop_by_prop(&property, &propname, NULL);
81                 if (!propvalue) {
82                         dev_err(dev, "Could not get the value for property %s\n",
83                                 propname);
84                         return -EINVAL;
85                 }
86
87                 if (!strncmp(propname, mode_prefix, mode_prefix_len))
88                         plat_data->count++;
89         }
90
91         plat_data->modes = devm_kcalloc(dev, plat_data->count,
92                                         sizeof(struct reboot_mode_mode), 0);
93
94         struct reboot_mode_mode *next = plat_data->modes;
95
96         dev_for_each_property(property, dev) {
97                 propvalue = dev_read_prop_by_prop(&property, &propname, NULL);
98                 if (!propvalue) {
99                         dev_err(dev, "Could not get the value for property %s\n",
100                                 propname);
101                         return -EINVAL;
102                 }
103
104                 if (!strncmp(propname, mode_prefix, mode_prefix_len)) {
105                         next->mode_name = &propname[mode_prefix_len];
106                         next->mode_id = fdt32_to_cpu(*propvalue);
107
108                         next++;
109                 }
110         }
111 #else
112         if (!plat_data->env_variable)
113                 plat_data->env_variable = "reboot-mode";
114
115 #endif
116
117         return 0;
118 }
119
120 UCLASS_DRIVER(reboot_mode) = {
121         .name   = "reboot-mode",
122         .id     = UCLASS_REBOOT_MODE,
123         .pre_probe      = dm_reboot_mode_pre_probe,
124         .per_device_plat_auto =
125                 sizeof(struct reboot_mode_uclass_platdata),
126 };