diff options
author | Geoff Levand <geoffrey.levand@am.sony.com> | 2007-10-06 17:35:47 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-10-09 07:01:59 -0400 |
commit | 7db19421a9b116a196845a1118729cf5988f1b57 (patch) | |
tree | a55e55e2506a1e21336d6b36d09652c774e4e206 | |
parent | d7b98e3dd87b4512462f6cdfe646a8e59673e62e (diff) |
[POWERPC] PS3: Save os-area params to device tree
Add the PS3 os-area startup params to the device tree. This allows
a second stage kernel loaded with kexec to use these values.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/platforms/ps3/os-area.c | 104 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/platform.h | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/setup.c | 1 |
3 files changed, 104 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 473aee8580ce..e50a276fcf67 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c | |||
@@ -119,10 +119,65 @@ struct os_area_params { | |||
119 | */ | 119 | */ |
120 | 120 | ||
121 | struct saved_params { | 121 | struct saved_params { |
122 | unsigned int valid; | ||
122 | s64 rtc_diff; | 123 | s64 rtc_diff; |
123 | unsigned int av_multi_out; | 124 | unsigned int av_multi_out; |
124 | } static saved_params; | 125 | } static saved_params; |
125 | 126 | ||
127 | static struct property property_rtc_diff = { | ||
128 | .name = "linux,rtc_diff", | ||
129 | .length = sizeof(saved_params.rtc_diff), | ||
130 | .value = &saved_params.rtc_diff, | ||
131 | }; | ||
132 | |||
133 | static struct property property_av_multi_out = { | ||
134 | .name = "linux,av_multi_out", | ||
135 | .length = sizeof(saved_params.av_multi_out), | ||
136 | .value = &saved_params.av_multi_out, | ||
137 | }; | ||
138 | |||
139 | /** | ||
140 | * os_area_set_property - Add or overwrite a saved_params value to the device tree. | ||
141 | * | ||
142 | * Overwrites an existing property. | ||
143 | */ | ||
144 | |||
145 | static void os_area_set_property(struct device_node *node, | ||
146 | struct property *prop) | ||
147 | { | ||
148 | int result; | ||
149 | struct property *tmp = of_find_property(node, prop->name, NULL); | ||
150 | |||
151 | if (tmp) { | ||
152 | pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name); | ||
153 | prom_remove_property(node, tmp); | ||
154 | } | ||
155 | |||
156 | result = prom_add_property(node, prop); | ||
157 | |||
158 | if (result) | ||
159 | pr_debug("%s:%d prom_set_property failed\n", __func__, | ||
160 | __LINE__); | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * os_area_get_property - Get a saved_params value from the device tree. | ||
165 | * | ||
166 | */ | ||
167 | |||
168 | static void __init os_area_get_property(struct device_node *node, | ||
169 | struct property *prop) | ||
170 | { | ||
171 | const struct property *tmp = of_find_property(node, prop->name, NULL); | ||
172 | |||
173 | if (tmp) { | ||
174 | BUG_ON(prop->length != tmp->length); | ||
175 | memcpy(prop->value, tmp->value, prop->length); | ||
176 | } else | ||
177 | pr_debug("%s:%d not found %s\n", __func__, __LINE__, | ||
178 | prop->name); | ||
179 | } | ||
180 | |||
126 | #define dump_header(_a) _dump_header(_a, __func__, __LINE__) | 181 | #define dump_header(_a) _dump_header(_a, __func__, __LINE__) |
127 | static void _dump_header(const struct os_area_header *h, const char *func, | 182 | static void _dump_header(const struct os_area_header *h, const char *func, |
128 | int line) | 183 | int line) |
@@ -196,8 +251,19 @@ static int __init verify_header(const struct os_area_header *header) | |||
196 | 251 | ||
197 | static void os_area_queue_work_handler(struct work_struct *work) | 252 | static void os_area_queue_work_handler(struct work_struct *work) |
198 | { | 253 | { |
254 | struct device_node *node; | ||
255 | |||
199 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | 256 | pr_debug(" -> %s:%d\n", __func__, __LINE__); |
200 | 257 | ||
258 | node = of_find_node_by_path("/"); | ||
259 | |||
260 | if (node) { | ||
261 | os_area_set_property(node, &property_rtc_diff); | ||
262 | of_node_put(node); | ||
263 | } else | ||
264 | pr_debug("%s:%d of_find_node_by_path failed\n", | ||
265 | __func__, __LINE__); | ||
266 | |||
201 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 267 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
202 | } | 268 | } |
203 | 269 | ||
@@ -244,6 +310,8 @@ void __init ps3_os_area_save_params(void) | |||
244 | result = verify_header(header); | 310 | result = verify_header(header); |
245 | 311 | ||
246 | if (result) { | 312 | if (result) { |
313 | /* Second stage kernels exit here. */ | ||
314 | |||
247 | pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); | 315 | pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); |
248 | dump_header(header); | 316 | dump_header(header); |
249 | return; | 317 | return; |
@@ -254,6 +322,7 @@ void __init ps3_os_area_save_params(void) | |||
254 | 322 | ||
255 | saved_params.rtc_diff = params->rtc_diff; | 323 | saved_params.rtc_diff = params->rtc_diff; |
256 | saved_params.av_multi_out = params->av_multi_out; | 324 | saved_params.av_multi_out = params->av_multi_out; |
325 | saved_params.valid = 1; | ||
257 | 326 | ||
258 | memset(header, 0, sizeof(*header)); | 327 | memset(header, 0, sizeof(*header)); |
259 | 328 | ||
@@ -261,13 +330,44 @@ void __init ps3_os_area_save_params(void) | |||
261 | } | 330 | } |
262 | 331 | ||
263 | /** | 332 | /** |
333 | * ps3_os_area_init - Setup os area device tree properties as needed. | ||
334 | */ | ||
335 | |||
336 | void __init ps3_os_area_init(void) | ||
337 | { | ||
338 | struct device_node *node; | ||
339 | |||
340 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
341 | |||
342 | node = of_find_node_by_path("/"); | ||
343 | |||
344 | if (!saved_params.valid && node) { | ||
345 | /* Second stage kernels should have a dt entry. */ | ||
346 | os_area_get_property(node, &property_rtc_diff); | ||
347 | os_area_get_property(node, &property_av_multi_out); | ||
348 | } | ||
349 | |||
350 | if(!saved_params.rtc_diff) | ||
351 | saved_params.rtc_diff = SECONDS_FROM_1970_TO_2000; | ||
352 | |||
353 | if (node) { | ||
354 | os_area_set_property(node, &property_rtc_diff); | ||
355 | os_area_set_property(node, &property_av_multi_out); | ||
356 | of_node_put(node); | ||
357 | } else | ||
358 | pr_debug("%s:%d of_find_node_by_path failed\n", | ||
359 | __func__, __LINE__); | ||
360 | |||
361 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
362 | } | ||
363 | |||
364 | /** | ||
264 | * ps3_os_area_get_rtc_diff - Returns the rtc diff value. | 365 | * ps3_os_area_get_rtc_diff - Returns the rtc diff value. |
265 | */ | 366 | */ |
266 | 367 | ||
267 | u64 ps3_os_area_get_rtc_diff(void) | 368 | u64 ps3_os_area_get_rtc_diff(void) |
268 | { | 369 | { |
269 | return saved_params.rtc_diff ? saved_params.rtc_diff | 370 | return saved_params.rtc_diff; |
270 | : SECONDS_FROM_1970_TO_2000; | ||
271 | } | 371 | } |
272 | 372 | ||
273 | /** | 373 | /** |
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 6b4f4dd2d15a..01f0c9506e11 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h | |||
@@ -63,6 +63,7 @@ int ps3_set_rtc_time(struct rtc_time *time); | |||
63 | /* os area */ | 63 | /* os area */ |
64 | 64 | ||
65 | void __init ps3_os_area_save_params(void); | 65 | void __init ps3_os_area_save_params(void); |
66 | void __init ps3_os_area_init(void); | ||
66 | u64 ps3_os_area_get_rtc_diff(void); | 67 | u64 ps3_os_area_get_rtc_diff(void); |
67 | void ps3_os_area_set_rtc_diff(u64 rtc_diff); | 68 | void ps3_os_area_set_rtc_diff(u64 rtc_diff); |
68 | 69 | ||
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index f0d5ec51ef17..5c2cbb08eb52 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c | |||
@@ -206,6 +206,7 @@ static void __init ps3_setup_arch(void) | |||
206 | prealloc_ps3flash_bounce_buffer(); | 206 | prealloc_ps3flash_bounce_buffer(); |
207 | 207 | ||
208 | ppc_md.power_save = ps3_power_save; | 208 | ppc_md.power_save = ps3_power_save; |
209 | ps3_os_area_init(); | ||
209 | 210 | ||
210 | DBG(" <- %s:%d\n", __func__, __LINE__); | 211 | DBG(" <- %s:%d\n", __func__, __LINE__); |
211 | } | 212 | } |