diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-11 21:55:47 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-11 21:55:47 -0700 |
commit | e86908614f2c7fec401827e5cefd7a6ea9407f85 (patch) | |
tree | fcb5d9e52422b37bdaf0e647126ebdfc1680f162 /arch/powerpc/platforms | |
parent | 547307420931344a868275bd7ea7a30f117a15a9 (diff) | |
parent | 9b4b8feb962f4b3e74768b7205f1f8f6cce87238 (diff) | |
download | talos-obmc-linux-e86908614f2c7fec401827e5cefd7a6ea9407f85.tar.gz talos-obmc-linux-e86908614f2c7fec401827e5cefd7a6ea9407f85.zip |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (408 commits)
[POWERPC] Add memchr() to the bootwrapper
[POWERPC] Implement logging of unhandled signals
[POWERPC] Add legacy serial support for OPB with flattened device tree
[POWERPC] Use 1TB segments
[POWERPC] XilinxFB: Allow fixed framebuffer base address
[POWERPC] XilinxFB: Add support for custom screen resolution
[POWERPC] XilinxFB: Use pdata to pass around framebuffer parameters
[POWERPC] PCI: Add 64-bit physical address support to setup_indirect_pci
[POWERPC] 4xx: Kilauea defconfig file
[POWERPC] 4xx: Kilauea DTS
[POWERPC] 4xx: Add AMCC Kilauea eval board support to platforms/40x
[POWERPC] 4xx: Add AMCC 405EX support to cputable.c
[POWERPC] Adjust TASK_SIZE on ppc32 systems to 3GB that are capable
[POWERPC] Use PAGE_OFFSET to tell if an address is user/kernel in SW TLB handlers
[POWERPC] 85xx: Enable FP emulation in MPC8560 ADS defconfig
[POWERPC] 85xx: Killed <asm/mpc85xx.h>
[POWERPC] 85xx: Add cpm nodes for 8541/8555 CDS
[POWERPC] 85xx: Convert mpc8560ads to the new CPM binding.
[POWERPC] mpc8272ads: Remove muram from the CPM reg property.
[POWERPC] Make clockevents work on PPC601 processors
...
Fixed up conflict in Documentation/powerpc/booting-without-of.txt manually.
Diffstat (limited to 'arch/powerpc/platforms')
162 files changed, 6213 insertions, 3430 deletions
diff --git a/arch/powerpc/platforms/4xx/Kconfig b/arch/powerpc/platforms/40x/Kconfig index ded357c17414..47b3b0a3864a 100644 --- a/arch/powerpc/platforms/4xx/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -1,16 +1,3 @@ -config 4xx - bool - depends on 40x || 44x - default y - -config BOOKE - bool - depends on 44x - default y - -menu "AMCC 40x options" - depends on 40x - #config BUBINGA # bool "Bubinga" # depends on 40x @@ -42,6 +29,13 @@ menu "AMCC 40x options" # help # This option enables support for the extra features of the EP405PC board. +config KILAUEA + bool "Kilauea" + depends on 40x + default n + help + This option enables support for the AMCC PPC405EX evaluation board. + #config REDWOOD_5 # bool "Redwood-5" # depends on 40x @@ -66,23 +60,30 @@ menu "AMCC 40x options" # help # This option enables support for the IBM PPC405GPr evaluation board. -#config WALNUT -# bool "Walnut" -# depends on 40x -# default y -# select 405GP -# help -# This option enables support for the IBM PPC405GP evaluation board. +config WALNUT + bool "Walnut" + depends on 40x + default y + select 405GP + help + This option enables support for the IBM PPC405GP evaluation board. -#config XILINX_ML300 -# bool "Xilinx-ML300" -# depends on 40x -# default y -# select VIRTEX_II_PRO -# help -# This option enables support for the Xilinx ML300 evaluation board. +config XILINX_VIRTEX_GENERIC_BOARD + bool "Generic Xilinx Virtex board" + depends on 40x + default n + select XILINX_VIRTEX_II_PRO + select XILINX_VIRTEX_4_FX + help + This option enables generic support for Xilinx Virtex based boards. + + The generic virtex board support matches any device tree which + specifies 'xilinx,virtex' in its compatible field. This includes + the Xilinx ML3xx and ML4xx reference designs using the powerpc + core. -endmenu + Most Virtex designs should use this unless it needs to do some + special configuration at board probe time. # 40x specific CPU modules, selected based on the board above. config NP405H @@ -106,11 +107,19 @@ config 405EP config 405GPR bool -config VIRTEX_II_PRO +config XILINX_VIRTEX + bool + +config XILINX_VIRTEX_II_PRO bool + select XILINX_VIRTEX select IBM405_ERR77 select IBM405_ERR51 +config XILINX_VIRTEX_4_FX + bool + select XILINX_VIRTEX + config STB03xxx bool select IBM405_ERR77 @@ -126,73 +135,6 @@ config IBM405_ERR77 config IBM405_ERR51 bool -menu "AMCC 44x options" - depends on 44x - -#config BAMBOO -# bool "Bamboo" -# depends on 44x -# default n -# select 440EP -# help -# This option enables support for the IBM PPC440EP evaluation board. - -config EBONY - bool "Ebony" - depends on 44x - default y - select 440GP - help - This option enables support for the IBM PPC440GP evaluation board. - -#config LUAN -# bool "Luan" -# depends on 44x -# default n -# select 440SP -# help -# This option enables support for the IBM PPC440SP evaluation board. - -#config OCOTEA -# bool "Ocotea" -# depends on 44x -# default n -# select 440GX -# help -# This option enables support for the IBM PPC440GX evaluation board. - -endmenu - -# 44x specific CPU modules, selected based on the board above. -config 440EP - bool - select PPC_FPU - select IBM440EP_ERR42 - -config 440GP - bool - select IBM_NEW_EMAC_ZMII - -config 440GX - bool - -config 440SP - bool - -config 440A - bool - depends on 440GX - default y - -# 44x errata/workaround config symbols, selected by the CPU models above -config IBM440EP_ERR42 - bool - -#config XILINX_OCP -# bool -# depends on XILINX_ML300 -# default y - #config BIOS_FIXUP # bool # depends on BUBINGA || EP405 || SYCAMORE || WALNUT diff --git a/arch/powerpc/platforms/40x/Makefile b/arch/powerpc/platforms/40x/Makefile new file mode 100644 index 000000000000..51dadeee6fc6 --- /dev/null +++ b/arch/powerpc/platforms/40x/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_KILAUEA) += kilauea.o +obj-$(CONFIG_WALNUT) += walnut.o +obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o diff --git a/arch/powerpc/platforms/40x/kilauea.c b/arch/powerpc/platforms/40x/kilauea.c new file mode 100644 index 000000000000..1bffdbdd21b1 --- /dev/null +++ b/arch/powerpc/platforms/40x/kilauea.c @@ -0,0 +1,58 @@ +/* + * Kilauea board specific routines + * + * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de> + * + * Based on the Walnut code by + * Josh Boyer <jwboyer@linux.vnet.ibm.com> + * Copyright 2007 IBM Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/init.h> +#include <linux/of_platform.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/time.h> +#include <asm/uic.h> + +static struct of_device_id kilauea_of_bus[] = { + { .compatible = "ibm,plb4", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init kilauea_device_probe(void) +{ + if (!machine_is(kilauea)) + return 0; + + of_platform_bus_probe(NULL, kilauea_of_bus, NULL); + + return 0; +} +device_initcall(kilauea_device_probe); + +static int __init kilauea_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "amcc,kilauea")) + return 0; + + return 1; +} + +define_machine(kilauea) { + .name = "Kilauea", + .probe = kilauea_probe, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/40x/virtex.c b/arch/powerpc/platforms/40x/virtex.c new file mode 100644 index 000000000000..14bbc328170f --- /dev/null +++ b/arch/powerpc/platforms/40x/virtex.c @@ -0,0 +1,45 @@ +/* + * Xilinx Virtex (IIpro & 4FX) based board support + * + * Copyright 2007 Secret Lab Technologies Ltd. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/of_platform.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/time.h> +#include <asm/xilinx_intc.h> + +static int __init virtex_device_probe(void) +{ + if (!machine_is(virtex)) + return 0; + + of_platform_bus_probe(NULL, NULL, NULL); + + return 0; +} +device_initcall(virtex_device_probe); + +static int __init virtex_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "xilinx,virtex")) + return 0; + + return 1; +} + +define_machine(virtex) { + .name = "Xilinx Virtex", + .probe = virtex_probe, + .init_IRQ = xilinx_intc_init_tree, + .get_irq = xilinx_intc_get_irq, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/40x/walnut.c b/arch/powerpc/platforms/40x/walnut.c new file mode 100644 index 000000000000..eb0c136b1c44 --- /dev/null +++ b/arch/powerpc/platforms/40x/walnut.c @@ -0,0 +1,63 @@ +/* + * Architecture- / platform-specific boot-time initialization code for + * IBM PowerPC 4xx based boards. Adapted from original + * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek + * <dan@net4x.com>. + * + * Copyright(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> + * + * Rewritten and ported to the merged powerpc tree: + * Copyright 2007 IBM Corporation + * Josh Boyer <jwboyer@linux.vnet.ibm.com> + * + * 2002 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include <linux/init.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/time.h> +#include <asm/uic.h> +#include <asm/of_platform.h> + +static struct of_device_id walnut_of_bus[] = { + { .compatible = "ibm,plb3", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init walnut_device_probe(void) +{ + if (!machine_is(walnut)) + return 0; + + /* FIXME: do bus probe here */ + of_platform_bus_probe(NULL, walnut_of_bus, NULL); + + return 0; +} +device_initcall(walnut_device_probe); + +static int __init walnut_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,walnut")) + return 0; + + return 1; +} + +define_machine(walnut) { + .name = "Walnut", + .probe = walnut_probe, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 8e66949e7c67..51f3ea40a285 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -1,10 +1,10 @@ -#config BAMBOO -# bool "Bamboo" -# depends on 44x -# default n -# select 440EP -# help -# This option enables support for the IBM PPC440EP evaluation board. +config BAMBOO + bool "Bamboo" + depends on 44x + default n + select 440EP + help + This option enables support for the IBM PPC440EP evaluation board. config EBONY bool "Ebony" @@ -14,6 +14,14 @@ config EBONY help This option enables support for the IBM PPC440GP evaluation board. +config SEQUOIA + bool "Sequoia" + depends on 44x + default n + select 440EPX + help + This option enables support for the AMCC PPC440EPX evaluation board. + #config LUAN # bool "Luan" # depends on 44x @@ -35,6 +43,14 @@ config 440EP bool select PPC_FPU select IBM440EP_ERR42 +# select IBM_NEW_EMAC_ZMII + +config 440EPX + bool + select PPC_FPU +# Disabled until the new EMAC Driver is merged. +# select IBM_NEW_EMAC_EMAC4 +# select IBM_NEW_EMAC_ZMII config 440GP bool @@ -48,7 +64,7 @@ config 440SP config 440A bool - depends on 440GX + depends on 440GX || 440EPX default y # 44x errata/workaround config symbols, selected by the CPU models above diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index 41d0a18a0e44..10ce6740cc7d 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile @@ -1,2 +1,4 @@ obj-$(CONFIG_44x) := misc_44x.o obj-$(CONFIG_EBONY) += ebony.o +obj-$(CONFIG_BAMBOO) += bamboo.o +obj-$(CONFIG_SEQUOIA) += sequoia.o diff --git a/arch/powerpc/platforms/44x/bamboo.c b/arch/powerpc/platforms/44x/bamboo.c new file mode 100644 index 000000000000..470e1a3fd755 --- /dev/null +++ b/arch/powerpc/platforms/44x/bamboo.c @@ -0,0 +1,61 @@ +/* + * Bamboo board specific routines + * + * Wade Farnsworth <wfarnsworth@mvista.com> + * Copyright 2004 MontaVista Software Inc. + * + * Rewritten and ported to the merged powerpc tree: + * Josh Boyer <jwboyer@linux.vnet.ibm.com> + * Copyright 2007 IBM Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/init.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/time.h> +#include <asm/uic.h> +#include <asm/of_platform.h> +#include "44x.h" + +static struct of_device_id bamboo_of_bus[] = { + { .compatible = "ibm,plb4", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init bamboo_device_probe(void) +{ + if (!machine_is(bamboo)) + return 0; + + of_platform_bus_probe(NULL, bamboo_of_bus, NULL); + + return 0; +} +device_initcall(bamboo_device_probe); + +static int __init bamboo_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "amcc,bamboo")) + return 0; + + return 1; +} + +define_machine(bamboo) { + .name = "Bamboo", + .probe = bamboo_probe, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .restart = ppc44x_reset_system, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c index 5a7fec8d10d3..40e18fcb666c 100644 --- a/arch/powerpc/platforms/44x/ebony.c +++ b/arch/powerpc/platforms/44x/ebony.c @@ -57,14 +57,9 @@ static int __init ebony_probe(void) return 1; } -static void __init ebony_setup_arch(void) -{ -} - define_machine(ebony) { .name = "Ebony", .probe = ebony_probe, - .setup_arch = ebony_setup_arch, .progress = udbg_progress, .init_IRQ = uic_init_tree, .get_irq = uic_get_irq, diff --git a/arch/powerpc/platforms/44x/sequoia.c b/arch/powerpc/platforms/44x/sequoia.c new file mode 100644 index 000000000000..30700b31d43b --- /dev/null +++ b/arch/powerpc/platforms/44x/sequoia.c @@ -0,0 +1,61 @@ +/* + * Sequoia board specific routines + * + * Valentine Barshak <vbarshak@ru.mvista.com> + * Copyright 2007 MontaVista Software Inc. + * + * Based on the Bamboo code by + * Josh Boyer <jwboyer@linux.vnet.ibm.com> + * Copyright 2007 IBM Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/init.h> +#include <asm/machdep.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/time.h> +#include <asm/uic.h> +#include <asm/of_platform.h> +#include "44x.h" + +static struct of_device_id sequoia_of_bus[] = { + { .compatible = "ibm,plb4", }, + { .compatible = "ibm,opb", }, + { .compatible = "ibm,ebc", }, + {}, +}; + +static int __init sequoia_device_probe(void) +{ + if (!machine_is(sequoia)) + return 0; + + of_platform_bus_probe(NULL, sequoia_of_bus, NULL); + + return 0; +} +device_initcall(sequoia_device_probe); + +static int __init sequoia_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "amcc,sequoia")) + return 0; + + return 1; +} + +define_machine(sequoia) { + .name = "Sequoia", + .probe = sequoia_probe, + .progress = udbg_progress, + .init_IRQ = uic_init_tree, + .get_irq = uic_get_irq, + .restart = ppc44x_reset_system, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/4xx/Makefile b/arch/powerpc/platforms/4xx/Makefile deleted file mode 100644 index 79ff6b1e887c..000000000000 --- a/arch/powerpc/platforms/4xx/Makefile +++ /dev/null @@ -1 +0,0 @@ -# empty makefile so make clean works
\ No newline at end of file diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig index 3ffaa066c2c8..2938d4927b83 100644 --- a/arch/powerpc/platforms/52xx/Kconfig +++ b/arch/powerpc/platforms/52xx/Kconfig @@ -1,6 +1,7 @@ config PPC_MPC52xx bool select FSL_SOC + select PPC_CLOCK default n config PPC_MPC5200 @@ -30,6 +31,7 @@ config PPC_EFIKA config PPC_LITE5200 bool "Freescale Lite5200 Eval Board" depends on PPC_MULTIPLATFORM && PPC32 + select WANT_DEVICE_TREE select PPC_MPC5200 default n diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile index b91e39c84d46..307dbc178091 100644 --- a/arch/powerpc/platforms/52xx/Makefile +++ b/arch/powerpc/platforms/52xx/Makefile @@ -10,3 +10,6 @@ obj-$(CONFIG_PPC_EFIKA) += efika.o obj-$(CONFIG_PPC_LITE5200) += lite5200.o obj-$(CONFIG_PM) += mpc52xx_sleep.o mpc52xx_pm.o +ifeq ($(CONFIG_PPC_LITE5200),y) + obj-$(CONFIG_PM) += lite5200_sleep.o lite5200_pm.o +endif diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 4be6e7a17b66..a0da70c8b502 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -9,33 +9,16 @@ * kind, whether express or implied. */ -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/reboot.h> #include <linux/init.h> #include <linux/utsrelease.h> -#include <linux/seq_file.h> -#include <linux/string.h> -#include <linux/root_dev.h> -#include <linux/initrd.h> -#include <linux/timer.h> #include <linux/pci.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/sections.h> -#include <asm/pci-bridge.h> -#include <asm/pgtable.h> +#include <linux/of.h> #include <asm/prom.h> #include <asm/time.h> #include <asm/machdep.h> #include <asm/rtas.h> -#include <asm/of_device.h> -#include <asm/of_platform.h> #include <asm/mpc52xx.h> - #define EFIKA_PLATFORM_NAME "Efika" @@ -78,8 +61,8 @@ static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops rtas_pci_ops = { - rtas_read_config, - rtas_write_config + .read = rtas_read_config, + .write = rtas_write_config, }; @@ -197,15 +180,6 @@ static void __init efika_setup_arch(void) { rtas_initialize(); -#ifdef CONFIG_BLK_DEV_INITRD - initrd_below_start_ok = 1; - - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif - ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ - efika_pcisetup(); #ifdef CONFIG_PM diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 5c46e898fd45..0caa3d955c3b 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -15,33 +15,13 @@ #undef DEBUG -#include <linux/stddef.h> -#include <linux/kernel.h> #include <linux/init.h> -#include <linux/errno.h> -#include <linux/reboot.h> #include <linux/pci.h> -#include <linux/kdev_t.h> -#include <linux/major.h> -#include <linux/console.h> -#include <linux/delay.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> -#include <linux/initrd.h> - -#include <asm/system.h> -#include <asm/atomic.h> +#include <linux/of.h> #include <asm/time.h> #include <asm/io.h> #include <asm/machdep.h> -#include <asm/ipic.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> #include <asm/prom.h> -#include <asm/udbg.h> -#include <sysdev/fsl_soc.h> -#include <asm/of_platform.h> - #include <asm/mpc52xx.h> /* ************************************************************************ @@ -50,19 +30,56 @@ * */ +/* + * Fix clock configuration. + * + * Firmware is supposed to be responsible for this. If you are creating a + * new board port, do *NOT* duplicate this code. Fix your boot firmware + * to set it correctly in the first place + */ +static void __init +lite5200_fix_clock_config(void) +{ + struct mpc52xx_cdm __iomem *cdm; + + /* Map zones */ + cdm = mpc52xx_find_and_map("mpc5200-cdm"); + if (!cdm) { + printk(KERN_ERR "%s() failed; expect abnormal behaviour\n", + __FUNCTION__); + return; + } + + /* Use internal 48 Mhz */ + out_8(&cdm->ext_48mhz_en, 0x00); + out_8(&cdm->fd_enable, 0x01); + if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */ + out_be16(&cdm->fd_counters, 0x0001); + else + out_be16(&cdm->fd_counters, 0x5555); + + /* Unmap the regs */ + iounmap(cdm); +} + +/* + * Fix setting of port_config register. + * + * Firmware is supposed to be responsible for this. If you are creating a + * new board port, do *NOT* duplicate this code. Fix your boot firmware + * to set it correctly in the first place + */ static void __init -lite5200_setup_cpu(void) +lite5200_fix_port_config(void) { struct mpc52xx_gpio __iomem *gpio; u32 port_config; - /* Map zones */ gpio = mpc52xx_find_and_map("mpc5200-gpio"); if (!gpio) { - printk(KERN_ERR __FILE__ ": " - "Error while mapping GPIO register for port config. " - "Expect some abnormal behavior\n"); - goto error; + printk(KERN_ERR "%s() failed. expect abnormal behavior\n", + __FUNCTION__); + return; } /* Set port config */ @@ -81,12 +98,10 @@ lite5200_setup_cpu(void) out_be32(&gpio->port_config, port_config); /* Unmap zone */ -error: iounmap(gpio); } #ifdef CONFIG_PM -static u32 descr_a; static void lite5200_suspend_prepare(void __iomem *mbar) { u8 pin = 1; /* GPIO_WKUP_1 (GPIO_PSC2_4) */ @@ -97,42 +112,41 @@ static void lite5200_suspend_prepare(void __iomem *mbar) * power down usb port * this needs to be called before of-ohci suspend code */ - descr_a = in_be32(mbar + 0x1048); - out_be32(mbar + 0x1048, (descr_a & ~0x200) | 0x100); + + /* set ports to "power switched" and "powered at the same time" + * USB Rh descriptor A: NPS = 0, PSM = 0 */ + out_be32(mbar + 0x1048, in_be32(mbar + 0x1048) & ~0x300); + /* USB Rh status: LPS = 1 - turn off power */ + out_be32(mbar + 0x1050, 0x00000001); } static void lite5200_resume_finish(void __iomem *mbar) { - out_be32(mbar + 0x1048, descr_a); + /* USB Rh status: LPSC = 1 - turn on power */ + out_be32(mbar + 0x1050, 0x00010000); } #endif static void __init lite5200_setup_arch(void) { +#ifdef CONFIG_PCI struct device_node *np; +#endif if (ppc_md.progress) ppc_md.progress("lite5200_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np) { - const unsigned int *fp = - of_get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } + /* Fix things that firmware should have done. */ + lite5200_fix_clock_config(); + lite5200_fix_port_config(); - /* CPU & Port mux setup */ - mpc52xx_setup_cpu(); /* Generic */ - lite5200_setup_cpu(); /* Platorm specific */ + /* Some mpc5200 & mpc5200b related configuration */ + mpc5200_setup_xlb_arbiter(); #ifdef CONFIG_PM mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; mpc52xx_suspend.board_resume_finish = lite5200_resume_finish; - mpc52xx_pm_init(); + lite5200_pm_init(); #endif #ifdef CONFIG_PCI @@ -156,20 +170,6 @@ static void __init lite5200_setup_arch(void) } -static void lite5200_show_cpuinfo(struct seq_file *m) -{ - struct device_node* np = of_find_all_nodes(NULL); - const char *model = NULL; - - if (np) - model = of_get_property(np, "model", NULL); - - seq_printf(m, "vendor\t\t: Freescale Semiconductor\n"); - seq_printf(m, "machine\t\t: %s\n", model ? model : "unknown"); - - of_node_put(np); -} - /* * Called very early, MMU is off, device-tree isn't unflattened */ @@ -193,6 +193,5 @@ define_machine(lite5200) { .init = mpc52xx_declare_of_platform_devices, .init_IRQ = mpc52xx_init_irq, .get_irq = mpc52xx_get_irq, - .show_cpuinfo = lite5200_show_cpuinfo, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c new file mode 100644 index 000000000000..f26afcd41757 --- /dev/null +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -0,0 +1,213 @@ +#include <linux/init.h> +#include <linux/pm.h> +#include <asm/io.h> +#include <asm/time.h> +#include <asm/mpc52xx.h> +#include "mpc52xx_pic.h" + +/* defined in lite5200_sleep.S and only used here */ +extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar); + +static struct mpc52xx_cdm __iomem *cdm; +static struct mpc52xx_intr __iomem *pic; +static struct mpc52xx_sdma __iomem *bes; +static struct mpc52xx_xlb __iomem *xlb; +static struct mpc52xx_gpio __iomem *gps; +static struct mpc52xx_gpio_wkup __iomem *gpw; +static void __iomem *sram; +static const int sram_size = 0x4000; /* 16 kBytes */ +static void __iomem *mbar; + +static int lite5200_pm_valid(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + return 1; + default: + return 0; + } +} + +static int lite5200_pm_prepare(suspend_state_t state) +{ + /* deep sleep? let mpc52xx code handle that */ + if (state == PM_SUSPEND_STANDBY) + return mpc52xx_pm_prepare(state); + + if (state != PM_SUSPEND_MEM) + return -EINVAL; + + /* map registers */ + mbar = mpc52xx_find_and_map("mpc5200"); + if (!mbar) { + printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); + return -ENOSYS; + } + + cdm = mbar + 0x200; + pic = mbar + 0x500; + gps = mbar + 0xb00; + gpw = mbar + 0xc00; + bes = mbar + 0x1200; + xlb = mbar + 0x1f00; + sram = mbar + 0x8000; + + return 0; +} + +/* save and restore registers not bound to any real devices */ +static struct mpc52xx_cdm scdm; +static struct mpc52xx_intr spic; +static struct mpc52xx_sdma sbes; +static struct mpc52xx_xlb sxlb; +static struct mpc52xx_gpio sgps; +static struct mpc52xx_gpio_wkup sgpw; + +static void lite5200_save_regs(void) +{ + _memcpy_fromio(&spic, pic, sizeof(*pic)); + _memcpy_fromio(&sbes, bes, sizeof(*bes)); + _memcpy_fromio(&scdm, cdm, sizeof(*cdm)); + _memcpy_fromio(&sxlb, xlb, sizeof(*xlb)); + _memcpy_fromio(&sgps, gps, sizeof(*gps)); + _memcpy_fromio(&sgpw, gpw, sizeof(*gpw)); + + _memcpy_fromio(saved_sram, sram, sram_size); +} + +static void lite5200_restore_regs(void) +{ + int i; + _memcpy_toio(sram, saved_sram, sram_size); + + + /* + * GPIOs. Interrupt Master Enable has higher address then other + * registers, so just memcpy is ok. + */ + _memcpy_toio(gpw, &sgpw, sizeof(*gpw)); + _memcpy_toio(gps, &sgps, sizeof(*gps)); + + + /* XLB Arbitrer */ + out_be32(&xlb->snoop_window, sxlb.snoop_window); + out_be32(&xlb->master_priority, sxlb.master_priority); + out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable); + + /* enable */ + out_be32(&xlb->int_enable, sxlb.int_enable); + out_be32(&xlb->config, sxlb.config); + + + /* CDM - Clock Distribution Module */ + out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel); + out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel); + + out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en); + out_8(&cdm->fd_enable, scdm.fd_enable); + out_be16(&cdm->fd_counters, scdm.fd_counters); + + out_be32(&cdm->clk_enables, scdm.clk_enables); + + out_8(&cdm->osc_disable, scdm.osc_disable); + + out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1); + out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2); + out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3); + out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6); + + + /* BESTCOMM */ + out_be32(&bes->taskBar, sbes.taskBar); + out_be32(&bes->currentPointer, sbes.currentPointer); + out_be32(&bes->endPointer, sbes.endPointer); + out_be32(&bes->variablePointer, sbes.variablePointer); + + out_8(&bes->IntVect1, sbes.IntVect1); + out_8(&bes->IntVect2, sbes.IntVect2); + out_be16(&bes->PtdCntrl, sbes.PtdCntrl); + + for (i=0; i<32; i++) + out_8(&bes->ipr[i], sbes.ipr[i]); + + out_be32(&bes->cReqSelect, sbes.cReqSelect); + out_be32(&bes->task_size0, sbes.task_size0); + out_be32(&bes->task_size1, sbes.task_size1); + out_be32(&bes->MDEDebug, sbes.MDEDebug); + out_be32(&bes->ADSDebug, sbes.ADSDebug); + out_be32(&bes->Value1, sbes.Value1); + out_be32(&bes->Value2, sbes.Value2); + out_be32(&bes->Control, sbes.Control); + out_be32(&bes->Status, sbes.Status); + out_be32(&bes->PTDDebug, sbes.PTDDebug); + + /* restore tasks */ + for (i=0; i<16; i++) + out_be16(&bes->tcr[i], sbes.tcr[i]); + + /* enable interrupts */ + out_be32(&bes->IntPend, sbes.IntPend); + out_be32(&bes->IntMask, sbes.IntMask); + + + /* PIC */ + out_be32(&pic->per_pri1, spic.per_pri1); + out_be32(&pic->per_pri2, spic.per_pri2); + out_be32(&pic->per_pri3, spic.per_pri3); + + out_be32(&pic->main_pri1, spic.main_pri1); + out_be32(&pic->main_pri2, spic.main_pri2); + + out_be32(&pic->enc_status, spic.enc_status); + + /* unmask and enable interrupts */ + out_be32(&pic->per_mask, spic.per_mask); + out_be32(&pic->main_mask, spic.main_mask); + out_be32(&pic->ctrl, spic.ctrl); +} + +static int lite5200_pm_enter(suspend_state_t state) +{ + /* deep sleep? let mpc52xx code handle that */ + if (state == PM_SUSPEND_STANDBY) { + return mpc52xx_pm_enter(state); + } + + lite5200_save_regs(); + + /* effectively save FP regs */ + enable_kernel_fp(); + + lite5200_low_power(sram, mbar); + + lite5200_restore_regs(); + + /* restart jiffies */ + wakeup_decrementer(); + + iounmap(mbar); + return 0; +} + +static int lite5200_pm_finish(suspend_state_t state) +{ + /* deep sleep? let mpc52xx code handle that */ + if (state == PM_SUSPEND_STANDBY) { + return mpc52xx_pm_finish(state); + } + return 0; +} + +static struct pm_ops lite5200_pm_ops = { + .valid = lite5200_pm_valid, + .prepare = lite5200_pm_prepare, + .enter = lite5200_pm_enter, + .finish = lite5200_pm_finish, +}; + +int __init lite5200_pm_init(void) +{ + pm_set_ops(&lite5200_pm_ops); + return 0; +} diff --git a/arch/powerpc/platforms/52xx/lite5200_sleep.S b/arch/powerpc/platforms/52xx/lite5200_sleep.S new file mode 100644 index 000000000000..08ab6fefcf7a --- /dev/null +++ b/arch/powerpc/platforms/52xx/lite5200_sleep.S @@ -0,0 +1,412 @@ +#include <asm/reg.h> +#include <asm/ppc_asm.h> +#include <asm/processor.h> +#include <asm/cache.h> + + +#define SDRAM_CTRL 0x104 +#define SC_MODE_EN (1<<31) +#define SC_CKE (1<<30) +#define SC_REF_EN (1<<28) +#define SC_SOFT_PRE (1<<1) + +#define GPIOW_GPIOE 0xc00 +#define GPIOW_DDR 0xc08 +#define GPIOW_DVO 0xc0c + +#define CDM_CE 0x214 +#define CDM_SDRAM (1<<3) + + +/* helpers... beware: r10 and r4 are overwritten */ +#define SAVE_SPRN(reg, addr) \ + mfspr r10, SPRN_##reg; \ + stw r10, ((addr)*4)(r4); + +#define LOAD_SPRN(reg, addr) \ + lwz r10, ((addr)*4)(r4); \ + mtspr SPRN_##reg, r10; \ + sync; \ + isync; + + + .data +registers: + .space 0x5c*4 + .text + +/* ---------------------------------------------------------------------- */ +/* low-power mode with help of M68HLC908QT1 */ + + .globl lite5200_low_power +lite5200_low_power: + + mr r7, r3 /* save SRAM va */ + mr r8, r4 /* save MBAR va */ + + /* setup wakeup address for u-boot at physical location 0x0 */ + lis r3, CONFIG_KERNEL_START@h + lis r4, lite5200_wakeup@h + ori r4, r4, lite5200_wakeup@l + sub r4, r4, r3 + stw r4, 0(r3) + + + /* + * save stuff BDI overwrites + * 0xf0 (0xe0->0x100 gets overwritten when BDI connected; + * even when CONFIG_BDI* is disabled and MMU XLAT commented; heisenbug?)) + * WARNING: self-refresh doesn't seem to work when BDI2000 is connected, + * possibly because BDI sets SDRAM registers before wakeup code does + */ + lis r4, registers@h + ori r4, r4, registers@l + lwz r10, 0xf0(r3) + stw r10, (0x1d*4)(r4) + + /* save registers to r4 [destroys r10] */ + SAVE_SPRN(LR, 0x1c) + bl save_regs + + /* flush caches [destroys r3, r4] */ + bl flush_data_cache + + + /* copy code to sram */ + mr r4, r7 + li r3, (sram_code_end - sram_code)/4 + mtctr r3 + lis r3, sram_code@h + ori r3, r3, sram_code@l +1: + lwz r5, 0(r3) + stw r5, 0(r4) + addi r3, r3, 4 + addi r4, r4, 4 + bdnz 1b + + /* get tb_ticks_per_usec */ + lis r3, tb_ticks_per_usec@h + lwz r11, tb_ticks_per_usec@l(r3) + + /* disable I and D caches */ + mfspr r3, SPRN_HID0 + ori r3, r3, HID0_ICE | HID0_DCE + xori r3, r3, HID0_ICE | HID0_DCE + sync; isync; + mtspr SPRN_HID0, r3 + sync; isync; + + /* jump to sram */ + mtlr r7 + blrl + /* doesn't return */ + + +sram_code: + /* self refresh */ + lwz r4, SDRAM_CTRL(r8) + + /* send NOP (precharge) */ + oris r4, r4, SC_MODE_EN@h /* mode_en */ + stw r4, SDRAM_CTRL(r8) + sync + + ori r4, r4, SC_SOFT_PRE /* soft_pre */ + stw r4, SDRAM_CTRL(r8) + sync + xori r4, r4, SC_SOFT_PRE + + xoris r4, r4, SC_MODE_EN@h /* !mode_en */ + stw r4, SDRAM_CTRL(r8) + sync + + /* delay (for NOP to finish) */ + li r12, 1 + bl udelay + + /* + * mode_en must not be set when enabling self-refresh + * send AR with CKE low (self-refresh) + */ + oris r4, r4, (SC_REF_EN | SC_CKE)@h + xoris r4, r4, (SC_CKE)@h /* ref_en !cke */ + stw r4, SDRAM_CTRL(r8) + sync + + /* delay (after !CKE there should be two cycles) */ + li r12, 1 + bl udelay + + /* disable clock */ + lwz r4, CDM_CE(r8) + ori r4, r4, CDM_SDRAM + xori r4, r4, CDM_SDRAM + stw r4, CDM_CE(r8) + sync + + /* delay a bit */ + li r12, 1 + bl udelay + + + /* turn off with QT chip */ + li r4, 0x02 + stb r4, GPIOW_GPIOE(r8) /* enable gpio_wkup1 */ + sync + + stb r4, GPIOW_DVO(r8) /* "output" high */ + sync + stb r4, GPIOW_DDR(r8) /* output */ + sync + stb r4, GPIOW_DVO(r8) /* output high */ + sync + + /* 10uS delay */ + li r12, 10 + bl udelay + + /* turn off */ + li r4, 0 + stb r4, GPIOW_DVO(r8) /* output low */ + sync + + /* wait until we're offline */ + 1: + b 1b + + + /* local udelay in sram is needed */ + udelay: /* r11 - tb_ticks_per_usec, r12 - usecs, overwrites r13 */ + mullw r12, r12, r11 + mftb r13 /* start */ + addi r12, r13, r12 /* end */ + 1: + mftb r13 /* current */ + cmp cr0, r13, r12 + blt 1b + blr + +sram_code_end: + + + +/* uboot jumps here on resume */ +lite5200_wakeup: + bl restore_regs + + + /* HIDs, MSR */ + LOAD_SPRN(HID1, 0x19) + LOAD_SPRN(HID2, 0x1a) + + + /* address translation is tricky (see turn_on_mmu) */ + mfmsr r10 + ori r10, r10, MSR_DR | MSR_IR + + + mtspr SPRN_SRR1, r10 + lis r10, mmu_on@h + ori r10, r10, mmu_on@l + mtspr SPRN_SRR0, r10 + sync + rfi +mmu_on: + /* kernel offset (r4 is still set from restore_registers) */ + addis r4, r4, CONFIG_KERNEL_START@h + + + /* restore MSR */ + lwz r10, (4*0x1b)(r4) + mtmsr r10 + sync; isync; + + /* invalidate caches */ + mfspr r10, SPRN_HID0 + ori r5, r10, HID0_ICFI | HID0_DCI + mtspr SPRN_HID0, r5 /* invalidate caches */ + sync; isync; + mtspr SPRN_HID0, r10 + sync; isync; + + /* enable caches */ + lwz r10, (4*0x18)(r4) + mtspr SPRN_HID0, r10 /* restore (enable caches, DPM) */ + /* ^ this has to be after address translation set in MSR */ + sync + isync + + + /* restore 0xf0 (BDI2000) */ + lis r3, CONFIG_KERNEL_START@h + lwz r10, (0x1d*4)(r4) + stw r10, 0xf0(r3) + + LOAD_SPRN(LR, 0x1c) + + + blr + + +/* ---------------------------------------------------------------------- */ +/* boring code: helpers */ + +/* save registers */ +#define SAVE_BAT(n, addr) \ + SAVE_SPRN(DBAT##n##L, addr); \ + SAVE_SPRN(DBAT##n##U, addr+1); \ + SAVE_SPRN(IBAT##n##L, addr+2); \ + SAVE_SPRN(IBAT##n##U, addr+3); + +#define SAVE_SR(n, addr) \ + mfsr r10, n; \ + stw r10, ((addr)*4)(r4); + +#define SAVE_4SR(n, addr) \ + SAVE_SR(n, addr); \ + SAVE_SR(n+1, addr+1); \ + SAVE_SR(n+2, addr+2); \ + SAVE_SR(n+3, addr+3); + +save_regs: + stw r0, 0(r4) + stw r1, 0x4(r4) + stw r2, 0x8(r4) + stmw r11, 0xc(r4) /* 0xc -> 0x5f, (0x18*4-1) */ + + SAVE_SPRN(HID0, 0x18) + SAVE_SPRN(HID1, 0x19) + SAVE_SPRN(HID2, 0x1a) + mfmsr r10 + stw r10, (4*0x1b)(r4) + /*SAVE_SPRN(LR, 0x1c) have to save it before the call */ + /* 0x1d reserved by 0xf0 */ + SAVE_SPRN(RPA, 0x1e) + SAVE_SPRN(SDR1, 0x1f) + + /* save MMU regs */ + SAVE_BAT(0, 0x20) + SAVE_BAT(1, 0x24) + SAVE_BAT(2, 0x28) + SAVE_BAT(3, 0x2c) + SAVE_BAT(4, 0x30) + SAVE_BAT(5, 0x34) + SAVE_BAT(6, 0x38) + SAVE_BAT(7, 0x3c) + + SAVE_4SR(0, 0x40) + SAVE_4SR(4, 0x44) + SAVE_4SR(8, 0x48) + SAVE_4SR(12, 0x4c) + + SAVE_SPRN(SPRG0, 0x50) + SAVE_SPRN(SPRG1, 0x51) + SAVE_SPRN(SPRG2, 0x52) + SAVE_SPRN(SPRG3, 0x53) + SAVE_SPRN(SPRG4, 0x54) + SAVE_SPRN(SPRG5, 0x55) + SAVE_SPRN(SPRG6, 0x56) + SAVE_SPRN(SPRG7, 0x57) + + SAVE_SPRN(IABR, 0x58) + SAVE_SPRN(DABR, 0x59) + SAVE_SPRN(TBRL, 0x5a) + SAVE_SPRN(TBRU, 0x5b) + + blr + + +/* restore registers */ +#define LOAD_BAT(n, addr) \ + LOAD_SPRN(DBAT##n##L, addr); \ + LOAD_SPRN(DBAT##n##U, addr+1); \ + LOAD_SPRN(IBAT##n##L, addr+2); \ + LOAD_SPRN(IBAT##n##U, addr+3); + +#define LOAD_SR(n, addr) \ + lwz r10, ((addr)*4)(r4); \ + mtsr n, r10; + +#define LOAD_4SR(n, addr) \ + LOAD_SR(n, addr); \ + LOAD_SR(n+1, addr+1); \ + LOAD_SR(n+2, addr+2); \ + LOAD_SR(n+3, addr+3); + +restore_regs: + lis r4, registers@h + ori r4, r4, registers@l + + /* MMU is not up yet */ + subis r4, r4, CONFIG_KERNEL_START@h + + lwz r0, 0(r4) + lwz r1, 0x4(r4) + lwz r2, 0x8(r4) + lmw r11, 0xc(r4) + + /* + * these are a bit tricky + * + * 0x18 - HID0 + * 0x19 - HID1 + * 0x1a - HID2 + * 0x1b - MSR + * 0x1c - LR + * 0x1d - reserved by 0xf0 (BDI2000) + */ + LOAD_SPRN(RPA, 0x1e); + LOAD_SPRN(SDR1, 0x1f); + + /* restore MMU regs */ + LOAD_BAT(0, 0x20) + LOAD_BAT(1, 0x24) + LOAD_BAT(2, 0x28) + LOAD_BAT(3, 0x2c) + LOAD_BAT(4, 0x30) + LOAD_BAT(5, 0x34) + LOAD_BAT(6, 0x38) + LOAD_BAT(7, 0x3c) + + LOAD_4SR(0, 0x40) + LOAD_4SR(4, 0x44) + LOAD_4SR(8, 0x48) + LOAD_4SR(12, 0x4c) + + /* rest of regs */ + LOAD_SPRN(SPRG0, 0x50); + LOAD_SPRN(SPRG1, 0x51); + LOAD_SPRN(SPRG2, 0x52); + LOAD_SPRN(SPRG3, 0x53); + LOAD_SPRN(SPRG4, 0x54); + LOAD_SPRN(SPRG5, 0x55); + LOAD_SPRN(SPRG6, 0x56); + LOAD_SPRN(SPRG7, 0x57); + + LOAD_SPRN(IABR, 0x58); + LOAD_SPRN(DABR, 0x59); + LOAD_SPRN(TBWL, 0x5a); /* these two have separate R/W regs */ + LOAD_SPRN(TBWU, 0x5b); + + blr + + + +/* cache flushing code. copied from arch/ppc/boot/util.S */ +#define NUM_CACHE_LINES (128*8) + +/* + * Flush data cache + * Do this by just reading lots of stuff into the cache. + */ +flush_data_cache: + lis r3,CONFIG_KERNEL_START@h + ori r3,r3,CONFIG_KERNEL_START@l + li r4,NUM_CACHE_LINES + mtctr r4 +1: + lwz r4,0(r3) + addi r3,r3,L1_CACHE_BYTES /* Next line, please */ + bdnz 1b + blr diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 2dd415ff55a9..3bc201e07e6b 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -13,10 +13,9 @@ #undef DEBUG #include <linux/kernel.h> - +#include <linux/of_platform.h> #include <asm/io.h> #include <asm/prom.h> -#include <asm/of_platform.h> #include <asm/mpc52xx.h> @@ -76,44 +75,33 @@ mpc52xx_find_ipb_freq(struct device_node *node) EXPORT_SYMBOL(mpc52xx_find_ipb_freq); +/* + * Configure the XLB arbiter settings to match what Linux expects. + */ void __init -mpc52xx_setup_cpu(void) +mpc5200_setup_xlb_arbiter(void) { - struct mpc52xx_cdm __iomem *cdm; struct mpc52xx_xlb __iomem *xlb; - /* Map zones */ - cdm = mpc52xx_find_and_map("mpc5200-cdm"); xlb = mpc52xx_find_and_map("mpc5200-xlb"); - - if (!cdm || !xlb) { + if (!xlb) { printk(KERN_ERR __FILE__ ": " - "Error while mapping CDM/XLB during mpc52xx_setup_cpu. " + "Error mapping XLB in mpc52xx_setup_cpu(). " "Expect some abnormal behavior\n"); - goto unmap_regs; + return; } - /* Use internal 48 Mhz */ - out_8(&cdm->ext_48mhz_en, 0x00); - out_8(&cdm->fd_enable, 0x01); - if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */ - out_be16(&cdm->fd_counters, 0x0001); - else - out_be16(&cdm->fd_counters, 0x5555); - /* Configure the XLB Arbiter priorities */ out_be32(&xlb->master_pri_enable, 0xff); out_be32(&xlb->master_priority, 0x11111111); - /* Disable XLB pipelining */ - /* (cfr errate 292. We could do this only just before ATA PIO - transaction and re-enable it afterwards ...) */ + /* Disable XLB pipelining + * (cfr errate 292. We could do this only just before ATA PIO + * transaction and re-enable it afterwards ...) + */ out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS); - /* Unmap zones */ -unmap_regs: - if (cdm) iounmap(cdm); - if (xlb) iounmap(xlb); + iounmap(xlb); } void __init diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index fbfff95b4437..61100f270c68 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -18,19 +18,9 @@ #undef DEBUG -#include <linux/stddef.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/stddef.h> -#include <linux/delay.h> #include <linux/irq.h> -#include <linux/hardirq.h> - +#include <linux/of.h> #include <asm/io.h> -#include <asm/processor.h> -#include <asm/system.h> -#include <asm/irq.h> #include <asm/prom.h> #include <asm/mpc52xx.h> #include "mpc52xx_pic.h" @@ -242,12 +232,6 @@ static struct irq_chip mpc52xx_sdma_irqchip = { * irq_host */ -static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) -{ - pr_debug("%s: node=%p\n", __func__, node); - return mpc52xx_irqhost->host_data == node; -} - static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, u32 * intspec, unsigned int intsize, irq_hw_number_t * out_hwirq, @@ -368,7 +352,6 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, } static struct irq_host_ops mpc52xx_irqhost_ops = { - .match = mpc52xx_irqhost_match, .xlate = mpc52xx_irqhost_xlate, .map = mpc52xx_irqhost_map, }; @@ -420,14 +403,13 @@ void __init mpc52xx_init_irq(void) * hw irq information provided by the ofw to linux virq */ - mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, + mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, MPC52xx_IRQ_HIGHTESTHWIRQ, &mpc52xx_irqhost_ops, -1); if (!mpc52xx_irqhost) panic(__FILE__ ": Cannot allocate the IRQ host\n"); - mpc52xx_irqhost->host_data = picnode; printk(KERN_INFO "MPC52xx PIC is up and running!\n"); } diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index 89fde43895c5..541fbb815631 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -1,17 +1,30 @@ choice prompt "82xx Board Type" depends on PPC_82xx - default MPC82xx_ADS + default MPC8272_ADS -config MPC82xx_ADS - bool "Freescale MPC82xx ADS" +config MPC8272_ADS + bool "Freescale MPC8272 ADS" select DEFAULT_UIMAGE select PQ2ADS select 8272 select 8260 select FSL_SOC + select PQ2_ADS_PCI_PIC if PCI + select PPC_CPM_NEW_BINDING help - This option enables support for the MPC8272 ADS board + This option enables support for the MPC8272 ADS board + +config PQ2FADS + bool "Freescale PQ2FADS" + select DEFAULT_UIMAGE + select PQ2ADS + select 8260 + select FSL_SOC + select PQ2_ADS_PCI_PIC if PCI + select PPC_CPM_NEW_BINDING + help + This option enables support for the PQ2FADS board endchoice @@ -34,3 +47,6 @@ config 8272 help The MPC8272 CPM has a different internal dpram setup than other CPM2 devices + +config PQ2_ADS_PCI_PIC + bool diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile index d9fd4c84d2e0..68c8b0c9772b 100644 --- a/arch/powerpc/platforms/82xx/Makefile +++ b/arch/powerpc/platforms/82xx/Makefile @@ -1,5 +1,7 @@ # # Makefile for the PowerPC 82xx linux kernel. # -obj-$(CONFIG_PPC_82xx) += mpc82xx.o -obj-$(CONFIG_MPC82xx_ADS) += mpc82xx_ads.o +obj-$(CONFIG_MPC8272_ADS) += mpc8272_ads.o +obj-$(CONFIG_CPM2) += pq2.o +obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o +obj-$(CONFIG_PQ2FADS) += pq2fads.o diff --git a/arch/powerpc/platforms/82xx/m82xx_pci.h b/arch/powerpc/platforms/82xx/m82xx_pci.h index 9cd8893b5a32..65e38a7ff48f 100644 --- a/arch/powerpc/platforms/82xx/m82xx_pci.h +++ b/arch/powerpc/platforms/82xx/m82xx_pci.h @@ -8,8 +8,6 @@ * 2 of the License, or (at your option) any later version. */ -#include <asm/m8260_pci.h> - #define SIU_INT_IRQ1 ((uint)0x13 + CPM_IRQ_OFFSET) #ifndef _IO_BASE diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c new file mode 100644 index 000000000000..fd83440eb287 --- /dev/null +++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c @@ -0,0 +1,196 @@ +/* + * MPC8272 ADS board support + * + * Copyright 2007 Freescale Semiconductor, Inc. + * Author: Scott Wood <scottwood@freescale.com> + * + * Based on code by Vitaly Bordug <vbordug@ru.mvista.com> + * Copyright (c) 2006 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/fsl_devices.h> +#include <linux/of_platform.h> +#include <linux/io.h> + +#include <asm/cpm2.h> +#include <asm/udbg.h> +#include <asm/machdep.h> +#include <asm/time.h> + +#include <platforms/82xx/pq2.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/cpm2_pic.h> + +#include "pq2ads.h" +#include "pq2.h" + +static void __init mpc8272_ads_pic_init(void) +{ + struct device_node *np = of_find_compatible_node(NULL, NULL, + "fsl,cpm2-pic"); + if (!np) { + printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); + return; + } + + cpm2_pic_init(np); + of_node_put(np); + + /* Initialize stuff for the 82xx CPLD IC and install demux */ + pq2ads_pci_init_irq(); +} + +struct cpm_pin { + int port, pin, flags; +}; + +static struct cpm_pin mpc8272_ads_pins[] = { + /* SCC1 */ + {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* SCC4 */ + {3, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* FCC1 */ + {0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, + {2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* FCC2 */ + {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {2, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, +}; + +static void __init init_ioports(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mpc8272_ads_pins); i++) { + struct cpm_pin *pin = &mpc8272_ads_pins[i]; + cpm2_set_pin(pin->port, pin->pin, pin->flags); + } + + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK15, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK16, CPM_CLK_TX); +} + +static void __init mpc8272_ads_setup_arch(void) +{ + struct device_node *np; + __be32 __iomem *bcsr; + + if (ppc_md.progress) + ppc_md.progress("mpc8272_ads_setup_arch()", 0); + + cpm2_reset(); + + np = of_find_compatible_node(NULL, NULL, "fsl,mpc8272ads-bcsr"); + if (!np) { + printk(KERN_ERR "No bcsr in device tree\n"); + return; + } + + bcsr = of_iomap(np, 0); + if (!bcsr) { + printk(KERN_ERR "Cannot map BCSR registers\n"); + return; + } + + of_node_put(np); + + clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); + setbits32(&bcsr[1], BCSR1_FETH_RST); + + clrbits32(&bcsr[3], BCSR3_FETHIEN2); + setbits32(&bcsr[3], BCSR3_FETH2_RST); + + iounmap(bcsr); + + init_ioports(); + pq2_init_pci(); + + if (ppc_md.progress) + ppc_md.progress("mpc8272_ads_setup_arch(), finish", 0); +} + +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + if (!machine_is(mpc8272_ads)) + return 0; + + /* Publish the QE devices */ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + return 0; +} +device_initcall(declare_of_platform_devices); + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc8272_ads_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + return of_flat_dt_is_compatible(root, "fsl,mpc8272ads"); +} + +define_machine(mpc8272_ads) +{ + .name = "Freescale MPC8272 ADS", + .probe = mpc8272_ads_probe, + .setup_arch = mpc8272_ads_setup_arch, + .init_IRQ = mpc8272_ads_pic_init, + .get_irq = cpm2_get_irq, + .calibrate_decr = generic_calibrate_decr, + .restart = pq2_restart, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c deleted file mode 100644 index cc9900d2e5ee..000000000000 --- a/arch/powerpc/platforms/82xx/mpc82xx.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * MPC82xx setup and early boot code plus other random bits. - * - * Author: Vitaly Bordug <vbordug@ru.mvista.com> - * - * Copyright (c) 2006 MontaVista Software, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <linux/stddef.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/reboot.h> -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/kdev_t.h> -#include <linux/major.h> -#include <linux/console.h> -#include <linux/delay.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> -#include <linux/initrd.h> -#include <linux/module.h> -#include <linux/fsl_devices.h> -#include <linux/fs_uart_pd.h> - -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/atomic.h> -#include <asm/time.h> -#include <asm/io.h> -#include <asm/machdep.h> -#include <asm/bootinfo.h> -#include <asm/pci-bridge.h> -#include <asm/mpc8260.h> -#include <asm/irq.h> -#include <mm/mmu_decl.h> -#include <asm/prom.h> -#include <asm/cpm2.h> -#include <asm/udbg.h> -#include <asm/i8259.h> -#include <linux/fs_enet_pd.h> - -#include <sysdev/fsl_soc.h> -#include <sysdev/cpm2_pic.h> - -#include "pq2ads.h" - -static int __init get_freq(char *name, unsigned long *val) -{ - struct device_node *cpu; - const unsigned int *fp; - int found = 0; - - /* The cpu node should have timebase and clock frequency properties */ - cpu = of_find_node_by_type(NULL, "cpu"); - - if (cpu) { - fp = of_get_property(cpu, name, NULL); - if (fp) { - found = 1; - *val = *fp; - } - - of_node_put(cpu); - } - - return found; -} - -void __init m82xx_calibrate_decr(void) -{ - ppc_tb_freq = 125000000; - if (!get_freq("bus-frequency", &ppc_tb_freq)) { - printk(KERN_ERR "WARNING: Estimating decrementer frequency " - "(not found)\n"); - } - ppc_tb_freq /= 4; - ppc_proc_freq = 1000000000; - if (!get_freq("clock-frequency", &ppc_proc_freq)) - printk(KERN_ERR "WARNING: Estimating processor frequency" - "(not found)\n"); -} - -void mpc82xx_ads_show_cpuinfo(struct seq_file *m) -{ - uint pvid, svid, phid1; - uint memsize = total_memory; - - pvid = mfspr(SPRN_PVR); - svid = mfspr(SPRN_SVR); - - seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - seq_printf(m, "Machine\t\t: %s\n", CPUINFO_MACHINE); - seq_printf(m, "PVR\t\t: 0x%x\n", pvid); - seq_printf(m, "SVR\t\t: 0x%x\n", svid); - - /* Display cpu Pll setting */ - phid1 = mfspr(SPRN_HID1); - seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); - - /* Display the amount of memory */ - seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); -} diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c deleted file mode 100644 index 2d1b05b9f8ef..000000000000 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ /dev/null @@ -1,641 +0,0 @@ -/* - * MPC82xx_ads setup and early boot code plus other random bits. - * - * Author: Vitaly Bordug <vbordug@ru.mvista.com> - * m82xx_restart fix by Wade Farnsworth <wfarnsworth@mvista.com> - * - * Copyright (c) 2006 MontaVista Software, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <linux/stddef.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/reboot.h> -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/kdev_t.h> -#include <linux/major.h> -#include <linux/console.h> -#include <linux/delay.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> -#include <linux/initrd.h> -#include <linux/module.h> -#include <linux/fsl_devices.h> -#include <linux/fs_uart_pd.h> - -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/atomic.h> -#include <asm/time.h> -#include <asm/io.h> -#include <asm/machdep.h> -#include <asm/bootinfo.h> -#include <asm/pci-bridge.h> -#include <asm/mpc8260.h> -#include <asm/irq.h> -#include <mm/mmu_decl.h> -#include <asm/prom.h> -#include <asm/cpm2.h> -#include <asm/udbg.h> -#include <asm/i8259.h> -#include <linux/fs_enet_pd.h> - -#include <sysdev/fsl_soc.h> -#include <sysdev/cpm2_pic.h> - -#include "pq2ads.h" - -#ifdef CONFIG_PCI -static uint pci_clk_frq; -static struct { - unsigned long *pci_int_stat_reg; - unsigned long *pci_int_mask_reg; -} pci_regs; - -static unsigned long pci_int_base; -static struct irq_host *pci_pic_host; -static struct device_node *pci_pic_node; -#endif - -static void __init mpc82xx_ads_pic_init(void) -{ - struct device_node *np = of_find_compatible_node(NULL, "cpm-pic", "CPM2"); - struct resource r; - cpm2_map_t *cpm_reg; - - if (np == NULL) { - printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); - return; - } - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_ERR "PIC init: invalid resource\n"); - of_node_put(np); - return; - } - cpm2_pic_init(np); - of_node_put(np); - - /* Initialize the default interrupt mapping priorities, - * in case the boot rom changed something on us. - */ - cpm_reg = (cpm2_map_t *) ioremap(get_immrbase(), sizeof(cpm2_map_t)); - cpm_reg->im_intctl.ic_siprr = 0x05309770; - iounmap(cpm_reg); -#ifdef CONFIG_PCI - /* Initialize stuff for the 82xx CPLD IC and install demux */ - m82xx_pci_init_irq(); -#endif -} - -static void init_fcc1_ioports(struct fs_platform_info *fpi) -{ - struct io_port *io; - u32 tempval; - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - struct device_node *np; - struct resource r; - u32 *bcsr; - - np = of_find_node_by_type(NULL, "memory"); - if (!np) { - printk(KERN_INFO "No memory node in device tree\n"); - return; - } - if (of_address_to_resource(np, 1, &r)) { - printk(KERN_INFO "No memory reg property [1] in devicetree\n"); - return; - } - of_node_put(np); - bcsr = ioremap(r.start + 4, sizeof(u32)); - io = &immap->im_ioport; - - /* Enable the PHY */ - clrbits32(bcsr, BCSR1_FETHIEN); - setbits32(bcsr, BCSR1_FETH_RST); - - /* FCC1 pins are on port A/C. */ - /* Configure port A and C pins for FCC1 Ethernet. */ - - tempval = in_be32(&io->iop_pdira); - tempval &= ~PA1_DIRA0; - tempval |= PA1_DIRA1; - out_be32(&io->iop_pdira, tempval); - - tempval = in_be32(&io->iop_psora); - tempval &= ~PA1_PSORA0; - tempval |= PA1_PSORA1; - out_be32(&io->iop_psora, tempval); - - setbits32(&io->iop_ppara, PA1_DIRA0 | PA1_DIRA1); - - /* Alter clocks */ - tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8); - - clrbits32(&io->iop_psorc, tempval); - clrbits32(&io->iop_pdirc, tempval); - setbits32(&io->iop_pparc, tempval); - - cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_rx, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_tx, CPM_CLK_TX); - - iounmap(bcsr); - iounmap(immap); -} - -static void init_fcc2_ioports(struct fs_platform_info *fpi) -{ - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - struct device_node *np; - struct resource r; - u32 *bcsr; - - struct io_port *io; - u32 tempval; - - np = of_find_node_by_type(NULL, "memory"); - if (!np) { - printk(KERN_INFO "No memory node in device tree\n"); - return; - } - if (of_address_to_resource(np, 1, &r)) { - printk(KERN_INFO "No memory reg property [1] in devicetree\n"); - return; - } - of_node_put(np); - io = &immap->im_ioport; - bcsr = ioremap(r.start + 12, sizeof(u32)); - - /* Enable the PHY */ - clrbits32(bcsr, BCSR3_FETHIEN2); - setbits32(bcsr, BCSR3_FETH2_RST); - - /* FCC2 are port B/C. */ - /* Configure port A and C pins for FCC2 Ethernet. */ - - tempval = in_be32(&io->iop_pdirb); - tempval &= ~PB2_DIRB0; - tempval |= PB2_DIRB1; - out_be32(&io->iop_pdirb, tempval); - - tempval = in_be32(&io->iop_psorb); - tempval &= ~PB2_PSORB0; - tempval |= PB2_PSORB1; - out_be32(&io->iop_psorb, tempval); - - setbits32(&io->iop_pparb, PB2_DIRB0 | PB2_DIRB1); - - tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8); - - /* Alter clocks */ - clrbits32(&io->iop_psorc, tempval); - clrbits32(&io->iop_pdirc, tempval); - setbits32(&io->iop_pparc, tempval); - - cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_rx, CPM_CLK_RX); - cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_tx, CPM_CLK_TX); - - iounmap(bcsr); - iounmap(immap); -} - -void init_fcc_ioports(struct fs_platform_info *fpi) -{ - int fcc_no = fs_get_fcc_index(fpi->fs_no); - - switch (fcc_no) { - case 0: - init_fcc1_ioports(fpi); - break; - case 1: - init_fcc2_ioports(fpi); - break; - default: - printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n"); - return; - } -} - -static void init_scc1_uart_ioports(struct fs_uart_platform_info *data) -{ - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - - /* SCC1 is only on port D */ - setbits32(&immap->im_ioport.iop_ppard, 0x00000003); - clrbits32(&immap->im_ioport.iop_psord, 0x00000001); - setbits32(&immap->im_ioport.iop_psord, 0x00000002); - clrbits32(&immap->im_ioport.iop_pdird, 0x00000001); - setbits32(&immap->im_ioport.iop_pdird, 0x00000002); - - clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx))); - clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx))); - setbits32(&immap->im_cpmux.cmx_scr, - ((data->clk_tx - 1) << (4 - data->clk_tx))); - setbits32(&immap->im_cpmux.cmx_scr, - ((data->clk_rx - 1) << (4 - data->clk_rx))); - - iounmap(immap); -} - -static void init_scc4_uart_ioports(struct fs_uart_platform_info *data) -{ - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - - setbits32(&immap->im_ioport.iop_ppard, 0x00000600); - clrbits32(&immap->im_ioport.iop_psord, 0x00000600); - clrbits32(&immap->im_ioport.iop_pdird, 0x00000200); - setbits32(&immap->im_ioport.iop_pdird, 0x00000400); - - clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx))); - clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx))); - setbits32(&immap->im_cpmux.cmx_scr, - ((data->clk_tx - 1) << (4 - data->clk_tx))); - setbits32(&immap->im_cpmux.cmx_scr, - ((data->clk_rx - 1) << (4 - data->clk_rx))); - - iounmap(immap); -} - -void init_scc_ioports(struct fs_uart_platform_info *data) -{ - int scc_no = fs_get_scc_index(data->fs_no); - - switch (scc_no) { - case 0: - init_scc1_uart_ioports(data); - data->brg = data->clk_rx; - break; - case 3: - init_scc4_uart_ioports(data); - data->brg = data->clk_rx; - break; - default: - printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); - return; - } -} - -void __init m82xx_board_setup(void) -{ - cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); - struct device_node *np; - struct resource r; - u32 *bcsr; - - np = of_find_node_by_type(NULL, "memory"); - if (!np) { - printk(KERN_INFO "No memory node in device tree\n"); - return; - } - if (of_address_to_resource(np, 1, &r)) { - printk(KERN_INFO "No memory reg property [1] in devicetree\n"); - return; - } - of_node_put(np); - bcsr = ioremap(r.start + 4, sizeof(u32)); - /* Enable the 2nd UART port */ - clrbits32(bcsr, BCSR1_RS232_EN2); - -#ifdef CONFIG_SERIAL_CPM_SCC1 - clrbits32((u32 *) & immap->im_scc[0].scc_sccm, - UART_SCCM_TX | UART_SCCM_RX); - clrbits32((u32 *) & immap->im_scc[0].scc_gsmrl, - SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - -#ifdef CONFIG_SERIAL_CPM_SCC2 - clrbits32((u32 *) & immap->im_scc[1].scc_sccm, - UART_SCCM_TX | UART_SCCM_RX); - clrbits32((u32 *) & immap->im_scc[1].scc_gsmrl, - SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - -#ifdef CONFIG_SERIAL_CPM_SCC3 - clrbits32((u32 *) & immap->im_scc[2].scc_sccm, - UART_SCCM_TX | UART_SCCM_RX); - clrbits32((u32 *) & immap->im_scc[2].scc_gsmrl, - SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - -#ifdef CONFIG_SERIAL_CPM_SCC4 - clrbits32((u32 *) & immap->im_scc[3].scc_sccm, - UART_SCCM_TX | UART_SCCM_RX); - clrbits32((u32 *) & immap->im_scc[3].scc_gsmrl, - SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - - iounmap(bcsr); - iounmap(immap); -} - -#ifdef CONFIG_PCI -static void m82xx_pci_mask_irq(unsigned int irq) -{ - int bit = irq - pci_int_base; - - *pci_regs.pci_int_mask_reg |= (1 << (31 - bit)); - return; -} - -static void m82xx_pci_unmask_irq(unsigned int irq) -{ - int bit = irq - pci_int_base; - - *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit)); - return; -} - -static void m82xx_pci_mask_and_ack(unsigned int irq) -{ - int bit = irq - pci_int_base; - - *pci_regs.pci_int_mask_reg |= (1 << (31 - bit)); - return; -} - -static void m82xx_pci_end_irq(unsigned int irq) -{ - int bit = irq - pci_int_base; - - *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit)); - return; -} - -struct hw_interrupt_type m82xx_pci_ic = { - .typename = "MPC82xx ADS PCI", - .name = "MPC82xx ADS PCI", - .enable = m82xx_pci_unmask_irq, - .disable = m82xx_pci_mask_irq, - .ack = m82xx_pci_mask_and_ack, - .end = m82xx_pci_end_irq, - .mask = m82xx_pci_mask_irq, - .mask_ack = m82xx_pci_mask_and_ack, - .unmask = m82xx_pci_unmask_irq, - .eoi = m82xx_pci_end_irq, -}; - -static void -m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc) -{ - unsigned long stat, mask, pend; - int bit; - - for (;;) { - stat = *pci_regs.pci_int_stat_reg; - mask = *pci_regs.pci_int_mask_reg; - pend = stat & ~mask & 0xf0000000; - if (!pend) - break; - for (bit = 0; pend != 0; ++bit, pend <<= 1) { - if (pend & 0x80000000) - __do_IRQ(pci_int_base + bit); - } - } -} - -static int pci_pic_host_match(struct irq_host *h, struct device_node *node) -{ - return node == pci_pic_node; -} - -static int pci_pic_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - get_irq_desc(virq)->status |= IRQ_LEVEL; - set_irq_chip(virq, &m82xx_pci_ic); - return 0; -} - -static void pci_host_unmap(struct irq_host *h, unsigned int virq) -{ - /* remove chip and handler */ - set_irq_chip(virq, NULL); -} - -static struct irq_host_ops pci_pic_host_ops = { - .match = pci_pic_host_match, - .map = pci_pic_host_map, - .unmap = pci_host_unmap, -}; - -void m82xx_pci_init_irq(void) -{ - int irq; - cpm2_map_t *immap; - struct device_node *np; - struct resource r; - const u32 *regs; - unsigned int size; - const u32 *irq_map; - int i; - unsigned int irq_max, irq_min; - - if ((np = of_find_node_by_type(NULL, "soc")) == NULL) { - printk(KERN_INFO "No SOC node in device tree\n"); - return; - } - memset(&r, 0, sizeof(r)); - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_INFO "No SOC reg property in device tree\n"); - return; - } - immap = ioremap(r.start, sizeof(*immap)); - of_node_put(np); - - /* install the demultiplexer for the PCI cascade interrupt */ - np = of_find_node_by_type(NULL, "pci"); - if (!np) { - printk(KERN_INFO "No pci node on device tree\n"); - iounmap(immap); - return; - } - irq_map = of_get_property(np, "interrupt-map", &size); - if ((!irq_map) || (size <= 7)) { - printk(KERN_INFO "No interrupt-map property of pci node\n"); - iounmap(immap); - return; - } - size /= sizeof(irq_map[0]); - for (i = 0, irq_max = 0, irq_min = 512; i < size; i += 7, irq_map += 7) { - if (irq_map[5] < irq_min) - irq_min = irq_map[5]; - if (irq_map[5] > irq_max) - irq_max = irq_map[5]; - } - pci_int_base = irq_min; - irq = irq_of_parse_and_map(np, 0); - set_irq_chained_handler(irq, m82xx_pci_irq_demux); - of_node_put(np); - np = of_find_node_by_type(NULL, "pci-pic"); - if (!np) { - printk(KERN_INFO "No pci pic node on device tree\n"); - iounmap(immap); - return; - } - pci_pic_node = of_node_get(np); - /* PCI interrupt controller registers: status and mask */ - regs = of_get_property(np, "reg", &size); - if ((!regs) || (size <= 2)) { - printk(KERN_INFO "No reg property in pci pic node\n"); - iounmap(immap); - return; - } - pci_regs.pci_int_stat_reg = - ioremap(regs[0], sizeof(*pci_regs.pci_int_stat_reg)); - pci_regs.pci_int_mask_reg = - ioremap(regs[1], sizeof(*pci_regs.pci_int_mask_reg)); - of_node_put(np); - /* configure chip select for PCI interrupt controller */ - immap->im_memctl.memc_br3 = regs[0] | 0x00001801; - immap->im_memctl.memc_or3 = 0xffff8010; - /* make PCI IRQ level sensitive */ - immap->im_intctl.ic_siexr &= ~(1 << (14 - (irq - SIU_INT_IRQ1))); - - /* mask all PCI interrupts */ - *pci_regs.pci_int_mask_reg |= 0xfff00000; - iounmap(immap); - pci_pic_host = - irq_alloc_host(IRQ_HOST_MAP_LINEAR, irq_max - irq_min + 1, - &pci_pic_host_ops, irq_max + 1); - return; -} - -static int m82xx_pci_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn) -{ - if (bus == 0 && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; - else - return PCIBIOS_SUCCESSFUL; -} - -static void __init mpc82xx_add_bridge(struct device_node *np) -{ - int len; - struct pci_controller *hose; - struct resource r; - const int *bus_range; - const uint *ptr; - - memset(&r, 0, sizeof(r)); - if (of_address_to_resource(np, 0, &r)) { - printk(KERN_INFO "No PCI reg property in device tree\n"); - return; - } - if (!(ptr = of_get_property(np, "clock-frequency", NULL))) { - printk(KERN_INFO "No clock-frequency property in PCI node"); - return; - } - pci_clk_frq = *ptr; - of_node_put(np); - bus_range = of_get_property(np, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume" - " bus 0\n", np->full_name); - } - - pci_assign_all_buses = 1; - - hose = pcibios_alloc_controller(np); - - if (!hose) - return; - - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; - - setup_indirect_pci(hose, - r.start + offsetof(pci_cpm2_t, pci_cfg_addr), - r.start + offsetof(pci_cpm2_t, pci_cfg_data), - 0); - - pci_process_bridge_OF_ranges(hose, np, 1); -} -#endif - -/* - * Setup the architecture - */ -static void __init mpc82xx_ads_setup_arch(void) -{ -#ifdef CONFIG_PCI - struct device_node *np; -#endif - - if (ppc_md.progress) - ppc_md.progress("mpc82xx_ads_setup_arch()", 0); - cpm2_reset(); - - /* Map I/O region to a 256MB BAT */ - - m82xx_board_setup(); - -#ifdef CONFIG_PCI - ppc_md.pci_exclude_device = m82xx_pci_exclude_device; - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - mpc82xx_add_bridge(np); - - of_node_put(np); -#endif - -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif - - if (ppc_md.progress) - ppc_md.progress("mpc82xx_ads_setup_arch(), finish", 0); -} - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init mpc82xx_ads_probe(void) -{ - /* We always match for now, eventually we should look at - * the flat dev tree to ensure this is the board we are - * supposed to run on - */ - return 1; -} - -#define RMR_CSRE 0x00000001 -static void m82xx_restart(char *cmd) -{ - __volatile__ unsigned char dummy; - - local_irq_disable(); - ((cpm2_map_t *) cpm2_immr)->im_clkrst.car_rmr |= RMR_CSRE; - - /* Clear the ME,EE,IR & DR bits in MSR to cause checkstop */ - mtmsr(mfmsr() & ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR)); - dummy = ((cpm2_map_t *) cpm2_immr)->im_clkrst.res[0]; - printk("Restart failed\n"); - while (1) ; -} - -static void m82xx_halt(void) -{ - local_irq_disable(); - while (1) ; -} - -define_machine(mpc82xx_ads) -{ - .name = "MPC82xx ADS", - .probe = mpc82xx_ads_probe, - .setup_arch = mpc82xx_ads_setup_arch, - .init_IRQ = mpc82xx_ads_pic_init, - .show_cpuinfo = mpc82xx_ads_show_cpuinfo, - .get_irq = cpm2_get_irq, - .calibrate_decr = m82xx_calibrate_decr, - .restart = m82xx_restart,.halt = m82xx_halt, -}; diff --git a/arch/powerpc/platforms/82xx/pq2.c b/arch/powerpc/platforms/82xx/pq2.c new file mode 100644 index 000000000000..a497cbaa1ac5 --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2.c @@ -0,0 +1,82 @@ +/* + * Common PowerQUICC II code. + * + * Author: Scott Wood <scottwood@freescale.com> + * Copyright (c) 2007 Freescale Semiconductor + * + * Based on code by Vitaly Bordug <vbordug@ru.mvista.com> + * pq2_restart fix by Wade Farnsworth <wfarnsworth@mvista.com> + * Copyright (c) 2006 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <asm/cpm2.h> +#include <asm/io.h> +#include <asm/pci-bridge.h> +#include <asm/system.h> + +#include <platforms/82xx/pq2.h> + +#define RMR_CSRE 0x00000001 + +void pq2_restart(char *cmd) +{ + local_irq_disable(); + setbits32(&cpm2_immr->im_clkrst.car_rmr, RMR_CSRE); + + /* Clear the ME,EE,IR & DR bits in MSR to cause checkstop */ + mtmsr(mfmsr() & ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR)); + in_8(&cpm2_immr->im_clkrst.res[0]); + + panic("Restart failed\n"); +} + +#ifdef CONFIG_PCI +static int pq2_pci_exclude_device(struct pci_controller *hose, + u_char bus, u8 devfn) +{ + if (bus == 0 && PCI_SLOT(devfn) == 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return PCIBIOS_SUCCESSFUL; +} + +static void __init pq2_pci_add_bridge(struct device_node *np) +{ + struct pci_controller *hose; + struct resource r; + + if (of_address_to_resource(np, 0, &r) || r.end - r.start < 0x10b) + goto err; + + pci_assign_all_buses = 1; + + hose = pcibios_alloc_controller(np); + if (!hose) + return; + + hose->arch_data = np; + + setup_indirect_pci(hose, r.start + 0x100, r.start + 0x104, 0); + pci_process_bridge_OF_ranges(hose, np, 1); + + return; + +err: + printk(KERN_ERR "No valid PCI reg property in device tree\n"); +} + +void __init pq2_init_pci(void) +{ + struct device_node *np = NULL; + + ppc_md.pci_exclude_device = pq2_pci_exclude_device; + + while ((np = of_find_compatible_node(np, NULL, "fsl,pq2-pci"))) + pq2_pci_add_bridge(np); +} +#endif diff --git a/arch/powerpc/platforms/82xx/pq2.h b/arch/powerpc/platforms/82xx/pq2.h new file mode 100644 index 000000000000..a41f84ae2325 --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2.h @@ -0,0 +1,20 @@ +#ifndef _PQ2_H +#define _PQ2_H + +void pq2_restart(char *cmd); + +#ifdef CONFIG_PCI +int pq2ads_pci_init_irq(void); +void pq2_init_pci(void); +#else +static inline int pq2ads_pci_init_irq(void) +{ + return 0; +} + +static inline void pq2_init_pci(void) +{ +} +#endif + +#endif diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c new file mode 100644 index 000000000000..a8013816125c --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -0,0 +1,195 @@ +/* + * PQ2 ADS-style PCI interrupt controller + * + * Copyright 2007 Freescale Semiconductor, Inc. + * Author: Scott Wood <scottwood@freescale.com> + * + * Loosely based on mpc82xx ADS support by Vitaly Bordug <vbordug@ru.mvista.com> + * Copyright (c) 2006 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/irq.h> +#include <linux/types.h> +#include <linux/bootmem.h> + +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/cpm2.h> + +#include "pq2.h" + +static DEFINE_SPINLOCK(pci_pic_lock); + +struct pq2ads_pci_pic { + struct device_node *node; + struct irq_host *host; + + struct { + u32 stat; + u32 mask; + } __iomem *regs; +}; + +#define NUM_IRQS 32 + +static void pq2ads_pci_mask_irq(unsigned int virq) +{ + struct pq2ads_pci_pic *priv = get_irq_chip_data(virq); + int irq = NUM_IRQS - virq_to_hw(virq) - 1; + + if (irq != -1) { + unsigned long flags; + spin_lock_irqsave(&pci_pic_lock, flags); + + setbits32(&priv->regs->mask, 1 << irq); + mb(); + + spin_unlock_irqrestore(&pci_pic_lock, flags); + } +} + +static void pq2ads_pci_unmask_irq(unsigned int virq) +{ + struct pq2ads_pci_pic *priv = get_irq_chip_data(virq); + int irq = NUM_IRQS - virq_to_hw(virq) - 1; + + if (irq != -1) { + unsigned long flags; + + spin_lock_irqsave(&pci_pic_lock, flags); + clrbits32(&priv->regs->mask, 1 << irq); + spin_unlock_irqrestore(&pci_pic_lock, flags); + } +} + +static struct irq_chip pq2ads_pci_ic = { + .typename = "PQ2 ADS PCI", + .name = "PQ2 ADS PCI", + .end = pq2ads_pci_unmask_irq, + .mask = pq2ads_pci_mask_irq, + .mask_ack = pq2ads_pci_mask_irq, + .ack = pq2ads_pci_mask_irq, + .unmask = pq2ads_pci_unmask_irq, + .enable = pq2ads_pci_unmask_irq, + .disable = pq2ads_pci_mask_irq +}; + +static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc) +{ + struct pq2ads_pci_pic *priv = desc->handler_data; + u32 stat, mask, pend; + int bit; + + for (;;) { + stat = in_be32(&priv->regs->stat); + mask = in_be32(&priv->regs->mask); + + pend = stat & ~mask; + + if (!pend) + break; + + for (bit = 0; pend != 0; ++bit, pend <<= 1) { + if (pend & 0x80000000) { + int virq = irq_linear_revmap(priv->host, bit); + generic_handle_irq(virq); + } + } + } +} + +static int pci_pic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + get_irq_desc(virq)->status |= IRQ_LEVEL; + set_irq_chip_data(virq, h->host_data); + set_irq_chip(virq, &pq2ads_pci_ic); + return 0; +} + +static void pci_host_unmap(struct irq_host *h, unsigned int virq) +{ + /* remove chip and handler */ + set_irq_chip_data(virq, NULL); + set_irq_chip(virq, NULL); +} + +static struct irq_host_ops pci_pic_host_ops = { + .map = pci_pic_host_map, + .unmap = pci_host_unmap, +}; + +int __init pq2ads_pci_init_irq(void) +{ + struct pq2ads_pci_pic *priv; + struct irq_host *host; + struct device_node *np; + int ret = -ENODEV; + int irq; + + np = of_find_compatible_node(NULL, NULL, "fsl,pq2ads-pci-pic"); + if (!np) { + printk(KERN_ERR "No pci pic node in device tree.\n"); + of_node_put(np); + goto out; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq == NO_IRQ) { + printk(KERN_ERR "No interrupt in pci pic node.\n"); + of_node_put(np); + goto out; + } + + priv = alloc_bootmem(sizeof(struct pq2ads_pci_pic)); + if (!priv) { + of_node_put(np); + ret = -ENOMEM; + goto out_unmap_irq; + } + + /* PCI interrupt controller registers: status and mask */ + priv->regs = of_iomap(np, 0); + if (!priv->regs) { + printk(KERN_ERR "Cannot map PCI PIC registers.\n"); + goto out_free_bootmem; + } + + /* mask all PCI interrupts */ + out_be32(&priv->regs->mask, ~0); + mb(); + + host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, NUM_IRQS, + &pci_pic_host_ops, NUM_IRQS); + if (!host) { + ret = -ENOMEM; + goto out_unmap_regs; + } + + host->host_data = priv; + + priv->host = host; + host->host_data = priv; + set_irq_data(irq, priv); + set_irq_chained_handler(irq, pq2ads_pci_irq_demux); + + of_node_put(np); + return 0; + +out_unmap_regs: + iounmap(priv->regs); +out_free_bootmem: + free_bootmem((unsigned long)priv, + sizeof(sizeof(struct pq2ads_pci_pic))); + of_node_put(np); +out_unmap_irq: + irq_dispose_mapping(irq); +out: + return ret; +} diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h index 5b5cca6c8c88..984db42cc8e7 100644 --- a/arch/powerpc/platforms/82xx/pq2ads.h +++ b/arch/powerpc/platforms/82xx/pq2ads.h @@ -23,11 +23,6 @@ #define __MACH_ADS8260_DEFS #include <linux/seq_file.h> -#include <asm/ppcboot.h> - -/* For our show_cpuinfo hooks. */ -#define CPUINFO_VENDOR "Freescale Semiconductor" -#define CPUINFO_MACHINE "PQ2 ADS PowerPC" /* Backword-compatibility stuff for the drivers */ #define CPM_MAP_ADDR ((uint)0xf0000000) @@ -58,9 +53,5 @@ #define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) #define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET) -void m82xx_pci_init_irq(void); -void mpc82xx_ads_show_cpuinfo(struct seq_file*); -void m82xx_calibrate_decr(void); - #endif /* __MACH_ADS8260_DEFS */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/platforms/82xx/pq2fads.c b/arch/powerpc/platforms/82xx/pq2fads.c new file mode 100644 index 000000000000..4f457a9c79ae --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2fads.c @@ -0,0 +1,198 @@ +/* + * PQ2FADS board support + * + * Copyright 2007 Freescale Semiconductor, Inc. + * Author: Scott Wood <scottwood@freescale.com> + * + * Loosely based on mp82xx ADS support by Vitaly Bordug <vbordug@ru.mvista.com> + * Copyright (c) 2006 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/fsl_devices.h> + +#include <asm/io.h> +#include <asm/cpm2.h> +#include <asm/udbg.h> +#include <asm/machdep.h> +#include <asm/of_platform.h> +#include <asm/time.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/cpm2_pic.h> + +#include "pq2ads.h" +#include "pq2.h" + +static void __init pq2fads_pic_init(void) +{ + struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); + if (!np) { + printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); + return; + } + + cpm2_pic_init(np); + of_node_put(np); + + /* Initialize stuff for the 82xx CPLD IC and install demux */ + pq2ads_pci_init_irq(); +} + +struct cpm_pin { + int port, pin, flags; +}; + +static struct cpm_pin pq2fads_pins[] = { + /* SCC1 */ + {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* SCC2 */ + {3, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* FCC2 */ + {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* FCC3 */ + {1, 4, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 6, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 7, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 9, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 12, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 13, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 14, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 15, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, +}; + +static void __init init_ioports(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pq2fads_pins); i++) { + struct cpm_pin *pin = &pq2fads_pins[i]; + cpm2_set_pin(pin->port, pin->pin, pin->flags); + } + + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK15, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK16, CPM_CLK_TX); +} + +static void __init pq2fads_setup_arch(void) +{ + struct device_node *np; + __be32 __iomem *bcsr; + + if (ppc_md.progress) + ppc_md.progress("pq2fads_setup_arch()", 0); + + cpm2_reset(); + + np = of_find_compatible_node(NULL, NULL, "fsl,pq2fads-bcsr"); + if (!np) { + printk(KERN_ERR "No fsl,pq2fads-bcsr in device tree\n"); + return; + } + + bcsr = of_iomap(np, 0); + if (!bcsr) { + printk(KERN_ERR "Cannot map BCSR registers\n"); + return; + } + + of_node_put(np); + + /* Enable the serial and ethernet ports */ + + clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); + setbits32(&bcsr[1], BCSR1_FETH_RST); + + clrbits32(&bcsr[3], BCSR3_FETHIEN2); + setbits32(&bcsr[3], BCSR3_FETH2_RST); + + iounmap(bcsr); + + init_ioports(); + + /* Enable external IRQs */ + clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_siumcr, 0x0c000000); + + pq2_init_pci(); + + if (ppc_md.progress) + ppc_md.progress("pq2fads_setup_arch(), finish", 0); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init pq2fads_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + return of_flat_dt_is_compatible(root, "fsl,pq2fads"); +} + +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + if (!machine_is(pq2fads)) + return 0; + + /* Publish the QE devices */ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + return 0; +} +device_initcall(declare_of_platform_devices); + +define_machine(pq2fads) +{ + .name = "Freescale PQ2FADS", + .probe = pq2fads_probe, + .setup_arch = pq2fads_setup_arch, + .init_IRQ = pq2fads_pic_init, + .get_irq = cpm2_get_irq, + .calibrate_decr = generic_calibrate_decr, + .restart = pq2_restart, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c index 3edfe170a03b..33766b8f2594 100644 --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c @@ -43,10 +43,8 @@ static void __init mpc8313_rdb_setup_arch(void) ppc_md.progress("mpc8313_rdb_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif mpc831x_usb_cfg(); } diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 2c8e641a739b..972fa8528a8c 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -32,7 +32,6 @@ #include <asm/io.h> #include <asm/machdep.h> #include <asm/ipic.h> -#include <asm/bootinfo.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/udbg.h> @@ -74,9 +73,8 @@ static void __init mpc832x_sys_setup_arch(void) } #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif #ifdef CONFIG_QUICC_ENGINE @@ -142,7 +140,7 @@ static void __init mpc832x_sys_init_IRQ(void) if (!np) return; - qe_ic_init(np, 0); + qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); of_node_put(np); #endif /* CONFIG_QUICC_ENGINE */ } diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 090906170a41..fbca336aa0ae 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -15,6 +15,7 @@ */ #include <linux/pci.h> +#include <linux/spi/spi.h> #include <asm/of_platform.h> #include <asm/time.h> @@ -22,6 +23,7 @@ #include <asm/udbg.h> #include <asm/qe.h> #include <asm/qe_ic.h> +#include <sysdev/fsl_soc.h> #include "mpc83xx.h" @@ -32,6 +34,50 @@ #define DBG(fmt...) #endif +static void mpc83xx_spi_activate_cs(u8 cs, u8 polarity) +{ + pr_debug("%s %d %d\n", __func__, cs, polarity); + par_io_data_set(3, 13, polarity); +} + +static void mpc83xx_spi_deactivate_cs(u8 cs, u8 polarity) +{ + pr_debug("%s %d %d\n", __func__, cs, polarity); + par_io_data_set(3, 13, !polarity); +} + +static struct spi_board_info mpc832x_spi_boardinfo = { + .bus_num = 0x4c0, + .chip_select = 0, + .max_speed_hz = 50000000, + /* + * XXX: This is spidev (spi in userspace) stub, should + * be replaced by "mmc_spi" when mmc_spi will hit mainline. + */ + .modalias = "spidev", +}; + +static int __init mpc832x_spi_init(void) +{ + if (!machine_is(mpc832x_rdb)) + return 0; + + par_io_config_pin(3, 0, 3, 0, 1, 0); /* SPI1 MOSI, I/O */ + par_io_config_pin(3, 1, 3, 0, 1, 0); /* SPI1 MISO, I/O */ + par_io_config_pin(3, 2, 3, 0, 1, 0); /* SPI1 CLK, I/O */ + par_io_config_pin(3, 3, 2, 0, 1, 0); /* SPI1 SEL, I */ + + par_io_config_pin(3, 13, 1, 0, 0, 0); /* !SD_CS, O */ + par_io_config_pin(3, 14, 2, 0, 0, 0); /* SD_INSERT, I */ + par_io_config_pin(3, 15, 2, 0, 0, 0); /* SD_PROTECT,I */ + + return fsl_spi_init(&mpc832x_spi_boardinfo, 1, + mpc83xx_spi_activate_cs, + mpc83xx_spi_deactivate_cs); +} + +device_initcall(mpc832x_spi_init); + /* ************************************************************************ * * Setup the architecture @@ -47,10 +93,8 @@ static void __init mpc832x_rdb_setup_arch(void) ppc_md.progress("mpc832x_rdb_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif #ifdef CONFIG_QUICC_ENGINE @@ -107,7 +151,7 @@ void __init mpc832x_rdb_init_IRQ(void) if (!np) return; - qe_ic_init(np, 0); + qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); of_node_put(np); #endif /* CONFIG_QUICC_ENGINE */ } diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 47ba5446f63c..aa768199432d 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -30,7 +30,6 @@ #include <asm/io.h> #include <asm/machdep.h> #include <asm/ipic.h> -#include <asm/bootinfo.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/udbg.h> @@ -53,10 +52,8 @@ static void __init mpc834x_itx_setup_arch(void) ppc_md.progress("mpc834x_itx_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif mpc834x_usb_cfg(); diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 4c9ff9cadfe4..00aed7c2269e 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -30,7 +30,6 @@ #include <asm/io.h> #include <asm/machdep.h> #include <asm/ipic.h> -#include <asm/bootinfo.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/udbg.h> @@ -84,10 +83,8 @@ static void __init mpc834x_mds_setup_arch(void) ppc_md.progress("mpc834x_mds_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif mpc834xemds_usb_cfg(); diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 84b58934aafd..0f3855c95ff5 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -38,7 +38,6 @@ #include <asm/io.h> #include <asm/machdep.h> #include <asm/ipic.h> -#include <asm/bootinfo.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/udbg.h> @@ -80,9 +79,8 @@ static void __init mpc836x_mds_setup_arch(void) } #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") mpc83xx_add_bridge(np); - ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif #ifdef CONFIG_QUICC_ENGINE @@ -149,7 +147,7 @@ static void __init mpc836x_mds_init_IRQ(void) if (!np) return; - qe_ic_init(np, 0); + qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); of_node_put(np); #endif /* CONFIG_QUICC_ENGINE */ } diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 589ee55730f3..b778cb4f3fb5 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -49,8 +49,6 @@ */ extern int mpc83xx_add_bridge(struct device_node *dev); -extern int mpc83xx_exclude_device(struct pci_controller *hose, - u_char bus, u_char devfn); extern void mpc83xx_restart(char *cmd); extern long mpc83xx_time_init(void); extern int mpc834x_usb_cfg(void); diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 92069469de20..80425d7b14f8 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -33,13 +33,6 @@ #define DBG(x...) #endif -int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) -{ - if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; - return PCIBIOS_SUCCESSFUL; -} - int __init mpc83xx_add_bridge(struct device_node *dev) { int len; diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index f620171ad6b1..7748a3a426db 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -12,6 +12,7 @@ config MPC8540_ADS config MPC8560_ADS bool "Freescale MPC8560 ADS" select DEFAULT_UIMAGE + select PPC_CPM_NEW_BINDING help This option enables support for the MPC 8560 ADS board @@ -25,17 +26,17 @@ config MPC85xx_CDS config MPC85xx_MDS bool "Freescale MPC85xx MDS" select DEFAULT_UIMAGE -# select QUICC_ENGINE + select QUICC_ENGINE help This option enables support for the MPC85xx MDS board -config MPC8544_DS - bool "Freescale MPC8544 DS" +config MPC85xx_DS + bool "Freescale MPC85xx DS" select PPC_I8259 select DEFAULT_UIMAGE select FSL_ULI1575 help - This option enables support for the MPC8544 DS board + This option enables support for the MPC85xx DS (MPC8544 DS) board endchoice @@ -58,4 +59,4 @@ config MPC85xx select FSL_PCI if PCI select SERIAL_8250_SHARE_IRQ if SERIAL_8250 default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS \ - || MPC85xx_MDS || MPC8544_DS + || MPC85xx_MDS || MPC85xx_DS diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index d70f2d0f9d36..5eca92023ec8 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -1,9 +1,8 @@ # # Makefile for the PowerPC 85xx linux kernel. # -obj-$(CONFIG_PPC_85xx) += misc.o obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o -obj-$(CONFIG_MPC8544_DS) += mpc8544_ds.o +obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o diff --git a/arch/powerpc/platforms/85xx/misc.c b/arch/powerpc/platforms/85xx/misc.c deleted file mode 100644 index 4fe376e9c3b6..000000000000 --- a/arch/powerpc/platforms/85xx/misc.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * MPC85xx generic code. - * - * Maintained by Kumar Gala (see MAINTAINERS for contact information) - * - * Copyright 2005 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#include <linux/irq.h> -#include <linux/module.h> -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <sysdev/fsl_soc.h> - -static __be32 __iomem *rstcr; - -extern void abort(void); - -static int __init mpc85xx_rstcr(void) -{ - struct device_node *np; - np = of_find_node_by_name(NULL, "global-utilities"); - if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) { - const u32 *prop = of_get_property(np, "reg", NULL); - if (prop) { - /* map reset control register - * 0xE00B0 is offset of reset control register - */ - rstcr = ioremap(get_immrbase() + *prop + 0xB0, 0xff); - if (!rstcr) - printk (KERN_EMERG "Error: reset control " - "register not mapped!\n"); - } - } else - printk (KERN_INFO "rstcr compatible register does not exist!\n"); - if (np) - of_node_put(np); - return 0; -} - -arch_initcall(mpc85xx_rstcr); - -void mpc85xx_restart(char *cmd) -{ - local_irq_disable(); - if (rstcr) - /* set reset control register */ - out_be32(rstcr, 0x2); /* HRESET_REQ */ - abort(); -} diff --git a/arch/powerpc/platforms/85xx/mpc8540_ads.h b/arch/powerpc/platforms/85xx/mpc8540_ads.h deleted file mode 100644 index da82f4c0fdac..000000000000 --- a/arch/powerpc/platforms/85xx/mpc8540_ads.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * arch/powerpc/platforms/85xx/mpc8540_ads.h - * - * MPC8540ADS board definitions - * - * Maintainer: Kumar Gala <kumar.gala@freescale.com> - * - * Copyright 2004 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifndef __MACH_MPC8540ADS_H__ -#define __MACH_MPC8540ADS_H__ - -#include <linux/initrd.h> - -#define BOARD_CCSRBAR ((uint)0xe0000000) -#define BCSR_ADDR ((uint)0xf8000000) -#define BCSR_SIZE ((uint)(32 * 1024)) - -/* PCI interrupt controller */ -#define PIRQA MPC85xx_IRQ_EXT1 -#define PIRQB MPC85xx_IRQ_EXT2 -#define PIRQC MPC85xx_IRQ_EXT3 -#define PIRQD MPC85xx_IRQ_EXT4 - -/* Offset of CPM register space */ -#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET) - -#endif /* __MACH_MPC8540ADS_H__ */ diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h deleted file mode 100644 index 5b34deef12b5..000000000000 --- a/arch/powerpc/platforms/85xx/mpc85xx.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * arch/powerpc/platforms/85xx/mpc85xx.h - * - * MPC85xx soc definitions/function decls - * - * Maintainer: Kumar Gala <kumar.gala@freescale.com> - * - * Copyright 2005 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -extern void mpc85xx_restart(char *); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 40a828675c7b..bccdc25f83a2 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -17,26 +17,22 @@ #include <linux/kdev_t.h> #include <linux/delay.h> #include <linux/seq_file.h> +#include <linux/of_platform.h> #include <asm/system.h> #include <asm/time.h> #include <asm/machdep.h> #include <asm/pci-bridge.h> -#include <asm/mpc85xx.h> -#include <asm/prom.h> #include <asm/mpic.h> #include <mm/mmu_decl.h> #include <asm/udbg.h> #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> -#include "mpc85xx.h" #ifdef CONFIG_CPM2 -#include <linux/fs_enet_pd.h> #include <asm/cpm2.h> #include <sysdev/cpm2_pic.h> -#include <asm/fs_pd.h> #endif #ifdef CONFIG_PCI @@ -96,10 +92,10 @@ static void __init mpc85xx_ads_pic_init(void) #ifdef CONFIG_CPM2 /* Setup CPM2 PIC */ - np = of_find_node_by_type(NULL, "cpm-pic"); + np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); if (np == NULL) { - printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); - return; + printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); + return; } irq = irq_of_parse_and_map(np, 0); @@ -112,87 +108,80 @@ static void __init mpc85xx_ads_pic_init(void) * Setup the architecture */ #ifdef CONFIG_CPM2 -void init_fcc_ioports(struct fs_platform_info *fpi) +struct cpm_pin { + int port, pin, flags; +}; + +static struct cpm_pin mpc8560_ads_pins[] = { + /* SCC1 */ + {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* SCC2 */ + {3, 26, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {3, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + + /* FCC2 */ + {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK14 */ + {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK13 */ + + /* FCC3 */ + {1, 4, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 6, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 7, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 9, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 12, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 13, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 14, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 15, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, + {1, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {1, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, + {2, 16, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK16 */ + {2, 17, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK15 */ +}; + +static void __init init_ioports(void) { - struct io_port *io = cpm2_map(im_ioport); - int fcc_no = fs_get_fcc_index(fpi->fs_no); - int target; - u32 tempval; - - switch(fcc_no) { - case 1: - tempval = in_be32(&io->iop_pdirb); - tempval &= ~PB2_DIRB0; - tempval |= PB2_DIRB1; - out_be32(&io->iop_pdirb, tempval); - - tempval = in_be32(&io->iop_psorb); - tempval &= ~PB2_PSORB0; - tempval |= PB2_PSORB1; - out_be32(&io->iop_psorb, tempval); - - tempval = in_be32(&io->iop_pparb); - tempval |= (PB2_DIRB0 | PB2_DIRB1); - out_be32(&io->iop_pparb, tempval); - - target = CPM_CLK_FCC2; - break; - case 2: - tempval = in_be32(&io->iop_pdirb); - tempval &= ~PB3_DIRB0; - tempval |= PB3_DIRB1; - out_be32(&io->iop_pdirb, tempval); - - tempval = in_be32(&io->iop_psorb); - tempval &= ~PB3_PSORB0; - tempval |= PB3_PSORB1; - out_be32(&io->iop_psorb, tempval); - - tempval = in_be32(&io->iop_pparb); - tempval |= (PB3_DIRB0 | PB3_DIRB1); - out_be32(&io->iop_pparb, tempval); - - tempval = in_be32(&io->iop_pdirc); - tempval |= PC3_DIRC1; - out_be32(&io->iop_pdirc, tempval); - - tempval = in_be32(&io->iop_pparc); - tempval |= PC3_DIRC1; - out_be32(&io->iop_pparc, tempval); - - target = CPM_CLK_FCC3; - break; - default: - printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n"); - return; + int i; + + for (i = 0; i < ARRAY_SIZE(mpc8560_ads_pins); i++) { + struct cpm_pin *pin = &mpc8560_ads_pins[i]; + cpm2_set_pin(pin->port, pin->pin, pin->flags); } - /* Port C has clocks...... */ - tempval = in_be32(&io->iop_psorc); - tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8)); - out_be32(&io->iop_psorc, tempval); - - tempval = in_be32(&io->iop_pdirc); - tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8)); - out_be32(&io->iop_pdirc, tempval); - tempval = in_be32(&io->iop_pparc); - tempval |= (PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8)); - out_be32(&io->iop_pparc, tempval); - - cpm2_unmap(io); - - /* Configure Serial Interface clock routing. - * First, clear FCC bits to zero, - * then set the ones we want. - */ - cpm2_clk_setup(target, fpi->clk_rx, CPM_CLK_RX); - cpm2_clk_setup(target, fpi->clk_tx, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); + cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK15, CPM_CLK_RX); + cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK16, CPM_CLK_TX); } #endif static void __init mpc85xx_ads_setup_arch(void) { - struct device_node *cpu; #ifdef CONFIG_PCI struct device_node *np; #endif @@ -200,25 +189,15 @@ static void __init mpc85xx_ads_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc85xx_ads_setup_arch()", 0); - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != 0) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(cpu); - } - #ifdef CONFIG_CPM2 cpm2_reset(); + init_ioports(); #endif #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "fsl,mpc8540-pci") fsl_add_bridge(np, 1); + ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif } @@ -244,6 +223,24 @@ static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); } +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .type = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + if (!machine_is(mpc85xx_ads)) + return 0; + + of_platform_bus_probe(NULL, of_bus_ids, NULL); + return 0; +} +device_initcall(declare_of_platform_devices); + /* * Called very early, device-tree isn't unflattened */ @@ -261,7 +258,7 @@ define_machine(mpc85xx_ads) { .init_IRQ = mpc85xx_ads_pic_init, .show_cpuinfo = mpc85xx_ads_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = mpc85xx_restart, + .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.h b/arch/powerpc/platforms/85xx/mpc85xx_ads.h deleted file mode 100644 index 46c3532992aa..000000000000 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * MPC85xx ADS board definitions - * - * Maintainer: Kumar Gala <galak@kernel.crashing.org> - * - * Copyright 2004 Freescale Semiconductor Inc. - * - * 2006 (c) MontaVista Software, Inc. - * Vitaly Bordug <vbordug@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifndef __MACH_MPC85XXADS_H -#define __MACH_MPC85XXADS_H - -#include <linux/initrd.h> -#include <sysdev/fsl_soc.h> - -#define BCSR_ADDR ((uint)0xf8000000) -#define BCSR_SIZE ((uint)(32 * 1024)) - -#ifdef CONFIG_CPM2 - -#define MPC85xx_CPM_OFFSET (0x80000) - -#define CPM_MAP_ADDR (get_immrbase() + MPC85xx_CPM_OFFSET) -#define CPM_IRQ_OFFSET 60 - -#define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET) -#define SIU_INT_SMC2 ((uint)0x05+CPM_IRQ_OFFSET) -#define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET) -#define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET) -#define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) -#define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET) - -/* FCC1 Clock Source Configuration. These can be - * redefined in the board specific file. - * Can only choose from CLK9-12 */ -#define F1_RXCLK 12 -#define F1_TXCLK 11 - -/* FCC2 Clock Source Configuration. These can be - * redefined in the board specific file. - * Can only choose from CLK13-16 */ -#define F2_RXCLK 13 -#define F2_TXCLK 14 - -/* FCC3 Clock Source Configuration. These can be - * redefined in the board specific file. - * Can only choose from CLK13-16 */ -#define F3_RXCLK 15 -#define F3_TXCLK 16 - -#endif /* CONFIG_CPM2 */ -#endif /* __MACH_MPC85XXADS_H */ diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 2d4cb7847604..4d063eec6210 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -35,9 +35,7 @@ #include <asm/io.h> #include <asm/machdep.h> #include <asm/ipic.h> -#include <asm/bootinfo.h> #include <asm/pci-bridge.h> -#include <asm/mpc85xx.h> #include <asm/irq.h> #include <mm/mmu_decl.h> #include <asm/prom.h> @@ -47,7 +45,15 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> -#include "mpc85xx.h" + +/* CADMUS info */ +/* xxx - galak, move into device tree */ +#define CADMUS_BASE (0xf8004000) +#define CADMUS_SIZE (256) +#define CM_VER (0) +#define CM_CSR (1) +#define CM_RST (2) + static int cds_pci_slot = 2; static volatile u8 *cadmus; @@ -97,7 +103,7 @@ static void mpc85xx_cds_restart(char *cmd) * If we can't find the VIA chip (maybe the P2P bridge is disabled) * or the VIA chip reset didn't work, just use the default reset. */ - mpc85xx_restart(NULL); + fsl_rstcr_restart(NULL); } static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev) @@ -266,7 +272,6 @@ device_initcall(mpc85xx_cds_8259_attach); */ static void __init mpc85xx_cds_setup_arch(void) { - struct device_node *cpu; #ifdef CONFIG_PCI struct device_node *np; #endif @@ -274,18 +279,6 @@ static void __init mpc85xx_cds_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc85xx_cds_setup_arch()", 0); - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != 0) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 500000000 / HZ; - of_node_put(cpu); - } - cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE); cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1; @@ -297,14 +290,18 @@ static void __init mpc85xx_cds_setup_arch(void) } #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == 0x8000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } } + ppc_md.pci_irq_fixup = mpc85xx_cds_pci_irq_fixup; ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif @@ -353,7 +350,7 @@ define_machine(mpc85xx_cds) { .restart = mpc85xx_cds_restart, .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #else - .restart = mpc85xx_restart, + .restart = fsl_rstcr_restart, #endif .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.h b/arch/powerpc/platforms/85xx/mpc85xx_cds.h deleted file mode 100644 index b251c9feb3dc..000000000000 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * arch/powerpc/platforms/85xx/mpc85xx_cds.h - * - * MPC85xx CDS board definitions - * - * Maintainer: Kumar Gala <galak@kernel.crashing.org> - * - * Copyright 2004 Freescale Semiconductor, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifndef __MACH_MPC85XX_CDS_H__ -#define __MACH_MPC85XX_CDS_H__ - -/* CADMUS info */ -#define CADMUS_BASE (0xf8004000) -#define CADMUS_SIZE (256) -#define CM_VER (0) -#define CM_CSR (1) -#define CM_RST (2) - -/* CDS NVRAM/RTC */ -#define CDS_RTC_ADDR (0xf8000000) -#define CDS_RTC_SIZE (8 * 1024) - -/* PCI interrupt controller */ -#define PIRQ0A MPC85xx_IRQ_EXT0 -#define PIRQ0B MPC85xx_IRQ_EXT1 -#define PIRQ0C MPC85xx_IRQ_EXT2 -#define PIRQ0D MPC85xx_IRQ_EXT3 -#define PIRQ1A MPC85xx_IRQ_EXT11 - -#define NR_8259_INTS 16 -#define CPM_IRQ_OFFSET NR_8259_INTS - -#define MPC85xx_OPENPIC_IRQ_OFFSET 80 - -#endif /* __MACH_MPC85XX_CDS_H__ */ diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 48983bc56d46..59c121a97ac7 100644 --- a/arch/powerpc/platforms/85xx/mpc8544_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -1,5 +1,5 @@ /* - * MPC8544 DS Board Setup + * MPC85xx DS Board Setup * * Author Xianghua Xiao (x.xiao@freescale.com) * Roy Zang <tie-fei.zang@freescale.com> @@ -24,7 +24,6 @@ #include <asm/time.h> #include <asm/machdep.h> #include <asm/pci-bridge.h> -#include <asm/mpc85xx.h> #include <mm/mmu_decl.h> #include <asm/prom.h> #include <asm/udbg.h> @@ -33,7 +32,6 @@ #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> -#include "mpc85xx.h" #undef DEBUG @@ -44,7 +42,7 @@ #endif #ifdef CONFIG_PPC_I8259 -static void mpc8544_8259_cascade(unsigned int irq, struct irq_desc *desc) +static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc) { unsigned int cascade_irq = i8259_irq(); @@ -55,7 +53,7 @@ static void mpc8544_8259_cascade(unsigned int irq, struct irq_desc *desc) } #endif /* CONFIG_PPC_I8259 */ -void __init mpc8544_ds_pic_init(void) +void __init mpc85xx_ds_pic_init(void) { struct mpic *mpic; struct resource r; @@ -104,16 +102,17 @@ void __init mpc8544_ds_pic_init(void) return; } - DBG("mpc8544ds: cascade mapped to irq %d\n", cascade_irq); + DBG("mpc85xxds: cascade mapped to irq %d\n", cascade_irq); i8259_init(cascade_node, 0); of_node_put(cascade_node); - set_irq_chained_handler(cascade_irq, mpc8544_8259_cascade); + set_irq_chained_handler(cascade_irq, mpc85xx_8259_cascade); #endif /* CONFIG_PPC_I8259 */ } #ifdef CONFIG_PCI +static int primary_phb_addr; extern int uses_fsl_uli_m1575; extern int uli_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn); @@ -121,13 +120,13 @@ extern int uli_exclude_device(struct pci_controller *hose, static int mpc85xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { - struct device_node* node; + struct device_node* node; struct resource rsrc; node = (struct device_node *)hose->arch_data; of_address_to_resource(node, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0xb000) { + if ((rsrc.start & 0xfffff) == primary_phb_addr) { return uli_exclude_device(hose, bus, devfn); } @@ -138,29 +137,33 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, /* * Setup the architecture */ -static void __init mpc8544_ds_setup_arch(void) +static void __init mpc85xx_ds_setup_arch(void) { #ifdef CONFIG_PCI struct device_node *np; #endif if (ppc_md.progress) - ppc_md.progress("mpc8544_ds_setup_arch()", 0); + ppc_md.progress("mpc85xx_ds_setup_arch()", 0); #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0xb000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == primary_phb_addr) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } } + uses_fsl_uli_m1575 = 1; ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif - printk("MPC8544 DS board from Freescale Semiconductor\n"); + printk("MPC85xx DS board from Freescale Semiconductor\n"); } /* @@ -170,19 +173,57 @@ static int __init mpc8544_ds_probe(void) { unsigned long root = of_get_flat_dt_root(); - return of_flat_dt_is_compatible(root, "MPC8544DS"); + if (of_flat_dt_is_compatible(root, "MPC8544DS")) { +#ifdef CONFIG_PCI + primary_phb_addr = 0xb000; +#endif + return 1; + } else { + return 0; + } +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc8572_ds_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS")) { +#ifdef CONFIG_PCI + primary_phb_addr = 0x8000; +#endif + return 1; + } else { + return 0; + } } define_machine(mpc8544_ds) { .name = "MPC8544 DS", .probe = mpc8544_ds_probe, - .setup_arch = mpc8544_ds_setup_arch, - .init_IRQ = mpc8544_ds_pic_init, + .setup_arch = mpc85xx_ds_setup_arch, + .init_IRQ = mpc85xx_ds_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; + +define_machine(mpc8572_ds) { + .name = "MPC8572 DS", + .probe = mpc8572_ds_probe, + .setup_arch = mpc85xx_ds_setup_arch, + .init_IRQ = mpc85xx_ds_pic_init, #ifdef CONFIG_PCI .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #endif .get_irq = mpic_get_irq, - .restart = mpc85xx_restart, + .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 7ca7e676f1c4..61b3eedf41b9 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -38,9 +38,7 @@ #include <asm/time.h> #include <asm/io.h> #include <asm/machdep.h> -#include <asm/bootinfo.h> #include <asm/pci-bridge.h> -#include <asm/mpc85xx.h> #include <asm/irq.h> #include <mm/mmu_decl.h> #include <asm/prom.h> @@ -51,8 +49,6 @@ #include <asm/qe_ic.h> #include <asm/mpic.h> -#include "mpc85xx.h" - #undef DEBUG #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -73,17 +69,6 @@ static void __init mpc85xx_mds_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc85xx_mds_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np != NULL) { - const unsigned int *fp = - of_get_property(np, "clock-frequency", NULL); - if (fp != NULL) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } - /* Map BCSR area */ np = of_find_node_by_name(NULL, "bcsr"); if (np != NULL) { @@ -95,9 +80,17 @@ static void __init mpc85xx_mds_setup_arch(void) } #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - fsl_add_bridge(np, 1); - of_node_put(np); + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == 0x8000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } + } #endif #ifdef CONFIG_QUICC_ENGINE @@ -119,18 +112,22 @@ static void __init mpc85xx_mds_setup_arch(void) } if (bcsr_regs) { - u8 bcsr_phy; +#define BCSR_UCC1_GETH_EN (0x1 << 7) +#define BCSR_UCC2_GETH_EN (0x1 << 7) +#define BCSR_UCC1_MODE_MSK (0x3 << 4) +#define BCSR_UCC2_MODE_MSK (0x3 << 0) - /* Reset the Ethernet PHY */ - bcsr_phy = in_be8(&bcsr_regs[9]); - bcsr_phy &= ~0x20; - out_be8(&bcsr_regs[9], bcsr_phy); + /* Turn off UCC1 & UCC2 */ + clrbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); + clrbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); - udelay(1000); + /* Mode is RGMII, all bits clear */ + clrbits8(&bcsr_regs[11], BCSR_UCC1_MODE_MSK | + BCSR_UCC2_MODE_MSK); - bcsr_phy = in_be8(&bcsr_regs[9]); - bcsr_phy |= 0x20; - out_be8(&bcsr_regs[9], bcsr_phy); + /* Turn UCC1 & UCC2 on */ + setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN); + setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN); iounmap(bcsr_regs); } @@ -186,7 +183,7 @@ static void __init mpc85xx_mds_pic_init(void) if (!np) return; - qe_ic_init(np, 0); + qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL); of_node_put(np); #endif /* CONFIG_QUICC_ENGINE */ } @@ -204,7 +201,7 @@ define_machine(mpc85xx_mds) { .setup_arch = mpc85xx_mds_setup_arch, .init_IRQ = mpc85xx_mds_pic_init, .get_irq = mpic_get_irq, - .restart = mpc85xx_restart, + .restart = fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, #ifdef CONFIG_PCI diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 685b2fbbbe00..21d113536b86 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -11,6 +11,12 @@ config MPC8641_HPCN help This option enables support for the MPC8641 HPCN board. +config MPC8610_HPCD + bool "Freescale MPC8610 HPCD" + select DEFAULT_UIMAGE + help + This option enables support for the MPC8610 HPCD board. + endchoice config MPC8641 @@ -19,3 +25,10 @@ config MPC8641 select PPC_UDBG_16550 select MPIC default y if MPC8641_HPCN + +config MPC8610 + bool + select FSL_PCI if PCI + select PPC_UDBG_16550 + select MPIC + default y if MPC8610_HPCD diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 3376c7767f2d..c96706327eaa 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o +obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c new file mode 100644 index 000000000000..6390895e5e92 --- /dev/null +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -0,0 +1,216 @@ +/* + * MPC8610 HPCD board specific routines + * + * Initial author: Xianghua Xiao <x.xiao@freescale.com> + * Recode: Jason Jin <jason.jin@freescale.com> + * + * Rewrite the interrupt routing. remove the 8259PIC support, + * All the integrated device in ULI use sideband interrupt. + * + * Copyright 2007 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/of.h> + +#include <asm/system.h> +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/mpc86xx.h> +#include <asm/prom.h> +#include <mm/mmu_decl.h> +#include <asm/udbg.h> + +#include <asm/mpic.h> + +#include <sysdev/fsl_pci.h> +#include <sysdev/fsl_soc.h> + +void __init +mpc86xx_hpcd_init_irq(void) +{ + struct mpic *mpic1; + struct device_node *np; + struct resource res; + + /* Determine PIC address. */ + np = of_find_node_by_type(NULL, "open-pic"); + if (np == NULL) + return; + of_address_to_resource(np, 0, &res); + + /* Alloc mpic structure and per isu has 16 INT entries. */ + mpic1 = mpic_alloc(np, res.start, + MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + 0, 256, " MPIC "); + BUG_ON(mpic1 == NULL); + + mpic_init(mpic1); +} + +#ifdef CONFIG_PCI +static void __devinit quirk_uli1575(struct pci_dev *dev) +{ + u32 temp32; + + /* Disable INTx */ + pci_read_config_dword(dev, 0x48, &temp32); + pci_write_config_dword(dev, 0x48, (temp32 | 1<<26)); + + /* Enable sideband interrupt */ + pci_read_config_dword(dev, 0x90, &temp32); + pci_write_config_dword(dev, 0x90, (temp32 | 1<<22)); +} + +static void __devinit quirk_uli5288(struct pci_dev *dev) +{ + unsigned char c; + unsigned short temp; + + /* Interrupt Disable, Needed when SATA disabled */ + pci_read_config_word(dev, PCI_COMMAND, &temp); + temp |= 1<<10; + pci_write_config_word(dev, PCI_COMMAND, temp); + + pci_read_config_byte(dev, 0x83, &c); + c |= 0x80; + pci_write_config_byte(dev, 0x83, c); + + pci_write_config_byte(dev, PCI_CLASS_PROG, 0x01); + pci_write_config_byte(dev, PCI_CLASS_DEVICE, 0x06); + + pci_read_config_byte(dev, 0x83, &c); + c &= 0x7f; + pci_write_config_byte(dev, 0x83, c); +} + +/* + * Since 8259PIC was disabled on the board, the IDE device can not + * use the legacy IRQ, we need to let the IDE device work under + * native mode and use the interrupt line like other PCI devices. + * IRQ14 is a sideband interrupt from IDE device to CPU and we use this + * as the interrupt for IDE device. + */ +static void __devinit quirk_uli5229(struct pci_dev *dev) +{ + unsigned char c; + + pci_read_config_byte(dev, 0x4b, &c); + c |= 0x10; + pci_write_config_byte(dev, 0x4b, c); +} + +/* + * SATA interrupt pin bug fix + * There's a chip bug for 5288, The interrupt pin should be 2, + * not the read only value 1, So it use INTB#, not INTA# which + * actually used by the IDE device 5229. + * As of this bug, during the PCI initialization, 5288 read the + * irq of IDE device from the device tree, this function fix this + * bug by re-assigning a correct irq to 5288. + * + */ +static void __devinit final_uli5288(struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct device_node *hosenode = hose ? hose->arch_data : NULL; + struct of_irq oirq; + int virq, pin = 2; + u32 laddr[3]; + + if (!hosenode) + return; + + laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8); + laddr[1] = laddr[2] = 0; + of_irq_map_raw(hosenode, &pin, 1, laddr, &oirq); + virq = irq_create_of_mapping(oirq.controller, oirq.specifier, + oirq.size); + dev->irq = virq; +} + +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_uli1575); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, quirk_uli5288); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5288, final_uli5288); +#endif /* CONFIG_PCI */ + +static void __init +mpc86xx_hpcd_setup_arch(void) +{ +#ifdef CONFIG_PCI + struct device_node *np; +#endif + if (ppc_md.progress) + ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0); + +#ifdef CONFIG_PCI + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8610-pci") + || of_device_is_compatible(np, "fsl,mpc8641-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == 0xa000) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + } + } +#endif + + printk("MPC86xx HPCD board from Freescale Semiconductor\n"); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc86xx_hpcd_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "fsl,MPC8610HPCD")) + return 1; /* Looks good */ + + return 0; +} + +long __init +mpc86xx_time_init(void) +{ + unsigned int temp; + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + temp = mfspr(SPRN_HID0); + temp |= HID0_TBEN; + mtspr(SPRN_HID0, temp); + asm volatile("isync"); + + return 0; +} + +define_machine(mpc86xx_hpcd) { + .name = "MPC86xx HPCD", + .probe = mpc86xx_hpcd_probe, + .setup_arch = mpc86xx_hpcd_setup_arch, + .init_IRQ = mpc86xx_hpcd_init_irq, + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .time_init = mpc86xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +}; diff --git a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h deleted file mode 100644 index 41e554c4af94..000000000000 --- a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * MPC8641 HPCN board definitions - * - * Copyright 2006 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Author: Xianghua Xiao <x.xiao@freescale.com> - */ - -#ifndef __MPC8641_HPCN_H__ -#define __MPC8641_HPCN_H__ - -#include <linux/init.h> - -#define MPC86XX_RSTCR_OFFSET (0xe00b0) /* Reset Control Register */ - -#endif /* __MPC8641_HPCN_H__ */ diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 47aafa76c933..32a531aebcb7 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -35,7 +35,6 @@ #include <sysdev/fsl_soc.h> #include "mpc86xx.h" -#include "mpc8641_hpcn.h" #undef DEBUG @@ -132,25 +131,15 @@ static int mpc86xx_exclude_device(struct pci_controller *hose, static void __init mpc86xx_hpcn_setup_arch(void) { +#ifdef CONFIG_PCI struct device_node *np; +#endif if (ppc_md.progress) ppc_md.progress("mpc86xx_hpcn_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np != 0) { - const unsigned int *fp; - - fp = of_get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } - #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { + for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") { struct resource rsrc; of_address_to_resource(np, 0, &rsrc); if ((rsrc.start & 0xfffff) == 0x8000) @@ -158,6 +147,7 @@ mpc86xx_hpcn_setup_arch(void) else fsl_add_bridge(np, 0); } + uses_fsl_uli_m1575 = 1; ppc_md.pci_exclude_device = mpc86xx_exclude_device; @@ -205,23 +195,6 @@ static int __init mpc86xx_hpcn_probe(void) return 0; } - -void -mpc86xx_restart(char *cmd) -{ - void __iomem *rstcr; - - rstcr = ioremap(get_immrbase() + MPC86XX_RSTCR_OFFSET, 0x100); - - local_irq_disable(); - - /* Assert reset request to Reset Control Register */ - out_be32(rstcr, 0x2); - - /* not reached */ -} - - long __init mpc86xx_time_init(void) { @@ -246,7 +219,7 @@ define_machine(mpc86xx_hpcn) { .init_IRQ = mpc86xx_hpcn_init_irq, .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = mpc86xx_restart, + .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 39bb8c5ebe70..bd28655043a0 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -3,6 +3,7 @@ config FADS config CPM1 bool + select CPM choice prompt "8xx Machine Type" @@ -25,12 +26,23 @@ config MPC86XADS config MPC885ADS bool "MPC885ADS" select CPM1 + select PPC_CPM_NEW_BINDING help Freescale Semiconductor MPC885 Application Development System (ADS). Also known as DUET. The MPC885ADS is meant to serve as a platform for s/w and h/w development around the MPC885 processor family. +config PPC_EP88XC + bool "Embedded Planet EP88xC (a.k.a. CWH-PPC-885XN-VE)" + select CPM1 + select PPC_CPM_NEW_BINDING + help + This enables support for the Embedded Planet EP88xC board. + + This board is also resold by Freescale as the QUICCStart + MPC885 Evaluation System and/or the CWH-PPC-885XN-VE. + endchoice menu "Freescale Ethernet driver platform-specific options" @@ -99,6 +111,22 @@ config 8xx_CPU6 If in doubt, say N here. +config 8xx_CPU15 + bool "CPU15 Silicon Errata" + default y + help + This enables a workaround for erratum CPU15 on MPC8xx chips. + This bug can cause incorrect code execution under certain + circumstances. This workaround adds some overhead (a TLB miss + every time execution crosses a page boundary), and you may wish + to disable it if you have worked around the bug in the compiler + (by not placing conditional branches or branches to LR or CTR + in the last word of a page, with a target of the last cache + line in the next page), or if you have used some other + workaround. + + If in doubt, say Y here. + choice prompt "Microcode patch selection" default NO_UCODE_PATCH diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile index 5e2dae3afd2f..8b7098018b59 100644 --- a/arch/powerpc/platforms/8xx/Makefile +++ b/arch/powerpc/platforms/8xx/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PPC_8xx) += m8xx_setup.o obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o +obj-$(CONFIG_PPC_EP88XC) += ep88xc.o diff --git a/arch/powerpc/platforms/8xx/ep88xc.c b/arch/powerpc/platforms/8xx/ep88xc.c new file mode 100644 index 000000000000..c518b6cc5fab --- /dev/null +++ b/arch/powerpc/platforms/8xx/ep88xc.c @@ -0,0 +1,176 @@ +/* + * Platform setup for the Embedded Planet EP88xC board + * + * Author: Scott Wood <scottwood@freescale.com> + * Copyright 2007 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/of_platform.h> + +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/udbg.h> +#include <asm/commproc.h> + +#include <sysdev/commproc.h> + +struct cpm_pin { + int port, pin, flags; +}; + +static struct cpm_pin ep88xc_pins[] = { + /* SMC1 */ + {1, 24, CPM_PIN_INPUT}, /* RX */ + {1, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ + + /* SCC2 */ + {0, 12, CPM_PIN_INPUT}, /* TX */ + {0, 13, CPM_PIN_INPUT}, /* RX */ + {2, 8, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CD */ + {2, 9, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CTS */ + {2, 14, CPM_PIN_INPUT}, /* RTS */ + + /* MII1 */ + {0, 0, CPM_PIN_INPUT}, + {0, 1, CPM_PIN_INPUT}, + {0, 2, CPM_PIN_INPUT}, + {0, 3, CPM_PIN_INPUT}, + {0, 4, CPM_PIN_OUTPUT}, + {0, 10, CPM_PIN_OUTPUT}, + {0, 11, CPM_PIN_OUTPUT}, + {1, 19, CPM_PIN_INPUT}, + {1, 31, CPM_PIN_INPUT}, + {2, 12, CPM_PIN_INPUT}, + {2, 13, CPM_PIN_INPUT}, + {3, 8, CPM_PIN_INPUT}, + {4, 30, CPM_PIN_OUTPUT}, + {4, 31, CPM_PIN_OUTPUT}, + + /* MII2 */ + {4, 14, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 15, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 16, CPM_PIN_OUTPUT}, + {4, 17, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 18, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 19, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 20, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {4, 21, CPM_PIN_OUTPUT}, + {4, 22, CPM_PIN_OUTPUT}, + {4, 23, CPM_PIN_OUTPUT}, + {4, 24, CPM_PIN_OUTPUT}, + {4, 25, CPM_PIN_OUTPUT}, + {4, 26, CPM_PIN_OUTPUT}, + {4, 27, CPM_PIN_OUTPUT}, + {4, 28, CPM_PIN_OUTPUT}, + {4, 29, CPM_PIN_OUTPUT}, + + /* USB */ + {0, 6, CPM_PIN_INPUT}, /* CLK2 */ + {0, 14, CPM_PIN_INPUT}, /* USBOE */ + {0, 15, CPM_PIN_INPUT}, /* USBRXD */ + {2, 6, CPM_PIN_OUTPUT}, /* USBTXN */ + {2, 7, CPM_PIN_OUTPUT}, /* USBTXP */ + {2, 10, CPM_PIN_INPUT}, /* USBRXN */ + {2, 11, CPM_PIN_INPUT}, /* USBRXP */ + + /* Misc */ + {1, 26, CPM_PIN_INPUT}, /* BRGO2 */ + {1, 27, CPM_PIN_INPUT}, /* BRGO1 */ +}; + +static void __init init_ioports(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ep88xc_pins); i++) { + struct cpm_pin *pin = &ep88xc_pins[i]; + cpm1_set_pin(pin->port, pin->pin, pin->flags); + } + + cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX); + cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK2, CPM_CLK_TX); /* USB */ + cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK2, CPM_CLK_RX); + cpm1_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX); + cpm1_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX); +} + +static u8 __iomem *ep88xc_bcsr; + +#define BCSR7_SCC2_ENABLE 0x10 + +#define BCSR8_PHY1_ENABLE 0x80 +#define BCSR8_PHY1_POWER 0x40 +#define BCSR8_PHY2_ENABLE 0x20 +#define BCSR8_PHY2_POWER 0x10 + +#define BCSR9_USB_ENABLE 0x80 +#define BCSR9_USB_POWER 0x40 +#define BCSR9_USB_HOST 0x20 +#define BCSR9_USB_FULL_SPEED_TARGET 0x10 + +static void __init ep88xc_setup_arch(void) +{ + struct device_node *np; + + cpm_reset(); + init_ioports(); + + np = of_find_compatible_node(NULL, NULL, "fsl,ep88xc-bcsr"); + if (!np) { + printk(KERN_CRIT "Could not find fsl,ep88xc-bcsr node\n"); + return; + } + + ep88xc_bcsr = of_iomap(np, 0); + of_node_put(np); + + if (!ep88xc_bcsr) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } + + setbits8(&ep88xc_bcsr[7], BCSR7_SCC2_ENABLE); + setbits8(&ep88xc_bcsr[8], BCSR8_PHY1_ENABLE | BCSR8_PHY1_POWER | + BCSR8_PHY2_ENABLE | BCSR8_PHY2_POWER); +} + +static int __init ep88xc_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + return of_flat_dt_is_compatible(root, "fsl,ep88xc"); +} + +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + /* Publish the QE devices */ + if (machine_is(ep88xc)) + of_platform_bus_probe(NULL, of_bus_ids, NULL); + + return 0; +} +device_initcall(declare_of_platform_devices); + +define_machine(ep88xc) { + .name = "Embedded Planet EP88xC", + .probe = ep88xc_probe, + .setup_arch = ep88xc_setup_arch, + .init_IRQ = m8xx_pic_init, + .get_irq = mpc8xx_get_irq, + .restart = mpc8xx_restart, + .calibrate_decr = mpc8xx_calibrate_decr, + .set_rtc_time = mpc8xx_set_rtc_time, + .get_rtc_time = mpc8xx_get_rtc_time, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index f1693550c70c..d35eda80e9e6 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -10,57 +10,33 @@ * bootup setup stuff.. */ -#include <linux/errno.h> -#include <linux/sched.h> #include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> #include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/major.h> #include <linux/interrupt.h> -#include <linux/reboot.h> #include <linux/init.h> -#include <linux/initrd.h> -#include <linux/ioport.h> -#include <linux/bootmem.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> #include <linux/time.h> #include <linux/rtc.h> -#include <linux/fsl_devices.h> -#include <asm/mmu.h> -#include <asm/reg.h> -#include <asm/residual.h> #include <asm/io.h> -#include <asm/pgtable.h> #include <asm/mpc8xx.h> #include <asm/8xx_immap.h> -#include <asm/machdep.h> -#include <asm/bootinfo.h> -#include <asm/time.h> #include <asm/prom.h> #include <asm/fs_pd.h> #include <mm/mmu_decl.h> -#include "sysdev/mpc8xx_pic.h" +#include <sysdev/mpc8xx_pic.h> +#include <sysdev/commproc.h> #ifdef CONFIG_PCMCIA_M8XX struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; #endif void m8xx_calibrate_decr(void); -extern void m8xx_wdt_handler_install(bd_t *bp); extern int cpm_pic_init(void); extern int cpm_get_irq(void); /* A place holder for time base interrupts, if they are ever enabled. */ -irqreturn_t timebase_interrupt(int irq, void * dev) +static irqreturn_t timebase_interrupt(int irq, void *dev) { printk ("timebase_interrupt()\n"); @@ -77,7 +53,7 @@ static struct irqaction tbint_irqaction = { void __init __attribute__ ((weak)) init_internal_rtc(void) { - sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit); + sit8xx_t __iomem *sys_tmr = immr_map(im_sit); /* Disable the RTC one second and alarm interrupts. */ clrbits16(&sys_tmr->sit_rtcsc, (RTCSC_SIE | RTCSC_ALE)); @@ -89,24 +65,24 @@ init_internal_rtc(void) static int __init get_freq(char *name, unsigned long *val) { - struct device_node *cpu; - const unsigned int *fp; - int found = 0; + struct device_node *cpu; + const unsigned int *fp; + int found = 0; - /* The cpu node should have timebase and clock frequency properties */ - cpu = of_find_node_by_type(NULL, "cpu"); + /* The cpu node should have timebase and clock frequency properties */ + cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu) { - fp = of_get_property(cpu, name, NULL); - if (fp) { - found = 1; - *val = *fp; - } + if (cpu) { + fp = of_get_property(cpu, name, NULL); + if (fp) { + found = 1; + *val = *fp; + } - of_node_put(cpu); - } + of_node_put(cpu); + } - return found; + return found; } /* The decrementer counts at the system (internal) clock frequency divided by @@ -116,13 +92,13 @@ static int __init get_freq(char *name, unsigned long *val) void __init mpc8xx_calibrate_decr(void) { struct device_node *cpu; - cark8xx_t *clk_r1; - car8xx_t *clk_r2; - sitk8xx_t *sys_tmr1; - sit8xx_t *sys_tmr2; + cark8xx_t __iomem *clk_r1; + car8xx_t __iomem *clk_r2; + sitk8xx_t __iomem *sys_tmr1; + sit8xx_t __iomem *sys_tmr2; int irq, virq; - clk_r1 = (cark8xx_t *) immr_map(im_clkrstk); + clk_r1 = immr_map(im_clkrstk); /* Unlock the SCCR. */ out_be32(&clk_r1->cark_sccrk, ~KAPWR_KEY); @@ -130,24 +106,24 @@ void __init mpc8xx_calibrate_decr(void) immr_unmap(clk_r1); /* Force all 8xx processors to use divide by 16 processor clock. */ - clk_r2 = (car8xx_t *) immr_map(im_clkrst); + clk_r2 = immr_map(im_clkrst); setbits32(&clk_r2->car_sccr, 0x02000000); immr_unmap(clk_r2); /* Processor frequency is MHz. */ - ppc_tb_freq = 50000000; - if (!get_freq("bus-frequency", &ppc_tb_freq)) { - printk(KERN_ERR "WARNING: Estimating decrementer frequency " - "(not found)\n"); - } - ppc_tb_freq /= 16; - ppc_proc_freq = 50000000; - if (!get_freq("clock-frequency", &ppc_proc_freq)) - printk(KERN_ERR "WARNING: Estimating processor frequency" - "(not found)\n"); - - printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); + ppc_tb_freq = 50000000; + if (!get_freq("bus-frequency", &ppc_tb_freq)) { + printk(KERN_ERR "WARNING: Estimating decrementer frequency " + "(not found)\n"); + } + ppc_tb_freq /= 16; + ppc_proc_freq = 50000000; + if (!get_freq("clock-frequency", &ppc_proc_freq)) + printk(KERN_ERR "WARNING: Estimating processor frequency" + "(not found)\n"); + + printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); /* Perform some more timer/timebase initialization. This used * to be done elsewhere, but other changes caused it to get @@ -164,7 +140,7 @@ void __init mpc8xx_calibrate_decr(void) * we guarantee the registers are locked, then we unlock them * for our use. */ - sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); + sys_tmr1 = immr_map(im_sitk); out_be32(&sys_tmr1->sitk_tbscrk, ~KAPWR_KEY); out_be32(&sys_tmr1->sitk_rtcsck, ~KAPWR_KEY); out_be32(&sys_tmr1->sitk_tbk, ~KAPWR_KEY); @@ -180,24 +156,17 @@ void __init mpc8xx_calibrate_decr(void) * we have to enable the timebase). The decrementer interrupt * is wired into the vector table, nothing to do here for that. */ - cpu = of_find_node_by_type(NULL, "cpu"); - virq= irq_of_parse_and_map(cpu, 0); + cpu = of_find_node_by_type(NULL, "cpu"); + virq= irq_of_parse_and_map(cpu, 0); irq = irq_map[virq].hwirq; - sys_tmr2 = (sit8xx_t *) immr_map(im_sit); + sys_tmr2 = immr_map(im_sit); out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) | (TBSCR_TBF | TBSCR_TBE)); immr_unmap(sys_tmr2); if (setup_irq(virq, &tbint_irqaction)) panic("Could not allocate timer IRQ!"); - -#ifdef CONFIG_8xx_WDT - /* Install watchdog timer handler early because it might be - * already enabled by the bootloader - */ - m8xx_wdt_handler_install(binfo); -#endif } /* The RTC on the MPC8xx is an internal register. @@ -207,14 +176,14 @@ void __init mpc8xx_calibrate_decr(void) int mpc8xx_set_rtc_time(struct rtc_time *tm) { - sitk8xx_t *sys_tmr1; - sit8xx_t *sys_tmr2; + sitk8xx_t __iomem *sys_tmr1; + sit8xx_t __iomem *sys_tmr2; int time; - sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); - sys_tmr2 = (sit8xx_t *) immr_map(im_sit); + sys_tmr1 = immr_map(im_sitk); + sys_tmr2 = immr_map(im_sit); time = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + tm->tm_hour, tm->tm_min, tm->tm_sec); out_be32(&sys_tmr1->sitk_rtck, KAPWR_KEY); out_be32(&sys_tmr2->sit_rtc, time); @@ -228,21 +197,20 @@ int mpc8xx_set_rtc_time(struct rtc_time *tm) void mpc8xx_get_rtc_time(struct rtc_time *tm) { unsigned long data; - sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit); + sit8xx_t __iomem *sys_tmr = immr_map(im_sit); /* Get time from the RTC. */ data = in_be32(&sys_tmr->sit_rtc); to_tm(data, tm); - tm->tm_year -= 1900; - tm->tm_mon -= 1; + tm->tm_year -= 1900; + tm->tm_mon -= 1; immr_unmap(sys_tmr); return; } void mpc8xx_restart(char *cmd) { - __volatile__ unsigned char dummy; - car8xx_t * clk_r = (car8xx_t *) immr_map(im_clkrst); + car8xx_t __iomem *clk_r = immr_map(im_clkrst); local_irq_disable(); @@ -252,26 +220,8 @@ void mpc8xx_restart(char *cmd) */ mtmsr(mfmsr() & ~0x1000); - dummy = in_8(&clk_r->res[0]); - printk("Restart failed\n"); - while(1); -} - -void mpc8xx_show_cpuinfo(struct seq_file *m) -{ - struct device_node *root; - uint memsize = total_memory; - const char *model = ""; - - seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - - root = of_find_node_by_path("/"); - if (root) - model = of_get_property(root, "model", NULL); - seq_printf(m, "Machine\t\t: %s\n", model); - of_node_put(root); - - seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); + in_8(&clk_r->res[0]); + panic("Restart failed\n"); } static void cpm_cascade(unsigned int irq, struct irq_desc *desc) @@ -298,7 +248,7 @@ void __init m8xx_pic_init(void) int irq; if (mpc8xx_pic_init()) { - printk(KERN_ERR "Failed interrupt 8xx controller initialization\n"); + printk(KERN_ERR "Failed interrupt 8xx controller initialization\n"); return; } diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h index 59bad2f9ae51..cffa194ccf1f 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads.h +++ b/arch/powerpc/platforms/8xx/mpc86xads.h @@ -15,7 +15,6 @@ #ifndef __ASM_MPC86XADS_H__ #define __ASM_MPC86XADS_H__ -#include <asm/ppcboot.h> #include <sysdev/fsl_soc.h> /* U-Boot maps BCSR to 0xff080000 */ @@ -30,9 +29,6 @@ #define CFG_PHYDEV_ADDR ((uint)0xff0a0000) #define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) -#define IMAP_ADDR (get_immrbase()) -#define IMAP_SIZE ((uint)(64 * 1024)) - #define MPC8xx_CPM_OFFSET (0x9c0) #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c index cf0e7bc8c2e7..49012835f453 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c @@ -31,21 +31,13 @@ #include <asm/processor.h> #include <asm/system.h> #include <asm/time.h> -#include <asm/ppcboot.h> #include <asm/mpc8xx.h> #include <asm/8xx_immap.h> #include <asm/commproc.h> #include <asm/fs_pd.h> #include <asm/prom.h> -extern void cpm_reset(void); -extern void mpc8xx_show_cpuinfo(struct seq_file*); -extern void mpc8xx_restart(char *cmd); -extern void mpc8xx_calibrate_decr(void); -extern int mpc8xx_set_rtc_time(struct rtc_time *tm); -extern void mpc8xx_get_rtc_time(struct rtc_time *tm); -extern void m8xx_pic_init(void); -extern unsigned int mpc8xx_get_irq(void); +#include <sysdev/commproc.h> static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); @@ -254,20 +246,6 @@ int platform_device_skip(const char *model, int id) static void __init mpc86xads_setup_arch(void) { - struct device_node *cpu; - - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != 0) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(cpu); - } - cpm_reset(); mpc86xads_board_setup(); @@ -292,7 +270,6 @@ define_machine(mpc86x_ads) { .probe = mpc86xads_probe, .setup_arch = mpc86xads_setup_arch, .init_IRQ = m8xx_pic_init, - .show_cpuinfo = mpc8xx_show_cpuinfo, .get_irq = mpc8xx_get_irq, .restart = mpc8xx_restart, .calibrate_decr = mpc8xx_calibrate_decr, diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h index 7c31aec284c2..a5076668bad6 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads.h +++ b/arch/powerpc/platforms/8xx/mpc885ads.h @@ -15,31 +15,12 @@ #ifndef __ASM_MPC885ADS_H__ #define __ASM_MPC885ADS_H__ -#include <asm/ppcboot.h> #include <sysdev/fsl_soc.h> -/* U-Boot maps BCSR to 0xff080000 */ -#define BCSR_ADDR ((uint)0xff080000) -#define BCSR_SIZE ((uint)32) -#define BCSR0 ((uint)(BCSR_ADDR + 0x00)) -#define BCSR1 ((uint)(BCSR_ADDR + 0x04)) -#define BCSR2 ((uint)(BCSR_ADDR + 0x08)) -#define BCSR3 ((uint)(BCSR_ADDR + 0x0c)) -#define BCSR4 ((uint)(BCSR_ADDR + 0x10)) - -#define CFG_PHYDEV_ADDR ((uint)0xff0a0000) -#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) - -#define IMAP_ADDR (get_immrbase()) -#define IMAP_SIZE ((uint)(64 * 1024)) - #define MPC8xx_CPM_OFFSET (0x9c0) #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver -#define PCMCIA_MEM_ADDR ((uint)0xff020000) -#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) - /* Bits of interest in the BCSRs. */ #define BCSR1_ETHEN ((uint)0x20000000) @@ -68,28 +49,5 @@ #define BCSR5_MII1_EN 0x02 #define BCSR5_MII1_RST 0x01 -/* Interrupt level assignments */ -#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */ -#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */ -#define SIU_INT_FEC2 SIU_LEVEL3 /* FEC2 interrupt */ -#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */ - -/* We don't use the 8259 */ -#define NR_8259_INTS 0 - -/* CPM Ethernet through SCC3 */ -#define PA_ENET_RXD ((ushort)0x0040) -#define PA_ENET_TXD ((ushort)0x0080) -#define PE_ENET_TCLK ((uint)0x00004000) -#define PE_ENET_RCLK ((uint)0x00008000) -#define PE_ENET_TENA ((uint)0x00000010) -#define PC_ENET_CLSN ((ushort)0x0400) -#define PC_ENET_RENA ((ushort)0x0800) - -/* Control bits in the SICR to route TCLK (CLK5) and RCLK (CLK6) to - * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero */ -#define SICR_ENET_MASK ((uint)0x00ff0000) -#define SICR_ENET_CLKRT ((uint)0x002c0000) - #endif /* __ASM_MPC885ADS_H__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index 5a808d611ae3..2cf1b6a75173 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -1,11 +1,13 @@ -/*arch/powerpc/platforms/8xx/mpc885ads_setup.c - * +/* * Platform setup for the Freescale mpc885ads board * * Vitaly Bordug <vbordug@ru.mvista.com> * * Copyright 2005 MontaVista Software Inc. * + * Heavily modified by Scott Wood <scottwood@freescale.com> + * Copyright 2007 Freescale Semiconductor, Inc. + * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. @@ -18,12 +20,12 @@ #include <linux/ioport.h> #include <linux/device.h> #include <linux/delay.h> -#include <linux/root_dev.h> #include <linux/fs_enet_pd.h> #include <linux/fs_uart_pd.h> #include <linux/fsl_devices.h> #include <linux/mii.h> +#include <linux/of_platform.h> #include <asm/delay.h> #include <asm/io.h> @@ -32,46 +34,28 @@ #include <asm/processor.h> #include <asm/system.h> #include <asm/time.h> -#include <asm/ppcboot.h> #include <asm/mpc8xx.h> #include <asm/8xx_immap.h> #include <asm/commproc.h> #include <asm/fs_pd.h> -#include <asm/prom.h> +#include <asm/udbg.h> -extern void cpm_reset(void); -extern void mpc8xx_show_cpuinfo(struct seq_file *); -extern void mpc8xx_restart(char *cmd); -extern void mpc8xx_calibrate_decr(void); -extern int mpc8xx_set_rtc_time(struct rtc_time *tm); -extern void mpc8xx_get_rtc_time(struct rtc_time *tm); -extern void m8xx_pic_init(void); -extern unsigned int mpc8xx_get_irq(void); +#include <sysdev/commproc.h> -static void init_smc1_uart_ioports(struct fs_uart_platform_info *fpi); -static void init_smc2_uart_ioports(struct fs_uart_platform_info *fpi); -static void init_scc3_ioports(struct fs_platform_info *ptr); +static u32 __iomem *bcsr, *bcsr5; #ifdef CONFIG_PCMCIA_M8XX static void pcmcia_hw_setup(int slot, int enable) { - unsigned *bcsr_io; - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); if (enable) - clrbits32(bcsr_io, BCSR1_PCCEN); + clrbits32(&bcsr[1], BCSR1_PCCEN); else - setbits32(bcsr_io, BCSR1_PCCEN); - - iounmap(bcsr_io); + setbits32(&bcsr[1], BCSR1_PCCEN); } static int pcmcia_set_voltage(int slot, int vcc, int vpp) { u32 reg = 0; - unsigned *bcsr_io; - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); switch (vcc) { case 0: @@ -106,344 +90,196 @@ static int pcmcia_set_voltage(int slot, int vcc, int vpp) } /* first, turn off all power */ - clrbits32(bcsr_io, 0x00610000); + clrbits32(&bcsr[1], 0x00610000); /* enable new powersettings */ - setbits32(bcsr_io, reg); + setbits32(&bcsr[1], reg); - iounmap(bcsr_io); return 0; } #endif -void __init mpc885ads_board_setup(void) -{ - cpm8xx_t *cp; - unsigned int *bcsr_io; - u8 tmpval8; - -#ifdef CONFIG_FS_ENET - iop8xx_t *io_port; -#endif - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); - cp = (cpm8xx_t *) immr_map(im_cpm); - - if (bcsr_io == NULL) { - printk(KERN_CRIT "Could not remap BCSR\n"); - return; - } -#ifdef CONFIG_SERIAL_CPM_SMC1 - clrbits32(bcsr_io, BCSR1_RS232EN_1); - clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */ - tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX); - out_8(&(cp->cp_smc[0].smc_smcm), tmpval8); - clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); /* brg1 */ -#else - setbits32(bcsr_io, BCSR1_RS232EN_1); - out_be16(&cp->cp_smc[0].smc_smcmr, 0); - out_8(&cp->cp_smc[0].smc_smce, 0); -#endif - -#ifdef CONFIG_SERIAL_CPM_SMC2 - clrbits32(bcsr_io, BCSR1_RS232EN_2); - clrbits32(&cp->cp_simode, 0xe0000000 >> 1); - setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */ - tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX); - out_8(&(cp->cp_smc[1].smc_smcm), tmpval8); - clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN); +struct cpm_pin { + int port, pin, flags; +}; - init_smc2_uart_ioports(0); -#else - setbits32(bcsr_io, BCSR1_RS232EN_2); - out_be16(&cp->cp_smc[1].smc_smcmr, 0); - out_8(&cp->cp_smc[1].smc_smce, 0); -#endif - immr_unmap(cp); - iounmap(bcsr_io); - -#ifdef CONFIG_FS_ENET - /* use MDC for MII (common) */ - io_port = (iop8xx_t *) immr_map(im_ioport); - setbits16(&io_port->iop_pdpar, 0x0080); - clrbits16(&io_port->iop_pddir, 0x0080); - - bcsr_io = ioremap(BCSR5, sizeof(unsigned long)); - clrbits32(bcsr_io, BCSR5_MII1_EN); - clrbits32(bcsr_io, BCSR5_MII1_RST); -#ifndef CONFIG_FC_ENET_HAS_SCC - clrbits32(bcsr_io, BCSR5_MII2_EN); - clrbits32(bcsr_io, BCSR5_MII2_RST); +static struct cpm_pin mpc885ads_pins[] = { + /* SMC1 */ + {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */ + {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ + /* SMC2 */ +#ifndef CONFIG_MPC8xx_SECOND_ETH_FEC2 + {CPM_PORTE, 21, CPM_PIN_INPUT}, /* RX */ + {CPM_PORTE, 20, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ #endif - iounmap(bcsr_io); - immr_unmap(io_port); + /* SCC3 */ + {CPM_PORTA, 9, CPM_PIN_INPUT}, /* RX */ + {CPM_PORTA, 8, CPM_PIN_INPUT}, /* TX */ + {CPM_PORTC, 4, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* RENA */ + {CPM_PORTC, 5, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CLSN */ + {CPM_PORTE, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TENA */ + {CPM_PORTE, 17, CPM_PIN_INPUT}, /* CLK5 */ + {CPM_PORTE, 16, CPM_PIN_INPUT}, /* CLK6 */ + + /* MII1 */ + {CPM_PORTA, 0, CPM_PIN_INPUT}, + {CPM_PORTA, 1, CPM_PIN_INPUT}, + {CPM_PORTA, 2, CPM_PIN_INPUT}, + {CPM_PORTA, 3, CPM_PIN_INPUT}, + {CPM_PORTA, 4, CPM_PIN_OUTPUT}, + {CPM_PORTA, 10, CPM_PIN_OUTPUT}, + {CPM_PORTA, 11, CPM_PIN_OUTPUT}, + {CPM_PORTB, 19, CPM_PIN_INPUT}, + {CPM_PORTB, 31, CPM_PIN_INPUT}, + {CPM_PORTC, 12, CPM_PIN_INPUT}, + {CPM_PORTC, 13, CPM_PIN_INPUT}, + {CPM_PORTE, 30, CPM_PIN_OUTPUT}, + {CPM_PORTE, 31, CPM_PIN_OUTPUT}, + + /* MII2 */ +#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2 + {CPM_PORTE, 14, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 15, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 16, CPM_PIN_OUTPUT}, + {CPM_PORTE, 17, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 18, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 19, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 20, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, + {CPM_PORTE, 21, CPM_PIN_OUTPUT}, + {CPM_PORTE, 22, CPM_PIN_OUTPUT}, + {CPM_PORTE, 23, CPM_PIN_OUTPUT}, + {CPM_PORTE, 24, CPM_PIN_OUTPUT}, + {CPM_PORTE, 25, CPM_PIN_OUTPUT}, + {CPM_PORTE, 26, CPM_PIN_OUTPUT}, + {CPM_PORTE, 27, CPM_PIN_OUTPUT}, + {CPM_PORTE, 28, CPM_PIN_OUTPUT}, + {CPM_PORTE, 29, CPM_PIN_OUTPUT}, #endif +}; -#ifdef CONFIG_PCMCIA_M8XX - /*Set up board specific hook-ups */ - m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup; - m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage; -#endif -} - -static void init_fec1_ioports(struct fs_platform_info *ptr) +static void __init init_ioports(void) { - cpm8xx_t *cp = (cpm8xx_t *) immr_map(im_cpm); - iop8xx_t *io_port = (iop8xx_t *) immr_map(im_ioport); - - /* configure FEC1 pins */ - setbits16(&io_port->iop_papar, 0xf830); - setbits16(&io_port->iop_padir, 0x0830); - clrbits16(&io_port->iop_padir, 0xf000); + int i; - setbits32(&cp->cp_pbpar, 0x00001001); - clrbits32(&cp->cp_pbdir, 0x00001001); - - setbits16(&io_port->iop_pcpar, 0x000c); - clrbits16(&io_port->iop_pcdir, 0x000c); + for (i = 0; i < ARRAY_SIZE(mpc885ads_pins); i++) { + struct cpm_pin *pin = &mpc885ads_pins[i]; + cpm1_set_pin(pin->port, pin->pin, pin->flags); + } - setbits32(&cp->cp_pepar, 0x00000003); - setbits32(&cp->cp_pedir, 0x00000003); - clrbits32(&cp->cp_peso, 0x00000003); - clrbits32(&cp->cp_cptr, 0x00000100); + cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX); + cpm1_clk_setup(CPM_CLK_SMC2, CPM_BRG2, CPM_CLK_RTX); + cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_TX); + cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK6, CPM_CLK_RX); - immr_unmap(io_port); - immr_unmap(cp); + /* Set FEC1 and FEC2 to MII mode */ + clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180); } -static void init_fec2_ioports(struct fs_platform_info *ptr) +static void __init mpc885ads_setup_arch(void) { - cpm8xx_t *cp = (cpm8xx_t *) immr_map(im_cpm); - iop8xx_t *io_port = (iop8xx_t *) immr_map(im_ioport); - - /* configure FEC2 pins */ - setbits32(&cp->cp_pepar, 0x0003fffc); - setbits32(&cp->cp_pedir, 0x0003fffc); - clrbits32(&cp->cp_peso, 0x000087fc); - setbits32(&cp->cp_peso, 0x00037800); - clrbits32(&cp->cp_cptr, 0x00000080); - - immr_unmap(io_port); - immr_unmap(cp); -} + struct device_node *np; -void init_fec_ioports(struct fs_platform_info *fpi) -{ - int fec_no = fs_get_fec_index(fpi->fs_no); + cpm_reset(); + init_ioports(); - switch (fec_no) { - case 0: - init_fec1_ioports(fpi); - break; - case 1: - init_fec2_ioports(fpi); - break; - default: - printk(KERN_ERR "init_fec_ioports: invalid FEC number\n"); + np = of_find_compatible_node(NULL, NULL, "fsl,mpc885ads-bcsr"); + if (!np) { + printk(KERN_CRIT "Could not find fsl,mpc885ads-bcsr node\n"); return; } -} - -static void init_scc3_ioports(struct fs_platform_info *fpi) -{ - unsigned *bcsr_io; - iop8xx_t *io_port; - cpm8xx_t *cp; - bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE); - io_port = (iop8xx_t *) immr_map(im_ioport); - cp = (cpm8xx_t *) immr_map(im_cpm); + bcsr = of_iomap(np, 0); + bcsr5 = of_iomap(np, 1); + of_node_put(np); - if (bcsr_io == NULL) { + if (!bcsr || !bcsr5) { printk(KERN_CRIT "Could not remap BCSR\n"); return; } - /* Enable the PHY. - */ - clrbits32(bcsr_io + 4, BCSR4_ETH10_RST); - udelay(1000); - setbits32(bcsr_io + 4, BCSR4_ETH10_RST); - /* Configure port A pins for Txd and Rxd. - */ - setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD); - clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD); + clrbits32(&bcsr[1], BCSR1_RS232EN_1); +#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2 + setbits32(&bcsr[1], BCSR1_RS232EN_2); +#else + clrbits32(&bcsr[1], BCSR1_RS232EN_2); +#endif - /* Configure port C pins to enable CLSN and RENA. - */ - clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA); - clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA); - setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA); + clrbits32(bcsr5, BCSR5_MII1_EN); + setbits32(bcsr5, BCSR5_MII1_RST); + udelay(1000); + clrbits32(bcsr5, BCSR5_MII1_RST); - /* Configure port E for TCLK and RCLK. - */ - setbits32(&cp->cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK); - clrbits32(&cp->cp_pepar, PE_ENET_TENA); - clrbits32(&cp->cp_pedir, PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA); - clrbits32(&cp->cp_peso, PE_ENET_TCLK | PE_ENET_RCLK); - setbits32(&cp->cp_peso, PE_ENET_TENA); - - /* Configure Serial Interface clock routing. - * First, clear all SCC bits to zero, then set the ones we want. - */ - clrbits32(&cp->cp_sicr, SICR_ENET_MASK); - setbits32(&cp->cp_sicr, SICR_ENET_CLKRT); +#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2 + clrbits32(bcsr5, BCSR5_MII2_EN); + setbits32(bcsr5, BCSR5_MII2_RST); + udelay(1000); + clrbits32(bcsr5, BCSR5_MII2_RST); +#else + setbits32(bcsr5, BCSR5_MII2_EN); +#endif - /* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used. - */ - clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); - /* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode - * by H/W setting after reset. SCC ethernet controller support only half duplex. - * This discrepancy of modes causes a lot of carrier lost errors. - */ +#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3 + clrbits32(&bcsr[4], BCSR4_ETH10_RST); + udelay(1000); + setbits32(&bcsr[4], BCSR4_ETH10_RST); - /* In the original SCC enet driver the following code is placed at - the end of the initialization */ - setbits32(&cp->cp_pepar, PE_ENET_TENA); - clrbits32(&cp->cp_pedir, PE_ENET_TENA); - setbits32(&cp->cp_peso, PE_ENET_TENA); + setbits32(&bcsr[1], BCSR1_ETHEN); - setbits32(bcsr_io + 4, BCSR1_ETHEN); - iounmap(bcsr_io); - immr_unmap(io_port); - immr_unmap(cp); -} + np = of_find_node_by_path("/soc@ff000000/cpm@9c0/serial@a80"); +#else + np = of_find_node_by_path("/soc@ff000000/cpm@9c0/ethernet@a40"); +#endif -void init_scc_ioports(struct fs_platform_info *fpi) -{ - int scc_no = fs_get_scc_index(fpi->fs_no); + /* The SCC3 enet registers overlap the SMC1 registers, so + * one of the two must be removed from the device tree. + */ - switch (scc_no) { - case 2: - init_scc3_ioports(fpi); - break; - default: - printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); - return; + if (np) { + of_detach_node(np); + of_node_put(np); } -} -static void init_smc1_uart_ioports(struct fs_uart_platform_info *ptr) -{ - unsigned *bcsr_io; - cpm8xx_t *cp; - - cp = (cpm8xx_t *) immr_map(im_cpm); - setbits32(&cp->cp_pepar, 0x000000c0); - clrbits32(&cp->cp_pedir, 0x000000c0); - clrbits32(&cp->cp_peso, 0x00000040); - setbits32(&cp->cp_peso, 0x00000080); - immr_unmap(cp); - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); - - if (bcsr_io == NULL) { - printk(KERN_CRIT "Could not remap BCSR1\n"); - return; - } - clrbits32(bcsr_io, BCSR1_RS232EN_1); - iounmap(bcsr_io); +#ifdef CONFIG_PCMCIA_M8XX + /* Set up board specific hook-ups.*/ + m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup; + m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage; +#endif } -static void init_smc2_uart_ioports(struct fs_uart_platform_info *fpi) +static int __init mpc885ads_probe(void) { - unsigned *bcsr_io; - cpm8xx_t *cp; - - cp = (cpm8xx_t *) immr_map(im_cpm); - setbits32(&cp->cp_pepar, 0x00000c00); - clrbits32(&cp->cp_pedir, 0x00000c00); - clrbits32(&cp->cp_peso, 0x00000400); - setbits32(&cp->cp_peso, 0x00000800); - immr_unmap(cp); - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); - - if (bcsr_io == NULL) { - printk(KERN_CRIT "Could not remap BCSR1\n"); - return; - } - clrbits32(bcsr_io, BCSR1_RS232EN_2); - iounmap(bcsr_io); + unsigned long root = of_get_flat_dt_root(); + return of_flat_dt_is_compatible(root, "fsl,mpc885ads"); } -void init_smc_ioports(struct fs_uart_platform_info *data) -{ - int smc_no = fs_uart_id_fsid2smc(data->fs_no); +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "cpm", }, + { .name = "localbus", }, + {}, +}; - switch (smc_no) { - case 0: - init_smc1_uart_ioports(data); - data->brg = data->clk_rx; - break; - case 1: - init_smc2_uart_ioports(data); - data->brg = data->clk_rx; - break; - default: - printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); - return; - } -} - -int platform_device_skip(const char *model, int id) +static int __init declare_of_platform_devices(void) { -#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3 - const char *dev = "FEC"; - int n = 2; -#else - const char *dev = "SCC"; - int n = 3; -#endif - - if (!strcmp(model, dev) && n == id) - return 1; + /* Publish the QE devices */ + if (machine_is(mpc885_ads)) + of_platform_bus_probe(NULL, of_bus_ids, NULL); return 0; } - -static void __init mpc885ads_setup_arch(void) -{ - struct device_node *cpu; - - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu != 0) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(cpu); - } - - cpm_reset(); - - mpc885ads_board_setup(); - - ROOT_DEV = Root_NFS; -} - -static int __init mpc885ads_probe(void) -{ - char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), - "model", NULL); - if (model == NULL) - return 0; - if (strcmp(model, "MPC885ADS")) - return 0; - - return 1; -} - -define_machine(mpc885_ads) -{ -.name = "MPC885 ADS",.probe = mpc885ads_probe,.setup_arch = - mpc885ads_setup_arch,.init_IRQ = - m8xx_pic_init,.show_cpuinfo = mpc8xx_show_cpuinfo,.get_irq = - mpc8xx_get_irq,.restart = mpc8xx_restart,.calibrate_decr = - mpc8xx_calibrate_decr,.set_rtc_time = - mpc8xx_set_rtc_time,.get_rtc_time = mpc8xx_get_rtc_time,}; +device_initcall(declare_of_platform_devices); + +define_machine(mpc885_ads) { + .name = "Freescale MPC885 ADS", + .probe = mpc885ads_probe, + .setup_arch = mpc885ads_setup_arch, + .init_IRQ = m8xx_pic_init, + .get_irq = mpc8xx_get_irq, + .restart = mpc8xx_restart, + .calibrate_decr = mpc8xx_calibrate_decr, + .set_rtc_time = mpc8xx_set_rtc_time, + .get_rtc_time = mpc8xx_get_rtc_time, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 19d4628edf79..cc6013ffc29a 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -12,13 +12,10 @@ config PPC_MULTIPLATFORM RS/6000 machine, an Apple machine, or a PReP, CHRP, Maple or Cell-based machine. -config EMBEDDED6xx - bool "Embedded 6xx/7xx/7xxx-based board" - depends on PPC32 && (BROKEN||BROKEN_ON_SMP) - config PPC_82xx bool "Freescale 82xx" depends on 6xx + select WANT_DEVICE_TREE config PPC_83xx bool "Freescale 83xx" @@ -58,7 +55,7 @@ source "arch/powerpc/platforms/85xx/Kconfig" source "arch/powerpc/platforms/86xx/Kconfig" source "arch/powerpc/platforms/embedded6xx/Kconfig" source "arch/powerpc/platforms/44x/Kconfig" -#source "arch/powerpc/platforms/4xx/Kconfig +source "arch/powerpc/platforms/40x/Kconfig" config PPC_NATIVE bool @@ -136,6 +133,16 @@ config MPIC_U3_HT_IRQS depends on PPC_MAPLE default y +config MPIC_BROKEN_REGREAD + bool + depends on MPIC + help + This option enables a MPIC driver workaround for some chips + that have a bug that causes some interrupt source information + to not read back properly. It is safe to use on other chips as + well, but enabling it uses about 8KB of memory to keep copies + of the register contents in software. + config IBMVIO depends on PPC_PSERIES || PPC_ISERIES bool @@ -266,12 +273,24 @@ config QUICC_ENGINE config CPM2 bool default n + select CPM help The CPM2 (Communications Processor Module) is a coprocessor on embedded CPUs made by Freescale. Selecting this option means that you wish to build a kernel for a machine with a CPM2 coprocessor on it (826x, 827x, 8560). +config PPC_CPM_NEW_BINDING + bool + depends on CPM1 || CPM2 + help + Select this if your board has been converted to use the new + device tree bindings for CPM, and no longer needs the + ioport callbacks or the platform device glue code. + + The fs_enet and cpm_uart drivers will be built as + of_platform devices. + config AXON_RAM tristate "Axon DDR2 memory device driver" depends on PPC_IBM_CELL_BLADE @@ -291,4 +310,7 @@ config FSL_ULI1575 Freescale reference boards. The boards all use the ULI in pretty much the same way. +config CPM + bool + endmenu diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index e4b2aee53a73..4c315be25015 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -36,10 +36,12 @@ config PPC_8xx bool "Freescale 8xx" select FSL_SOC select 8xx + select WANT_DEVICE_TREE config 40x bool "AMCC 40x" select PPC_DCR_NATIVE + select WANT_DEVICE_TREE config 44x bool "AMCC 44x" @@ -69,6 +71,18 @@ config POWER4 depends on PPC64 def_bool y +config TUNE_CELL + bool "Optimize for Cell Broadband Engine" + depends on PPC64 + help + Cause the compiler to optimize for the PPE of the Cell Broadband + Engine. This will make the code run considerably faster on Cell + but somewhat slower on other machines. This option only changes + the scheduling of instructions, not the selection of instructions + itself, so the resulting kernel will keep running on all other + machines. When building a kernel that is supposed to run only + on Cell, you should also select the POWER4_ONLY option. + config 6xx bool diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index d44e832b01f2..6d9079da5f5a 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_PPC_PMAC) += powermac/ endif endif obj-$(CONFIG_PPC_CHRP) += chrp/ -#obj-$(CONFIG_4xx) += 4xx/ +obj-$(CONFIG_40x) += 40x/ obj-$(CONFIG_44x) += 44x/ obj-$(CONFIG_PPC_MPC52xx) += 52xx/ obj-$(CONFIG_PPC_8xx) += 8xx/ diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index f88a7c76f296..61d12f183036 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -13,15 +13,13 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o endif # needed only when building loadable spufs.ko -spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ - spu_coredump.o \ - $(spufs-modular-m) \ + spu_syscalls.o \ $(spu-priv1-y) \ $(spu-manage-y) \ spufs/ diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 4c9ab5b70bae..1245b2f517bb 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -64,13 +64,11 @@ struct axon_msic { - struct device_node *dn; struct irq_host *irq_host; __le32 *fifo; dcr_host_t dcr_host; struct list_head list; u32 read_offset; - u32 dcr_base; }; static LIST_HEAD(axon_msic_list); @@ -79,12 +77,12 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val) { pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n); - dcr_write(msic->dcr_host, msic->dcr_base + dcr_n, val); + dcr_write(msic->dcr_host, msic->dcr_host.base + dcr_n, val); } static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n) { - return dcr_read(msic->dcr_host, msic->dcr_base + dcr_n); + return dcr_read(msic->dcr_host, msic->dcr_host.base + dcr_n); } static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) @@ -126,7 +124,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) const phandle *ph; struct axon_msic *msic = NULL; - dn = pci_device_to_OF_node(dev); + dn = of_node_get(pci_device_to_OF_node(dev)); if (!dn) { dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n"); return NULL; @@ -183,7 +181,7 @@ static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) int len; const u32 *prop; - dn = pci_device_to_OF_node(dev); + dn = of_node_get(pci_device_to_OF_node(dev)); if (!dn) { dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n"); return -ENODEV; @@ -295,15 +293,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int msic_host_match(struct irq_host *host, struct device_node *dn) -{ - struct axon_msic *msic = host->host_data; - - return msic->dn == dn; -} - static struct irq_host_ops msic_host_ops = { - .match = msic_host_match, .map = msic_host_map, }; @@ -314,7 +304,8 @@ static int axon_msi_notify_reboot(struct notifier_block *nb, u32 tmp; list_for_each_entry(msic, &axon_msic_list, list) { - pr_debug("axon_msi: disabling %s\n", msic->dn->full_name); + pr_debug("axon_msi: disabling %s\n", + msic->irq_host->of_node->full_name); tmp = msic_dcr_read(msic, MSIC_CTRL_REG); tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; msic_dcr_write(msic, MSIC_CTRL_REG, tmp); @@ -332,7 +323,7 @@ static int axon_msi_setup_one(struct device_node *dn) struct page *page; struct axon_msic *msic; unsigned int virq; - int dcr_len; + int dcr_base, dcr_len; pr_debug("axon_msi: setting up dn %s\n", dn->full_name); @@ -343,17 +334,17 @@ static int axon_msi_setup_one(struct device_node *dn) goto out; } - msic->dcr_base = dcr_resource_start(dn, 0); + dcr_base = dcr_resource_start(dn, 0); dcr_len = dcr_resource_len(dn, 0); - if (msic->dcr_base == 0 || dcr_len == 0) { + if (dcr_base == 0 || dcr_len == 0) { printk(KERN_ERR "axon_msi: couldn't parse dcr properties on %s\n", dn->full_name); goto out; } - msic->dcr_host = dcr_map(dn, msic->dcr_base, dcr_len); + msic->dcr_host = dcr_map(dn, dcr_base, dcr_len); if (!DCR_MAP_OK(msic->dcr_host)) { printk(KERN_ERR "axon_msi: dcr_map failed for %s\n", dn->full_name); @@ -370,8 +361,8 @@ static int axon_msi_setup_one(struct device_node *dn) msic->fifo = page_address(page); - msic->irq_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, NR_IRQS, - &msic_host_ops, 0); + msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP, + NR_IRQS, &msic_host_ops, 0); if (!msic->irq_host) { printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n", dn->full_name); @@ -387,8 +378,6 @@ static int axon_msi_setup_one(struct device_node *dn) goto out_free_host; } - msic->dn = of_node_get(dn); - set_irq_data(virq, msic); set_irq_chained_handler(virq, axon_msi_cascade); pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq); diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c index 0b6e8ee85ab1..901236fa0f07 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -24,7 +24,7 @@ #include <asm/machdep.h> #include <asm/of_platform.h> #include <asm/prom.h> -#include "cbe_regs.h" +#include <asm/cell-regs.h> #include "cbe_cpufreq.h" static DEFINE_MUTEX(cbe_switch_mutex); diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c index 163263b3e1cd..70fa7aef5edd 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c @@ -28,8 +28,8 @@ #include <linux/time.h> #include <asm/machdep.h> #include <asm/hw_irq.h> +#include <asm/cell-regs.h> -#include "cbe_regs.h" #include "cbe_cpufreq.h" /* to write to MIC register */ diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c index fc6f38982ff4..6a2c1b0a9a94 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c @@ -27,12 +27,12 @@ #include <asm/processor.h> #include <asm/prom.h> #include <asm/pmi.h> +#include <asm/cell-regs.h> #ifdef DEBUG #include <asm/time.h> #endif -#include "cbe_regs.h" #include "cbe_cpufreq.h" static u8 pmi_slow_mode_limit[MAX_CBE]; diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c index c8f7f0007422..16a9b07e7b0c 100644 --- a/arch/powerpc/platforms/cell/cbe_regs.c +++ b/arch/powerpc/platforms/cell/cbe_regs.c @@ -16,8 +16,7 @@ #include <asm/ptrace.h> #include <asm/of_device.h> #include <asm/of_platform.h> - -#include "cbe_regs.h" +#include <asm/cell-regs.h> /* * Current implementation uses "cpu" nodes. We build our own mapping diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h deleted file mode 100644 index b24025f2ac7a..000000000000 --- a/arch/powerpc/platforms/cell/cbe_regs.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * cbe_regs.h - * - * This file is intended to hold the various register definitions for CBE - * on-chip system devices (memory controller, IO controller, etc...) - * - * (C) Copyright IBM Corporation 2001,2006 - * - * Authors: Maximino Aguilar (maguilar@us.ibm.com) - * David J. Erb (djerb@us.ibm.com) - * - * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. - */ - -#ifndef CBE_REGS_H -#define CBE_REGS_H - -#include <asm/cell-pmu.h> - -/* - * - * Some HID register definitions - * - */ - -/* CBE specific HID0 bits */ -#define HID0_CBE_THERM_WAKEUP 0x0000020000000000ul -#define HID0_CBE_SYSERR_WAKEUP 0x0000008000000000ul -#define HID0_CBE_THERM_INT_EN 0x0000000400000000ul -#define HID0_CBE_SYSERR_INT_EN 0x0000000200000000ul - -#define MAX_CBE 2 - -/* - * - * Pervasive unit register definitions - * - */ - -union spe_reg { - u64 val; - u8 spe[8]; -}; - -union ppe_spe_reg { - u64 val; - struct { - u32 ppe; - u32 spe; - }; -}; - - -struct cbe_pmd_regs { - /* Debug Bus Control */ - u64 pad_0x0000; /* 0x0000 */ - - u64 group_control; /* 0x0008 */ - - u8 pad_0x0010_0x00a8 [0x00a8 - 0x0010]; /* 0x0010 */ - - u64 debug_bus_control; /* 0x00a8 */ - - u8 pad_0x00b0_0x0100 [0x0100 - 0x00b0]; /* 0x00b0 */ - - u64 trace_aux_data; /* 0x0100 */ - u64 trace_buffer_0_63; /* 0x0108 */ - u64 trace_buffer_64_127; /* 0x0110 */ - u64 trace_address; /* 0x0118 */ - u64 ext_tr_timer; /* 0x0120 */ - - u8 pad_0x0128_0x0400 [0x0400 - 0x0128]; /* 0x0128 */ - - /* Performance Monitor */ - u64 pm_status; /* 0x0400 */ - u64 pm_control; /* 0x0408 */ - u64 pm_interval; /* 0x0410 */ - u64 pm_ctr[4]; /* 0x0418 */ - u64 pm_start_stop; /* 0x0438 */ - u64 pm07_control[8]; /* 0x0440 */ - - u8 pad_0x0480_0x0800 [0x0800 - 0x0480]; /* 0x0480 */ - - /* Thermal Sensor Registers */ - union spe_reg ts_ctsr1; /* 0x0800 */ - u64 ts_ctsr2; /* 0x0808 */ - union spe_reg ts_mtsr1; /* 0x0810 */ - u64 ts_mtsr2; /* 0x0818 */ - union spe_reg ts_itr1; /* 0x0820 */ - u64 ts_itr2; /* 0x0828 */ - u64 ts_gitr; /* 0x0830 */ - u64 ts_isr; /* 0x0838 */ - u64 ts_imr; /* 0x0840 */ - union spe_reg tm_cr1; /* 0x0848 */ - u64 tm_cr2; /* 0x0850 */ - u64 tm_simr; /* 0x0858 */ - union ppe_spe_reg tm_tpr; /* 0x0860 */ - union spe_reg tm_str1; /* 0x0868 */ - u64 tm_str2; /* 0x0870 */ - union ppe_spe_reg tm_tsr; /* 0x0878 */ - - /* Power Management */ - u64 pmcr; /* 0x0880 */ -#define CBE_PMD_PAUSE_ZERO_CONTROL 0x10000 - u64 pmsr; /* 0x0888 */ - - /* Time Base Register */ - u64 tbr; /* 0x0890 */ - - u8 pad_0x0898_0x0c00 [0x0c00 - 0x0898]; /* 0x0898 */ - - /* Fault Isolation Registers */ - u64 checkstop_fir; /* 0x0c00 */ - u64 recoverable_fir; /* 0x0c08 */ - u64 spec_att_mchk_fir; /* 0x0c10 */ - u32 fir_mode_reg; /* 0x0c18 */ - u8 pad_0x0c1c_0x0c20 [4]; /* 0x0c1c */ -#define CBE_PMD_FIR_MODE_M8 0x00800 - u64 fir_enable_mask; /* 0x0c20 */ - - u8 pad_0x0c28_0x0ca8 [0x0ca8 - 0x0c28]; /* 0x0c28 */ - u64 ras_esc_0; /* 0x0ca8 */ - u8 pad_0x0cb0_0x1000 [0x1000 - 0x0cb0]; /* 0x0cb0 */ -}; - -extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np); -extern struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu); - -/* - * PMU shadow registers - * - * Many of the registers in the performance monitoring unit are write-only, - * so we need to save a copy of what we write to those registers. - * - * The actual data counters are read/write. However, writing to the counters - * only takes effect if the PMU is enabled. Otherwise the value is stored in - * a hardware latch until the next time the PMU is enabled. So we save a copy - * of the counter values if we need to read them back while the PMU is - * disabled. The counter_value_in_latch field is a bitmap indicating which - * counters currently have a value waiting to be written. - */ - -struct cbe_pmd_shadow_regs { - u32 group_control; - u32 debug_bus_control; - u32 trace_address; - u32 ext_tr_timer; - u32 pm_status; - u32 pm_control; - u32 pm_interval; - u32 pm_start_stop; - u32 pm07_control[NR_CTRS]; - - u32 pm_ctr[NR_PHYS_CTRS]; - u32 counter_value_in_latch; -}; - -extern struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np); -extern struct cbe_pmd_shadow_regs *cbe_get_cpu_pmd_shadow_regs(int cpu); - -/* - * - * IIC unit register definitions - * - */ - -struct cbe_iic_pending_bits { - u32 data; - u8 flags; - u8 class; - u8 source; - u8 prio; -}; - -#define CBE_IIC_IRQ_VALID 0x80 -#define CBE_IIC_IRQ_IPI 0x40 - -struct cbe_iic_thread_regs { - struct cbe_iic_pending_bits pending; - struct cbe_iic_pending_bits pending_destr; - u64 generate; - u64 prio; -}; - -struct cbe_iic_regs { - u8 pad_0x0000_0x0400[0x0400 - 0x0000]; /* 0x0000 */ - - /* IIC interrupt registers */ - struct cbe_iic_thread_regs thread[2]; /* 0x0400 */ - - u64 iic_ir; /* 0x0440 */ -#define CBE_IIC_IR_PRIO(x) (((x) & 0xf) << 12) -#define CBE_IIC_IR_DEST_NODE(x) (((x) & 0xf) << 4) -#define CBE_IIC_IR_DEST_UNIT(x) ((x) & 0xf) -#define CBE_IIC_IR_IOC_0 0x0 -#define CBE_IIC_IR_IOC_1S 0xb -#define CBE_IIC_IR_PT_0 0xe -#define CBE_IIC_IR_PT_1 0xf - - u64 iic_is; /* 0x0448 */ -#define CBE_IIC_IS_PMI 0x2 - - u8 pad_0x0450_0x0500[0x0500 - 0x0450]; /* 0x0450 */ - - /* IOC FIR */ - u64 ioc_fir_reset; /* 0x0500 */ - u64 ioc_fir_set; /* 0x0508 */ - u64 ioc_checkstop_enable; /* 0x0510 */ - u64 ioc_fir_error_mask; /* 0x0518 */ - u64 ioc_syserr_enable; /* 0x0520 */ - u64 ioc_fir; /* 0x0528 */ - - u8 pad_0x0530_0x1000[0x1000 - 0x0530]; /* 0x0530 */ -}; - -extern struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np); -extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu); - - -struct cbe_mic_tm_regs { - u8 pad_0x0000_0x0040[0x0040 - 0x0000]; /* 0x0000 */ - - u64 mic_ctl_cnfg2; /* 0x0040 */ -#define CBE_MIC_ENABLE_AUX_TRC 0x8000000000000000LL -#define CBE_MIC_DISABLE_PWR_SAV_2 0x0200000000000000LL -#define CBE_MIC_DISABLE_AUX_TRC_WRAP 0x0100000000000000LL -#define CBE_MIC_ENABLE_AUX_TRC_INT 0x0080000000000000LL - - u64 pad_0x0048; /* 0x0048 */ - - u64 mic_aux_trc_base; /* 0x0050 */ - u64 mic_aux_trc_max_addr; /* 0x0058 */ - u64 mic_aux_trc_cur_addr; /* 0x0060 */ - u64 mic_aux_trc_grf_addr; /* 0x0068 */ - u64 mic_aux_trc_grf_data; /* 0x0070 */ - - u64 pad_0x0078; /* 0x0078 */ - - u64 mic_ctl_cnfg_0; /* 0x0080 */ -#define CBE_MIC_DISABLE_PWR_SAV_0 0x8000000000000000LL - - u64 pad_0x0088; /* 0x0088 */ - - u64 slow_fast_timer_0; /* 0x0090 */ - u64 slow_next_timer_0; /* 0x0098 */ - - u8 pad_0x00a0_0x01c0[0x01c0 - 0x0a0]; /* 0x00a0 */ - - u64 mic_ctl_cnfg_1; /* 0x01c0 */ -#define CBE_MIC_DISABLE_PWR_SAV_1 0x8000000000000000LL - u64 pad_0x01c8; /* 0x01c8 */ - - u64 slow_fast_timer_1; /* 0x01d0 */ - u64 slow_next_timer_1; /* 0x01d8 */ - - u8 pad_0x01e0_0x1000[0x1000 - 0x01e0]; /* 0x01e0 */ -}; - -extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np); -extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu); - -/* some utility functions to deal with SMT */ -extern u32 cbe_get_hw_thread_id(int cpu); -extern u32 cbe_cpu_to_node(int cpu); -extern u32 cbe_node_to_cpu(int node); - -/* Init this module early */ -extern void cbe_regs_init(void); - - -#endif /* CBE_REGS_H */ diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c index fb5eda48467d..4852bf312d83 100644 --- a/arch/powerpc/platforms/cell/cbe_thermal.c +++ b/arch/powerpc/platforms/cell/cbe_thermal.c @@ -52,8 +52,8 @@ #include <asm/spu.h> #include <asm/io.h> #include <asm/prom.h> +#include <asm/cell-regs.h> -#include "cbe_regs.h" #include "spu_priv1_mmio.h" #define TEMP_MIN 65 diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 47264e722029..151fd8b82d63 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -41,9 +41,9 @@ #include <asm/prom.h> #include <asm/ptrace.h> #include <asm/machdep.h> +#include <asm/cell-regs.h> #include "interrupt.h" -#include "cbe_regs.h" struct iic { struct cbe_iic_thread_regs __iomem *regs; @@ -381,7 +381,7 @@ static int __init setup_iic(void) void __init iic_init_IRQ(void) { /* Setup an irq host data structure */ - iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, + iic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, &iic_host_ops, IIC_IRQ_INVALID); BUG_ON(iic_host == NULL); irq_set_default_host(iic_host); diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 760caa76841a..faabc3fdc130 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -34,8 +34,8 @@ #include <asm/udbg.h> #include <asm/of_platform.h> #include <asm/lmb.h> +#include <asm/cell-regs.h> -#include "cbe_regs.h" #include "interrupt.h" /* Define CELL_IOMMU_REAL_UNMAP to actually unmap non-used pages diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 4ede22d363fa..0304589c0a80 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c @@ -34,9 +34,9 @@ #include <asm/prom.h> #include <asm/pgtable.h> #include <asm/reg.h> +#include <asm/cell-regs.h> #include "pervasive.h" -#include "cbe_regs.h" static int sysreset_hack; diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c index 66ca4b5a1dbc..1ed303678887 100644 --- a/arch/powerpc/platforms/cell/pmu.c +++ b/arch/powerpc/platforms/cell/pmu.c @@ -30,8 +30,8 @@ #include <asm/pmc.h> #include <asm/reg.h> #include <asm/spu.h> +#include <asm/cell-regs.h> -#include "cbe_regs.h" #include "interrupt.h" /* diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index 3961a085b432..b2494ebcdbe9 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c @@ -10,9 +10,9 @@ #include <asm/prom.h> #include <asm/machdep.h> #include <asm/rtas.h> +#include <asm/cell-regs.h> #include "ras.h" -#include "cbe_regs.h" static void dump_fir(int cpu) diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index db6654272e13..98e7ef8e6fc6 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -52,9 +52,9 @@ #include <asm/udbg.h> #include <asm/mpic.h> #include <asm/of_platform.h> +#include <asm/cell-regs.h> #include "interrupt.h" -#include "cbe_regs.h" #include "pervasive.h" #include "ras.h" @@ -83,12 +83,22 @@ static void cell_progress(char *s, unsigned short hex) static int __init cell_publish_devices(void) { + int node; + if (!machine_is(cell)) return 0; /* Publish OF platform devices for southbridge IOs */ of_platform_bus_probe(NULL, NULL, NULL); + /* There is no device for the MIC memory controller, thus we create + * a platform device for it to attach the EDAC driver to. + */ + for_each_online_node(node) { + if (cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(node)) == NULL) + continue; + platform_device_register_simple("cbe-mic", node, NULL, 0); + } return 0; } device_initcall(cell_publish_devices); @@ -161,11 +171,6 @@ static void __init cell_setup_arch(void) /* init to some ~sane value until calibrate_delay() runs */ loops_per_jiffy = 50000000; - if (ROOT_DEV == 0) { - printk("No ramdisk, default root is /dev/hda2\n"); - ROOT_DEV = Root_HDA2; - } - /* Find and initialize PCI host bridges */ init_pci_config_tokens(); find_and_init_phbs(); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 05f4b3d3d756..3f4b4aef756d 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -63,7 +63,6 @@ enum { struct spider_pic { struct irq_host *host; - struct device_node *of_node; void __iomem *regs; unsigned int node_id; }; @@ -176,12 +175,6 @@ static struct irq_chip spider_pic = { .set_type = spider_set_irq_type, }; -static int spider_host_match(struct irq_host *h, struct device_node *node) -{ - struct spider_pic *pic = h->host_data; - return node == pic->of_node; -} - static int spider_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { @@ -208,7 +201,6 @@ static int spider_host_xlate(struct irq_host *h, struct device_node *ct, } static struct irq_host_ops spider_host_ops = { - .match = spider_host_match, .map = spider_host_map, .xlate = spider_host_xlate, }; @@ -247,18 +239,18 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) * tree in case the device-tree is ever fixed */ struct of_irq oirq; - if (of_irq_map_one(pic->of_node, 0, &oirq) == 0) { + if (of_irq_map_one(pic->host->of_node, 0, &oirq) == 0) { virq = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size); return virq; } /* Now do the horrible hacks */ - tmp = of_get_property(pic->of_node, "#interrupt-cells", NULL); + tmp = of_get_property(pic->host->of_node, "#interrupt-cells", NULL); if (tmp == NULL) return NO_IRQ; intsize = *tmp; - imap = of_get_property(pic->of_node, "interrupt-map", &imaplen); + imap = of_get_property(pic->host->of_node, "interrupt-map", &imaplen); if (imap == NULL || imaplen < (intsize + 1)) return NO_IRQ; iic = of_find_node_by_phandle(imap[intsize]); @@ -308,15 +300,13 @@ static void __init spider_init_one(struct device_node *of_node, int chip, panic("spider_pic: can't map registers !"); /* Allocate a host */ - pic->host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, SPIDER_SRC_COUNT, - &spider_host_ops, SPIDER_IRQ_INVALID); + pic->host = irq_alloc_host(of_node_get(of_node), IRQ_HOST_MAP_LINEAR, + SPIDER_SRC_COUNT, &spider_host_ops, + SPIDER_IRQ_INVALID); if (pic->host == NULL) panic("spider_pic: can't allocate irq host !"); pic->host->host_data = pic; - /* Fill out other bits */ - pic->of_node = of_node_get(of_node); - /* Go through all sources and disable them */ for (i = 0; i < SPIDER_SRC_COUNT; i++) { void __iomem *cfg = pic->regs + TIR_CFGA + 8 * i; diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 106d2921e2d9..c83c3e3f5178 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -168,7 +168,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) #else psize = mm->context.user_psize; #endif - vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | + vsid = (get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_USER; break; case VMALLOC_REGION_ID: @@ -176,12 +176,12 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) psize = mmu_vmalloc_psize; else psize = mmu_io_psize; - vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | + vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL; break; case KERNEL_REGION_ID: psize = mmu_linear_psize; - vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | + vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL; break; default: @@ -458,7 +458,7 @@ static int spu_shutdown(struct sys_device *sysdev) return 0; } -struct sysdev_class spu_sysdev_class = { +static struct sysdev_class spu_sysdev_class = { set_kset_name("spu"), .shutdown = spu_shutdown, }; diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c index 47ec3be3edcd..dceb8b6a9382 100644 --- a/arch/powerpc/platforms/cell/spu_callbacks.c +++ b/arch/powerpc/platforms/cell/spu_callbacks.c @@ -2,7 +2,7 @@ * System call callback functions for SPUs */ -#define DEBUG +#undef DEBUG #include <linux/kallsyms.h> #include <linux/module.h> @@ -33,7 +33,7 @@ * mbind, mq_open, ipc, ... */ -void *spu_syscall_table[] = { +static void *spu_syscall_table[] = { #define SYSCALL(func) sys_ni_syscall, #define COMPAT_SYS(func) sys_ni_syscall, #define PPC_SYS(func) sys_ni_syscall, diff --git a/arch/powerpc/platforms/cell/spu_coredump.c b/arch/powerpc/platforms/cell/spu_coredump.c deleted file mode 100644 index 4fd37ff1e210..000000000000 --- a/arch/powerpc/platforms/cell/spu_coredump.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SPU core dump code - * - * (C) Copyright 2006 IBM Corp. - * - * Author: Dwayne Grant McConnell <decimal@us.ibm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/file.h> -#include <linux/module.h> -#include <linux/syscalls.h> - -#include <asm/spu.h> - -static struct spu_coredump_calls *spu_coredump_calls; -static DEFINE_MUTEX(spu_coredump_mutex); - -int arch_notes_size(void) -{ - long ret; - - ret = -ENOSYS; - mutex_lock(&spu_coredump_mutex); - if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) { - ret = spu_coredump_calls->arch_notes_size(); - module_put(spu_coredump_calls->owner); - } - mutex_unlock(&spu_coredump_mutex); - return ret; -} - -void arch_write_notes(struct file *file) -{ - mutex_lock(&spu_coredump_mutex); - if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) { - spu_coredump_calls->arch_write_notes(file); - module_put(spu_coredump_calls->owner); - } - mutex_unlock(&spu_coredump_mutex); -} - -int register_arch_coredump_calls(struct spu_coredump_calls *calls) -{ - int ret = 0; - - - mutex_lock(&spu_coredump_mutex); - if (spu_coredump_calls) - ret = -EBUSY; - else - spu_coredump_calls = calls; - mutex_unlock(&spu_coredump_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(register_arch_coredump_calls); - -void unregister_arch_coredump_calls(struct spu_coredump_calls *calls) -{ - BUG_ON(spu_coredump_calls != calls); - - mutex_lock(&spu_coredump_mutex); - spu_coredump_calls = NULL; - mutex_unlock(&spu_coredump_mutex); -} -EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls); diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index 0e14f532500e..1b010707488d 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -377,10 +377,10 @@ static int qs20_reg_memory[QS20_SPES_PER_BE] = { 1, 1, 0, 0, 0, 0, 0, 0 }; static struct spu *spu_lookup_reg(int node, u32 reg) { struct spu *spu; - u32 *spu_reg; + const u32 *spu_reg; list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { - spu_reg = (u32*)of_get_property(spu_devnode(spu), "reg", NULL); + spu_reg = of_get_property(spu_devnode(spu), "reg", NULL); if (*spu_reg == reg) return spu; } diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index 027ac32cc636..a9438b719fe8 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -2,6 +2,7 @@ * SPU file system -- system call stubs * * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 + * (C) Copyright 2006-2007, IBM Corporation * * Author: Arnd Bergmann <arndb@de.ibm.com> * @@ -20,44 +21,73 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/file.h> +#include <linux/fs.h> #include <linux/module.h> #include <linux/syscalls.h> +#include <linux/rcupdate.h> #include <asm/spu.h> -struct spufs_calls spufs_calls = { - .owner = NULL, -}; +/* protected by rcu */ +static struct spufs_calls *spufs_calls; -/* These stub syscalls are needed to have the actual implementation - * within a loadable module. When spufs is built into the kernel, - * this file is not used and the syscalls directly enter the fs code */ +#ifdef CONFIG_SPU_FS_MODULE + +static inline struct spufs_calls *spufs_calls_get(void) +{ + struct spufs_calls *calls = NULL; + + rcu_read_lock(); + calls = rcu_dereference(spufs_calls); + if (calls && !try_module_get(calls->owner)) + calls = NULL; + rcu_read_unlock(); + + return calls; +} + +static inline void spufs_calls_put(struct spufs_calls *calls) +{ + BUG_ON(calls != spufs_calls); + + /* we don't need to rcu this, as we hold a reference to the module */ + module_put(spufs_calls->owner); +} + +#else /* !defined CONFIG_SPU_FS_MODULE */ + +static inline struct spufs_calls *spufs_calls_get(void) +{ + return spufs_calls; +} + +static inline void spufs_calls_put(struct spufs_calls *calls) { } + +#endif /* CONFIG_SPU_FS_MODULE */ asmlinkage long sys_spu_create(const char __user *name, unsigned int flags, mode_t mode, int neighbor_fd) { long ret; - struct module *owner = spufs_calls.owner; struct file *neighbor; int fput_needed; + struct spufs_calls *calls; - ret = -ENOSYS; - if (owner && try_module_get(owner)) { - if (flags & SPU_CREATE_AFFINITY_SPU) { - neighbor = fget_light(neighbor_fd, &fput_needed); - ret = -EBADF; - if (neighbor) { - ret = spufs_calls.create_thread(name, flags, - mode, neighbor); - fput_light(neighbor, fput_needed); - } - } - else { - ret = spufs_calls.create_thread(name, flags, - mode, NULL); + calls = spufs_calls_get(); + if (!calls) + return -ENOSYS; + + if (flags & SPU_CREATE_AFFINITY_SPU) { + ret = -EBADF; + neighbor = fget_light(neighbor_fd, &fput_needed); + if (neighbor) { + ret = calls->create_thread(name, flags, mode, neighbor); + fput_light(neighbor, fput_needed); } - module_put(owner); - } + } else + ret = calls->create_thread(name, flags, mode, NULL); + + spufs_calls_put(calls); return ret; } @@ -66,37 +96,69 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) long ret; struct file *filp; int fput_needed; - struct module *owner = spufs_calls.owner; + struct spufs_calls *calls; - ret = -ENOSYS; - if (owner && try_module_get(owner)) { - ret = -EBADF; - filp = fget_light(fd, &fput_needed); - if (filp) { - ret = spufs_calls.spu_run(filp, unpc, ustatus); - fput_light(filp, fput_needed); - } - module_put(owner); + calls = spufs_calls_get(); + if (!calls) + return -ENOSYS; + + ret = -EBADF; + filp = fget_light(fd, &fput_needed); + if (filp) { + ret = calls->spu_run(filp, unpc, ustatus); + fput_light(filp, fput_needed); } + + spufs_calls_put(calls); + return ret; +} + +int elf_coredump_extra_notes_size(void) +{ + struct spufs_calls *calls; + int ret; + + calls = spufs_calls_get(); + if (!calls) + return 0; + + ret = calls->coredump_extra_notes_size(); + + spufs_calls_put(calls); + + return ret; +} + +int elf_coredump_extra_notes_write(struct file *file, loff_t *foffset) +{ + struct spufs_calls *calls; + int ret; + + calls = spufs_calls_get(); + if (!calls) + return 0; + + ret = calls->coredump_extra_notes_write(file, foffset); + + spufs_calls_put(calls); + return ret; } int register_spu_syscalls(struct spufs_calls *calls) { - if (spufs_calls.owner) + if (spufs_calls) return -EBUSY; - spufs_calls.create_thread = calls->create_thread; - spufs_calls.spu_run = calls->spu_run; - smp_mb(); - spufs_calls.owner = calls->owner; + rcu_assign_pointer(spufs_calls, calls); return 0; } EXPORT_SYMBOL_GPL(register_spu_syscalls); void unregister_spu_syscalls(struct spufs_calls *calls) { - BUG_ON(spufs_calls.owner != calls->owner); - spufs_calls.owner = NULL; + BUG_ON(spufs_calls->owner != calls->owner); + rcu_assign_pointer(spufs_calls, NULL); + synchronize_rcu(); } EXPORT_SYMBOL_GPL(unregister_spu_syscalls); diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 5e31799b1e3f..80f62363e1ce 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -31,16 +31,7 @@ #include "spufs.h" -struct spufs_ctx_info { - struct list_head list; - int dfd; - int memsize; /* in bytes */ - struct spu_context *ctx; -}; - -static LIST_HEAD(ctx_info_list); - -static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *buffer, +static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer, size_t size, loff_t *off) { u64 data; @@ -50,49 +41,57 @@ static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *b return spufs_coredump_read[num].read(ctx, buffer, size, off); data = spufs_coredump_read[num].get(ctx); - ret = copy_to_user(buffer, &data, 8); - return ret ? -EFAULT : 8; + ret = snprintf(buffer, size, "0x%.16lx", data); + if (ret >= size) + return size; + return ++ret; /* count trailing NULL */ } /* * These are the only things you should do on a core-file: use only these * functions to write out all the necessary info. */ -static int spufs_dump_write(struct file *file, const void *addr, int nr) +static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset) { - return file->f_op->write(file, addr, nr, &file->f_pos) == nr; -} + unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; + ssize_t written; -static int spufs_dump_seek(struct file *file, loff_t off) -{ - if (file->f_op->llseek) { - if (file->f_op->llseek(file, off, 0) != off) - return 0; - } else - file->f_pos = off; - return 1; + if (*foffset + nr > limit) + return -EIO; + + written = file->f_op->write(file, addr, nr, &file->f_pos); + *foffset += written; + + if (written != nr) + return -EIO; + + return 0; } -static void spufs_fill_memsize(struct spufs_ctx_info *ctx_info) +static int spufs_dump_align(struct file *file, char *buf, loff_t new_off, + loff_t *foffset) { - struct spu_context *ctx; - unsigned long long lslr; + int rc, size; + + size = min((loff_t)PAGE_SIZE, new_off - *foffset); + memset(buf, 0, size); + + rc = 0; + while (rc == 0 && new_off > *foffset) { + size = min((loff_t)PAGE_SIZE, new_off - *foffset); + rc = spufs_dump_write(file, buf, size, foffset); + } - ctx = ctx_info->ctx; - lslr = ctx->csa.priv2.spu_lslr_RW; - ctx_info->memsize = lslr + 1; + return rc; } -static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info) +static int spufs_ctx_note_size(struct spu_context *ctx, int dfd) { - int dfd, memsize, i, sz, total = 0; + int i, sz, total = 0; char *name; char fullname[80]; - dfd = ctx_info->dfd; - memsize = ctx_info->memsize; - - for (i = 0; spufs_coredump_read[i].name; i++) { + for (i = 0; spufs_coredump_read[i].name != NULL; i++) { name = spufs_coredump_read[i].name; sz = spufs_coredump_read[i].size; @@ -100,39 +99,12 @@ static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info) total += sizeof(struct elf_note); total += roundup(strlen(fullname) + 1, 4); - if (!strcmp(name, "mem")) - total += roundup(memsize, 4); - else - total += roundup(sz, 4); + total += roundup(sz, 4); } return total; } -static int spufs_add_one_context(struct file *file, int dfd) -{ - struct spu_context *ctx; - struct spufs_ctx_info *ctx_info; - int size; - - ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx; - if (ctx->flags & SPU_CREATE_NOSCHED) - return 0; - - ctx_info = kzalloc(sizeof(*ctx_info), GFP_KERNEL); - if (unlikely(!ctx_info)) - return -ENOMEM; - - ctx_info->dfd = dfd; - ctx_info->ctx = ctx; - - spufs_fill_memsize(ctx_info); - - size = spufs_ctx_note_size(ctx_info); - list_add(&ctx_info->list, &ctx_info_list); - return size; -} - /* * The additional architecture-specific notes for Cell are various * context files in the spu context. @@ -142,33 +114,57 @@ static int spufs_add_one_context(struct file *file, int dfd) * internal functionality to dump them without needing to actually * open the files. */ -static int spufs_arch_notes_size(void) +static struct spu_context *coredump_next_context(int *fd) { struct fdtable *fdt = files_fdtable(current->files); - int size = 0, fd; + struct file *file; + struct spu_context *ctx = NULL; - for (fd = 0; fd < fdt->max_fds; fd++) { - if (FD_ISSET(fd, fdt->open_fds)) { - struct file *file = fcheck(fd); + for (; *fd < fdt->max_fds; (*fd)++) { + if (!FD_ISSET(*fd, fdt->open_fds)) + continue; - if (file && file->f_op == &spufs_context_fops) { - int rval = spufs_add_one_context(file, fd); - if (rval < 0) - break; - size += rval; - } - } + file = fcheck(*fd); + + if (!file || file->f_op != &spufs_context_fops) + continue; + + ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx; + if (ctx->flags & SPU_CREATE_NOSCHED) + continue; + + /* start searching the next fd next time we're called */ + (*fd)++; + break; } - return size; + return ctx; } -static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, - struct file *file) +int spufs_coredump_extra_notes_size(void) { struct spu_context *ctx; + int size = 0, rc, fd; + + fd = 0; + while ((ctx = coredump_next_context(&fd)) != NULL) { + spu_acquire_saved(ctx); + rc = spufs_ctx_note_size(ctx, fd); + spu_release_saved(ctx); + if (rc < 0) + break; + + size += rc; + } + + return size; +} + +static int spufs_arch_write_note(struct spu_context *ctx, int i, + struct file *file, int dfd, loff_t *foffset) +{ loff_t pos = 0; - int sz, dfd, rc, total = 0; + int sz, rc, nread, total = 0; const int bufsz = PAGE_SIZE; char *name; char fullname[80], *buf; @@ -176,64 +172,70 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, buf = (void *)get_zeroed_page(GFP_KERNEL); if (!buf) - return; + return -ENOMEM; - dfd = ctx_info->dfd; name = spufs_coredump_read[i].name; - - if (!strcmp(name, "mem")) - sz = ctx_info->memsize; - else - sz = spufs_coredump_read[i].size; - - ctx = ctx_info->ctx; - if (!ctx) - goto out; + sz = spufs_coredump_read[i].size; sprintf(fullname, "SPU/%d/%s", dfd, name); en.n_namesz = strlen(fullname) + 1; en.n_descsz = sz; en.n_type = NT_SPU; - if (!spufs_dump_write(file, &en, sizeof(en))) + rc = spufs_dump_write(file, &en, sizeof(en), foffset); + if (rc) goto out; - if (!spufs_dump_write(file, fullname, en.n_namesz)) + + rc = spufs_dump_write(file, fullname, en.n_namesz, foffset); + if (rc) goto out; - if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4))) + + rc = spufs_dump_align(file, buf, roundup(*foffset, 4), foffset); + if (rc) goto out; do { - rc = do_coredump_read(i, ctx, buf, bufsz, &pos); - if (rc > 0) { - if (!spufs_dump_write(file, buf, rc)) + nread = do_coredump_read(i, ctx, buf, bufsz, &pos); + if (nread > 0) { + rc = spufs_dump_write(file, buf, nread, foffset); + if (rc) goto out; - total += rc; + total += nread; } - } while (rc == bufsz && total < sz); + } while (nread == bufsz && total < sz); + + if (nread < 0) { + rc = nread; + goto out; + } + + rc = spufs_dump_align(file, buf, roundup(*foffset - total + sz, 4), + foffset); - spufs_dump_seek(file, roundup((unsigned long)file->f_pos - - total + sz, 4)); out: free_page((unsigned long)buf); + return rc; } -static void spufs_arch_write_notes(struct file *file) +int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset) { - int j; - struct spufs_ctx_info *ctx_info, *next; - - list_for_each_entry_safe(ctx_info, next, &ctx_info_list, list) { - spu_acquire_saved(ctx_info->ctx); - for (j = 0; j < spufs_coredump_num_notes; j++) - spufs_arch_write_note(ctx_info, j, file); - spu_release_saved(ctx_info->ctx); - list_del(&ctx_info->list); - kfree(ctx_info); + struct spu_context *ctx; + int fd, j, rc; + + fd = 0; + while ((ctx = coredump_next_context(&fd)) != NULL) { + spu_acquire_saved(ctx); + + for (j = 0; spufs_coredump_read[j].name != NULL; j++) { + rc = spufs_arch_write_note(ctx, j, file, fd, foffset); + if (rc) { + spu_release_saved(ctx); + return rc; + } + } + + spu_release_saved(ctx); } -} -struct spu_coredump_calls spufs_coredump_calls = { - .arch_notes_size = spufs_arch_notes_size, - .arch_write_notes = spufs_arch_write_notes, - .owner = THIS_MODULE, -}; + return 0; +} diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 7de4e919687b..d72b16d6816e 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -199,9 +199,9 @@ static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) } #ifdef CONFIG_SPU_FS_64K_LS -unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, - unsigned long flags) +static unsigned long spufs_get_unmapped_area(struct file *file, + unsigned long addr, unsigned long len, unsigned long pgoff, + unsigned long flags) { struct spu_context *ctx = file->private_data; struct spu_state *csa = &ctx->csa; @@ -1076,6 +1076,36 @@ static const struct file_operations spufs_signal2_nosched_fops = { .mmap = spufs_signal2_mmap, }; +/* + * This is a wrapper around DEFINE_SIMPLE_ATTRIBUTE which does the + * work of acquiring (or not) the SPU context before calling through + * to the actual get routine. The set routine is called directly. + */ +#define SPU_ATTR_NOACQUIRE 0 +#define SPU_ATTR_ACQUIRE 1 +#define SPU_ATTR_ACQUIRE_SAVED 2 + +#define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ +static u64 __##__get(void *data) \ +{ \ + struct spu_context *ctx = data; \ + u64 ret; \ + \ + if (__acquire == SPU_ATTR_ACQUIRE) { \ + spu_acquire(ctx); \ + ret = __get(ctx); \ + spu_release(ctx); \ + } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ + spu_acquire_saved(ctx); \ + ret = __get(ctx); \ + spu_release_saved(ctx); \ + } else \ + ret = __get(ctx); \ + \ + return ret; \ +} \ +DEFINE_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); + static void spufs_signal1_type_set(void *data, u64 val) { struct spu_context *ctx = data; @@ -1085,25 +1115,13 @@ static void spufs_signal1_type_set(void *data, u64 val) spu_release(ctx); } -static u64 __spufs_signal1_type_get(void *data) +static u64 spufs_signal1_type_get(struct spu_context *ctx) { - struct spu_context *ctx = data; return ctx->ops->signal1_type_get(ctx); } +DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, + spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); -static u64 spufs_signal1_type_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - - spu_acquire(ctx); - ret = __spufs_signal1_type_get(data); - spu_release(ctx); - - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, - spufs_signal1_type_set, "%llu"); static void spufs_signal2_type_set(void *data, u64 val) { @@ -1114,25 +1132,12 @@ static void spufs_signal2_type_set(void *data, u64 val) spu_release(ctx); } -static u64 __spufs_signal2_type_get(void *data) +static u64 spufs_signal2_type_get(struct spu_context *ctx) { - struct spu_context *ctx = data; return ctx->ops->signal2_type_get(ctx); } - -static u64 spufs_signal2_type_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - - spu_acquire(ctx); - ret = __spufs_signal2_type_get(data); - spu_release(ctx); - - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, - spufs_signal2_type_set, "%llu"); +DEFINE_SPUFS_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, + spufs_signal2_type_set, "%llu", SPU_ATTR_ACQUIRE); #if SPUFS_MMAP_4K static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, @@ -1608,17 +1613,12 @@ static void spufs_npc_set(void *data, u64 val) spu_release(ctx); } -static u64 spufs_npc_get(void *data) +static u64 spufs_npc_get(struct spu_context *ctx) { - struct spu_context *ctx = data; - u64 ret; - spu_acquire(ctx); - ret = ctx->ops->npc_read(ctx); - spu_release(ctx); - return ret; + return ctx->ops->npc_read(ctx); } -DEFINE_SIMPLE_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, - "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, + "0x%llx\n", SPU_ATTR_ACQUIRE); static void spufs_decr_set(void *data, u64 val) { @@ -1629,24 +1629,13 @@ static void spufs_decr_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 __spufs_decr_get(void *data) +static u64 spufs_decr_get(struct spu_context *ctx) { - struct spu_context *ctx = data; struct spu_lscsa *lscsa = ctx->csa.lscsa; return lscsa->decr.slot[0]; } - -static u64 spufs_decr_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - spu_acquire_saved(ctx); - ret = __spufs_decr_get(data); - spu_release_saved(ctx); - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, - "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, + "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); static void spufs_decr_status_set(void *data, u64 val) { @@ -1659,26 +1648,16 @@ static void spufs_decr_status_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 __spufs_decr_status_get(void *data) +static u64 spufs_decr_status_get(struct spu_context *ctx) { - struct spu_context *ctx = data; if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) return SPU_DECR_STATUS_RUNNING; else return 0; } - -static u64 spufs_decr_status_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - spu_acquire_saved(ctx); - ret = __spufs_decr_status_get(data); - spu_release_saved(ctx); - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, - spufs_decr_status_set, "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, + spufs_decr_status_set, "0x%llx\n", + SPU_ATTR_ACQUIRE_SAVED); static void spufs_event_mask_set(void *data, u64 val) { @@ -1689,28 +1668,18 @@ static void spufs_event_mask_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 __spufs_event_mask_get(void *data) +static u64 spufs_event_mask_get(struct spu_context *ctx) { - struct spu_context *ctx = data; struct spu_lscsa *lscsa = ctx->csa.lscsa; return lscsa->event_mask.slot[0]; } -static u64 spufs_event_mask_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - spu_acquire_saved(ctx); - ret = __spufs_event_mask_get(data); - spu_release_saved(ctx); - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, - spufs_event_mask_set, "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, + spufs_event_mask_set, "0x%llx\n", + SPU_ATTR_ACQUIRE_SAVED); -static u64 __spufs_event_status_get(void *data) +static u64 spufs_event_status_get(struct spu_context *ctx) { - struct spu_context *ctx = data; struct spu_state *state = &ctx->csa; u64 stat; stat = state->spu_chnlcnt_RW[0]; @@ -1718,19 +1687,8 @@ static u64 __spufs_event_status_get(void *data) return state->spu_chnldata_RW[0]; return 0; } - -static u64 spufs_event_status_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret = 0; - - spu_acquire_saved(ctx); - ret = __spufs_event_status_get(data); - spu_release_saved(ctx); - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, - NULL, "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, + NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) static void spufs_srr0_set(void *data, u64 val) { @@ -1741,45 +1699,32 @@ static void spufs_srr0_set(void *data, u64 val) spu_release_saved(ctx); } -static u64 spufs_srr0_get(void *data) +static u64 spufs_srr0_get(struct spu_context *ctx) { - struct spu_context *ctx = data; struct spu_lscsa *lscsa = ctx->csa.lscsa; - u64 ret; - spu_acquire_saved(ctx); - ret = lscsa->srr0.slot[0]; - spu_release_saved(ctx); - return ret; + return lscsa->srr0.slot[0]; } -DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, - "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, + "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) -static u64 spufs_id_get(void *data) +static u64 spufs_id_get(struct spu_context *ctx) { - struct spu_context *ctx = data; u64 num; - spu_acquire(ctx); if (ctx->state == SPU_STATE_RUNNABLE) num = ctx->spu->number; else num = (unsigned int)-1; - spu_release(ctx); return num; } -DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") - -static u64 __spufs_object_id_get(void *data) -{ - struct spu_context *ctx = data; - return ctx->object_id; -} +DEFINE_SPUFS_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n", + SPU_ATTR_ACQUIRE) -static u64 spufs_object_id_get(void *data) +static u64 spufs_object_id_get(struct spu_context *ctx) { /* FIXME: Should there really be no locking here? */ - return __spufs_object_id_get(data); + return ctx->object_id; } static void spufs_object_id_set(void *data, u64 id) @@ -1788,27 +1733,15 @@ static void spufs_object_id_set(void *data, u64 id) ctx->object_id = id; } -DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, - spufs_object_id_set, "0x%llx\n"); +DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, + spufs_object_id_set, "0x%llx\n", SPU_ATTR_NOACQUIRE); -static u64 __spufs_lslr_get(void *data) +static u64 spufs_lslr_get(struct spu_context *ctx) { - struct spu_context *ctx = data; return ctx->csa.priv2.spu_lslr_RW; } - -static u64 spufs_lslr_get(void *data) -{ - struct spu_context *ctx = data; - u64 ret; - - spu_acquire_saved(ctx); - ret = __spufs_lslr_get(data); - spu_release_saved(ctx); - - return ret; -} -DEFINE_SIMPLE_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n") +DEFINE_SPUFS_ATTRIBUTE(spufs_lslr_ops, spufs_lslr_get, NULL, "0x%llx\n", + SPU_ATTR_ACQUIRE_SAVED); static int spufs_info_open(struct inode *inode, struct file *file) { @@ -2231,25 +2164,25 @@ struct tree_descr spufs_dir_nosched_contents[] = { }; struct spufs_coredump_reader spufs_coredump_read[] = { - { "regs", __spufs_regs_read, NULL, 128 * 16 }, - { "fpcr", __spufs_fpcr_read, NULL, 16 }, - { "lslr", NULL, __spufs_lslr_get, 11 }, - { "decr", NULL, __spufs_decr_get, 11 }, - { "decr_status", NULL, __spufs_decr_status_get, 11 }, - { "mem", __spufs_mem_read, NULL, 256 * 1024, }, - { "signal1", __spufs_signal1_read, NULL, 4 }, - { "signal1_type", NULL, __spufs_signal1_type_get, 2 }, - { "signal2", __spufs_signal2_read, NULL, 4 }, - { "signal2_type", NULL, __spufs_signal2_type_get, 2 }, - { "event_mask", NULL, __spufs_event_mask_get, 8 }, - { "event_status", NULL, __spufs_event_status_get, 8 }, - { "mbox_info", __spufs_mbox_info_read, NULL, 4 }, - { "ibox_info", __spufs_ibox_info_read, NULL, 4 }, - { "wbox_info", __spufs_wbox_info_read, NULL, 16 }, - { "dma_info", __spufs_dma_info_read, NULL, 69 * 8 }, - { "proxydma_info", __spufs_proxydma_info_read, NULL, 35 * 8 }, - { "object-id", NULL, __spufs_object_id_get, 19 }, - { }, + { "regs", __spufs_regs_read, NULL, sizeof(struct spu_reg128[128])}, + { "fpcr", __spufs_fpcr_read, NULL, sizeof(struct spu_reg128) }, + { "lslr", NULL, spufs_lslr_get, 19 }, + { "decr", NULL, spufs_decr_get, 19 }, + { "decr_status", NULL, spufs_decr_status_get, 19 }, + { "mem", __spufs_mem_read, NULL, LS_SIZE, }, + { "signal1", __spufs_signal1_read, NULL, sizeof(u32) }, + { "signal1_type", NULL, spufs_signal1_type_get, 19 }, + { "signal2", __spufs_signal2_read, NULL, sizeof(u32) }, + { "signal2_type", NULL, spufs_signal2_type_get, 19 }, + { "event_mask", NULL, spufs_event_mask_get, 19 }, + { "event_status", NULL, spufs_event_status_get, 19 }, + { "mbox_info", __spufs_mbox_info_read, NULL, sizeof(u32) }, + { "ibox_info", __spufs_ibox_info_read, NULL, sizeof(u32) }, + { "wbox_info", __spufs_wbox_info_read, NULL, 4 * sizeof(u32)}, + { "dma_info", __spufs_dma_info_read, NULL, sizeof(struct spu_dma_info)}, + { "proxydma_info", __spufs_proxydma_info_read, + NULL, sizeof(struct spu_proxydma_info)}, + { "object-id", NULL, spufs_object_id_get, 19 }, + { "npc", NULL, spufs_npc_get, 19 }, + { NULL }, }; -int spufs_coredump_num_notes = ARRAY_SIZE(spufs_coredump_read) - 1; - diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index b3d0dd118dd0..11098747d09b 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -43,6 +43,7 @@ static struct kmem_cache *spufs_inode_cache; char *isolated_loader; +static int isolated_loader_size; static struct inode * spufs_alloc_inode(struct super_block *sb) @@ -667,7 +668,8 @@ spufs_parse_options(char *options, struct inode *root) static void spufs_exit_isolated_loader(void) { - kfree(isolated_loader); + free_pages((unsigned long) isolated_loader, + get_order(isolated_loader_size)); } static void @@ -685,11 +687,12 @@ spufs_init_isolated_loader(void) if (!loader) return; - /* kmalloc should align on a 16 byte boundary..* */ - isolated_loader = kmalloc(size, GFP_KERNEL); + /* the loader must be align on a 16 byte boundary */ + isolated_loader = (char *)__get_free_pages(GFP_KERNEL, get_order(size)); if (!isolated_loader) return; + isolated_loader_size = size; memcpy(isolated_loader, loader, size); printk(KERN_INFO "spufs: SPU isolation mode enabled\n"); } @@ -787,16 +790,11 @@ static int __init spufs_init(void) ret = register_spu_syscalls(&spufs_calls); if (ret) goto out_fs; - ret = register_arch_coredump_calls(&spufs_coredump_calls); - if (ret) - goto out_syscalls; spufs_init_isolated_loader(); return 0; -out_syscalls: - unregister_spu_syscalls(&spufs_calls); out_fs: unregister_filesystem(&spufs_type); out_sched: @@ -812,7 +810,6 @@ static void __exit spufs_exit(void) { spu_sched_exit(); spufs_exit_isolated_loader(); - unregister_arch_coredump_calls(&spufs_coredump_calls); unregister_spu_syscalls(&spufs_calls); unregister_filesystem(&spufs_type); kmem_cache_destroy(spufs_inode_cache); diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 958f10e90fdd..1ce5e22ea5f4 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -205,7 +205,7 @@ static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, * This means we can only do a very rough approximation of POSIX * signal semantics. */ -int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, +static int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, unsigned int *npc) { int ret; @@ -241,7 +241,7 @@ int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, return ret; } -int spu_process_callback(struct spu_context *ctx) +static int spu_process_callback(struct spu_context *ctx) { struct spu_syscall_block s; u32 ls_pointer, npc; diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 5bebe7fbe056..4d257b3f9336 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -230,8 +230,6 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) if (ctx->flags & SPU_CREATE_NOSCHED) atomic_inc(&cbe_spu_info[spu->node].reserved_spus); - if (!list_empty(&ctx->aff_list)) - atomic_inc(&ctx->gang->aff_sched_count); ctx->stats.slb_flt_base = spu->stats.slb_flt; ctx->stats.class2_intr_base = spu->stats.class2_intr; @@ -392,7 +390,6 @@ static int has_affinity(struct spu_context *ctx) if (list_empty(&ctx->aff_list)) return 0; - mutex_lock(&gang->aff_mutex); if (!gang->aff_ref_spu) { if (!(gang->aff_flags & AFF_MERGED)) aff_merge_remaining_ctxs(gang); @@ -400,7 +397,6 @@ static int has_affinity(struct spu_context *ctx) aff_set_offsets(gang); aff_set_ref_point_location(gang); } - mutex_unlock(&gang->aff_mutex); return gang->aff_ref_spu != NULL; } @@ -418,9 +414,16 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) if (spu->ctx->flags & SPU_CREATE_NOSCHED) atomic_dec(&cbe_spu_info[spu->node].reserved_spus); - if (!list_empty(&ctx->aff_list)) - if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) - ctx->gang->aff_ref_spu = NULL; + + if (ctx->gang){ + mutex_lock(&ctx->gang->aff_mutex); + if (has_affinity(ctx)) { + if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) + ctx->gang->aff_ref_spu = NULL; + } + mutex_unlock(&ctx->gang->aff_mutex); + } + spu_switch_notify(spu, NULL); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); @@ -511,20 +514,32 @@ static void spu_prio_wait(struct spu_context *ctx) static struct spu *spu_get_idle(struct spu_context *ctx) { - struct spu *spu; + struct spu *spu, *aff_ref_spu; int node, n; - if (has_affinity(ctx)) { - node = ctx->gang->aff_ref_spu->node; + if (ctx->gang) { + mutex_lock(&ctx->gang->aff_mutex); + if (has_affinity(ctx)) { + aff_ref_spu = ctx->gang->aff_ref_spu; + atomic_inc(&ctx->gang->aff_sched_count); + mutex_unlock(&ctx->gang->aff_mutex); + node = aff_ref_spu->node; - mutex_lock(&cbe_spu_info[node].list_mutex); - spu = ctx_location(ctx->gang->aff_ref_spu, ctx->aff_offset, node); - if (spu && spu->alloc_state == SPU_FREE) - goto found; - mutex_unlock(&cbe_spu_info[node].list_mutex); - return NULL; - } + mutex_lock(&cbe_spu_info[node].list_mutex); + spu = ctx_location(aff_ref_spu, ctx->aff_offset, node); + if (spu && spu->alloc_state == SPU_FREE) + goto found; + mutex_unlock(&cbe_spu_info[node].list_mutex); + mutex_lock(&ctx->gang->aff_mutex); + if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) + ctx->gang->aff_ref_spu = NULL; + mutex_unlock(&ctx->gang->aff_mutex); + + return NULL; + } + mutex_unlock(&ctx->gang->aff_mutex); + } node = cpu_to_node(raw_smp_processor_id()); for (n = 0; n < MAX_NUMNODES; n++, node++) { node = (node < MAX_NUMNODES) ? node : 0; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 2bfdeb8ea8bd..ca47b991bda5 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -200,9 +200,14 @@ extern struct tree_descr spufs_dir_contents[]; extern struct tree_descr spufs_dir_nosched_contents[]; /* system call implementation */ +extern struct spufs_calls spufs_calls; long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, struct file *filp); +/* ELF coredump callbacks for writing SPU ELF notes */ +extern int spufs_coredump_extra_notes_size(void); +extern int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset); + extern const struct file_operations spufs_context_fops; /* gang management */ @@ -295,7 +300,7 @@ struct spufs_coredump_reader { char *name; ssize_t (*read)(struct spu_context *ctx, char __user *buffer, size_t size, loff_t *pos); - u64 (*get)(void *data); + u64 (*get)(struct spu_context *ctx); size_t size; }; extern struct spufs_coredump_reader spufs_coredump_read[]; diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 27ffdae98e5a..3d64c81cc6e2 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -699,7 +699,7 @@ static inline void get_kernel_slb(u64 ea, u64 slb[2]) llp = mmu_psize_defs[mmu_linear_psize].sllp; else llp = mmu_psize_defs[mmu_virtual_psize].sllp; - slb[0] = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | + slb[0] = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | SLB_VSID_KERNEL | llp; slb[1] = (ea & ESID_MASK) | SLB_ESID_V; } @@ -1559,15 +1559,15 @@ static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu) * "wrapped" flag is set, OR in a '1' to * CSA.SPU_Event_Status[Tm]. */ - if (csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) { - csa->spu_chnldata_RW[0] |= 0x20; - } - if ((csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) && - (csa->spu_chnlcnt_RW[0] == 0 && - ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) && - ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) { + if (!(csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED)) + return; + + if ((csa->spu_chnlcnt_RW[0] == 0) && + (csa->spu_chnldata_RW[1] & 0x20) && + !(csa->spu_chnldata_RW[0] & 0x20)) csa->spu_chnlcnt_RW[0] = 1; - } + + csa->spu_chnldata_RW[0] |= 0x20; } static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu) @@ -2146,19 +2146,6 @@ int spu_restore(struct spu_state *new, struct spu *spu) } EXPORT_SYMBOL_GPL(spu_restore); -/** - * spu_harvest - SPU harvest (reset) operation - * @spu: pointer to SPU iomem structure. - * - * Perform SPU harvest (reset) operation. - */ -void spu_harvest(struct spu *spu) -{ - acquire_spu_lock(spu); - harvest(NULL, spu); - release_spu_lock(spu); -} - static void init_prob(struct spu_state *csa) { csa->spu_chnlcnt_RW[9] = 1; diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 43f0fb88abbc..2c34f7170190 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -58,26 +58,8 @@ out: return ret; } -#ifndef MODULE -asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) -{ - int fput_needed; - struct file *filp; - long ret; - - ret = -EBADF; - filp = fget_light(fd, &fput_needed); - if (filp) { - ret = do_spu_run(filp, unpc, ustatus); - fput_light(filp, fput_needed); - } - - return ret; -} -#endif - -asmlinkage long do_spu_create(const char __user *pathname, unsigned int flags, - mode_t mode, struct file *neighbor) +static long do_spu_create(const char __user *pathname, unsigned int flags, + mode_t mode, struct file *neighbor) { char *tmp; int ret; @@ -99,32 +81,10 @@ asmlinkage long do_spu_create(const char __user *pathname, unsigned int flags, return ret; } -#ifndef MODULE -asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags, - mode_t mode, int neighbor_fd) -{ - int fput_needed; - struct file *neighbor; - long ret; - - if (flags & SPU_CREATE_AFFINITY_SPU) { - ret = -EBADF; - neighbor = fget_light(neighbor_fd, &fput_needed); - if (neighbor) { - ret = do_spu_create(pathname, flags, mode, neighbor); - fput_light(neighbor, fput_needed); - } - } - else { - ret = do_spu_create(pathname, flags, mode, NULL); - } - - return ret; -} -#endif - struct spufs_calls spufs_calls = { .create_thread = do_spu_create, .spu_run = do_spu_run, + .coredump_extra_notes_size = spufs_coredump_extra_notes_size, + .coredump_extra_notes_write = spufs_coredump_extra_notes_write, .owner = THIS_MODULE, }; diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig index 2db1e293433e..04748d410fc9 100644 --- a/arch/powerpc/platforms/celleb/Kconfig +++ b/arch/powerpc/platforms/celleb/Kconfig @@ -2,6 +2,7 @@ config PPC_CELLEB bool "Toshiba's Cell Reference Set 'Celleb' Architecture" depends on PPC_MULTIPLATFORM && PPC64 select PPC_CELL + select PPC_INDIRECT_IO select PPC_OF_PLATFORM_PCI select HAS_TXX9_SERIAL select PPC_UDBG_BEAT diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile index 5240046d8671..889d43f715ea 100644 --- a/arch/powerpc/platforms/celleb/Makefile +++ b/arch/powerpc/platforms/celleb/Makefile @@ -1,6 +1,7 @@ obj-y += interrupt.o iommu.o setup.o \ - htab.o beat.o pci.o \ - scc_epci.o scc_uhc.o hvCall.o + htab.o beat.o hvCall.o pci.o \ + scc_epci.o scc_uhc.o \ + io-workarounds.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/celleb/beat.c index 99341ce8a697..93ebb7d85120 100644 --- a/arch/powerpc/platforms/celleb/beat.c +++ b/arch/powerpc/platforms/celleb/beat.c @@ -22,16 +22,24 @@ #include <linux/init.h> #include <linux/err.h> #include <linux/rtc.h> +#include <linux/interrupt.h> +#include <linux/irqreturn.h> +#include <linux/reboot.h> #include <asm/hvconsole.h> #include <asm/time.h> +#include <asm/machdep.h> +#include <asm/firmware.h> #include "beat_wrapper.h" #include "beat.h" +#include "interrupt.h" + +static int beat_pm_poweroff_flag; void beat_restart(char *cmd) { - beat_shutdown_logical_partition(1); + beat_shutdown_logical_partition(!beat_pm_poweroff_flag); } void beat_power_off(void) @@ -158,6 +166,102 @@ int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2) return beat_put_characters_to_console(vterm, len, (u8*)db); } +void beat_power_save(void) +{ + beat_pause(0); +} + +#ifdef CONFIG_KEXEC +void beat_kexec_cpu_down(int crash, int secondary) +{ + beatic_deinit_IRQ(); +} +#endif + +static irqreturn_t beat_power_event(int virq, void *arg) +{ + printk(KERN_DEBUG "Beat: power button pressed\n"); + beat_pm_poweroff_flag = 1; + ctrl_alt_del(); + return IRQ_HANDLED; +} + +static irqreturn_t beat_reset_event(int virq, void *arg) +{ + printk(KERN_DEBUG "Beat: reset button pressed\n"); + beat_pm_poweroff_flag = 0; + ctrl_alt_del(); + return IRQ_HANDLED; +} + +static struct beat_event_list { + const char *typecode; + irq_handler_t handler; + unsigned int virq; +} beat_event_list[] = { + { "power", beat_power_event, 0 }, + { "reset", beat_reset_event, 0 }, +}; + +static int __init beat_register_event(void) +{ + u64 path[4], data[2]; + int rc, i; + unsigned int virq; + + for (i = 0; i < ARRAY_SIZE(beat_event_list); i++) { + struct beat_event_list *ev = &beat_event_list[i]; + + if (beat_construct_event_receive_port(data) != 0) { + printk(KERN_ERR "Beat: " + "cannot construct event receive port for %s\n", + ev->typecode); + return -EINVAL; + } + + virq = irq_create_mapping(NULL, data[0]); + if (virq == NO_IRQ) { + printk(KERN_ERR "Beat: failed to get virtual IRQ" + " for event receive port for %s\n", + ev->typecode); + beat_destruct_event_receive_port(data[0]); + return -EIO; + } + ev->virq = virq; + + rc = request_irq(virq, ev->handler, IRQF_DISABLED, + ev->typecode, NULL); + if (rc != 0) { + printk(KERN_ERR "Beat: failed to request virtual IRQ" + " for event receive port for %s\n", + ev->typecode); + beat_destruct_event_receive_port(data[0]); + return rc; + } + + path[0] = 0x1000000065780000ul; /* 1,ex */ + path[1] = 0x627574746f6e0000ul; /* button */ + path[2] = 0; + strncpy((char *)&path[2], ev->typecode, 8); + path[3] = 0; + data[1] = 0; + + beat_create_repository_node(path, data); + } + return 0; +} + +static int __init beat_event_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_BEAT)) + return -EINVAL; + + beat_pm_poweroff_flag = 0; + return beat_register_event(); +} + +device_initcall(beat_event_init); + EXPORT_SYMBOL(beat_get_term_char); EXPORT_SYMBOL(beat_put_term_char); EXPORT_SYMBOL(beat_halt_code); diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/celleb/beat.h index 2b16bf3bee89..b2e292df13ca 100644 --- a/arch/powerpc/platforms/celleb/beat.h +++ b/arch/powerpc/platforms/celleb/beat.h @@ -36,5 +36,7 @@ ssize_t beat_nvram_get_size(void); ssize_t beat_nvram_read(char *, size_t, loff_t *); ssize_t beat_nvram_write(char *, size_t, loff_t *); int beat_set_xdabr(unsigned long); +void beat_power_save(void); +void beat_kexec_cpu_down(int, int); #endif /* _CELLEB_BEAT_H */ diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/celleb/beat_syscall.h index 14e16974773f..8580dc7e1798 100644 --- a/arch/powerpc/platforms/celleb/beat_syscall.h +++ b/arch/powerpc/platforms/celleb/beat_syscall.h @@ -157,4 +157,8 @@ #define HV_rtc_write __BEAT_ADD_VENDOR_ID(0x191, 1) #define HV_eeprom_read __BEAT_ADD_VENDOR_ID(0x192, 1) #define HV_eeprom_write __BEAT_ADD_VENDOR_ID(0x193, 1) +#define HV_insert_htab_entry3 __BEAT_ADD_VENDOR_ID(0x104, 1) +#define HV_invalidate_htab_entry3 __BEAT_ADD_VENDOR_ID(0x105, 1) +#define HV_update_htab_permission3 __BEAT_ADD_VENDOR_ID(0x106, 1) +#define HV_clear_htab3 __BEAT_ADD_VENDOR_ID(0x107, 1) #endif diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/celleb/beat_wrapper.h index 76ea0a6a9011..cbc1487df7de 100644 --- a/arch/powerpc/platforms/celleb/beat_wrapper.h +++ b/arch/powerpc/platforms/celleb/beat_wrapper.h @@ -98,6 +98,37 @@ static inline s64 beat_write_htab_entry(u64 htab_id, u64 slot, return ret; } +static inline s64 beat_insert_htab_entry3(u64 htab_id, u64 group, + u64 hpte_v, u64 hpte_r, u64 mask_v, u64 value_v, u64 *slot) +{ + u64 dummy[1]; + s64 ret; + + ret = beat_hcall1(HV_insert_htab_entry3, dummy, htab_id, group, + hpte_v, hpte_r, mask_v, value_v); + *slot = dummy[0]; + return ret; +} + +static inline s64 beat_invalidate_htab_entry3(u64 htab_id, u64 group, + u64 va, u64 pss) +{ + return beat_hcall_norets(HV_invalidate_htab_entry3, + htab_id, group, va, pss); +} + +static inline s64 beat_update_htab_permission3(u64 htab_id, u64 group, + u64 va, u64 pss, u64 ptel_mask, u64 ptel_value) +{ + return beat_hcall_norets(HV_update_htab_permission3, + htab_id, group, va, pss, ptel_mask, ptel_value); +} + +static inline s64 beat_clear_htab3(u64 htab_id) +{ + return beat_hcall_norets(HV_clear_htab3, htab_id); +} + static inline void beat_shutdown_logical_partition(u64 code) { (void)beat_hcall_norets(HV_shutdown_logical_partition, code); @@ -217,4 +248,41 @@ static inline s64 beat_put_iopte(u64 ioas_id, u64 io_addr, u64 real_addr, ioid, flags); } +static inline s64 beat_construct_event_receive_port(u64 *port) +{ + u64 dummy[1]; + s64 ret; + + ret = beat_hcall1(HV_construct_event_receive_port, dummy); + *port = dummy[0]; + return ret; +} + +static inline s64 beat_destruct_event_receive_port(u64 port) +{ + s64 ret; + + ret = beat_hcall_norets(HV_destruct_event_receive_port, port); + return ret; +} + +static inline s64 beat_create_repository_node(u64 path[4], u64 data[2]) +{ + s64 ret; + + ret = beat_hcall_norets(HV_create_repository_node2, + path[0], path[1], path[2], path[3], data[0], data[1]); + return ret; +} + +static inline s64 beat_get_repository_node_value(u64 lpid, u64 path[4], + u64 data[2]) +{ + s64 ret; + + ret = beat_hcall2(HV_get_repository_node_value2, data, + lpid, path[0], path[1], path[2], path[3]); + return ret; +} + #endif diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/celleb/htab.c index 279d7339e170..fbf27c74ebda 100644 --- a/arch/powerpc/platforms/celleb/htab.c +++ b/arch/powerpc/platforms/celleb/htab.c @@ -90,7 +90,7 @@ static inline unsigned int beat_read_mask(unsigned hpte_group) static long beat_lpar_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long pa, unsigned long rflags, unsigned long vflags, - int psize) + int psize, int ssize) { unsigned long lpar_rc; unsigned long slot; @@ -105,7 +105,8 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group, "rflags=%lx, vflags=%lx, psize=%d)\n", hpte_group, va, pa, rflags, vflags, psize); - hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + hpte_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) | + vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) @@ -184,12 +185,12 @@ static void beat_lpar_hptab_clear(void) static long beat_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long lpar_rc; unsigned long dummy0, dummy1, want_v; - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); DBG_LOW(" update: " "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ", @@ -225,8 +226,8 @@ static long beat_lpar_hpte_find(unsigned long va, int psize) long slot; unsigned long want_v, hpte_v; - hash = hpt_hash(va, mmu_psize_defs[psize].shift); - want_v = hpte_encode_v(va, psize); + hash = hpt_hash(va, mmu_psize_defs[psize].shift, MMU_SEGSIZE_256M); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); for (j = 0; j < 2; j++) { slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; @@ -251,11 +252,11 @@ static long beat_lpar_hpte_find(unsigned long va, int psize) static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize) + int psize, int ssize) { unsigned long lpar_rc, slot, vsid, va, dummy0, dummy1; - vsid = get_kernel_vsid(ea); + vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); va = (vsid << 28) | (ea & 0x0fffffff); spin_lock(&beat_htab_lock); @@ -270,7 +271,7 @@ static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, } static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long want_v; unsigned long lpar_rc; @@ -279,7 +280,7 @@ static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va, DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", slot, va, psize, local); - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); spin_lock_irqsave(&beat_htab_lock, flags); dummy1 = beat_lpar_hpte_getword0(slot); @@ -306,3 +307,134 @@ void __init hpte_init_beat(void) ppc_md.hpte_remove = beat_lpar_hpte_remove; ppc_md.hpte_clear_all = beat_lpar_hptab_clear; } + +static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, + unsigned long va, unsigned long pa, + unsigned long rflags, unsigned long vflags, + int psize, int ssize) +{ + unsigned long lpar_rc; + unsigned long slot; + unsigned long hpte_v, hpte_r; + + /* same as iseries */ + if (vflags & HPTE_V_SECONDARY) + return -1; + + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " + "rflags=%lx, vflags=%lx, psize=%d)\n", + hpte_group, va, pa, rflags, vflags, psize); + + hpte_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) | + vflags | HPTE_V_VALID; + hpte_r = hpte_encode_r(pa, psize) | rflags; + + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); + + if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) + hpte_r &= ~_PAGE_COHERENT; + + /* insert into not-volted entry */ + lpar_rc = beat_insert_htab_entry3(0, hpte_group, hpte_v, hpte_r, + HPTE_V_BOLTED, 0, &slot); + /* + * Since we try and ioremap PHBs we don't own, the pte insert + * will fail. However we must catch the failure in hash_page + * or we will loop forever, so return -2 in this case. + */ + if (unlikely(lpar_rc != 0)) { + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" lpar err %lx\n", lpar_rc); + return -2; + } + if (!(vflags & HPTE_V_BOLTED)) + DBG_LOW(" -> slot: %lx\n", slot); + + /* We have to pass down the secondary bucket bit here as well */ + return (slot ^ hpte_group) & 15; +} + +/* + * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and + * the low 3 bits of flags happen to line up. So no transform is needed. + * We can probably optimize here and assume the high bits of newpp are + * already zero. For now I am paranoid. + */ +static long beat_lpar_hpte_updatepp_v3(unsigned long slot, + unsigned long newpp, + unsigned long va, + int psize, int ssize, int local) +{ + unsigned long lpar_rc; + unsigned long want_v; + unsigned long pss; + + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); + pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc; + + DBG_LOW(" update: " + "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ", + want_v & HPTE_V_AVPN, slot, psize, newpp); + + lpar_rc = beat_update_htab_permission3(0, slot, want_v, pss, 7, newpp); + + if (lpar_rc == 0xfffffff7) { + DBG_LOW("not found !\n"); + return -1; + } + + DBG_LOW("ok\n"); + + BUG_ON(lpar_rc != 0); + + return 0; +} + +static void beat_lpar_hpte_invalidate_v3(unsigned long slot, unsigned long va, + int psize, int ssize, int local) +{ + unsigned long want_v; + unsigned long lpar_rc; + unsigned long pss; + + DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", + slot, va, psize, local); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); + pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc; + + lpar_rc = beat_invalidate_htab_entry3(0, slot, want_v, pss); + + /* E_busy can be valid output: page may be already replaced */ + BUG_ON(lpar_rc != 0 && lpar_rc != 0xfffffff7); +} + +static int64_t _beat_lpar_hptab_clear_v3(void) +{ + return beat_clear_htab3(0); +} + +static void beat_lpar_hptab_clear_v3(void) +{ + _beat_lpar_hptab_clear_v3(); +} + +void __init hpte_init_beat_v3(void) +{ + if (_beat_lpar_hptab_clear_v3() == 0) { + ppc_md.hpte_invalidate = beat_lpar_hpte_invalidate_v3; + ppc_md.hpte_updatepp = beat_lpar_hpte_updatepp_v3; + ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp; + ppc_md.hpte_insert = beat_lpar_hpte_insert_v3; + ppc_md.hpte_remove = beat_lpar_hpte_remove; + ppc_md.hpte_clear_all = beat_lpar_hptab_clear_v3; + } else { + ppc_md.hpte_invalidate = beat_lpar_hpte_invalidate; + ppc_md.hpte_updatepp = beat_lpar_hpte_updatepp; + ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp; + ppc_md.hpte_insert = beat_lpar_hpte_insert; + ppc_md.hpte_remove = beat_lpar_hpte_remove; + ppc_md.hpte_clear_all = beat_lpar_hptab_clear; + } +} diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/celleb/interrupt.c index 98e6665681d3..c7c68ca70c82 100644 --- a/arch/powerpc/platforms/celleb/interrupt.c +++ b/arch/powerpc/platforms/celleb/interrupt.c @@ -175,11 +175,18 @@ static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } +static int beatic_pic_host_match(struct irq_host *h, struct device_node *np) +{ + /* Match all */ + return 1; +} + static struct irq_host_ops beatic_pic_host_ops = { .map = beatic_pic_host_map, .remap = beatic_pic_host_remap, .unmap = beatic_pic_host_unmap, .xlate = beatic_pic_host_xlate, + .match = beatic_pic_host_match, }; /* @@ -242,7 +249,7 @@ void __init beatic_init_IRQ(void) ppc_md.get_irq = beatic_get_irq; /* Allocate an irq host */ - beatic_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, + beatic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &beatic_pic_host_ops, 0); BUG_ON(beatic_host == NULL); diff --git a/arch/powerpc/platforms/celleb/io-workarounds.c b/arch/powerpc/platforms/celleb/io-workarounds.c new file mode 100644 index 000000000000..2b912140bcbb --- /dev/null +++ b/arch/powerpc/platforms/celleb/io-workarounds.c @@ -0,0 +1,279 @@ +/* + * Support for Celleb io workarounds + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * This file is based to arch/powerpc/platform/cell/io-workarounds.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include <linux/of_device.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/ppc-pci.h> + +#include "pci.h" + +#define MAX_CELLEB_PCI_BUS 4 + +void *celleb_dummy_page_va; + +static struct celleb_pci_bus { + struct pci_controller *phb; + void (*dummy_read)(struct pci_controller *); +} celleb_pci_busses[MAX_CELLEB_PCI_BUS]; + +static int celleb_pci_count = 0; + +static struct celleb_pci_bus *celleb_pci_find(unsigned long vaddr, + unsigned long paddr) +{ + int i, j; + struct resource *res; + + for (i = 0; i < celleb_pci_count; i++) { + struct celleb_pci_bus *bus = &celleb_pci_busses[i]; + struct pci_controller *phb = bus->phb; + if (paddr) + for (j = 0; j < 3; j++) { + res = &phb->mem_resources[j]; + if (paddr >= res->start && paddr <= res->end) + return bus; + } + res = &phb->io_resource; + if (vaddr && vaddr >= res->start && vaddr <= res->end) + return bus; + } + return NULL; +} + +static void celleb_io_flush(const PCI_IO_ADDR addr) +{ + struct celleb_pci_bus *bus; + int token; + + token = PCI_GET_ADDR_TOKEN(addr); + + if (token && token <= celleb_pci_count) + bus = &celleb_pci_busses[token - 1]; + else { + unsigned long vaddr, paddr; + pte_t *ptep; + + vaddr = (unsigned long)PCI_FIX_ADDR(addr); + if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END) + return; + + ptep = find_linux_pte(init_mm.pgd, vaddr); + if (ptep == NULL) + paddr = 0; + else + paddr = pte_pfn(*ptep) << PAGE_SHIFT; + bus = celleb_pci_find(vaddr, paddr); + + if (bus == NULL) + return; + } + + if (bus->dummy_read) + bus->dummy_read(bus->phb); +} + +static u8 celleb_readb(const PCI_IO_ADDR addr) +{ + u8 val; + val = __do_readb(addr); + celleb_io_flush(addr); + return val; +} + +static u16 celleb_readw(const PCI_IO_ADDR addr) +{ + u16 val; + val = __do_readw(addr); + celleb_io_flush(addr); + return val; +} + +static u32 celleb_readl(const PCI_IO_ADDR addr) +{ + u32 val; + val = __do_readl(addr); + celleb_io_flush(addr); + return val; +} + +static u64 celleb_readq(const PCI_IO_ADDR addr) +{ + u64 val; + val = __do_readq(addr); + celleb_io_flush(addr); + return val; +} + +static u16 celleb_readw_be(const PCI_IO_ADDR addr) +{ + u16 val; + val = __do_readw_be(addr); + celleb_io_flush(addr); + return val; +} + +static u32 celleb_readl_be(const PCI_IO_ADDR addr) +{ + u32 val; + val = __do_readl_be(addr); + celleb_io_flush(addr); + return val; +} + +static u64 celleb_readq_be(const PCI_IO_ADDR addr) +{ + u64 val; + val = __do_readq_be(addr); + celleb_io_flush(addr); + return val; +} + +static void celleb_readsb(const PCI_IO_ADDR addr, + void *buf, unsigned long count) +{ + __do_readsb(addr, buf, count); + celleb_io_flush(addr); +} + +static void celleb_readsw(const PCI_IO_ADDR addr, + void *buf, unsigned long count) +{ + __do_readsw(addr, buf, count); + celleb_io_flush(addr); +} + +static void celleb_readsl(const PCI_IO_ADDR addr, + void *buf, unsigned long count) +{ + __do_readsl(addr, buf, count); + celleb_io_flush(addr); +} + +static void celleb_memcpy_fromio(void *dest, + const PCI_IO_ADDR src, + unsigned long n) +{ + __do_memcpy_fromio(dest, src, n); + celleb_io_flush(src); +} + +static void __iomem *celleb_ioremap(unsigned long addr, + unsigned long size, + unsigned long flags) +{ + struct celleb_pci_bus *bus; + void __iomem *res = __ioremap(addr, size, flags); + int busno; + + bus = celleb_pci_find(0, addr); + if (bus != NULL) { + busno = bus - celleb_pci_busses; + PCI_SET_ADDR_TOKEN(res, busno + 1); + } + return res; +} + +static void celleb_iounmap(volatile void __iomem *addr) +{ + return __iounmap(PCI_FIX_ADDR(addr)); +} + +static struct ppc_pci_io celleb_pci_io __initdata = { + .readb = celleb_readb, + .readw = celleb_readw, + .readl = celleb_readl, + .readq = celleb_readq, + .readw_be = celleb_readw_be, + .readl_be = celleb_readl_be, + .readq_be = celleb_readq_be, + .readsb = celleb_readsb, + .readsw = celleb_readsw, + .readsl = celleb_readsl, + .memcpy_fromio = celleb_memcpy_fromio, +}; + +void __init celleb_pci_add_one(struct pci_controller *phb, + void (*dummy_read)(struct pci_controller *)) +{ + struct celleb_pci_bus *bus = &celleb_pci_busses[celleb_pci_count]; + struct device_node *np = phb->arch_data; + + if (celleb_pci_count >= MAX_CELLEB_PCI_BUS) { + printk(KERN_ERR "Too many pci bridges, workarounds" + " disabled for %s\n", np->full_name); + return; + } + + celleb_pci_count++; + + bus->phb = phb; + bus->dummy_read = dummy_read; +} + +static struct of_device_id celleb_pci_workaround_match[] __initdata = { + { + .name = "pci-pseudo", + .data = fake_pci_workaround_init, + }, { + .name = "epci", + .data = epci_workaround_init, + }, { + }, +}; + +int __init celleb_pci_workaround_init(void) +{ + struct pci_controller *phb; + struct device_node *node; + const struct of_device_id *match; + void (*init_func)(struct pci_controller *); + + celleb_dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!celleb_dummy_page_va) { + printk(KERN_ERR "Celleb: dummy read disabled." + "Alloc celleb_dummy_page_va failed\n"); + return 1; + } + + list_for_each_entry(phb, &hose_list, list_node) { + node = phb->arch_data; + match = of_match_node(celleb_pci_workaround_match, node); + + if (match) { + init_func = match->data; + (*init_func)(phb); + } + } + + ppc_pci_io = celleb_pci_io; + ppc_md.ioremap = celleb_ioremap; + ppc_md.iounmap = celleb_iounmap; + + return 0; +} diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c index e9ac19c4bba4..6bc32fda7a6b 100644 --- a/arch/powerpc/platforms/celleb/pci.c +++ b/arch/powerpc/platforms/celleb/pci.c @@ -31,6 +31,7 @@ #include <linux/init.h> #include <linux/bootmem.h> #include <linux/pci_regs.h> +#include <linux/of_device.h> #include <asm/io.h> #include <asm/irq.h> @@ -242,8 +243,8 @@ static int celleb_fake_pci_write_config(struct pci_bus *bus, } static struct pci_ops celleb_fake_pci_ops = { - celleb_fake_pci_read_config, - celleb_fake_pci_write_config + .read = celleb_fake_pci_read_config, + .write = celleb_fake_pci_write_config, }; static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose, @@ -288,8 +289,8 @@ static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose, celleb_config_write_fake(config, PCI_COMMAND, 2, val); } -static int __devinit celleb_setup_fake_pci_device(struct device_node *node, - struct pci_controller *hose) +static int __init celleb_setup_fake_pci_device(struct device_node *node, + struct pci_controller *hose) { unsigned int rlen; int num_base_addr = 0; @@ -327,10 +328,7 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node, size = 256; config = &private->fake_config[devno][fn]; - if (mem_init_done) - *config = kzalloc(size, GFP_KERNEL); - else - *config = alloc_bootmem(size); + *config = alloc_maybe_bootmem(size, GFP_KERNEL); if (*config == NULL) { printk(KERN_ERR "PCI: " "not enough memory for fake configuration space\n"); @@ -341,10 +339,7 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node, size = sizeof(struct celleb_pci_resource); res = &private->res[devno][fn]; - if (mem_init_done) - *res = kzalloc(size, GFP_KERNEL); - else - *res = alloc_bootmem(size); + *res = alloc_maybe_bootmem(size, GFP_KERNEL); if (*res == NULL) { printk(KERN_ERR "PCI: not enough memory for resource data space\n"); @@ -418,8 +413,8 @@ error: return 1; } -static int __devinit phb_set_bus_ranges(struct device_node *dev, - struct pci_controller *phb) +static int __init phb_set_bus_ranges(struct device_node *dev, + struct pci_controller *phb) { const int *bus_range; unsigned int len; @@ -434,46 +429,65 @@ static int __devinit phb_set_bus_ranges(struct device_node *dev, return 0; } -static void __devinit celleb_alloc_private_mem(struct pci_controller *hose) +static void __init celleb_alloc_private_mem(struct pci_controller *hose) { - if (mem_init_done) - hose->private_data = - kzalloc(sizeof(struct celleb_pci_private), GFP_KERNEL); - else - hose->private_data = - alloc_bootmem(sizeof(struct celleb_pci_private)); + hose->private_data = + alloc_maybe_bootmem(sizeof(struct celleb_pci_private), + GFP_KERNEL); } -int __devinit celleb_setup_phb(struct pci_controller *phb) +static int __init celleb_setup_fake_pci(struct device_node *dev, + struct pci_controller *phb) { - const char *name; - struct device_node *dev = phb->arch_data; struct device_node *node; - unsigned int rlen; - name = of_get_property(dev, "name", &rlen); - if (!name) - return 1; + phb->ops = &celleb_fake_pci_ops; + celleb_alloc_private_mem(phb); - pr_debug("PCI: celleb_setup_phb() %s\n", name); - phb_set_bus_ranges(dev, phb); - phb->buid = 1; + for (node = of_get_next_child(dev, NULL); + node != NULL; node = of_get_next_child(dev, node)) + celleb_setup_fake_pci_device(node, phb); + + return 0; +} - if (strcmp(name, "epci") == 0) { - phb->ops = &celleb_epci_ops; - return celleb_setup_epci(dev, phb); +void __init fake_pci_workaround_init(struct pci_controller *phb) +{ + /** + * We will add fake pci bus to scc_pci_bus for the purpose to improve + * I/O Macro performance. But device-tree and device drivers + * are not ready to use address with a token. + */ + + /* celleb_pci_add_one(phb, NULL); */ +} - } else if (strcmp(name, "pci-pseudo") == 0) { - phb->ops = &celleb_fake_pci_ops; - celleb_alloc_private_mem(phb); - for (node = of_get_next_child(dev, NULL); - node != NULL; node = of_get_next_child(dev, node)) - celleb_setup_fake_pci_device(node, phb); +static struct of_device_id celleb_phb_match[] __initdata = { + { + .name = "pci-pseudo", + .data = celleb_setup_fake_pci, + }, { + .name = "epci", + .data = celleb_setup_epci, + }, { + }, +}; - } else +int __init celleb_setup_phb(struct pci_controller *phb) +{ + struct device_node *dev = phb->arch_data; + const struct of_device_id *match; + int (*setup_func)(struct device_node *, struct pci_controller *); + + match = of_match_node(celleb_phb_match, dev); + if (!match) return 1; - return 0; + phb_set_bus_ranges(dev, phb); + phb->buid = 1; + + setup_func = match->data; + return (*setup_func)(dev, phb); } int celleb_pci_probe_mode(struct pci_bus *bus) diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/celleb/pci.h index 5340e348e297..5d5544ffeddb 100644 --- a/arch/powerpc/platforms/celleb/pci.h +++ b/arch/powerpc/platforms/celleb/pci.h @@ -25,11 +25,18 @@ #include <asm/pci-bridge.h> #include <asm/prom.h> +#include <asm/ppc-pci.h> extern int celleb_setup_phb(struct pci_controller *); extern int celleb_pci_probe_mode(struct pci_bus *); -extern struct pci_ops celleb_epci_ops; extern int celleb_setup_epci(struct device_node *, struct pci_controller *); +extern void *celleb_dummy_page_va; +extern int __init celleb_pci_workaround_init(void); +extern void __init celleb_pci_add_one(struct pci_controller *, + void (*)(struct pci_controller *)); +extern void fake_pci_workaround_init(struct pci_controller *); +extern void epci_workaround_init(struct pci_controller *); + #endif /* _CELLEB_PCI_H */ diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/celleb/scc.h index e9ce8a7c1882..6be1542a6e66 100644 --- a/arch/powerpc/platforms/celleb/scc.h +++ b/arch/powerpc/platforms/celleb/scc.h @@ -53,7 +53,7 @@ #define SCC_EPCI_STATUS 0x808 #define SCC_EPCI_ABTSET 0x80c #define SCC_EPCI_WATRP 0x810 -#define SCC_EPCI_DUMMYRADR 0x814 +#define SCC_EPCI_DUMYRADR 0x814 #define SCC_EPCI_SWRESP 0x818 #define SCC_EPCI_CNTOPT 0x81c #define SCC_EPCI_ECMODE 0xf00 diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c index c4b011094bd6..9d076426676c 100644 --- a/arch/powerpc/platforms/celleb/scc_epci.c +++ b/arch/powerpc/platforms/celleb/scc_epci.c @@ -43,7 +43,11 @@ #define iob() __asm__ __volatile__("eieio; sync":::"memory") -static inline volatile void __iomem *celleb_epci_get_epci_base( +struct epci_private { + dma_addr_t dummy_page_da; +}; + +static inline PCI_IO_ADDR celleb_epci_get_epci_base( struct pci_controller *hose) { /* @@ -55,7 +59,7 @@ static inline volatile void __iomem *celleb_epci_get_epci_base( return hose->cfg_addr; } -static inline volatile void __iomem *celleb_epci_get_epci_cfg( +static inline PCI_IO_ADDR celleb_epci_get_epci_cfg( struct pci_controller *hose) { /* @@ -67,20 +71,11 @@ static inline volatile void __iomem *celleb_epci_get_epci_cfg( return hose->cfg_data; } -#if 0 /* test code for epci dummy read */ -static void celleb_epci_dummy_read(struct pci_dev *dev) +static void scc_epci_dummy_read(struct pci_controller *hose) { - volatile void __iomem *epci_base; - struct device_node *node; - struct pci_controller *hose; + PCI_IO_ADDR epci_base; u32 val; - node = (struct device_node *)dev->bus->sysdata; - hose = pci_find_hose_for_OF_device(node); - - if (!hose) - return; - epci_base = celleb_epci_get_epci_base(hose); val = in_be32(epci_base + SCC_EPCI_WATRP); @@ -88,21 +83,45 @@ static void celleb_epci_dummy_read(struct pci_dev *dev) return; } -#endif + +void __init epci_workaround_init(struct pci_controller *hose) +{ + PCI_IO_ADDR epci_base; + PCI_IO_ADDR reg; + struct epci_private *private = hose->private_data; + + BUG_ON(!private); + + private->dummy_page_da = dma_map_single(hose->parent, + celleb_dummy_page_va, PAGE_SIZE, DMA_FROM_DEVICE); + if (private->dummy_page_da == DMA_ERROR_CODE) { + printk(KERN_ERR "EPCI: dummy read disabled." + "Map dummy page failed.\n"); + return; + } + + celleb_pci_add_one(hose, scc_epci_dummy_read); + epci_base = celleb_epci_get_epci_base(hose); + + reg = epci_base + SCC_EPCI_DUMYRADR; + out_be32(reg, private->dummy_page_da); +} static inline void clear_and_disable_master_abort_interrupt( struct pci_controller *hose) { - volatile void __iomem *epci_base, *reg; + PCI_IO_ADDR epci_base; + PCI_IO_ADDR reg; epci_base = celleb_epci_get_epci_base(hose); reg = epci_base + PCI_COMMAND; out_be32(reg, in_be32(reg) | (PCI_STATUS_REC_MASTER_ABORT << 16)); } static int celleb_epci_check_abort(struct pci_controller *hose, - volatile void __iomem *addr) + PCI_IO_ADDR addr) { - volatile void __iomem *reg, *epci_base; + PCI_IO_ADDR reg; + PCI_IO_ADDR epci_base; u32 val; iob(); @@ -132,12 +151,12 @@ static int celleb_epci_check_abort(struct pci_controller *hose, return PCIBIOS_SUCCESSFUL; } -static volatile void __iomem *celleb_epci_make_config_addr( +static PCI_IO_ADDR celleb_epci_make_config_addr( struct pci_bus *bus, struct pci_controller *hose, unsigned int devfn, int where) { - volatile void __iomem *addr; + PCI_IO_ADDR addr; if (bus != hose->bus) addr = celleb_epci_get_epci_cfg(hose) + @@ -157,7 +176,8 @@ static volatile void __iomem *celleb_epci_make_config_addr( static int celleb_epci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) { - volatile void __iomem *epci_base, *addr; + PCI_IO_ADDR epci_base; + PCI_IO_ADDR addr; struct device_node *node; struct pci_controller *hose; @@ -220,7 +240,8 @@ static int celleb_epci_read_config(struct pci_bus *bus, static int celleb_epci_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - volatile void __iomem *epci_base, *addr; + PCI_IO_ADDR epci_base; + PCI_IO_ADDR addr; struct device_node *node; struct pci_controller *hose; @@ -278,15 +299,16 @@ static int celleb_epci_write_config(struct pci_bus *bus, } struct pci_ops celleb_epci_ops = { - celleb_epci_read_config, - celleb_epci_write_config, + .read = celleb_epci_read_config, + .write = celleb_epci_write_config, }; /* to be moved in FW */ -static int __devinit celleb_epci_init(struct pci_controller *hose) +static int __init celleb_epci_init(struct pci_controller *hose) { u32 val; - volatile void __iomem *reg, *epci_base; + PCI_IO_ADDR reg; + PCI_IO_ADDR epci_base; int hwres = 0; epci_base = celleb_epci_get_epci_base(hose); @@ -403,7 +425,7 @@ static int __devinit celleb_epci_init(struct pci_controller *hose) return 0; } -int __devinit celleb_setup_epci(struct device_node *node, +int __init celleb_setup_epci(struct device_node *node, struct pci_controller *hose) { struct resource r; @@ -440,10 +462,24 @@ int __devinit celleb_setup_epci(struct device_node *node, r.start, (unsigned long)hose->cfg_data, (r.end - r.start + 1)); + hose->private_data = kzalloc(sizeof(struct epci_private), GFP_KERNEL); + if (hose->private_data == NULL) { + printk(KERN_ERR "EPCI: no memory for private data.\n"); + goto error; + } + + hose->ops = &celleb_epci_ops; celleb_epci_init(hose); return 0; error: + kfree(hose->private_data); + + if (hose->cfg_addr) + iounmap(hose->cfg_addr); + + if (hose->cfg_data) + iounmap(hose->cfg_data); return 1; } diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/celleb/scc_sio.c index bcd25f54d986..610008211ca1 100644 --- a/arch/powerpc/platforms/celleb/scc_sio.c +++ b/arch/powerpc/platforms/celleb/scc_sio.c @@ -1,7 +1,7 @@ /* * setup serial port in SCC * - * (C) Copyright 2006 TOSHIBA CORPORATION + * (C) Copyright 2006-2007 TOSHIBA CORPORATION * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,58 +28,58 @@ /* sio irq0=0xb00010022 irq0=0xb00010023 irq2=0xb00010024 mmio=0xfff000-0x1000,0xff2000-0x1000 */ -static int txx9_serial_bitmap = 0; +static int txx9_serial_bitmap __initdata = 0; static struct { uint32_t offset; uint32_t index; -} txx9_scc_tab[3] = { +} txx9_scc_tab[3] __initdata = { { 0x300, 0 }, /* 0xFFF300 */ { 0x400, 0 }, /* 0xFFF400 */ { 0x800, 1 } /* 0xFF2800 */ }; -static int txx9_serial_init(void) +static int __init txx9_serial_init(void) { extern int early_serial_txx9_setup(struct uart_port *port); - struct device_node *node; + struct device_node *node = NULL; int i; struct uart_port req; struct of_irq irq; struct resource res; - node = of_find_node_by_path("/ioif1/sio"); - if (!node) - return 0; + while ((node = of_find_compatible_node(node, + "serial", "toshiba,sio-scc")) != NULL) { + for (i = 0; i < ARRAY_SIZE(txx9_scc_tab); i++) { + if (!(txx9_serial_bitmap & (1<<i))) + continue; - for(i = 0; i < sizeof(txx9_scc_tab)/sizeof(txx9_scc_tab[0]); i++) { - if (!(txx9_serial_bitmap & (1<<i))) - continue; + if (of_irq_map_one(node, i, &irq)) + continue; + if (of_address_to_resource(node, + txx9_scc_tab[i].index, &res)) + continue; - if (of_irq_map_one(node, i, &irq)) - continue; - if (of_address_to_resource(node, txx9_scc_tab[i].index, &res)) - continue; - - memset(&req, 0, sizeof(req)); - req.line = i; - req.iotype = UPIO_MEM; - req.mapbase = res.start + txx9_scc_tab[i].offset; + memset(&req, 0, sizeof(req)); + req.line = i; + req.iotype = UPIO_MEM; + req.mapbase = res.start + txx9_scc_tab[i].offset; #ifdef CONFIG_SERIAL_TXX9_CONSOLE - req.membase = ioremap(req.mapbase, 0x24); + req.membase = ioremap(req.mapbase, 0x24); #endif - req.irq = irq_create_of_mapping(irq.controller, - irq.specifier, irq.size); - req.flags |= UPF_IOREMAP | UPF_BUGGY_UART /*HAVE_CTS_LINE*/; - req.uartclk = 83300000; - early_serial_txx9_setup(&req); + req.irq = irq_create_of_mapping(irq.controller, + irq.specifier, irq.size); + req.flags |= UPF_IOREMAP | UPF_BUGGY_UART + /*HAVE_CTS_LINE*/; + req.uartclk = 83300000; + early_serial_txx9_setup(&req); + } } - of_node_put(node); return 0; } -static int txx9_serial_config(char *ptr) +static int __init txx9_serial_config(char *ptr) { int i; diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c index 5e9f7f163571..1769d755eff3 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/celleb/setup.c @@ -73,7 +73,7 @@ static void celleb_show_cpuinfo(struct seq_file *m) of_node_put(root); } -static int celleb_machine_type_hack(char *ptr) +static int __init celleb_machine_type_hack(char *ptr) { strncpy(celleb_machine_type, ptr, sizeof(celleb_machine_type)); celleb_machine_type[sizeof(celleb_machine_type)-1] = 0; @@ -101,21 +101,11 @@ static void __init celleb_setup_arch(void) /* init to some ~sane value until calibrate_delay() runs */ loops_per_jiffy = 50000000; - if (ROOT_DEV == 0) { - printk("No ramdisk, default root is /dev/hda2\n"); - ROOT_DEV = Root_HDA2; - } - #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif } -static void beat_power_save(void) -{ - beat_pause(0); -} - static int __init celleb_probe(void) { unsigned long root = of_get_flat_dt_root(); @@ -124,18 +114,11 @@ static int __init celleb_probe(void) return 0; powerpc_firmware_features |= FW_FEATURE_CELLEB_POSSIBLE; - hpte_init_beat(); + hpte_init_beat_v3(); return 1; } -#ifdef CONFIG_KEXEC -static void celleb_kexec_cpu_down(int crash, int secondary) -{ - beatic_deinit_IRQ(); -} -#endif - -static struct of_device_id celleb_bus_ids[] = { +static struct of_device_id celleb_bus_ids[] __initdata = { { .type = "scc", }, { .type = "ioif", }, /* old style */ {}, @@ -149,6 +132,8 @@ static int __init celleb_publish_devices(void) /* Publish OF platform devices for southbridge IOs */ of_platform_bus_probe(NULL, celleb_bus_ids, NULL); + celleb_pci_workaround_init(); + return 0; } device_initcall(celleb_publish_devices); @@ -175,7 +160,7 @@ define_machine(celleb) { .pci_probe_mode = celleb_pci_probe_mode, .pci_setup_phb = celleb_setup_phb, #ifdef CONFIG_KEXEC - .kexec_cpu_down = celleb_kexec_cpu_down, + .kexec_cpu_down = beat_kexec_cpu_down, .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, .machine_crash_shutdown = default_machine_crash_shutdown, diff --git a/arch/powerpc/platforms/chrp/gg2.h b/arch/powerpc/platforms/chrp/gg2.h new file mode 100644 index 000000000000..341ae55b99fb --- /dev/null +++ b/arch/powerpc/platforms/chrp/gg2.h @@ -0,0 +1,61 @@ +/* + * include/asm-ppc/gg2.h -- VLSI VAS96011/12 `Golden Gate 2' register definitions + * + * Copyright (C) 1997 Geert Uytterhoeven + * + * This file is based on the following documentation: + * + * The VAS96011/12 Chipset, Data Book, Edition 1.0 + * VLSI Technology, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _ASMPPC_GG2_H +#define _ASMPPC_GG2_H + + /* + * Memory Map (CHRP mode) + */ + +#define GG2_PCI_MEM_BASE 0xc0000000 /* Peripheral memory space */ +#define GG2_ISA_MEM_BASE 0xf7000000 /* Peripheral memory alias */ +#define GG2_ISA_IO_BASE 0xf8000000 /* Peripheral I/O space */ +#define GG2_PCI_CONFIG_BASE 0xfec00000 /* PCI configuration space */ +#define GG2_INT_ACK_SPECIAL 0xfec80000 /* Interrupt acknowledge and */ + /* special PCI cycles */ +#define GG2_ROM_BASE0 0xff000000 /* ROM bank 0 */ +#define GG2_ROM_BASE1 0xff800000 /* ROM bank 1 */ + + + /* + * GG2 specific PCI Registers + */ + +extern void __iomem *gg2_pci_config_base; /* kernel virtual address */ + +#define GG2_PCI_BUSNO 0x40 /* Bus number */ +#define GG2_PCI_SUBBUSNO 0x41 /* Subordinate bus number */ +#define GG2_PCI_DISCCTR 0x42 /* Disconnect counter */ +#define GG2_PCI_PPC_CTRL 0x50 /* PowerPC interface control register */ +#define GG2_PCI_ADDR_MAP 0x5c /* Address map */ +#define GG2_PCI_PCI_CTRL 0x60 /* PCI interface control register */ +#define GG2_PCI_ROM_CTRL 0x70 /* ROM interface control register */ +#define GG2_PCI_ROM_TIME 0x74 /* ROM timing */ +#define GG2_PCI_CC_CTRL 0x80 /* Cache controller control register */ +#define GG2_PCI_DRAM_BANK0 0x90 /* Control register for DRAM bank #0 */ +#define GG2_PCI_DRAM_BANK1 0x94 /* Control register for DRAM bank #1 */ +#define GG2_PCI_DRAM_BANK2 0x98 /* Control register for DRAM bank #2 */ +#define GG2_PCI_DRAM_BANK3 0x9c /* Control register for DRAM bank #3 */ +#define GG2_PCI_DRAM_BANK4 0xa0 /* Control register for DRAM bank #4 */ +#define GG2_PCI_DRAM_BANK5 0xa4 /* Control register for DRAM bank #5 */ +#define GG2_PCI_DRAM_TIME0 0xb0 /* Timing parameters set #0 */ +#define GG2_PCI_DRAM_TIME1 0xb4 /* Timing parameters set #1 */ +#define GG2_PCI_DRAM_CTRL 0xc0 /* DRAM control */ +#define GG2_PCI_ERR_CTRL 0xd0 /* Error control register */ +#define GG2_PCI_ERR_STATUS 0xd4 /* Error status register */ + /* Cleared when read */ + +#endif /* _ASMPPC_GG2_H */ diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index 28d1647b204e..e43465d34d29 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -13,7 +13,6 @@ #include <asm/irq.h> #include <asm/hydra.h> #include <asm/prom.h> -#include <asm/gg2.h> #include <asm/machdep.h> #include <asm/sections.h> #include <asm/pci-bridge.h> @@ -21,6 +20,7 @@ #include <asm/rtas.h> #include "chrp.h" +#include "gg2.h" /* LongTrail */ void __iomem *gg2_pci_config_base; @@ -86,8 +86,8 @@ int gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off, static struct pci_ops gg2_pci_ops = { - gg2_read_config, - gg2_write_config + .read = gg2_read_config, + .write = gg2_write_config, }; /* @@ -124,8 +124,8 @@ int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset, static struct pci_ops rtas_pci_ops = { - rtas_read_config, - rtas_write_config + .read = rtas_read_config, + .write = rtas_write_config, }; volatile struct Hydra __iomem *Hydra = NULL; @@ -338,3 +338,32 @@ void chrp_pci_fixup_winbond_ata(struct pci_dev *sl82c105) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, chrp_pci_fixup_winbond_ata); + +/* Pegasos2 firmware version 20040810 configures the built-in IDE controller + * in legacy mode, but sets the PCI registers to PCI native mode. + * The chip can only operate in legacy mode, so force the PCI class into legacy + * mode as well. The same fixup must be done to the class-code property in + * the IDE node /pci@80000000/ide@C,1 + */ +static void chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) +{ + u8 progif; + struct pci_dev *viaisa; + + if (!machine_is(chrp) || _chrp_type != _CHRP_Pegasos) + return; + if (viaide->irq != 14) + return; + + viaisa = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL); + if (!viaisa) + return; + printk("Fixing VIA IDE, force legacy mode on '%s'\n", viaide->dev.bus_id); + + pci_read_config_byte(viaide, PCI_CLASS_PROG, &progif); + pci_write_config_byte(viaide, PCI_CLASS_PROG, progif & ~0x5); + viaide->class &= ~0x5; + + pci_dev_put(viaisa); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 373de4c063db..59306261f5b2 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -32,13 +32,11 @@ #include <linux/seq_file.h> #include <linux/root_dev.h> #include <linux/initrd.h> -#include <linux/module.h> #include <linux/timer.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/prom.h> -#include <asm/gg2.h> #include <asm/pci-bridge.h> #include <asm/dma.h> #include <asm/machdep.h> @@ -52,6 +50,7 @@ #include <asm/xmon.h> #include "chrp.h" +#include "gg2.h" void rtas_indicator_progress(char *, unsigned short); @@ -291,16 +290,6 @@ void __init chrp_setup_arch(void) ppc_md.set_rtc_time = rtas_set_rtc_time; } -#ifdef CONFIG_BLK_DEV_INITRD - /* this is fine for chrp */ - initrd_below_start_ok = 1; - - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif - ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ - /* On pegasos, enable the L2 cache if not already done by OF */ pegasos_set_l2cr(); diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c index 3ea0eb78568e..10a4a4d063b6 100644 --- a/arch/powerpc/platforms/chrp/smp.c +++ b/arch/powerpc/platforms/chrp/smp.c @@ -26,10 +26,8 @@ #include <asm/io.h> #include <asm/prom.h> #include <asm/smp.h> -#include <asm/residual.h> #include <asm/time.h> #include <asm/machdep.h> -#include <asm/smp.h> #include <asm/mpic.h> #include <asm/rtas.h> diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 2d12f77e46bc..8924095a7928 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -1,9 +1,10 @@ -choice - prompt "Machine Type" - depends on EMBEDDED6xx +config EMBEDDED6xx + bool "Embedded 6xx/7xx/7xxx-based boards" + depends on PPC32 && BROKEN_ON_SMP && PPC_MULTIPLATFORM config LINKSTATION bool "Linkstation / Kurobox(HG) from Buffalo" + depends on EMBEDDED6xx select MPIC select FSL_SOC select PPC_UDBG_16550 if SERIAL_8250 @@ -17,15 +18,18 @@ config LINKSTATION config MPC7448HPC2 bool "Freescale MPC7448HPC2(Taiga)" + depends on EMBEDDED6xx select TSI108_BRIDGE select DEFAULT_UIMAGE select PPC_UDBG_16550 + select WANT_DEVICE_TREE help Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga) platform config PPC_HOLLY bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)" + depends on EMBEDDED6xx select TSI108_BRIDGE select PPC_UDBG_16550 select WANT_DEVICE_TREE @@ -35,12 +39,12 @@ config PPC_HOLLY config PPC_PRPMC2800 bool "Motorola-PrPMC2800" + depends on EMBEDDED6xx select MV64X60 select NOT_COHERENT_CACHE select WANT_DEVICE_TREE help This option enables support for the Motorola PrPMC2800 board -endchoice config TSI108_BRIDGE bool diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 6292e36dc577..b6de2b5223dd 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -113,23 +113,11 @@ static void holly_remap_bridge(void) static void __init holly_setup_arch(void) { - struct device_node *cpu; struct device_node *np; if (ppc_md.progress) ppc_md.progress("holly_setup_arch():set_bridge", 0); - cpu = of_find_node_by_type(NULL, "cpu"); - if (cpu) { - const unsigned int *fp; - - fp = of_get_property(cpu, "clock-frequency", NULL); - if (fp) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(cpu); - } tsi108_csr_vir_base = get_vir_csrbase(); /* setup PCI host bridge */ @@ -147,7 +135,7 @@ static void __init holly_setup_arch(void) } /* - * Interrupt setup and service. Interrrupts on the holly come + * Interrupt setup and service. Interrupts on the holly come * from the four external INT pins, PCI interrupts are routed via * PCI interrupt control registers, it generates internal IRQ23 * diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index bd5ca58345a1..eb5d74e26fe9 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -11,16 +11,16 @@ */ #include <linux/kernel.h> -#include <linux/pci.h> #include <linux/initrd.h> #include <linux/mtd/physmap.h> #include <asm/time.h> #include <asm/prom.h> #include <asm/mpic.h> -#include <asm/mpc10x.h> #include <asm/pci-bridge.h> +#include "mpc10x.h" + static struct mtd_partition linkstation_physmap_partitions[] = { { .name = "mtd_firmimg", @@ -91,7 +91,7 @@ static void __init linkstation_setup_arch(void) #endif /* Lookup PCI host bridges */ - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "mpc10x-pci") linkstation_add_bridge(np); printk(KERN_INFO "BUFFALO Network Attached Storage Series\n"); @@ -99,7 +99,7 @@ static void __init linkstation_setup_arch(void) } /* - * Interrupt setup and service. Interrrupts on the linkstation come + * Interrupt setup and service. Interrupts on the linkstation come * from the four PCI slots plus onboard 8241 devices: I2C, DUART. */ static void __init linkstation_init_IRQ(void) diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index d0bee9f19e4e..c99264cedda5 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c @@ -1,14 +1,25 @@ +/* + * AVR power-management chip interface for the Buffalo Linkstation / + * Kurobox Platform. + * + * Author: 2006 (c) G. Liakhovetski + * g.liakhovetski@gmx.de + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of + * any kind, whether express or implied. + */ #include <linux/workqueue.h> #include <linux/string.h> #include <linux/delay.h> #include <linux/serial_reg.h> #include <linux/serial_8250.h> #include <asm/io.h> -#include <asm/mpc10x.h> -#include <asm/ppc_sys.h> #include <asm/prom.h> #include <asm/termbits.h> +#include "mpc10x.h" + static void __iomem *avr_addr; static unsigned long avr_clock; @@ -106,6 +117,9 @@ static int __init ls_uarts_init(void) phys_addr_t phys_addr; int len; + if (!machine_is(linkstation)) + return 0; + avr = of_find_node_by_path("/soc10x/serial@80004500"); if (!avr) return -EINVAL; diff --git a/arch/powerpc/platforms/embedded6xx/mpc10x.h b/arch/powerpc/platforms/embedded6xx/mpc10x.h new file mode 100644 index 000000000000..b30a6a3b5bd2 --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/mpc10x.h @@ -0,0 +1,180 @@ +/* + * Common routines for the Motorola SPS MPC106/8240/107 Host bridge/Mem + * ctlr/EPIC/etc. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * 2001 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef __PPC_KERNEL_MPC10X_H +#define __PPC_KERNEL_MPC10X_H + +#include <linux/pci_ids.h> +#include <asm/pci-bridge.h> + +/* + * The values here don't completely map everything but should work in most + * cases. + * + * MAP A (PReP Map) + * Processor: 0x80000000 - 0x807fffff -> PCI I/O: 0x00000000 - 0x007fffff + * Processor: 0xc0000000 - 0xdfffffff -> PCI MEM: 0x00000000 - 0x1fffffff + * PCI MEM: 0x80000000 -> Processor System Memory: 0x00000000 + * EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB) + * + * MAP B (CHRP Map) + * Processor: 0xfe000000 - 0xfebfffff -> PCI I/O: 0x00000000 - 0x00bfffff + * Processor: 0x80000000 - 0xbfffffff -> PCI MEM: 0x80000000 - 0xbfffffff + * PCI MEM: 0x00000000 -> Processor System Memory: 0x00000000 + * EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB) + */ + +/* + * Define the vendor/device IDs for the various bridges--should be added to + * <linux/pci_ids.h> + */ +#define MPC10X_BRIDGE_106 ((PCI_DEVICE_ID_MOTOROLA_MPC106 << 16) | \ + PCI_VENDOR_ID_MOTOROLA) +#define MPC10X_BRIDGE_8240 ((0x0003 << 16) | PCI_VENDOR_ID_MOTOROLA) +#define MPC10X_BRIDGE_107 ((0x0004 << 16) | PCI_VENDOR_ID_MOTOROLA) +#define MPC10X_BRIDGE_8245 ((0x0006 << 16) | PCI_VENDOR_ID_MOTOROLA) + +/* Define the type of map to use */ +#define MPC10X_MEM_MAP_A 1 +#define MPC10X_MEM_MAP_B 2 + +/* Map A (PReP Map) Defines */ +#define MPC10X_MAPA_CNFG_ADDR 0x80000cf8 +#define MPC10X_MAPA_CNFG_DATA 0x80000cfc + +#define MPC10X_MAPA_ISA_IO_BASE 0x80000000 +#define MPC10X_MAPA_ISA_MEM_BASE 0xc0000000 +#define MPC10X_MAPA_DRAM_OFFSET 0x80000000 + +#define MPC10X_MAPA_PCI_INTACK_ADDR 0xbffffff0 +#define MPC10X_MAPA_PCI_IO_START 0x00000000 +#define MPC10X_MAPA_PCI_IO_END (0x00800000 - 1) +#define MPC10X_MAPA_PCI_MEM_START 0x00000000 +#define MPC10X_MAPA_PCI_MEM_END (0x20000000 - 1) + +#define MPC10X_MAPA_PCI_MEM_OFFSET (MPC10X_MAPA_ISA_MEM_BASE - \ + MPC10X_MAPA_PCI_MEM_START) + +/* Map B (CHRP Map) Defines */ +#define MPC10X_MAPB_CNFG_ADDR 0xfec00000 +#define MPC10X_MAPB_CNFG_DATA 0xfee00000 + +#define MPC10X_MAPB_ISA_IO_BASE 0xfe000000 +#define MPC10X_MAPB_ISA_MEM_BASE 0x80000000 +#define MPC10X_MAPB_DRAM_OFFSET 0x00000000 + +#define MPC10X_MAPB_PCI_INTACK_ADDR 0xfef00000 +#define MPC10X_MAPB_PCI_IO_START 0x00000000 +#define MPC10X_MAPB_PCI_IO_END (0x00c00000 - 1) +#define MPC10X_MAPB_PCI_MEM_START 0x80000000 +#define MPC10X_MAPB_PCI_MEM_END (0xc0000000 - 1) + +#define MPC10X_MAPB_PCI_MEM_OFFSET (MPC10X_MAPB_ISA_MEM_BASE - \ + MPC10X_MAPB_PCI_MEM_START) + +/* Set hose members to values appropriate for the mem map used */ +#define MPC10X_SETUP_HOSE(hose, map) { \ + (hose)->pci_mem_offset = MPC10X_MAP##map##_PCI_MEM_OFFSET; \ + (hose)->io_space.start = MPC10X_MAP##map##_PCI_IO_START; \ + (hose)->io_space.end = MPC10X_MAP##map##_PCI_IO_END; \ + (hose)->mem_space.start = MPC10X_MAP##map##_PCI_MEM_START; \ + (hose)->mem_space.end = MPC10X_MAP##map##_PCI_MEM_END; \ + (hose)->io_base_virt = (void *)MPC10X_MAP##map##_ISA_IO_BASE; \ +} + + +/* Miscellaneous Configuration register offsets */ +#define MPC10X_CFG_PIR_REG 0x09 +#define MPC10X_CFG_PIR_HOST_BRIDGE 0x00 +#define MPC10X_CFG_PIR_AGENT 0x01 + +#define MPC10X_CFG_EUMBBAR 0x78 + +#define MPC10X_CFG_PICR1_REG 0xa8 +#define MPC10X_CFG_PICR1_ADDR_MAP_MASK 0x00010000 +#define MPC10X_CFG_PICR1_ADDR_MAP_A 0x00010000 +#define MPC10X_CFG_PICR1_ADDR_MAP_B 0x00000000 +#define MPC10X_CFG_PICR1_SPEC_PCI_RD 0x00000004 +#define MPC10X_CFG_PICR1_ST_GATH_EN 0x00000040 + +#define MPC10X_CFG_PICR2_REG 0xac +#define MPC10X_CFG_PICR2_COPYBACK_OPT 0x00000001 + +#define MPC10X_CFG_MAPB_OPTIONS_REG 0xe0 +#define MPC10X_CFG_MAPB_OPTIONS_CFAE 0x80 /* CPU_FD_ALIAS_EN */ +#define MPC10X_CFG_MAPB_OPTIONS_PFAE 0x40 /* PCI_FD_ALIAS_EN */ +#define MPC10X_CFG_MAPB_OPTIONS_DR 0x20 /* DLL_RESET */ +#define MPC10X_CFG_MAPB_OPTIONS_PCICH 0x08 /* PCI_COMPATIBILITY_HOLE */ +#define MPC10X_CFG_MAPB_OPTIONS_PROCCH 0x04 /* PROC_COMPATIBILITY_HOLE */ + +/* Define offsets for the memory controller registers in the config space */ +#define MPC10X_MCTLR_MEM_START_1 0x80 /* Banks 0-3 */ +#define MPC10X_MCTLR_MEM_START_2 0x84 /* Banks 4-7 */ +#define MPC10X_MCTLR_EXT_MEM_START_1 0x88 /* Banks 0-3 */ +#define MPC10X_MCTLR_EXT_MEM_START_2 0x8c /* Banks 4-7 */ + +#define MPC10X_MCTLR_MEM_END_1 0x90 /* Banks 0-3 */ +#define MPC10X_MCTLR_MEM_END_2 0x94 /* Banks 4-7 */ +#define MPC10X_MCTLR_EXT_MEM_END_1 0x98 /* Banks 0-3 */ +#define MPC10X_MCTLR_EXT_MEM_END_2 0x9c /* Banks 4-7 */ + +#define MPC10X_MCTLR_MEM_BANK_ENABLES 0xa0 + +/* Define some offset in the EUMB */ +#define MPC10X_EUMB_SIZE 0x00100000 /* Total EUMB size (1MB) */ + +#define MPC10X_EUMB_MU_OFFSET 0x00000000 /* Msg Unit reg offset */ +#define MPC10X_EUMB_MU_SIZE 0x00001000 /* Msg Unit reg size */ +#define MPC10X_EUMB_DMA_OFFSET 0x00001000 /* DMA Unit reg offset */ +#define MPC10X_EUMB_DMA_SIZE 0x00001000 /* DMA Unit reg size */ +#define MPC10X_EUMB_ATU_OFFSET 0x00002000 /* Addr xlate reg offset */ +#define MPC10X_EUMB_ATU_SIZE 0x00001000 /* Addr xlate reg size */ +#define MPC10X_EUMB_I2C_OFFSET 0x00003000 /* I2C Unit reg offset */ +#define MPC10X_EUMB_I2C_SIZE 0x00001000 /* I2C Unit reg size */ +#define MPC10X_EUMB_DUART_OFFSET 0x00004000 /* DUART Unit reg offset (8245) */ +#define MPC10X_EUMB_DUART_SIZE 0x00001000 /* DUART Unit reg size (8245) */ +#define MPC10X_EUMB_EPIC_OFFSET 0x00040000 /* EPIC offset in EUMB */ +#define MPC10X_EUMB_EPIC_SIZE 0x00030000 /* EPIC size */ +#define MPC10X_EUMB_PM_OFFSET 0x000fe000 /* Performance Monitor reg offset (8245) */ +#define MPC10X_EUMB_PM_SIZE 0x00001000 /* Performance Monitor reg size (8245) */ +#define MPC10X_EUMB_WP_OFFSET 0x000ff000 /* Data path diagnostic, watchpoint reg offset */ +#define MPC10X_EUMB_WP_SIZE 0x00001000 /* Data path diagnostic, watchpoint reg size */ + +/* + * Define some recommended places to put the EUMB regs. + * For both maps, recommend putting the EUMB from 0xeff00000 to 0xefffffff. + */ +extern unsigned long ioremap_base; +#define MPC10X_MAPA_EUMB_BASE (ioremap_base - MPC10X_EUMB_SIZE) +#define MPC10X_MAPB_EUMB_BASE MPC10X_MAPA_EUMB_BASE + +enum ppc_sys_devices { + MPC10X_IIC1, + MPC10X_DMA0, + MPC10X_DMA1, + MPC10X_UART0, + MPC10X_UART1, + NUM_PPC_SYS_DEVS, +}; + +int mpc10x_bridge_init(struct pci_controller *hose, + uint current_map, + uint new_map, + uint phys_eumb_base); +unsigned long mpc10x_get_mem_size(uint mem_map); +int mpc10x_enable_store_gathering(struct pci_controller *hose); +int mpc10x_disable_store_gathering(struct pci_controller *hose); + +/* For MPC107 boards that use the built-in openpic */ +void mpc10x_set_openpic(void); + +#endif /* __PPC_KERNEL_MPC10X_H */ diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 1e3cc69487b5..a2c04b9d42b1 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -40,7 +40,6 @@ #include <asm/pci-bridge.h> #include <asm/reg.h> #include <mm/mmu_decl.h> -#include "mpc7448_hpc2.h" #include <asm/tsi108_pci.h> #include <asm/tsi108_irq.h> #include <asm/mpic.h> @@ -75,7 +74,7 @@ static void __init mpc7448_hpc2_setup_arch(void) /* setup PCI host bridge */ #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) + for_each_compatible_node(np, "pci", "tsi108-pci") tsi108_setup_pci(np, MPC7448HPC2_PCI_CFG_PHYS, 0); ppc_md.pci_exclude_device = mpc7448_hpc2_exclude_device; @@ -91,7 +90,7 @@ static void __init mpc7448_hpc2_setup_arch(void) } /* - * Interrupt setup and service. Interrrupts on the mpc7448_hpc2 come + * Interrupt setup and service. Interrupts on the mpc7448_hpc2 come * from the four external INT pins, PCI interrupts are routed via * PCI interrupt control registers, it generates internal IRQ23 * diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h deleted file mode 100644 index f7e0e0c7f8d8..000000000000 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * mpc7448_hpc2.h - * - * Definitions for Freescale MPC7448_HPC2 platform - * - * Author: Jacob Pan - * jacob.pan@freescale.com - * Maintainer: Roy Zang <roy.zang@freescale.com> - * - * 2006 (c) Freescale Semiconductor, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __PPC_PLATFORMS_MPC7448_HPC2_H -#define __PPC_PLATFORMS_MPC7448_HPC2_H - -#include <asm/ppcboot.h> - -#endif /* __PPC_PLATFORMS_MPC7448_HPC2_H */ diff --git a/arch/powerpc/platforms/embedded6xx/prpmc2800.c b/arch/powerpc/platforms/embedded6xx/prpmc2800.c index 53420951dc53..e484cac75095 100644 --- a/arch/powerpc/platforms/embedded6xx/prpmc2800.c +++ b/arch/powerpc/platforms/embedded6xx/prpmc2800.c @@ -44,7 +44,6 @@ static void __init prpmc2800_setup_arch(void) struct device_node *np; phys_addr_t paddr; const unsigned int *reg; - const unsigned int *prop; /* * ioremap mpp and gpp registers in case they are later @@ -62,12 +61,6 @@ static void __init prpmc2800_setup_arch(void) of_node_put(np); mv64x60_gpp_reg_base = ioremap(paddr, reg[1]); - np = of_find_node_by_type(NULL, "cpu"); - prop = of_get_property(np, "clock-frequency", NULL); - if (prop) - loops_per_jiffy = *prop / HZ; - of_node_put(np); - #ifdef CONFIG_PCI mv64x60_pci_init(); #endif @@ -158,6 +151,7 @@ define_machine(prpmc2800){ .name = prpmc2800_platform_name, .probe = prpmc2800_probe, .setup_arch = prpmc2800_setup_arch, + .init_early = mv64x60_init_early, .show_cpuinfo = prpmc2800_show_cpuinfo, .init_IRQ = mv64x60_init_irq, .get_irq = mv64x60_get_irq, diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 13ac3015d91c..a65f1b44abf8 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -2,11 +2,12 @@ EXTRA_CFLAGS += -mno-minimal-toc extra-y += dt.o +obj-y += exception.o obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \ hvcall.o proc.o htab.o iommu.o misc.o irq.o obj-$(CONFIG_PCI) += pci.o vpdinfo.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_VIOPATH) += viopath.o +obj-$(CONFIG_VIOPATH) += viopath.o vio.o obj-$(CONFIG_MODULES) += ksyms.o quiet_cmd_dt_strings = DT_STR $@ diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 9e8a334a518a..4543c4bc3a56 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c @@ -72,8 +72,6 @@ static char __initdata device_type_cpu[] = "cpu"; static char __initdata device_type_memory[] = "memory"; static char __initdata device_type_serial[] = "serial"; static char __initdata device_type_network[] = "network"; -static char __initdata device_type_block[] = "block"; -static char __initdata device_type_byte[] = "byte"; static char __initdata device_type_pci[] = "pci"; static char __initdata device_type_vdevice[] = "vdevice"; static char __initdata device_type_vscsi[] = "vscsi"; @@ -375,21 +373,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt) dt_end_node(dt); } - reg += HVMAXARCHITECTEDVIRTUALLANS; - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) - dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, - "IBM,iSeries-viodasd", 1); - reg += HVMAXARCHITECTEDVIRTUALDISKS; - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) - dt_do_vdevice(dt, "viocd", reg, i, device_type_block, - "IBM,iSeries-viocd", 1); - reg += HVMAXARCHITECTEDVIRTUALCDROMS; - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) - dt_do_vdevice(dt, "viotape", reg, i, device_type_byte, - "IBM,iSeries-viotape", 1); dt_end_node(dt); } diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S new file mode 100644 index 000000000000..5381038f0881 --- /dev/null +++ b/arch/powerpc/platforms/iseries/exception.S @@ -0,0 +1,251 @@ +/* + * Low level routines for legacy iSeries support. + * + * Extracted from head_64.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com + * + * This file contains the low-level support and setup for the + * PowerPC-64 platform, including trap and interrupt dispatch. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <asm/reg.h> +#include <asm/ppc_asm.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> +#include <asm/ptrace.h> +#include <asm/cputable.h> + +#include "exception.h" + + .text + + .globl system_reset_iSeries +system_reset_iSeries: + mfspr r13,SPRN_SPRG3 /* Get paca address */ + mfmsr r24 + ori r24,r24,MSR_RI + mtmsrd r24 /* RI on */ + lhz r24,PACAPACAINDEX(r13) /* Get processor # */ + cmpwi 0,r24,0 /* Are we processor 0? */ + bne 1f + b .__start_initialization_iSeries /* Start up the first processor */ +1: mfspr r4,SPRN_CTRLF + li r5,CTRL_RUNLATCH /* Turn off the run light */ + andc r4,r4,r5 + mtspr SPRN_CTRLT,r4 + +1: + HMT_LOW +#ifdef CONFIG_SMP + lbz r23,PACAPROCSTART(r13) /* Test if this processor + * should start */ + sync + LOAD_REG_IMMEDIATE(r3,current_set) + sldi r28,r24,3 /* get current_set[cpu#] */ + ldx r3,r3,r28 + addi r1,r3,THREAD_SIZE + subi r1,r1,STACK_FRAME_OVERHEAD + + cmpwi 0,r23,0 + beq iSeries_secondary_smp_loop /* Loop until told to go */ + b __secondary_start /* Loop until told to go */ +iSeries_secondary_smp_loop: + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ +#else /* CONFIG_SMP */ + /* Yield the processor. This is required for non-SMP kernels + which are running on multi-threaded machines. */ + lis r3,0x8000 + rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ + addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ + li r4,0 /* "yield timed" */ + li r5,-1 /* "yield forever" */ +#endif /* CONFIG_SMP */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */ + b 1b /* If SMP not configured, secondaries + * loop forever */ + +/*** ISeries-LPAR interrupt handlers ***/ + + STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC) + + .globl data_access_iSeries +data_access_iSeries: + mtspr SPRN_SPRG1,r13 +BEGIN_FTR_SECTION + mtspr SPRN_SPRG2,r12 + mfspr r13,SPRN_DAR + mfspr r12,SPRN_DSISR + srdi r13,r13,60 + rlwimi r13,r12,16,0x20 + mfcr r12 + cmpwi r13,0x2c + beq .do_stab_bolted_iSeries + mtcrf 0x80,r12 + mfspr r12,SPRN_SPRG2 +END_FTR_SECTION_IFCLR(CPU_FTR_SLB) + EXCEPTION_PROLOG_1(PACA_EXGEN) + EXCEPTION_PROLOG_ISERIES_1 + b data_access_common + +.do_stab_bolted_iSeries: + mtcrf 0x80,r12 + mfspr r12,SPRN_SPRG2 + EXCEPTION_PROLOG_1(PACA_EXSLB) + EXCEPTION_PROLOG_ISERIES_1 + b .do_stab_bolted + + .globl data_access_slb_iSeries +data_access_slb_iSeries: + mtspr SPRN_SPRG1,r13 /* save r13 */ + mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ + std r3,PACA_EXSLB+EX_R3(r13) + mfspr r3,SPRN_DAR + std r9,PACA_EXSLB+EX_R9(r13) + mfcr r9 +#ifdef __DISABLED__ + cmpdi r3,0 + bge slb_miss_user_iseries +#endif + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + mfspr r10,SPRN_SPRG1 + std r10,PACA_EXSLB+EX_R13(r13) + ld r12,PACALPPACAPTR(r13) + ld r12,LPPACASRR1(r12) + b .slb_miss_realmode + + STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN) + + .globl instruction_access_slb_iSeries +instruction_access_slb_iSeries: + mtspr SPRN_SPRG1,r13 /* save r13 */ + mfspr r13,SPRN_SPRG3 /* get paca address into r13 */ + std r3,PACA_EXSLB+EX_R3(r13) + ld r3,PACALPPACAPTR(r13) + ld r3,LPPACASRR0(r3) /* get SRR0 value */ + std r9,PACA_EXSLB+EX_R9(r13) + mfcr r9 +#ifdef __DISABLED__ + cmpdi r3,0 + bge slb_miss_user_iseries +#endif + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + mfspr r10,SPRN_SPRG1 + std r10,PACA_EXSLB+EX_R13(r13) + ld r12,PACALPPACAPTR(r13) + ld r12,LPPACASRR1(r12) + b .slb_miss_realmode + +#ifdef __DISABLED__ +slb_miss_user_iseries: + std r10,PACA_EXGEN+EX_R10(r13) + std r11,PACA_EXGEN+EX_R11(r13) + std r12,PACA_EXGEN+EX_R12(r13) + mfspr r10,SPRG1 + ld r11,PACA_EXSLB+EX_R9(r13) + ld r12,PACA_EXSLB+EX_R3(r13) + std r10,PACA_EXGEN+EX_R13(r13) + std r11,PACA_EXGEN+EX_R9(r13) + std r12,PACA_EXGEN+EX_R3(r13) + EXCEPTION_PROLOG_ISERIES_1 + b slb_miss_user_common +#endif + + MASKABLE_EXCEPTION_ISERIES(hardware_interrupt) + STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN) + STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN) + STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN) + MASKABLE_EXCEPTION_ISERIES(decrementer) + STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN) + STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN) + + .globl system_call_iSeries +system_call_iSeries: + mr r9,r13 + mfspr r13,SPRN_SPRG3 + EXCEPTION_PROLOG_ISERIES_1 + b system_call_common + + STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN) + STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN) + STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN) + +decrementer_iSeries_masked: + /* We may not have a valid TOC pointer in here. */ + li r11,1 + ld r12,PACALPPACAPTR(r13) + stb r11,LPPACADECRINT(r12) + LOAD_REG_IMMEDIATE(r12, tb_ticks_per_jiffy) + lwz r12,0(r12) + mtspr SPRN_DEC,r12 + /* fall through */ + +hardware_interrupt_iSeries_masked: + mtcrf 0x80,r9 /* Restore regs */ + ld r12,PACALPPACAPTR(r13) + ld r11,LPPACASRR0(r12) + ld r12,LPPACASRR1(r12) + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 + ld r9,PACA_EXGEN+EX_R9(r13) + ld r10,PACA_EXGEN+EX_R10(r13) + ld r11,PACA_EXGEN+EX_R11(r13) + ld r12,PACA_EXGEN+EX_R12(r13) + ld r13,PACA_EXGEN+EX_R13(r13) + rfid + b . /* prevent speculative execution */ + +_INIT_STATIC(__start_initialization_iSeries) + /* Clear out the BSS */ + LOAD_REG_IMMEDIATE(r11,__bss_stop) + LOAD_REG_IMMEDIATE(r8,__bss_start) + sub r11,r11,r8 /* bss size */ + addi r11,r11,7 /* round up to an even double word */ + rldicl. r11,r11,61,3 /* shift right by 3 */ + beq 4f + addi r8,r8,-8 + li r0,0 + mtctr r11 /* zero this many doublewords */ +3: stdu r0,8(r8) + bdnz 3b +4: + LOAD_REG_IMMEDIATE(r1,init_thread_union) + addi r1,r1,THREAD_SIZE + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + + LOAD_REG_IMMEDIATE(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + + bl .iSeries_early_setup + bl .early_setup + + /* relocation is on at this point */ + + b .start_here_common diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h new file mode 100644 index 000000000000..ced45a8fa1aa --- /dev/null +++ b/arch/powerpc/platforms/iseries/exception.h @@ -0,0 +1,58 @@ +#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H +#define _ASM_POWERPC_ISERIES_EXCEPTION_H +/* + * Extracted from head_64.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com + * + * This file contains the low-level support and setup for the + * PowerPC-64 platform, including trap and interrupt dispatch. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <asm/exception.h> + +#define EXCEPTION_PROLOG_ISERIES_1 \ + mfmsr r10; \ + ld r12,PACALPPACAPTR(r13); \ + ld r11,LPPACASRR0(r12); \ + ld r12,LPPACASRR1(r12); \ + ori r10,r10,MSR_RI; \ + mtmsrd r10,1 + +#define STD_EXCEPTION_ISERIES(label, area) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + EXCEPTION_PROLOG_1(area); \ + EXCEPTION_PROLOG_ISERIES_1; \ + b label##_common + +#define MASKABLE_EXCEPTION_ISERIES(label) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG1,r13; /* save r13 */ \ + EXCEPTION_PROLOG_1(PACA_EXGEN); \ + lbz r10,PACASOFTIRQEN(r13); \ + cmpwi 0,r10,0; \ + beq- label##_iSeries_masked; \ + EXCEPTION_PROLOG_ISERIES_1; \ + b label##_common; \ + +#endif /* _ASM_POWERPC_ISERIES_EXCEPTION_H */ diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c index b4e2c7a038e1..15a7097e5dd7 100644 --- a/arch/powerpc/platforms/iseries/htab.c +++ b/arch/powerpc/platforms/iseries/htab.c @@ -86,7 +86,8 @@ long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, } - lhpte.v = hpte_encode_v(va, MMU_PAGE_4K) | vflags | HPTE_V_VALID; + lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) | + vflags | HPTE_V_VALID; lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags; /* Now fill in the actual HPTE */ @@ -142,7 +143,7 @@ static long iSeries_hpte_remove(unsigned long hpte_group) * bits 61..63 : PP2,PP1,PP0 */ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int psize, int local) + unsigned long va, int psize, int ssize, int local) { struct hash_pte hpte; unsigned long want_v; @@ -150,7 +151,7 @@ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, iSeries_hlock(slot); HvCallHpt_get(&hpte, slot); - want_v = hpte_encode_v(va, MMU_PAGE_4K); + want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M); if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) { /* @@ -205,14 +206,14 @@ static long iSeries_hpte_find(unsigned long vpn) * No need to lock here because we should be the only user. */ static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize) + int psize, int ssize) { unsigned long vsid,va,vpn; long slot; BUG_ON(psize != MMU_PAGE_4K); - vsid = get_kernel_vsid(ea); + vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); va = (vsid << 28) | (ea & 0x0fffffff); vpn = va >> HW_PAGE_SHIFT; slot = iSeries_hpte_find(vpn); @@ -222,7 +223,7 @@ static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, } static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long hpte_v; unsigned long avpn = va >> 23; diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 3b6a9666c2c0..49e9c664ea89 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -28,14 +28,17 @@ #include <linux/dma-mapping.h> #include <linux/list.h> #include <linux/pci.h> +#include <linux/module.h> #include <asm/iommu.h> +#include <asm/vio.h> #include <asm/tce.h> #include <asm/machdep.h> #include <asm/abs_addr.h> #include <asm/prom.h> #include <asm/pci-bridge.h> #include <asm/iseries/hv_call_xm.h> +#include <asm/iseries/hv_call_event.h> #include <asm/iseries/iommu.h> static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, @@ -189,6 +192,55 @@ void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn) } #endif +static struct iommu_table veth_iommu_table; +static struct iommu_table vio_iommu_table; + +void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag) +{ + return iommu_alloc_coherent(&vio_iommu_table, size, dma_handle, + DMA_32BIT_MASK, flag, -1); +} +EXPORT_SYMBOL_GPL(iseries_hv_alloc); + +void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle) +{ + iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle); +} +EXPORT_SYMBOL_GPL(iseries_hv_free); + +dma_addr_t iseries_hv_map(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + return iommu_map_single(&vio_iommu_table, vaddr, size, + DMA_32BIT_MASK, direction); +} + +void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction); +} + +void __init iommu_vio_init(void) +{ + iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table); + veth_iommu_table.it_size /= 2; + vio_iommu_table = veth_iommu_table; + vio_iommu_table.it_offset += veth_iommu_table.it_size; + + if (!iommu_init_table(&veth_iommu_table, -1)) + printk("Virtual Bus VETH TCE table failed.\n"); + if (!iommu_init_table(&vio_iommu_table, -1)) + printk("Virtual Bus VIO TCE table failed.\n"); +} + +struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev) +{ + if (strcmp(dev->type, "network") == 0) + return &veth_iommu_table; + return &vio_iommu_table; +} + void iommu_init_early_iSeries(void) { ppc_md.tce_build = tce_build_iSeries; diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 63b33675848b..701d9297c207 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -346,8 +346,15 @@ static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, return 0; } +static int iseries_irq_host_match(struct irq_host *h, struct device_node *np) +{ + /* Match all */ + return 1; +} + static struct irq_host_ops iseries_irq_host_ops = { .map = iseries_irq_host_map, + .match = iseries_irq_host_match, }; /* @@ -369,7 +376,8 @@ void __init iSeries_init_IRQ(void) /* Create irq host. No need for a revmap since HV will give us * back our virtual irq number */ - host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &iseries_irq_host_ops, 0); + host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, + &iseries_irq_host_ops, 0); BUG_ON(host == NULL); irq_set_default_host(host); diff --git a/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h index 9bbf58986819..cf6dcf6ef07b 100644 --- a/arch/powerpc/platforms/iseries/it_lp_naca.h +++ b/arch/powerpc/platforms/iseries/it_lp_naca.h @@ -60,7 +60,7 @@ struct ItLpNaca { u8 xRsvd2_0[128]; // Reserved x00-x7F // CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators -// NB: Padding required to keep xInterrruptHdlr at x300 which is required +// NB: Padding required to keep xInterruptHdlr at x300 which is required // for v4r4 PLIC. u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F u8 xRsvd3_0[384]; // Reserved 180-2FF diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index b1187d95e3b2..c0f2433bc16e 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c @@ -39,9 +39,9 @@ #include <asm/paca.h> #include <asm/abs_addr.h> #include <asm/firmware.h> -#include <asm/iseries/vio.h> #include <asm/iseries/mf.h> #include <asm/iseries/hv_lp_config.h> +#include <asm/iseries/hv_lp_event.h> #include <asm/iseries/it_lp_queue.h> #include "setup.h" @@ -870,8 +870,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off, if ((off + count) > 256) count = 256 - off; - dma_addr = dma_map_single(iSeries_vio_dev, page, off + count, - DMA_FROM_DEVICE); + dma_addr = iseries_hv_map(page, off + count, DMA_FROM_DEVICE); if (dma_mapping_error(dma_addr)) return -ENOMEM; memset(page, 0, off + count); @@ -883,8 +882,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off, vsp_cmd.sub_data.kern.length = off + count; mb(); rc = signal_vsp_instruction(&vsp_cmd); - dma_unmap_single(iSeries_vio_dev, dma_addr, off + count, - DMA_FROM_DEVICE); + iseries_hv_unmap(dma_addr, off + count, DMA_FROM_DEVICE); if (rc) return rc; if (vsp_cmd.result_code != 0) @@ -919,8 +917,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) int len = *size; dma_addr_t dma_addr; - dma_addr = dma_map_single(iSeries_vio_dev, buffer, len, - DMA_FROM_DEVICE); + dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE); memset(buffer, 0, len); memset(&vsp_cmd, 0, sizeof(vsp_cmd)); vsp_cmd.cmd = 32; @@ -938,7 +935,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) rc = -ENOMEM; } - dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE); + iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE); return rc; } @@ -1149,8 +1146,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer, goto out; dma_addr = 0; - page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, - GFP_ATOMIC); + page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); ret = -ENOMEM; if (page == NULL) goto out; @@ -1170,7 +1166,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer, ret = count; out_free: - dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); + iseries_hv_free(count, page, dma_addr); out: return ret; } @@ -1190,8 +1186,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file, goto out; dma_addr = 0; - page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, - GFP_ATOMIC); + page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); rc = -ENOMEM; if (page == NULL) { printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); @@ -1219,7 +1214,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file, *ppos += count; rc = count; out_free: - dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); + iseries_hv_free(count, page, dma_addr); out: return rc; } diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 13a8b1908ded..37ae07ee54a9 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -26,6 +26,8 @@ #include <linux/major.h> #include <linux/root_dev.h> #include <linux/kernel.h> +#include <linux/hrtimer.h> +#include <linux/tick.h> #include <asm/processor.h> #include <asm/machdep.h> @@ -41,7 +43,6 @@ #include <asm/time.h> #include <asm/paca.h> #include <asm/cache.h> -#include <asm/sections.h> #include <asm/abs_addr.h> #include <asm/iseries/hv_lp_config.h> #include <asm/iseries/hv_call_event.h> @@ -562,6 +563,7 @@ static void yield_shared_processor(void) static void iseries_shared_idle(void) { while (1) { + tick_nohz_stop_sched_tick(); while (!need_resched() && !hvlpevent_is_pending()) { local_irq_disable(); ppc64_runlatch_off(); @@ -575,6 +577,7 @@ static void iseries_shared_idle(void) } ppc64_runlatch_on(); + tick_nohz_restart_sched_tick(); if (hvlpevent_is_pending()) process_iSeries_events(); @@ -590,6 +593,7 @@ static void iseries_dedicated_idle(void) set_thread_flag(TIF_POLLING_NRFLAG); while (1) { + tick_nohz_stop_sched_tick(); if (!need_resched()) { while (!need_resched()) { ppc64_runlatch_off(); @@ -606,6 +610,7 @@ static void iseries_dedicated_idle(void) } ppc64_runlatch_on(); + tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c new file mode 100644 index 000000000000..910b00b4703e --- /dev/null +++ b/arch/powerpc/platforms/iseries/vio.c @@ -0,0 +1,553 @@ +/* + * Legacy iSeries specific vio initialisation + * that needs to be built in (not a module). + * + * © Copyright 2007 IBM Corporation + * Author: Stephen Rothwell + * Some parts collected from various other files + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/of.h> +#include <linux/init.h> +#include <linux/gfp.h> +#include <linux/completion.h> +#include <linux/proc_fs.h> +#include <linux/module.h> + +#include <asm/firmware.h> +#include <asm/vio.h> +#include <asm/iseries/vio.h> +#include <asm/iseries/iommu.h> +#include <asm/iseries/hv_types.h> +#include <asm/iseries/hv_lp_event.h> + +#define FIRST_VTY 0 +#define NUM_VTYS 1 +#define FIRST_VSCSI (FIRST_VTY + NUM_VTYS) +#define NUM_VSCSIS 1 +#define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS) +#define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS +#define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS) +#define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS +#define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS) +#define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS +#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS) +#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES + +struct vio_waitevent { + struct completion com; + int rc; + u16 sub_result; +}; + +struct vio_resource { + char rsrcname[10]; + char type[4]; + char model[3]; +}; + +static struct property *new_property(const char *name, int length, + const void *value) +{ + struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, + GFP_KERNEL); + + if (!np) + return NULL; + np->name = (char *)(np + 1); + np->value = np->name + strlen(name) + 1; + strcpy(np->name, name); + memcpy(np->value, value, length); + np->length = length; + return np; +} + +static void __init free_property(struct property *np) +{ + kfree(np); +} + +static struct device_node *new_node(const char *path, + struct device_node *parent) +{ + struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); + + if (!np) + return NULL; + np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL); + if (!np->full_name) { + kfree(np); + return NULL; + } + strcpy(np->full_name, path); + of_node_set_flag(np, OF_DYNAMIC); + kref_init(&np->kref); + np->parent = of_node_get(parent); + return np; +} + +static void free_node(struct device_node *np) +{ + struct property *next; + struct property *prop; + + next = np->properties; + while (next) { + prop = next; + next = prop->next; + free_property(prop); + } + of_node_put(np->parent); + kfree(np->full_name); + kfree(np); +} + +static int add_string_property(struct device_node *np, const char *name, + const char *value) +{ + struct property *nprop = new_property(name, strlen(value) + 1, value); + + if (!nprop) + return 0; + prom_add_property(np, nprop); + return 1; +} + +static int add_raw_property(struct device_node *np, const char *name, + int length, const void *value) +{ + struct property *nprop = new_property(name, length, value); + + if (!nprop) + return 0; + prom_add_property(np, nprop); + return 1; +} + +static struct device_node *do_device_node(struct device_node *parent, + const char *name, u32 reg, u32 unit, const char *type, + const char *compat, struct vio_resource *res) +{ + struct device_node *np; + char path[32]; + + snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg); + np = new_node(path, parent); + if (!np) + return NULL; + if (!add_string_property(np, "name", name) || + !add_string_property(np, "device_type", type) || + !add_string_property(np, "compatible", compat) || + !add_raw_property(np, "reg", sizeof(reg), ®) || + !add_raw_property(np, "linux,unit_address", + sizeof(unit), &unit)) { + goto node_free; + } + if (res) { + if (!add_raw_property(np, "linux,vio_rsrcname", + sizeof(res->rsrcname), res->rsrcname) || + !add_raw_property(np, "linux,vio_type", + sizeof(res->type), res->type) || + !add_raw_property(np, "linux,vio_model", + sizeof(res->model), res->model)) + goto node_free; + } + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + of_attach_node(np); +#ifdef CONFIG_PROC_DEVICETREE + if (parent->pde) { + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde); + if (ent) + proc_device_tree_add_node(np, ent); + } +#endif + return np; + + node_free: + free_node(np); + return NULL; +} + +/* + * This is here so that we can dynamically add viodasd + * devices without exposing all the above infrastructure. + */ +struct vio_dev *vio_create_viodasd(u32 unit) +{ + struct device_node *vio_root; + struct device_node *np; + struct vio_dev *vdev = NULL; + + vio_root = of_find_node_by_path("/vdevice"); + if (!vio_root) + return NULL; + np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, + "block", "IBM,iSeries-viodasd", NULL); + of_node_put(vio_root); + if (np) { + vdev = vio_register_device_node(np); + if (!vdev) + free_node(np); + } + return vdev; +} +EXPORT_SYMBOL_GPL(vio_create_viodasd); + +static void __init handle_block_event(struct HvLpEvent *event) +{ + struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; + struct vio_waitevent *pwe; + + if (event == NULL) + /* Notification that a partition went away! */ + return; + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + printk(KERN_WARNING "handle_viod_request: " + "Yikes! got an int in viodasd event handler!\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case vioblockopen: + /* + * Handle a response to an open request. We get all the + * disk information in the response, so update it. The + * correlation token contains a pointer to a waitevent + * structure that has a completion in it. update the + * return code in the waitevent structure and post the + * completion to wake up the guy who sent the request + */ + pwe = (struct vio_waitevent *)event->xCorrelationToken; + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + case vioblockclose: + break; + default: + printk(KERN_WARNING "handle_viod_request: unexpected subtype!"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static void __init probe_disk(struct device_node *vio_root, u32 unit) +{ + HvLpEvent_Rc hvrc; + struct vio_waitevent we; + u16 flags = 0; + +retry: + init_completion(&we.com); + + /* Send the open event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + ((u64)unit << 48) | ((u64)flags<< 32), + 0, 0, 0); + if (hvrc != 0) { + printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n", + (int)hvrc); + return; + } + + wait_for_completion(&we.com); + + if (we.rc != 0) { + if (flags != 0) + return; + /* try again with read only flag set */ + flags = vioblockflags_ro; + goto retry; + } + + /* Send the close event to OS/400. We DON'T expect a response */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockclose, + HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + 0, VIOVERSION << 16, + ((u64)unit << 48) | ((u64)flags << 32), + 0, 0, 0); + if (hvrc != 0) { + printk(KERN_WARNING "probe_disk: " + "bad rc sending event to OS/400 %d\n", (int)hvrc); + return; + } + + do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, + "block", "IBM,iSeries-viodasd", NULL); +} + +static void __init get_viodasd_info(struct device_node *vio_root) +{ + int rc; + u32 unit; + + rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2); + if (rc) { + printk(KERN_WARNING "get_viodasd_info: " + "error opening path to host partition %d\n", + viopath_hostLp); + return; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_blockio, handle_block_event); + + for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++) + probe_disk(vio_root, unit); + + vio_clearHandler(viomajorsubtype_blockio); + viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2); +} + +static void __init handle_cd_event(struct HvLpEvent *event) +{ + struct viocdlpevent *bevent; + struct vio_waitevent *pwe; + + if (!event) + /* Notification that a partition went away! */ + return; + + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + printk(KERN_WARNING "handle_cd_event: got an unexpected int\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + bevent = (struct viocdlpevent *)event; + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viocdgetinfo: + pwe = (struct vio_waitevent *)event->xCorrelationToken; + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + + default: + printk(KERN_WARNING "handle_cd_event: " + "message with unexpected subtype %0x04X!\n", + event->xSubtype & VIOMINOR_SUBTYPE_MASK); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static void __init get_viocd_info(struct device_node *vio_root) +{ + HvLpEvent_Rc hvrc; + u32 unit; + struct vio_waitevent we; + struct vio_resource *unitinfo; + dma_addr_t unitinfo_dmaaddr; + int ret; + + ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2); + if (ret) { + printk(KERN_WARNING + "get_viocd_info: error opening path to host partition %d\n", + viopath_hostLp); + return; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_cdio, handle_cd_event); + + unitinfo = iseries_hv_alloc( + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, + &unitinfo_dmaaddr, GFP_ATOMIC); + if (!unitinfo) { + printk(KERN_WARNING + "get_viocd_info: error allocating unitinfo\n"); + goto clear_handler; + } + + memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS); + + init_completion(&we.com); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdgetinfo, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(KERN_WARNING + "get_viocd_info: cdrom error sending event. rc %d\n", + (int)hvrc); + goto hv_free; + } + + wait_for_completion(&we.com); + + if (we.rc) { + printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n", + we.rc, we.sub_result); + goto hv_free; + } + + for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && + unitinfo[unit].rsrcname[0]; unit++) { + if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit, + "block", "IBM,iSeries-viocd", &unitinfo[unit])) + break; + } + + hv_free: + iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, + unitinfo, unitinfo_dmaaddr); + clear_handler: + vio_clearHandler(viomajorsubtype_cdio); + viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); +} + +/* Handle interrupt events for tape */ +static void __init handle_tape_event(struct HvLpEvent *event) +{ + struct vio_waitevent *we; + struct viotapelpevent *tevent = (struct viotapelpevent *)event; + + if (event == NULL) + /* Notification that a partition went away! */ + return; + + we = (struct vio_waitevent *)event->xCorrelationToken; + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viotapegetinfo: + we->rc = tevent->sub_type_result; + complete(&we->com); + break; + default: + printk(KERN_WARNING "handle_tape_event: weird ack\n"); + } +} + +static void __init get_viotape_info(struct device_node *vio_root) +{ + HvLpEvent_Rc hvrc; + u32 unit; + struct vio_resource *unitinfo; + dma_addr_t unitinfo_dmaaddr; + size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES; + struct vio_waitevent we; + int ret; + + ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2); + if (ret) { + printk(KERN_WARNING "get_viotape_info: " + "error on viopath_open to hostlp %d\n", ret); + return; + } + + vio_setHandler(viomajorsubtype_tape, handle_tape_event); + + unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC); + if (!unitinfo) + goto clear_handler; + + memset(unitinfo, 0, len); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapegetinfo, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + unitinfo_dmaaddr, len, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(KERN_WARNING "get_viotape_info: hv error on op %d\n", + (int)hvrc); + goto hv_free; + } + + wait_for_completion(&we.com); + + for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && + unitinfo[unit].rsrcname[0]; unit++) { + if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit, + unit, "byte", "IBM,iSeries-viotape", + &unitinfo[unit])) + break; + } + + hv_free: + iseries_hv_free(len, unitinfo, unitinfo_dmaaddr); + clear_handler: + vio_clearHandler(viomajorsubtype_tape); + viopath_close(viopath_hostLp, viomajorsubtype_tape, 2); +} + +static int __init iseries_vio_init(void) +{ + struct device_node *vio_root; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + + iommu_vio_init(); + + vio_root = of_find_node_by_path("/vdevice"); + if (!vio_root) + return -ENODEV; + + if (viopath_hostLp == HvLpIndexInvalid) { + vio_set_hostlp(); + /* If we don't have a host, bail out */ + if (viopath_hostLp == HvLpIndexInvalid) + goto put_node; + } + + get_viodasd_info(vio_root); + get_viocd_info(vio_root); + get_viotape_info(vio_root); + + return 0; + + put_node: + of_node_put(vio_root); + return -ENODEV; +} +arch_initcall(iseries_vio_init); diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c index 6a0060a5f2ec..df23331eb25c 100644 --- a/arch/powerpc/platforms/iseries/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c @@ -124,8 +124,7 @@ static int proc_viopath_show(struct seq_file *m, void *v) if (!buf) return 0; - handle = dma_map_single(iSeries_vio_dev, buf, HW_PAGE_SIZE, - DMA_FROM_DEVICE); + handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE); hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, HvLpEvent_Type_VirtualIo, @@ -146,8 +145,7 @@ static int proc_viopath_show(struct seq_file *m, void *v) buf[HW_PAGE_SIZE-1] = '\0'; seq_printf(m, "%s", buf); - dma_unmap_single(iSeries_vio_dev, handle, HW_PAGE_SIZE, - DMA_FROM_DEVICE); + iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE); kfree(buf); seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); @@ -596,7 +594,7 @@ int viopath_close(HvLpIndex remoteLp, int subtype, int numReq) numOpen += viopathStatus[remoteLp].users[i]; if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) { - printk(VIOPATH_KERN_INFO "closing connection to partition %d", + printk(VIOPATH_KERN_INFO "closing connection to partition %d\n", remoteLp); HvCallEvent_closeLpEventPath(remoteLp, diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 2542403288f9..771ed0cf29a5 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -169,15 +169,12 @@ static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -185,8 +182,8 @@ static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u3_agp_pci_ops = { - u3_agp_read_config, - u3_agp_write_config + .read = u3_agp_read_config, + .write = u3_agp_write_config, }; static unsigned long u3_ht_cfa0(u8 devfn, u8 off) @@ -268,15 +265,12 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -284,8 +278,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u3_ht_pci_ops = { - u3_ht_read_config, - u3_ht_write_config + .read = u3_ht_read_config, + .write = u3_ht_write_config, }; static unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off) @@ -376,15 +370,12 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -392,8 +383,8 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u4_pcie_pci_ops = { - u4_pcie_read_config, - u4_pcie_write_config + .read = u4_pcie_read_config, + .write = u4_pcie_write_config, }; static void __init setup_u3_agp(struct pci_controller* hose) diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index e95261ef6f98..735e1536cbfc 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig @@ -5,6 +5,7 @@ config PPC_PASEMI select MPIC select PPC_UDBG_16550 select PPC_NATIVE + select MPIC_BROKEN_REGREAD help This option enables support for PA Semi's PWRficient line of SoC processors, including PA6T-1682M diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index c91a33593bb8..dae9f658122e 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -320,10 +320,12 @@ static struct of_device_id gpio_mdio_match[] = static struct of_platform_driver gpio_mdio_driver = { - .name = "gpio-mdio-bitbang", .match_table = gpio_mdio_match, .probe = gpio_mdio_probe, .remove = gpio_mdio_remove, + .driver = { + .name = "gpio-mdio-bitbang", + }, }; int gpio_mdio_init(void) diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c index 3c962d5757be..d8e1fcc78513 100644 --- a/arch/powerpc/platforms/pasemi/idle.c +++ b/arch/powerpc/platforms/pasemi/idle.c @@ -72,8 +72,11 @@ static int pasemi_system_reset_exception(struct pt_regs *regs) return 1; } -void __init pasemi_idle_init(void) +static int __init pasemi_idle_init(void) { + if (!machine_is(pasemi)) + return -ENODEV; + #ifndef CONFIG_PPC_PASEMI_CPUFREQ printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); current_mode = 0; @@ -82,7 +85,10 @@ void __init pasemi_idle_init(void) ppc_md.system_reset_exception = pasemi_system_reset_exception; ppc_md.power_save = modes[current_mode].entry; printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); + + return 0; } +late_initcall(pasemi_idle_init); static int __init idle_param(char *p) { diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index a1111b5c6cb4..9916a0f3e431 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -192,7 +192,7 @@ static void pci_dma_dev_setup_pasemi(struct pci_dev *dev) static void pci_dma_bus_setup_null(struct pci_bus *b) { } static void pci_dma_dev_setup_null(struct pci_dev *d) { } -int iob_init(struct device_node *dn) +int __init iob_init(struct device_node *dn) { unsigned long tmp; u32 regword; @@ -238,7 +238,7 @@ int iob_init(struct device_node *dn) /* These are called very early. */ -void iommu_init_early_pasemi(void) +void __init iommu_init_early_pasemi(void) { int iommu_off; diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h index be8495497611..516acabb4e96 100644 --- a/arch/powerpc/platforms/pasemi/pasemi.h +++ b/arch/powerpc/platforms/pasemi/pasemi.h @@ -6,9 +6,9 @@ extern void pas_pci_init(void); extern void __devinit pas_pci_irq_fixup(struct pci_dev *dev); extern void __devinit pas_pci_dma_dev_setup(struct pci_dev *dev); -extern void __init alloc_iobmap_l2(void); +extern void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset); -extern void __init pasemi_idle_init(void); +extern void __init alloc_iobmap_l2(void); /* Power savings modes, implemented in asm */ extern void idle_spin(void); diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index ab1f5f62bcd8..b6a0ec45c695 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -51,6 +51,61 @@ static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose, return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset); } +static inline int is_root_port(int busno, int devfn) +{ + return ((busno == 0) && (PCI_FUNC(devfn) < 4) && + ((PCI_SLOT(devfn) == 16) || (PCI_SLOT(devfn) == 17))); +} + +static inline int is_5945_reg(int reg) +{ + return (((reg >= 0x18) && (reg < 0x34)) || + ((reg >= 0x158) && (reg < 0x178))); +} + +static int workaround_5945(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) +{ + struct pci_controller *hose; + void volatile __iomem *addr, *dummy; + int byte; + u32 tmp; + + if (!is_root_port(bus->number, devfn) || !is_5945_reg(offset)) + return 0; + + hose = pci_bus_to_host(bus); + + addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset & ~0x3); + byte = offset & 0x3; + + /* Workaround bug 5945: write 0 to a dummy register before reading, + * and write back what we read. We must read/write the full 32-bit + * contents so we need to shift and mask by hand. + */ + dummy = pa_pxp_cfg_addr(hose, bus->number, devfn, 0x10); + out_le32(dummy, 0); + tmp = in_le32(addr); + out_le32(addr, tmp); + + switch (len) { + case 1: + *val = (tmp >> (8*byte)) & 0xff; + break; + case 2: + if (byte == 0) + *val = tmp & 0xffff; + else + *val = (tmp >> 16) & 0xffff; + break; + default: + *val = tmp; + break; + } + + return 1; +} + static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { @@ -64,6 +119,9 @@ static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn, if (!pa_pxp_offset_valid(bus->number, devfn, offset)) return PCIBIOS_BAD_REGISTER_NUMBER; + if (workaround_5945(bus, devfn, offset, len, val)) + return PCIBIOS_SUCCESSFUL; + addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset); /* @@ -107,23 +165,20 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; } static struct pci_ops pa_pxp_ops = { - pa_pxp_read_config, - pa_pxp_write_config, + .read = pa_pxp_read_config, + .write = pa_pxp_write_config, }; static void __init setup_pa_pxp(struct pci_controller *hose) @@ -178,3 +233,12 @@ void __init pas_pci_init(void) /* Use the common resource allocation mechanism */ pci_probe_only = 1; } + +void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset) +{ + struct pci_controller *hose; + + hose = pci_bus_to_host(dev->bus); + + return (void __iomem *)pa_pxp_cfg_addr(hose, dev->bus->number, dev->devfn, offset); +} diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index ffe6528048b5..5ddf40a66ae8 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -39,8 +39,21 @@ #include "pasemi.h" +/* SDC reset register, must be pre-mapped at reset time */ static void __iomem *reset_reg; +/* Various error status registers, must be pre-mapped at MCE time */ + +#define MAX_MCE_REGS 32 +struct mce_regs { + char *name; + void __iomem *addr; +}; + +static struct mce_regs mce_regs[MAX_MCE_REGS]; +static int num_mce_regs; + + static void pas_restart(char *cmd) { printk("Restarting...\n"); @@ -50,26 +63,30 @@ static void pas_restart(char *cmd) #ifdef CONFIG_SMP static DEFINE_SPINLOCK(timebase_lock); +static unsigned long timebase; static void __devinit pas_give_timebase(void) { - unsigned long tb; - spin_lock(&timebase_lock); mtspr(SPRN_TBCTL, TBCTL_FREEZE); - tb = mftb(); - mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff)); - mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32)); - mtspr(SPRN_TBCTL, TBCTL_RESTART); + isync(); + timebase = get_tb(); spin_unlock(&timebase_lock); - pr_debug("pas_give_timebase: cpu %d gave tb %lx\n", - smp_processor_id(), tb); + + while (timebase) + barrier(); + mtspr(SPRN_TBCTL, TBCTL_RESTART); } static void __devinit pas_take_timebase(void) { - pr_debug("pas_take_timebase: cpu %d has tb %lx\n", - smp_processor_id(), mftb()); + while (!timebase) + smp_rmb(); + + spin_lock(&timebase_lock); + set_tb(timebase >> 32, timebase & 0xffffffff); + timebase = 0; + spin_unlock(&timebase_lock); } struct smp_ops_t pas_smp_ops = { @@ -98,9 +115,60 @@ void __init pas_setup_arch(void) /* Remap SDC register for doing reset */ /* XXXOJN This should maybe come out of the device tree */ reset_reg = ioremap(0xfc101100, 4); +} + +static int __init pas_setup_mce_regs(void) +{ + struct pci_dev *dev; + int reg; + + if (!machine_is(pasemi)) + return -ENODEV; + + /* Remap various SoC status registers for use by the MCE handler */ + + reg = 0; + + dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, NULL); + while (dev && reg < MAX_MCE_REGS) { + mce_regs[reg].name = kasprintf(GFP_KERNEL, + "mc%d_mcdebug_errsta", reg); + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x730); + dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, dev); + reg++; + } + + dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); + if (dev && reg+4 < MAX_MCE_REGS) { + mce_regs[reg].name = "iobdbg_IntStatus1"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x438); + reg++; + mce_regs[reg].name = "iobdbg_IOCTbusIntDbgReg"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x454); + reg++; + mce_regs[reg].name = "iobiom_IntStatus"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc10); + reg++; + mce_regs[reg].name = "iobiom_IntDbgReg"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc1c); + reg++; + } + + dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa009, NULL); + if (dev && reg+2 < MAX_MCE_REGS) { + mce_regs[reg].name = "l2csts_IntStatus"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x200); + reg++; + mce_regs[reg].name = "l2csts_Cnt"; + mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x214); + reg++; + } - pasemi_idle_init(); + num_mce_regs = reg; + + return 0; } +device_initcall(pas_setup_mce_regs); static __init void pas_init_IRQ(void) { @@ -162,25 +230,34 @@ static int pas_machine_check_handler(struct pt_regs *regs) { int cpu = smp_processor_id(); unsigned long srr0, srr1, dsisr; + int dump_slb = 0; + int i; srr0 = regs->nip; srr1 = regs->msr; dsisr = mfspr(SPRN_DSISR); printk(KERN_ERR "Machine Check on CPU %d\n", cpu); - printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); - printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); + printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); + printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); + printk(KERN_ERR "BER 0x%016lx MER 0x%016lx\n", mfspr(SPRN_PA6T_BER), + mfspr(SPRN_PA6T_MER)); + printk(KERN_ERR "IER 0x%016lx DER 0x%016lx\n", mfspr(SPRN_PA6T_IER), + mfspr(SPRN_PA6T_DER)); printk(KERN_ERR "Cause:\n"); if (srr1 & 0x200000) printk(KERN_ERR "Signalled by SDC\n"); + if (srr1 & 0x100000) { printk(KERN_ERR "Load/Store detected error:\n"); if (dsisr & 0x8000) printk(KERN_ERR "D-cache ECC double-bit error or bus error\n"); if (dsisr & 0x4000) printk(KERN_ERR "LSU snoop response error\n"); - if (dsisr & 0x2000) + if (dsisr & 0x2000) { printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n"); + dump_slb = 1; + } if (dsisr & 0x1000) printk(KERN_ERR "Recoverable Duptags\n"); if (dsisr & 0x800) @@ -188,13 +265,40 @@ static int pas_machine_check_handler(struct pt_regs *regs) if (dsisr & 0x400) printk(KERN_ERR "TLB parity error count overflow\n"); } + if (srr1 & 0x80000) printk(KERN_ERR "Bus Error\n"); - if (srr1 & 0x40000) + + if (srr1 & 0x40000) { printk(KERN_ERR "I-side SLB multiple hit\n"); + dump_slb = 1; + } + if (srr1 & 0x20000) printk(KERN_ERR "I-cache parity error hit\n"); + if (num_mce_regs == 0) + printk(KERN_ERR "No MCE registers mapped yet, can't dump\n"); + else + printk(KERN_ERR "SoC debug registers:\n"); + + for (i = 0; i < num_mce_regs; i++) + printk(KERN_ERR "%s: 0x%08x\n", mce_regs[i].name, + in_le32(mce_regs[i].addr)); + + if (dump_slb) { + unsigned long e, v; + int i; + + printk(KERN_ERR "slb contents:\n"); + for (i = 0; i < SLB_NUM_ENTRIES; i++) { + asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i)); + asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i)); + printk(KERN_ERR "%02d %016lx %016lx\n", i, e, v); + } + } + + /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ return !!(srr1 & 0x2); } diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index 9d73d0234c5d..cf660916ae0b 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -17,7 +17,6 @@ #include <asm/prom.h> #include <asm/page.h> #include <asm/bootx.h> -#include <asm/bootinfo.h> #include <asm/btext.h> #include <asm/io.h> diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index efdf5eb81ecc..da2007e3db0e 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -40,7 +40,6 @@ #include <linux/completion.h> #include <linux/platform_device.h> #include <linux/interrupt.h> -#include <linux/completion.h> #include <linux/timer.h> #include <linux/mutex.h> #include <asm/keylargo.h> diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 92586db19754..ec49099830d5 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -209,15 +209,12 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -225,8 +222,8 @@ static int macrisc_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops macrisc_pci_ops = { - macrisc_read_config, - macrisc_write_config + .read = macrisc_read_config, + .write = macrisc_write_config, }; #ifdef CONFIG_PPC32 @@ -280,8 +277,8 @@ chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset, static struct pci_ops chaos_pci_ops = { - chaos_read_config, - chaos_write_config + .read = chaos_read_config, + .write = chaos_write_config, }; static void __init setup_chaos(struct pci_controller *hose, @@ -440,15 +437,12 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32((u32 __iomem *)addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -456,8 +450,8 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u3_ht_pci_ops = { - u3_ht_read_config, - u3_ht_write_config + .read = u3_ht_read_config, + .write = u3_ht_write_config, }; #define U4_PCIE_CFA0(devfn, off) \ @@ -545,15 +539,12 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, switch (len) { case 1: out_8(addr, val); - (void) in_8(addr); break; case 2: out_le16(addr, val); - (void) in_le16(addr); break; default: out_le32(addr, val); - (void) in_le32(addr); break; } return PCIBIOS_SUCCESSFUL; @@ -561,8 +552,8 @@ static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, static struct pci_ops u4_pcie_pci_ops = { - u4_pcie_read_config, - u4_pcie_write_config + .read = u4_pcie_read_config, + .write = u4_pcie_write_config, }; #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 87cd6805171a..999f5e160897 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -384,7 +384,7 @@ static void __init pmac_pic_probe_oldstyle(void) /* * Allocate an irq host */ - pmac_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, max_irqs, + pmac_pic_host = irq_alloc_host(master, IRQ_HOST_MAP_LINEAR, max_irqs, &pmac_pic_host_ops, max_irqs); BUG_ON(pmac_pic_host == NULL); diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 6e090a7dea83..fcde070f7054 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -22,9 +22,6 @@ extern void pmac_read_rtc_time(void); extern void pmac_calibrate_decr(void); extern void pmac_pci_irq_fixup(struct pci_dev *); extern void pmac_pci_init(void); -extern unsigned long pmac_ide_get_base(int index); -extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, - unsigned long data_port, unsigned long ctrl_port, int *irq); extern void pmac_nvram_update(void); extern unsigned char pmac_nvram_read_byte(int addr); @@ -33,7 +30,6 @@ extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); extern void pmac_pcibios_after_init(void); extern int of_show_percpuinfo(struct seq_file *m, int i); -extern void pmac_pci_init(void); extern void pmac_setup_pci_dma(void); extern void pmac_check_ht_link(void); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 7ccb9236e8b4..02c533096627 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -387,69 +387,13 @@ static void __init pmac_setup_arch(void) #endif /* CONFIG_ADB */ } -char *bootpath; -char *bootdevice; -void *boot_host; -int boot_target; -int boot_part; -static dev_t boot_dev; - #ifdef CONFIG_SCSI void note_scsi_host(struct device_node *node, void *host) { - int l; - char *p; - - l = strlen(node->full_name); - if (bootpath != NULL && bootdevice != NULL - && strncmp(node->full_name, bootdevice, l) == 0 - && (bootdevice[l] == '/' || bootdevice[l] == 0)) { - boot_host = host; - /* - * There's a bug in OF 1.0.5. (Why am I not surprised.) - * If you pass a path like scsi/sd@1:0 to canon, it returns - * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 - * That is, the scsi target number doesn't get preserved. - * So we pick the target number out of bootpath and use that. - */ - p = strstr(bootpath, "/sd@"); - if (p != NULL) { - p += 4; - boot_target = simple_strtoul(p, NULL, 10); - p = strchr(p, ':'); - if (p != NULL) - boot_part = simple_strtoul(p + 1, NULL, 10); - } - } } EXPORT_SYMBOL(note_scsi_host); #endif -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) -static dev_t __init find_ide_boot(void) -{ - char *p; - int n; - dev_t __init pmac_find_ide_boot(char *bootdevice, int n); - - if (bootdevice == NULL) - return 0; - p = strrchr(bootdevice, '/'); - if (p == NULL) - return 0; - n = p - bootdevice; - - return pmac_find_ide_boot(bootdevice, n); -} -#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ - -static void __init find_boot_device(void) -{ -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) - boot_dev = find_ide_boot(); -#endif -} - static int initializing = 1; static int pmac_late_init(void) @@ -466,10 +410,14 @@ static int pmac_late_init(void) late_initcall(pmac_late_init); -/* can't be __init - can be called whenever a disk is first accessed */ -void note_bootable_part(dev_t dev, int part, int goodness) +/* + * This is __init_refok because we check for "initializing" before + * touching any of the __init sensitive things and "initializing" + * will be false after __init time. This can't be __init because it + * can be called whenever a disk is first accessed. + */ +void __init_refok note_bootable_part(dev_t dev, int part, int goodness) { - static int found_boot = 0; char *p; if (!initializing) @@ -481,15 +429,8 @@ void note_bootable_part(dev_t dev, int part, int goodness) if (p != NULL && (p == boot_command_line || p[-1] == ' ')) return; - if (!found_boot) { - find_boot_device(); - found_boot = 1; - } - if (!boot_dev || dev == boot_dev) { - ROOT_DEV = dev + part; - boot_dev = 0; - current_root_goodness = goodness; - } + ROOT_DEV = dev + part; + current_root_goodness = goodness; } #ifdef CONFIG_ADB_CUDA diff --git a/arch/powerpc/platforms/powermac/udbg_adb.c b/arch/powerpc/platforms/powermac/udbg_adb.c index 6124e59e1038..44e0b55a2a02 100644 --- a/arch/powerpc/platforms/powermac/udbg_adb.c +++ b/arch/powerpc/platforms/powermac/udbg_adb.c @@ -12,7 +12,6 @@ #include <asm/xmon.h> #include <asm/prom.h> #include <asm/bootx.h> -#include <asm/machdep.h> #include <asm/errno.h> #include <asm/pmac_feature.h> #include <asm/processor.h> @@ -150,7 +149,7 @@ static void udbg_adb_putc(char c) return udbg_adb_old_putc(c); } -void udbg_adb_init_early(void) +void __init udbg_adb_init_early(void) { #ifdef CONFIG_BOOTX_TEXT if (btext_find_display(1) == 0) { @@ -160,7 +159,7 @@ void udbg_adb_init_early(void) #endif } -int udbg_adb_init(int force_btext) +int __init udbg_adb_init(int force_btext) { struct device_node *np; diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index ce15cada88d4..fd063fe0c9b3 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -297,8 +297,8 @@ static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) u64 dev_port; } *notify_event; - pr_debug(" -> %s:%u: bus_id %u, dev_id %u, dev_type %u\n", __func__, - __LINE__, repo->bus_id, repo->dev_id, repo->dev_type); + pr_debug(" -> %s:%u: (%u:%u:%u)\n", __func__, __LINE__, repo->bus_id, + repo->dev_id, repo->dev_type); buf = kzalloc(512, GFP_KERNEL); if (!buf) @@ -359,6 +359,11 @@ static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) break; } + pr_debug("%s:%d: notify event (%u:%u:%u): event_type 0x%lx, " + "port %lu\n", __func__, __LINE__, repo->bus_index, + repo->dev_index, repo->dev_type, + notify_event->event_type, notify_event->dev_port); + if (notify_event->event_type != notify_region_probe || notify_event->bus_id != repo->bus_id) { pr_debug("%s:%u: bad notify_event: event %lu, " @@ -370,8 +375,9 @@ static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) if (notify_event->dev_id == repo->dev_id && notify_event->dev_type == repo->dev_type) { - pr_debug("%s:%u: device ready: dev_id %u\n", __func__, - __LINE__, repo->dev_id); + pr_debug("%s:%u: device ready (%u:%u:%u)\n", __func__, + __LINE__, repo->bus_index, repo->dev_index, + repo->dev_type); error = 0; break; } @@ -412,9 +418,10 @@ static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, return -ENODEV; } - pr_debug("%s:%u: index %u:%u: port %lu blk_size %lu num_blocks %lu " + pr_debug("%s:%u: (%u:%u:%u): port %lu blk_size %lu num_blocks %lu " "num_regions %u\n", __func__, __LINE__, repo->bus_index, - repo->dev_index, port, blk_size, num_blocks, num_regions); + repo->dev_index, repo->dev_type, port, blk_size, num_blocks, + num_regions); p = kzalloc(sizeof(struct ps3_storage_device) + num_regions * sizeof(struct ps3_storage_region), @@ -681,8 +688,9 @@ static int ps3_probe_thread(void *data) pr_debug("%s:%u: find device error.\n", __func__, __LINE__); else { - pr_debug("%s:%u: found device\n", __func__, - __LINE__); + pr_debug("%s:%u: found device (%u:%u:%u)\n", + __func__, __LINE__, repo->bus_index, + repo->dev_index, repo->dev_type); ps3_register_repository_device(repo); ps3_repository_bump_device(repo); ms = 250; diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 5d2e176a1b18..7382f195c4f8 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -60,7 +60,8 @@ static void _debug_dump_hpte(unsigned long pa, unsigned long va, } static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, - unsigned long pa, unsigned long rflags, unsigned long vflags, int psize) + unsigned long pa, unsigned long rflags, unsigned long vflags, + int psize, int ssize) { unsigned long slot; struct hash_pte lhpte; @@ -72,7 +73,8 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, vflags &= ~HPTE_V_SECONDARY; /* this bit is ignored */ - lhpte.v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + lhpte.v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) | + vflags | HPTE_V_VALID; lhpte.r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags; p_pteg = hpte_group / HPTES_PER_GROUP; @@ -167,14 +169,14 @@ static long ps3_hpte_remove(unsigned long hpte_group) } static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int psize, int local) + unsigned long va, int psize, int ssize, int local) { unsigned long flags; unsigned long result; unsigned long pteg, bit; unsigned long hpte_v, want_v; - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); spin_lock_irqsave(&ps3_bolttab_lock, flags); @@ -205,13 +207,13 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, } static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize) + int psize, int ssize) { panic("ps3_hpte_updateboltedpp() not implemented"); } static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long flags; unsigned long result; diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 67e32ec9b37e..3a6db04aa940 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -673,9 +673,16 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq, return 0; } +static int ps3_host_match(struct irq_host *h, struct device_node *np) +{ + /* Match all */ + return 1; +} + static struct irq_host_ops ps3_host_ops = { .map = ps3_host_map, .unmap = ps3_host_unmap, + .match = ps3_host_match, }; void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) @@ -726,7 +733,7 @@ void __init ps3_init_IRQ(void) unsigned cpu; struct irq_host *host; - host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, + host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, PS3_INVALID_OUTLET); irq_set_default_host(host); irq_set_virq_count(PS3_PLUG_MAX + 1); diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index b70e474014f0..766685ab26f8 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -1,5 +1,5 @@ /* - * PS3 'Other OS' area data. + * PS3 flash memory os area. * * Copyright (C) 2006 Sony Computer Entertainment Inc. * Copyright 2006 Sony Corp. @@ -20,6 +20,9 @@ #include <linux/kernel.h> #include <linux/io.h> +#include <linux/workqueue.h> +#include <linux/fs.h> +#include <linux/syscalls.h> #include <asm/lmb.h> @@ -29,7 +32,7 @@ enum { OS_AREA_SEGMENT_SIZE = 0X200, }; -enum { +enum os_area_ldr_format { HEADER_LDR_FORMAT_RAW = 0, HEADER_LDR_FORMAT_GZIP = 1, }; @@ -38,7 +41,7 @@ enum { * struct os_area_header - os area header segment. * @magic_num: Always 'cell_ext_os_area'. * @hdr_version: Header format version number. - * @os_area_offset: Starting segment number of os image area. + * @db_area_offset: Starting segment number of other os database area. * @ldr_area_offset: Starting segment number of bootloader image area. * @ldr_format: HEADER_LDR_FORMAT flag. * @ldr_size: Size of bootloader image in bytes. @@ -50,9 +53,9 @@ enum { */ struct os_area_header { - s8 magic_num[16]; + u8 magic_num[16]; u32 hdr_version; - u32 os_area_offset; + u32 db_area_offset; u32 ldr_area_offset; u32 _reserved_1; u32 ldr_format; @@ -60,12 +63,12 @@ struct os_area_header { u32 _reserved_2[6]; }; -enum { +enum os_area_boot_flag { PARAM_BOOT_FLAG_GAME_OS = 0, PARAM_BOOT_FLAG_OTHER_OS = 1, }; -enum { +enum os_area_ctrl_button { PARAM_CTRL_BUTTON_O_IS_YES = 0, PARAM_CTRL_BUTTON_X_IS_YES = 1, }; @@ -84,6 +87,9 @@ enum { * @dns_primary: User preference of static primary dns server. * @dns_secondary: User preference of static secondary dns server. * + * The ps3 rtc maintains a read-only value that approximates seconds since + * 2000-01-01 00:00:00 UTC. + * * User preference of zero for static_ip_addr means use dhcp. */ @@ -108,45 +114,172 @@ struct os_area_params { u8 _reserved_5[8]; }; +enum { + OS_AREA_DB_MAGIC_NUM = 0x2d64622dU, +}; + /** - * struct saved_params - Static working copies of data from the 'Other OS' area. + * struct os_area_db - Shared flash memory database. + * @magic_num: Always '-db-' = 0x2d64622d. + * @version: os_area_db format version number. + * @index_64: byte offset of the database id index for 64 bit variables. + * @count_64: number of usable 64 bit index entries + * @index_32: byte offset of the database id index for 32 bit variables. + * @count_32: number of usable 32 bit index entries + * @index_16: byte offset of the database id index for 16 bit variables. + * @count_16: number of usable 16 bit index entries * - * For the convinience of the guest, the HV makes a copy of the 'Other OS' area - * in flash to a high address in the boot memory region and then puts that RAM - * address and the byte count into the repository for retreval by the guest. - * We copy the data we want into a static variable and allow the memory setup - * by the HV to be claimed by the lmb manager. + * Flash rom storage for exclusive use by guests running in the other os lpar. + * The current system configuration allocates 1K (two segments) for other os + * use. + */ + +struct os_area_db { + u32 magic_num; + u16 version; + u16 _reserved_1; + u16 index_64; + u16 count_64; + u16 index_32; + u16 count_32; + u16 index_16; + u16 count_16; + u32 _reserved_2; + u8 _db_data[1000]; +}; + +/** + * enum os_area_db_owner - Data owners. + */ + +enum os_area_db_owner { + OS_AREA_DB_OWNER_ANY = -1, + OS_AREA_DB_OWNER_NONE = 0, + OS_AREA_DB_OWNER_PROTOTYPE = 1, + OS_AREA_DB_OWNER_LINUX = 2, + OS_AREA_DB_OWNER_PETITBOOT = 3, + OS_AREA_DB_OWNER_MAX = 32, +}; + +enum os_area_db_key { + OS_AREA_DB_KEY_ANY = -1, + OS_AREA_DB_KEY_NONE = 0, + OS_AREA_DB_KEY_RTC_DIFF = 1, + OS_AREA_DB_KEY_VIDEO_MODE = 2, + OS_AREA_DB_KEY_MAX = 8, +}; + +struct os_area_db_id { + int owner; + int key; +}; + +static const struct os_area_db_id os_area_db_id_empty = { + .owner = OS_AREA_DB_OWNER_NONE, + .key = OS_AREA_DB_KEY_NONE +}; + +static const struct os_area_db_id os_area_db_id_any = { + .owner = OS_AREA_DB_OWNER_ANY, + .key = OS_AREA_DB_KEY_ANY +}; + +static const struct os_area_db_id os_area_db_id_rtc_diff = { + .owner = OS_AREA_DB_OWNER_LINUX, + .key = OS_AREA_DB_KEY_RTC_DIFF +}; + +static const struct os_area_db_id os_area_db_id_video_mode = { + .owner = OS_AREA_DB_OWNER_LINUX, + .key = OS_AREA_DB_KEY_VIDEO_MODE +}; + +#define SECONDS_FROM_1970_TO_2000 946684800LL + +/** + * struct saved_params - Static working copies of data from the PS3 'os area'. + * + * The order of preference we use for the rtc_diff source: + * 1) The database value. + * 2) The game os value. + * 3) The number of seconds from 1970 to 2000. */ struct saved_params { - /* param 0 */ + unsigned int valid; s64 rtc_diff; unsigned int av_multi_out; - unsigned int ctrl_button; - /* param 1 */ - u8 static_ip_addr[4]; - u8 network_mask[4]; - u8 default_gateway[4]; - /* param 2 */ - u8 dns_primary[4]; - u8 dns_secondary[4]; } 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) { - pr_debug("%s:%d: h.magic_num: '%s'\n", func, line, + pr_debug("%s:%d: h.magic_num: '%s'\n", func, line, h->magic_num); - pr_debug("%s:%d: h.hdr_version: %u\n", func, line, + pr_debug("%s:%d: h.hdr_version: %u\n", func, line, h->hdr_version); - pr_debug("%s:%d: h.os_area_offset: %u\n", func, line, - h->os_area_offset); + pr_debug("%s:%d: h.db_area_offset: %u\n", func, line, + h->db_area_offset); pr_debug("%s:%d: h.ldr_area_offset: %u\n", func, line, h->ldr_area_offset); - pr_debug("%s:%d: h.ldr_format: %u\n", func, line, + pr_debug("%s:%d: h.ldr_format: %u\n", func, line, h->ldr_format); - pr_debug("%s:%d: h.ldr_size: %xh\n", func, line, + pr_debug("%s:%d: h.ldr_size: %xh\n", func, line, h->ldr_size); } @@ -176,7 +309,7 @@ static void _dump_params(const struct os_area_params *p, const char *func, p->dns_secondary[2], p->dns_secondary[3]); } -static int __init verify_header(const struct os_area_header *header) +static int verify_header(const struct os_area_header *header) { if (memcmp(header->magic_num, "cell_ext_os_area", 16)) { pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); @@ -188,7 +321,7 @@ static int __init verify_header(const struct os_area_header *header) return -1; } - if (header->os_area_offset > header->ldr_area_offset) { + if (header->db_area_offset > header->ldr_area_offset) { pr_debug("%s:%d offsets failed\n", __func__, __LINE__); return -1; } @@ -196,58 +329,477 @@ static int __init verify_header(const struct os_area_header *header) return 0; } -int __init ps3_os_area_init(void) +static int db_verify(const struct os_area_db *db) +{ + if (db->magic_num != OS_AREA_DB_MAGIC_NUM) { + pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); + return -1; + } + + if (db->version != 1) { + pr_debug("%s:%d version failed\n", __func__, __LINE__); + return -1; + } + + return 0; +} + +struct db_index { + uint8_t owner:5; + uint8_t key:3; +}; + +struct db_iterator { + const struct os_area_db *db; + struct os_area_db_id match_id; + struct db_index *idx; + struct db_index *last_idx; + union { + uint64_t *value_64; + uint32_t *value_32; + uint16_t *value_16; + }; +}; + +static unsigned int db_align_up(unsigned int val, unsigned int size) +{ + return (val + (size - 1)) & (~(size - 1)); +} + +/** + * db_for_each_64 - Iterator for 64 bit entries. + * + * A NULL value for id can be used to match all entries. + * OS_AREA_DB_OWNER_ANY and OS_AREA_DB_KEY_ANY can be used to match all. + */ + +static int db_for_each_64(const struct os_area_db *db, + const struct os_area_db_id *match_id, struct db_iterator *i) +{ +next: + if (!i->db) { + i->db = db; + i->match_id = match_id ? *match_id : os_area_db_id_any; + i->idx = (void *)db + db->index_64; + i->last_idx = i->idx + db->count_64; + i->value_64 = (void *)db + db->index_64 + + db_align_up(db->count_64, 8); + } else { + i->idx++; + i->value_64++; + } + + if (i->idx >= i->last_idx) { + pr_debug("%s:%d: reached end\n", __func__, __LINE__); + return 0; + } + + if (i->match_id.owner != OS_AREA_DB_OWNER_ANY + && i->match_id.owner != (int)i->idx->owner) + goto next; + if (i->match_id.key != OS_AREA_DB_KEY_ANY + && i->match_id.key != (int)i->idx->key) + goto next; + + return 1; +} + +static int db_delete_64(struct os_area_db *db, const struct os_area_db_id *id) +{ + struct db_iterator i; + + for (i.db = NULL; db_for_each_64(db, id, &i); ) { + + pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__, + i.idx->owner, i.idx->key, + (unsigned long long)*i.value_64); + + i.idx->owner = 0; + i.idx->key = 0; + *i.value_64 = 0; + } + return 0; +} + +static int db_set_64(struct os_area_db *db, const struct os_area_db_id *id, + uint64_t value) +{ + struct db_iterator i; + + pr_debug("%s:%d: (%d:%d) <= %llxh\n", __func__, __LINE__, + id->owner, id->key, (unsigned long long)value); + + if (!id->owner || id->owner == OS_AREA_DB_OWNER_ANY + || id->key == OS_AREA_DB_KEY_ANY) { + pr_debug("%s:%d: bad id: (%d:%d)\n", __func__, + __LINE__, id->owner, id->key); + return -1; + } + + db_delete_64(db, id); + + i.db = NULL; + if (db_for_each_64(db, &os_area_db_id_empty, &i)) { + + pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__, + i.idx->owner, i.idx->key, + (unsigned long long)*i.value_64); + + i.idx->owner = id->owner; + i.idx->key = id->key; + *i.value_64 = value; + + pr_debug("%s:%d: set (%d:%d) <= %llxh\n", __func__, __LINE__, + i.idx->owner, i.idx->key, + (unsigned long long)*i.value_64); + return 0; + } + pr_debug("%s:%d: database full.\n", + __func__, __LINE__); + return -1; +} + +static int db_get_64(const struct os_area_db *db, + const struct os_area_db_id *id, uint64_t *value) +{ + struct db_iterator i; + + i.db = NULL; + if (db_for_each_64(db, id, &i)) { + *value = *i.value_64; + pr_debug("%s:%d: found %lld\n", __func__, __LINE__, + (long long int)*i.value_64); + return 0; + } + pr_debug("%s:%d: not found\n", __func__, __LINE__); + return -1; +} + +static int db_get_rtc_diff(const struct os_area_db *db, int64_t *rtc_diff) +{ + return db_get_64(db, &os_area_db_id_rtc_diff, (uint64_t*)rtc_diff); +} + +#define dump_db(a) _dump_db(a, __func__, __LINE__) +static void _dump_db(const struct os_area_db *db, const char *func, + int line) +{ + pr_debug("%s:%d: db.magic_num: '%s'\n", func, line, + (const char*)&db->magic_num); + pr_debug("%s:%d: db.version: %u\n", func, line, + db->version); + pr_debug("%s:%d: db.index_64: %u\n", func, line, + db->index_64); + pr_debug("%s:%d: db.count_64: %u\n", func, line, + db->count_64); + pr_debug("%s:%d: db.index_32: %u\n", func, line, + db->index_32); + pr_debug("%s:%d: db.count_32: %u\n", func, line, + db->count_32); + pr_debug("%s:%d: db.index_16: %u\n", func, line, + db->index_16); + pr_debug("%s:%d: db.count_16: %u\n", func, line, + db->count_16); +} + +static void os_area_db_init(struct os_area_db *db) +{ + enum { + HEADER_SIZE = offsetof(struct os_area_db, _db_data), + INDEX_64_COUNT = 64, + VALUES_64_COUNT = 57, + INDEX_32_COUNT = 64, + VALUES_32_COUNT = 57, + INDEX_16_COUNT = 64, + VALUES_16_COUNT = 57, + }; + + memset(db, 0, sizeof(struct os_area_db)); + + db->magic_num = OS_AREA_DB_MAGIC_NUM; + db->version = 1; + db->index_64 = HEADER_SIZE; + db->count_64 = VALUES_64_COUNT; + db->index_32 = HEADER_SIZE + + INDEX_64_COUNT * sizeof(struct db_index) + + VALUES_64_COUNT * sizeof(u64); + db->count_32 = VALUES_32_COUNT; + db->index_16 = HEADER_SIZE + + INDEX_64_COUNT * sizeof(struct db_index) + + VALUES_64_COUNT * sizeof(u64) + + INDEX_32_COUNT * sizeof(struct db_index) + + VALUES_32_COUNT * sizeof(u32); + db->count_16 = VALUES_16_COUNT; + + /* Rules to check db layout. */ + + BUILD_BUG_ON(sizeof(struct db_index) != 1); + BUILD_BUG_ON(sizeof(struct os_area_db) != 2 * OS_AREA_SEGMENT_SIZE); + BUILD_BUG_ON(INDEX_64_COUNT & 0x7); + BUILD_BUG_ON(VALUES_64_COUNT > INDEX_64_COUNT); + BUILD_BUG_ON(INDEX_32_COUNT & 0x7); + BUILD_BUG_ON(VALUES_32_COUNT > INDEX_32_COUNT); + BUILD_BUG_ON(INDEX_16_COUNT & 0x7); + BUILD_BUG_ON(VALUES_16_COUNT > INDEX_16_COUNT); + BUILD_BUG_ON(HEADER_SIZE + + INDEX_64_COUNT * sizeof(struct db_index) + + VALUES_64_COUNT * sizeof(u64) + + INDEX_32_COUNT * sizeof(struct db_index) + + VALUES_32_COUNT * sizeof(u32) + + INDEX_16_COUNT * sizeof(struct db_index) + + VALUES_16_COUNT * sizeof(u16) + > sizeof(struct os_area_db)); +} + +/** + * update_flash_db - Helper for os_area_queue_work_handler. + * + */ + +static void update_flash_db(void) +{ + int result; + int file; + off_t offset; + ssize_t count; + static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE; + const struct os_area_header *header; + struct os_area_db* db; + + /* Read in header and db from flash. */ + + file = sys_open("/dev/ps3flash", O_RDWR, 0); + + if (file < 0) { + pr_debug("%s:%d sys_open failed\n", __func__, __LINE__); + goto fail_open; + } + + header = kmalloc(buf_len, GFP_KERNEL); + + if (!header) { + pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__); + goto fail_malloc; + } + + offset = sys_lseek(file, 0, SEEK_SET); + + if (offset != 0) { + pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); + goto fail_header_seek; + } + + count = sys_read(file, (char __user *)header, buf_len); + + result = count < OS_AREA_SEGMENT_SIZE || verify_header(header) + || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE; + + if (result) { + pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); + dump_header(header); + goto fail_header; + } + + /* Now got a good db offset and some maybe good db data. */ + + db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE; + + result = db_verify(db); + + if (result) { + printk(KERN_NOTICE "%s:%d: Verify of flash database failed, " + "formatting.\n", __func__, __LINE__); + dump_db(db); + os_area_db_init(db); + } + + /* Now got good db data. */ + + db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff); + + offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE, + SEEK_SET); + + if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) { + pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); + goto fail_db_seek; + } + + count = sys_write(file, (const char __user *)db, + sizeof(struct os_area_db)); + + if (count < sizeof(struct os_area_db)) { + pr_debug("%s:%d sys_write failed\n", __func__, __LINE__); + } + +fail_db_seek: +fail_header: +fail_header_seek: + kfree(header); +fail_malloc: + sys_close(file); +fail_open: + return; +} + +/** + * os_area_queue_work_handler - Asynchronous write handler. + * + * An asynchronous write for flash memory and the device tree. Do not + * call directly, use os_area_queue_work(). + */ + +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__); + +#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) + update_flash_db(); +#else + printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n", + __func__, __LINE__); +#endif + pr_debug(" <- %s:%d\n", __func__, __LINE__); +} + +static void os_area_queue_work(void) +{ + static DECLARE_WORK(q, os_area_queue_work_handler); + + wmb(); + schedule_work(&q); +} + +/** + * ps3_os_area_save_params - Copy data from os area mirror to @saved_params. + * + * For the convenience of the guest the HV makes a copy of the os area in + * flash to a high address in the boot memory region and then puts that RAM + * address and the byte count into the repository for retrieval by the guest. + * We copy the data we want into a static variable and allow the memory setup + * by the HV to be claimed by the lmb manager. + * + * The os area mirror will not be available to a second stage kernel, and + * the header verify will fail. In this case, the saved_params values will + * be set from flash memory or the passed in device tree in ps3_os_area_init(). + */ + +void __init ps3_os_area_save_params(void) { int result; u64 lpar_addr; unsigned int size; struct os_area_header *header; struct os_area_params *params; + struct os_area_db *db; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); result = ps3_repository_read_boot_dat_info(&lpar_addr, &size); if (result) { pr_debug("%s:%d ps3_repository_read_boot_dat_info failed\n", __func__, __LINE__); - return result; + return; } header = (struct os_area_header *)__va(lpar_addr); - params = (struct os_area_params *)__va(lpar_addr + OS_AREA_SEGMENT_SIZE); + params = (struct os_area_params *)__va(lpar_addr + + OS_AREA_SEGMENT_SIZE); 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 -EIO; + return; } + db = (struct os_area_db *)__va(lpar_addr + + header->db_area_offset * OS_AREA_SEGMENT_SIZE); + dump_header(header); dump_params(params); + dump_db(db); - saved_params.rtc_diff = params->rtc_diff; + result = db_verify(db) || db_get_rtc_diff(db, &saved_params.rtc_diff); + if (result) + saved_params.rtc_diff = params->rtc_diff ? params->rtc_diff + : SECONDS_FROM_1970_TO_2000; saved_params.av_multi_out = params->av_multi_out; - saved_params.ctrl_button = params->ctrl_button; - memcpy(saved_params.static_ip_addr, params->static_ip_addr, 4); - memcpy(saved_params.network_mask, params->network_mask, 4); - memcpy(saved_params.default_gateway, params->default_gateway, 4); - memcpy(saved_params.dns_secondary, params->dns_secondary, 4); + saved_params.valid = 1; + + memset(header, 0, sizeof(*header)); - return result; + pr_debug(" <- %s:%d\n", __func__, __LINE__); } /** - * ps3_os_area_rtc_diff - Returns the ps3 rtc diff value. + * 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; +} + +/** + * ps3_os_area_set_rtc_diff - Set the rtc diff value. * - * The ps3 rtc maintains a value that approximates seconds since - * 2000-01-01 00:00:00 UTC. Returns the exact number of seconds from 1970 to - * 2000 when saved_params.rtc_diff has not been properly set up. + * An asynchronous write is needed to support writing updates from + * the timer interrupt context. */ -u64 ps3_os_area_rtc_diff(void) +void ps3_os_area_set_rtc_diff(u64 rtc_diff) { - return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL; + if (saved_params.rtc_diff != rtc_diff) { + saved_params.rtc_diff = rtc_diff; + os_area_queue_work(); + } } /** diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 2eb8f92704b4..01f0c9506e11 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -47,7 +47,11 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); /* smp */ void smp_init_ps3(void); +#ifdef CONFIG_SMP void ps3_smp_cleanup_cpu(int cpu); +#else +static inline void ps3_smp_cleanup_cpu(int cpu) { } +#endif /* time */ @@ -58,8 +62,10 @@ int ps3_set_rtc_time(struct rtc_time *time); /* os area */ -int __init ps3_os_area_init(void); -u64 ps3_os_area_rtc_diff(void); +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); /* spu */ diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 609945dbe394..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) prealloc_ps3flash_bounce_buffer(); ppc_md.power_save = ps3_power_save; + ps3_os_area_init(); DBG(" <- %s:%d\n", __func__, __LINE__); } @@ -228,7 +229,7 @@ static int __init ps3_probe(void) 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); diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c index 802a9ccacb5e..d0daf7d6d3b2 100644 --- a/arch/powerpc/platforms/ps3/time.c +++ b/arch/powerpc/platforms/ps3/time.c @@ -50,12 +50,6 @@ static void __maybe_unused _dump_time(int time, const char *func, _dump_tm(&tm, func, line); } -/** - * rtc_shift - Difference in seconds between 1970 and the ps3 rtc value. - */ - -static s64 rtc_shift; - void __init ps3_calibrate_decr(void) { int result; @@ -66,8 +60,6 @@ void __init ps3_calibrate_decr(void) ppc_tb_freq = tmp; ppc_proc_freq = ppc_tb_freq * 40; - - rtc_shift = ps3_os_area_rtc_diff(); } static u64 read_rtc(void) @@ -87,18 +79,18 @@ int ps3_set_rtc_time(struct rtc_time *tm) u64 now = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - rtc_shift = now - read_rtc(); + ps3_os_area_set_rtc_diff(now - read_rtc()); return 0; } void ps3_get_rtc_time(struct rtc_time *tm) { - to_tm(read_rtc() + rtc_shift, tm); + to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm); tm->tm_year -= 1900; tm->tm_mon -= 1; } unsigned long __init ps3_get_boot_time(void) { - return read_rtc() + rtc_shift; + return read_rtc() + ps3_os_area_get_rtc_diff(); } diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index b8770395013d..22322b35a0ff 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -169,6 +169,8 @@ static void rtas_slot_error_detail(struct pci_dn *pdn, int severity, */ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) { + struct device_node *dn; + struct pci_dev *dev = pdn->pcidev; u32 cfg; int cap, i; int n = 0; @@ -184,6 +186,17 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); + /* Gather bridge-specific registers */ + if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { + rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg); + n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); + printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); + + rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg); + n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); + printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); + } + /* Dump out the PCI-X command and status regs */ cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_PCIX); if (cap) { @@ -209,7 +222,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); } - cap = pci_find_ext_capability(pdn->pcidev,PCI_EXT_CAP_ID_ERR); + cap = pci_find_ext_capability(pdn->pcidev, PCI_EXT_CAP_ID_ERR); if (cap) { n += scnprintf(buf+n, len-n, "pci-e AER:\n"); printk(KERN_WARNING @@ -222,6 +235,18 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) } } } + + /* Gather status on devices under the bridge */ + if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { + dn = pdn->node->child; + while (dn) { + pdn = PCI_DN(dn); + if (pdn) + n += gather_pci_data(pdn, buf+n, len-n); + dn = dn->sibling; + } + } + return n; } @@ -750,12 +775,12 @@ int rtas_set_slot_reset(struct pci_dn *pdn) return 0; if (rc < 0) { - printk (KERN_ERR "EEH: unrecoverable slot failure %s\n", - pdn->node->full_name); + printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", + pdn->node->full_name); return -1; } - printk (KERN_ERR "EEH: bus reset %d failed on slot %s\n", - i+1, pdn->node->full_name); + printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", + i+1, pdn->node->full_name, rc); } return -1; @@ -930,7 +955,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) pdn->eeh_freeze_count = 0; pdn->eeh_false_positives = 0; - if (status && strcmp(status, "ok") != 0) + if (status && strncmp(status, "ok", 2) != 0) return NULL; /* ignore devices with bad status */ /* Ignore bad nodes. */ @@ -944,23 +969,6 @@ static void *early_enable_eeh(struct device_node *dn, void *data) } pdn->class_code = *class_code; - /* - * Now decide if we are going to "Disable" EEH checking - * for this device. We still run with the EEH hardware active, - * but we won't be checking for ff's. This means a driver - * could return bad data (very bad!), an interrupt handler could - * hang waiting on status bits that won't change, etc. - * But there are a few cases like display devices that make sense. - */ - enable = 1; /* i.e. we will do checking */ -#if 0 - if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY) - enable = 0; -#endif - - if (!enable) - pdn->eeh_mode |= EEH_MODE_NOCHECK; - /* Ok... see if this device supports EEH. Some do, some don't, * and the only way to find out is to check each and every one. */ regs = of_get_property(dn, "reg", NULL); diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index e49c815eae23..1e83fcd0df31 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -225,6 +225,10 @@ void pci_addr_cache_insert_device(struct pci_dev *dev) { unsigned long flags; + /* Ignore PCI bridges */ + if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) + return; + spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); __pci_addr_cache_insert_device(dev); spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); @@ -285,16 +289,13 @@ void __init pci_addr_cache_build(void) spin_lock_init(&pci_io_addr_cache_root.piar_lock); while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - /* Ignore PCI bridges */ - if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) - continue; pci_addr_cache_insert_device(dev); dn = pci_device_to_OF_node(dev); if (!dn) continue; - pci_dev_get (dev); /* matching put is in eeh_remove_device() */ + pci_dev_get(dev); /* matching put is in eeh_remove_device() */ PCI_DN(dn)->pcidev = dev; eeh_sysfs_add_device(dev); diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 9711eb0d5496..fc48b96c81bf 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -252,6 +252,20 @@ static struct notifier_block pseries_smp_nb = { static int __init pseries_cpu_hotplug_init(void) { + struct device_node *np; + const char *typep; + + for_each_node_by_name(np, "interrupt-controller") { + typep = of_get_property(np, "compatible", NULL); + if (strstr(typep, "open-pic")) { + of_node_put(np); + + printk(KERN_INFO "CPU Hotplug not supported on " + "systems using MPIC\n"); + return 0; + } + } + rtas_stop_self_args.token = rtas_token("stop-self"); qcss_tok = rtas_token("query-cpu-stopped-state"); diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 8cc6eeeaae2f..9a455d46379d 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -35,7 +35,6 @@ #include <asm/tlbflush.h> #include <asm/tlb.h> #include <asm/prom.h> -#include <asm/abs_addr.h> #include <asm/cputable.h> #include <asm/udbg.h> #include <asm/smp.h> @@ -285,7 +284,7 @@ void vpa_init(int cpu) static long pSeries_lpar_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long pa, unsigned long rflags, unsigned long vflags, - int psize) + int psize, int ssize) { unsigned long lpar_rc; unsigned long flags; @@ -297,7 +296,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, "rflags=%lx, vflags=%lx, psize=%d)\n", hpte_group, va, pa, rflags, vflags, psize); - hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; + hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) @@ -393,6 +392,22 @@ static void pSeries_lpar_hptab_clear(void) } /* + * This computes the AVPN and B fields of the first dword of a HPTE, + * for use when we want to match an existing PTE. The bottom 7 bits + * of the returned value are zero. + */ +static inline unsigned long hpte_encode_avpn(unsigned long va, int psize, + int ssize) +{ + unsigned long v; + + v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm); + v <<= HPTE_V_AVPN_SHIFT; + v |= ((unsigned long) ssize) << HPTE_V_SSIZE_SHIFT; + return v; +} + +/* * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and * the low 3 bits of flags happen to line up. So no transform is needed. * We can probably optimize here and assume the high bits of newpp are @@ -401,18 +416,18 @@ static void pSeries_lpar_hptab_clear(void) static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long lpar_rc; unsigned long flags = (newpp & 7) | H_AVPN; unsigned long want_v; - want_v = hpte_encode_v(va, psize); + want_v = hpte_encode_avpn(va, psize, ssize); DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ", - want_v & HPTE_V_AVPN, slot, flags, psize); + want_v, slot, flags, psize); - lpar_rc = plpar_pte_protect(flags, slot, want_v & HPTE_V_AVPN); + lpar_rc = plpar_pte_protect(flags, slot, want_v); if (lpar_rc == H_NOT_FOUND) { DBG_LOW("not found !\n"); @@ -445,32 +460,25 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) return dword0; } -static long pSeries_lpar_hpte_find(unsigned long va, int psize) +static long pSeries_lpar_hpte_find(unsigned long va, int psize, int ssize) { unsigned long hash; - unsigned long i, j; + unsigned long i; long slot; unsigned long want_v, hpte_v; - hash = hpt_hash(va, mmu_psize_defs[psize].shift); - want_v = hpte_encode_v(va, psize); - - for (j = 0; j < 2; j++) { - slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; - for (i = 0; i < HPTES_PER_GROUP; i++) { - hpte_v = pSeries_lpar_hpte_getword0(slot); - - if (HPTE_V_COMPARE(hpte_v, want_v) - && (hpte_v & HPTE_V_VALID) - && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { - /* HPTE matches */ - if (j) - slot = -slot; - return slot; - } - ++slot; - } - hash = ~hash; + hash = hpt_hash(va, mmu_psize_defs[psize].shift, ssize); + want_v = hpte_encode_avpn(va, psize, ssize); + + /* Bolted entries are always in the primary group */ + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; + for (i = 0; i < HPTES_PER_GROUP; i++) { + hpte_v = pSeries_lpar_hpte_getword0(slot); + + if (HPTE_V_COMPARE(hpte_v, want_v) && (hpte_v & HPTE_V_VALID)) + /* HPTE matches */ + return slot; + ++slot; } return -1; @@ -478,14 +486,14 @@ static long pSeries_lpar_hpte_find(unsigned long va, int psize) static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize) + int psize, int ssize) { unsigned long lpar_rc, slot, vsid, va, flags; - vsid = get_kernel_vsid(ea); - va = (vsid << 28) | (ea & 0x0fffffff); + vsid = get_kernel_vsid(ea, ssize); + va = hpt_va(ea, vsid, ssize); - slot = pSeries_lpar_hpte_find(va, psize); + slot = pSeries_lpar_hpte_find(va, psize, ssize); BUG_ON(slot == -1); flags = newpp & 7; @@ -495,7 +503,7 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, } static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int local) + int psize, int ssize, int local) { unsigned long want_v; unsigned long lpar_rc; @@ -504,9 +512,8 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d", slot, va, psize, local); - want_v = hpte_encode_v(va, psize); - lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v & HPTE_V_AVPN, - &dummy1, &dummy2); + want_v = hpte_encode_avpn(va, psize, ssize); + lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v, &dummy1, &dummy2); if (lpar_rc == H_NOT_FOUND) return; @@ -534,18 +541,19 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) unsigned long va; unsigned long hash, index, shift, hidx, slot; real_pte_t pte; - int psize; + int psize, ssize; if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); psize = batch->psize; + ssize = batch->ssize; pix = 0; for (i = 0; i < number; i++) { va = batch->vaddr[i]; pte = batch->pte[i]; pte_iterate_hashed_subpages(pte, psize, va, index, shift) { - hash = hpt_hash(va, shift); + hash = hpt_hash(va, shift, ssize); hidx = __rpte_to_hidx(pte, index); if (hidx & _PTEIDX_SECONDARY) hash = ~hash; @@ -553,11 +561,11 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) slot += hidx & _PTEIDX_GROUP_IX; if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { pSeries_lpar_hpte_invalidate(slot, va, psize, - local); + ssize, local); } else { param[pix] = HBR_REQUEST | HBR_AVPN | slot; - param[pix+1] = hpte_encode_v(va, psize) & - HPTE_V_AVPN; + param[pix+1] = hpte_encode_avpn(va, psize, + ssize); pix += 2; if (pix == 8) { rc = plpar_hcall9(H_BULK_REMOVE, param, diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 6063ea2f67ad..2793a1b100e6 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -70,11 +70,15 @@ static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs) seq_num = rtas_ret[1]; } while (rtas_busy_delay(rc)); - if (rc == 0) /* Success */ - rc = rtas_ret[0]; + /* + * If the RTAS call succeeded, check the number of irqs is actually + * what we asked for. If not, return an error. + */ + if (rc == 0 && rtas_ret[0] != num_irqs) + rc = -ENOSPC; - pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d) = (%d)\n", - func, num_irqs, rc); + pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d), got %d rc = %d\n", + func, num_irqs, rtas_ret[0], rc); return rc; } @@ -87,7 +91,7 @@ static void rtas_disable_msi(struct pci_dev *pdev) if (!pdn) return; - if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0) + if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0)) pr_debug("rtas_msi: Setting MSIs to 0 failed!\n"); } @@ -180,38 +184,31 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) if (type == PCI_CAP_ID_MSI) { rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); - if (rc != nvec) { + if (rc) { pr_debug("rtas_msi: trying the old firmware call.\n"); rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec); } } else rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); - if (rc != nvec) { + if (rc) { pr_debug("rtas_msi: rtas_change_msi() failed\n"); - - /* - * In case of an error it's not clear whether the device is - * left with MSI enabled or not, so we explicitly disable. - */ - goto out_free; + return rc; } i = 0; list_for_each_entry(entry, &pdev->msi_list, list) { hwirq = rtas_query_irq_number(pdn, i); if (hwirq < 0) { - rc = hwirq; pr_debug("rtas_msi: error (%d) getting hwirq\n", rc); - goto out_free; + return hwirq; } virq = irq_create_mapping(NULL, hwirq); if (virq == NO_IRQ) { pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq); - rc = -ENOSPC; - goto out_free; + return -ENOSPC; } dev_dbg(&pdev->dev, "rtas_msi: allocated virq %d\n", virq); @@ -220,10 +217,6 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) } return 0; - - out_free: - rtas_teardown_msi_irqs(pdev); - return rc; } static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev) diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index 9797b10b2935..73401c820110 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -44,15 +44,20 @@ static unsigned long rtas_log_start; static unsigned long rtas_log_size; static int surveillance_timeout = -1; -static unsigned int rtas_event_scan_rate; static unsigned int rtas_error_log_max; static unsigned int rtas_error_log_buffer_max; -static int full_rtas_msgs = 0; +/* RTAS service tokens */ +static unsigned int event_scan; +static unsigned int rtas_event_scan_rate; -extern int no_logging; +static int full_rtas_msgs = 0; -volatile int error_log_cnt = 0; +/* Stop logging to nvram after first fatal error */ +static int logging_enabled; /* Until we initialize everything, + * make sure we don't try logging + * anything */ +static int error_log_cnt; /* * Since we use 32 bit RTAS, the physical address of this must be below @@ -61,8 +66,6 @@ volatile int error_log_cnt = 0; */ static unsigned char logdata[RTAS_ERROR_LOG_MAX]; -static int get_eventscan_parms(void); - static char *rtas_type[] = { "Unknown", "Retry", "TCE Error", "Internal Device Failure", "Timeout", "Data Parity", "Address Parity", "Cache Parity", @@ -166,9 +169,9 @@ static int log_rtas_len(char * buf) len += err->extended_log_length; } - if (rtas_error_log_max == 0) { - get_eventscan_parms(); - } + if (rtas_error_log_max == 0) + rtas_error_log_max = rtas_get_error_log_max(); + if (len > rtas_error_log_max) len = rtas_error_log_max; @@ -215,8 +218,8 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) } /* Write error to NVRAM */ - if (!no_logging && !(err_type & ERR_FLAG_BOOT)) - nvram_write_error_log(buf, len, err_type); + if (logging_enabled && !(err_type & ERR_FLAG_BOOT)) + nvram_write_error_log(buf, len, err_type, error_log_cnt); /* * rtas errors can occur during boot, and we do want to capture @@ -227,8 +230,8 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) printk_log_rtas(buf, len); /* Check to see if we need to or have stopped logging */ - if (fatal || no_logging) { - no_logging = 1; + if (fatal || !logging_enabled) { + logging_enabled = 0; spin_unlock_irqrestore(&rtasd_log_lock, s); return; } @@ -300,7 +303,7 @@ static ssize_t rtas_log_read(struct file * file, char __user * buf, spin_lock_irqsave(&rtasd_log_lock, s); /* if it's 0, then we know we got the last one (the one in NVRAM) */ - if (rtas_log_size == 0 && !no_logging) + if (rtas_log_size == 0 && logging_enabled) nvram_clear_error_log(); spin_unlock_irqrestore(&rtasd_log_lock, s); @@ -356,32 +359,7 @@ static int enable_surveillance(int timeout) return -1; } -static int get_eventscan_parms(void) -{ - struct device_node *node; - const int *ip; - - node = of_find_node_by_path("/rtas"); - - ip = of_get_property(node, "rtas-event-scan-rate", NULL); - if (ip == NULL) { - printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n"); - of_node_put(node); - return -1; - } - rtas_event_scan_rate = *ip; - DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate); - - /* Make room for the sequence number */ - rtas_error_log_max = rtas_get_error_log_max(); - rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); - - of_node_put(node); - - return 0; -} - -static void do_event_scan(int event_scan) +static void do_event_scan(void) { int error; do { @@ -408,7 +386,7 @@ static void do_event_scan_all_cpus(long delay) cpu = first_cpu(cpu_online_map); for (;;) { set_cpus_allowed(current, cpumask_of_cpu(cpu)); - do_event_scan(rtas_token("event-scan")); + do_event_scan(); set_cpus_allowed(current, CPU_MASK_ALL); /* Drop hotplug lock, and sleep for the specified delay */ @@ -426,31 +404,19 @@ static void do_event_scan_all_cpus(long delay) static int rtasd(void *unused) { unsigned int err_type; - int event_scan = rtas_token("event-scan"); int rc; daemonize("rtasd"); - if (event_scan == RTAS_UNKNOWN_SERVICE || get_eventscan_parms() == -1) - goto error; - - rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); - if (!rtas_log_buf) { - printk(KERN_ERR "rtasd: no memory\n"); - goto error; - } - printk(KERN_DEBUG "RTAS daemon started\n"); - DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate)); /* See if we have any error stored in NVRAM */ memset(logdata, 0, rtas_error_log_max); - - rc = nvram_read_error_log(logdata, rtas_error_log_max, &err_type); - + rc = nvram_read_error_log(logdata, rtas_error_log_max, + &err_type, &error_log_cnt); /* We can use rtas_log_buf now */ - no_logging = 0; + logging_enabled = 1; if (!rc) { if (err_type != ERR_FLAG_ALREADY_LOGGED) { @@ -473,8 +439,6 @@ static int rtasd(void *unused) for (;;) do_event_scan_all_cpus(30000/rtas_event_scan_rate); -error: - /* Should delete proc entries */ return -EINVAL; } @@ -486,11 +450,28 @@ static int __init rtas_init(void) return 0; /* No RTAS */ - if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { + event_scan = rtas_token("event-scan"); + if (event_scan == RTAS_UNKNOWN_SERVICE) { printk(KERN_DEBUG "rtasd: no event-scan on system\n"); return -ENODEV; } + rtas_event_scan_rate = rtas_token("rtas-event-scan-rate"); + if (rtas_event_scan_rate == RTAS_UNKNOWN_SERVICE) { + printk(KERN_ERR "rtasd: no rtas-event-scan-rate on system\n"); + return -ENODEV; + } + + /* Make room for the sequence number */ + rtas_error_log_max = rtas_get_error_log_max(); + rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); + + rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); + if (!rtas_log_buf) { + printk(KERN_ERR "rtasd: no memory\n"); + return -ENOMEM; + } + entry = create_proc_entry("ppc64/rtas/error_log", S_IRUSR, NULL); if (entry) entry->proc_fops = &proc_rtas_log_operations; diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index f0b7146a110f..fdb9b1c8f977 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -257,11 +257,6 @@ static void __init pSeries_setup_arch(void) /* init to some ~sane value until calibrate_delay() runs */ loops_per_jiffy = 50000000; - if (ROOT_DEV == 0) { - printk("No ramdisk, default root is /dev/sda2\n"); - ROOT_DEV = Root_SDA2; - } - fwnmi_init(); /* Find and initialize PCI host bridges */ diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index f0b5ff17d860..66e7d68ffeb1 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -540,7 +540,7 @@ static void __init xics_init_host(void) ops = &xics_host_lpar_ops; else ops = &xics_host_direct_ops; - xics_host = irq_alloc_host(IRQ_HOST_MAP_TREE, 0, ops, + xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, ops, XICS_IRQ_SPURIOUS); BUG_ON(xics_host == NULL); irq_set_default_host(xics_host); |