From 7db19421a9b116a196845a1118729cf5988f1b57 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sun, 7 Oct 2007 07:35:47 +1000 Subject: [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 Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/os-area.c | 104 +++++++++++++++++++++++++++++++++- arch/powerpc/platforms/ps3/platform.h | 1 + arch/powerpc/platforms/ps3/setup.c | 1 + 3 files changed, 104 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/platforms/ps3') diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 473aee8580c..e50a276fcf6 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 { */ struct saved_params { + unsigned int valid; s64 rtc_diff; unsigned int av_multi_out; } static saved_params; +static struct property property_rtc_diff = { + .name = "linux,rtc_diff", + .length = sizeof(saved_params.rtc_diff), + .value = &saved_params.rtc_diff, +}; + +static struct property property_av_multi_out = { + .name = "linux,av_multi_out", + .length = sizeof(saved_params.av_multi_out), + .value = &saved_params.av_multi_out, +}; + +/** + * os_area_set_property - Add or overwrite a saved_params value to the device tree. + * + * Overwrites an existing property. + */ + +static void os_area_set_property(struct device_node *node, + struct property *prop) +{ + int result; + struct property *tmp = of_find_property(node, prop->name, NULL); + + if (tmp) { + pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name); + prom_remove_property(node, tmp); + } + + result = prom_add_property(node, prop); + + if (result) + pr_debug("%s:%d prom_set_property failed\n", __func__, + __LINE__); +} + +/** + * os_area_get_property - Get a saved_params value from the device tree. + * + */ + +static void __init os_area_get_property(struct device_node *node, + struct property *prop) +{ + const struct property *tmp = of_find_property(node, prop->name, NULL); + + if (tmp) { + BUG_ON(prop->length != tmp->length); + memcpy(prop->value, tmp->value, prop->length); + } else + pr_debug("%s:%d not found %s\n", __func__, __LINE__, + prop->name); +} + #define dump_header(_a) _dump_header(_a, __func__, __LINE__) static void _dump_header(const struct os_area_header *h, const char *func, int line) @@ -196,8 +251,19 @@ static int __init verify_header(const struct os_area_header *header) static void os_area_queue_work_handler(struct work_struct *work) { + struct device_node *node; + pr_debug(" -> %s:%d\n", __func__, __LINE__); + node = of_find_node_by_path("/"); + + if (node) { + os_area_set_property(node, &property_rtc_diff); + of_node_put(node); + } else + pr_debug("%s:%d of_find_node_by_path failed\n", + __func__, __LINE__); + pr_debug(" <- %s:%d\n", __func__, __LINE__); } @@ -244,6 +310,8 @@ void __init ps3_os_area_save_params(void) result = verify_header(header); if (result) { + /* Second stage kernels exit here. */ + pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); dump_header(header); return; @@ -254,20 +322,52 @@ void __init ps3_os_area_save_params(void) saved_params.rtc_diff = params->rtc_diff; saved_params.av_multi_out = params->av_multi_out; + saved_params.valid = 1; memset(header, 0, sizeof(*header)); pr_debug(" <- %s:%d\n", __func__, __LINE__); } +/** + * ps3_os_area_init - Setup os area device tree properties as needed. + */ + +void __init ps3_os_area_init(void) +{ + struct device_node *node; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + node = of_find_node_by_path("/"); + + if (!saved_params.valid && node) { + /* Second stage kernels should have a dt entry. */ + os_area_get_property(node, &property_rtc_diff); + os_area_get_property(node, &property_av_multi_out); + } + + if(!saved_params.rtc_diff) + saved_params.rtc_diff = SECONDS_FROM_1970_TO_2000; + + if (node) { + os_area_set_property(node, &property_rtc_diff); + os_area_set_property(node, &property_av_multi_out); + of_node_put(node); + } else + pr_debug("%s:%d of_find_node_by_path failed\n", + __func__, __LINE__); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); +} + /** * ps3_os_area_get_rtc_diff - Returns the rtc diff value. */ u64 ps3_os_area_get_rtc_diff(void) { - return saved_params.rtc_diff ? saved_params.rtc_diff - : SECONDS_FROM_1970_TO_2000; + return saved_params.rtc_diff; } /** diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 6b4f4dd2d15..01f0c9506e1 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); /* os area */ void __init ps3_os_area_save_params(void); +void __init ps3_os_area_init(void); u64 ps3_os_area_get_rtc_diff(void); void ps3_os_area_set_rtc_diff(u64 rtc_diff); diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index f0d5ec51ef1..5c2cbb08eb5 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) prealloc_ps3flash_bounce_buffer(); ppc_md.power_save = ps3_power_save; + ps3_os_area_init(); DBG(" <- %s:%d\n", __func__, __LINE__); } -- cgit v1.2.3-70-g09d2