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