aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/40x/Kconfig (renamed from arch/powerpc/platforms/4xx/Kconfig)134
-rw-r--r--arch/powerpc/platforms/40x/Makefile3
-rw-r--r--arch/powerpc/platforms/40x/kilauea.c58
-rw-r--r--arch/powerpc/platforms/40x/virtex.c45
-rw-r--r--arch/powerpc/platforms/40x/walnut.c63
-rw-r--r--arch/powerpc/platforms/44x/Kconfig32
-rw-r--r--arch/powerpc/platforms/44x/Makefile2
-rw-r--r--arch/powerpc/platforms/44x/bamboo.c61
-rw-r--r--arch/powerpc/platforms/44x/ebony.c5
-rw-r--r--arch/powerpc/platforms/44x/sequoia.c61
-rw-r--r--arch/powerpc/platforms/4xx/Makefile1
-rw-r--r--arch/powerpc/platforms/52xx/Kconfig2
-rw-r--r--arch/powerpc/platforms/52xx/Makefile3
-rw-r--r--arch/powerpc/platforms/52xx/efika.c32
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c121
-rw-r--r--arch/powerpc/platforms/52xx/lite5200_pm.c213
-rw-r--r--arch/powerpc/platforms/52xx/lite5200_sleep.S412
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_common.c38
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.c22
-rw-r--r--arch/powerpc/platforms/82xx/Kconfig24
-rw-r--r--arch/powerpc/platforms/82xx/Makefile6
-rw-r--r--arch/powerpc/platforms/82xx/m82xx_pci.h2
-rw-r--r--arch/powerpc/platforms/82xx/mpc8272_ads.c196
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx.c110
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx_ads.c641
-rw-r--r--arch/powerpc/platforms/82xx/pq2.c82
-rw-r--r--arch/powerpc/platforms/82xx/pq2.h20
-rw-r--r--arch/powerpc/platforms/82xx/pq2ads-pci-pic.c195
-rw-r--r--arch/powerpc/platforms/82xx/pq2ads.h9
-rw-r--r--arch/powerpc/platforms/82xx/pq2fads.c198
-rw-r--r--arch/powerpc/platforms/83xx/mpc8313_rdb.c4
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c6
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_rdb.c52
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_itx.c5
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_mds.c5
-rw-r--r--arch/powerpc/platforms/83xx/mpc836x_mds.c6
-rw-r--r--arch/powerpc/platforms/83xx/mpc83xx.h2
-rw-r--r--arch/powerpc/platforms/83xx/pci.c7
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig11
-rw-r--r--arch/powerpc/platforms/85xx/Makefile3
-rw-r--r--arch/powerpc/platforms/85xx/misc.c55
-rw-r--r--arch/powerpc/platforms/85xx/mpc8540_ads.h35
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx.h17
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.c187
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.h60
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.c47
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.h43
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ds.c (renamed from arch/powerpc/platforms/85xx/mpc8544_ds.c)87
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c55
-rw-r--r--arch/powerpc/platforms/86xx/Kconfig13
-rw-r--r--arch/powerpc/platforms/86xx/Makefile1
-rw-r--r--arch/powerpc/platforms/86xx/mpc8610_hpcd.c216
-rw-r--r--arch/powerpc/platforms/86xx/mpc8641_hpcn.h21
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_hpcn.c37
-rw-r--r--arch/powerpc/platforms/8xx/Kconfig28
-rw-r--r--arch/powerpc/platforms/8xx/Makefile1
-rw-r--r--arch/powerpc/platforms/8xx/ep88xc.c176
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c154
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads.h4
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads_setup.c25
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads.h42
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads_setup.c472
-rw-r--r--arch/powerpc/platforms/Kconfig32
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype14
-rw-r--r--arch/powerpc/platforms/Makefile2
-rw-r--r--arch/powerpc/platforms/cell/Makefile4
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c35
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq.c2
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c2
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c2
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c3
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.h271
-rw-r--r--arch/powerpc/platforms/cell/cbe_thermal.c2
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c4
-rw-r--r--arch/powerpc/platforms/cell/iommu.c2
-rw-r--r--arch/powerpc/platforms/cell/pervasive.c2
-rw-r--r--arch/powerpc/platforms/cell/pmu.c2
-rw-r--r--arch/powerpc/platforms/cell/ras.c2
-rw-r--r--arch/powerpc/platforms/cell/setup.c17
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c22
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c8
-rw-r--r--arch/powerpc/platforms/cell/spu_callbacks.c4
-rw-r--r--arch/powerpc/platforms/cell/spu_coredump.c79
-rw-r--r--arch/powerpc/platforms/cell/spu_manage.c4
-rw-r--r--arch/powerpc/platforms/cell/spu_syscalls.c142
-rw-r--r--arch/powerpc/platforms/cell/spufs/coredump.c236
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c251
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c15
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c49
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h7
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c31
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c48
-rw-r--r--arch/powerpc/platforms/celleb/Kconfig1
-rw-r--r--arch/powerpc/platforms/celleb/Makefile5
-rw-r--r--arch/powerpc/platforms/celleb/beat.c106
-rw-r--r--arch/powerpc/platforms/celleb/beat.h2
-rw-r--r--arch/powerpc/platforms/celleb/beat_syscall.h4
-rw-r--r--arch/powerpc/platforms/celleb/beat_wrapper.h68
-rw-r--r--arch/powerpc/platforms/celleb/htab.c152
-rw-r--r--arch/powerpc/platforms/celleb/interrupt.c9
-rw-r--r--arch/powerpc/platforms/celleb/io-workarounds.c279
-rw-r--r--arch/powerpc/platforms/celleb/pci.c98
-rw-r--r--arch/powerpc/platforms/celleb/pci.h9
-rw-r--r--arch/powerpc/platforms/celleb/scc.h2
-rw-r--r--arch/powerpc/platforms/celleb/scc_epci.c88
-rw-r--r--arch/powerpc/platforms/celleb/scc_sio.c56
-rw-r--r--arch/powerpc/platforms/celleb/setup.c27
-rw-r--r--arch/powerpc/platforms/chrp/gg2.h61
-rw-r--r--arch/powerpc/platforms/chrp/pci.c39
-rw-r--r--arch/powerpc/platforms/chrp/setup.c13
-rw-r--r--arch/powerpc/platforms/chrp/smp.c2
-rw-r--r--arch/powerpc/platforms/embedded6xx/Kconfig12
-rw-r--r--arch/powerpc/platforms/embedded6xx/holly.c14
-rw-r--r--arch/powerpc/platforms/embedded6xx/linkstation.c8
-rw-r--r--arch/powerpc/platforms/embedded6xx/ls_uart.c18
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc10x.h180
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c5
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h21
-rw-r--r--arch/powerpc/platforms/embedded6xx/prpmc2800.c8
-rw-r--r--arch/powerpc/platforms/iseries/Makefile3
-rw-r--r--arch/powerpc/platforms/iseries/dt.c17
-rw-r--r--arch/powerpc/platforms/iseries/exception.S251
-rw-r--r--arch/powerpc/platforms/iseries/exception.h58
-rw-r--r--arch/powerpc/platforms/iseries/htab.c13
-rw-r--r--arch/powerpc/platforms/iseries/iommu.c52
-rw-r--r--arch/powerpc/platforms/iseries/irq.c10
-rw-r--r--arch/powerpc/platforms/iseries/it_lp_naca.h2
-rw-r--r--arch/powerpc/platforms/iseries/mf.c23
-rw-r--r--arch/powerpc/platforms/iseries/setup.c7
-rw-r--r--arch/powerpc/platforms/iseries/vio.c553
-rw-r--r--arch/powerpc/platforms/iseries/viopath.c8
-rw-r--r--arch/powerpc/platforms/maple/pci.c21
-rw-r--r--arch/powerpc/platforms/pasemi/Kconfig1
-rw-r--r--arch/powerpc/platforms/pasemi/gpio_mdio.c4
-rw-r--r--arch/powerpc/platforms/pasemi/idle.c8
-rw-r--r--arch/powerpc/platforms/pasemi/iommu.c4
-rw-r--r--arch/powerpc/platforms/pasemi/pasemi.h4
-rw-r--r--arch/powerpc/platforms/pasemi/pci.c74
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c134
-rw-r--r--arch/powerpc/platforms/powermac/bootx_init.c1
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c1
-rw-r--r--arch/powerpc/platforms/powermac/pci.c25
-rw-r--r--arch/powerpc/platforms/powermac/pic.c2
-rw-r--r--arch/powerpc/platforms/powermac/pmac.h4
-rw-r--r--arch/powerpc/platforms/powermac/setup.c77
-rw-r--r--arch/powerpc/platforms/powermac/udbg_adb.c5
-rw-r--r--arch/powerpc/platforms/ps3/device-init.c24
-rw-r--r--arch/powerpc/platforms/ps3/htab.c14
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c9
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c646
-rw-r--r--arch/powerpc/platforms/ps3/platform.h10
-rw-r--r--arch/powerpc/platforms/ps3/setup.c3
-rw-r--r--arch/powerpc/platforms/ps3/time.c14
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c54
-rw-r--r--arch/powerpc/platforms/pseries/eeh_cache.c9
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c14
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c90
-rw-r--r--arch/powerpc/platforms/pseries/msi.c35
-rw-r--r--arch/powerpc/platforms/pseries/rtasd.c99
-rw-r--r--arch/powerpc/platforms/pseries/setup.c5
-rw-r--r--arch/powerpc/platforms/pseries/xics.c2
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), &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);