diff options
Diffstat (limited to 'arch/powerpc/platforms/ps3/setup.c')
| -rw-r--r-- | arch/powerpc/platforms/ps3/setup.c | 193 |
1 files changed, 153 insertions, 40 deletions
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index d8b5cadbe80..3f509f86432 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -23,7 +23,8 @@ #include <linux/fs.h> #include <linux/root_dev.h> #include <linux/console.h> -#include <linux/kexec.h> +#include <linux/export.h> +#include <linux/bootmem.h> #include <asm/machdep.h> #include <asm/firmware.h> @@ -32,19 +33,41 @@ #include <asm/udbg.h> #include <asm/prom.h> #include <asm/lv1call.h> +#include <asm/ps3gpu.h> #include "platform.h" #if defined(DEBUG) -#define DBG(fmt...) udbg_printf(fmt) +#define DBG udbg_printf #else -#define DBG(fmt...) do{if(0)printk(fmt);}while(0) +#define DBG pr_debug #endif -static void ps3_show_cpuinfo(struct seq_file *m) +/* mutex synchronizing GPU accesses and video mode changes */ +DEFINE_MUTEX(ps3_gpu_mutex); +EXPORT_SYMBOL_GPL(ps3_gpu_mutex); + +static union ps3_firmware_version ps3_firmware_version; + +void ps3_get_firmware_version(union ps3_firmware_version *v) +{ + *v = ps3_firmware_version; +} +EXPORT_SYMBOL_GPL(ps3_get_firmware_version); + +int ps3_compare_firmware_version(u16 major, u16 minor, u16 rev) { - seq_printf(m, "machine\t\t: %s\n", ppc_md.name); + union ps3_firmware_version x; + + x.pad = 0; + x.major = major; + x.minor = minor; + x.rev = rev; + + return (ps3_firmware_version.raw > x.raw) - + (ps3_firmware_version.raw < x.raw); } +EXPORT_SYMBOL_GPL(ps3_compare_firmware_version); static void ps3_power_save(void) { @@ -57,27 +80,134 @@ static void ps3_power_save(void) lv1_pause(0); } +static void ps3_restart(char *cmd) +{ + DBG("%s:%d cmd '%s'\n", __func__, __LINE__, cmd); + + smp_send_stop(); + ps3_sys_manager_restart(); /* never returns */ +} + +static void ps3_power_off(void) +{ + DBG("%s:%d\n", __func__, __LINE__); + + smp_send_stop(); + ps3_sys_manager_power_off(); /* never returns */ +} + +static void ps3_halt(void) +{ + DBG("%s:%d\n", __func__, __LINE__); + + smp_send_stop(); + ps3_sys_manager_halt(); /* never returns */ +} + static void ps3_panic(char *str) { DBG("%s:%d %s\n", __func__, __LINE__, str); -#ifdef CONFIG_SMP smp_send_stop(); -#endif printk("\n"); printk(" System does not reboot automatically.\n"); printk(" Please press POWER button.\n"); printk("\n"); - for (;;) ; + while(1) + lv1_pause(1); +} + +#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) || \ + defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) +static void __init prealloc(struct ps3_prealloc *p) +{ + if (!p->size) + return; + + p->address = __alloc_bootmem(p->size, p->align, __pa(MAX_DMA_ADDRESS)); + if (!p->address) { + printk(KERN_ERR "%s: Cannot allocate %s\n", __func__, + p->name); + return; + } + + printk(KERN_INFO "%s: %lu bytes at %p\n", p->name, p->size, + p->address); +} +#endif + +#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) +struct ps3_prealloc ps3fb_videomemory = { + .name = "ps3fb videomemory", + .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, + .align = 1024*1024 /* the GPU requires 1 MiB alignment */ +}; +EXPORT_SYMBOL_GPL(ps3fb_videomemory); +#define prealloc_ps3fb_videomemory() prealloc(&ps3fb_videomemory) + +static int __init early_parse_ps3fb(char *p) +{ + if (!p) + return 1; + + ps3fb_videomemory.size = _ALIGN_UP(memparse(p, &p), + ps3fb_videomemory.align); + return 0; +} +early_param("ps3fb", early_parse_ps3fb); +#else +#define prealloc_ps3fb_videomemory() do { } while (0) +#endif + +#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) +struct ps3_prealloc ps3flash_bounce_buffer = { + .name = "ps3flash bounce buffer", + .size = 256*1024, + .align = 256*1024 +}; +EXPORT_SYMBOL_GPL(ps3flash_bounce_buffer); +#define prealloc_ps3flash_bounce_buffer() prealloc(&ps3flash_bounce_buffer) + +static int __init early_parse_ps3flash(char *p) +{ + if (!p) + return 1; + + if (!strcmp(p, "off")) + ps3flash_bounce_buffer.size = 0; + + return 0; +} +early_param("ps3flash", early_parse_ps3flash); +#else +#define prealloc_ps3flash_bounce_buffer() do { } while (0) +#endif + +static int ps3_set_dabr(unsigned long dabr, unsigned long dabrx) +{ + /* Have to set at least one bit in the DABRX */ + if (dabrx == 0 && dabr == 0) + dabrx = DABRX_USER; + /* hypervisor only allows us to set BTI, Kernel and user */ + dabrx &= DABRX_BTI | DABRX_KERNEL | DABRX_USER; + + return lv1_set_dabr(dabr, dabrx) ? -1 : 0; } static void __init ps3_setup_arch(void) { + u64 tmp; + DBG(" -> %s:%d\n", __func__, __LINE__); + lv1_get_version_info(&ps3_firmware_version.raw, &tmp); + + printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", + ps3_firmware_version.major, ps3_firmware_version.minor, + ps3_firmware_version.rev); + ps3_spu_set_platform(); - ps3_map_htab(); #ifdef CONFIG_SMP smp_init_ps3(); @@ -87,7 +217,11 @@ static void __init ps3_setup_arch(void) conswitchp = &dummy_con; #endif + prealloc_ps3fb_videomemory(); + prealloc_ps3flash_bounce_buffer(); + ppc_md.power_save = ps3_power_save; + ps3_os_area_init(); DBG(" <- %s:%d\n", __func__, __LINE__); } @@ -105,12 +239,12 @@ static int __init ps3_probe(void) DBG(" -> %s:%d\n", __func__, __LINE__); dt_root = of_get_flat_dt_root(); - if (!of_flat_dt_is_compatible(dt_root, "PS3")) + if (!of_flat_dt_is_compatible(dt_root, "sony,ps3")) return 0; powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE; - ps3_os_area_init(); + ps3_os_area_save_params(); ps3_mm_init(); ps3_mm_vas_create(&htab_size); ps3_hpte_init(htab_size); @@ -122,31 +256,12 @@ static int __init ps3_probe(void) #if defined(CONFIG_KEXEC) static void ps3_kexec_cpu_down(int crash_shutdown, int secondary) { - DBG(" -> %s:%d\n", __func__, __LINE__); - - if (secondary) { - int cpu; - for_each_online_cpu(cpu) - if (cpu) - ps3_smp_cleanup_cpu(cpu); - } else - ps3_smp_cleanup_cpu(0); - - DBG(" <- %s:%d\n", __func__, __LINE__); -} - -static void ps3_machine_kexec(struct kimage *image) -{ - unsigned long ppe_id; - - DBG(" -> %s:%d\n", __func__, __LINE__); + int cpu = smp_processor_id(); - lv1_get_logical_ppe_id(&ppe_id); - lv1_configure_irq_state_bitmap(ppe_id, 0, 0); - ps3_mm_shutdown(); - ps3_mm_vas_destroy(); + DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); - default_machine_kexec(image); + ps3_smp_cleanup_cpu(cpu); + ps3_shutdown_IRQ(cpu); DBG(" <- %s:%d\n", __func__, __LINE__); } @@ -156,18 +271,16 @@ define_machine(ps3) { .name = "PS3", .probe = ps3_probe, .setup_arch = ps3_setup_arch, - .show_cpuinfo = ps3_show_cpuinfo, .init_IRQ = ps3_init_IRQ, .panic = ps3_panic, .get_boot_time = ps3_get_boot_time, - .set_rtc_time = ps3_set_rtc_time, - .get_rtc_time = ps3_get_rtc_time, + .set_dabr = ps3_set_dabr, .calibrate_decr = ps3_calibrate_decr, .progress = ps3_progress, + .restart = ps3_restart, + .power_off = ps3_power_off, + .halt = ps3_halt, #if defined(CONFIG_KEXEC) .kexec_cpu_down = ps3_kexec_cpu_down, - .machine_kexec = ps3_machine_kexec, - .machine_kexec_prepare = default_machine_kexec_prepare, - .machine_crash_shutdown = default_machine_crash_shutdown, #endif }; |
