aboutsummaryrefslogtreecommitdiff
path: root/arch/ppc/platforms
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/platforms
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/ppc/platforms')
-rw-r--r--arch/ppc/platforms/4xx/Kconfig247
-rw-r--r--arch/ppc/platforms/4xx/Makefile27
-rw-r--r--arch/ppc/platforms/4xx/ash.c250
-rw-r--r--arch/ppc/platforms/4xx/ash.h83
-rw-r--r--arch/ppc/platforms/4xx/bubinga.c263
-rw-r--r--arch/ppc/platforms/4xx/bubinga.h69
-rw-r--r--arch/ppc/platforms/4xx/cpci405.c84
-rw-r--r--arch/ppc/platforms/4xx/cpci405.h37
-rw-r--r--arch/ppc/platforms/4xx/ebony.c356
-rw-r--r--arch/ppc/platforms/4xx/ebony.h91
-rw-r--r--arch/ppc/platforms/4xx/ep405.c197
-rw-r--r--arch/ppc/platforms/4xx/ep405.h54
-rw-r--r--arch/ppc/platforms/4xx/ibm405ep.c143
-rw-r--r--arch/ppc/platforms/4xx/ibm405ep.h148
-rw-r--r--arch/ppc/platforms/4xx/ibm405gp.c120
-rw-r--r--arch/ppc/platforms/4xx/ibm405gp.h151
-rw-r--r--arch/ppc/platforms/4xx/ibm405gpr.c117
-rw-r--r--arch/ppc/platforms/4xx/ibm405gpr.h151
-rw-r--r--arch/ppc/platforms/4xx/ibm440gp.c164
-rw-r--r--arch/ppc/platforms/4xx/ibm440gp.h66
-rw-r--r--arch/ppc/platforms/4xx/ibm440gx.c234
-rw-r--r--arch/ppc/platforms/4xx/ibm440gx.h74
-rw-r--r--arch/ppc/platforms/4xx/ibm440sp.c131
-rw-r--r--arch/ppc/platforms/4xx/ibm440sp.h64
-rw-r--r--arch/ppc/platforms/4xx/ibmnp405h.c172
-rw-r--r--arch/ppc/platforms/4xx/ibmnp405h.h157
-rw-r--r--arch/ppc/platforms/4xx/ibmstb4.c83
-rw-r--r--arch/ppc/platforms/4xx/ibmstb4.h238
-rw-r--r--arch/ppc/platforms/4xx/ibmstbx25.c68
-rw-r--r--arch/ppc/platforms/4xx/ibmstbx25.h261
-rw-r--r--arch/ppc/platforms/4xx/luan.c387
-rw-r--r--arch/ppc/platforms/4xx/luan.h80
-rw-r--r--arch/ppc/platforms/4xx/oak.c255
-rw-r--r--arch/ppc/platforms/4xx/oak.h96
-rw-r--r--arch/ppc/platforms/4xx/oak_setup.h50
-rw-r--r--arch/ppc/platforms/4xx/ocotea.c367
-rw-r--r--arch/ppc/platforms/4xx/ocotea.h88
-rw-r--r--arch/ppc/platforms/4xx/redwood5.c110
-rw-r--r--arch/ppc/platforms/4xx/redwood5.h54
-rw-r--r--arch/ppc/platforms/4xx/redwood6.c159
-rw-r--r--arch/ppc/platforms/4xx/redwood6.h55
-rw-r--r--arch/ppc/platforms/4xx/sycamore.c278
-rw-r--r--arch/ppc/platforms/4xx/sycamore.h67
-rw-r--r--arch/ppc/platforms/4xx/virtex-ii_pro.c60
-rw-r--r--arch/ppc/platforms/4xx/virtex-ii_pro.h99
-rw-r--r--arch/ppc/platforms/4xx/walnut.c249
-rw-r--r--arch/ppc/platforms/4xx/walnut.h72
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml300.c146
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml300.h47
-rw-r--r--arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h310
-rw-r--r--arch/ppc/platforms/83xx/Makefile4
-rw-r--r--arch/ppc/platforms/83xx/mpc834x_sys.c289
-rw-r--r--arch/ppc/platforms/83xx/mpc834x_sys.h51
-rw-r--r--arch/ppc/platforms/85xx/Kconfig76
-rw-r--r--arch/ppc/platforms/85xx/Makefile8
-rw-r--r--arch/ppc/platforms/85xx/mpc8540_ads.c218
-rw-r--r--arch/ppc/platforms/85xx/mpc8540_ads.h25
-rw-r--r--arch/ppc/platforms/85xx/mpc8555_cds.h26
-rw-r--r--arch/ppc/platforms/85xx/mpc8560_ads.c210
-rw-r--r--arch/ppc/platforms/85xx/mpc8560_ads.h27
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_ads_common.c225
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_ads_common.h50
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_cds_common.c467
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_cds_common.h80
-rw-r--r--arch/ppc/platforms/85xx/sbc8560.c227
-rw-r--r--arch/ppc/platforms/85xx/sbc8560.h49
-rw-r--r--arch/ppc/platforms/85xx/sbc85xx.c203
-rw-r--r--arch/ppc/platforms/85xx/sbc85xx.h55
-rw-r--r--arch/ppc/platforms/85xx/stx_gp3.c355
-rw-r--r--arch/ppc/platforms/85xx/stx_gp3.h74
-rw-r--r--arch/ppc/platforms/Makefile53
-rw-r--r--arch/ppc/platforms/adir.h95
-rw-r--r--arch/ppc/platforms/adir_pci.c247
-rw-r--r--arch/ppc/platforms/adir_pic.c130
-rw-r--r--arch/ppc/platforms/adir_setup.c210
-rw-r--r--arch/ppc/platforms/apus_pci.c208
-rw-r--r--arch/ppc/platforms/apus_pci.h34
-rw-r--r--arch/ppc/platforms/apus_setup.c815
-rw-r--r--arch/ppc/platforms/bseip.h38
-rw-r--r--arch/ppc/platforms/ccm.h28
-rw-r--r--arch/ppc/platforms/chestnut.c580
-rw-r--r--arch/ppc/platforms/chestnut.h129
-rw-r--r--arch/ppc/platforms/chrp_pci.c309
-rw-r--r--arch/ppc/platforms/chrp_pegasos_eth.c101
-rw-r--r--arch/ppc/platforms/chrp_setup.c615
-rw-r--r--arch/ppc/platforms/chrp_smp.c98
-rw-r--r--arch/ppc/platforms/chrp_time.c194
-rw-r--r--arch/ppc/platforms/cpci690.c491
-rw-r--r--arch/ppc/platforms/cpci690.h78
-rw-r--r--arch/ppc/platforms/est8260.h35
-rw-r--r--arch/ppc/platforms/ev64260.c651
-rw-r--r--arch/ppc/platforms/ev64260.h128
-rw-r--r--arch/ppc/platforms/fads.h57
-rw-r--r--arch/ppc/platforms/gemini.h168
-rw-r--r--arch/ppc/platforms/gemini_pci.c41
-rw-r--r--arch/ppc/platforms/gemini_prom.S93
-rw-r--r--arch/ppc/platforms/gemini_serial.h41
-rw-r--r--arch/ppc/platforms/gemini_setup.c584
-rw-r--r--arch/ppc/platforms/hdpu.c1062
-rw-r--r--arch/ppc/platforms/hdpu.h82
-rw-r--r--arch/ppc/platforms/hermes.h27
-rw-r--r--arch/ppc/platforms/ip860.h36
-rw-r--r--arch/ppc/platforms/ivms8.h56
-rw-r--r--arch/ppc/platforms/k2.c613
-rw-r--r--arch/ppc/platforms/k2.h82
-rw-r--r--arch/ppc/platforms/katana.c795
-rw-r--r--arch/ppc/platforms/katana.h255
-rw-r--r--arch/ppc/platforms/lantec.h21
-rw-r--r--arch/ppc/platforms/lite5200.c236
-rw-r--r--arch/ppc/platforms/lite5200.h23
-rw-r--r--arch/ppc/platforms/lopec.c411
-rw-r--r--arch/ppc/platforms/lopec.h39
-rw-r--r--arch/ppc/platforms/lwmon.h60
-rw-r--r--arch/ppc/platforms/mbx.h117
-rw-r--r--arch/ppc/platforms/mcpn765.c527
-rw-r--r--arch/ppc/platforms/mcpn765.h122
-rw-r--r--arch/ppc/platforms/mpc5200.c53
-rw-r--r--arch/ppc/platforms/mvme5100.c349
-rw-r--r--arch/ppc/platforms/mvme5100.h91
-rw-r--r--arch/ppc/platforms/pal4.h42
-rw-r--r--arch/ppc/platforms/pal4_pci.c77
-rw-r--r--arch/ppc/platforms/pal4_serial.h39
-rw-r--r--arch/ppc/platforms/pal4_setup.c175
-rw-r--r--arch/ppc/platforms/pcore.c352
-rw-r--r--arch/ppc/platforms/pcore.h39
-rw-r--r--arch/ppc/platforms/pcu_e.h28
-rw-r--r--arch/ppc/platforms/pmac_backlight.c202
-rw-r--r--arch/ppc/platforms/pmac_cache.S325
-rw-r--r--arch/ppc/platforms/pmac_cpufreq.c571
-rw-r--r--arch/ppc/platforms/pmac_feature.c2972
-rw-r--r--arch/ppc/platforms/pmac_low_i2c.c513
-rw-r--r--arch/ppc/platforms/pmac_nvram.c584
-rw-r--r--arch/ppc/platforms/pmac_pci.c1125
-rw-r--r--arch/ppc/platforms/pmac_pic.c689
-rw-r--r--arch/ppc/platforms/pmac_pic.h11
-rw-r--r--arch/ppc/platforms/pmac_setup.c745
-rw-r--r--arch/ppc/platforms/pmac_sleep.S390
-rw-r--r--arch/ppc/platforms/pmac_smp.c640
-rw-r--r--arch/ppc/platforms/pmac_time.c292
-rw-r--r--arch/ppc/platforms/powerpmc250.c383
-rw-r--r--arch/ppc/platforms/powerpmc250.h52
-rw-r--r--arch/ppc/platforms/pplus.c917
-rw-r--r--arch/ppc/platforms/pplus.h67
-rw-r--r--arch/ppc/platforms/pq2ads.c26
-rw-r--r--arch/ppc/platforms/pq2ads.h96
-rw-r--r--arch/ppc/platforms/prep_pci.c1336
-rw-r--r--arch/ppc/platforms/prep_setup.c1181
-rw-r--r--arch/ppc/platforms/prpmc750.c364
-rw-r--r--arch/ppc/platforms/prpmc750.h95
-rw-r--r--arch/ppc/platforms/prpmc800.c477
-rw-r--r--arch/ppc/platforms/prpmc800.h82
-rw-r--r--arch/ppc/platforms/radstone_ppc7d.c1452
-rw-r--r--arch/ppc/platforms/radstone_ppc7d.h434
-rw-r--r--arch/ppc/platforms/residual.c1034
-rw-r--r--arch/ppc/platforms/rpx8260.h81
-rw-r--r--arch/ppc/platforms/rpxclassic.h119
-rw-r--r--arch/ppc/platforms/rpxhiox.h41
-rw-r--r--arch/ppc/platforms/rpxlite.h96
-rw-r--r--arch/ppc/platforms/sandpoint.c742
-rw-r--r--arch/ppc/platforms/sandpoint.h80
-rw-r--r--arch/ppc/platforms/sbc82xx.c259
-rw-r--r--arch/ppc/platforms/sbc82xx.h36
-rw-r--r--arch/ppc/platforms/sbs8260.h28
-rw-r--r--arch/ppc/platforms/spd8xx.h92
-rw-r--r--arch/ppc/platforms/spruce.c325
-rw-r--r--arch/ppc/platforms/spruce.h71
-rw-r--r--arch/ppc/platforms/tqm8260.h23
-rw-r--r--arch/ppc/platforms/tqm8260_setup.c44
-rw-r--r--arch/ppc/platforms/tqm8xx.h179
169 files changed, 41379 insertions, 0 deletions
diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig
new file mode 100644
index 00000000000..a0612a86455
--- /dev/null
+++ b/arch/ppc/platforms/4xx/Kconfig
@@ -0,0 +1,247 @@
+config 4xx
+ bool
+ depends on 40x || 44x
+ default y
+
+menu "IBM 4xx options"
+ depends on 4xx
+
+choice
+ prompt "Machine Type"
+ depends on 40x
+ default WALNUT
+
+config ASH
+ bool "Ash"
+ help
+ This option enables support for the IBM NP405H evaluation board.
+
+config BUBINGA
+ bool "Bubinga"
+ help
+ This option enables support for the IBM 405EP evaluation board.
+
+config CPCI405
+ bool "CPCI405"
+ help
+ This option enables support for the CPCI405 board.
+
+config EP405
+ bool "EP405/EP405PC"
+ help
+ This option enables support for the EP405/EP405PC boards.
+
+config OAK
+ bool "Oak"
+ help
+ This option enables support for the IBM 403GCX evaluation board.
+
+config REDWOOD_5
+ bool "Redwood-5"
+ help
+ This option enables support for the IBM STB04 evaluation board.
+
+config REDWOOD_6
+ bool "Redwood-6"
+ help
+ This option enables support for the IBM STBx25xx evaluation board.
+
+config SYCAMORE
+ bool "Sycamore"
+ help
+ This option enables support for the IBM PPC405GPr evaluation board.
+
+config WALNUT
+ bool "Walnut"
+ help
+ This option enables support for the IBM PPC405GP evaluation board.
+
+config XILINX_ML300
+ bool "Xilinx-ML300"
+ help
+ This option enables support for the Xilinx ML300 evaluation board.
+
+endchoice
+
+choice
+ prompt "Machine Type"
+ depends on 44x
+ default EBONY
+
+config EBONY
+ bool "Ebony"
+ help
+ This option enables support for the IBM PPC440GP evaluation board.
+
+config LUAN
+ bool "Luan"
+ help
+ This option enables support for the IBM PPC440SP evaluation board.
+
+config OCOTEA
+ bool "Ocotea"
+ help
+ This option enables support for the IBM PPC440GX evaluation board.
+
+endchoice
+
+config EP405PC
+ bool "EP405PC Support"
+ depends on EP405
+
+
+# It's often necessary to know the specific 4xx processor type.
+# Fortunately, it is impled (so far) from the board type, so we
+# don't need to ask more redundant questions.
+config NP405H
+ bool
+ depends on ASH
+ default y
+
+config 440GP
+ bool
+ depends on EBONY
+ default y
+
+config 440GX
+ bool
+ depends on OCOTEA
+ default y
+
+config 440SP
+ bool
+ depends on LUAN
+ default y
+
+config 440
+ bool
+ depends on 440GP || 440SP
+ default y
+
+config 440A
+ bool
+ depends on 440GX
+ default y
+
+# All 405-based cores up until the 405GPR and 405EP have this errata.
+config IBM405_ERR77
+ bool
+ depends on 40x && !403GCX && !405GPR
+ default y
+
+# All 40x-based cores, up until the 405GPR and 405EP have this errata.
+config IBM405_ERR51
+ bool
+ depends on 40x && !405GPR
+ default y
+
+config BOOKE
+ bool
+ depends on 44x
+ default y
+
+config IBM_OCP
+ bool
+ depends on ASH || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
+ default y
+
+config XILINX_OCP
+ bool
+ depends on XILINX_ML300
+ default y
+
+config IBM_EMAC4
+ bool
+ depends on 440GX || 440SP
+ default y
+
+config BIOS_FIXUP
+ bool
+ depends on BUBINGA || EP405 || SYCAMORE || WALNUT
+ default y
+
+config 403GCX
+ bool
+ depends OAK
+ default y
+
+config 405EP
+ bool
+ depends on BUBINGA
+ default y
+
+config 405GP
+ bool
+ depends on CPCI405 || EP405 || WALNUT
+ default y
+
+config 405GPR
+ bool
+ depends on SYCAMORE
+ default y
+
+config VIRTEX_II_PRO
+ bool
+ depends on XILINX_ML300
+ default y
+
+config STB03xxx
+ bool
+ depends on REDWOOD_5 || REDWOOD_6
+ default y
+
+config EMBEDDEDBOOT
+ bool
+ depends on EP405 || XILINX_ML300
+ default y
+
+config IBM_OPENBIOS
+ bool
+ depends on ASH || BUBINGA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
+ default y
+
+config PPC4xx_DMA
+ bool "PPC4xx DMA controller support"
+ depends on 4xx
+
+config PPC4xx_EDMA
+ bool
+ depends on !STB03xxx && PPC4xx_DMA
+ default y
+
+config PPC_GEN550
+ bool
+ depends on 4xx
+ default y
+
+config PM
+ bool "Power Management support (EXPERIMENTAL)"
+ depends on 4xx && EXPERIMENTAL
+
+choice
+ prompt "TTYS0 device and default console"
+ depends on 40x
+ default UART0_TTYS0
+
+config UART0_TTYS0
+ bool "UART0"
+
+config UART0_TTYS1
+ bool "UART1"
+
+endchoice
+
+config SERIAL_SICC
+ bool "SICC Serial port support"
+ depends on STB03xxx
+
+config UART1_DFLT_CONSOLE
+ bool
+ depends on SERIAL_SICC && UART0_TTYS1
+ default y
+
+config SERIAL_SICC_CONSOLE
+ bool
+ depends on SERIAL_SICC && UART0_TTYS1
+ default y
+endmenu
diff --git a/arch/ppc/platforms/4xx/Makefile b/arch/ppc/platforms/4xx/Makefile
new file mode 100644
index 00000000000..ea470c6adbb
--- /dev/null
+++ b/arch/ppc/platforms/4xx/Makefile
@@ -0,0 +1,27 @@
+#
+# Makefile for the PowerPC 4xx linux kernel.
+
+obj-$(CONFIG_ASH) += ash.o
+obj-$(CONFIG_CPCI405) += cpci405.o
+obj-$(CONFIG_EBONY) += ebony.o
+obj-$(CONFIG_EP405) += ep405.o
+obj-$(CONFIG_BUBINGA) += bubinga.o
+obj-$(CONFIG_LUAN) += luan.o
+obj-$(CONFIG_OAK) += oak.o
+obj-$(CONFIG_OCOTEA) += ocotea.o
+obj-$(CONFIG_REDWOOD_5) += redwood5.o
+obj-$(CONFIG_REDWOOD_6) += redwood6.o
+obj-$(CONFIG_SYCAMORE) += sycamore.o
+obj-$(CONFIG_WALNUT) += walnut.o
+obj-$(CONFIG_XILINX_ML300) += xilinx_ml300.o
+
+obj-$(CONFIG_405GP) += ibm405gp.o
+obj-$(CONFIG_REDWOOD_5) += ibmstb4.o
+obj-$(CONFIG_NP405H) += ibmnp405h.o
+obj-$(CONFIG_REDWOOD_6) += ibmstbx25.o
+obj-$(CONFIG_440GP) += ibm440gp.o
+obj-$(CONFIG_440GX) += ibm440gx.o
+obj-$(CONFIG_440SP) += ibm440sp.o
+obj-$(CONFIG_405EP) += ibm405ep.o
+obj-$(CONFIG_405GPR) += ibm405gpr.o
+obj-$(CONFIG_VIRTEX_II_PRO) += virtex-ii_pro.o
diff --git a/arch/ppc/platforms/4xx/ash.c b/arch/ppc/platforms/4xx/ash.c
new file mode 100644
index 00000000000..ce291179371
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ash.c
@@ -0,0 +1,250 @@
+/*
+ * arch/ppc/platforms/4xx/ash.c
+ *
+ * Support for the IBM NP405H ash eval board
+ *
+ * Author: Armin Kuster <akuster@mvista.com>
+ *
+ * 2001-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/config.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/pci.h>
+
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/io.h>
+#include <asm/ocp.h>
+#include <asm/ibm_ocp_pci.h>
+#include <asm/todc.h>
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+void *ash_rtc_base;
+
+/* Some IRQs unique to Walnut.
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {24, 24, 24, 24}, /* IDSEL 1 - PCI slot 1 */
+ {25, 25, 25, 25}, /* IDSEL 2 - PCI slot 2 */
+ {26, 26, 26, 26}, /* IDSEL 3 - PCI slot 3 */
+ {27, 27, 27, 27}, /* IDSEL 4 - PCI slot 4 */
+ };
+
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+void __init
+ash_setup_arch(void)
+{
+ ppc4xx_setup_arch();
+
+ ibm_ocp_set_emac(0, 3);
+
+#ifdef CONFIG_DEBUG_BRINGUP
+ int i;
+ printk("\n");
+ printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
+ printk("\n");
+ printk("bi_s_version\t %s\n", bip->bi_s_version);
+ printk("bi_r_version\t %s\n", bip->bi_r_version);
+ printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,
+ bip->bi_memsize / (1024 * 1000));
+ for (i = 0; i < EMAC_NUMS; i++) {
+ printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", i,
+ bip->bi_enetaddr[i][0], bip->bi_enetaddr[i][1],
+ bip->bi_enetaddr[i][2], bip->bi_enetaddr[i][3],
+ bip->bi_enetaddr[i][4], bip->bi_enetaddr[i][5]);
+ }
+ printk("bi_pci_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
+ bip->bi_pci_enetaddr[0], bip->bi_pci_enetaddr[1],
+ bip->bi_pci_enetaddr[2], bip->bi_pci_enetaddr[3],
+ bip->bi_pci_enetaddr[4], bip->bi_pci_enetaddr[5]);
+
+ printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
+ bip->bi_intfreq, bip->bi_intfreq / 1000000);
+
+ printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
+ bip->bi_busfreq, bip->bi_busfreq / 1000000);
+ printk("bi_pci_busfreq\t 0x%8.8x\t pci bus clock:\t %dMHz\n",
+ bip->bi_pci_busfreq, bip->bi_pci_busfreq / 1000000);
+
+ printk("\n");
+#endif
+ /* RTC step for ash */
+ ash_rtc_base = (void *) ASH_RTC_VADDR;
+ TODC_INIT(TODC_TYPE_DS1743, ash_rtc_base, ash_rtc_base, ash_rtc_base,
+ 8);
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+ /*
+ * Expected PCI mapping:
+ *
+ * PLB addr PCI memory addr
+ * --------------------- ---------------------
+ * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff
+ * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff
+ *
+ * PLB addr PCI io addr
+ * --------------------- ---------------------
+ * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000
+ *
+ * The following code is simplified by assuming that the bootrom
+ * has been well behaved in following this mapping.
+ */
+
+#ifdef DEBUG
+ int i;
+
+ printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
+ printk("PCI bridge regs before fixup \n");
+ for (i = 0; i <= 2; i++) {
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+ printk(" pmm%dla\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+ printk(" pmm%dpcila\t0x%x\n", i,
+ in_le32(&(pcip->pmm[i].pcila)));
+ printk(" pmm%dpciha\t0x%x\n", i,
+ in_le32(&(pcip->pmm[i].pciha)));
+ }
+ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+ for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+ early_read_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ &bar_response);
+ DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+ hose->first_busno, PCI_SLOT(hose->first_busno),
+ PCI_FUNC(hose->first_busno), bar, bar_response);
+ }
+
+#endif
+ if (ppc_md.progress)
+ ppc_md.progress("bios_fixup(): enter", 0x800);
+
+ /* added for IBM boot rom version 1.15 bios bar changes -AK */
+
+ /* Disable region first */
+ out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+ /* PLB starting addr, PCI: 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+ /* PCI start addr, 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+ /* 512MB range of PLB to PCI */
+ out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+ /* Enable no pre-fetch, enable region */
+ out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+ (PPC405_PCI_UPPER_MEM -
+ PPC405_PCI_MEM_BASE)) | 0x01));
+
+ /* Disable region one */
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+
+ /* Disable region two */
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+
+ /* Enable PTM1 and PTM2, mapped to PLB address 0. */
+
+ out_le32((void *) &(pcip->ptm1la), 0x00000000);
+ out_le32((void *) &(pcip->ptm1ms), 0x00000001);
+ out_le32((void *) &(pcip->ptm2la), 0x00000000);
+ out_le32((void *) &(pcip->ptm2ms), 0x00000001);
+
+ /* Write zero to PTM1 BAR. */
+
+ early_write_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno),
+ PCI_BASE_ADDRESS_1,
+ 0x00000000);
+
+ /* Disable PTM2 (unused) */
+
+ out_le32((void *) &(pcip->ptm2la), 0x00000000);
+ out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+ /* end work arround */
+ if (ppc_md.progress)
+ ppc_md.progress("bios_fixup(): done", 0x800);
+
+#ifdef DEBUG
+ printk("PCI bridge regs after fixup \n");
+ for (i = 0; i <= 2; i++) {
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+ printk(" pmm%dla\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+ printk(" pmm%dpcila\t0x%x\n", i,
+ in_le32(&(pcip->pmm[i].pcila)));
+ printk(" pmm%dpciha\t0x%x\n", i,
+ in_le32(&(pcip->pmm[i].pciha)));
+ }
+ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+ for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+ early_read_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ &bar_response);
+ DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+ hose->first_busno, PCI_SLOT(hose->first_busno),
+ PCI_FUNC(hose->first_busno), bar, bar_response);
+ }
+
+
+#endif
+}
+
+void __init
+ash_map_io(void)
+{
+ ppc4xx_map_io();
+ io_block_mapping(ASH_RTC_VADDR, ASH_RTC_PADDR, ASH_RTC_SIZE, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ ppc4xx_init(r3, r4, r5, r6, r7);
+
+ ppc_md.setup_arch = ash_setup_arch;
+ ppc_md.setup_io_mappings = ash_map_io;
+
+#ifdef CONFIG_PPC_RTC
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+#endif
+}
diff --git a/arch/ppc/platforms/4xx/ash.h b/arch/ppc/platforms/4xx/ash.h
new file mode 100644
index 00000000000..5f7448ea418
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ash.h
@@ -0,0 +1,83 @@
+/*
+ * arch/ppc/platforms/4xx/ash.h
+ *
+ * Macros, definitions, and data structures specific to the IBM PowerPC
+ * Ash eval board.
+ *
+ * Author: Armin Kuster <akuster@mvista.com>
+ *
+ * 2000-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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_ASH_H__
+#define __ASM_ASH_H__
+#include <platforms/4xx/ibmnp405h.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Ash" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+ unsigned char bi_s_version[4]; /* Version of this structure */
+ unsigned char bi_r_version[30]; /* Version of the IBM ROM */
+ unsigned int bi_memsize; /* DRAM installed, in bytes */
+ unsigned char bi_enetaddr[4][6]; /* Local Ethernet MAC address */
+ unsigned char bi_pci_enetaddr[6];
+ unsigned int bi_intfreq; /* Processor speed, in Hz */
+ unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
+ unsigned int bi_pci_busfreq; /* PCI speed in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+/* Memory map for the IBM "Ash" NP405H evaluation board.
+ */
+
+extern void *ash_rtc_base;
+#define ASH_RTC_PADDR ((uint)0xf0000000)
+#define ASH_RTC_VADDR ASH_RTC_PADDR
+#define ASH_RTC_SIZE ((uint)8*1024)
+
+
+/* Early initialization address mapping for block_io.
+ * Standard 405GP map.
+ */
+#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR
+#define PPC4xx_PCI_IO_SIZE ((uint)64*1024)
+#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR
+#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024)
+#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR
+#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024)
+#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000)
+#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR
+#define PPC4xx_ONB_IO_SIZE ((uint)4*1024)
+
+#define NR_BOARD_IRQS 32
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD 201600
+#else
+#define BASE_BAUD 691200
+#endif
+
+#define PPC4xx_MACHINE_NAME "IBM NP405H Ash"
+
+extern char pci_irq_table[][4];
+
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_ASH_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/bubinga.c b/arch/ppc/platforms/4xx/bubinga.c
new file mode 100644
index 00000000000..3678abf8631
--- /dev/null
+++ b/arch/ppc/platforms/4xx/bubinga.c
@@ -0,0 +1,263 @@
+/*
+ * Support for IBM PPC 405EP evaluation board (Bubinga).
+ *
+ * Author: SAW (IBM), derived from walnut.c.
+ * Maintained by MontaVista Software <source@mvista.com>
+ *
+ * 2003 (c) MontaVista Softare 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/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/todc.h>
+#include <asm/kgdb.h>
+#include <asm/ocp.h>
+#include <asm/ibm_ocp_pci.h>
+
+#include <platforms/4xx/ibm405ep.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+extern bd_t __res;
+
+void *bubinga_rtc_base;
+
+/* Some IRQs unique to the board
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {28, 28, 28, 28}, /* IDSEL 1 - PCI slot 1 */
+ {29, 29, 29, 29}, /* IDSEL 2 - PCI slot 2 */
+ {30, 30, 30, 30}, /* IDSEL 3 - PCI slot 3 */
+ {31, 31, 31, 31}, /* IDSEL 4 - PCI slot 4 */
+ };
+
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+};
+
+/* The serial clock for the chip is an internal clock determined by
+ * different clock speeds/dividers.
+ * Calculate the proper input baud rate and setup the serial driver.
+ */
+static void __init
+bubinga_early_serial_map(void)
+{
+ u32 uart_div;
+ int uart_clock;
+ struct uart_port port;
+
+ /* Calculate the serial clock input frequency
+ *
+ * The base baud is the PLL OUTA (provided in the board info
+ * structure) divided by the external UART Divisor, divided
+ * by 16.
+ */
+ uart_div = (mfdcr(DCRN_CPC0_UCR_BASE) & DCRN_CPC0_UCR_U0DIV);
+ uart_clock = __res.bi_pllouta_freq / uart_div;
+
+ /* Setup serial port access */
+ memset(&port, 0, sizeof(port));
+ port.membase = (void*)ACTING_UART0_IO_BASE;
+ port.irq = ACTING_UART0_INT;
+ port.uartclk = uart_clock;
+ port.regshift = 0;
+ port.iotype = SERIAL_IO_MEM;
+ port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+ port.line = 0;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 0 failed\n");
+ }
+
+ port.membase = (void*)ACTING_UART1_IO_BASE;
+ port.irq = ACTING_UART1_INT;
+ port.line = 1;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 1 failed\n");
+ }
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+
+ unsigned int bar_response, bar;
+ /*
+ * Expected PCI mapping:
+ *
+ * PLB addr PCI memory addr
+ * --------------------- ---------------------
+ * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff
+ * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff
+ *
+ * PLB addr PCI io addr
+ * --------------------- ---------------------
+ * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000
+ *
+ * The following code is simplified by assuming that the bootrom
+ * has been well behaved in following this mapping.
+ */
+
+#ifdef DEBUG
+ int i;
+
+ printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
+ printk("PCI bridge regs before fixup \n");
+ for (i = 0; i <= 3; i++) {
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+ }
+ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+
+ /* added for IBM boot rom version 1.15 bios bar changes -AK */
+
+ /* Disable region first */
+ out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+ /* PLB starting addr, PCI: 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+ /* PCI start addr, 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+ /* 512MB range of PLB to PCI */
+ out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+ /* Enable no pre-fetch, enable region */
+ out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+ (PPC405_PCI_UPPER_MEM -
+ PPC405_PCI_MEM_BASE)) | 0x01));
+
+ /* Disable region one */
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->ptm1ms), 0x00000001);
+
+ /* Disable region two */
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+ out_le32((void *) &(pcip->ptm2la), 0x00000000);
+
+ /* Zero config bars */
+ for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+ early_write_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ 0x00000000);
+ early_read_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ &bar_response);
+ DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+ hose->first_busno, PCI_SLOT(hose->first_busno),
+ PCI_FUNC(hose->first_busno), bar, bar_response);
+ }
+ /* end work arround */
+
+#ifdef DEBUG
+ printk("PCI bridge regs after fixup \n");
+ for (i = 0; i <= 3; i++) {
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+ }
+ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+}
+
+void __init
+bubinga_setup_arch(void)
+{
+ ppc4xx_setup_arch();
+
+ ibm_ocp_set_emac(0, 1);
+
+ bubinga_early_serial_map();
+
+ /* RTC step for the evb405ep */
+ bubinga_rtc_base = (void *) BUBINGA_RTC_VADDR;
+ TODC_INIT(TODC_TYPE_DS1743, bubinga_rtc_base, bubinga_rtc_base,
+ bubinga_rtc_base, 8);
+ /* Identify the system */
+ printk("IBM Bubinga port (MontaVista Software, Inc. <source@mvista.com>)\n");
+}
+
+void __init
+bubinga_map_io(void)
+{
+ ppc4xx_map_io();
+ io_block_mapping(BUBINGA_RTC_VADDR,
+ BUBINGA_RTC_PADDR, BUBINGA_RTC_SIZE, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ ppc4xx_init(r3, r4, r5, r6, r7);
+
+ ppc_md.setup_arch = bubinga_setup_arch;
+ ppc_md.setup_io_mappings = bubinga_map_io;
+
+#ifdef CONFIG_GEN_RTC
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+#endif
+#ifdef CONFIG_KGDB
+ ppc_md.early_serial_map = bubinga_early_serial_map;
+#endif
+}
+
diff --git a/arch/ppc/platforms/4xx/bubinga.h b/arch/ppc/platforms/4xx/bubinga.h
new file mode 100644
index 00000000000..b1df856f8e2
--- /dev/null
+++ b/arch/ppc/platforms/4xx/bubinga.h
@@ -0,0 +1,69 @@
+/*
+ * Support for IBM PPC 405EP evaluation board (Bubinga).
+ *
+ * Author: SAW (IBM), derived from walnut.h.
+ * Maintained by MontaVista Software <source@mvista.com>
+ *
+ * 2003 (c) MontaVista Softare 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __BUBINGA_H__
+#define __BUBINGA_H__
+
+/* 405EP */
+#include <platforms/4xx/ibm405ep.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+ unsigned char bi_s_version[4]; /* Version of this structure */
+ unsigned char bi_r_version[30]; /* Version of the IBM ROM */
+ unsigned int bi_memsize; /* DRAM installed, in bytes */
+ unsigned char bi_enetaddr[2][6]; /* Local Ethernet MAC address */ unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */
+ unsigned int bi_intfreq; /* Processor speed, in Hz */
+ unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
+ unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
+ unsigned int bi_opb_busfreq; /* OPB Bus speed, in Hz */
+ unsigned int bi_pllouta_freq; /* PLL OUTA speed, in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+
+/* Memory map for the Bubinga board.
+ * Generic 4xx plus RTC.
+ */
+
+extern void *bubinga_rtc_base;
+#define BUBINGA_RTC_PADDR ((uint)0xf0000000)
+#define BUBINGA_RTC_VADDR BUBINGA_RTC_PADDR
+#define BUBINGA_RTC_SIZE ((uint)8*1024)
+
+/* The UART clock is based off an internal clock -
+ * define BASE_BAUD based on the internal clock and divider(s).
+ * Since BASE_BAUD must be a constant, we will initialize it
+ * using clock/divider values which OpenBIOS initializes
+ * for typical configurations at various CPU speeds.
+ * The base baud is calculated as (FWDA / EXT UART DIV / 16)
+ */
+#define BASE_BAUD 0
+
+#define BUBINGA_FPGA_BASE 0xF0300000
+
+#define PPC4xx_MACHINE_NAME "IBM Bubinga"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __BUBINGA_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/cpci405.c b/arch/ppc/platforms/4xx/cpci405.c
new file mode 100644
index 00000000000..ff966773a0b
--- /dev/null
+++ b/arch/ppc/platforms/4xx/cpci405.c
@@ -0,0 +1,84 @@
+/*
+ * arch/ppc/platforms/cpci405.c
+ *
+ * Board setup routines for the esd CPCI-405 cPCI Board.
+ *
+ * Author: Stefan Roese
+ * stefan.roese@esd-electronics.com
+ *
+ * Copyright 2001 esd electronic system design - hannover germany
+ *
+ * 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/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/todc.h>
+#include <asm/ocp.h>
+
+void *cpci405_nvram;
+
+/*
+ * Some IRQs unique to CPCI-405.
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {28, 28, 28, 28}, /* IDSEL 15 - cPCI slot 8 */
+ {29, 29, 29, 29}, /* IDSEL 16 - cPCI slot 7 */
+ {30, 30, 30, 30}, /* IDSEL 17 - cPCI slot 6 */
+ {27, 27, 27, 27}, /* IDSEL 18 - cPCI slot 5 */
+ {28, 28, 28, 28}, /* IDSEL 19 - cPCI slot 4 */
+ {29, 29, 29, 29}, /* IDSEL 20 - cPCI slot 3 */
+ {30, 30, 30, 30}, /* IDSEL 21 - cPCI slot 2 */
+ };
+ const long min_idsel = 15, max_idsel = 21, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+};
+
+void __init
+cpci405_setup_arch(void)
+{
+ ppc4xx_setup_arch();
+
+ ibm_ocp_set_emac(0, 0);
+
+ TODC_INIT(TODC_TYPE_MK48T35, cpci405_nvram, cpci405_nvram, cpci405_nvram, 8);
+}
+
+void __init
+cpci405_map_io(void)
+{
+ ppc4xx_map_io();
+ cpci405_nvram = ioremap(CPCI405_NVRAM_PADDR, CPCI405_NVRAM_SIZE);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ ppc4xx_init(r3, r4, r5, r6, r7);
+
+ ppc_md.setup_arch = cpci405_setup_arch;
+ ppc_md.setup_io_mappings = cpci405_map_io;
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+}
diff --git a/arch/ppc/platforms/4xx/cpci405.h b/arch/ppc/platforms/4xx/cpci405.h
new file mode 100644
index 00000000000..e27f7cb650d
--- /dev/null
+++ b/arch/ppc/platforms/4xx/cpci405.h
@@ -0,0 +1,37 @@
+/*
+ * CPCI-405 board specific definitions
+ *
+ * Copyright (c) 2001 Stefan Roese (stefan.roese@esd-electronics.com)
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_CPCI405_H__
+#define __ASM_CPCI405_H__
+
+#include <linux/config.h>
+
+/* We have a 405GP core */
+#include <platforms/4xx/ibm405gp.h>
+
+#include <asm/ppcboot.h>
+
+#ifndef __ASSEMBLY__
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+/* Map for the NVRAM space */
+#define CPCI405_NVRAM_PADDR ((uint)0xf0200000)
+#define CPCI405_NVRAM_SIZE ((uint)32*1024)
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD 201600
+#else
+#define BASE_BAUD 691200
+#endif
+
+#define PPC4xx_MACHINE_NAME "esd CPCI-405"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_CPCI405_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c
new file mode 100644
index 00000000000..f63bca83e75
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ebony.c
@@ -0,0 +1,356 @@
+/*
+ * arch/ppc/platforms/4xx/ebony.c
+ *
+ * Ebony board specific routines
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2002-2005 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ * 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/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/initrd.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ocp.h>
+#include <asm/pci-bridge.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/ppc4xx_pic.h>
+#include <asm/ppcboot.h>
+
+#include <syslib/gen550.h>
+#include <syslib/ibm440gp_common.h>
+
+/*
+ * This is a horrible kludge, we eventually need to abstract this
+ * generic PHY stuff, so the standard phy mode defines can be
+ * easily used from arch code.
+ */
+#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
+
+bd_t __res;
+
+static struct ibm44x_clocks clocks __initdata;
+
+/*
+ * Ebony external IRQ triggering/polarity settings
+ */
+unsigned char ppc4xx_uic_ext_irq_cfg[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ0: PCI slot 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ1: PCI slot 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ2: PCI slot 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ3: PCI slot 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ4: IRDA */
+ (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* IRQ5: SMI pushbutton */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ6: PHYs */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ7: AUX */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ8: EXT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ9: EXT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ10: EXT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ11: EXT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ12: EXT */
+};
+
+static void __init
+ebony_calibrate_decr(void)
+{
+ unsigned int freq;
+
+ /*
+ * Determine system clock speed
+ *
+ * If we are on Rev. B silicon, then use
+ * default external system clock. If we are
+ * on Rev. C silicon then errata forces us to
+ * use the internal clock.
+ */
+ switch (PVR_REV(mfspr(SPRN_PVR))) {
+ case PVR_REV(PVR_440GP_RB):
+ freq = EBONY_440GP_RB_SYSCLK;
+ break;
+ case PVR_REV(PVR_440GP_RC1):
+ default:
+ freq = EBONY_440GP_RC_SYSCLK;
+ break;
+ }
+
+ ibm44x_calibrate_decr(freq);
+}
+
+static int
+ebony_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: IBM\n");
+ seq_printf(m, "machine\t\t: Ebony\n");
+
+ return 0;
+}
+
+static inline int
+ebony_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 23, 23, 23, 23 }, /* IDSEL 1 - PCI Slot 0 */
+ { 24, 24, 24, 24 }, /* IDSEL 2 - PCI Slot 1 */
+ { 25, 25, 25, 25 }, /* IDSEL 3 - PCI Slot 2 */
+ { 26, 26, 26, 26 }, /* IDSEL 4 - PCI Slot 3 */
+ };
+
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+#define PCIX_WRITEL(value, offset) \
+ (writel(value, pcix_reg_base + offset))
+
+/*
+ * FIXME: This is only here to "make it work". This will move
+ * to a ibm_pcix.c which will contain a generic IBM PCIX bridge
+ * configuration library. -Matt
+ */
+static void __init
+ebony_setup_pcix(void)
+{
+ void *pcix_reg_base;
+
+ pcix_reg_base = ioremap64(PCIX0_REG_BASE, PCIX_REG_SIZE);
+
+ /* Disable all windows */
+ PCIX_WRITEL(0, PCIX0_POM0SA);
+ PCIX_WRITEL(0, PCIX0_POM1SA);
+ PCIX_WRITEL(0, PCIX0_POM2SA);
+ PCIX_WRITEL(0, PCIX0_PIM0SA);
+ PCIX_WRITEL(0, PCIX0_PIM1SA);
+ PCIX_WRITEL(0, PCIX0_PIM2SA);
+
+ /* Setup 2GB PLB->PCI outbound mem window (3_8000_0000->0_8000_0000) */
+ PCIX_WRITEL(0x00000003, PCIX0_POM0LAH);
+ PCIX_WRITEL(0x80000000, PCIX0_POM0LAL);
+ PCIX_WRITEL(0x00000000, PCIX0_POM0PCIAH);
+ PCIX_WRITEL(0x80000000, PCIX0_POM0PCIAL);
+ PCIX_WRITEL(0x80000001, PCIX0_POM0SA);
+
+ /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
+ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
+ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
+ PCIX_WRITEL(0x80000007, PCIX0_PIM0SA);
+
+ eieio();
+}
+
+static void __init
+ebony_setup_hose(void)
+{
+ struct pci_controller *hose;
+
+ /* Configure windows on the PCI-X host bridge */
+ ebony_setup_pcix();
+
+ hose = pcibios_alloc_controller();
+
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ hose->pci_mem_offset = EBONY_PCI_MEM_OFFSET;
+
+ pci_init_resource(&hose->io_resource,
+ EBONY_PCI_LOWER_IO,
+ EBONY_PCI_UPPER_IO,
+ IORESOURCE_IO,
+ "PCI host bridge");
+
+ pci_init_resource(&hose->mem_resources[0],
+ EBONY_PCI_LOWER_MEM,
+ EBONY_PCI_UPPER_MEM,
+ IORESOURCE_MEM,
+ "PCI host bridge");
+
+ hose->io_space.start = EBONY_PCI_LOWER_IO;
+ hose->io_space.end = EBONY_PCI_UPPER_IO;
+ hose->mem_space.start = EBONY_PCI_LOWER_MEM;
+ hose->mem_space.end = EBONY_PCI_UPPER_MEM;
+ isa_io_base =
+ (unsigned long)ioremap64(EBONY_PCI_IO_BASE, EBONY_PCI_IO_SIZE);
+ hose->io_base_virt = (void *)isa_io_base;
+
+ setup_indirect_pci(hose,
+ EBONY_PCI_CFGA_PLB32,
+ EBONY_PCI_CFGD_PLB32);
+ hose->set_cfg_type = 1;
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = ebony_map_irq;
+}
+
+TODC_ALLOC();
+
+static void __init
+ebony_early_serial_map(void)
+{
+ struct uart_port port;
+
+ /* Setup ioremapped serial port access */
+ memset(&port, 0, sizeof(port));
+ port.membase = ioremap64(PPC440GP_UART0_ADDR, 8);
+ port.irq = 0;
+ port.uartclk = clocks.uart0;
+ port.regshift = 0;
+ port.iotype = SERIAL_IO_MEM;
+ port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+ port.line = 0;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 0 failed\n");
+ }
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ /* Configure debug serial access */
+ gen550_init(0, &port);
+#endif
+
+ port.membase = ioremap64(PPC440GP_UART1_ADDR, 8);
+ port.irq = 1;
+ port.uartclk = clocks.uart1;
+ port.line = 1;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 1 failed\n");
+ }
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ /* Configure debug serial access */
+ gen550_init(1, &port);
+#endif
+}
+
+static void __init
+ebony_setup_arch(void)
+{
+ struct ocp_def *def;
+ struct ocp_func_emac_data *emacdata;
+
+ /* Set mac_addr for each EMAC */
+ def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0);
+ emacdata = def->additions;
+ emacdata->phy_map = 0x00000001; /* Skip 0x00 */
+ emacdata->phy_mode = PHY_MODE_RMII;
+ memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6);
+
+ def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 1);
+ emacdata = def->additions;
+ emacdata->phy_map = 0x00000001; /* Skip 0x00 */
+ emacdata->phy_mode = PHY_MODE_RMII;
+ memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6);
+
+ /*
+ * Determine various clocks.
+ * To be completely correct we should get SysClk
+ * from FPGA, because it can be changed by on-board switches
+ * --ebs
+ */
+ ibm440gp_get_clocks(&clocks, 33333333, 6 * 1843200);
+ ocp_sys_info.opb_bus_freq = clocks.opb;
+
+ /* Setup TODC access */
+ TODC_INIT(TODC_TYPE_DS1743,
+ 0,
+ 0,
+ ioremap64(EBONY_RTC_ADDR, EBONY_RTC_SIZE),
+ 8);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000/HZ;
+
+ /* Setup PCI host bridge */
+ ebony_setup_hose();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+
+ ebony_early_serial_map();
+
+ /* Identify the system */
+ printk("IBM Ebony port (MontaVista Software, Inc. (source@mvista.com))\n");
+}
+
+void __init platform_init(unsigned long r3, unsigned long r4,
+ unsigned long r5, unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3)
+ __res = *(bd_t *)(r3 + KERNELBASE);
+
+ ibm44x_platform_init();
+
+ ppc_md.setup_arch = ebony_setup_arch;
+ ppc_md.show_cpuinfo = ebony_show_cpuinfo;
+ ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */
+
+ ppc_md.calibrate_decr = ebony_calibrate_decr;
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+#ifdef CONFIG_KGDB
+ ppc_md.early_serial_map = ebony_early_serial_map;
+#endif
+}
+
diff --git a/arch/ppc/platforms/4xx/ebony.h b/arch/ppc/platforms/4xx/ebony.h
new file mode 100644
index 00000000000..47c391c9174
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ebony.h
@@ -0,0 +1,91 @@
+/*
+ * arch/ppc/platforms/ebony.h
+ *
+ * Ebony board definitions
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_EBONY_H__
+#define __ASM_EBONY_H__
+
+#include <linux/config.h>
+#include <platforms/4xx/ibm440gp.h>
+
+/* F/W TLB mapping used in bootloader glue to reset EMAC */
+#define PPC44x_EMAC0_MR0 0xE0000800
+
+/* Where to find the MAC info */
+#define EBONY_OPENBIOS_MAC_BASE 0xfffffe0c
+#define EBONY_OPENBIOS_MAC_OFFSET 0x0c
+
+/* Default clock rates for Rev. B and Rev. C silicon */
+#define EBONY_440GP_RB_SYSCLK 33000000
+#define EBONY_440GP_RC_SYSCLK 400000000
+
+/* RTC/NVRAM location */
+#define EBONY_RTC_ADDR 0x0000000148000000ULL
+#define EBONY_RTC_SIZE 0x2000
+
+/* Flash */
+#define EBONY_FPGA_ADDR 0x0000000148300000ULL
+#define EBONY_BOOT_SMALL_FLASH(x) (x & 0x20)
+#define EBONY_ONBRD_FLASH_EN(x) (x & 0x02)
+#define EBONY_FLASH_SEL(x) (x & 0x01)
+#define EBONY_SMALL_FLASH_LOW1 0x00000001ff800000ULL
+#define EBONY_SMALL_FLASH_LOW2 0x00000001ff880000ULL
+#define EBONY_SMALL_FLASH_HIGH1 0x00000001fff00000ULL
+#define EBONY_SMALL_FLASH_HIGH2 0x00000001fff80000ULL
+#define EBONY_SMALL_FLASH_SIZE 0x80000
+#define EBONY_LARGE_FLASH_LOW 0x00000001ff800000ULL
+#define EBONY_LARGE_FLASH_HIGH 0x00000001ffc00000ULL
+#define EBONY_LARGE_FLASH_SIZE 0x400000
+
+#define EBONY_SMALL_FLASH_BASE 0x00000001fff80000ULL
+#define EBONY_LARGE_FLASH_BASE 0x00000001ff800000ULL
+
+/*
+ * Serial port defines
+ */
+
+/* OpenBIOS defined UART mappings, used before early_serial_setup */
+#define UART0_IO_BASE 0xE0000200
+#define UART1_IO_BASE 0xE0000300
+
+/* external Epson SG-615P */
+#define BASE_BAUD 691200
+
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, \
+ (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
+ iomem_base: UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+
+/* PCI support */
+#define EBONY_PCI_LOWER_IO 0x00000000
+#define EBONY_PCI_UPPER_IO 0x0000ffff
+#define EBONY_PCI_LOWER_MEM 0x80002000
+#define EBONY_PCI_UPPER_MEM 0xffffefff
+
+#define EBONY_PCI_CFGREGS_BASE 0x000000020ec00000
+#define EBONY_PCI_CFGA_PLB32 0x0ec00000
+#define EBONY_PCI_CFGD_PLB32 0x0ec00004
+
+#define EBONY_PCI_IO_BASE 0x0000000208000000ULL
+#define EBONY_PCI_IO_SIZE 0x00010000
+#define EBONY_PCI_MEM_OFFSET 0x00000000
+
+#endif /* __ASM_EBONY_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ep405.c b/arch/ppc/platforms/4xx/ep405.c
new file mode 100644
index 00000000000..26a07cdb30e
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ep405.c
@@ -0,0 +1,197 @@
+/*
+ * arch/ppc/platforms/4xx/ep405.c
+ *
+ * Embedded Planet 405GP board
+ * http://www.embeddedplanet.com
+ *
+ * Author: Matthew Locke <mlocke@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.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/todc.h>
+#include <asm/ocp.h>
+#include <asm/ibm_ocp_pci.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+u8 *ep405_bcsr;
+u8 *ep405_nvram;
+
+static struct {
+ u8 cpld_xirq_select;
+ int pci_idsel;
+ int irq;
+} ep405_devtable[] = {
+#ifdef CONFIG_EP405PC
+ {0x07, 0x0E, 25}, /* EP405PC: USB */
+#endif
+};
+
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ int i;
+
+ /* AFAICT this is only called a few times during PCI setup, so
+ performance is not critical */
+ for (i = 0; i < ARRAY_SIZE(ep405_devtable); i++) {
+ if (idsel == ep405_devtable[i].pci_idsel)
+ return ep405_devtable[i].irq;
+ }
+ return -1;
+};
+
+void __init
+ep405_setup_arch(void)
+{
+ ppc4xx_setup_arch();
+
+ ibm_ocp_set_emac(0, 0);
+
+ if (__res.bi_nvramsize == 512*1024) {
+ /* FIXME: we should properly handle NVRTCs of different sizes */
+ TODC_INIT(TODC_TYPE_DS1557, ep405_nvram, ep405_nvram, ep405_nvram, 8);
+ }
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+ unsigned int bar_response, bar;
+ /*
+ * Expected PCI mapping:
+ *
+ * PLB addr PCI memory addr
+ * --------------------- ---------------------
+ * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff
+ * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff
+ *
+ * PLB addr PCI io addr
+ * --------------------- ---------------------
+ * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000
+ *
+ */
+
+ /* Disable region zero first */
+ out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+ /* PLB starting addr, PCI: 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+ /* PCI start addr, 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+ /* 512MB range of PLB to PCI */
+ out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+ /* Enable no pre-fetch, enable region */
+ out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+ (PPC405_PCI_UPPER_MEM -
+ PPC405_PCI_MEM_BASE)) | 0x01));
+
+ /* Disable region one */
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->ptm1ms), 0x00000000);
+
+ /* Disable region two */
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+ /* Configure PTM (PCI->PLB) region 1 */
+ out_le32((void *) &(pcip->ptm1la), 0x00000000); /* PLB base address */
+ /* Disable PTM region 2 */
+ out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+ /* Zero config bars */
+ for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+ early_write_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ 0x00000000);
+ early_read_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ &bar_response);
+ DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+ hose->first_busno, PCI_SLOT(hose->first_busno),
+ PCI_FUNC(hose->first_busno), bar, bar_response);
+ }
+ /* end work arround */
+}
+
+void __init
+ep405_map_io(void)
+{
+ bd_t *bip = &__res;
+
+ ppc4xx_map_io();
+
+ ep405_bcsr = ioremap(EP405_BCSR_PADDR, EP405_BCSR_SIZE);
+
+ if (bip->bi_nvramsize > 0) {
+ ep405_nvram = ioremap(EP405_NVRAM_PADDR, bip->bi_nvramsize);
+ }
+}
+
+void __init
+ep405_init_IRQ(void)
+{
+ int i;
+
+ ppc4xx_init_IRQ();
+
+ /* Workaround for a bug in the firmware it incorrectly sets
+ the IRQ polarities for XIRQ0 and XIRQ1 */
+ mtdcr(DCRN_UIC_PR(DCRN_UIC0_BASE), 0xffffff80); /* set the polarity */
+ mtdcr(DCRN_UIC_SR(DCRN_UIC0_BASE), 0x00000060); /* clear bogus interrupts */
+
+ /* Activate the XIRQs from the CPLD */
+ writeb(0xf0, ep405_bcsr+10);
+
+ /* Set up IRQ routing */
+ for (i = 0; i < ARRAY_SIZE(ep405_devtable); i++) {
+ if ( (ep405_devtable[i].irq >= 25)
+ && (ep405_devtable[i].irq) <= 31) {
+ writeb(ep405_devtable[i].cpld_xirq_select, ep405_bcsr+5);
+ writeb(ep405_devtable[i].irq - 25, ep405_bcsr+6);
+ }
+ }
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ ppc4xx_init(r3, r4, r5, r6, r7);
+
+ ppc_md.setup_arch = ep405_setup_arch;
+ ppc_md.setup_io_mappings = ep405_map_io;
+ ppc_md.init_IRQ = ep405_init_IRQ;
+
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+
+ if (__res.bi_nvramsize == 512*1024) {
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ } else {
+ printk("EP405: NVRTC size is not 512k (not a DS1557). Not sure what to do with it\n");
+ }
+}
diff --git a/arch/ppc/platforms/4xx/ep405.h b/arch/ppc/platforms/4xx/ep405.h
new file mode 100644
index 00000000000..ea3eb21338f
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ep405.h
@@ -0,0 +1,54 @@
+/*
+ * arch/ppc/platforms/4xx/ep405.h
+ *
+ * Embedded Planet 405GP board
+ * http://www.embeddedplanet.com
+ *
+ * Author: Matthew Locke <mlocke@mvista.com>
+ *
+ * 2000 (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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_EP405_H__
+#define __ASM_EP405_H__
+
+/* We have a 405GP core */
+#include <platforms/4xx/ibm405gp.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+typedef struct board_info {
+ unsigned int bi_memsize; /* DRAM installed, in bytes */
+ unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */
+ unsigned int bi_intfreq; /* Processor speed, in Hz */
+ unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
+ unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
+ unsigned int bi_nvramsize; /* Size of the NVRAM/RTC */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+extern u8 *ep405_bcsr;
+extern u8 *ep405_nvram;
+
+/* Map for the BCSR and NVRAM space */
+#define EP405_BCSR_PADDR ((uint)0xf4000000)
+#define EP405_BCSR_SIZE ((uint)16)
+#define EP405_NVRAM_PADDR ((uint)0xf4200000)
+
+/* serial defines */
+#define BASE_BAUD 399193
+
+#define PPC4xx_MACHINE_NAME "Embedded Planet 405GP"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_EP405_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ibm405ep.c b/arch/ppc/platforms/4xx/ibm405ep.c
new file mode 100644
index 00000000000..6d44567f4dd
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm405ep.c
@@ -0,0 +1,143 @@
+/*
+ * arch/ppc/platforms/ibm405ep.c
+ *
+ * Support for IBM PPC 405EP processors.
+ *
+ * Author: SAW (IBM), derived from ibmnp405l.c.
+ * Maintained by MontaVista Software <source@mvista.com>
+ *
+ * 2003 (c) MontaVista Softare 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/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+
+#include <asm/ibm4xx.h>
+#include <asm/ocp.h>
+#include <asm/ppc4xx_pic.h>
+
+#include <platforms/4xx/ibm405ep.h>
+
+static struct ocp_func_mal_data ibm405ep_mal0_def = {
+ .num_tx_chans = 4, /* Number of TX channels */
+ .num_rx_chans = 2, /* Number of RX channels */
+ .txeob_irq = 11, /* TX End Of Buffer IRQ */
+ .rxeob_irq = 12, /* RX End Of Buffer IRQ */
+ .txde_irq = 13, /* TX Descriptor Error IRQ */
+ .rxde_irq = 14, /* RX Descriptor Error IRQ */
+ .serr_irq = 10, /* MAL System Error IRQ */
+};
+OCP_SYSFS_MAL_DATA()
+
+static struct ocp_func_emac_data ibm405ep_emac0_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = -1, /* ZMII device index */
+ .zmii_mux = 0, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 0, /* MAL rx channel number */
+ .mal_tx_chan = 0, /* MAL tx channel number */
+ .wol_irq = 9, /* WOL interrupt number */
+ .mdio_idx = 0, /* MDIO via EMAC0 */
+ .tah_idx = -1, /* No TAH */
+};
+
+static struct ocp_func_emac_data ibm405ep_emac1_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = -1, /* ZMII device index */
+ .zmii_mux = 0, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 1, /* MAL rx channel number */
+ .mal_tx_chan = 2, /* MAL tx channel number */
+ .wol_irq = 9, /* WOL interrupt number */
+ .mdio_idx = 0, /* MDIO via EMAC0 */
+ .tah_idx = -1, /* No TAH */
+};
+OCP_SYSFS_EMAC_DATA()
+
+static struct ocp_func_iic_data ibm405ep_iic0_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+OCP_SYSFS_IIC_DATA()
+
+struct ocp_def core_ocp[] = {
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_OPB,
+ .index = 0,
+ .paddr = 0xEF600000,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = UART0_IO_BASE,
+ .irq = UART0_INT,
+ .pm = IBM_CPM_UART0
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = UART1_IO_BASE,
+ .irq = UART1_INT,
+ .pm = IBM_CPM_UART1
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .paddr = 0xEF600500,
+ .irq = 2,
+ .pm = IBM_CPM_IIC0,
+ .additions = &ibm405ep_iic0_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_GPIO,
+ .paddr = 0xEF600700,
+ .irq = OCP_IRQ_NA,
+ .pm = IBM_CPM_GPIO0
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_MAL,
+ .paddr = OCP_PADDR_NA,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm405ep_mal0_def,
+ .show = &ocp_show_mal_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 0,
+ .paddr = EMAC0_BASE,
+ .irq = 15,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm405ep_emac0_def,
+ .show = &ocp_show_emac_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 1,
+ .paddr = 0xEF600900,
+ .irq = 17,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm405ep_emac1_def,
+ .show = &ocp_show_emac_data
+ },
+ { .vendor = OCP_VENDOR_INVALID
+ }
+};
+
+/* Polarity and triggering settings for internal interrupt sources */
+struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = {
+ { .polarity = 0xffff7f80,
+ .triggering = 0x00000000,
+ .ext_irq_mask = 0x0000007f, /* IRQ0 - IRQ6 */
+ }
+};
diff --git a/arch/ppc/platforms/4xx/ibm405ep.h b/arch/ppc/platforms/4xx/ibm405ep.h
new file mode 100644
index 00000000000..e051e3fe8c6
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm405ep.h
@@ -0,0 +1,148 @@
+/*
+ * arch/ppc/platforms/4xx/ibm405ep.h
+ *
+ * IBM PPC 405EP processor defines.
+ *
+ * Author: SAW (IBM), derived from ibm405gp.h.
+ * Maintained by MontaVista Software <source@mvista.com>
+ *
+ * 2003 (c) MontaVista Softare 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBM405EP_H__
+#define __ASM_IBM405EP_H__
+
+#include <linux/config.h>
+
+/* ibm405.h at bottom of this file */
+
+/* PCI
+ * PCI Bridge config reg definitions
+ * see 17-19 of manual
+ */
+
+#define PPC405_PCI_CONFIG_ADDR 0xeec00000
+#define PPC405_PCI_CONFIG_DATA 0xeec00004
+
+#define PPC405_PCI_PHY_MEM_BASE 0x80000000 /* hose_a->pci_mem_offset */
+ /* setbat */
+#define PPC405_PCI_MEM_BASE PPC405_PCI_PHY_MEM_BASE /* setbat */
+#define PPC405_PCI_PHY_IO_BASE 0xe8000000 /* setbat */
+#define PPC405_PCI_IO_BASE PPC405_PCI_PHY_IO_BASE /* setbat */
+
+#define PPC405_PCI_LOWER_MEM 0x80000000 /* hose_a->mem_space.start */
+#define PPC405_PCI_UPPER_MEM 0xBfffffff /* hose_a->mem_space.end */
+#define PPC405_PCI_LOWER_IO 0x00000000 /* hose_a->io_space.start */
+#define PPC405_PCI_UPPER_IO 0x0000ffff /* hose_a->io_space.end */
+
+#define PPC405_ISA_IO_BASE PPC405_PCI_IO_BASE
+
+#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR
+#define PPC4xx_PCI_IO_SIZE ((uint)64*1024)
+#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR
+#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024)
+#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR
+#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024)
+#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000)
+#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR
+#define PPC4xx_ONB_IO_SIZE ((uint)4*1024)
+
+/* serial port defines */
+#define RS_TABLE_SIZE 2
+
+#define UART0_INT 0
+#define UART1_INT 1
+
+#define PCIL0_BASE 0xEF400000
+#define UART0_IO_BASE 0xEF600300
+#define UART1_IO_BASE 0xEF600400
+#define EMAC0_BASE 0xEF600800
+
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i]
+
+#if defined(CONFIG_UART0_TTYS0)
+#define ACTING_UART0_IO_BASE UART0_IO_BASE
+#define ACTING_UART1_IO_BASE UART1_IO_BASE
+#define ACTING_UART0_INT UART0_INT
+#define ACTING_UART1_INT UART1_INT
+#else
+#define ACTING_UART0_IO_BASE UART1_IO_BASE
+#define ACTING_UART1_IO_BASE UART0_IO_BASE
+#define ACTING_UART0_INT UART1_INT
+#define ACTING_UART1_INT UART0_INT
+#endif
+
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, ACTING_UART##num##_INT, \
+ (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
+ iomem_base: (u8 *)ACTING_UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#define SERIAL_DEBUG_IO_BASE ACTING_UART0_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+
+/* DCR defines */
+#define DCRN_CPMSR_BASE 0x0BA
+#define DCRN_CPMFR_BASE 0x0B9
+
+#define DCRN_CPC0_PLLMR0_BASE 0x0F0
+#define DCRN_CPC0_BOOT_BASE 0x0F1
+#define DCRN_CPC0_CR1_BASE 0x0F2
+#define DCRN_CPC0_EPRCSR_BASE 0x0F3
+#define DCRN_CPC0_PLLMR1_BASE 0x0F4
+#define DCRN_CPC0_UCR_BASE 0x0F5
+#define DCRN_CPC0_UCR_U0DIV 0x07F
+#define DCRN_CPC0_SRR_BASE 0x0F6
+#define DCRN_CPC0_JTAGID_BASE 0x0F7
+#define DCRN_CPC0_SPARE_BASE 0x0F8
+#define DCRN_CPC0_PCI_BASE 0x0F9
+
+
+#define IBM_CPM_GPT 0x80000000 /* GPT interface */
+#define IBM_CPM_PCI 0x40000000 /* PCI bridge */
+#define IBM_CPM_UIC 0x00010000 /* Universal Int Controller */
+#define IBM_CPM_CPU 0x00008000 /* processor core */
+#define IBM_CPM_EBC 0x00002000 /* EBC controller */
+#define IBM_CPM_SDRAM0 0x00004000 /* SDRAM memory controller */
+#define IBM_CPM_GPIO0 0x00001000 /* General Purpose IO */
+#define IBM_CPM_TMRCLK 0x00000400 /* CPU timers */
+#define IBM_CPM_PLB 0x00000100 /* PLB bus arbiter */
+#define IBM_CPM_OPB 0x00000080 /* PLB to OPB bridge */
+#define IBM_CPM_DMA 0x00000040 /* DMA controller */
+#define IBM_CPM_IIC0 0x00000010 /* IIC interface */
+#define IBM_CPM_UART1 0x00000002 /* serial port 0 */
+#define IBM_CPM_UART0 0x00000001 /* serial port 1 */
+#define DFLT_IBM4xx_PM ~(IBM_CPM_PCI | IBM_CPM_CPU | IBM_CPM_DMA \
+ | IBM_CPM_OPB | IBM_CPM_EBC \
+ | IBM_CPM_SDRAM0 | IBM_CPM_PLB \
+ | IBM_CPM_UIC | IBM_CPM_TMRCLK)
+#define DCRN_DMA0_BASE 0x100
+#define DCRN_DMA1_BASE 0x108
+#define DCRN_DMA2_BASE 0x110
+#define DCRN_DMA3_BASE 0x118
+#define DCRNCAP_DMA_SG 1 /* have DMA scatter/gather capability */
+#define DCRN_DMASR_BASE 0x120
+#define DCRN_EBC_BASE 0x012
+#define DCRN_DCP0_BASE 0x014
+#define DCRN_MAL_BASE 0x180
+#define DCRN_OCM0_BASE 0x018
+#define DCRN_PLB0_BASE 0x084
+#define DCRN_PLLMR_BASE 0x0B0
+#define DCRN_POB0_BASE 0x0A0
+#define DCRN_SDRAM0_BASE 0x010
+#define DCRN_UIC0_BASE 0x0C0
+#define UIC0 DCRN_UIC0_BASE
+
+#include <asm/ibm405.h>
+
+#endif /* __ASM_IBM405EP_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ibm405gp.c b/arch/ppc/platforms/4xx/ibm405gp.c
new file mode 100644
index 00000000000..dfd7ef3ba5f
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm405gp.c
@@ -0,0 +1,120 @@
+/*
+ *
+ * Copyright 2000-2001 MontaVista Software Inc.
+ * Original author: Armin Kuster akuster@mvista.com
+ *
+ * Module name: ibm405gp.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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <platforms/4xx/ibm405gp.h>
+#include <asm/ibm4xx.h>
+#include <asm/ocp.h>
+#include <asm/ppc4xx_pic.h>
+
+static struct ocp_func_emac_data ibm405gp_emac0_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = -1, /* ZMII device index */
+ .zmii_mux = 0, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 0, /* MAL rx channel number */
+ .mal_tx_chan = 0, /* MAL tx channel number */
+ .wol_irq = 9, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+OCP_SYSFS_EMAC_DATA()
+
+static struct ocp_func_mal_data ibm405gp_mal0_def = {
+ .num_tx_chans = 1, /* Number of TX channels */
+ .num_rx_chans = 1, /* Number of RX channels */
+ .txeob_irq = 11, /* TX End Of Buffer IRQ */
+ .rxeob_irq = 12, /* RX End Of Buffer IRQ */
+ .txde_irq = 13, /* TX Descriptor Error IRQ */
+ .rxde_irq = 14, /* RX Descriptor Error IRQ */
+ .serr_irq = 10, /* MAL System Error IRQ */
+};
+OCP_SYSFS_MAL_DATA()
+
+static struct ocp_func_iic_data ibm405gp_iic0_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+OCP_SYSFS_IIC_DATA()
+
+struct ocp_def core_ocp[] = {
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_OPB,
+ .index = 0,
+ .paddr = 0xEF600000,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = UART0_IO_BASE,
+ .irq = UART0_INT,
+ .pm = IBM_CPM_UART0
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = UART1_IO_BASE,
+ .irq = UART1_INT,
+ .pm = IBM_CPM_UART1
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .paddr = 0xEF600500,
+ .irq = 2,
+ .pm = IBM_CPM_IIC0,
+ .additions = &ibm405gp_iic0_def,
+ .show = &ocp_show_iic_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_GPIO,
+ .paddr = 0xEF600700,
+ .irq = OCP_IRQ_NA,
+ .pm = IBM_CPM_GPIO0
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_MAL,
+ .paddr = OCP_PADDR_NA,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm405gp_mal0_def,
+ .show = &ocp_show_mal_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 0,
+ .paddr = EMAC0_BASE,
+ .irq = 15,
+ .pm = IBM_CPM_EMAC0,
+ .additions = &ibm405gp_emac0_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_INVALID
+ }
+};
+
+/* Polarity and triggering settings for internal interrupt sources */
+struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = {
+ { .polarity = 0xffffff80,
+ .triggering = 0x10000000,
+ .ext_irq_mask = 0x0000007f, /* IRQ0 - IRQ6 */
+ }
+};
diff --git a/arch/ppc/platforms/4xx/ibm405gp.h b/arch/ppc/platforms/4xx/ibm405gp.h
new file mode 100644
index 00000000000..b2b642e81af
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm405gp.h
@@ -0,0 +1,151 @@
+/*
+ * arch/ppc/platforms/4xx/ibm405gp.h
+ *
+ * Author: Armin Kuster akuster@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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBM405GP_H__
+#define __ASM_IBM405GP_H__
+
+#include <linux/config.h>
+
+/* ibm405.h at bottom of this file */
+
+/* PCI
+ * PCI Bridge config reg definitions
+ * see 17-19 of manual
+ */
+
+#define PPC405_PCI_CONFIG_ADDR 0xeec00000
+#define PPC405_PCI_CONFIG_DATA 0xeec00004
+
+#define PPC405_PCI_PHY_MEM_BASE 0x80000000 /* hose_a->pci_mem_offset */
+ /* setbat */
+#define PPC405_PCI_MEM_BASE PPC405_PCI_PHY_MEM_BASE /* setbat */
+#define PPC405_PCI_PHY_IO_BASE 0xe8000000 /* setbat */
+#define PPC405_PCI_IO_BASE PPC405_PCI_PHY_IO_BASE /* setbat */
+
+#define PPC405_PCI_LOWER_MEM 0x80000000 /* hose_a->mem_space.start */
+#define PPC405_PCI_UPPER_MEM 0xBfffffff /* hose_a->mem_space.end */
+#define PPC405_PCI_LOWER_IO 0x00000000 /* hose_a->io_space.start */
+#define PPC405_PCI_UPPER_IO 0x0000ffff /* hose_a->io_space.end */
+
+#define PPC405_ISA_IO_BASE PPC405_PCI_IO_BASE
+
+#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR
+#define PPC4xx_PCI_IO_SIZE ((uint)64*1024)
+#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR
+#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024)
+#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR
+#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024)
+#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000)
+#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR
+#define PPC4xx_ONB_IO_SIZE ((uint)4*1024)
+
+/* serial port defines */
+#define RS_TABLE_SIZE 2
+
+#define UART0_INT 0
+#define UART1_INT 1
+
+#define PCIL0_BASE 0xEF400000
+#define UART0_IO_BASE 0xEF600300
+#define UART1_IO_BASE 0xEF600400
+#define EMAC0_BASE 0xEF600800
+
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
+
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, \
+ (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
+ iomem_base: (u8 *)UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_DEBUG_IO_BASE UART1_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(1) \
+ STD_UART_OP(0)
+#endif
+
+/* DCR defines */
+#define DCRN_CHCR_BASE 0x0B1
+#define DCRN_CHPSR_BASE 0x0B4
+#define DCRN_CPMSR_BASE 0x0B8
+#define DCRN_CPMFR_BASE 0x0BA
+
+#define CHR0_U0EC 0x00000080 /* Select external clock for UART0 */
+#define CHR0_U1EC 0x00000040 /* Select external clock for UART1 */
+#define CHR0_UDIV 0x0000003E /* UART internal clock divisor */
+#define CHR1_CETE 0x00800000 /* CPU external timer enable */
+
+#define DCRN_CHPSR_BASE 0x0B4
+#define PSR_PLL_FWD_MASK 0xC0000000
+#define PSR_PLL_FDBACK_MASK 0x30000000
+#define PSR_PLL_TUNING_MASK 0x0E000000
+#define PSR_PLB_CPU_MASK 0x01800000
+#define PSR_OPB_PLB_MASK 0x00600000
+#define PSR_PCI_PLB_MASK 0x00180000
+#define PSR_EB_PLB_MASK 0x00060000
+#define PSR_ROM_WIDTH_MASK 0x00018000
+#define PSR_ROM_LOC 0x00004000
+#define PSR_PCI_ASYNC_EN 0x00001000
+#define PSR_PCI_ARBIT_EN 0x00000400
+
+#define IBM_CPM_IIC0 0x80000000 /* IIC interface */
+#define IBM_CPM_PCI 0x40000000 /* PCI bridge */
+#define IBM_CPM_CPU 0x20000000 /* processor core */
+#define IBM_CPM_DMA 0x10000000 /* DMA controller */
+#define IBM_CPM_OPB 0x08000000 /* PLB to OPB bridge */
+#define IBM_CPM_DCP 0x04000000 /* CodePack */
+#define IBM_CPM_EBC 0x02000000 /* ROM/SRAM peripheral controller */
+#define IBM_CPM_SDRAM0 0x01000000 /* SDRAM memory controller */
+#define IBM_CPM_PLB 0x00800000 /* PLB bus arbiter */
+#define IBM_CPM_GPIO0 0x00400000 /* General Purpose IO (??) */
+#define IBM_CPM_UART0 0x00200000 /* serial port 0 */
+#define IBM_CPM_UART1 0x00100000 /* serial port 1 */
+#define IBM_CPM_UIC 0x00080000 /* Universal Interrupt Controller */
+#define IBM_CPM_TMRCLK 0x00040000 /* CPU timers */
+#define IBM_CPM_EMAC0 0x00020000 /* on-chip ethernet MM unit */
+#define DFLT_IBM4xx_PM ~(IBM_CPM_PCI | IBM_CPM_CPU | IBM_CPM_DMA \
+ | IBM_CPM_OPB | IBM_CPM_EBC \
+ | IBM_CPM_SDRAM0 | IBM_CPM_PLB \
+ | IBM_CPM_UIC | IBM_CPM_TMRCLK)
+
+#define DCRN_DMA0_BASE 0x100
+#define DCRN_DMA1_BASE 0x108
+#define DCRN_DMA2_BASE 0x110
+#define DCRN_DMA3_BASE 0x118
+#define DCRNCAP_DMA_SG 1 /* have DMA scatter/gather capability */
+#define DCRN_DMASR_BASE 0x120
+#define DCRN_EBC_BASE 0x012
+#define DCRN_DCP0_BASE 0x014
+#define DCRN_MAL_BASE 0x180
+#define DCRN_OCM0_BASE 0x018
+#define DCRN_PLB0_BASE 0x084
+#define DCRN_PLLMR_BASE 0x0B0
+#define DCRN_POB0_BASE 0x0A0
+#define DCRN_SDRAM0_BASE 0x010
+#define DCRN_UIC0_BASE 0x0C0
+#define UIC0 DCRN_UIC0_BASE
+
+#include <asm/ibm405.h>
+
+#endif /* __ASM_IBM405GP_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ibm405gpr.c b/arch/ppc/platforms/4xx/ibm405gpr.c
new file mode 100644
index 00000000000..01c8ccbc721
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm405gpr.c
@@ -0,0 +1,117 @@
+/*
+ * arch/ppc/platforms/4xx/ibm405gpr.c
+ *
+ * Author: Armin Kuster <akuster@mvista.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/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <platforms/4xx/ibm405gpr.h>
+#include <asm/ibm4xx.h>
+#include <asm/ocp.h>
+#include <asm/ppc4xx_pic.h>
+
+static struct ocp_func_emac_data ibm405gpr_emac0_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = -1, /* ZMII device index */
+ .zmii_mux = 0, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 0, /* MAL rx channel number */
+ .mal_tx_chan = 0, /* MAL tx channel number */
+ .wol_irq = 9, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+OCP_SYSFS_EMAC_DATA()
+
+static struct ocp_func_mal_data ibm405gpr_mal0_def = {
+ .num_tx_chans = 1, /* Number of TX channels */
+ .num_rx_chans = 1, /* Number of RX channels */
+ .txeob_irq = 11, /* TX End Of Buffer IRQ */
+ .rxeob_irq = 12, /* RX End Of Buffer IRQ */
+ .txde_irq = 13, /* TX Descriptor Error IRQ */
+ .rxde_irq = 14, /* RX Descriptor Error IRQ */
+ .serr_irq = 10, /* MAL System Error IRQ */
+};
+OCP_SYSFS_MAL_DATA()
+
+static struct ocp_func_iic_data ibm405gpr_iic0_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+
+OCP_SYSFS_IIC_DATA()
+
+struct ocp_def core_ocp[] = {
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_OPB,
+ .index = 0,
+ .paddr = 0xEF600000,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = UART0_IO_BASE,
+ .irq = UART0_INT,
+ .pm = IBM_CPM_UART0
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = UART1_IO_BASE,
+ .irq = UART1_INT,
+ .pm = IBM_CPM_UART1
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .paddr = 0xEF600500,
+ .irq = 2,
+ .pm = IBM_CPM_IIC0,
+ .additions = &ibm405gpr_iic0_def,
+ .show = &ocp_show_iic_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_GPIO,
+ .paddr = 0xEF600700,
+ .irq = OCP_IRQ_NA,
+ .pm = IBM_CPM_GPIO0
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_MAL,
+ .paddr = OCP_PADDR_NA,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm405gpr_mal0_def,
+ .show = &ocp_show_mal_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 0,
+ .paddr = EMAC0_BASE,
+ .irq = 15,
+ .pm = IBM_CPM_EMAC0,
+ .additions = &ibm405gpr_emac0_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_INVALID
+ }
+};
+
+/* Polarity and triggering settings for internal interrupt sources */
+struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = {
+ { .polarity = 0xffffe000,
+ .triggering = 0x10000000,
+ .ext_irq_mask = 0x00001fff, /* IRQ7 - IRQ12, IRQ0 - IRQ6 */
+ }
+};
diff --git a/arch/ppc/platforms/4xx/ibm405gpr.h b/arch/ppc/platforms/4xx/ibm405gpr.h
new file mode 100644
index 00000000000..45412fb4368
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm405gpr.h
@@ -0,0 +1,151 @@
+/*
+ * arch/ppc/platforms/4xx/ibm405gpr.h
+ *
+ * Author: Armin Kuster <akuster@mvista.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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBM405GPR_H__
+#define __ASM_IBM405GPR_H__
+
+#include <linux/config.h>
+
+/* ibm405.h at bottom of this file */
+
+/* PCI
+ * PCI Bridge config reg definitions
+ * see 17-19 of manual
+ */
+
+#define PPC405_PCI_CONFIG_ADDR 0xeec00000
+#define PPC405_PCI_CONFIG_DATA 0xeec00004
+
+#define PPC405_PCI_PHY_MEM_BASE 0x80000000 /* hose_a->pci_mem_offset */
+ /* setbat */
+#define PPC405_PCI_MEM_BASE PPC405_PCI_PHY_MEM_BASE /* setbat */
+#define PPC405_PCI_PHY_IO_BASE 0xe8000000 /* setbat */
+#define PPC405_PCI_IO_BASE PPC405_PCI_PHY_IO_BASE /* setbat */
+
+#define PPC405_PCI_LOWER_MEM 0x80000000 /* hose_a->mem_space.start */
+#define PPC405_PCI_UPPER_MEM 0xBfffffff /* hose_a->mem_space.end */
+#define PPC405_PCI_LOWER_IO 0x00000000 /* hose_a->io_space.start */
+#define PPC405_PCI_UPPER_IO 0x0000ffff /* hose_a->io_space.end */
+
+#define PPC405_ISA_IO_BASE PPC405_PCI_IO_BASE
+
+#define PPC4xx_PCI_IO_PADDR ((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_VADDR PPC4xx_PCI_IO_PADDR
+#define PPC4xx_PCI_IO_SIZE ((uint)64*1024)
+#define PPC4xx_PCI_CFG_PADDR ((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_VADDR PPC4xx_PCI_CFG_PADDR
+#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024)
+#define PPC4xx_PCI_LCFG_PADDR ((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_VADDR PPC4xx_PCI_LCFG_PADDR
+#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024)
+#define PPC4xx_ONB_IO_PADDR ((uint)0xef600000)
+#define PPC4xx_ONB_IO_VADDR PPC4xx_ONB_IO_PADDR
+#define PPC4xx_ONB_IO_SIZE ((uint)4*1024)
+
+/* serial port defines */
+#define RS_TABLE_SIZE 2
+
+#define UART0_INT 0
+#define UART1_INT 1
+
+#define PCIL0_BASE 0xEF400000
+#define UART0_IO_BASE 0xEF600300
+#define UART1_IO_BASE 0xEF600400
+#define EMAC0_BASE 0xEF600800
+
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
+
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, \
+ (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
+ iomem_base: (u8 *)UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_DEBUG_IO_BASE UART1_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(1) \
+ STD_UART_OP(0)
+#endif
+
+/* DCR defines */
+#define DCRN_CHCR_BASE 0x0B1
+#define DCRN_CHPSR_BASE 0x0B4
+#define DCRN_CPMSR_BASE 0x0B8
+#define DCRN_CPMFR_BASE 0x0BA
+
+#define CHR0_U0EC 0x00000080 /* Select external clock for UART0 */
+#define CHR0_U1EC 0x00000040 /* Select external clock for UART1 */
+#define CHR0_UDIV 0x0000003E /* UART internal clock divisor */
+#define CHR1_CETE 0x00800000 /* CPU external timer enable */
+
+#define DCRN_CHPSR_BASE 0x0B4
+#define PSR_PLL_FWD_MASK 0xC0000000
+#define PSR_PLL_FDBACK_MASK 0x30000000
+#define PSR_PLL_TUNING_MASK 0x0E000000
+#define PSR_PLB_CPU_MASK 0x01800000
+#define PSR_OPB_PLB_MASK 0x00600000
+#define PSR_PCI_PLB_MASK 0x00180000
+#define PSR_EB_PLB_MASK 0x00060000
+#define PSR_ROM_WIDTH_MASK 0x00018000
+#define PSR_ROM_LOC 0x00004000
+#define PSR_PCI_ASYNC_EN 0x00001000
+#define PSR_PCI_ARBIT_EN 0x00000400
+
+#define IBM_CPM_IIC0 0x80000000 /* IIC interface */
+#define IBM_CPM_PCI 0x40000000 /* PCI bridge */
+#define IBM_CPM_CPU 0x20000000 /* processor core */
+#define IBM_CPM_DMA 0x10000000 /* DMA controller */
+#define IBM_CPM_OPB 0x08000000 /* PLB to OPB bridge */
+#define IBM_CPM_DCP 0x04000000 /* CodePack */
+#define IBM_CPM_EBC 0x02000000 /* ROM/SRAM peripheral controller */
+#define IBM_CPM_SDRAM0 0x01000000 /* SDRAM memory controller */
+#define IBM_CPM_PLB 0x00800000 /* PLB bus arbiter */
+#define IBM_CPM_GPIO0 0x00400000 /* General Purpose IO (??) */
+#define IBM_CPM_UART0 0x00200000 /* serial port 0 */
+#define IBM_CPM_UART1 0x00100000 /* serial port 1 */
+#define IBM_CPM_UIC 0x00080000 /* Universal Interrupt Controller */
+#define IBM_CPM_TMRCLK 0x00040000 /* CPU timers */
+#define IBM_CPM_EMAC0 0x00020000 /* on-chip ethernet MM unit */
+#define DFLT_IBM4xx_PM ~(IBM_CPM_PCI | IBM_CPM_CPU | IBM_CPM_DMA \
+ | IBM_CPM_OPB | IBM_CPM_EBC \
+ | IBM_CPM_SDRAM0 | IBM_CPM_PLB \
+ | IBM_CPM_UIC | IBM_CPM_TMRCLK)
+
+#define DCRN_DMA0_BASE 0x100
+#define DCRN_DMA1_BASE 0x108
+#define DCRN_DMA2_BASE 0x110
+#define DCRN_DMA3_BASE 0x118
+#define DCRNCAP_DMA_SG 1 /* have DMA scatter/gather capability */
+#define DCRN_DMASR_BASE 0x120
+#define DCRN_EBC_BASE 0x012
+#define DCRN_DCP0_BASE 0x014
+#define DCRN_MAL_BASE 0x180
+#define DCRN_OCM0_BASE 0x018
+#define DCRN_PLB0_BASE 0x084
+#define DCRN_PLLMR_BASE 0x0B0
+#define DCRN_POB0_BASE 0x0A0
+#define DCRN_SDRAM0_BASE 0x010
+#define DCRN_UIC0_BASE 0x0C0
+#define UIC0 DCRN_UIC0_BASE
+
+#include <asm/ibm405.h>
+
+#endif /* __ASM_IBM405GPR_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ibm440gp.c b/arch/ppc/platforms/4xx/ibm440gp.c
new file mode 100644
index 00000000000..27615ef8309
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm440gp.c
@@ -0,0 +1,164 @@
+/*
+ * arch/ppc/platforms/4xx/ibm440gp.c
+ *
+ * PPC440GP I/O descriptions
+ *
+ * Matt Porter <mporter@mvista.com>
+ * Copyright 2002-2004 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ * 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/module.h>
+#include <platforms/4xx/ibm440gp.h>
+#include <asm/ocp.h>
+#include <asm/ppc4xx_pic.h>
+
+static struct ocp_func_emac_data ibm440gp_emac0_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 0, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 0, /* MAL rx channel number */
+ .mal_tx_chan = 0, /* MAL tx channel number */
+ .wol_irq = 61, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+
+static struct ocp_func_emac_data ibm440gp_emac1_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 1, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 1, /* MAL rx channel number */
+ .mal_tx_chan = 2, /* MAL tx channel number */
+ .wol_irq = 63, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+OCP_SYSFS_EMAC_DATA()
+
+static struct ocp_func_mal_data ibm440gp_mal0_def = {
+ .num_tx_chans = 4, /* Number of TX channels */
+ .num_rx_chans = 2, /* Number of RX channels */
+ .txeob_irq = 10, /* TX End Of Buffer IRQ */
+ .rxeob_irq = 11, /* RX End Of Buffer IRQ */
+ .txde_irq = 33, /* TX Descriptor Error IRQ */
+ .rxde_irq = 34, /* RX Descriptor Error IRQ */
+ .serr_irq = 32, /* MAL System Error IRQ */
+};
+OCP_SYSFS_MAL_DATA()
+
+static struct ocp_func_iic_data ibm440gp_iic0_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+
+static struct ocp_func_iic_data ibm440gp_iic1_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+OCP_SYSFS_IIC_DATA()
+
+struct ocp_def core_ocp[] = {
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_OPB,
+ .index = 0,
+ .paddr = 0x0000000140000000ULL,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = PPC440GP_UART0_ADDR,
+ .irq = UART0_INT,
+ .pm = IBM_CPM_UART0,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = PPC440GP_UART1_ADDR,
+ .irq = UART1_INT,
+ .pm = IBM_CPM_UART1,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .index = 0,
+ .paddr = 0x0000000140000400ULL,
+ .irq = 2,
+ .pm = IBM_CPM_IIC0,
+ .additions = &ibm440gp_iic0_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .index = 1,
+ .paddr = 0x0000000140000500ULL,
+ .irq = 3,
+ .pm = IBM_CPM_IIC1,
+ .additions = &ibm440gp_iic1_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_GPIO,
+ .index = 0,
+ .paddr = 0x0000000140000700ULL,
+ .irq = OCP_IRQ_NA,
+ .pm = IBM_CPM_GPIO0,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_MAL,
+ .paddr = OCP_PADDR_NA,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440gp_mal0_def,
+ .show = &ocp_show_mal_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 0,
+ .paddr = 0x0000000140000800ULL,
+ .irq = 60,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440gp_emac0_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 1,
+ .paddr = 0x0000000140000900ULL,
+ .irq = 62,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440gp_emac1_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_ZMII,
+ .paddr = 0x0000000140000780ULL,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_INVALID
+ }
+};
+
+/* Polarity and triggering settings for internal interrupt sources */
+struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = {
+ { .polarity = 0xfffffe03,
+ .triggering = 0x01c00000,
+ .ext_irq_mask = 0x000001fc, /* IRQ0 - IRQ6 */
+ },
+ { .polarity = 0xffffc0ff,
+ .triggering = 0x00ff8000,
+ .ext_irq_mask = 0x00003f00, /* IRQ7 - IRQ12 */
+ },
+};
diff --git a/arch/ppc/platforms/4xx/ibm440gp.h b/arch/ppc/platforms/4xx/ibm440gp.h
new file mode 100644
index 00000000000..ae1efc03b29
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm440gp.h
@@ -0,0 +1,66 @@
+/*
+ * arch/ppc/platforms/4xx/ibm440gp.h
+ *
+ * PPC440GP definitions
+ *
+ * Roland Dreier <roland@digitalvampire.org>
+ *
+ * Copyright 2002 Roland Dreier
+ *
+ * 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 file contains code that was originally in the files ibm44x.h
+ * and ebony.h, which were written by Matt Porter of MontaVista Software Inc.
+ */
+
+#ifdef __KERNEL__
+#ifndef __PPC_PLATFORMS_IBM440GP_H
+#define __PPC_PLATFORMS_IBM440GP_H
+
+#include <linux/config.h>
+
+/* UART */
+#define PPC440GP_UART0_ADDR 0x0000000140000200ULL
+#define PPC440GP_UART1_ADDR 0x0000000140000300ULL
+#define UART0_INT 0
+#define UART1_INT 1
+
+/* Clock and Power Management */
+#define IBM_CPM_IIC0 0x80000000 /* IIC interface */
+#define IBM_CPM_IIC1 0x40000000 /* IIC interface */
+#define IBM_CPM_PCI 0x20000000 /* PCI bridge */
+#define IBM_CPM_CPU 0x02000000 /* processor core */
+#define IBM_CPM_DMA 0x01000000 /* DMA controller */
+#define IBM_CPM_BGO 0x00800000 /* PLB to OPB bus arbiter */
+#define IBM_CPM_BGI 0x00400000 /* OPB to PLB bridge */
+#define IBM_CPM_EBC 0x00200000 /* External Bux Controller */
+#define IBM_CPM_EBM 0x00100000 /* Ext Bus Master Interface */
+#define IBM_CPM_DMC 0x00080000 /* SDRAM peripheral controller */
+#define IBM_CPM_PLB 0x00040000 /* PLB bus arbiter */
+#define IBM_CPM_SRAM 0x00020000 /* SRAM memory controller */
+#define IBM_CPM_PPM 0x00002000 /* PLB Performance Monitor */
+#define IBM_CPM_UIC1 0x00001000 /* Universal Interrupt Controller */
+#define IBM_CPM_GPIO0 0x00000800 /* General Purpose IO (??) */
+#define IBM_CPM_GPT 0x00000400 /* General Purpose Timers */
+#define IBM_CPM_UART0 0x00000200 /* serial port 0 */
+#define IBM_CPM_UART1 0x00000100 /* serial port 1 */
+#define IBM_CPM_UIC0 0x00000080 /* Universal Interrupt Controller */
+#define IBM_CPM_TMRCLK 0x00000040 /* CPU timers */
+
+#define DFLT_IBM4xx_PM ~(IBM_CPM_UIC | IBM_CPM_UIC1 | IBM_CPM_CPU \
+ | IBM_CPM_EBC | IBM_CPM_SRAM | IBM_CPM_BGO \
+ | IBM_CPM_EBM | IBM_CPM_PLB | IBM_CPM_OPB \
+ | IBM_CPM_TMRCLK | IBM_CPM_DMA | IBM_CPM_PCI)
+/*
+ * Serial port defines
+ */
+#define RS_TABLE_SIZE 2
+
+#include <asm/ibm44x.h>
+#include <syslib/ibm440gp_common.h>
+
+#endif /* __PPC_PLATFORMS_IBM440GP_H */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ibm440gx.c b/arch/ppc/platforms/4xx/ibm440gx.c
new file mode 100644
index 00000000000..1f38f42835b
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm440gx.c
@@ -0,0 +1,234 @@
+/*
+ * arch/ppc/platforms/4xx/ibm440gx.c
+ *
+ * PPC440GX I/O descriptions
+ *
+ * Matt Porter <mporter@mvista.com>
+ * Copyright 2002-2004 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ * 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/module.h>
+#include <platforms/4xx/ibm440gx.h>
+#include <asm/ocp.h>
+#include <asm/ppc4xx_pic.h>
+
+static struct ocp_func_emac_data ibm440gx_emac0_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 0, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 0, /* MAL rx channel number */
+ .mal_tx_chan = 0, /* MAL tx channel number */
+ .wol_irq = 61, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+
+static struct ocp_func_emac_data ibm440gx_emac1_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 1, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 1, /* MAL rx channel number */
+ .mal_tx_chan = 1, /* MAL tx channel number */
+ .wol_irq = 63, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+
+static struct ocp_func_emac_data ibm440gx_emac2_def = {
+ .rgmii_idx = 0, /* RGMII device index */
+ .rgmii_mux = 0, /* RGMII input of this EMAC */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 2, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 2, /* MAL rx channel number */
+ .mal_tx_chan = 2, /* MAL tx channel number */
+ .wol_irq = 65, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = 0, /* TAH device index */
+ .jumbo = 1, /* Jumbo frames supported */
+};
+
+static struct ocp_func_emac_data ibm440gx_emac3_def = {
+ .rgmii_idx = 0, /* RGMII device index */
+ .rgmii_mux = 1, /* RGMII input of this EMAC */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 3, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 3, /* MAL rx channel number */
+ .mal_tx_chan = 3, /* MAL tx channel number */
+ .wol_irq = 67, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = 1, /* TAH device index */
+ .jumbo = 1, /* Jumbo frames supported */
+};
+OCP_SYSFS_EMAC_DATA()
+
+static struct ocp_func_mal_data ibm440gx_mal0_def = {
+ .num_tx_chans = 4, /* Number of TX channels */
+ .num_rx_chans = 4, /* Number of RX channels */
+ .txeob_irq = 10, /* TX End Of Buffer IRQ */
+ .rxeob_irq = 11, /* RX End Of Buffer IRQ */
+ .txde_irq = 33, /* TX Descriptor Error IRQ */
+ .rxde_irq = 34, /* RX Descriptor Error IRQ */
+ .serr_irq = 32, /* MAL System Error IRQ */
+};
+OCP_SYSFS_MAL_DATA()
+
+static struct ocp_func_iic_data ibm440gx_iic0_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+
+static struct ocp_func_iic_data ibm440gx_iic1_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+OCP_SYSFS_IIC_DATA()
+
+struct ocp_def core_ocp[] = {
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_OPB,
+ .index = 0,
+ .paddr = 0x0000000140000000ULL,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = PPC440GX_UART0_ADDR,
+ .irq = UART0_INT,
+ .pm = IBM_CPM_UART0,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = PPC440GX_UART1_ADDR,
+ .irq = UART1_INT,
+ .pm = IBM_CPM_UART1,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .index = 0,
+ .paddr = 0x0000000140000400ULL,
+ .irq = 2,
+ .pm = IBM_CPM_IIC0,
+ .additions = &ibm440gx_iic0_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .index = 1,
+ .paddr = 0x0000000140000500ULL,
+ .irq = 3,
+ .pm = IBM_CPM_IIC1,
+ .additions = &ibm440gx_iic1_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_GPIO,
+ .index = 0,
+ .paddr = 0x0000000140000700ULL,
+ .irq = OCP_IRQ_NA,
+ .pm = IBM_CPM_GPIO0,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_MAL,
+ .paddr = OCP_PADDR_NA,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440gx_mal0_def,
+ .show = &ocp_show_mal_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 0,
+ .paddr = 0x0000000140000800ULL,
+ .irq = 60,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440gx_emac0_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 1,
+ .paddr = 0x0000000140000900ULL,
+ .irq = 62,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440gx_emac1_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 2,
+ .paddr = 0x0000000140000C00ULL,
+ .irq = 64,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440gx_emac2_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 3,
+ .paddr = 0x0000000140000E00ULL,
+ .irq = 66,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440gx_emac3_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_RGMII,
+ .paddr = 0x0000000140000790ULL,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_ZMII,
+ .paddr = 0x0000000140000780ULL,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_TAH,
+ .index = 0,
+ .paddr = 0x0000000140000b50ULL,
+ .irq = 68,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_TAH,
+ .index = 1,
+ .paddr = 0x0000000140000d50ULL,
+ .irq = 69,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_INVALID
+ }
+};
+
+/* Polarity and triggering settings for internal interrupt sources */
+struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = {
+ { .polarity = 0xfffffe03,
+ .triggering = 0x01c00000,
+ .ext_irq_mask = 0x000001fc, /* IRQ0 - IRQ6 */
+ },
+ { .polarity = 0xffffc0ff,
+ .triggering = 0x00ff8000,
+ .ext_irq_mask = 0x00003f00, /* IRQ7 - IRQ12 */
+ },
+ { .polarity = 0xffff83ff,
+ .triggering = 0x000f83c0,
+ .ext_irq_mask = 0x00007c00, /* IRQ13 - IRQ17 */
+ },
+};
diff --git a/arch/ppc/platforms/4xx/ibm440gx.h b/arch/ppc/platforms/4xx/ibm440gx.h
new file mode 100644
index 00000000000..0b59d8dcd03
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm440gx.h
@@ -0,0 +1,74 @@
+/*
+ * arch/ppc/platforms/ibm440gx.h
+ *
+ * PPC440GX definitions
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002 Roland Dreier
+ * Copyright 2003 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.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __PPC_PLATFORMS_IBM440GX_H
+#define __PPC_PLATFORMS_IBM440GX_H
+
+#include <linux/config.h>
+
+#include <asm/ibm44x.h>
+
+/* UART */
+#define PPC440GX_UART0_ADDR 0x0000000140000200ULL
+#define PPC440GX_UART1_ADDR 0x0000000140000300ULL
+#define UART0_INT 0
+#define UART1_INT 1
+
+/* Clock and Power Management */
+#define IBM_CPM_IIC0 0x80000000 /* IIC interface */
+#define IBM_CPM_IIC1 0x40000000 /* IIC interface */
+#define IBM_CPM_PCI 0x20000000 /* PCI bridge */
+#define IBM_CPM_RGMII 0x10000000 /* RGMII */
+#define IBM_CPM_TAHOE0 0x08000000 /* TAHOE 0 */
+#define IBM_CPM_TAHOE1 0x04000000 /* TAHOE 1 */
+#define IBM_CPM_CPU 0x02000000 /* processor core */
+#define IBM_CPM_DMA 0x01000000 /* DMA controller */
+#define IBM_CPM_BGO 0x00800000 /* PLB to OPB bus arbiter */
+#define IBM_CPM_BGI 0x00400000 /* OPB to PLB bridge */
+#define IBM_CPM_EBC 0x00200000 /* External Bux Controller */
+#define IBM_CPM_EBM 0x00100000 /* Ext Bus Master Interface */
+#define IBM_CPM_DMC 0x00080000 /* SDRAM peripheral controller */
+#define IBM_CPM_PLB 0x00040000 /* PLB bus arbiter */
+#define IBM_CPM_SRAM 0x00020000 /* SRAM memory controller */
+#define IBM_CPM_PPM 0x00002000 /* PLB Performance Monitor */
+#define IBM_CPM_UIC1 0x00001000 /* Universal Interrupt Controller */
+#define IBM_CPM_GPIO0 0x00000800 /* General Purpose IO (??) */
+#define IBM_CPM_GPT 0x00000400 /* General Purpose Timers */
+#define IBM_CPM_UART0 0x00000200 /* serial port 0 */
+#define IBM_CPM_UART1 0x00000100 /* serial port 1 */
+#define IBM_CPM_UIC0 0x00000080 /* Universal Interrupt Controller */
+#define IBM_CPM_TMRCLK 0x00000040 /* CPU timers */
+#define IBM_CPM_EMAC0 0x00000020 /* EMAC 0 */
+#define IBM_CPM_EMAC1 0x00000010 /* EMAC 1 */
+#define IBM_CPM_EMAC2 0x00000008 /* EMAC 2 */
+#define IBM_CPM_EMAC3 0x00000004 /* EMAC 3 */
+
+#define DFLT_IBM4xx_PM ~(IBM_CPM_UIC | IBM_CPM_UIC1 | IBM_CPM_CPU \
+ | IBM_CPM_EBC | IBM_CPM_SRAM | IBM_CPM_BGO \
+ | IBM_CPM_EBM | IBM_CPM_PLB | IBM_CPM_OPB \
+ | IBM_CPM_TMRCLK | IBM_CPM_DMA | IBM_CPM_PCI \
+ | IBM_CPM_TAHOE0 | IBM_CPM_TAHOE1 \
+ | IBM_CPM_EMAC0 | IBM_CPM_EMAC1 \
+ | IBM_CPM_EMAC2 | IBM_CPM_EMAC3 )
+/*
+ * Serial port defines
+ */
+#define RS_TABLE_SIZE 2
+
+#endif /* __PPC_PLATFORMS_IBM440GX_H */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ibm440sp.c b/arch/ppc/platforms/4xx/ibm440sp.c
new file mode 100644
index 00000000000..a203efb47ab
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm440sp.c
@@ -0,0 +1,131 @@
+/*
+ * arch/ppc/platforms/4xx/ibm440sp.c
+ *
+ * PPC440SP I/O descriptions
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2002-2005 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ * 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/module.h>
+#include <platforms/4xx/ibm440sp.h>
+#include <asm/ocp.h>
+
+static struct ocp_func_emac_data ibm440sp_emac0_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = -1, /* No ZMII */
+ .zmii_mux = -1, /* No ZMII */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 0, /* MAL rx channel number */
+ .mal_tx_chan = 0, /* MAL tx channel number */
+ .wol_irq = 61, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+ .jumbo = 1, /* Jumbo frames supported */
+};
+OCP_SYSFS_EMAC_DATA()
+
+static struct ocp_func_mal_data ibm440sp_mal0_def = {
+ .num_tx_chans = 4, /* Number of TX channels */
+ .num_rx_chans = 4, /* Number of RX channels */
+ .txeob_irq = 38, /* TX End Of Buffer IRQ */
+ .rxeob_irq = 39, /* RX End Of Buffer IRQ */
+ .txde_irq = 34, /* TX Descriptor Error IRQ */
+ .rxde_irq = 35, /* RX Descriptor Error IRQ */
+ .serr_irq = 33, /* MAL System Error IRQ */
+};
+OCP_SYSFS_MAL_DATA()
+
+static struct ocp_func_iic_data ibm440sp_iic0_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+
+static struct ocp_func_iic_data ibm440sp_iic1_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+OCP_SYSFS_IIC_DATA()
+
+struct ocp_def core_ocp[] = {
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_OPB,
+ .index = 0,
+ .paddr = 0x0000000140000000ULL,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = PPC440SP_UART0_ADDR,
+ .irq = UART0_INT,
+ .pm = IBM_CPM_UART0,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = PPC440SP_UART1_ADDR,
+ .irq = UART1_INT,
+ .pm = IBM_CPM_UART1,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 2,
+ .paddr = PPC440SP_UART2_ADDR,
+ .irq = UART2_INT,
+ .pm = IBM_CPM_UART2,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .index = 0,
+ .paddr = 0x00000001f0000400ULL,
+ .irq = 2,
+ .pm = IBM_CPM_IIC0,
+ .additions = &ibm440sp_iic0_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .index = 1,
+ .paddr = 0x00000001f0000500ULL,
+ .irq = 3,
+ .pm = IBM_CPM_IIC1,
+ .additions = &ibm440sp_iic1_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_GPIO,
+ .index = 0,
+ .paddr = 0x00000001f0000700ULL,
+ .irq = OCP_IRQ_NA,
+ .pm = IBM_CPM_GPIO0,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_MAL,
+ .paddr = OCP_PADDR_NA,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440sp_mal0_def,
+ .show = &ocp_show_mal_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 0,
+ .paddr = 0x00000001f0000800ULL,
+ .irq = 60,
+ .pm = OCP_CPM_NA,
+ .additions = &ibm440sp_emac0_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_INVALID
+ }
+};
diff --git a/arch/ppc/platforms/4xx/ibm440sp.h b/arch/ppc/platforms/4xx/ibm440sp.h
new file mode 100644
index 00000000000..c71e46a18b9
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibm440sp.h
@@ -0,0 +1,64 @@
+/*
+ * arch/ppc/platforms/4xx/ibm440sp.h
+ *
+ * PPC440SP definitions
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright 2004-2005 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __PPC_PLATFORMS_IBM440SP_H
+#define __PPC_PLATFORMS_IBM440SP_H
+
+#include <linux/config.h>
+
+#include <asm/ibm44x.h>
+
+/* UART */
+#define PPC440SP_UART0_ADDR 0x00000001f0000200ULL
+#define PPC440SP_UART1_ADDR 0x00000001f0000300ULL
+#define PPC440SP_UART2_ADDR 0x00000001f0000600ULL
+#define UART0_INT 0
+#define UART1_INT 1
+#define UART2_INT 2
+
+/* Clock and Power Management */
+#define IBM_CPM_IIC0 0x80000000 /* IIC interface */
+#define IBM_CPM_IIC1 0x40000000 /* IIC interface */
+#define IBM_CPM_PCI 0x20000000 /* PCI bridge */
+#define IBM_CPM_CPU 0x02000000 /* processor core */
+#define IBM_CPM_DMA 0x01000000 /* DMA controller */
+#define IBM_CPM_BGO 0x00800000 /* PLB to OPB bus arbiter */
+#define IBM_CPM_BGI 0x00400000 /* OPB to PLB bridge */
+#define IBM_CPM_EBC 0x00200000 /* External Bux Controller */
+#define IBM_CPM_EBM 0x00100000 /* Ext Bus Master Interface */
+#define IBM_CPM_DMC 0x00080000 /* SDRAM peripheral controller */
+#define IBM_CPM_PLB 0x00040000 /* PLB bus arbiter */
+#define IBM_CPM_SRAM 0x00020000 /* SRAM memory controller */
+#define IBM_CPM_PPM 0x00002000 /* PLB Performance Monitor */
+#define IBM_CPM_UIC1 0x00001000 /* Universal Interrupt Controller */
+#define IBM_CPM_GPIO0 0x00000800 /* General Purpose IO (??) */
+#define IBM_CPM_GPT 0x00000400 /* General Purpose Timers */
+#define IBM_CPM_UART0 0x00000200 /* serial port 0 */
+#define IBM_CPM_UART1 0x00000100 /* serial port 1 */
+#define IBM_CPM_UART2 0x00000100 /* serial port 1 */
+#define IBM_CPM_UIC0 0x00000080 /* Universal Interrupt Controller */
+#define IBM_CPM_TMRCLK 0x00000040 /* CPU timers */
+#define IBM_CPM_EMAC0 0x00000020 /* EMAC 0 */
+
+#define DFLT_IBM4xx_PM ~(IBM_CPM_UIC | IBM_CPM_UIC1 | IBM_CPM_CPU \
+ | IBM_CPM_EBC | IBM_CPM_SRAM | IBM_CPM_BGO \
+ | IBM_CPM_EBM | IBM_CPM_PLB | IBM_CPM_OPB \
+ | IBM_CPM_TMRCLK | IBM_CPM_DMA | IBM_CPM_PCI \
+ | IBM_CPM_TAHOE0 | IBM_CPM_TAHOE1 \
+ | IBM_CPM_EMAC0 | IBM_CPM_EMAC1 \
+ | IBM_CPM_EMAC2 | IBM_CPM_EMAC3 )
+#endif /* __PPC_PLATFORMS_IBM440SP_H */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ibmnp405h.c b/arch/ppc/platforms/4xx/ibmnp405h.c
new file mode 100644
index 00000000000..ecdc5be6ae2
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibmnp405h.c
@@ -0,0 +1,172 @@
+/*
+ * arch/ppc/platforms/4xx/ibmnp405h.c
+ *
+ * Author: Armin Kuster <akuster@mvista.com>
+ *
+ * 2000-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/config.h>
+#include <linux/init.h>
+#include <asm/ocp.h>
+#include <platforms/4xx/ibmnp405h.h>
+
+static struct ocp_func_emac_data ibmnp405h_emac0_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 0, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 0, /* MAL rx channel number */
+ .mal_tx_chan = 0, /* MAL tx channel number */
+ .wol_irq = 41, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+
+static struct ocp_func_emac_data ibmnp405h_emac1_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 1, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 1, /* MAL rx channel number */
+ .mal_tx_chan = 1, /* MAL tx channel number */
+ .wol_irq = 41, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+static struct ocp_func_emac_data ibmnp405h_emac2_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 2, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 2, /* MAL rx channel number */
+ .mal_tx_chan = 2, /* MAL tx channel number */
+ .wol_irq = 41, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+static struct ocp_func_emac_data ibmnp405h_emac3_def = {
+ .rgmii_idx = -1, /* No RGMII */
+ .rgmii_mux = -1, /* No RGMII */
+ .zmii_idx = 0, /* ZMII device index */
+ .zmii_mux = 3, /* ZMII input of this EMAC */
+ .mal_idx = 0, /* MAL device index */
+ .mal_rx_chan = 3, /* MAL rx channel number */
+ .mal_tx_chan = 3, /* MAL tx channel number */
+ .wol_irq = 41, /* WOL interrupt number */
+ .mdio_idx = -1, /* No shared MDIO */
+ .tah_idx = -1, /* No TAH */
+};
+OCP_SYSFS_EMAC_DATA()
+
+static struct ocp_func_mal_data ibmnp405h_mal0_def = {
+ .num_tx_chans = 8, /* Number of TX channels */
+ .num_rx_chans = 4, /* Number of RX channels */
+ .txeob_irq = 17, /* TX End Of Buffer IRQ */
+ .rxeob_irq = 18, /* RX End Of Buffer IRQ */
+ .txde_irq = 46, /* TX Descriptor Error IRQ */
+ .rxde_irq = 47, /* RX Descriptor Error IRQ */
+ .serr_irq = 45, /* MAL System Error IRQ */
+};
+OCP_SYSFS_MAL_DATA()
+
+static struct ocp_func_iic_data ibmnp405h_iic0_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+OCP_SYSFS_IIC_DATA()
+
+struct ocp_def core_ocp[] = {
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_OPB,
+ .index = 0,
+ .paddr = 0xEF600000,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = UART0_IO_BASE,
+ .irq = UART0_INT,
+ .pm = IBM_CPM_UART0
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = UART1_IO_BASE,
+ .irq = UART1_INT,
+ .pm = IBM_CPM_UART1
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .paddr = 0xEF600500,
+ .irq = 2,
+ .pm = IBM_CPM_IIC0,
+ .additions = &ibmnp405h_iic0_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_GPIO,
+ .paddr = 0xEF600700,
+ .irq = OCP_IRQ_NA,
+ .pm = IBM_CPM_GPIO0
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_MAL,
+ .paddr = OCP_PADDR_NA,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ .additions = &ibmnp405h_mal0_def,
+ .show = &ocp_show_mal_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 0,
+ .paddr = EMAC0_BASE,
+ .irq = 37,
+ .pm = IBM_CPM_EMAC0,
+ .additions = &ibmnp405h_emac0_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 1,
+ .paddr = 0xEF600900,
+ .irq = 38,
+ .pm = IBM_CPM_EMAC1,
+ .additions = &ibmnp405h_emac1_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 2,
+ .paddr = 0xEF600a00,
+ .irq = 39,
+ .pm = IBM_CPM_EMAC2,
+ .additions = &ibmnp405h_emac2_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_EMAC,
+ .index = 3,
+ .paddr = 0xEF600b00,
+ .irq = 40,
+ .pm = IBM_CPM_EMAC3,
+ .additions = &ibmnp405h_emac3_def,
+ .show = &ocp_show_emac_data,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_ZMII,
+ .paddr = 0xEF600C10,
+ .irq = OCP_IRQ_NA,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_INVALID
+ }
+};
diff --git a/arch/ppc/platforms/4xx/ibmnp405h.h b/arch/ppc/platforms/4xx/ibmnp405h.h
new file mode 100644
index 00000000000..e2c2b06128c
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibmnp405h.h
@@ -0,0 +1,157 @@
+/*
+ * arch/ppc/platforms/4xx/ibmnp405h.h
+ *
+ * Author: Armin Kuster <akuster@mvista.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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBMNP405H_H__
+#define __ASM_IBMNP405H_H__
+
+#include <linux/config.h>
+
+/* ibm405.h at bottom of this file */
+
+#define PPC405_PCI_CONFIG_ADDR 0xeec00000
+#define PPC405_PCI_CONFIG_DATA 0xeec00004
+#define PPC405_PCI_PHY_MEM_BASE 0x80000000 /* hose_a->pci_mem_offset */
+ /* setbat */
+#define PPC405_PCI_MEM_BASE PPC405_PCI_PHY_MEM_BASE /* setbat */
+#define PPC405_PCI_PHY_IO_BASE 0xe8000000 /* setbat */
+#define PPC405_PCI_IO_BASE PPC405_PCI_PHY_IO_BASE /* setbat */
+
+#define PPC405_PCI_LOWER_MEM 0x00000000 /* hose_a->mem_space.start */
+#define PPC405_PCI_UPPER_MEM 0xBfffffff /* hose_a->mem_space.end */
+#define PPC405_PCI_LOWER_IO 0x00000000 /* hose_a->io_space.start */
+#define PPC405_PCI_UPPER_IO 0x0000ffff /* hose_a->io_space.end */
+
+#define PPC405_ISA_IO_BASE PPC405_PCI_IO_BASE
+
+#define PPC4xx_PCI_IO_ADDR ((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_SIZE ((uint)64*1024)
+#define PPC4xx_PCI_CFG_ADDR ((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_SIZE ((uint)4*1024)
+#define PPC4xx_PCI_LCFG_ADDR ((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_SIZE ((uint)4*1024)
+#define PPC4xx_ONB_IO_ADDR ((uint)0xef600000)
+#define PPC4xx_ONB_IO_SIZE ((uint)4*1024)
+
+/* serial port defines */
+#define RS_TABLE_SIZE 4
+
+#define UART0_INT 0
+#define UART1_INT 1
+#define PCIL0_BASE 0xEF400000
+#define UART0_IO_BASE 0xEF600300
+#define UART1_IO_BASE 0xEF600400
+#define OPB0_BASE 0xEF600600
+#define EMAC0_BASE 0xEF600800
+
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i]
+
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, \
+ (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
+ iomem_base:(u8 *) UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(1) \
+ STD_UART_OP(0)
+#endif
+
+/* DCR defines */
+/* ------------------------------------------------------------------------- */
+
+#define DCRN_CHCR_BASE 0x0F1
+#define DCRN_CHPSR_BASE 0x0B4
+#define DCRN_CPMSR_BASE 0x0BA
+#define DCRN_CPMFR_BASE 0x0B9
+#define DCRN_CPMER_BASE 0x0B8
+
+/* CPM Clocking & Power Mangement defines */
+#define IBM_CPM_PCI 0x40000000 /* PCI */
+#define IBM_CPM_EMAC2 0x20000000 /* EMAC 2 MII */
+#define IBM_CPM_EMAC3 0x04000000 /* EMAC 3 MII */
+#define IBM_CPM_EMAC0 0x00800000 /* EMAC 0 MII */
+#define IBM_CPM_EMAC1 0x00100000 /* EMAC 1 MII */
+#define IBM_CPM_EMMII 0 /* Shift value for MII */
+#define IBM_CPM_EMRX 1 /* Shift value for recv */
+#define IBM_CPM_EMTX 2 /* Shift value for MAC */
+#define IBM_CPM_UIC1 0x00020000 /* Universal Interrupt Controller */
+#define IBM_CPM_UIC0 0x00010000 /* Universal Interrupt Controller */
+#define IBM_CPM_CPU 0x00008000 /* processor core */
+#define IBM_CPM_EBC 0x00004000 /* ROM/SRAM peripheral controller */
+#define IBM_CPM_SDRAM0 0x00002000 /* SDRAM memory controller */
+#define IBM_CPM_GPIO0 0x00001000 /* General Purpose IO (??) */
+#define IBM_CPM_HDLC 0x00000800 /* HDCL */
+#define IBM_CPM_TMRCLK 0x00000400 /* CPU timers */
+#define IBM_CPM_PLB 0x00000100 /* PLB bus arbiter */
+#define IBM_CPM_OPB 0x00000080 /* PLB to OPB bridge */
+#define IBM_CPM_DMA 0x00000040 /* DMA controller */
+#define IBM_CPM_IIC0 0x00000010 /* IIC interface */
+#define IBM_CPM_UART0 0x00000002 /* serial port 0 */
+#define IBM_CPM_UART1 0x00000001 /* serial port 1 */
+/* this is the default setting for devices put to sleep when booting */
+
+#define DFLT_IBM4xx_PM ~(IBM_CPM_UIC0 | IBM_CPM_UIC1 | IBM_CPM_CPU \
+ | IBM_CPM_EBC | IBM_CPM_SDRAM0 | IBM_CPM_PLB \
+ | IBM_CPM_OPB | IBM_CPM_TMRCLK | IBM_CPM_DMA \
+ | IBM_CPM_EMAC0 | IBM_CPM_EMAC1 | IBM_CPM_EMAC2 \
+ | IBM_CPM_EMAC3 | IBM_CPM_PCI)
+
+#define DCRN_DMA0_BASE 0x100
+#define DCRN_DMA1_BASE 0x108
+#define DCRN_DMA2_BASE 0x110
+#define DCRN_DMA3_BASE 0x118
+#define DCRNCAP_DMA_SG 1 /* have DMA scatter/gather capability */
+#define DCRN_DMASR_BASE 0x120
+#define DCRN_EBC_BASE 0x012
+#define DCRN_DCP0_BASE 0x014
+#define DCRN_MAL_BASE 0x180
+#define DCRN_OCM0_BASE 0x018
+#define DCRN_PLB0_BASE 0x084
+#define DCRN_PLLMR_BASE 0x0B0
+#define DCRN_POB0_BASE 0x0A0
+#define DCRN_SDRAM0_BASE 0x010
+#define DCRN_UIC0_BASE 0x0C0
+#define DCRN_UIC1_BASE 0x0D0
+#define DCRN_CPC0_EPRCSR 0x0F3
+
+#define UIC0_UIC1NC 0x00000002
+
+#define CHR1_CETE 0x00000004 /* CPU external timer enable */
+#define UIC0 DCRN_UIC0_BASE
+#define UIC1 DCRN_UIC1_BASE
+
+#undef NR_UICS
+#define NR_UICS 2
+
+/* EMAC DCRN's FIXME: armin */
+#define DCRN_MALRXCTP2R(base) ((base) + 0x42) /* Channel Rx 2 Channel Table Pointer */
+#define DCRN_MALRXCTP3R(base) ((base) + 0x43) /* Channel Rx 3 Channel Table Pointer */
+#define DCRN_MALTXCTP4R(base) ((base) + 0x24) /* Channel Tx 4 Channel Table Pointer */
+#define DCRN_MALTXCTP5R(base) ((base) + 0x25) /* Channel Tx 5 Channel Table Pointer */
+#define DCRN_MALTXCTP6R(base) ((base) + 0x26) /* Channel Tx 6 Channel Table Pointer */
+#define DCRN_MALTXCTP7R(base) ((base) + 0x27) /* Channel Tx 7 Channel Table Pointer */
+#define DCRN_MALRCBS2(base) ((base) + 0x62) /* Channel Rx 2 Channel Buffer Size */
+#define DCRN_MALRCBS3(base) ((base) + 0x63) /* Channel Rx 3 Channel Buffer Size */
+
+#include <asm/ibm405.h>
+
+#endif /* __ASM_IBMNP405H_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ibmstb4.c b/arch/ppc/platforms/4xx/ibmstb4.c
new file mode 100644
index 00000000000..874d16bab73
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibmstb4.c
@@ -0,0 +1,83 @@
+/*
+ * arch/ppc/platforms/4xx/ibmstb4.c
+ *
+ * Author: Armin Kuster <akuster@mvista.com>
+ *
+ * 2000-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.
+ */
+
+#include <linux/init.h>
+#include <asm/ocp.h>
+#include <platforms/4xx/ibmstb4.h>
+
+static struct ocp_func_iic_data ibmstb4_iic0_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+
+static struct ocp_func_iic_data ibmstb4_iic1_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+OCP_SYSFS_IIC_DATA()
+
+struct ocp_def core_ocp[] __initdata = {
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = UART0_IO_BASE,
+ .irq = UART0_INT,
+ .pm = IBM_CPM_UART0,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = UART1_IO_BASE,
+ .irq = UART1_INT,
+ .pm = IBM_CPM_UART1,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 2,
+ .paddr = UART2_IO_BASE,
+ .irq = UART2_INT,
+ .pm = IBM_CPM_UART2,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .paddr = IIC0_BASE,
+ .irq = IIC0_IRQ,
+ .pm = IBM_CPM_IIC0,
+ .additions = &ibmstb4_iic0_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .paddr = IIC1_BASE,
+ .irq = IIC1_IRQ,
+ .pm = IBM_CPM_IIC1,
+ .additions = &ibmstb4_iic1_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_GPIO,
+ .paddr = GPIO0_BASE,
+ .irq = OCP_IRQ_NA,
+ .pm = IBM_CPM_GPIO0,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IDE,
+ .paddr = IDE0_BASE,
+ .irq = IDE0_IRQ,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_USB,
+ .paddr = USB0_BASE,
+ .irq = USB0_IRQ,
+ .pm = OCP_CPM_NA,
+ },
+ { .vendor = OCP_VENDOR_INVALID,
+ }
+};
diff --git a/arch/ppc/platforms/4xx/ibmstb4.h b/arch/ppc/platforms/4xx/ibmstb4.h
new file mode 100644
index 00000000000..bcb4b1ee71f
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibmstb4.h
@@ -0,0 +1,238 @@
+/*
+ * arch/ppc/platforms/4xx/ibmstb4.h
+ *
+ * Author: Armin Kuster <akuster@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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBMSTB4_H__
+#define __ASM_IBMSTB4_H__
+
+#include <linux/config.h>
+
+/* serial port defines */
+#define STB04xxx_IO_BASE ((uint)0xe0000000)
+#define PPC4xx_PCI_IO_ADDR STB04xxx_IO_BASE
+#define PPC4xx_ONB_IO_PADDR STB04xxx_IO_BASE
+#define PPC4xx_ONB_IO_VADDR ((uint)0xe0000000)
+#define PPC4xx_ONB_IO_SIZE ((uint)14*64*1024)
+
+/*
+ * map STB04xxx internal i/o address (0x400x00xx) to an address
+ * which is below the 2GB limit...
+ *
+ * 4000 000x uart1 -> 0xe000 000x
+ * 4001 00xx ppu
+ * 4002 00xx smart card
+ * 4003 000x iic
+ * 4004 000x uart0
+ * 4005 0xxx timer
+ * 4006 00xx gpio
+ * 4007 00xx smart card
+ * 400b 000x iic
+ * 400c 000x scp
+ * 400d 000x modem
+ * 400e 000x uart2
+*/
+#define STB04xxx_MAP_IO_ADDR(a) (((uint)(a)) + (STB04xxx_IO_BASE - 0x40000000))
+
+#define RS_TABLE_SIZE 3
+#define UART0_INT 20
+
+#ifdef __BOOTER__
+#define UART0_IO_BASE 0x40040000
+#else
+#define UART0_IO_BASE 0xe0040000
+#endif
+
+#define UART1_INT 21
+
+#ifdef __BOOTER__
+#define UART1_IO_BASE 0x40000000
+#else
+#define UART1_IO_BASE 0xe0000000
+#endif
+
+#define UART2_INT 31
+#ifdef __BOOTER__
+#define UART2_IO_BASE 0x400e0000
+#else
+#define UART2_IO_BASE 0xe00e0000
+#endif
+
+#define IDE0_BASE 0x400F0000
+#define IDE0_SIZE 0x200
+#define IDE0_IRQ 25
+#define IIC0_BASE 0x40030000
+#define IIC1_BASE 0x400b0000
+#define OPB0_BASE 0x40000000
+#define GPIO0_BASE 0x40060000
+
+#define USB0_IRQ 18
+#define USB0_BASE STB04xxx_MAP_IO_ADDR(0x40010000)
+#define USB0_EXTENT 4096
+
+#define IIC_NUMS 2
+#define UART_NUMS 3
+#define IIC0_IRQ 9
+#define IIC1_IRQ 10
+#define IIC_OWN 0x55
+#define IIC_CLOCK 50
+
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
+
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, \
+ (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
+ iomem_base: (u8 *)UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1) \
+ STD_UART_OP(2)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(1) \
+ STD_UART_OP(0) \
+ STD_UART_OP(2)
+#endif
+
+#if defined(CONFIG_UART0_TTYS2)
+#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(2) \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+#endif
+
+#define DCRN_BE_BASE 0x090
+#define DCRN_DMA0_BASE 0x0C0
+#define DCRN_DMA1_BASE 0x0C8
+#define DCRN_DMA2_BASE 0x0D0
+#define DCRN_DMA3_BASE 0x0D8
+#define DCRNCAP_DMA_CC 1 /* have DMA chained count capability */
+#define DCRN_DMASR_BASE 0x0E0
+#define DCRN_PLB0_BASE 0x054
+#define DCRN_PLB1_BASE 0x064
+#define DCRN_POB0_BASE 0x0B0
+#define DCRN_SCCR_BASE 0x120
+#define DCRN_UIC0_BASE 0x040
+#define DCRN_BE_BASE 0x090
+#define DCRN_DMA0_BASE 0x0C0
+#define DCRN_DMA1_BASE 0x0C8
+#define DCRN_DMA2_BASE 0x0D0
+#define DCRN_DMA3_BASE 0x0D8
+#define DCRN_CIC_BASE 0x030
+#define DCRN_DMASR_BASE 0x0E0
+#define DCRN_EBIMC_BASE 0x070
+#define DCRN_DCRX_BASE 0x020
+#define DCRN_CPMFR_BASE 0x102
+#define DCRN_SCCR_BASE 0x120
+#define UIC0 DCRN_UIC0_BASE
+
+#define IBM_CPM_IIC0 0x80000000 /* IIC 0 interface */
+#define IBM_CPM_USB0 0x40000000 /* IEEE-1284 */
+#define IBM_CPM_IIC1 0x20000000 /* IIC 1 interface */
+#define IBM_CPM_CPU 0x10000000 /* PPC405B3 clock control */
+#define IBM_CPM_AUD 0x08000000 /* Audio Decoder */
+#define IBM_CPM_EBIU 0x04000000 /* External Bus Interface Unit */
+#define IBM_CPM_SDRAM1 0x02000000 /* SDRAM 1 memory controller */
+#define IBM_CPM_DMA 0x01000000 /* DMA controller */
+#define IBM_CPM_DMA1 0x00800000 /* reserved */
+#define IBM_CPM_XPT1 0x00400000 /* reserved */
+#define IBM_CPM_XPT2 0x00200000 /* reserved */
+#define IBM_CPM_UART1 0x00100000 /* Serial 1 / Infrared */
+#define IBM_CPM_UART0 0x00080000 /* Serial 0 / 16550 */
+#define IBM_CPM_EPI 0x00040000 /* DCR Extension */
+#define IBM_CPM_SC0 0x00020000 /* Smart Card 0 */
+#define IBM_CPM_VID 0x00010000 /* reserved */
+#define IBM_CPM_SC1 0x00008000 /* Smart Card 1 */
+#define IBM_CPM_USBSDRA 0x00004000 /* SDRAM 0 memory controller */
+#define IBM_CPM_XPT0 0x00002000 /* Transport - 54 Mhz */
+#define IBM_CPM_CBS 0x00001000 /* Cross Bar Switch */
+#define IBM_CPM_GPT 0x00000800 /* GPTPWM */
+#define IBM_CPM_GPIO0 0x00000400 /* General Purpose IO 0 */
+#define IBM_CPM_DENC 0x00000200 /* Digital video Encoder */
+#define IBM_CPM_TMRCLK 0x00000100 /* CPU timers */
+#define IBM_CPM_XPT27 0x00000080 /* Transport - 27 Mhz */
+#define IBM_CPM_UIC 0x00000040 /* Universal Interrupt Controller */
+#define IBM_CPM_SSP 0x00000010 /* Modem Serial Interface (SSP) */
+#define IBM_CPM_UART2 0x00000008 /* Serial Control Port */
+#define IBM_CPM_DDIO 0x00000004 /* Descrambler */
+#define IBM_CPM_VID2 0x00000002 /* Video Decoder clock domain 2 */
+
+#define DFLT_IBM4xx_PM ~(IBM_CPM_CPU | IBM_CPM_EBIU | IBM_CPM_SDRAM1 \
+ | IBM_CPM_DMA | IBM_CPM_DMA1 | IBM_CPM_CBS \
+ | IBM_CPM_USBSDRA | IBM_CPM_XPT0 | IBM_CPM_TMRCLK \
+ | IBM_CPM_XPT27 | IBM_CPM_UIC )
+
+#define DCRN_BEAR (DCRN_BE_BASE + 0x0) /* Bus Error Address Register */
+#define DCRN_BESR (DCRN_BE_BASE + 0x1) /* Bus Error Syndrome Register */
+/* DCRN_BESR */
+#define BESR_DSES 0x80000000 /* Data-Side Error Status */
+#define BESR_DMES 0x40000000 /* DMA Error Status */
+#define BESR_RWS 0x20000000 /* Read/Write Status */
+#define BESR_ETMASK 0x1C000000 /* Error Type */
+#define ET_PROT 0
+#define ET_PARITY 1
+#define ET_NCFG 2
+#define ET_BUSERR 4
+#define ET_BUSTO 6
+
+#define CHR1_CETE 0x00800000 /* CPU external timer enable */
+#define CHR1_PCIPW 0x00008000 /* PCI Int enable/Peripheral Write enable */
+
+#define DCRN_CICCR (DCRN_CIC_BASE + 0x0) /* CIC Control Register */
+#define DCRN_DMAS1 (DCRN_CIC_BASE + 0x1) /* DMA Select1 Register */
+#define DCRN_DMAS2 (DCRN_CIC_BASE + 0x2) /* DMA Select2 Register */
+#define DCRN_CICVCR (DCRN_CIC_BASE + 0x3) /* CIC Video COntro Register */
+#define DCRN_CICSEL3 (DCRN_CIC_BASE + 0x5) /* CIC Select 3 Register */
+#define DCRN_SGPO (DCRN_CIC_BASE + 0x6) /* CIC GPIO Output Register */
+#define DCRN_SGPOD (DCRN_CIC_BASE + 0x7) /* CIC GPIO OD Register */
+#define DCRN_SGPTC (DCRN_CIC_BASE + 0x8) /* CIC GPIO Tristate Ctrl Reg */
+#define DCRN_SGPI (DCRN_CIC_BASE + 0x9) /* CIC GPIO Input Reg */
+
+#define DCRN_DCRXICR (DCRN_DCRX_BASE + 0x0) /* Internal Control Register */
+#define DCRN_DCRXISR (DCRN_DCRX_BASE + 0x1) /* Internal Status Register */
+#define DCRN_DCRXECR (DCRN_DCRX_BASE + 0x2) /* External Control Register */
+#define DCRN_DCRXESR (DCRN_DCRX_BASE + 0x3) /* External Status Register */
+#define DCRN_DCRXTAR (DCRN_DCRX_BASE + 0x4) /* Target Address Register */
+#define DCRN_DCRXTDR (DCRN_DCRX_BASE + 0x5) /* Target Data Register */
+#define DCRN_DCRXIGR (DCRN_DCRX_BASE + 0x6) /* Interrupt Generation Register */
+#define DCRN_DCRXBCR (DCRN_DCRX_BASE + 0x7) /* Line Buffer Control Register */
+
+#define DCRN_BRCRH0 (DCRN_EBIMC_BASE + 0x0) /* Bus Region Config High 0 */
+#define DCRN_BRCRH1 (DCRN_EBIMC_BASE + 0x1) /* Bus Region Config High 1 */
+#define DCRN_BRCRH2 (DCRN_EBIMC_BASE + 0x2) /* Bus Region Config High 2 */
+#define DCRN_BRCRH3 (DCRN_EBIMC_BASE + 0x3) /* Bus Region Config High 3 */
+#define DCRN_BRCRH4 (DCRN_EBIMC_BASE + 0x4) /* Bus Region Config High 4 */
+#define DCRN_BRCRH5 (DCRN_EBIMC_BASE + 0x5) /* Bus Region Config High 5 */
+#define DCRN_BRCRH6 (DCRN_EBIMC_BASE + 0x6) /* Bus Region Config High 6 */
+#define DCRN_BRCRH7 (DCRN_EBIMC_BASE + 0x7) /* Bus Region Config High 7 */
+#define DCRN_BRCR0 (DCRN_EBIMC_BASE + 0x10) /* BRC 0 */
+#define DCRN_BRCR1 (DCRN_EBIMC_BASE + 0x11) /* BRC 1 */
+#define DCRN_BRCR2 (DCRN_EBIMC_BASE + 0x12) /* BRC 2 */
+#define DCRN_BRCR3 (DCRN_EBIMC_BASE + 0x13) /* BRC 3 */
+#define DCRN_BRCR4 (DCRN_EBIMC_BASE + 0x14) /* BRC 4 */
+#define DCRN_BRCR5 (DCRN_EBIMC_BASE + 0x15) /* BRC 5 */
+#define DCRN_BRCR6 (DCRN_EBIMC_BASE + 0x16) /* BRC 6 */
+#define DCRN_BRCR7 (DCRN_EBIMC_BASE + 0x17) /* BRC 7 */
+#define DCRN_BEAR0 (DCRN_EBIMC_BASE + 0x20) /* Bus Error Address Register */
+#define DCRN_BESR0 (DCRN_EBIMC_BASE + 0x21) /* Bus Error Status Register */
+#define DCRN_BIUCR (DCRN_EBIMC_BASE + 0x2A) /* Bus Interfac Unit Ctrl Reg */
+
+#include <asm/ibm405.h>
+
+#endif /* __ASM_IBMSTB4_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/ibmstbx25.c b/arch/ppc/platforms/4xx/ibmstbx25.c
new file mode 100644
index 00000000000..b895b9cca57
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibmstbx25.c
@@ -0,0 +1,68 @@
+/*
+ * arch/ppc/platforms/4xx/ibmstbx25.c
+ *
+ * Author: Armin Kuster <akuster@mvista.com>
+ *
+ * 2000-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/ocp.h>
+#include <platforms/4xx/ibmstbx25.h>
+#include <asm/ppc4xx_pic.h>
+
+static struct ocp_func_iic_data ibmstbx25_iic0_def = {
+ .fast_mode = 0, /* Use standad mode (100Khz) */
+};
+OCP_SYSFS_IIC_DATA()
+
+struct ocp_def core_ocp[] __initdata = {
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = UART0_IO_BASE,
+ .irq = UART0_INT,
+ .pm = IBM_CPM_UART0,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = UART1_IO_BASE,
+ .irq = UART1_INT,
+ .pm = IBM_CPM_UART1,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_16550,
+ .index = 2,
+ .paddr = UART2_IO_BASE,
+ .irq = UART2_INT,
+ .pm = IBM_CPM_UART2,
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_IIC,
+ .paddr = IIC0_BASE,
+ .irq = IIC0_IRQ,
+ .pm = IBM_CPM_IIC0,
+ .additions = &ibmstbx25_iic0_def,
+ .show = &ocp_show_iic_data
+ },
+ { .vendor = OCP_VENDOR_IBM,
+ .function = OCP_FUNC_GPIO,
+ .paddr = GPIO0_BASE,
+ .irq = OCP_IRQ_NA,
+ .pm = IBM_CPM_GPIO0,
+ },
+ { .vendor = OCP_VENDOR_INVALID
+ }
+};
+
+/* Polarity and triggering settings for internal interrupt sources */
+struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = {
+ { .polarity = 0xffff8f80,
+ .triggering = 0x00000000,
+ .ext_irq_mask = 0x0000707f, /* IRQ7 - IRQ9, IRQ0 - IRQ6 */
+ }
+};
diff --git a/arch/ppc/platforms/4xx/ibmstbx25.h b/arch/ppc/platforms/4xx/ibmstbx25.h
new file mode 100644
index 00000000000..9a2efc366e9
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ibmstbx25.h
@@ -0,0 +1,261 @@
+/*
+ * arch/ppc/platforms/4xx/ibmstbx25.h
+ *
+ * Author: Armin Kuster <akuster@mvista.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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBMSTBX25_H__
+#define __ASM_IBMSTBX25_H__
+
+#include <linux/config.h>
+
+/* serial port defines */
+#define STBx25xx_IO_BASE ((uint)0xe0000000)
+#define PPC4xx_ONB_IO_PADDR STBx25xx_IO_BASE
+#define PPC4xx_ONB_IO_VADDR ((uint)0xe0000000)
+#define PPC4xx_ONB_IO_SIZE ((uint)14*64*1024)
+
+/*
+ * map STBxxxx internal i/o address (0x400x00xx) to an address
+ * which is below the 2GB limit...
+ *
+ * 4000 000x uart1 -> 0xe000 000x
+ * 4001 00xx uart2
+ * 4002 00xx smart card
+ * 4003 000x iic
+ * 4004 000x uart0
+ * 4005 0xxx timer
+ * 4006 00xx gpio
+ * 4007 00xx smart card
+ * 400b 000x iic
+ * 400c 000x scp
+ * 400d 000x modem
+ * 400e 000x uart2
+*/
+#define STBx25xx_MAP_IO_ADDR(a) (((uint)(a)) + (STBx25xx_IO_BASE - 0x40000000))
+
+#define RS_TABLE_SIZE 3
+
+#define OPB_BASE_START 0x40000000
+#define EBIU_BASE_START 0xF0100000
+#define DCR_BASE_START 0x0000
+
+#ifdef __BOOTER__
+#define UART1_IO_BASE 0x40000000
+#define UART2_IO_BASE 0x40010000
+#else
+#define UART1_IO_BASE 0xe0000000
+#define UART2_IO_BASE 0xe0010000
+#endif
+#define SC0_BASE 0x40020000 /* smart card #0 */
+#define IIC0_BASE 0x40030000
+#ifdef __BOOTER__
+#define UART0_IO_BASE 0x40040000
+#else
+#define UART0_IO_BASE 0xe0040000
+#endif
+#define SCC0_BASE 0x40040000 /* Serial 0 controller IrdA */
+#define GPT0_BASE 0x40050000 /* General purpose timers */
+#define GPIO0_BASE 0x40060000
+#define SC1_BASE 0x40070000 /* smart card #1 */
+#define SCP0_BASE 0x400C0000 /* Serial Controller Port */
+#define SSP0_BASE 0x400D0000 /* Sync serial port */
+
+#define IDE0_BASE 0xf0100000
+#define REDWOOD_IDE_CTRL 0xf1100000
+
+#define RTCFPC_IRQ 0
+#define XPORT_IRQ 1
+#define AUD_IRQ 2
+#define AID_IRQ 3
+#define DMA0 4
+#define DMA1_IRQ 5
+#define DMA2_IRQ 6
+#define DMA3_IRQ 7
+#define SC0_IRQ 8
+#define IIC0_IRQ 9
+#define IIR0_IRQ 10
+#define GPT0_IRQ 11
+#define GPT1_IRQ 12
+#define SCP0_IRQ 13
+#define SSP0_IRQ 14
+#define GPT2_IRQ 15 /* count down timer */
+#define SC1_IRQ 16
+/* IRQ 17 - 19 external */
+#define UART0_INT 20
+#define UART1_INT 21
+#define UART2_INT 22
+#define XPTDMA_IRQ 23
+#define DCRIDE_IRQ 24
+/* IRQ 25 - 30 external */
+#define IDE0_IRQ 26
+
+#define IIC_NUMS 1
+#define UART_NUMS 3
+#define IIC_OWN 0x55
+#define IIC_CLOCK 50
+
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
+
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, \
+ (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
+ iomem_base: (u8 *)UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1) \
+ STD_UART_OP(2)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(1) \
+ STD_UART_OP(0) \
+ STD_UART_OP(2)
+#endif
+
+#if defined(CONFIG_UART0_TTYS2)
+#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(2) \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+#endif
+
+#define DCRN_BE_BASE 0x090
+#define DCRN_DMA0_BASE 0x0C0
+#define DCRN_DMA1_BASE 0x0C8
+#define DCRN_DMA2_BASE 0x0D0
+#define DCRN_DMA3_BASE 0x0D8
+#define DCRNCAP_DMA_CC 1 /* have DMA chained count capability */
+#define DCRN_DMASR_BASE 0x0E0
+#define DCRN_PLB0_BASE 0x054
+#define DCRN_PLB1_BASE 0x064
+#define DCRN_POB0_BASE 0x0B0
+#define DCRN_SCCR_BASE 0x120
+#define DCRN_UIC0_BASE 0x040
+#define DCRN_BE_BASE 0x090
+#define DCRN_DMA0_BASE 0x0C0
+#define DCRN_DMA1_BASE 0x0C8
+#define DCRN_DMA2_BASE 0x0D0
+#define DCRN_DMA3_BASE 0x0D8
+#define DCRN_CIC_BASE 0x030
+#define DCRN_DMASR_BASE 0x0E0
+#define DCRN_EBIMC_BASE 0x070
+#define DCRN_DCRX_BASE 0x020
+#define DCRN_CPMFR_BASE 0x102
+#define DCRN_SCCR_BASE 0x120
+#define DCRN_RTCFP_BASE 0x310
+
+#define UIC0 DCRN_UIC0_BASE
+
+#define IBM_CPM_IIC0 0x80000000 /* IIC 0 interface */
+#define IBM_CPM_CPU 0x10000000 /* PPC405B3 clock control */
+#define IBM_CPM_AUD 0x08000000 /* Audio Decoder */
+#define IBM_CPM_EBIU 0x04000000 /* External Bus Interface Unit */
+#define IBM_CPM_IRR 0x02000000 /* Infrared receiver */
+#define IBM_CPM_DMA 0x01000000 /* DMA controller */
+#define IBM_CPM_UART2 0x00200000 /* Serial Control Port */
+#define IBM_CPM_UART1 0x00100000 /* Serial 1 / Infrared */
+#define IBM_CPM_UART0 0x00080000 /* Serial 0 / 16550 */
+#define IBM_PM_DCRIDE 0x00040000 /* DCR timeout & IDE line Mode clock */
+#define IBM_CPM_SC0 0x00020000 /* Smart Card 0 */
+#define IBM_CPM_VID 0x00010000 /* reserved */
+#define IBM_CPM_SC1 0x00008000 /* Smart Card 0 */
+#define IBM_CPM_XPT0 0x00002000 /* Transport - 54 Mhz */
+#define IBM_CPM_CBS 0x00001000 /* Cross Bar Switch */
+#define IBM_CPM_GPT 0x00000800 /* GPTPWM */
+#define IBM_CPM_GPIO0 0x00000400 /* General Purpose IO 0 */
+#define IBM_CPM_DENC 0x00000200 /* Digital video Encoder */
+#define IBM_CPM_C405T 0x00000100 /* CPU timers */
+#define IBM_CPM_XPT27 0x00000080 /* Transport - 27 Mhz */
+#define IBM_CPM_UIC 0x00000040 /* Universal Interrupt Controller */
+#define IBM_CPM_RTCFPC 0x00000020 /* Realtime clock and front panel */
+#define IBM_CPM_SSP 0x00000010 /* Modem Serial Interface (SSP) */
+#define IBM_CPM_VID2 0x00000002 /* Video Decoder clock domain 2 */
+#define DFLT_IBM4xx_PM ~(IBM_CPM_CPU | IBM_CPM_EBIU | IBM_CPM_DMA \
+ | IBM_CPM_CBS | IBM_CPM_XPT0 | IBM_CPM_C405T \
+ | IBM_CPM_XPT27 | IBM_CPM_UIC)
+
+#define DCRN_BEAR (DCRN_BE_BASE + 0x0) /* Bus Error Address Register */
+#define DCRN_BESR (DCRN_BE_BASE + 0x1) /* Bus Error Syndrome Register */
+/* DCRN_BESR */
+#define BESR_DSES 0x80000000 /* Data-Side Error Status */
+#define BESR_DMES 0x40000000 /* DMA Error Status */
+#define BESR_RWS 0x20000000 /* Read/Write Status */
+#define BESR_ETMASK 0x1C000000 /* Error Type */
+#define ET_PROT 0
+#define ET_PARITY 1
+#define ET_NCFG 2
+#define ET_BUSERR 4
+#define ET_BUSTO 6
+
+#define CHR1_CETE 0x00800000 /* CPU external timer enable */
+#define CHR1_PCIPW 0x00008000 /* PCI Int enable/Peripheral Write enable */
+
+#define DCRN_CICCR (DCRN_CIC_BASE + 0x0) /* CIC Control Register */
+#define DCRN_DMAS1 (DCRN_CIC_BASE + 0x1) /* DMA Select1 Register */
+#define DCRN_DMAS2 (DCRN_CIC_BASE + 0x2) /* DMA Select2 Register */
+#define DCRN_CICVCR (DCRN_CIC_BASE + 0x3) /* CIC Video COntro Register */
+#define DCRN_CICSEL3 (DCRN_CIC_BASE + 0x5) /* CIC Select 3 Register */
+#define DCRN_SGPO (DCRN_CIC_BASE + 0x6) /* CIC GPIO Output Register */
+#define DCRN_SGPOD (DCRN_CIC_BASE + 0x7) /* CIC GPIO OD Register */
+#define DCRN_SGPTC (DCRN_CIC_BASE + 0x8) /* CIC GPIO Tristate Ctrl Reg */
+#define DCRN_SGPI (DCRN_CIC_BASE + 0x9) /* CIC GPIO Input Reg */
+
+#define DCRN_DCRXICR (DCRN_DCRX_BASE + 0x0) /* Internal Control Register */
+#define DCRN_DCRXISR (DCRN_DCRX_BASE + 0x1) /* Internal Status Register */
+#define DCRN_DCRXECR (DCRN_DCRX_BASE + 0x2) /* External Control Register */
+#define DCRN_DCRXESR (DCRN_DCRX_BASE + 0x3) /* External Status Register */
+#define DCRN_DCRXTAR (DCRN_DCRX_BASE + 0x4) /* Target Address Register */
+#define DCRN_DCRXTDR (DCRN_DCRX_BASE + 0x5) /* Target Data Register */
+#define DCRN_DCRXIGR (DCRN_DCRX_BASE + 0x6) /* Interrupt Generation Register */
+#define DCRN_DCRXBCR (DCRN_DCRX_BASE + 0x7) /* Line Buffer Control Register */
+
+#define DCRN_BRCRH0 (DCRN_EBIMC_BASE + 0x0) /* Bus Region Config High 0 */
+#define DCRN_BRCRH1 (DCRN_EBIMC_BASE + 0x1) /* Bus Region Config High 1 */
+#define DCRN_BRCRH2 (DCRN_EBIMC_BASE + 0x2) /* Bus Region Config High 2 */
+#define DCRN_BRCRH3 (DCRN_EBIMC_BASE + 0x3) /* Bus Region Config High 3 */
+#define DCRN_BRCRH4 (DCRN_EBIMC_BASE + 0x4) /* Bus Region Config High 4 */
+#define DCRN_BRCRH5 (DCRN_EBIMC_BASE + 0x5) /* Bus Region Config High 5 */
+#define DCRN_BRCRH6 (DCRN_EBIMC_BASE + 0x6) /* Bus Region Config High 6 */
+#define DCRN_BRCRH7 (DCRN_EBIMC_BASE + 0x7) /* Bus Region Config High 7 */
+#define DCRN_BRCR0 (DCRN_EBIMC_BASE + 0x10) /* BRC 0 */
+#define DCRN_BRCR1 (DCRN_EBIMC_BASE + 0x11) /* BRC 1 */
+#define DCRN_BRCR2 (DCRN_EBIMC_BASE + 0x12) /* BRC 2 */
+#define DCRN_BRCR3 (DCRN_EBIMC_BASE + 0x13) /* BRC 3 */
+#define DCRN_BRCR4 (DCRN_EBIMC_BASE + 0x14) /* BRC 4 */
+#define DCRN_BRCR5 (DCRN_EBIMC_BASE + 0x15) /* BRC 5 */
+#define DCRN_BRCR6 (DCRN_EBIMC_BASE + 0x16) /* BRC 6 */
+#define DCRN_BRCR7 (DCRN_EBIMC_BASE + 0x17) /* BRC 7 */
+#define DCRN_BEAR0 (DCRN_EBIMC_BASE + 0x20) /* Bus Error Address Register */
+#define DCRN_BESR0 (DCRN_EBIMC_BASE + 0x21) /* Bus Error Status Register */
+#define DCRN_BIUCR (DCRN_EBIMC_BASE + 0x2A) /* Bus Interfac Unit Ctrl Reg */
+
+#define DCRN_RTC_FPC0_CNTL (DCRN_RTCFP_BASE + 0x00) /* RTC cntl */
+#define DCRN_RTC_FPC0_INT (DCRN_RTCFP_BASE + 0x01) /* RTC Interrupt */
+#define DCRN_RTC_FPC0_TIME (DCRN_RTCFP_BASE + 0x02) /* RTC time reg */
+#define DCRN_RTC_FPC0_ALRM (DCRN_RTCFP_BASE + 0x03) /* RTC Alarm reg */
+#define DCRN_RTC_FPC0_D1 (DCRN_RTCFP_BASE + 0x04) /* LED Data 1 */
+#define DCRN_RTC_FPC0_D2 (DCRN_RTCFP_BASE + 0x05) /* LED Data 2 */
+#define DCRN_RTC_FPC0_D3 (DCRN_RTCFP_BASE + 0x06) /* LED Data 3 */
+#define DCRN_RTC_FPC0_D4 (DCRN_RTCFP_BASE + 0x07) /* LED Data 4 */
+#define DCRN_RTC_FPC0_D5 (DCRN_RTCFP_BASE + 0x08) /* LED Data 5 */
+#define DCRN_RTC_FPC0_FCNTL (DCRN_RTCFP_BASE + 0x09) /* LED control */
+#define DCRN_RTC_FPC0_BRT (DCRN_RTCFP_BASE + 0x0A) /* Brightness cntl */
+
+#include <asm/ibm405.h>
+
+#endif /* __ASM_IBMSTBX25_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c
new file mode 100644
index 00000000000..1df2339f1f6
--- /dev/null
+++ b/arch/ppc/platforms/4xx/luan.c
@@ -0,0 +1,387 @@
+/*
+ * arch/ppc/platforms/4xx/luan.c
+ *
+ * Luan board specific routines
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright 2004-2005 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/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/initrd.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ocp.h>
+#include <asm/pci-bridge.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/ppc4xx_pic.h>
+#include <asm/ppcboot.h>
+
+#include <syslib/ibm44x_common.h>
+#include <syslib/ibm440gx_common.h>
+#include <syslib/ibm440sp_common.h>
+
+/*
+ * This is a horrible kludge, we eventually need to abstract this
+ * generic PHY stuff, so the standard phy mode defines can be
+ * easily used from arch code.
+ */
+#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
+
+bd_t __res;
+
+static struct ibm44x_clocks clocks __initdata;
+
+static void __init
+luan_calibrate_decr(void)
+{
+ unsigned int freq;
+
+ if (mfspr(SPRN_CCR1) & CCR1_TCS)
+ freq = LUAN_TMR_CLK;
+ else
+ freq = clocks.cpu;
+
+ ibm44x_calibrate_decr(freq);
+}
+
+static int
+luan_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: IBM\n");
+ seq_printf(m, "machine\t\t: PPC440SP EVB (Luan)\n");
+
+ return 0;
+}
+
+static inline int
+luan_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+
+ /* PCIX0 in adapter mode, no host interrupt routing */
+
+ /* PCIX1 */
+ if (hose->index == 0) {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 49, 49, 49, 49 }, /* IDSEL 1 - PCIX1 Slot 0 */
+ { 49, 49, 49, 49 }, /* IDSEL 2 - PCIX1 Slot 1 */
+ { 49, 49, 49, 49 }, /* IDSEL 3 - PCIX1 Slot 2 */
+ { 49, 49, 49, 49 }, /* IDSEL 4 - PCIX1 Slot 3 */
+ };
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ /* PCIX2 */
+ } else if (hose->index == 1) {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 50, 50, 50, 50 }, /* IDSEL 1 - PCIX2 Slot 0 */
+ { 50, 50, 50, 50 }, /* IDSEL 2 - PCIX2 Slot 1 */
+ { 50, 50, 50, 50 }, /* IDSEL 3 - PCIX2 Slot 2 */
+ { 50, 50, 50, 50 }, /* IDSEL 4 - PCIX2 Slot 3 */
+ };
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ }
+ return -1;
+}
+
+static void __init luan_set_emacdata(void)
+{
+ struct ocp_def *def;
+ struct ocp_func_emac_data *emacdata;
+
+ /* Set phy_map, phy_mode, and mac_addr for the EMAC */
+ def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0);
+ emacdata = def->additions;
+ emacdata->phy_map = 0x00000001; /* Skip 0x00 */
+ emacdata->phy_mode = PHY_MODE_GMII;
+ memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6);
+}
+
+#define PCIX_READW(offset) \
+ (readw((void *)((u32)pcix_reg_base+offset)))
+
+#define PCIX_WRITEW(value, offset) \
+ (writew(value, (void *)((u32)pcix_reg_base+offset)))
+
+#define PCIX_WRITEL(value, offset) \
+ (writel(value, (void *)((u32)pcix_reg_base+offset)))
+
+static void __init
+luan_setup_pcix(void)
+{
+ int i;
+ void *pcix_reg_base;
+
+ for (i=0;i<3;i++) {
+ pcix_reg_base = ioremap64(PCIX0_REG_BASE + i*PCIX_REG_OFFSET, PCIX_REG_SIZE);
+
+ /* Enable PCIX0 I/O, Mem, and Busmaster cycles */
+ PCIX_WRITEW(PCIX_READW(PCIX0_COMMAND) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, PCIX0_COMMAND);
+
+ /* Disable all windows */
+ PCIX_WRITEL(0, PCIX0_POM0SA);
+ PCIX_WRITEL(0, PCIX0_POM1SA);
+ PCIX_WRITEL(0, PCIX0_POM2SA);
+ PCIX_WRITEL(0, PCIX0_PIM0SA);
+ PCIX_WRITEL(0, PCIX0_PIM0SAH);
+ PCIX_WRITEL(0, PCIX0_PIM1SA);
+ PCIX_WRITEL(0, PCIX0_PIM2SA);
+ PCIX_WRITEL(0, PCIX0_PIM2SAH);
+
+ /*
+ * Setup 512MB PLB->PCI outbound mem window
+ * (a_n000_0000->0_n000_0000)
+ * */
+ PCIX_WRITEL(0x0000000a, PCIX0_POM0LAH);
+ PCIX_WRITEL(0x80000000 | i*LUAN_PCIX_MEM_SIZE, PCIX0_POM0LAL);
+ PCIX_WRITEL(0x00000000, PCIX0_POM0PCIAH);
+ PCIX_WRITEL(0x80000000 | i*LUAN_PCIX_MEM_SIZE, PCIX0_POM0PCIAL);
+ PCIX_WRITEL(0xe0000001, PCIX0_POM0SA);
+
+ /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
+ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
+ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
+ PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+ PCIX_WRITEL(0xffffffff, PCIX0_PIM0SAH);
+
+ iounmap(pcix_reg_base);
+ }
+
+ eieio();
+}
+
+static void __init
+luan_setup_hose(struct pci_controller *hose,
+ int lower_mem,
+ int upper_mem,
+ int cfga,
+ int cfgd,
+ u64 pcix_io_base)
+{
+ char name[20];
+
+ sprintf(name, "PCIX%d host bridge", hose->index);
+
+ hose->pci_mem_offset = LUAN_PCIX_MEM_OFFSET;
+
+ pci_init_resource(&hose->io_resource,
+ LUAN_PCIX_LOWER_IO,
+ LUAN_PCIX_UPPER_IO,
+ IORESOURCE_IO,
+ name);
+
+ pci_init_resource(&hose->mem_resources[0],
+ lower_mem,
+ upper_mem,
+ IORESOURCE_MEM,
+ name);
+
+ hose->io_space.start = LUAN_PCIX_LOWER_IO;
+ hose->io_space.end = LUAN_PCIX_UPPER_IO;
+ hose->mem_space.start = lower_mem;
+ hose->mem_space.end = upper_mem;
+ isa_io_base =
+ (unsigned long)ioremap64(pcix_io_base, PCIX_IO_SIZE);
+ hose->io_base_virt = (void *)isa_io_base;
+
+ setup_indirect_pci(hose, cfga, cfgd);
+ hose->set_cfg_type = 1;
+}
+
+static void __init
+luan_setup_hoses(void)
+{
+ struct pci_controller *hose1, *hose2;
+
+ /* Configure windows on the PCI-X host bridge */
+ luan_setup_pcix();
+
+ /* Allocate hoses for PCIX1 and PCIX2 */
+ hose1 = pcibios_alloc_controller();
+ hose2 = pcibios_alloc_controller();
+ if (!hose1 || !hose2)
+ return;
+
+ /* Setup PCIX1 */
+ hose1->first_busno = 0;
+ hose1->last_busno = 0xff;
+
+ luan_setup_hose(hose1,
+ LUAN_PCIX1_LOWER_MEM,
+ LUAN_PCIX1_UPPER_MEM,
+ PCIX1_CFGA,
+ PCIX1_CFGD,
+ PCIX1_IO_BASE);
+
+ hose1->last_busno = pciauto_bus_scan(hose1, hose1->first_busno);
+
+ /* Setup PCIX2 */
+ hose2->first_busno = hose1->last_busno + 1;
+ hose2->last_busno = 0xff;
+
+ luan_setup_hose(hose2,
+ LUAN_PCIX2_LOWER_MEM,
+ LUAN_PCIX2_UPPER_MEM,
+ PCIX2_CFGA,
+ PCIX2_CFGD,
+ PCIX2_IO_BASE);
+
+ hose2->last_busno = pciauto_bus_scan(hose2, hose2->first_busno);
+
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = luan_map_irq;
+}
+
+TODC_ALLOC();
+
+static void __init
+luan_early_serial_map(void)
+{
+ struct uart_port port;
+
+ /* Setup ioremapped serial port access */
+ memset(&port, 0, sizeof(port));
+ port.membase = ioremap64(PPC440SP_UART0_ADDR, 8);
+ port.irq = UART0_INT;
+ port.uartclk = clocks.uart0;
+ port.regshift = 0;
+ port.iotype = SERIAL_IO_MEM;
+ port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+ port.line = 0;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 0 failed\n");
+ }
+
+ port.membase = ioremap64(PPC440SP_UART1_ADDR, 8);
+ port.irq = UART1_INT;
+ port.uartclk = clocks.uart1;
+ port.line = 1;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 1 failed\n");
+ }
+
+ port.membase = ioremap64(PPC440SP_UART2_ADDR, 8);
+ port.irq = UART2_INT;
+ port.uartclk = BASE_BAUD;
+ port.line = 2;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 2 failed\n");
+ }
+}
+
+static void __init
+luan_setup_arch(void)
+{
+ luan_set_emacdata();
+
+#if !defined(CONFIG_BDI_SWITCH)
+ /*
+ * The Abatron BDI JTAG debugger does not tolerate others
+ * mucking with the debug registers.
+ */
+ mtspr(SPRN_DBCR0, (DBCR0_TDE | DBCR0_IDM));
+#endif
+
+ /*
+ * Determine various clocks.
+ * To be completely correct we should get SysClk
+ * from FPGA, because it can be changed by on-board switches
+ * --ebs
+ */
+ /* 440GX and 440SP clocking is the same -mdp */
+ ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200);
+ ocp_sys_info.opb_bus_freq = clocks.opb;
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000/HZ;
+
+ /* Setup PCIXn host bridges */
+ luan_setup_hoses();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+
+ luan_early_serial_map();
+
+ /* Identify the system */
+ printk("Luan port (MontaVista Software, Inc. <source@mvista.com>)\n");
+}
+
+void __init platform_init(unsigned long r3, unsigned long r4,
+ unsigned long r5, unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3)
+ __res = *(bd_t *)(r3 + KERNELBASE);
+
+ ibm44x_platform_init();
+
+ ppc_md.setup_arch = luan_setup_arch;
+ ppc_md.show_cpuinfo = luan_show_cpuinfo;
+ ppc_md.find_end_of_memory = ibm440sp_find_end_of_memory;
+ ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */
+
+ ppc_md.calibrate_decr = luan_calibrate_decr;
+#ifdef CONFIG_KGDB
+ ppc_md.early_serial_map = luan_early_serial_map;
+#endif
+}
diff --git a/arch/ppc/platforms/4xx/luan.h b/arch/ppc/platforms/4xx/luan.h
new file mode 100644
index 00000000000..09b444c8781
--- /dev/null
+++ b/arch/ppc/platforms/4xx/luan.h
@@ -0,0 +1,80 @@
+/*
+ * arch/ppc/platforms/4xx/luan.h
+ *
+ * Luan board definitions
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright 2004-2005 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.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_LUAN_H__
+#define __ASM_LUAN_H__
+
+#include <linux/config.h>
+#include <platforms/4xx/ibm440sp.h>
+
+/* F/W TLB mapping used in bootloader glue to reset EMAC */
+#define PPC44x_EMAC0_MR0 0xa0000800
+
+/* Location of MAC addresses in PIBS image */
+#define PIBS_FLASH_BASE 0xffe00000
+#define PIBS_MAC_BASE (PIBS_FLASH_BASE+0x1b0400)
+
+/* External timer clock frequency */
+#define LUAN_TMR_CLK 25000000
+
+/* Flash */
+#define LUAN_FPGA_REG_0 0x0000000148300000ULL
+#define LUAN_BOOT_LARGE_FLASH(x) (x & 0x40)
+#define LUAN_SMALL_FLASH_LOW 0x00000001ff900000ULL
+#define LUAN_SMALL_FLASH_HIGH 0x00000001ffe00000ULL
+#define LUAN_SMALL_FLASH_SIZE 0x100000
+#define LUAN_LARGE_FLASH_LOW 0x00000001ff800000ULL
+#define LUAN_LARGE_FLASH_HIGH 0x00000001ffc00000ULL
+#define LUAN_LARGE_FLASH_SIZE 0x400000
+
+/*
+ * Serial port defines
+ */
+#define RS_TABLE_SIZE 3
+
+/* PIBS defined UART mappings, used before early_serial_setup */
+#define UART0_IO_BASE 0xa0000200
+#define UART1_IO_BASE 0xa0000300
+#define UART2_IO_BASE 0xa0000600
+
+#define BASE_BAUD 11059200
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, \
+ (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
+ iomem_base: UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1) \
+ STD_UART_OP(2)
+
+/* PCI support */
+#define LUAN_PCIX_LOWER_IO 0x00000000
+#define LUAN_PCIX_UPPER_IO 0x0000ffff
+#define LUAN_PCIX0_LOWER_MEM 0x80000000
+#define LUAN_PCIX0_UPPER_MEM 0x9fffffff
+#define LUAN_PCIX1_LOWER_MEM 0xa0000000
+#define LUAN_PCIX1_UPPER_MEM 0xbfffffff
+#define LUAN_PCIX2_LOWER_MEM 0xc0000000
+#define LUAN_PCIX2_UPPER_MEM 0xdfffffff
+
+#define LUAN_PCIX_MEM_SIZE 0x20000000
+#define LUAN_PCIX_MEM_OFFSET 0x00000000
+
+#endif /* __ASM_LUAN_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/oak.c b/arch/ppc/platforms/4xx/oak.c
new file mode 100644
index 00000000000..fa25ee1fa73
--- /dev/null
+++ b/arch/ppc/platforms/4xx/oak.c
@@ -0,0 +1,255 @@
+/*
+ *
+ * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: oak.c
+ *
+ * Description:
+ * Architecture- / platform-specific boot-time initialization code for
+ * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
+ * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ * <dan@net4x.com>.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/initrd.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/bootinfo.h>
+#include <asm/ppc4xx_pic.h>
+#include <asm/time.h>
+
+#include "oak.h"
+
+/* Function Prototypes */
+
+extern void abort(void);
+
+/* Global Variables */
+
+unsigned char __res[sizeof(bd_t)];
+
+
+/*
+ * void __init oak_init()
+ *
+ * Description:
+ * This routine...
+ *
+ * Input(s):
+ * r3 - Optional pointer to a board information structure.
+ * r4 - Optional pointer to the physical starting address of the init RAM
+ * disk.
+ * r5 - Optional pointer to the physical ending address of the init RAM
+ * disk.
+ * r6 - Optional pointer to the physical starting address of any kernel
+ * command-line parameters.
+ * r7 - Optional pointer to the physical ending address of any kernel
+ * command-line parameters.
+ *
+ * Output(s):
+ * N/A
+ *
+ * Returns:
+ * N/A
+ *
+ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+ }
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+ /*
+ * If the init RAM disk has been configured in, and there's a valid
+ * starting address for it, set it up.
+ */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Copy the kernel command line arguments to a safe place. */
+
+ if (r6) {
+ *(char *)(r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6 + KERNELBASE));
+ }
+
+ /* Initialize machine-dependency vectors */
+
+ ppc_md.setup_arch = oak_setup_arch;
+ ppc_md.show_percpuinfo = oak_show_percpuinfo;
+ ppc_md.irq_canonicalize = NULL;
+ ppc_md.init_IRQ = ppc4xx_pic_init;
+ ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */
+ ppc_md.init = NULL;
+
+ ppc_md.restart = oak_restart;
+ ppc_md.power_off = oak_power_off;
+ ppc_md.halt = oak_halt;
+
+ ppc_md.time_init = oak_time_init;
+ ppc_md.set_rtc_time = oak_set_rtc_time;
+ ppc_md.get_rtc_time = oak_get_rtc_time;
+ ppc_md.calibrate_decr = oak_calibrate_decr;
+}
+
+/*
+ * Document me.
+ */
+void __init
+oak_setup_arch(void)
+{
+ /* XXX - Implement me */
+}
+
+/*
+ * int oak_show_percpuinfo()
+ *
+ * Description:
+ * This routine pretty-prints the platform's internal CPU and bus clock
+ * frequencies into the buffer for usage in /proc/cpuinfo.
+ *
+ * Input(s):
+ * *buffer - Buffer into which CPU and bus clock frequencies are to be
+ * printed.
+ *
+ * Output(s):
+ * *buffer - Buffer with the CPU and bus clock frequencies.
+ *
+ * Returns:
+ * The number of bytes copied into 'buffer' if OK, otherwise zero or less
+ * on error.
+ */
+int
+oak_show_percpuinfo(struct seq_file *m, int i)
+{
+ bd_t *bp = (bd_t *)__res;
+
+ seq_printf(m, "clock\t\t: %dMHz\n"
+ "bus clock\t\t: %dMHz\n",
+ bp->bi_intfreq / 1000000,
+ bp->bi_busfreq / 1000000);
+
+ return 0;
+}
+
+/*
+ * Document me.
+ */
+void
+oak_restart(char *cmd)
+{
+ abort();
+}
+
+/*
+ * Document me.
+ */
+void
+oak_power_off(void)
+{
+ oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void
+oak_halt(void)
+{
+ oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+long __init
+oak_time_init(void)
+{
+ /* XXX - Implement me */
+ return 0;
+}
+
+/*
+ * Document me.
+ */
+int __init
+oak_set_rtc_time(unsigned long time)
+{
+ /* XXX - Implement me */
+
+ return (0);
+}
+
+/*
+ * Document me.
+ */
+unsigned long __init
+oak_get_rtc_time(void)
+{
+ /* XXX - Implement me */
+
+ return (0);
+}
+
+/*
+ * void __init oak_calibrate_decr()
+ *
+ * Description:
+ * This routine retrieves the internal processor frequency from the board
+ * information structure, sets up the kernel timer decrementer based on
+ * that value, enables the 403 programmable interval timer (PIT) and sets
+ * it up for auto-reload.
+ *
+ * Input(s):
+ * N/A
+ *
+ * Output(s):
+ * N/A
+ *
+ * Returns:
+ * N/A
+ *
+ */
+void __init
+oak_calibrate_decr(void)
+{
+ unsigned int freq;
+ bd_t *bip = (bd_t *)__res;
+
+ freq = bip->bi_intfreq;
+
+ decrementer_count = freq / HZ;
+ count_period_num = 1;
+ count_period_den = freq;
+
+ /* Enable the PIT and set auto-reload of its value */
+
+ mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
+
+ /* Clear any pending timer interrupts */
+
+ mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
+}
diff --git a/arch/ppc/platforms/4xx/oak.h b/arch/ppc/platforms/4xx/oak.h
new file mode 100644
index 00000000000..1b86a4c66b0
--- /dev/null
+++ b/arch/ppc/platforms/4xx/oak.h
@@ -0,0 +1,96 @@
+/*
+ *
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: oak.h
+ *
+ * Description:
+ * Macros, definitions, and data structures specific to the IBM PowerPC
+ * 403G{A,B,C,CX} "Oak" evaluation board. Anything specific to the pro-
+ * cessor itself is defined elsewhere.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_OAK_H__
+#define __ASM_OAK_H__
+
+/* We have an IBM 403G{A,B,C,CX} core */
+#include <asm/ibm403.h>
+
+#define _IO_BASE 0
+#define _ISA_MEM_BASE 0
+#define PCI_DRAM_OFFSET 0
+
+/* Memory map for the "Oak" evaluation board */
+
+#define PPC403SPU_IO_BASE 0x40000000 /* 403 On-chip serial port */
+#define PPC403SPU_IO_SIZE 0x00000008
+#define OAKSERIAL_IO_BASE 0x7E000000 /* NS16550DV serial port */
+#define OAKSERIAL_IO_SIZE 0x00000008
+#define OAKNET_IO_BASE 0xF4000000 /* NS83902AV Ethernet */
+#define OAKNET_IO_SIZE 0x00000040
+#define OAKPROM_IO_BASE 0xFFFE0000 /* AMD 29F010 Flash ROM */
+#define OAKPROM_IO_SIZE 0x00020000
+
+
+/* Interrupt assignments fixed by the hardware implementation */
+
+/* This is annoying kbuild-2.4 problem. -- Tom */
+
+#define PPC403SPU_RX_INT 4 /* AIC_INT4 */
+#define PPC403SPU_TX_INT 5 /* AIC_INT5 */
+#define OAKNET_INT 27 /* AIC_INT27 */
+#define OAKSERIAL_INT 28 /* AIC_INT28 */
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Oak" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+ unsigned char bi_s_version[4]; /* Version of this structure */
+ unsigned char bi_r_version[30]; /* Version of the IBM ROM */
+ unsigned int bi_memsize; /* DRAM installed, in bytes */
+ unsigned char bi_enetaddr[6]; /* Ethernet MAC address */
+ unsigned int bi_intfreq; /* Processor speed, in Hz */
+ unsigned int bi_busfreq; /* Bus speed, in Hz */
+} bd_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void oak_init(unsigned long r3,
+ unsigned long ird_start,
+ unsigned long ird_end,
+ unsigned long cline_start,
+ unsigned long cline_end);
+extern void oak_setup_arch(void);
+extern int oak_setup_residual(char *buffer);
+extern void oak_init_IRQ(void);
+extern int oak_get_irq(struct pt_regs *regs);
+extern void oak_restart(char *cmd);
+extern void oak_power_off(void);
+extern void oak_halt(void);
+extern void oak_time_init(void);
+extern int oak_set_rtc_time(unsigned long now);
+extern unsigned long oak_get_rtc_time(void);
+extern void oak_calibrate_decr(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+#define PPC4xx_MACHINE_NAME "IBM Oak"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_OAK_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/oak_setup.h b/arch/ppc/platforms/4xx/oak_setup.h
new file mode 100644
index 00000000000..8648bd084df
--- /dev/null
+++ b/arch/ppc/platforms/4xx/oak_setup.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * Module name: oak_setup.h
+ *
+ * Description:
+ * Architecture- / platform-specific boot-time initialization code for
+ * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
+ * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
+ * <dan@netx4.com>.
+ *
+ */
+
+#ifndef __OAK_SETUP_H__
+#define __OAK_SETUP_H__
+
+#include <asm/ptrace.h>
+#include <asm/board.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned char __res[sizeof(bd_t)];
+
+extern void oak_init(unsigned long r3,
+ unsigned long ird_start,
+ unsigned long ird_end,
+ unsigned long cline_start,
+ unsigned long cline_end);
+extern void oak_setup_arch(void);
+extern int oak_setup_residual(char *buffer);
+extern void oak_init_IRQ(void);
+extern int oak_get_irq(struct pt_regs *regs);
+extern void oak_restart(char *cmd);
+extern void oak_power_off(void);
+extern void oak_halt(void);
+extern void oak_time_init(void);
+extern int oak_set_rtc_time(unsigned long now);
+extern unsigned long oak_get_rtc_time(void);
+extern void oak_calibrate_decr(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OAK_SETUP_H__ */
diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
new file mode 100644
index 00000000000..28de707434f
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ocotea.c
@@ -0,0 +1,367 @@
+/*
+ * arch/ppc/platforms/4xx/ocotea.c
+ *
+ * Ocotea board specific routines
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright 2003-2005 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/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/initrd.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ocp.h>
+#include <asm/pci-bridge.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/ppc4xx_pic.h>
+#include <asm/ppcboot.h>
+
+#include <syslib/gen550.h>
+#include <syslib/ibm440gx_common.h>
+
+/*
+ * This is a horrible kludge, we eventually need to abstract this
+ * generic PHY stuff, so the standard phy mode defines can be
+ * easily used from arch code.
+ */
+#include "../../../../drivers/net/ibm_emac/ibm_emac_phy.h"
+
+bd_t __res;
+
+static struct ibm44x_clocks clocks __initdata;
+
+static void __init
+ocotea_calibrate_decr(void)
+{
+ unsigned int freq;
+
+ if (mfspr(SPRN_CCR1) & CCR1_TCS)
+ freq = OCOTEA_TMR_CLK;
+ else
+ freq = clocks.cpu;
+
+ ibm44x_calibrate_decr(freq);
+}
+
+static int
+ocotea_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: IBM\n");
+ seq_printf(m, "machine\t\t: PPC440GX EVB (Ocotea)\n");
+ ibm440gx_show_cpuinfo(m);
+ return 0;
+}
+
+static inline int
+ocotea_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 23, 23, 23, 23 }, /* IDSEL 1 - PCI Slot 0 */
+ { 24, 24, 24, 24 }, /* IDSEL 2 - PCI Slot 1 */
+ { 25, 25, 25, 25 }, /* IDSEL 3 - PCI Slot 2 */
+ { 26, 26, 26, 26 }, /* IDSEL 4 - PCI Slot 3 */
+ };
+
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static void __init ocotea_set_emacdata(void)
+{
+ struct ocp_def *def;
+ struct ocp_func_emac_data *emacdata;
+ int i;
+
+ /*
+ * Note: Current rev. board only operates in Group 4a
+ * mode, so we always set EMAC0-1 for SMII and EMAC2-3
+ * for RGMII (though these could run in RTBI just the same).
+ *
+ * The FPGA reg 3 information isn't even suitable for
+ * determining the phy_mode, so if the board becomes
+ * usable in !4a, it will be necessary to parse an environment
+ * variable from the firmware or similar to properly configure
+ * the phy_map/phy_mode.
+ */
+ /* Set phy_map, phy_mode, and mac_addr for each EMAC */
+ for (i=0; i<4; i++) {
+ def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i);
+ emacdata = def->additions;
+ if (i < 2) {
+ emacdata->phy_map = 0x00000001; /* Skip 0x00 */
+ emacdata->phy_mode = PHY_MODE_SMII;
+ }
+ else {
+ emacdata->phy_map = 0x0000ffff; /* Skip 0x00-0x0f */
+ emacdata->phy_mode = PHY_MODE_RGMII;
+ }
+ if (i == 0)
+ memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6);
+ else if (i == 1)
+ memcpy(emacdata->mac_addr, __res.bi_enet1addr, 6);
+ else if (i == 2)
+ memcpy(emacdata->mac_addr, __res.bi_enet2addr, 6);
+ else if (i == 3)
+ memcpy(emacdata->mac_addr, __res.bi_enet3addr, 6);
+ }
+}
+
+#define PCIX_READW(offset) \
+ (readw(pcix_reg_base+offset))
+
+#define PCIX_WRITEW(value, offset) \
+ (writew(value, pcix_reg_base+offset))
+
+#define PCIX_WRITEL(value, offset) \
+ (writel(value, pcix_reg_base+offset))
+
+/*
+ * FIXME: This is only here to "make it work". This will move
+ * to a ibm_pcix.c which will contain a generic IBM PCIX bridge
+ * configuration library. -Matt
+ */
+static void __init
+ocotea_setup_pcix(void)
+{
+ void *pcix_reg_base;
+
+ pcix_reg_base = ioremap64(PCIX0_REG_BASE, PCIX_REG_SIZE);
+
+ /* Enable PCIX0 I/O, Mem, and Busmaster cycles */
+ PCIX_WRITEW(PCIX_READW(PCIX0_COMMAND) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, PCIX0_COMMAND);
+
+ /* Disable all windows */
+ PCIX_WRITEL(0, PCIX0_POM0SA);
+ PCIX_WRITEL(0, PCIX0_POM1SA);
+ PCIX_WRITEL(0, PCIX0_POM2SA);
+ PCIX_WRITEL(0, PCIX0_PIM0SA);
+ PCIX_WRITEL(0, PCIX0_PIM0SAH);
+ PCIX_WRITEL(0, PCIX0_PIM1SA);
+ PCIX_WRITEL(0, PCIX0_PIM2SA);
+ PCIX_WRITEL(0, PCIX0_PIM2SAH);
+
+ /* Setup 2GB PLB->PCI outbound mem window (3_8000_0000->0_8000_0000) */
+ PCIX_WRITEL(0x00000003, PCIX0_POM0LAH);
+ PCIX_WRITEL(0x80000000, PCIX0_POM0LAL);
+ PCIX_WRITEL(0x00000000, PCIX0_POM0PCIAH);
+ PCIX_WRITEL(0x80000000, PCIX0_POM0PCIAL);
+ PCIX_WRITEL(0x80000001, PCIX0_POM0SA);
+
+ /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
+ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
+ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
+ PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+
+ eieio();
+}
+
+static void __init
+ocotea_setup_hose(void)
+{
+ struct pci_controller *hose;
+
+ /* Configure windows on the PCI-X host bridge */
+ ocotea_setup_pcix();
+
+ hose = pcibios_alloc_controller();
+
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ hose->pci_mem_offset = OCOTEA_PCI_MEM_OFFSET;
+
+ pci_init_resource(&hose->io_resource,
+ OCOTEA_PCI_LOWER_IO,
+ OCOTEA_PCI_UPPER_IO,
+ IORESOURCE_IO,
+ "PCI host bridge");
+
+ pci_init_resource(&hose->mem_resources[0],
+ OCOTEA_PCI_LOWER_MEM,
+ OCOTEA_PCI_UPPER_MEM,
+ IORESOURCE_MEM,
+ "PCI host bridge");
+
+ hose->io_space.start = OCOTEA_PCI_LOWER_IO;
+ hose->io_space.end = OCOTEA_PCI_UPPER_IO;
+ hose->mem_space.start = OCOTEA_PCI_LOWER_MEM;
+ hose->mem_space.end = OCOTEA_PCI_UPPER_MEM;
+ isa_io_base =
+ (unsigned long)ioremap64(OCOTEA_PCI_IO_BASE, OCOTEA_PCI_IO_SIZE);
+ hose->io_base_virt = (void *)isa_io_base;
+
+ setup_indirect_pci(hose,
+ OCOTEA_PCI_CFGA_PLB32,
+ OCOTEA_PCI_CFGD_PLB32);
+ hose->set_cfg_type = 1;
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = ocotea_map_irq;
+}
+
+
+TODC_ALLOC();
+
+static void __init
+ocotea_early_serial_map(void)
+{
+ struct uart_port port;
+
+ /* Setup ioremapped serial port access */
+ memset(&port, 0, sizeof(port));
+ port.membase = ioremap64(PPC440GX_UART0_ADDR, 8);
+ port.irq = UART0_INT;
+ port.uartclk = clocks.uart0;
+ port.regshift = 0;
+ port.iotype = SERIAL_IO_MEM;
+ port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+ port.line = 0;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 0 failed\n");
+ }
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ /* Configure debug serial access */
+ gen550_init(0, &port);
+#endif
+
+ port.membase = ioremap64(PPC440GX_UART1_ADDR, 8);
+ port.irq = UART1_INT;
+ port.uartclk = clocks.uart1;
+ port.line = 1;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port 1 failed\n");
+ }
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ /* Configure debug serial access */
+ gen550_init(1, &port);
+#endif
+}
+
+static void __init
+ocotea_setup_arch(void)
+{
+ ocotea_set_emacdata();
+
+ ibm440gx_tah_enable();
+
+ /* Setup TODC access */
+ TODC_INIT(TODC_TYPE_DS1743,
+ 0,
+ 0,
+ ioremap64(OCOTEA_RTC_ADDR, OCOTEA_RTC_SIZE),
+ 8);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000/HZ;
+
+ /* Setup PCI host bridge */
+ ocotea_setup_hose();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+
+ ocotea_early_serial_map();
+
+ /* Identify the system */
+ printk("IBM Ocotea port (MontaVista Software, Inc. <source@mvista.com>)\n");
+}
+
+static void __init ocotea_init(void)
+{
+ ibm440gx_l2c_setup(&clocks);
+}
+
+void __init platform_init(unsigned long r3, unsigned long r4,
+ unsigned long r5, unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3)
+ __res = *(bd_t *)(r3 + KERNELBASE);
+
+ /*
+ * Determine various clocks.
+ * To be completely correct we should get SysClk
+ * from FPGA, because it can be changed by on-board switches
+ * --ebs
+ */
+ ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200);
+ ocp_sys_info.opb_bus_freq = clocks.opb;
+
+ ibm44x_platform_init();
+
+ ppc_md.setup_arch = ocotea_setup_arch;
+ ppc_md.show_cpuinfo = ocotea_show_cpuinfo;
+ ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */
+
+ ppc_md.calibrate_decr = ocotea_calibrate_decr;
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+#ifdef CONFIG_KGDB
+ ppc_md.early_serial_map = ocotea_early_serial_map;
+#endif
+ ppc_md.init = ocotea_init;
+}
diff --git a/arch/ppc/platforms/4xx/ocotea.h b/arch/ppc/platforms/4xx/ocotea.h
new file mode 100644
index 00000000000..202dc825119
--- /dev/null
+++ b/arch/ppc/platforms/4xx/ocotea.h
@@ -0,0 +1,88 @@
+/*
+ * arch/ppc/platforms/ocotea.h
+ *
+ * Ocotea board definitions
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright 2003-2005 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.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_OCOTEA_H__
+#define __ASM_OCOTEA_H__
+
+#include <linux/config.h>
+#include <platforms/4xx/ibm440gx.h>
+
+/* F/W TLB mapping used in bootloader glue to reset EMAC */
+#define PPC44x_EMAC0_MR0 0xe0000800
+
+/* Location of MAC addresses in PIBS image */
+#define PIBS_FLASH_BASE 0xfff00000
+#define PIBS_MAC_BASE (PIBS_FLASH_BASE+0xb0500)
+#define PIBS_MAC_SIZE 0x200
+#define PIBS_MAC_OFFSET 0x100
+
+/* External timer clock frequency */
+#define OCOTEA_TMR_CLK 25000000
+
+/* RTC/NVRAM location */
+#define OCOTEA_RTC_ADDR 0x0000000148000000ULL
+#define OCOTEA_RTC_SIZE 0x2000
+
+/* Flash */
+#define OCOTEA_FPGA_REG_0 0x0000000148300000ULL
+#define OCOTEA_BOOT_LARGE_FLASH(x) (x & 0x40)
+#define OCOTEA_SMALL_FLASH_LOW 0x00000001ff900000ULL
+#define OCOTEA_SMALL_FLASH_HIGH 0x00000001fff00000ULL
+#define OCOTEA_SMALL_FLASH_SIZE 0x100000
+#define OCOTEA_LARGE_FLASH_LOW 0x00000001ff800000ULL
+#define OCOTEA_LARGE_FLASH_HIGH 0x00000001ffc00000ULL
+#define OCOTEA_LARGE_FLASH_SIZE 0x400000
+
+/* FPGA_REG_3 (Ethernet Groups) */
+#define OCOTEA_FPGA_REG_3 0x0000000148300003ULL
+
+/*
+ * Serial port defines
+ */
+#define RS_TABLE_SIZE 2
+
+/* OpenBIOS defined UART mappings, used before early_serial_setup */
+#define UART0_IO_BASE 0xE0000200
+#define UART1_IO_BASE 0xE0000300
+
+#define BASE_BAUD 11059200/16
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, \
+ (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
+ iomem_base: UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+
+/* PCI support */
+#define OCOTEA_PCI_LOWER_IO 0x00000000
+#define OCOTEA_PCI_UPPER_IO 0x0000ffff
+#define OCOTEA_PCI_LOWER_MEM 0x80000000
+#define OCOTEA_PCI_UPPER_MEM 0xffffefff
+
+#define OCOTEA_PCI_CFGREGS_BASE 0x000000020ec00000ULL
+#define OCOTEA_PCI_CFGA_PLB32 0x0ec00000
+#define OCOTEA_PCI_CFGD_PLB32 0x0ec00004
+
+#define OCOTEA_PCI_IO_BASE 0x0000000208000000ULL
+#define OCOTEA_PCI_IO_SIZE 0x00010000
+#define OCOTEA_PCI_MEM_OFFSET 0x00000000
+
+#endif /* __ASM_OCOTEA_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/redwood5.c b/arch/ppc/platforms/4xx/redwood5.c
new file mode 100644
index 00000000000..2f5e410afbc
--- /dev/null
+++ b/arch/ppc/platforms/4xx/redwood5.c
@@ -0,0 +1,110 @@
+/*
+ * arch/ppc/platforms/4xx/redwood5.c
+ *
+ * Support for the IBM redwood5 eval board file
+ *
+ * Author: Armin Kuster <akuster@mvista.com>
+ *
+ * 2000-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.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = SMC91111_BASE_ADDR,
+ .end = SMC91111_BASE_ADDR + SMC91111_REG_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = SMC91111_IRQ,
+ .end = SMC91111_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static struct platform_device *redwood5_devs[] __initdata = {
+ &smc91x_device,
+};
+
+static int __init
+redwood5_platform_add_devices(void)
+{
+ return platform_add_devices(redwood5_devs, ARRAY_SIZE(redwood5_devs));
+}
+
+void __init
+redwood5_setup_arch(void)
+{
+ ppc4xx_setup_arch();
+
+#ifdef CONFIG_DEBUG_BRINGUP
+ printk("\n");
+ printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
+ printk("\n");
+ printk("bi_s_version\t %s\n", bip->bi_s_version);
+ printk("bi_r_version\t %s\n", bip->bi_r_version);
+ printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,bip->bi_memsize/(1024*1000));
+ printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
+ bip->bi_enetaddr[0], bip->bi_enetaddr[1],
+ bip->bi_enetaddr[2], bip->bi_enetaddr[3],
+ bip->bi_enetaddr[4], bip->bi_enetaddr[5]);
+
+ printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
+ bip->bi_intfreq, bip->bi_intfreq/ 1000000);
+
+ printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
+ bip->bi_busfreq, bip->bi_busfreq / 1000000 );
+ printk("bi_tbfreq\t 0x%8.8x\t TB freq:\t %dMHz\n",
+ bip->bi_tbfreq, bip->bi_tbfreq/1000000);
+
+ printk("\n");
+#endif
+ device_initcall(redwood5_platform_add_devices);
+}
+
+void __init
+redwood5_map_io(void)
+{
+ int i;
+
+ ppc4xx_map_io();
+ for (i = 0; i < 16; i++) {
+ unsigned long v, p;
+
+ /* 0x400x0000 -> 0xe00x0000 */
+ p = 0x40000000 | (i << 16);
+ v = STB04xxx_IO_BASE | (i << 16);
+
+ io_block_mapping(v, p, PAGE_SIZE,
+ _PAGE_NO_CACHE | pgprot_val(PAGE_KERNEL) | _PAGE_GUARDED);
+ }
+
+
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ ppc4xx_init(r3, r4, r5, r6, r7);
+
+ ppc_md.setup_arch = redwood5_setup_arch;
+ ppc_md.setup_io_mappings = redwood5_map_io;
+}
diff --git a/arch/ppc/platforms/4xx/redwood5.h b/arch/ppc/platforms/4xx/redwood5.h
new file mode 100644
index 00000000000..264e34fb3fb
--- /dev/null
+++ b/arch/ppc/platforms/4xx/redwood5.h
@@ -0,0 +1,54 @@
+/*
+ * arch/ppc/platforms/4xx/redwood5.h
+ *
+ * Macros, definitions, and data structures specific to the IBM PowerPC
+ * STB03xxx "Redwood" evaluation board.
+ *
+ * Author: Armin Kuster <akuster@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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_REDWOOD5_H__
+#define __ASM_REDWOOD5_H__
+
+/* Redwood5 has an STB04xxx core */
+#include <platforms/4xx/ibmstb4.h>
+
+#ifndef __ASSEMBLY__
+typedef struct board_info {
+ unsigned char bi_s_version[4]; /* Version of this structure */
+ unsigned char bi_r_version[30]; /* Version of the IBM ROM */
+ unsigned int bi_memsize; /* DRAM installed, in bytes */
+ unsigned int bi_dummy; /* field shouldn't exist */
+ unsigned char bi_enetaddr[6]; /* Ethernet MAC address */
+ unsigned int bi_intfreq; /* Processor speed, in Hz */
+ unsigned int bi_busfreq; /* Bus speed, in Hz */
+ unsigned int bi_tbfreq; /* Software timebase freq */
+} bd_t;
+#endif /* !__ASSEMBLY__ */
+
+
+#define SMC91111_BASE_ADDR 0xf2000300
+#define SMC91111_REG_SIZE 16
+#define SMC91111_IRQ 28
+
+#ifdef MAX_HWIFS
+#undef MAX_HWIFS
+#endif
+#define MAX_HWIFS 1
+
+#define _IO_BASE 0
+#define _ISA_MEM_BASE 0
+#define PCI_DRAM_OFFSET 0
+
+#define BASE_BAUD (378000000 / 18 / 16)
+
+#define PPC4xx_MACHINE_NAME "IBM Redwood5"
+
+#endif /* __ASM_REDWOOD5_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/redwood6.c b/arch/ppc/platforms/4xx/redwood6.c
new file mode 100644
index 00000000000..8b1012994df
--- /dev/null
+++ b/arch/ppc/platforms/4xx/redwood6.c
@@ -0,0 +1,159 @@
+/*
+ * arch/ppc/platforms/4xx/redwood6.c
+ *
+ * Author: Armin Kuster <akuster@mvista.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/config.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/ppc4xx_pic.h>
+#include <linux/delay.h>
+#include <asm/machdep.h>
+
+/*
+ * Define external IRQ senses and polarities.
+ */
+unsigned char ppc4xx_uic_ext_irq_cfg[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 7 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 8 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 9 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 4 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 5 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 6 */
+};
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = SMC91111_BASE_ADDR,
+ .end = SMC91111_BASE_ADDR + SMC91111_REG_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = SMC91111_IRQ,
+ .end = SMC91111_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static struct platform_device *redwood6_devs[] __initdata = {
+ &smc91x_device,
+};
+
+static int __init
+redwood6_platform_add_devices(void)
+{
+ return platform_add_devices(redwood6_devs, ARRAY_SIZE(redwood6_devs));
+}
+
+
+void __init
+redwood6_setup_arch(void)
+{
+#ifdef CONFIG_IDE
+ void *xilinx, *xilinx_1, *xilinx_2;
+ unsigned short us_reg5;
+#endif
+
+ ppc4xx_setup_arch();
+
+#ifdef CONFIG_IDE
+ xilinx = (unsigned long) ioremap(IDE_XLINUX_MUX_BASE, 0x10);
+ /* init xilinx control registers - enable ide mux, clear reset bit */
+ if (!xilinx) {
+ printk(KERN_CRIT
+ "redwood6_setup_arch() xilinxi ioremap failed\n");
+ return;
+ }
+ xilinx_1 = xilinx + 0xa;
+ xilinx_2 = xilinx + 0xe;
+
+ us_reg5 = readb(xilinx_1);
+ writeb(0x01d1, xilinx_1);
+ writeb(0x0008, xilinx_2);
+
+ udelay(10 * 1000);
+
+ writeb(0x01d1, xilinx_1);
+ writeb(0x0008, xilinx_2);
+#endif
+
+#ifdef DEBUG_BRINGUP
+ bd_t *bip = (bd_t *) __res;
+ printk("\n");
+ printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
+ printk("\n");
+ printk("bi_s_version\t %s\n", bip->bi_s_version);
+ printk("bi_r_version\t %s\n", bip->bi_r_version);
+ printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,
+ bip->bi_memsize / (1024 * 1000));
+ printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
+ bip->bi_enetaddr[0], bip->bi_enetaddr[1], bip->bi_enetaddr[2],
+ bip->bi_enetaddr[3], bip->bi_enetaddr[4], bip->bi_enetaddr[5]);
+
+ printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
+ bip->bi_intfreq, bip->bi_intfreq / 1000000);
+
+ printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
+ bip->bi_busfreq, bip->bi_busfreq / 1000000);
+ printk("bi_tbfreq\t 0x%8.8x\t TB freq:\t %dMHz\n",
+ bip->bi_tbfreq, bip->bi_tbfreq / 1000000);
+
+ printk("\n");
+#endif
+
+ /* Identify the system */
+ printk(KERN_INFO "IBM Redwood6 (STBx25XX) Platform\n");
+ printk(KERN_INFO
+ "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+
+ device_initcall(redwood6_platform_add_devices);
+}
+
+void __init
+redwood6_map_io(void)
+{
+ int i;
+
+ ppc4xx_map_io();
+ for (i = 0; i < 16; i++) {
+ unsigned long v, p;
+
+ /* 0x400x0000 -> 0xe00x0000 */
+ p = 0x40000000 | (i << 16);
+ v = STBx25xx_IO_BASE | (i << 16);
+
+ io_block_mapping(v, p, PAGE_SIZE,
+ _PAGE_NO_CACHE | pgprot_val(PAGE_KERNEL) |
+ _PAGE_GUARDED);
+ }
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ ppc4xx_init(r3, r4, r5, r6, r7);
+
+ ppc_md.setup_arch = redwood6_setup_arch;
+ ppc_md.setup_io_mappings = redwood6_map_io;
+}
diff --git a/arch/ppc/platforms/4xx/redwood6.h b/arch/ppc/platforms/4xx/redwood6.h
new file mode 100644
index 00000000000..1814b9f5fc3
--- /dev/null
+++ b/arch/ppc/platforms/4xx/redwood6.h
@@ -0,0 +1,55 @@
+/*
+ * arch/ppc/platforms/4xx/redwood6.h
+ *
+ * Macros, definitions, and data structures specific to the IBM PowerPC
+ * STBx25xx "Redwood6" evaluation board.
+ *
+ * Author: Armin Kuster <akuster@mvista.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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_REDWOOD5_H__
+#define __ASM_REDWOOD5_H__
+
+/* Redwood6 has an STBx25xx core */
+#include <platforms/4xx/ibmstbx25.h>
+
+#ifndef __ASSEMBLY__
+typedef struct board_info {
+ unsigned char bi_s_version[4]; /* Version of this structure */
+ unsigned char bi_r_version[30]; /* Version of the IBM ROM */
+ unsigned int bi_memsize; /* DRAM installed, in bytes */
+ unsigned int bi_dummy; /* field shouldn't exist */
+ unsigned char bi_enetaddr[6]; /* Ethernet MAC address */
+ unsigned int bi_intfreq; /* Processor speed, in Hz */
+ unsigned int bi_busfreq; /* Bus speed, in Hz */
+ unsigned int bi_tbfreq; /* Software timebase freq */
+} bd_t;
+#endif /* !__ASSEMBLY__ */
+
+#define SMC91111_BASE_ADDR 0xf2030300
+#define SMC91111_REG_SIZE 16
+#define SMC91111_IRQ 27
+#define IDE_XLINUX_MUX_BASE 0xf2040000
+#define IDE_DMA_ADDR 0xfce00000
+
+#ifdef MAX_HWIFS
+#undef MAX_HWIFS
+#endif
+#define MAX_HWIFS 1
+
+#define _IO_BASE 0
+#define _ISA_MEM_BASE 0
+#define PCI_DRAM_OFFSET 0
+
+#define BASE_BAUD (378000000 / 18 / 16)
+
+#define PPC4xx_MACHINE_NAME "IBM Redwood6"
+
+#endif /* __ASM_REDWOOD5_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/sycamore.c b/arch/ppc/platforms/4xx/sycamore.c
new file mode 100644
index 00000000000..d8019eec470
--- /dev/null
+++ b/arch/ppc/platforms/4xx/sycamore.c
@@ -0,0 +1,278 @@
+/*
+ * arch/ppc/platforms/4xx/sycamore.c
+ *
+ * Architecture- / platform-specific boot-time initialization code for
+ * IBM PowerPC 4xx based boards.
+ *
+ * Author: Armin Kuster <akuster@mvista.com>
+ *
+ * 2000-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/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+
+#include <asm/ocp.h>
+#include <asm/ppc4xx_pic.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/ibm_ocp_pci.h>
+#include <asm/todc.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+void *kb_cs;
+void *kb_data;
+void *sycamore_rtc_base;
+
+/*
+ * Define external IRQ senses and polarities.
+ */
+unsigned char ppc4xx_uic_ext_irq_cfg[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 7 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 8 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 9 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 10 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 11 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 12 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 4 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 5 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Ext Int 6 */
+};
+
+
+/* Some IRQs unique to Sycamore.
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {28, 28, 28, 28}, /* IDSEL 1 - PCI slot 1 */
+ {29, 29, 29, 29}, /* IDSEL 2 - PCI slot 2 */
+ {30, 30, 30, 30}, /* IDSEL 3 - PCI slot 3 */
+ {31, 31, 31, 31}, /* IDSEL 4 - PCI slot 4 */
+ };
+
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+};
+
+void __init
+sycamore_setup_arch(void)
+{
+#define SYCAMORE_PS2_BASE 0xF0100000
+#define SYCAMORE_FPGA_BASE 0xF0300000
+
+ void *fpga_brdc;
+ unsigned char fpga_brdc_data;
+ void *fpga_enable;
+ void *fpga_polarity;
+ void *fpga_status;
+ void *fpga_trigger;
+
+ ppc4xx_setup_arch();
+
+ ibm_ocp_set_emac(0, 1);
+
+ kb_data = ioremap(SYCAMORE_PS2_BASE, 8);
+ if (!kb_data) {
+ printk(KERN_CRIT
+ "sycamore_setup_arch() kb_data ioremap failed\n");
+ return;
+ }
+
+ kb_cs = kb_data + 1;
+
+ fpga_status = ioremap(SYCAMORE_FPGA_BASE, 8);
+ if (!fpga_status) {
+ printk(KERN_CRIT
+ "sycamore_setup_arch() fpga_status ioremap failed\n");
+ return;
+ }
+
+ fpga_enable = fpga_status + 1;
+ fpga_polarity = fpga_status + 2;
+ fpga_trigger = fpga_status + 3;
+ fpga_brdc = fpga_status + 4;
+
+ /* split the keyboard and mouse interrupts */
+ fpga_brdc_data = readb(fpga_brdc);
+ fpga_brdc_data |= 0x80;
+ writeb(fpga_brdc_data, fpga_brdc);
+
+ writeb(0x3, fpga_enable);
+
+ writeb(0x3, fpga_polarity);
+
+ writeb(0x3, fpga_trigger);
+
+ /* RTC step for the sycamore */
+ sycamore_rtc_base = (void *) SYCAMORE_RTC_VADDR;
+ TODC_INIT(TODC_TYPE_DS1743, sycamore_rtc_base, sycamore_rtc_base,
+ sycamore_rtc_base, 8);
+
+ /* Identify the system */
+ printk(KERN_INFO "IBM Sycamore (IBM405GPr) Platform\n");
+ printk(KERN_INFO
+ "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+#ifdef CONFIG_PCI
+ unsigned int bar_response, bar;
+ /*
+ * Expected PCI mapping:
+ *
+ * PLB addr PCI memory addr
+ * --------------------- ---------------------
+ * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff
+ * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff
+ *
+ * PLB addr PCI io addr
+ * --------------------- ---------------------
+ * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000
+ *
+ * The following code is simplified by assuming that the bootrom
+ * has been well behaved in following this mapping.
+ */
+
+#ifdef DEBUG
+ int i;
+
+ printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
+ printk("PCI bridge regs before fixup \n");
+ for (i = 0; i <= 3; i++) {
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+ }
+ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+
+ /* added for IBM boot rom version 1.15 bios bar changes -AK */
+
+ /* Disable region first */
+ out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+ /* PLB starting addr, PCI: 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+ /* PCI start addr, 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+ /* 512MB range of PLB to PCI */
+ out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+ /* Enable no pre-fetch, enable region */
+ out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+ (PPC405_PCI_UPPER_MEM -
+ PPC405_PCI_MEM_BASE)) | 0x01));
+
+ /* Enable inbound region one - 1GB size */
+ out_le32((void *) &(pcip->ptm1ms), 0xc0000001);
+
+ /* Disable outbound region one */
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+
+ /* Disable inbound region two */
+ out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+ /* Disable outbound region two */
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+
+ /* Zero config bars */
+ for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+ early_write_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ 0x00000000);
+ early_read_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ &bar_response);
+ DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+ hose->first_busno, PCI_SLOT(hose->first_busno),
+ PCI_FUNC(hose->first_busno), bar, bar_response);
+ }
+ /* end work arround */
+
+#ifdef DEBUG
+ printk("PCI bridge regs after fixup \n");
+ for (i = 0; i <= 3; i++) {
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+ }
+ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+#endif
+
+}
+
+void __init
+sycamore_map_io(void)
+{
+ ppc4xx_map_io();
+ io_block_mapping(SYCAMORE_RTC_VADDR,
+ SYCAMORE_RTC_PADDR, SYCAMORE_RTC_SIZE, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ ppc4xx_init(r3, r4, r5, r6, r7);
+
+ ppc_md.setup_arch = sycamore_setup_arch;
+ ppc_md.setup_io_mappings = sycamore_map_io;
+
+#ifdef CONFIG_GEN_RTC
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+#endif
+}
diff --git a/arch/ppc/platforms/4xx/sycamore.h b/arch/ppc/platforms/4xx/sycamore.h
new file mode 100644
index 00000000000..3e7b4e2c8c5
--- /dev/null
+++ b/arch/ppc/platforms/4xx/sycamore.h
@@ -0,0 +1,67 @@
+/*
+ * arch/ppc/platforms/4xx/sycamore.h
+ *
+ * Macros, definitions, and data structures specific to the IBM PowerPC
+ * 405GPr "Sycamore" evaluation board.
+ *
+ * Author: Armin Kuster <akuster@mvista.com>
+ *
+ * 2000 (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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_SYCAMORE_H__
+#define __ASM_SYCAMORE_H__
+
+#include <platforms/4xx/ibm405gpr.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Sycamore" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+ unsigned char bi_s_version[4]; /* Version of this structure */
+ unsigned char bi_r_version[30]; /* Version of the IBM ROM */
+ unsigned int bi_memsize; /* DRAM installed, in bytes */
+ unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */
+ unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */
+ unsigned int bi_intfreq; /* Processor speed, in Hz */
+ unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
+ unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+
+/* Memory map for the IBM "Sycamore" 405GP evaluation board.
+ * Generic 4xx plus RTC.
+ */
+
+extern void *sycamore_rtc_base;
+#define SYCAMORE_RTC_PADDR ((uint)0xf0000000)
+#define SYCAMORE_RTC_VADDR SYCAMORE_RTC_PADDR
+#define SYCAMORE_RTC_SIZE ((uint)8*1024)
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD 201600
+#else
+#define BASE_BAUD 691200
+#endif
+
+#define SYCAMORE_PS2_BASE 0xF0100000
+#define SYCAMORE_FPGA_BASE 0xF0300000
+
+#define PPC4xx_MACHINE_NAME "IBM Sycamore"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_SYCAMORE_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/virtex-ii_pro.c b/arch/ppc/platforms/4xx/virtex-ii_pro.c
new file mode 100644
index 00000000000..097cc9d5aca
--- /dev/null
+++ b/arch/ppc/platforms/4xx/virtex-ii_pro.c
@@ -0,0 +1,60 @@
+/*
+ * arch/ppc/platforms/4xx/virtex-ii_pro.c
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2002-2004 (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/config.h>
+#include <linux/init.h>
+#include <asm/ocp.h>
+#include "virtex-ii_pro.h"
+
+/* Have OCP take care of the serial ports. */
+struct ocp_def core_ocp[] = {
+#ifdef XPAR_UARTNS550_0_BASEADDR
+ { .vendor = OCP_VENDOR_XILINX,
+ .function = OCP_FUNC_16550,
+ .index = 0,
+ .paddr = XPAR_UARTNS550_0_BASEADDR,
+ .irq = XPAR_INTC_0_UARTNS550_0_VEC_ID,
+ .pm = OCP_CPM_NA
+ },
+#ifdef XPAR_UARTNS550_1_BASEADDR
+ { .vendor = OCP_VENDOR_XILINX,
+ .function = OCP_FUNC_16550,
+ .index = 1,
+ .paddr = XPAR_UARTNS550_1_BASEADDR,
+ .irq = XPAR_INTC_0_UARTNS550_1_VEC_ID,
+ .pm = OCP_CPM_NA
+ },
+#ifdef XPAR_UARTNS550_2_BASEADDR
+ { .vendor = OCP_VENDOR_XILINX,
+ .function = OCP_FUNC_16550,
+ .index = 2,
+ .paddr = XPAR_UARTNS550_2_BASEADDR,
+ .irq = XPAR_INTC_0_UARTNS550_2_VEC_ID,
+ .pm = OCP_CPM_NA
+ },
+#ifdef XPAR_UARTNS550_3_BASEADDR
+ { .vendor = OCP_VENDOR_XILINX,
+ .function = OCP_FUNC_16550,
+ .index = 3,
+ .paddr = XPAR_UARTNS550_3_BASEADDR,
+ .irq = XPAR_INTC_0_UARTNS550_3_VEC_ID,
+ .pm = OCP_CPM_NA
+ },
+#ifdef XPAR_UARTNS550_4_BASEADDR
+#error Edit this file to add more devices.
+#endif /* 4 */
+#endif /* 3 */
+#endif /* 2 */
+#endif /* 1 */
+#endif /* 0 */
+ { .vendor = OCP_VENDOR_INVALID
+ }
+};
diff --git a/arch/ppc/platforms/4xx/virtex-ii_pro.h b/arch/ppc/platforms/4xx/virtex-ii_pro.h
new file mode 100644
index 00000000000..9014c488733
--- /dev/null
+++ b/arch/ppc/platforms/4xx/virtex-ii_pro.h
@@ -0,0 +1,99 @@
+/*
+ * arch/ppc/platforms/4xx/virtex-ii_pro.h
+ *
+ * Include file that defines the Xilinx Virtex-II Pro processor
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2002-2004 (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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_VIRTEXIIPRO_H__
+#define __ASM_VIRTEXIIPRO_H__
+
+#include <linux/config.h>
+#include <asm/xparameters.h>
+
+/* serial defines */
+
+#define RS_TABLE_SIZE 4 /* change this and add more devices below
+ if you have more then 4 16x50 UARTs */
+
+#define BASE_BAUD (XPAR_UARTNS550_0_CLOCK_FREQ_HZ/16)
+
+/* The serial ports in the Virtex-II Pro have each I/O byte in the
+ * LSByte of a word. This means that iomem_reg_shift needs to be 2 to
+ * change the byte offsets into word offsets. In addition the base
+ * addresses need to have 3 added to them to get to the LSByte.
+ */
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
+ ASYNC_BOOT_AUTOCONF, \
+ .iomem_base = (u8 *)XPAR_UARTNS550_##num##_BASEADDR + 3, \
+ .iomem_reg_shift = 2, \
+ .io_type = SERIAL_IO_MEM},
+
+#if defined(XPAR_INTC_0_UARTNS550_0_VEC_ID)
+#define ML300_UART0 STD_UART_OP(0)
+#else
+#define ML300_UART0
+#endif
+
+#if defined(XPAR_INTC_0_UARTNS550_1_VEC_ID)
+#define ML300_UART1 STD_UART_OP(1)
+#else
+#define ML300_UART1
+#endif
+
+#if defined(XPAR_INTC_0_UARTNS550_2_VEC_ID)
+#define ML300_UART2 STD_UART_OP(2)
+#else
+#define ML300_UART2
+#endif
+
+#if defined(XPAR_INTC_0_UARTNS550_3_VEC_ID)
+#define ML300_UART3 STD_UART_OP(3)
+#else
+#define ML300_UART3
+#endif
+
+#if defined(XPAR_INTC_0_UARTNS550_4_VEC_ID)
+#error Edit this file to add more devices.
+#elif defined(XPAR_INTC_0_UARTNS550_3_VEC_ID)
+#define NR_SER_PORTS 4
+#elif defined(XPAR_INTC_0_UARTNS550_2_VEC_ID)
+#define NR_SER_PORTS 3
+#elif defined(XPAR_INTC_0_UARTNS550_1_VEC_ID)
+#define NR_SER_PORTS 2
+#elif defined(XPAR_INTC_0_UARTNS550_0_VEC_ID)
+#define NR_SER_PORTS 1
+#else
+#define NR_SER_PORTS 0
+#endif
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_PORT_DFNS \
+ ML300_UART0 \
+ ML300_UART1 \
+ ML300_UART2 \
+ ML300_UART3
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_PORT_DFNS \
+ ML300_UART1 \
+ ML300_UART0 \
+ ML300_UART2 \
+ ML300_UART3
+#endif
+
+#define DCRN_CPMFR_BASE 0
+
+#include <asm/ibm405.h>
+
+#endif /* __ASM_VIRTEXIIPRO_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/walnut.c b/arch/ppc/platforms/4xx/walnut.c
new file mode 100644
index 00000000000..a33eda4b748
--- /dev/null
+++ b/arch/ppc/platforms/4xx/walnut.c
@@ -0,0 +1,249 @@
+/*
+ * arch/ppc/platforms/4xx/walnut.c
+ *
+ * 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>
+ *
+ * 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/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/ocp.h>
+#include <asm/ibm_ocp_pci.h>
+#include <asm/todc.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+void *kb_cs;
+void *kb_data;
+void *walnut_rtc_base;
+
+/* Some IRQs unique to Walnut.
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {28, 28, 28, 28}, /* IDSEL 1 - PCI slot 1 */
+ {29, 29, 29, 29}, /* IDSEL 2 - PCI slot 2 */
+ {30, 30, 30, 30}, /* IDSEL 3 - PCI slot 3 */
+ {31, 31, 31, 31}, /* IDSEL 4 - PCI slot 4 */
+ };
+
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+};
+
+void __init
+walnut_setup_arch(void)
+{
+
+ void *fpga_brdc;
+ unsigned char fpga_brdc_data;
+ void *fpga_enable;
+ void *fpga_polarity;
+ void *fpga_status;
+ void *fpga_trigger;
+
+ ppc4xx_setup_arch();
+
+ ibm_ocp_set_emac(0, 0);
+
+ kb_data = ioremap(WALNUT_PS2_BASE, 8);
+ if (!kb_data) {
+ printk(KERN_CRIT
+ "walnut_setup_arch() kb_data ioremap failed\n");
+ return;
+ }
+
+ kb_cs = kb_data + 1;
+
+ fpga_status = ioremap(WALNUT_FPGA_BASE, 8);
+ if (!fpga_status) {
+ printk(KERN_CRIT
+ "walnut_setup_arch() fpga_status ioremap failed\n");
+ return;
+ }
+
+ fpga_enable = fpga_status + 1;
+ fpga_polarity = fpga_status + 2;
+ fpga_trigger = fpga_status + 3;
+ fpga_brdc = fpga_status + 4;
+
+ /* split the keyboard and mouse interrupts */
+ fpga_brdc_data = readb(fpga_brdc);
+ fpga_brdc_data |= 0x80;
+ writeb(fpga_brdc_data, fpga_brdc);
+
+ writeb(0x3, fpga_enable);
+
+ writeb(0x3, fpga_polarity);
+
+ writeb(0x3, fpga_trigger);
+
+ /* RTC step for the walnut */
+ walnut_rtc_base = (void *) WALNUT_RTC_VADDR;
+ TODC_INIT(TODC_TYPE_DS1743, walnut_rtc_base, walnut_rtc_base,
+ walnut_rtc_base, 8);
+ /* Identify the system */
+ printk("IBM Walnut port (C) 2000-2002 MontaVista Software, Inc. (source@mvista.com)\n");
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+#ifdef CONFIG_PCI
+ unsigned int bar_response, bar;
+ /*
+ * Expected PCI mapping:
+ *
+ * PLB addr PCI memory addr
+ * --------------------- ---------------------
+ * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff
+ * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff
+ *
+ * PLB addr PCI io addr
+ * --------------------- ---------------------
+ * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000
+ *
+ * The following code is simplified by assuming that the bootrom
+ * has been well behaved in following this mapping.
+ */
+
+#ifdef DEBUG
+ int i;
+
+ printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
+ printk("PCI bridge regs before fixup \n");
+ for (i = 0; i <= 3; i++) {
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+ }
+ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+
+ /* added for IBM boot rom version 1.15 bios bar changes -AK */
+
+ /* Disable region first */
+ out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+ /* PLB starting addr, PCI: 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+ /* PCI start addr, 0x80000000 */
+ out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+ /* 512MB range of PLB to PCI */
+ out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+ /* Enable no pre-fetch, enable region */
+ out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+ (PPC405_PCI_UPPER_MEM -
+ PPC405_PCI_MEM_BASE)) | 0x01));
+
+ /* Disable region one */
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+ out_le32((void *) &(pcip->ptm1ms), 0x00000000);
+
+ /* Disable region two */
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+ out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+ /* Zero config bars */
+ for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+ early_write_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ 0x00000000);
+ early_read_config_dword(hose, hose->first_busno,
+ PCI_FUNC(hose->first_busno), bar,
+ &bar_response);
+ DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+ hose->first_busno, PCI_SLOT(hose->first_busno),
+ PCI_FUNC(hose->first_busno), bar, bar_response);
+ }
+ /* end work arround */
+
+#ifdef DEBUG
+ printk("PCI bridge regs after fixup \n");
+ for (i = 0; i <= 3; i++) {
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+ }
+ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+#endif
+}
+
+void __init
+walnut_map_io(void)
+{
+ ppc4xx_map_io();
+ io_block_mapping(WALNUT_RTC_VADDR,
+ WALNUT_RTC_PADDR, WALNUT_RTC_SIZE, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ ppc4xx_init(r3, r4, r5, r6, r7);
+
+ ppc_md.setup_arch = walnut_setup_arch;
+ ppc_md.setup_io_mappings = walnut_map_io;
+
+#ifdef CONFIG_GEN_RTC
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+#endif
+}
diff --git a/arch/ppc/platforms/4xx/walnut.h b/arch/ppc/platforms/4xx/walnut.h
new file mode 100644
index 00000000000..04cfbf3696b
--- /dev/null
+++ b/arch/ppc/platforms/4xx/walnut.h
@@ -0,0 +1,72 @@
+/*
+ * arch/ppc/platforms/4xx/walnut.h
+ *
+ * Macros, definitions, and data structures specific to the IBM PowerPC
+ * 405GP "Walnut" evaluation board.
+ *
+ * Authors: Grant Erickson <grant@lcse.umn.edu>, Frank Rowand
+ * <frank_rowand@mvista.com>, Debbie Chu <debbie_chu@mvista.com> or
+ * source@mvista.com
+ *
+ * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ * 2000 (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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_WALNUT_H__
+#define __ASM_WALNUT_H__
+
+/* We have a 405GP core */
+#include <platforms/4xx/ibm405gp.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Walnut" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+ unsigned char bi_s_version[4]; /* Version of this structure */
+ unsigned char bi_r_version[30]; /* Version of the IBM ROM */
+ unsigned int bi_memsize; /* DRAM installed, in bytes */
+ unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */
+ unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */
+ unsigned int bi_intfreq; /* Processor speed, in Hz */
+ unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
+ unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+
+/* Memory map for the IBM "Walnut" 405GP evaluation board.
+ * Generic 4xx plus RTC.
+ */
+
+extern void *walnut_rtc_base;
+#define WALNUT_RTC_PADDR ((uint)0xf0000000)
+#define WALNUT_RTC_VADDR WALNUT_RTC_PADDR
+#define WALNUT_RTC_SIZE ((uint)8*1024)
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD 201600
+#else
+#define BASE_BAUD 691200
+#endif
+
+#define WALNUT_PS2_BASE 0xF0100000
+#define WALNUT_FPGA_BASE 0xF0300000
+
+#define PPC4xx_MACHINE_NAME "IBM Walnut"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_WALNUT_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c
new file mode 100644
index 00000000000..0b1b77d986b
--- /dev/null
+++ b/arch/ppc/platforms/4xx/xilinx_ml300.c
@@ -0,0 +1,146 @@
+/*
+ * arch/ppc/platforms/4xx/xilinx_ml300.c
+ *
+ * Xilinx ML300 evaluation board initialization
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2002-2004 (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/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serialP.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ocp.h>
+
+#include <platforms/4xx/virtex-ii_pro.h> /* for NR_SER_PORTS */
+
+/*
+ * As an overview of how the following functions (platform_init,
+ * ml300_map_io, ml300_setup_arch and ml300_init_IRQ) fit into the
+ * kernel startup procedure, here's a call tree:
+ *
+ * start_here arch/ppc/kernel/head_4xx.S
+ * early_init arch/ppc/kernel/setup.c
+ * machine_init arch/ppc/kernel/setup.c
+ * platform_init this file
+ * ppc4xx_init arch/ppc/syslib/ppc4xx_setup.c
+ * parse_bootinfo
+ * find_bootinfo
+ * "setup some default ppc_md pointers"
+ * MMU_init arch/ppc/mm/init.c
+ * *ppc_md.setup_io_mappings == ml300_map_io this file
+ * ppc4xx_map_io arch/ppc/syslib/ppc4xx_setup.c
+ * start_kernel init/main.c
+ * setup_arch arch/ppc/kernel/setup.c
+ * #if defined(CONFIG_KGDB)
+ * *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc
+ * #endif
+ * *ppc_md.setup_arch == ml300_setup_arch this file
+ * ppc4xx_setup_arch arch/ppc/syslib/ppc4xx_setup.c
+ * ppc4xx_find_bridges arch/ppc/syslib/ppc405_pci.c
+ * init_IRQ arch/ppc/kernel/irq.c
+ * *ppc_md.init_IRQ == ml300_init_IRQ this file
+ * ppc4xx_init_IRQ arch/ppc/syslib/ppc4xx_setup.c
+ * ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c
+ */
+
+#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
+
+static volatile unsigned *powerdown_base =
+ (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
+
+static void
+xilinx_power_off(void)
+{
+ local_irq_disable();
+ out_be32(powerdown_base, XPAR_POWER_0_POWERDOWN_VALUE);
+ while (1) ;
+}
+#endif
+
+void __init
+ml300_map_io(void)
+{
+ ppc4xx_map_io();
+
+#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
+ powerdown_base = ioremap((unsigned long) powerdown_base,
+ XPAR_POWER_0_POWERDOWN_HIGHADDR -
+ XPAR_POWER_0_POWERDOWN_BASEADDR + 1);
+#endif
+}
+
+static void __init
+ml300_early_serial_map(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct serial_state old_ports[] = { SERIAL_PORT_DFNS };
+ struct uart_port port;
+ int i;
+
+ /* Setup ioremapped serial port access */
+ for (i = 0; i < ARRAY_SIZE(old_ports); i++ ) {
+ memset(&port, 0, sizeof(port));
+ port.membase = ioremap((phys_addr_t)(old_ports[i].iomem_base), 16);
+ port.irq = old_ports[i].irq;
+ port.uartclk = old_ports[i].baud_base * 16;
+ port.regshift = old_ports[i].iomem_reg_shift;
+ port.iotype = SERIAL_IO_MEM;
+ port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+ port.line = i;
+
+ if (early_serial_setup(&port) != 0) {
+ printk("Early serial init of port %d failed\n", i);
+ }
+ }
+#endif /* CONFIG_SERIAL_8250 */
+}
+
+void __init
+ml300_setup_arch(void)
+{
+ ppc4xx_setup_arch(); /* calls ppc4xx_find_bridges() */
+
+ ml300_early_serial_map();
+
+ /* Identify the system */
+ printk(KERN_INFO "Xilinx Virtex-II Pro port\n");
+ printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+}
+
+/* Called after board_setup_irq from ppc4xx_init_IRQ(). */
+void __init
+ml300_init_irq(void)
+{
+ ppc4xx_init_IRQ();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ ppc4xx_init(r3, r4, r5, r6, r7);
+
+ ppc_md.setup_arch = ml300_setup_arch;
+ ppc_md.setup_io_mappings = ml300_map_io;
+ ppc_md.init_IRQ = ml300_init_irq;
+
+#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
+ ppc_md.power_off = xilinx_power_off;
+#endif
+
+#ifdef CONFIG_KGDB
+ ppc_md.early_serial_map = ml300_early_serial_map;
+#endif
+}
+
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.h b/arch/ppc/platforms/4xx/xilinx_ml300.h
new file mode 100644
index 00000000000..f8c58841233
--- /dev/null
+++ b/arch/ppc/platforms/4xx/xilinx_ml300.h
@@ -0,0 +1,47 @@
+/*
+ * arch/ppc/platforms/4xx/xilinx_ml300.h
+ *
+ * Include file that defines the Xilinx ML300 evaluation board
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2002-2004 (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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_XILINX_ML300_H__
+#define __ASM_XILINX_ML300_H__
+
+/* ML300 has a Xilinx Virtex-II Pro processor */
+#include <platforms/4xx/virtex-ii_pro.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+typedef struct board_info {
+ unsigned int bi_memsize; /* DRAM installed, in bytes */
+ unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */
+ unsigned int bi_intfreq; /* Processor speed, in Hz */
+ unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
+ unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+#endif /* !__ASSEMBLY__ */
+
+/* We don't need anything mapped. Size of zero will accomplish that. */
+#define PPC4xx_ONB_IO_PADDR 0u
+#define PPC4xx_ONB_IO_VADDR 0u
+#define PPC4xx_ONB_IO_SIZE 0u
+
+#define PPC4xx_MACHINE_NAME "Xilinx ML300"
+
+#endif /* __ASM_XILINX_ML300_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h b/arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h
new file mode 100644
index 00000000000..97e3f4d4bd5
--- /dev/null
+++ b/arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h
@@ -0,0 +1,310 @@
+/*******************************************************************
+*
+* Author: Xilinx, 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.
+*
+*
+* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
+* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
+* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD,
+* XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
+* FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING
+* ANY THIRD PARTY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
+* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
+* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY
+* WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM
+* CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND
+* FITNESS FOR A PARTICULAR PURPOSE.
+*
+*
+* Xilinx hardware products are not intended for use in life support
+* appliances, devices, or systems. Use in such applications is
+* expressly prohibited.
+*
+*
+* (c) Copyright 2002-2004 Xilinx Inc.
+* All rights reserved.
+*
+*
+* 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.
+*
+* Description: Driver parameters
+*
+*******************************************************************/
+
+#define XPAR_XPCI_NUM_INSTANCES 1
+#define XPAR_XPCI_CLOCK_HZ 33333333
+#define XPAR_OPB_PCI_REF_0_DEVICE_ID 0
+#define XPAR_OPB_PCI_REF_0_BASEADDR 0x20000000
+#define XPAR_OPB_PCI_REF_0_HIGHADDR 0x3FFFFFFF
+#define XPAR_OPB_PCI_REF_0_CONFIG_ADDR 0x3C000000
+#define XPAR_OPB_PCI_REF_0_CONFIG_DATA 0x3C000004
+#define XPAR_OPB_PCI_REF_0_LCONFIG_ADDR 0x3E000000
+#define XPAR_OPB_PCI_REF_0_MEM_BASEADDR 0x20000000
+#define XPAR_OPB_PCI_REF_0_MEM_HIGHADDR 0x37FFFFFF
+#define XPAR_OPB_PCI_REF_0_IO_BASEADDR 0x38000000
+#define XPAR_OPB_PCI_REF_0_IO_HIGHADDR 0x3BFFFFFF
+
+/******************************************************************/
+
+#define XPAR_XEMAC_NUM_INSTANCES 1
+#define XPAR_OPB_ETHERNET_0_BASEADDR 0x60000000
+#define XPAR_OPB_ETHERNET_0_HIGHADDR 0x60003FFF
+#define XPAR_OPB_ETHERNET_0_DEVICE_ID 0
+#define XPAR_OPB_ETHERNET_0_ERR_COUNT_EXIST 1
+#define XPAR_OPB_ETHERNET_0_DMA_PRESENT 1
+#define XPAR_OPB_ETHERNET_0_MII_EXIST 1
+
+/******************************************************************/
+
+#define XPAR_MY_OPB_GPIO_0_DEVICE_ID_0 0
+#define XPAR_MY_OPB_GPIO_0_BASEADDR_0 0x90000000
+#define XPAR_MY_OPB_GPIO_0_HIGHADDR_0 (0x90000000+0x7)
+#define XPAR_MY_OPB_GPIO_0_DEVICE_ID_1 1
+#define XPAR_MY_OPB_GPIO_0_BASEADDR_1 (0x90000000+0x8)
+#define XPAR_MY_OPB_GPIO_0_HIGHADDR_1 (0x90000000+0x1F)
+#define XPAR_XGPIO_NUM_INSTANCES 2
+
+/******************************************************************/
+
+#define XPAR_XIIC_NUM_INSTANCES 1
+#define XPAR_OPB_IIC_0_BASEADDR 0xA8000000
+#define XPAR_OPB_IIC_0_HIGHADDR 0xA80001FF
+#define XPAR_OPB_IIC_0_DEVICE_ID 0
+#define XPAR_OPB_IIC_0_TEN_BIT_ADR 0
+
+/******************************************************************/
+
+#define XPAR_XUARTNS550_NUM_INSTANCES 2
+#define XPAR_XUARTNS550_CLOCK_HZ 100000000
+#define XPAR_OPB_UART16550_0_BASEADDR 0xA0000000
+#define XPAR_OPB_UART16550_0_HIGHADDR 0xA0001FFF
+#define XPAR_OPB_UART16550_0_DEVICE_ID 0
+#define XPAR_OPB_UART16550_1_BASEADDR 0xA0010000
+#define XPAR_OPB_UART16550_1_HIGHADDR 0xA0011FFF
+#define XPAR_OPB_UART16550_1_DEVICE_ID 1
+
+/******************************************************************/
+
+#define XPAR_XSPI_NUM_INSTANCES 1
+#define XPAR_OPB_SPI_0_BASEADDR 0xA4000000
+#define XPAR_OPB_SPI_0_HIGHADDR 0xA400007F
+#define XPAR_OPB_SPI_0_DEVICE_ID 0
+#define XPAR_OPB_SPI_0_FIFO_EXIST 1
+#define XPAR_OPB_SPI_0_SPI_SLAVE_ONLY 0
+#define XPAR_OPB_SPI_0_NUM_SS_BITS 1
+
+/******************************************************************/
+
+#define XPAR_XPS2_NUM_INSTANCES 2
+#define XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_0 0
+#define XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_0 0xA9000000
+#define XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_0 (0xA9000000+0x3F)
+#define XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_1 1
+#define XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_1 (0xA9000000+0x1000)
+#define XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_1 (0xA9000000+0x103F)
+
+/******************************************************************/
+
+#define XPAR_XTOUCHSCREEN_NUM_INSTANCES 1
+#define XPAR_OPB_TSD_REF_0_BASEADDR 0xAA000000
+#define XPAR_OPB_TSD_REF_0_HIGHADDR 0xAA000007
+#define XPAR_OPB_TSD_REF_0_DEVICE_ID 0
+
+/******************************************************************/
+
+#define XPAR_OPB_AC97_CONTROLLER_REF_0_BASEADDR 0xA6000000
+#define XPAR_OPB_AC97_CONTROLLER_REF_0_HIGHADDR 0xA60000FF
+#define XPAR_OPB_PAR_PORT_REF_0_BASEADDR 0x90010000
+#define XPAR_OPB_PAR_PORT_REF_0_HIGHADDR 0x900100FF
+#define XPAR_PLB_DDR_0_BASEADDR 0x00000000
+#define XPAR_PLB_DDR_0_HIGHADDR 0x0FFFFFFF
+
+/******************************************************************/
+
+#define XPAR_XINTC_HAS_IPR 1
+#define XPAR_INTC_MAX_NUM_INTR_INPUTS 18
+#define XPAR_XINTC_USE_DCR 0
+#define XPAR_XINTC_NUM_INSTANCES 1
+#define XPAR_DCR_INTC_0_BASEADDR 0xD0000FC0
+#define XPAR_DCR_INTC_0_HIGHADDR 0xD0000FDF
+#define XPAR_DCR_INTC_0_DEVICE_ID 0
+#define XPAR_DCR_INTC_0_KIND_OF_INTR 0x00038000
+
+/******************************************************************/
+
+#define XPAR_DCR_INTC_0_MISC_LOGIC_0_PHY_MII_INT_INTR 0
+#define XPAR_DCR_INTC_0_OPB_ETHERNET_0_IP2INTC_IRPT_INTR 1
+#define XPAR_DCR_INTC_0_MISC_LOGIC_0_IIC_TEMP_CRIT_INTR 2
+#define XPAR_DCR_INTC_0_MISC_LOGIC_0_IIC_IRQ_INTR 3
+#define XPAR_DCR_INTC_0_OPB_IIC_0_IP2INTC_IRPT_INTR 4
+#define XPAR_DCR_INTC_0_OPB_SYSACE_0_SYSACE_IRQ_INTR 5
+#define XPAR_DCR_INTC_0_OPB_UART16550_0_IP2INTC_IRPT_INTR 6
+#define XPAR_DCR_INTC_0_OPB_UART16550_1_IP2INTC_IRPT_INTR 7
+#define XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR1_INTR 8
+#define XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR2_INTR 9
+#define XPAR_DCR_INTC_0_OPB_SPI_0_IP2INTC_IRPT_INTR 10
+#define XPAR_DCR_INTC_0_OPB_TSD_REF_0_INTR_INTR 11
+#define XPAR_DCR_INTC_0_OPB_AC97_CONTROLLER_REF_0_PLAYBACK_INTERRUPT_INTR 12
+#define XPAR_DCR_INTC_0_OPB_AC97_CONTROLLER_REF_0_RECORD_INTERRUPT_INTR 13
+#define XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR 14
+#define XPAR_DCR_INTC_0_PLB2OPB_BRIDGE_0_BUS_ERROR_DET_INTR 15
+#define XPAR_DCR_INTC_0_PLB_V34_0_BUS_ERROR_DET_INTR 16
+#define XPAR_DCR_INTC_0_OPB2PLB_BRIDGE_0_BUS_ERROR_DET_INTR 17
+
+/******************************************************************/
+
+#define XPAR_XTFT_NUM_INSTANCES 1
+#define XPAR_PLB_TFT_CNTLR_REF_0_DCR_BASEADDR 0xD0000200
+#define XPAR_PLB_TFT_CNTLR_REF_0_DCR_HIGHADDR 0xD0000207
+#define XPAR_PLB_TFT_CNTLR_REF_0_DEVICE_ID 0
+
+/******************************************************************/
+
+#define XPAR_XSYSACE_MEM_WIDTH 8
+#define XPAR_XSYSACE_NUM_INSTANCES 1
+#define XPAR_OPB_SYSACE_0_BASEADDR 0xCF000000
+#define XPAR_OPB_SYSACE_0_HIGHADDR 0xCF0001FF
+#define XPAR_OPB_SYSACE_0_DEVICE_ID 0
+#define XPAR_OPB_SYSACE_0_MEM_WIDTH 8
+
+/******************************************************************/
+
+#define XPAR_CPU_PPC405_CORE_CLOCK_FREQ_HZ 300000000
+
+/******************************************************************/
+
+/******************************************************************/
+
+/* Linux Redefines */
+
+/******************************************************************/
+
+#define XPAR_UARTNS550_0_BASEADDR (XPAR_OPB_UART16550_0_BASEADDR+0x1000)
+#define XPAR_UARTNS550_0_HIGHADDR XPAR_OPB_UART16550_0_HIGHADDR
+#define XPAR_UARTNS550_0_CLOCK_FREQ_HZ XPAR_XUARTNS550_CLOCK_HZ
+#define XPAR_UARTNS550_0_DEVICE_ID XPAR_OPB_UART16550_0_DEVICE_ID
+#define XPAR_UARTNS550_1_BASEADDR (XPAR_OPB_UART16550_1_BASEADDR+0x1000)
+#define XPAR_UARTNS550_1_HIGHADDR XPAR_OPB_UART16550_1_HIGHADDR
+#define XPAR_UARTNS550_1_CLOCK_FREQ_HZ XPAR_XUARTNS550_CLOCK_HZ
+#define XPAR_UARTNS550_1_DEVICE_ID XPAR_OPB_UART16550_1_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_GPIO_0_BASEADDR XPAR_MY_OPB_GPIO_0_BASEADDR_0
+#define XPAR_GPIO_0_HIGHADDR XPAR_MY_OPB_GPIO_0_HIGHADDR_0
+#define XPAR_GPIO_0_DEVICE_ID XPAR_MY_OPB_GPIO_0_DEVICE_ID_0
+#define XPAR_GPIO_1_BASEADDR XPAR_MY_OPB_GPIO_0_BASEADDR_1
+#define XPAR_GPIO_1_HIGHADDR XPAR_MY_OPB_GPIO_0_HIGHADDR_1
+#define XPAR_GPIO_1_DEVICE_ID XPAR_MY_OPB_GPIO_0_DEVICE_ID_1
+
+/******************************************************************/
+
+#define XPAR_IIC_0_BASEADDR XPAR_OPB_IIC_0_BASEADDR
+#define XPAR_IIC_0_HIGHADDR XPAR_OPB_IIC_0_HIGHADDR
+#define XPAR_IIC_0_TEN_BIT_ADR XPAR_OPB_IIC_0_TEN_BIT_ADR
+#define XPAR_IIC_0_DEVICE_ID XPAR_OPB_IIC_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_SYSACE_0_BASEADDR XPAR_OPB_SYSACE_0_BASEADDR
+#define XPAR_SYSACE_0_HIGHADDR XPAR_OPB_SYSACE_0_HIGHADDR
+#define XPAR_SYSACE_0_DEVICE_ID XPAR_OPB_SYSACE_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_INTC_0_BASEADDR XPAR_DCR_INTC_0_BASEADDR
+#define XPAR_INTC_0_HIGHADDR XPAR_DCR_INTC_0_HIGHADDR
+#define XPAR_INTC_0_KIND_OF_INTR XPAR_DCR_INTC_0_KIND_OF_INTR
+#define XPAR_INTC_0_DEVICE_ID XPAR_DCR_INTC_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_INTC_0_EMAC_0_VEC_ID XPAR_DCR_INTC_0_OPB_ETHERNET_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_IIC_0_VEC_ID XPAR_DCR_INTC_0_OPB_IIC_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_SYSACE_0_VEC_ID XPAR_DCR_INTC_0_OPB_SYSACE_0_SYSACE_IRQ_INTR
+#define XPAR_INTC_0_UARTNS550_0_VEC_ID XPAR_DCR_INTC_0_OPB_UART16550_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_UARTNS550_1_VEC_ID XPAR_DCR_INTC_0_OPB_UART16550_1_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_PS2_0_VEC_ID XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR1_INTR
+#define XPAR_INTC_0_PS2_1_VEC_ID XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR2_INTR
+#define XPAR_INTC_0_SPI_0_VEC_ID XPAR_DCR_INTC_0_OPB_SPI_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_TOUCHSCREEN_0_VEC_ID XPAR_DCR_INTC_0_OPB_TSD_REF_0_INTR_INTR
+#define XPAR_INTC_0_PCI_0_VEC_ID_A XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR
+#define XPAR_INTC_0_PCI_0_VEC_ID_B XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR
+#define XPAR_INTC_0_PCI_0_VEC_ID_C XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR
+#define XPAR_INTC_0_PCI_0_VEC_ID_D XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR
+
+/******************************************************************/
+
+#define XPAR_EMAC_0_BASEADDR XPAR_OPB_ETHERNET_0_BASEADDR
+#define XPAR_EMAC_0_HIGHADDR XPAR_OPB_ETHERNET_0_HIGHADDR
+#define XPAR_EMAC_0_DMA_PRESENT XPAR_OPB_ETHERNET_0_DMA_PRESENT
+#define XPAR_EMAC_0_MII_EXIST XPAR_OPB_ETHERNET_0_MII_EXIST
+#define XPAR_EMAC_0_ERR_COUNT_EXIST XPAR_OPB_ETHERNET_0_ERR_COUNT_EXIST
+#define XPAR_EMAC_0_DEVICE_ID XPAR_OPB_ETHERNET_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_SPI_0_BASEADDR XPAR_OPB_SPI_0_BASEADDR
+#define XPAR_SPI_0_HIGHADDR XPAR_OPB_SPI_0_HIGHADDR
+#define XPAR_SPI_0_DEVICE_ID XPAR_OPB_SPI_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_TOUCHSCREEN_0_BASEADDR XPAR_OPB_TSD_REF_0_BASEADDR
+#define XPAR_TOUCHSCREEN_0_HIGHADDR XPAR_OPB_TSD_REF_0_HIGHADDR
+#define XPAR_TOUCHSCREEN_0_DEVICE_ID XPAR_OPB_TSD_REF_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_TFT_0_BASEADDR XPAR_PLB_TFT_CNTLR_REF_0_DCR_BASEADDR
+
+/******************************************************************/
+
+#define XPAR_PCI_0_BASEADDR XPAR_OPB_PCI_REF_0_BASEADDR
+#define XPAR_PCI_0_HIGHADDR XPAR_OPB_PCI_REF_0_HIGHADDR
+#define XPAR_PCI_0_CONFIG_ADDR XPAR_OPB_PCI_REF_0_CONFIG_ADDR
+#define XPAR_PCI_0_CONFIG_DATA XPAR_OPB_PCI_REF_0_CONFIG_DATA
+#define XPAR_PCI_0_LCONFIG_ADDR XPAR_OPB_PCI_REF_0_LCONFIG_ADDR
+#define XPAR_PCI_0_MEM_BASEADDR XPAR_OPB_PCI_REF_0_MEM_BASEADDR
+#define XPAR_PCI_0_MEM_HIGHADDR XPAR_OPB_PCI_REF_0_MEM_HIGHADDR
+#define XPAR_PCI_0_IO_BASEADDR XPAR_OPB_PCI_REF_0_IO_BASEADDR
+#define XPAR_PCI_0_IO_HIGHADDR XPAR_OPB_PCI_REF_0_IO_HIGHADDR
+#define XPAR_PCI_0_CLOCK_FREQ_HZ XPAR_XPCI_CLOCK_HZ
+#define XPAR_PCI_0_DEVICE_ID XPAR_OPB_PCI_REF_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_PS2_0_BASEADDR XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_0
+#define XPAR_PS2_0_HIGHADDR XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_0
+#define XPAR_PS2_0_DEVICE_ID XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_0
+#define XPAR_PS2_1_BASEADDR XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_1
+#define XPAR_PS2_1_HIGHADDR XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_1
+#define XPAR_PS2_1_DEVICE_ID XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_1
+
+/******************************************************************/
+
+#define XPAR_PLB_CLOCK_FREQ_HZ 100000000
+#define XPAR_CORE_CLOCK_FREQ_HZ XPAR_CPU_PPC405_CORE_CLOCK_FREQ_HZ
+#define XPAR_DDR_0_SIZE 0x08000000
+
+/******************************************************************/
+
+#define XPAR_PERSISTENT_0_IIC_0_BASEADDR 0x00000400
+#define XPAR_PERSISTENT_0_IIC_0_HIGHADDR 0x000007FF
+#define XPAR_PERSISTENT_0_IIC_0_EEPROMADDR 0xA0
+
+/******************************************************************/
+
+#define XPAR_POWER_0_POWERDOWN_BASEADDR 0x90000004
+#define XPAR_POWER_0_POWERDOWN_HIGHADDR 0x90000007
+#define XPAR_POWER_0_POWERDOWN_VALUE 0xFF
+
+/******************************************************************/
diff --git a/arch/ppc/platforms/83xx/Makefile b/arch/ppc/platforms/83xx/Makefile
new file mode 100644
index 00000000000..eb55341d6a1
--- /dev/null
+++ b/arch/ppc/platforms/83xx/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for the PowerPC 83xx linux kernel.
+#
+obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
new file mode 100644
index 00000000000..b3b0f51979d
--- /dev/null
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -0,0 +1,289 @@
+/*
+ * arch/ppc/platforms/83xx/mpc834x_sys.c
+ *
+ * MPC834x SYS board specific routines
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#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/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.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/prom.h>
+#include <asm/ipic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc83xx.h>
+#include <asm/irq.h>
+#include <asm/kgdb.h>
+#include <asm/ppc_sys.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc83xx_setup.h>
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+extern unsigned long total_memory; /* in mm/init */
+
+unsigned char __res[sizeof (bd_t)];
+
+#ifdef CONFIG_PCI
+#error "PCI is not supported"
+/* NEED mpc83xx_map_irq & mpc83xx_exclude_device
+ see platforms/85xx/mpc85xx_ads_common.c */
+#endif /* CONFIG_PCI */
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+mpc834x_sys_setup_arch(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+ struct gianfar_platform_data *pdata;
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ /* Set loops_per_jiffy to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+ /* setup PCI host bridges */
+ mpc83xx_sys_setup_hose();
+#endif
+ mpc83xx_early_serial_map();
+
+ /* setup the board related information for the enet controllers */
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC83xx_IRQ_EXT1;
+ pdata->phyid = 0;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC83xx_IRQ_EXT2;
+ pdata->phyid = 1;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+static void __init
+mpc834x_sys_map_io(void)
+{
+ /* we steal the lowest ioremap addr for virt space */
+ io_block_mapping(VIRT_IMMRBAR, immrbar, 1024*1024, _PAGE_IO);
+ io_block_mapping(BCSR_VIRT_ADDR, BCSR_PHYS_ADDR, BCSR_SIZE, _PAGE_IO);
+}
+
+int
+mpc834x_sys_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid, svid, phid1;
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ pvid = mfspr(SPRN_PVR);
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Freescale Inc.\n");
+ seq_printf(m, "Machine\t\t: mpc%s sys\n", cur_ppc_sys_spec->ppc_sys_name);
+ seq_printf(m, "core clock\t: %d MHz\n"
+ "bus clock\t: %d MHz\n",
+ (int)(binfo->bi_intfreq / 1000000),
+ (int)(binfo->bi_busfreq / 1000000));
+ 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", (int)(binfo->bi_memsize / (1024 * 1024)));
+
+ return 0;
+}
+
+
+void __init
+mpc834x_sys_init_IRQ(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+
+ u8 senses[8] = {
+ 0, /* EXT 0 */
+ IRQ_SENSE_LEVEL, /* EXT 1 */
+ IRQ_SENSE_LEVEL, /* EXT 2 */
+ 0, /* EXT 3 */
+ 0, /* EXT 4 */
+ 0, /* EXT 5 */
+ 0, /* EXT 6 */
+ 0, /* EXT 7 */
+ };
+
+ ipic_init(binfo->bi_immr_base + 0x00700, 0, MPC83xx_IPIC_IRQ_OFFSET, senses, 8);
+
+ /* Initialize the default interrupt mapping priorities,
+ * in case the boot rom changed something on us.
+ */
+ ipic_set_default_priority();
+}
+
+static __inline__ void
+mpc834x_sys_set_bat(void)
+{
+ /* we steal the lowest ioremap addr for virt space */
+ mb();
+ mtspr(SPRN_DBAT1U, VIRT_IMMRBAR | 0x1e);
+ mtspr(SPRN_DBAT1L, immrbar | 0x2a);
+ mb();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ bd_t *binfo = (bd_t *) __res;
+
+ /* parse_bootinfo must always be called first */
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+ sizeof (bd_t));
+ }
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+ /*
+ * If the init RAM disk has been configured in, and there's a valid
+ * starting address for it, set it up.
+ */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Copy the kernel command line arguments to a safe place. */
+ if (r6) {
+ *(char *) (r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+ }
+
+ immrbar = binfo->bi_immr_base;
+
+ mpc834x_sys_set_bat();
+
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+ {
+ struct uart_port p;
+
+ memset(&p, 0, sizeof (p));
+ p.iotype = SERIAL_IO_MEM;
+ p.membase = (unsigned char __iomem *)(VIRT_IMMRBAR + 0x4500);
+ p.uartclk = binfo->bi_busfreq;
+
+ gen550_init(0, &p);
+
+ memset(&p, 0, sizeof (p));
+ p.iotype = SERIAL_IO_MEM;
+ p.membase = (unsigned char __iomem *)(VIRT_IMMRBAR + 0x4600);
+ p.uartclk = binfo->bi_busfreq;
+
+ gen550_init(1, &p);
+ }
+#endif
+
+ identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+ /* setup the PowerPC module struct */
+ ppc_md.setup_arch = mpc834x_sys_setup_arch;
+ ppc_md.show_cpuinfo = mpc834x_sys_show_cpuinfo;
+
+ ppc_md.init_IRQ = mpc834x_sys_init_IRQ;
+ ppc_md.get_irq = ipic_get_irq;
+
+ ppc_md.restart = mpc83xx_restart;
+ ppc_md.power_off = mpc83xx_power_off;
+ ppc_md.halt = mpc83xx_halt;
+
+ ppc_md.find_end_of_memory = mpc83xx_find_end_of_memory;
+ ppc_md.setup_io_mappings = mpc834x_sys_map_io;
+
+ ppc_md.time_init = mpc83xx_time_init;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.calibrate_decr = mpc83xx_calibrate_decr;
+
+ ppc_md.early_serial_map = mpc83xx_early_serial_map;
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+ ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc834x_sys_init(): exit", 0);
+
+ return;
+}
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h
new file mode 100644
index 00000000000..f4d055ae19c
--- /dev/null
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.h
@@ -0,0 +1,51 @@
+/*
+ * arch/ppc/platforms/83xx/mpc834x_sys.h
+ *
+ * MPC834X SYS common board definitions
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MACH_MPC83XX_SYS_H__
+#define __MACH_MPC83XX_SYS_H__
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <syslib/ppc83xx_setup.h>
+#include <asm/ppcboot.h>
+
+#define VIRT_IMMRBAR ((uint)0xfe000000)
+
+#define BCSR_PHYS_ADDR ((uint)0xf8000000)
+#define BCSR_VIRT_ADDR ((uint)0xfe100000)
+#define BCSR_SIZE ((uint)(32 * 1024))
+
+#ifdef CONFIG_PCI
+/* PCI interrupt controller */
+#define PIRQA MPC83xx_IRQ_IRQ4
+#define PIRQB MPC83xx_IRQ_IRQ5
+#define PIRQC MPC83xx_IRQ_IRQ6
+#define PIRQD MPC83xx_IRQ_IRQ7
+
+#define MPC834x_SYS_PCI1_LOWER_IO 0x00000000
+#define MPC834x_SYS_PCI1_UPPER_IO 0x00ffffff
+
+#define MPC834x_SYS_PCI1_LOWER_MEM 0x80000000
+#define MPC834x_SYS_PCI1_UPPER_MEM 0x9fffffff
+
+#define MPC834x_SYS_PCI1_IO_BASE 0xe2000000
+#define MPC834x_SYS_PCI1_MEM_OFFSET 0x00000000
+
+#define MPC834x_SYS_PCI1_IO_SIZE 0x01000000
+#endif /* CONFIG_PCI */
+
+#endif /* __MACH_MPC83XX_SYS_H__ */
diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig
new file mode 100644
index 00000000000..ff92e38e7da
--- /dev/null
+++ b/arch/ppc/platforms/85xx/Kconfig
@@ -0,0 +1,76 @@
+config 85xx
+ bool
+ depends on E500
+ default y
+
+config PPC_INDIRECT_PCI_BE
+ bool
+ depends on 85xx
+ default y
+
+menu "Freescale 85xx options"
+ depends on E500
+
+choice
+ prompt "Machine Type"
+ depends on 85xx
+ default MPC8540_ADS
+
+config MPC8540_ADS
+ bool "Freescale MPC8540 ADS"
+ help
+ This option enables support for the MPC 8540 ADS evaluation board.
+
+config MPC8555_CDS
+ bool "Freescale MPC8555 CDS"
+ help
+ This option enablese support for the MPC8555 CDS evaluation board.
+
+config MPC8560_ADS
+ bool "Freescale MPC8560 ADS"
+ help
+ This option enables support for the MPC 8560 ADS evaluation board.
+
+config SBC8560
+ bool "WindRiver PowerQUICC III SBC8560"
+ help
+ This option enables support for the WindRiver PowerQUICC III
+ SBC8560 board.
+
+config STX_GP3
+ bool "Silicon Turnkey Express GP3"
+ help
+ This option enables support for the Silicon Turnkey Express GP3
+ board.
+
+endchoice
+
+# It's often necessary to know the specific 85xx processor type.
+# Fortunately, it is implied (so far) from the board type, so we
+# don't need to ask more redundant questions.
+config MPC8540
+ bool
+ depends on MPC8540_ADS
+ default y
+
+config MPC8555
+ bool
+ depends on MPC8555_CDS
+ default y
+
+config MPC8560
+ bool
+ depends on SBC8560 || MPC8560_ADS || STX_GP3
+ default y
+
+config 85xx_PCI2
+ bool "Supprt for 2nd PCI host controller"
+ depends on MPC8555_CDS
+ default y
+
+config PPC_GEN550
+ bool
+ depends on MPC8540 || SBC8560 || MPC8555
+ default y
+
+endmenu
diff --git a/arch/ppc/platforms/85xx/Makefile b/arch/ppc/platforms/85xx/Makefile
new file mode 100644
index 00000000000..854fbd298ba
--- /dev/null
+++ b/arch/ppc/platforms/85xx/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the PowerPC 85xx linux kernel.
+#
+obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads_common.o mpc8540_ads.o
+obj-$(CONFIG_MPC8555_CDS) += mpc85xx_cds_common.o
+obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads_common.o mpc8560_ads.o
+obj-$(CONFIG_SBC8560) += sbc85xx.o sbc8560.o
+obj-$(CONFIG_STX_GP3) += stx_gp3.o
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c
new file mode 100644
index 00000000000..4d857d6d633
--- /dev/null
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.c
@@ -0,0 +1,218 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8540_ads.c
+ *
+ * MPC8540ADS board specific routines
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#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/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.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/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ppc_sys.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc85xx_setup.h>
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+mpc8540ads_setup_arch(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+ struct gianfar_platform_data *pdata;
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc8540ads_setup_arch()", 0);
+
+ /* Set loops_per_jiffy to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+ /* setup PCI host bridges */
+ mpc85xx_setup_hose();
+#endif
+
+#ifdef CONFIG_SERIAL_8250
+ mpc85xx_early_serial_map();
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ /* Invalidate the entry we stole earlier the serial ports
+ * should be properly mapped */
+ invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+#endif
+
+ /* setup the board related information for the enet controllers */
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 0;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 1;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
+ pdata->board_flags = 0;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 3;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /* parse_bootinfo must always be called first */
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+ sizeof (bd_t));
+ }
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ {
+ bd_t *binfo = (bd_t *) __res;
+ struct uart_port p;
+
+ /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+ settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base,
+ binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
+
+ memset(&p, 0, sizeof (p));
+ p.iotype = SERIAL_IO_MEM;
+ p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART0_OFFSET;
+ p.uartclk = binfo->bi_busfreq;
+
+ gen550_init(0, &p);
+
+ memset(&p, 0, sizeof (p));
+ p.iotype = SERIAL_IO_MEM;
+ p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART1_OFFSET;
+ p.uartclk = binfo->bi_busfreq;
+
+ gen550_init(1, &p);
+ }
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+ /*
+ * If the init RAM disk has been configured in, and there's a valid
+ * starting address for it, set it up.
+ */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Copy the kernel command line arguments to a safe place. */
+
+ if (r6) {
+ *(char *) (r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+ }
+
+ identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+ /* setup the PowerPC module struct */
+ ppc_md.setup_arch = mpc8540ads_setup_arch;
+ ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo;
+
+ ppc_md.init_IRQ = mpc85xx_ads_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.restart = mpc85xx_restart;
+ ppc_md.power_off = mpc85xx_power_off;
+ ppc_md.halt = mpc85xx_halt;
+
+ ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+ ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc8540ads_init(): exit", 0);
+
+ return;
+}
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.h b/arch/ppc/platforms/85xx/mpc8540_ads.h
new file mode 100644
index 00000000000..3d05d7c4a93
--- /dev/null
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.h
@@ -0,0 +1,25 @@
+/*
+ * arch/ppc/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/config.h>
+#include <linux/initrd.h>
+#include <syslib/ppc85xx_setup.h>
+#include <platforms/85xx/mpc85xx_ads_common.h>
+
+#endif /* __MACH_MPC8540ADS_H__ */
diff --git a/arch/ppc/platforms/85xx/mpc8555_cds.h b/arch/ppc/platforms/85xx/mpc8555_cds.h
new file mode 100644
index 00000000000..e0e75568bc5
--- /dev/null
+++ b/arch/ppc/platforms/85xx/mpc8555_cds.h
@@ -0,0 +1,26 @@
+/*
+ * arch/ppc/platforms/mpc8555_cds.h
+ *
+ * MPC8555CDS 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_MPC8555CDS_H__
+#define __MACH_MPC8555CDS_H__
+
+#include <linux/config.h>
+#include <syslib/ppc85xx_setup.h>
+#include <platforms/85xx/mpc85xx_cds_common.h>
+
+#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#endif /* __MACH_MPC8555CDS_H__ */
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
new file mode 100644
index 00000000000..761b8c7b25d
--- /dev/null
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -0,0 +1,210 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8560_ads.c
+ *
+ * MPC8560ADS board specific routines
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#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/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.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/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ppc_sys.h>
+#include <asm/cpm2.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/cpm2_pic.h>
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_setup.h>
+
+extern void cpm2_reset(void);
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+
+static void __init
+mpc8560ads_setup_arch(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+ struct gianfar_platform_data *pdata;
+
+ cpm2_reset();
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc8560ads_setup_arch()", 0);
+
+ /* Set loops_per_jiffy to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+ /* setup PCI host bridges */
+ mpc85xx_setup_hose();
+#endif
+
+ /* setup the board related information for the enet controllers */
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 0;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 1;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+{
+ while ((irq = cpm2_get_irq(regs)) >= 0)
+ __do_IRQ(irq, regs);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction cpm2_irqaction = {
+ .handler = cpm2_cascade,
+ .flags = SA_INTERRUPT,
+ .mask = CPU_MASK_NONE,
+ .name = "cpm2_cascade",
+};
+
+static void __init
+mpc8560_ads_init_IRQ(void)
+{
+ /* Setup OpenPIC */
+ mpc85xx_ads_init_IRQ();
+
+ /* Setup CPM2 PIC */
+ cpm2_init_IRQ();
+
+ setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
+
+ return;
+}
+
+
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /* parse_bootinfo must always be called first */
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+ sizeof (bd_t));
+
+ }
+#if defined(CONFIG_BLK_DEV_INITRD)
+ /*
+ * If the init RAM disk has been configured in, and there's a valid
+ * starting address for it, set it up.
+ */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Copy the kernel command line arguments to a safe place. */
+
+ if (r6) {
+ *(char *) (r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+ }
+
+ identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+ /* setup the PowerPC module struct */
+ ppc_md.setup_arch = mpc8560ads_setup_arch;
+ ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo;
+
+ ppc_md.init_IRQ = mpc8560_ads_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.restart = mpc85xx_restart;
+ ppc_md.power_off = mpc85xx_power_off;
+ ppc_md.halt = mpc85xx_halt;
+
+ ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc8560ads_init(): exit", 0);
+
+ return;
+}
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.h b/arch/ppc/platforms/85xx/mpc8560_ads.h
new file mode 100644
index 00000000000..7df885d73e9
--- /dev/null
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.h
@@ -0,0 +1,27 @@
+/*
+ * arch/ppc/platforms/mpc8560_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_MPC8560ADS_H
+#define __MACH_MPC8560ADS_H
+
+#include <linux/config.h>
+#include <syslib/ppc85xx_setup.h>
+#include <platforms/85xx/mpc85xx_ads_common.h>
+
+#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET)
+#define PHY_INTERRUPT MPC85xx_IRQ_EXT7
+
+#endif /* __MACH_MPC8560ADS_H */
diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
new file mode 100644
index 00000000000..ba9f9f562c4
--- /dev/null
+++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
@@ -0,0 +1,225 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx_ads_common.c
+ *
+ * MPC85xx ADS board common routines
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#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/irq.h>
+#include <linux/seq_file.h>
+#include <linux/serial.h>
+#include <linux/module.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/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/ppc_sys.h>
+
+#include <mm/mmu_decl.h>
+
+#include <platforms/85xx/mpc85xx_ads_common.h>
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+extern unsigned long total_memory; /* in mm/init */
+
+unsigned char __res[sizeof (bd_t)];
+
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+
+static u_char mpc85xx_ads_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+ 0x0, /* External 0: */
+#if defined(CONFIG_PCI)
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI slot 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI slot 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI slot 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 4: PCI slot 3 */
+#else
+ 0x0, /* External 1: */
+ 0x0, /* External 2: */
+ 0x0, /* External 3: */
+ 0x0, /* External 4: */
+#endif
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PHY */
+ 0x0, /* External 6: */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 7: PHY */
+ 0x0, /* External 8: */
+ 0x0, /* External 9: */
+ 0x0, /* External 10: */
+ 0x0, /* External 11: */
+};
+
+/* ************************************************************************ */
+int
+mpc85xx_ads_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid, svid, phid1;
+ uint memsize = total_memory;
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ pvid = mfspr(SPRN_PVR);
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+ seq_printf(m, "Machine\t\t: mpc%sads\n", cur_ppc_sys_spec->ppc_sys_name);
+ seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
+ 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));
+
+ return 0;
+}
+
+void __init
+mpc85xx_ads_init_IRQ(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+ /* Determine the Physical Address of the OpenPIC regs */
+ phys_addr_t OpenPIC_PAddr =
+ binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+ OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+ OpenPIC_InitSenses = mpc85xx_ads_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof (mpc85xx_ads_openpic_initsenses);
+
+ /* Skip reserved space and internal sources */
+ openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+ /* Map PIC IRQs 0-11 */
+ openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+
+ /* we let openpic interrupts starting from an offset, to
+ * leave space for cascading interrupts underneath.
+ */
+ openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+
+ return;
+}
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+
+int
+mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * This is little evil, but works around the fact
+ * that revA boards have IDSEL starting at 18
+ * and others boards (older) start at 12
+ *
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 2 */
+ {PIRQD, PIRQA, PIRQB, PIRQC},
+ {PIRQC, PIRQD, PIRQA, PIRQB},
+ {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 5 */
+ {0, 0, 0, 0}, /* -- */
+ {0, 0, 0, 0}, /* -- */
+ {0, 0, 0, 0}, /* -- */
+ {0, 0, 0, 0}, /* -- */
+ {0, 0, 0, 0}, /* -- */
+ {0, 0, 0, 0}, /* -- */
+ {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 12 */
+ {PIRQD, PIRQA, PIRQB, PIRQC},
+ {PIRQC, PIRQD, PIRQA, PIRQB},
+ {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 15 */
+ {0, 0, 0, 0}, /* -- */
+ {0, 0, 0, 0}, /* -- */
+ {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 18 */
+ {PIRQD, PIRQA, PIRQB, PIRQC},
+ {PIRQC, PIRQD, PIRQA, PIRQB},
+ {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 21 */
+ };
+
+ const long min_idsel = 2, max_idsel = 21, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+int
+mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+
+#endif /* CONFIG_PCI */
diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
new file mode 100644
index 00000000000..3875e839cff
--- /dev/null
+++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
@@ -0,0 +1,50 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx_ads_common.h
+ *
+ * MPC85XX ADS common 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_MPC85XX_ADS_H__
+#define __MACH_MPC85XX_ADS_H__
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <asm/ppcboot.h>
+
+#define BOARD_CCSRBAR ((uint)0xe0000000)
+#define BCSR_ADDR ((uint)0xf8000000)
+#define BCSR_SIZE ((uint)(32 * 1024))
+
+extern int mpc85xx_ads_show_cpuinfo(struct seq_file *m);
+extern void mpc85xx_ads_init_IRQ(void) __init;
+extern void mpc85xx_ads_map_io(void) __init;
+
+/* PCI interrupt controller */
+#define PIRQA MPC85xx_IRQ_EXT1
+#define PIRQB MPC85xx_IRQ_EXT2
+#define PIRQC MPC85xx_IRQ_EXT3
+#define PIRQD MPC85xx_IRQ_EXT4
+
+#define MPC85XX_PCI1_LOWER_IO 0x00000000
+#define MPC85XX_PCI1_UPPER_IO 0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM 0x80000000
+#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE 0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET 0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE 0x01000000
+
+#endif /* __MACH_MPC85XX_ADS_H__ */
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
new file mode 100644
index 00000000000..6c020d67ad7
--- /dev/null
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -0,0 +1,467 @@
+/*
+ * arch/ppc/platform/85xx/mpc85xx_cds_common.c
+ *
+ * MPC85xx CDS board specific routines
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#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/irq.h>
+#include <linux/seq_file.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/immap_cpm2.h>
+#include <asm/ppc_sys.h>
+#include <asm/kgdb.h>
+
+#include <mm/mmu_decl.h>
+#include <syslib/cpm2_pic.h>
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_setup.h>
+
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+extern unsigned long total_memory; /* in mm/init */
+
+unsigned char __res[sizeof (bd_t)];
+
+static int cds_pci_slot = 2;
+static volatile u8 * cadmus;
+
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+
+static u_char mpc85xx_cds_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+#if defined(CONFIG_PCI)
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 0: PCI1 slot */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI1 slot */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI1 slot */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI1 slot */
+#else
+ 0x0, /* External 0: */
+ 0x0, /* External 1: */
+ 0x0, /* External 2: */
+ 0x0, /* External 3: */
+#endif
+ 0x0, /* External 4: */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PHY */
+ 0x0, /* External 6: */
+ 0x0, /* External 7: */
+ 0x0, /* External 8: */
+ 0x0, /* External 9: */
+ 0x0, /* External 10: */
+#if defined(CONFIG_85xx_PCI2) && defined(CONFIG_PCI)
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 11: PCI2 slot 0 */
+#else
+ 0x0, /* External 11: */
+#endif
+};
+
+/* ************************************************************************ */
+int
+mpc85xx_cds_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid, svid, phid1;
+ uint memsize = total_memory;
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ pvid = mfspr(SPRN_PVR);
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+ seq_printf(m, "Machine\t\t: CDS - MPC%s (%x)\n", cur_ppc_sys_spec->ppc_sys_name, cadmus[CM_VER]);
+ seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
+ 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));
+
+ return 0;
+}
+
+#ifdef CONFIG_CPM2
+static void cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+{
+ while((irq = cpm2_get_irq(regs)) >= 0)
+ __do_IRQ(irq, regs);
+}
+
+static struct irqaction cpm2_irqaction = {
+ .handler = cpm2_cascade,
+ .flags = SA_INTERRUPT,
+ .mask = CPU_MASK_NONE,
+ .name = "cpm2_cascade",
+};
+#endif /* CONFIG_CPM2 */
+
+void __init
+mpc85xx_cds_init_IRQ(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+
+ /* Determine the Physical Address of the OpenPIC regs */
+ phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+ OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+ OpenPIC_InitSenses = mpc85xx_cds_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof (mpc85xx_cds_openpic_initsenses);
+
+ /* Skip reserved space and internal sources */
+ openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+ /* Map PIC IRQs 0-11 */
+ openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+
+ /* we let openpic interrupts starting from an offset, to
+ * leave space for cascading interrupts underneath.
+ */
+ openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+
+#ifdef CONFIG_CPM2
+ /* Setup CPM2 PIC */
+ cpm2_init_IRQ();
+
+ setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
+#endif
+
+ return;
+}
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+int
+mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+
+ if (!hose->index)
+ {
+ /* Handle PCI1 interrupts */
+ char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+
+ /* Note IRQ assignment for slots is based on which slot the elysium is
+ * in -- in this setup elysium is in slot #2 (this PIRQA as first
+ * interrupt on slot */
+ {
+ { 0, 1, 2, 3 }, /* 16 - PMC */
+ { 3, 0, 0, 0 }, /* 17 P2P (Tsi320) */
+ { 0, 1, 2, 3 }, /* 18 - Slot 1 */
+ { 1, 2, 3, 0 }, /* 19 - Slot 2 */
+ { 2, 3, 0, 1 }, /* 20 - Slot 3 */
+ { 3, 0, 1, 2 }, /* 21 - Slot 4 */
+ };
+
+ const long min_idsel = 16, max_idsel = 21, irqs_per_slot = 4;
+ int i, j;
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 4; j++)
+ pci_irq_table[i][j] =
+ ((pci_irq_table[i][j] + 5 -
+ cds_pci_slot) & 0x3) + PIRQ0A;
+
+ return PCI_IRQ_TABLE_LOOKUP;
+ } else {
+ /* Handle PCI2 interrupts (if we have one) */
+ char pci_irq_table[][4] =
+ {
+ /*
+ * We only have one slot and one interrupt
+ * going to PIRQA - PIRQD */
+ { PIRQ1A, PIRQ1A, PIRQ1A, PIRQ1A }, /* 21 - slot 0 */
+ };
+
+ const long min_idsel = 21, max_idsel = 21, irqs_per_slot = 4;
+
+ return PCI_IRQ_TABLE_LOOKUP;
+ }
+}
+
+#define ARCADIA_HOST_BRIDGE_IDSEL 17
+#define ARCADIA_2ND_BRIDGE_IDSEL 3
+
+extern int mpc85xx_pci1_last_busno;
+
+int
+mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+#ifdef CONFIG_85xx_PCI2
+ if (mpc85xx_pci1_last_busno)
+ if (bus == (mpc85xx_pci1_last_busno + 1) && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+#endif
+ /* We explicitly do not go past the Tundra 320 Bridge */
+ if (bus == 1)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+#endif /* CONFIG_PCI */
+
+TODC_ALLOC();
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+mpc85xx_cds_setup_arch(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+ struct gianfar_platform_data *pdata;
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ printk("mpc85xx_cds_setup_arch\n");
+
+#ifdef CONFIG_CPM2
+ cpm2_reset();
+#endif
+
+ cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE);
+ cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1;
+ printk("CDS Version = %x in PCI slot %d\n", cadmus[CM_VER], cds_pci_slot);
+
+ /* Setup TODC access */
+ TODC_INIT(TODC_TYPE_DS1743,
+ 0,
+ 0,
+ ioremap(CDS_RTC_ADDR, CDS_RTC_SIZE),
+ 8);
+
+ /* Set loops_per_jiffy to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+ /* setup PCI host bridges */
+ mpc85xx_setup_hose();
+#endif
+
+#ifdef CONFIG_SERIAL_8250
+ mpc85xx_early_serial_map();
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ /* Invalidate the entry we stole earlier the serial ports
+ * should be properly mapped */
+ invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+#endif
+
+ /* setup the board related information for the enet controllers */
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 0;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 1;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /* parse_bootinfo must always be called first */
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+ sizeof (bd_t));
+
+ }
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ {
+ bd_t *binfo = (bd_t *) __res;
+ struct uart_port p;
+
+ /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+ settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base,
+ binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
+
+ memset(&p, 0, sizeof (p));
+ p.iotype = SERIAL_IO_MEM;
+ p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART0_OFFSET;
+ p.uartclk = binfo->bi_busfreq;
+
+ gen550_init(0, &p);
+
+ memset(&p, 0, sizeof (p));
+ p.iotype = SERIAL_IO_MEM;
+ p.membase = (void *) binfo->bi_immr_base + MPC85xx_UART1_OFFSET;
+ p.uartclk = binfo->bi_busfreq;
+
+ gen550_init(1, &p);
+ }
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+ /*
+ * If the init RAM disk has been configured in, and there's a valid
+ * starting address for it, set it up.
+ */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Copy the kernel command line arguments to a safe place. */
+
+ if (r6) {
+ *(char *) (r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+ }
+
+ identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+ /* setup the PowerPC module struct */
+ ppc_md.setup_arch = mpc85xx_cds_setup_arch;
+ ppc_md.show_cpuinfo = mpc85xx_cds_show_cpuinfo;
+
+ ppc_md.init_IRQ = mpc85xx_cds_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.restart = mpc85xx_restart;
+ ppc_md.power_off = mpc85xx_power_off;
+ ppc_md.halt = mpc85xx_halt;
+
+ ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+ ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+ ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc85xx_cds_init(): exit", 0);
+
+ return;
+}
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
new file mode 100644
index 00000000000..7627d77504b
--- /dev/null
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
@@ -0,0 +1,80 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx_cds_common.h
+ *
+ * MPC85xx CDS 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_MPC85XX_CDS_H__
+#define __MACH_MPC85XX_CDS_H__
+
+#include <linux/config.h>
+#include <linux/serial.h>
+#include <asm/ppcboot.h>
+#include <linux/initrd.h>
+#include <syslib/ppc85xx_setup.h>
+
+#define BOARD_CCSRBAR ((uint)0xe0000000)
+#define CCSRBAR_SIZE ((uint)1024*1024)
+
+/* 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 config */
+#define PCI1_CFG_ADDR_OFFSET (0x8000)
+#define PCI1_CFG_DATA_OFFSET (0x8004)
+
+#define PCI2_CFG_ADDR_OFFSET (0x9000)
+#define PCI2_CFG_DATA_OFFSET (0x9004)
+
+/* 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
+
+/* PCI 1 memory map */
+#define MPC85XX_PCI1_LOWER_IO 0x00000000
+#define MPC85XX_PCI1_UPPER_IO 0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM 0x80000000
+#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE 0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET 0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE 0x01000000
+
+/* PCI 2 memory map */
+/* Note: the standard PPC fixups will cause IO space to get bumped by
+ * hose->io_base_virt - isa_io_base => MPC85XX_PCI1_IO_SIZE */
+#define MPC85XX_PCI2_LOWER_IO 0x00000000
+#define MPC85XX_PCI2_UPPER_IO 0x00ffffff
+
+#define MPC85XX_PCI2_LOWER_MEM 0xa0000000
+#define MPC85XX_PCI2_UPPER_MEM 0xbfffffff
+
+#define MPC85XX_PCI2_IO_BASE 0xe3000000
+#define MPC85XX_PCI2_MEM_OFFSET 0x00000000
+
+#define MPC85XX_PCI2_IO_SIZE 0x01000000
+
+#endif /* __MACH_MPC85XX_CDS_H__ */
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c
new file mode 100644
index 00000000000..9ab05e590c3
--- /dev/null
+++ b/arch/ppc/platforms/85xx/sbc8560.c
@@ -0,0 +1,227 @@
+/*
+ * arch/ppc/platforms/85xx/sbc8560.c
+ *
+ * Wind River SBC8560 board specific routines
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#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/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.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/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ppc_sys.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_setup.h>
+
+#ifdef CONFIG_SERIAL_8250
+static void __init
+sbc8560_early_serial_map(void)
+{
+ struct uart_port uart_req;
+
+ /* Setup serial port access */
+ memset(&uart_req, 0, sizeof (uart_req));
+ uart_req.irq = MPC85xx_IRQ_EXT9;
+ uart_req.flags = STD_COM_FLAGS;
+ uart_req.uartclk = BASE_BAUD * 16;
+ uart_req.iotype = SERIAL_IO_MEM;
+ uart_req.mapbase = UARTA_ADDR;
+ uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART0_SIZE);
+ uart_req.type = PORT_16650;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ gen550_init(0, &uart_req);
+#endif
+
+ if (early_serial_setup(&uart_req) != 0)
+ printk("Early serial init of port 0 failed\n");
+
+ /* Assume early_serial_setup() doesn't modify uart_req */
+ uart_req.line = 1;
+ uart_req.mapbase = UARTB_ADDR;
+ uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART1_SIZE);
+ uart_req.irq = MPC85xx_IRQ_EXT10;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ gen550_init(1, &uart_req);
+#endif
+
+ if (early_serial_setup(&uart_req) != 0)
+ printk("Early serial init of port 1 failed\n");
+}
+#endif
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+sbc8560_setup_arch(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+ struct gianfar_platform_data *pdata;
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ if (ppc_md.progress)
+ ppc_md.progress("sbc8560_setup_arch()", 0);
+
+ /* Set loops_per_jiffy to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+ /* setup PCI host bridges */
+ mpc85xx_setup_hose();
+#endif
+#ifdef CONFIG_SERIAL_8250
+ sbc8560_early_serial_map();
+#endif
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ /* Invalidate the entry we stole earlier the serial ports
+ * should be properly mapped */
+ invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+#endif
+
+ /* setup the board related information for the enet controllers */
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT6;
+ pdata->phyid = 25;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT7;
+ pdata->phyid = 26;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /* parse_bootinfo must always be called first */
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+ sizeof (bd_t));
+ }
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ /* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+ settlbcam(NUM_TLBCAMS - 1, UARTA_ADDR,
+ UARTA_ADDR, 0x1000, _PAGE_IO, 0);
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+ /*
+ * If the init RAM disk has been configured in, and there's a valid
+ * starting address for it, set it up.
+ */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Copy the kernel command line arguments to a safe place. */
+
+ if (r6) {
+ *(char *) (r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+ }
+
+ identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+ /* setup the PowerPC module struct */
+ ppc_md.setup_arch = sbc8560_setup_arch;
+ ppc_md.show_cpuinfo = sbc8560_show_cpuinfo;
+
+ ppc_md.init_IRQ = sbc8560_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.restart = mpc85xx_restart;
+ ppc_md.power_off = mpc85xx_power_off;
+ ppc_md.halt = mpc85xx_halt;
+
+ ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+ ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+
+ if (ppc_md.progress)
+ ppc_md.progress("sbc8560_init(): exit", 0);
+}
diff --git a/arch/ppc/platforms/85xx/sbc8560.h b/arch/ppc/platforms/85xx/sbc8560.h
new file mode 100644
index 00000000000..5e1b00c77da
--- /dev/null
+++ b/arch/ppc/platforms/85xx/sbc8560.h
@@ -0,0 +1,49 @@
+/*
+ * arch/ppc/platforms/85xx/sbc8560.h
+ *
+ * Wind River SBC8560 board definitions
+ *
+ * Copyright 2003 Motorola 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_SBC8560_H__
+#define __MACH_SBC8560_H__
+
+#include <linux/config.h>
+#include <platforms/85xx/sbc85xx.h>
+
+#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE 64
+#else
+#define RS_TABLE_SIZE 2
+#endif
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define BASE_BAUD ( 1843200 / 16 )
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
+#endif
+
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, UARTA_ADDR, MPC85xx_IRQ_EXT9, STD_COM_FLAGS, /* ttyS0 */ \
+ iomem_base: (u8 *)UARTA_ADDR, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, UARTB_ADDR, MPC85xx_IRQ_EXT10, STD_COM_FLAGS, /* ttyS1 */ \
+ iomem_base: (u8 *)UARTB_ADDR, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
+
+#endif /* __MACH_SBC8560_H__ */
diff --git a/arch/ppc/platforms/85xx/sbc85xx.c b/arch/ppc/platforms/85xx/sbc85xx.c
new file mode 100644
index 00000000000..2d638c1c1bd
--- /dev/null
+++ b/arch/ppc/platforms/85xx/sbc85xx.c
@@ -0,0 +1,203 @@
+/*
+ * arch/ppc/platform/85xx/sbc85xx.c
+ *
+ * WindRiver PowerQUICC III SBC85xx board common routines
+ *
+ * Copyright 2002, 2003 Motorola Inc.
+ * Copyright 2004 Red Hat, 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/config.h>
+#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/irq.h>
+#include <linux/seq_file.h>
+#include <linux/serial.h>
+#include <linux/module.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/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/ppc_sys.h>
+
+#include <mm/mmu_decl.h>
+
+#include <platforms/85xx/sbc85xx.h>
+
+unsigned char __res[sizeof (bd_t)];
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+unsigned long pci_dram_offset = 0;
+#endif
+
+extern unsigned long total_memory; /* in mm/init */
+
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+
+static u_char sbc8560_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+ 0x0, /* External 0: */
+ 0x0, /* External 1: */
+#if defined(CONFIG_PCI)
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI slot 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI slot 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 4: PCI slot 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 5: PCI slot 3 */
+#else
+ 0x0, /* External 2: */
+ 0x0, /* External 3: */
+ 0x0, /* External 4: */
+ 0x0, /* External 5: */
+#endif
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 6: PHY */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 7: PHY */
+ 0x0, /* External 8: */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* External 9: PHY */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* External 10: PHY */
+ 0x0, /* External 11: */
+};
+
+/* ************************************************************************ */
+int
+sbc8560_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid, svid, phid1;
+ uint memsize = total_memory;
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ pvid = mfspr(SPRN_PVR);
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Wind River\n");
+ seq_printf(m, "Machine\t\t: SBC%s\n", cur_ppc_sys_spec->ppc_sys_name);
+ seq_printf(m, "clock\t\t: %dMHz\n", freq / 1000000);
+ 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));
+
+ return 0;
+}
+
+void __init
+sbc8560_init_IRQ(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+ /* Determine the Physical Address of the OpenPIC regs */
+ phys_addr_t OpenPIC_PAddr =
+ binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+ OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+ OpenPIC_InitSenses = sbc8560_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof (sbc8560_openpic_initsenses);
+
+ /* Skip reserved space and internal sources */
+ openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+ /* Map PIC IRQs 0-11 */
+ openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+
+ /* we let openpic interrupts starting from an offset, to
+ * leave space for cascading interrupts underneath.
+ */
+ openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+
+ return;
+}
+
+/*
+ * interrupt routing
+ */
+
+#ifdef CONFIG_PCI
+int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel,
+ unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {PIRQA, PIRQB, PIRQC, PIRQD},
+ {PIRQD, PIRQA, PIRQB, PIRQC},
+ {PIRQC, PIRQD, PIRQA, PIRQB},
+ {PIRQB, PIRQC, PIRQD, PIRQA},
+ };
+
+ const long min_idsel = 12, max_idsel = 15, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+int mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+#endif /* CONFIG_PCI */
diff --git a/arch/ppc/platforms/85xx/sbc85xx.h b/arch/ppc/platforms/85xx/sbc85xx.h
new file mode 100644
index 00000000000..7af93c691a6
--- /dev/null
+++ b/arch/ppc/platforms/85xx/sbc85xx.h
@@ -0,0 +1,55 @@
+/*
+ * arch/ppc/platforms/85xx/sbc85xx.h
+ *
+ * WindRiver PowerQUICC III SBC85xx common board definitions
+ *
+ * Copyright 2003 Motorola Inc.
+ * Copyright 2004 Red Hat, 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 __PLATFORMS_85XX_SBC85XX_H__
+#define __PLATFORMS_85XX_SBC85XX_H__
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <asm/ppcboot.h>
+
+#define BOARD_CCSRBAR ((uint)0xff700000)
+#define CCSRBAR_SIZE ((uint)1024*1024)
+
+#define BCSR_ADDR ((uint)0xfc000000)
+#define BCSR_SIZE ((uint)(16 * 1024 * 1024))
+
+#define UARTA_ADDR (BCSR_ADDR + 0x00700000)
+#define UARTB_ADDR (BCSR_ADDR + 0x00800000)
+#define RTC_DEVICE_ADDR (BCSR_ADDR + 0x00900000)
+#define EEPROM_ADDR (BCSR_ADDR + 0x00b00000)
+
+extern int sbc8560_show_cpuinfo(struct seq_file *m);
+extern void sbc8560_init_IRQ(void) __init;
+
+/* PCI interrupt controller */
+#define PIRQA MPC85xx_IRQ_EXT1
+#define PIRQB MPC85xx_IRQ_EXT2
+#define PIRQC MPC85xx_IRQ_EXT3
+#define PIRQD MPC85xx_IRQ_EXT4
+
+#define MPC85XX_PCI1_LOWER_IO 0x00000000
+#define MPC85XX_PCI1_UPPER_IO 0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM 0x80000000
+#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE 0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET 0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE 0x01000000
+
+#endif /* __PLATFORMS_85XX_SBC85XX_H__ */
diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c
new file mode 100644
index 00000000000..bc95836e417
--- /dev/null
+++ b/arch/ppc/platforms/85xx/stx_gp3.c
@@ -0,0 +1,355 @@
+/*
+ * arch/ppc/platforms/85xx/stx_gp3.c
+ *
+ * STx GP3 board specific routines
+ *
+ * Dan Malek <dan@embeddededge.com>
+ * Copyright 2004 Embedded Edge, LLC
+ *
+ * Copied from mpc8560_ads.c
+ * Copyright 2002, 2003 Motorola Inc.
+ *
+ * Ported to 2.6, Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2004-2005 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/config.h>
+#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/blkdev.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/root_dev.h>
+#include <linux/seq_file.h>
+#include <linux/serial.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+#include <linux/interrupt.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/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/immap_cpm2.h>
+#include <asm/mpc85xx.h>
+#include <asm/ppc_sys.h>
+
+#include <syslib/cpm2_pic.h>
+#include <syslib/ppc85xx_common.h>
+
+extern void cpm2_reset(void);
+
+unsigned char __res[sizeof(bd_t)];
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+unsigned long pci_dram_offset = 0;
+#endif
+
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+static u8 gp3_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: L2 Cache */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: ECM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCI/PCI-X */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: RIO Inbound Port Write Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: RIO Doorbell Inbound */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: RIO Outbound Message */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: RIO Inbound Message */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 0 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 0 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 0 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 1 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 1 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 1 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Fast Ethernet */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: CPM */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+ 0x0, /* External 0: */
+#if defined(CONFIG_PCI)
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 1: PCI slot 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 2: PCI slot 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 3: PCI slot 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 4: PCI slot 3 */
+#else
+ 0x0, /* External 1: */
+ 0x0, /* External 2: */
+ 0x0, /* External 3: */
+ 0x0, /* External 4: */
+#endif
+ 0x0, /* External 5: */
+ 0x0, /* External 6: */
+ 0x0, /* External 7: */
+ 0x0, /* External 8: */
+ 0x0, /* External 9: */
+ 0x0, /* External 10: */
+ 0x0, /* External 11: */
+};
+
+/*
+ * Setup the architecture
+ */
+static void __init
+gp3_setup_arch(void)
+{
+ bd_t *binfo = (bd_t *) __res;
+ unsigned int freq;
+ struct gianfar_platform_data *pdata;
+
+ cpm2_reset();
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ if (ppc_md.progress)
+ ppc_md.progress("gp3_setup_arch()", 0);
+
+ /* Set loops_per_jiffy to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+ /* setup PCI host bridges */
+ mpc85xx_setup_hose();
+#endif
+
+ /* setup the board related information for the enet controllers */
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
+/* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 2;
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+
+ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
+/* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 4;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+
+ printk ("bi_immr_base = %8.8lx\n", binfo->bi_immr_base);
+}
+
+static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+{
+ while ((irq = cpm2_get_irq(regs)) >= 0)
+ __do_IRQ(irq, regs);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction cpm2_irqaction = {
+ .handler = cpm2_cascade,
+ .flags = SA_INTERRUPT,
+ .mask = CPU_MASK_NONE,
+ .name = "cpm2_cascade",
+};
+
+static void __init
+gp3_init_IRQ(void)
+{
+ int i;
+ bd_t *binfo = (bd_t *) __res;
+
+ /*
+ * Setup OpenPIC
+ */
+
+ /* Determine the Physical Address of the OpenPIC regs */
+ phys_addr_t OpenPIC_PAddr =
+ binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+ OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+ OpenPIC_InitSenses = gp3_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof (gp3_openpic_initsenses);
+
+ /* Skip reserved space and internal sources */
+ openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+
+ /* Map PIC IRQs 0-11 */
+ openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+
+ /*
+ * Let openpic interrupts starting from an offset, to
+ * leave space for cascading interrupts underneath.
+ */
+ openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+
+ /* Setup CPM2 PIC */
+ cpm2_init_IRQ();
+
+ setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
+
+ return;
+}
+
+static int
+gp3_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid, svid, phid1;
+ bd_t *binfo = (bd_t *) __res;
+ uint memsize;
+ unsigned int freq;
+ extern unsigned long total_memory; /* in mm/init */
+
+ /* get the core frequency */
+ freq = binfo->bi_intfreq;
+
+ pvid = mfspr(SPRN_PVR);
+ svid = mfspr(SPRN_SVR);
+
+ memsize = total_memory;
+
+ seq_printf(m, "Vendor\t\t: RPC Electronics STx \n");
+ seq_printf(m, "Machine\t\t: GP3 - MPC%s\n", cur_ppc_sys_spec->ppc_sys_name);
+ seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000,
+ freq % 1000000);
+ 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));
+
+ return 0;
+}
+
+#ifdef CONFIG_PCI
+int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel,
+ unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {PIRQA, PIRQB, PIRQC, PIRQD},
+ {PIRQD, PIRQA, PIRQB, PIRQC},
+ {PIRQC, PIRQD, PIRQA, PIRQB},
+ {PIRQB, PIRQC, PIRQD, PIRQA},
+ };
+
+ const long min_idsel = 12, max_idsel = 15, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+int mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+#endif /* CONFIG_PCI */
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /* parse_bootinfo must always be called first */
+ parse_bootinfo(find_bootinfo());
+
+ /*
+ * If we were passed in a board information, copy it into the
+ * residual data area.
+ */
+ if (r3) {
+ memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+ sizeof (bd_t));
+
+ }
+#if defined(CONFIG_BLK_DEV_INITRD)
+ /*
+ * If the init RAM disk has been configured in, and there's a valid
+ * starting address for it, set it up.
+ */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Copy the kernel command line arguments to a safe place. */
+
+ if (r6) {
+ *(char *) (r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+ }
+
+ identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+ /* setup the PowerPC module struct */
+ ppc_md.setup_arch = gp3_setup_arch;
+ ppc_md.show_cpuinfo = gp3_show_cpuinfo;
+
+ ppc_md.init_IRQ = gp3_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.restart = mpc85xx_restart;
+ ppc_md.power_off = mpc85xx_power_off;
+ ppc_md.halt = mpc85xx_halt;
+
+ ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+ ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+ if (ppc_md.progress)
+ ppc_md.progress("platform_init(): exit", 0);
+
+ return;
+}
diff --git a/arch/ppc/platforms/85xx/stx_gp3.h b/arch/ppc/platforms/85xx/stx_gp3.h
new file mode 100644
index 00000000000..7bcc6c35a41
--- /dev/null
+++ b/arch/ppc/platforms/85xx/stx_gp3.h
@@ -0,0 +1,74 @@
+/*
+ * arch/ppc/platforms/stx8560_gp3.h
+ *
+ * STx GP3 board definitions
+ *
+ * Dan Malek (dan@embeddededge.com)
+ * Copyright 2004 Embedded Edge, LLC
+ *
+ * Ported to 2.6, Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2004-2005 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.
+ *
+ */
+
+#ifndef __MACH_STX_GP3_H
+#define __MACH_STX_GP3_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <asm/ppcboot.h>
+
+#define BOARD_CCSRBAR ((uint)0xe0000000)
+#define CCSRBAR_SIZE ((uint)1024*1024)
+
+#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#define BCSR_ADDR ((uint)0xfc000000)
+#define BCSR_SIZE ((uint)(16 * 1024))
+
+#define BCSR_TSEC1_RESET 0x00000080
+#define BCSR_TSEC2_RESET 0x00000040
+#define BCSR_LED1 0x00000008
+#define BCSR_LED2 0x00000004
+#define BCSR_LED3 0x00000002
+#define BCSR_LED4 0x00000001
+
+extern void mpc85xx_setup_hose(void) __init;
+extern void mpc85xx_restart(char *cmd);
+extern void mpc85xx_power_off(void);
+extern void mpc85xx_halt(void);
+extern int mpc85xx_show_cpuinfo(struct seq_file *m);
+extern void mpc85xx_init_IRQ(void) __init;
+extern unsigned long mpc85xx_find_end_of_memory(void) __init;
+extern void mpc85xx_calibrate_decr(void) __init;
+
+#define PCI_CFG_ADDR_OFFSET (0x8000)
+#define PCI_CFG_DATA_OFFSET (0x8004)
+
+/* PCI interrupt controller */
+#define PIRQA MPC85xx_IRQ_EXT1
+#define PIRQB MPC85xx_IRQ_EXT2
+#define PIRQC MPC85xx_IRQ_EXT3
+#define PIRQD MPC85xx_IRQ_EXT4
+#define PCI_MIN_IDSEL 16
+#define PCI_MAX_IDSEL 19
+#define PCI_IRQ_SLOT 4
+
+#define MPC85XX_PCI1_LOWER_IO 0x00000000
+#define MPC85XX_PCI1_UPPER_IO 0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM 0x80000000
+#define MPC85XX_PCI1_UPPER_MEM 0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE 0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET 0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE 0x01000000
+
+#endif /* __MACH_STX_GP3_H */
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
new file mode 100644
index 00000000000..5488a053f41
--- /dev/null
+++ b/arch/ppc/platforms/Makefile
@@ -0,0 +1,53 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Extra CFLAGS so we don't have to do relative includes
+CFLAGS_pmac_setup.o += -Iarch/$(ARCH)/mm
+
+obj-$(CONFIG_APUS) += apus_setup.o
+ifeq ($(CONFIG_APUS),y)
+obj-$(CONFIG_PCI) += apus_pci.o
+endif
+obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \
+ pmac_feature.o pmac_pci.o pmac_sleep.o \
+ pmac_low_i2c.o pmac_cache.o
+obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o \
+ chrp_pegasos_eth.o
+obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_setup.o
+ifeq ($(CONFIG_PPC_PMAC),y)
+obj-$(CONFIG_NVRAM) += pmac_nvram.o
+obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o
+endif
+obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o
+obj-$(CONFIG_PREP_RESIDUAL) += residual.o
+obj-$(CONFIG_ADIR) += adir_setup.o adir_pic.o adir_pci.o
+obj-$(CONFIG_PQ2ADS) += pq2ads.o
+obj-$(CONFIG_TQM8260) += tqm8260_setup.o
+obj-$(CONFIG_CPCI690) += cpci690.o
+obj-$(CONFIG_EV64260) += ev64260.o
+obj-$(CONFIG_CHESTNUT) += chestnut.o
+obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o
+obj-$(CONFIG_K2) += k2.o
+obj-$(CONFIG_LOPEC) += lopec.o
+obj-$(CONFIG_KATANA) += katana.o
+obj-$(CONFIG_HDPU) += hdpu.o
+obj-$(CONFIG_MCPN765) += mcpn765.o
+obj-$(CONFIG_MENF1) += menf1_setup.o menf1_pci.o
+obj-$(CONFIG_MVME5100) += mvme5100.o
+obj-$(CONFIG_PAL4) += pal4_setup.o pal4_pci.o
+obj-$(CONFIG_PCORE) += pcore.o
+obj-$(CONFIG_POWERPMC250) += powerpmc250.o
+obj-$(CONFIG_PPLUS) += pplus.o
+obj-$(CONFIG_PRPMC750) += prpmc750.o
+obj-$(CONFIG_PRPMC800) += prpmc800.o
+obj-$(CONFIG_RADSTONE_PPC7D) += radstone_ppc7d.o
+obj-$(CONFIG_SANDPOINT) += sandpoint.o
+obj-$(CONFIG_SBC82xx) += sbc82xx.o
+obj-$(CONFIG_SPRUCE) += spruce.o
+obj-$(CONFIG_LITE5200) += lite5200.o
+
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_PPC_PMAC) += pmac_smp.o
+obj-$(CONFIG_PPC_CHRP) += chrp_smp.o
+endif
diff --git a/arch/ppc/platforms/adir.h b/arch/ppc/platforms/adir.h
new file mode 100644
index 00000000000..13a748b4695
--- /dev/null
+++ b/arch/ppc/platforms/adir.h
@@ -0,0 +1,95 @@
+/*
+ * arch/ppc/platforms/adir.h
+ *
+ * Definitions for SBS Adirondack board support
+ *
+ * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
+ */
+
+#ifndef __PPC_PLATFORMS_ADIR_H
+#define __PPC_PLATFORMS_ADIR_H
+
+/*
+ * SBS Adirondack definitions
+ */
+
+/* PPC physical address space layout. We use the one set up by the firmware. */
+#define ADIR_PCI32_MEM_BASE 0x80000000
+#define ADIR_PCI32_MEM_SIZE 0x20000000
+#define ADIR_PCI64_MEM_BASE 0xA0000000
+#define ADIR_PCI64_MEM_SIZE 0x20000000
+#define ADIR_PCI32_IO_BASE 0xC0000000
+#define ADIR_PCI32_IO_SIZE 0x10000000
+#define ADIR_PCI64_IO_BASE 0xD0000000
+#define ADIR_PCI64_IO_SIZE 0x10000000
+#define ADIR_PCI64_PHB 0xFF400000
+#define ADIR_PCI32_PHB 0xFF500000
+
+#define ADIR_PCI64_CONFIG_ADDR (ADIR_PCI64_PHB + 0x000f8000)
+#define ADIR_PCI64_CONFIG_DATA (ADIR_PCI64_PHB + 0x000f8010)
+
+#define ADIR_PCI32_CONFIG_ADDR (ADIR_PCI32_PHB + 0x000f8000)
+#define ADIR_PCI32_CONFIG_DATA (ADIR_PCI32_PHB + 0x000f8010)
+
+/* System memory as seen from PCI */
+#define ADIR_PCI_SYS_MEM_BASE 0x80000000
+
+/* Static virtual mapping of PCI I/O */
+#define ADIR_PCI32_VIRT_IO_BASE 0xFE000000
+#define ADIR_PCI32_VIRT_IO_SIZE 0x01000000
+#define ADIR_PCI64_VIRT_IO_BASE 0xFF000000
+#define ADIR_PCI64_VIRT_IO_SIZE 0x01000000
+
+/* Registers */
+#define ADIR_NVRAM_RTC_ADDR 0x74
+#define ADIR_NVRAM_RTC_DATA 0x75
+
+#define ADIR_BOARD_ID_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF0)
+#define ADIR_CPLD1REV_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF1)
+#define ADIR_CPLD2REV_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF2)
+#define ADIR_FLASHCTL_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF3)
+#define ADIR_CPC710_STAT_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF4)
+#define ADIR_CLOCK_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF5)
+#define ADIR_GPIO_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF8)
+#define ADIR_MISC_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFF9)
+#define ADIR_LED_REG (ADIR_PCI32_VIRT_IO_BASE + 0x08FFFA)
+
+#define ADIR_CLOCK_REG_PD 0x10
+#define ADIR_CLOCK_REG_SPREAD 0x08
+#define ADIR_CLOCK_REG_SEL133 0x04
+#define ADIR_CLOCK_REG_SEL1 0x02
+#define ADIR_CLOCK_REG_SEL0 0x01
+
+#define ADIR_PROCA_INT_MASK (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF0)
+#define ADIR_PROCB_INT_MASK (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF2)
+#define ADIR_PROCA_INT_STAT (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF4)
+#define ADIR_PROCB_INT_STAT (ADIR_PCI32_VIRT_IO_BASE + 0x0EFFF6)
+
+/* Linux IRQ numbers */
+#define ADIR_IRQ_NONE -1
+#define ADIR_IRQ_SERIAL2 3
+#define ADIR_IRQ_SERIAL1 4
+#define ADIR_IRQ_FDC 6
+#define ADIR_IRQ_PARALLEL 7
+#define ADIR_IRQ_VIA_AUDIO 10
+#define ADIR_IRQ_VIA_USB 11
+#define ADIR_IRQ_IDE0 14
+#define ADIR_IRQ_IDE1 15
+#define ADIR_IRQ_PCI0_INTA 16
+#define ADIR_IRQ_PCI0_INTB 17
+#define ADIR_IRQ_PCI0_INTC 18
+#define ADIR_IRQ_PCI0_INTD 19
+#define ADIR_IRQ_PCI1_INTA 20
+#define ADIR_IRQ_PCI1_INTB 21
+#define ADIR_IRQ_PCI1_INTC 22
+#define ADIR_IRQ_PCI1_INTD 23
+#define ADIR_IRQ_MBSCSI 24 /* motherboard SCSI */
+#define ADIR_IRQ_MBETH1 25 /* motherboard Ethernet 1 */
+#define ADIR_IRQ_MBETH0 26 /* motherboard Ethernet 0 */
+#define ADIR_IRQ_CPC710_INT1 27
+#define ADIR_IRQ_CPC710_INT2 28
+#define ADIR_IRQ_VT82C686_NMI 29
+#define ADIR_IRQ_VT82C686_INTR 30
+#define ADIR_IRQ_INTERPROC 31
+
+#endif /* __PPC_PLATFORMS_ADIR_H */
diff --git a/arch/ppc/platforms/adir_pci.c b/arch/ppc/platforms/adir_pci.c
new file mode 100644
index 00000000000..f94ac53e071
--- /dev/null
+++ b/arch/ppc/platforms/adir_pci.c
@@ -0,0 +1,247 @@
+/*
+ * arch/ppc/platforms/adir_pci.c
+ *
+ * PCI support for SBS Adirondack
+ *
+ * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
+ * based on the K2 version by Matt Porter <mporter@mvista.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+
+#include <syslib/cpc710.h>
+#include "adir.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG */
+
+static inline int __init
+adir_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+#define PCIIRQ(a,b,c,d) {ADIR_IRQ_##a,ADIR_IRQ_##b,ADIR_IRQ_##c,ADIR_IRQ_##d},
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+ /*
+ * The three PCI devices on the motherboard have dedicated lines to the
+ * CPLD interrupt controller, bypassing the standard PCI INTA-D and the
+ * PC interrupt controller. All other PCI devices (slots) have usual
+ * staggered INTA-D lines, resulting in 8 lines total (PCI0 INTA-D and
+ * PCI1 INTA-D). All 8 go to the CPLD interrupt controller. PCI0 INTA-D
+ * also go to the south bridge, so we have the option of taking them
+ * via the CPLD interrupt controller or via the south bridge 8259
+ * 8258 thingy. PCI1 INTA-D can only be taken via the CPLD interrupt
+ * controller. We take all PCI interrupts via the CPLD interrupt
+ * controller as recommended by SBS.
+ *
+ * We also have some monkey business with the PCI devices within the
+ * VT82C686B south bridge itself. This chip actually has 7 functions on
+ * its IDSEL. Function 0 is the actual south bridge, function 1 is IDE,
+ * and function 4 is some special stuff. The other 4 functions are just
+ * regular PCI devices bundled in the chip. 2 and 3 are USB UHCIs and 5
+ * and 6 are audio (not supported on the Adirondack).
+ *
+ * This is where the monkey business begins. PCI devices are supposed
+ * to signal normal PCI interrupts. But the 4 functions in question are
+ * located in the south bridge chip, which is designed with the
+ * assumption that it will be fielding PCI INTA-D interrupts rather
+ * than generating them. Here's what it does. Each of the functions in
+ * question routes its interrupt to one of the IRQs on the 8259 thingy.
+ * Which one? It looks at the Interrupt Line register in the PCI config
+ * space, even though the PCI spec says it's for BIOS/OS interaction
+ * only.
+ *
+ * How do we deal with this? We take these interrupts via 8259 IRQs as
+ * we have to. We return the desired IRQ numbers from this routine when
+ * called for the functions in question. The PCI scan code will then
+ * stick our return value into the Interrupt Line register in the PCI
+ * config space, and the interrupt will actually go there. We identify
+ * these functions within the south bridge IDSEL by their interrupt pin
+ * numbers, as the VT82C686B has 04 in the Interrupt Pin register for
+ * USB and 03 for audio.
+ */
+ if (!hose->index) {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ /* south bridge */ PCIIRQ(IDE0, NONE, VIA_AUDIO, VIA_USB)
+ /* Ethernet 0 */ PCIIRQ(MBETH0, MBETH0, MBETH0, MBETH0)
+ /* PCI0 slot 1 */ PCIIRQ(PCI0_INTB, PCI0_INTC, PCI0_INTD, PCI0_INTA)
+ /* PCI0 slot 2 */ PCIIRQ(PCI0_INTC, PCI0_INTD, PCI0_INTA, PCI0_INTB)
+ /* PCI0 slot 3 */ PCIIRQ(PCI0_INTD, PCI0_INTA, PCI0_INTB, PCI0_INTC)
+ };
+ const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ } else {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ /* Ethernet 1 */ PCIIRQ(MBETH1, MBETH1, MBETH1, MBETH1)
+ /* SCSI */ PCIIRQ(MBSCSI, MBSCSI, MBSCSI, MBSCSI)
+ /* PCI1 slot 1 */ PCIIRQ(PCI1_INTB, PCI1_INTC, PCI1_INTD, PCI1_INTA)
+ /* PCI1 slot 2 */ PCIIRQ(PCI1_INTC, PCI1_INTD, PCI1_INTA, PCI1_INTB)
+ /* PCI1 slot 3 */ PCIIRQ(PCI1_INTD, PCI1_INTA, PCI1_INTB, PCI1_INTC)
+ };
+ const long min_idsel = 3, max_idsel = 7, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ }
+#undef PCIIRQ
+}
+
+static void
+adir_pcibios_fixup_resources(struct pci_dev *dev)
+{
+ int i;
+
+ if ((dev->vendor == PCI_VENDOR_ID_IBM) &&
+ (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64))
+ {
+ DBG("Fixup CPC710 resources\n");
+ for (i=0; i<DEVICE_COUNT_RESOURCE; i++)
+ {
+ dev->resource[i].start = 0;
+ dev->resource[i].end = 0;
+ }
+ }
+}
+
+/*
+ * CPC710 DD3 has an errata causing it to hang the system if a type 0 config
+ * cycle is attempted on its PCI32 interface with a device number > 21.
+ * CPC710's PCI bridges map device numbers 1 through 21 to AD11 through AD31.
+ * Per the PCI spec it MUST accept all other device numbers and do nothing, and
+ * software MUST scan all device numbers without assuming how IDSELs are
+ * mapped. However, as the CPC710 DD3's errata causes such correct scanning
+ * procedure to hang the system, we have no choice but to introduce this hack
+ * of knowingly avoiding device numbers > 21 on PCI0,
+ */
+static int
+adir_exclude_device(u_char bus, u_char devfn)
+{
+ if ((bus == 0) && (PCI_SLOT(devfn) > 21))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+
+void adir_find_bridges(void)
+{
+ struct pci_controller *hose_a, *hose_b;
+
+ /* Setup PCI32 hose */
+ hose_a = pcibios_alloc_controller();
+ if (!hose_a)
+ return;
+
+ hose_a->first_busno = 0;
+ hose_a->last_busno = 0xff;
+ hose_a->pci_mem_offset = ADIR_PCI32_MEM_BASE;
+ hose_a->io_space.start = 0;
+ hose_a->io_space.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
+ hose_a->mem_space.start = 0;
+ hose_a->mem_space.end = ADIR_PCI32_MEM_SIZE - 1;
+ hose_a->io_resource.start = 0;
+ hose_a->io_resource.end = ADIR_PCI32_VIRT_IO_SIZE - 1;
+ hose_a->io_resource.flags = IORESOURCE_IO;
+ hose_a->mem_resources[0].start = ADIR_PCI32_MEM_BASE;
+ hose_a->mem_resources[0].end = ADIR_PCI32_MEM_BASE +
+ ADIR_PCI32_MEM_SIZE - 1;
+ hose_a->mem_resources[0].flags = IORESOURCE_MEM;
+ hose_a->io_base_phys = ADIR_PCI32_IO_BASE;
+ hose_a->io_base_virt = (void *) ADIR_PCI32_VIRT_IO_BASE;
+
+ ppc_md.pci_exclude_device = adir_exclude_device;
+ setup_indirect_pci(hose_a, ADIR_PCI32_CONFIG_ADDR,
+ ADIR_PCI32_CONFIG_DATA);
+
+ /* Initialize PCI32 bus registers */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(0, 0),
+ CPC710_BUS_NUMBER,
+ hose_a->first_busno);
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(0, 0),
+ CPC710_SUB_BUS_NUMBER,
+ hose_a->last_busno);
+
+ hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
+
+ /* Write out correct max subordinate bus number for hose A */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(0, 0),
+ CPC710_SUB_BUS_NUMBER,
+ hose_a->last_busno);
+
+ /* Setup PCI64 hose */
+ hose_b = pcibios_alloc_controller();
+ if (!hose_b)
+ return;
+
+ hose_b->first_busno = hose_a->last_busno + 1;
+ hose_b->last_busno = 0xff;
+ hose_b->pci_mem_offset = ADIR_PCI64_MEM_BASE;
+ hose_b->io_space.start = 0;
+ hose_b->io_space.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
+ hose_b->mem_space.start = 0;
+ hose_b->mem_space.end = ADIR_PCI64_MEM_SIZE - 1;
+ hose_b->io_resource.start = 0;
+ hose_b->io_resource.end = ADIR_PCI64_VIRT_IO_SIZE - 1;
+ hose_b->io_resource.flags = IORESOURCE_IO;
+ hose_b->mem_resources[0].start = ADIR_PCI64_MEM_BASE;
+ hose_b->mem_resources[0].end = ADIR_PCI64_MEM_BASE +
+ ADIR_PCI64_MEM_SIZE - 1;
+ hose_b->mem_resources[0].flags = IORESOURCE_MEM;
+ hose_b->io_base_phys = ADIR_PCI64_IO_BASE;
+ hose_b->io_base_virt = (void *) ADIR_PCI64_VIRT_IO_BASE;
+
+ setup_indirect_pci(hose_b, ADIR_PCI64_CONFIG_ADDR,
+ ADIR_PCI64_CONFIG_DATA);
+
+ /* Initialize PCI64 bus registers */
+ early_write_config_byte(hose_b,
+ 0,
+ PCI_DEVFN(0, 0),
+ CPC710_SUB_BUS_NUMBER,
+ 0xff);
+
+ early_write_config_byte(hose_b,
+ 0,
+ PCI_DEVFN(0, 0),
+ CPC710_BUS_NUMBER,
+ hose_b->first_busno);
+
+ hose_b->last_busno = pciauto_bus_scan(hose_b,
+ hose_b->first_busno);
+
+ /* Write out correct max subordinate bus number for hose B */
+ early_write_config_byte(hose_b,
+ hose_b->first_busno,
+ PCI_DEVFN(0, 0),
+ CPC710_SUB_BUS_NUMBER,
+ hose_b->last_busno);
+
+ ppc_md.pcibios_fixup = NULL;
+ ppc_md.pcibios_fixup_resources = adir_pcibios_fixup_resources;
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = adir_map_irq;
+}
diff --git a/arch/ppc/platforms/adir_pic.c b/arch/ppc/platforms/adir_pic.c
new file mode 100644
index 00000000000..9947cba52af
--- /dev/null
+++ b/arch/ppc/platforms/adir_pic.c
@@ -0,0 +1,130 @@
+/*
+ * arch/ppc/platforms/adir_pic.c
+ *
+ * Interrupt controller support for SBS Adirondack
+ *
+ * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
+ * based on the K2 and SCM versions by Matt Porter <mporter@mvista.com>
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/i8259.h>
+#include "adir.h"
+
+static void adir_onboard_pic_enable(unsigned int irq);
+static void adir_onboard_pic_disable(unsigned int irq);
+
+__init static void
+adir_onboard_pic_init(void)
+{
+ volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
+
+ /* Disable all Adirondack onboard interrupts */
+ out_be16(maskreg, 0xFFFF);
+}
+
+static int
+adir_onboard_pic_get_irq(void)
+{
+ volatile u_short *statreg = (volatile u_short *) ADIR_PROCA_INT_STAT;
+ int irq;
+ u_short int_status, int_test;
+
+ int_status = in_be16(statreg);
+ for (irq = 0, int_test = 1; irq < 16; irq++, int_test <<= 1) {
+ if (int_status & int_test)
+ break;
+ }
+
+ if (irq == 16)
+ return -1;
+
+ return (irq+16);
+}
+
+static void
+adir_onboard_pic_enable(unsigned int irq)
+{
+ volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
+
+ /* Change irq to Adirondack onboard native value */
+ irq -= 16;
+
+ /* Enable requested irq number */
+ out_be16(maskreg, in_be16(maskreg) & ~(1 << irq));
+}
+
+static void
+adir_onboard_pic_disable(unsigned int irq)
+{
+ volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
+
+ /* Change irq to Adirondack onboard native value */
+ irq -= 16;
+
+ /* Disable requested irq number */
+ out_be16(maskreg, in_be16(maskreg) | (1 << irq));
+}
+
+static struct hw_interrupt_type adir_onboard_pic = {
+ " ADIR PIC ",
+ NULL,
+ NULL,
+ adir_onboard_pic_enable, /* unmask */
+ adir_onboard_pic_disable, /* mask */
+ adir_onboard_pic_disable, /* mask and ack */
+ NULL,
+ NULL
+};
+
+static struct irqaction noop_action = {
+ .handler = no_action,
+ .flags = SA_INTERRUPT,
+ .mask = CPU_MASK_NONE,
+ .name = "82c59 primary cascade",
+};
+
+/*
+ * Linux interrupt values are assigned as follows:
+ *
+ * 0-15 VT82C686 8259 interrupts
+ * 16-31 Adirondack CPLD interrupts
+ */
+__init void
+adir_init_IRQ(void)
+{
+ int i;
+
+ /* Initialize the cascaded 8259's on the VT82C686 */
+ for (i=0; i<16; i++)
+ irq_desc[i].handler = &i8259_pic;
+ i8259_init(NULL);
+
+ /* Initialize Adirondack CPLD PIC and enable 8259 interrupt cascade */
+ for (i=16; i<32; i++)
+ irq_desc[i].handler = &adir_onboard_pic;
+ adir_onboard_pic_init();
+
+ /* Enable 8259 interrupt cascade */
+ setup_irq(ADIR_IRQ_VT82C686_INTR, &noop_action);
+}
+
+int
+adir_get_irq(struct pt_regs *regs)
+{
+ int irq;
+
+ if ((irq = adir_onboard_pic_get_irq()) < 0)
+ return irq;
+
+ if (irq == ADIR_IRQ_VT82C686_INTR)
+ irq = i8259_irq(regs);
+
+ return irq;
+}
diff --git a/arch/ppc/platforms/adir_setup.c b/arch/ppc/platforms/adir_setup.c
new file mode 100644
index 00000000000..6a6754ee061
--- /dev/null
+++ b/arch/ppc/platforms/adir_setup.c
@@ -0,0 +1,210 @@
+/*
+ * arch/ppc/platforms/adir_setup.c
+ *
+ * Board setup routines for SBS Adirondack
+ *
+ * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
+ * based on the K2 version by Matt Porter <mporter@mvista.com>
+ */
+
+#include <linux/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+
+#include "adir.h"
+
+extern void adir_init_IRQ(void);
+extern int adir_get_irq(struct pt_regs *);
+extern void adir_find_bridges(void);
+extern unsigned long loops_per_jiffy;
+
+static unsigned int cpu_750cx[16] = {
+ 5, 15, 14, 0, 4, 13, 0, 9, 6, 11, 8, 10, 16, 12, 7, 0
+};
+
+static int
+adir_get_bus_speed(void)
+{
+ if (!(*((u_char *) ADIR_CLOCK_REG) & ADIR_CLOCK_REG_SEL133))
+ return 100000000;
+ else
+ return 133333333;
+}
+
+static int
+adir_get_cpu_speed(void)
+{
+ unsigned long hid1;
+ int cpu_speed;
+
+ hid1 = mfspr(SPRN_HID1) >> 28;
+
+ hid1 = cpu_750cx[hid1];
+
+ cpu_speed = adir_get_bus_speed()*hid1/2;
+ return cpu_speed;
+}
+
+static void __init
+adir_calibrate_decr(void)
+{
+ int freq, divisor = 4;
+
+ /* determine processor bus speed */
+ freq = adir_get_bus_speed();
+ tb_ticks_per_jiffy = freq / HZ / divisor;
+ tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+}
+
+static int
+adir_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: SBS\n");
+ seq_printf(m, "machine\t\t: Adirondack\n");
+ seq_printf(m, "cpu speed\t: %dMhz\n", adir_get_cpu_speed()/1000000);
+ seq_printf(m, "bus speed\t: %dMhz\n", adir_get_bus_speed()/1000000);
+ seq_printf(m, "memory type\t: SDRAM\n");
+
+ return 0;
+}
+
+extern char cmd_line[];
+
+TODC_ALLOC();
+
+static void __init
+adir_setup_arch(void)
+{
+ unsigned int cpu;
+
+ /* Setup TODC access */
+ TODC_INIT(TODC_TYPE_MC146818, ADIR_NVRAM_RTC_ADDR, 0,
+ ADIR_NVRAM_RTC_DATA, 8);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000/HZ;
+
+ /* Setup PCI host bridges */
+ adir_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA1;
+#endif
+
+ /* Identify the system */
+ printk("System Identification: SBS Adirondack - PowerPC 750CXe @ %d Mhz\n", adir_get_cpu_speed()/1000000);
+ printk("SBS Adirondack port (C) 2001 SBS Technologies, Inc.\n");
+
+ /* Identify the CPU manufacturer */
+ cpu = mfspr(SPRN_PVR);
+ printk("CPU manufacturer: IBM [rev=%04x]\n", (cpu & 0xffff));
+}
+
+static void
+adir_restart(char *cmd)
+{
+ local_irq_disable();
+ /* SRR0 has system reset vector, SRR1 has default MSR value */
+ /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+ __asm__ __volatile__
+ ("lis 3,0xfff0\n\t"
+ "ori 3,3,0x0100\n\t"
+ "mtspr 26,3\n\t"
+ "li 3,0\n\t"
+ "mtspr 27,3\n\t"
+ "rfi\n\t");
+ for(;;);
+}
+
+static void
+adir_power_off(void)
+{
+ for(;;);
+}
+
+static void
+adir_halt(void)
+{
+ adir_restart(NULL);
+}
+
+static unsigned long __init
+adir_find_end_of_memory(void)
+{
+ return boot_mem_size;
+}
+
+static void __init
+adir_map_io(void)
+{
+ io_block_mapping(ADIR_PCI32_VIRT_IO_BASE, ADIR_PCI32_IO_BASE,
+ ADIR_PCI32_VIRT_IO_SIZE, _PAGE_IO);
+ io_block_mapping(ADIR_PCI64_VIRT_IO_BASE, ADIR_PCI64_IO_BASE,
+ ADIR_PCI64_VIRT_IO_SIZE, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /*
+ * On the Adirondack we use bi_recs and pass the pointer to them in R3.
+ */
+ parse_bootinfo((struct bi_record *) (r3 + KERNELBASE));
+
+ /* Remember, isa_io_base is virtual but isa_mem_base is physical! */
+ isa_io_base = ADIR_PCI32_VIRT_IO_BASE;
+ isa_mem_base = ADIR_PCI32_MEM_BASE;
+ pci_dram_offset = ADIR_PCI_SYS_MEM_BASE;
+
+ ppc_md.setup_arch = adir_setup_arch;
+ ppc_md.show_cpuinfo = adir_show_cpuinfo;
+ ppc_md.irq_canonicalize = NULL;
+ ppc_md.init_IRQ = adir_init_IRQ;
+ ppc_md.get_irq = adir_get_irq;
+ ppc_md.init = NULL;
+
+ ppc_md.find_end_of_memory = adir_find_end_of_memory;
+ ppc_md.setup_io_mappings = adir_map_io;
+
+ ppc_md.restart = adir_restart;
+ ppc_md.power_off = adir_power_off;
+ ppc_md.halt = adir_halt;
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.nvram_read_val = todc_mc146818_read_val;
+ ppc_md.nvram_write_val = todc_mc146818_write_val;
+ ppc_md.calibrate_decr = adir_calibrate_decr;
+}
diff --git a/arch/ppc/platforms/apus_pci.c b/arch/ppc/platforms/apus_pci.c
new file mode 100644
index 00000000000..33dad6db824
--- /dev/null
+++ b/arch/ppc/platforms/apus_pci.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch>
+ *
+ * APUS PCI routines.
+ *
+ * Currently, only B/CVisionPPC cards (Permedia2) are supported.
+ *
+ * Thanks to Geert Uytterhoeven for the idea:
+ * Read values from given config space(s) for the first devices, -1 otherwise
+ *
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_AMIGA
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "apus_pci.h"
+
+
+/* These definitions are mostly adapted from pm2fb.c */
+
+#undef APUS_PCI_MASTER_DEBUG
+#ifdef APUS_PCI_MASTER_DEBUG
+#define DPRINTK(a,b...) printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif
+
+/*
+ * The _DEFINITIVE_ memory mapping/unmapping functions.
+ * This is due to the fact that they're changing soooo often...
+ */
+#define DEFW() wmb()
+#define DEFR() rmb()
+#define DEFRW() mb()
+
+#define DEVNO(d) ((d)>>3)
+#define FNNO(d) ((d)&7)
+
+
+extern unsigned long powerup_PCI_present;
+
+static struct pci_controller *apus_hose;
+
+
+void *pci_io_base(unsigned int bus)
+{
+ return 0;
+}
+
+
+int
+apus_pcibios_read_config(struct pci_bus *bus, int devfn, int offset,
+ int len, u32 *val)
+{
+ int fnno = FNNO(devfn);
+ int devno = DEVNO(devfn);
+ volatile unsigned char *cfg_data;
+
+ if (bus->number > 0 || devno != 1) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ /* base address + function offset + offset ^ endianness conversion */
+ /* XXX the fnno<<5 bit seems wacky -- paulus */
+ cfg_data = apus_hose->cfg_data + (fnno<<5) + (offset ^ (len - 1));
+ switch (len) {
+ case 1:
+ *val = readb(cfg_data);
+ break;
+ case 2:
+ *val = readw(cfg_data);
+ break;
+ default:
+ *val = readl(cfg_data);
+ break;
+ }
+
+ DPRINTK("read b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, l: %d, v: 0x%x\n",
+ bus->number, devfn>>3, devfn&7, offset, len, *val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+apus_pcibios_write_config(struct pci_bus *bus, int devfn, int offset,
+ int len, u32 *val)
+{
+ int fnno = FNNO(devfn);
+ int devno = DEVNO(devfn);
+ volatile unsigned char *cfg_data;
+
+ if (bus->number > 0 || devno != 1) {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ /* base address + function offset + offset ^ endianness conversion */
+ /* XXX the fnno<<5 bit seems wacky -- paulus */
+ cfg_data = apus_hose->cfg_data + (fnno<<5) + (offset ^ (len - 1));
+ switch (len) {
+ case 1:
+ writeb(val, cfg_data); DEFW();
+ break;
+ case 2:
+ writew(val, cfg_data); DEFW();
+ break;
+ default:
+ writel(val, cfg_data); DEFW();
+ break;
+ }
+
+ DPRINTK("write b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, l: %d, v: 0x%x\n",
+ bus->number, devfn>>3, devfn&7, offset, len, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops apus_pci_ops = {
+ apus_pcibios_read_config,
+ apus_pcibios_write_config
+};
+
+static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM };
+
+void __init
+apus_pcibios_fixup(void)
+{
+/* struct pci_dev *dev = pci_find_slot(0, 1<<3);
+ unsigned int reg, val, offset;*/
+
+ /* FIXME: interrupt? */
+ /*dev->interrupt = xxx;*/
+
+ request_resource(&iomem_resource, &pci_mem);
+ printk("%s: PCI mem resource requested\n", __FUNCTION__);
+}
+
+static void __init apus_pcibios_fixup_bus(struct pci_bus *bus)
+{
+ bus->resource[1] = &pci_mem;
+}
+
+
+/*
+ * This is from pm2fb.c again
+ *
+ * Check if PCI (B/CVisionPPC) is available, initialize it and set up
+ * the pcibios_* pointers
+ */
+
+
+void __init
+apus_setup_pci_ptrs(void)
+{
+ if (!powerup_PCI_present) {
+ DPRINTK("no PCI bridge detected\n");
+ return;
+ }
+ DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n");
+
+ apus_hose = pcibios_alloc_controller();
+ if (!apus_hose) {
+ printk("apus_pci: Can't allocate PCI controller structure\n");
+ return;
+ }
+
+ if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) {
+ printk("apus_pci: unable to map PCI config region\n");
+ return;
+ }
+
+ if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) {
+ printk("apus_pci: unable to map PCI bridge\n");
+ return;
+ }
+
+ writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN);
+ DEFW();
+
+ writel(CVPPC_REGS_REGION, apus_hose->cfg_data+ PCI_BASE_ADDRESS_0);
+ DEFW();
+ writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1);
+ DEFW();
+ writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2);
+ DEFW();
+ writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS);
+ DEFW();
+
+ writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND);
+ DEFW();
+
+ apus_hose->first_busno = 0;
+ apus_hose->last_busno = 0;
+ apus_hose->ops = &apus_pci_ops;
+ ppc_md.pcibios_fixup = apus_pcibios_fixup;
+ ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus;
+
+ return;
+}
+
+#endif /* CONFIG_AMIGA */
diff --git a/arch/ppc/platforms/apus_pci.h b/arch/ppc/platforms/apus_pci.h
new file mode 100644
index 00000000000..f15974ae018
--- /dev/null
+++ b/arch/ppc/platforms/apus_pci.h
@@ -0,0 +1,34 @@
+/*
+ * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer
+ * driver.
+ *
+ * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * --------------------------------------------------------------------------
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef APUS_PCI_H
+#define APUS_PCI_H
+
+
+#define CSPPC_PCI_BRIDGE 0xfffe0000
+#define CSPPC_BRIDGE_ENDIAN 0x0000
+#define CSPPC_BRIDGE_INT 0x0010
+
+#define CVPPC_PCI_CONFIG 0xfffc0000
+#define CVPPC_ROM_ADDRESS 0xe2000001
+#define CVPPC_REGS_REGION 0xef000000
+#define CVPPC_FB_APERTURE_ONE 0xe0000000
+#define CVPPC_FB_APERTURE_TWO 0xe1000000
+#define CVPPC_FB_SIZE 0x00800000
+
+/* CVPPC_BRIDGE_ENDIAN */
+#define CSPPCF_BRIDGE_BIG_ENDIAN 0x02
+
+/* CVPPC_BRIDGE_INT */
+#define CSPPCF_BRIDGE_ACTIVE_INT2 0x01
+
+
+#endif /* APUS_PCI_H */
diff --git a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c
new file mode 100644
index 00000000000..2f74fde98eb
--- /dev/null
+++ b/arch/ppc/platforms/apus_setup.c
@@ -0,0 +1,815 @@
+/*
+ * arch/ppc/platforms/apus_setup.c
+ *
+ * Copyright (C) 1998, 1999 Jesper Skov
+ *
+ * Basically what is needed to replace functionality found in
+ * arch/m68k allowing Amiga drivers to work under APUS.
+ * Bits of code and/or ideas from arch/m68k and arch/ppc files.
+ *
+ * TODO:
+ * This file needs a *really* good cleanup. Restructure and optimize.
+ * Make sure it can be compiled for non-APUS configs. Begin to move
+ * Amiga specific stuff into mach/amiga.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/seq_file.h>
+
+/* Needs INITSERIAL call in head.S! */
+#undef APUS_DEBUG
+
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigappc.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+
+unsigned long m68k_machtype;
+char debug_device[6] = "";
+
+extern void amiga_init_IRQ(void);
+
+extern void apus_setup_pci_ptrs(void);
+
+void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
+/* machine dependent irq functions */
+void (*mach_init_IRQ) (void) __initdata = NULL;
+void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
+void (*mach_get_model) (char *model) = NULL;
+int (*mach_get_hardware_list) (char *buffer) = NULL;
+int (*mach_get_irq_list) (struct seq_file *, void *) = NULL;
+void (*mach_process_int) (int, struct pt_regs *) = NULL;
+/* machine dependent timer functions */
+unsigned long (*mach_gettimeoffset) (void);
+void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
+int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
+int (*mach_set_clock_mmss) (unsigned long) = NULL;
+void (*mach_reset)( void );
+long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
+#if defined(CONFIG_AMIGA_FLOPPY)
+void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
+#endif
+#ifdef CONFIG_HEARTBEAT
+void (*mach_heartbeat) (int) = NULL;
+extern void apus_heartbeat (void);
+#endif
+
+extern unsigned long amiga_model;
+extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */
+extern unsigned count_period_num; /* 1 decrementer count equals */
+extern unsigned count_period_den; /* count_period_num / count_period_den us */
+
+int num_memory = 0;
+struct mem_info memory[NUM_MEMINFO];/* memory description */
+/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */
+int m68k_realnum_memory = 0;
+struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
+
+struct mem_info ramdisk;
+
+extern void amiga_floppy_setup(char *, int *);
+extern void config_amiga(void);
+
+static int __60nsram = 0;
+
+/* for cpuinfo */
+static int __bus_speed = 0;
+static int __speed_test_failed = 0;
+
+/********************************************** COMPILE PROTECTION */
+/* Provide some stubs that links to Amiga specific functions.
+ * This allows CONFIG_APUS to be removed from generic PPC files while
+ * preventing link errors for other PPC targets.
+ */
+unsigned long apus_get_rtc_time(void)
+{
+#ifdef CONFIG_APUS
+ extern unsigned long m68k_get_rtc_time(void);
+
+ return m68k_get_rtc_time ();
+#else
+ return 0;
+#endif
+}
+
+int apus_set_rtc_time(unsigned long nowtime)
+{
+#ifdef CONFIG_APUS
+ extern int m68k_set_rtc_time(unsigned long nowtime);
+
+ return m68k_set_rtc_time (nowtime);
+#else
+ return 0;
+#endif
+}
+
+/*********************************************************** SETUP */
+/* From arch/m68k/kernel/setup.c. */
+void __init apus_setup_arch(void)
+{
+#ifdef CONFIG_APUS
+ extern char cmd_line[];
+ int i;
+ char *p, *q;
+
+ /* Let m68k-shared code know it should do the Amiga thing. */
+ m68k_machtype = MACH_AMIGA;
+
+ /* Parse the command line for arch-specific options.
+ * For the m68k, this is currently only "debug=xxx" to enable printing
+ * certain kernel messages to some machine-specific device. */
+ for( p = cmd_line; p && *p; ) {
+ i = 0;
+ if (!strncmp( p, "debug=", 6 )) {
+ strlcpy( debug_device, p+6, sizeof(debug_device) );
+ if ((q = strchr( debug_device, ' ' ))) *q = 0;
+ i = 1;
+ } else if (!strncmp( p, "60nsram", 7 )) {
+ APUS_WRITE (APUS_REG_WAITSTATE,
+ REGWAITSTATE_SETRESET
+ |REGWAITSTATE_PPCR
+ |REGWAITSTATE_PPCW);
+ __60nsram = 1;
+ i = 1;
+ }
+
+ if (i) {
+ /* option processed, delete it */
+ if ((q = strchr( p, ' ' )))
+ strcpy( p, q+1 );
+ else
+ *p = 0;
+ } else {
+ if ((p = strchr( p, ' ' ))) ++p;
+ }
+ }
+
+ config_amiga();
+
+#if 0 /* Enable for logging - also include logging.o in Makefile rule */
+ {
+#define LOG_SIZE 4096
+ void* base;
+
+ /* Throw away some memory - the P5 firmare stomps on top
+ * of CHIP memory during bootup.
+ */
+ amiga_chip_alloc(0x1000);
+
+ base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t));
+ LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE);
+ }
+#endif
+#endif
+}
+
+int
+apus_show_cpuinfo(struct seq_file *m)
+{
+ extern int __map_without_bats;
+ extern unsigned long powerup_PCI_present;
+
+ seq_printf(m, "machine\t\t: Amiga\n");
+ seq_printf(m, "bus speed\t: %d%s", __bus_speed,
+ (__speed_test_failed) ? " [failed]\n" : "\n");
+ seq_printf(m, "using BATs\t: %s\n",
+ (__map_without_bats) ? "No" : "Yes");
+ seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70);
+ seq_printf(m, "PCI bridge\t: %s\n",
+ (powerup_PCI_present) ? "Yes" : "No");
+ return 0;
+}
+
+static void get_current_tb(unsigned long long *time)
+{
+ __asm __volatile ("1:mftbu 4 \n\t"
+ " mftb 5 \n\t"
+ " mftbu 6 \n\t"
+ " cmpw 4,6 \n\t"
+ " bne 1b \n\t"
+ " stw 4,0(%0)\n\t"
+ " stw 5,4(%0)\n\t"
+ :
+ : "r" (time)
+ : "r4", "r5", "r6");
+}
+
+
+void apus_calibrate_decr(void)
+{
+#ifdef CONFIG_APUS
+ unsigned long freq;
+
+ /* This algorithm for determining the bus speed was
+ contributed by Ralph Schmidt. */
+ unsigned long long start, stop;
+ int bus_speed;
+ int speed_test_failed = 0;
+
+ {
+ unsigned long loop = amiga_eclock / 10;
+
+ get_current_tb (&start);
+ while (loop--) {
+ unsigned char tmp;
+
+ tmp = ciaa.pra;
+ }
+ get_current_tb (&stop);
+ }
+
+ bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000;
+ if (AMI_1200 == amiga_model)
+ bus_speed /= 2;
+
+ if ((bus_speed >= 47) && (bus_speed < 53)) {
+ bus_speed = 50;
+ freq = 12500000;
+ } else if ((bus_speed >= 57) && (bus_speed < 63)) {
+ bus_speed = 60;
+ freq = 15000000;
+ } else if ((bus_speed >= 63) && (bus_speed < 69)) {
+ bus_speed = 67;
+ freq = 16666667;
+ } else {
+ printk ("APUS: Unable to determine bus speed (%d). "
+ "Defaulting to 50MHz", bus_speed);
+ bus_speed = 50;
+ freq = 12500000;
+ speed_test_failed = 1;
+ }
+
+ /* Ease diagnostics... */
+ {
+ extern int __map_without_bats;
+ extern unsigned long powerup_PCI_present;
+
+ printk ("APUS: BATs=%d, BUS=%dMHz",
+ (__map_without_bats) ? 0 : 1,
+ bus_speed);
+ if (speed_test_failed)
+ printk ("[FAILED - please report]");
+
+ printk (", RAM=%dns, PCI bridge=%d\n",
+ (__60nsram) ? 60 : 70,
+ (powerup_PCI_present) ? 1 : 0);
+
+ /* print a bit more if asked politely... */
+ if (!(ciaa.pra & 0x40)){
+ extern unsigned int bat_addrs[4][3];
+ int b;
+ for (b = 0; b < 4; ++b) {
+ printk ("APUS: BAT%d ", b);
+ printk ("%08x-%08x -> %08x\n",
+ bat_addrs[b][0],
+ bat_addrs[b][1],
+ bat_addrs[b][2]);
+ }
+ }
+
+ }
+
+ printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ freq/1000000, freq%1000000);
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+ __bus_speed = bus_speed;
+ __speed_test_failed = speed_test_failed;
+#endif
+}
+
+void arch_gettod(int *year, int *mon, int *day, int *hour,
+ int *min, int *sec)
+{
+#ifdef CONFIG_APUS
+ if (mach_gettod)
+ mach_gettod(year, mon, day, hour, min, sec);
+ else
+ *year = *mon = *day = *hour = *min = *sec = 0;
+#endif
+}
+
+/* for "kbd-reset" cmdline param */
+__init
+void kbd_reset_setup(char *str, int *ints)
+{
+}
+
+/*********************************************************** FLOPPY */
+#if defined(CONFIG_AMIGA_FLOPPY)
+__init
+void floppy_setup(char *str, int *ints)
+{
+ if (mach_floppy_setup)
+ mach_floppy_setup (str, ints);
+}
+#endif
+
+/*********************************************************** MEMORY */
+#define KMAP_MAX 32
+unsigned long kmap_chunks[KMAP_MAX*3];
+int kmap_chunk_count = 0;
+
+/* From pgtable.h */
+static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va)
+{
+ pgd_t *dir = 0;
+ pmd_t *pmd = 0;
+ pte_t *pte = 0;
+
+ va &= PAGE_MASK;
+
+ dir = pgd_offset( mm, va );
+ if (dir)
+ {
+ pmd = pmd_offset(dir, va & PAGE_MASK);
+ if (pmd && pmd_present(*pmd))
+ {
+ pte = pte_offset(pmd, va);
+ }
+ }
+ return pte;
+}
+
+
+/* Again simulating an m68k/mm/kmap.c function. */
+void kernel_set_cachemode( unsigned long address, unsigned long size,
+ unsigned int cmode )
+{
+ unsigned long mask, flags;
+
+ switch (cmode)
+ {
+ case IOMAP_FULL_CACHING:
+ mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
+ flags = 0;
+ break;
+ case IOMAP_NOCACHE_SER:
+ mask = ~0;
+ flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
+ break;
+ default:
+ panic ("kernel_set_cachemode() doesn't support mode %d\n",
+ cmode);
+ break;
+ }
+
+ size /= PAGE_SIZE;
+ address &= PAGE_MASK;
+ while (size--)
+ {
+ pte_t *pte;
+
+ pte = my_find_pte(&init_mm, address);
+ if ( !pte )
+ {
+ printk("pte NULL in kernel_set_cachemode()\n");
+ return;
+ }
+
+ pte_val (*pte) &= mask;
+ pte_val (*pte) |= flags;
+ flush_tlb_page(find_vma(&init_mm,address),address);
+
+ address += PAGE_SIZE;
+ }
+}
+
+unsigned long mm_ptov (unsigned long paddr)
+{
+ unsigned long ret;
+ if (paddr < 16*1024*1024)
+ ret = ZTWO_VADDR(paddr);
+ else {
+ int i;
+
+ for (i = 0; i < kmap_chunk_count;){
+ unsigned long phys = kmap_chunks[i++];
+ unsigned long size = kmap_chunks[i++];
+ unsigned long virt = kmap_chunks[i++];
+ if (paddr >= phys
+ && paddr < (phys + size)){
+ ret = virt + paddr - phys;
+ goto exit;
+ }
+ }
+
+ ret = (unsigned long) __va(paddr);
+ }
+exit:
+#ifdef DEBUGPV
+ printk ("PTOV(%lx)=%lx\n", paddr, ret);
+#endif
+ return ret;
+}
+
+int mm_end_of_chunk (unsigned long addr, int len)
+{
+ if (memory[0].addr + memory[0].size == addr + len)
+ return 1;
+ return 0;
+}
+
+/*********************************************************** CACHE */
+
+#define L1_CACHE_BYTES 32
+#define MAX_CACHE_SIZE 8192
+void cache_push(__u32 addr, int length)
+{
+ addr = mm_ptov(addr);
+
+ if (MAX_CACHE_SIZE < length)
+ length = MAX_CACHE_SIZE;
+
+ while(length > 0){
+ __asm ("dcbf 0,%0\n\t"
+ : : "r" (addr));
+ addr += L1_CACHE_BYTES;
+ length -= L1_CACHE_BYTES;
+ }
+ /* Also flush trailing block */
+ __asm ("dcbf 0,%0\n\t"
+ "sync \n\t"
+ : : "r" (addr));
+}
+
+void cache_clear(__u32 addr, int length)
+{
+ if (MAX_CACHE_SIZE < length)
+ length = MAX_CACHE_SIZE;
+
+ addr = mm_ptov(addr);
+
+ __asm ("dcbf 0,%0\n\t"
+ "sync \n\t"
+ "icbi 0,%0 \n\t"
+ "isync \n\t"
+ : : "r" (addr));
+
+ addr += L1_CACHE_BYTES;
+ length -= L1_CACHE_BYTES;
+
+ while(length > 0){
+ __asm ("dcbf 0,%0\n\t"
+ "sync \n\t"
+ "icbi 0,%0 \n\t"
+ "isync \n\t"
+ : : "r" (addr));
+ addr += L1_CACHE_BYTES;
+ length -= L1_CACHE_BYTES;
+ }
+
+ __asm ("dcbf 0,%0\n\t"
+ "sync \n\t"
+ "icbi 0,%0 \n\t"
+ "isync \n\t"
+ : : "r" (addr));
+}
+
+/****************************************************** from setup.c */
+void
+apus_restart(char *cmd)
+{
+ local_irq_disable();
+
+ APUS_WRITE(APUS_REG_LOCK,
+ REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
+ APUS_WRITE(APUS_REG_LOCK,
+ REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
+ APUS_WRITE(APUS_REG_LOCK,
+ REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
+ APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
+ APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
+ for(;;);
+}
+
+void
+apus_power_off(void)
+{
+ for (;;);
+}
+
+void
+apus_halt(void)
+{
+ apus_restart(NULL);
+}
+
+/****************************************************** IRQ stuff */
+
+static unsigned char last_ipl[8];
+
+int apus_get_irq(struct pt_regs* regs)
+{
+ unsigned char ipl_emu, mask;
+ unsigned int level;
+
+ APUS_READ(APUS_IPL_EMU, ipl_emu);
+ level = (ipl_emu >> 3) & IPLEMU_IPLMASK;
+ mask = IPLEMU_SETRESET|IPLEMU_DISABLEINT|level;
+ level ^= 7;
+
+ /* Save previous IPL value */
+ if (last_ipl[level])
+ return -2;
+ last_ipl[level] = ipl_emu;
+
+ /* Set to current IPL value */
+ APUS_WRITE(APUS_IPL_EMU, mask);
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|level);
+
+
+#ifdef __INTERRUPT_DEBUG
+ printk("<%d:%d>", level, ~ipl_emu & IPLEMU_IPLMASK);
+#endif
+ return level + IRQ_AMIGA_AUTO;
+}
+
+void apus_end_irq(unsigned int irq)
+{
+ unsigned char ipl_emu;
+ unsigned int level = irq - IRQ_AMIGA_AUTO;
+#ifdef __INTERRUPT_DEBUG
+ printk("{%d}", ~last_ipl[level] & IPLEMU_IPLMASK);
+#endif
+ /* Restore IPL to the previous value */
+ ipl_emu = last_ipl[level] & IPLEMU_IPLMASK;
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET|IPLEMU_DISABLEINT|ipl_emu);
+ last_ipl[level] = 0;
+ ipl_emu ^= 7;
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|ipl_emu);
+}
+
+/****************************************************** debugging */
+
+/* some serial hardware definitions */
+#define SDR_OVRUN (1<<15)
+#define SDR_RBF (1<<14)
+#define SDR_TBE (1<<13)
+#define SDR_TSRE (1<<12)
+
+#define AC_SETCLR (1<<15)
+#define AC_UARTBRK (1<<11)
+
+#define SER_DTR (1<<7)
+#define SER_RTS (1<<6)
+#define SER_DCD (1<<5)
+#define SER_CTS (1<<4)
+#define SER_DSR (1<<3)
+
+static __inline__ void ser_RTSon(void)
+{
+ ciab.pra &= ~SER_RTS; /* active low */
+}
+
+int __debug_ser_out( unsigned char c )
+{
+ custom.serdat = c | 0x100;
+ mb();
+ while (!(custom.serdatr & 0x2000))
+ barrier();
+ return 1;
+}
+
+unsigned char __debug_ser_in( void )
+{
+ unsigned char c;
+
+ /* XXX: is that ok?? derived from amiga_ser.c... */
+ while( !(custom.intreqr & IF_RBF) )
+ barrier();
+ c = custom.serdatr;
+ /* clear the interrupt, so that another character can be read */
+ custom.intreq = IF_RBF;
+ return c;
+}
+
+int __debug_serinit( void )
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ /* turn off Rx and Tx interrupts */
+ custom.intena = IF_RBF | IF_TBE;
+
+ /* clear any pending interrupt */
+ custom.intreq = IF_RBF | IF_TBE;
+
+ local_irq_restore(flags);
+
+ /*
+ * set the appropriate directions for the modem control flags,
+ * and clear RTS and DTR
+ */
+ ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */
+ ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */
+
+#ifdef CONFIG_KGDB
+ /* turn Rx interrupts on for GDB */
+ custom.intena = IF_SETCLR | IF_RBF;
+ ser_RTSon();
+#endif
+
+ return 0;
+}
+
+void __debug_print_hex(unsigned long x)
+{
+ int i;
+ char hexchars[] = "0123456789ABCDEF";
+
+ for (i = 0; i < 8; i++) {
+ __debug_ser_out(hexchars[(x >> 28) & 15]);
+ x <<= 4;
+ }
+ __debug_ser_out('\n');
+ __debug_ser_out('\r');
+}
+
+void __debug_print_string(char* s)
+{
+ unsigned char c;
+ while((c = *s++))
+ __debug_ser_out(c);
+ __debug_ser_out('\n');
+ __debug_ser_out('\r');
+}
+
+static void apus_progress(char *s, unsigned short value)
+{
+ __debug_print_string(s);
+}
+
+/****************************************************** init */
+
+/* The number of spurious interrupts */
+volatile unsigned int num_spurious;
+
+extern struct irqaction amiga_sys_irqaction[AUTO_IRQS];
+
+
+extern void amiga_enable_irq(unsigned int irq);
+extern void amiga_disable_irq(unsigned int irq);
+
+struct hw_interrupt_type amiga_sys_irqctrl = {
+ .typename = "Amiga IPL",
+ .end = apus_end_irq,
+};
+
+struct hw_interrupt_type amiga_irqctrl = {
+ .typename = "Amiga ",
+ .enable = amiga_enable_irq,
+ .disable = amiga_disable_irq,
+};
+
+#define HARDWARE_MAPPED_SIZE (512*1024)
+unsigned long __init apus_find_end_of_memory(void)
+{
+ int shadow = 0;
+ unsigned long total;
+
+ /* The memory size reported by ADOS excludes the 512KB
+ reserved for PPC exception registers and possibly 512KB
+ containing a shadow of the ADOS ROM. */
+ {
+ unsigned long size = memory[0].size;
+
+ /* If 2MB aligned, size was probably user
+ specified. We can't tell anything about shadowing
+ in this case so skip shadow assignment. */
+ if (0 != (size & 0x1fffff)){
+ /* Align to 512KB to ensure correct handling
+ of both memfile and system specified
+ sizes. */
+ size = ((size+0x0007ffff) & 0xfff80000);
+ /* If memory is 1MB aligned, assume
+ shadowing. */
+ shadow = !(size & 0x80000);
+ }
+
+ /* Add the chunk that ADOS does not see. by aligning
+ the size to the nearest 2MB limit upwards. */
+ memory[0].size = ((size+0x001fffff) & 0xffe00000);
+ }
+
+ ppc_memstart = memory[0].addr;
+ ppc_memoffset = PAGE_OFFSET - PPC_MEMSTART;
+ total = memory[0].size;
+
+ /* Remove the memory chunks that are controlled by special
+ Phase5 hardware. */
+
+ /* Remove the upper 512KB if it contains a shadow of
+ the ADOS ROM. FIXME: It might be possible to
+ disable this shadow HW. Check the booter
+ (ppc_boot.c) */
+ if (shadow)
+ total -= HARDWARE_MAPPED_SIZE;
+
+ /* Remove the upper 512KB where the PPC exception
+ vectors are mapped. */
+ total -= HARDWARE_MAPPED_SIZE;
+
+ /* Linux/APUS only handles one block of memory -- the one on
+ the PowerUP board. Other system memory is horrible slow in
+ comparison. The user can use other memory for swapping
+ using the z2ram device. */
+ return total;
+}
+
+static void __init
+apus_map_io(void)
+{
+ /* Map PPC exception vectors. */
+ io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL);
+ /* Map chip and ZorroII memory */
+ io_block_mapping(zTwoBase, 0x00000000, 0x01000000, _PAGE_IO);
+}
+
+__init
+void apus_init_IRQ(void)
+{
+ struct irqaction *action;
+ int i;
+
+#ifdef CONFIG_PCI
+ apus_setup_pci_ptrs();
+#endif
+
+ for ( i = 0 ; i < AMI_IRQS; i++ ) {
+ irq_desc[i].status = IRQ_LEVEL;
+ if (i < IRQ_AMIGA_AUTO) {
+ irq_desc[i].handler = &amiga_irqctrl;
+ } else {
+ irq_desc[i].handler = &amiga_sys_irqctrl;
+ action = &amiga_sys_irqaction[i-IRQ_AMIGA_AUTO];
+ if (action->name)
+ setup_irq(i, action);
+ }
+ }
+
+ amiga_init_IRQ();
+
+}
+
+__init
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ extern int parse_bootinfo(const struct bi_record *);
+ extern char _end[];
+
+ /* Parse bootinfo. The bootinfo is located right after
+ the kernel bss */
+ parse_bootinfo((const struct bi_record *)&_end);
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* Take care of initrd if we have one. Use data from
+ bootinfo to avoid the need to initialize PPC
+ registers when kernel is booted via a PPC reset. */
+ if ( ramdisk.addr ) {
+ initrd_start = (unsigned long) __va(ramdisk.addr);
+ initrd_end = (unsigned long)
+ __va(ramdisk.size + ramdisk.addr);
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+
+ ppc_md.setup_arch = apus_setup_arch;
+ ppc_md.show_cpuinfo = apus_show_cpuinfo;
+ ppc_md.init_IRQ = apus_init_IRQ;
+ ppc_md.get_irq = apus_get_irq;
+
+#ifdef CONFIG_HEARTBEAT
+ ppc_md.heartbeat = apus_heartbeat;
+ ppc_md.heartbeat_count = 1;
+#endif
+#ifdef APUS_DEBUG
+ __debug_serinit();
+ ppc_md.progress = apus_progress;
+#endif
+ ppc_md.init = NULL;
+
+ ppc_md.restart = apus_restart;
+ ppc_md.power_off = apus_power_off;
+ ppc_md.halt = apus_halt;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = apus_set_rtc_time;
+ ppc_md.get_rtc_time = apus_get_rtc_time;
+ ppc_md.calibrate_decr = apus_calibrate_decr;
+
+ ppc_md.find_end_of_memory = apus_find_end_of_memory;
+ ppc_md.setup_io_mappings = apus_map_io;
+}
diff --git a/arch/ppc/platforms/bseip.h b/arch/ppc/platforms/bseip.h
new file mode 100644
index 00000000000..691f4a52b0a
--- /dev/null
+++ b/arch/ppc/platforms/bseip.h
@@ -0,0 +1,38 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Bright Star Engineering ip-Engine board. Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_BSEIP_DEFS
+#define __MACH_BSEIP_DEFS
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+ unsigned int bi_memstart; /* Memory start address */
+ unsigned int bi_memsize; /* Memory (end) size in bytes */
+ unsigned int bi_intfreq; /* Internal Freq, in Hz */
+ unsigned int bi_busfreq; /* Bus Freq, in Hz */
+ unsigned char bi_enetaddr[6];
+ unsigned int bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * All we need to get started is the IMMR.
+ */
+#define IMAP_ADDR ((uint)0xff000000)
+#define IMAP_SIZE ((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR ((uint)0x04000000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
+#endif /* !__ASSEMBLY__ */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif
diff --git a/arch/ppc/platforms/ccm.h b/arch/ppc/platforms/ccm.h
new file mode 100644
index 00000000000..edb87b57383
--- /dev/null
+++ b/arch/ppc/platforms/ccm.h
@@ -0,0 +1,28 @@
+/*
+ * Siemens Card Controller Module specific definitions
+ *
+ * Copyright (C) 2001-2002 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifndef __MACH_CCM_H
+#define __MACH_CCM_H
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define CCM_IMMR_BASE 0xF0000000 /* phys. addr of IMMR */
+#define CCM_IMAP_SIZE (64 * 1024) /* size of mapped area */
+
+#define IMAP_ADDR CCM_IMMR_BASE /* physical base address of IMMR area */
+#define IMAP_SIZE CCM_IMAP_SIZE /* mapped size of IMMR area */
+
+#define FEC_INTERRUPT 13 /* = SIU_LEVEL6 */
+#define DEC_INTERRUPT 11 /* = SIU_LEVEL5 */
+#define CPM_INTERRUPT 9 /* = SIU_LEVEL4 */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif /* __MACH_CCM_H */
diff --git a/arch/ppc/platforms/chestnut.c b/arch/ppc/platforms/chestnut.c
new file mode 100644
index 00000000000..7786818bd9d
--- /dev/null
+++ b/arch/ppc/platforms/chestnut.c
@@ -0,0 +1,580 @@
+/*
+ * arch/ppc/platforms/chestnut.c
+ *
+ * Board setup routines for IBM Chestnut
+ *
+ * Author: <source@mvista.com>
+ *
+ * <2004> (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/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/console.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/ide.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/mtd/physmap.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <linux/irq.h>
+#include <asm/hw_irq.h>
+#include <asm/machdep.h>
+#include <asm/kgdb.h>
+#include <asm/bootinfo.h>
+#include <asm/mv64x60.h>
+#include <platforms/chestnut.h>
+
+static void __iomem *sram_base; /* Virtual addr of Internal SRAM */
+static void __iomem *cpld_base; /* Virtual addr of CPLD Regs */
+
+static mv64x60_handle_t bh;
+
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct uart_port *);
+extern void mv64360_pcibios_fixup(mv64x60_handle_t *bh);
+
+#define BIT(x) (1<<x)
+#define CHESTNUT_PRESERVE_MASK (BIT(MV64x60_CPU2DEV_0_WIN) | \
+ BIT(MV64x60_CPU2DEV_1_WIN) | \
+ BIT(MV64x60_CPU2DEV_2_WIN) | \
+ BIT(MV64x60_CPU2DEV_3_WIN) | \
+ BIT(MV64x60_CPU2BOOT_WIN))
+/**************************************************************************
+ * FUNCTION: chestnut_calibrate_decr
+ *
+ * DESCRIPTION: initialize decrementer interrupt frequency (used as system
+ * timer)
+ *
+ ****/
+static void __init
+chestnut_calibrate_decr(void)
+{
+ ulong freq;
+
+ freq = CHESTNUT_BUS_SPEED / 4;
+
+ printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ freq/1000000, freq%1000000);
+
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
+
+static int
+chestnut_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: IBM\n");
+ seq_printf(m, "machine\t\t: 750FX/GX Eval Board (Chestnut/Buckeye)\n");
+
+ return 0;
+}
+
+/**************************************************************************
+ * FUNCTION: chestnut_find_end_of_memory
+ *
+ * DESCRIPTION: ppc_md memory size callback
+ *
+ ****/
+unsigned long __init
+chestnut_find_end_of_memory(void)
+{
+ static int mem_size = 0;
+
+ if (mem_size == 0) {
+ mem_size = mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
+ MV64x60_TYPE_MV64460);
+ }
+ return mem_size;
+}
+
+#if defined(CONFIG_SERIAL_8250)
+static void __init
+chestnut_early_serial_map(void)
+{
+ struct uart_port port;
+
+ /* Setup serial port access */
+ memset(&port, 0, sizeof(port));
+ port.uartclk = BASE_BAUD * 16;
+ port.irq = UART0_INT;
+ port.flags = STD_COM_FLAGS | UPF_IOREMAP;
+ port.iotype = SERIAL_IO_MEM;
+ port.mapbase = CHESTNUT_UART0_IO_BASE;
+ port.regshift = 0;
+
+ if (early_serial_setup(&port) != 0)
+ printk("Early serial init of port 0 failed\n");
+
+ /* Assume early_serial_setup() doesn't modify serial_req */
+ port.line = 1;
+ port.irq = UART1_INT;
+ port.mapbase = CHESTNUT_UART1_IO_BASE;
+
+ if (early_serial_setup(&port) != 0)
+ printk("Early serial init of port 1 failed\n");
+}
+#endif
+
+/**************************************************************************
+ * FUNCTION: chestnut_map_irq
+ *
+ * DESCRIPTION: 0 return since PCI IRQs not needed
+ *
+ ****/
+static int __init
+chestnut_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] = {
+ {CHESTNUT_PCI_SLOT0_IRQ, CHESTNUT_PCI_SLOT0_IRQ,
+ CHESTNUT_PCI_SLOT0_IRQ, CHESTNUT_PCI_SLOT0_IRQ},
+ {CHESTNUT_PCI_SLOT1_IRQ, CHESTNUT_PCI_SLOT1_IRQ,
+ CHESTNUT_PCI_SLOT1_IRQ, CHESTNUT_PCI_SLOT1_IRQ},
+ {CHESTNUT_PCI_SLOT2_IRQ, CHESTNUT_PCI_SLOT2_IRQ,
+ CHESTNUT_PCI_SLOT2_IRQ, CHESTNUT_PCI_SLOT2_IRQ},
+ {CHESTNUT_PCI_SLOT3_IRQ, CHESTNUT_PCI_SLOT3_IRQ,
+ CHESTNUT_PCI_SLOT3_IRQ, CHESTNUT_PCI_SLOT3_IRQ},
+ };
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+
+/**************************************************************************
+ * FUNCTION: chestnut_setup_bridge
+ *
+ * DESCRIPTION: initalize board-specific settings on the MV64360
+ *
+ ****/
+static void __init
+chestnut_setup_bridge(void)
+{
+ struct mv64x60_setup_info si;
+ int i;
+
+ if ( ppc_md.progress )
+ ppc_md.progress("chestnut_setup_bridge: enter", 0);
+
+ memset(&si, 0, sizeof(si));
+
+ si.phys_reg_base = CONFIG_MV64X60_NEW_BASE;
+
+ /* setup only PCI bus 0 (bus 1 not used) */
+ si.pci_0.enable_bus = 1;
+ si.pci_0.pci_io.cpu_base = CHESTNUT_PCI0_IO_PROC_ADDR;
+ si.pci_0.pci_io.pci_base_hi = 0;
+ si.pci_0.pci_io.pci_base_lo = CHESTNUT_PCI0_IO_PCI_ADDR;
+ si.pci_0.pci_io.size = CHESTNUT_PCI0_IO_SIZE;
+ si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE; /* no swapping */
+ si.pci_0.pci_mem[0].cpu_base = CHESTNUT_PCI0_MEM_PROC_ADDR;
+ si.pci_0.pci_mem[0].pci_base_hi = CHESTNUT_PCI0_MEM_PCI_HI_ADDR;
+ si.pci_0.pci_mem[0].pci_base_lo = CHESTNUT_PCI0_MEM_PCI_LO_ADDR;
+ si.pci_0.pci_mem[0].size = CHESTNUT_PCI0_MEM_SIZE;
+ si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE; /* no swapping */
+ si.pci_0.pci_cmd_bits = 0;
+ si.pci_0.latency_timer = 0x80;
+
+ for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ si.cpu_prot_options[i] = 0;
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+#else
+ si.cpu_prot_options[i] = 0;
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_WB |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+#endif
+ }
+
+ /* Lookup host bridge - on CPU 0 - no SMP support */
+ if (mv64x60_init(&bh, &si)) {
+ printk("\n\nPCI Bridge initialization failed!\n");
+ }
+
+ pci_dram_offset = 0;
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = chestnut_map_irq;
+ ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
+
+ mv64x60_set_bus(&bh, 0, 0);
+ bh.hose_a->first_busno = 0;
+ bh.hose_a->last_busno = 0xff;
+ bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0);
+}
+
+void __init
+chestnut_setup_peripherals(void)
+{
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+ CHESTNUT_BOOT_8BIT_BASE, CHESTNUT_BOOT_8BIT_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN,
+ CHESTNUT_32BIT_BASE, CHESTNUT_32BIT_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
+ CHESTNUT_CPLD_BASE, CHESTNUT_CPLD_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+ cpld_base = ioremap(CHESTNUT_CPLD_BASE, CHESTNUT_CPLD_SIZE);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN,
+ CHESTNUT_UART_BASE, CHESTNUT_UART_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN,
+ CHESTNUT_FRAM_BASE, CHESTNUT_FRAM_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+ CHESTNUT_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+
+#ifdef CONFIG_NOT_COHERENT_CACHE
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b0);
+#else
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2);
+#endif
+ sram_base = ioremap(CHESTNUT_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE);
+ memset(sram_base, 0, MV64360_SRAM_SIZE);
+
+ /*
+ * Configure MPP pins for PCI DMA
+ *
+ * PCI Slot GNT pin REQ pin
+ * 0 MPP16 MPP17
+ * 1 MPP18 MPP19
+ * 2 MPP20 MPP21
+ * 3 MPP22 MPP23
+ */
+ mv64x60_write(&bh, MV64x60_MPP_CNTL_2,
+ (0x1 << 0) | /* MPPSel16 PCI0_GNT[0] */
+ (0x1 << 4) | /* MPPSel17 PCI0_REQ[0] */
+ (0x1 << 8) | /* MPPSel18 PCI0_GNT[1] */
+ (0x1 << 12) | /* MPPSel19 PCI0_REQ[1] */
+ (0x1 << 16) | /* MPPSel20 PCI0_GNT[2] */
+ (0x1 << 20) | /* MPPSel21 PCI0_REQ[2] */
+ (0x1 << 24) | /* MPPSel22 PCI0_GNT[3] */
+ (0x1 << 28)); /* MPPSel23 PCI0_REQ[3] */
+ /*
+ * Set unused MPP pins for output, as per schematic note
+ *
+ * Unused Pins: MPP01, MPP02, MPP04, MPP05, MPP06
+ * MPP09, MPP10, MPP13, MPP14, MPP15
+ */
+ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_0,
+ (0xf << 4) | /* MPPSel01 GPIO[1] */
+ (0xf << 8) | /* MPPSel02 GPIO[2] */
+ (0xf << 16) | /* MPPSel04 GPIO[4] */
+ (0xf << 20) | /* MPPSel05 GPIO[5] */
+ (0xf << 24)); /* MPPSel06 GPIO[6] */
+ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1,
+ (0xf << 4) | /* MPPSel09 GPIO[9] */
+ (0xf << 8) | /* MPPSel10 GPIO[10] */
+ (0xf << 20) | /* MPPSel13 GPIO[13] */
+ (0xf << 24) | /* MPPSel14 GPIO[14] */
+ (0xf << 28)); /* MPPSel15 GPIO[15] */
+ mv64x60_set_bits(&bh, MV64x60_GPP_IO_CNTL, /* Output */
+ BIT(1) | BIT(2) | BIT(4) | BIT(5) | BIT(6) |
+ BIT(9) | BIT(10) | BIT(13) | BIT(14) | BIT(15));
+
+ /*
+ * Configure the following MPP pins to indicate a level
+ * triggered interrupt
+ *
+ * MPP24 - Board Reset (just map the MPP & GPP for chestnut_reset)
+ * MPP25 - UART A (high)
+ * MPP26 - UART B (high)
+ * MPP28 - PCI Slot 3 (low)
+ * MPP29 - PCI Slot 2 (low)
+ * MPP30 - PCI Slot 1 (low)
+ * MPP31 - PCI Slot 0 (low)
+ */
+ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_3,
+ BIT(3) | BIT(2) | BIT(1) | BIT(0) | /* MPP 24 */
+ BIT(7) | BIT(6) | BIT(5) | BIT(4) | /* MPP 25 */
+ BIT(11) | BIT(10) | BIT(9) | BIT(8) | /* MPP 26 */
+ BIT(19) | BIT(18) | BIT(17) | BIT(16) | /* MPP 28 */
+ BIT(23) | BIT(22) | BIT(21) | BIT(20) | /* MPP 29 */
+ BIT(27) | BIT(26) | BIT(25) | BIT(24) | /* MPP 30 */
+ BIT(31) | BIT(30) | BIT(29) | BIT(28)); /* MPP 31 */
+
+ /*
+ * Define GPP 25 (high), 26 (high), 28 (low), 29 (low), 30 (low),
+ * 31 (low) interrupt polarity input signal and level triggered
+ */
+ mv64x60_clr_bits(&bh, MV64x60_GPP_LEVEL_CNTL, BIT(25) | BIT(26));
+ mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL,
+ BIT(28) | BIT(29) | BIT(30) | BIT(31));
+ mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL,
+ BIT(25) | BIT(26) | BIT(28) | BIT(29) | BIT(30) |
+ BIT(31));
+
+ /* Config GPP interrupt controller to respond to level trigger */
+ mv64x60_set_bits(&bh, MV64360_COMM_ARBITER_CNTL, BIT(10));
+
+ /*
+ * Dismiss and then enable interrupt on GPP interrupt cause for CPU #0
+ */
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE,
+ ~(BIT(25) | BIT(26) | BIT(28) | BIT(29) | BIT(30) |
+ BIT(31)));
+ mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK,
+ BIT(25) | BIT(26) | BIT(28) | BIT(29) | BIT(30) |
+ BIT(31));
+
+ /*
+ * Dismiss and then enable interrupt on CPU #0 high cause register
+ * BIT27 summarizes GPP interrupts 24-31
+ */
+ mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, BIT(27));
+
+ if (ppc_md.progress)
+ ppc_md.progress("chestnut_setup_bridge: exit", 0);
+}
+
+/**************************************************************************
+ * FUNCTION: chestnut_setup_arch
+ *
+ * DESCRIPTION: ppc_md machine configuration callback
+ *
+ ****/
+static void __init
+chestnut_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("chestnut_setup_arch: enter", 0);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000 / HZ;
+
+ /* if the time base value is greater than bus freq/4 (the TB and
+ * decrementer tick rate) + signed integer rollover value, we
+ * can spend a fair amount of time waiting for the rollover to
+ * happen. To get around this, initialize the time base register
+ * to a "safe" value.
+ */
+ set_tb(0, 0);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ /*
+ * Set up the L2CR register.
+ */
+ _set_L2CR(_get_L2CR() | L2CR_L2E);
+
+ chestnut_setup_bridge();
+ chestnut_setup_peripherals();
+
+#ifdef CONFIG_DUMMY_CONSOLE
+ conswitchp = &dummy_con;
+#endif
+
+#if defined(CONFIG_SERIAL_8250)
+ chestnut_early_serial_map();
+#endif
+
+ /* Identify the system */
+ printk(KERN_INFO "System Identification: IBM 750FX/GX Eval Board\n");
+ printk(KERN_INFO "IBM 750FX/GX port (C) 2004 MontaVista Software, Inc."
+ " (source@mvista.com)\n");
+
+ if (ppc_md.progress)
+ ppc_md.progress("chestnut_setup_arch: exit", 0);
+}
+
+#ifdef CONFIG_MTD_PHYSMAP
+static struct mtd_partition ptbl;
+
+static int __init
+chestnut_setup_mtd(void)
+{
+ memset(&ptbl, 0, sizeof(ptbl));
+
+ ptbl.name = "User FS";
+ ptbl.size = CHESTNUT_32BIT_SIZE;
+
+ physmap_map.size = CHESTNUT_32BIT_SIZE;
+ physmap_set_partitions(&ptbl, 1);
+ return 0;
+}
+
+arch_initcall(chestnut_setup_mtd);
+#endif
+
+/**************************************************************************
+ * FUNCTION: chestnut_restart
+ *
+ * DESCRIPTION: ppc_md machine reset callback
+ * reset the board via the CPLD command register
+ *
+ ****/
+static void
+chestnut_restart(char *cmd)
+{
+ volatile ulong i = 10000000;
+
+ local_irq_disable();
+
+ /*
+ * Set CPLD Reg 3 bit 0 to 1 to allow MPP signals on reset to work
+ *
+ * MPP24 - board reset
+ */
+ writeb(0x1, cpld_base + 3);
+
+ /* GPP pin tied to MPP earlier */
+ mv64x60_set_bits(&bh, MV64x60_GPP_VALUE_SET, BIT(24));
+
+ while (i-- > 0);
+ panic("restart failed\n");
+}
+
+static void
+chestnut_halt(void)
+{
+ local_irq_disable();
+ for (;;);
+ /* NOTREACHED */
+}
+
+static void
+chestnut_power_off(void)
+{
+ chestnut_halt();
+ /* NOTREACHED */
+}
+
+/**************************************************************************
+ * FUNCTION: chestnut_map_io
+ *
+ * DESCRIPTION: configure fixed memory-mapped IO
+ *
+ ****/
+static void __init
+chestnut_map_io(void)
+{
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ io_block_mapping(CHESTNUT_UART_BASE, CHESTNUT_UART_BASE, 0x100000,
+ _PAGE_IO);
+#endif
+}
+
+/**************************************************************************
+ * FUNCTION: chestnut_set_bat
+ *
+ * DESCRIPTION: configures a (temporary) bat mapping for early access to
+ * device I/O
+ *
+ ****/
+static __inline__ void
+chestnut_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT3U, 0xf0001ffe);
+ mtspr(SPRN_DBAT3L, 0xf000002a);
+ mb();
+}
+
+/**************************************************************************
+ * FUNCTION: platform_init
+ *
+ * DESCRIPTION: main entry point for configuring board-specific machine
+ * callbacks
+ *
+ ****/
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /* Copy the kernel command line arguments to a safe place. */
+
+ if (r6) {
+ *(char *) (r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+ }
+
+ isa_mem_base = 0;
+
+ ppc_md.setup_arch = chestnut_setup_arch;
+ ppc_md.show_cpuinfo = chestnut_show_cpuinfo;
+ ppc_md.irq_canonicalize = NULL;
+ ppc_md.init_IRQ = mv64360_init_irq;
+ ppc_md.get_irq = mv64360_get_irq;
+ ppc_md.init = NULL;
+
+ ppc_md.find_end_of_memory = chestnut_find_end_of_memory;
+ ppc_md.setup_io_mappings = chestnut_map_io;
+
+ ppc_md.restart = chestnut_restart;
+ ppc_md.power_off = chestnut_power_off;
+ ppc_md.halt = chestnut_halt;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.calibrate_decr = chestnut_calibrate_decr;
+
+ ppc_md.nvram_read_val = NULL;
+ ppc_md.nvram_write_val = NULL;
+
+ ppc_md.heartbeat = NULL;
+
+ bh.p_base = CONFIG_MV64X60_NEW_BASE;
+
+ chestnut_set_bat();
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG)
+ ppc_md.progress = gen550_progress;
+#endif
+#if defined(CONFIG_KGDB)
+ ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
+#endif
+
+ if (ppc_md.progress)
+ ppc_md.progress("chestnut_init(): exit", 0);
+}
diff --git a/arch/ppc/platforms/chestnut.h b/arch/ppc/platforms/chestnut.h
new file mode 100644
index 00000000000..0400b2be40a
--- /dev/null
+++ b/arch/ppc/platforms/chestnut.h
@@ -0,0 +1,129 @@
+/*
+ * arch/ppc/platforms/chestnut.h
+ *
+ * Definitions for IBM 750FXGX Eval (Chestnut)
+ *
+ * Author: <source@mvista.com>
+ *
+ * Based on Artesyn Katana code done by Tim Montgomery <timm@artesyncp.com>
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by Mark A. Greer <mgreer@mvista.com>
+ *
+ * <2004> (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.
+ */
+
+/*
+ * This is the CPU physical memory map (windows must be at least 1MB and start
+ * on a boundary that is a multiple of the window size):
+ *
+ * Seems on the IBM 750FXGX Eval board, the MV64460 Registers can be in
+ * only 2 places per switch U17 0x14000000 or 0xf1000000 easily - chose to
+ * implement at 0xf1000000 only at this time
+ *
+ * 0xfff00000-0xffffffff - 8 Flash
+ * 0xffe00000-0xffefffff - BOOT SRAM
+ * 0xffd00000-0xffd00004 - CPLD
+ * 0xffc00000-0xffc0000f - UART
+ * 0xffb00000-0xffb07fff - FRAM
+ * 0xff840000-0xffafffff - *** HOLE ***
+ * 0xff800000-0xff83ffff - MV64460 Integrated SRAM
+ * 0xfe000000-0xff8fffff - *** HOLE ***
+ * 0xfc000000-0xfdffffff - 32bit Flash
+ * 0xf1010000-0xfbffffff - *** HOLE ***
+ * 0xf1000000-0xf100ffff - MV64460 Registers
+ */
+
+#ifndef __PPC_PLATFORMS_CHESTNUT_H__
+#define __PPC_PLATFORMS_CHESTNUT_H__
+
+#define CHESTNUT_BOOT_8BIT_BASE 0xfff00000
+#define CHESTNUT_BOOT_8BIT_SIZE_ACTUAL (1024*1024)
+#define CHESTNUT_BOOT_SRAM_BASE 0xffe00000
+#define CHESTNUT_BOOT_SRAM_SIZE_ACTUAL (1024*1024)
+#define CHESTNUT_CPLD_BASE 0xffd00000
+#define CHESTNUT_CPLD_SIZE_ACTUAL 5
+#define CHESTNUT_CPLD_REG3 (CHESTNUT_CPLD_BASE+3)
+#define CHESTNUT_UART_BASE 0xffc00000
+#define CHESTNUT_UART_SIZE_ACTUAL 16
+#define CHESTNUT_FRAM_BASE 0xffb00000
+#define CHESTNUT_FRAM_SIZE_ACTUAL (32*1024)
+#define CHESTNUT_INTERNAL_SRAM_BASE 0xff800000
+#define CHESTNUT_32BIT_BASE 0xfc000000
+#define CHESTNUT_32BIT_SIZE (32*1024*1024)
+
+#define CHESTNUT_BOOT_8BIT_SIZE max(MV64360_WINDOW_SIZE_MIN, \
+ CHESTNUT_BOOT_8BIT_SIZE_ACTUAL)
+#define CHESTNUT_BOOT_SRAM_SIZE max(MV64360_WINDOW_SIZE_MIN, \
+ CHESTNUT_BOOT_SRAM_SIZE_ACTUAL)
+#define CHESTNUT_CPLD_SIZE max(MV64360_WINDOW_SIZE_MIN, \
+ CHESTNUT_CPLD_SIZE_ACTUAL)
+#define CHESTNUT_UART_SIZE max(MV64360_WINDOW_SIZE_MIN, \
+ CHESTNUT_UART_SIZE_ACTUAL)
+#define CHESTNUT_FRAM_SIZE max(MV64360_WINDOW_SIZE_MIN, \
+ CHESTNUT_FRAM_SIZE_ACTUAL)
+
+#define CHESTNUT_BUS_SPEED 200000000
+#define CHESTNUT_PIBS_DATABASE 0xf0000 /* from PIBS src code */
+
+#define KATANA_ETH0_PHY_ADDR 12
+#define KATANA_ETH1_PHY_ADDR 11
+#define KATANA_ETH2_PHY_ADDR 4
+
+#define CHESTNUT_ETH_TX_QUEUE_SIZE 800
+#define CHESTNUT_ETH_RX_QUEUE_SIZE 400
+
+/*
+ * PCI windows
+ */
+
+#define CHESTNUT_PCI0_MEM_PROC_ADDR 0x80000000
+#define CHESTNUT_PCI0_MEM_PCI_HI_ADDR 0x00000000
+#define CHESTNUT_PCI0_MEM_PCI_LO_ADDR 0x80000000
+#define CHESTNUT_PCI0_MEM_SIZE 0x10000000
+#define CHESTNUT_PCI0_IO_PROC_ADDR 0xa0000000
+#define CHESTNUT_PCI0_IO_PCI_ADDR 0x00000000
+#define CHESTNUT_PCI0_IO_SIZE 0x01000000
+
+/*
+ * Board-specific IRQ info
+ */
+#define CHESTNUT_PCI_SLOT0_IRQ (64 + 31)
+#define CHESTNUT_PCI_SLOT1_IRQ (64 + 30)
+#define CHESTNUT_PCI_SLOT2_IRQ (64 + 29)
+#define CHESTNUT_PCI_SLOT3_IRQ (64 + 28)
+
+/* serial port definitions */
+#define CHESTNUT_UART0_IO_BASE (CHESTNUT_UART_BASE + 8)
+#define CHESTNUT_UART1_IO_BASE CHESTNUT_UART_BASE
+
+#define UART0_INT (64 + 25)
+#define UART1_INT (64 + 26)
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE 64
+#else
+#define RS_TABLE_SIZE 2
+#endif
+
+/* Rate for the 3.6864 Mhz clock for the onboard serial chip */
+#define BASE_BAUD (3686400 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#endif
+
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, STD_COM_FLAGS, \
+ iomem_base: (u8 *)CHESTNUT_UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+
+#endif /* __PPC_PLATFORMS_CHESTNUT_H__ */
diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c
new file mode 100644
index 00000000000..5bb6492ecf8
--- /dev/null
+++ b/arch/ppc/platforms/chrp_pci.c
@@ -0,0 +1,309 @@
+/*
+ * CHRP pci routines.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#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>
+#include <asm/open_pic.h>
+
+/* LongTrail */
+void __iomem *gg2_pci_config_base;
+
+/*
+ * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
+ * limit the bus number to 3 bits
+ */
+
+int __chrp gg2_read_config(struct pci_bus *bus, unsigned int devfn, int off,
+ int len, u32 *val)
+{
+ volatile void __iomem *cfg_data;
+ struct pci_controller *hose = bus->sysdata;
+
+ if (bus->number > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that off is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off);
+ switch (len) {
+ case 1:
+ *val = in_8(cfg_data);
+ break;
+ case 2:
+ *val = in_le16(cfg_data);
+ break;
+ default:
+ *val = in_le32(cfg_data);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int __chrp gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off,
+ int len, u32 val)
+{
+ volatile void __iomem *cfg_data;
+ struct pci_controller *hose = bus->sysdata;
+
+ if (bus->number > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that off is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off);
+ switch (len) {
+ case 1:
+ out_8(cfg_data, val);
+ break;
+ case 2:
+ out_le16(cfg_data, val);
+ break;
+ default:
+ out_le32(cfg_data, val);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops gg2_pci_ops =
+{
+ gg2_read_config,
+ gg2_write_config
+};
+
+/*
+ * Access functions for PCI config space using RTAS calls.
+ */
+int __chrp
+rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 *val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
+ | (((bus->number - hose->first_busno) & 0xff) << 16)
+ | (hose->index << 24);
+ unsigned long ret = ~0UL;
+ int rval;
+
+ rval = call_rtas("read-pci-config", 2, 2, &ret, addr, len);
+ *val = ret;
+ return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;
+}
+
+int __chrp
+rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
+ | (((bus->number - hose->first_busno) & 0xff) << 16)
+ | (hose->index << 24);
+ int rval;
+
+ rval = call_rtas("write-pci-config", 3, 1, NULL, addr, len, val);
+ return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops rtas_pci_ops =
+{
+ rtas_read_config,
+ rtas_write_config
+};
+
+volatile struct Hydra *Hydra = NULL;
+
+int __init
+hydra_init(void)
+{
+ struct device_node *np;
+
+ np = find_devices("mac-io");
+ if (np == NULL || np->n_addrs == 0)
+ return 0;
+ Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
+ printk("Hydra Mac I/O at %x\n", np->addrs[0].address);
+ printk("Hydra Feature_Control was %x",
+ in_le32(&Hydra->Feature_Control));
+ out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
+ HYDRA_FC_SCSI_CELL_EN |
+ HYDRA_FC_SCCA_ENABLE |
+ HYDRA_FC_SCCB_ENABLE |
+ HYDRA_FC_ARB_BYPASS |
+ HYDRA_FC_MPIC_ENABLE |
+ HYDRA_FC_SLOW_SCC_PCLK |
+ HYDRA_FC_MPIC_IS_MASTER));
+ printk(", now %x\n", in_le32(&Hydra->Feature_Control));
+ return 1;
+}
+
+void __init
+chrp_pcibios_fixup(void)
+{
+ struct pci_dev *dev = NULL;
+ struct device_node *np;
+
+ /* PCI interrupts are controlled by the OpenPIC */
+ for_each_pci_dev(dev) {
+ np = pci_device_to_OF_node(dev);
+ if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0))
+ dev->irq = np->intrs[0].line;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ }
+}
+
+#define PRG_CL_RESET_VALID 0x00010000
+
+static void __init
+setup_python(struct pci_controller *hose, struct device_node *dev)
+{
+ u32 *reg, val;
+ unsigned long addr = dev->addrs[0].address;
+
+ setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010);
+
+ /* Clear the magic go-slow bit */
+ reg = (u32 *) ioremap(dev->addrs[0].address + 0xf6000, 0x40);
+ val = in_be32(&reg[12]);
+ if (val & PRG_CL_RESET_VALID) {
+ out_be32(&reg[12], val & ~PRG_CL_RESET_VALID);
+ in_be32(&reg[12]);
+ }
+ iounmap(reg);
+}
+
+/* Marvell Discovery II based Pegasos 2 */
+static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev)
+{
+ struct device_node *root = find_path_device("/");
+ struct device_node *rtas;
+
+ rtas = of_find_node_by_name (root, "rtas");
+ if (rtas) {
+ hose->ops = &rtas_pci_ops;
+ } else {
+ printk ("RTAS supporting Pegasos OF not found, please upgrade"
+ " your firmware\n");
+ }
+ pci_assign_all_busses = 1;
+}
+
+void __init
+chrp_find_bridges(void)
+{
+ struct device_node *dev;
+ int *bus_range;
+ int len, index = -1;
+ struct pci_controller *hose;
+ unsigned int *dma;
+ char *model, *machine;
+ int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
+ struct device_node *root = find_path_device("/");
+
+ /*
+ * The PCI host bridge nodes on some machines don't have
+ * properties to adequately identify them, so we have to
+ * look at what sort of machine this is as well.
+ */
+ machine = get_property(root, "model", NULL);
+ if (machine != NULL) {
+ is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
+ is_mot = strncmp(machine, "MOT", 3) == 0;
+ if (strncmp(machine, "Pegasos2", 8) == 0)
+ is_pegasos = 2;
+ else if (strncmp(machine, "Pegasos", 7) == 0)
+ is_pegasos = 1;
+ }
+ for (dev = root->child; dev != NULL; dev = dev->sibling) {
+ if (dev->type == NULL || strcmp(dev->type, "pci") != 0)
+ continue;
+ ++index;
+ /* The GG2 bridge on the LongTrail doesn't have an address */
+ if (dev->n_addrs < 1 && !is_longtrail) {
+ printk(KERN_WARNING "Can't use %s: no address\n",
+ dev->full_name);
+ continue;
+ }
+ bus_range = (int *) get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ dev->full_name);
+ continue;
+ }
+ if (bus_range[1] == bus_range[0])
+ printk(KERN_INFO "PCI bus %d", bus_range[0]);
+ else
+ printk(KERN_INFO "PCI buses %d..%d",
+ bus_range[0], bus_range[1]);
+ printk(" controlled by %s", dev->type);
+ if (dev->n_addrs > 0)
+ printk(" at %x", dev->addrs[0].address);
+ printk("\n");
+
+ hose = pcibios_alloc_controller();
+ if (!hose) {
+ printk("Can't allocate PCI controller structure for %s\n",
+ dev->full_name);
+ continue;
+ }
+ hose->arch_data = dev;
+ hose->first_busno = bus_range[0];
+ hose->last_busno = bus_range[1];
+
+ model = get_property(dev, "model", NULL);
+ if (model == NULL)
+ model = "<none>";
+ if (device_is_compatible(dev, "IBM,python")) {
+ setup_python(hose, dev);
+ } else if (is_mot
+ || strncmp(model, "Motorola, Grackle", 17) == 0) {
+ setup_grackle(hose);
+ } else if (is_longtrail) {
+ void __iomem *p = ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
+ hose->ops = &gg2_pci_ops;
+ hose->cfg_data = p;
+ gg2_pci_config_base = p;
+ } else if (is_pegasos == 1) {
+ setup_indirect_pci(hose, 0xfec00cf8, 0xfee00cfc);
+ } else if (is_pegasos == 2) {
+ setup_peg2(hose, dev);
+ } else {
+ printk("No methods for %s (model %s), using RTAS\n",
+ dev->full_name, model);
+ hose->ops = &rtas_pci_ops;
+ }
+
+ pci_process_bridge_OF_ranges(hose, dev, index == 0);
+
+ /* check the first bridge for a property that we can
+ use to set pci_dram_offset */
+ dma = (unsigned int *)
+ get_property(dev, "ibm,dma-ranges", &len);
+ if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
+ pci_dram_offset = dma[2] - dma[3];
+ printk("pci_dram_offset = %lx\n", pci_dram_offset);
+ }
+ }
+
+ /* Do not fixup interrupts from OF tree on pegasos */
+ if (is_pegasos == 0)
+ ppc_md.pcibios_fixup = chrp_pcibios_fixup;
+}
diff --git a/arch/ppc/platforms/chrp_pegasos_eth.c b/arch/ppc/platforms/chrp_pegasos_eth.c
new file mode 100644
index 00000000000..cad5bfa153b
--- /dev/null
+++ b/arch/ppc/platforms/chrp_pegasos_eth.c
@@ -0,0 +1,101 @@
+/*
+ * arch/ppc/platforms/chrp_pegasos_eth.c
+ *
+ * Copyright (C) 2005 Sven Luther <sl@bplan-gmbh.de>
+ * Thanks to :
+ * Dale Farnsworth <dale@farnsworth.org>
+ * Mark A. Greer <mgreer@mvista.com>
+ * Nicolas DET <nd@bplan-gmbh.de>
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * And anyone else who helped me on this.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/mv643xx.h>
+#include <linux/pci.h>
+
+/* Pegasos 2 specific Marvell MV 64361 gigabit ethernet port setup */
+static struct resource mv643xx_eth_shared_resources[] = {
+ [0] = {
+ .name = "ethernet shared base",
+ .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS,
+ .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS +
+ MV643XX_ETH_SHARED_REGS_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device mv643xx_eth_shared_device = {
+ .name = MV643XX_ETH_SHARED_NAME,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources),
+ .resource = mv643xx_eth_shared_resources,
+};
+
+static struct resource mv643xx_eth0_resources[] = {
+ [0] = {
+ .name = "eth0 irq",
+ .start = 9,
+ .end = 9,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mv643xx_eth_platform_data eth0_pd;
+
+static struct platform_device eth0_device = {
+ .name = MV643XX_ETH_NAME,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mv643xx_eth0_resources),
+ .resource = mv643xx_eth0_resources,
+ .dev = {
+ .platform_data = &eth0_pd,
+ },
+};
+
+static struct resource mv643xx_eth1_resources[] = {
+ [0] = {
+ .name = "eth1 irq",
+ .start = 9,
+ .end = 9,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mv643xx_eth_platform_data eth1_pd;
+
+static struct platform_device eth1_device = {
+ .name = MV643XX_ETH_NAME,
+ .id = 1,
+ .num_resources = ARRAY_SIZE(mv643xx_eth1_resources),
+ .resource = mv643xx_eth1_resources,
+ .dev = {
+ .platform_data = &eth1_pd,
+ },
+};
+
+static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
+ &mv643xx_eth_shared_device,
+ &eth0_device,
+ &eth1_device,
+};
+
+
+int
+mv643xx_eth_add_pds(void)
+{
+ int ret = 0;
+ static struct pci_device_id pci_marvell_mv64360[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) },
+ { }
+ };
+
+ if (pci_dev_present(pci_marvell_mv64360)) {
+ ret = platform_add_devices(mv643xx_eth_pd_devs, ARRAY_SIZE(mv643xx_eth_pd_devs));
+ }
+ return ret;
+}
+device_initcall(mv643xx_eth_add_pds);
diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
new file mode 100644
index 00000000000..f23c4f32076
--- /dev/null
+++ b/arch/ppc/platforms/chrp_setup.c
@@ -0,0 +1,615 @@
+/*
+ * arch/ppc/platforms/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#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/pci.h>
+#include <linux/version.h>
+#include <linux/adb.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/irq.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/module.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>
+#include <asm/irq.h>
+#include <asm/hydra.h>
+#include <asm/sections.h>
+#include <asm/time.h>
+#include <asm/btext.h>
+#include <asm/i8259.h>
+#include <asm/open_pic.h>
+#include <asm/xmon.h>
+
+unsigned long chrp_get_rtc_time(void);
+int chrp_set_rtc_time(unsigned long nowtime);
+void chrp_calibrate_decr(void);
+long chrp_time_init(void);
+
+void chrp_find_bridges(void);
+void chrp_event_scan(void);
+void rtas_display_progress(char *, unsigned short);
+void rtas_indicator_progress(char *, unsigned short);
+void btext_progress(char *, unsigned short);
+
+extern unsigned long pmac_find_end_of_memory(void);
+extern int of_show_percpuinfo(struct seq_file *, int);
+
+int _chrp_type;
+EXPORT_SYMBOL(_chrp_type);
+
+/*
+ * XXX this should be in xmon.h, but putting it there means xmon.h
+ * has to include <linux/interrupt.h> (to get irqreturn_t), which
+ * causes all sorts of problems. -- paulus
+ */
+extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
+
+extern dev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_jiffy;
+static int max_width;
+
+#ifdef CONFIG_SMP
+extern struct smp_ops_t chrp_smp_ops;
+#endif
+
+static const char *gg2_memtypes[4] = {
+ "FPM", "SDRAM", "EDO", "BEDO"
+};
+static const char *gg2_cachesizes[4] = {
+ "256 KB", "512 KB", "1 MB", "Reserved"
+};
+static const char *gg2_cachetypes[4] = {
+ "Asynchronous", "Reserved", "Flow-Through Synchronous",
+ "Pipelined Synchronous"
+};
+static const char *gg2_cachemodes[4] = {
+ "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
+};
+
+int __chrp
+chrp_show_cpuinfo(struct seq_file *m)
+{
+ int i, sdramen;
+ unsigned int t;
+ struct device_node *root;
+ const char *model = "";
+
+ root = find_path_device("/");
+ if (root)
+ model = get_property(root, "model", NULL);
+ seq_printf(m, "machine\t\t: CHRP %s\n", model);
+
+ /* longtrail (goldengate) stuff */
+ if (!strncmp(model, "IBM,LongTrail", 13)) {
+ /* VLSI VAS96011/12 `Golden Gate 2' */
+ /* Memory banks */
+ sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL)
+ >>31) & 1;
+ for (i = 0; i < (sdramen ? 4 : 6); i++) {
+ t = in_le32(gg2_pci_config_base+
+ GG2_PCI_DRAM_BANK0+
+ i*4);
+ if (!(t & 1))
+ continue;
+ switch ((t>>8) & 0x1f) {
+ case 0x1f:
+ model = "4 MB";
+ break;
+ case 0x1e:
+ model = "8 MB";
+ break;
+ case 0x1c:
+ model = "16 MB";
+ break;
+ case 0x18:
+ model = "32 MB";
+ break;
+ case 0x10:
+ model = "64 MB";
+ break;
+ case 0x00:
+ model = "128 MB";
+ break;
+ default:
+ model = "Reserved";
+ break;
+ }
+ seq_printf(m, "memory bank %d\t: %s %s\n", i, model,
+ gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
+ }
+ /* L2 cache */
+ t = in_le32(gg2_pci_config_base+GG2_PCI_CC_CTRL);
+ seq_printf(m, "board l2\t: %s %s (%s)\n",
+ gg2_cachesizes[(t>>7) & 3],
+ gg2_cachetypes[(t>>2) & 3],
+ gg2_cachemodes[t & 3]);
+ }
+ return 0;
+}
+
+/*
+ * Fixes for the National Semiconductor PC78308VUL SuperI/O
+ *
+ * Some versions of Open Firmware incorrectly initialize the IRQ settings
+ * for keyboard and mouse
+ */
+static inline void __init sio_write(u8 val, u8 index)
+{
+ outb(index, 0x15c);
+ outb(val, 0x15d);
+}
+
+static inline u8 __init sio_read(u8 index)
+{
+ outb(index, 0x15c);
+ return inb(0x15d);
+}
+
+static void __init sio_fixup_irq(const char *name, u8 device, u8 level,
+ u8 type)
+{
+ u8 level0, type0, active;
+
+ /* select logical device */
+ sio_write(device, 0x07);
+ active = sio_read(0x30);
+ level0 = sio_read(0x70);
+ type0 = sio_read(0x71);
+ if (level0 != level || type0 != type || !active) {
+ printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: "
+ "remapping to level %d, type %d, active\n",
+ name, level0, type0, !active ? "in" : "", level, type);
+ sio_write(0x01, 0x30);
+ sio_write(level, 0x70);
+ sio_write(type, 0x71);
+ }
+}
+
+static void __init sio_init(void)
+{
+ struct device_node *root;
+
+ if ((root = find_path_device("/")) &&
+ !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
+ /* logical device 0 (KBC/Keyboard) */
+ sio_fixup_irq("keyboard", 0, 1, 2);
+ /* select logical device 1 (KBC/Mouse) */
+ sio_fixup_irq("mouse", 1, 12, 2);
+ }
+}
+
+
+static void __init pegasos_set_l2cr(void)
+{
+ struct device_node *np;
+
+ /* On Pegasos, enable the l2 cache if needed, as the OF forgets it */
+ if (_chrp_type != _CHRP_Pegasos)
+ return;
+
+ /* Enable L2 cache if needed */
+ np = find_type_devices("cpu");
+ if (np != NULL) {
+ unsigned int *l2cr = (unsigned int *)
+ get_property (np, "l2cr", NULL);
+ if (l2cr == NULL) {
+ printk ("Pegasos l2cr : no cpu l2cr property found\n");
+ return;
+ }
+ if (!((*l2cr) & 0x80000000)) {
+ printk ("Pegasos l2cr : L2 cache was not active, "
+ "activating\n");
+ _set_L2CR(0);
+ _set_L2CR((*l2cr) | 0x80000000);
+ }
+ }
+}
+
+void __init chrp_setup_arch(void)
+{
+ struct device_node *device;
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000/HZ;
+
+#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();
+
+ /* Lookup PCI host bridges */
+ chrp_find_bridges();
+
+#ifndef CONFIG_PPC64BRIDGE
+ /*
+ * Temporary fixes for PCI devices.
+ * -- Geert
+ */
+ hydra_init(); /* Mac I/O */
+
+#endif /* CONFIG_PPC64BRIDGE */
+
+ /*
+ * Fix the Super I/O configuration
+ */
+ sio_init();
+
+ /* Get the event scan rate for the rtas so we know how
+ * often it expects a heartbeat. -- Cort
+ */
+ if ( rtas_data ) {
+ struct property *p;
+ device = find_devices("rtas");
+ for ( p = device->properties;
+ p && strncmp(p->name, "rtas-event-scan-rate", 20);
+ p = p->next )
+ /* nothing */ ;
+ if ( p && *(unsigned long *)p->value ) {
+ ppc_md.heartbeat = chrp_event_scan;
+ ppc_md.heartbeat_reset = (HZ/(*(unsigned long *)p->value)*30)-1;
+ ppc_md.heartbeat_count = 1;
+ printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n",
+ *(unsigned long *)p->value, ppc_md.heartbeat_reset );
+ }
+ }
+
+ pci_create_OF_bus_map();
+}
+
+void __chrp
+chrp_event_scan(void)
+{
+ unsigned char log[1024];
+ unsigned long ret = 0;
+ /* XXX: we should loop until the hardware says no more error logs -- Cort */
+ call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0,
+ __pa(log), 1024 );
+ ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+}
+
+void __chrp
+chrp_restart(char *cmd)
+{
+ printk("RTAS system-reboot returned %d\n",
+ call_rtas("system-reboot", 0, 1, NULL));
+ for (;;);
+}
+
+void __chrp
+chrp_power_off(void)
+{
+ /* allow power on only with power button press */
+ printk("RTAS power-off returned %d\n",
+ call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff));
+ for (;;);
+}
+
+void __chrp
+chrp_halt(void)
+{
+ chrp_power_off();
+}
+
+u_int __chrp
+chrp_irq_canonicalize(u_int irq)
+{
+ if (irq == 2)
+ return 9;
+ return irq;
+}
+
+/*
+ * Finds the open-pic node and sets OpenPIC_Addr based on its reg property.
+ * Then checks if it has an interrupt-ranges property. If it does then
+ * we have a distributed open-pic, so call openpic_set_sources to tell
+ * the openpic code where to find the interrupt source registers.
+ */
+static void __init chrp_find_openpic(void)
+{
+ struct device_node *np;
+ int len, i;
+ unsigned int *iranges;
+ void *isu;
+
+ np = find_type_devices("open-pic");
+ if (np == NULL || np->n_addrs == 0)
+ return;
+ printk(KERN_INFO "OpenPIC at %x (size %x)\n",
+ np->addrs[0].address, np->addrs[0].size);
+ OpenPIC_Addr = ioremap(np->addrs[0].address, 0x40000);
+ if (OpenPIC_Addr == NULL) {
+ printk(KERN_ERR "Failed to map OpenPIC!\n");
+ return;
+ }
+
+ iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len);
+ if (iranges == NULL || len < 2 * sizeof(unsigned int))
+ return; /* not distributed */
+
+ /*
+ * The first pair of cells in interrupt-ranges refers to the
+ * IDU; subsequent pairs refer to the ISUs.
+ */
+ len /= 2 * sizeof(unsigned int);
+ if (np->n_addrs < len) {
+ printk(KERN_ERR "Insufficient addresses for distributed"
+ " OpenPIC (%d < %d)\n", np->n_addrs, len);
+ return;
+ }
+ if (iranges[1] != 0) {
+ printk(KERN_INFO "OpenPIC irqs %d..%d in IDU\n",
+ iranges[0], iranges[0] + iranges[1] - 1);
+ openpic_set_sources(iranges[0], iranges[1], NULL);
+ }
+ for (i = 1; i < len; ++i) {
+ iranges += 2;
+ printk(KERN_INFO "OpenPIC irqs %d..%d in ISU at %x (%x)\n",
+ iranges[0], iranges[0] + iranges[1] - 1,
+ np->addrs[i].address, np->addrs[i].size);
+ isu = ioremap(np->addrs[i].address, np->addrs[i].size);
+ if (isu != NULL)
+ openpic_set_sources(iranges[0], iranges[1], isu);
+ else
+ printk(KERN_ERR "Failed to map OpenPIC ISU at %x!\n",
+ np->addrs[i].address);
+ }
+}
+
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+static struct irqaction xmon_irqaction = {
+ .handler = xmon_irq,
+ .mask = CPU_MASK_NONE,
+ .name = "XMON break",
+};
+#endif
+
+void __init chrp_init_IRQ(void)
+{
+ struct device_node *np;
+ int i;
+ unsigned long chrp_int_ack = 0;
+ unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+ struct device_node *kbd;
+#endif
+
+ for (np = find_devices("pci"); np != NULL; np = np->next) {
+ unsigned int *addrp = (unsigned int *)
+ get_property(np, "8259-interrupt-acknowledge", NULL);
+
+ if (addrp == NULL)
+ continue;
+ chrp_int_ack = addrp[prom_n_addr_cells(np)-1];
+ break;
+ }
+ if (np == NULL)
+ printk(KERN_ERR "Cannot find PCI interrupt acknowledge address\n");
+
+ chrp_find_openpic();
+
+ if (OpenPIC_Addr) {
+ prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS);
+ OpenPIC_InitSenses = init_senses;
+ OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
+
+ openpic_init(NUM_8259_INTERRUPTS);
+ /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+ openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+ i8259_irq);
+
+ }
+ for (i = 0; i < NUM_8259_INTERRUPTS; i++)
+ irq_desc[i].handler = &i8259_pic;
+ i8259_init(chrp_int_ack);
+
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+ /* see if there is a keyboard in the device tree
+ with a parent of type "adb" */
+ for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
+ if (kbd->parent && kbd->parent->type
+ && strcmp(kbd->parent->type, "adb") == 0)
+ break;
+ if (kbd)
+ setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction);
+#endif
+}
+
+void __init
+chrp_init2(void)
+{
+#ifdef CONFIG_NVRAM
+// XX replace this in a more saner way
+// pmac_nvram_init();
+#endif
+
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+
+ if (ppc_md.progress)
+ ppc_md.progress(" Have fun! ", 0x7777);
+}
+
+void __init
+chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ struct device_node *root = find_path_device ("/");
+ char *machine = NULL;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if ( r6 )
+ {
+ initrd_start = r6 + KERNELBASE;
+ initrd_end = r6 + r7 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+ isa_io_base = CHRP_ISA_IO_BASE; /* default value */
+
+ if (root)
+ machine = get_property(root, "model", NULL);
+ if (machine && strncmp(machine, "Pegasos", 7) == 0) {
+ _chrp_type = _CHRP_Pegasos;
+ } else if (machine && strncmp(machine, "IBM", 3) == 0) {
+ _chrp_type = _CHRP_IBM;
+ } else if (machine && strncmp(machine, "MOT", 3) == 0) {
+ _chrp_type = _CHRP_Motorola;
+ } else {
+ /* Let's assume it is an IBM chrp if all else fails */
+ _chrp_type = _CHRP_IBM;
+ }
+
+ ppc_md.setup_arch = chrp_setup_arch;
+ ppc_md.show_percpuinfo = of_show_percpuinfo;
+ ppc_md.show_cpuinfo = chrp_show_cpuinfo;
+
+ ppc_md.irq_canonicalize = chrp_irq_canonicalize;
+ ppc_md.init_IRQ = chrp_init_IRQ;
+ if (_chrp_type == _CHRP_Pegasos)
+ ppc_md.get_irq = i8259_irq;
+ else
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.init = chrp_init2;
+
+ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
+ ppc_md.restart = chrp_restart;
+ ppc_md.power_off = chrp_power_off;
+ ppc_md.halt = chrp_halt;
+
+ ppc_md.time_init = chrp_time_init;
+ ppc_md.set_rtc_time = chrp_set_rtc_time;
+ ppc_md.get_rtc_time = chrp_get_rtc_time;
+ ppc_md.calibrate_decr = chrp_calibrate_decr;
+
+ ppc_md.find_end_of_memory = pmac_find_end_of_memory;
+
+ if (rtas_data) {
+ struct device_node *rtas;
+ unsigned int *p;
+
+ rtas = find_devices("rtas");
+ if (rtas != NULL) {
+ if (get_property(rtas, "display-character", NULL)) {
+ ppc_md.progress = rtas_display_progress;
+ p = (unsigned int *) get_property
+ (rtas, "ibm,display-line-length", NULL);
+ if (p)
+ max_width = *p;
+ } else if (get_property(rtas, "set-indicator", NULL))
+ ppc_md.progress = rtas_indicator_progress;
+ }
+ }
+#ifdef CONFIG_BOOTX_TEXT
+ if (ppc_md.progress == NULL && boot_text_mapped)
+ ppc_md.progress = btext_progress;
+#endif
+
+#ifdef CONFIG_SMP
+ ppc_md.smp_ops = &chrp_smp_ops;
+#endif /* CONFIG_SMP */
+
+ /*
+ * Print the banner, then scroll down so boot progress
+ * can be printed. -- Cort
+ */
+ if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
+}
+
+void __chrp
+rtas_display_progress(char *s, unsigned short hex)
+{
+ int width;
+ char *os = s;
+
+ if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) )
+ return;
+
+ width = max_width;
+ while ( *os )
+ {
+ if ( (*os == '\n') || (*os == '\r') )
+ width = max_width;
+ else
+ width--;
+ call_rtas( "display-character", 1, 1, NULL, *os++ );
+ /* if we overwrite the screen length */
+ if ( width == 0 )
+ while ( (*os != 0) && (*os != '\n') && (*os != '\r') )
+ os++;
+ }
+
+ /*while ( width-- > 0 )*/
+ call_rtas( "display-character", 1, 1, NULL, ' ' );
+}
+
+void __chrp
+rtas_indicator_progress(char *s, unsigned short hex)
+{
+ call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex);
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+void
+btext_progress(char *s, unsigned short hex)
+{
+ prom_print(s);
+ prom_print("\n");
+}
+#endif /* CONFIG_BOOTX_TEXT */
diff --git a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c
new file mode 100644
index 00000000000..0ea1f7d9e46
--- /dev/null
+++ b/arch/ppc/platforms/chrp_smp.c
@@ -0,0 +1,98 @@
+/*
+ * Smp support for CHRP machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
+ * deal of code from the sparc and intel versions.
+ *
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/residual.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+
+extern unsigned long smp_chrp_cpu_nr;
+
+static int __init
+smp_chrp_probe(void)
+{
+ if (smp_chrp_cpu_nr > 1)
+ openpic_request_IPIs();
+
+ return smp_chrp_cpu_nr;
+}
+
+static void __devinit
+smp_chrp_kick_cpu(int nr)
+{
+ *(unsigned long *)KERNELBASE = nr;
+ asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+}
+
+static void __devinit
+smp_chrp_setup_cpu(int cpu_nr)
+{
+ if (OpenPIC_Addr)
+ do_openpic_setup_cpu();
+}
+
+static DEFINE_SPINLOCK(timebase_lock);
+static unsigned int timebase_upper = 0, timebase_lower = 0;
+
+void __devinit
+smp_chrp_give_timebase(void)
+{
+ spin_lock(&timebase_lock);
+ call_rtas("freeze-time-base", 0, 1, NULL);
+ timebase_upper = get_tbu();
+ timebase_lower = get_tbl();
+ spin_unlock(&timebase_lock);
+
+ while (timebase_upper || timebase_lower)
+ barrier();
+ call_rtas("thaw-time-base", 0, 1, NULL);
+}
+
+void __devinit
+smp_chrp_take_timebase(void)
+{
+ while (!(timebase_upper || timebase_lower))
+ barrier();
+ spin_lock(&timebase_lock);
+ set_tb(timebase_upper, timebase_lower);
+ timebase_upper = 0;
+ timebase_lower = 0;
+ spin_unlock(&timebase_lock);
+ printk("CPU %i taken timebase\n", smp_processor_id());
+}
+
+/* CHRP with openpic */
+struct smp_ops_t chrp_smp_ops __chrpdata = {
+ .message_pass = smp_openpic_message_pass,
+ .probe = smp_chrp_probe,
+ .kick_cpu = smp_chrp_kick_cpu,
+ .setup_cpu = smp_chrp_setup_cpu,
+ .give_timebase = smp_chrp_give_timebase,
+ .take_timebase = smp_chrp_take_timebase,
+};
diff --git a/arch/ppc/platforms/chrp_time.c b/arch/ppc/platforms/chrp_time.c
new file mode 100644
index 00000000000..e2be0c838d8
--- /dev/null
+++ b/arch/ppc/platforms/chrp_time.c
@@ -0,0 +1,194 @@
+/*
+ * arch/ppc/platforms/chrp_time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * Adapted for PowerPC (PReP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu).
+ * Copied and modified from arch/i386/kernel/time.c
+ *
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/init.h>
+#include <linux/bcd.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/nvram.h>
+#include <asm/prom.h>
+#include <asm/sections.h>
+#include <asm/time.h>
+
+extern spinlock_t rtc_lock;
+
+static int nvram_as1 = NVRAM_AS1;
+static int nvram_as0 = NVRAM_AS0;
+static int nvram_data = NVRAM_DATA;
+
+long __init chrp_time_init(void)
+{
+ struct device_node *rtcs;
+ int base;
+
+ rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+ if (rtcs == NULL)
+ rtcs = find_compatible_devices("rtc", "ds1385-rtc");
+ if (rtcs == NULL || rtcs->addrs == NULL)
+ return 0;
+ base = rtcs->addrs[0].address;
+ nvram_as1 = 0;
+ nvram_as0 = base;
+ nvram_data = base + 1;
+
+ return 0;
+}
+
+int __chrp chrp_cmos_clock_read(int addr)
+{
+ if (nvram_as1 != 0)
+ outb(addr>>8, nvram_as1);
+ outb(addr, nvram_as0);
+ return (inb(nvram_data));
+}
+
+void __chrp chrp_cmos_clock_write(unsigned long val, int addr)
+{
+ if (nvram_as1 != 0)
+ outb(addr>>8, nvram_as1);
+ outb(addr, nvram_as0);
+ outb(val, nvram_data);
+ return;
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+int __chrp chrp_set_rtc_time(unsigned long nowtime)
+{
+ unsigned char save_control, save_freq_select;
+ struct rtc_time tm;
+
+ spin_lock(&rtc_lock);
+ to_tm(nowtime, &tm);
+
+ save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
+
+ chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+
+ chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ tm.tm_year -= 1900;
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(tm.tm_sec);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_year);
+ }
+ chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+ chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+ chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+ chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+ chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+ chrp_cmos_clock_write(tm.tm_year,RTC_YEAR);
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ chrp_cmos_clock_write(save_control, RTC_CONTROL);
+ chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+
+ if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+ time_state = TIME_OK;
+ spin_unlock(&rtc_lock);
+ return 0;
+}
+
+unsigned long __chrp chrp_get_rtc_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int uip, i;
+
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
+ */
+
+ /* Since the UIP flag is set for about 2.2 ms and the clock
+ * is typically written with a precision of 1 jiffy, trying
+ * to obtain a precision better than a few milliseconds is
+ * an illusion. Only consistency is interesting, this also
+ * allows to use the routine for /dev/rtc without a potential
+ * 1 second kernel busy loop triggered by any reader of /dev/rtc.
+ */
+
+ for ( i = 0; i<1000000; i++) {
+ uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
+ sec = chrp_cmos_clock_read(RTC_SECONDS);
+ min = chrp_cmos_clock_read(RTC_MINUTES);
+ hour = chrp_cmos_clock_read(RTC_HOURS);
+ day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
+ mon = chrp_cmos_clock_read(RTC_MONTH);
+ year = chrp_cmos_clock_read(RTC_YEAR);
+ uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
+ if ((uip & RTC_UIP)==0) break;
+ }
+
+ if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+
+void __init chrp_calibrate_decr(void)
+{
+ struct device_node *cpu;
+ unsigned int freq, *fp;
+
+ if (via_calibrate_decr())
+ return;
+
+ /*
+ * The cpu node should have a timebase-frequency property
+ * to tell us the rate at which the decrementer counts.
+ */
+ freq = 16666000; /* hardcoded default */
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (unsigned int *)
+ get_property(cpu, "timebase-frequency", NULL);
+ if (fp != 0)
+ freq = *fp;
+ }
+ printk("time_init: decrementer frequency = %u.%.6u MHz\n",
+ freq/1000000, freq%1000000);
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
diff --git a/arch/ppc/platforms/cpci690.c b/arch/ppc/platforms/cpci690.c
new file mode 100644
index 00000000000..507870c9a97
--- /dev/null
+++ b/arch/ppc/platforms/cpci690.c
@@ -0,0 +1,491 @@
+/*
+ * arch/ppc/platforms/cpci690.c
+ *
+ * Board setup routines for the Force CPCI690 board.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This programr
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/irq.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/initrd.h>
+#include <linux/root_dev.h>
+#include <linux/mv643xx.h>
+#include <asm/bootinfo.h>
+#include <asm/machdep.h>
+#include <asm/todc.h>
+#include <asm/time.h>
+#include <asm/mv64x60.h>
+#include <platforms/cpci690.h>
+
+#define BOARD_VENDOR "Force"
+#define BOARD_MACHINE "CPCI690"
+
+/* Set IDE controllers into Native mode? */
+#define SET_PCI_IDE_NATIVE
+
+static struct mv64x60_handle bh;
+static u32 cpci690_br_base;
+
+static const unsigned int cpu_7xx[16] = { /* 7xx & 74xx (but not 745x) */
+ 18, 15, 14, 2, 4, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
+};
+
+TODC_ALLOC();
+
+static int __init
+cpci690_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+
+ if (hose->index == 0) {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 90, 91, 88, 89}, /* IDSEL 30/20 - Sentinel */
+ };
+
+ const long min_idsel = 20, max_idsel = 20, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ } else {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 93, 94, 95, 92}, /* IDSEL 28/18 - PMC slot 2 */
+ { 0, 0, 0, 0}, /* IDSEL 29/19 - Not used */
+ { 94, 95, 92, 93}, /* IDSEL 30/20 - PMC slot 1 */
+ };
+
+ const long min_idsel = 18, max_idsel = 20, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ }
+}
+
+static int
+cpci690_get_cpu_speed(void)
+{
+ unsigned long hid1;
+
+ hid1 = mfspr(SPRN_HID1) >> 28;
+ return CPCI690_BUS_FREQ * cpu_7xx[hid1]/2;
+}
+
+#define KB (1024UL)
+#define MB (1024UL * KB)
+#define GB (1024UL * MB)
+
+unsigned long __init
+cpci690_find_end_of_memory(void)
+{
+ u32 mem_ctlr_size;
+ static u32 board_size;
+ static u8 first_time = 1;
+
+ if (first_time) {
+ /* Using cpci690_set_bat() mapping ==> virt addr == phys addr */
+ switch (in_8((u8 *) (cpci690_br_base +
+ CPCI690_BR_MEM_CTLR)) & 0x07) {
+ case 0x01:
+ board_size = 256*MB;
+ break;
+ case 0x02:
+ board_size = 512*MB;
+ break;
+ case 0x03:
+ board_size = 768*MB;
+ break;
+ case 0x04:
+ board_size = 1*GB;
+ break;
+ case 0x05:
+ board_size = 1*GB + 512*MB;
+ break;
+ case 0x06:
+ board_size = 2*GB;
+ break;
+ default:
+ board_size = 0xffffffff; /* use mem ctlr size */
+ } /* switch */
+
+ mem_ctlr_size = mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
+ MV64x60_TYPE_GT64260A);
+
+ /* Check that mem ctlr & board reg agree. If not, pick MIN. */
+ if (board_size != mem_ctlr_size) {
+ printk(KERN_WARNING "Board register & memory controller"
+ "mem size disagree (board reg: 0x%lx, "
+ "mem ctlr: 0x%lx)\n",
+ (ulong)board_size, (ulong)mem_ctlr_size);
+ board_size = min(board_size, mem_ctlr_size);
+ }
+
+ first_time = 0;
+ } /* if */
+
+ return board_size;
+}
+
+static void __init
+cpci690_setup_bridge(void)
+{
+ struct mv64x60_setup_info si;
+ int i;
+
+ memset(&si, 0, sizeof(si));
+
+ si.phys_reg_base = CONFIG_MV64X60_NEW_BASE;
+
+ si.pci_0.enable_bus = 1;
+ si.pci_0.pci_io.cpu_base = CPCI690_PCI0_IO_START_PROC_ADDR;
+ si.pci_0.pci_io.pci_base_hi = 0;
+ si.pci_0.pci_io.pci_base_lo = CPCI690_PCI0_IO_START_PCI_ADDR;
+ si.pci_0.pci_io.size = CPCI690_PCI0_IO_SIZE;
+ si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_0.pci_mem[0].cpu_base = CPCI690_PCI0_MEM_START_PROC_ADDR;
+ si.pci_0.pci_mem[0].pci_base_hi = CPCI690_PCI0_MEM_START_PCI_HI_ADDR;
+ si.pci_0.pci_mem[0].pci_base_lo = CPCI690_PCI0_MEM_START_PCI_LO_ADDR;
+ si.pci_0.pci_mem[0].size = CPCI690_PCI0_MEM_SIZE;
+ si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_0.pci_cmd_bits = 0;
+ si.pci_0.latency_timer = 0x80;
+
+ si.pci_1.enable_bus = 1;
+ si.pci_1.pci_io.cpu_base = CPCI690_PCI1_IO_START_PROC_ADDR;
+ si.pci_1.pci_io.pci_base_hi = 0;
+ si.pci_1.pci_io.pci_base_lo = CPCI690_PCI1_IO_START_PCI_ADDR;
+ si.pci_1.pci_io.size = CPCI690_PCI1_IO_SIZE;
+ si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_mem[0].cpu_base = CPCI690_PCI1_MEM_START_PROC_ADDR;
+ si.pci_1.pci_mem[0].pci_base_hi = CPCI690_PCI1_MEM_START_PCI_HI_ADDR;
+ si.pci_1.pci_mem[0].pci_base_lo = CPCI690_PCI1_MEM_START_PCI_LO_ADDR;
+ si.pci_1.pci_mem[0].size = CPCI690_PCI1_MEM_SIZE;
+ si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_cmd_bits = 0;
+ si.pci_1.latency_timer = 0x80;
+
+ for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) {
+ si.cpu_prot_options[i] = 0;
+ si.cpu_snoop_options[i] = GT64260_CPU_SNOOP_WB;
+ si.pci_0.acc_cntl_options[i] =
+ GT64260_PCI_ACC_CNTL_DREADEN |
+ GT64260_PCI_ACC_CNTL_RDPREFETCH |
+ GT64260_PCI_ACC_CNTL_RDLINEPREFETCH |
+ GT64260_PCI_ACC_CNTL_RDMULPREFETCH |
+ GT64260_PCI_ACC_CNTL_SWAP_NONE |
+ GT64260_PCI_ACC_CNTL_MBURST_32_BTYES;
+ si.pci_0.snoop_options[i] = GT64260_PCI_SNOOP_WB;
+ si.pci_1.acc_cntl_options[i] =
+ GT64260_PCI_ACC_CNTL_DREADEN |
+ GT64260_PCI_ACC_CNTL_RDPREFETCH |
+ GT64260_PCI_ACC_CNTL_RDLINEPREFETCH |
+ GT64260_PCI_ACC_CNTL_RDMULPREFETCH |
+ GT64260_PCI_ACC_CNTL_SWAP_NONE |
+ GT64260_PCI_ACC_CNTL_MBURST_32_BTYES;
+ si.pci_1.snoop_options[i] = GT64260_PCI_SNOOP_WB;
+ }
+
+ /* Lookup PCI host bridges */
+ if (mv64x60_init(&bh, &si))
+ printk(KERN_ERR "Bridge initialization failed.\n");
+
+ pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = cpci690_map_irq;
+ ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
+
+ mv64x60_set_bus(&bh, 0, 0);
+ bh.hose_a->first_busno = 0;
+ bh.hose_a->last_busno = 0xff;
+ bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0);
+
+ bh.hose_b->first_busno = bh.hose_a->last_busno + 1;
+ mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno);
+ bh.hose_b->last_busno = 0xff;
+ bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b,
+ bh.hose_b->first_busno);
+}
+
+static void __init
+cpci690_setup_peripherals(void)
+{
+ /* Set up windows to CPLD, RTC/TODC, IPMI. */
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, CPCI690_BR_BASE,
+ CPCI690_BR_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
+ cpci690_br_base = (u32)ioremap(CPCI690_BR_BASE, CPCI690_BR_SIZE);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, CPCI690_TODC_BASE,
+ CPCI690_TODC_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+ TODC_INIT(TODC_TYPE_MK48T35, 0, 0,
+ ioremap(CPCI690_TODC_BASE, CPCI690_TODC_SIZE), 8);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN, CPCI690_IPMI_BASE,
+ CPCI690_IPMI_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN);
+
+ mv64x60_set_bits(&bh, MV64x60_PCI0_ARBITER_CNTL, (1<<31));
+ mv64x60_set_bits(&bh, MV64x60_PCI1_ARBITER_CNTL, (1<<31));
+
+ mv64x60_set_bits(&bh, MV64x60_CPU_MASTER_CNTL, (1<<9)); /* Only 1 cpu */
+
+ /*
+ * Turn off timer/counters. Not turning off watchdog timer because
+ * can't read its reg on the 64260A so don't know if we'll be enabling
+ * or disabling.
+ */
+ mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL,
+ ((1<<0) | (1<<8) | (1<<16) | (1<<24)));
+ mv64x60_clr_bits(&bh, GT64260_TIMR_CNTR_4_7_CNTL,
+ ((1<<0) | (1<<8) | (1<<16) | (1<<24)));
+
+ /*
+ * Set MPSC Multiplex RMII
+ * NOTE: ethernet driver modifies bit 0 and 1
+ */
+ mv64x60_write(&bh, GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
+
+#define GPP_EXTERNAL_INTERRUPTS \
+ ((1<<24) | (1<<25) | (1<<26) | (1<<27) | \
+ (1<<28) | (1<<29) | (1<<30) | (1<<31))
+ /* PCI interrupts are inputs */
+ mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, GPP_EXTERNAL_INTERRUPTS);
+ /* PCI interrupts are active low */
+ mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, GPP_EXTERNAL_INTERRUPTS);
+
+ /* Clear any pending interrupts for these inputs and enable them. */
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~GPP_EXTERNAL_INTERRUPTS);
+ mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, GPP_EXTERNAL_INTERRUPTS);
+
+ /* Route MPP interrupt inputs to GPP */
+ mv64x60_write(&bh, MV64x60_MPP_CNTL_2, 0x00000000);
+ mv64x60_write(&bh, MV64x60_MPP_CNTL_3, 0x00000000);
+}
+
+static void __init
+cpci690_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("cpci690_setup_arch: enter", 0);
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ if (ppc_md.progress)
+ ppc_md.progress("cpci690_setup_arch: Enabling L2 cache", 0);
+
+ /* Enable L2 and L3 caches (if 745x) */
+ _set_L2CR(_get_L2CR() | L2CR_L2E);
+ _set_L3CR(_get_L3CR() | L3CR_L3E);
+
+ if (ppc_md.progress)
+ ppc_md.progress("cpci690_setup_arch: Initializing bridge", 0);
+
+ cpci690_setup_bridge(); /* set up PCI bridge(s) */
+ cpci690_setup_peripherals(); /* set up chip selects/GPP/MPP etc */
+
+ if (ppc_md.progress)
+ ppc_md.progress("cpci690_setup_arch: bridge init complete", 0);
+
+ printk(KERN_INFO "%s %s port (C) 2003 MontaVista Software, Inc. "
+ "(source@mvista.com)\n", BOARD_VENDOR, BOARD_MACHINE);
+
+ if (ppc_md.progress)
+ ppc_md.progress("cpci690_setup_arch: exit", 0);
+}
+
+/* Platform device data fixup routines. */
+#if defined(CONFIG_SERIAL_MPSC)
+static void __init
+cpci690_fixup_mpsc_pdata(struct platform_device *pdev)
+{
+ struct mpsc_pdata *pdata;
+
+ pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+
+ pdata->max_idle = 40;
+ pdata->default_baud = CPCI690_MPSC_BAUD;
+ pdata->brg_clk_src = CPCI690_MPSC_CLK_SRC;
+ pdata->brg_clk_freq = CPCI690_BUS_FREQ;
+}
+
+static int __init
+cpci690_platform_notify(struct device *dev)
+{
+ static struct {
+ char *bus_id;
+ void ((*rtn)(struct platform_device *pdev));
+ } dev_map[] = {
+ { MPSC_CTLR_NAME ".0", cpci690_fixup_mpsc_pdata },
+ { MPSC_CTLR_NAME ".1", cpci690_fixup_mpsc_pdata },
+ };
+ struct platform_device *pdev;
+ int i;
+
+ if (dev && dev->bus_id)
+ for (i=0; i<ARRAY_SIZE(dev_map); i++)
+ if (!strncmp(dev->bus_id, dev_map[i].bus_id,
+ BUS_ID_SIZE)) {
+
+ pdev = container_of(dev,
+ struct platform_device, dev);
+ dev_map[i].rtn(pdev);
+ }
+
+ return 0;
+}
+#endif
+
+static void
+cpci690_reset_board(void)
+{
+ u32 i = 10000;
+
+ local_irq_disable();
+ out_8((u8 *)(cpci690_br_base + CPCI690_BR_SW_RESET), 0x11);
+
+ while (i != 0) i++;
+ panic("restart failed\n");
+}
+
+static void
+cpci690_restart(char *cmd)
+{
+ cpci690_reset_board();
+}
+
+static void
+cpci690_halt(void)
+{
+ while (1);
+ /* NOTREACHED */
+}
+
+static void
+cpci690_power_off(void)
+{
+ cpci690_halt();
+ /* NOTREACHED */
+}
+
+static int
+cpci690_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n");
+ seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n");
+ seq_printf(m, "cpu MHz\t\t: %d\n", cpci690_get_cpu_speed()/1000/1000);
+ seq_printf(m, "bus MHz\t\t: %d\n", CPCI690_BUS_FREQ/1000/1000);
+
+ return 0;
+}
+
+static void __init
+cpci690_calibrate_decr(void)
+{
+ ulong freq;
+
+ freq = CPCI690_BUS_FREQ / 4;
+
+ printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ freq/1000000, freq%1000000);
+
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
+
+static __inline__ void
+cpci690_set_bat(u32 addr, u32 size)
+{
+ addr &= 0xfffe0000;
+ size &= 0x1ffe0000;
+ size = ((size >> 17) - 1) << 2;
+
+ mb();
+ mtspr(SPRN_DBAT1U, addr | size | 0x2); /* Vs == 1; Vp == 0 */
+ mtspr(SPRN_DBAT1L, addr | 0x2a); /* WIMG bits == 0101; PP == r/w access */
+ mb();
+}
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+static void __init
+cpci690_map_io(void)
+{
+ io_block_mapping(CONFIG_MV64X60_NEW_BASE, CONFIG_MV64X60_NEW_BASE,
+ 128 * KB, _PAGE_IO);
+}
+#endif
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+ initrd_start=initrd_end=0;
+ initrd_below_start_ok=0;
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ parse_bootinfo(find_bootinfo());
+
+ loops_per_jiffy = cpci690_get_cpu_speed() / HZ;
+
+ isa_mem_base = 0;
+
+ ppc_md.setup_arch = cpci690_setup_arch;
+ ppc_md.show_cpuinfo = cpci690_show_cpuinfo;
+ ppc_md.init_IRQ = gt64260_init_irq;
+ ppc_md.get_irq = gt64260_get_irq;
+ ppc_md.restart = cpci690_restart;
+ ppc_md.power_off = cpci690_power_off;
+ ppc_md.halt = cpci690_halt;
+ ppc_md.find_end_of_memory = cpci690_find_end_of_memory;
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+ ppc_md.calibrate_decr = cpci690_calibrate_decr;
+
+ /*
+ * Need to map in board regs (used by cpci690_find_end_of_memory())
+ * and the bridge's regs (used by progress);
+ */
+ cpci690_set_bat(CPCI690_BR_BASE, 32 * MB);
+ cpci690_br_base = CPCI690_BR_BASE;
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.setup_io_mappings = cpci690_map_io;
+ ppc_md.progress = mv64x60_mpsc_progress;
+ mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#ifdef CONFIG_KGDB
+ ppc_md.setup_io_mappings = cpci690_map_io;
+ ppc_md.early_serial_map = cpci690_early_serial_map;
+#endif /* CONFIG_KGDB */
+
+#if defined(CONFIG_SERIAL_MPSC)
+ platform_notify = cpci690_platform_notify;
+#endif
+}
diff --git a/arch/ppc/platforms/cpci690.h b/arch/ppc/platforms/cpci690.h
new file mode 100644
index 00000000000..36cd2673c74
--- /dev/null
+++ b/arch/ppc/platforms/cpci690.h
@@ -0,0 +1,78 @@
+/*
+ * arch/ppc/platforms/cpci690.h
+ *
+ * Definitions for Force CPCI690
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2003 (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.
+ */
+
+/*
+ * The GT64260 has 2 PCI buses each with 1 window from the CPU bus to
+ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
+ */
+
+#ifndef __PPC_PLATFORMS_CPCI690_H
+#define __PPC_PLATFORMS_CPCI690_H
+
+/*
+ * Define bd_t to pass in the MAC addresses used by the GT64260's enet ctlrs.
+ */
+#define CPCI690_BI_MAGIC 0xFE8765DC
+
+typedef struct board_info {
+ u32 bi_magic;
+ u8 bi_enetaddr[3][6];
+} bd_t;
+
+/* PCI bus Resource setup */
+#define CPCI690_PCI0_MEM_START_PROC_ADDR 0x80000000
+#define CPCI690_PCI0_MEM_START_PCI_HI_ADDR 0x00000000
+#define CPCI690_PCI0_MEM_START_PCI_LO_ADDR 0x80000000
+#define CPCI690_PCI0_MEM_SIZE 0x10000000
+#define CPCI690_PCI0_IO_START_PROC_ADDR 0xa0000000
+#define CPCI690_PCI0_IO_START_PCI_ADDR 0x00000000
+#define CPCI690_PCI0_IO_SIZE 0x01000000
+
+#define CPCI690_PCI1_MEM_START_PROC_ADDR 0x90000000
+#define CPCI690_PCI1_MEM_START_PCI_HI_ADDR 0x00000000
+#define CPCI690_PCI1_MEM_START_PCI_LO_ADDR 0x90000000
+#define CPCI690_PCI1_MEM_SIZE 0x10000000
+#define CPCI690_PCI1_IO_START_PROC_ADDR 0xa1000000
+#define CPCI690_PCI1_IO_START_PCI_ADDR 0x01000000
+#define CPCI690_PCI1_IO_SIZE 0x01000000
+
+/* Board Registers */
+#define CPCI690_BR_BASE 0xf0000000
+#define CPCI690_BR_SIZE_ACTUAL 0x8
+#define CPCI690_BR_SIZE max(GT64260_WINDOW_SIZE_MIN, \
+ CPCI690_BR_SIZE_ACTUAL)
+#define CPCI690_BR_LED_CNTL 0x00
+#define CPCI690_BR_SW_RESET 0x01
+#define CPCI690_BR_MISC_STATUS 0x02
+#define CPCI690_BR_SWITCH_STATUS 0x03
+#define CPCI690_BR_MEM_CTLR 0x04
+#define CPCI690_BR_LAST_RESET_1 0x05
+#define CPCI690_BR_LAST_RESET_2 0x06
+
+#define CPCI690_TODC_BASE 0xf0100000
+#define CPCI690_TODC_SIZE_ACTUAL 0x8000 /* Size or NVRAM + RTC */
+#define CPCI690_TODC_SIZE max(GT64260_WINDOW_SIZE_MIN, \
+ CPCI690_TODC_SIZE_ACTUAL)
+#define CPCI690_MAC_OFFSET 0x7c10 /* MAC in RTC NVRAM */
+
+#define CPCI690_IPMI_BASE 0xf0200000
+#define CPCI690_IPMI_SIZE_ACTUAL 0x10 /* 16 bytes of IPMI */
+#define CPCI690_IPMI_SIZE max(GT64260_WINDOW_SIZE_MIN, \
+ CPCI690_IPMI_SIZE_ACTUAL)
+
+#define CPCI690_MPSC_BAUD 9600
+#define CPCI690_MPSC_CLK_SRC 8 /* TCLK */
+
+#define CPCI690_BUS_FREQ 133333333
+
+#endif /* __PPC_PLATFORMS_CPCI690_H */
diff --git a/arch/ppc/platforms/est8260.h b/arch/ppc/platforms/est8260.h
new file mode 100644
index 00000000000..adba68ecf57
--- /dev/null
+++ b/arch/ppc/platforms/est8260.h
@@ -0,0 +1,35 @@
+/* Board information for the EST8260, which should be generic for
+ * all 8260 boards. The IMMR is now given to us so the hard define
+ * will soon be removed. All of the clock values are computed from
+ * the configuration SCMR and the Power-On-Reset word.
+ */
+#ifndef __EST8260_PLATFORM
+#define __EST8260_PLATFORM
+
+#define CPM_MAP_ADDR ((uint)0xf0000000)
+
+#define BOOTROM_RESTART_ADDR ((uint)0xff000104)
+
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "EST Corporation"
+#define CPUINFO_MACHINE "SBC8260 PowerPC"
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+ unsigned int bi_memstart; /* Memory start address */
+ unsigned int bi_memsize; /* Memory (end) size in bytes */
+ unsigned int bi_intfreq; /* Internal Freq, in Hz */
+ unsigned int bi_busfreq; /* Bus Freq, in MHz */
+ unsigned int bi_cpmfreq; /* CPM Freq, in MHz */
+ unsigned int bi_brgfreq; /* BRG Freq, in MHz */
+ unsigned int bi_vco; /* VCO Out from PLL */
+ unsigned int bi_baudrate; /* Default console baud rate */
+ unsigned int bi_immr; /* IMMR when called from boot rom */
+ unsigned char bi_enetaddr[6];
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+#endif /* __EST8260_PLATFORM */
diff --git a/arch/ppc/platforms/ev64260.c b/arch/ppc/platforms/ev64260.c
new file mode 100644
index 00000000000..aa50637a5cf
--- /dev/null
+++ b/arch/ppc/platforms/ev64260.c
@@ -0,0 +1,651 @@
+/*
+ * arch/ppc/platforms/ev64260.c
+ *
+ * Board setup routines for the Marvell/Galileo EV-64260-BP Evaluation Board.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2001-2003 (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.
+ */
+
+/*
+ * The EV-64260-BP port is the result of hard work from many people from
+ * many companies. In particular, employees of Marvell/Galileo, Mission
+ * Critical Linux, Xyterra, and MontaVista Software were heavily involved.
+ *
+ * Note: I have not been able to get *all* PCI slots to work reliably
+ * at 66 MHz. I recommend setting jumpers J15 & J16 to short pins 1&2
+ * so that 33 MHz is used. --MAG
+ * Note: The 750CXe and 7450 are not stable with a 125MHz or 133MHz TCLK/SYSCLK.
+ * At 100MHz, they are solid.
+ */
+#include <linux/config.h>
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/irq.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/initrd.h>
+#include <linux/root_dev.h>
+#if !defined(CONFIG_SERIAL_MPSC_CONSOLE)
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#else
+#include <linux/mv643xx.h>
+#endif
+#include <asm/bootinfo.h>
+#include <asm/machdep.h>
+#include <asm/mv64x60.h>
+#include <asm/todc.h>
+#include <asm/time.h>
+
+#include <platforms/ev64260.h>
+
+#define BOARD_VENDOR "Marvell/Galileo"
+#define BOARD_MACHINE "EV-64260-BP"
+
+static struct mv64x60_handle bh;
+
+#if !defined(CONFIG_SERIAL_MPSC_CONSOLE)
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct uart_port *);
+#endif
+
+static const unsigned int cpu_7xx[16] = { /* 7xx & 74xx (but not 745x) */
+ 18, 15, 14, 2, 4, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
+};
+static const unsigned int cpu_745x[2][16] = { /* PLL_EXT 0 & 1 */
+ { 1, 15, 14, 2, 4, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0 },
+ { 0, 30, 0, 2, 0, 26, 0, 18, 0, 22, 20, 24, 28, 32, 0, 0 }
+};
+
+
+TODC_ALLOC();
+
+static int
+ev64260_get_bus_speed(void)
+{
+ return 100000000;
+}
+
+static int
+ev64260_get_cpu_speed(void)
+{
+ unsigned long pvr, hid1, pll_ext;
+
+ pvr = PVR_VER(mfspr(SPRN_PVR));
+
+ if (pvr != PVR_VER(PVR_7450)) {
+ hid1 = mfspr(SPRN_HID1) >> 28;
+ return ev64260_get_bus_speed() * cpu_7xx[hid1]/2;
+ }
+ else {
+ hid1 = (mfspr(SPRN_HID1) & 0x0001e000) >> 13;
+ pll_ext = 0; /* No way to read; must get from schematic */
+ return ev64260_get_bus_speed() * cpu_745x[pll_ext][hid1]/2;
+ }
+}
+
+unsigned long __init
+ev64260_find_end_of_memory(void)
+{
+ return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
+ MV64x60_TYPE_GT64260A);
+}
+
+/*
+ * Marvell/Galileo EV-64260-BP Evaluation Board PCI interrupt routing.
+ * Note: By playing with J8 and JP1-4, you can get 2 IRQ's from the first
+ * PCI bus (in which cast, INTPIN B would be EV64260_PCI_1_IRQ).
+ * This is the most IRQs you can get from one bus with this board, though.
+ */
+static int __init
+ev64260_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+
+ if (hose->index == 0) {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {EV64260_PCI_0_IRQ,0,0,0}, /* IDSEL 7 - PCI bus 0 */
+ {EV64260_PCI_0_IRQ,0,0,0}, /* IDSEL 8 - PCI bus 0 */
+ };
+
+ const long min_idsel = 7, max_idsel = 8, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ }
+ else {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { EV64260_PCI_1_IRQ,0,0,0}, /* IDSEL 7 - PCI bus 1 */
+ { EV64260_PCI_1_IRQ,0,0,0}, /* IDSEL 8 - PCI bus 1 */
+ };
+
+ const long min_idsel = 7, max_idsel = 8, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ }
+}
+
+static void __init
+ev64260_setup_peripherals(void)
+{
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+ EV64260_EMB_FLASH_BASE, EV64260_EMB_FLASH_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN,
+ EV64260_EXT_SRAM_BASE, EV64260_EXT_SRAM_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
+ EV64260_TODC_BASE, EV64260_TODC_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN,
+ EV64260_UART_BASE, EV64260_UART_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN,
+ EV64260_EXT_FLASH_BASE, EV64260_EXT_FLASH_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN);
+
+ TODC_INIT(TODC_TYPE_DS1501, 0, 0,
+ ioremap(EV64260_TODC_BASE, EV64260_TODC_SIZE), 8);
+
+ mv64x60_clr_bits(&bh, MV64x60_CPU_CONFIG,((1<<12) | (1<<28) | (1<<29)));
+ mv64x60_set_bits(&bh, MV64x60_CPU_CONFIG, (1<<27));
+
+ if (ev64260_get_bus_speed() > 100000000)
+ mv64x60_set_bits(&bh, MV64x60_CPU_CONFIG, (1<<23));
+
+ mv64x60_set_bits(&bh, MV64x60_PCI0_PCI_DECODE_CNTL, ((1<<0) | (1<<3)));
+ mv64x60_set_bits(&bh, MV64x60_PCI1_PCI_DECODE_CNTL, ((1<<0) | (1<<3)));
+
+ /*
+ * Enabling of PCI internal-vs-external arbitration
+ * is a platform- and errata-dependent decision.
+ */
+ if (bh.type == MV64x60_TYPE_GT64260A ) {
+ mv64x60_set_bits(&bh, MV64x60_PCI0_ARBITER_CNTL, (1<<31));
+ mv64x60_set_bits(&bh, MV64x60_PCI1_ARBITER_CNTL, (1<<31));
+ }
+
+ mv64x60_set_bits(&bh, MV64x60_CPU_MASTER_CNTL, (1<<9)); /* Only 1 cpu */
+
+ /*
+ * Turn off timer/counters. Not turning off watchdog timer because
+ * can't read its reg on the 64260A so don't know if we'll be enabling
+ * or disabling.
+ */
+ mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL,
+ ((1<<0) | (1<<8) | (1<<16) | (1<<24)));
+ mv64x60_clr_bits(&bh, GT64260_TIMR_CNTR_4_7_CNTL,
+ ((1<<0) | (1<<8) | (1<<16) | (1<<24)));
+
+ /*
+ * Set MPSC Multiplex RMII
+ * NOTE: ethernet driver modifies bit 0 and 1
+ */
+ mv64x60_write(&bh, GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
+
+ /*
+ * The EV-64260-BP uses several Multi-Purpose Pins (MPP) on the 64260
+ * bridge as interrupt inputs (via the General Purpose Ports (GPP)
+ * register). Need to route the MPP inputs to the GPP and set the
+ * polarity correctly.
+ *
+ * In MPP Control 2 Register
+ * MPP 21 -> GPP 21 (DUART channel A intr) bits 20-23 -> 0
+ * MPP 22 -> GPP 22 (DUART channel B intr) bits 24-27 -> 0
+ */
+ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_2, (0xf<<20) | (0xf<<24) );
+
+ /*
+ * In MPP Control 3 Register
+ * MPP 26 -> GPP 26 (RTC INT) bits 8-11 -> 0
+ * MPP 27 -> GPP 27 (PCI 0 INTA) bits 12-15 -> 0
+ * MPP 29 -> GPP 29 (PCI 1 INTA) bits 20-23 -> 0
+ */
+ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_3, (0xf<<8)|(0xf<<12)|(0xf<<20));
+
+#define GPP_EXTERNAL_INTERRUPTS \
+ ((1<<21) | (1<<22) | (1<<26) | (1<<27) | (1<<29))
+ /* DUART & PCI interrupts are inputs */
+ mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, GPP_EXTERNAL_INTERRUPTS);
+ /* DUART & PCI interrupts are active low */
+ mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, GPP_EXTERNAL_INTERRUPTS);
+
+ /* Clear any pending interrupts for these inputs and enable them. */
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~GPP_EXTERNAL_INTERRUPTS);
+ mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, GPP_EXTERNAL_INTERRUPTS);
+
+ return;
+}
+
+static void __init
+ev64260_setup_bridge(void)
+{
+ struct mv64x60_setup_info si;
+ int i;
+
+ memset(&si, 0, sizeof(si));
+
+ si.phys_reg_base = CONFIG_MV64X60_NEW_BASE;
+
+ si.pci_0.enable_bus = 1;
+ si.pci_0.pci_io.cpu_base = EV64260_PCI0_IO_CPU_BASE;
+ si.pci_0.pci_io.pci_base_hi = 0;
+ si.pci_0.pci_io.pci_base_lo = EV64260_PCI0_IO_PCI_BASE;
+ si.pci_0.pci_io.size = EV64260_PCI0_IO_SIZE;
+ si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_0.pci_mem[0].cpu_base = EV64260_PCI0_MEM_CPU_BASE;
+ si.pci_0.pci_mem[0].pci_base_hi = 0;
+ si.pci_0.pci_mem[0].pci_base_lo = EV64260_PCI0_MEM_PCI_BASE;
+ si.pci_0.pci_mem[0].size = EV64260_PCI0_MEM_SIZE;
+ si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_0.pci_cmd_bits = 0;
+ si.pci_0.latency_timer = 0x8;
+
+ si.pci_1.enable_bus = 1;
+ si.pci_1.pci_io.cpu_base = EV64260_PCI1_IO_CPU_BASE;
+ si.pci_1.pci_io.pci_base_hi = 0;
+ si.pci_1.pci_io.pci_base_lo = EV64260_PCI1_IO_PCI_BASE;
+ si.pci_1.pci_io.size = EV64260_PCI1_IO_SIZE;
+ si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_mem[0].cpu_base = EV64260_PCI1_MEM_CPU_BASE;
+ si.pci_1.pci_mem[0].pci_base_hi = 0;
+ si.pci_1.pci_mem[0].pci_base_lo = EV64260_PCI1_MEM_PCI_BASE;
+ si.pci_1.pci_mem[0].size = EV64260_PCI1_MEM_SIZE;
+ si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_cmd_bits = 0;
+ si.pci_1.latency_timer = 0x8;
+
+ for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) {
+ si.cpu_prot_options[i] = 0;
+ si.cpu_snoop_options[i] = GT64260_CPU_SNOOP_WB;
+ si.pci_0.acc_cntl_options[i] =
+ GT64260_PCI_ACC_CNTL_DREADEN |
+ GT64260_PCI_ACC_CNTL_RDPREFETCH |
+ GT64260_PCI_ACC_CNTL_RDLINEPREFETCH |
+ GT64260_PCI_ACC_CNTL_RDMULPREFETCH |
+ GT64260_PCI_ACC_CNTL_SWAP_NONE |
+ GT64260_PCI_ACC_CNTL_MBURST_32_BTYES;
+ si.pci_0.snoop_options[i] = GT64260_PCI_SNOOP_WB;
+ si.pci_1.acc_cntl_options[i] =
+ GT64260_PCI_ACC_CNTL_DREADEN |
+ GT64260_PCI_ACC_CNTL_RDPREFETCH |
+ GT64260_PCI_ACC_CNTL_RDLINEPREFETCH |
+ GT64260_PCI_ACC_CNTL_RDMULPREFETCH |
+ GT64260_PCI_ACC_CNTL_SWAP_NONE |
+ GT64260_PCI_ACC_CNTL_MBURST_32_BTYES;
+ si.pci_1.snoop_options[i] = GT64260_PCI_SNOOP_WB;
+ }
+
+ /* Lookup PCI host bridges */
+ if (mv64x60_init(&bh, &si))
+ printk(KERN_ERR "Bridge initialization failed.\n");
+
+ pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = ev64260_map_irq;
+ ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
+
+ mv64x60_set_bus(&bh, 0, 0);
+ bh.hose_a->first_busno = 0;
+ bh.hose_a->last_busno = 0xff;
+ bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0);
+
+ bh.hose_b->first_busno = bh.hose_a->last_busno + 1;
+ mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno);
+ bh.hose_b->last_busno = 0xff;
+ bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b,
+ bh.hose_b->first_busno);
+
+ return;
+}
+
+#if defined(CONFIG_SERIAL_8250) && !defined(CONFIG_SERIAL_MPSC_CONSOLE)
+static void __init
+ev64260_early_serial_map(void)
+{
+ struct uart_port port;
+ static char first_time = 1;
+
+ if (first_time) {
+ memset(&port, 0, sizeof(port));
+
+ port.membase = ioremap(EV64260_SERIAL_0, EV64260_UART_SIZE);
+ port.irq = EV64260_UART_0_IRQ;
+ port.uartclk = BASE_BAUD * 16;
+ port.regshift = 2;
+ port.iotype = SERIAL_IO_MEM;
+ port.flags = STD_COM_FLAGS;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ gen550_init(0, &port);
+#endif
+
+ if (early_serial_setup(&port) != 0)
+ printk(KERN_WARNING "Early serial init of port 0"
+ "failed\n");
+
+ first_time = 0;
+ }
+
+ return;
+}
+#elif defined(CONFIG_SERIAL_MPSC_CONSOLE)
+static void __init
+ev64260_early_serial_map(void)
+{
+}
+#endif
+
+static void __init
+ev64260_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("ev64260_setup_arch: enter", 0);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ if (ppc_md.progress)
+ ppc_md.progress("ev64260_setup_arch: Enabling L2 cache", 0);
+
+ /* Enable L2 and L3 caches (if 745x) */
+ _set_L2CR(_get_L2CR() | L2CR_L2E);
+ _set_L3CR(_get_L3CR() | L3CR_L3E);
+
+ if (ppc_md.progress)
+ ppc_md.progress("ev64260_setup_arch: Initializing bridge", 0);
+
+ ev64260_setup_bridge(); /* set up PCI bridge(s) */
+ ev64260_setup_peripherals(); /* set up chip selects/GPP/MPP etc */
+
+ if (ppc_md.progress)
+ ppc_md.progress("ev64260_setup_arch: bridge init complete", 0);
+
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ ev64260_early_serial_map();
+#endif
+
+ printk(KERN_INFO "%s %s port (C) 2001 MontaVista Software, Inc."
+ "(source@mvista.com)\n", BOARD_VENDOR, BOARD_MACHINE);
+
+ if (ppc_md.progress)
+ ppc_md.progress("ev64260_setup_arch: exit", 0);
+
+ return;
+}
+
+/* Platform device data fixup routines. */
+#if defined(CONFIG_SERIAL_MPSC)
+static void __init
+ev64260_fixup_mpsc_pdata(struct platform_device *pdev)
+{
+ struct mpsc_pdata *pdata;
+
+ pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+
+ pdata->max_idle = 40;
+ pdata->default_baud = EV64260_DEFAULT_BAUD;
+ pdata->brg_clk_src = EV64260_MPSC_CLK_SRC;
+ pdata->brg_clk_freq = EV64260_MPSC_CLK_FREQ;
+
+ return;
+}
+
+static int __init
+ev64260_platform_notify(struct device *dev)
+{
+ static struct {
+ char *bus_id;
+ void ((*rtn)(struct platform_device *pdev));
+ } dev_map[] = {
+ { MPSC_CTLR_NAME ".0", ev64260_fixup_mpsc_pdata },
+ { MPSC_CTLR_NAME ".1", ev64260_fixup_mpsc_pdata },
+ };
+ struct platform_device *pdev;
+ int i;
+
+ if (dev && dev->bus_id)
+ for (i=0; i<ARRAY_SIZE(dev_map); i++)
+ if (!strncmp(dev->bus_id, dev_map[i].bus_id,
+ BUS_ID_SIZE)) {
+
+ pdev = container_of(dev,
+ struct platform_device, dev);
+ dev_map[i].rtn(pdev);
+ }
+
+ return 0;
+}
+#endif
+
+static void
+ev64260_reset_board(void *addr)
+{
+ local_irq_disable();
+
+ /* disable and invalidate the L2 cache */
+ _set_L2CR(0);
+ _set_L2CR(0x200000);
+
+ /* flush and disable L1 I/D cache */
+ __asm__ __volatile__
+ ("mfspr 3,1008\n\t"
+ "ori 5,5,0xcc00\n\t"
+ "ori 4,3,0xc00\n\t"
+ "andc 5,3,5\n\t"
+ "sync\n\t"
+ "mtspr 1008,4\n\t"
+ "isync\n\t"
+ "sync\n\t"
+ "mtspr 1008,5\n\t"
+ "isync\n\t"
+ "sync\n\t");
+
+ /* unmap any other random cs's that might overlap with bootcs */
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, 0, 0, 0);
+ bh.ci->disable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, 0, 0, 0);
+ bh.ci->disable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN, 0, 0, 0);
+ bh.ci->disable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN, 0, 0, 0);
+ bh.ci->disable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN);
+
+ /* map bootrom back in to gt @ reset defaults */
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+ 0xff800000, 8*1024*1024, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+
+ /* move reg base back to default, setup default pci0 */
+ mv64x60_write(&bh, MV64x60_INTERNAL_SPACE_DECODE,
+ (1<<24) | CONFIG_MV64X60_BASE >> 20);
+
+ /* NOTE: FROM NOW ON no more GT_REGS accesses.. 0x1 is not mapped
+ * via BAT or MMU, and MSR IR/DR is ON */
+ /* SRR0 has system reset vector, SRR1 has default MSR value */
+ /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+ /* NOTE: assumes reset vector is at 0xfff00100 */
+ __asm__ __volatile__
+ ("mtspr 26, %0\n\t"
+ "li 4,(1<<6)\n\t"
+ "mtspr 27,4\n\t"
+ "rfi\n\t"
+ :: "r" (addr):"r4");
+
+ return;
+}
+
+static void
+ev64260_restart(char *cmd)
+{
+ volatile ulong i = 10000000;
+
+ ev64260_reset_board((void *)0xfff00100);
+
+ while (i-- > 0);
+ panic("restart failed\n");
+}
+
+static void
+ev64260_halt(void)
+{
+ local_irq_disable();
+ while (1);
+ /* NOTREACHED */
+}
+
+static void
+ev64260_power_off(void)
+{
+ ev64260_halt();
+ /* NOTREACHED */
+}
+
+static int
+ev64260_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid;
+
+ pvid = mfspr(SPRN_PVR);
+ seq_printf(m, "vendor\t\t: " BOARD_VENDOR "\n");
+ seq_printf(m, "machine\t\t: " BOARD_MACHINE "\n");
+ seq_printf(m, "cpu MHz\t\t: %d\n", ev64260_get_cpu_speed()/1000/1000);
+ seq_printf(m, "bus MHz\t\t: %d\n", ev64260_get_bus_speed()/1000/1000);
+
+ return 0;
+}
+
+/* DS1501 RTC has too much variation to use RTC for calibration */
+static void __init
+ev64260_calibrate_decr(void)
+{
+ ulong freq;
+
+ freq = ev64260_get_bus_speed()/4;
+
+ printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ freq/1000000, freq%1000000);
+
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+ return;
+}
+
+/*
+ * Set BAT 3 to map 0xfb000000 to 0xfc000000 of physical memory space.
+ */
+static __inline__ void
+ev64260_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT1U, 0xfb0001fe);
+ mtspr(SPRN_DBAT1L, 0xfb00002a);
+ mb();
+
+ return;
+}
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+static void __init
+ev64260_map_io(void)
+{
+ io_block_mapping(0xfb000000, 0xfb000000, 0x01000000, _PAGE_IO);
+}
+#endif
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+ extern int initrd_below_start_ok;
+
+ initrd_start=initrd_end=0;
+ initrd_below_start_ok=0;
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ parse_bootinfo(find_bootinfo());
+
+ isa_mem_base = 0;
+ isa_io_base = EV64260_PCI0_IO_CPU_BASE;
+ pci_dram_offset = EV64260_PCI0_MEM_CPU_BASE;
+
+ loops_per_jiffy = ev64260_get_cpu_speed() / HZ;
+
+ ppc_md.setup_arch = ev64260_setup_arch;
+ ppc_md.show_cpuinfo = ev64260_show_cpuinfo;
+ ppc_md.init_IRQ = gt64260_init_irq;
+ ppc_md.get_irq = gt64260_get_irq;
+
+ ppc_md.restart = ev64260_restart;
+ ppc_md.power_off = ev64260_power_off;
+ ppc_md.halt = ev64260_halt;
+
+ ppc_md.find_end_of_memory = ev64260_find_end_of_memory;
+
+ ppc_md.init = NULL;
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+ ppc_md.calibrate_decr = ev64260_calibrate_decr;
+
+ bh.p_base = CONFIG_MV64X60_NEW_BASE;
+
+ ev64260_set_bat();
+
+#ifdef CONFIG_SERIAL_8250
+#if defined(CONFIG_SERIAL_TEXT_DEBUG)
+ ppc_md.setup_io_mappings = ev64260_map_io;
+ ppc_md.progress = gen550_progress;
+#endif
+#if defined(CONFIG_KGDB)
+ ppc_md.setup_io_mappings = ev64260_map_io;
+ ppc_md.early_serial_map = ev64260_early_serial_map;
+#endif
+#elif defined(CONFIG_SERIAL_MPSC_CONSOLE)
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.setup_io_mappings = ev64260_map_io;
+ ppc_md.progress = mv64x60_mpsc_progress;
+ mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#ifdef CONFIG_KGDB
+ ppc_md.setup_io_mappings = ev64260_map_io;
+ ppc_md.early_serial_map = ev64260_early_serial_map;
+#endif /* CONFIG_KGDB */
+
+#endif
+
+#if defined(CONFIG_SERIAL_MPSC)
+ platform_notify = ev64260_platform_notify;
+#endif
+
+ return;
+}
diff --git a/arch/ppc/platforms/ev64260.h b/arch/ppc/platforms/ev64260.h
new file mode 100644
index 00000000000..bedffced3a0
--- /dev/null
+++ b/arch/ppc/platforms/ev64260.h
@@ -0,0 +1,128 @@
+/*
+ * arch/ppc/platforms/ev64260.h
+ *
+ * Definitions for Marvell/Galileo EV-64260-BP Evaluation Board.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2001-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.
+ */
+
+/*
+ * The MV64x60 has 2 PCI buses each with 1 window from the CPU bus to
+ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
+ * We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 1MB and start
+ * on a boundary that is a multiple of the window size):
+ *
+ * 0xfc000000-0xffffffff - External FLASH on device module
+ * 0xfbf00000-0xfbffffff - Embedded (on board) FLASH
+ * 0xfbe00000-0xfbefffff - GT64260 Registers (preferably)
+ * but really a config option
+ * 0xfbd00000-0xfbdfffff - External SRAM on device module
+ * 0xfbc00000-0xfbcfffff - TODC chip on device module
+ * 0xfbb00000-0xfbbfffff - External UART on device module
+ * 0xa2000000-0xfbafffff - <hole>
+ * 0xa1000000-0xa1ffffff - PCI 1 I/O (defined in gt64260.h)
+ * 0xa0000000-0xa0ffffff - PCI 0 I/O (defined in gt64260.h)
+ * 0x90000000-0x9fffffff - PCI 1 MEM (defined in gt64260.h)
+ * 0x80000000-0x8fffffff - PCI 0 MEM (defined in gt64260.h)
+ */
+
+#ifndef __PPC_PLATFORMS_EV64260_H
+#define __PPC_PLATFORMS_EV64260_H
+
+/* PCI mappings */
+#define EV64260_PCI0_IO_CPU_BASE 0xa0000000
+#define EV64260_PCI0_IO_PCI_BASE 0x00000000
+#define EV64260_PCI0_IO_SIZE 0x01000000
+
+#define EV64260_PCI0_MEM_CPU_BASE 0x80000000
+#define EV64260_PCI0_MEM_PCI_BASE 0x80000000
+#define EV64260_PCI0_MEM_SIZE 0x10000000
+
+#define EV64260_PCI1_IO_CPU_BASE (EV64260_PCI0_IO_CPU_BASE + \
+ EV64260_PCI0_IO_SIZE)
+#define EV64260_PCI1_IO_PCI_BASE (EV64260_PCI0_IO_PCI_BASE + \
+ EV64260_PCI0_IO_SIZE)
+#define EV64260_PCI1_IO_SIZE 0x01000000
+
+#define EV64260_PCI1_MEM_CPU_BASE (EV64260_PCI0_MEM_CPU_BASE + \
+ EV64260_PCI0_MEM_SIZE)
+#define EV64260_PCI1_MEM_PCI_BASE (EV64260_PCI0_MEM_PCI_BASE + \
+ EV64260_PCI0_MEM_SIZE)
+#define EV64260_PCI1_MEM_SIZE 0x10000000
+
+/* CPU Physical Memory Map setup (other than PCI) */
+#define EV64260_EXT_FLASH_BASE 0xfc000000
+#define EV64260_EMB_FLASH_BASE 0xfbf00000
+#define EV64260_EXT_SRAM_BASE 0xfbd00000
+#define EV64260_TODC_BASE 0xfbc00000
+#define EV64260_UART_BASE 0xfbb00000
+
+#define EV64260_EXT_FLASH_SIZE_ACTUAL 0x04000000 /* <= 64MB Extern FLASH */
+#define EV64260_EMB_FLASH_SIZE_ACTUAL 0x00080000 /* 512KB of Embed FLASH */
+#define EV64260_EXT_SRAM_SIZE_ACTUAL 0x00100000 /* 1MB SDRAM */
+#define EV64260_TODC_SIZE_ACTUAL 0x00000020 /* 32 bytes for TODC */
+#define EV64260_UART_SIZE_ACTUAL 0x00000040 /* 64 bytes for DUART */
+
+#define EV64260_EXT_FLASH_SIZE max(GT64260_WINDOW_SIZE_MIN, \
+ EV64260_EXT_FLASH_SIZE_ACTUAL)
+#define EV64260_EMB_FLASH_SIZE max(GT64260_WINDOW_SIZE_MIN, \
+ EV64260_EMB_FLASH_SIZE_ACTUAL)
+#define EV64260_EXT_SRAM_SIZE max(GT64260_WINDOW_SIZE_MIN, \
+ EV64260_EXT_SRAM_SIZE_ACTUAL)
+#define EV64260_TODC_SIZE max(GT64260_WINDOW_SIZE_MIN, \
+ EV64260_TODC_SIZE_ACTUAL)
+/* Assembler in bootwrapper blows up if 'max' is used */
+#define EV64260_UART_SIZE GT64260_WINDOW_SIZE_MIN
+#define EV64260_UART_END ((EV64260_UART_BASE + \
+ EV64260_UART_SIZE - 1) & 0xfff00000)
+
+/* Board-specific IRQ info */
+#define EV64260_UART_0_IRQ 85
+#define EV64260_UART_1_IRQ 86
+#define EV64260_PCI_0_IRQ 91
+#define EV64260_PCI_1_IRQ 93
+
+/* Serial port setup */
+#define EV64260_DEFAULT_BAUD 115200
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+#define SERIAL_PORT_DFNS
+
+#define EV64260_MPSC_CLK_SRC 8 /* TCLK */
+#define EV64260_MPSC_CLK_FREQ 100000000 /* 100MHz clk */
+#else
+#define EV64260_SERIAL_0 (EV64260_UART_BASE + 0x20)
+#define EV64260_SERIAL_1 EV64260_UART_BASE
+
+#define BASE_BAUD (EV64260_DEFAULT_BAUD * 2)
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE 64
+#else
+#define RS_TABLE_SIZE 2
+#endif
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#endif
+
+/* Required for bootloader's ns16550.c code */
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, EV64260_SERIAL_0, EV64260_UART_0_IRQ, STD_COM_FLAGS, \
+ iomem_base: (u8 *)EV64260_SERIAL_0, /* ttyS0 */ \
+ iomem_reg_shift: 2, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
+#endif
+#endif /* __PPC_PLATFORMS_EV64260_H */
diff --git a/arch/ppc/platforms/fads.h b/arch/ppc/platforms/fads.h
new file mode 100644
index 00000000000..632b8178ce6
--- /dev/null
+++ b/arch/ppc/platforms/fads.h
@@ -0,0 +1,57 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Motorola 860T FADS board. Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_FADS_H__
+#define __ASM_FADS_H__
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+/* Memory map is configured by the PROM startup.
+ * I tried to follow the FADS manual, although the startup PROM
+ * dictates this and we simply have to move some of the physical
+ * addresses for Linux.
+ */
+#define BCSR_ADDR ((uint)0xff010000)
+#define BCSR_SIZE ((uint)(64 * 1024))
+#define BCSR0 ((uint)0xff010000)
+#define BCSR1 ((uint)0xff010004)
+#define BCSR2 ((uint)0xff010008)
+#define BCSR3 ((uint)0xff01000c)
+#define BCSR4 ((uint)0xff010010)
+
+#define IMAP_ADDR ((uint)0xff000000)
+#define IMAP_SIZE ((uint)(64 * 1024))
+
+#define PCMCIA_MEM_ADDR ((uint)0xff020000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
+
+/* Bits of interest in the BCSRs.
+ */
+#define BCSR1_ETHEN ((uint)0x20000000)
+#define BCSR1_RS232EN_1 ((uint)0x01000000)
+#define BCSR1_RS232EN_2 ((uint)0x00040000)
+#define BCSR4_ETHLOOP ((uint)0x80000000) /* EEST Loopback */
+#define BCSR4_EEFDX ((uint)0x40000000) /* EEST FDX enable */
+#define BCSR4_FETH_EN ((uint)0x08000000) /* PHY enable */
+#define BCSR4_FETHCFG0 ((uint)0x04000000) /* PHY autoneg mode */
+#define BCSR4_FETHCFG1 ((uint)0x00400000) /* PHY autoneg mode */
+#define BCSR4_FETHFDE ((uint)0x02000000) /* PHY FDX advertise */
+#define BCSR4_FETHRST ((uint)0x00200000) /* PHY Reset */
+
+/* Interrupt level assignments.
+ */
+#define FEC_INTERRUPT SIU_LEVEL1 /* FEC interrupt */
+#define PHY_INTERRUPT SIU_IRQ2 /* PHY link change interrupt */
+
+/* We don't use the 8259.
+ */
+#define NR_8259_INTS 0
+
+#endif /* __ASM_FADS_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/gemini.h b/arch/ppc/platforms/gemini.h
new file mode 100644
index 00000000000..06de5924891
--- /dev/null
+++ b/arch/ppc/platforms/gemini.h
@@ -0,0 +1,168 @@
+/*
+ * arch/ppc/platforms/gemini.h
+ *
+ *
+ * Onboard registers and descriptions for Synergy Microsystems'
+ * "Gemini" boards.
+ *
+ */
+#ifdef __KERNEL__
+#ifndef __PPC_GEMINI_H
+#define __PPC_GEMINI_H
+
+/* Registers */
+
+#define GEMINI_SERIAL_B (0xffeffb00)
+#define GEMINI_SERIAL_A (0xffeffb08)
+#define GEMINI_USWITCH (0xffeffd00)
+#define GEMINI_BREV (0xffeffe00)
+#define GEMINI_BECO (0xffeffe08)
+#define GEMINI_FEAT (0xffeffe10)
+#define GEMINI_BSTAT (0xffeffe18)
+#define GEMINI_CPUSTAT (0xffeffe20)
+#define GEMINI_L2CFG (0xffeffe30)
+#define GEMINI_MEMCFG (0xffeffe38)
+#define GEMINI_FLROM (0xffeffe40)
+#define GEMINI_P0PCI (0xffeffe48)
+#define GEMINI_FLWIN (0xffeffe50)
+#define GEMINI_P0INTMASK (0xffeffe60)
+#define GEMINI_P0INTAP (0xffeffe68)
+#define GEMINI_PCIERR (0xffeffe70)
+#define GEMINI_LEDBASE (0xffeffe80)
+#define GEMINI_RTC (0xffe9fff8)
+#define GEMINI_LEDS 8
+#define GEMINI_SWITCHES 8
+
+
+/* Flash ROM bit definitions */
+#define GEMINI_FLS_WEN (1<<0)
+#define GEMINI_FLS_JMP (1<<6)
+#define GEMINI_FLS_BOOT (1<<7)
+
+/* Memory bit definitions */
+#define GEMINI_MEM_TYPE_MASK 0xc0
+#define GEMINI_MEM_SIZE_MASK 0x38
+#define GEMINI_MEM_BANK_MASK 0x07
+
+/* L2 cache bit definitions */
+#define GEMINI_L2_SIZE_MASK 0xc0
+#define GEMINI_L2_RATIO_MASK 0x03
+
+/* Timebase register bit definitons */
+#define GEMINI_TIMEB0_EN (1<<0)
+#define GEMINI_TIMEB1_EN (1<<1)
+#define GEMINI_TIMEB2_EN (1<<2)
+#define GEMINI_TIMEB3_EN (1<<3)
+
+/* CPU status bit definitions */
+#define GEMINI_CPU_ID_MASK 0x03
+#define GEMINI_CPU_COUNT_MASK 0x0c
+#define GEMINI_CPU0_HALTED (1<<4)
+#define GEMINI_CPU1_HALTED (1<<5)
+#define GEMINI_CPU2_HALTED (1<<6)
+#define GEMINI_CPU3_HALTED (1<<7)
+
+/* Board status bit definitions */
+#define GEMINI_BRD_FAIL (1<<0) /* FAIL led is lit */
+#define GEMINI_BRD_BUS_MASK 0x0c /* PowerPC bus speed */
+
+/* Board family/feature bit descriptions */
+#define GEMINI_FEAT_HAS_FLASH (1<<0)
+#define GEMINI_FEAT_HAS_ETH (1<<1)
+#define GEMINI_FEAT_HAS_SCSI (1<<2)
+#define GEMINI_FEAT_HAS_P0 (1<<3)
+#define GEMINI_FEAT_FAM_MASK 0xf0
+
+/* Mod/ECO bit definitions */
+#define GEMINI_ECO_LEVEL_MASK 0x0f
+#define GEMINI_MOD_MASK 0xf0
+
+/* Type/revision bit definitions */
+#define GEMINI_REV_MASK 0x0f
+#define GEMINI_TYPE_MASK 0xf0
+
+/* User switch definitions */
+#define GEMINI_SWITCH_VERBOSE 1 /* adds "debug" to boot cmd line */
+#define GEMINI_SWITCH_SINGLE_USER 7 /* boots into "single-user" mode */
+
+#define SGS_RTC_CONTROL 0
+#define SGS_RTC_SECONDS 1
+#define SGS_RTC_MINUTES 2
+#define SGS_RTC_HOURS 3
+#define SGS_RTC_DAY 4
+#define SGS_RTC_DAY_OF_MONTH 5
+#define SGS_RTC_MONTH 6
+#define SGS_RTC_YEAR 7
+
+#define SGS_RTC_SET 0x80
+#define SGS_RTC_IS_STOPPED 0x80
+
+#define GRACKLE_CONFIG_ADDR_ADDR (0xfec00000)
+#define GRACKLE_CONFIG_DATA_ADDR (0xfee00000)
+
+#define GEMINI_BOOT_INIT (0xfff00100)
+
+#ifndef __ASSEMBLY__
+
+static inline void grackle_write( unsigned long addr, unsigned long data )
+{
+ __asm__ __volatile__(
+ " stwbrx %1, 0, %0\n \
+ sync\n \
+ stwbrx %3, 0, %2\n \
+ sync "
+ : /* no output */
+ : "r" (GRACKLE_CONFIG_ADDR_ADDR), "r" (addr),
+ "r" (GRACKLE_CONFIG_DATA_ADDR), "r" (data));
+}
+
+static inline unsigned long grackle_read( unsigned long addr )
+{
+ unsigned long val;
+
+ __asm__ __volatile__(
+ " stwbrx %1, 0, %2\n \
+ sync\n \
+ lwbrx %0, 0, %3\n \
+ sync "
+ : "=r" (val)
+ : "r" (addr), "r" (GRACKLE_CONFIG_ADDR_ADDR),
+ "r" (GRACKLE_CONFIG_DATA_ADDR));
+
+ return val;
+}
+
+static inline void gemini_led_on( int led )
+{
+ if (led >= 0 && led < GEMINI_LEDS)
+ *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 1;
+}
+
+static inline void gemini_led_off(int led)
+{
+ if (led >= 0 && led < GEMINI_LEDS)
+ *(unsigned char *)(GEMINI_LEDBASE + (led<<3)) = 0;
+}
+
+static inline int gemini_led_val(int led)
+{
+ int val = 0;
+ if (led >= 0 && led < GEMINI_LEDS)
+ val = *(unsigned char *)(GEMINI_LEDBASE + (led<<3));
+ return (val & 0x1);
+}
+
+/* returns processor id from the board */
+static inline int gemini_processor(void)
+{
+ unsigned char cpu = *(unsigned char *)(GEMINI_CPUSTAT);
+ return (int) ((cpu == 0) ? 4 : (cpu & GEMINI_CPU_ID_MASK));
+}
+
+
+extern void _gemini_reboot(void);
+extern void gemini_prom_init(void);
+extern void gemini_init_l2(void);
+#endif /* __ASSEMBLY__ */
+#endif
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/gemini_pci.c b/arch/ppc/platforms/gemini_pci.c
new file mode 100644
index 00000000000..95656091ba2
--- /dev/null
+++ b/arch/ppc/platforms/gemini_pci.c
@@ -0,0 +1,41 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/machdep.h>
+#include <platforms/gemini.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pci-bridge.h>
+
+void __init gemini_pcibios_fixup(void)
+{
+ int i;
+ struct pci_dev *dev = NULL;
+
+ for_each_pci_dev(dev) {
+ for(i = 0; i < 6; i++) {
+ if (dev->resource[i].flags & IORESOURCE_IO) {
+ dev->resource[i].start |= (0xfe << 24);
+ dev->resource[i].end |= (0xfe << 24);
+ }
+ }
+ }
+}
+
+
+/* The "bootloader" for Synergy boards does none of this for us, so we need to
+ lay it all out ourselves... --Dan */
+void __init gemini_find_bridges(void)
+{
+ struct pci_controller* hose;
+
+ ppc_md.pcibios_fixup = gemini_pcibios_fixup;
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return;
+ setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
+}
diff --git a/arch/ppc/platforms/gemini_prom.S b/arch/ppc/platforms/gemini_prom.S
new file mode 100644
index 00000000000..8c5065d5650
--- /dev/null
+++ b/arch/ppc/platforms/gemini_prom.S
@@ -0,0 +1,93 @@
+/*
+ * arch/ppc/platforms/gemini_prom.S
+ *
+ * Not really prom support code (yet), but sort of anti-prom code. The current
+ * bootloader does a number of things it shouldn't and doesn't do things that it
+ * should. The stuff in here is mainly a hodge-podge collection of setup code
+ * to get the board up and running.
+ * ---Dan
+ */
+
+#include <linux/config.h>
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <platforms/gemini.h>
+#include <asm/ppc_asm.h>
+
+/*
+ * On 750's the MMU is on when Linux is booted, so we need to clear out the
+ * bootloader's BAT settings, make sure we're in supervisor state (gotcha!),
+ * and turn off the MMU.
+ *
+ */
+
+_GLOBAL(gemini_prom_init)
+#ifdef CONFIG_SMP
+ /* Since the MMU's on, get stuff in rom space that we'll need */
+ lis r4,GEMINI_CPUSTAT@h
+ ori r4,r4,GEMINI_CPUSTAT@l
+ lbz r5,0(r4)
+ andi. r5,r5,3
+ mr r24,r5 /* cpu # used later on */
+#endif
+ mfmsr r4
+ li r3,MSR_PR /* ensure supervisor! */
+ ori r3,r3,MSR_IR|MSR_DR
+ andc r4,r4,r3
+ mtmsr r4
+ isync
+#if 0
+ /* zero out the bats now that the MMU is off */
+prom_no_mmu:
+ li r3,0
+ mtspr SPRN_IBAT0U,r3
+ mtspr SPRN_IBAT0L,r3
+ mtspr SPRN_IBAT1U,r3
+ mtspr SPRN_IBAT1L,r3
+ mtspr SPRN_IBAT2U,r3
+ mtspr SPRN_IBAT2L,r3
+ mtspr SPRN_IBAT3U,r3
+ mtspr SPRN_IBAT3L,r3
+
+ mtspr SPRN_DBAT0U,r3
+ mtspr SPRN_DBAT0L,r3
+ mtspr SPRN_DBAT1U,r3
+ mtspr SPRN_DBAT1L,r3
+ mtspr SPRN_DBAT2U,r3
+ mtspr SPRN_DBAT2L,r3
+ mtspr SPRN_DBAT3U,r3
+ mtspr SPRN_DBAT3L,r3
+#endif
+
+ /* the bootloader (as far as I'm currently aware) doesn't mess with page
+ tables, but since we're already here, might as well zap these, too */
+ li r4,0
+ mtspr SPRN_SDR1,r4
+
+ li r4,16
+ mtctr r4
+ li r3,0
+ li r4,0
+3: mtsrin r3,r4
+ addi r3,r3,1
+ bdnz 3b
+
+#ifdef CONFIG_SMP
+ /* The 750 book (and Mot/IBM support) says that this will "assist" snooping
+ when in SMP. Not sure yet whether this should stay or leave... */
+ mfspr r4,SPRN_HID0
+ ori r4,r4,HID0_ABE
+ mtspr SPRN_HID0,r4
+ sync
+#endif /* CONFIG_SMP */
+ blr
+
+/* apparently, SMon doesn't pay attention to HID0[SRST]. Disable the MMU and
+ branch to 0xfff00100 */
+_GLOBAL(_gemini_reboot)
+ lis r5,GEMINI_BOOT_INIT@h
+ ori r5,r5,GEMINI_BOOT_INIT@l
+ li r6,MSR_IP
+ mtspr SPRN_SRR0,r5
+ mtspr SPRN_SRR1,r6
+ rfi
diff --git a/arch/ppc/platforms/gemini_serial.h b/arch/ppc/platforms/gemini_serial.h
new file mode 100644
index 00000000000..69855aeec88
--- /dev/null
+++ b/arch/ppc/platforms/gemini_serial.h
@@ -0,0 +1,41 @@
+#ifdef __KERNEL__
+#ifndef __ASMPPC_GEMINI_SERIAL_H
+#define __ASMPPC_GEMINI_SERIAL_H
+
+#include <linux/config.h>
+#include <platforms/gemini.h>
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE 64
+#else
+#define RS_TABLE_SIZE 4
+#endif
+
+/* Rate for the 24.576 Mhz clock for the onboard serial chip */
+#define BASE_BAUD (24576000 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define STD_SERIAL_PORT_DEFNS \
+ { 0, BASE_BAUD, GEMINI_SERIAL_A, 15, STD_COM_FLAGS }, /* ttyS0 */ \
+ { 0, BASE_BAUD, GEMINI_SERIAL_B, 14, STD_COM_FLAGS }, /* ttyS1 */ \
+
+#ifdef CONFIG_GEMINI_PU32
+#define PU32_SERIAL_PORT_DEFNS \
+ { 0, BASE_BAUD, NULL, 0, STD_COM_FLAGS },
+#else
+#define PU32_SERIAL_PORT_DEFNS
+#endif
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DEFNS \
+ PU32_SERIAL_PORT_DEFNS
+
+#endif
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c
new file mode 100644
index 00000000000..1a42cb9b113
--- /dev/null
+++ b/arch/ppc/platforms/gemini_setup.c
@@ -0,0 +1,584 @@
+/*
+ * arch/ppc/platforms/gemini_setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Synergy Microsystems board support by Dan Cox (dan@synergymicro.com)
+ *
+ */
+
+#include <linux/config.h>
+#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/time.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/bcd.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/m48t35.h>
+#include <platforms/gemini.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+
+void gemini_find_bridges(void);
+static int gemini_get_clock_speed(void);
+extern void gemini_pcibios_fixup(void);
+
+static char *gemini_board_families[] = {
+ "VGM", "VSS", "KGM", "VGR", "VCM", "VCS", "KCM", "VCR"
+};
+static int gemini_board_count = sizeof(gemini_board_families) /
+ sizeof(gemini_board_families[0]);
+
+static unsigned int cpu_7xx[16] = {
+ 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
+};
+static unsigned int cpu_6xx[16] = {
+ 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
+};
+
+/*
+ * prom_init is the Gemini version of prom.c:prom_init. We only need
+ * the BSS clearing code, so I copied that out of prom.c. This is a
+ * lot simpler than hacking prom.c so it will build with Gemini. -VAL
+ */
+
+#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) + offset))
+
+unsigned long
+prom_init(void)
+{
+ unsigned long offset = reloc_offset();
+ unsigned long phys;
+ extern char __bss_start, _end;
+
+ /* First zero the BSS -- use memset, some arches don't have
+ * caches on yet */
+ memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start);
+
+ /* Default */
+ phys = offset + KERNELBASE;
+
+ gemini_prom_init();
+
+ return phys;
+}
+
+int
+gemini_show_cpuinfo(struct seq_file *m)
+{
+ unsigned char reg, rev;
+ char *family;
+ unsigned int type;
+
+ reg = readb(GEMINI_FEAT);
+ family = gemini_board_families[((reg>>4) & 0xf)];
+ if (((reg>>4) & 0xf) > gemini_board_count)
+ printk(KERN_ERR "cpuinfo(): unable to determine board family\n");
+
+ reg = readb(GEMINI_BREV);
+ type = (reg>>4) & 0xf;
+ rev = reg & 0xf;
+
+ reg = readb(GEMINI_BECO);
+
+ seq_printf(m, "machine\t\t: Gemini %s%d, rev %c, eco %d\n",
+ family, type, (rev + 'A'), (reg & 0xf));
+
+ seq_printf(m, "board\t\t: Gemini %s", family);
+ if (type > 9)
+ seq_printf(m, "%c", (type - 10) + 'A');
+ else
+ seq_printf(m, "%d", type);
+
+ seq_printf(m, ", rev %c, eco %d\n", (rev + 'A'), (reg & 0xf));
+
+ seq_printf(m, "clock\t\t: %dMhz\n", gemini_get_clock_speed());
+
+ return 0;
+}
+
+static u_char gemini_openpic_initsenses[] = {
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1, /* remainder are level-triggered */
+};
+
+#define GEMINI_MPIC_ADDR (0xfcfc0000)
+#define GEMINI_MPIC_PCI_CFG (0x80005800)
+
+void __init gemini_openpic_init(void)
+{
+
+ OpenPIC_Addr = (volatile struct OpenPIC *)
+ grackle_read(GEMINI_MPIC_PCI_CFG + 0x10);
+ OpenPIC_InitSenses = gemini_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof( gemini_openpic_initsenses );
+
+ ioremap( GEMINI_MPIC_ADDR, OPENPIC_SIZE);
+}
+
+
+extern unsigned long loops_per_jiffy;
+extern int root_mountflags;
+extern char cmd_line[];
+
+void
+gemini_heartbeat(void)
+{
+ static unsigned long led = GEMINI_LEDBASE+(4*8);
+ static char direction = 8;
+
+
+ /* We only want to do this on 1 CPU */
+ if (smp_processor_id())
+ return;
+ *(char *)led = 0;
+ if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) ||
+ (led + direction) < (GEMINI_LEDBASE+(4*8)) )
+ direction *= -1;
+ led += direction;
+ *(char *)led = 0xff;
+ ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+}
+
+void __init gemini_setup_arch(void)
+{
+ extern char cmd_line[];
+
+
+ loops_per_jiffy = 50000000/HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* bootable off CDROM */
+ if (initrd_start)
+ ROOT_DEV = Root_SR0;
+ else
+#endif
+ ROOT_DEV = Root_SDA1;
+
+ /* nothing but serial consoles... */
+ sprintf(cmd_line, "%s console=ttyS0", cmd_line);
+
+ printk("Boot arguments: %s\n", cmd_line);
+
+ ppc_md.heartbeat = gemini_heartbeat;
+ ppc_md.heartbeat_reset = HZ/8;
+ ppc_md.heartbeat_count = 1;
+
+ /* Lookup PCI hosts */
+ gemini_find_bridges();
+ /* take special pains to map the MPIC, since it isn't mapped yet */
+ gemini_openpic_init();
+ /* start the L2 */
+ gemini_init_l2();
+}
+
+
+int
+gemini_get_clock_speed(void)
+{
+ unsigned long hid1, pvr;
+ int clock;
+
+ pvr = mfspr(SPRN_PVR);
+ hid1 = (mfspr(SPRN_HID1) >> 28) & 0xf;
+ if (PVR_VER(pvr) == 8 ||
+ PVR_VER(pvr) == 12)
+ hid1 = cpu_7xx[hid1];
+ else
+ hid1 = cpu_6xx[hid1];
+
+ switch((readb(GEMINI_BSTAT) & 0xc) >> 2) {
+
+ case 0:
+ default:
+ clock = (hid1*100)/3;
+ break;
+
+ case 1:
+ clock = (hid1*125)/3;
+ break;
+
+ case 2:
+ clock = (hid1*50);
+ break;
+ }
+
+ return clock;
+}
+
+void __init gemini_init_l2(void)
+{
+ unsigned char reg, brev, fam, creg;
+ unsigned long cache;
+ unsigned long pvr;
+
+ reg = readb(GEMINI_L2CFG);
+ brev = readb(GEMINI_BREV);
+ fam = readb(GEMINI_FEAT);
+ pvr = mfspr(SPRN_PVR);
+
+ switch(PVR_VER(pvr)) {
+
+ case 8:
+ if (reg & 0xc0)
+ cache = (((reg >> 6) & 0x3) << 28);
+ else
+ cache = 0x3 << 28;
+
+#ifdef CONFIG_SMP
+ /* Pre-3.0 processor revs had snooping errata. Leave
+ their L2's disabled with SMP. -- Dan */
+ if (PVR_CFG(pvr) < 3) {
+ printk("Pre-3.0 750; L2 left disabled!\n");
+ return;
+ }
+#endif /* CONFIG_SMP */
+
+ /* Special case: VGM5-B's came before L2 ratios were set on
+ the board. Processor speed shouldn't be too high, so
+ set L2 ratio to 1:1.5. */
+ if ((brev == 0x51) && ((fam & 0xa0) >> 4) == 0)
+ reg |= 1;
+
+ /* determine best cache ratio based upon what the board
+ tells us (which sometimes _may_ not be true) and
+ the processor speed. */
+ else {
+ if (gemini_get_clock_speed() > 250)
+ reg = 2;
+ }
+ break;
+ case 12:
+ {
+ static unsigned long l2_size_val = 0;
+
+ if (!l2_size_val)
+ l2_size_val = _get_L2CR();
+ cache = l2_size_val;
+ break;
+ }
+ case 4:
+ case 9:
+ creg = readb(GEMINI_CPUSTAT);
+ if (((creg & 0xc) >> 2) != 1)
+ printk("Dual-604 boards don't support the use of L2\n");
+ else
+ writeb(1, GEMINI_L2CFG);
+ return;
+ default:
+ printk("Unknown processor; L2 left disabled\n");
+ return;
+ }
+
+ cache |= ((1<<reg) << 25);
+ cache |= (L2CR_L2RAM_MASK|L2CR_L2CTL|L2CR_L2DO);
+ _set_L2CR(0);
+ _set_L2CR(cache | L2CR_L2E);
+
+}
+
+void
+gemini_restart(char *cmd)
+{
+ local_irq_disable();
+ /* make a clean restart, not via the MPIC */
+ _gemini_reboot();
+ for(;;);
+}
+
+void
+gemini_power_off(void)
+{
+ for(;;);
+}
+
+void
+gemini_halt(void)
+{
+ gemini_restart(NULL);
+}
+
+void __init gemini_init_IRQ(void)
+{
+ /* gemini has no 8259 */
+ openpic_init(1, 0, 0, -1);
+}
+
+#define gemini_rtc_read(x) (readb(GEMINI_RTC+(x)))
+#define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x))))
+
+/* ensure that the RTC is up and running */
+long __init gemini_time_init(void)
+{
+ unsigned char reg;
+
+ reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+
+ if ( reg & M48T35_RTC_STOPPED ) {
+ printk(KERN_INFO "M48T35 real-time-clock was stopped. Now starting...\n");
+ gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
+ gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
+ }
+ return 0;
+}
+
+#undef DEBUG_RTC
+
+unsigned long
+gemini_get_rtc_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ unsigned char reg;
+
+ reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+ gemini_rtc_write((reg|M48T35_RTC_READ), M48T35_RTC_CONTROL);
+#ifdef DEBUG_RTC
+ printk("get rtc: reg = %x\n", reg);
+#endif
+
+ do {
+ sec = gemini_rtc_read(M48T35_RTC_SECONDS);
+ min = gemini_rtc_read(M48T35_RTC_MINUTES);
+ hour = gemini_rtc_read(M48T35_RTC_HOURS);
+ day = gemini_rtc_read(M48T35_RTC_DOM);
+ mon = gemini_rtc_read(M48T35_RTC_MONTH);
+ year = gemini_rtc_read(M48T35_RTC_YEAR);
+ } while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
+#ifdef DEBUG_RTC
+ printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
+ sec, min, hour, day, mon, year);
+#endif
+
+ gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+
+ if ((year += 1900) < 1970)
+ year += 100;
+#ifdef DEBUG_RTC
+ printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
+ sec, min, hour, day, mon, year);
+#endif
+
+ return mktime( year, mon, day, hour, min, sec );
+}
+
+
+int
+gemini_set_rtc_time( unsigned long now )
+{
+ unsigned char reg;
+ struct rtc_time tm;
+
+ to_tm( now, &tm );
+
+ reg = gemini_rtc_read(M48T35_RTC_CONTROL);
+#ifdef DEBUG_RTC
+ printk("set rtc: reg = %x\n", reg);
+#endif
+
+ gemini_rtc_write((reg|M48T35_RTC_SET), M48T35_RTC_CONTROL);
+#ifdef DEBUG_RTC
+ printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+ tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+
+ tm.tm_year -= 1900;
+ BIN_TO_BCD(tm.tm_sec);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_year);
+#ifdef DEBUG_RTC
+ printk("set rtc: tm vals - sec=%x, min=%x, hour=%x, mon=%x, mday=%x, year=%x\n",
+ tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mon, tm.tm_mday, tm.tm_year);
+#endif
+
+ gemini_rtc_write(tm.tm_sec, M48T35_RTC_SECONDS);
+ gemini_rtc_write(tm.tm_min, M48T35_RTC_MINUTES);
+ gemini_rtc_write(tm.tm_hour, M48T35_RTC_HOURS);
+ gemini_rtc_write(tm.tm_mday, M48T35_RTC_DOM);
+ gemini_rtc_write(tm.tm_mon, M48T35_RTC_MONTH);
+ gemini_rtc_write(tm.tm_year, M48T35_RTC_YEAR);
+
+ /* done writing */
+ gemini_rtc_write(reg, M48T35_RTC_CONTROL);
+
+ if ((time_state == TIME_ERROR) || (time_state == TIME_BAD))
+ time_state = TIME_OK;
+
+ return 0;
+}
+
+/* use the RTC to determine the decrementer count */
+void __init gemini_calibrate_decr(void)
+{
+ int freq, divisor;
+ unsigned char reg;
+
+ /* determine processor bus speed */
+ reg = readb(GEMINI_BSTAT);
+
+ switch(((reg & 0x0c)>>2)&0x3) {
+ case 0:
+ default:
+ freq = 66667;
+ break;
+ case 1:
+ freq = 83000;
+ break;
+ case 2:
+ freq = 100000;
+ break;
+ }
+
+ freq *= 1000;
+ divisor = 4;
+ tb_ticks_per_jiffy = freq / HZ / divisor;
+ tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+}
+
+unsigned long __init gemini_find_end_of_memory(void)
+{
+ unsigned long total;
+ unsigned char reg;
+
+ reg = readb(GEMINI_MEMCFG);
+ total = ((1<<((reg & 0x7) - 1)) *
+ (8<<((reg >> 3) & 0x7)));
+ total *= (1024*1024);
+ return total;
+}
+
+static void __init
+gemini_map_io(void)
+{
+ io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+ io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
+}
+
+#ifdef CONFIG_SMP
+static int
+smp_gemini_probe(void)
+{
+ int i, nr;
+
+ nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
+ if (nr == 0)
+ nr = 4;
+
+ if (nr > 1) {
+ openpic_request_IPIs();
+ for (i = 1; i < nr; ++i)
+ smp_hw_index[i] = i;
+ }
+
+ return nr;
+}
+
+static void
+smp_gemini_kick_cpu(int nr)
+{
+ openpic_reset_processor_phys(1 << nr);
+ openpic_reset_processor_phys(0);
+}
+
+static void
+smp_gemini_setup_cpu(int cpu_nr)
+{
+ if (OpenPIC_Addr)
+ do_openpic_setup_cpu();
+ if (cpu_nr > 0)
+ gemini_init_l2();
+}
+
+static struct smp_ops_t gemini_smp_ops = {
+ smp_openpic_message_pass,
+ smp_gemini_probe,
+ smp_gemini_kick_cpu,
+ smp_gemini_setup_cpu,
+ .give_timebase = smp_generic_give_timebase,
+ .take_timebase = smp_generic_take_timebase,
+};
+#endif /* CONFIG_SMP */
+
+void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ int i;
+
+ /* Restore BATs for now */
+ mtspr(SPRN_DBAT3U, 0xf0001fff);
+ mtspr(SPRN_DBAT3L, 0xf000002a);
+
+ parse_bootinfo(find_bootinfo());
+
+ for(i = 0; i < GEMINI_LEDS; i++)
+ gemini_led_off(i);
+
+ ISA_DMA_THRESHOLD = 0;
+ DMA_MODE_READ = 0;
+ DMA_MODE_WRITE = 0;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif
+
+ ppc_md.setup_arch = gemini_setup_arch;
+ ppc_md.show_cpuinfo = gemini_show_cpuinfo;
+ ppc_md.irq_canonicalize = NULL;
+ ppc_md.init_IRQ = gemini_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+ ppc_md.init = NULL;
+
+ ppc_md.restart = gemini_restart;
+ ppc_md.power_off = gemini_power_off;
+ ppc_md.halt = gemini_halt;
+
+ ppc_md.time_init = gemini_time_init;
+ ppc_md.set_rtc_time = gemini_set_rtc_time;
+ ppc_md.get_rtc_time = gemini_get_rtc_time;
+ ppc_md.calibrate_decr = gemini_calibrate_decr;
+
+ ppc_md.find_end_of_memory = gemini_find_end_of_memory;
+ ppc_md.setup_io_mappings = gemini_map_io;
+
+ ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
+
+#ifdef CONFIG_SMP
+ ppc_md.smp_ops = &gemini_smp_ops;
+#endif /* CONFIG_SMP */
+}
diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c
new file mode 100644
index 00000000000..b659d7b3d74
--- /dev/null
+++ b/arch/ppc/platforms/hdpu.c
@@ -0,0 +1,1062 @@
+
+/*
+ * arch/ppc/platforms/hdpu_setup.c
+ *
+ * Board setup routines for the Sky Computers HDPU Compute Blade.
+ *
+ * Written by Brian Waite <waite@skycomputers.com>
+ *
+ * Based on code done by - Mark A. Greer <mgreer@mvista.com>
+ * Rabeeh Khoury - rabeeh@galileo.co.il
+ *
+ * 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/config.h>
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+
+#include <linux/initrd.h>
+#include <linux/root_dev.h>
+#include <linux/smp.h>
+
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/todc.h>
+#include <asm/mv64x60.h>
+#include <asm/ppcboot.h>
+#include <platforms/hdpu.h>
+#include <linux/mv643xx.h>
+#include <linux/hdpu_features.h>
+#include <linux/device.h>
+#include <linux/mtd/physmap.h>
+
+#define BOARD_VENDOR "Sky Computers"
+#define BOARD_MACHINE "HDPU-CB-A"
+
+bd_t ppcboot_bd;
+int ppcboot_bd_valid = 0;
+
+static mv64x60_handle_t bh;
+
+extern char cmd_line[];
+
+unsigned long hdpu_find_end_of_memory(void);
+void hdpu_mpsc_progress(char *s, unsigned short hex);
+void hdpu_heartbeat(void);
+
+static void parse_bootinfo(unsigned long r3,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7);
+static void hdpu_set_l1pe(void);
+static void hdpu_cpustate_set(unsigned char new_state);
+#ifdef CONFIG_SMP
+static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int timebase_upper = 0, timebase_lower = 0;
+extern int smp_tb_synchronized;
+
+void __devinit hdpu_tben_give(void);
+void __devinit hdpu_tben_take(void);
+#endif
+
+static int __init
+hdpu_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+
+ if (hose->index == 0) {
+ static char pci_irq_table[][4] = {
+ {HDPU_PCI_0_IRQ, 0, 0, 0},
+ {HDPU_PCI_0_IRQ, 0, 0, 0},
+ };
+
+ const long min_idsel = 1, max_idsel = 2, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ } else {
+ static char pci_irq_table[][4] = {
+ {HDPU_PCI_1_IRQ, 0, 0, 0},
+ };
+
+ const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ }
+}
+
+static void __init hdpu_intr_setup(void)
+{
+ mv64x60_write(&bh, MV64x60_GPP_IO_CNTL,
+ (1 | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) |
+ (1 << 6) | (1 << 7) | (1 << 12) | (1 << 16) |
+ (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21) |
+ (1 << 22) | (1 << 23) | (1 << 24) | (1 << 25) |
+ (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29)));
+
+ /* XXXX Erranum FEr PCI-#8 */
+ mv64x60_clr_bits(&bh, MV64x60_PCI0_CMD, (1 << 5) | (1 << 9));
+ mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1 << 5) | (1 << 9));
+
+ /*
+ * Dismiss and then enable interrupt on GPP interrupt cause
+ * for CPU #0
+ */
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~((1 << 8) | (1 << 13)));
+ mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, (1 << 8) | (1 << 13));
+
+ /*
+ * Dismiss and then enable interrupt on CPU #0 high cause reg
+ * BIT25 summarizes GPP interrupts 8-15
+ */
+ mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, (1 << 25));
+}
+
+static void __init hdpu_setup_peripherals(void)
+{
+ unsigned int val;
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+ HDPU_EMB_FLASH_BASE, HDPU_EMB_FLASH_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN,
+ HDPU_TBEN_BASE, HDPU_TBEN_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
+ HDPU_NEXUS_ID_BASE, HDPU_NEXUS_ID_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+ HDPU_INTERNAL_SRAM_BASE,
+ HDPU_INTERNAL_SRAM_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+
+ bh.ci->disable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN, 0, 0, 0);
+
+ mv64x60_clr_bits(&bh, MV64x60_PCI0_PCI_DECODE_CNTL, (1 << 3));
+ mv64x60_clr_bits(&bh, MV64x60_PCI1_PCI_DECODE_CNTL, (1 << 3));
+ mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL,
+ ((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24)));
+
+ /* Enable pipelining */
+ mv64x60_set_bits(&bh, MV64x60_CPU_CONFIG, (1 << 13));
+ /* Enable Snoop Pipelineing */
+ mv64x60_set_bits(&bh, MV64360_D_UNIT_CONTROL_HIGH, (1 << 24));
+
+ /*
+ * Change DRAM read buffer assignment.
+ * Assign read buffer 0 dedicated only for CPU,
+ * and the rest read buffer 1.
+ */
+ val = mv64x60_read(&bh, MV64360_SDRAM_CONFIG);
+ val = val & 0x03ffffff;
+ val = val | 0xf8000000;
+ mv64x60_write(&bh, MV64360_SDRAM_CONFIG, val);
+
+ /*
+ * Configure internal SRAM -
+ * Cache coherent write back, if CONFIG_MV64360_SRAM_CACHE_COHERENT set
+ * Parity enabled.
+ * Parity error propagation
+ * Arbitration not parked for CPU only
+ * Other bits are reserved.
+ */
+#ifdef CONFIG_MV64360_SRAM_CACHE_COHERENT
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2);
+#else
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b0);
+#endif
+
+ hdpu_intr_setup();
+}
+
+static void __init hdpu_setup_bridge(void)
+{
+ struct mv64x60_setup_info si;
+ int i;
+
+ memset(&si, 0, sizeof(si));
+
+ si.phys_reg_base = HDPU_BRIDGE_REG_BASE;
+ si.pci_0.enable_bus = 1;
+ si.pci_0.pci_io.cpu_base = HDPU_PCI0_IO_START_PROC_ADDR;
+ si.pci_0.pci_io.pci_base_hi = 0;
+ si.pci_0.pci_io.pci_base_lo = HDPU_PCI0_IO_START_PCI_ADDR;
+ si.pci_0.pci_io.size = HDPU_PCI0_IO_SIZE;
+ si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_0.pci_mem[0].cpu_base = HDPU_PCI0_MEM_START_PROC_ADDR;
+ si.pci_0.pci_mem[0].pci_base_hi = HDPU_PCI0_MEM_START_PCI_HI_ADDR;
+ si.pci_0.pci_mem[0].pci_base_lo = HDPU_PCI0_MEM_START_PCI_LO_ADDR;
+ si.pci_0.pci_mem[0].size = HDPU_PCI0_MEM_SIZE;
+ si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_0.pci_cmd_bits = 0;
+ si.pci_0.latency_timer = 0x80;
+
+ si.pci_1.enable_bus = 1;
+ si.pci_1.pci_io.cpu_base = HDPU_PCI1_IO_START_PROC_ADDR;
+ si.pci_1.pci_io.pci_base_hi = 0;
+ si.pci_1.pci_io.pci_base_lo = HDPU_PCI1_IO_START_PCI_ADDR;
+ si.pci_1.pci_io.size = HDPU_PCI1_IO_SIZE;
+ si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_mem[0].cpu_base = HDPU_PCI1_MEM_START_PROC_ADDR;
+ si.pci_1.pci_mem[0].pci_base_hi = HDPU_PCI1_MEM_START_PCI_HI_ADDR;
+ si.pci_1.pci_mem[0].pci_base_lo = HDPU_PCI1_MEM_START_PCI_LO_ADDR;
+ si.pci_1.pci_mem[0].size = HDPU_PCI1_MEM_SIZE;
+ si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_cmd_bits = 0;
+ si.pci_1.latency_timer = 0x80;
+
+ for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ si.cpu_prot_options[i] = 0;
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+
+ si.pci_0.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+
+#else
+ si.cpu_prot_options[i] = 0;
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_WB; /* errata */
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_WB; /* errata */
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_WB; /* errata */
+
+ si.pci_0.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_WB |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_WB |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+#endif
+ }
+
+ hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_INIT_PCI);
+
+ /* Lookup PCI host bridges */
+ mv64x60_init(&bh, &si);
+ pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = hdpu_map_irq;
+
+ mv64x60_set_bus(&bh, 0, 0);
+ bh.hose_a->first_busno = 0;
+ bh.hose_a->last_busno = 0xff;
+ bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0);
+
+ bh.hose_b->first_busno = bh.hose_a->last_busno + 1;
+ mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno);
+ bh.hose_b->last_busno = 0xff;
+ bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b,
+ bh.hose_b->first_busno);
+
+ ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
+
+ hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_INIT_REG);
+ /*
+ * Enabling of PCI internal-vs-external arbitration
+ * is a platform- and errata-dependent decision.
+ */
+ return;
+}
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+static void __init hdpu_early_serial_map(void)
+{
+#ifdef CONFIG_KGDB
+ static char first_time = 1;
+
+#if defined(CONFIG_KGDB_TTYS0)
+#define KGDB_PORT 0
+#elif defined(CONFIG_KGDB_TTYS1)
+#define KGDB_PORT 1
+#else
+#error "Invalid kgdb_tty port"
+#endif
+
+ if (first_time) {
+ gt_early_mpsc_init(KGDB_PORT,
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL);
+ first_time = 0;
+ }
+
+ return;
+#endif
+}
+#endif
+
+static void hdpu_init2(void)
+{
+ return;
+}
+
+#if defined(CONFIG_MV643XX_ETH)
+static void __init hdpu_fixup_eth_pdata(struct platform_device *pd)
+{
+
+ struct mv643xx_eth_platform_data *eth_pd;
+ eth_pd = pd->dev.platform_data;
+
+ eth_pd->port_serial_control =
+ mv64x60_read(&bh, MV643XX_ETH_PORT_SERIAL_CONTROL_REG(pd->id) & ~1);
+
+ eth_pd->force_phy_addr = 1;
+ eth_pd->phy_addr = pd->id;
+ eth_pd->tx_queue_size = 400;
+ eth_pd->rx_queue_size = 800;
+}
+#endif
+
+static void __init hdpu_fixup_mpsc_pdata(struct platform_device *pd)
+{
+
+ struct mpsc_pdata *pdata;
+
+ pdata = (struct mpsc_pdata *)pd->dev.platform_data;
+
+ pdata->max_idle = 40;
+ if (ppcboot_bd_valid)
+ pdata->default_baud = ppcboot_bd.bi_baudrate;
+ else
+ pdata->default_baud = HDPU_DEFAULT_BAUD;
+ pdata->brg_clk_src = HDPU_MPSC_CLK_SRC;
+ pdata->brg_clk_freq = HDPU_MPSC_CLK_FREQ;
+}
+
+#if defined(CONFIG_HDPU_FEATURES)
+static void __init hdpu_fixup_cpustate_pdata(struct platform_device *pd)
+{
+ struct platform_device *pds[1];
+ pds[0] = pd;
+ mv64x60_pd_fixup(&bh, pds, 1);
+}
+#endif
+
+static int __init hdpu_platform_notify(struct device *dev)
+{
+ static struct {
+ char *bus_id;
+ void ((*rtn) (struct platform_device * pdev));
+ } dev_map[] = {
+ {
+ MPSC_CTLR_NAME ".0", hdpu_fixup_mpsc_pdata},
+#if defined(CONFIG_MV643XX_ETH)
+ {
+ MV643XX_ETH_NAME ".0", hdpu_fixup_eth_pdata},
+#endif
+#if defined(CONFIG_HDPU_FEATURES)
+ {
+ HDPU_CPUSTATE_NAME ".0", hdpu_fixup_cpustate_pdata},
+#endif
+ };
+ struct platform_device *pdev;
+ int i;
+
+ if (dev && dev->bus_id)
+ for (i = 0; i < ARRAY_SIZE(dev_map); i++)
+ if (!strncmp(dev->bus_id, dev_map[i].bus_id,
+ BUS_ID_SIZE)) {
+
+ pdev = container_of(dev,
+ struct platform_device,
+ dev);
+ dev_map[i].rtn(pdev);
+ }
+
+ return 0;
+}
+
+static void __init hdpu_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("hdpu_setup_arch: enter", 0);
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ ppc_md.heartbeat = hdpu_heartbeat;
+
+ ppc_md.heartbeat_reset = HZ;
+ ppc_md.heartbeat_count = 1;
+
+ if (ppc_md.progress)
+ ppc_md.progress("hdpu_setup_arch: Enabling L2 cache", 0);
+
+ /* Enable L1 Parity Bits */
+ hdpu_set_l1pe();
+
+ /* Enable L2 and L3 caches (if 745x) */
+ _set_L2CR(0x80080000);
+
+ if (ppc_md.progress)
+ ppc_md.progress("hdpu_setup_arch: enter", 0);
+
+ hdpu_setup_bridge();
+
+ hdpu_setup_peripherals();
+
+#ifdef CONFIG_SERIAL_MPSC_CONSOLE
+ hdpu_early_serial_map();
+#endif
+
+ printk("SKY HDPU Compute Blade \n");
+
+ if (ppc_md.progress)
+ ppc_md.progress("hdpu_setup_arch: exit", 0);
+
+ hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_OK);
+ return;
+}
+static void __init hdpu_init_irq(void)
+{
+ mv64360_init_irq();
+}
+
+static void __init hdpu_set_l1pe()
+{
+ unsigned long ictrl;
+ asm volatile ("mfspr %0, 1011":"=r" (ictrl):);
+ ictrl |= ICTRL_EICE | ICTRL_EDC | ICTRL_EICP;
+ asm volatile ("mtspr 1011, %0"::"r" (ictrl));
+}
+
+/*
+ * Set BAT 1 to map 0xf1000000 to end of physical memory space.
+ */
+static __inline__ void hdpu_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT1U, 0xf10001fe);
+ mtspr(SPRN_DBAT1L, 0xf100002a);
+ mb();
+
+ return;
+}
+
+unsigned long __init hdpu_find_end_of_memory(void)
+{
+ return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
+ MV64x60_TYPE_MV64360);
+}
+
+static void hdpu_reset_board(void)
+{
+ volatile int infinite = 1;
+
+ hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_RESET);
+
+ local_irq_disable();
+
+ /* Clear all the LEDs */
+ mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, ((1 << 4) |
+ (1 << 5) | (1 << 6)));
+
+ /* disable and invalidate the L2 cache */
+ _set_L2CR(0);
+ _set_L2CR(0x200000);
+
+ /* flush and disable L1 I/D cache */
+ __asm__ __volatile__
+ ("\n"
+ "mfspr 3,1008\n"
+ "ori 5,5,0xcc00\n"
+ "ori 4,3,0xc00\n"
+ "andc 5,3,5\n"
+ "sync\n"
+ "mtspr 1008,4\n"
+ "isync\n" "sync\n" "mtspr 1008,5\n" "isync\n" "sync\n");
+
+ /* Hit the reset bit */
+ mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (1 << 3));
+
+ while (infinite)
+ infinite = infinite;
+
+ return;
+}
+
+static void hdpu_restart(char *cmd)
+{
+ volatile ulong i = 10000000;
+
+ hdpu_reset_board();
+
+ while (i-- > 0) ;
+ panic("restart failed\n");
+}
+
+static void hdpu_halt(void)
+{
+ local_irq_disable();
+
+ hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_HALT);
+
+ /* Clear all the LEDs */
+ mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, ((1 << 4) | (1 << 5) |
+ (1 << 6)));
+ while (1) ;
+ /* NOTREACHED */
+}
+
+static void hdpu_power_off(void)
+{
+ hdpu_halt();
+ /* NOTREACHED */
+}
+
+static int hdpu_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid;
+
+ pvid = mfspr(SPRN_PVR);
+ seq_printf(m, "vendor\t\t: Sky Computers\n");
+ seq_printf(m, "machine\t\t: HDPU Compute Blade\n");
+ seq_printf(m, "PVID\t\t: 0x%x, vendor: %s\n",
+ pvid, (pvid & (1 << 15) ? "IBM" : "Motorola"));
+
+ return 0;
+}
+
+static void __init hdpu_calibrate_decr(void)
+{
+ ulong freq;
+
+ if (ppcboot_bd_valid)
+ freq = ppcboot_bd.bi_busfreq / 4;
+ else
+ freq = 133000000;
+
+ printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ freq / 1000000, freq % 1000000);
+
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+ return;
+}
+
+static void parse_bootinfo(unsigned long r3,
+ unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ bd_t *bd = NULL;
+ char *cmdline_start = NULL;
+ int cmdline_len = 0;
+
+ if (r3) {
+ if ((r3 & 0xf0000000) == 0)
+ r3 += KERNELBASE;
+ if ((r3 & 0xf0000000) == KERNELBASE) {
+ bd = (void *)r3;
+
+ memcpy(&ppcboot_bd, bd, sizeof(ppcboot_bd));
+ ppcboot_bd_valid = 1;
+ }
+ }
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (r4 && r5 && r5 > r4) {
+ if ((r4 & 0xf0000000) == 0)
+ r4 += KERNELBASE;
+ if ((r5 & 0xf0000000) == 0)
+ r5 += KERNELBASE;
+ if ((r4 & 0xf0000000) == KERNELBASE) {
+ initrd_start = r4;
+ initrd_end = r5;
+ initrd_below_start_ok = 1;
+ }
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ if (r6 && r7 && r7 > r6) {
+ if ((r6 & 0xf0000000) == 0)
+ r6 += KERNELBASE;
+ if ((r7 & 0xf0000000) == 0)
+ r7 += KERNELBASE;
+ if ((r6 & 0xf0000000) == KERNELBASE) {
+ cmdline_start = (void *)r6;
+ cmdline_len = (r7 - r6);
+ strncpy(cmd_line, cmdline_start, cmdline_len);
+ }
+ }
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+static int hdpu_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return check_region(from, extent);
+}
+
+static void
+hdpu_ide_request_region(ide_ioreg_t from, unsigned int extent, const char *name)
+{
+ request_region(from, extent, name);
+ return;
+}
+
+static void hdpu_ide_release_region(ide_ioreg_t from, unsigned int extent)
+{
+ release_region(from, extent);
+ return;
+}
+
+static void __init
+hdpu_ide_pci_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port,
+ ide_ioreg_t ctrl_port, int *irq)
+{
+ struct pci_dev *dev;
+
+ pci_for_each_dev(dev) {
+ if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) ||
+ ((dev->class >> 8) == PCI_CLASS_STORAGE_RAID)) {
+ hw->irq = dev->irq;
+
+ if (irq != NULL) {
+ *irq = dev->irq;
+ }
+ }
+ }
+
+ return;
+}
+#endif
+
+void hdpu_heartbeat(void)
+{
+ if (mv64x60_read(&bh, MV64x60_GPP_VALUE) & (1 << 5))
+ mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (1 << 5));
+ else
+ mv64x60_write(&bh, MV64x60_GPP_VALUE_SET, (1 << 5));
+
+ ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+
+}
+
+static void __init hdpu_map_io(void)
+{
+ io_block_mapping(0xf1000000, 0xf1000000, 0x20000, _PAGE_IO);
+}
+
+#ifdef CONFIG_SMP
+char hdpu_smp0[] = "SMP Cpu #0";
+char hdpu_smp1[] = "SMP Cpu #1";
+
+static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ volatile unsigned int doorbell;
+
+ doorbell = mv64x60_read(&bh, MV64360_CPU0_DOORBELL);
+
+ /* Ack the doorbell interrupts */
+ mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, doorbell);
+
+ if (doorbell & 1) {
+ smp_message_recv(0, regs);
+ }
+ if (doorbell & 2) {
+ smp_message_recv(1, regs);
+ }
+ if (doorbell & 4) {
+ smp_message_recv(2, regs);
+ }
+ if (doorbell & 8) {
+ smp_message_recv(3, regs);
+ }
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ volatile unsigned int doorbell;
+
+ doorbell = mv64x60_read(&bh, MV64360_CPU1_DOORBELL);
+
+ /* Ack the doorbell interrupts */
+ mv64x60_write(&bh, MV64360_CPU1_DOORBELL_CLR, doorbell);
+
+ if (doorbell & 1) {
+ smp_message_recv(0, regs);
+ }
+ if (doorbell & 2) {
+ smp_message_recv(1, regs);
+ }
+ if (doorbell & 4) {
+ smp_message_recv(2, regs);
+ }
+ if (doorbell & 8) {
+ smp_message_recv(3, regs);
+ }
+ return IRQ_HANDLED;
+}
+
+static void smp_hdpu_CPU_two(void)
+{
+ __asm__ __volatile__
+ ("\n"
+ "lis 3,0x0000\n"
+ "ori 3,3,0x00c0\n"
+ "mtspr 26, 3\n" "li 4,0\n" "mtspr 27,4\n" "rfi");
+
+}
+
+static int smp_hdpu_probe(void)
+{
+ int *cpu_count_reg;
+ int num_cpus = 0;
+
+ cpu_count_reg = ioremap(HDPU_NEXUS_ID_BASE, HDPU_NEXUS_ID_SIZE);
+ if (cpu_count_reg) {
+ num_cpus = (*cpu_count_reg >> 20) & 0x3;
+ iounmap(cpu_count_reg);
+ }
+
+ /* Validate the bits in the CPLD. If we could not map the reg, return 2.
+ * If the register reported 0 or 3, return 2.
+ * Older CPLD revisions set these bits to all ones (val = 3).
+ */
+ if ((num_cpus < 1) || (num_cpus > 2)) {
+ printk
+ ("Unable to determine the number of processors %d . deafulting to 2.\n",
+ num_cpus);
+ num_cpus = 2;
+ }
+ return num_cpus;
+}
+
+static void
+smp_hdpu_message_pass(int target, int msg, unsigned long data, int wait)
+{
+ if (msg > 0x3) {
+ printk("SMP %d: smp_message_pass: unknown msg %d\n",
+ smp_processor_id(), msg);
+ return;
+ }
+ switch (target) {
+ case MSG_ALL:
+ mv64x60_write(&bh, MV64360_CPU0_DOORBELL, 1 << msg);
+ mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg);
+ break;
+ case MSG_ALL_BUT_SELF:
+ if (smp_processor_id())
+ mv64x60_write(&bh, MV64360_CPU0_DOORBELL, 1 << msg);
+ else
+ mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg);
+ break;
+ default:
+ if (target == 0)
+ mv64x60_write(&bh, MV64360_CPU0_DOORBELL, 1 << msg);
+ else
+ mv64x60_write(&bh, MV64360_CPU1_DOORBELL, 1 << msg);
+ break;
+ }
+}
+
+static void smp_hdpu_kick_cpu(int nr)
+{
+ volatile unsigned int *bootaddr;
+
+ if (ppc_md.progress)
+ ppc_md.progress("smp_hdpu_kick_cpu", 0);
+
+ hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR | CPUSTATE_KERNEL_CPU1_KICK);
+
+ /* Disable BootCS. Must also reduce the windows size to zero. */
+ bh.ci->disable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, 0, 0, 0);
+
+ bootaddr = ioremap(HDPU_INTERNAL_SRAM_BASE, HDPU_INTERNAL_SRAM_SIZE);
+ if (!bootaddr) {
+ if (ppc_md.progress)
+ ppc_md.progress("smp_hdpu_kick_cpu: ioremap failed", 0);
+ return;
+ }
+
+ memcpy((void *)(bootaddr + 0x40), (void *)&smp_hdpu_CPU_two, 0x20);
+
+ /* map SRAM to 0xfff00000 */
+ bh.ci->disable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+ 0xfff00000, HDPU_INTERNAL_SRAM_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+
+ /* Enable CPU1 arbitration */
+ mv64x60_clr_bits(&bh, MV64x60_CPU_MASTER_CNTL, (1 << 9));
+
+ /*
+ * Wait 100mSecond until other CPU has reached __secondary_start.
+ * When it reaches, it is permittable to rever the SRAM mapping etc...
+ */
+ mdelay(100);
+ *(unsigned long *)KERNELBASE = nr;
+ asm volatile ("dcbf 0,%0"::"r" (KERNELBASE):"memory");
+
+ iounmap(bootaddr);
+
+ /* Set up window for internal sram (256KByte insize) */
+ bh.ci->disable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+ HDPU_INTERNAL_SRAM_BASE,
+ HDPU_INTERNAL_SRAM_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+ /*
+ * Set up windows for embedded FLASH (using boot CS window).
+ */
+
+ bh.ci->disable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+ HDPU_EMB_FLASH_BASE, HDPU_EMB_FLASH_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+}
+
+static void smp_hdpu_setup_cpu(int cpu_nr)
+{
+ if (cpu_nr == 0) {
+ if (ppc_md.progress)
+ ppc_md.progress("smp_hdpu_setup_cpu 0", 0);
+ mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, 0xff);
+ mv64x60_write(&bh, MV64360_CPU0_DOORBELL_MASK, 0xff);
+ request_irq(60, hdpu_smp_cpu0_int_handler,
+ SA_INTERRUPT, hdpu_smp0, 0);
+ }
+
+ if (cpu_nr == 1) {
+ if (ppc_md.progress)
+ ppc_md.progress("smp_hdpu_setup_cpu 1", 0);
+
+ hdpu_cpustate_set(CPUSTATE_KERNEL_MAJOR |
+ CPUSTATE_KERNEL_CPU1_OK);
+
+ /* Enable L1 Parity Bits */
+ hdpu_set_l1pe();
+
+ /* Enable L2 cache */
+ _set_L2CR(0);
+ _set_L2CR(0x80080000);
+
+ mv64x60_write(&bh, MV64360_CPU1_DOORBELL_CLR, 0x0);
+ mv64x60_write(&bh, MV64360_CPU1_DOORBELL_MASK, 0xff);
+ request_irq(28, hdpu_smp_cpu1_int_handler,
+ SA_INTERRUPT, hdpu_smp1, 0);
+ }
+
+}
+
+void __devinit hdpu_tben_give()
+{
+ volatile unsigned long *val = 0;
+
+ /* By writing 0 to the TBEN_BASE, the timebases is frozen */
+ val = ioremap(HDPU_TBEN_BASE, 4);
+ *val = 0;
+ mb();
+
+ spin_lock(&timebase_lock);
+ timebase_upper = get_tbu();
+ timebase_lower = get_tbl();
+ spin_unlock(&timebase_lock);
+
+ while (timebase_upper || timebase_lower)
+ barrier();
+
+ /* By writing 1 to the TBEN_BASE, the timebases is thawed */
+ *val = 1;
+ mb();
+
+ iounmap(val);
+
+}
+
+void __devinit hdpu_tben_take()
+{
+ while (!(timebase_upper || timebase_lower))
+ barrier();
+
+ spin_lock(&timebase_lock);
+ set_tb(timebase_upper, timebase_lower);
+ timebase_upper = 0;
+ timebase_lower = 0;
+ spin_unlock(&timebase_lock);
+}
+
+static struct smp_ops_t hdpu_smp_ops = {
+ .message_pass = smp_hdpu_message_pass,
+ .probe = smp_hdpu_probe,
+ .kick_cpu = smp_hdpu_kick_cpu,
+ .setup_cpu = smp_hdpu_setup_cpu,
+ .give_timebase = hdpu_tben_give,
+ .take_timebase = hdpu_tben_take,
+};
+#endif /* CONFIG_SMP */
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(r3, r4, r5, r6, r7);
+
+ isa_mem_base = 0;
+
+ ppc_md.setup_arch = hdpu_setup_arch;
+ ppc_md.init = hdpu_init2;
+ ppc_md.show_cpuinfo = hdpu_show_cpuinfo;
+ ppc_md.init_IRQ = hdpu_init_irq;
+ ppc_md.get_irq = mv64360_get_irq;
+ ppc_md.restart = hdpu_restart;
+ ppc_md.power_off = hdpu_power_off;
+ ppc_md.halt = hdpu_halt;
+ ppc_md.find_end_of_memory = hdpu_find_end_of_memory;
+ ppc_md.calibrate_decr = hdpu_calibrate_decr;
+ ppc_md.setup_io_mappings = hdpu_map_io;
+
+ bh.p_base = CONFIG_MV64X60_NEW_BASE;
+ bh.v_base = (unsigned long *)bh.p_base;
+
+ hdpu_set_bat();
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG)
+ ppc_md.progress = hdpu_mpsc_progress; /* embedded UART */
+ mv64x60_progress_init(bh.p_base);
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+
+#ifdef CONFIG_SMP
+ ppc_md.smp_ops = &hdpu_smp_ops;
+#endif /* CONFIG_SMP */
+
+#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH)
+ platform_notify = hdpu_platform_notify;
+#endif
+ return;
+}
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
+/* SMP safe version of the serial text debug routine. Uses Semaphore 0 */
+void hdpu_mpsc_progress(char *s, unsigned short hex)
+{
+ while (mv64x60_read(&bh, MV64360_WHO_AM_I) !=
+ mv64x60_read(&bh, MV64360_SEMAPHORE_0)) {
+ }
+ mv64x60_mpsc_progress(s, hex);
+ mv64x60_write(&bh, MV64360_SEMAPHORE_0, 0xff);
+}
+#endif
+
+static void hdpu_cpustate_set(unsigned char new_state)
+{
+ unsigned int state = (new_state << 21);
+ mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, (0xff << 21));
+ mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, state);
+}
+
+#ifdef CONFIG_MTD_PHYSMAP
+static struct mtd_partition hdpu_partitions[] = {
+ {
+ .name = "Root FS",
+ .size = 0x03400000,
+ .offset = 0,
+ .mask_flags = 0,
+ },{
+ .name = "User FS",
+ .size = 0x00800000,
+ .offset = 0x03400000,
+ .mask_flags = 0,
+ },{
+ .name = "Kernel Image",
+ .size = 0x002C0000,
+ .offset = 0x03C00000,
+ .mask_flags = 0,
+ },{
+ .name = "bootEnv",
+ .size = 0x00040000,
+ .offset = 0x03EC0000,
+ .mask_flags = 0,
+ },{
+ .name = "bootROM",
+ .size = 0x00100000,
+ .offset = 0x03F00000,
+ .mask_flags = 0,
+ }
+};
+
+static int __init hdpu_setup_mtd(void)
+{
+
+ physmap_set_partitions(hdpu_partitions, 5);
+ return 0;
+}
+
+arch_initcall(hdpu_setup_mtd);
+#endif
+
+#ifdef CONFIG_HDPU_FEATURES
+
+static struct resource hdpu_cpustate_resources[] = {
+ [0] = {
+ .name = "addr base",
+ .start = MV64x60_GPP_VALUE_SET,
+ .end = MV64x60_GPP_VALUE_CLR + 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource hdpu_nexus_resources[] = {
+ [0] = {
+ .name = "nexus register",
+ .start = HDPU_NEXUS_ID_BASE,
+ .end = HDPU_NEXUS_ID_BASE + HDPU_NEXUS_ID_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device hdpu_cpustate_device = {
+ .name = HDPU_CPUSTATE_NAME,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(hdpu_cpustate_resources),
+ .resource = hdpu_cpustate_resources,
+};
+
+static struct platform_device hdpu_nexus_device = {
+ .name = HDPU_NEXUS_NAME,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(hdpu_nexus_resources),
+ .resource = hdpu_nexus_resources,
+};
+
+static int __init hdpu_add_pds(void)
+{
+ platform_device_register(&hdpu_cpustate_device);
+ platform_device_register(&hdpu_nexus_device);
+ return 0;
+}
+
+arch_initcall(hdpu_add_pds);
+#endif
diff --git a/arch/ppc/platforms/hdpu.h b/arch/ppc/platforms/hdpu.h
new file mode 100644
index 00000000000..07c3cffb5c7
--- /dev/null
+++ b/arch/ppc/platforms/hdpu.h
@@ -0,0 +1,82 @@
+/*
+ * arch/ppc/platforms/hdpu.h
+ *
+ * Definitions for Sky Computers HDPU board.
+ *
+ * Brian Waite <waite@skycomputers.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by Mark A. Greer <mgreer@mvista.com>
+ * Based on code done by Tim Montgomery <timm@artesyncp.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.
+ */
+
+/*
+ * The MV64360 has 2 PCI buses each with 1 window from the CPU bus to
+ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
+ * We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 64K and start
+ * on a boundary that is a multiple of the window size):
+ *
+ * 0x80000000-0x8fffffff - PCI 0 MEM
+ * 0xa0000000-0xafffffff - PCI 1 MEM
+ * 0xc0000000-0xc0ffffff - PCI 0 I/O
+ * 0xc1000000-0xc1ffffff - PCI 1 I/O
+
+ * 0xf1000000-0xf100ffff - MV64360 Registers
+ * 0xf1010000-0xfb9fffff - HOLE
+ * 0xfbfa0000-0xfbfaffff - TBEN
+ * 0xfbf00000-0xfbfbffff - NEXUS
+ * 0xfbfc0000-0xfbffffff - Internal SRAM
+ * 0xfc000000-0xffffffff - Boot window
+ */
+
+#ifndef __PPC_PLATFORMS_HDPU_H
+#define __PPC_PLATFORMS_HDPU_H
+
+/* CPU Physical Memory Map setup. */
+#define HDPU_BRIDGE_REG_BASE 0xf1000000
+
+#define HDPU_TBEN_BASE 0xfbfa0000
+#define HDPU_TBEN_SIZE 0x00010000
+#define HDPU_NEXUS_ID_BASE 0xfbfb0000
+#define HDPU_NEXUS_ID_SIZE 0x00010000
+#define HDPU_INTERNAL_SRAM_BASE 0xfbfc0000
+#define HDPU_INTERNAL_SRAM_SIZE 0x00040000
+#define HDPU_EMB_FLASH_BASE 0xfc000000
+#define HDPU_EMB_FLASH_SIZE 0x04000000
+
+/* PCI Mappings */
+
+#define HDPU_PCI0_MEM_START_PROC_ADDR 0x80000000
+#define HDPU_PCI0_MEM_START_PCI_HI_ADDR 0x00000000
+#define HDPU_PCI0_MEM_START_PCI_LO_ADDR HDPU_PCI0_MEM_START_PROC_ADDR
+#define HDPU_PCI0_MEM_SIZE 0x10000000
+
+#define HDPU_PCI1_MEM_START_PROC_ADDR 0xc0000000
+#define HDPU_PCI1_MEM_START_PCI_HI_ADDR 0x00000000
+#define HDPU_PCI1_MEM_START_PCI_LO_ADDR HDPU_PCI1_MEM_START_PROC_ADDR
+#define HDPU_PCI1_MEM_SIZE 0x20000000
+
+#define HDPU_PCI0_IO_START_PROC_ADDR 0xc0000000
+#define HDPU_PCI0_IO_START_PCI_ADDR 0x00000000
+#define HDPU_PCI0_IO_SIZE 0x01000000
+
+#define HDPU_PCI1_IO_START_PROC_ADDR 0xc1000000
+#define HDPU_PCI1_IO_START_PCI_ADDR 0x01000000
+#define HDPU_PCI1_IO_SIZE 0x01000000
+
+#define HDPU_DEFAULT_BAUD 115200
+#define HDPU_MPSC_CLK_SRC 8 /* TCLK */
+#define HDPU_MPSC_CLK_FREQ 133000000 /* 133 Mhz */
+
+#define HDPU_PCI_0_IRQ (8+64)
+#define HDPU_PCI_1_IRQ (13+64)
+
+#endif /* __PPC_PLATFORMS_HDPU_H */
diff --git a/arch/ppc/platforms/hermes.h b/arch/ppc/platforms/hermes.h
new file mode 100644
index 00000000000..198fc590b9f
--- /dev/null
+++ b/arch/ppc/platforms/hermes.h
@@ -0,0 +1,27 @@
+/*
+ * Multidata HERMES-PRO ( / SL ) board specific definitions
+ *
+ * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifndef __MACH_HERMES_H
+#define __MACH_HERMES_H
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define HERMES_IMMR_BASE 0xFF000000 /* phys. addr of IMMR */
+#define HERMES_IMAP_SIZE (64 * 1024) /* size of mapped area */
+
+#define IMAP_ADDR HERMES_IMMR_BASE /* physical base address of IMMR area */
+#define IMAP_SIZE HERMES_IMAP_SIZE /* mapped size of IMMR area */
+
+#define FEC_INTERRUPT 9 /* = SIU_LEVEL4 */
+#define CPM_INTERRUPT 11 /* = SIU_LEVEL5 (was: SIU_LEVEL2) */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif /* __MACH_HERMES_H */
diff --git a/arch/ppc/platforms/ip860.h b/arch/ppc/platforms/ip860.h
new file mode 100644
index 00000000000..8c3836c5f05
--- /dev/null
+++ b/arch/ppc/platforms/ip860.h
@@ -0,0 +1,36 @@
+/*
+ * MicroSys IP860 VMEBus board specific definitions
+ *
+ * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifndef __MACH_IP860_H
+#define __MACH_IP860_H
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define IP860_IMMR_BASE 0xF1000000 /* phys. addr of IMMR */
+#define IP860_IMAP_SIZE (64 * 1024) /* size of mapped area */
+
+#define IMAP_ADDR IP860_IMMR_BASE /* physical base address of IMMR area */
+#define IMAP_SIZE IP860_IMAP_SIZE /* mapped size of IMMR area */
+
+/*
+ * MPC8xx Chip Select Usage
+ */
+#define IP860_BOOT_CS 0 /* Boot (VMEBus or Flash) Chip Select 0 */
+#define IP860_FLASH_CS 1 /* Flash is on Chip Select 1 */
+#define IP860_SDRAM_CS 2 /* SDRAM is on Chip Select 2 */
+#define IP860_SRAM_CS 3 /* SRAM is on Chip Select 3 */
+#define IP860_BCSR_CS 4 /* BCSR is on Chip Select 4 */
+#define IP860_IP_CS 5 /* IP Slots are on Chip Select 5 */
+#define IP860_VME_STD_CS 6 /* VME Standard I/O is on Chip Select 6 */
+#define IP860_VME_SHORT_CS 7 /* VME Short I/O is on Chip Select 7 */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif /* __MACH_IP860_H */
diff --git a/arch/ppc/platforms/ivms8.h b/arch/ppc/platforms/ivms8.h
new file mode 100644
index 00000000000..d4be310f808
--- /dev/null
+++ b/arch/ppc/platforms/ivms8.h
@@ -0,0 +1,56 @@
+/*
+ * Speech Design Integrated Voicemail board specific definitions
+ * - IVMS8 (small, 8 channels)
+ * - IVML24 (large, 24 channels)
+ *
+ * In 2.5 when we force a new bootloader, we can merge these two, and add
+ * in _MACH_'s for them. -- Tom
+ *
+ * Copyright (c) 2000, 2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IVMS8_H__
+#define __ASM_IVMS8_H__
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define IVMS_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */
+#define IVMS_IMAP_SIZE (64 * 1024) /* size of mapped area */
+
+#define IMAP_ADDR IVMS_IMMR_BASE /* phys. base address of IMMR area */
+#define IMAP_SIZE IVMS_IMAP_SIZE /* mapped size of IMMR area */
+
+#define PCMCIA_MEM_ADDR ((uint)0xFE100000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
+
+#define FEC_INTERRUPT 9 /* = SIU_LEVEL4 */
+#define IDE0_INTERRUPT 10 /* = IRQ5 */
+#define CPM_INTERRUPT 11 /* = SIU_LEVEL5 (was: SIU_LEVEL2) */
+#define PHY_INTERRUPT 12 /* = IRQ6 */
+
+/* override the default number of IDE hardware interfaces */
+#define MAX_HWIFS 1
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET 0x0000 /* Offset in PCMCIA memory */
+#define IDE0_DATA_REG_OFFSET 0x0000
+#define IDE0_ERROR_REG_OFFSET 0x0081
+#define IDE0_NSECTOR_REG_OFFSET 0x0082
+#define IDE0_SECTOR_REG_OFFSET 0x0083
+#define IDE0_LCYL_REG_OFFSET 0x0084
+#define IDE0_HCYL_REG_OFFSET 0x0085
+#define IDE0_SELECT_REG_OFFSET 0x0086
+#define IDE0_STATUS_REG_OFFSET 0x0087
+#define IDE0_CONTROL_REG_OFFSET 0x0106
+#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */
+
+/* We don't use the 8259. */
+#define NR_8259_INTS 0
+
+#endif /* __ASM_IVMS8_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/k2.c b/arch/ppc/platforms/k2.c
new file mode 100644
index 00000000000..aacb438708f
--- /dev/null
+++ b/arch/ppc/platforms/k2.c
@@ -0,0 +1,613 @@
+/*
+ * arch/ppc/platforms/k2.c
+ *
+ * Board setup routines for SBS K2
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Updated by: Randy Vinson <rvinson@mvista.com.
+ *
+ * 2001-2004 (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/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/i8259.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+
+#include <syslib/cpc710.h>
+#include "k2.h"
+
+extern unsigned long loops_per_jiffy;
+extern void gen550_progress(char *, unsigned short);
+
+static unsigned int cpu_7xx[16] = {
+ 0, 15, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 16, 12, 7, 0
+};
+static unsigned int cpu_6xx[16] = {
+ 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
+};
+
+static inline int __init
+k2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+ /*
+ * Check our hose index. If we are zero then we are on the
+ * local PCI hose, otherwise we are on the cPCI hose.
+ */
+ if (!hose->index) {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {1, 0, 0, 0}, /* Ethernet */
+ {5, 5, 5, 5}, /* PMC Site 1 */
+ {6, 6, 6, 6}, /* PMC Site 2 */
+ {0, 0, 0, 0}, /* unused */
+ {0, 0, 0, 0}, /* unused */
+ {0, 0, 0, 0}, /* PCI-ISA Bridge */
+ {0, 0, 0, 0}, /* unused */
+ {0, 0, 0, 0}, /* unused */
+ {0, 0, 0, 0}, /* unused */
+ {0, 0, 0, 0}, /* unused */
+ {0, 0, 0, 0}, /* unused */
+ {0, 0, 0, 0}, /* unused */
+ {0, 0, 0, 0}, /* unused */
+ {0, 0, 0, 0}, /* unused */
+ {15, 0, 0, 0}, /* M5229 IDE */
+ };
+ const long min_idsel = 3, max_idsel = 17, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ } else {
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {10, 11, 12, 9}, /* cPCI slot 8 */
+ {11, 12, 9, 10}, /* cPCI slot 7 */
+ {12, 9, 10, 11}, /* cPCI slot 6 */
+ {9, 10, 11, 12}, /* cPCI slot 5 */
+ {10, 11, 12, 9}, /* cPCI slot 4 */
+ {11, 12, 9, 10}, /* cPCI slot 3 */
+ {12, 9, 10, 11}, /* cPCI slot 2 */
+ };
+ const long min_idsel = 15, max_idsel = 21, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+ }
+}
+
+void k2_pcibios_fixup(void)
+{
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ struct pci_dev *ide_dev;
+
+ /*
+ * Enable DMA support on hdc
+ */
+ ide_dev = pci_get_device(PCI_VENDOR_ID_AL,
+ PCI_DEVICE_ID_AL_M5229, NULL);
+
+ if (ide_dev) {
+
+ unsigned long ide_dma_base;
+
+ ide_dma_base = pci_resource_start(ide_dev, 4);
+ outb(0x00, ide_dma_base + 0x2);
+ outb(0x20, ide_dma_base + 0xa);
+ pci_dev_put(ide_dev);
+ }
+#endif
+}
+
+void k2_pcibios_fixup_resources(struct pci_dev *dev)
+{
+ int i;
+
+ if ((dev->vendor == PCI_VENDOR_ID_IBM) &&
+ (dev->device == PCI_DEVICE_ID_IBM_CPC710_PCI64)) {
+ pr_debug("Fixup CPC710 resources\n");
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ dev->resource[i].start = 0;
+ dev->resource[i].end = 0;
+ }
+ }
+}
+
+void k2_setup_hoses(void)
+{
+ struct pci_controller *hose_a, *hose_b;
+
+ /*
+ * Reconfigure CPC710 memory map so
+ * we have some more PCI memory space.
+ */
+
+ /* Set FPHB mode */
+ __raw_writel(0x808000e0, PGCHP); /* Set FPHB mode */
+
+ /* PCI32 mappings */
+ __raw_writel(0x00000000, K2_PCI32_BAR + PIBAR); /* PCI I/O base */
+ __raw_writel(0x00000000, K2_PCI32_BAR + PMBAR); /* PCI Mem base */
+ __raw_writel(0xf0000000, K2_PCI32_BAR + MSIZE); /* 256MB */
+ __raw_writel(0xfff00000, K2_PCI32_BAR + IOSIZE); /* 1MB */
+ __raw_writel(0xc0000000, K2_PCI32_BAR + SMBAR); /* Base@0xc0000000 */
+ __raw_writel(0x80000000, K2_PCI32_BAR + SIBAR); /* Base@0x80000000 */
+ __raw_writel(0x000000c0, K2_PCI32_BAR + PSSIZE); /* 1GB space */
+ __raw_writel(0x000000c0, K2_PCI32_BAR + PPSIZE); /* 1GB space */
+ __raw_writel(0x00000000, K2_PCI32_BAR + BARPS); /* Base@0x00000000 */
+ __raw_writel(0x00000000, K2_PCI32_BAR + BARPP); /* Base@0x00000000 */
+ __raw_writel(0x00000080, K2_PCI32_BAR + PSBAR); /* Base@0x80 */
+ __raw_writel(0x00000000, K2_PCI32_BAR + PPBAR);
+
+ __raw_writel(0xc0000000, K2_PCI32_BAR + BPMDLK);
+ __raw_writel(0xd0000000, K2_PCI32_BAR + TPMDLK);
+ __raw_writel(0x80000000, K2_PCI32_BAR + BIODLK);
+ __raw_writel(0x80100000, K2_PCI32_BAR + TIODLK);
+ __raw_writel(0xe0008000, K2_PCI32_BAR + DLKCTRL);
+ __raw_writel(0xffffffff, K2_PCI32_BAR + DLKDEV);
+
+ /* PCI64 mappings */
+ __raw_writel(0x00100000, K2_PCI64_BAR + PIBAR); /* PCI I/O base */
+ __raw_writel(0x10000000, K2_PCI64_BAR + PMBAR); /* PCI Mem base */
+ __raw_writel(0xf0000000, K2_PCI64_BAR + MSIZE); /* 256MB */
+ __raw_writel(0xfff00000, K2_PCI64_BAR + IOSIZE); /* 1MB */
+ __raw_writel(0xd0000000, K2_PCI64_BAR + SMBAR); /* Base@0xd0000000 */
+ __raw_writel(0x80100000, K2_PCI64_BAR + SIBAR); /* Base@0x80100000 */
+ __raw_writel(0x000000c0, K2_PCI64_BAR + PSSIZE); /* 1GB space */
+ __raw_writel(0x000000c0, K2_PCI64_BAR + PPSIZE); /* 1GB space */
+ __raw_writel(0x00000000, K2_PCI64_BAR + BARPS); /* Base@0x00000000 */
+ __raw_writel(0x00000000, K2_PCI64_BAR + BARPP); /* Base@0x00000000 */
+
+ /* Setup PCI32 hose */
+ hose_a = pcibios_alloc_controller();
+ if (!hose_a)
+ return;
+
+ hose_a->first_busno = 0;
+ hose_a->last_busno = 0xff;
+ hose_a->pci_mem_offset = K2_PCI32_MEM_BASE;
+
+ pci_init_resource(&hose_a->io_resource,
+ K2_PCI32_LOWER_IO,
+ K2_PCI32_UPPER_IO,
+ IORESOURCE_IO, "PCI32 host bridge");
+
+ pci_init_resource(&hose_a->mem_resources[0],
+ K2_PCI32_LOWER_MEM + K2_PCI32_MEM_BASE,
+ K2_PCI32_UPPER_MEM + K2_PCI32_MEM_BASE,
+ IORESOURCE_MEM, "PCI32 host bridge");
+
+ hose_a->io_space.start = K2_PCI32_LOWER_IO;
+ hose_a->io_space.end = K2_PCI32_UPPER_IO;
+ hose_a->mem_space.start = K2_PCI32_LOWER_MEM;
+ hose_a->mem_space.end = K2_PCI32_UPPER_MEM;
+ hose_a->io_base_virt = (void *)K2_ISA_IO_BASE;
+
+ setup_indirect_pci(hose_a, K2_PCI32_CONFIG_ADDR, K2_PCI32_CONFIG_DATA);
+
+ /* Initialize PCI32 bus registers */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(0, 0),
+ CPC710_BUS_NUMBER, hose_a->first_busno);
+
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(0, 0),
+ CPC710_SUB_BUS_NUMBER, hose_a->last_busno);
+
+ /* Enable PCI interrupt polling */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(8, 0), 0x45, 0x80);
+
+ /* Route polled PCI interrupts */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(8, 0), 0x48, 0x58);
+
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(8, 0), 0x49, 0x07);
+
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(8, 0), 0x4a, 0x31);
+
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(8, 0), 0x4b, 0xb9);
+
+ /* route secondary IDE channel interrupt to IRQ 15 */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(8, 0), 0x75, 0x0f);
+
+ /* enable IDE controller IDSEL */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(8, 0), 0x58, 0x48);
+
+ /* Enable IDE function */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(17, 0), 0x50, 0x03);
+
+ /* Set M5229 IDE controller to native mode */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(17, 0), PCI_CLASS_PROG, 0xdf);
+
+ hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
+
+ /* Write out correct max subordinate bus number for hose A */
+ early_write_config_byte(hose_a,
+ hose_a->first_busno,
+ PCI_DEVFN(0, 0),
+ CPC710_SUB_BUS_NUMBER, hose_a->last_busno);
+
+ /* Only setup PCI64 hose if we are in the system slot */
+ if (!(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK)) {
+ /* Setup PCI64 hose */
+ hose_b = pcibios_alloc_controller();
+ if (!hose_b)
+ return;
+
+ hose_b->first_busno = hose_a->last_busno + 1;
+ hose_b->last_busno = 0xff;
+
+ /* Reminder: quit changing the following, it is correct. */
+ hose_b->pci_mem_offset = K2_PCI32_MEM_BASE;
+
+ pci_init_resource(&hose_b->io_resource,
+ K2_PCI64_LOWER_IO,
+ K2_PCI64_UPPER_IO,
+ IORESOURCE_IO, "PCI64 host bridge");
+
+ pci_init_resource(&hose_b->mem_resources[0],
+ K2_PCI64_LOWER_MEM + K2_PCI32_MEM_BASE,
+ K2_PCI64_UPPER_MEM + K2_PCI32_MEM_BASE,
+ IORESOURCE_MEM, "PCI64 host bridge");
+
+ hose_b->io_space.start = K2_PCI64_LOWER_IO;
+ hose_b->io_space.end = K2_PCI64_UPPER_IO;
+ hose_b->mem_space.start = K2_PCI64_LOWER_MEM;
+ hose_b->mem_space.end = K2_PCI64_UPPER_MEM;
+ hose_b->io_base_virt = (void *)K2_ISA_IO_BASE;
+
+ setup_indirect_pci(hose_b,
+ K2_PCI64_CONFIG_ADDR, K2_PCI64_CONFIG_DATA);
+
+ /* Initialize PCI64 bus registers */
+ early_write_config_byte(hose_b,
+ 0,
+ PCI_DEVFN(0, 0),
+ CPC710_SUB_BUS_NUMBER, 0xff);
+
+ early_write_config_byte(hose_b,
+ 0,
+ PCI_DEVFN(0, 0),
+ CPC710_BUS_NUMBER, hose_b->first_busno);
+
+ hose_b->last_busno = pciauto_bus_scan(hose_b,
+ hose_b->first_busno);
+
+ /* Write out correct max subordinate bus number for hose B */
+ early_write_config_byte(hose_b,
+ hose_b->first_busno,
+ PCI_DEVFN(0, 0),
+ CPC710_SUB_BUS_NUMBER,
+ hose_b->last_busno);
+
+ /* Configure PCI64 PSBAR */
+ early_write_config_dword(hose_b,
+ hose_b->first_busno,
+ PCI_DEVFN(0, 0),
+ PCI_BASE_ADDRESS_0,
+ K2_PCI64_SYS_MEM_BASE);
+ }
+
+ /* Configure i8259 level/edge settings */
+ outb(0x62, 0x4d0);
+ outb(0xde, 0x4d1);
+
+#ifdef CONFIG_CPC710_DATA_GATHERING
+ {
+ unsigned int tmp;
+ tmp = __raw_readl(ABCNTL);
+ /* Enable data gathering on both PCI interfaces */
+ __raw_writel(tmp | 0x05000000, ABCNTL);
+ }
+#endif
+
+ ppc_md.pcibios_fixup = k2_pcibios_fixup;
+ ppc_md.pcibios_fixup_resources = k2_pcibios_fixup_resources;
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = k2_map_irq;
+}
+
+static int k2_get_bus_speed(void)
+{
+ int bus_speed;
+ unsigned char board_id;
+
+ board_id = *(unsigned char *)K2_BOARD_ID_REG;
+
+ switch (K2_BUS_SPD(board_id)) {
+
+ case 0:
+ default:
+ bus_speed = 100000000;
+ break;
+
+ case 1:
+ bus_speed = 83333333;
+ break;
+
+ case 2:
+ bus_speed = 75000000;
+ break;
+
+ case 3:
+ bus_speed = 66666666;
+ break;
+ }
+ return bus_speed;
+}
+
+static int k2_get_cpu_speed(void)
+{
+ unsigned long hid1;
+ int cpu_speed;
+
+ hid1 = mfspr(SPRN_HID1) >> 28;
+
+ if ((mfspr(SPRN_PVR) >> 16) == 8)
+ hid1 = cpu_7xx[hid1];
+ else
+ hid1 = cpu_6xx[hid1];
+
+ cpu_speed = k2_get_bus_speed() * hid1 / 2;
+ return cpu_speed;
+}
+
+static void __init k2_calibrate_decr(void)
+{
+ int freq, divisor = 4;
+
+ /* determine processor bus speed */
+ freq = k2_get_bus_speed();
+ tb_ticks_per_jiffy = freq / HZ / divisor;
+ tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
+}
+
+static int k2_show_cpuinfo(struct seq_file *m)
+{
+ unsigned char k2_geo_bits, k2_system_slot;
+
+ seq_printf(m, "vendor\t\t: SBS\n");
+ seq_printf(m, "machine\t\t: K2\n");
+ seq_printf(m, "cpu speed\t: %dMhz\n", k2_get_cpu_speed() / 1000000);
+ seq_printf(m, "bus speed\t: %dMhz\n", k2_get_bus_speed() / 1000000);
+ seq_printf(m, "memory type\t: SDRAM\n");
+
+ k2_geo_bits = readb(K2_MSIZ_GEO_REG) & K2_GEO_ADR_MASK;
+ k2_system_slot = !(readb(K2_MISC_REG) & K2_SYS_SLOT_MASK);
+ seq_printf(m, "backplane\t: %s slot board",
+ k2_system_slot ? "System" : "Non system");
+ seq_printf(m, "with geographical address %x\n", k2_geo_bits);
+
+ return 0;
+}
+
+TODC_ALLOC();
+
+static void __init k2_setup_arch(void)
+{
+ unsigned int cpu;
+
+ /* Setup TODC access */
+ TODC_INIT(TODC_TYPE_MK48T37, 0, 0,
+ ioremap(K2_RTC_BASE_ADDRESS, K2_RTC_SIZE), 8);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000 / HZ;
+
+ /* make FLASH transactions higher priority than PCI to avoid deadlock */
+ __raw_writel(__raw_readl(SIOC1) | 0x80000000, SIOC1);
+
+ /* Set hardware to access FLASH page 2 */
+ __raw_writel(1 << 29, GPOUT);
+
+ /* Setup PCI host bridges */
+ k2_setup_hoses();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDC1;
+#endif
+
+ /* Identify the system */
+ printk(KERN_INFO "System Identification: SBS K2 - PowerPC 750 @ "
+ "%d Mhz\n", k2_get_cpu_speed() / 1000000);
+ printk(KERN_INFO "Port by MontaVista Software, Inc. "
+ "(source@mvista.com)\n");
+
+ /* Identify the CPU manufacturer */
+ cpu = PVR_REV(mfspr(SPRN_PVR));
+ printk(KERN_INFO "CPU manufacturer: %s [rev=%04x]\n",
+ (cpu & (1 << 15)) ? "IBM" : "Motorola", cpu);
+}
+
+static void k2_restart(char *cmd)
+{
+ local_irq_disable();
+
+ /* Flip FLASH back to page 1 to access firmware image */
+ __raw_writel(0, GPOUT);
+
+ /* SRR0 has system reset vector, SRR1 has default MSR value */
+ /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+ mtspr(SPRN_SRR0, 0xfff00100);
+ mtspr(SPRN_SRR1, 0);
+ __asm__ __volatile__("rfi\n\t");
+
+ /* not reached */
+ for (;;) ;
+}
+
+static void k2_power_off(void)
+{
+ for (;;) ;
+}
+
+static void k2_halt(void)
+{
+ k2_restart(NULL);
+}
+
+/*
+ * Set BAT 3 to map PCI32 I/O space.
+ */
+static __inline__ void k2_set_bat(void)
+{
+ /* wait for all outstanding memory accesses to complete */
+ mb();
+
+ /* setup DBATs */
+ mtspr(SPRN_DBAT2U, 0x80001ffe);
+ mtspr(SPRN_DBAT2L, 0x8000002a);
+ mtspr(SPRN_DBAT3U, 0xf0001ffe);
+ mtspr(SPRN_DBAT3L, 0xf000002a);
+
+ /* wait for updates */
+ mb();
+}
+
+static unsigned long __init k2_find_end_of_memory(void)
+{
+ unsigned long total;
+ unsigned char msize = 7; /* Default to 128MB */
+
+ msize = K2_MEM_SIZE(readb(K2_MSIZ_GEO_REG));
+
+ switch (msize) {
+ case 2:
+ /*
+ * This will break without a lowered
+ * KERNELBASE or CONFIG_HIGHMEM on.
+ * It seems non 1GB builds exist yet,
+ * though.
+ */
+ total = K2_MEM_SIZE_1GB;
+ break;
+ case 3:
+ case 4:
+ total = K2_MEM_SIZE_512MB;
+ break;
+ case 5:
+ case 6:
+ total = K2_MEM_SIZE_256MB;
+ break;
+ case 7:
+ total = K2_MEM_SIZE_128MB;
+ break;
+ default:
+ printk
+ ("K2: Invalid memory size detected, defaulting to 128MB\n");
+ total = K2_MEM_SIZE_128MB;
+ break;
+ }
+ return total;
+}
+
+static void __init k2_map_io(void)
+{
+ io_block_mapping(K2_PCI32_IO_BASE,
+ K2_PCI32_IO_BASE, 0x00200000, _PAGE_IO);
+ io_block_mapping(0xff000000, 0xff000000, 0x01000000, _PAGE_IO);
+}
+
+static void __init k2_init_irq(void)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ irq_desc[i].handler = &i8259_pic;
+
+ i8259_init(0);
+}
+
+void __init platform_init(unsigned long r3, unsigned long r4,
+ unsigned long r5, unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo((struct bi_record *)(r3 + KERNELBASE));
+
+ k2_set_bat();
+
+ isa_io_base = K2_ISA_IO_BASE;
+ isa_mem_base = K2_ISA_MEM_BASE;
+ pci_dram_offset = K2_PCI32_SYS_MEM_BASE;
+
+ ppc_md.setup_arch = k2_setup_arch;
+ ppc_md.show_cpuinfo = k2_show_cpuinfo;
+ ppc_md.init_IRQ = k2_init_irq;
+ ppc_md.get_irq = i8259_irq;
+
+ ppc_md.find_end_of_memory = k2_find_end_of_memory;
+ ppc_md.setup_io_mappings = k2_map_io;
+
+ ppc_md.restart = k2_restart;
+ ppc_md.power_off = k2_power_off;
+ ppc_md.halt = k2_halt;
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.calibrate_decr = k2_calibrate_decr;
+
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = gen550_progress;
+#endif
+}
diff --git a/arch/ppc/platforms/k2.h b/arch/ppc/platforms/k2.h
new file mode 100644
index 00000000000..78326aba198
--- /dev/null
+++ b/arch/ppc/platforms/k2.h
@@ -0,0 +1,82 @@
+/*
+ * arch/ppc/platforms/k2.h
+ *
+ * Definitions for SBS K2 board support
+ *
+ * Author: Matt Porter <mporter@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_PLATFORMS_K2_H
+#define __PPC_PLATFORMS_K2_H
+
+/*
+ * SBS K2 definitions
+ */
+
+#define K2_PCI64_BAR 0xff400000
+#define K2_PCI32_BAR 0xff500000
+
+#define K2_PCI64_CONFIG_ADDR (K2_PCI64_BAR + 0x000f8000)
+#define K2_PCI64_CONFIG_DATA (K2_PCI64_BAR + 0x000f8010)
+
+#define K2_PCI32_CONFIG_ADDR (K2_PCI32_BAR + 0x000f8000)
+#define K2_PCI32_CONFIG_DATA (K2_PCI32_BAR + 0x000f8010)
+
+#define K2_PCI64_MEM_BASE 0xd0000000
+#define K2_PCI64_IO_BASE 0x80100000
+
+#define K2_PCI32_MEM_BASE 0xc0000000
+#define K2_PCI32_IO_BASE 0x80000000
+
+#define K2_PCI32_SYS_MEM_BASE 0x80000000
+#define K2_PCI64_SYS_MEM_BASE K2_PCI32_SYS_MEM_BASE
+
+#define K2_PCI32_LOWER_MEM 0x00000000
+#define K2_PCI32_UPPER_MEM 0x0fffffff
+#define K2_PCI32_LOWER_IO 0x00000000
+#define K2_PCI32_UPPER_IO 0x000fffff
+
+#define K2_PCI64_LOWER_MEM 0x10000000
+#define K2_PCI64_UPPER_MEM 0x1fffffff
+#define K2_PCI64_LOWER_IO 0x00100000
+#define K2_PCI64_UPPER_IO 0x001fffff
+
+#define K2_ISA_IO_BASE K2_PCI32_IO_BASE
+#define K2_ISA_MEM_BASE K2_PCI32_MEM_BASE
+
+#define K2_BOARD_ID_REG (K2_ISA_IO_BASE + 0x800)
+#define K2_MISC_REG (K2_ISA_IO_BASE + 0x804)
+#define K2_MSIZ_GEO_REG (K2_ISA_IO_BASE + 0x808)
+#define K2_HOT_SWAP_REG (K2_ISA_IO_BASE + 0x80c)
+#define K2_PLD2_REG (K2_ISA_IO_BASE + 0x80e)
+#define K2_PLD3_REG (K2_ISA_IO_BASE + 0x80f)
+
+#define K2_BUS_SPD(board_id) (board_id >> 2) & 3
+
+#define K2_RTC_BASE_OFFSET 0x90000
+#define K2_RTC_BASE_ADDRESS (K2_PCI32_MEM_BASE + K2_RTC_BASE_OFFSET)
+#define K2_RTC_SIZE 0x8000
+
+#define K2_MEM_SIZE_MASK 0xe0
+#define K2_MEM_SIZE(size_reg) (size_reg & K2_MEM_SIZE_MASK) >> 5
+#define K2_MEM_SIZE_1GB 0x40000000
+#define K2_MEM_SIZE_512MB 0x20000000
+#define K2_MEM_SIZE_256MB 0x10000000
+#define K2_MEM_SIZE_128MB 0x08000000
+
+#define K2_L2CACHE_MASK 0x03 /* Mask for 2 L2 Cache bits */
+#define K2_L2CACHE_512KB 0x00 /* 512KB */
+#define K2_L2CACHE_256KB 0x01 /* 256KB */
+#define K2_L2CACHE_1MB 0x02 /* 1MB */
+#define K2_L2CACHE_NONE 0x03 /* None */
+
+#define K2_GEO_ADR_MASK 0x1f
+
+#define K2_SYS_SLOT_MASK 0x08
+
+#endif /* __PPC_PLATFORMS_K2_H */
diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c
new file mode 100644
index 00000000000..eda922ac316
--- /dev/null
+++ b/arch/ppc/platforms/katana.c
@@ -0,0 +1,795 @@
+/*
+ * arch/ppc/platforms/katana.c
+ *
+ * Board setup routines for the Artesyn Katana cPCI boards.
+ *
+ * Author: Tim Montgomery <timm@artesyncp.com>
+ * Maintained by: Mark A. Greer <mgreer@mvista.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by - Mark A. Greer <mgreer@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.
+ */
+/*
+ * Supports the Artesyn 750i, 752i, and 3750. The 752i is virtually identical
+ * to the 750i except that it has an mv64460 bridge.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/initrd.h>
+#include <linux/root_dev.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/bootmem.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mv643xx.h>
+#ifdef CONFIG_BOOTIMG
+#include <linux/bootimg.h>
+#endif
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/smp.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/ppcboot.h>
+#include <asm/mv64x60.h>
+#include <platforms/katana.h>
+
+static struct mv64x60_handle bh;
+static katana_id_t katana_id;
+static void __iomem *cpld_base;
+static void __iomem *sram_base;
+
+static u32 katana_flash_size_0;
+static u32 katana_flash_size_1;
+
+static u32 katana_bus_frequency;
+
+unsigned char __res[sizeof(bd_t)];
+
+/* PCI Interrupt routing */
+static int __init
+katana_irq_lookup_750i(unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] = {
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ /* IDSEL 4 (PMC 1) */
+ { KATANA_PCI_INTB_IRQ_750i, KATANA_PCI_INTC_IRQ_750i,
+ KATANA_PCI_INTD_IRQ_750i, KATANA_PCI_INTA_IRQ_750i },
+ /* IDSEL 5 (PMC 2) */
+ { KATANA_PCI_INTC_IRQ_750i, KATANA_PCI_INTD_IRQ_750i,
+ KATANA_PCI_INTA_IRQ_750i, KATANA_PCI_INTB_IRQ_750i },
+ /* IDSEL 6 (T8110) */
+ {KATANA_PCI_INTD_IRQ_750i, 0, 0, 0 },
+ };
+ const long min_idsel = 4, max_idsel = 6, irqs_per_slot = 4;
+
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static int __init
+katana_irq_lookup_3750(unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] = {
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ { KATANA_PCI_INTA_IRQ_3750, 0, 0, 0 }, /* IDSEL 3 (BCM5691) */
+ { KATANA_PCI_INTB_IRQ_3750, 0, 0, 0 }, /* IDSEL 4 (MV64360 #2)*/
+ { KATANA_PCI_INTC_IRQ_3750, 0, 0, 0 }, /* IDSEL 5 (MV64360 #3)*/
+ };
+ const long min_idsel = 3, max_idsel = 5, irqs_per_slot = 4;
+
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static int __init
+katana_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ switch (katana_id) {
+ case KATANA_ID_750I:
+ case KATANA_ID_752I:
+ return katana_irq_lookup_750i(idsel, pin);
+
+ case KATANA_ID_3750:
+ return katana_irq_lookup_3750(idsel, pin);
+
+ default:
+ printk(KERN_ERR "Bogus board ID\n");
+ return 0;
+ }
+}
+
+/* Board info retrieval routines */
+void __init
+katana_get_board_id(void)
+{
+ switch (in_8(cpld_base + KATANA_CPLD_PRODUCT_ID)) {
+ case KATANA_PRODUCT_ID_3750:
+ katana_id = KATANA_ID_3750;
+ break;
+
+ case KATANA_PRODUCT_ID_750i:
+ katana_id = KATANA_ID_750I;
+ break;
+
+ case KATANA_PRODUCT_ID_752i:
+ katana_id = KATANA_ID_752I;
+ break;
+
+ default:
+ printk(KERN_ERR "Unsupported board\n");
+ }
+}
+
+int __init
+katana_get_proc_num(void)
+{
+ u16 val;
+ u8 save_exclude;
+ static int proc = -1;
+ static u8 first_time = 1;
+
+ if (first_time) {
+ if (katana_id != KATANA_ID_3750)
+ proc = 0;
+ else {
+ save_exclude = mv64x60_pci_exclude_bridge;
+ mv64x60_pci_exclude_bridge = 0;
+
+ early_read_config_word(bh.hose_a, 0,
+ PCI_DEVFN(0,0), PCI_DEVICE_ID, &val);
+
+ mv64x60_pci_exclude_bridge = save_exclude;
+
+ switch(val) {
+ case PCI_DEVICE_ID_KATANA_3750_PROC0:
+ proc = 0;
+ break;
+
+ case PCI_DEVICE_ID_KATANA_3750_PROC1:
+ proc = 1;
+ break;
+
+ case PCI_DEVICE_ID_KATANA_3750_PROC2:
+ proc = 2;
+ break;
+
+ default:
+ printk(KERN_ERR "Bogus Device ID\n");
+ }
+ }
+
+ first_time = 0;
+ }
+
+ return proc;
+}
+
+static inline int
+katana_is_monarch(void)
+{
+ return in_8(cpld_base + KATANA_CPLD_BD_CFG_3) &
+ KATANA_CPLD_BD_CFG_3_MONARCH;
+}
+
+static void __init
+katana_setup_bridge(void)
+{
+ struct pci_controller hose;
+ struct mv64x60_setup_info si;
+ void __iomem *vaddr;
+ int i;
+ u16 val;
+ u8 save_exclude;
+
+ /*
+ * Some versions of the Katana firmware mistakenly change the vendor
+ * & device id fields in the bridge's pci device (visible via pci
+ * config accesses). This breaks mv64x60_init() because those values
+ * are used to identify the type of bridge that's there. Artesyn
+ * claims that the subsystem vendor/device id's will have the correct
+ * Marvell values so this code puts back the correct values from there.
+ */
+ memset(&hose, 0, sizeof(hose));
+ vaddr = ioremap(CONFIG_MV64X60_NEW_BASE, MV64x60_INTERNAL_SPACE_SIZE);
+ setup_indirect_pci_nomap(&hose, vaddr + MV64x60_PCI0_CONFIG_ADDR,
+ vaddr + MV64x60_PCI0_CONFIG_DATA);
+ save_exclude = mv64x60_pci_exclude_bridge;
+ mv64x60_pci_exclude_bridge = 0;
+
+ early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID, &val);
+
+ if (val != PCI_VENDOR_ID_MARVELL) {
+ early_read_config_word(&hose, 0, PCI_DEVFN(0, 0),
+ PCI_SUBSYSTEM_VENDOR_ID, &val);
+ early_write_config_word(&hose, 0, PCI_DEVFN(0, 0),
+ PCI_VENDOR_ID, val);
+ early_read_config_word(&hose, 0, PCI_DEVFN(0, 0),
+ PCI_SUBSYSTEM_ID, &val);
+ early_write_config_word(&hose, 0, PCI_DEVFN(0, 0),
+ PCI_DEVICE_ID, val);
+ }
+
+ mv64x60_pci_exclude_bridge = save_exclude;
+ iounmap(vaddr);
+
+ memset(&si, 0, sizeof(si));
+
+ si.phys_reg_base = CONFIG_MV64X60_NEW_BASE;
+
+ si.pci_1.enable_bus = 1;
+ si.pci_1.pci_io.cpu_base = KATANA_PCI1_IO_START_PROC_ADDR;
+ si.pci_1.pci_io.pci_base_hi = 0;
+ si.pci_1.pci_io.pci_base_lo = KATANA_PCI1_IO_START_PCI_ADDR;
+ si.pci_1.pci_io.size = KATANA_PCI1_IO_SIZE;
+ si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_mem[0].cpu_base = KATANA_PCI1_MEM_START_PROC_ADDR;
+ si.pci_1.pci_mem[0].pci_base_hi = KATANA_PCI1_MEM_START_PCI_HI_ADDR;
+ si.pci_1.pci_mem[0].pci_base_lo = KATANA_PCI1_MEM_START_PCI_LO_ADDR;
+ si.pci_1.pci_mem[0].size = KATANA_PCI1_MEM_SIZE;
+ si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_cmd_bits = 0;
+ si.pci_1.latency_timer = 0x80;
+
+ for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ si.cpu_prot_options[i] = 0;
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+#else
+ si.cpu_prot_options[i] = 0;
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE; /* errata */
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE; /* errata */
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE; /* errata */
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_WB |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+#endif
+ }
+
+ /* Lookup PCI host bridges */
+ if (mv64x60_init(&bh, &si))
+ printk(KERN_WARNING "Bridge initialization failed.\n");
+
+ pci_dram_offset = 0; /* sys mem at same addr on PCI & cpu bus */
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = katana_map_irq;
+ ppc_md.pci_exclude_device = mv64x60_pci_exclude_device;
+
+ mv64x60_set_bus(&bh, 1, 0);
+ bh.hose_b->first_busno = 0;
+ bh.hose_b->last_busno = 0xff;
+}
+
+/* Bridge & platform setup routines */
+void __init
+katana_intr_setup(void)
+{
+ /* MPP 8, 9, and 10 */
+ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, 0xfff);
+
+ /* MPP 14 */
+ if ((katana_id == KATANA_ID_750I) || (katana_id == KATANA_ID_752I))
+ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, 0x0f000000);
+
+ /*
+ * Define GPP 8,9,and 10 interrupt polarity as active low
+ * input signal and level triggered
+ */
+ mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, 0x700);
+ mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, 0x700);
+
+ if ((katana_id == KATANA_ID_750I) || (katana_id == KATANA_ID_752I)) {
+ mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, (1<<14));
+ mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, (1<<14));
+ }
+
+ /* Config GPP intr ctlr to respond to level trigger */
+ mv64x60_set_bits(&bh, MV64x60_COMM_ARBITER_CNTL, (1<<10));
+
+ /* Erranum FEr PCI-#8 */
+ mv64x60_clr_bits(&bh, MV64x60_PCI0_CMD, (1<<5) | (1<<9));
+ mv64x60_clr_bits(&bh, MV64x60_PCI1_CMD, (1<<5) | (1<<9));
+
+ /*
+ * Dismiss and then enable interrupt on GPP interrupt cause
+ * for CPU #0
+ */
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~0x700);
+ mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, 0x700);
+
+ if ((katana_id == KATANA_ID_750I) || (katana_id == KATANA_ID_752I)) {
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~(1<<14));
+ mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, (1<<14));
+ }
+
+ /*
+ * Dismiss and then enable interrupt on CPU #0 high cause reg
+ * BIT25 summarizes GPP interrupts 8-15
+ */
+ mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, (1<<25));
+}
+
+void __init
+katana_setup_peripherals(void)
+{
+ u32 base;
+
+ /* Set up windows for boot CS, soldered & socketed flash, and CPLD */
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+ KATANA_BOOT_WINDOW_BASE, KATANA_BOOT_WINDOW_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+
+ /* Assume firmware set up window sizes correctly for dev 0 & 1 */
+ mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, &base,
+ &katana_flash_size_0);
+
+ if (katana_flash_size_0 > 0) {
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN,
+ KATANA_SOLDERED_FLASH_BASE, katana_flash_size_0, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_0_WIN);
+ }
+
+ mv64x60_get_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, &base,
+ &katana_flash_size_1);
+
+ if (katana_flash_size_1 > 0) {
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN,
+ (KATANA_SOLDERED_FLASH_BASE + katana_flash_size_0),
+ katana_flash_size_1, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN);
+ }
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN,
+ KATANA_SOCKET_BASE, KATANA_SOCKETED_FLASH_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN,
+ KATANA_CPLD_BASE, KATANA_CPLD_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN);
+ cpld_base = ioremap(KATANA_CPLD_BASE, KATANA_CPLD_SIZE);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+ KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+ sram_base = ioremap(KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE);
+
+ /* Set up Enet->SRAM window */
+ mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN,
+ KATANA_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0x2);
+ bh.ci->enable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN);
+
+ /* Give enet r/w access to memory region */
+ mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_0, (0x3 << (4 << 1)));
+ mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_1, (0x3 << (4 << 1)));
+ mv64x60_set_bits(&bh, MV64360_ENET2MEM_ACC_PROT_2, (0x3 << (4 << 1)));
+
+ mv64x60_clr_bits(&bh, MV64x60_PCI1_PCI_DECODE_CNTL, (1 << 3));
+ mv64x60_clr_bits(&bh, MV64x60_TIMR_CNTR_0_3_CNTL,
+ ((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24)));
+
+ /* Must wait until window set up before retrieving board id */
+ katana_get_board_id();
+
+ /* Enumerate pci bus (must know board id before getting proc number) */
+ if (katana_get_proc_num() == 0)
+ bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b, 0);
+
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x00160000);
+#else
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2);
+#endif
+
+ /*
+ * Setting the SRAM to 0. Note that this generates parity errors on
+ * internal data path in SRAM since it's first time accessing it
+ * while after reset it's not configured.
+ */
+ memset(sram_base, 0, MV64360_SRAM_SIZE);
+
+ /* Only processor zero [on 3750] is an PCI interrupt controller */
+ if (katana_get_proc_num() == 0)
+ katana_intr_setup();
+}
+
+static void __init
+katana_enable_ipmi(void)
+{
+ u8 reset_out;
+
+ /* Enable access to IPMI ctlr by clearing IPMI PORTSEL bit in CPLD */
+ reset_out = in_8(cpld_base + KATANA_CPLD_RESET_OUT);
+ reset_out &= ~KATANA_CPLD_RESET_OUT_PORTSEL;
+ out_8(cpld_base + KATANA_CPLD_RESET_OUT, reset_out);
+}
+
+static void __init
+katana_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("katana_setup_arch: enter", 0);
+
+ set_tb(0, 0);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ /*
+ * Set up the L2CR register.
+ *
+ * 750FX has only L2E, L2PE (bits 2-8 are reserved)
+ * DD2.0 has bug that requires the L2 to be in WRT mode
+ * avoid dirty data in cache
+ */
+ if (PVR_REV(mfspr(SPRN_PVR)) == 0x0200) {
+ printk(KERN_INFO "DD2.0 detected. Setting L2 cache"
+ "to Writethrough mode\n");
+ _set_L2CR(L2CR_L2E | L2CR_L2PE | L2CR_L2WT);
+ } else
+ _set_L2CR(L2CR_L2E | L2CR_L2PE);
+
+ if (ppc_md.progress)
+ ppc_md.progress("katana_setup_arch: calling setup_bridge", 0);
+
+ katana_setup_bridge();
+ katana_setup_peripherals();
+ katana_enable_ipmi();
+
+ katana_bus_frequency = katana_bus_freq(cpld_base);
+
+ printk(KERN_INFO "Artesyn Communication Products, LLC - Katana(TM)\n");
+ if (ppc_md.progress)
+ ppc_md.progress("katana_setup_arch: exit", 0);
+}
+
+/* Platform device data fixup routines. */
+#if defined(CONFIG_SERIAL_MPSC)
+static void __init
+katana_fixup_mpsc_pdata(struct platform_device *pdev)
+{
+ struct mpsc_pdata *pdata;
+
+ pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+
+ pdata->max_idle = 40;
+ pdata->default_baud = KATANA_DEFAULT_BAUD;
+ pdata->brg_clk_src = KATANA_MPSC_CLK_SRC;
+ /*
+ * TCLK (not SysCLk) is routed to BRG, then to the MPSC. On most parts,
+ * TCLK == SysCLK but on 64460, they are separate pins.
+ * SysCLK can go up to 200 MHz but TCLK can only go up to 133 MHz.
+ */
+ pdata->brg_clk_freq = min(katana_bus_frequency, MV64x60_TCLK_FREQ_MAX);
+}
+#endif
+
+#if defined(CONFIG_MV643XX_ETH)
+static void __init
+katana_fixup_eth_pdata(struct platform_device *pdev)
+{
+ struct mv643xx_eth_platform_data *eth_pd;
+ static u16 phy_addr[] = {
+ KATANA_ETH0_PHY_ADDR,
+ KATANA_ETH1_PHY_ADDR,
+ KATANA_ETH2_PHY_ADDR,
+ };
+
+ eth_pd = pdev->dev.platform_data;
+ eth_pd->force_phy_addr = 1;
+ eth_pd->phy_addr = phy_addr[pdev->id];
+ eth_pd->tx_queue_size = KATANA_ETH_TX_QUEUE_SIZE;
+ eth_pd->rx_queue_size = KATANA_ETH_RX_QUEUE_SIZE;
+}
+#endif
+
+static int __init
+katana_platform_notify(struct device *dev)
+{
+ static struct {
+ char *bus_id;
+ void ((*rtn)(struct platform_device *pdev));
+ } dev_map[] = {
+#if defined(CONFIG_SERIAL_MPSC)
+ { MPSC_CTLR_NAME ".0", katana_fixup_mpsc_pdata },
+ { MPSC_CTLR_NAME ".1", katana_fixup_mpsc_pdata },
+#endif
+#if defined(CONFIG_MV643XX_ETH)
+ { MV643XX_ETH_NAME ".0", katana_fixup_eth_pdata },
+ { MV643XX_ETH_NAME ".1", katana_fixup_eth_pdata },
+ { MV643XX_ETH_NAME ".2", katana_fixup_eth_pdata },
+#endif
+ };
+ struct platform_device *pdev;
+ int i;
+
+ if (dev && dev->bus_id)
+ for (i=0; i<ARRAY_SIZE(dev_map); i++)
+ if (!strncmp(dev->bus_id, dev_map[i].bus_id,
+ BUS_ID_SIZE)) {
+
+ pdev = container_of(dev,
+ struct platform_device, dev);
+ dev_map[i].rtn(pdev);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_MTD_PHYSMAP
+
+#ifndef MB
+#define MB (1 << 20)
+#endif
+
+/*
+ * MTD Layout depends on amount of soldered FLASH in system. Sizes in MB.
+ *
+ * FLASH Amount: 128 64 32 16
+ * ------------- --- -- -- --
+ * Monitor: 1 1 1 1
+ * Primary Kernel: 1.5 1.5 1.5 1.5
+ * Primary fs: 30 30 <end> <end>
+ * Secondary Kernel: 1.5 1.5 N/A N/A
+ * Secondary fs: <end> <end> N/A N/A
+ * User: <overlays entire FLASH except for "Monitor" section>
+ */
+static int __init
+katana_setup_mtd(void)
+{
+ u32 size;
+ int ptbl_entries;
+ static struct mtd_partition *ptbl;
+
+ size = katana_flash_size_0 + katana_flash_size_1;
+ if (!size)
+ return -ENOMEM;
+
+ ptbl_entries = (size >= (64*MB)) ? 6 : 4;
+
+ if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition),
+ GFP_KERNEL)) == NULL) {
+
+ printk(KERN_WARNING "Can't alloc MTD partition table\n");
+ return -ENOMEM;
+ }
+ memset(ptbl, 0, ptbl_entries * sizeof(struct mtd_partition));
+
+ ptbl[0].name = "Monitor";
+ ptbl[0].size = KATANA_MTD_MONITOR_SIZE;
+ ptbl[1].name = "Primary Kernel";
+ ptbl[1].offset = MTDPART_OFS_NXTBLK;
+ ptbl[1].size = 0x00180000; /* 1.5 MB */
+ ptbl[2].name = "Primary Filesystem";
+ ptbl[2].offset = MTDPART_OFS_APPEND;
+ ptbl[2].size = MTDPART_SIZ_FULL; /* Correct for 16 & 32 MB */
+ ptbl[ptbl_entries-1].name = "User FLASH";
+ ptbl[ptbl_entries-1].offset = KATANA_MTD_MONITOR_SIZE;
+ ptbl[ptbl_entries-1].size = MTDPART_SIZ_FULL;
+
+ if (size >= (64*MB)) {
+ ptbl[2].size = 30*MB;
+ ptbl[3].name = "Secondary Kernel";
+ ptbl[3].offset = MTDPART_OFS_NXTBLK;
+ ptbl[3].size = 0x00180000; /* 1.5 MB */
+ ptbl[4].name = "Secondary Filesystem";
+ ptbl[4].offset = MTDPART_OFS_APPEND;
+ ptbl[4].size = MTDPART_SIZ_FULL;
+ }
+
+ physmap_map.size = size;
+ physmap_set_partitions(ptbl, ptbl_entries);
+ return 0;
+}
+
+arch_initcall(katana_setup_mtd);
+#endif
+
+static void
+katana_restart(char *cmd)
+{
+ ulong i = 10000000;
+
+ /* issue hard reset to the reset command register */
+ out_8(cpld_base + KATANA_CPLD_RST_CMD, KATANA_CPLD_RST_CMD_HR);
+
+ while (i-- > 0) ;
+ panic("restart failed\n");
+}
+
+static void
+katana_halt(void)
+{
+ u8 v;
+
+ if (katana_id == KATANA_ID_752I) {
+ v = in_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF);
+ v |= HSL_PLD_HOT_SWAP_LED_BIT;
+ out_8(cpld_base + HSL_PLD_BASE + HSL_PLD_HOT_SWAP_OFF, v);
+ }
+
+ while (1) ;
+ /* NOTREACHED */
+}
+
+static void
+katana_power_off(void)
+{
+ katana_halt();
+ /* NOTREACHED */
+}
+
+static int
+katana_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: Artesyn Communication Products, LLC\n");
+
+ seq_printf(m, "board\t\t: ");
+
+ switch (katana_id) {
+ case KATANA_ID_3750:
+ seq_printf(m, "Katana 3750\n");
+ break;
+
+ case KATANA_ID_750I:
+ seq_printf(m, "Katana 750i\n");
+ break;
+
+ case KATANA_ID_752I:
+ seq_printf(m, "Katana 752i\n");
+ break;
+
+ default:
+ seq_printf(m, "Unknown\n");
+ break;
+ }
+
+ seq_printf(m, "product ID\t: 0x%x\n",
+ in_8(cpld_base + KATANA_CPLD_PRODUCT_ID));
+ seq_printf(m, "hardware rev\t: 0x%x\n",
+ in_8(cpld_base+KATANA_CPLD_HARDWARE_VER));
+ seq_printf(m, "PLD rev\t\t: 0x%x\n",
+ in_8(cpld_base + KATANA_CPLD_PLD_VER));
+ seq_printf(m, "PLB freq\t: %ldMhz\n",
+ (long)katana_bus_frequency / 1000000);
+ seq_printf(m, "PCI\t\t: %sMonarch\n", katana_is_monarch()? "" : "Non-");
+
+ return 0;
+}
+
+static void __init
+katana_calibrate_decr(void)
+{
+ u32 freq;
+
+ freq = katana_bus_frequency / 4;
+
+ printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ (long)freq / 1000000, (long)freq % 1000000);
+
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
+
+unsigned long __init
+katana_find_end_of_memory(void)
+{
+ return mv64x60_get_mem_size(CONFIG_MV64X60_NEW_BASE,
+ MV64x60_TYPE_MV64360);
+}
+
+#if defined(CONFIG_I2C_MV64XXX) && defined(CONFIG_SENSORS_M41T00)
+extern ulong m41t00_get_rtc_time(void);
+extern int m41t00_set_rtc_time(ulong);
+
+static int __init
+katana_rtc_hookup(void)
+{
+ struct timespec tv;
+
+ ppc_md.get_rtc_time = m41t00_get_rtc_time;
+ ppc_md.set_rtc_time = m41t00_set_rtc_time;
+
+ tv.tv_nsec = 0;
+ tv.tv_sec = (ppc_md.get_rtc_time)();
+ do_settimeofday(&tv);
+
+ return 0;
+}
+late_initcall(katana_rtc_hookup);
+#endif
+
+static inline void
+katana_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT2U, 0xf0001ffe);
+ mtspr(SPRN_DBAT2L, 0xf000002a);
+ mb();
+}
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
+static void __init
+katana_map_io(void)
+{
+ io_block_mapping(0xf8100000, 0xf8100000, 0x00020000, _PAGE_IO);
+}
+#endif
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /* ASSUMPTION: If both r3 (bd_t pointer) and r6 (cmdline pointer)
+ * are non-zero, then we should use the board info from the bd_t
+ * structure and the cmdline pointed to by r6 instead of the
+ * information from birecs, if any. Otherwise, use the information
+ * from birecs as discovered by the preceeding call to
+ * parse_bootinfo(). This rule should work with both PPCBoot, which
+ * uses a bd_t board info structure, and the kernel boot wrapper,
+ * which uses birecs.
+ */
+ if (r3 && r6) {
+ /* copy board info structure */
+ memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+ /* copy command line */
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+
+ isa_mem_base = 0;
+
+ ppc_md.setup_arch = katana_setup_arch;
+ ppc_md.show_cpuinfo = katana_show_cpuinfo;
+ ppc_md.init_IRQ = mv64360_init_irq;
+ ppc_md.get_irq = mv64360_get_irq;
+ ppc_md.restart = katana_restart;
+ ppc_md.power_off = katana_power_off;
+ ppc_md.halt = katana_halt;
+ ppc_md.find_end_of_memory = katana_find_end_of_memory;
+ ppc_md.calibrate_decr = katana_calibrate_decr;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ ppc_md.setup_io_mappings = katana_map_io;
+ ppc_md.progress = mv64x60_mpsc_progress;
+ mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
+#endif
+
+#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH)
+ platform_notify = katana_platform_notify;
+#endif
+
+ katana_set_bat(); /* Need for katana_find_end_of_memory and progress */
+}
diff --git a/arch/ppc/platforms/katana.h b/arch/ppc/platforms/katana.h
new file mode 100644
index 00000000000..b82ed81950f
--- /dev/null
+++ b/arch/ppc/platforms/katana.h
@@ -0,0 +1,255 @@
+/*
+ * arch/ppc/platforms/katana.h
+ *
+ * Definitions for Artesyn Katana750i/3750 board.
+ *
+ * Author: Tim Montgomery <timm@artesyncp.com>
+ * Maintained by: Mark A. Greer <mgreer@mvista.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by Mark A. Greer <mgreer@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.
+ */
+
+/*
+ * The MV64360 has 2 PCI buses each with 1 window from the CPU bus to
+ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
+ * We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 64 KB and start
+ * on a boundary that is a multiple of the window size):
+ *
+ * 0xff800000-0xffffffff - Boot window
+ * 0xf8400000-0xf843ffff - Internal SRAM
+ * 0xf8200000-0xf83fffff - CPLD
+ * 0xf8100000-0xf810ffff - MV64360 Registers (CONFIG_MV64X60_NEW_BASE)
+ * 0xf8000000-0xf80fffff - Socketed FLASH
+ * 0xe0000000-0xefffffff - Soldered FLASH
+ * 0xc0000000-0xc3ffffff - PCI I/O (second hose)
+ * 0x80000000-0xbfffffff - PCI MEM (second hose)
+ */
+
+#ifndef __PPC_PLATFORMS_KATANA_H
+#define __PPC_PLATFORMS_KATANA_H
+
+/* CPU Physical Memory Map setup. */
+#define KATANA_BOOT_WINDOW_BASE 0xff800000
+#define KATANA_BOOT_WINDOW_SIZE 0x00800000 /* 8 MB */
+#define KATANA_INTERNAL_SRAM_BASE 0xf8400000
+#define KATANA_CPLD_BASE 0xf8200000
+#define KATANA_CPLD_SIZE 0x00200000 /* 2 MB */
+#define KATANA_SOCKET_BASE 0xf8000000
+#define KATANA_SOCKETED_FLASH_SIZE 0x00100000 /* 1 MB */
+#define KATANA_SOLDERED_FLASH_BASE 0xe0000000
+#define KATANA_SOLDERED_FLASH_SIZE 0x10000000 /* 256 MB */
+
+#define KATANA_PCI1_MEM_START_PROC_ADDR 0x80000000
+#define KATANA_PCI1_MEM_START_PCI_HI_ADDR 0x00000000
+#define KATANA_PCI1_MEM_START_PCI_LO_ADDR 0x80000000
+#define KATANA_PCI1_MEM_SIZE 0x40000000 /* 1 GB */
+#define KATANA_PCI1_IO_START_PROC_ADDR 0xc0000000
+#define KATANA_PCI1_IO_START_PCI_ADDR 0x00000000
+#define KATANA_PCI1_IO_SIZE 0x04000000 /* 64 MB */
+
+/* Board-specific IRQ info */
+#define KATANA_PCI_INTA_IRQ_3750 64+8
+#define KATANA_PCI_INTB_IRQ_3750 64+9
+#define KATANA_PCI_INTC_IRQ_3750 64+10
+
+#define KATANA_PCI_INTA_IRQ_750i 64+8
+#define KATANA_PCI_INTB_IRQ_750i 64+9
+#define KATANA_PCI_INTC_IRQ_750i 64+10
+#define KATANA_PCI_INTD_IRQ_750i 64+14
+
+#define KATANA_CPLD_RST_EVENT 0x00000000
+#define KATANA_CPLD_RST_CMD 0x00001000
+#define KATANA_CPLD_PCI_ERR_INT_EN 0x00002000
+#define KATANA_CPLD_PCI_ERR_INT_PEND 0x00003000
+#define KATANA_CPLD_PRODUCT_ID 0x00004000
+#define KATANA_CPLD_EREADY 0x00005000
+
+#define KATANA_CPLD_HARDWARE_VER 0x00007000
+#define KATANA_CPLD_PLD_VER 0x00008000
+#define KATANA_CPLD_BD_CFG_0 0x00009000
+#define KATANA_CPLD_BD_CFG_1 0x0000a000
+#define KATANA_CPLD_BD_CFG_3 0x0000c000
+#define KATANA_CPLD_LED 0x0000d000
+#define KATANA_CPLD_RESET_OUT 0x0000e000
+
+#define KATANA_CPLD_RST_EVENT_INITACT 0x80
+#define KATANA_CPLD_RST_EVENT_SW 0x40
+#define KATANA_CPLD_RST_EVENT_WD 0x20
+#define KATANA_CPLD_RST_EVENT_COPS 0x10
+#define KATANA_CPLD_RST_EVENT_COPH 0x08
+#define KATANA_CPLD_RST_EVENT_CPCI 0x02
+#define KATANA_CPLD_RST_EVENT_FP 0x01
+
+#define KATANA_CPLD_RST_CMD_SCL 0x80
+#define KATANA_CPLD_RST_CMD_SDA 0x40
+#define KATANA_CPLD_RST_CMD_I2C 0x10
+#define KATANA_CPLD_RST_CMD_FR 0x08
+#define KATANA_CPLD_RST_CMD_SR 0x04
+#define KATANA_CPLD_RST_CMD_HR 0x01
+
+#define KATANA_CPLD_BD_CFG_0_SYSCLK_MASK 0xc0
+#define KATANA_CPLD_BD_CFG_0_SYSCLK_200 0x00
+#define KATANA_CPLD_BD_CFG_0_SYSCLK_166 0x80
+#define KATANA_CPLD_BD_CFG_0_SYSCLK_133 0xc0
+#define KATANA_CPLD_BD_CFG_0_SYSCLK_100 0x40
+
+#define KATANA_CPLD_BD_CFG_1_FL_BANK_MASK 0x03
+#define KATANA_CPLD_BD_CFG_1_FL_BANK_16MB 0x00
+#define KATANA_CPLD_BD_CFG_1_FL_BANK_32MB 0x01
+#define KATANA_CPLD_BD_CFG_1_FL_BANK_64MB 0x02
+#define KATANA_CPLD_BD_CFG_1_FL_BANK_128MB 0x03
+
+#define KATANA_CPLD_BD_CFG_1_FL_NUM_BANKS_MASK 0x04
+#define KATANA_CPLD_BD_CFG_1_FL_NUM_BANKS_ONE 0x00
+#define KATANA_CPLD_BD_CFG_1_FL_NUM_BANKS_TWO 0x04
+
+#define KATANA_CPLD_BD_CFG_3_MONARCH 0x04
+
+#define KATANA_CPLD_RESET_OUT_PORTSEL 0x80
+#define KATANA_CPLD_RESET_OUT_WD 0x20
+#define KATANA_CPLD_RESET_OUT_COPH 0x08
+#define KATANA_CPLD_RESET_OUT_PCI_RST_PCI 0x02
+#define KATANA_CPLD_RESET_OUT_PCI_RST_FP 0x01
+
+#define KATANA_MBOX_RESET_REQUEST 0xC83A
+#define KATANA_MBOX_RESET_ACK 0xE430
+#define KATANA_MBOX_RESET_DONE 0x32E5
+
+#define HSL_PLD_BASE 0x00010000
+#define HSL_PLD_J4SGA_REG_OFF 0
+#define HSL_PLD_J4GA_REG_OFF 1
+#define HSL_PLD_J2GA_REG_OFF 2
+#define HSL_PLD_HOT_SWAP_OFF 6
+#define HSL_PLD_HOT_SWAP_LED_BIT 0x1
+#define GA_MASK 0x1f
+#define HSL_PLD_SIZE 0x1000
+#define K3750_GPP_GEO_ADDR_PINS 0xf8000000
+#define K3750_GPP_GEO_ADDR_SHIFT 27
+
+#define K3750_GPP_EVENT_PROC_0 (1 << 21)
+#define K3750_GPP_EVENT_PROC_1_2 (1 << 2)
+
+#define PCI_VENDOR_ID_ARTESYN 0x1223
+#define PCI_DEVICE_ID_KATANA_3750_PROC0 0x0041
+#define PCI_DEVICE_ID_KATANA_3750_PROC1 0x0042
+#define PCI_DEVICE_ID_KATANA_3750_PROC2 0x0043
+
+#define COPROC_MEM_FUNCTION 0
+#define COPROC_MEM_BAR 0
+#define COPROC_REGS_FUNCTION 0
+#define COPROC_REGS_BAR 4
+#define COPROC_FLASH_FUNCTION 2
+#define COPROC_FLASH_BAR 4
+
+#define KATANA_IPMB_LOCAL_I2C_ADDR 0x08
+
+#define KATANA_DEFAULT_BAUD 9600
+#define KATANA_MPSC_CLK_SRC 8 /* TCLK */
+
+#define KATANA_MTD_MONITOR_SIZE (1 << 20) /* 1 MB */
+
+#define KATANA_ETH0_PHY_ADDR 12
+#define KATANA_ETH1_PHY_ADDR 11
+#define KATANA_ETH2_PHY_ADDR 4
+
+#define KATANA_PRODUCT_ID_3750 0x01
+#define KATANA_PRODUCT_ID_750i 0x02
+#define KATANA_PRODUCT_ID_752i 0x04
+
+#define KATANA_ETH_TX_QUEUE_SIZE 800
+#define KATANA_ETH_RX_QUEUE_SIZE 400
+
+#define KATANA_ETH_PORT_CONFIG_VALUE \
+ ETH_UNICAST_NORMAL_MODE | \
+ ETH_DEFAULT_RX_QUEUE_0 | \
+ ETH_DEFAULT_RX_ARP_QUEUE_0 | \
+ ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \
+ ETH_RECEIVE_BC_IF_IP | \
+ ETH_RECEIVE_BC_IF_ARP | \
+ ETH_CAPTURE_TCP_FRAMES_DIS | \
+ ETH_CAPTURE_UDP_FRAMES_DIS | \
+ ETH_DEFAULT_RX_TCP_QUEUE_0 | \
+ ETH_DEFAULT_RX_UDP_QUEUE_0 | \
+ ETH_DEFAULT_RX_BPDU_QUEUE_0
+
+#define KATANA_ETH_PORT_CONFIG_EXTEND_VALUE \
+ ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \
+ ETH_PARTITION_DISABLE
+
+#define GT_ETH_IPG_INT_RX(value) \
+ ((value & 0x3fff) << 8)
+
+#define KATANA_ETH_PORT_SDMA_CONFIG_VALUE \
+ ETH_RX_BURST_SIZE_4_64BIT | \
+ GT_ETH_IPG_INT_RX(0) | \
+ ETH_TX_BURST_SIZE_4_64BIT
+
+#define KATANA_ETH_PORT_SERIAL_CONTROL_VALUE \
+ ETH_FORCE_LINK_PASS | \
+ ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \
+ ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \
+ ETH_ADV_SYMMETRIC_FLOW_CTRL | \
+ ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \
+ ETH_FORCE_BP_MODE_NO_JAM | \
+ BIT9 | \
+ ETH_DO_NOT_FORCE_LINK_FAIL | \
+ ETH_RETRANSMIT_16_ATTEMPTS | \
+ ETH_ENABLE_AUTO_NEG_SPEED_GMII | \
+ ETH_DTE_ADV_0 | \
+ ETH_DISABLE_AUTO_NEG_BYPASS | \
+ ETH_AUTO_NEG_NO_CHANGE | \
+ ETH_MAX_RX_PACKET_9700BYTE | \
+ ETH_CLR_EXT_LOOPBACK | \
+ ETH_SET_FULL_DUPLEX_MODE | \
+ ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
+
+#ifndef __ASSEMBLY__
+
+typedef enum {
+ KATANA_ID_3750,
+ KATANA_ID_750I,
+ KATANA_ID_752I,
+ KATANA_ID_MAX
+} katana_id_t;
+
+#endif
+
+static inline u32
+katana_bus_freq(void __iomem *cpld_base)
+{
+ u8 bd_cfg_0;
+
+ bd_cfg_0 = in_8(cpld_base + KATANA_CPLD_BD_CFG_0);
+
+ switch (bd_cfg_0 & KATANA_CPLD_BD_CFG_0_SYSCLK_MASK) {
+ case KATANA_CPLD_BD_CFG_0_SYSCLK_200:
+ return 200000000;
+ break;
+
+ case KATANA_CPLD_BD_CFG_0_SYSCLK_166:
+ return 166666666;
+ break;
+
+ case KATANA_CPLD_BD_CFG_0_SYSCLK_133:
+ return 133333333;
+ break;
+
+ case KATANA_CPLD_BD_CFG_0_SYSCLK_100:
+ return 100000000;
+ break;
+
+ default:
+ return 133333333;
+ break;
+ }
+}
+
+#endif /* __PPC_PLATFORMS_KATANA_H */
diff --git a/arch/ppc/platforms/lantec.h b/arch/ppc/platforms/lantec.h
new file mode 100644
index 00000000000..8c87642c510
--- /dev/null
+++ b/arch/ppc/platforms/lantec.h
@@ -0,0 +1,21 @@
+/*
+ * LANTEC board specific definitions
+ *
+ * Copyright (c) 2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifndef __MACH_LANTEC_H
+#define __MACH_LANTEC_H
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define IMAP_ADDR 0xFFF00000 /* physical base address of IMMR area */
+#define IMAP_SIZE (64 * 1024) /* mapped size of IMMR area */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif /* __MACH_LANTEC_H */
diff --git a/arch/ppc/platforms/lite5200.c b/arch/ppc/platforms/lite5200.c
new file mode 100644
index 00000000000..b604cf8b3ca
--- /dev/null
+++ b/arch/ppc/platforms/lite5200.c
@@ -0,0 +1,236 @@
+/*
+ * arch/ppc/platforms/lite5200.c
+ *
+ * Platform support file for the Freescale LITE5200 based on MPC52xx.
+ * A maximum of this file should be moved to syslib/mpc52xx_?????
+ * so that new platform based on MPC52xx need a minimal platform file
+ * ( avoid code duplication )
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Based on the 2.4 code written by Kent Borg,
+ * Dale Farnsworth <dale.farnsworth@mvista.com> and
+ * Wolfgang Denk <wd@denx.de>
+ *
+ * Copyright 2004-2005 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright 2003 Motorola Inc.
+ * Copyright 2003 MontaVista Software Inc.
+ * Copyright 2003 DENX Software Engineering (wd@denx.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/config.h>
+#include <linux/initrd.h>
+#include <linux/seq_file.h>
+#include <linux/kdev_t.h>
+#include <linux/root_dev.h>
+#include <linux/console.h>
+#include <linux/module.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include <asm/ppc_sys.h>
+
+#include <syslib/mpc52xx_pci.h>
+
+
+extern int powersave_nap;
+
+/* Board data given by U-Boot */
+bd_t __res;
+EXPORT_SYMBOL(__res); /* For modules */
+
+
+/* ======================================================================== */
+/* Platform specific code */
+/* ======================================================================== */
+
+/* Supported PSC function in "preference" order */
+struct mpc52xx_psc_func mpc52xx_psc_functions[] = {
+ { .id = 0,
+ .func = "uart",
+ },
+ { .id = -1, /* End entry */
+ .func = NULL,
+ }
+ };
+
+
+static int
+lite5200_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "machine\t\t: Freescale LITE5200\n");
+ return 0;
+}
+
+#ifdef CONFIG_PCI
+static int
+lite5200_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ return (pin == 1) && (idsel==24) ? MPC52xx_IRQ0 : -1;
+}
+#endif
+
+static void __init
+lite5200_setup_cpu(void)
+{
+ struct mpc52xx_cdm __iomem *cdm;
+ struct mpc52xx_gpio __iomem *gpio;
+ struct mpc52xx_intr __iomem *intr;
+ struct mpc52xx_xlb __iomem *xlb;
+
+ u32 port_config;
+ u32 intr_ctrl;
+
+ /* Map zones */
+ cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
+ gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
+ xlb = ioremap(MPC52xx_PA(MPC52xx_XLB_OFFSET), MPC52xx_XLB_SIZE);
+ intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
+
+ if (!cdm || !gpio || !xlb || !intr) {
+ printk("lite5200.c: Error while mapping CDM/GPIO/XLB/INTR during"
+ "lite5200_setup_cpu\n");
+ goto unmap_regs;
+ }
+
+ /* 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);
+
+ /* Get port mux config */
+ port_config = in_be32(&gpio->port_config);
+
+ /* 48Mhz internal, pin is GPIO */
+ port_config &= ~0x00800000;
+
+ /* USB port */
+ port_config &= ~0x00007000; /* Differential mode - USB1 only */
+ port_config |= 0x00001000;
+
+ /* Commit port config */
+ out_be32(&gpio->port_config, port_config);
+
+ /* Configure the XLB Arbiter */
+ out_be32(&xlb->master_pri_enable, 0xff);
+ out_be32(&xlb->master_priority, 0x11111111);
+
+ /* Enable ram snooping for 1GB window */
+ out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP);
+ out_be32(&xlb->snoop_window, MPC52xx_PCI_TARGET_MEM | 0x1d);
+
+ /* IRQ[0-3] setup : IRQ0 - Level Active Low */
+ /* IRQ[1-3] - Level Active High */
+ intr_ctrl = in_be32(&intr->ctrl);
+ intr_ctrl &= ~0x00ff0000;
+ intr_ctrl |= 0x00c00000;
+ out_be32(&intr->ctrl, intr_ctrl);
+
+ /* Unmap reg zone */
+unmap_regs:
+ if (cdm) iounmap(cdm);
+ if (gpio) iounmap(gpio);
+ if (xlb) iounmap(xlb);
+ if (intr) iounmap(intr);
+}
+
+static void __init
+lite5200_setup_arch(void)
+{
+ /* CPU & Port mux setup */
+ lite5200_setup_cpu();
+
+#ifdef CONFIG_PCI
+ /* PCI Bridge setup */
+ mpc52xx_find_bridges();
+#endif
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /* Generic MPC52xx platform initialization */
+ /* TODO Create one and move a max of stuff in it.
+ Put this init in the syslib */
+
+ struct bi_record *bootinfo = find_bootinfo();
+
+ if (bootinfo)
+ parse_bootinfo(bootinfo);
+ else {
+ /* Load the bd_t board info structure */
+ if (r3)
+ memcpy((void*)&__res,(void*)(r3+KERNELBASE),
+ sizeof(bd_t));
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* Load the initrd */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif
+
+ /* Load the command line */
+ if (r6) {
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+ }
+
+ /* PPC Sys identification */
+ identify_ppc_sys_by_id(mfspr(SPRN_SVR));
+
+ /* BAT setup */
+ mpc52xx_set_bat();
+
+ /* No ISA bus by default */
+ isa_io_base = 0;
+ isa_mem_base = 0;
+
+ /* Powersave */
+ /* This is provided as an example on how to do it. But you
+ need to be aware that NAP disable bus snoop and that may
+ be required for some devices to work properly, like USB ... */
+ /* powersave_nap = 1; */
+
+
+ /* Setup the ppc_md struct */
+ ppc_md.setup_arch = lite5200_setup_arch;
+ ppc_md.show_cpuinfo = lite5200_show_cpuinfo;
+ ppc_md.show_percpuinfo = NULL;
+ ppc_md.init_IRQ = mpc52xx_init_irq;
+ ppc_md.get_irq = mpc52xx_get_irq;
+
+#ifdef CONFIG_PCI
+ ppc_md.pci_map_irq = lite5200_map_irq;
+#endif
+
+ ppc_md.find_end_of_memory = mpc52xx_find_end_of_memory;
+ ppc_md.setup_io_mappings = mpc52xx_map_io;
+
+ ppc_md.restart = mpc52xx_restart;
+ ppc_md.power_off = mpc52xx_power_off;
+ ppc_md.halt = mpc52xx_halt;
+
+ /* No time keeper on the LITE5200 */
+ ppc_md.time_init = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.set_rtc_time = NULL;
+
+ ppc_md.calibrate_decr = mpc52xx_calibrate_decr;
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = mpc52xx_progress;
+#endif
+}
+
diff --git a/arch/ppc/platforms/lite5200.h b/arch/ppc/platforms/lite5200.h
new file mode 100644
index 00000000000..c1de2aa4717
--- /dev/null
+++ b/arch/ppc/platforms/lite5200.h
@@ -0,0 +1,23 @@
+/*
+ * arch/ppc/platforms/lite5200.h
+ *
+ * Definitions for Freescale LITE5200 : MPC52xx Standard Development
+ * Platform board support
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * 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 __PLATFORMS_LITE5200_H__
+#define __PLATFORMS_LITE5200_H__
+
+/* Serial port used for low-level debug */
+#define MPC52xx_PF_CONSOLE_PORT 1 /* PSC1 */
+
+
+#endif /* __PLATFORMS_LITE5200_H__ */
diff --git a/arch/ppc/platforms/lopec.c b/arch/ppc/platforms/lopec.c
new file mode 100644
index 00000000000..a5569525e0a
--- /dev/null
+++ b/arch/ppc/platforms/lopec.c
@@ -0,0 +1,411 @@
+/*
+ * arch/ppc/platforms/lopec.c
+ *
+ * Setup routines for the Motorola LoPEC.
+ *
+ * Author: Dan Cox
+ * Maintainer: Tom Rini <trini@kernel.crashing.org>
+ *
+ * 2001-2004 (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/config.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci_ids.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/root_dev.h>
+#include <linux/pci.h>
+
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/io.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/mpc10x.h>
+#include <asm/hw_irq.h>
+#include <asm/prep_nvram.h>
+#include <asm/kgdb.h>
+
+/*
+ * Define all of the IRQ senses and polarities. Taken from the
+ * LoPEC Programmer's Reference Guide.
+ */
+static u_char lopec_openpic_initsenses[16] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 4 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 5 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 6 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 7 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 8 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 9 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 10 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 11 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* IRQ 12 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* IRQ 13 */
+ (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* IRQ 14 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE) /* IRQ 15 */
+};
+
+static inline int __init
+lopec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ int irq;
+ static char pci_irq_table[][4] = {
+ {16, 0, 0, 0}, /* ID 11 - Winbond */
+ {22, 0, 0, 0}, /* ID 12 - SCSI */
+ {0, 0, 0, 0}, /* ID 13 - nothing */
+ {17, 0, 0, 0}, /* ID 14 - 82559 Ethernet */
+ {27, 0, 0, 0}, /* ID 15 - USB */
+ {23, 0, 0, 0}, /* ID 16 - PMC slot 1 */
+ {24, 0, 0, 0}, /* ID 17 - PMC slot 2 */
+ {25, 0, 0, 0}, /* ID 18 - PCI slot */
+ {0, 0, 0, 0}, /* ID 19 - nothing */
+ {0, 0, 0, 0}, /* ID 20 - nothing */
+ {0, 0, 0, 0}, /* ID 21 - nothing */
+ {0, 0, 0, 0}, /* ID 22 - nothing */
+ {0, 0, 0, 0}, /* ID 23 - nothing */
+ {0, 0, 0, 0}, /* ID 24 - PMC slot 1b */
+ {0, 0, 0, 0}, /* ID 25 - nothing */
+ {0, 0, 0, 0} /* ID 26 - PMC Slot 2b */
+ };
+ const long min_idsel = 11, max_idsel = 26, irqs_per_slot = 4;
+
+ irq = PCI_IRQ_TABLE_LOOKUP;
+ if (!irq)
+ return 0;
+
+ return irq;
+}
+
+static void __init
+lopec_setup_winbond_83553(struct pci_controller *hose)
+{
+ int devfn;
+
+ devfn = PCI_DEVFN(11,0);
+
+ /* IDE interrupt routing (primary 14, secondary 15) */
+ early_write_config_byte(hose, 0, devfn, 0x43, 0xef);
+ /* PCI interrupt routing */
+ early_write_config_word(hose, 0, devfn, 0x44, 0x0000);
+
+ /* ISA-PCI address decoder */
+ early_write_config_byte(hose, 0, devfn, 0x48, 0xf0);
+
+ /* RTC, kb, not used in PPC */
+ early_write_config_byte(hose, 0, devfn, 0x4d, 0x00);
+ early_write_config_byte(hose, 0, devfn, 0x4e, 0x04);
+ devfn = PCI_DEVFN(11, 1);
+ early_write_config_byte(hose, 0, devfn, 0x09, 0x8f);
+ early_write_config_dword(hose, 0, devfn, 0x40, 0x00ff0011);
+}
+
+static void __init
+lopec_find_bridges(void)
+{
+ struct pci_controller *hose;
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ if (mpc10x_bridge_init(hose, MPC10X_MEM_MAP_B, MPC10X_MEM_MAP_B,
+ MPC10X_MAPB_EUMB_BASE) == 0) {
+
+ hose->mem_resources[0].end = 0xffffffff;
+ lopec_setup_winbond_83553(hose);
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = lopec_map_irq;
+ }
+}
+
+static int
+lopec_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "machine\t\t: Motorola LoPEC\n");
+ return 0;
+}
+
+static u32
+lopec_irq_canonicalize(u32 irq)
+{
+ if (irq == 2)
+ return 9;
+ else
+ return irq;
+}
+
+static void
+lopec_restart(char *cmd)
+{
+#define LOPEC_SYSSTAT1 0xffe00000
+ /* force a hard reset, if possible */
+ unsigned char reg = *((unsigned char *) LOPEC_SYSSTAT1);
+ reg |= 0x80;
+ *((unsigned char *) LOPEC_SYSSTAT1) = reg;
+
+ local_irq_disable();
+ while(1);
+#undef LOPEC_SYSSTAT1
+}
+
+static void
+lopec_halt(void)
+{
+ local_irq_disable();
+ while(1);
+}
+
+static void
+lopec_power_off(void)
+{
+ lopec_halt();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+int lopec_ide_ports_known = 0;
+static unsigned long lopec_ide_regbase[MAX_HWIFS];
+static unsigned long lopec_ide_ctl_regbase[MAX_HWIFS];
+static unsigned long lopec_idedma_regbase;
+
+static void
+lopec_ide_probe(void)
+{
+ struct pci_dev *dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_82C105,
+ NULL);
+ lopec_ide_ports_known = 1;
+
+ if (dev) {
+ lopec_ide_regbase[0] = dev->resource[0].start;
+ lopec_ide_regbase[1] = dev->resource[2].start;
+ lopec_ide_ctl_regbase[0] = dev->resource[1].start;
+ lopec_ide_ctl_regbase[1] = dev->resource[3].start;
+ lopec_idedma_regbase = dev->resource[4].start;
+ pci_dev_put(dev);
+ }
+}
+
+static int
+lopec_ide_default_irq(unsigned long base)
+{
+ if (lopec_ide_ports_known == 0)
+ lopec_ide_probe();
+
+ if (base == lopec_ide_regbase[0])
+ return 14;
+ else if (base == lopec_ide_regbase[1])
+ return 15;
+ else
+ return 0;
+}
+
+static unsigned long
+lopec_ide_default_io_base(int index)
+{
+ if (lopec_ide_ports_known == 0)
+ lopec_ide_probe();
+ return lopec_ide_regbase[index];
+}
+
+static void __init
+lopec_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data,
+ unsigned long ctl, int *irq)
+{
+ unsigned long reg = data;
+ uint alt_status_base;
+ int i;
+
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+ hw->io_ports[i] = reg++;
+
+ if (data == lopec_ide_regbase[0]) {
+ alt_status_base = lopec_ide_ctl_regbase[0] + 2;
+ hw->irq = 14;
+ } else if (data == lopec_ide_regbase[1]) {
+ alt_status_base = lopec_ide_ctl_regbase[1] + 2;
+ hw->irq = 15;
+ } else {
+ alt_status_base = 0;
+ hw->irq = 0;
+ }
+
+ if (ctl)
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+ else
+ hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base;
+
+ if (irq != NULL)
+ *irq = hw->irq;
+
+}
+#endif /* BLK_DEV_IDE */
+
+static void __init
+lopec_init_IRQ(void)
+{
+ int i;
+
+ /*
+ * Provide the open_pic code with the correct table of interrupts.
+ */
+ OpenPIC_InitSenses = lopec_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(lopec_openpic_initsenses);
+
+ mpc10x_set_openpic();
+
+ /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+ openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+ &i8259_irq);
+
+ /* Map i8259 interrupts */
+ for(i = 0; i < NUM_8259_INTERRUPTS; i++)
+ irq_desc[i].handler = &i8259_pic;
+
+ /*
+ * The EPIC allows for a read in the range of 0xFEF00000 ->
+ * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction.
+ */
+ i8259_init(0xfef00000);
+}
+
+static int __init
+lopec_request_io(void)
+{
+ outb(0x00, 0x4d0);
+ outb(0xc0, 0x4d1);
+
+ request_region(0x00, 0x20, "dma1");
+ request_region(0x20, 0x20, "pic1");
+ request_region(0x40, 0x20, "timer");
+ request_region(0x80, 0x10, "dma page reg");
+ request_region(0xa0, 0x20, "pic2");
+ request_region(0xc0, 0x20, "dma2");
+
+ return 0;
+}
+
+device_initcall(lopec_request_io);
+
+static void __init
+lopec_map_io(void)
+{
+ io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+ io_block_mapping(0xb0000000, 0xb0000000, 0x10000000, _PAGE_IO);
+}
+
+/*
+ * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1.
+ */
+static __inline__ void
+lopec_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT1U, 0xf8000ffe);
+ mtspr(SPRN_DBAT1L, 0xf800002a);
+ mb();
+}
+
+TODC_ALLOC();
+
+static void __init
+lopec_setup_arch(void)
+{
+
+ TODC_INIT(TODC_TYPE_MK48T37, 0, 0,
+ ioremap(0xffe80000, 0x8000), 8);
+
+ loops_per_jiffy = 100000000/HZ;
+
+ lopec_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#elif defined(CONFIG_ROOT_NFS)
+ ROOT_DEV = Root_NFS;
+#elif defined(CONFIG_BLK_DEV_IDEDISK)
+ ROOT_DEV = Root_HDA1;
+#else
+ ROOT_DEV = Root_SDA1;
+#endif
+
+#ifdef CONFIG_PPCBUG_NVRAM
+ /* Read in NVRAM data */
+ init_prep_nvram();
+
+ /* if no bootargs, look in NVRAM */
+ if ( cmd_line[0] == '\0' ) {
+ char *bootargs;
+ bootargs = prep_nvram_get_var("bootargs");
+ if (bootargs != NULL) {
+ strcpy(cmd_line, bootargs);
+ /* again.. */
+ strcpy(saved_command_line, cmd_line);
+ }
+ }
+#endif
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+ lopec_set_bat();
+
+ isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
+ isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
+ pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ ppc_md.setup_arch = lopec_setup_arch;
+ ppc_md.show_cpuinfo = lopec_show_cpuinfo;
+ ppc_md.irq_canonicalize = lopec_irq_canonicalize;
+ ppc_md.init_IRQ = lopec_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.restart = lopec_restart;
+ ppc_md.power_off = lopec_power_off;
+ ppc_md.halt = lopec_halt;
+
+ ppc_md.setup_io_mappings = lopec_map_io;
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.calibrate_decr = todc_calibrate_decr;
+
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.default_irq = lopec_ide_default_irq;
+ ppc_ide_md.default_io_base = lopec_ide_default_io_base;
+ ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports;
+#endif
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = gen550_progress;
+#endif
+}
diff --git a/arch/ppc/platforms/lopec.h b/arch/ppc/platforms/lopec.h
new file mode 100644
index 00000000000..5490edb2d26
--- /dev/null
+++ b/arch/ppc/platforms/lopec.h
@@ -0,0 +1,39 @@
+/*
+ * include/asm-ppc/lopec_serial.h
+ *
+ * Definitions for Motorola LoPEC board.
+ *
+ * Author: Dan Cox
+ * danc@mvista.com (or, alternately, source@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 __H_LOPEC_SERIAL
+#define __H_LOPEC_SERIAL
+
+#define RS_TABLE_SIZE 3
+
+#define BASE_BAUD (1843200 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#endif
+
+#define SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, 0xffe10000, 29, STD_COM_FLAGS, \
+ iomem_base: (u8 *) 0xffe10000, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, 0xffe11000, 20, STD_COM_FLAGS, \
+ iomem_base: (u8 *) 0xffe11000, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, 0xffe12000, 21, STD_COM_FLAGS, \
+ iomem_base: (u8 *) 0xffe12000, \
+ io_type: SERIAL_IO_MEM }
+
+#endif
diff --git a/arch/ppc/platforms/lwmon.h b/arch/ppc/platforms/lwmon.h
new file mode 100644
index 00000000000..995bf5112df
--- /dev/null
+++ b/arch/ppc/platforms/lwmon.h
@@ -0,0 +1,60 @@
+/*
+ * Liebherr LWMON board specific definitions
+ *
+ * Copyright (c) 2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifndef __MACH_LWMON_H
+#define __MACH_LWMON_H
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define IMAP_ADDR 0xFFF00000 /* physical base address of IMMR area */
+#define IMAP_SIZE (64 * 1024) /* mapped size of IMMR area */
+
+/*-----------------------------------------------------------------------
+ * PCMCIA stuff
+ *-----------------------------------------------------------------------
+ *
+ */
+#define PCMCIA_MEM_SIZE ( 64 << 20 )
+
+#define MAX_HWIFS 1 /* overwrite default in include/asm-ppc/ide.h */
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET 0
+#define IDE0_DATA_REG_OFFSET (PCMCIA_MEM_SIZE + 0x320)
+#define IDE0_ERROR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 1)
+#define IDE0_NSECTOR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 2)
+#define IDE0_SECTOR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 3)
+#define IDE0_LCYL_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 4)
+#define IDE0_HCYL_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 5)
+#define IDE0_SELECT_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 6)
+#define IDE0_STATUS_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 7)
+#define IDE0_CONTROL_REG_OFFSET 0x0106
+#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */
+
+#define IDE0_INTERRUPT 13
+
+/*
+ * Definitions for I2C devices
+ */
+#define I2C_ADDR_AUDIO 0x28 /* Audio volume control */
+#define I2C_ADDR_SYSMON 0x2E /* LM87 System Monitor */
+#define I2C_ADDR_RTC 0x51 /* PCF8563 RTC */
+#define I2C_ADDR_POWER_A 0x52 /* PCMCIA/USB power switch, channel A */
+#define I2C_ADDR_POWER_B 0x53 /* PCMCIA/USB power switch, channel B */
+#define I2C_ADDR_KEYBD 0x56 /* PIC LWE keyboard */
+#define I2C_ADDR_PICIO 0x57 /* PIC IO Expander */
+#define I2C_ADDR_EEPROM 0x58 /* EEPROM AT24C164 */
+
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif /* __MACH_LWMON_H */
diff --git a/arch/ppc/platforms/mbx.h b/arch/ppc/platforms/mbx.h
new file mode 100644
index 00000000000..fe81ca4ea0a
--- /dev/null
+++ b/arch/ppc/platforms/mbx.h
@@ -0,0 +1,117 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Motorola MBX boards. This was originally created for the
+ * MBX860, and probably needs revisions for other boards (like the 821).
+ * When this file gets out of control, we can split it up into more
+ * meaningful pieces.
+ *
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_MBX_DEFS
+#define __MACH_MBX_DEFS
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * EPPC-Bug starts it up.
+ */
+typedef struct bd_info {
+ unsigned int bi_tag; /* Should be 0x42444944 "BDID" */
+ unsigned int bi_size; /* Size of this structure */
+ unsigned int bi_revision; /* revision of this structure */
+ unsigned int bi_bdate; /* EPPCbug date, i.e. 0x11061997 */
+ unsigned int bi_memstart; /* Memory start address */
+ unsigned int bi_memsize; /* Memory (end) size in bytes */
+ unsigned int bi_intfreq; /* Internal Freq, in Hz */
+ unsigned int bi_busfreq; /* Bus Freq, in Hz */
+ unsigned int bi_clun; /* Boot device controller */
+ unsigned int bi_dlun; /* Boot device logical dev */
+
+ /* These fields are not part of the board information structure
+ * provided by the boot rom. They are filled in by embed_config.c
+ * so we have the information consistent with other platforms.
+ */
+ unsigned char bi_enetaddr[6];
+ unsigned int bi_baudrate;
+} bd_t;
+
+/* Memory map for the MBX as configured by EPPC-Bug. We could reprogram
+ * The SIU and PCI bridge, and try to use larger MMU pages, but the
+ * performance gain is not measureable and it certainly complicates the
+ * generic MMU model.
+ *
+ * In a effort to minimize memory usage for embedded applications, any
+ * PCI driver or ISA driver must request or map the region required by
+ * the device. For convenience (and since we can map up to 4 Mbytes with
+ * a single page table page), the MMU initialization will map the
+ * NVRAM, Status/Control registers, CPM Dual Port RAM, and the PCI
+ * Bridge CSRs 1:1 into the kernel address space.
+ */
+#define PCI_ISA_IO_ADDR ((unsigned)0x80000000)
+#define PCI_ISA_IO_SIZE ((uint)(512 * 1024 * 1024))
+#define PCI_IDE_ADDR ((unsigned)0x81000000)
+#define PCI_ISA_MEM_ADDR ((unsigned)0xc0000000)
+#define PCI_ISA_MEM_SIZE ((uint)(512 * 1024 * 1024))
+#define PCMCIA_MEM_ADDR ((uint)0xe0000000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024 * 1024))
+#define PCMCIA_DMA_ADDR ((uint)0xe4000000)
+#define PCMCIA_DMA_SIZE ((uint)(64 * 1024 * 1024))
+#define PCMCIA_ATTRB_ADDR ((uint)0xe8000000)
+#define PCMCIA_ATTRB_SIZE ((uint)(64 * 1024 * 1024))
+#define PCMCIA_IO_ADDR ((uint)0xec000000)
+#define PCMCIA_IO_SIZE ((uint)(64 * 1024 * 1024))
+#define NVRAM_ADDR ((uint)0xfa000000)
+#define NVRAM_SIZE ((uint)(1 * 1024 * 1024))
+#define MBX_CSR_ADDR ((uint)0xfa100000)
+#define MBX_CSR_SIZE ((uint)(1 * 1024 * 1024))
+#define IMAP_ADDR ((uint)0xfa200000)
+#define IMAP_SIZE ((uint)(64 * 1024))
+#define PCI_CSR_ADDR ((uint)0xfa210000)
+#define PCI_CSR_SIZE ((uint)(64 * 1024))
+
+/* Map additional physical space into well known virtual addresses. Due
+ * to virtual address mapping, these physical addresses are not accessible
+ * in a 1:1 virtual to physical mapping.
+ */
+#define ISA_IO_VIRT_ADDR ((uint)0xfa220000)
+#define ISA_IO_VIRT_SIZE ((uint)64 * 1024)
+
+/* Interrupt assignments.
+ * These are defined (and fixed) by the MBX hardware implementation.
+ */
+#define POWER_FAIL_INT SIU_IRQ0 /* Power fail */
+#define TEMP_HILO_INT SIU_IRQ1 /* Temperature sensor */
+#define QSPAN_INT SIU_IRQ2 /* PCI Bridge (DMA CTLR?) */
+#define ISA_BRIDGE_INT SIU_IRQ3 /* All those PC things */
+#define COMM_L_INT SIU_IRQ6 /* MBX Comm expansion connector pin */
+#define STOP_ABRT_INT SIU_IRQ7 /* Stop/Abort header pin */
+
+/* CPM Ethernet through SCCx.
+ *
+ * Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use. The TCLK and RCLK seem unique
+ * to the MBX860 board. Any two of the four available clocks could be
+ * used, and the MPC860 cookbook manual has an example using different
+ * clock pins.
+ */
+#define PA_ENET_RXD ((ushort)0x0001)
+#define PA_ENET_TXD ((ushort)0x0002)
+#define PA_ENET_TCLK ((ushort)0x0200)
+#define PA_ENET_RCLK ((ushort)0x0800)
+#define PC_ENET_TENA ((ushort)0x0001)
+#define PC_ENET_CLSN ((ushort)0x0010)
+#define PC_ENET_RENA ((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT ((uint)0x0000003d)
+
+/* The MBX uses the 8259.
+*/
+#define NR_8259_INTS 16
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __MACH_MBX_DEFS */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/mcpn765.c b/arch/ppc/platforms/mcpn765.c
new file mode 100644
index 00000000000..e88d294ea59
--- /dev/null
+++ b/arch/ppc/platforms/mcpn765.c
@@ -0,0 +1,527 @@
+/*
+ * arch/ppc/platforms/mcpn765.c
+ *
+ * Board setup routines for the Motorola MCG MCPN765 cPCI Board.
+ *
+ * Author: Mark A. Greer
+ * mgreer@mvista.com
+ *
+ * Modified by Randy Vinson (rvinson@mvista.com)
+ *
+ * 2001-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.
+ */
+
+/*
+ * This file adds support for the Motorola MCG MCPN765.
+ */
+#include <linux/config.h>
+#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/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/todc.h>
+#include <asm/pci-bridge.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bootinfo.h>
+#include <asm/hawk.h>
+#include <asm/kgdb.h>
+
+#include "mcpn765.h"
+
+static u_char mcpn765_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE),/* 16: i8259 cascade */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 17: COM1,2,3,4 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 18: Enet 1 (front) */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 19: HAWK WDT XXXX */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 20: 21554 bridge */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 21: cPCI INTA# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 22: cPCI INTB# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 23: cPCI INTC# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 24: cPCI INTD# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 25: PMC1 INTA#,PMC2 INTB#*/
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 26: PMC1 INTB#,PMC2 INTC#*/
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 27: PMC1 INTC#,PMC2 INTD#*/
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 28: PMC1 INTD#,PMC2 INTA#*/
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 29: Enet 2 (J3) */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 30: Abort Switch */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/* 31: RTC Alarm */
+};
+
+extern void mcpn765_set_VIA_IDE_native(void);
+
+extern u_int openpic_irq(void);
+extern char cmd_line[];
+
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct uart_port *);
+
+int use_of_interrupt_tree = 0;
+
+static void mcpn765_halt(void);
+
+TODC_ALLOC();
+
+/*
+ * Motorola MCG MCPN765 interrupt routing.
+ */
+static inline int
+mcpn765_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 14, 0, 0, 0 }, /* IDSEL 11 - have to manually set */
+ { 0, 0, 0, 0 }, /* IDSEL 12 - unused */
+ { 0, 0, 0, 0 }, /* IDSEL 13 - unused */
+ { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 0 */
+ { 0, 0, 0, 0 }, /* IDSEL 15 - unused */
+ { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */
+ { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */
+ { 0, 0, 0, 0 }, /* IDSEL 18 - PMC 2B Connector XXXX */
+ { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 1 */
+ { 20, 0, 0, 0 }, /* IDSEL 20 - 21554 cPCI bridge */
+ };
+
+ const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+void __init
+mcpn765_set_VIA_IDE_legacy(void)
+{
+ unsigned short vend, dev;
+
+ early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
+ early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
+
+ if ((vend == PCI_VENDOR_ID_VIA) &&
+ (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
+
+ unsigned char temp;
+
+ /* put back original "standard" port base addresses */
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_0, 0x1f1);
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_1, 0x3f5);
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_2, 0x171);
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_3, 0x375);
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_4, 0xcc01);
+
+ /* put into legacy mode */
+ early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+ &temp);
+ temp &= ~0x05;
+ early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+ temp);
+ }
+}
+
+void
+mcpn765_set_VIA_IDE_native(void)
+{
+ unsigned short vend, dev;
+
+ early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
+ early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
+
+ if ((vend == PCI_VENDOR_ID_VIA) &&
+ (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
+
+ unsigned char temp;
+
+ /* put into native mode */
+ early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+ &temp);
+ temp |= 0x05;
+ early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+ temp);
+ }
+}
+
+/*
+ * Initialize the VIA 82c586b.
+ */
+static void __init
+mcpn765_setup_via_82c586b(void)
+{
+ struct pci_dev *dev;
+ u_char c;
+
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C586_0,
+ NULL)) == NULL) {
+ printk("No VIA ISA bridge found\n");
+ mcpn765_halt();
+ /* NOTREACHED */
+ }
+
+ /*
+ * If the firmware left the EISA 4d0/4d1 ports enabled, make sure
+ * IRQ 14 is set for edge.
+ */
+ pci_read_config_byte(dev, 0x47, &c);
+
+ if (c & (1<<5)) {
+ c = inb(0x4d1);
+ c &= ~(1<<6);
+ outb(c, 0x4d1);
+ }
+
+ /* Disable PNP IRQ routing since we use the Hawk's MPIC */
+ pci_write_config_dword(dev, 0x54, 0);
+ pci_write_config_byte(dev, 0x58, 0);
+
+ pci_dev_put(dev);
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C586_1,
+ NULL)) == NULL) {
+ printk("No VIA ISA bridge found\n");
+ mcpn765_halt();
+ /* NOTREACHED */
+ }
+
+ /*
+ * PPCBug doesn't set the enable bits for the IDE device.
+ * Turn them on now.
+ */
+ pci_read_config_byte(dev, 0x40, &c);
+ c |= 0x03;
+ pci_write_config_byte(dev, 0x40, c);
+ pci_dev_put(dev);
+
+ return;
+}
+
+void __init
+mcpn765_pcibios_fixup(void)
+{
+ /* Do MCPN765 board specific initialization. */
+ mcpn765_setup_via_82c586b();
+}
+
+void __init
+mcpn765_find_bridges(void)
+{
+ struct pci_controller *hose;
+
+ hose = pcibios_alloc_controller();
+
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+ hose->pci_mem_offset = MCPN765_PCI_PHY_MEM_OFFSET;
+
+ pci_init_resource(&hose->io_resource,
+ MCPN765_PCI_IO_START,
+ MCPN765_PCI_IO_END,
+ IORESOURCE_IO,
+ "PCI host bridge");
+
+ pci_init_resource(&hose->mem_resources[0],
+ MCPN765_PCI_MEM_START,
+ MCPN765_PCI_MEM_END,
+ IORESOURCE_MEM,
+ "PCI host bridge");
+
+ hose->io_space.start = MCPN765_PCI_IO_START;
+ hose->io_space.end = MCPN765_PCI_IO_END;
+ hose->mem_space.start = MCPN765_PCI_MEM_START;
+ hose->mem_space.end = MCPN765_PCI_MEM_END - HAWK_MPIC_SIZE;
+
+ if (hawk_init(hose,
+ MCPN765_HAWK_PPC_REG_BASE,
+ MCPN765_PROC_PCI_MEM_START,
+ MCPN765_PROC_PCI_MEM_END - HAWK_MPIC_SIZE,
+ MCPN765_PROC_PCI_IO_START,
+ MCPN765_PROC_PCI_IO_END,
+ MCPN765_PCI_MEM_END - HAWK_MPIC_SIZE + 1) != 0) {
+ printk("Could not initialize HAWK bridge\n");
+ }
+
+ /* VIA IDE BAR decoders are only 16-bits wide. PCI Auto Config
+ * will reassign the bars outside of 16-bit I/O space, which will
+ * "break" things. To prevent this, we'll set the IDE chip into
+ * legacy mode and seed the bars with their legacy addresses (in 16-bit
+ * I/O space). The Auto Config code will skip the IDE contoller in
+ * legacy mode, so our bar values will stick.
+ */
+ mcpn765_set_VIA_IDE_legacy();
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ /* Now that we've got 16-bit addresses in the bars, we can switch the
+ * IDE controller back into native mode so we can do "modern" resource
+ * and interrupt management.
+ */
+ mcpn765_set_VIA_IDE_native();
+
+ ppc_md.pcibios_fixup = mcpn765_pcibios_fixup;
+ ppc_md.pcibios_fixup_bus = NULL;
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = mcpn765_map_irq;
+
+ return;
+}
+static void __init
+mcpn765_setup_arch(void)
+{
+ struct pci_controller *hose;
+
+ if ( ppc_md.progress )
+ ppc_md.progress("mcpn765_setup_arch: enter", 0);
+
+ loops_per_jiffy = 50000000 / HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ if ( ppc_md.progress )
+ ppc_md.progress("mcpn765_setup_arch: find_bridges", 0);
+
+ /* Lookup PCI host bridges */
+ mcpn765_find_bridges();
+
+ hose = pci_bus_to_hose(0);
+ isa_io_base = (ulong)hose->io_base_virt;
+
+ TODC_INIT(TODC_TYPE_MK48T37,
+ (MCPN765_PHYS_NVRAM_AS0 - isa_io_base),
+ (MCPN765_PHYS_NVRAM_AS1 - isa_io_base),
+ (MCPN765_PHYS_NVRAM_DATA - isa_io_base),
+ 8);
+
+ OpenPIC_InitSenses = mcpn765_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(mcpn765_openpic_initsenses);
+
+ printk("Motorola MCG MCPN765 cPCI Non-System Board\n");
+ printk("MCPN765 port (MontaVista Software, Inc. (source@mvista.com))\n");
+
+ if ( ppc_md.progress )
+ ppc_md.progress("mcpn765_setup_arch: exit", 0);
+
+ return;
+}
+
+static void __init
+mcpn765_init2(void)
+{
+
+ request_region(0x00,0x20,"dma1");
+ request_region(0x20,0x20,"pic1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0xc0,0x20,"dma2");
+
+ return;
+}
+
+/*
+ * Interrupt setup and service.
+ * Have MPIC on HAWK and cascaded 8259s on VIA 82586 cascaded to MPIC.
+ */
+static void __init
+mcpn765_init_IRQ(void)
+{
+ int i;
+
+ if ( ppc_md.progress )
+ ppc_md.progress("init_irq: enter", 0);
+
+ openpic_init(NUM_8259_INTERRUPTS);
+ openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+ i8259_irq);
+
+ for(i=0; i < NUM_8259_INTERRUPTS; i++)
+ irq_desc[i].handler = &i8259_pic;
+
+ i8259_init(0);
+
+ if ( ppc_md.progress )
+ ppc_md.progress("init_irq: exit", 0);
+
+ return;
+}
+
+static u32
+mcpn765_irq_canonicalize(u32 irq)
+{
+ if (irq == 2)
+ return 9;
+ else
+ return irq;
+}
+
+static unsigned long __init
+mcpn765_find_end_of_memory(void)
+{
+ return hawk_get_mem_size(MCPN765_HAWK_SMC_BASE);
+}
+
+static void __init
+mcpn765_map_io(void)
+{
+ io_block_mapping(0xfe800000, 0xfe800000, 0x00800000, _PAGE_IO);
+}
+
+static void
+mcpn765_reset_board(void)
+{
+ local_irq_disable();
+
+ /* set VIA IDE controller into native mode */
+ mcpn765_set_VIA_IDE_native();
+
+ /* Set exception prefix high - to the firmware */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ out_8((u_char *)MCPN765_BOARD_MODRST_REG, 0x01);
+
+ return;
+}
+
+static void
+mcpn765_restart(char *cmd)
+{
+ volatile ulong i = 10000000;
+
+ mcpn765_reset_board();
+
+ while (i-- > 0);
+ panic("restart failed\n");
+}
+
+static void
+mcpn765_power_off(void)
+{
+ mcpn765_halt();
+ /* NOTREACHED */
+}
+
+static void
+mcpn765_halt(void)
+{
+ local_irq_disable();
+ while (1);
+ /* NOTREACHED */
+}
+
+static int
+mcpn765_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: Motorola MCG\n");
+ seq_printf(m, "machine\t\t: MCPN765\n");
+
+ return 0;
+}
+
+/*
+ * Set BAT 3 to map 0xf0000000 to end of physical memory space.
+ */
+static __inline__ void
+mcpn765_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT1U, 0xfe8000fe);
+ mtspr(SPRN_DBAT1L, 0xfe80002a);
+ mb();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /* Map in board regs, etc. */
+ mcpn765_set_bat();
+
+ isa_mem_base = MCPN765_ISA_MEM_BASE;
+ pci_dram_offset = MCPN765_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ ppc_md.setup_arch = mcpn765_setup_arch;
+ ppc_md.show_cpuinfo = mcpn765_show_cpuinfo;
+ ppc_md.irq_canonicalize = mcpn765_irq_canonicalize;
+ ppc_md.init_IRQ = mcpn765_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+ ppc_md.init = mcpn765_init2;
+
+ ppc_md.restart = mcpn765_restart;
+ ppc_md.power_off = mcpn765_power_off;
+ ppc_md.halt = mcpn765_halt;
+
+ ppc_md.find_end_of_memory = mcpn765_find_end_of_memory;
+ ppc_md.setup_io_mappings = mcpn765_map_io;
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.calibrate_decr = todc_calibrate_decr;
+
+ ppc_md.nvram_read_val = todc_m48txx_read_val;
+ ppc_md.nvram_write_val = todc_m48txx_write_val;
+
+ ppc_md.heartbeat = NULL;
+ ppc_md.heartbeat_reset = 0;
+ ppc_md.heartbeat_count = 0;
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = gen550_progress;
+#endif
+#ifdef CONFIG_KGDB
+ ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
+#endif
+
+ return;
+}
diff --git a/arch/ppc/platforms/mcpn765.h b/arch/ppc/platforms/mcpn765.h
new file mode 100644
index 00000000000..4d35ecad097
--- /dev/null
+++ b/arch/ppc/platforms/mcpn765.h
@@ -0,0 +1,122 @@
+/*
+ * arch/ppc/platforms/mcpn765.h
+ *
+ * Definitions for Motorola MCG MCPN765 cPCI Board.
+ *
+ * Author: Mark A. Greer
+ * mgreer@mvista.com
+ *
+ * 2001-2004 (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.
+ */
+
+/*
+ * From Processor to PCI:
+ * PCI Mem Space: 0x80000000 - 0xc0000000 -> 0x80000000 - 0xc0000000 (1 GB)
+ * PCI I/O Space: 0xfd800000 - 0xfe000000 -> 0x00000000 - 0x00800000 (8 MB)
+ * Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area
+ * MPIC in PCI Mem Space: 0xfe800000 - 0xfe830000 (not all used by MPIC)
+ *
+ * From PCI to Processor:
+ * System Memory: 0x00000000 -> 0x00000000
+ */
+
+#ifndef __PPC_PLATFORMS_MCPN765_H
+#define __PPC_PLATFORMS_MCPN765_H
+#include <linux/config.h>
+
+/* PCI Memory space mapping info */
+#define MCPN765_PCI_MEM_SIZE 0x40000000U
+#define MCPN765_PROC_PCI_MEM_START 0x80000000U
+#define MCPN765_PROC_PCI_MEM_END (MCPN765_PROC_PCI_MEM_START + \
+ MCPN765_PCI_MEM_SIZE - 1)
+#define MCPN765_PCI_MEM_START 0x80000000U
+#define MCPN765_PCI_MEM_END (MCPN765_PCI_MEM_START + \
+ MCPN765_PCI_MEM_SIZE - 1)
+
+/* PCI I/O space mapping info */
+#define MCPN765_PCI_IO_SIZE 0x00800000U
+#define MCPN765_PROC_PCI_IO_START 0xfd800000U
+#define MCPN765_PROC_PCI_IO_END (MCPN765_PROC_PCI_IO_START + \
+ MCPN765_PCI_IO_SIZE - 1)
+#define MCPN765_PCI_IO_START 0x00000000U
+#define MCPN765_PCI_IO_END (MCPN765_PCI_IO_START + \
+ MCPN765_PCI_IO_SIZE - 1)
+
+/* System memory mapping info */
+#define MCPN765_PCI_DRAM_OFFSET 0x00000000U
+#define MCPN765_PCI_PHY_MEM_OFFSET 0x00000000U
+
+#define MCPN765_ISA_MEM_BASE 0x00000000U
+#define MCPN765_ISA_IO_BASE MCPN765_PROC_PCI_IO_START
+
+/* Define base addresses for important sets of registers */
+#define MCPN765_HAWK_MPIC_BASE 0xfe800000U
+#define MCPN765_HAWK_SMC_BASE 0xfef80000U
+#define MCPN765_HAWK_PPC_REG_BASE 0xfeff0000U
+
+/* Define MCPN765 board register addresses. */
+#define MCPN765_BOARD_STATUS_REG 0xfef88080U
+#define MCPN765_BOARD_MODFAIL_REG 0xfef88090U
+#define MCPN765_BOARD_MODRST_REG 0xfef880a0U
+#define MCPN765_BOARD_TBEN_REG 0xfef880c0U
+#define MCPN765_BOARD_GEOGRAPHICAL_REG 0xfef880e8U
+#define MCPN765_BOARD_EXT_FEATURE_REG 0xfef880f0U
+#define MCPN765_BOARD_LAST_RESET_REG 0xfef880f8U
+
+/* Defines for UART */
+
+/* Define the UART base addresses */
+#define MCPN765_SERIAL_1 0xfef88000
+#define MCPN765_SERIAL_2 0xfef88200
+#define MCPN765_SERIAL_3 0xfef88400
+#define MCPN765_SERIAL_4 0xfef88600
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE 64
+#else
+#define RS_TABLE_SIZE 4
+#endif
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define BASE_BAUD ( 1843200 / 16 )
+#define UART_CLK 1843200
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#endif
+
+/* All UART IRQ's are wire-OR'd to IRQ 17 */
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, MCPN765_SERIAL_1, 17, STD_COM_FLAGS, /* ttyS0 */\
+ iomem_base: (u8 *)MCPN765_SERIAL_1, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, MCPN765_SERIAL_2, 17, STD_COM_FLAGS, /* ttyS1 */\
+ iomem_base: (u8 *)MCPN765_SERIAL_2, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, MCPN765_SERIAL_3, 17, STD_COM_FLAGS, /* ttyS2 */\
+ iomem_base: (u8 *)MCPN765_SERIAL_3, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, MCPN765_SERIAL_4, 17, STD_COM_FLAGS, /* ttyS3 */\
+ iomem_base: (u8 *)MCPN765_SERIAL_4, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
+
+/* Define the NVRAM/RTC address strobe & data registers */
+#define MCPN765_PHYS_NVRAM_AS0 0xfef880c8U
+#define MCPN765_PHYS_NVRAM_AS1 0xfef880d0U
+#define MCPN765_PHYS_NVRAM_DATA 0xfef880d8U
+
+extern void mcpn765_find_bridges(void);
+
+#endif /* __PPC_PLATFORMS_MCPN765_H */
diff --git a/arch/ppc/platforms/mpc5200.c b/arch/ppc/platforms/mpc5200.c
new file mode 100644
index 00000000000..a58db438c16
--- /dev/null
+++ b/arch/ppc/platforms/mpc5200.c
@@ -0,0 +1,53 @@
+/*
+ * arch/ppc/platforms/mpc5200.c
+ *
+ * OCP Definitions for the boards based on MPC5200 processor. Contains
+ * definitions for every common peripherals. (Mostly all but PSCs)
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright 2004 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * 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 <asm/ocp.h>
+#include <asm/mpc52xx.h>
+
+
+static struct ocp_fs_i2c_data mpc5200_i2c_def = {
+ .flags = FS_I2C_CLOCK_5200,
+};
+
+
+/* Here is the core_ocp struct.
+ * With all the devices common to all board. Even if port multiplexing is
+ * not setup for them (if the user don't want them, just don't select the
+ * config option). The potentially conflicting devices (like PSCs) goes in
+ * board specific file.
+ */
+struct ocp_def core_ocp[] = {
+ {
+ .vendor = OCP_VENDOR_FREESCALE,
+ .function = OCP_FUNC_IIC,
+ .index = 0,
+ .paddr = MPC52xx_I2C1,
+ .irq = OCP_IRQ_NA, /* MPC52xx_IRQ_I2C1 - Buggy */
+ .pm = OCP_CPM_NA,
+ .additions = &mpc5200_i2c_def,
+ },
+ {
+ .vendor = OCP_VENDOR_FREESCALE,
+ .function = OCP_FUNC_IIC,
+ .index = 1,
+ .paddr = MPC52xx_I2C2,
+ .irq = OCP_IRQ_NA, /* MPC52xx_IRQ_I2C2 - Buggy */
+ .pm = OCP_CPM_NA,
+ .additions = &mpc5200_i2c_def,
+ },
+ { /* Terminating entry */
+ .vendor = OCP_VENDOR_INVALID
+ }
+};
diff --git a/arch/ppc/platforms/mvme5100.c b/arch/ppc/platforms/mvme5100.c
new file mode 100644
index 00000000000..b292b44b760
--- /dev/null
+++ b/arch/ppc/platforms/mvme5100.c
@@ -0,0 +1,349 @@
+/*
+ * arch/ppc/platforms/mvme5100.c
+ *
+ * Board setup routines for the Motorola MVME5100.
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * 2001-2004 (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/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/kdev_t.h>
+#include <linux/root_dev.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/todc.h>
+#include <asm/pci-bridge.h>
+#include <asm/bootinfo.h>
+#include <asm/hawk.h>
+
+#include <platforms/pplus.h>
+#include <platforms/mvme5100.h>
+
+static u_char mvme5100_openpic_initsenses[16] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* i8259 cascade */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* TL16C550 UART 1,2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet1 front panel or P2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Hawk Watchdog 1,2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* DS1621 thermal alarm */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT0# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT1# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT2# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT3# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTA#, PMC2 INTB# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTB#, PMC2 INTC# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTC#, PMC2 INTD# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTD#, PMC2 INTA# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet 2 (front panel) */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Abort Switch */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* RTC Alarm */
+};
+
+static inline int
+mvme5100_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ int irq;
+
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 0, 0, 0, 0 }, /* IDSEL 11 - Winbond */
+ { 0, 0, 0, 0 }, /* IDSEL 12 - unused */
+ { 21, 22, 23, 24 }, /* IDSEL 13 - Universe II */
+ { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 1 */
+ { 0, 0, 0, 0 }, /* IDSEL 15 - unused */
+ { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */
+ { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */
+ { 0, 0, 0, 0 }, /* IDSEL 18 - unused */
+ { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 2 */
+ { 0, 0, 0, 0 }, /* IDSEL 20 - PMCSPAN */
+ };
+
+ const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4;
+ irq = PCI_IRQ_TABLE_LOOKUP;
+ /* If lookup is zero, always return 0 */
+ if (!irq)
+ return 0;
+ else
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+ /* If IPMC761 present, return table value */
+ return irq;
+#else
+ /* If IPMC761 not present, we don't have an i8259 so adjust */
+ return (irq - NUM_8259_INTERRUPTS);
+#endif
+}
+
+static void
+mvme5100_pcibios_fixup_resources(struct pci_dev *dev)
+{
+ int i;
+
+ if ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
+ (dev->device == PCI_DEVICE_ID_MOTOROLA_HAWK))
+ for (i=0; i<DEVICE_COUNT_RESOURCE; i++)
+ {
+ dev->resource[i].start = 0;
+ dev->resource[i].end = 0;
+ }
+}
+
+static void __init
+mvme5100_setup_bridge(void)
+{
+ struct pci_controller* hose;
+
+ hose = pcibios_alloc_controller();
+
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+ hose->pci_mem_offset = MVME5100_PCI_MEM_OFFSET;
+
+ pci_init_resource(&hose->io_resource, MVME5100_PCI_LOWER_IO,
+ MVME5100_PCI_UPPER_IO, IORESOURCE_IO,
+ "PCI host bridge");
+
+ pci_init_resource(&hose->mem_resources[0], MVME5100_PCI_LOWER_MEM,
+ MVME5100_PCI_UPPER_MEM, IORESOURCE_MEM,
+ "PCI host bridge");
+
+ hose->io_space.start = MVME5100_PCI_LOWER_IO;
+ hose->io_space.end = MVME5100_PCI_UPPER_IO;
+ hose->mem_space.start = MVME5100_PCI_LOWER_MEM;
+ hose->mem_space.end = MVME5100_PCI_UPPER_MEM;
+ hose->io_base_virt = (void *)MVME5100_ISA_IO_BASE;
+
+ /* Use indirect method of Hawk */
+ setup_indirect_pci(hose, MVME5100_PCI_CONFIG_ADDR,
+ MVME5100_PCI_CONFIG_DATA);
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pcibios_fixup_resources = mvme5100_pcibios_fixup_resources;
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = mvme5100_map_irq;
+}
+
+static void __init
+mvme5100_setup_arch(void)
+{
+ if ( ppc_md.progress )
+ ppc_md.progress("mvme5100_setup_arch: enter", 0);
+
+ loops_per_jiffy = 50000000 / HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ if ( ppc_md.progress )
+ ppc_md.progress("mvme5100_setup_arch: find_bridges", 0);
+
+ /* Setup PCI host bridge */
+ mvme5100_setup_bridge();
+
+ /* Find and map our OpenPIC */
+ hawk_mpic_init(MVME5100_PCI_MEM_OFFSET);
+ OpenPIC_InitSenses = mvme5100_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(mvme5100_openpic_initsenses);
+
+ printk("MVME5100 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n");
+
+ if ( ppc_md.progress )
+ ppc_md.progress("mvme5100_setup_arch: exit", 0);
+
+ return;
+}
+
+static void __init
+mvme5100_init2(void)
+{
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+ request_region(0x00,0x20,"dma1");
+ request_region(0x20,0x20,"pic1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0xc0,0x20,"dma2");
+#endif
+ return;
+}
+
+/*
+ * Interrupt setup and service.
+ * Have MPIC on HAWK and cascaded 8259s on Winbond cascaded to MPIC.
+ */
+static void __init
+mvme5100_init_IRQ(void)
+{
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+ int i;
+#endif
+
+ if ( ppc_md.progress )
+ ppc_md.progress("init_irq: enter", 0);
+
+ openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000);
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+ openpic_init(NUM_8259_INTERRUPTS);
+ openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+ &i8259_irq);
+
+ /* Map i8259 interrupts. */
+ for (i = 0; i < NUM_8259_INTERRUPTS; i++)
+ irq_desc[i].handler = &i8259_pic;
+
+ i8259_init(0);
+#else
+ openpic_init(0);
+#endif
+
+ if ( ppc_md.progress )
+ ppc_md.progress("init_irq: exit", 0);
+
+ return;
+}
+
+/*
+ * Set BAT 3 to map 0xf0000000 to end of physical memory space.
+ */
+static __inline__ void
+mvme5100_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT1U, 0xf0001ffe);
+ mtspr(SPRN_DBAT1L, 0xf000002a);
+ mb();
+}
+
+static unsigned long __init
+mvme5100_find_end_of_memory(void)
+{
+ return hawk_get_mem_size(MVME5100_HAWK_SMC_BASE);
+}
+
+static void __init
+mvme5100_map_io(void)
+{
+ io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO);
+ ioremap_base = 0xfe000000;
+}
+
+static void
+mvme5100_reset_board(void)
+{
+ local_irq_disable();
+
+ /* Set exception prefix high - to the firmware */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ out_8((u_char *)MVME5100_BOARD_MODRST_REG, 0x01);
+
+ return;
+}
+
+static void
+mvme5100_restart(char *cmd)
+{
+ volatile ulong i = 10000000;
+
+ mvme5100_reset_board();
+
+ while (i-- > 0);
+ panic("restart failed\n");
+}
+
+static void
+mvme5100_halt(void)
+{
+ local_irq_disable();
+ while (1);
+}
+
+static void
+mvme5100_power_off(void)
+{
+ mvme5100_halt();
+}
+
+static int
+mvme5100_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: Motorola\n");
+ seq_printf(m, "machine\t\t: MVME5100\n");
+
+ return 0;
+}
+
+TODC_ALLOC();
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+ mvme5100_set_bat();
+
+ isa_io_base = MVME5100_ISA_IO_BASE;
+ isa_mem_base = MVME5100_ISA_MEM_BASE;
+ pci_dram_offset = MVME5100_PCI_DRAM_OFFSET;
+
+ ppc_md.setup_arch = mvme5100_setup_arch;
+ ppc_md.show_cpuinfo = mvme5100_show_cpuinfo;
+ ppc_md.init_IRQ = mvme5100_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+ ppc_md.init = mvme5100_init2;
+
+ ppc_md.restart = mvme5100_restart;
+ ppc_md.power_off = mvme5100_power_off;
+ ppc_md.halt = mvme5100_halt;
+
+ ppc_md.find_end_of_memory = mvme5100_find_end_of_memory;
+ ppc_md.setup_io_mappings = mvme5100_map_io;
+
+ TODC_INIT(TODC_TYPE_MK48T37, MVME5100_NVRAM_AS0, MVME5100_NVRAM_AS1,
+ MVME5100_NVRAM_DATA, 8);
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.calibrate_decr = todc_calibrate_decr;
+
+ ppc_md.nvram_read_val = todc_m48txx_read_val;
+ ppc_md.nvram_write_val = todc_m48txx_write_val;
+}
diff --git a/arch/ppc/platforms/mvme5100.h b/arch/ppc/platforms/mvme5100.h
new file mode 100644
index 00000000000..edd479439a4
--- /dev/null
+++ b/arch/ppc/platforms/mvme5100.h
@@ -0,0 +1,91 @@
+/*
+ * include/asm-ppc/platforms/mvme5100.h
+ *
+ * Definitions for Motorola MVME5100.
+ *
+ * Author: Matt Porter <mporter@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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_MVME5100_H__
+#define __ASM_MVME5100_H__
+
+#define MVME5100_HAWK_SMC_BASE 0xfef80000
+
+#define MVME5100_PCI_CONFIG_ADDR 0xfe000cf8
+#define MVME5100_PCI_CONFIG_DATA 0xfe000cfc
+
+#define MVME5100_PCI_IO_BASE 0xfe000000
+#define MVME5100_PCI_MEM_BASE 0x80000000
+
+#define MVME5100_PCI_MEM_OFFSET 0x00000000
+
+#define MVME5100_PCI_DRAM_OFFSET 0x00000000
+#define MVME5100_ISA_MEM_BASE 0x00000000
+#define MVME5100_ISA_IO_BASE MVME5100_PCI_IO_BASE
+
+#define MVME5100_PCI_LOWER_MEM 0x80000000
+#define MVME5100_PCI_UPPER_MEM 0xf3f7ffff
+#define MVME5100_PCI_LOWER_IO 0x00000000
+#define MVME5100_PCI_UPPER_IO 0x0077ffff
+
+/* MVME5100 board register addresses. */
+#define MVME5100_BOARD_STATUS_REG 0xfef88080
+#define MVME5100_BOARD_MODFAIL_REG 0xfef88090
+#define MVME5100_BOARD_MODRST_REG 0xfef880a0
+#define MVME5100_BOARD_TBEN_REG 0xfef880c0
+#define MVME5100_BOARD_SW_READ_REG 0xfef880e0
+#define MVME5100_BOARD_GEO_ADDR_REG 0xfef880e8
+#define MVME5100_BOARD_EXT_FEATURE1_REG 0xfef880f0
+#define MVME5100_BOARD_EXT_FEATURE2_REG 0xfef88100
+
+/* Define the NVRAM/RTC address strobe & data registers */
+#define MVME5100_PHYS_NVRAM_AS0 0xfef880c8
+#define MVME5100_PHYS_NVRAM_AS1 0xfef880d0
+#define MVME5100_PHYS_NVRAM_DATA 0xfef880d8
+
+#define MVME5100_NVRAM_AS0 (MVME5100_PHYS_NVRAM_AS0 - MVME5100_ISA_IO_BASE)
+#define MVME5100_NVRAM_AS1 (MVME5100_PHYS_NVRAM_AS1 - MVME5100_ISA_IO_BASE)
+#define MVME5100_NVRAM_DATA (MVME5100_PHYS_NVRAM_DATA - MVME5100_ISA_IO_BASE)
+
+/* UART clock, addresses, and irq */
+#define MVME5100_BASE_BAUD 1843200
+#define MVME5100_SERIAL_1 0xfef88000
+#define MVME5100_SERIAL_2 0xfef88200
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+#define MVME5100_SERIAL_IRQ 17
+#else
+#define MVME5100_SERIAL_IRQ 1
+#endif
+
+#define RS_TABLE_SIZE 4
+
+#define BASE_BAUD ( MVME5100_BASE_BAUD / 16 )
+
+#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
+
+/* All UART IRQ's are wire-OR'd to one MPIC IRQ */
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, MVME5100_SERIAL_1, \
+ MVME5100_SERIAL_IRQ, \
+ STD_COM_FLAGS, /* ttyS0 */ \
+ iomem_base: (unsigned char *)MVME5100_SERIAL_1, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, MVME5100_SERIAL_2, \
+ MVME5100_SERIAL_IRQ, \
+ STD_COM_FLAGS, /* ttyS1 */ \
+ iomem_base: (unsigned char *)MVME5100_SERIAL_2, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
+
+#endif /* __ASM_MVME5100_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/pal4.h b/arch/ppc/platforms/pal4.h
new file mode 100644
index 00000000000..641a11a3165
--- /dev/null
+++ b/arch/ppc/platforms/pal4.h
@@ -0,0 +1,42 @@
+/*
+ * arch/ppc/platforms/pal4.h
+ *
+ * Definitions for SBS Palomar IV board
+ *
+ * Author: Dan Cox
+ *
+ * 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.
+ */
+
+#ifndef __PPC_PLATFORMS_PAL4_H
+#define __PPC_PLATFORMS_PAL4_H
+
+#define PAL4_NVRAM 0xfffc0000
+#define PAL4_NVRAM_SIZE 0x8000
+
+#define PAL4_DRAM 0xfff80000
+#define PAL4_DRAM_BR_MASK 0xc0
+#define PAL4_DRAM_BR_SHIFT 6
+#define PAL4_DRAM_RESET 0x10
+#define PAL4_DRAM_EREADY 0x40
+
+#define PAL4_MISC 0xfff80004
+#define PAL4_MISC_FB_MASK 0xc0
+#define PAL4_MISC_FLASH 0x20 /* StratFlash mapping: 1->0xff80, 0->0xfff0 */
+#define PAL4_MISC_MISC 0x08
+#define PAL4_MISC_BITF 0x02
+#define PAL4_MISC_NVKS 0x01
+
+#define PAL4_L2 0xfff80008
+#define PAL4_L2_MASK 0x07
+
+#define PAL4_PLDR 0xfff8000c
+
+/* Only two Ethernet devices on the board... */
+#define PAL4_ETH 31
+#define PAL4_INTA 20
+
+#endif /* __PPC_PLATFORMS_PAL4_H */
diff --git a/arch/ppc/platforms/pal4_pci.c b/arch/ppc/platforms/pal4_pci.c
new file mode 100644
index 00000000000..c3b1b757a48
--- /dev/null
+++ b/arch/ppc/platforms/pal4_pci.c
@@ -0,0 +1,77 @@
+/*
+ * arch/ppc/platforms/pal4_pci.c
+ *
+ * PCI support for SBS Palomar IV
+ *
+ * Author: Dan Cox
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/byteorder.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/uaccess.h>
+
+#include <syslib/cpc700.h>
+
+#include "pal4.h"
+
+/* not much to this.... */
+static inline int __init
+pal4_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ if (idsel == 9)
+ return PAL4_ETH;
+ else
+ return PAL4_INTA + (idsel - 3);
+}
+
+void __init
+pal4_find_bridges(void)
+{
+ struct pci_controller *hose;
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+ hose->pci_mem_offset = 0;
+
+ /* Could snatch these from the CPC700.... */
+ pci_init_resource(&hose->io_resource,
+ 0x0,
+ 0x03ffffff,
+ IORESOURCE_IO,
+ "PCI host bridge");
+
+ pci_init_resource(&hose->mem_resources[0],
+ 0x90000000,
+ 0x9fffffff,
+ IORESOURCE_MEM,
+ "PCI host bridge");
+
+ hose->io_space.start = 0x00800000;
+ hose->io_space.end = 0x03ffffff;
+ hose->mem_space.start = 0x90000000;
+ hose->mem_space.end = 0x9fffffff;
+ hose->io_base_virt = (void *) 0xf8000000;
+
+ setup_indirect_pci(hose, CPC700_PCI_CONFIG_ADDR,
+ CPC700_PCI_CONFIG_DATA);
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = pal4_map_irq;
+}
diff --git a/arch/ppc/platforms/pal4_serial.h b/arch/ppc/platforms/pal4_serial.h
new file mode 100644
index 00000000000..a715c66e1ad
--- /dev/null
+++ b/arch/ppc/platforms/pal4_serial.h
@@ -0,0 +1,39 @@
+/*
+ * arch/ppc/platforms/pal4_serial.h
+ *
+ * Definitions for SBS PalomarIV serial support
+ *
+ * Author: Dan Cox
+ *
+ * 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.
+ */
+
+#ifndef __PPC_PAL4_SERIAL_H
+#define __PPC_PAL4_SERIAL_H
+
+#define CPC700_SERIAL_1 0xff600300
+#define CPC700_SERIAL_2 0xff600400
+
+#define RS_TABLE_SIZE 2
+#define BASE_BAUD (33333333 / 4 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define SERIAL_PORT_DFNS \
+ {0, BASE_BAUD, CPC700_SERIAL_1, 3, STD_COM_FLAGS, \
+ iomem_base: (unsigned char *) CPC700_SERIAL_1, \
+ io_type: SERIAL_IO_MEM}, /* ttyS0 */ \
+ {0, BASE_BAUD, CPC700_SERIAL_2, 4, STD_COM_FLAGS, \
+ iomem_base: (unsigned char *) CPC700_SERIAL_2, \
+ io_type: SERIAL_IO_MEM}
+
+#endif
diff --git a/arch/ppc/platforms/pal4_setup.c b/arch/ppc/platforms/pal4_setup.c
new file mode 100644
index 00000000000..12446b93e38
--- /dev/null
+++ b/arch/ppc/platforms/pal4_setup.c
@@ -0,0 +1,175 @@
+/*
+ * arch/ppc/platforms/pal4_setup.c
+ *
+ * Board setup routines for the SBS PalomarIV.
+ *
+ * Author: Dan Cox
+ *
+ * 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/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/irq.h>
+#include <linux/kdev_t.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/io.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+
+#include <syslib/cpc700.h>
+
+#include "pal4.h"
+
+extern void pal4_find_bridges(void);
+
+unsigned int cpc700_irq_assigns[][2] = {
+ {1, 1}, /* IRQ 0: ECC correctable error */
+ {1, 1}, /* IRQ 1: PCI write to memory range */
+ {0, 1}, /* IRQ 2: PCI write to command register */
+ {0, 1}, /* IRQ 3: UART 0 */
+ {0, 1}, /* IRQ 4: UART 1 */
+ {0, 1}, /* IRQ 5: ICC 0 */
+ {0, 1}, /* IRQ 6: ICC 1 */
+ {0, 1}, /* IRQ 7: GPT compare 0 */
+ {0, 1}, /* IRQ 8: GPT compare 1 */
+ {0, 1}, /* IRQ 9: GPT compare 2 */
+ {0, 1}, /* IRQ 10: GPT compare 3 */
+ {0, 1}, /* IRQ 11: GPT compare 4 */
+ {0, 1}, /* IRQ 12: GPT capture 0 */
+ {0, 1}, /* IRQ 13: GPT capture 1 */
+ {0, 1}, /* IRQ 14: GPT capture 2 */
+ {0, 1}, /* IRQ 15: GPT capture 3 */
+ {0, 1}, /* IRQ 16: GPT capture 4 */
+ {0, 0}, /* IRQ 17: reserved */
+ {0, 0}, /* IRQ 18: reserved */
+ {0, 0}, /* IRQ 19: reserved */
+ {0, 0}, /* IRQ 20: reserved */
+ {0, 1}, /* IRQ 21: Ethernet */
+ {0, 0}, /* IRQ 22: reserved */
+ {0, 0}, /* IRQ 23: reserved */
+ {0, 0}, /* IRQ 24: resreved */
+ {0, 0}, /* IRQ 25: reserved */
+ {0, 0}, /* IRQ 26: reserved */
+ {0, 0}, /* IRQ 27: reserved */
+ {0, 0}, /* IRQ 28: reserved */
+ {0, 0}, /* IRQ 29: reserved */
+ {0, 0}, /* IRQ 30: reserved */
+ {0, 0}, /* IRQ 31: reserved */
+};
+
+static int
+pal4_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "board\t\t: SBS Palomar IV\n");
+
+ return 0;
+}
+
+static void
+pal4_restart(char *cmd)
+{
+ local_irq_disable();
+ __asm__ __volatile__("lis 3,0xfff0\n \
+ ori 3,3,0x100\n \
+ mtspr 26,3\n \
+ li 3,0\n \
+ mtspr 27,3\n \
+ rfi");
+
+ for(;;);
+}
+
+static void
+pal4_power_off(void)
+{
+ local_irq_disable();
+ for(;;);
+}
+
+static void
+pal4_halt(void)
+{
+ pal4_power_off();
+}
+
+TODC_ALLOC();
+
+static void __init
+pal4_setup_arch(void)
+{
+ unsigned long l2;
+
+ TODC_INIT(TODC_TYPE_MK48T37, 0, 0,
+ ioremap(PAL4_NVRAM, PAL4_NVRAM_SIZE), 8);
+
+ pal4_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+ ROOT_DEV = Root_NFS;
+
+ /* The L2 gets disabled in the bootloader, but all the proper
+ bits should be present from the fw, so just re-enable it */
+ l2 = _get_L2CR();
+ if (!(l2 & L2CR_L2E)) {
+ /* presume that it was initially set if the size is
+ still present. */
+ if (l2 ^ L2CR_L2SIZ_MASK)
+ _set_L2CR(l2 | L2CR_L2E);
+ else
+ printk("L2 not set by firmware; left disabled.\n");
+ }
+}
+
+static void __init
+pal4_map_io(void)
+{
+ io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ isa_io_base = 0 /*PAL4_ISA_IO_BASE*/;
+ pci_dram_offset = 0 /*PAL4_PCI_SYS_MEM_BASE*/;
+
+ ppc_md.setup_arch = pal4_setup_arch;
+ ppc_md.show_cpuinfo = pal4_show_cpuinfo;
+
+ ppc_md.setup_io_mappings = pal4_map_io;
+
+ ppc_md.init_IRQ = cpc700_init_IRQ;
+ ppc_md.get_irq = cpc700_get_irq;
+
+ ppc_md.restart = pal4_restart;
+ ppc_md.halt = pal4_halt;
+ ppc_md.power_off = pal4_power_off;
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.calibrate_decr = todc_calibrate_decr;
+
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+}
+
diff --git a/arch/ppc/platforms/pcore.c b/arch/ppc/platforms/pcore.c
new file mode 100644
index 00000000000..d7191630a65
--- /dev/null
+++ b/arch/ppc/platforms/pcore.c
@@ -0,0 +1,352 @@
+/*
+ * arch/ppc/platforms/pcore_setup.c
+ *
+ * Setup routines for Force PCORE boards
+ *
+ * Author: Matt Porter <mporter@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.
+ */
+
+#include <linux/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/i8259.h>
+#include <asm/mpc10x.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/kgdb.h>
+
+#include "pcore.h"
+
+extern unsigned long loops_per_jiffy;
+
+static int board_type;
+
+static inline int __init
+pcore_6750_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {9, 10, 11, 12}, /* IDSEL 24 - DEC 21554 */
+ {10, 0, 0, 0}, /* IDSEL 25 - DEC 21143 */
+ {11, 12, 9, 10}, /* IDSEL 26 - PMC I */
+ {12, 9, 10, 11}, /* IDSEL 27 - PMC II */
+ {0, 0, 0, 0}, /* IDSEL 28 - unused */
+ {0, 0, 9, 0}, /* IDSEL 29 - unused */
+ {0, 0, 0, 0}, /* IDSEL 30 - Winbond */
+ };
+ const long min_idsel = 24, max_idsel = 30, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+};
+
+static inline int __init
+pcore_680_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {9, 10, 11, 12}, /* IDSEL 24 - Sentinel */
+ {10, 0, 0, 0}, /* IDSEL 25 - i82559 #1 */
+ {11, 12, 9, 10}, /* IDSEL 26 - PMC I */
+ {12, 9, 10, 11}, /* IDSEL 27 - PMC II */
+ {9, 0, 0, 0}, /* IDSEL 28 - i82559 #2 */
+ {0, 0, 0, 0}, /* IDSEL 29 - unused */
+ {0, 0, 0, 0}, /* IDSEL 30 - Winbond */
+ };
+ const long min_idsel = 24, max_idsel = 30, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+};
+
+void __init
+pcore_pcibios_fixup(void)
+{
+ struct pci_dev *dev;
+
+ if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_83C553,
+ 0)))
+ {
+ /* Reroute interrupts both IDE channels to 15 */
+ pci_write_config_byte(dev,
+ PCORE_WINBOND_IDE_INT,
+ 0xff);
+
+ /* Route INTA-D to IRQ9-12, respectively */
+ pci_write_config_word(dev,
+ PCORE_WINBOND_PCI_INT,
+ 0x9abc);
+
+ /*
+ * Set up 8259 edge/level triggering
+ */
+ outb(0x00, PCORE_WINBOND_PRI_EDG_LVL);
+ outb(0x1e, PCORE_WINBOND_SEC_EDG_LVL);
+ pci_dev_put(dev);
+ }
+}
+
+int __init
+pcore_find_bridges(void)
+{
+ struct pci_controller* hose;
+ int host_bridge, board_type;
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return 0;
+
+ mpc10x_bridge_init(hose,
+ MPC10X_MEM_MAP_B,
+ MPC10X_MEM_MAP_B,
+ MPC10X_MAPB_EUMB_BASE);
+
+ /* Determine board type */
+ early_read_config_dword(hose,
+ 0,
+ PCI_DEVFN(0,0),
+ PCI_VENDOR_ID,
+ &host_bridge);
+ if (host_bridge == MPC10X_BRIDGE_106)
+ board_type = PCORE_TYPE_6750;
+ else /* MPC10X_BRIDGE_107 */
+ board_type = PCORE_TYPE_680;
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pcibios_fixup = pcore_pcibios_fixup;
+ ppc_md.pci_swizzle = common_swizzle;
+
+ if (board_type == PCORE_TYPE_6750)
+ ppc_md.pci_map_irq = pcore_6750_map_irq;
+ else /* PCORE_TYPE_680 */
+ ppc_md.pci_map_irq = pcore_680_map_irq;
+
+ return board_type;
+}
+
+/* Dummy variable to satisfy mpc10x_common.o */
+void *OpenPIC_Addr;
+
+static int
+pcore_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: Force Computers\n");
+
+ if (board_type == PCORE_TYPE_6750)
+ seq_printf(m, "machine\t\t: PowerCore 6750\n");
+ else /* PCORE_TYPE_680 */
+ seq_printf(m, "machine\t\t: PowerCore 680\n");
+
+ seq_printf(m, "L2\t\t: " );
+ if (board_type == PCORE_TYPE_6750)
+ switch (readb(PCORE_DCCR_REG) & PCORE_DCCR_L2_MASK)
+ {
+ case PCORE_DCCR_L2_0KB:
+ seq_printf(m, "nocache");
+ break;
+ case PCORE_DCCR_L2_256KB:
+ seq_printf(m, "256KB");
+ break;
+ case PCORE_DCCR_L2_1MB:
+ seq_printf(m, "1MB");
+ break;
+ case PCORE_DCCR_L2_512KB:
+ seq_printf(m, "512KB");
+ break;
+ default:
+ seq_printf(m, "error");
+ break;
+ }
+ else /* PCORE_TYPE_680 */
+ switch (readb(PCORE_DCCR_REG) & PCORE_DCCR_L2_MASK)
+ {
+ case PCORE_DCCR_L2_2MB:
+ seq_printf(m, "2MB");
+ break;
+ case PCORE_DCCR_L2_256KB:
+ seq_printf(m, "reserved");
+ break;
+ case PCORE_DCCR_L2_1MB:
+ seq_printf(m, "1MB");
+ break;
+ case PCORE_DCCR_L2_512KB:
+ seq_printf(m, "512KB");
+ break;
+ default:
+ seq_printf(m, "error");
+ break;
+ }
+
+ seq_printf(m, "\n");
+
+ return 0;
+}
+
+static void __init
+pcore_setup_arch(void)
+{
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000/HZ;
+
+ /* Lookup PCI host bridges */
+ board_type = pcore_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ printk(KERN_INFO "Force PowerCore ");
+ if (board_type == PCORE_TYPE_6750)
+ printk("6750\n");
+ else
+ printk("680\n");
+ printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+ _set_L2CR(L2CR_L2E | _get_L2CR());
+
+}
+
+static void
+pcore_restart(char *cmd)
+{
+ local_irq_disable();
+ /* Hard reset */
+ writeb(0x11, 0xfe000332);
+ while(1);
+}
+
+static void
+pcore_halt(void)
+{
+ local_irq_disable();
+ /* Turn off user LEDs */
+ writeb(0x00, 0xfe000300);
+ while (1);
+}
+
+static void
+pcore_power_off(void)
+{
+ pcore_halt();
+}
+
+
+static void __init
+pcore_init_IRQ(void)
+{
+ int i;
+
+ for ( i = 0 ; i < 16 ; i++ )
+ irq_desc[i].handler = &i8259_pic;
+
+ i8259_init(0);
+}
+
+/*
+ * Set BAT 3 to map 0xf0000000 to end of physical memory space.
+ */
+static __inline__ void
+pcore_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT3U, 0xf0001ffe);
+ mtspr(SPRN_DBAT3L, 0xfe80002a);
+ mb();
+
+}
+
+static unsigned long __init
+pcore_find_end_of_memory(void)
+{
+
+ return mpc10x_get_mem_size(MPC10X_MEM_MAP_B);
+}
+
+static void __init
+pcore_map_io(void)
+{
+ io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO);
+}
+
+TODC_ALLOC();
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /* Cover I/O space with a BAT */
+ /* yuck, better hope your ram size is a power of 2 -- paulus */
+ pcore_set_bat();
+
+ isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
+ isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
+ pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET;
+
+ ppc_md.setup_arch = pcore_setup_arch;
+ ppc_md.show_cpuinfo = pcore_show_cpuinfo;
+ ppc_md.init_IRQ = pcore_init_IRQ;
+ ppc_md.get_irq = i8259_irq;
+
+ ppc_md.find_end_of_memory = pcore_find_end_of_memory;
+ ppc_md.setup_io_mappings = pcore_map_io;
+
+ ppc_md.restart = pcore_restart;
+ ppc_md.power_off = pcore_power_off;
+ ppc_md.halt = pcore_halt;
+
+ TODC_INIT(TODC_TYPE_MK48T59,
+ PCORE_NVRAM_AS0,
+ PCORE_NVRAM_AS1,
+ PCORE_NVRAM_DATA,
+ 8);
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.calibrate_decr = todc_calibrate_decr;
+
+ ppc_md.nvram_read_val = todc_m48txx_read_val;
+ ppc_md.nvram_write_val = todc_m48txx_write_val;
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = gen550_progress;
+#endif
+#ifdef CONFIG_KGDB
+ ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
+#endif
+}
diff --git a/arch/ppc/platforms/pcore.h b/arch/ppc/platforms/pcore.h
new file mode 100644
index 00000000000..c6a26e76492
--- /dev/null
+++ b/arch/ppc/platforms/pcore.h
@@ -0,0 +1,39 @@
+/*
+ * arch/ppc/platforms/pcore.h
+ *
+ * Definitions for Force PowerCore board support
+ *
+ * Author: Matt Porter <mporter@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_PLATFORMS_PCORE_H
+#define __PPC_PLATFORMS_PCORE_H
+
+#include <asm/mpc10x.h>
+
+#define PCORE_TYPE_6750 1
+#define PCORE_TYPE_680 2
+
+#define PCORE_NVRAM_AS0 0x73
+#define PCORE_NVRAM_AS1 0x75
+#define PCORE_NVRAM_DATA 0x77
+
+#define PCORE_DCCR_REG (MPC10X_MAPB_ISA_IO_BASE + 0x308)
+#define PCORE_DCCR_L2_MASK 0xc0
+#define PCORE_DCCR_L2_0KB 0x00
+#define PCORE_DCCR_L2_256KB 0x40
+#define PCORE_DCCR_L2_512KB 0xc0
+#define PCORE_DCCR_L2_1MB 0x80
+#define PCORE_DCCR_L2_2MB 0x00
+
+#define PCORE_WINBOND_IDE_INT 0x43
+#define PCORE_WINBOND_PCI_INT 0x44
+#define PCORE_WINBOND_PRI_EDG_LVL 0x4d0
+#define PCORE_WINBOND_SEC_EDG_LVL 0x4d1
+
+#endif /* __PPC_PLATFORMS_PCORE_H */
diff --git a/arch/ppc/platforms/pcu_e.h b/arch/ppc/platforms/pcu_e.h
new file mode 100644
index 00000000000..91a820a6fbc
--- /dev/null
+++ b/arch/ppc/platforms/pcu_e.h
@@ -0,0 +1,28 @@
+/*
+ * Siemens PCU E board specific definitions
+ *
+ * Copyright (c) 2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifndef __MACH_PCU_E_H
+#define __MACH_PCU_E_H
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define PCU_E_IMMR_BASE 0xFE000000 /* phys. addr of IMMR */
+#define PCU_E_IMAP_SIZE (64 * 1024) /* size of mapped area */
+
+#define IMAP_ADDR PCU_E_IMMR_BASE /* physical base address of IMMR area */
+#define IMAP_SIZE PCU_E_IMAP_SIZE /* mapped size of IMMR area */
+
+#define FEC_INTERRUPT 15 /* = SIU_LEVEL7 */
+#define DEC_INTERRUPT 13 /* = SIU_LEVEL6 */
+#define CPM_INTERRUPT 11 /* = SIU_LEVEL5 (was: SIU_LEVEL2) */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif /* __MACH_PCU_E_H */
diff --git a/arch/ppc/platforms/pmac_backlight.c b/arch/ppc/platforms/pmac_backlight.c
new file mode 100644
index 00000000000..ed2b1cebc19
--- /dev/null
+++ b/arch/ppc/platforms/pmac_backlight.c
@@ -0,0 +1,202 @@
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ * Contains support for the backlight.
+ *
+ * Copyright (C) 2000 Benjamin Herrenschmidt
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
+#include <linux/console.h>
+#include <asm/sections.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+#include <asm/backlight.h>
+
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+static struct backlight_controller *backlighter;
+static void* backlighter_data;
+static int backlight_autosave;
+static int backlight_level = BACKLIGHT_MAX;
+static int backlight_enabled = 1;
+static int backlight_req_level = -1;
+static int backlight_req_enable = -1;
+
+static void backlight_callback(void *);
+static DECLARE_WORK(backlight_work, backlight_callback, NULL);
+
+void __pmac register_backlight_controller(struct backlight_controller *ctrler,
+ void *data, char *type)
+{
+ struct device_node* bk_node;
+ char *prop;
+ int valid = 0;
+
+ /* There's already a matching controller, bail out */
+ if (backlighter != NULL)
+ return;
+
+ bk_node = find_devices("backlight");
+
+#ifdef CONFIG_ADB_PMU
+ /* Special case for the old PowerBook since I can't test on it */
+ backlight_autosave = machine_is_compatible("AAPL,3400/2400")
+ || machine_is_compatible("AAPL,3500");
+ if ((backlight_autosave
+ || machine_is_compatible("AAPL,PowerBook1998")
+ || machine_is_compatible("PowerBook1,1"))
+ && !strcmp(type, "pmu"))
+ valid = 1;
+#endif
+ if (bk_node) {
+ prop = get_property(bk_node, "backlight-control", NULL);
+ if (prop && !strncmp(prop, type, strlen(type)))
+ valid = 1;
+ }
+ if (!valid)
+ return;
+ backlighter = ctrler;
+ backlighter_data = data;
+
+ if (bk_node && !backlight_autosave)
+ prop = get_property(bk_node, "bklt", NULL);
+ else
+ prop = NULL;
+ if (prop) {
+ backlight_level = ((*prop)+1) >> 1;
+ if (backlight_level > BACKLIGHT_MAX)
+ backlight_level = BACKLIGHT_MAX;
+ }
+
+#ifdef CONFIG_ADB_PMU
+ if (backlight_autosave) {
+ struct adb_request req;
+ pmu_request(&req, NULL, 2, 0xd9, 0);
+ while (!req.complete)
+ pmu_poll();
+ backlight_level = req.reply[0] >> 4;
+ }
+#endif
+ acquire_console_sem();
+ if (!backlighter->set_enable(1, backlight_level, data))
+ backlight_enabled = 1;
+ release_console_sem();
+
+ printk(KERN_INFO "Registered \"%s\" backlight controller,"
+ "level: %d/15\n", type, backlight_level);
+}
+EXPORT_SYMBOL(register_backlight_controller);
+
+void __pmac unregister_backlight_controller(struct backlight_controller
+ *ctrler, void *data)
+{
+ /* We keep the current backlight level (for now) */
+ if (ctrler == backlighter && data == backlighter_data)
+ backlighter = NULL;
+}
+EXPORT_SYMBOL(unregister_backlight_controller);
+
+static int __pmac __set_backlight_enable(int enable)
+{
+ int rc;
+
+ if (!backlighter)
+ return -ENODEV;
+ acquire_console_sem();
+ rc = backlighter->set_enable(enable, backlight_level,
+ backlighter_data);
+ if (!rc)
+ backlight_enabled = enable;
+ release_console_sem();
+ return rc;
+}
+int __pmac set_backlight_enable(int enable)
+{
+ if (!backlighter)
+ return -ENODEV;
+ backlight_req_enable = enable;
+ schedule_work(&backlight_work);
+ return 0;
+}
+
+EXPORT_SYMBOL(set_backlight_enable);
+
+int __pmac get_backlight_enable(void)
+{
+ if (!backlighter)
+ return -ENODEV;
+ return backlight_enabled;
+}
+EXPORT_SYMBOL(get_backlight_enable);
+
+static int __pmac __set_backlight_level(int level)
+{
+ int rc = 0;
+
+ if (!backlighter)
+ return -ENODEV;
+ if (level < BACKLIGHT_MIN)
+ level = BACKLIGHT_OFF;
+ if (level > BACKLIGHT_MAX)
+ level = BACKLIGHT_MAX;
+ acquire_console_sem();
+ if (backlight_enabled)
+ rc = backlighter->set_level(level, backlighter_data);
+ if (!rc)
+ backlight_level = level;
+ release_console_sem();
+ if (!rc && !backlight_autosave) {
+ level <<=1;
+ if (level & 0x10)
+ level |= 0x01;
+ // -- todo: save to property "bklt"
+ }
+ return rc;
+}
+int __pmac set_backlight_level(int level)
+{
+ if (!backlighter)
+ return -ENODEV;
+ backlight_req_level = level;
+ schedule_work(&backlight_work);
+ return 0;
+}
+
+EXPORT_SYMBOL(set_backlight_level);
+
+int __pmac get_backlight_level(void)
+{
+ if (!backlighter)
+ return -ENODEV;
+ return backlight_level;
+}
+EXPORT_SYMBOL(get_backlight_level);
+
+static void backlight_callback(void *dummy)
+{
+ int level, enable;
+
+ do {
+ level = backlight_req_level;
+ enable = backlight_req_enable;
+ mb();
+
+ if (level >= 0)
+ __set_backlight_level(level);
+ if (enable >= 0)
+ __set_backlight_enable(enable);
+ } while(cmpxchg(&backlight_req_level, level, -1) != level ||
+ cmpxchg(&backlight_req_enable, enable, -1) != enable);
+}
diff --git a/arch/ppc/platforms/pmac_cache.S b/arch/ppc/platforms/pmac_cache.S
new file mode 100644
index 00000000000..c00e0352044
--- /dev/null
+++ b/arch/ppc/platforms/pmac_cache.S
@@ -0,0 +1,325 @@
+/*
+ * This file contains low-level cache management functions
+ * used for sleep and CPU speed changes on Apple machines.
+ * (In fact the only thing that is Apple-specific is that we assume
+ * that we can read from ROM at physical address 0xfff00000.)
+ *
+ * Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and
+ * Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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/config.h>
+#include <asm/processor.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+
+/*
+ * Flush and disable all data caches (dL1, L2, L3). This is used
+ * when going to sleep, when doing a PMU based cpufreq transition,
+ * or when "offlining" a CPU on SMP machines. This code is over
+ * paranoid, but I've had enough issues with various CPU revs and
+ * bugs that I decided it was worth beeing over cautious
+ */
+
+_GLOBAL(flush_disable_caches)
+BEGIN_FTR_SECTION
+ b flush_disable_745x
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
+BEGIN_FTR_SECTION
+ b flush_disable_75x
+END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
+ b __flush_disable_L1
+
+/* This is the code for G3 and 74[01]0 */
+flush_disable_75x:
+ mflr r10
+
+ /* Turn off EE and DR in MSR */
+ mfmsr r11
+ rlwinm r0,r11,0,~MSR_EE
+ rlwinm r0,r0,0,~MSR_DR
+ sync
+ mtmsr r0
+ isync
+
+ /* Stop DST streams */
+BEGIN_FTR_SECTION
+ DSSALL
+ sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+
+ /* Stop DPM */
+ mfspr r8,SPRN_HID0 /* Save SPRN_HID0 in r8 */
+ rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */
+ sync
+ mtspr SPRN_HID0,r4 /* Disable DPM */
+ sync
+
+ /* disp-flush L1 */
+ li r4,0x4000
+ mtctr r4
+ lis r4,0xfff0
+1: lwzx r0,r0,r4
+ addi r4,r4,32
+ bdnz 1b
+ sync
+ isync
+
+ /* disable / invalidate / enable L1 data */
+ mfspr r3,SPRN_HID0
+ rlwinm r0,r0,0,~HID0_DCE
+ mtspr SPRN_HID0,r3
+ sync
+ isync
+ ori r3,r3,HID0_DCE|HID0_DCI
+ sync
+ isync
+ mtspr SPRN_HID0,r3
+ xori r3,r3,HID0_DCI
+ mtspr SPRN_HID0,r3
+ sync
+
+ /* Get the current enable bit of the L2CR into r4 */
+ mfspr r5,SPRN_L2CR
+ /* Set to data-only (pre-745x bit) */
+ oris r3,r5,L2CR_L2DO@h
+ b 2f
+ /* When disabling L2, code must be in L1 */
+ .balign 32
+1: mtspr SPRN_L2CR,r3
+3: sync
+ isync
+ b 1f
+2: b 3f
+3: sync
+ isync
+ b 1b
+1: /* disp-flush L2. The interesting thing here is that the L2 can be
+ * up to 2Mb ... so using the ROM, we'll end up wrapping back to memory
+ * but that is probbaly fine. We disp-flush over 4Mb to be safe
+ */
+ lis r4,2
+ mtctr r4
+ lis r4,0xfff0
+1: lwzx r0,r0,r4
+ addi r4,r4,32
+ bdnz 1b
+ sync
+ isync
+ /* now disable L2 */
+ rlwinm r5,r5,0,~L2CR_L2E
+ b 2f
+ /* When disabling L2, code must be in L1 */
+ .balign 32
+1: mtspr SPRN_L2CR,r5
+3: sync
+ isync
+ b 1f
+2: b 3f
+3: sync
+ isync
+ b 1b
+1: sync
+ isync
+ /* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */
+ oris r4,r5,L2CR_L2I@h
+ mtspr SPRN_L2CR,r4
+ sync
+ isync
+ xoris r4,r4,L2CR_L2I@h
+ sync
+ mtspr SPRN_L2CR,r4
+ sync
+
+ /* now disable the L1 data cache */
+ mfspr r0,SPRN_HID0
+ rlwinm r0,r0,0,~HID0_DCE
+ mtspr SPRN_HID0,r0
+ sync
+ isync
+
+ /* Restore HID0[DPM] to whatever it was before */
+ sync
+ mtspr SPRN_HID0,r8
+ sync
+
+ /* restore DR and EE */
+ sync
+ mtmsr r11
+ isync
+
+ mtlr r10
+ blr
+
+/* This code is for 745x processors */
+flush_disable_745x:
+ /* Turn off EE and DR in MSR */
+ mfmsr r11
+ rlwinm r0,r11,0,~MSR_EE
+ rlwinm r0,r0,0,~MSR_DR
+ sync
+ mtmsr r0
+ isync
+
+ /* Stop prefetch streams */
+ DSSALL
+ sync
+
+ /* Disable L2 prefetching */
+ mfspr r0,SPRN_MSSCR0
+ rlwinm r0,r0,0,0,29
+ mtspr SPRN_MSSCR0,r0
+ sync
+ isync
+ lis r4,0
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+ dcbf 0,r4
+
+ /* Due to a bug with the HW flush on some CPU revs, we occasionally
+ * experience data corruption. I'm adding a displacement flush along
+ * with a dcbf loop over a few Mb to "help". The problem isn't totally
+ * fixed by this in theory, but at least, in practice, I couldn't reproduce
+ * it even with a big hammer...
+ */
+
+ lis r4,0x0002
+ mtctr r4
+ li r4,0
+1:
+ lwzx r0,r0,r4
+ addi r4,r4,32 /* Go to start of next cache line */
+ bdnz 1b
+ isync
+
+ /* Now, flush the first 4MB of memory */
+ lis r4,0x0002
+ mtctr r4
+ li r4,0
+ sync
+1:
+ dcbf 0,r4
+ addi r4,r4,32 /* Go to start of next cache line */
+ bdnz 1b
+
+ /* Flush and disable the L1 data cache */
+ mfspr r6,SPRN_LDSTCR
+ lis r3,0xfff0 /* read from ROM for displacement flush */
+ li r4,0xfe /* start with only way 0 unlocked */
+ li r5,128 /* 128 lines in each way */
+1: mtctr r5
+ rlwimi r6,r4,0,24,31
+ mtspr SPRN_LDSTCR,r6
+ sync
+ isync
+2: lwz r0,0(r3) /* touch each cache line */
+ addi r3,r3,32
+ bdnz 2b
+ rlwinm r4,r4,1,24,30 /* move on to the next way */
+ ori r4,r4,1
+ cmpwi r4,0xff /* all done? */
+ bne 1b
+ /* now unlock the L1 data cache */
+ li r4,0
+ rlwimi r6,r4,0,24,31
+ sync
+ mtspr SPRN_LDSTCR,r6
+ sync
+ isync
+
+ /* Flush the L2 cache using the hardware assist */
+ mfspr r3,SPRN_L2CR
+ cmpwi r3,0 /* check if it is enabled first */
+ bge 4f
+ oris r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h
+ b 2f
+ /* When disabling/locking L2, code must be in L1 */
+ .balign 32
+1: mtspr SPRN_L2CR,r0 /* lock the L2 cache */
+3: sync
+ isync
+ b 1f
+2: b 3f
+3: sync
+ isync
+ b 1b
+1: sync
+ isync
+ ori r0,r3,L2CR_L2HWF_745x
+ sync
+ mtspr SPRN_L2CR,r0 /* set the hardware flush bit */
+3: mfspr r0,SPRN_L2CR /* wait for it to go to 0 */
+ andi. r0,r0,L2CR_L2HWF_745x
+ bne 3b
+ sync
+ rlwinm r3,r3,0,~L2CR_L2E
+ b 2f
+ /* When disabling L2, code must be in L1 */
+ .balign 32
+1: mtspr SPRN_L2CR,r3 /* disable the L2 cache */
+3: sync
+ isync
+ b 1f
+2: b 3f
+3: sync
+ isync
+ b 1b
+1: sync
+ isync
+ oris r4,r3,L2CR_L2I@h
+ mtspr SPRN_L2CR,r4
+ sync
+ isync
+1: mfspr r4,SPRN_L2CR
+ andis. r0,r4,L2CR_L2I@h
+ bne 1b
+ sync
+
+BEGIN_FTR_SECTION
+ /* Flush the L3 cache using the hardware assist */
+4: mfspr r3,SPRN_L3CR
+ cmpwi r3,0 /* check if it is enabled */
+ bge 6f
+ oris r0,r3,L3CR_L3IO@h
+ ori r0,r0,L3CR_L3DO
+ sync
+ mtspr SPRN_L3CR,r0 /* lock the L3 cache */
+ sync
+ isync
+ ori r0,r0,L3CR_L3HWF
+ sync
+ mtspr SPRN_L3CR,r0 /* set the hardware flush bit */
+5: mfspr r0,SPRN_L3CR /* wait for it to go to zero */
+ andi. r0,r0,L3CR_L3HWF
+ bne 5b
+ rlwinm r3,r3,0,~L3CR_L3E
+ sync
+ mtspr SPRN_L3CR,r3 /* disable the L3 cache */
+ sync
+ ori r4,r3,L3CR_L3I
+ mtspr SPRN_L3CR,r4
+1: mfspr r4,SPRN_L3CR
+ andi. r0,r4,L3CR_L3I
+ bne 1b
+ sync
+END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
+
+6: mfspr r0,SPRN_HID0 /* now disable the L1 data cache */
+ rlwinm r0,r0,0,~HID0_DCE
+ mtspr SPRN_HID0,r0
+ sync
+ isync
+ mtmsr r11 /* restore DR and EE */
+ isync
+ blr
diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c
new file mode 100644
index 00000000000..9c85f9ca1cf
--- /dev/null
+++ b/arch/ppc/platforms/pmac_cpufreq.c
@@ -0,0 +1,571 @@
+/*
+ * arch/ppc/platforms/pmac_cpufreq.c
+ *
+ * Copyright (C) 2002 - 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * Copyright (C) 2004 John Steele Scott <toojays@toojays.net>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+#include <linux/i2c.h>
+#include <linux/hardirq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/pmac_feature.h>
+#include <asm/mmu_context.h>
+#include <asm/sections.h>
+#include <asm/cputable.h>
+#include <asm/time.h>
+#include <asm/system.h>
+#include <asm/open_pic.h>
+
+/* WARNING !!! This will cause calibrate_delay() to be called,
+ * but this is an __init function ! So you MUST go edit
+ * init/main.c to make it non-init before enabling DEBUG_FREQ
+ */
+#undef DEBUG_FREQ
+
+/*
+ * There is a problem with the core cpufreq code on SMP kernels,
+ * it won't recalculate the Bogomips properly
+ */
+#ifdef CONFIG_SMP
+#warning "WARNING, CPUFREQ not recommended on SMP kernels"
+#endif
+
+extern void low_choose_7447a_dfs(int dfs);
+extern void low_choose_750fx_pll(int pll);
+extern void low_sleep_handler(void);
+
+/*
+ * Currently, PowerMac cpufreq supports only high & low frequencies
+ * that are set by the firmware
+ */
+static unsigned int low_freq;
+static unsigned int hi_freq;
+static unsigned int cur_freq;
+
+/*
+ * Different models uses different mecanisms to switch the frequency
+ */
+static int (*set_speed_proc)(int low_speed);
+
+/*
+ * Some definitions used by the various speedprocs
+ */
+static u32 voltage_gpio;
+static u32 frequency_gpio;
+static u32 slew_done_gpio;
+
+
+#define PMAC_CPU_LOW_SPEED 1
+#define PMAC_CPU_HIGH_SPEED 0
+
+/* There are only two frequency states for each processor. Values
+ * are in kHz for the time being.
+ */
+#define CPUFREQ_HIGH PMAC_CPU_HIGH_SPEED
+#define CPUFREQ_LOW PMAC_CPU_LOW_SPEED
+
+static struct cpufreq_frequency_table pmac_cpu_freqs[] = {
+ {CPUFREQ_HIGH, 0},
+ {CPUFREQ_LOW, 0},
+ {0, CPUFREQ_TABLE_END},
+};
+
+static inline void wakeup_decrementer(void)
+{
+ set_dec(tb_ticks_per_jiffy);
+ /* No currently-supported powerbook has a 601,
+ * so use get_tbl, not native
+ */
+ last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
+}
+
+#ifdef DEBUG_FREQ
+static inline void debug_calc_bogomips(void)
+{
+ /* This will cause a recalc of bogomips and display the
+ * result. We backup/restore the value to avoid affecting the
+ * core cpufreq framework's own calculation.
+ */
+ extern void calibrate_delay(void);
+
+ unsigned long save_lpj = loops_per_jiffy;
+ calibrate_delay();
+ loops_per_jiffy = save_lpj;
+}
+#endif /* DEBUG_FREQ */
+
+/* Switch CPU speed under 750FX CPU control
+ */
+static int __pmac cpu_750fx_cpu_speed(int low_speed)
+{
+#ifdef DEBUG_FREQ
+ printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
+#endif
+#ifdef CONFIG_6xx
+ low_choose_750fx_pll(low_speed);
+#endif
+#ifdef DEBUG_FREQ
+ printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
+ debug_calc_bogomips();
+#endif
+
+ return 0;
+}
+
+/* Switch CPU speed using DFS */
+static int __pmac dfs_set_cpu_speed(int low_speed)
+{
+ if (low_speed == 0) {
+ /* ramping up, set voltage first */
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
+ /* Make sure we sleep for at least 1ms */
+ msleep(1);
+ }
+
+ /* set frequency */
+ low_choose_7447a_dfs(low_speed);
+
+ if (low_speed == 1) {
+ /* ramping down, set voltage last */
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
+ msleep(1);
+ }
+
+ return 0;
+}
+
+static unsigned int __pmac dfs_get_cpu_speed(unsigned int cpu)
+{
+ if (mfspr(SPRN_HID1) & HID1_DFS)
+ return low_freq;
+ else
+ return hi_freq;
+}
+
+
+/* Switch CPU speed using slewing GPIOs
+ */
+static int __pmac gpios_set_cpu_speed(int low_speed)
+{
+ int gpio;
+
+ /* If ramping up, set voltage first */
+ if (low_speed == 0) {
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
+ /* Delay is way too big but it's ok, we schedule */
+ msleep(10);
+ }
+
+ /* Set frequency */
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio,
+ low_speed ? 0x04 : 0x05);
+ udelay(200);
+ do {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0);
+ } while((gpio & 0x02) == 0);
+
+ /* If ramping down, set voltage last */
+ if (low_speed == 1) {
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
+ /* Delay is way too big but it's ok, we schedule */
+ msleep(10);
+ }
+
+#ifdef DEBUG_FREQ
+ debug_calc_bogomips();
+#endif
+
+ return 0;
+}
+
+/* Switch CPU speed under PMU control
+ */
+static int __pmac pmu_set_cpu_speed(int low_speed)
+{
+ struct adb_request req;
+ unsigned long save_l2cr;
+ unsigned long save_l3cr;
+
+ preempt_disable();
+
+#ifdef DEBUG_FREQ
+ printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
+#endif
+ /* Disable all interrupt sources on openpic */
+ openpic_set_priority(0xf);
+
+ /* Make sure the decrementer won't interrupt us */
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+ /* Make sure any pending DEC interrupt occuring while we did
+ * the above didn't re-enable the DEC */
+ mb();
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+ /* We can now disable MSR_EE */
+ local_irq_disable();
+
+ /* Giveup the FPU & vec */
+ enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+ /* Save & disable L2 and L3 caches */
+ save_l3cr = _get_L3CR(); /* (returns -1 if not available) */
+ save_l2cr = _get_L2CR(); /* (returns -1 if not available) */
+
+ /* Send the new speed command. My assumption is that this command
+ * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep
+ */
+ pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed);
+ while (!req.complete)
+ pmu_poll();
+
+ /* Prepare the northbridge for the speed transition */
+ pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1);
+
+ /* Call low level code to backup CPU state and recover from
+ * hardware reset
+ */
+ low_sleep_handler();
+
+ /* Restore the northbridge */
+ pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0);
+
+ /* Restore L2 cache */
+ if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
+ _set_L2CR(save_l2cr);
+ /* Restore L3 cache */
+ if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
+ _set_L3CR(save_l3cr);
+
+ /* Restore userland MMU context */
+ set_context(current->active_mm->context, current->active_mm->pgd);
+
+#ifdef DEBUG_FREQ
+ printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
+#endif
+
+ /* Restore low level PMU operations */
+ pmu_unlock();
+
+ /* Restore decrementer */
+ wakeup_decrementer();
+
+ /* Restore interrupts */
+ openpic_set_priority(0);
+
+ /* Let interrupts flow again ... */
+ local_irq_enable();
+
+#ifdef DEBUG_FREQ
+ debug_calc_bogomips();
+#endif
+
+ preempt_enable();
+
+ return 0;
+}
+
+static int __pmac do_set_cpu_speed(int speed_mode)
+{
+ struct cpufreq_freqs freqs;
+
+ freqs.old = cur_freq;
+ freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq;
+ freqs.cpu = smp_processor_id();
+
+ if (freqs.old == freqs.new)
+ return 0;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ set_speed_proc(speed_mode == PMAC_CPU_LOW_SPEED);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq;
+
+ return 0;
+}
+
+static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs);
+}
+
+static int __pmac pmac_cpufreq_target( struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int newstate = 0;
+
+ if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs,
+ target_freq, relation, &newstate))
+ return -EINVAL;
+
+ return do_set_cpu_speed(newstate);
+}
+
+unsigned int __pmac pmac_get_one_cpufreq(int i)
+{
+ /* Supports only one CPU for now */
+ return (i == 0) ? cur_freq : 0;
+}
+
+static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ if (policy->cpu != 0)
+ return -ENODEV;
+
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ policy->cur = cur_freq;
+
+ return cpufreq_frequency_table_cpuinfo(policy, &pmac_cpu_freqs[0]);
+}
+
+static u32 __pmac read_gpio(struct device_node *np)
+{
+ u32 *reg = (u32 *)get_property(np, "reg", NULL);
+
+ if (reg == NULL)
+ return 0;
+ /* That works for all keylargos but shall be fixed properly
+ * some day...
+ */
+ return 0x50 + (*reg);
+}
+
+static struct cpufreq_driver pmac_cpufreq_driver = {
+ .verify = pmac_cpufreq_verify,
+ .target = pmac_cpufreq_target,
+ .init = pmac_cpufreq_cpu_init,
+ .name = "powermac",
+ .owner = THIS_MODULE,
+};
+
+
+static int __pmac pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
+{
+ struct device_node *volt_gpio_np = of_find_node_by_name(NULL,
+ "voltage-gpio");
+ struct device_node *freq_gpio_np = of_find_node_by_name(NULL,
+ "frequency-gpio");
+ struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL,
+ "slewing-done");
+ u32 *value;
+
+ /*
+ * Check to see if it's GPIO driven or PMU only
+ *
+ * The way we extract the GPIO address is slightly hackish, but it
+ * works well enough for now. We need to abstract the whole GPIO
+ * stuff sooner or later anyway
+ */
+
+ if (volt_gpio_np)
+ voltage_gpio = read_gpio(volt_gpio_np);
+ if (freq_gpio_np)
+ frequency_gpio = read_gpio(freq_gpio_np);
+ if (slew_done_gpio_np)
+ slew_done_gpio = read_gpio(slew_done_gpio_np);
+
+ /* If we use the frequency GPIOs, calculate the min/max speeds based
+ * on the bus frequencies
+ */
+ if (frequency_gpio && slew_done_gpio) {
+ int lenp, rc;
+ u32 *freqs, *ratio;
+
+ freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp);
+ lenp /= sizeof(u32);
+ if (freqs == NULL || lenp != 2) {
+ printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n");
+ return 1;
+ }
+ ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL);
+ if (ratio == NULL) {
+ printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n");
+ return 1;
+ }
+
+ /* Get the min/max bus frequencies */
+ low_freq = min(freqs[0], freqs[1]);
+ hi_freq = max(freqs[0], freqs[1]);
+
+ /* Grrrr.. It _seems_ that the device-tree is lying on the low bus
+ * frequency, it claims it to be around 84Mhz on some models while
+ * it appears to be approx. 101Mhz on all. Let's hack around here...
+ * fortunately, we don't need to be too precise
+ */
+ if (low_freq < 98000000)
+ low_freq = 101000000;
+
+ /* Convert those to CPU core clocks */
+ low_freq = (low_freq * (*ratio)) / 2000;
+ hi_freq = (hi_freq * (*ratio)) / 2000;
+
+ /* Now we get the frequencies, we read the GPIO to see what is out current
+ * speed
+ */
+ rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
+ cur_freq = (rc & 0x01) ? hi_freq : low_freq;
+
+ set_speed_proc = gpios_set_cpu_speed;
+ return 1;
+ }
+
+ /* If we use the PMU, look for the min & max frequencies in the
+ * device-tree
+ */
+ value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL);
+ if (!value)
+ return 1;
+ low_freq = (*value) / 1000;
+ /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree
+ * here */
+ if (low_freq < 100000)
+ low_freq *= 10;
+
+ value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL);
+ if (!value)
+ return 1;
+ hi_freq = (*value) / 1000;
+ set_speed_proc = pmu_set_cpu_speed;
+
+ return 0;
+}
+
+static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode)
+{
+ struct device_node *volt_gpio_np;
+ u32 *reg;
+ struct cpufreq_driver *driver = &pmac_cpufreq_driver;
+
+ /* Look for voltage GPIO */
+ volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
+ reg = (u32 *)get_property(volt_gpio_np, "reg", NULL);
+ voltage_gpio = *reg;
+ if (!volt_gpio_np){
+ printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n");
+ return 1;
+ }
+
+ /* OF only reports the high frequency */
+ hi_freq = cur_freq;
+ low_freq = cur_freq/2;
+
+ /* Read actual frequency from CPU */
+ driver->get = dfs_get_cpu_speed;
+ cur_freq = driver->get(0);
+ set_speed_proc = dfs_set_cpu_speed;
+
+ return 0;
+}
+
+/* Currently, we support the following machines:
+ *
+ * - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz)
+ * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz)
+ * - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz)
+ * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz)
+ * - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz)
+ * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage)
+ * - Recent MacRISC3 laptops
+ * - All new machines with 7447A CPUs
+ */
+static int __init pmac_cpufreq_setup(void)
+{
+ struct device_node *cpunode;
+ u32 *value;
+
+ if (strstr(cmd_line, "nocpufreq"))
+ return 0;
+
+ /* Assume only one CPU */
+ cpunode = find_type_devices("cpu");
+ if (!cpunode)
+ goto out;
+
+ /* Get current cpu clock freq */
+ value = (u32 *)get_property(cpunode, "clock-frequency", NULL);
+ if (!value)
+ goto out;
+ cur_freq = (*value) / 1000;
+
+ /* Check for 7447A based MacRISC3 */
+ if (machine_is_compatible("MacRISC3") &&
+ get_property(cpunode, "dynamic-power-step", NULL) &&
+ PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
+ pmac_cpufreq_init_7447A(cpunode);
+ /* Check for other MacRISC3 machines */
+ } else if (machine_is_compatible("PowerBook3,4") ||
+ machine_is_compatible("PowerBook3,5") ||
+ machine_is_compatible("MacRISC3")) {
+ pmac_cpufreq_init_MacRISC3(cpunode);
+ /* Else check for iBook2 500/600 */
+ } else if (machine_is_compatible("PowerBook4,1")) {
+ hi_freq = cur_freq;
+ low_freq = 400000;
+ set_speed_proc = pmu_set_cpu_speed;
+ }
+ /* Else check for TiPb 400 & 500 */
+ else if (machine_is_compatible("PowerBook3,2")) {
+ /* We only know about the 400 MHz and the 500Mhz model
+ * they both have 300 MHz as low frequency
+ */
+ if (cur_freq < 350000 || cur_freq > 550000)
+ goto out;
+ hi_freq = cur_freq;
+ low_freq = 300000;
+ set_speed_proc = pmu_set_cpu_speed;
+ }
+ /* Else check for 750FX */
+ else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000) {
+ if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+ goto out;
+ hi_freq = cur_freq;
+ value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL);
+ if (!value)
+ goto out;
+ low_freq = (*value) / 1000;
+ set_speed_proc = cpu_750fx_cpu_speed;
+ }
+out:
+ if (set_speed_proc == NULL)
+ return -ENODEV;
+
+ pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq;
+ pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq;
+
+ printk(KERN_INFO "Registering PowerMac CPU frequency driver\n");
+ printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n",
+ low_freq/1000, hi_freq/1000, cur_freq/1000);
+
+ return cpufreq_register_driver(&pmac_cpufreq_driver);
+}
+
+module_init(pmac_cpufreq_setup);
+
diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
new file mode 100644
index 00000000000..8e60550863a
--- /dev/null
+++ b/arch/ppc/platforms/pmac_feature.c
@@ -0,0 +1,2972 @@
+/*
+ * arch/ppc/platforms/pmac_feature.c
+ *
+ * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
+ * Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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.
+ *
+ * TODO:
+ *
+ * - Replace mdelay with some schedule loop if possible
+ * - Shorten some obfuscated delays on some routines (like modem
+ * power)
+ * - Refcount some clocks (see darwin)
+ * - Split split split...
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/sections.h>
+#include <asm/errno.h>
+#include <asm/ohare.h>
+#include <asm/heathrow.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/dbdma.h>
+#include <asm/pci-bridge.h>
+#include <asm/pmac_low_i2c.h>
+
+#undef DEBUG_FEATURE
+
+#ifdef DEBUG_FEATURE
+#define DBG(fmt,...) printk(KERN_DEBUG fmt)
+#else
+#define DBG(fmt,...)
+#endif
+
+#ifdef CONFIG_6xx
+extern int powersave_lowspeed;
+#endif
+
+extern int powersave_nap;
+extern struct device_node *k2_skiplist[2];
+
+
+/*
+ * We use a single global lock to protect accesses. Each driver has
+ * to take care of its own locking
+ */
+static DEFINE_SPINLOCK(feature_lock __pmacdata);
+
+#define LOCK(flags) spin_lock_irqsave(&feature_lock, flags);
+#define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags);
+
+
+/*
+ * Instance of some macio stuffs
+ */
+struct macio_chip macio_chips[MAX_MACIO_CHIPS] __pmacdata;
+
+struct macio_chip* __pmac
+macio_find(struct device_node* child, int type)
+{
+ while(child) {
+ int i;
+
+ for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
+ if (child == macio_chips[i].of_node &&
+ (!type || macio_chips[i].type == type))
+ return &macio_chips[i];
+ child = child->parent;
+ }
+ return NULL;
+}
+
+static const char* macio_names[] __pmacdata =
+{
+ "Unknown",
+ "Grand Central",
+ "OHare",
+ "OHareII",
+ "Heathrow",
+ "Gatwick",
+ "Paddington",
+ "Keylargo",
+ "Pangea",
+ "Intrepid",
+ "K2"
+};
+
+
+
+/*
+ * Uninorth reg. access. Note that Uni-N regs are big endian
+ */
+
+#define UN_REG(r) (uninorth_base + ((r) >> 2))
+#define UN_IN(r) (in_be32(UN_REG(r)))
+#define UN_OUT(r,v) (out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v)))
+
+static struct device_node* uninorth_node __pmacdata;
+static u32 __iomem * uninorth_base __pmacdata;
+static u32 uninorth_rev __pmacdata;
+static int uninorth_u3 __pmacdata;
+static void __iomem *u3_ht;
+
+/*
+ * For each motherboard family, we have a table of functions pointers
+ * that handle the various features.
+ */
+
+typedef long (*feature_call)(struct device_node* node, long param, long value);
+
+struct feature_table_entry {
+ unsigned int selector;
+ feature_call function;
+};
+
+struct pmac_mb_def
+{
+ const char* model_string;
+ const char* model_name;
+ int model_id;
+ struct feature_table_entry* features;
+ unsigned long board_flags;
+};
+static struct pmac_mb_def pmac_mb __pmacdata;
+
+/*
+ * Here are the chip specific feature functions
+ */
+
+static inline int __pmac
+simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int value)
+{
+ struct macio_chip* macio;
+ unsigned long flags;
+
+ macio = macio_find(node, type);
+ if (!macio)
+ return -ENODEV;
+ LOCK(flags);
+ if (value)
+ MACIO_BIS(reg, mask);
+ else
+ MACIO_BIC(reg, mask);
+ (void)MACIO_IN32(reg);
+ UNLOCK(flags);
+
+ return 0;
+}
+
+#ifndef CONFIG_POWER4
+
+static long __pmac
+ohare_htw_scc_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ unsigned long chan_mask;
+ unsigned long fcr;
+ unsigned long flags;
+ int htw, trans;
+ unsigned long rmask;
+
+ macio = macio_find(node, 0);
+ if (!macio)
+ return -ENODEV;
+ if (!strcmp(node->name, "ch-a"))
+ chan_mask = MACIO_FLAG_SCCA_ON;
+ else if (!strcmp(node->name, "ch-b"))
+ chan_mask = MACIO_FLAG_SCCB_ON;
+ else
+ return -ENODEV;
+
+ htw = (macio->type == macio_heathrow || macio->type == macio_paddington
+ || macio->type == macio_gatwick);
+ /* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
+ trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
+ pmac_mb.model_id != PMAC_TYPE_YIKES);
+ if (value) {
+#ifdef CONFIG_ADB_PMU
+ if ((param & 0xfff) == PMAC_SCC_IRDA)
+ pmu_enable_irled(1);
+#endif /* CONFIG_ADB_PMU */
+ LOCK(flags);
+ fcr = MACIO_IN32(OHARE_FCR);
+ /* Check if scc cell need enabling */
+ if (!(fcr & OH_SCC_ENABLE)) {
+ fcr |= OH_SCC_ENABLE;
+ if (htw) {
+ /* Side effect: this will also power up the
+ * modem, but it's too messy to figure out on which
+ * ports this controls the tranceiver and on which
+ * it controls the modem
+ */
+ if (trans)
+ fcr &= ~HRW_SCC_TRANS_EN_N;
+ MACIO_OUT32(OHARE_FCR, fcr);
+ fcr |= (rmask = HRW_RESET_SCC);
+ MACIO_OUT32(OHARE_FCR, fcr);
+ } else {
+ fcr |= (rmask = OH_SCC_RESET);
+ MACIO_OUT32(OHARE_FCR, fcr);
+ }
+ UNLOCK(flags);
+ (void)MACIO_IN32(OHARE_FCR);
+ mdelay(15);
+ LOCK(flags);
+ fcr &= ~rmask;
+ MACIO_OUT32(OHARE_FCR, fcr);
+ }
+ if (chan_mask & MACIO_FLAG_SCCA_ON)
+ fcr |= OH_SCCA_IO;
+ if (chan_mask & MACIO_FLAG_SCCB_ON)
+ fcr |= OH_SCCB_IO;
+ MACIO_OUT32(OHARE_FCR, fcr);
+ macio->flags |= chan_mask;
+ UNLOCK(flags);
+ if (param & PMAC_SCC_FLAG_XMON)
+ macio->flags |= MACIO_FLAG_SCC_LOCKED;
+ } else {
+ if (macio->flags & MACIO_FLAG_SCC_LOCKED)
+ return -EPERM;
+ LOCK(flags);
+ fcr = MACIO_IN32(OHARE_FCR);
+ if (chan_mask & MACIO_FLAG_SCCA_ON)
+ fcr &= ~OH_SCCA_IO;
+ if (chan_mask & MACIO_FLAG_SCCB_ON)
+ fcr &= ~OH_SCCB_IO;
+ MACIO_OUT32(OHARE_FCR, fcr);
+ if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
+ fcr &= ~OH_SCC_ENABLE;
+ if (htw && trans)
+ fcr |= HRW_SCC_TRANS_EN_N;
+ MACIO_OUT32(OHARE_FCR, fcr);
+ }
+ macio->flags &= ~(chan_mask);
+ UNLOCK(flags);
+ mdelay(10);
+#ifdef CONFIG_ADB_PMU
+ if ((param & 0xfff) == PMAC_SCC_IRDA)
+ pmu_enable_irled(0);
+#endif /* CONFIG_ADB_PMU */
+ }
+ return 0;
+}
+
+static long __pmac
+ohare_floppy_enable(struct device_node* node, long param, long value)
+{
+ return simple_feature_tweak(node, macio_ohare,
+ OHARE_FCR, OH_FLOPPY_ENABLE, value);
+}
+
+static long __pmac
+ohare_mesh_enable(struct device_node* node, long param, long value)
+{
+ return simple_feature_tweak(node, macio_ohare,
+ OHARE_FCR, OH_MESH_ENABLE, value);
+}
+
+static long __pmac
+ohare_ide_enable(struct device_node* node, long param, long value)
+{
+ switch(param) {
+ case 0:
+ /* For some reason, setting the bit in set_initial_features()
+ * doesn't stick. I'm still investigating... --BenH.
+ */
+ if (value)
+ simple_feature_tweak(node, macio_ohare,
+ OHARE_FCR, OH_IOBUS_ENABLE, 1);
+ return simple_feature_tweak(node, macio_ohare,
+ OHARE_FCR, OH_IDE0_ENABLE, value);
+ case 1:
+ return simple_feature_tweak(node, macio_ohare,
+ OHARE_FCR, OH_BAY_IDE_ENABLE, value);
+ default:
+ return -ENODEV;
+ }
+}
+
+static long __pmac
+ohare_ide_reset(struct device_node* node, long param, long value)
+{
+ switch(param) {
+ case 0:
+ return simple_feature_tweak(node, macio_ohare,
+ OHARE_FCR, OH_IDE0_RESET_N, !value);
+ case 1:
+ return simple_feature_tweak(node, macio_ohare,
+ OHARE_FCR, OH_IDE1_RESET_N, !value);
+ default:
+ return -ENODEV;
+ }
+}
+
+static long __pmac
+ohare_sleep_state(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio = &macio_chips[0];
+
+ if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+ return -EPERM;
+ if (value == 1) {
+ MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
+ } else if (value == 0) {
+ MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+ }
+
+ return 0;
+}
+
+static long __pmac
+heathrow_modem_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ u8 gpio;
+ unsigned long flags;
+
+ macio = macio_find(node, macio_unknown);
+ if (!macio)
+ return -ENODEV;
+ gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
+ if (!value) {
+ LOCK(flags);
+ MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
+ UNLOCK(flags);
+ (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+ mdelay(250);
+ }
+ if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
+ pmac_mb.model_id != PMAC_TYPE_YIKES) {
+ LOCK(flags);
+ if (value)
+ MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+ else
+ MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+ UNLOCK(flags);
+ (void)MACIO_IN32(HEATHROW_FCR);
+ mdelay(250);
+ }
+ if (value) {
+ LOCK(flags);
+ MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
+ (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+ UNLOCK(flags); mdelay(250); LOCK(flags);
+ MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
+ (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+ UNLOCK(flags); mdelay(250); LOCK(flags);
+ MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
+ (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
+ UNLOCK(flags); mdelay(250);
+ }
+ return 0;
+}
+
+static long __pmac
+heathrow_floppy_enable(struct device_node* node, long param, long value)
+{
+ return simple_feature_tweak(node, macio_unknown,
+ HEATHROW_FCR,
+ HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
+ value);
+}
+
+static long __pmac
+heathrow_mesh_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ unsigned long flags;
+
+ macio = macio_find(node, macio_unknown);
+ if (!macio)
+ return -ENODEV;
+ LOCK(flags);
+ /* Set clear mesh cell enable */
+ if (value)
+ MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
+ else
+ MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
+ (void)MACIO_IN32(HEATHROW_FCR);
+ udelay(10);
+ /* Set/Clear termination power */
+ if (value)
+ MACIO_BIC(HEATHROW_MBCR, 0x04000000);
+ else
+ MACIO_BIS(HEATHROW_MBCR, 0x04000000);
+ (void)MACIO_IN32(HEATHROW_MBCR);
+ udelay(10);
+ UNLOCK(flags);
+
+ return 0;
+}
+
+static long __pmac
+heathrow_ide_enable(struct device_node* node, long param, long value)
+{
+ switch(param) {
+ case 0:
+ return simple_feature_tweak(node, macio_unknown,
+ HEATHROW_FCR, HRW_IDE0_ENABLE, value);
+ case 1:
+ return simple_feature_tweak(node, macio_unknown,
+ HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
+ default:
+ return -ENODEV;
+ }
+}
+
+static long __pmac
+heathrow_ide_reset(struct device_node* node, long param, long value)
+{
+ switch(param) {
+ case 0:
+ return simple_feature_tweak(node, macio_unknown,
+ HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
+ case 1:
+ return simple_feature_tweak(node, macio_unknown,
+ HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
+ default:
+ return -ENODEV;
+ }
+}
+
+static long __pmac
+heathrow_bmac_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ unsigned long flags;
+
+ macio = macio_find(node, 0);
+ if (!macio)
+ return -ENODEV;
+ if (value) {
+ LOCK(flags);
+ MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
+ MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
+ UNLOCK(flags);
+ (void)MACIO_IN32(HEATHROW_FCR);
+ mdelay(10);
+ LOCK(flags);
+ MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
+ UNLOCK(flags);
+ (void)MACIO_IN32(HEATHROW_FCR);
+ mdelay(10);
+ } else {
+ LOCK(flags);
+ MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
+ UNLOCK(flags);
+ }
+ return 0;
+}
+
+static long __pmac
+heathrow_sound_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ unsigned long flags;
+
+ /* B&W G3 and Yikes don't support that properly (the
+ * sound appear to never come back after beeing shut down).
+ */
+ if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
+ pmac_mb.model_id == PMAC_TYPE_YIKES)
+ return 0;
+
+ macio = macio_find(node, 0);
+ if (!macio)
+ return -ENODEV;
+ if (value) {
+ LOCK(flags);
+ MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+ MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+ UNLOCK(flags);
+ (void)MACIO_IN32(HEATHROW_FCR);
+ } else {
+ LOCK(flags);
+ MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
+ MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+ UNLOCK(flags);
+ }
+ return 0;
+}
+
+static u32 save_fcr[6] __pmacdata;
+static u32 save_mbcr __pmacdata;
+static u32 save_gpio_levels[2] __pmacdata;
+static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata;
+static u8 save_gpio_normal[KEYLARGO_GPIO_CNT] __pmacdata;
+static u32 save_unin_clock_ctl __pmacdata;
+static struct dbdma_regs save_dbdma[13] __pmacdata;
+static struct dbdma_regs save_alt_dbdma[13] __pmacdata;
+
+static void __pmac
+dbdma_save(struct macio_chip* macio, struct dbdma_regs* save)
+{
+ int i;
+
+ /* Save state & config of DBDMA channels */
+ for (i=0; i<13; i++) {
+ volatile struct dbdma_regs __iomem * chan = (void __iomem *)
+ (macio->base + ((0x8000+i*0x100)>>2));
+ save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
+ save[i].cmdptr = in_le32(&chan->cmdptr);
+ save[i].intr_sel = in_le32(&chan->intr_sel);
+ save[i].br_sel = in_le32(&chan->br_sel);
+ save[i].wait_sel = in_le32(&chan->wait_sel);
+ }
+}
+
+static void __pmac
+dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save)
+{
+ int i;
+
+ /* Save state & config of DBDMA channels */
+ for (i=0; i<13; i++) {
+ volatile struct dbdma_regs __iomem * chan = (void __iomem *)
+ (macio->base + ((0x8000+i*0x100)>>2));
+ out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
+ while (in_le32(&chan->status) & ACTIVE)
+ mb();
+ out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
+ out_le32(&chan->cmdptr, save[i].cmdptr);
+ out_le32(&chan->intr_sel, save[i].intr_sel);
+ out_le32(&chan->br_sel, save[i].br_sel);
+ out_le32(&chan->wait_sel, save[i].wait_sel);
+ }
+}
+
+static void __pmac
+heathrow_sleep(struct macio_chip* macio, int secondary)
+{
+ if (secondary) {
+ dbdma_save(macio, save_alt_dbdma);
+ save_fcr[2] = MACIO_IN32(0x38);
+ save_fcr[3] = MACIO_IN32(0x3c);
+ } else {
+ dbdma_save(macio, save_dbdma);
+ save_fcr[0] = MACIO_IN32(0x38);
+ save_fcr[1] = MACIO_IN32(0x3c);
+ save_mbcr = MACIO_IN32(0x34);
+ /* Make sure sound is shut down */
+ MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
+ MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+ /* This seems to be necessary as well or the fan
+ * keeps coming up and battery drains fast */
+ MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
+ MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);
+ /* Make sure eth is down even if module or sleep
+ * won't work properly */
+ MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
+ }
+ /* Make sure modem is shut down */
+ MACIO_OUT8(HRW_GPIO_MODEM_RESET,
+ MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
+ MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
+ MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
+
+ /* Let things settle */
+ (void)MACIO_IN32(HEATHROW_FCR);
+}
+
+static void __pmac
+heathrow_wakeup(struct macio_chip* macio, int secondary)
+{
+ if (secondary) {
+ MACIO_OUT32(0x38, save_fcr[2]);
+ (void)MACIO_IN32(0x38);
+ mdelay(1);
+ MACIO_OUT32(0x3c, save_fcr[3]);
+ (void)MACIO_IN32(0x38);
+ mdelay(10);
+ dbdma_restore(macio, save_alt_dbdma);
+ } else {
+ MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
+ (void)MACIO_IN32(0x38);
+ mdelay(1);
+ MACIO_OUT32(0x3c, save_fcr[1]);
+ (void)MACIO_IN32(0x38);
+ mdelay(1);
+ MACIO_OUT32(0x34, save_mbcr);
+ (void)MACIO_IN32(0x38);
+ mdelay(10);
+ dbdma_restore(macio, save_dbdma);
+ }
+}
+
+static long __pmac
+heathrow_sleep_state(struct device_node* node, long param, long value)
+{
+ if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+ return -EPERM;
+ if (value == 1) {
+ if (macio_chips[1].type == macio_gatwick)
+ heathrow_sleep(&macio_chips[0], 1);
+ heathrow_sleep(&macio_chips[0], 0);
+ } else if (value == 0) {
+ heathrow_wakeup(&macio_chips[0], 0);
+ if (macio_chips[1].type == macio_gatwick)
+ heathrow_wakeup(&macio_chips[0], 1);
+ }
+ return 0;
+}
+
+static long __pmac
+core99_scc_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ unsigned long flags;
+ unsigned long chan_mask;
+ u32 fcr;
+
+ macio = macio_find(node, 0);
+ if (!macio)
+ return -ENODEV;
+ if (!strcmp(node->name, "ch-a"))
+ chan_mask = MACIO_FLAG_SCCA_ON;
+ else if (!strcmp(node->name, "ch-b"))
+ chan_mask = MACIO_FLAG_SCCB_ON;
+ else
+ return -ENODEV;
+
+ if (value) {
+ int need_reset_scc = 0;
+ int need_reset_irda = 0;
+
+ LOCK(flags);
+ fcr = MACIO_IN32(KEYLARGO_FCR0);
+ /* Check if scc cell need enabling */
+ if (!(fcr & KL0_SCC_CELL_ENABLE)) {
+ fcr |= KL0_SCC_CELL_ENABLE;
+ need_reset_scc = 1;
+ }
+ if (chan_mask & MACIO_FLAG_SCCA_ON) {
+ fcr |= KL0_SCCA_ENABLE;
+ /* Don't enable line drivers for I2S modem */
+ if ((param & 0xfff) == PMAC_SCC_I2S1)
+ fcr &= ~KL0_SCC_A_INTF_ENABLE;
+ else
+ fcr |= KL0_SCC_A_INTF_ENABLE;
+ }
+ if (chan_mask & MACIO_FLAG_SCCB_ON) {
+ fcr |= KL0_SCCB_ENABLE;
+ /* Perform irda specific inits */
+ if ((param & 0xfff) == PMAC_SCC_IRDA) {
+ fcr &= ~KL0_SCC_B_INTF_ENABLE;
+ fcr |= KL0_IRDA_ENABLE;
+ fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
+ fcr |= KL0_IRDA_SOURCE1_SEL;
+ fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
+ fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
+ need_reset_irda = 1;
+ } else
+ fcr |= KL0_SCC_B_INTF_ENABLE;
+ }
+ MACIO_OUT32(KEYLARGO_FCR0, fcr);
+ macio->flags |= chan_mask;
+ if (need_reset_scc) {
+ MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ UNLOCK(flags);
+ mdelay(15);
+ LOCK(flags);
+ MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
+ }
+ if (need_reset_irda) {
+ MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ UNLOCK(flags);
+ mdelay(15);
+ LOCK(flags);
+ MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
+ }
+ UNLOCK(flags);
+ if (param & PMAC_SCC_FLAG_XMON)
+ macio->flags |= MACIO_FLAG_SCC_LOCKED;
+ } else {
+ if (macio->flags & MACIO_FLAG_SCC_LOCKED)
+ return -EPERM;
+ LOCK(flags);
+ fcr = MACIO_IN32(KEYLARGO_FCR0);
+ if (chan_mask & MACIO_FLAG_SCCA_ON)
+ fcr &= ~KL0_SCCA_ENABLE;
+ if (chan_mask & MACIO_FLAG_SCCB_ON) {
+ fcr &= ~KL0_SCCB_ENABLE;
+ /* Perform irda specific clears */
+ if ((param & 0xfff) == PMAC_SCC_IRDA) {
+ fcr &= ~KL0_IRDA_ENABLE;
+ fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
+ fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
+ fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
+ }
+ }
+ MACIO_OUT32(KEYLARGO_FCR0, fcr);
+ if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
+ fcr &= ~KL0_SCC_CELL_ENABLE;
+ MACIO_OUT32(KEYLARGO_FCR0, fcr);
+ }
+ macio->flags &= ~(chan_mask);
+ UNLOCK(flags);
+ mdelay(10);
+ }
+ return 0;
+}
+
+static long __pmac
+core99_modem_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ u8 gpio;
+ unsigned long flags;
+
+ /* Hack for internal USB modem */
+ if (node == NULL) {
+ if (macio_chips[0].type != macio_keylargo)
+ return -ENODEV;
+ node = macio_chips[0].of_node;
+ }
+ macio = macio_find(node, 0);
+ if (!macio)
+ return -ENODEV;
+ gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+ gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+ gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+
+ if (!value) {
+ LOCK(flags);
+ MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+ UNLOCK(flags);
+ (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+ mdelay(250);
+ }
+ LOCK(flags);
+ if (value) {
+ MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+ UNLOCK(flags);
+ (void)MACIO_IN32(KEYLARGO_FCR2);
+ mdelay(250);
+ } else {
+ MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+ UNLOCK(flags);
+ }
+ if (value) {
+ LOCK(flags);
+ MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+ (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+ UNLOCK(flags); mdelay(250); LOCK(flags);
+ MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+ (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+ UNLOCK(flags); mdelay(250); LOCK(flags);
+ MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+ (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+ UNLOCK(flags); mdelay(250);
+ }
+ return 0;
+}
+
+static long __pmac
+pangea_modem_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ u8 gpio;
+ unsigned long flags;
+
+ /* Hack for internal USB modem */
+ if (node == NULL) {
+ if (macio_chips[0].type != macio_pangea &&
+ macio_chips[0].type != macio_intrepid)
+ return -ENODEV;
+ node = macio_chips[0].of_node;
+ }
+ macio = macio_find(node, 0);
+ if (!macio)
+ return -ENODEV;
+ gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+ gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+ gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+
+ if (!value) {
+ LOCK(flags);
+ MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+ UNLOCK(flags);
+ (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+ mdelay(250);
+ }
+ LOCK(flags);
+ if (value) {
+ MACIO_OUT8(KL_GPIO_MODEM_POWER,
+ KEYLARGO_GPIO_OUTPUT_ENABLE);
+ UNLOCK(flags);
+ (void)MACIO_IN32(KEYLARGO_FCR2);
+ mdelay(250);
+ } else {
+ MACIO_OUT8(KL_GPIO_MODEM_POWER,
+ KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+ UNLOCK(flags);
+ }
+ if (value) {
+ LOCK(flags);
+ MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+ (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+ UNLOCK(flags); mdelay(250); LOCK(flags);
+ MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+ (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+ UNLOCK(flags); mdelay(250); LOCK(flags);
+ MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+ (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+ UNLOCK(flags); mdelay(250);
+ }
+ return 0;
+}
+
+static long __pmac
+core99_ata100_enable(struct device_node* node, long value)
+{
+ unsigned long flags;
+ struct pci_dev *pdev = NULL;
+ u8 pbus, pid;
+
+ if (uninorth_rev < 0x24)
+ return -ENODEV;
+
+ LOCK(flags);
+ if (value)
+ UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
+ else
+ UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
+ (void)UN_IN(UNI_N_CLOCK_CNTL);
+ UNLOCK(flags);
+ udelay(20);
+
+ if (value) {
+ if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
+ pdev = pci_find_slot(pbus, pid);
+ if (pdev == NULL)
+ return 0;
+ pci_enable_device(pdev);
+ pci_set_master(pdev);
+ }
+ return 0;
+}
+
+static long __pmac
+core99_ide_enable(struct device_node* node, long param, long value)
+{
+ /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2
+ * based ata-100
+ */
+ switch(param) {
+ case 0:
+ return simple_feature_tweak(node, macio_unknown,
+ KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
+ case 1:
+ return simple_feature_tweak(node, macio_unknown,
+ KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
+ case 2:
+ return simple_feature_tweak(node, macio_unknown,
+ KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
+ case 3:
+ return core99_ata100_enable(node, value);
+ default:
+ return -ENODEV;
+ }
+}
+
+static long __pmac
+core99_ide_reset(struct device_node* node, long param, long value)
+{
+ switch(param) {
+ case 0:
+ return simple_feature_tweak(node, macio_unknown,
+ KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
+ case 1:
+ return simple_feature_tweak(node, macio_unknown,
+ KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
+ case 2:
+ return simple_feature_tweak(node, macio_unknown,
+ KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
+ default:
+ return -ENODEV;
+ }
+}
+
+static long __pmac
+core99_gmac_enable(struct device_node* node, long param, long value)
+{
+ unsigned long flags;
+
+ LOCK(flags);
+ if (value)
+ UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+ else
+ UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+ (void)UN_IN(UNI_N_CLOCK_CNTL);
+ UNLOCK(flags);
+ udelay(20);
+
+ return 0;
+}
+
+static long __pmac
+core99_gmac_phy_reset(struct device_node* node, long param, long value)
+{
+ unsigned long flags;
+ struct macio_chip* macio;
+
+ macio = &macio_chips[0];
+ if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+ macio->type != macio_intrepid)
+ return -ENODEV;
+
+ LOCK(flags);
+ MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
+ (void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
+ UNLOCK(flags);
+ mdelay(10);
+ LOCK(flags);
+ MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */
+ KEYLARGO_GPIO_OUTOUT_DATA);
+ UNLOCK(flags);
+ mdelay(10);
+
+ return 0;
+}
+
+static long __pmac
+core99_sound_chip_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ unsigned long flags;
+
+ macio = macio_find(node, 0);
+ if (!macio)
+ return -ENODEV;
+
+ /* Do a better probe code, screamer G4 desktops &
+ * iMacs can do that too, add a recalibrate in
+ * the driver as well
+ */
+ if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
+ pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
+ LOCK(flags);
+ if (value)
+ MACIO_OUT8(KL_GPIO_SOUND_POWER,
+ KEYLARGO_GPIO_OUTPUT_ENABLE |
+ KEYLARGO_GPIO_OUTOUT_DATA);
+ else
+ MACIO_OUT8(KL_GPIO_SOUND_POWER,
+ KEYLARGO_GPIO_OUTPUT_ENABLE);
+ (void)MACIO_IN8(KL_GPIO_SOUND_POWER);
+ UNLOCK(flags);
+ }
+ return 0;
+}
+
+static long __pmac
+core99_airport_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ unsigned long flags;
+ int state;
+
+ macio = macio_find(node, 0);
+ if (!macio)
+ return -ENODEV;
+
+ /* Hint: we allow passing of macio itself for the sake of the
+ * sleep code
+ */
+ if (node != macio->of_node &&
+ (!node->parent || node->parent != macio->of_node))
+ return -ENODEV;
+ state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
+ if (value == state)
+ return 0;
+ if (value) {
+ /* This code is a reproduction of OF enable-cardslot
+ * and init-wireless methods, slightly hacked until
+ * I got it working.
+ */
+ LOCK(flags);
+ MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
+ (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
+ UNLOCK(flags);
+ mdelay(10);
+ LOCK(flags);
+ MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
+ (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
+ UNLOCK(flags);
+
+ mdelay(10);
+
+ LOCK(flags);
+ MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
+ (void)MACIO_IN32(KEYLARGO_FCR2);
+ udelay(10);
+ MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
+ (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
+ udelay(10);
+ MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
+ (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
+ udelay(10);
+ MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
+ (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
+ udelay(10);
+ MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
+ (void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
+ udelay(10);
+ MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
+ (void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
+ UNLOCK(flags);
+ udelay(10);
+ MACIO_OUT32(0x1c000, 0);
+ mdelay(1);
+ MACIO_OUT8(0x1a3e0, 0x41);
+ (void)MACIO_IN8(0x1a3e0);
+ udelay(10);
+ LOCK(flags);
+ MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
+ (void)MACIO_IN32(KEYLARGO_FCR2);
+ UNLOCK(flags);
+ mdelay(100);
+
+ macio->flags |= MACIO_FLAG_AIRPORT_ON;
+ } else {
+ LOCK(flags);
+ MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
+ (void)MACIO_IN32(KEYLARGO_FCR2);
+ MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
+ MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
+ MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
+ MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
+ MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
+ (void)MACIO_IN8(KL_GPIO_AIRPORT_4);
+ UNLOCK(flags);
+
+ macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_SMP
+static long __pmac
+core99_reset_cpu(struct device_node* node, long param, long value)
+{
+ unsigned int reset_io = 0;
+ unsigned long flags;
+ struct macio_chip* macio;
+ struct device_node* np;
+ const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0,
+ KL_GPIO_RESET_CPU1,
+ KL_GPIO_RESET_CPU2,
+ KL_GPIO_RESET_CPU3 };
+
+ macio = &macio_chips[0];
+ if (macio->type != macio_keylargo)
+ return -ENODEV;
+
+ np = find_path_device("/cpus");
+ if (np == NULL)
+ return -ENODEV;
+ for (np = np->child; np != NULL; np = np->sibling) {
+ u32* num = (u32 *)get_property(np, "reg", NULL);
+ u32* rst = (u32 *)get_property(np, "soft-reset", NULL);
+ if (num == NULL || rst == NULL)
+ continue;
+ if (param == *num) {
+ reset_io = *rst;
+ break;
+ }
+ }
+ if (np == NULL || reset_io == 0)
+ reset_io = dflt_reset_lines[param];
+
+ LOCK(flags);
+ MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
+ (void)MACIO_IN8(reset_io);
+ udelay(1);
+ MACIO_OUT8(reset_io, 0);
+ (void)MACIO_IN8(reset_io);
+ UNLOCK(flags);
+
+ return 0;
+}
+#endif /* CONFIG_SMP */
+
+static long __pmac
+core99_usb_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio;
+ unsigned long flags;
+ char* prop;
+ int number;
+ u32 reg;
+
+ macio = &macio_chips[0];
+ if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+ macio->type != macio_intrepid)
+ return -ENODEV;
+
+ prop = (char *)get_property(node, "AAPL,clock-id", NULL);
+ if (!prop)
+ return -ENODEV;
+ if (strncmp(prop, "usb0u048", 8) == 0)
+ number = 0;
+ else if (strncmp(prop, "usb1u148", 8) == 0)
+ number = 2;
+ else if (strncmp(prop, "usb2u248", 8) == 0)
+ number = 4;
+ else
+ return -ENODEV;
+
+ /* Sorry for the brute-force locking, but this is only used during
+ * sleep and the timing seem to be critical
+ */
+ LOCK(flags);
+ if (value) {
+ /* Turn ON */
+ if (number == 0) {
+ MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ UNLOCK(flags);
+ mdelay(1);
+ LOCK(flags);
+ MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+ } else if (number == 2) {
+ MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+ UNLOCK(flags);
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ mdelay(1);
+ LOCK(flags);
+ MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+ } else if (number == 4) {
+ MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
+ UNLOCK(flags);
+ (void)MACIO_IN32(KEYLARGO_FCR1);
+ mdelay(1);
+ LOCK(flags);
+ MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE);
+ }
+ if (number < 4) {
+ reg = MACIO_IN32(KEYLARGO_FCR4);
+ reg &= ~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+ KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
+ reg &= ~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+ KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
+ MACIO_OUT32(KEYLARGO_FCR4, reg);
+ (void)MACIO_IN32(KEYLARGO_FCR4);
+ udelay(10);
+ } else {
+ reg = MACIO_IN32(KEYLARGO_FCR3);
+ reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
+ KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0));
+ reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
+ KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1));
+ MACIO_OUT32(KEYLARGO_FCR3, reg);
+ (void)MACIO_IN32(KEYLARGO_FCR3);
+ udelay(10);
+ }
+ if (macio->type == macio_intrepid) {
+ /* wait for clock stopped bits to clear */
+ u32 test0 = 0, test1 = 0;
+ u32 status0, status1;
+ int timeout = 1000;
+
+ UNLOCK(flags);
+ switch (number) {
+ case 0:
+ test0 = UNI_N_CLOCK_STOPPED_USB0;
+ test1 = UNI_N_CLOCK_STOPPED_USB0PCI;
+ break;
+ case 2:
+ test0 = UNI_N_CLOCK_STOPPED_USB1;
+ test1 = UNI_N_CLOCK_STOPPED_USB1PCI;
+ break;
+ case 4:
+ test0 = UNI_N_CLOCK_STOPPED_USB2;
+ test1 = UNI_N_CLOCK_STOPPED_USB2PCI;
+ break;
+ }
+ do {
+ if (--timeout <= 0) {
+ printk(KERN_ERR "core99_usb_enable: "
+ "Timeout waiting for clocks\n");
+ break;
+ }
+ mdelay(1);
+ status0 = UN_IN(UNI_N_CLOCK_STOP_STATUS0);
+ status1 = UN_IN(UNI_N_CLOCK_STOP_STATUS1);
+ } while ((status0 & test0) | (status1 & test1));
+ LOCK(flags);
+ }
+ } else {
+ /* Turn OFF */
+ if (number < 4) {
+ reg = MACIO_IN32(KEYLARGO_FCR4);
+ reg |= KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+ KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
+ reg |= KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+ KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
+ MACIO_OUT32(KEYLARGO_FCR4, reg);
+ (void)MACIO_IN32(KEYLARGO_FCR4);
+ udelay(1);
+ } else {
+ reg = MACIO_IN32(KEYLARGO_FCR3);
+ reg |= KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
+ KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0);
+ reg |= KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
+ KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1);
+ MACIO_OUT32(KEYLARGO_FCR3, reg);
+ (void)MACIO_IN32(KEYLARGO_FCR3);
+ udelay(1);
+ }
+ if (number == 0) {
+ if (macio->type != macio_intrepid)
+ MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ udelay(1);
+ MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ } else if (number == 2) {
+ if (macio->type != macio_intrepid)
+ MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ udelay(1);
+ MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ } else if (number == 4) {
+ udelay(1);
+ MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
+ (void)MACIO_IN32(KEYLARGO_FCR1);
+ }
+ udelay(1);
+ }
+ UNLOCK(flags);
+
+ return 0;
+}
+
+static long __pmac
+core99_firewire_enable(struct device_node* node, long param, long value)
+{
+ unsigned long flags;
+ struct macio_chip* macio;
+
+ macio = &macio_chips[0];
+ if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+ macio->type != macio_intrepid)
+ return -ENODEV;
+ if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
+ return -ENODEV;
+
+ LOCK(flags);
+ if (value) {
+ UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
+ (void)UN_IN(UNI_N_CLOCK_CNTL);
+ } else {
+ UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
+ (void)UN_IN(UNI_N_CLOCK_CNTL);
+ }
+ UNLOCK(flags);
+ mdelay(1);
+
+ return 0;
+}
+
+static long __pmac
+core99_firewire_cable_power(struct device_node* node, long param, long value)
+{
+ unsigned long flags;
+ struct macio_chip* macio;
+
+ /* Trick: we allow NULL node */
+ if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
+ return -ENODEV;
+ macio = &macio_chips[0];
+ if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+ macio->type != macio_intrepid)
+ return -ENODEV;
+ if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
+ return -ENODEV;
+
+ LOCK(flags);
+ if (value) {
+ MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
+ MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
+ udelay(10);
+ } else {
+ MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
+ MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
+ }
+ UNLOCK(flags);
+ mdelay(1);
+
+ return 0;
+}
+
+static long __pmac
+intrepid_aack_delay_enable(struct device_node* node, long param, long value)
+{
+ unsigned long flags;
+
+ if (uninorth_rev < 0xd2)
+ return -ENODEV;
+
+ LOCK(flags);
+ if (param)
+ UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
+ else
+ UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
+ UNLOCK(flags);
+
+ return 0;
+}
+
+
+#endif /* CONFIG_POWER4 */
+
+static long __pmac
+core99_read_gpio(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio = &macio_chips[0];
+
+ return MACIO_IN8(param);
+}
+
+
+static long __pmac
+core99_write_gpio(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio = &macio_chips[0];
+
+ MACIO_OUT8(param, (u8)(value & 0xff));
+ return 0;
+}
+
+#ifdef CONFIG_POWER4
+
+static long __pmac
+g5_gmac_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio = &macio_chips[0];
+ unsigned long flags;
+ u8 pbus, pid;
+
+ LOCK(flags);
+ if (value) {
+ MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
+ mb();
+ k2_skiplist[0] = NULL;
+ } else {
+ k2_skiplist[0] = node;
+ mb();
+ MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
+ }
+
+ UNLOCK(flags);
+ mdelay(1);
+
+ return 0;
+}
+
+static long __pmac
+g5_fw_enable(struct device_node* node, long param, long value)
+{
+ struct macio_chip* macio = &macio_chips[0];
+ unsigned long flags;
+
+ LOCK(flags);
+ if (value) {
+ MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
+ mb();
+ k2_skiplist[1] = NULL;
+ } else {
+ k2_skiplist[1] = node;
+ mb();
+ MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
+ }
+
+ UNLOCK(flags);
+ mdelay(1);
+
+ return 0;
+}
+
+static long __pmac
+g5_mpic_enable(struct device_node* node, long param, long value)
+{
+ unsigned long flags;
+
+ if (node->parent == NULL || strcmp(node->parent->name, "u3"))
+ return 0;
+
+ LOCK(flags);
+ UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE);
+ UNLOCK(flags);
+
+ return 0;
+}
+
+#ifdef CONFIG_SMP
+static long __pmac
+g5_reset_cpu(struct device_node* node, long param, long value)
+{
+ unsigned int reset_io = 0;
+ unsigned long flags;
+ struct macio_chip* macio;
+ struct device_node* np;
+
+ macio = &macio_chips[0];
+ if (macio->type != macio_keylargo2)
+ return -ENODEV;
+
+ np = find_path_device("/cpus");
+ if (np == NULL)
+ return -ENODEV;
+ for (np = np->child; np != NULL; np = np->sibling) {
+ u32* num = (u32 *)get_property(np, "reg", NULL);
+ u32* rst = (u32 *)get_property(np, "soft-reset", NULL);
+ if (num == NULL || rst == NULL)
+ continue;
+ if (param == *num) {
+ reset_io = *rst;
+ break;
+ }
+ }
+ if (np == NULL || reset_io == 0)
+ return -ENODEV;
+
+ LOCK(flags);
+ MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
+ (void)MACIO_IN8(reset_io);
+ udelay(1);
+ MACIO_OUT8(reset_io, 0);
+ (void)MACIO_IN8(reset_io);
+ UNLOCK(flags);
+
+ return 0;
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * This can be called from pmac_smp so isn't static
+ *
+ * This takes the second CPU off the bus on dual CPU machines
+ * running UP
+ */
+void __pmac g5_phy_disable_cpu1(void)
+{
+ UN_OUT(U3_API_PHY_CONFIG_1, 0);
+}
+
+#endif /* CONFIG_POWER4 */
+
+#ifndef CONFIG_POWER4
+
+static void __pmac
+keylargo_shutdown(struct macio_chip* macio, int sleep_mode)
+{
+ u32 temp;
+
+ if (sleep_mode) {
+ mdelay(1);
+ MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ mdelay(1);
+ }
+
+ MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+ KL0_SCC_CELL_ENABLE |
+ KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
+ KL0_IRDA_CLK19_ENABLE);
+
+ MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
+ MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
+
+ MACIO_BIC(KEYLARGO_FCR1,
+ KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
+ KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
+ KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+ KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+ KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+ KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
+ KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
+ KL1_UIDE_ENABLE);
+
+ MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+ MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
+
+ temp = MACIO_IN32(KEYLARGO_FCR3);
+ if (macio->rev >= 2) {
+ temp |= KL3_SHUTDOWN_PLL2X;
+ if (sleep_mode)
+ temp |= KL3_SHUTDOWN_PLL_TOTAL;
+ }
+
+ temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+ KL3_SHUTDOWN_PLLKW35;
+ if (sleep_mode)
+ temp |= KL3_SHUTDOWN_PLLKW12;
+ temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
+ | KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
+ if (sleep_mode)
+ temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+ MACIO_OUT32(KEYLARGO_FCR3, temp);
+
+ /* Flush posted writes & wait a bit */
+ (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
+}
+
+static void __pmac
+pangea_shutdown(struct macio_chip* macio, int sleep_mode)
+{
+ u32 temp;
+
+ MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+ KL0_SCC_CELL_ENABLE |
+ KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
+
+ MACIO_BIC(KEYLARGO_FCR1,
+ KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
+ KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
+ KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+ KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+ KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+ KL1_UIDE_ENABLE);
+ if (pmac_mb.board_flags & PMAC_MB_MOBILE)
+ MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
+
+ MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+
+ temp = MACIO_IN32(KEYLARGO_FCR3);
+ temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+ KL3_SHUTDOWN_PLLKW35;
+ temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE
+ | KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE);
+ if (sleep_mode)
+ temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE);
+ MACIO_OUT32(KEYLARGO_FCR3, temp);
+
+ /* Flush posted writes & wait a bit */
+ (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
+}
+
+static void __pmac
+intrepid_shutdown(struct macio_chip* macio, int sleep_mode)
+{
+ u32 temp;
+
+ MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+ KL0_SCC_CELL_ENABLE);
+
+ MACIO_BIC(KEYLARGO_FCR1,
+ /*KL1_USB2_CELL_ENABLE |*/
+ KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+ KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+ KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE);
+ if (pmac_mb.board_flags & PMAC_MB_MOBILE)
+ MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
+
+ temp = MACIO_IN32(KEYLARGO_FCR3);
+ temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE |
+ KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
+ if (sleep_mode)
+ temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE);
+ MACIO_OUT32(KEYLARGO_FCR3, temp);
+
+ /* Flush posted writes & wait a bit */
+ (void)MACIO_IN32(KEYLARGO_FCR0);
+ mdelay(10);
+}
+
+static int __pmac
+core99_sleep(void)
+{
+ struct macio_chip* macio;
+ int i;
+
+ macio = &macio_chips[0];
+ if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+ macio->type != macio_intrepid)
+ return -ENODEV;
+
+ /* The device-tree contains that in the hwclock node */
+ if (macio->type == macio_intrepid) {
+ UN_OUT(UNI_N_CLOCK_SPREADING, 0);
+ mdelay(40);
+ }
+
+ /* We power off the wireless slot in case it was not done
+ * by the driver. We don't power it on automatically however
+ */
+ if (macio->flags & MACIO_FLAG_AIRPORT_ON)
+ core99_airport_enable(macio->of_node, 0, 0);
+
+ /* We power off the FW cable. Should be done by the driver... */
+ if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
+ core99_firewire_enable(NULL, 0, 0);
+ core99_firewire_cable_power(NULL, 0, 0);
+ }
+
+ /* We make sure int. modem is off (in case driver lost it) */
+ if (macio->type == macio_keylargo)
+ core99_modem_enable(macio->of_node, 0, 0);
+ else
+ pangea_modem_enable(macio->of_node, 0, 0);
+
+ /* We make sure the sound is off as well */
+ core99_sound_chip_enable(macio->of_node, 0, 0);
+
+ /*
+ * Save various bits of KeyLargo
+ */
+
+ /* Save the state of the various GPIOs */
+ save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
+ save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
+ for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+ save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
+ for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+ save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
+
+ /* Save the FCRs */
+ if (macio->type == macio_keylargo)
+ save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
+ save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
+ save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
+ save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
+ save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
+ save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
+ if (macio->type == macio_pangea || macio->type == macio_intrepid)
+ save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5);
+
+ /* Save state & config of DBDMA channels */
+ dbdma_save(macio, save_dbdma);
+
+ /*
+ * Turn off as much as we can
+ */
+ if (macio->type == macio_pangea)
+ pangea_shutdown(macio, 1);
+ else if (macio->type == macio_intrepid)
+ intrepid_shutdown(macio, 1);
+ else if (macio->type == macio_keylargo)
+ keylargo_shutdown(macio, 1);
+
+ /*
+ * Put the host bridge to sleep
+ */
+
+ save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
+ /* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it
+ * enabled !
+ */
+ UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
+ ~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
+ udelay(100);
+ UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+ UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
+ mdelay(10);
+
+ /*
+ * FIXME: A bit of black magic with OpenPIC (don't ask me why)
+ */
+ if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
+ MACIO_BIS(0x506e0, 0x00400000);
+ MACIO_BIS(0x506e0, 0x80000000);
+ }
+ return 0;
+}
+
+static int __pmac
+core99_wake_up(void)
+{
+ struct macio_chip* macio;
+ int i;
+
+ macio = &macio_chips[0];
+ if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+ macio->type != macio_intrepid)
+ return -ENODEV;
+
+ /*
+ * Wakeup the host bridge
+ */
+ UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+ udelay(10);
+ UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+ udelay(10);
+
+ /*
+ * Restore KeyLargo
+ */
+
+ if (macio->type == macio_keylargo) {
+ MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
+ (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+ }
+ MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
+ (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+ MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
+ (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+ MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
+ (void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
+ MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
+ (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+ MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
+ (void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
+ if (macio->type == macio_pangea || macio->type == macio_intrepid) {
+ MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]);
+ (void)MACIO_IN32(KEYLARGO_FCR5); udelay(10);
+ }
+
+ dbdma_restore(macio, save_dbdma);
+
+ MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
+ MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
+ for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+ MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
+ for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+ MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
+
+ /* FIXME more black magic with OpenPIC ... */
+ if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
+ MACIO_BIC(0x506e0, 0x00400000);
+ MACIO_BIC(0x506e0, 0x80000000);
+ }
+
+ UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
+ udelay(100);
+
+ /* Restore clock spreading */
+ if (macio->type == macio_intrepid) {
+ UN_OUT(UNI_N_CLOCK_SPREADING, 2);
+ mdelay(40);
+ }
+
+ return 0;
+}
+
+static long __pmac
+core99_sleep_state(struct device_node* node, long param, long value)
+{
+ /* Param == 1 means to enter the "fake sleep" mode that is
+ * used for CPU speed switch
+ */
+ if (param == 1) {
+ if (value == 1) {
+ UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+ UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2);
+ } else {
+ UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+ udelay(10);
+ UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+ udelay(10);
+ }
+ return 0;
+ }
+ if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
+ return -EPERM;
+
+#ifdef CONFIG_CPU_FREQ_PMAC
+ /* XXX should be elsewhere */
+ if (machine_is_compatible("PowerBook6,5") ||
+ machine_is_compatible("PowerBook6,4") ||
+ machine_is_compatible("PowerBook5,5") ||
+ machine_is_compatible("PowerBook5,4")) {
+ struct device_node *volt_gpio_np;
+ u32 *reg = NULL;
+
+ volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
+ if (volt_gpio_np != NULL)
+ reg = (u32 *)get_property(volt_gpio_np, "reg", NULL);
+ if (reg != NULL) {
+ /* Set the CPU voltage high if sleeping */
+ if (value == 1) {
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
+ *reg, 0x05);
+ } else if (value == 0 && (mfspr(SPRN_HID1) & HID1_DFS)) {
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL,
+ *reg, 0x04);
+ }
+ mdelay(2);
+ }
+ }
+#endif /* CONFIG_CPU_FREQ_PMAC */
+
+ if (value == 1)
+ return core99_sleep();
+ else if (value == 0)
+ return core99_wake_up();
+ return 0;
+}
+
+#endif /* CONFIG_POWER4 */
+
+static long __pmac
+generic_dev_can_wake(struct device_node* node, long param, long value)
+{
+ /* Todo: eventually check we are really dealing with on-board
+ * video device ...
+ */
+
+ if (pmac_mb.board_flags & PMAC_MB_MAY_SLEEP)
+ pmac_mb.board_flags |= PMAC_MB_CAN_SLEEP;
+ return 0;
+}
+
+static long __pmac
+generic_get_mb_info(struct device_node* node, long param, long value)
+{
+ switch(param) {
+ case PMAC_MB_INFO_MODEL:
+ return pmac_mb.model_id;
+ case PMAC_MB_INFO_FLAGS:
+ return pmac_mb.board_flags;
+ case PMAC_MB_INFO_NAME:
+ /* hack hack hack... but should work */
+ *((const char **)value) = pmac_mb.model_name;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+/*
+ * Table definitions
+ */
+
+/* Used on any machine
+ */
+static struct feature_table_entry any_features[] __pmacdata = {
+ { PMAC_FTR_GET_MB_INFO, generic_get_mb_info },
+ { PMAC_FTR_DEVICE_CAN_WAKE, generic_dev_can_wake },
+ { 0, NULL }
+};
+
+#ifndef CONFIG_POWER4
+
+/* OHare based motherboards. Currently, we only use these on the
+ * 2400,3400 and 3500 series powerbooks. Some older desktops seem
+ * to have issues with turning on/off those asic cells
+ */
+static struct feature_table_entry ohare_features[] __pmacdata = {
+ { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable },
+ { PMAC_FTR_SWIM3_ENABLE, ohare_floppy_enable },
+ { PMAC_FTR_MESH_ENABLE, ohare_mesh_enable },
+ { PMAC_FTR_IDE_ENABLE, ohare_ide_enable},
+ { PMAC_FTR_IDE_RESET, ohare_ide_reset},
+ { PMAC_FTR_SLEEP_STATE, ohare_sleep_state },
+ { 0, NULL }
+};
+
+/* Heathrow desktop machines (Beige G3).
+ * Separated as some features couldn't be properly tested
+ * and the serial port control bits appear to confuse it.
+ */
+static struct feature_table_entry heathrow_desktop_features[] __pmacdata = {
+ { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable },
+ { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable },
+ { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable },
+ { PMAC_FTR_IDE_RESET, heathrow_ide_reset },
+ { PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable },
+ { 0, NULL }
+};
+
+/* Heathrow based laptop, that is the Wallstreet and mainstreet
+ * powerbooks.
+ */
+static struct feature_table_entry heathrow_laptop_features[] __pmacdata = {
+ { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable },
+ { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable },
+ { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable },
+ { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable },
+ { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable },
+ { PMAC_FTR_IDE_RESET, heathrow_ide_reset },
+ { PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable },
+ { PMAC_FTR_SOUND_CHIP_ENABLE, heathrow_sound_enable },
+ { PMAC_FTR_SLEEP_STATE, heathrow_sleep_state },
+ { 0, NULL }
+};
+
+/* Paddington based machines
+ * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
+ */
+static struct feature_table_entry paddington_features[] __pmacdata = {
+ { PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable },
+ { PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable },
+ { PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable },
+ { PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable },
+ { PMAC_FTR_IDE_ENABLE, heathrow_ide_enable },
+ { PMAC_FTR_IDE_RESET, heathrow_ide_reset },
+ { PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable },
+ { PMAC_FTR_SOUND_CHIP_ENABLE, heathrow_sound_enable },
+ { PMAC_FTR_SLEEP_STATE, heathrow_sleep_state },
+ { 0, NULL }
+};
+
+/* Core99 & MacRISC 2 machines (all machines released since the
+ * iBook (included), that is all AGP machines, except pangea
+ * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
+ * used on iBook2 & iMac "flow power".
+ */
+static struct feature_table_entry core99_features[] __pmacdata = {
+ { PMAC_FTR_SCC_ENABLE, core99_scc_enable },
+ { PMAC_FTR_MODEM_ENABLE, core99_modem_enable },
+ { PMAC_FTR_IDE_ENABLE, core99_ide_enable },
+ { PMAC_FTR_IDE_RESET, core99_ide_reset },
+ { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable },
+ { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset },
+ { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable },
+ { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable },
+ { PMAC_FTR_USB_ENABLE, core99_usb_enable },
+ { PMAC_FTR_1394_ENABLE, core99_firewire_enable },
+ { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power },
+ { PMAC_FTR_SLEEP_STATE, core99_sleep_state },
+#ifdef CONFIG_SMP
+ { PMAC_FTR_RESET_CPU, core99_reset_cpu },
+#endif /* CONFIG_SMP */
+ { PMAC_FTR_READ_GPIO, core99_read_gpio },
+ { PMAC_FTR_WRITE_GPIO, core99_write_gpio },
+ { 0, NULL }
+};
+
+/* RackMac
+ */
+static struct feature_table_entry rackmac_features[] __pmacdata = {
+ { PMAC_FTR_SCC_ENABLE, core99_scc_enable },
+ { PMAC_FTR_IDE_ENABLE, core99_ide_enable },
+ { PMAC_FTR_IDE_RESET, core99_ide_reset },
+ { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable },
+ { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset },
+ { PMAC_FTR_USB_ENABLE, core99_usb_enable },
+ { PMAC_FTR_1394_ENABLE, core99_firewire_enable },
+ { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power },
+ { PMAC_FTR_SLEEP_STATE, core99_sleep_state },
+#ifdef CONFIG_SMP
+ { PMAC_FTR_RESET_CPU, core99_reset_cpu },
+#endif /* CONFIG_SMP */
+ { PMAC_FTR_READ_GPIO, core99_read_gpio },
+ { PMAC_FTR_WRITE_GPIO, core99_write_gpio },
+ { 0, NULL }
+};
+
+/* Pangea features
+ */
+static struct feature_table_entry pangea_features[] __pmacdata = {
+ { PMAC_FTR_SCC_ENABLE, core99_scc_enable },
+ { PMAC_FTR_MODEM_ENABLE, pangea_modem_enable },
+ { PMAC_FTR_IDE_ENABLE, core99_ide_enable },
+ { PMAC_FTR_IDE_RESET, core99_ide_reset },
+ { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable },
+ { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset },
+ { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable },
+ { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable },
+ { PMAC_FTR_USB_ENABLE, core99_usb_enable },
+ { PMAC_FTR_1394_ENABLE, core99_firewire_enable },
+ { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power },
+ { PMAC_FTR_SLEEP_STATE, core99_sleep_state },
+ { PMAC_FTR_READ_GPIO, core99_read_gpio },
+ { PMAC_FTR_WRITE_GPIO, core99_write_gpio },
+ { 0, NULL }
+};
+
+/* Intrepid features
+ */
+static struct feature_table_entry intrepid_features[] __pmacdata = {
+ { PMAC_FTR_SCC_ENABLE, core99_scc_enable },
+ { PMAC_FTR_MODEM_ENABLE, pangea_modem_enable },
+ { PMAC_FTR_IDE_ENABLE, core99_ide_enable },
+ { PMAC_FTR_IDE_RESET, core99_ide_reset },
+ { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable },
+ { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset },
+ { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable },
+ { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable },
+ { PMAC_FTR_USB_ENABLE, core99_usb_enable },
+ { PMAC_FTR_1394_ENABLE, core99_firewire_enable },
+ { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power },
+ { PMAC_FTR_SLEEP_STATE, core99_sleep_state },
+ { PMAC_FTR_READ_GPIO, core99_read_gpio },
+ { PMAC_FTR_WRITE_GPIO, core99_write_gpio },
+ { PMAC_FTR_AACK_DELAY_ENABLE, intrepid_aack_delay_enable },
+ { 0, NULL }
+};
+
+#else /* CONFIG_POWER4 */
+
+/* G5 features
+ */
+static struct feature_table_entry g5_features[] __pmacdata = {
+ { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable },
+ { PMAC_FTR_1394_ENABLE, g5_fw_enable },
+ { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable },
+#ifdef CONFIG_SMP
+ { PMAC_FTR_RESET_CPU, g5_reset_cpu },
+#endif /* CONFIG_SMP */
+ { PMAC_FTR_READ_GPIO, core99_read_gpio },
+ { PMAC_FTR_WRITE_GPIO, core99_write_gpio },
+ { 0, NULL }
+};
+
+#endif /* CONFIG_POWER4 */
+
+static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
+#ifndef CONFIG_POWER4
+ /*
+ * Desktops
+ */
+
+ { "AAPL,8500", "PowerMac 8500/8600",
+ PMAC_TYPE_PSURGE, NULL,
+ 0
+ },
+ { "AAPL,9500", "PowerMac 9500/9600",
+ PMAC_TYPE_PSURGE, NULL,
+ 0
+ },
+ { "AAPL,7200", "PowerMac 7200",
+ PMAC_TYPE_PSURGE, NULL,
+ 0
+ },
+ { "AAPL,7300", "PowerMac 7200/7300",
+ PMAC_TYPE_PSURGE, NULL,
+ 0
+ },
+ { "AAPL,7500", "PowerMac 7500",
+ PMAC_TYPE_PSURGE, NULL,
+ 0
+ },
+ { "AAPL,ShinerESB", "Apple Network Server",
+ PMAC_TYPE_ANS, NULL,
+ 0
+ },
+ { "AAPL,e407", "Alchemy",
+ PMAC_TYPE_ALCHEMY, NULL,
+ 0
+ },
+ { "AAPL,e411", "Gazelle",
+ PMAC_TYPE_GAZELLE, NULL,
+ 0
+ },
+ { "AAPL,Gossamer", "PowerMac G3 (Gossamer)",
+ PMAC_TYPE_GOSSAMER, heathrow_desktop_features,
+ 0
+ },
+ { "AAPL,PowerMac G3", "PowerMac G3 (Silk)",
+ PMAC_TYPE_SILK, heathrow_desktop_features,
+ 0
+ },
+ { "PowerMac1,1", "Blue&White G3",
+ PMAC_TYPE_YOSEMITE, paddington_features,
+ 0
+ },
+ { "PowerMac1,2", "PowerMac G4 PCI Graphics",
+ PMAC_TYPE_YIKES, paddington_features,
+ 0
+ },
+ { "PowerMac2,1", "iMac FireWire",
+ PMAC_TYPE_FW_IMAC, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+ },
+ { "PowerMac2,2", "iMac FireWire",
+ PMAC_TYPE_FW_IMAC, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+ },
+ { "PowerMac3,1", "PowerMac G4 AGP Graphics",
+ PMAC_TYPE_SAWTOOTH, core99_features,
+ PMAC_MB_OLD_CORE99
+ },
+ { "PowerMac3,2", "PowerMac G4 AGP Graphics",
+ PMAC_TYPE_SAWTOOTH, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+ },
+ { "PowerMac3,3", "PowerMac G4 AGP Graphics",
+ PMAC_TYPE_SAWTOOTH, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+ },
+ { "PowerMac3,4", "PowerMac G4 Silver",
+ PMAC_TYPE_QUICKSILVER, core99_features,
+ PMAC_MB_MAY_SLEEP
+ },
+ { "PowerMac3,5", "PowerMac G4 Silver",
+ PMAC_TYPE_QUICKSILVER, core99_features,
+ PMAC_MB_MAY_SLEEP
+ },
+ { "PowerMac3,6", "PowerMac G4 Windtunnel",
+ PMAC_TYPE_WINDTUNNEL, core99_features,
+ PMAC_MB_MAY_SLEEP,
+ },
+ { "PowerMac4,1", "iMac \"Flower Power\"",
+ PMAC_TYPE_PANGEA_IMAC, pangea_features,
+ PMAC_MB_MAY_SLEEP
+ },
+ { "PowerMac4,2", "Flat panel iMac",
+ PMAC_TYPE_FLAT_PANEL_IMAC, pangea_features,
+ PMAC_MB_CAN_SLEEP
+ },
+ { "PowerMac4,4", "eMac",
+ PMAC_TYPE_EMAC, core99_features,
+ PMAC_MB_MAY_SLEEP
+ },
+ { "PowerMac5,1", "PowerMac G4 Cube",
+ PMAC_TYPE_CUBE, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
+ },
+ { "PowerMac6,1", "Flat panel iMac",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP,
+ },
+ { "PowerMac6,3", "Flat panel iMac",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP,
+ },
+ { "PowerMac6,4", "eMac",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP,
+ },
+ { "PowerMac10,1", "Mac mini",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER,
+ },
+ { "iMac,1", "iMac (first generation)",
+ PMAC_TYPE_ORIG_IMAC, paddington_features,
+ 0
+ },
+
+ /*
+ * Xserve's
+ */
+
+ { "RackMac1,1", "XServe",
+ PMAC_TYPE_RACKMAC, rackmac_features,
+ 0,
+ },
+ { "RackMac1,2", "XServe rev. 2",
+ PMAC_TYPE_RACKMAC, rackmac_features,
+ 0,
+ },
+
+ /*
+ * Laptops
+ */
+
+ { "AAPL,3400/2400", "PowerBook 3400",
+ PMAC_TYPE_HOOPER, ohare_features,
+ PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+ },
+ { "AAPL,3500", "PowerBook 3500",
+ PMAC_TYPE_KANGA, ohare_features,
+ PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+ },
+ { "AAPL,PowerBook1998", "PowerBook Wallstreet",
+ PMAC_TYPE_WALLSTREET, heathrow_laptop_features,
+ PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
+ },
+ { "PowerBook1,1", "PowerBook 101 (Lombard)",
+ PMAC_TYPE_101_PBOOK, paddington_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_MOBILE
+ },
+ { "PowerBook2,1", "iBook (first generation)",
+ PMAC_TYPE_ORIG_IBOOK, core99_features,
+ PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
+ },
+ { "PowerBook2,2", "iBook FireWire",
+ PMAC_TYPE_FW_IBOOK, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
+ PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
+ },
+ { "PowerBook3,1", "PowerBook Pismo",
+ PMAC_TYPE_PISMO, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
+ PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
+ },
+ { "PowerBook3,2", "PowerBook Titanium",
+ PMAC_TYPE_TITANIUM, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+ },
+ { "PowerBook3,3", "PowerBook Titanium II",
+ PMAC_TYPE_TITANIUM2, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+ },
+ { "PowerBook3,4", "PowerBook Titanium III",
+ PMAC_TYPE_TITANIUM3, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+ },
+ { "PowerBook3,5", "PowerBook Titanium IV",
+ PMAC_TYPE_TITANIUM4, core99_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+ },
+ { "PowerBook4,1", "iBook 2",
+ PMAC_TYPE_IBOOK2, pangea_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+ },
+ { "PowerBook4,2", "iBook 2",
+ PMAC_TYPE_IBOOK2, pangea_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+ },
+ { "PowerBook4,3", "iBook 2 rev. 2",
+ PMAC_TYPE_IBOOK2, pangea_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+ },
+ { "PowerBook5,1", "PowerBook G4 17\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook5,2", "PowerBook G4 15\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook5,3", "PowerBook G4 17\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook5,4", "PowerBook G4 15\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook5,5", "PowerBook G4 17\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook5,6", "PowerBook G4 15\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook5,7", "PowerBook G4 17\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook6,1", "PowerBook G4 12\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook6,2", "PowerBook G4",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook6,3", "iBook G4",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook6,4", "PowerBook G4 12\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook6,5", "iBook G4",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook6,8", "PowerBook G4 12\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+#else /* CONFIG_POWER4 */
+ { "PowerMac7,2", "PowerMac G5",
+ PMAC_TYPE_POWERMAC_G5, g5_features,
+ 0,
+ },
+#endif /* CONFIG_POWER4 */
+};
+
+/*
+ * The toplevel feature_call callback
+ */
+long __pmac
+pmac_do_feature_call(unsigned int selector, ...)
+{
+ struct device_node* node;
+ long param, value;
+ int i;
+ feature_call func = NULL;
+ va_list args;
+
+ if (pmac_mb.features)
+ for (i=0; pmac_mb.features[i].function; i++)
+ if (pmac_mb.features[i].selector == selector) {
+ func = pmac_mb.features[i].function;
+ break;
+ }
+ if (!func)
+ for (i=0; any_features[i].function; i++)
+ if (any_features[i].selector == selector) {
+ func = any_features[i].function;
+ break;
+ }
+ if (!func)
+ return -ENODEV;
+
+ va_start(args, selector);
+ node = (struct device_node*)va_arg(args, void*);
+ param = va_arg(args, long);
+ value = va_arg(args, long);
+ va_end(args);
+
+ return func(node, param, value);
+}
+
+static int __init
+probe_motherboard(void)
+{
+ int i;
+ struct macio_chip* macio = &macio_chips[0];
+ const char* model = NULL;
+ struct device_node *dt;
+
+ /* Lookup known motherboard type in device-tree. First try an
+ * exact match on the "model" property, then try a "compatible"
+ * match is none is found.
+ */
+ dt = find_devices("device-tree");
+ if (dt != NULL)
+ model = (const char *) get_property(dt, "model", NULL);
+ for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+ if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
+ pmac_mb = pmac_mb_defs[i];
+ goto found;
+ }
+ }
+ for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+ if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
+ pmac_mb = pmac_mb_defs[i];
+ goto found;
+ }
+ }
+
+ /* Fallback to selection depending on mac-io chip type */
+ switch(macio->type) {
+#ifndef CONFIG_POWER4
+ case macio_grand_central:
+ pmac_mb.model_id = PMAC_TYPE_PSURGE;
+ pmac_mb.model_name = "Unknown PowerSurge";
+ break;
+ case macio_ohare:
+ pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
+ pmac_mb.model_name = "Unknown OHare-based";
+ break;
+ case macio_heathrow:
+ pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
+ pmac_mb.model_name = "Unknown Heathrow-based";
+ pmac_mb.features = heathrow_desktop_features;
+ break;
+ case macio_paddington:
+ pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
+ pmac_mb.model_name = "Unknown Paddington-based";
+ pmac_mb.features = paddington_features;
+ break;
+ case macio_keylargo:
+ pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
+ pmac_mb.model_name = "Unknown Keylargo-based";
+ pmac_mb.features = core99_features;
+ break;
+ case macio_pangea:
+ pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
+ pmac_mb.model_name = "Unknown Pangea-based";
+ pmac_mb.features = pangea_features;
+ break;
+ case macio_intrepid:
+ pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID;
+ pmac_mb.model_name = "Unknown Intrepid-based";
+ pmac_mb.features = intrepid_features;
+ break;
+#else /* CONFIG_POWER4 */
+ case macio_keylargo2:
+ pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;
+ pmac_mb.model_name = "Unknown G5";
+ pmac_mb.features = g5_features;
+ break;
+#endif /* CONFIG_POWER4 */
+ default:
+ return -ENODEV;
+ }
+found:
+#ifndef CONFIG_POWER4
+ /* Fixup Hooper vs. Comet */
+ if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
+ u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4);
+ if (!mach_id_ptr)
+ return -ENODEV;
+ /* Here, I used to disable the media-bay on comet. It
+ * appears this is wrong, the floppy connector is actually
+ * a kind of media-bay and works with the current driver.
+ */
+ if (__raw_readl(mach_id_ptr) & 0x20000000UL)
+ pmac_mb.model_id = PMAC_TYPE_COMET;
+ iounmap(mach_id_ptr);
+ }
+#endif /* CONFIG_POWER4 */
+
+#ifdef CONFIG_6xx
+ /* Set default value of powersave_nap on machines that support it.
+ * It appears that uninorth rev 3 has a problem with it, we don't
+ * enable it on those. In theory, the flush-on-lock property is
+ * supposed to be set when not supported, but I'm not very confident
+ * that all Apple OF revs did it properly, I do it the paranoid way.
+ */
+ while (uninorth_base && uninorth_rev > 3) {
+ struct device_node* np = find_path_device("/cpus");
+ if (!np || !np->child) {
+ printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
+ break;
+ }
+ np = np->child;
+ /* Nap mode not supported on SMP */
+ if (np->sibling)
+ break;
+ /* Nap mode not supported if flush-on-lock property is present */
+ if (get_property(np, "flush-on-lock", NULL))
+ break;
+ powersave_nap = 1;
+ printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
+ break;
+ }
+
+ /* On CPUs that support it (750FX), lowspeed by default during
+ * NAP mode
+ */
+ powersave_lowspeed = 1;
+#endif /* CONFIG_6xx */
+#ifdef CONFIG_POWER4
+ powersave_nap = 1;
+#endif
+ /* Check for "mobile" machine */
+ if (model && (strncmp(model, "PowerBook", 9) == 0
+ || strncmp(model, "iBook", 5) == 0))
+ pmac_mb.board_flags |= PMAC_MB_MOBILE;
+
+
+ printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
+ return 0;
+}
+
+/* Initialize the Core99 UniNorth host bridge and memory controller
+ */
+static void __init
+probe_uninorth(void)
+{
+ unsigned long actrl;
+
+ /* Locate core99 Uni-N */
+ uninorth_node = of_find_node_by_name(NULL, "uni-n");
+ /* Locate G5 u3 */
+ if (uninorth_node == NULL) {
+ uninorth_node = of_find_node_by_name(NULL, "u3");
+ uninorth_u3 = 1;
+ }
+ if (uninorth_node && uninorth_node->n_addrs > 0) {
+ unsigned long address = uninorth_node->addrs[0].address;
+ uninorth_base = ioremap(address, 0x40000);
+ uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+ if (uninorth_u3)
+ u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
+ } else
+ uninorth_node = NULL;
+
+ if (!uninorth_node)
+ return;
+
+ printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n",
+ uninorth_u3 ? "U3" : "UniNorth", uninorth_rev);
+ printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
+
+ /* Set the arbitrer QAck delay according to what Apple does
+ */
+ if (uninorth_rev < 0x11) {
+ actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
+ actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
+ UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+ UN_OUT(UNI_N_ARB_CTRL, actrl);
+ }
+
+ /* Some more magic as done by them in recent MacOS X on UniNorth
+ * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
+ * memory timeout
+ */
+ if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
+ UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
+}
+
+static void __init
+probe_one_macio(const char* name, const char* compat, int type)
+{
+ struct device_node* node;
+ int i;
+ volatile u32 __iomem * base;
+ u32* revp;
+
+ node = find_devices(name);
+ if (!node || !node->n_addrs)
+ return;
+ if (compat)
+ do {
+ if (device_is_compatible(node, compat))
+ break;
+ node = node->next;
+ } while (node);
+ if (!node)
+ return;
+ for(i=0; i<MAX_MACIO_CHIPS; i++) {
+ if (!macio_chips[i].of_node)
+ break;
+ if (macio_chips[i].of_node == node)
+ return;
+ }
+ if (i >= MAX_MACIO_CHIPS) {
+ printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
+ printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
+ return;
+ }
+ base = ioremap(node->addrs[0].address, node->addrs[0].size);
+ if (!base) {
+ printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
+ return;
+ }
+ if (type == macio_keylargo) {
+ u32* did = (u32 *)get_property(node, "device-id", NULL);
+ if (*did == 0x00000025)
+ type = macio_pangea;
+ if (*did == 0x0000003e)
+ type = macio_intrepid;
+ }
+ macio_chips[i].of_node = node;
+ macio_chips[i].type = type;
+ macio_chips[i].base = base;
+ macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
+ macio_chips[i].name = macio_names[type];
+ revp = (u32 *)get_property(node, "revision-id", NULL);
+ if (revp)
+ macio_chips[i].rev = *revp;
+ printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
+ macio_names[type], macio_chips[i].rev, macio_chips[i].base);
+}
+
+static int __init
+probe_macios(void)
+{
+ /* Warning, ordering is important */
+ probe_one_macio("gc", NULL, macio_grand_central);
+ probe_one_macio("ohare", NULL, macio_ohare);
+ probe_one_macio("pci106b,7", NULL, macio_ohareII);
+ probe_one_macio("mac-io", "keylargo", macio_keylargo);
+ probe_one_macio("mac-io", "paddington", macio_paddington);
+ probe_one_macio("mac-io", "gatwick", macio_gatwick);
+ probe_one_macio("mac-io", "heathrow", macio_heathrow);
+ probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);
+
+ /* Make sure the "main" macio chip appear first */
+ if (macio_chips[0].type == macio_gatwick
+ && macio_chips[1].type == macio_heathrow) {
+ struct macio_chip temp = macio_chips[0];
+ macio_chips[0] = macio_chips[1];
+ macio_chips[1] = temp;
+ }
+ if (macio_chips[0].type == macio_ohareII
+ && macio_chips[1].type == macio_ohare) {
+ struct macio_chip temp = macio_chips[0];
+ macio_chips[0] = macio_chips[1];
+ macio_chips[1] = temp;
+ }
+ macio_chips[0].lbus.index = 0;
+ macio_chips[1].lbus.index = 1;
+
+ return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
+}
+
+static void __init
+initial_serial_shutdown(struct device_node* np)
+{
+ int len;
+ struct slot_names_prop {
+ int count;
+ char name[1];
+ } *slots;
+ char *conn;
+ int port_type = PMAC_SCC_ASYNC;
+ int modem = 0;
+
+ slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
+ conn = get_property(np, "AAPL,connector", &len);
+ if (conn && (strcmp(conn, "infrared") == 0))
+ port_type = PMAC_SCC_IRDA;
+ else if (device_is_compatible(np, "cobalt"))
+ modem = 1;
+ else if (slots && slots->count > 0) {
+ if (strcmp(slots->name, "IrDA") == 0)
+ port_type = PMAC_SCC_IRDA;
+ else if (strcmp(slots->name, "Modem") == 0)
+ modem = 1;
+ }
+ if (modem)
+ pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
+ pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
+}
+
+static void __init
+set_initial_features(void)
+{
+ struct device_node* np;
+
+ /* That hack appears to be necessary for some StarMax motherboards
+ * but I'm not too sure it was audited for side-effects on other
+ * ohare based machines...
+ * Since I still have difficulties figuring the right way to
+ * differenciate them all and since that hack was there for a long
+ * time, I'll keep it around
+ */
+ if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
+ struct macio_chip* macio = &macio_chips[0];
+ MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
+ } else if (macio_chips[0].type == macio_ohare) {
+ struct macio_chip* macio = &macio_chips[0];
+ MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+ } else if (macio_chips[1].type == macio_ohare) {
+ struct macio_chip* macio = &macio_chips[1];
+ MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+ }
+
+#ifdef CONFIG_POWER4
+ if (macio_chips[0].type == macio_keylargo2) {
+#ifndef CONFIG_SMP
+ /* On SMP machines running UP, we have the second CPU eating
+ * bus cycles. We need to take it off the bus. This is done
+ * from pmac_smp for SMP kernels running on one CPU
+ */
+ np = of_find_node_by_type(NULL, "cpu");
+ if (np != NULL)
+ np = of_find_node_by_type(np, "cpu");
+ if (np != NULL) {
+ g5_phy_disable_cpu1();
+ of_node_put(np);
+ }
+#endif /* CONFIG_SMP */
+ /* Enable GMAC for now for PCI probing. It will be disabled
+ * later on after PCI probe
+ */
+ np = of_find_node_by_name(NULL, "ethernet");
+ while(np) {
+ if (device_is_compatible(np, "K2-GMAC"))
+ g5_gmac_enable(np, 0, 1);
+ np = of_find_node_by_name(np, "ethernet");
+ }
+
+ /* Enable FW before PCI probe. Will be disabled later on
+ * Note: We should have a batter way to check that we are
+ * dealing with uninorth internal cell and not a PCI cell
+ * on the external PCI. The code below works though.
+ */
+ np = of_find_node_by_name(NULL, "firewire");
+ while(np) {
+ if (device_is_compatible(np, "pci106b,5811")) {
+ macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
+ g5_fw_enable(np, 0, 1);
+ }
+ np = of_find_node_by_name(np, "firewire");
+ }
+ }
+#else /* CONFIG_POWER4 */
+
+ if (macio_chips[0].type == macio_keylargo ||
+ macio_chips[0].type == macio_pangea ||
+ macio_chips[0].type == macio_intrepid) {
+ /* Enable GMAC for now for PCI probing. It will be disabled
+ * later on after PCI probe
+ */
+ np = of_find_node_by_name(NULL, "ethernet");
+ while(np) {
+ if (np->parent
+ && device_is_compatible(np->parent, "uni-north")
+ && device_is_compatible(np, "gmac"))
+ core99_gmac_enable(np, 0, 1);
+ np = of_find_node_by_name(np, "ethernet");
+ }
+
+ /* Enable FW before PCI probe. Will be disabled later on
+ * Note: We should have a batter way to check that we are
+ * dealing with uninorth internal cell and not a PCI cell
+ * on the external PCI. The code below works though.
+ */
+ np = of_find_node_by_name(NULL, "firewire");
+ while(np) {
+ if (np->parent
+ && device_is_compatible(np->parent, "uni-north")
+ && (device_is_compatible(np, "pci106b,18") ||
+ device_is_compatible(np, "pci106b,30") ||
+ device_is_compatible(np, "pci11c1,5811"))) {
+ macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
+ core99_firewire_enable(np, 0, 1);
+ }
+ np = of_find_node_by_name(np, "firewire");
+ }
+
+ /* Enable ATA-100 before PCI probe. */
+ np = of_find_node_by_name(NULL, "ata-6");
+ while(np) {
+ if (np->parent
+ && device_is_compatible(np->parent, "uni-north")
+ && device_is_compatible(np, "kauai-ata")) {
+ core99_ata100_enable(np, 1);
+ }
+ np = of_find_node_by_name(np, "ata-6");
+ }
+
+ /* Switch airport off */
+ np = find_devices("radio");
+ while(np) {
+ if (np && np->parent == macio_chips[0].of_node) {
+ macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
+ core99_airport_enable(np, 0, 0);
+ }
+ np = np->next;
+ }
+ }
+
+ /* On all machines that support sound PM, switch sound off */
+ if (macio_chips[0].of_node)
+ pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
+ macio_chips[0].of_node, 0, 0);
+
+ /* While on some desktop G3s, we turn it back on */
+ if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
+ && (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
+ pmac_mb.model_id == PMAC_TYPE_SILK)) {
+ struct macio_chip* macio = &macio_chips[0];
+ MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+ MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+ }
+
+ /* Hack for bumping clock speed on the new PowerBooks and the
+ * iBook G4. This implements the "platform-do-clockspreading" OF
+ * property. For safety, we also check the product ID in the
+ * device-tree to make reasonably sure we won't set wrong values
+ * in the clock chip.
+ *
+ * Of course, ultimately, we have to implement a real parser for
+ * the platform-do-* stuff...
+ */
+ while (machine_is_compatible("PowerBook5,2") ||
+ machine_is_compatible("PowerBook5,3") ||
+ machine_is_compatible("PowerBook6,2") ||
+ machine_is_compatible("PowerBook6,3")) {
+ struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
+ struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
+ u8 buffer[9];
+ u32 *productID;
+ int i, rc, changed = 0;
+
+ if (dt == NULL)
+ break;
+ productID = (u32 *)get_property(dt, "pid#", NULL);
+ if (productID == NULL)
+ break;
+ while(ui2c) {
+ struct device_node *p = of_get_parent(ui2c);
+ if (p && !strcmp(p->name, "uni-n"))
+ break;
+ ui2c = of_find_node_by_type(ui2c, "i2c");
+ }
+ if (ui2c == NULL)
+ break;
+ DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
+ rc = pmac_low_i2c_open(ui2c, 1);
+ if (rc != 0)
+ break;
+ pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
+ rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
+ DBG("read result: %d,", rc);
+ if (rc != 0) {
+ pmac_low_i2c_close(ui2c);
+ break;
+ }
+ for (i=0; i<9; i++)
+ DBG(" %02x", buffer[i]);
+ DBG("\n");
+
+ switch(*productID) {
+ case 0x1182: /* AlBook 12" rev 2 */
+ case 0x1183: /* iBook G4 12" */
+ buffer[0] = (buffer[0] & 0x8f) | 0x70;
+ buffer[2] = (buffer[2] & 0x7f) | 0x00;
+ buffer[5] = (buffer[5] & 0x80) | 0x31;
+ buffer[6] = (buffer[6] & 0x40) | 0xb0;
+ buffer[7] = (buffer[7] & 0x00) | 0xc0;
+ buffer[8] = (buffer[8] & 0x00) | 0x30;
+ changed = 1;
+ break;
+ case 0x3142: /* AlBook 15" (ATI M10) */
+ case 0x3143: /* AlBook 17" (ATI M10) */
+ buffer[0] = (buffer[0] & 0xaf) | 0x50;
+ buffer[2] = (buffer[2] & 0x7f) | 0x00;
+ buffer[5] = (buffer[5] & 0x80) | 0x31;
+ buffer[6] = (buffer[6] & 0x40) | 0xb0;
+ buffer[7] = (buffer[7] & 0x00) | 0xd0;
+ buffer[8] = (buffer[8] & 0x00) | 0x30;
+ changed = 1;
+ break;
+ default:
+ DBG("i2c-hwclock: Machine model not handled\n");
+ break;
+ }
+ if (!changed) {
+ pmac_low_i2c_close(ui2c);
+ break;
+ }
+ pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
+ rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
+ DBG("write result: %d,", rc);
+ pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
+ rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
+ DBG("read result: %d,", rc);
+ if (rc != 0) {
+ pmac_low_i2c_close(ui2c);
+ break;
+ }
+ for (i=0; i<9; i++)
+ DBG(" %02x", buffer[i]);
+ pmac_low_i2c_close(ui2c);
+ break;
+ }
+
+#endif /* CONFIG_POWER4 */
+
+ /* On all machines, switch modem & serial ports off */
+ np = find_devices("ch-a");
+ while(np) {
+ initial_serial_shutdown(np);
+ np = np->next;
+ }
+ np = find_devices("ch-b");
+ while(np) {
+ initial_serial_shutdown(np);
+ np = np->next;
+ }
+}
+
+void __init
+pmac_feature_init(void)
+{
+ /* Detect the UniNorth memory controller */
+ probe_uninorth();
+
+ /* Probe mac-io controllers */
+ if (probe_macios()) {
+ printk(KERN_WARNING "No mac-io chip found\n");
+ return;
+ }
+
+ /* Setup low-level i2c stuffs */
+ pmac_init_low_i2c();
+
+ /* Probe machine type */
+ if (probe_motherboard())
+ printk(KERN_WARNING "Unknown PowerMac !\n");
+
+ /* Set some initial features (turn off some chips that will
+ * be later turned on)
+ */
+ set_initial_features();
+}
+
+int __init
+pmac_feature_late_init(void)
+{
+ struct device_node* np;
+
+ /* Request some resources late */
+ if (uninorth_node)
+ request_OF_resource(uninorth_node, 0, NULL);
+ np = find_devices("hammerhead");
+ if (np)
+ request_OF_resource(np, 0, NULL);
+ np = find_devices("interrupt-controller");
+ if (np)
+ request_OF_resource(np, 0, NULL);
+ return 0;
+}
+
+device_initcall(pmac_feature_late_init);
+
+#ifdef CONFIG_POWER4
+
+static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
+{
+ int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 };
+ int bits[8] = { 8,16,0,32,2,4,0,0 };
+ int freq = (frq >> 8) & 0xf;
+
+ if (freqs[freq] == 0)
+ printk("%s: Unknown HT link frequency %x\n", name, freq);
+ else
+ printk("%s: %d MHz on main link, (%d in / %d out) bits width\n",
+ name, freqs[freq],
+ bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]);
+}
+
+void __init pmac_check_ht_link(void)
+{
+ u32 ufreq, freq, ucfg, cfg;
+ struct device_node *pcix_node;
+ u8 px_bus, px_devfn;
+ struct pci_controller *px_hose;
+
+ (void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
+ ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
+ ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
+ dump_HT_speeds("U3 HyperTransport", cfg, freq);
+
+ pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
+ if (pcix_node == NULL) {
+ printk("No PCI-X bridge found\n");
+ return;
+ }
+ if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) {
+ printk("PCI-X bridge found but not matched to pci\n");
+ return;
+ }
+ px_hose = pci_find_hose_for_OF_device(pcix_node);
+ if (px_hose == NULL) {
+ printk("PCI-X bridge found but not matched to host\n");
+ return;
+ }
+ early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
+ early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
+ dump_HT_speeds("PCI-X HT Uplink", cfg, freq);
+ early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg);
+ early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq);
+ dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
+}
+
+#endif /* CONFIG_POWER4 */
+
+/*
+ * Early video resume hook
+ */
+
+static void (*pmac_early_vresume_proc)(void *data) __pmacdata;
+static void *pmac_early_vresume_data __pmacdata;
+
+void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
+{
+ if (_machine != _MACH_Pmac)
+ return;
+ preempt_disable();
+ pmac_early_vresume_proc = proc;
+ pmac_early_vresume_data = data;
+ preempt_enable();
+}
+EXPORT_SYMBOL(pmac_set_early_video_resume);
+
+void __pmac pmac_call_early_video_resume(void)
+{
+ if (pmac_early_vresume_proc)
+ pmac_early_vresume_proc(pmac_early_vresume_data);
+}
diff --git a/arch/ppc/platforms/pmac_low_i2c.c b/arch/ppc/platforms/pmac_low_i2c.c
new file mode 100644
index 00000000000..d07579f2b8b
--- /dev/null
+++ b/arch/ppc/platforms/pmac_low_i2c.c
@@ -0,0 +1,513 @@
+/*
+ * arch/ppc/platforms/pmac_low_i2c.c
+ *
+ * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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 file contains some low-level i2c access routines that
+ * need to be used by various bits of the PowerMac platform code
+ * at times where the real asynchronous & interrupt driven driver
+ * cannot be used. The API borrows some semantics from the darwin
+ * driver in order to ease the implementation of the platform
+ * properties parser
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_low_i2c.h>
+
+#define MAX_LOW_I2C_HOST 4
+
+#if 1
+#define DBG(x...) do {\
+ printk(KERN_DEBUG "KW:" x); \
+ } while(0)
+#else
+#define DBGG(x...)
+#endif
+
+struct low_i2c_host;
+
+typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
+
+struct low_i2c_host
+{
+ struct device_node *np; /* OF device node */
+ struct semaphore mutex; /* Access mutex for use by i2c-keywest */
+ low_i2c_func_t func; /* Access function */
+ int is_open : 1; /* Poor man's access control */
+ int mode; /* Current mode */
+ int channel; /* Current channel */
+ int num_channels; /* Number of channels */
+ unsigned long base; /* For keywest-i2c, base address */
+ int bsteps; /* And register stepping */
+ int speed; /* And speed */
+};
+
+static struct low_i2c_host low_i2c_hosts[MAX_LOW_I2C_HOST];
+
+/* No locking is necessary on allocation, we are running way before
+ * anything can race with us
+ */
+static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < MAX_LOW_I2C_HOST; i++)
+ if (low_i2c_hosts[i].np == np)
+ return &low_i2c_hosts[i];
+ return NULL;
+}
+
+/*
+ *
+ * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
+ *
+ */
+
+/*
+ * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
+ * should be moved somewhere in include/asm-ppc/
+ */
+/* Register indices */
+typedef enum {
+ reg_mode = 0,
+ reg_control,
+ reg_status,
+ reg_isr,
+ reg_ier,
+ reg_addr,
+ reg_subaddr,
+ reg_data
+} reg_t;
+
+
+/* Mode register */
+#define KW_I2C_MODE_100KHZ 0x00
+#define KW_I2C_MODE_50KHZ 0x01
+#define KW_I2C_MODE_25KHZ 0x02
+#define KW_I2C_MODE_DUMB 0x00
+#define KW_I2C_MODE_STANDARD 0x04
+#define KW_I2C_MODE_STANDARDSUB 0x08
+#define KW_I2C_MODE_COMBINED 0x0C
+#define KW_I2C_MODE_MODE_MASK 0x0C
+#define KW_I2C_MODE_CHAN_MASK 0xF0
+
+/* Control register */
+#define KW_I2C_CTL_AAK 0x01
+#define KW_I2C_CTL_XADDR 0x02
+#define KW_I2C_CTL_STOP 0x04
+#define KW_I2C_CTL_START 0x08
+
+/* Status register */
+#define KW_I2C_STAT_BUSY 0x01
+#define KW_I2C_STAT_LAST_AAK 0x02
+#define KW_I2C_STAT_LAST_RW 0x04
+#define KW_I2C_STAT_SDA 0x08
+#define KW_I2C_STAT_SCL 0x10
+
+/* IER & ISR registers */
+#define KW_I2C_IRQ_DATA 0x01
+#define KW_I2C_IRQ_ADDR 0x02
+#define KW_I2C_IRQ_STOP 0x04
+#define KW_I2C_IRQ_START 0x08
+#define KW_I2C_IRQ_MASK 0x0F
+
+/* State machine states */
+enum {
+ state_idle,
+ state_addr,
+ state_read,
+ state_write,
+ state_stop,
+ state_dead
+};
+
+#define WRONG_STATE(name) do {\
+ printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
+ name, __kw_state_names[state], isr); \
+ } while(0)
+
+static const char *__kw_state_names[] = {
+ "state_idle",
+ "state_addr",
+ "state_read",
+ "state_write",
+ "state_stop",
+ "state_dead"
+};
+
+static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
+{
+ return in_8(((volatile u8 *)host->base)
+ + (((unsigned)reg) << host->bsteps));
+}
+
+static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
+{
+ out_8(((volatile u8 *)host->base)
+ + (((unsigned)reg) << host->bsteps), val);
+ (void)__kw_read_reg(host, reg_subaddr);
+}
+
+#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val)
+#define kw_read_reg(reg) __kw_read_reg(host, reg)
+
+
+/* Don't schedule, the g5 fan controller is too
+ * timing sensitive
+ */
+static u8 kw_wait_interrupt(struct low_i2c_host* host)
+{
+ int i;
+ u8 isr;
+
+ for (i = 0; i < 200000; i++) {
+ isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
+ if (isr != 0)
+ return isr;
+ udelay(1);
+ }
+ return isr;
+}
+
+static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
+{
+ u8 ack;
+
+ if (isr == 0) {
+ if (state != state_stop) {
+ DBG("KW: Timeout !\n");
+ *rc = -EIO;
+ goto stop;
+ }
+ if (state == state_stop) {
+ ack = kw_read_reg(reg_status);
+ if (!(ack & KW_I2C_STAT_BUSY)) {
+ state = state_idle;
+ kw_write_reg(reg_ier, 0x00);
+ }
+ }
+ return state;
+ }
+
+ if (isr & KW_I2C_IRQ_ADDR) {
+ ack = kw_read_reg(reg_status);
+ if (state != state_addr) {
+ kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+ WRONG_STATE("KW_I2C_IRQ_ADDR");
+ *rc = -EIO;
+ goto stop;
+ }
+ if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+ *rc = -ENODEV;
+ DBG("KW: NAK on address\n");
+ return state_stop;
+ } else {
+ if (rw) {
+ state = state_read;
+ if (*len > 1)
+ kw_write_reg(reg_control, KW_I2C_CTL_AAK);
+ } else {
+ state = state_write;
+ kw_write_reg(reg_data, **data);
+ (*data)++; (*len)--;
+ }
+ }
+ kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+ }
+
+ if (isr & KW_I2C_IRQ_DATA) {
+ if (state == state_read) {
+ **data = kw_read_reg(reg_data);
+ (*data)++; (*len)--;
+ kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+ if ((*len) == 0)
+ state = state_stop;
+ else if ((*len) == 1)
+ kw_write_reg(reg_control, 0);
+ } else if (state == state_write) {
+ ack = kw_read_reg(reg_status);
+ if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+ DBG("KW: nack on data write\n");
+ *rc = -EIO;
+ goto stop;
+ } else if (*len) {
+ kw_write_reg(reg_data, **data);
+ (*data)++; (*len)--;
+ } else {
+ kw_write_reg(reg_control, KW_I2C_CTL_STOP);
+ state = state_stop;
+ *rc = 0;
+ }
+ kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+ } else {
+ kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+ WRONG_STATE("KW_I2C_IRQ_DATA");
+ if (state != state_stop) {
+ *rc = -EIO;
+ goto stop;
+ }
+ }
+ }
+
+ if (isr & KW_I2C_IRQ_STOP) {
+ kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
+ if (state != state_stop) {
+ WRONG_STATE("KW_I2C_IRQ_STOP");
+ *rc = -EIO;
+ }
+ return state_idle;
+ }
+
+ if (isr & KW_I2C_IRQ_START)
+ kw_write_reg(reg_isr, KW_I2C_IRQ_START);
+
+ return state;
+
+ stop:
+ kw_write_reg(reg_control, KW_I2C_CTL_STOP);
+ return state_stop;
+}
+
+static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
+{
+ u8 mode_reg = host->speed;
+ int state = state_addr;
+ int rc = 0;
+
+ /* Setup mode & subaddress if any */
+ switch(host->mode) {
+ case pmac_low_i2c_mode_dumb:
+ printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
+ return -EINVAL;
+ case pmac_low_i2c_mode_std:
+ mode_reg |= KW_I2C_MODE_STANDARD;
+ break;
+ case pmac_low_i2c_mode_stdsub:
+ mode_reg |= KW_I2C_MODE_STANDARDSUB;
+ kw_write_reg(reg_subaddr, subaddr);
+ break;
+ case pmac_low_i2c_mode_combined:
+ mode_reg |= KW_I2C_MODE_COMBINED;
+ kw_write_reg(reg_subaddr, subaddr);
+ break;
+ }
+
+ /* Setup channel & clear pending irqs */
+ kw_write_reg(reg_isr, kw_read_reg(reg_isr));
+ kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
+ kw_write_reg(reg_status, 0);
+
+ /* Set up address and r/w bit */
+ kw_write_reg(reg_addr, addr);
+
+ /* Start sending address & disable interrupt*/
+ kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
+ kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
+
+ /* State machine, to turn into an interrupt handler */
+ while(state != state_idle) {
+ u8 isr = kw_wait_interrupt(host);
+ state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
+ }
+
+ return rc;
+}
+
+static void keywest_low_i2c_add(struct device_node *np)
+{
+ struct low_i2c_host *host = find_low_i2c_host(NULL);
+ unsigned long *psteps, *prate, steps, aoffset = 0;
+ struct device_node *parent;
+
+ if (host == NULL) {
+ printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
+ np->full_name);
+ return;
+ }
+ memset(host, 0, sizeof(*host));
+
+ init_MUTEX(&host->mutex);
+ host->np = of_node_get(np);
+ psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL);
+ steps = psteps ? (*psteps) : 0x10;
+ for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
+ steps >>= 1;
+ parent = of_get_parent(np);
+ host->num_channels = 1;
+ if (parent && parent->name[0] == 'u') {
+ host->num_channels = 2;
+ aoffset = 3;
+ }
+ /* Select interface rate */
+ host->speed = KW_I2C_MODE_100KHZ;
+ prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL);
+ if (prate) switch(*prate) {
+ case 100:
+ host->speed = KW_I2C_MODE_100KHZ;
+ break;
+ case 50:
+ host->speed = KW_I2C_MODE_50KHZ;
+ break;
+ case 25:
+ host->speed = KW_I2C_MODE_25KHZ;
+ break;
+ }
+ host->mode = pmac_low_i2c_mode_std;
+ host->base = (unsigned long)ioremap(np->addrs[0].address + aoffset,
+ np->addrs[0].size);
+ host->func = keywest_low_i2c_func;
+}
+
+/*
+ *
+ * PMU implementation
+ *
+ */
+
+
+#ifdef CONFIG_ADB_PMU
+
+static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
+{
+ // TODO
+ return -ENODEV;
+}
+
+static void pmu_low_i2c_add(struct device_node *np)
+{
+ struct low_i2c_host *host = find_low_i2c_host(NULL);
+
+ if (host == NULL) {
+ printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
+ np->full_name);
+ return;
+ }
+ memset(host, 0, sizeof(*host));
+
+ init_MUTEX(&host->mutex);
+ host->np = of_node_get(np);
+ host->num_channels = 3;
+ host->mode = pmac_low_i2c_mode_std;
+ host->func = pmu_low_i2c_func;
+}
+
+#endif /* CONFIG_ADB_PMU */
+
+void __init pmac_init_low_i2c(void)
+{
+ struct device_node *np;
+
+ /* Probe keywest-i2c busses */
+ np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
+ while(np) {
+ keywest_low_i2c_add(np);
+ np = of_find_compatible_node(np, "i2c", "keywest-i2c");
+ }
+
+#ifdef CONFIG_ADB_PMU
+ /* Probe PMU busses */
+ np = of_find_node_by_name(NULL, "via-pmu");
+ if (np)
+ pmu_low_i2c_add(np);
+#endif /* CONFIG_ADB_PMU */
+
+ /* TODO: Add CUDA support as well */
+}
+
+int pmac_low_i2c_lock(struct device_node *np)
+{
+ struct low_i2c_host *host = find_low_i2c_host(np);
+
+ if (!host)
+ return -ENODEV;
+ down(&host->mutex);
+ return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_lock);
+
+int pmac_low_i2c_unlock(struct device_node *np)
+{
+ struct low_i2c_host *host = find_low_i2c_host(np);
+
+ if (!host)
+ return -ENODEV;
+ up(&host->mutex);
+ return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_unlock);
+
+
+int pmac_low_i2c_open(struct device_node *np, int channel)
+{
+ struct low_i2c_host *host = find_low_i2c_host(np);
+
+ if (!host)
+ return -ENODEV;
+
+ if (channel >= host->num_channels)
+ return -EINVAL;
+
+ down(&host->mutex);
+ host->is_open = 1;
+ host->channel = channel;
+
+ return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_open);
+
+int pmac_low_i2c_close(struct device_node *np)
+{
+ struct low_i2c_host *host = find_low_i2c_host(np);
+
+ if (!host)
+ return -ENODEV;
+
+ host->is_open = 0;
+ up(&host->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_close);
+
+int pmac_low_i2c_setmode(struct device_node *np, int mode)
+{
+ struct low_i2c_host *host = find_low_i2c_host(np);
+
+ if (!host)
+ return -ENODEV;
+ WARN_ON(!host->is_open);
+ host->mode = mode;
+
+ return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_setmode);
+
+int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
+{
+ struct low_i2c_host *host = find_low_i2c_host(np);
+
+ if (!host)
+ return -ENODEV;
+ WARN_ON(!host->is_open);
+
+ return host->func(host, addrdir, subaddr, data, len);
+}
+EXPORT_SYMBOL(pmac_low_i2c_xfer);
+
diff --git a/arch/ppc/platforms/pmac_nvram.c b/arch/ppc/platforms/pmac_nvram.c
new file mode 100644
index 00000000000..c9de6420599
--- /dev/null
+++ b/arch/ppc/platforms/pmac_nvram.c
@@ -0,0 +1,584 @@
+/*
+ * arch/ppc/platforms/pmac_nvram.c
+ *
+ * Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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.
+ *
+ * Todo: - add support for the OF persistent properties
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/bootmem.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */
+
+#define CORE99_SIGNATURE 0x5a
+#define CORE99_ADLER_START 0x14
+
+/* On Core99, nvram is either a sharp, a micron or an AMD flash */
+#define SM_FLASH_STATUS_DONE 0x80
+#define SM_FLASH_STATUS_ERR 0x38
+#define SM_FLASH_CMD_ERASE_CONFIRM 0xd0
+#define SM_FLASH_CMD_ERASE_SETUP 0x20
+#define SM_FLASH_CMD_RESET 0xff
+#define SM_FLASH_CMD_WRITE_SETUP 0x40
+#define SM_FLASH_CMD_CLEAR_STATUS 0x50
+#define SM_FLASH_CMD_READ_STATUS 0x70
+
+/* CHRP NVRAM header */
+struct chrp_header {
+ u8 signature;
+ u8 cksum;
+ u16 len;
+ char name[12];
+ u8 data[0];
+};
+
+struct core99_header {
+ struct chrp_header hdr;
+ u32 adler;
+ u32 generation;
+ u32 reserved[2];
+};
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+static int nvram_mult, is_core_99;
+static int core99_bank = 0;
+static int nvram_partitions[3];
+static DEFINE_SPINLOCK(nv_lock);
+
+extern int pmac_newworld;
+extern int system_running;
+
+static int (*core99_write_bank)(int bank, u8* datas);
+static int (*core99_erase_bank)(int bank);
+
+static char *nvram_image __pmacdata;
+
+
+static unsigned char __pmac core99_nvram_read_byte(int addr)
+{
+ if (nvram_image == NULL)
+ return 0xff;
+ return nvram_image[addr];
+}
+
+static void __pmac core99_nvram_write_byte(int addr, unsigned char val)
+{
+ if (nvram_image == NULL)
+ return;
+ nvram_image[addr] = val;
+}
+
+
+static unsigned char __openfirmware direct_nvram_read_byte(int addr)
+{
+ return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]);
+}
+
+static void __openfirmware direct_nvram_write_byte(int addr, unsigned char val)
+{
+ out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val);
+}
+
+
+static unsigned char __pmac indirect_nvram_read_byte(int addr)
+{
+ unsigned char val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nv_lock, flags);
+ out_8(nvram_addr, addr >> 5);
+ val = in_8(&nvram_data[(addr & 0x1f) << 4]);
+ spin_unlock_irqrestore(&nv_lock, flags);
+
+ return val;
+}
+
+static void __pmac indirect_nvram_write_byte(int addr, unsigned char val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&nv_lock, flags);
+ out_8(nvram_addr, addr >> 5);
+ out_8(&nvram_data[(addr & 0x1f) << 4], val);
+ spin_unlock_irqrestore(&nv_lock, flags);
+}
+
+
+#ifdef CONFIG_ADB_PMU
+
+static void __pmac pmu_nvram_complete(struct adb_request *req)
+{
+ if (req->arg)
+ complete((struct completion *)req->arg);
+}
+
+static unsigned char __pmac pmu_nvram_read_byte(int addr)
+{
+ struct adb_request req;
+ DECLARE_COMPLETION(req_complete);
+
+ req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
+ if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM,
+ (addr >> 8) & 0xff, addr & 0xff))
+ return 0xff;
+ if (system_state == SYSTEM_RUNNING)
+ wait_for_completion(&req_complete);
+ while (!req.complete)
+ pmu_poll();
+ return req.reply[0];
+}
+
+static void __pmac pmu_nvram_write_byte(int addr, unsigned char val)
+{
+ struct adb_request req;
+ DECLARE_COMPLETION(req_complete);
+
+ req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
+ if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM,
+ (addr >> 8) & 0xff, addr & 0xff, val))
+ return;
+ if (system_state == SYSTEM_RUNNING)
+ wait_for_completion(&req_complete);
+ while (!req.complete)
+ pmu_poll();
+}
+
+#endif /* CONFIG_ADB_PMU */
+
+
+static u8 __pmac chrp_checksum(struct chrp_header* hdr)
+{
+ u8 *ptr;
+ u16 sum = hdr->signature;
+ for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
+ sum += *ptr;
+ while (sum > 0xFF)
+ sum = (sum & 0xFF) + (sum>>8);
+ return sum;
+}
+
+static u32 __pmac core99_calc_adler(u8 *buffer)
+{
+ int cnt;
+ u32 low, high;
+
+ buffer += CORE99_ADLER_START;
+ low = 1;
+ high = 0;
+ for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+ if ((cnt % 5000) == 0) {
+ high %= 65521UL;
+ high %= 65521UL;
+ }
+ low += buffer[cnt];
+ high += low;
+ }
+ low %= 65521UL;
+ high %= 65521UL;
+
+ return (high << 16) | low;
+}
+
+static u32 __pmac core99_check(u8* datas)
+{
+ struct core99_header* hdr99 = (struct core99_header*)datas;
+
+ if (hdr99->hdr.signature != CORE99_SIGNATURE) {
+ DBG("Invalid signature\n");
+ return 0;
+ }
+ if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
+ DBG("Invalid checksum\n");
+ return 0;
+ }
+ if (hdr99->adler != core99_calc_adler(datas)) {
+ DBG("Invalid adler\n");
+ return 0;
+ }
+ return hdr99->generation;
+}
+
+static int __pmac sm_erase_bank(int bank)
+{
+ int stat, i;
+ unsigned long timeout;
+
+ u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+ DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
+
+ out_8(base, SM_FLASH_CMD_ERASE_SETUP);
+ out_8(base, SM_FLASH_CMD_ERASE_CONFIRM);
+ timeout = 0;
+ do {
+ if (++timeout > 1000000) {
+ printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n");
+ break;
+ }
+ out_8(base, SM_FLASH_CMD_READ_STATUS);
+ stat = in_8(base);
+ } while (!(stat & SM_FLASH_STATUS_DONE));
+
+ out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
+ out_8(base, SM_FLASH_CMD_RESET);
+
+ for (i=0; i<NVRAM_SIZE; i++)
+ if (base[i] != 0xff) {
+ printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int __pmac sm_write_bank(int bank, u8* datas)
+{
+ int i, stat = 0;
+ unsigned long timeout;
+
+ u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+ DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
+
+ for (i=0; i<NVRAM_SIZE; i++) {
+ out_8(base+i, SM_FLASH_CMD_WRITE_SETUP);
+ udelay(1);
+ out_8(base+i, datas[i]);
+ timeout = 0;
+ do {
+ if (++timeout > 1000000) {
+ printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n");
+ break;
+ }
+ out_8(base, SM_FLASH_CMD_READ_STATUS);
+ stat = in_8(base);
+ } while (!(stat & SM_FLASH_STATUS_DONE));
+ if (!(stat & SM_FLASH_STATUS_DONE))
+ break;
+ }
+ out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
+ out_8(base, SM_FLASH_CMD_RESET);
+ for (i=0; i<NVRAM_SIZE; i++)
+ if (base[i] != datas[i]) {
+ printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int __pmac amd_erase_bank(int bank)
+{
+ int i, stat = 0;
+ unsigned long timeout;
+
+ u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+ DBG("nvram: AMD Erasing bank %d...\n", bank);
+
+ /* Unlock 1 */
+ out_8(base+0x555, 0xaa);
+ udelay(1);
+ /* Unlock 2 */
+ out_8(base+0x2aa, 0x55);
+ udelay(1);
+
+ /* Sector-Erase */
+ out_8(base+0x555, 0x80);
+ udelay(1);
+ out_8(base+0x555, 0xaa);
+ udelay(1);
+ out_8(base+0x2aa, 0x55);
+ udelay(1);
+ out_8(base, 0x30);
+ udelay(1);
+
+ timeout = 0;
+ do {
+ if (++timeout > 1000000) {
+ printk(KERN_ERR "nvram: AMD flash erase timeout !\n");
+ break;
+ }
+ stat = in_8(base) ^ in_8(base);
+ } while (stat != 0);
+
+ /* Reset */
+ out_8(base, 0xf0);
+ udelay(1);
+
+ for (i=0; i<NVRAM_SIZE; i++)
+ if (base[i] != 0xff) {
+ printk(KERN_ERR "nvram: AMD flash erase failed !\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int __pmac amd_write_bank(int bank, u8* datas)
+{
+ int i, stat = 0;
+ unsigned long timeout;
+
+ u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+ DBG("nvram: AMD Writing bank %d...\n", bank);
+
+ for (i=0; i<NVRAM_SIZE; i++) {
+ /* Unlock 1 */
+ out_8(base+0x555, 0xaa);
+ udelay(1);
+ /* Unlock 2 */
+ out_8(base+0x2aa, 0x55);
+ udelay(1);
+
+ /* Write single word */
+ out_8(base+0x555, 0xa0);
+ udelay(1);
+ out_8(base+i, datas[i]);
+
+ timeout = 0;
+ do {
+ if (++timeout > 1000000) {
+ printk(KERN_ERR "nvram: AMD flash write timeout !\n");
+ break;
+ }
+ stat = in_8(base) ^ in_8(base);
+ } while (stat != 0);
+ if (stat != 0)
+ break;
+ }
+
+ /* Reset */
+ out_8(base, 0xf0);
+ udelay(1);
+
+ for (i=0; i<NVRAM_SIZE; i++)
+ if (base[i] != datas[i]) {
+ printk(KERN_ERR "nvram: AMD flash write failed !\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static void __init lookup_partitions(void)
+{
+ u8 buffer[17];
+ int i, offset;
+ struct chrp_header* hdr;
+
+ if (pmac_newworld) {
+ nvram_partitions[pmac_nvram_OF] = -1;
+ nvram_partitions[pmac_nvram_XPRAM] = -1;
+ nvram_partitions[pmac_nvram_NR] = -1;
+ hdr = (struct chrp_header *)buffer;
+
+ offset = 0;
+ buffer[16] = 0;
+ do {
+ for (i=0;i<16;i++)
+ buffer[i] = nvram_read_byte(offset+i);
+ if (!strcmp(hdr->name, "common"))
+ nvram_partitions[pmac_nvram_OF] = offset + 0x10;
+ if (!strcmp(hdr->name, "APL,MacOS75")) {
+ nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
+ nvram_partitions[pmac_nvram_NR] = offset + 0x110;
+ }
+ offset += (hdr->len * 0x10);
+ } while(offset < NVRAM_SIZE);
+ } else {
+ nvram_partitions[pmac_nvram_OF] = 0x1800;
+ nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
+ nvram_partitions[pmac_nvram_NR] = 0x1400;
+ }
+ DBG("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
+ DBG("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
+ DBG("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+}
+
+static void __pmac core99_nvram_sync(void)
+{
+ struct core99_header* hdr99;
+ unsigned long flags;
+
+ if (!is_core_99 || !nvram_data || !nvram_image)
+ return;
+
+ spin_lock_irqsave(&nv_lock, flags);
+ if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
+ NVRAM_SIZE))
+ goto bail;
+
+ DBG("Updating nvram...\n");
+
+ hdr99 = (struct core99_header*)nvram_image;
+ hdr99->generation++;
+ hdr99->hdr.signature = CORE99_SIGNATURE;
+ hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
+ hdr99->adler = core99_calc_adler(nvram_image);
+ core99_bank = core99_bank ? 0 : 1;
+ if (core99_erase_bank)
+ if (core99_erase_bank(core99_bank)) {
+ printk("nvram: Error erasing bank %d\n", core99_bank);
+ goto bail;
+ }
+ if (core99_write_bank)
+ if (core99_write_bank(core99_bank, nvram_image))
+ printk("nvram: Error writing bank %d\n", core99_bank);
+ bail:
+ spin_unlock_irqrestore(&nv_lock, flags);
+
+#ifdef DEBUG
+ mdelay(2000);
+#endif
+}
+
+void __init pmac_nvram_init(void)
+{
+ struct device_node *dp;
+
+ nvram_naddrs = 0;
+
+ dp = find_devices("nvram");
+ if (dp == NULL) {
+ printk(KERN_ERR "Can't find NVRAM device\n");
+ return;
+ }
+ nvram_naddrs = dp->n_addrs;
+ is_core_99 = device_is_compatible(dp, "nvram,flash");
+ if (is_core_99) {
+ int i;
+ u32 gen_bank0, gen_bank1;
+
+ if (nvram_naddrs < 1) {
+ printk(KERN_ERR "nvram: no address\n");
+ return;
+ }
+ nvram_image = alloc_bootmem(NVRAM_SIZE);
+ if (nvram_image == NULL) {
+ printk(KERN_ERR "nvram: can't allocate ram image\n");
+ return;
+ }
+ nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+ nvram_naddrs = 1; /* Make sure we get the correct case */
+
+ DBG("nvram: Checking bank 0...\n");
+
+ gen_bank0 = core99_check((u8 *)nvram_data);
+ gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
+ core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
+
+ DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
+ DBG("nvram: Active bank is: %d\n", core99_bank);
+
+ for (i=0; i<NVRAM_SIZE; i++)
+ nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
+
+ ppc_md.nvram_read_val = core99_nvram_read_byte;
+ ppc_md.nvram_write_val = core99_nvram_write_byte;
+ ppc_md.nvram_sync = core99_nvram_sync;
+ /*
+ * Maybe we could be smarter here though making an exclusive list
+ * of known flash chips is a bit nasty as older OF didn't provide us
+ * with a useful "compatible" entry. A solution would be to really
+ * identify the chip using flash id commands and base ourselves on
+ * a list of known chips IDs
+ */
+ if (device_is_compatible(dp, "amd-0137")) {
+ core99_erase_bank = amd_erase_bank;
+ core99_write_bank = amd_write_bank;
+ } else {
+ core99_erase_bank = sm_erase_bank;
+ core99_write_bank = sm_write_bank;
+ }
+ } else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+ nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
+ dp->addrs[0].size);
+ nvram_mult = 1;
+ ppc_md.nvram_read_val = direct_nvram_read_byte;
+ ppc_md.nvram_write_val = direct_nvram_write_byte;
+ } else if (nvram_naddrs == 1) {
+ nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
+ ppc_md.nvram_read_val = direct_nvram_read_byte;
+ ppc_md.nvram_write_val = direct_nvram_write_byte;
+ } else if (nvram_naddrs == 2) {
+ nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+ ppc_md.nvram_read_val = indirect_nvram_read_byte;
+ ppc_md.nvram_write_val = indirect_nvram_write_byte;
+ } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
+#ifdef CONFIG_ADB_PMU
+ nvram_naddrs = -1;
+ ppc_md.nvram_read_val = pmu_nvram_read_byte;
+ ppc_md.nvram_write_val = pmu_nvram_write_byte;
+#endif /* CONFIG_ADB_PMU */
+ } else {
+ printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
+ nvram_naddrs);
+ }
+ lookup_partitions();
+}
+
+int __pmac pmac_get_partition(int partition)
+{
+ return nvram_partitions[partition];
+}
+
+u8 __pmac pmac_xpram_read(int xpaddr)
+{
+ int offset = nvram_partitions[pmac_nvram_XPRAM];
+
+ if (offset < 0)
+ return 0xff;
+
+ return ppc_md.nvram_read_val(xpaddr + offset);
+}
+
+void __pmac pmac_xpram_write(int xpaddr, u8 data)
+{
+ int offset = nvram_partitions[pmac_nvram_XPRAM];
+
+ if (offset < 0)
+ return;
+
+ ppc_md.nvram_write_val(xpaddr + offset, data);
+}
+
+EXPORT_SYMBOL(pmac_get_partition);
+EXPORT_SYMBOL(pmac_xpram_read);
+EXPORT_SYMBOL(pmac_xpram_write);
diff --git a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c
new file mode 100644
index 00000000000..f6ff5192406
--- /dev/null
+++ b/arch/ppc/platforms/pmac_pci.c
@@ -0,0 +1,1125 @@
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#ifdef CONFIG_XMON
+extern void xmon_printf(const char *fmt, ...);
+#define DBG(x...) xmon_printf(x)
+#else
+#define DBG(x...) printk(x)
+#endif
+#else
+#define DBG(x...)
+#endif
+
+static int add_bridge(struct device_node *dev);
+extern void pmac_check_ht_link(void);
+
+/* XXX Could be per-controller, but I don't think we risk anything by
+ * assuming we won't have both UniNorth and Bandit */
+static int has_uninorth;
+#ifdef CONFIG_POWER4
+static struct pci_controller *u3_agp;
+#endif /* CONFIG_POWER4 */
+
+extern u8 pci_cache_line_size;
+extern int pcibios_assign_bus_offset;
+
+struct device_node *k2_skiplist[2];
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define BANDIT_DEVID_2 8
+#define BANDIT_REVID 3
+
+#define BANDIT_DEVNUM 11
+#define BANDIT_MAGIC 0x50
+#define BANDIT_COHERENT 0x40
+
+static int __init
+fixup_one_level_bus_range(struct device_node *node, int higher)
+{
+ for (; node != 0;node = node->sibling) {
+ int * bus_range;
+ unsigned int *class_code;
+ int len;
+
+ /* For PCI<->PCI bridges or CardBus bridges, we go down */
+ class_code = (unsigned int *) get_property(node, "class-code", NULL);
+ if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+ (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+ continue;
+ bus_range = (int *) get_property(node, "bus-range", &len);
+ if (bus_range != NULL && len > 2 * sizeof(int)) {
+ if (bus_range[1] > higher)
+ higher = bus_range[1];
+ }
+ higher = fixup_one_level_bus_range(node->child, higher);
+ }
+ return higher;
+}
+
+/* This routine fixes the "bus-range" property of all bridges in the
+ * system since they tend to have their "last" member wrong on macs
+ *
+ * Note that the bus numbers manipulated here are OF bus numbers, they
+ * are not Linux bus numbers.
+ */
+static void __init
+fixup_bus_range(struct device_node *bridge)
+{
+ int * bus_range;
+ int len;
+
+ /* Lookup the "bus-range" property for the hose */
+ bus_range = (int *) get_property(bridge, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ bridge->full_name);
+ return;
+ }
+ bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+}
+
+/*
+ * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers.
+ *
+ * The "Bandit" version is present in all early PCI PowerMacs,
+ * and up to the first ones using Grackle. Some machines may
+ * have 2 bandit controllers (2 PCI busses).
+ *
+ * "Chaos" is used in some "Bandit"-type machines as a bridge
+ * for the separate display bus. It is accessed the same
+ * way as bandit, but cannot be probed for devices. It therefore
+ * has its own config access functions.
+ *
+ * The "UniNorth" version is present in all Core99 machines
+ * (iBook, G4, new IMacs, and all the recent Apple machines).
+ * It contains 3 controllers in one ASIC.
+ *
+ * The U3 is the bridge used on G5 machines. It contains an
+ * AGP bus which is dealt with the old UniNorth access routines
+ * and a HyperTransport bus which uses its own set of access
+ * functions.
+ */
+
+#define MACRISC_CFA0(devfn, off) \
+ ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+ | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+ | (((unsigned long)(off)) & 0xFCUL))
+
+#define MACRISC_CFA1(bus, devfn, off) \
+ ((((unsigned long)(bus)) << 16) \
+ |(((unsigned long)(devfn)) << 8) \
+ |(((unsigned long)(off)) & 0xFCUL) \
+ |1UL)
+
+static void volatile __iomem * __pmac
+macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset)
+{
+ unsigned int caddr;
+
+ if (bus == hose->first_busno) {
+ if (dev_fn < (11 << 3))
+ return NULL;
+ caddr = MACRISC_CFA0(dev_fn, offset);
+ } else
+ caddr = MACRISC_CFA1(bus, dev_fn, offset);
+
+ /* Uninorth will return garbage if we don't read back the value ! */
+ do {
+ out_le32(hose->cfg_addr, caddr);
+ } while (in_le32(hose->cfg_addr) != caddr);
+
+ offset &= has_uninorth ? 0x07 : 0x03;
+ return hose->cfg_data + offset;
+}
+
+static int __pmac
+macrisc_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 *val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ void volatile __iomem *addr;
+
+ addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ switch (len) {
+ case 1:
+ *val = in_8(addr);
+ break;
+ case 2:
+ *val = in_le16(addr);
+ break;
+ default:
+ *val = in_le32(addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int __pmac
+macrisc_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ void volatile __iomem *addr;
+
+ addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ 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 macrisc_pci_ops =
+{
+ macrisc_read_config,
+ macrisc_write_config
+};
+
+/*
+ * Verifiy that a specific (bus, dev_fn) exists on chaos
+ */
+static int __pmac
+chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
+{
+ struct device_node *np;
+ u32 *vendor, *device;
+
+ np = pci_busdev_to_OF_node(bus, devfn);
+ if (np == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ vendor = (u32 *)get_property(np, "vendor-id", NULL);
+ device = (u32 *)get_property(np, "device-id", NULL);
+ if (vendor == NULL || device == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10)
+ && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int __pmac
+chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 *val)
+{
+ int result = chaos_validate_dev(bus, devfn, offset);
+ if (result == PCIBIOS_BAD_REGISTER_NUMBER)
+ *val = ~0U;
+ if (result != PCIBIOS_SUCCESSFUL)
+ return result;
+ return macrisc_read_config(bus, devfn, offset, len, val);
+}
+
+static int __pmac
+chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 val)
+{
+ int result = chaos_validate_dev(bus, devfn, offset);
+ if (result != PCIBIOS_SUCCESSFUL)
+ return result;
+ return macrisc_write_config(bus, devfn, offset, len, val);
+}
+
+static struct pci_ops chaos_pci_ops =
+{
+ chaos_read_config,
+ chaos_write_config
+};
+
+#ifdef CONFIG_POWER4
+
+/*
+ * These versions of U3 HyperTransport config space access ops do not
+ * implement self-view of the HT host yet
+ */
+
+#define U3_HT_CFA0(devfn, off) \
+ ((((unsigned long)devfn) << 8) | offset)
+#define U3_HT_CFA1(bus, devfn, off) \
+ (U3_HT_CFA0(devfn, off) \
+ + (((unsigned long)bus) << 16) \
+ + 0x01000000UL)
+
+static void volatile __iomem * __pmac
+u3_ht_cfg_access(struct pci_controller* hose, u8 bus, u8 devfn, u8 offset)
+{
+ if (bus == hose->first_busno) {
+ /* For now, we don't self probe U3 HT bridge */
+ if (PCI_FUNC(devfn) != 0 || PCI_SLOT(devfn) > 7 ||
+ PCI_SLOT(devfn) < 1)
+ return 0;
+ return hose->cfg_data + U3_HT_CFA0(devfn, offset);
+ } else
+ return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset);
+}
+
+static int __pmac
+u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 *val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ void volatile __iomem *addr;
+ int i;
+
+ struct device_node *np = pci_busdev_to_OF_node(bus, devfn);
+ if (np == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * When a device in K2 is powered down, we die on config
+ * cycle accesses. Fix that here.
+ */
+ for (i=0; i<2; i++)
+ if (k2_skiplist[i] == np) {
+ switch (len) {
+ case 1:
+ *val = 0xff; break;
+ case 2:
+ *val = 0xffff; break;
+ default:
+ *val = 0xfffffffful; break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ switch (len) {
+ case 1:
+ *val = in_8(addr);
+ break;
+ case 2:
+ *val = in_le16(addr);
+ break;
+ default:
+ *val = in_le32(addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int __pmac
+u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ void volatile __iomem *addr;
+ int i;
+
+ struct device_node *np = pci_busdev_to_OF_node(bus, devfn);
+ if (np == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * When a device in K2 is powered down, we die on config
+ * cycle accesses. Fix that here.
+ */
+ for (i=0; i<2; i++)
+ if (k2_skiplist[i] == np)
+ return PCIBIOS_SUCCESSFUL;
+
+ addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ 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 u3_ht_pci_ops =
+{
+ u3_ht_read_config,
+ u3_ht_write_config
+};
+
+#endif /* CONFIG_POWER4 */
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we could clean this up using the hose ops directly.
+ */
+static void __init
+init_bandit(struct pci_controller *bp)
+{
+ unsigned int vendev, magic;
+ int rev;
+
+ /* read the word at offset 0 in config space for device 11 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+ udelay(2);
+ vendev = in_le32(bp->cfg_data);
+ if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) +
+ PCI_VENDOR_ID_APPLE) {
+ /* read the revision id */
+ out_le32(bp->cfg_addr,
+ (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+ udelay(2);
+ rev = in_8(bp->cfg_data);
+ if (rev != BANDIT_REVID)
+ printk(KERN_WARNING
+ "Unknown revision %d for bandit\n", rev);
+ } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
+ printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+ return;
+ }
+
+ /* read the word at offset 0x50 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+ udelay(2);
+ magic = in_le32(bp->cfg_data);
+ if ((magic & BANDIT_COHERENT) != 0)
+ return;
+ magic |= BANDIT_COHERENT;
+ udelay(2);
+ out_le32(bp->cfg_data, magic);
+ printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
+}
+
+
+/*
+ * Tweak the PCI-PCI bridge chip on the blue & white G3s.
+ */
+static void __init
+init_p2pbridge(void)
+{
+ struct device_node *p2pbridge;
+ struct pci_controller* hose;
+ u8 bus, devfn;
+ u16 val;
+
+ /* XXX it would be better here to identify the specific
+ PCI-PCI bridge chip we have. */
+ if ((p2pbridge = find_devices("pci-bridge")) == 0
+ || p2pbridge->parent == NULL
+ || strcmp(p2pbridge->parent->name, "pci") != 0)
+ return;
+ if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
+ DBG("Can't find PCI infos for PCI<->PCI bridge\n");
+ return;
+ }
+ /* Warning: At this point, we have not yet renumbered all busses.
+ * So we must use OF walking to find out hose
+ */
+ hose = pci_find_hose_for_OF_device(p2pbridge);
+ if (!hose) {
+ DBG("Can't find hose for PCI<->PCI bridge\n");
+ return;
+ }
+ if (early_read_config_word(hose, bus, devfn,
+ PCI_BRIDGE_CONTROL, &val) < 0) {
+ printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n");
+ return;
+ }
+ val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
+ early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
+}
+
+/*
+ * Some Apple desktop machines have a NEC PD720100A USB2 controller
+ * on the motherboard. Open Firmware, on these, will disable the
+ * EHCI part of it so it behaves like a pair of OHCI's. This fixup
+ * code re-enables it ;)
+ */
+static void __init
+fixup_nec_usb2(void)
+{
+ struct device_node *nec;
+
+ for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) {
+ struct pci_controller *hose;
+ u32 data, *prop;
+ u8 bus, devfn;
+
+ prop = (u32 *)get_property(nec, "vendor-id", NULL);
+ if (prop == NULL)
+ continue;
+ if (0x1033 != *prop)
+ continue;
+ prop = (u32 *)get_property(nec, "device-id", NULL);
+ if (prop == NULL)
+ continue;
+ if (0x0035 != *prop)
+ continue;
+ prop = (u32 *)get_property(nec, "reg", NULL);
+ if (prop == NULL)
+ continue;
+ devfn = (prop[0] >> 8) & 0xff;
+ bus = (prop[0] >> 16) & 0xff;
+ if (PCI_FUNC(devfn) != 0)
+ continue;
+ hose = pci_find_hose_for_OF_device(nec);
+ if (!hose)
+ continue;
+ early_read_config_dword(hose, bus, devfn, 0xe4, &data);
+ if (data & 1UL) {
+ printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n");
+ data &= ~1UL;
+ early_write_config_dword(hose, bus, devfn, 0xe4, data);
+ early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE,
+ nec->intrs[0].line);
+ }
+ }
+}
+
+void __init
+pmac_find_bridges(void)
+{
+ struct device_node *np, *root;
+ struct device_node *ht = NULL;
+
+ root = of_find_node_by_path("/");
+ if (root == NULL) {
+ printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n");
+ return;
+ }
+ for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
+ if (np->name == NULL)
+ continue;
+ if (strcmp(np->name, "bandit") == 0
+ || strcmp(np->name, "chaos") == 0
+ || strcmp(np->name, "pci") == 0) {
+ if (add_bridge(np) == 0)
+ of_node_get(np);
+ }
+ if (strcmp(np->name, "ht") == 0) {
+ of_node_get(np);
+ ht = np;
+ }
+ }
+ of_node_put(root);
+
+ /* Probe HT last as it relies on the agp resources to be already
+ * setup
+ */
+ if (ht && add_bridge(ht) != 0)
+ of_node_put(ht);
+
+ init_p2pbridge();
+ fixup_nec_usb2();
+
+ /* We are still having some issues with the Xserve G4, enabling
+ * some offset between bus number and domains for now when we
+ * assign all busses should help for now
+ */
+ if (pci_assign_all_busses)
+ pcibios_assign_bus_offset = 0x10;
+
+#ifdef CONFIG_POWER4
+ /* There is something wrong with DMA on U3/HT. I haven't figured out
+ * the details yet, but if I set the cache line size to 128 bytes like
+ * it should, I'm getting memory corruption caused by devices like
+ * sungem (even without the MWI bit set, but maybe sungem doesn't
+ * care). Right now, it appears that setting up a 64 bytes line size
+ * works properly, 64 bytes beeing the max transfer size of HT, I
+ * suppose this is related the way HT/PCI are hooked together. I still
+ * need to dive into more specs though to be really sure of what's
+ * going on. --BenH.
+ *
+ * Ok, apparently, it's just that HT can't do more than 64 bytes
+ * transactions. MWI seem to be meaningless there as well, it may
+ * be worth nop'ing out pci_set_mwi too though I haven't done that
+ * yet.
+ *
+ * Note that it's a bit different for whatever is in the AGP slot.
+ * For now, I don't care, but this can become a real issue, we
+ * should probably hook pci_set_mwi anyway to make sure it sets
+ * the real cache line size in there.
+ */
+ if (machine_is_compatible("MacRISC4"))
+ pci_cache_line_size = 16; /* 64 bytes */
+
+ pmac_check_ht_link();
+#endif /* CONFIG_POWER4 */
+}
+
+#define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \
+ | (((o) & ~3) << 24))
+
+#define GRACKLE_PICR1_STG 0x00000040
+#define GRACKLE_PICR1_LOOPSNOOP 0x00000010
+
+/* N.B. this is called before bridges is initialized, so we can't
+ use grackle_pcibios_{read,write}_config_dword. */
+static inline void grackle_set_stg(struct pci_controller* bp, int enable)
+{
+ unsigned int val;
+
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ val = in_le32(bp->cfg_data);
+ val = enable? (val | GRACKLE_PICR1_STG) :
+ (val & ~GRACKLE_PICR1_STG);
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ out_le32(bp->cfg_data, val);
+ (void)in_le32(bp->cfg_data);
+}
+
+static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
+{
+ unsigned int val;
+
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ val = in_le32(bp->cfg_data);
+ val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
+ (val & ~GRACKLE_PICR1_LOOPSNOOP);
+ out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+ out_le32(bp->cfg_data, val);
+ (void)in_le32(bp->cfg_data);
+}
+
+static int __init
+setup_uninorth(struct pci_controller* hose, struct reg_property* addr)
+{
+ pci_assign_all_busses = 1;
+ has_uninorth = 1;
+ hose->ops = &macrisc_pci_ops;
+ hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+ /* We "know" that the bridge at f2000000 has the PCI slots. */
+ return addr->address == 0xf2000000;
+}
+
+static void __init
+setup_bandit(struct pci_controller* hose, struct reg_property* addr)
+{
+ hose->ops = &macrisc_pci_ops;
+ hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+ init_bandit(hose);
+}
+
+static void __init
+setup_chaos(struct pci_controller* hose, struct reg_property* addr)
+{
+ /* assume a `chaos' bridge */
+ hose->ops = &chaos_pci_ops;
+ hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+}
+
+#ifdef CONFIG_POWER4
+
+static void __init
+setup_u3_agp(struct pci_controller* hose, struct reg_property* addr)
+{
+ /* On G5, we move AGP up to high bus number so we don't need
+ * to reassign bus numbers for HT. If we ever have P2P bridges
+ * on AGP, we'll have to move pci_assign_all_busses to the
+ * pci_controller structure so we enable it for AGP and not for
+ * HT childs.
+ * We hard code the address because of the different size of
+ * the reg address cell, we shall fix that by killing struct
+ * reg_property and using some accessor functions instead
+ */
+ hose->first_busno = 0xf0;
+ hose->last_busno = 0xff;
+ has_uninorth = 1;
+ hose->ops = &macrisc_pci_ops;
+ hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
+
+ u3_agp = hose;
+}
+
+static void __init
+setup_u3_ht(struct pci_controller* hose, struct reg_property *addr)
+{
+ struct device_node *np = (struct device_node *)hose->arch_data;
+ int i, cur;
+
+ hose->ops = &u3_ht_pci_ops;
+
+ /* We hard code the address because of the different size of
+ * the reg address cell, we shall fix that by killing struct
+ * reg_property and using some accessor functions instead
+ */
+ hose->cfg_data = ioremap(0xf2000000, 0x02000000);
+
+ /*
+ * /ht node doesn't expose a "ranges" property, so we "remove" regions that
+ * have been allocated to AGP. So far, this version of the code doesn't assign
+ * any of the 0xfxxxxxxx "fine" memory regions to /ht.
+ * We need to fix that sooner or later by either parsing all child "ranges"
+ * properties or figuring out the U3 address space decoding logic and
+ * then read its configuration register (if any).
+ */
+ hose->io_base_phys = 0xf4000000;
+ hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000);
+ isa_io_base = (unsigned long) hose->io_base_virt;
+ hose->io_resource.name = np->full_name;
+ hose->io_resource.start = 0;
+ hose->io_resource.end = 0x003fffff;
+ hose->io_resource.flags = IORESOURCE_IO;
+ hose->pci_mem_offset = 0;
+ hose->first_busno = 0;
+ hose->last_busno = 0xef;
+ hose->mem_resources[0].name = np->full_name;
+ hose->mem_resources[0].start = 0x80000000;
+ hose->mem_resources[0].end = 0xefffffff;
+ hose->mem_resources[0].flags = IORESOURCE_MEM;
+
+ if (u3_agp == NULL) {
+ DBG("U3 has no AGP, using full resource range\n");
+ return;
+ }
+
+ /* We "remove" the AGP resources from the resources allocated to HT, that
+ * is we create "holes". However, that code does assumptions that so far
+ * happen to be true (cross fingers...), typically that resources in the
+ * AGP node are properly ordered
+ */
+ cur = 0;
+ for (i=0; i<3; i++) {
+ struct resource *res = &u3_agp->mem_resources[i];
+ if (res->flags != IORESOURCE_MEM)
+ continue;
+ /* We don't care about "fine" resources */
+ if (res->start >= 0xf0000000)
+ continue;
+ /* Check if it's just a matter of "shrinking" us in one direction */
+ if (hose->mem_resources[cur].start == res->start) {
+ DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",
+ cur, hose->mem_resources[cur].start, res->end + 1);
+ hose->mem_resources[cur].start = res->end + 1;
+ continue;
+ }
+ if (hose->mem_resources[cur].end == res->end) {
+ DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",
+ cur, hose->mem_resources[cur].end, res->start - 1);
+ hose->mem_resources[cur].end = res->start - 1;
+ continue;
+ }
+ /* No, it's not the case, we need a hole */
+ if (cur == 2) {
+ /* not enough resources to make a hole, we drop part of the range */
+ printk(KERN_WARNING "Running out of resources for /ht host !\n");
+ hose->mem_resources[cur].end = res->start - 1;
+ continue;
+ }
+ cur++;
+ DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
+ cur-1, res->start - 1, cur, res->end + 1);
+ hose->mem_resources[cur].name = np->full_name;
+ hose->mem_resources[cur].flags = IORESOURCE_MEM;
+ hose->mem_resources[cur].start = res->end + 1;
+ hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;
+ hose->mem_resources[cur-1].end = res->start - 1;
+ }
+}
+
+#endif /* CONFIG_POWER4 */
+
+void __init
+setup_grackle(struct pci_controller *hose)
+{
+ setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
+ if (machine_is_compatible("AAPL,PowerBook1998"))
+ grackle_set_loop_snoop(hose, 1);
+#if 0 /* Disabled for now, HW problems ??? */
+ grackle_set_stg(hose, 1);
+#endif
+}
+
+/*
+ * We assume that if we have a G3 powermac, we have one bridge called
+ * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
+ * if we have one or more bandit or chaos bridges, we don't have a MPC106.
+ */
+static int __init
+add_bridge(struct device_node *dev)
+{
+ int len;
+ struct pci_controller *hose;
+ struct reg_property *addr;
+ char* disp_name;
+ int *bus_range;
+ int primary = 1;
+
+ DBG("Adding PCI host bridge %s\n", dev->full_name);
+
+ addr = (struct reg_property *) get_property(dev, "reg", &len);
+ if (addr == NULL || len < sizeof(*addr)) {
+ printk(KERN_WARNING "Can't use %s: no address\n",
+ dev->full_name);
+ return -ENODEV;
+ }
+ bus_range = (int *) get_property(dev, "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",
+ dev->full_name);
+ }
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return -ENOMEM;
+ hose->arch_data = dev;
+ hose->first_busno = bus_range ? bus_range[0] : 0;
+ hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+ disp_name = NULL;
+#ifdef CONFIG_POWER4
+ if (device_is_compatible(dev, "u3-agp")) {
+ setup_u3_agp(hose, addr);
+ disp_name = "U3-AGP";
+ primary = 0;
+ } else if (device_is_compatible(dev, "u3-ht")) {
+ setup_u3_ht(hose, addr);
+ disp_name = "U3-HT";
+ primary = 1;
+ } else
+#endif /* CONFIG_POWER4 */
+ if (device_is_compatible(dev, "uni-north")) {
+ primary = setup_uninorth(hose, addr);
+ disp_name = "UniNorth";
+ } else if (strcmp(dev->name, "pci") == 0) {
+ /* XXX assume this is a mpc106 (grackle) */
+ setup_grackle(hose);
+ disp_name = "Grackle (MPC106)";
+ } else if (strcmp(dev->name, "bandit") == 0) {
+ setup_bandit(hose, addr);
+ disp_name = "Bandit";
+ } else if (strcmp(dev->name, "chaos") == 0) {
+ setup_chaos(hose, addr);
+ disp_name = "Chaos";
+ primary = 0;
+ }
+ printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
+ disp_name, addr->address, hose->first_busno, hose->last_busno);
+ DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
+ hose, hose->cfg_addr, hose->cfg_data);
+
+ /* Interpret the "ranges" property */
+ /* This also maps the I/O region and sets isa_io/mem_base */
+ pci_process_bridge_OF_ranges(hose, dev, primary);
+
+ /* Fixup "bus-range" OF property */
+ fixup_bus_range(dev);
+
+ return 0;
+}
+
+static void __init
+pcibios_fixup_OF_interrupts(void)
+{
+ struct pci_dev* dev = NULL;
+
+ /*
+ * Open Firmware often doesn't initialize the
+ * PCI_INTERRUPT_LINE config register properly, so we
+ * should find the device node and apply the interrupt
+ * obtained from the OF device-tree
+ */
+ for_each_pci_dev(dev) {
+ struct device_node *node;
+ node = pci_device_to_OF_node(dev);
+ /* this is the node, see if it has interrupts */
+ if (node && node->n_intrs > 0)
+ dev->irq = node->intrs[0].line;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ }
+}
+
+void __init
+pmac_pcibios_fixup(void)
+{
+ /* Fixup interrupts according to OF tree */
+ pcibios_fixup_OF_interrupts();
+}
+
+int __pmac
+pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
+{
+ struct device_node* node;
+ int updatecfg = 0;
+ int uninorth_child;
+
+ node = pci_device_to_OF_node(dev);
+
+ /* We don't want to enable USB controllers absent from the OF tree
+ * (iBook second controller)
+ */
+ if (dev->vendor == PCI_VENDOR_ID_APPLE
+ && (dev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10))
+ && !node) {
+ printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n",
+ pci_name(dev));
+ return -EINVAL;
+ }
+
+ if (!node)
+ return 0;
+
+ uninorth_child = node->parent &&
+ device_is_compatible(node->parent, "uni-north");
+
+ /* Firewire & GMAC were disabled after PCI probe, the driver is
+ * claiming them, we must re-enable them now.
+ */
+ if (uninorth_child && !strcmp(node->name, "firewire") &&
+ (device_is_compatible(node, "pci106b,18") ||
+ device_is_compatible(node, "pci106b,30") ||
+ device_is_compatible(node, "pci11c1,5811"))) {
+ pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
+ pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
+ updatecfg = 1;
+ }
+ if (uninorth_child && !strcmp(node->name, "ethernet") &&
+ device_is_compatible(node, "gmac")) {
+ pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
+ updatecfg = 1;
+ }
+
+ if (updatecfg) {
+ u16 cmd;
+
+ /*
+ * Make sure PCI is correctly configured
+ *
+ * We use old pci_bios versions of the function since, by
+ * default, gmac is not powered up, and so will be absent
+ * from the kernel initial PCI lookup.
+ *
+ * Should be replaced by 2.4 new PCI mechanisms and really
+ * register the device.
+ */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
+ }
+
+ return 0;
+}
+
+/* We power down some devices after they have been probed. They'll
+ * be powered back on later on
+ */
+void __init
+pmac_pcibios_after_init(void)
+{
+ struct device_node* nd;
+
+#ifdef CONFIG_BLK_DEV_IDE
+ struct pci_dev *dev = NULL;
+
+ /* OF fails to initialize IDE controllers on macs
+ * (and maybe other machines)
+ *
+ * Ideally, this should be moved to the IDE layer, but we need
+ * to check specifically with Andre Hedrick how to do it cleanly
+ * since the common IDE code seem to care about the fact that the
+ * BIOS may have disabled a controller.
+ *
+ * -- BenH
+ */
+ for_each_pci_dev(dev) {
+ if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE)
+ pci_enable_device(dev);
+ }
+#endif /* CONFIG_BLK_DEV_IDE */
+
+ nd = find_devices("firewire");
+ while (nd) {
+ if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
+ device_is_compatible(nd, "pci106b,30") ||
+ device_is_compatible(nd, "pci11c1,5811"))
+ && device_is_compatible(nd->parent, "uni-north")) {
+ pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
+ pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
+ }
+ nd = nd->next;
+ }
+ nd = find_devices("ethernet");
+ while (nd) {
+ if (nd->parent && device_is_compatible(nd, "gmac")
+ && device_is_compatible(nd->parent, "uni-north"))
+ pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
+ nd = nd->next;
+ }
+}
+
+void pmac_pci_fixup_cardbus(struct pci_dev* dev)
+{
+ if (_machine != _MACH_Pmac)
+ return;
+ /*
+ * Fix the interrupt routing on the various cardbus bridges
+ * used on powerbooks
+ */
+ if (dev->vendor != PCI_VENDOR_ID_TI)
+ return;
+ if (dev->device == PCI_DEVICE_ID_TI_1130 ||
+ dev->device == PCI_DEVICE_ID_TI_1131) {
+ u8 val;
+ /* Enable PCI interrupt */
+ if (pci_read_config_byte(dev, 0x91, &val) == 0)
+ pci_write_config_byte(dev, 0x91, val | 0x30);
+ /* Disable ISA interrupt mode */
+ if (pci_read_config_byte(dev, 0x92, &val) == 0)
+ pci_write_config_byte(dev, 0x92, val & ~0x06);
+ }
+ if (dev->device == PCI_DEVICE_ID_TI_1210 ||
+ dev->device == PCI_DEVICE_ID_TI_1211 ||
+ dev->device == PCI_DEVICE_ID_TI_1410 ||
+ dev->device == PCI_DEVICE_ID_TI_1510) {
+ u8 val;
+ /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
+ signal out the MFUNC0 pin */
+ if (pci_read_config_byte(dev, 0x8c, &val) == 0)
+ pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
+ /* Disable ISA interrupt mode */
+ if (pci_read_config_byte(dev, 0x92, &val) == 0)
+ pci_write_config_byte(dev, 0x92, val & ~0x06);
+ }
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus);
+
+void pmac_pci_fixup_pciata(struct pci_dev* dev)
+{
+ u8 progif = 0;
+
+ /*
+ * On PowerMacs, we try to switch any PCI ATA controller to
+ * fully native mode
+ */
+ if (_machine != _MACH_Pmac)
+ return;
+ /* Some controllers don't have the class IDE */
+ if (dev->vendor == PCI_VENDOR_ID_PROMISE)
+ switch(dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20246:
+ case PCI_DEVICE_ID_PROMISE_20262:
+ case PCI_DEVICE_ID_PROMISE_20263:
+ case PCI_DEVICE_ID_PROMISE_20265:
+ case PCI_DEVICE_ID_PROMISE_20267:
+ case PCI_DEVICE_ID_PROMISE_20268:
+ case PCI_DEVICE_ID_PROMISE_20269:
+ case PCI_DEVICE_ID_PROMISE_20270:
+ case PCI_DEVICE_ID_PROMISE_20271:
+ case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
+ case PCI_DEVICE_ID_PROMISE_20277:
+ goto good;
+ }
+ /* Others, check PCI class */
+ if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+ return;
+ good:
+ pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+ if ((progif & 5) != 5) {
+ printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev));
+ (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+ if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+ (progif & 5) != 5)
+ printk(KERN_ERR "Rewrite of PROGIF failed !\n");
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata);
+
+
+/*
+ * Disable second function on K2-SATA, it's broken
+ * and disable IO BARs on first one
+ */
+void __pmac pmac_pci_fixup_k2_sata(struct pci_dev* dev)
+{
+ int i;
+ u16 cmd;
+
+ if (PCI_FUNC(dev->devfn) > 0) {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ for (i = 0; i < 6; i++) {
+ dev->resource[i].start = dev->resource[i].end = 0;
+ dev->resource[i].flags = 0;
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+ }
+ } else {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd &= ~PCI_COMMAND_IO;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ for (i = 0; i < 5; i++) {
+ dev->resource[i].start = dev->resource[i].end = 0;
+ dev->resource[i].flags = 0;
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+ }
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata);
diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c
new file mode 100644
index 00000000000..9f92e1bb7f3
--- /dev/null
+++ b/arch/ppc/platforms/pmac_pic.c
@@ -0,0 +1,689 @@
+/*
+ * Support for the interrupt controllers found on Power Macintosh,
+ * currently Apple's "Grand Central" interrupt controller in all
+ * it's incarnations. OpenPIC support used on newer machines is
+ * in a separate file
+ *
+ * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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/config.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/sysdev.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+#include <asm/xmon.h>
+#include <asm/pmac_feature.h>
+
+#include "pmac_pic.h"
+
+/*
+ * XXX this should be in xmon.h, but putting it there means xmon.h
+ * has to include <linux/interrupt.h> (to get irqreturn_t), which
+ * causes all sorts of problems. -- paulus
+ */
+extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
+
+struct pmac_irq_hw {
+ unsigned int event;
+ unsigned int enable;
+ unsigned int ack;
+ unsigned int level;
+};
+
+/* Default addresses */
+static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = {
+ (struct pmac_irq_hw *) 0xf3000020,
+ (struct pmac_irq_hw *) 0xf3000010,
+ (struct pmac_irq_hw *) 0xf4000020,
+ (struct pmac_irq_hw *) 0xf4000010,
+};
+
+#define GC_LEVEL_MASK 0x3ff00000
+#define OHARE_LEVEL_MASK 0x1ff00000
+#define HEATHROW_LEVEL_MASK 0x1ff00000
+
+static int max_irqs __pmacdata;
+static int max_real_irqs __pmacdata;
+static u32 level_mask[4] __pmacdata;
+
+static DEFINE_SPINLOCK(pmac_pic_lock __pmacdata);
+
+
+#define GATWICK_IRQ_POOL_SIZE 10
+static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE] __pmacdata;
+
+/*
+ * Mark an irq as "lost". This is only used on the pmac
+ * since it can lose interrupts (see pmac_set_irq_mask).
+ * -- Cort
+ */
+void __pmac
+__set_lost(unsigned long irq_nr, int nokick)
+{
+ if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
+ atomic_inc(&ppc_n_lost_interrupts);
+ if (!nokick)
+ set_dec(1);
+ }
+}
+
+static void __pmac
+pmac_mask_and_ack_irq(unsigned int irq_nr)
+{
+ unsigned long bit = 1UL << (irq_nr & 0x1f);
+ int i = irq_nr >> 5;
+ unsigned long flags;
+
+ if ((unsigned)irq_nr >= max_irqs)
+ return;
+
+ clear_bit(irq_nr, ppc_cached_irq_mask);
+ if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+ atomic_dec(&ppc_n_lost_interrupts);
+ spin_lock_irqsave(&pmac_pic_lock, flags);
+ out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+ out_le32(&pmac_irq_hw[i]->ack, bit);
+ do {
+ /* make sure ack gets to controller before we enable
+ interrupts */
+ mb();
+ } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+ != (ppc_cached_irq_mask[i] & bit));
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
+{
+ unsigned long bit = 1UL << (irq_nr & 0x1f);
+ int i = irq_nr >> 5;
+ unsigned long flags;
+
+ if ((unsigned)irq_nr >= max_irqs)
+ return;
+
+ spin_lock_irqsave(&pmac_pic_lock, flags);
+ /* enable unmasked interrupts */
+ out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+
+ do {
+ /* make sure mask gets to controller before we
+ return to user */
+ mb();
+ } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+ != (ppc_cached_irq_mask[i] & bit));
+
+ /*
+ * Unfortunately, setting the bit in the enable register
+ * when the device interrupt is already on *doesn't* set
+ * the bit in the flag register or request another interrupt.
+ */
+ if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
+ __set_lost((ulong)irq_nr, nokicklost);
+ spin_unlock_irqrestore(&pmac_pic_lock, flags);
+}
+
+/* When an irq gets requested for the first client, if it's an
+ * edge interrupt, we clear any previous one on the controller
+ */
+static unsigned int __pmac pmac_startup_irq(unsigned int irq_nr)
+{
+ unsigned long bit = 1UL << (irq_nr & 0x1f);
+ int i = irq_nr >> 5;
+
+ if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
+ out_le32(&pmac_irq_hw[i]->ack, bit);
+ set_bit(irq_nr, ppc_cached_irq_mask);
+ pmac_set_irq_mask(irq_nr, 0);
+
+ return 0;
+}
+
+static void __pmac pmac_mask_irq(unsigned int irq_nr)
+{
+ clear_bit(irq_nr, ppc_cached_irq_mask);
+ pmac_set_irq_mask(irq_nr, 0);
+ mb();
+}
+
+static void __pmac pmac_unmask_irq(unsigned int irq_nr)
+{
+ set_bit(irq_nr, ppc_cached_irq_mask);
+ pmac_set_irq_mask(irq_nr, 0);
+}
+
+static void __pmac pmac_end_irq(unsigned int irq_nr)
+{
+ if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+ && irq_desc[irq_nr].action) {
+ set_bit(irq_nr, ppc_cached_irq_mask);
+ pmac_set_irq_mask(irq_nr, 1);
+ }
+}
+
+
+struct hw_interrupt_type pmac_pic = {
+ .typename = " PMAC-PIC ",
+ .startup = pmac_startup_irq,
+ .enable = pmac_unmask_irq,
+ .disable = pmac_mask_irq,
+ .ack = pmac_mask_and_ack_irq,
+ .end = pmac_end_irq,
+};
+
+struct hw_interrupt_type gatwick_pic = {
+ .typename = " GATWICK ",
+ .startup = pmac_startup_irq,
+ .enable = pmac_unmask_irq,
+ .disable = pmac_mask_irq,
+ .ack = pmac_mask_and_ack_irq,
+ .end = pmac_end_irq,
+};
+
+static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ int irq, bits;
+
+ for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
+ int i = irq >> 5;
+ bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
+ /* We must read level interrupts from the level register */
+ bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
+ bits &= ppc_cached_irq_mask[i];
+ if (bits == 0)
+ continue;
+ irq += __ilog2(bits);
+ __do_IRQ(irq, regs);
+ return IRQ_HANDLED;
+ }
+ printk("gatwick irq not from gatwick pic\n");
+ return IRQ_NONE;
+}
+
+int
+pmac_get_irq(struct pt_regs *regs)
+{
+ int irq;
+ unsigned long bits = 0;
+
+#ifdef CONFIG_SMP
+ void psurge_smp_message_recv(struct pt_regs *);
+
+ /* IPI's are a hack on the powersurge -- Cort */
+ if ( smp_processor_id() != 0 ) {
+ psurge_smp_message_recv(regs);
+ return -2; /* ignore, already handled */
+ }
+#endif /* CONFIG_SMP */
+ for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
+ int i = irq >> 5;
+ bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
+ /* We must read level interrupts from the level register */
+ bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
+ bits &= ppc_cached_irq_mask[i];
+ if (bits == 0)
+ continue;
+ irq += __ilog2(bits);
+ break;
+ }
+
+ return irq;
+}
+
+/* This routine will fix some missing interrupt values in the device tree
+ * on the gatwick mac-io controller used by some PowerBooks
+ */
+static void __init
+pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+{
+ struct device_node *node;
+ int count;
+
+ memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
+ node = gw->child;
+ count = 0;
+ while(node)
+ {
+ /* Fix SCC */
+ if (strcasecmp(node->name, "escc") == 0)
+ if (node->child) {
+ if (node->child->n_intrs < 3) {
+ node->child->intrs = &gatwick_int_pool[count];
+ count += 3;
+ }
+ node->child->n_intrs = 3;
+ node->child->intrs[0].line = 15+irq_base;
+ node->child->intrs[1].line = 4+irq_base;
+ node->child->intrs[2].line = 5+irq_base;
+ printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
+ node->child->intrs[0].line,
+ node->child->intrs[1].line,
+ node->child->intrs[2].line);
+ }
+ /* Fix media-bay & left SWIM */
+ if (strcasecmp(node->name, "media-bay") == 0) {
+ struct device_node* ya_node;
+
+ if (node->n_intrs == 0)
+ node->intrs = &gatwick_int_pool[count++];
+ node->n_intrs = 1;
+ node->intrs[0].line = 29+irq_base;
+ printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
+ node->intrs[0].line);
+
+ ya_node = node->child;
+ while(ya_node)
+ {
+ if (strcasecmp(ya_node->name, "floppy") == 0) {
+ if (ya_node->n_intrs < 2) {
+ ya_node->intrs = &gatwick_int_pool[count];
+ count += 2;
+ }
+ ya_node->n_intrs = 2;
+ ya_node->intrs[0].line = 19+irq_base;
+ ya_node->intrs[1].line = 1+irq_base;
+ printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
+ ya_node->intrs[0].line, ya_node->intrs[1].line);
+ }
+ if (strcasecmp(ya_node->name, "ata4") == 0) {
+ if (ya_node->n_intrs < 2) {
+ ya_node->intrs = &gatwick_int_pool[count];
+ count += 2;
+ }
+ ya_node->n_intrs = 2;
+ ya_node->intrs[0].line = 14+irq_base;
+ ya_node->intrs[1].line = 3+irq_base;
+ printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
+ ya_node->intrs[0].line, ya_node->intrs[1].line);
+ }
+ ya_node = ya_node->sibling;
+ }
+ }
+ node = node->sibling;
+ }
+ if (count > 10) {
+ printk("WARNING !! Gatwick interrupt pool overflow\n");
+ printk(" GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
+ printk(" requested = %d\n", count);
+ }
+}
+
+/*
+ * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
+ * card which includes an ohare chip that acts as a second interrupt
+ * controller. If we find this second ohare, set it up and fix the
+ * interrupt value in the device tree for the ethernet chip.
+ */
+static int __init enable_second_ohare(void)
+{
+ unsigned char bus, devfn;
+ unsigned short cmd;
+ unsigned long addr;
+ struct device_node *irqctrler = find_devices("pci106b,7");
+ struct device_node *ether;
+
+ if (irqctrler == NULL || irqctrler->n_addrs <= 0)
+ return -1;
+ addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
+ pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
+ max_irqs = 64;
+ if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
+ struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
+ if (!hose)
+ printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
+ else {
+ early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ cmd &= ~PCI_COMMAND_IO;
+ early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
+ }
+ }
+
+ /* Fix interrupt for the modem/ethernet combo controller. The number
+ in the device tree (27) is bogus (correct for the ethernet-only
+ board but not the combo ethernet/modem board).
+ The real interrupt is 28 on the second controller -> 28+32 = 60.
+ */
+ ether = find_devices("pci1011,14");
+ if (ether && ether->n_intrs > 0) {
+ ether->intrs[0].line = 60;
+ printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
+ ether->intrs[0].line);
+ }
+
+ /* Return the interrupt number of the cascade */
+ return irqctrler->intrs[0].line;
+}
+
+#ifdef CONFIG_POWER4
+static irqreturn_t k2u3_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ int irq;
+
+ irq = openpic2_get_irq(regs);
+ if (irq != -1)
+ __do_IRQ(irq, regs);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction k2u3_cascade_action = {
+ .handler = k2u3_action,
+ .flags = 0,
+ .mask = CPU_MASK_NONE,
+ .name = "U3->K2 Cascade",
+};
+#endif /* CONFIG_POWER4 */
+
+#ifdef CONFIG_XMON
+static struct irqaction xmon_action = {
+ .handler = xmon_irq,
+ .flags = 0,
+ .mask = CPU_MASK_NONE,
+ .name = "NMI - XMON"
+};
+#endif
+
+static struct irqaction gatwick_cascade_action = {
+ .handler = gatwick_action,
+ .flags = SA_INTERRUPT,
+ .mask = CPU_MASK_NONE,
+ .name = "cascade",
+};
+
+void __init pmac_pic_init(void)
+{
+ int i;
+ struct device_node *irqctrler = NULL;
+ struct device_node *irqctrler2 = NULL;
+ struct device_node *np;
+ unsigned long addr;
+ int irq_cascade = -1;
+
+ /* We first try to detect Apple's new Core99 chipset, since mac-io
+ * is quite different on those machines and contains an IBM MPIC2.
+ */
+ np = find_type_devices("open-pic");
+ while(np) {
+ if (np->parent && !strcmp(np->parent->name, "u3"))
+ irqctrler2 = np;
+ else
+ irqctrler = np;
+ np = np->next;
+ }
+ if (irqctrler != NULL)
+ {
+ if (irqctrler->n_addrs > 0)
+ {
+ unsigned char senses[128];
+
+ printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
+ irqctrler->addrs[0].address);
+
+ prom_get_irq_senses(senses, 0, 128);
+ OpenPIC_InitSenses = senses;
+ OpenPIC_NumInitSenses = 128;
+ ppc_md.get_irq = openpic_get_irq;
+ pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
+ OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
+ irqctrler->addrs[0].size);
+ openpic_init(0);
+
+#ifdef CONFIG_POWER4
+ if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
+ irqctrler2->n_addrs > 0) {
+ printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
+ irqctrler2->addrs[0].address,
+ irqctrler2->intrs[0].line);
+ pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
+ OpenPIC2_Addr = ioremap(irqctrler2->addrs[0].address,
+ irqctrler2->addrs[0].size);
+ prom_get_irq_senses(senses, PMAC_OPENPIC2_OFFSET,
+ PMAC_OPENPIC2_OFFSET+128);
+ OpenPIC_InitSenses = senses;
+ OpenPIC_NumInitSenses = 128;
+ openpic2_init(PMAC_OPENPIC2_OFFSET);
+
+ if (setup_irq(irqctrler2->intrs[0].line,
+ &k2u3_cascade_action))
+ printk("Unable to get OpenPIC IRQ for cascade\n");
+ }
+#endif /* CONFIG_POWER4 */
+
+#ifdef CONFIG_XMON
+ {
+ struct device_node* pswitch;
+ int nmi_irq;
+
+ pswitch = find_devices("programmer-switch");
+ if (pswitch && pswitch->n_intrs) {
+ nmi_irq = pswitch->intrs[0].line;
+ openpic_init_nmi_irq(nmi_irq);
+ setup_irq(nmi_irq, &xmon_action);
+ }
+ }
+#endif /* CONFIG_XMON */
+ return;
+ }
+ irqctrler = NULL;
+ }
+
+ /* Get the level/edge settings, assume if it's not
+ * a Grand Central nor an OHare, then it's an Heathrow
+ * (or Paddington).
+ */
+ if (find_devices("gc"))
+ level_mask[0] = GC_LEVEL_MASK;
+ else if (find_devices("ohare")) {
+ level_mask[0] = OHARE_LEVEL_MASK;
+ /* We might have a second cascaded ohare */
+ level_mask[1] = OHARE_LEVEL_MASK;
+ } else {
+ level_mask[0] = HEATHROW_LEVEL_MASK;
+ level_mask[1] = 0;
+ /* We might have a second cascaded heathrow */
+ level_mask[2] = HEATHROW_LEVEL_MASK;
+ level_mask[3] = 0;
+ }
+
+ /*
+ * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
+ * 1998 G3 Series PowerBooks have 128,
+ * other powermacs have 32.
+ * The combo ethernet/modem card for the Powerstar powerbooks
+ * (2400/3400/3500, ohare based) has a second ohare chip
+ * effectively making a total of 64.
+ */
+ max_irqs = max_real_irqs = 32;
+ irqctrler = find_devices("mac-io");
+ if (irqctrler)
+ {
+ max_real_irqs = 64;
+ if (irqctrler->next)
+ max_irqs = 128;
+ else
+ max_irqs = 64;
+ }
+ for ( i = 0; i < max_real_irqs ; i++ )
+ irq_desc[i].handler = &pmac_pic;
+
+ /* get addresses of first controller */
+ if (irqctrler) {
+ if (irqctrler->n_addrs > 0) {
+ addr = (unsigned long)
+ ioremap(irqctrler->addrs[0].address, 0x40);
+ for (i = 0; i < 2; ++i)
+ pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+ (addr + (2 - i) * 0x10);
+ }
+
+ /* get addresses of second controller */
+ irqctrler = irqctrler->next;
+ if (irqctrler && irqctrler->n_addrs > 0) {
+ addr = (unsigned long)
+ ioremap(irqctrler->addrs[0].address, 0x40);
+ for (i = 2; i < 4; ++i)
+ pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+ (addr + (4 - i) * 0x10);
+ irq_cascade = irqctrler->intrs[0].line;
+ if (device_is_compatible(irqctrler, "gatwick"))
+ pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+ }
+ } else {
+ /* older powermacs have a GC (grand central) or ohare at
+ f3000000, with interrupt control registers at f3000020. */
+ addr = (unsigned long) ioremap(0xf3000000, 0x40);
+ pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
+ }
+
+ /* PowerBooks 3400 and 3500 can have a second controller in a second
+ ohare chip, on the combo ethernet/modem card */
+ if (machine_is_compatible("AAPL,3400/2400")
+ || machine_is_compatible("AAPL,3500"))
+ irq_cascade = enable_second_ohare();
+
+ /* disable all interrupts in all controllers */
+ for (i = 0; i * 32 < max_irqs; ++i)
+ out_le32(&pmac_irq_hw[i]->enable, 0);
+ /* mark level interrupts */
+ for (i = 0; i < max_irqs; i++)
+ if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
+ irq_desc[i].status = IRQ_LEVEL;
+
+ /* get interrupt line of secondary interrupt controller */
+ if (irq_cascade >= 0) {
+ printk(KERN_INFO "irq: secondary controller on irq %d\n",
+ (int)irq_cascade);
+ for ( i = max_real_irqs ; i < max_irqs ; i++ )
+ irq_desc[i].handler = &gatwick_pic;
+ setup_irq(irq_cascade, &gatwick_cascade_action);
+ }
+ printk("System has %d possible interrupts\n", max_irqs);
+ if (max_irqs != max_real_irqs)
+ printk(KERN_DEBUG "%d interrupts on main controller\n",
+ max_real_irqs);
+
+#ifdef CONFIG_XMON
+ setup_irq(20, &xmon_action);
+#endif /* CONFIG_XMON */
+}
+
+#ifdef CONFIG_PM
+/*
+ * These procedures are used in implementing sleep on the powerbooks.
+ * sleep_save_intrs() saves the states of all interrupt enables
+ * and disables all interrupts except for the nominated one.
+ * sleep_restore_intrs() restores the states of all interrupt enables.
+ */
+unsigned long sleep_save_mask[2];
+
+/* This used to be passed by the PMU driver but that link got
+ * broken with the new driver model. We use this tweak for now...
+ */
+static int pmacpic_find_viaint(void)
+{
+ int viaint = -1;
+
+#ifdef CONFIG_ADB_PMU
+ struct device_node *np;
+
+ if (pmu_get_model() != PMU_OHARE_BASED)
+ goto not_found;
+ np = of_find_node_by_name(NULL, "via-pmu");
+ if (np == NULL)
+ goto not_found;
+ viaint = np->intrs[0].line;
+#endif /* CONFIG_ADB_PMU */
+
+not_found:
+ return viaint;
+}
+
+static int pmacpic_suspend(struct sys_device *sysdev, u32 state)
+{
+ int viaint = pmacpic_find_viaint();
+
+ sleep_save_mask[0] = ppc_cached_irq_mask[0];
+ sleep_save_mask[1] = ppc_cached_irq_mask[1];
+ ppc_cached_irq_mask[0] = 0;
+ ppc_cached_irq_mask[1] = 0;
+ if (viaint > 0)
+ set_bit(viaint, ppc_cached_irq_mask);
+ out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
+ if (max_real_irqs > 32)
+ out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
+ (void)in_le32(&pmac_irq_hw[0]->event);
+ /* make sure mask gets to controller before we return to caller */
+ mb();
+ (void)in_le32(&pmac_irq_hw[0]->enable);
+
+ return 0;
+}
+
+static int pmacpic_resume(struct sys_device *sysdev)
+{
+ int i;
+
+ out_le32(&pmac_irq_hw[0]->enable, 0);
+ if (max_real_irqs > 32)
+ out_le32(&pmac_irq_hw[1]->enable, 0);
+ mb();
+ for (i = 0; i < max_real_irqs; ++i)
+ if (test_bit(i, sleep_save_mask))
+ pmac_unmask_irq(i);
+
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static struct sysdev_class pmacpic_sysclass = {
+ set_kset_name("pmac_pic"),
+};
+
+static struct sys_device device_pmacpic = {
+ .id = 0,
+ .cls = &pmacpic_sysclass,
+};
+
+static struct sysdev_driver driver_pmacpic = {
+#ifdef CONFIG_PM
+ .suspend = &pmacpic_suspend,
+ .resume = &pmacpic_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init init_pmacpic_sysfs(void)
+{
+ if (max_irqs == 0)
+ return -ENODEV;
+
+ printk(KERN_DEBUG "Registering pmac pic with sysfs...\n");
+ sysdev_class_register(&pmacpic_sysclass);
+ sysdev_register(&device_pmacpic);
+ sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic);
+ return 0;
+}
+
+subsys_initcall(init_pmacpic_sysfs);
+
diff --git a/arch/ppc/platforms/pmac_pic.h b/arch/ppc/platforms/pmac_pic.h
new file mode 100644
index 00000000000..664103dfeef
--- /dev/null
+++ b/arch/ppc/platforms/pmac_pic.h
@@ -0,0 +1,11 @@
+#ifndef __PPC_PLATFORMS_PMAC_PIC_H
+#define __PPC_PLATFORMS_PMAC_PIC_H
+
+#include <linux/irq.h>
+
+extern struct hw_interrupt_type pmac_pic;
+
+void pmac_pic_init(void);
+int pmac_get_irq(struct pt_regs *regs);
+
+#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
new file mode 100644
index 00000000000..4d324b630f4
--- /dev/null
+++ b/arch/ppc/platforms/pmac_setup.c
@@ -0,0 +1,745 @@
+/*
+ * arch/ppc/platforms/setup.c
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Adapted for Power Macintosh by Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * Derived from "arch/alpha/kernel/setup.c"
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#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/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/bitops.h>
+#include <linux/suspend.h>
+
+#include <asm/reg.h>
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/ohare.h>
+#include <asm/mediabay.h>
+#include <asm/machdep.h>
+#include <asm/dma.h>
+#include <asm/bootx.h>
+#include <asm/cputable.h>
+#include <asm/btext.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+#include <asm/of_device.h>
+#include <asm/mmu_context.h>
+
+#include "pmac_pic.h"
+#include "mem_pieces.h"
+
+#undef SHOW_GATWICK_IRQS
+
+extern long pmac_time_init(void);
+extern unsigned long pmac_get_rtc_time(void);
+extern int pmac_set_rtc_time(unsigned long nowtime);
+extern void pmac_read_rtc_time(void);
+extern void pmac_calibrate_decr(void);
+extern void pmac_pcibios_fixup(void);
+extern void pmac_find_bridges(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);
+extern void pmac_nvram_write_byte(int addr, unsigned char val);
+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);
+
+struct device_node *memory_node;
+
+unsigned char drive_info;
+
+int ppc_override_l2cr = 0;
+int ppc_override_l2cr_value;
+int has_l2cache = 0;
+
+static int current_root_goodness = -1;
+
+extern int pmac_newworld;
+
+#define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */
+
+extern void zs_kgdb_hook(int tty_num);
+static void ohare_init(void);
+#ifdef CONFIG_BOOTX_TEXT
+void pmac_progress(char *s, unsigned short hex);
+#endif
+
+sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
+
+#ifdef CONFIG_SMP
+extern struct smp_ops_t psurge_smp_ops;
+extern struct smp_ops_t core99_smp_ops;
+#endif /* CONFIG_SMP */
+
+int __pmac
+pmac_show_cpuinfo(struct seq_file *m)
+{
+ struct device_node *np;
+ char *pp;
+ int plen;
+ int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+ NULL, PMAC_MB_INFO_MODEL, 0);
+ unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+ NULL, PMAC_MB_INFO_FLAGS, 0);
+ char* mbname;
+
+ if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
+ mbname = "Unknown";
+
+ /* find motherboard type */
+ seq_printf(m, "machine\t\t: ");
+ np = find_devices("device-tree");
+ if (np != NULL) {
+ pp = (char *) get_property(np, "model", NULL);
+ if (pp != NULL)
+ seq_printf(m, "%s\n", pp);
+ else
+ seq_printf(m, "PowerMac\n");
+ pp = (char *) get_property(np, "compatible", &plen);
+ if (pp != NULL) {
+ seq_printf(m, "motherboard\t:");
+ while (plen > 0) {
+ int l = strlen(pp) + 1;
+ seq_printf(m, " %s", pp);
+ plen -= l;
+ pp += l;
+ }
+ seq_printf(m, "\n");
+ }
+ } else
+ seq_printf(m, "PowerMac\n");
+
+ /* print parsed model */
+ seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
+ seq_printf(m, "pmac flags\t: %08x\n", mbflags);
+
+ /* find l2 cache info */
+ np = find_devices("l2-cache");
+ if (np == 0)
+ np = find_type_devices("cache");
+ if (np != 0) {
+ unsigned int *ic = (unsigned int *)
+ get_property(np, "i-cache-size", NULL);
+ unsigned int *dc = (unsigned int *)
+ get_property(np, "d-cache-size", NULL);
+ seq_printf(m, "L2 cache\t:");
+ has_l2cache = 1;
+ if (get_property(np, "cache-unified", NULL) != 0 && dc) {
+ seq_printf(m, " %dK unified", *dc / 1024);
+ } else {
+ if (ic)
+ seq_printf(m, " %dK instruction", *ic / 1024);
+ if (dc)
+ seq_printf(m, "%s %dK data",
+ (ic? " +": ""), *dc / 1024);
+ }
+ pp = get_property(np, "ram-type", NULL);
+ if (pp)
+ seq_printf(m, " %s", pp);
+ seq_printf(m, "\n");
+ }
+
+ /* find ram info */
+ np = find_devices("memory");
+ if (np != 0) {
+ int n;
+ struct reg_property *reg = (struct reg_property *)
+ get_property(np, "reg", &n);
+
+ if (reg != 0) {
+ unsigned long total = 0;
+
+ for (n /= sizeof(struct reg_property); n > 0; --n)
+ total += (reg++)->size;
+ seq_printf(m, "memory\t\t: %luMB\n", total >> 20);
+ }
+ }
+
+ /* Checks "l2cr-value" property in the registry */
+ np = find_devices("cpus");
+ if (np == 0)
+ np = find_type_devices("cpu");
+ if (np != 0) {
+ unsigned int *l2cr = (unsigned int *)
+ get_property(np, "l2cr-value", NULL);
+ if (l2cr != 0) {
+ seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr);
+ }
+ }
+
+ /* Indicate newworld/oldworld */
+ seq_printf(m, "pmac-generation\t: %s\n",
+ pmac_newworld ? "NewWorld" : "OldWorld");
+
+
+ return 0;
+}
+
+int __openfirmware
+pmac_show_percpuinfo(struct seq_file *m, int i)
+{
+#ifdef CONFIG_CPU_FREQ_PMAC
+ extern unsigned int pmac_get_one_cpufreq(int i);
+ unsigned int freq = pmac_get_one_cpufreq(i);
+ if (freq != 0) {
+ seq_printf(m, "clock\t\t: %dMHz\n", freq/1000);
+ return 0;
+ }
+#endif /* CONFIG_CPU_FREQ_PMAC */
+ return of_show_percpuinfo(m, i);
+}
+
+static volatile u32 *sysctrl_regs;
+
+void __init
+pmac_setup_arch(void)
+{
+ struct device_node *cpu;
+ int *fp;
+ unsigned long pvr;
+
+ pvr = PVR_VER(mfspr(SPRN_PVR));
+
+ /* Set loops_per_jiffy to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (int *) get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0) {
+ if (pvr == 4 || pvr >= 8)
+ /* 604, G3, G4 etc. */
+ loops_per_jiffy = *fp / HZ;
+ else
+ /* 601, 603, etc. */
+ loops_per_jiffy = *fp / (2*HZ);
+ } else
+ loops_per_jiffy = 50000000 / HZ;
+ }
+
+ /* this area has the CPU identification register
+ and some registers used by smp boards */
+ sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
+ ohare_init();
+
+ /* Lookup PCI hosts */
+ pmac_find_bridges();
+
+ /* Checks "l2cr-value" property in the registry */
+ if (cpu_has_feature(CPU_FTR_L2CR)) {
+ struct device_node *np = find_devices("cpus");
+ if (np == 0)
+ np = find_type_devices("cpu");
+ if (np != 0) {
+ unsigned int *l2cr = (unsigned int *)
+ get_property(np, "l2cr-value", NULL);
+ if (l2cr != 0) {
+ ppc_override_l2cr = 1;
+ ppc_override_l2cr_value = *l2cr;
+ _set_L2CR(0);
+ _set_L2CR(ppc_override_l2cr_value);
+ }
+ }
+ }
+
+ if (ppc_override_l2cr)
+ printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
+ ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
+ ? "enabled" : "disabled");
+
+#ifdef CONFIG_KGDB
+ zs_kgdb_hook(0);
+#endif
+
+#ifdef CONFIG_ADB_CUDA
+ find_via_cuda();
+#else
+ if (find_devices("via-cuda")) {
+ printk("WARNING ! Your machine is Cuda based but your kernel\n");
+ printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n");
+ }
+#endif
+#ifdef CONFIG_ADB_PMU
+ find_via_pmu();
+#else
+ if (find_devices("via-pmu")) {
+ printk("WARNING ! Your machine is PMU based but your kernel\n");
+ printk(" wasn't compiled with CONFIG_ADB_PMU option !\n");
+ }
+#endif
+#ifdef CONFIG_NVRAM
+ pmac_nvram_init();
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+ ROOT_DEV = DEFAULT_ROOT_DEVICE;
+
+#ifdef CONFIG_SMP
+ /* Check for Core99 */
+ if (find_devices("uni-n") || find_devices("u3"))
+ ppc_md.smp_ops = &core99_smp_ops;
+ else
+ ppc_md.smp_ops = &psurge_smp_ops;
+#endif /* CONFIG_SMP */
+
+ pci_create_OF_bus_map();
+}
+
+static void __init ohare_init(void)
+{
+ /*
+ * Turn on the L2 cache.
+ * We assume that we have a PSX memory controller iff
+ * we have an ohare I/O controller.
+ */
+ if (find_devices("ohare") != NULL) {
+ if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
+ if (sysctrl_regs[4] & 0x10)
+ sysctrl_regs[4] |= 0x04000020;
+ else
+ sysctrl_regs[4] |= 0x04000000;
+ if(has_l2cache)
+ printk(KERN_INFO "Level 2 cache enabled\n");
+ }
+ }
+}
+
+extern char *bootpath;
+extern char *bootdevice;
+void *boot_host;
+int boot_target;
+int boot_part;
+extern dev_t boot_dev;
+
+#ifdef CONFIG_SCSI
+void __init
+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);
+ }
+ }
+}
+#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 */
+
+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;
+/* TODO: Merge the suspend-to-ram with the common code !!!
+ * currently, this is a stub implementation for suspend-to-disk
+ * only
+ */
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+
+static int pmac_pm_prepare(suspend_state_t state)
+{
+ printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+ return 0;
+}
+
+static int pmac_pm_enter(suspend_state_t state)
+{
+ printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+ /* Giveup the lazy FPU & vec so we don't have to back them
+ * up from the low level code
+ */
+ enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+ if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
+ enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+ return 0;
+}
+
+static int pmac_pm_finish(suspend_state_t state)
+{
+ printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+ /* Restore userland MMU context */
+ set_context(current->active_mm->context, current->active_mm->pgd);
+
+ return 0;
+}
+
+static struct pm_ops pmac_pm_ops = {
+ .pm_disk_mode = PM_DISK_SHUTDOWN,
+ .prepare = pmac_pm_prepare,
+ .enter = pmac_pm_enter,
+ .finish = pmac_pm_finish,
+};
+
+#endif /* CONFIG_SOFTWARE_SUSPEND */
+
+static int pmac_late_init(void)
+{
+ initializing = 0;
+#ifdef CONFIG_SOFTWARE_SUSPEND
+ pm_set_ops(&pmac_pm_ops);
+#endif /* CONFIG_SOFTWARE_SUSPEND */
+ return 0;
+}
+
+late_initcall(pmac_late_init);
+
+/* can't be __init - can be called whenever a disk is first accessed */
+void __pmac
+note_bootable_part(dev_t dev, int part, int goodness)
+{
+ static int found_boot = 0;
+ char *p;
+
+ if (!initializing)
+ return;
+ if ((goodness <= current_root_goodness) &&
+ ROOT_DEV != DEFAULT_ROOT_DEVICE)
+ return;
+ p = strstr(saved_command_line, "root=");
+ if (p != NULL && (p == saved_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;
+ }
+}
+
+void __pmac
+pmac_restart(char *cmd)
+{
+#ifdef CONFIG_ADB_CUDA
+ struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
+
+ switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+ case SYS_CTRLER_CUDA:
+ cuda_request(&req, NULL, 2, CUDA_PACKET,
+ CUDA_RESET_SYSTEM);
+ for (;;)
+ cuda_poll();
+ break;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+ case SYS_CTRLER_PMU:
+ pmu_restart();
+ break;
+#endif /* CONFIG_ADB_PMU */
+ default: ;
+ }
+}
+
+void __pmac
+pmac_power_off(void)
+{
+#ifdef CONFIG_ADB_CUDA
+ struct adb_request req;
+#endif /* CONFIG_ADB_CUDA */
+
+ switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+ case SYS_CTRLER_CUDA:
+ cuda_request(&req, NULL, 2, CUDA_PACKET,
+ CUDA_POWERDOWN);
+ for (;;)
+ cuda_poll();
+ break;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+ case SYS_CTRLER_PMU:
+ pmu_shutdown();
+ break;
+#endif /* CONFIG_ADB_PMU */
+ default: ;
+ }
+}
+
+void __pmac
+pmac_halt(void)
+{
+ pmac_power_off();
+}
+
+/*
+ * Read in a property describing some pieces of memory.
+ */
+
+static int __init
+get_mem_prop(char *name, struct mem_pieces *mp)
+{
+ struct reg_property *rp;
+ int i, s;
+ unsigned int *ip;
+ int nac = prom_n_addr_cells(memory_node);
+ int nsc = prom_n_size_cells(memory_node);
+
+ ip = (unsigned int *) get_property(memory_node, name, &s);
+ if (ip == NULL) {
+ printk(KERN_ERR "error: couldn't get %s property on /memory\n",
+ name);
+ return 0;
+ }
+ s /= (nsc + nac) * 4;
+ rp = mp->regions;
+ for (i = 0; i < s; ++i, ip += nac+nsc) {
+ if (nac >= 2 && ip[nac-2] != 0)
+ continue;
+ rp->address = ip[nac-1];
+ if (nsc >= 2 && ip[nac+nsc-2] != 0)
+ rp->size = ~0U;
+ else
+ rp->size = ip[nac+nsc-1];
+ ++rp;
+ }
+ mp->n_regions = rp - mp->regions;
+
+ /* Make sure the pieces are sorted. */
+ mem_pieces_sort(mp);
+ mem_pieces_coalesce(mp);
+ return 1;
+}
+
+/*
+ * On systems with Open Firmware, collect information about
+ * physical RAM and which pieces are already in use.
+ * At this point, we have (at least) the first 8MB mapped with a BAT.
+ * Our text, data, bss use something over 1MB, starting at 0.
+ * Open Firmware may be using 1MB at the 4MB point.
+ */
+unsigned long __init
+pmac_find_end_of_memory(void)
+{
+ unsigned long a, total;
+ struct mem_pieces phys_mem;
+
+ /*
+ * Find out where physical memory is, and check that it
+ * starts at 0 and is contiguous. It seems that RAM is
+ * always physically contiguous on Power Macintoshes.
+ *
+ * Supporting discontiguous physical memory isn't hard,
+ * it just makes the virtual <-> physical mapping functions
+ * more complicated (or else you end up wasting space
+ * in mem_map).
+ */
+ memory_node = find_devices("memory");
+ if (memory_node == NULL || !get_mem_prop("reg", &phys_mem)
+ || phys_mem.n_regions == 0)
+ panic("No RAM??");
+ a = phys_mem.regions[0].address;
+ if (a != 0)
+ panic("RAM doesn't start at physical address 0");
+ total = phys_mem.regions[0].size;
+
+ if (phys_mem.n_regions > 1) {
+ printk("RAM starting at 0x%x is not contiguous\n",
+ phys_mem.regions[1].address);
+ printk("Using RAM from 0 to 0x%lx\n", total-1);
+ }
+
+ return total;
+}
+
+void __init
+pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ /* isa_io_base gets set in pmac_find_bridges */
+ isa_mem_base = PMAC_ISA_MEM_BASE;
+ pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 1;
+ DMA_MODE_WRITE = 2;
+
+ ppc_md.setup_arch = pmac_setup_arch;
+ ppc_md.show_cpuinfo = pmac_show_cpuinfo;
+ ppc_md.show_percpuinfo = pmac_show_percpuinfo;
+ ppc_md.irq_canonicalize = NULL;
+ ppc_md.init_IRQ = pmac_pic_init;
+ ppc_md.get_irq = pmac_get_irq; /* Changed later on ... */
+
+ ppc_md.pcibios_fixup = pmac_pcibios_fixup;
+ ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
+ ppc_md.pcibios_after_init = pmac_pcibios_after_init;
+ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
+ ppc_md.restart = pmac_restart;
+ ppc_md.power_off = pmac_power_off;
+ ppc_md.halt = pmac_halt;
+
+ ppc_md.time_init = pmac_time_init;
+ ppc_md.set_rtc_time = pmac_set_rtc_time;
+ ppc_md.get_rtc_time = pmac_get_rtc_time;
+ ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+ ppc_md.find_end_of_memory = pmac_find_end_of_memory;
+
+ ppc_md.feature_call = pmac_do_feature_call;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+ ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
+ ppc_ide_md.default_io_base = pmac_ide_get_base;
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
+
+#ifdef CONFIG_BOOTX_TEXT
+ ppc_md.progress = pmac_progress;
+#endif /* CONFIG_BOOTX_TEXT */
+
+ if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
+
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+void __init
+pmac_progress(char *s, unsigned short hex)
+{
+ if (boot_text_mapped) {
+ btext_drawstring(s);
+ btext_drawchar('\n');
+ }
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static int __init
+pmac_declare_of_platform_devices(void)
+{
+ struct device_node *np;
+
+ np = find_devices("uni-n");
+ if (np) {
+ for (np = np->child; np != NULL; np = np->sibling)
+ if (strncmp(np->name, "i2c", 3) == 0) {
+ of_platform_device_create(np, "uni-n-i2c");
+ break;
+ }
+ }
+ np = find_devices("u3");
+ if (np) {
+ for (np = np->child; np != NULL; np = np->sibling)
+ if (strncmp(np->name, "i2c", 3) == 0) {
+ of_platform_device_create(np, "u3-i2c");
+ break;
+ }
+ }
+
+ np = find_devices("valkyrie");
+ if (np)
+ of_platform_device_create(np, "valkyrie");
+ np = find_devices("platinum");
+ if (np)
+ of_platform_device_create(np, "platinum");
+
+ return 0;
+}
+
+device_initcall(pmac_declare_of_platform_devices);
diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S
new file mode 100644
index 00000000000..3139b6766ad
--- /dev/null
+++ b/arch/ppc/platforms/pmac_sleep.S
@@ -0,0 +1,390 @@
+/*
+ * This file contains sleep low-level functions for PowerBook G3.
+ * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ * and Paul Mackerras (paulus@samba.org).
+ *
+ * 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/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/offsets.h>
+
+#define MAGIC 0x4c617273 /* 'Lars' */
+
+/*
+ * Structure for storing CPU registers on the stack.
+ */
+#define SL_SP 0
+#define SL_PC 4
+#define SL_MSR 8
+#define SL_SDR1 0xc
+#define SL_SPRG0 0x10 /* 4 sprg's */
+#define SL_DBAT0 0x20
+#define SL_IBAT0 0x28
+#define SL_DBAT1 0x30
+#define SL_IBAT1 0x38
+#define SL_DBAT2 0x40
+#define SL_IBAT2 0x48
+#define SL_DBAT3 0x50
+#define SL_IBAT3 0x58
+#define SL_TB 0x60
+#define SL_R2 0x68
+#define SL_CR 0x6c
+#define SL_R12 0x70 /* r12 to r31 */
+#define SL_SIZE (SL_R12 + 80)
+
+ .section .text
+ .align 5
+
+#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC)
+
+/* This gets called by via-pmu.c late during the sleep process.
+ * The PMU was already send the sleep command and will shut us down
+ * soon. We need to save all that is needed and setup the wakeup
+ * vector that will be called by the ROM on wakeup
+ */
+_GLOBAL(low_sleep_handler)
+#ifndef CONFIG_6xx
+ blr
+#else
+ mflr r0
+ stw r0,4(r1)
+ stwu r1,-SL_SIZE(r1)
+ mfcr r0
+ stw r0,SL_CR(r1)
+ stw r2,SL_R2(r1)
+ stmw r12,SL_R12(r1)
+
+ /* Save MSR & SDR1 */
+ mfmsr r4
+ stw r4,SL_MSR(r1)
+ mfsdr1 r4
+ stw r4,SL_SDR1(r1)
+
+ /* Get a stable timebase and save it */
+1: mftbu r4
+ stw r4,SL_TB(r1)
+ mftb r5
+ stw r5,SL_TB+4(r1)
+ mftbu r3
+ cmpw r3,r4
+ bne 1b
+
+ /* Save SPRGs */
+ mfsprg r4,0
+ stw r4,SL_SPRG0(r1)
+ mfsprg r4,1
+ stw r4,SL_SPRG0+4(r1)
+ mfsprg r4,2
+ stw r4,SL_SPRG0+8(r1)
+ mfsprg r4,3
+ stw r4,SL_SPRG0+12(r1)
+
+ /* Save BATs */
+ mfdbatu r4,0
+ stw r4,SL_DBAT0(r1)
+ mfdbatl r4,0
+ stw r4,SL_DBAT0+4(r1)
+ mfdbatu r4,1
+ stw r4,SL_DBAT1(r1)
+ mfdbatl r4,1
+ stw r4,SL_DBAT1+4(r1)
+ mfdbatu r4,2
+ stw r4,SL_DBAT2(r1)
+ mfdbatl r4,2
+ stw r4,SL_DBAT2+4(r1)
+ mfdbatu r4,3
+ stw r4,SL_DBAT3(r1)
+ mfdbatl r4,3
+ stw r4,SL_DBAT3+4(r1)
+ mfibatu r4,0
+ stw r4,SL_IBAT0(r1)
+ mfibatl r4,0
+ stw r4,SL_IBAT0+4(r1)
+ mfibatu r4,1
+ stw r4,SL_IBAT1(r1)
+ mfibatl r4,1
+ stw r4,SL_IBAT1+4(r1)
+ mfibatu r4,2
+ stw r4,SL_IBAT2(r1)
+ mfibatl r4,2
+ stw r4,SL_IBAT2+4(r1)
+ mfibatu r4,3
+ stw r4,SL_IBAT3(r1)
+ mfibatl r4,3
+ stw r4,SL_IBAT3+4(r1)
+
+ /* Backup various CPU config stuffs */
+ bl __save_cpu_setup
+
+ /* The ROM can wake us up via 2 different vectors:
+ * - On wallstreet & lombard, we must write a magic
+ * value 'Lars' at address 4 and a pointer to a
+ * memory location containing the PC to resume from
+ * at address 0.
+ * - On Core99, we must store the wakeup vector at
+ * address 0x80 and eventually it's parameters
+ * at address 0x84. I've have some trouble with those
+ * parameters however and I no longer use them.
+ */
+ lis r5,grackle_wake_up@ha
+ addi r5,r5,grackle_wake_up@l
+ tophys(r5,r5)
+ stw r5,SL_PC(r1)
+ lis r4,KERNELBASE@h
+ tophys(r5,r1)
+ addi r5,r5,SL_PC
+ lis r6,MAGIC@ha
+ addi r6,r6,MAGIC@l
+ stw r5,0(r4)
+ stw r6,4(r4)
+ /* Setup stuffs at 0x80-0x84 for Core99 */
+ lis r3,core99_wake_up@ha
+ addi r3,r3,core99_wake_up@l
+ tophys(r3,r3)
+ stw r3,0x80(r4)
+ stw r5,0x84(r4)
+ /* Store a pointer to our backup storage into
+ * a kernel global
+ */
+ lis r3,sleep_storage@ha
+ addi r3,r3,sleep_storage@l
+ stw r5,0(r3)
+
+ /* Flush & disable all caches */
+ bl flush_disable_caches
+
+ /* Turn off data relocation. */
+ mfmsr r3 /* Save MSR in r7 */
+ rlwinm r3,r3,0,28,26 /* Turn off DR bit */
+ sync
+ mtmsr r3
+ isync
+
+BEGIN_FTR_SECTION
+ /* Flush any pending L2 data prefetches to work around HW bug */
+ sync
+ lis r3,0xfff0
+ lwz r0,0(r3) /* perform cache-inhibited load to ROM */
+ sync /* (caches are disabled at this point) */
+END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
+
+/*
+ * Set the HID0 and MSR for sleep.
+ */
+ mfspr r2,SPRN_HID0
+ rlwinm r2,r2,0,10,7 /* clear doze, nap */
+ oris r2,r2,HID0_SLEEP@h
+ sync
+ isync
+ mtspr SPRN_HID0,r2
+ sync
+
+/* This loop puts us back to sleep in case we have a spurrious
+ * wakeup so that the host bridge properly stays asleep. The
+ * CPU will be turned off, either after a known time (about 1
+ * second) on wallstreet & lombard, or as soon as the CPU enters
+ * SLEEP mode on core99
+ */
+ mfmsr r2
+ oris r2,r2,MSR_POW@h
+1: sync
+ mtmsr r2
+ isync
+ b 1b
+
+/*
+ * Here is the resume code.
+ */
+
+
+/*
+ * Core99 machines resume here
+ * r4 has the physical address of SL_PC(sp) (unused)
+ */
+_GLOBAL(core99_wake_up)
+ /* Make sure HID0 no longer contains any sleep bit and that data cache
+ * is disabled
+ */
+ mfspr r3,SPRN_HID0
+ rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */
+ rlwinm 3,r3,0,18,15 /* clear DCE, ICE */
+ mtspr SPRN_HID0,r3
+ sync
+ isync
+
+ /* sanitize MSR */
+ mfmsr r3
+ ori r3,r3,MSR_EE|MSR_IP
+ xori r3,r3,MSR_EE|MSR_IP
+ sync
+ isync
+ mtmsr r3
+ sync
+ isync
+
+ /* Recover sleep storage */
+ lis r3,sleep_storage@ha
+ addi r3,r3,sleep_storage@l
+ tophys(r3,r3)
+ lwz r1,0(r3)
+
+ /* Pass thru to older resume code ... */
+/*
+ * Here is the resume code for older machines.
+ * r1 has the physical address of SL_PC(sp).
+ */
+
+grackle_wake_up:
+
+ /* Restore the kernel's segment registers before
+ * we do any r1 memory access as we are not sure they
+ * are in a sane state above the first 256Mb region
+ */
+ li r0,16 /* load up segment register values */
+ mtctr r0 /* for context 0 */
+ lis r3,0x2000 /* Ku = 1, VSID = 0 */
+ li r4,0
+3: mtsrin r3,r4
+ addi r3,r3,0x111 /* increment VSID */
+ addis r4,r4,0x1000 /* address of next segment */
+ bdnz 3b
+ sync
+ isync
+
+ subi r1,r1,SL_PC
+
+ /* Restore various CPU config stuffs */
+ bl __restore_cpu_setup
+
+ /* Invalidate & enable L1 cache, we don't care about
+ * whatever the ROM may have tried to write to memory
+ */
+ bl __inval_enable_L1
+
+ /* Restore the BATs, and SDR1. Then we can turn on the MMU. */
+ lwz r4,SL_SDR1(r1)
+ mtsdr1 r4
+ lwz r4,SL_SPRG0(r1)
+ mtsprg 0,r4
+ lwz r4,SL_SPRG0+4(r1)
+ mtsprg 1,r4
+ lwz r4,SL_SPRG0+8(r1)
+ mtsprg 2,r4
+ lwz r4,SL_SPRG0+12(r1)
+ mtsprg 3,r4
+
+ lwz r4,SL_DBAT0(r1)
+ mtdbatu 0,r4
+ lwz r4,SL_DBAT0+4(r1)
+ mtdbatl 0,r4
+ lwz r4,SL_DBAT1(r1)
+ mtdbatu 1,r4
+ lwz r4,SL_DBAT1+4(r1)
+ mtdbatl 1,r4
+ lwz r4,SL_DBAT2(r1)
+ mtdbatu 2,r4
+ lwz r4,SL_DBAT2+4(r1)
+ mtdbatl 2,r4
+ lwz r4,SL_DBAT3(r1)
+ mtdbatu 3,r4
+ lwz r4,SL_DBAT3+4(r1)
+ mtdbatl 3,r4
+ lwz r4,SL_IBAT0(r1)
+ mtibatu 0,r4
+ lwz r4,SL_IBAT0+4(r1)
+ mtibatl 0,r4
+ lwz r4,SL_IBAT1(r1)
+ mtibatu 1,r4
+ lwz r4,SL_IBAT1+4(r1)
+ mtibatl 1,r4
+ lwz r4,SL_IBAT2(r1)
+ mtibatu 2,r4
+ lwz r4,SL_IBAT2+4(r1)
+ mtibatl 2,r4
+ lwz r4,SL_IBAT3(r1)
+ mtibatu 3,r4
+ lwz r4,SL_IBAT3+4(r1)
+ mtibatl 3,r4
+
+BEGIN_FTR_SECTION
+ li r4,0
+ mtspr SPRN_DBAT4U,r4
+ mtspr SPRN_DBAT4L,r4
+ mtspr SPRN_DBAT5U,r4
+ mtspr SPRN_DBAT5L,r4
+ mtspr SPRN_DBAT6U,r4
+ mtspr SPRN_DBAT6L,r4
+ mtspr SPRN_DBAT7U,r4
+ mtspr SPRN_DBAT7L,r4
+ mtspr SPRN_IBAT4U,r4
+ mtspr SPRN_IBAT4L,r4
+ mtspr SPRN_IBAT5U,r4
+ mtspr SPRN_IBAT5L,r4
+ mtspr SPRN_IBAT6U,r4
+ mtspr SPRN_IBAT6L,r4
+ mtspr SPRN_IBAT7U,r4
+ mtspr SPRN_IBAT7L,r4
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+
+ /* Flush all TLBs */
+ lis r4,0x1000
+1: addic. r4,r4,-0x1000
+ tlbie r4
+ blt 1b
+ sync
+
+ /* restore the MSR and turn on the MMU */
+ lwz r3,SL_MSR(r1)
+ bl turn_on_mmu
+
+ /* get back the stack pointer */
+ tovirt(r1,r1)
+
+ /* Restore TB */
+ li r3,0
+ mttbl r3
+ lwz r3,SL_TB(r1)
+ lwz r4,SL_TB+4(r1)
+ mttbu r3
+ mttbl r4
+
+ /* Restore the callee-saved registers and return */
+ lwz r0,SL_CR(r1)
+ mtcr r0
+ lwz r2,SL_R2(r1)
+ lmw r12,SL_R12(r1)
+ addi r1,r1,SL_SIZE
+ lwz r0,4(r1)
+ mtlr r0
+ blr
+
+turn_on_mmu:
+ mflr r4
+ tovirt(r4,r4)
+ mtsrr0 r4
+ mtsrr1 r3
+ sync
+ isync
+ rfi
+
+#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */
+
+ .section .data
+ .balign L1_CACHE_LINE_SIZE
+sleep_storage:
+ .long 0
+ .balign L1_CACHE_LINE_SIZE, 0
+
+#endif /* CONFIG_6xx */
+ .section .text
diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
new file mode 100644
index 00000000000..2b88745576a
--- /dev/null
+++ b/arch/ppc/platforms/pmac_smp.c
@@ -0,0 +1,640 @@
+/*
+ * SMP support for power macintosh.
+ *
+ * We support both the old "powersurge" SMP architecture
+ * and the current Core99 (G4 PowerMac) machines.
+ *
+ * Note that we don't support the very first rev. of
+ * Apple/DayStar 2 CPUs board, the one with the funky
+ * watchdog. Hopefully, none of these should be there except
+ * maybe internally to Apple. I should probably still add some
+ * code to detect this card though and disable SMP. --BenH.
+ *
+ * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
+ * and Ben Herrenschmidt <benh@kernel.crashing.org>.
+ *
+ * Support for DayStar quad CPU cards
+ * Copyright (C) XLR8, Inc. 1994-2000
+ *
+ * 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/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/residual.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+#include <asm/cacheflush.h>
+#include <asm/keylargo.h>
+
+/*
+ * Powersurge (old powermac SMP) support.
+ */
+
+extern void __secondary_start_psurge(void);
+extern void __secondary_start_psurge2(void); /* Temporary horrible hack */
+extern void __secondary_start_psurge3(void); /* Temporary horrible hack */
+
+/* Addresses for powersurge registers */
+#define HAMMERHEAD_BASE 0xf8000000
+#define HHEAD_CONFIG 0x90
+#define HHEAD_SEC_INTR 0xc0
+
+/* register for interrupting the primary processor on the powersurge */
+/* N.B. this is actually the ethernet ROM! */
+#define PSURGE_PRI_INTR 0xf3019000
+
+/* register for storing the start address for the secondary processor */
+/* N.B. this is the PCI config space address register for the 1st bridge */
+#define PSURGE_START 0xf2800000
+
+/* Daystar/XLR8 4-CPU card */
+#define PSURGE_QUAD_REG_ADDR 0xf8800000
+
+#define PSURGE_QUAD_IRQ_SET 0
+#define PSURGE_QUAD_IRQ_CLR 1
+#define PSURGE_QUAD_IRQ_PRIMARY 2
+#define PSURGE_QUAD_CKSTOP_CTL 3
+#define PSURGE_QUAD_PRIMARY_ARB 4
+#define PSURGE_QUAD_BOARD_ID 6
+#define PSURGE_QUAD_WHICH_CPU 7
+#define PSURGE_QUAD_CKSTOP_RDBK 8
+#define PSURGE_QUAD_RESET_CTL 11
+
+#define PSURGE_QUAD_OUT(r, v) (out_8(quad_base + ((r) << 4) + 4, (v)))
+#define PSURGE_QUAD_IN(r) (in_8(quad_base + ((r) << 4) + 4) & 0x0f)
+#define PSURGE_QUAD_BIS(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
+#define PSURGE_QUAD_BIC(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
+
+/* virtual addresses for the above */
+static volatile u8 *hhead_base;
+static volatile u8 *quad_base;
+static volatile u32 *psurge_pri_intr;
+static volatile u8 *psurge_sec_intr;
+static volatile u32 *psurge_start;
+
+/* values for psurge_type */
+#define PSURGE_NONE -1
+#define PSURGE_DUAL 0
+#define PSURGE_QUAD_OKEE 1
+#define PSURGE_QUAD_COTTON 2
+#define PSURGE_QUAD_ICEGRASS 3
+
+/* what sort of powersurge board we have */
+static int psurge_type = PSURGE_NONE;
+
+/* L2 and L3 cache settings to pass from CPU0 to CPU1 */
+volatile static long int core99_l2_cache;
+volatile static long int core99_l3_cache;
+
+/* Timebase freeze GPIO */
+static unsigned int core99_tb_gpio;
+
+/* Sync flag for HW tb sync */
+static volatile int sec_tb_reset = 0;
+
+static void __init core99_init_caches(int cpu)
+{
+ if (!cpu_has_feature(CPU_FTR_L2CR))
+ return;
+
+ if (cpu == 0) {
+ core99_l2_cache = _get_L2CR();
+ printk("CPU0: L2CR is %lx\n", core99_l2_cache);
+ } else {
+ printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
+ _set_L2CR(0);
+ _set_L2CR(core99_l2_cache);
+ printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
+ }
+
+ if (!cpu_has_feature(CPU_FTR_L3CR))
+ return;
+
+ if (cpu == 0){
+ core99_l3_cache = _get_L3CR();
+ printk("CPU0: L3CR is %lx\n", core99_l3_cache);
+ } else {
+ printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
+ _set_L3CR(0);
+ _set_L3CR(core99_l3_cache);
+ printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
+ }
+}
+
+/*
+ * Set and clear IPIs for powersurge.
+ */
+static inline void psurge_set_ipi(int cpu)
+{
+ if (psurge_type == PSURGE_NONE)
+ return;
+ if (cpu == 0)
+ in_be32(psurge_pri_intr);
+ else if (psurge_type == PSURGE_DUAL)
+ out_8(psurge_sec_intr, 0);
+ else
+ PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
+}
+
+static inline void psurge_clr_ipi(int cpu)
+{
+ if (cpu > 0) {
+ switch(psurge_type) {
+ case PSURGE_DUAL:
+ out_8(psurge_sec_intr, ~0);
+ case PSURGE_NONE:
+ break;
+ default:
+ PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
+ }
+ }
+}
+
+/*
+ * On powersurge (old SMP powermac architecture) we don't have
+ * separate IPIs for separate messages like openpic does. Instead
+ * we have a bitmap for each processor, where a 1 bit means that
+ * the corresponding message is pending for that processor.
+ * Ideally each cpu's entry would be in a different cache line.
+ * -- paulus.
+ */
+static unsigned long psurge_smp_message[NR_CPUS];
+
+void __pmac psurge_smp_message_recv(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+ int msg;
+
+ /* clear interrupt */
+ psurge_clr_ipi(cpu);
+
+ if (num_online_cpus() < 2)
+ return;
+
+ /* make sure there is a message there */
+ for (msg = 0; msg < 4; msg++)
+ if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
+ smp_message_recv(msg, regs);
+}
+
+irqreturn_t __pmac psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
+{
+ psurge_smp_message_recv(regs);
+ return IRQ_HANDLED;
+}
+
+static void __pmac smp_psurge_message_pass(int target, int msg, unsigned long data,
+ int wait)
+{
+ int i;
+
+ if (num_online_cpus() < 2)
+ return;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_online(i))
+ continue;
+ if (target == MSG_ALL
+ || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
+ || target == i) {
+ set_bit(msg, &psurge_smp_message[i]);
+ psurge_set_ipi(i);
+ }
+ }
+}
+
+/*
+ * Determine a quad card presence. We read the board ID register, we
+ * force the data bus to change to something else, and we read it again.
+ * It it's stable, then the register probably exist (ugh !)
+ */
+static int __init psurge_quad_probe(void)
+{
+ int type;
+ unsigned int i;
+
+ type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
+ if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
+ || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+ return PSURGE_DUAL;
+
+ /* looks OK, try a slightly more rigorous test */
+ /* bogus is not necessarily cacheline-aligned,
+ though I don't suppose that really matters. -- paulus */
+ for (i = 0; i < 100; i++) {
+ volatile u32 bogus[8];
+ bogus[(0+i)%8] = 0x00000000;
+ bogus[(1+i)%8] = 0x55555555;
+ bogus[(2+i)%8] = 0xFFFFFFFF;
+ bogus[(3+i)%8] = 0xAAAAAAAA;
+ bogus[(4+i)%8] = 0x33333333;
+ bogus[(5+i)%8] = 0xCCCCCCCC;
+ bogus[(6+i)%8] = 0xCCCCCCCC;
+ bogus[(7+i)%8] = 0x33333333;
+ wmb();
+ asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
+ mb();
+ if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+ return PSURGE_DUAL;
+ }
+ return type;
+}
+
+static void __init psurge_quad_init(void)
+{
+ int procbits;
+
+ if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
+ procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
+ if (psurge_type == PSURGE_QUAD_ICEGRASS)
+ PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+ else
+ PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
+ mdelay(33);
+ out_8(psurge_sec_intr, ~0);
+ PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
+ PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+ if (psurge_type != PSURGE_QUAD_ICEGRASS)
+ PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
+ PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
+ mdelay(33);
+ PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
+ mdelay(33);
+ PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
+ mdelay(33);
+}
+
+static int __init smp_psurge_probe(void)
+{
+ int i, ncpus;
+
+ /* We don't do SMP on the PPC601 -- paulus */
+ if (PVR_VER(mfspr(SPRN_PVR)) == 1)
+ return 1;
+
+ /*
+ * The powersurge cpu board can be used in the generation
+ * of powermacs that have a socket for an upgradeable cpu card,
+ * including the 7500, 8500, 9500, 9600.
+ * The device tree doesn't tell you if you have 2 cpus because
+ * OF doesn't know anything about the 2nd processor.
+ * Instead we look for magic bits in magic registers,
+ * in the hammerhead memory controller in the case of the
+ * dual-cpu powersurge board. -- paulus.
+ */
+ if (find_devices("hammerhead") == NULL)
+ return 1;
+
+ hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
+ quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
+ psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
+
+ psurge_type = psurge_quad_probe();
+ if (psurge_type != PSURGE_DUAL) {
+ psurge_quad_init();
+ /* All released cards using this HW design have 4 CPUs */
+ ncpus = 4;
+ } else {
+ iounmap((void *) quad_base);
+ if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
+ /* not a dual-cpu card */
+ iounmap((void *) hhead_base);
+ psurge_type = PSURGE_NONE;
+ return 1;
+ }
+ ncpus = 2;
+ }
+
+ psurge_start = ioremap(PSURGE_START, 4);
+ psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
+
+ /* this is not actually strictly necessary -- paulus. */
+ for (i = 1; i < ncpus; ++i)
+ smp_hw_index[i] = i;
+
+ if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
+
+ return ncpus;
+}
+
+static void __init smp_psurge_kick_cpu(int nr)
+{
+ void (*start)(void) = __secondary_start_psurge;
+ unsigned long a;
+
+ /* may need to flush here if secondary bats aren't setup */
+ for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+ asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+ asm volatile("sync");
+
+ if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
+
+ /* setup entry point of secondary processor */
+ switch (nr) {
+ case 2:
+ start = __secondary_start_psurge2;
+ break;
+ case 3:
+ start = __secondary_start_psurge3;
+ break;
+ }
+
+ out_be32(psurge_start, __pa(start));
+ mb();
+
+ psurge_set_ipi(nr);
+ udelay(10);
+ psurge_clr_ipi(nr);
+
+ if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
+}
+
+/*
+ * With the dual-cpu powersurge board, the decrementers and timebases
+ * of both cpus are frozen after the secondary cpu is started up,
+ * until we give the secondary cpu another interrupt. This routine
+ * uses this to get the timebases synchronized.
+ * -- paulus.
+ */
+static void __init psurge_dual_sync_tb(int cpu_nr)
+{
+ int t;
+
+ set_dec(tb_ticks_per_jiffy);
+ set_tb(0, 0);
+ last_jiffy_stamp(cpu_nr) = 0;
+
+ if (cpu_nr > 0) {
+ mb();
+ sec_tb_reset = 1;
+ return;
+ }
+
+ /* wait for the secondary to have reset its TB before proceeding */
+ for (t = 10000000; t > 0 && !sec_tb_reset; --t)
+ ;
+
+ /* now interrupt the secondary, starting both TBs */
+ psurge_set_ipi(1);
+
+ smp_tb_synchronized = 1;
+}
+
+static struct irqaction psurge_irqaction = {
+ .handler = psurge_primary_intr,
+ .flags = SA_INTERRUPT,
+ .mask = CPU_MASK_NONE,
+ .name = "primary IPI",
+};
+
+static void __init smp_psurge_setup_cpu(int cpu_nr)
+{
+
+ if (cpu_nr == 0) {
+ /* If we failed to start the second CPU, we should still
+ * send it an IPI to start the timebase & DEC or we might
+ * have them stuck.
+ */
+ if (num_online_cpus() < 2) {
+ if (psurge_type == PSURGE_DUAL)
+ psurge_set_ipi(1);
+ return;
+ }
+ /* reset the entry point so if we get another intr we won't
+ * try to startup again */
+ out_be32(psurge_start, 0x100);
+ if (setup_irq(30, &psurge_irqaction))
+ printk(KERN_ERR "Couldn't get primary IPI interrupt");
+ }
+
+ if (psurge_type == PSURGE_DUAL)
+ psurge_dual_sync_tb(cpu_nr);
+}
+
+void __init smp_psurge_take_timebase(void)
+{
+ /* Dummy implementation */
+}
+
+void __init smp_psurge_give_timebase(void)
+{
+ /* Dummy implementation */
+}
+
+static int __init smp_core99_probe(void)
+{
+#ifdef CONFIG_6xx
+ extern int powersave_nap;
+#endif
+ struct device_node *cpus, *firstcpu;
+ int i, ncpus = 0, boot_cpu = -1;
+ u32 *tbprop;
+
+ if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
+ cpus = firstcpu = find_type_devices("cpu");
+ while(cpus != NULL) {
+ u32 *regprop = (u32 *)get_property(cpus, "reg", NULL);
+ char *stateprop = (char *)get_property(cpus, "state", NULL);
+ if (regprop != NULL && stateprop != NULL &&
+ !strncmp(stateprop, "running", 7))
+ boot_cpu = *regprop;
+ ++ncpus;
+ cpus = cpus->next;
+ }
+ if (boot_cpu == -1)
+ printk(KERN_WARNING "Couldn't detect boot CPU !\n");
+ if (boot_cpu != 0)
+ printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu);
+
+ if (machine_is_compatible("MacRISC4")) {
+ extern struct smp_ops_t core99_smp_ops;
+
+ core99_smp_ops.take_timebase = smp_generic_take_timebase;
+ core99_smp_ops.give_timebase = smp_generic_give_timebase;
+ } else {
+ if (firstcpu != NULL)
+ tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL);
+ if (tbprop)
+ core99_tb_gpio = *tbprop;
+ else
+ core99_tb_gpio = KL_GPIO_TB_ENABLE;
+ }
+
+ if (ncpus > 1) {
+ openpic_request_IPIs();
+ for (i = 1; i < ncpus; ++i)
+ smp_hw_index[i] = i;
+#ifdef CONFIG_6xx
+ powersave_nap = 0;
+#endif
+ core99_init_caches(0);
+ }
+
+ return ncpus;
+}
+
+static void __init smp_core99_kick_cpu(int nr)
+{
+ unsigned long save_vector, new_vector;
+ unsigned long flags;
+
+ volatile unsigned long *vector
+ = ((volatile unsigned long *)(KERNELBASE+0x100));
+ if (nr < 1 || nr > 3)
+ return;
+ if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
+
+ local_irq_save(flags);
+ local_irq_disable();
+
+ /* Save reset vector */
+ save_vector = *vector;
+
+ /* Setup fake reset vector that does
+ * b __secondary_start_psurge - KERNELBASE
+ */
+ switch(nr) {
+ case 1:
+ new_vector = (unsigned long)__secondary_start_psurge;
+ break;
+ case 2:
+ new_vector = (unsigned long)__secondary_start_psurge2;
+ break;
+ case 3:
+ new_vector = (unsigned long)__secondary_start_psurge3;
+ break;
+ }
+ *vector = 0x48000002 + new_vector - KERNELBASE;
+
+ /* flush data cache and inval instruction cache */
+ flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+ /* Put some life in our friend */
+ pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
+
+ /* FIXME: We wait a bit for the CPU to take the exception, I should
+ * instead wait for the entry code to set something for me. Well,
+ * ideally, all that crap will be done in prom.c and the CPU left
+ * in a RAM-based wait loop like CHRP.
+ */
+ mdelay(1);
+
+ /* Restore our exception vector */
+ *vector = save_vector;
+ flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+ local_irq_restore(flags);
+ if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
+}
+
+static void __init smp_core99_setup_cpu(int cpu_nr)
+{
+ /* Setup L2/L3 */
+ if (cpu_nr != 0)
+ core99_init_caches(cpu_nr);
+
+ /* Setup openpic */
+ do_openpic_setup_cpu();
+
+ if (cpu_nr == 0) {
+#ifdef CONFIG_POWER4
+ extern void g5_phy_disable_cpu1(void);
+
+ /* If we didn't start the second CPU, we must take
+ * it off the bus
+ */
+ if (machine_is_compatible("MacRISC4") &&
+ num_online_cpus() < 2)
+ g5_phy_disable_cpu1();
+#endif /* CONFIG_POWER4 */
+ if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+ }
+}
+
+void __init smp_core99_take_timebase(void)
+{
+ /* Secondary processor "takes" the timebase by freezing
+ * it, resetting its local TB and telling CPU 0 to go on
+ */
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+ pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+ mb();
+
+ set_dec(tb_ticks_per_jiffy);
+ set_tb(0, 0);
+ last_jiffy_stamp(smp_processor_id()) = 0;
+
+ mb();
+ sec_tb_reset = 1;
+}
+
+void __init smp_core99_give_timebase(void)
+{
+ unsigned int t;
+
+ /* Primary processor waits for secondary to have frozen
+ * the timebase, resets local TB, and kick timebase again
+ */
+ /* wait for the secondary to have reset its TB before proceeding */
+ for (t = 1000; t > 0 && !sec_tb_reset; --t)
+ udelay(1000);
+ if (t == 0)
+ printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
+
+ set_dec(tb_ticks_per_jiffy);
+ set_tb(0, 0);
+ last_jiffy_stamp(smp_processor_id()) = 0;
+ mb();
+
+ /* Now, restart the timebase by leaving the GPIO to an open collector */
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
+ pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+
+ smp_tb_synchronized = 1;
+}
+
+
+/* PowerSurge-style Macs */
+struct smp_ops_t psurge_smp_ops __pmacdata = {
+ .message_pass = smp_psurge_message_pass,
+ .probe = smp_psurge_probe,
+ .kick_cpu = smp_psurge_kick_cpu,
+ .setup_cpu = smp_psurge_setup_cpu,
+ .give_timebase = smp_psurge_give_timebase,
+ .take_timebase = smp_psurge_take_timebase,
+};
+
+/* Core99 Macs (dual G4s) */
+struct smp_ops_t core99_smp_ops __pmacdata = {
+ .message_pass = smp_openpic_message_pass,
+ .probe = smp_core99_probe,
+ .kick_cpu = smp_core99_kick_cpu,
+ .setup_cpu = smp_core99_setup_cpu,
+ .give_timebase = smp_core99_give_timebase,
+ .take_timebase = smp_core99_take_timebase,
+};
diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c
new file mode 100644
index 00000000000..09636546f44
--- /dev/null
+++ b/arch/ppc/platforms/pmac_time.c
@@ -0,0 +1,292 @@
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * We use the decrementer register for our periodic interrupts.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/hardirq.h>
+
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/nvram.h>
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET 2082844800
+
+/*
+ * Calibrate the decrementer frequency with the VIA timer 1.
+ */
+#define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */
+
+/* VIA registers */
+#define RS 0x200 /* skip between registers */
+#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
+#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
+#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
+#define ACR (11*RS) /* Auxiliary control register */
+#define IFR (13*RS) /* Interrupt flag register */
+
+/* Bits in ACR */
+#define T1MODE 0xc0 /* Timer 1 mode */
+#define T1MODE_CONT 0x40 /* continuous interrupts */
+
+/* Bits in IFR and IER */
+#define T1_INT 0x40 /* Timer 1 interrupt */
+
+extern struct timezone sys_tz;
+
+long __init
+pmac_time_init(void)
+{
+#ifdef CONFIG_NVRAM
+ s32 delta = 0;
+ int dst;
+
+ delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
+ delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
+ delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
+ if (delta & 0x00800000UL)
+ delta |= 0xFF000000UL;
+ dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
+ printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
+ dst ? "on" : "off");
+ return delta;
+#else
+ return 0;
+#endif
+}
+
+unsigned long __pmac
+pmac_get_rtc_time(void)
+{
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
+ struct adb_request req;
+ unsigned long now;
+#endif
+
+ /* Get the time from the RTC */
+ switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+ case SYS_CTRLER_CUDA:
+ if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
+ return 0;
+ while (!req.complete)
+ cuda_poll();
+ if (req.reply_len != 7)
+ printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ now = (req.reply[3] << 24) + (req.reply[4] << 16)
+ + (req.reply[5] << 8) + req.reply[6];
+ return now - RTC_OFFSET;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+ case SYS_CTRLER_PMU:
+ if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+ return 0;
+ while (!req.complete)
+ pmu_poll();
+ if (req.reply_len != 4)
+ printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ now = (req.reply[0] << 24) + (req.reply[1] << 16)
+ + (req.reply[2] << 8) + req.reply[3];
+ return now - RTC_OFFSET;
+#endif /* CONFIG_ADB_PMU */
+ default: ;
+ }
+ return 0;
+}
+
+int __pmac
+pmac_set_rtc_time(unsigned long nowtime)
+{
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
+ struct adb_request req;
+#endif
+
+ nowtime += RTC_OFFSET;
+
+ switch (sys_ctrler) {
+#ifdef CONFIG_ADB_CUDA
+ case SYS_CTRLER_CUDA:
+ if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+ nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+ return 0;
+ while (!req.complete)
+ cuda_poll();
+ if ((req.reply_len != 3) && (req.reply_len != 7))
+ printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return 1;
+#endif /* CONFIG_ADB_CUDA */
+#ifdef CONFIG_ADB_PMU
+ case SYS_CTRLER_PMU:
+ if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+ nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+ return 0;
+ while (!req.complete)
+ pmu_poll();
+ if (req.reply_len != 0)
+ printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return 1;
+#endif /* CONFIG_ADB_PMU */
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Calibrate the decrementer register using VIA timer 1.
+ * This is used both on powermacs and CHRP machines.
+ */
+int __init
+via_calibrate_decr(void)
+{
+ struct device_node *vias;
+ volatile unsigned char *via;
+ int count = VIA_TIMER_FREQ_6 / 100;
+ unsigned int dstart, dend;
+
+ vias = find_devices("via-cuda");
+ if (vias == 0)
+ vias = find_devices("via-pmu");
+ if (vias == 0)
+ vias = find_devices("via");
+ if (vias == 0 || vias->n_addrs == 0)
+ return 0;
+ via = (volatile unsigned char *)
+ ioremap(vias->addrs[0].address, vias->addrs[0].size);
+
+ /* set timer 1 for continuous interrupts */
+ out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
+ /* set the counter to a small value */
+ out_8(&via[T1CH], 2);
+ /* set the latch to `count' */
+ out_8(&via[T1LL], count);
+ out_8(&via[T1LH], count >> 8);
+ /* wait until it hits 0 */
+ while ((in_8(&via[IFR]) & T1_INT) == 0)
+ ;
+ dstart = get_dec();
+ /* clear the interrupt & wait until it hits 0 again */
+ in_8(&via[T1CL]);
+ while ((in_8(&via[IFR]) & T1_INT) == 0)
+ ;
+ dend = get_dec();
+
+ tb_ticks_per_jiffy = (dstart - dend) / (6 * (HZ/100));
+ tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
+
+ printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
+ tb_ticks_per_jiffy, dstart - dend);
+
+ iounmap((void*)via);
+
+ return 1;
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Reset the time after a sleep.
+ */
+static int __pmac
+time_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+ static unsigned long time_diff;
+ unsigned long flags;
+ unsigned long seq;
+
+ switch (when) {
+ case PBOOK_SLEEP_NOW:
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ time_diff = xtime.tv_sec - pmac_get_rtc_time();
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+ break;
+ case PBOOK_WAKE:
+ write_seqlock_irqsave(&xtime_lock, flags);
+ xtime.tv_sec = pmac_get_rtc_time() + time_diff;
+ xtime.tv_nsec = 0;
+ last_rtc_update = xtime.tv_sec;
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+ break;
+ }
+ return PBOOK_SLEEP_OK;
+}
+
+static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
+ time_sleep_notify, SLEEP_LEVEL_MISC,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+/*
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
+ */
+void __init
+pmac_calibrate_decr(void)
+{
+ struct device_node *cpu;
+ unsigned int freq, *fp;
+
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_register_sleep_notifier(&time_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+ /* We assume MacRISC2 machines have correct device-tree
+ * calibration. That's better since the VIA itself seems
+ * to be slightly off. --BenH
+ */
+ if (!machine_is_compatible("MacRISC2") &&
+ !machine_is_compatible("MacRISC3") &&
+ !machine_is_compatible("MacRISC4"))
+ if (via_calibrate_decr())
+ return;
+
+ /* Special case: QuickSilver G4s seem to have a badly calibrated
+ * timebase-frequency in OF, VIA is much better on these. We should
+ * probably implement calibration based on the KL timer on these
+ * machines anyway... -BenH
+ */
+ if (machine_is_compatible("PowerMac3,5"))
+ if (via_calibrate_decr())
+ return;
+ /*
+ * The cpu node should have a timebase-frequency property
+ * to tell us the rate at which the decrementer counts.
+ */
+ cpu = find_type_devices("cpu");
+ if (cpu == 0)
+ panic("can't find cpu node in time_init");
+ fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
+ if (fp == 0)
+ panic("can't get cpu timebase frequency");
+ freq = *fp;
+ printk("time_init: decrementer frequency = %u.%.6u MHz\n",
+ freq/1000000, freq%1000000);
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
diff --git a/arch/ppc/platforms/powerpmc250.c b/arch/ppc/platforms/powerpmc250.c
new file mode 100644
index 00000000000..0abe15159e6
--- /dev/null
+++ b/arch/ppc/platforms/powerpmc250.c
@@ -0,0 +1,383 @@
+/*
+ * arch/ppc/platforms/powerpmc250.c
+ *
+ * Board setup routines for Force PowerPMC-250 Processor PMC
+ *
+ * Author: Troy Benjegerdes <tbenjegerdes@mvista.com>
+ * Borrowed heavily from prpmc750_*.c by
+ * Matt Porter <mporter@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.
+ */
+
+#include <linux/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/ide.h>
+#include <linux/root_dev.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <platforms/powerpmc250.h>
+#include <asm/open_pic.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc10x.h>
+#include <asm/uaccess.h>
+#include <asm/bootinfo.h>
+
+extern void powerpmc250_find_bridges(void);
+extern unsigned long loops_per_jiffy;
+
+static u_char powerpmc250_openpic_initsenses[] __initdata =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, /* PMC INTA (also MPC107 output interrupt INTA) */
+ 1, /* PMC INTB (also I82559 Ethernet controller) */
+ 1, /* PMC INTC */
+ 1, /* PMC INTD */
+ 0, /* DUART interrupt (active high) */
+};
+
+static int
+powerpmc250_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m,"machine\t\t: Force PowerPMC250\n");
+
+ return 0;
+}
+
+static void __init
+powerpmc250_setup_arch(void)
+{
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000/HZ;
+
+ /* Lookup PCI host bridges */
+ powerpmc250_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ printk("Force PowerPMC250 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n");
+}
+
+#if 0
+/*
+ * Compute the PrPMC750's bus speed using the baud clock as a
+ * reference.
+ */
+unsigned long __init powerpmc250_get_bus_speed(void)
+{
+ unsigned long tbl_start, tbl_end;
+ unsigned long current_state, old_state, bus_speed;
+ unsigned char lcr, dll, dlm;
+ int baud_divisor, count;
+
+ /* Read the UART's baud clock divisor */
+ lcr = readb(PRPMC750_SERIAL_0_LCR);
+ writeb(lcr | UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR);
+ dll = readb(PRPMC750_SERIAL_0_DLL);
+ dlm = readb(PRPMC750_SERIAL_0_DLM);
+ writeb(lcr & ~UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR);
+ baud_divisor = (dlm << 8) | dll;
+
+ /*
+ * Use the baud clock divisor and base baud clock
+ * to determine the baud rate and use that as
+ * the number of baud clock edges we use for
+ * the time base sample. Make it half the baud
+ * rate.
+ */
+ count = PRPMC750_BASE_BAUD / (baud_divisor * 16);
+
+ /* Find the first edge of the baud clock */
+ old_state = readb(PRPMC750_STATUS_REG) & PRPMC750_BAUDOUT_MASK;
+ do {
+ current_state = readb(PRPMC750_STATUS_REG) &
+ PRPMC750_BAUDOUT_MASK;
+ } while(old_state == current_state);
+
+ old_state = current_state;
+
+ /* Get the starting time base value */
+ tbl_start = get_tbl();
+
+ /*
+ * Loop until we have found a number of edges equal
+ * to half the count (half the baud rate)
+ */
+ do {
+ do {
+ current_state = readb(PRPMC750_STATUS_REG) &
+ PRPMC750_BAUDOUT_MASK;
+ } while(old_state == current_state);
+ old_state = current_state;
+ } while (--count);
+
+ /* Get the ending time base value */
+ tbl_end = get_tbl();
+
+ /* Compute bus speed */
+ bus_speed = (tbl_end-tbl_start)*128;
+
+ return bus_speed;
+}
+#endif
+
+static void __init
+powerpmc250_calibrate_decr(void)
+{
+ unsigned long freq;
+ int divisor = 4;
+
+ //freq = powerpmc250_get_bus_speed();
+#warning hardcoded bus freq
+ freq = 100000000;
+
+ tb_ticks_per_jiffy = freq / (HZ * divisor);
+ tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+}
+
+static void
+powerpmc250_restart(char *cmd)
+{
+ local_irq_disable();
+ /* Hard reset */
+ writeb(0x11, 0xfe000332);
+ while(1);
+}
+
+static void
+powerpmc250_halt(void)
+{
+ local_irq_disable();
+ while (1);
+}
+
+static void
+powerpmc250_power_off(void)
+{
+ powerpmc250_halt();
+}
+
+static void __init
+powerpmc250_init_IRQ(void)
+{
+
+ OpenPIC_InitSenses = powerpmc250_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(powerpmc250_openpic_initsenses);
+ mpc10x_set_openpic();
+}
+
+/*
+ * Set BAT 3 to map 0xf0000000 to end of physical memory space.
+ */
+static __inline__ void
+powerpmc250_set_bat(void)
+{
+ unsigned long bat3u, bat3l;
+ static int mapping_set = 0;
+
+ if (!mapping_set)
+ {
+ __asm__ __volatile__(
+ " lis %0,0xf000\n \
+ ori %1,%0,0x002a\n \
+ ori %0,%0,0x1ffe\n \
+ mtspr 0x21e,%0\n \
+ mtspr 0x21f,%1\n \
+ isync\n \
+ sync "
+ : "=r" (bat3u), "=r" (bat3l));
+
+ mapping_set = 1;
+ }
+ return;
+}
+
+static unsigned long __init
+powerpmc250_find_end_of_memory(void)
+{
+ /* Cover I/O space with a BAT */
+ /* yuck, better hope your ram size is a power of 2 -- paulus */
+ powerpmc250_set_bat();
+
+ return mpc10x_get_mem_size(MPC10X_MEM_MAP_B);
+}
+
+static void __init
+powerpmc250_map_io(void)
+{
+ io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif
+
+ /* Copy cmd_line parameters */
+ if ( r6)
+ {
+ *(char *)(r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6 + KERNELBASE));
+ }
+
+ isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
+ isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
+ pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET;
+
+ ppc_md.setup_arch = powerpmc250_setup_arch;
+ ppc_md.show_cpuinfo = powerpmc250_show_cpuinfo;
+ ppc_md.init_IRQ = powerpmc250_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.find_end_of_memory = powerpmc250_find_end_of_memory;
+ ppc_md.setup_io_mappings = powerpmc250_map_io;
+
+ ppc_md.restart = powerpmc250_restart;
+ ppc_md.power_off = powerpmc250_power_off;
+ ppc_md.halt = powerpmc250_halt;
+
+ /* PowerPMC250 has no timekeeper part */
+ ppc_md.time_init = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.calibrate_decr = powerpmc250_calibrate_decr;
+}
+
+
+/*
+ * (This used to be arch/ppc/platforms/powerpmc250_pci.c)
+ *
+ * PCI support for Force PowerPMC250
+ *
+ */
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG */
+
+static inline int __init
+powerpmc250_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {17, 0, 0, 0}, /* Device 11 - 82559 */
+ {0, 0, 0, 0}, /* 12 */
+ {0, 0, 0, 0}, /* 13 */
+ {0, 0, 0, 0}, /* 14 */
+ {0, 0, 0, 0}, /* 15 */
+ {16, 17, 18, 19}, /* Device 16 - PMC A1?? */
+ };
+ const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+};
+
+static int
+powerpmc250_exclude_device(u_char bus, u_char devfn)
+{
+ /*
+ * While doing PCI Scan the MPC107 will 'detect' itself as
+ * device on the PCI Bus, will create an incorrect response and
+ * later will respond incorrectly to Configuration read coming
+ * from another device.
+ *
+ * The work around is that when doing a PCI Scan one
+ * should skip its own device number in the scan.
+ *
+ * The top IDsel is AD13 and the middle is AD14.
+ *
+ * -- Note from force
+ */
+
+ if ((bus == 0) && (PCI_SLOT(devfn) == 13 || PCI_SLOT(devfn) == 14)) {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ else {
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+void __init
+powerpmc250_find_bridges(void)
+{
+ struct pci_controller* hose;
+
+ hose = pcibios_alloc_controller();
+ if (!hose){
+ printk("Can't allocate PCI 'hose' structure!!!\n");
+ return;
+ }
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ if (mpc10x_bridge_init(hose,
+ MPC10X_MEM_MAP_B,
+ MPC10X_MEM_MAP_B,
+ MPC10X_MAPB_EUMB_BASE) == 0) {
+
+ hose->mem_resources[0].end = 0xffffffff;
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ /* ppc_md.pcibios_fixup = pcore_pcibios_fixup; */
+ ppc_md.pci_swizzle = common_swizzle;
+
+ ppc_md.pci_exclude_device = powerpmc250_exclude_device;
+ ppc_md.pci_map_irq = powerpmc250_map_irq;
+ } else {
+ if (ppc_md.progress)
+ ppc_md.progress("Bridge init failed", 0x100);
+ printk("Host bridge init failed\n");
+ }
+
+}
diff --git a/arch/ppc/platforms/powerpmc250.h b/arch/ppc/platforms/powerpmc250.h
new file mode 100644
index 00000000000..41a6dc88191
--- /dev/null
+++ b/arch/ppc/platforms/powerpmc250.h
@@ -0,0 +1,52 @@
+/*
+ * include/asm-ppc/platforms/powerpmc250.h
+ *
+ * Definitions for Force PowerPMC-250 board support
+ *
+ * Author: Troy Benjegerdes <tbenjegerdes@mvista.com>
+ *
+ * Borrowed heavily from prpmc750.h by Matt Porter <mporter@mvista.com>
+ *
+ * 2001-2004 (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 __ASMPPC_POWERPMC250_H
+#define __ASMPPC_POWERPMC250_H
+
+#define POWERPMC250_PCI_CONFIG_ADDR 0x80000cf8
+#define POWERPMC250_PCI_CONFIG_DATA 0x80000cfc
+
+#define POWERPMC250_PCI_PHY_MEM_BASE 0xc0000000
+#define POWERPMC250_PCI_MEM_BASE 0xf0000000
+#define POWERPMC250_PCI_IO_BASE 0x80000000
+
+#define POWERPMC250_ISA_IO_BASE POWERPMC250_PCI_IO_BASE
+#define POWERPMC250_ISA_MEM_BASE POWERPMC250_PCI_MEM_BASE
+#define POWERPMC250_PCI_MEM_OFFSET POWERPMC250_PCI_PHY_MEM_BASE
+
+#define POWERPMC250_SYS_MEM_BASE 0x80000000
+
+#define POWERPMC250_HAWK_SMC_BASE 0xfef80000
+
+#define POWERPMC250_BASE_BAUD 12288000
+#define POWERPMC250_SERIAL 0xff000000
+#define POWERPMC250_SERIAL_IRQ 20
+
+/* UART Defines. */
+#define RS_TABLE_SIZE 1
+
+#define BASE_BAUD (POWERPMC250_BASE_BAUD / 16)
+
+#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
+
+#define SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, POWERPMC250_SERIAL, POWERPMC250_SERIAL_IRQ, \
+ STD_COM_FLAGS, /* ttyS0 */ \
+ iomem_base: (u8 *)POWERPMC250_SERIAL, \
+ iomem_reg_shift: 0, \
+ io_type: SERIAL_IO_MEM }
+
+#endif /* __ASMPPC_POWERPMC250_H */
diff --git a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c
new file mode 100644
index 00000000000..65705c91179
--- /dev/null
+++ b/arch/ppc/platforms/pplus.c
@@ -0,0 +1,917 @@
+/*
+ * arch/ppc/platforms/pplus.c
+ *
+ * Board and PCI setup routines for MCG PowerPlus
+ *
+ * Author: Randy Vinson <rvinson@mvista.com>
+ *
+ * Derived from original PowerPlus PReP work by
+ * Cort Dougan, Johnnie Peters, Matt Porter, and
+ * Troy Benjegerdes.
+ *
+ * 2001-2004 (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/config.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+#include <asm/vga.h>
+#include <asm/i8259.h>
+#include <asm/open_pic.h>
+#include <asm/hawk.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/kgdb.h>
+#include <asm/reg.h>
+
+#include "pplus.h"
+
+#undef DUMP_DBATS
+
+TODC_ALLOC();
+
+extern void pplus_setup_hose(void);
+extern void pplus_set_VIA_IDE_native(void);
+
+extern unsigned long loops_per_jiffy;
+unsigned char *Motherboard_map_name;
+
+/* Tables for known hardware */
+
+/* Motorola Mesquite */
+static inline int
+mesquite_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+ * Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {18, 0, 0, 0}, /* IDSEL 14 - Enet 0 */
+ { 0, 0, 0, 0}, /* IDSEL 15 - unused */
+ {19, 19, 19, 19}, /* IDSEL 16 - PMC Slot 1 */
+ { 0, 0, 0, 0}, /* IDSEL 17 - unused */
+ { 0, 0, 0, 0}, /* IDSEL 18 - unused */
+ { 0, 0, 0, 0}, /* IDSEL 19 - unused */
+ {24, 25, 26, 27}, /* IDSEL 20 - P2P bridge (to cPCI 1) */
+ { 0, 0, 0, 0}, /* IDSEL 21 - unused */
+ {28, 29, 30, 31} /* IDSEL 22 - P2P bridge (to cPCI 2) */
+ };
+
+ const long min_idsel = 14, max_idsel = 22, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+/* Motorola Sitka */
+static inline int
+sitka_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+ * Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {18, 0, 0, 0}, /* IDSEL 14 - Enet 0 */
+ { 0, 0, 0, 0}, /* IDSEL 15 - unused */
+ {25, 26, 27, 28}, /* IDSEL 16 - PMC Slot 1 */
+ {28, 25, 26, 27}, /* IDSEL 17 - PMC Slot 2 */
+ { 0, 0, 0, 0}, /* IDSEL 18 - unused */
+ { 0, 0, 0, 0}, /* IDSEL 19 - unused */
+ {20, 0, 0, 0} /* IDSEL 20 - P2P bridge (to cPCI) */
+ };
+
+ const long min_idsel = 14, max_idsel = 20, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+/* Motorola MTX */
+static inline int
+MTX_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+ * Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {19, 0, 0, 0}, /* IDSEL 12 - SCSI */
+ { 0, 0, 0, 0}, /* IDSEL 13 - unused */
+ {18, 0, 0, 0}, /* IDSEL 14 - Enet */
+ { 0, 0, 0, 0}, /* IDSEL 15 - unused */
+ {25, 26, 27, 28}, /* IDSEL 16 - PMC Slot 1 */
+ {26, 27, 28, 25}, /* IDSEL 17 - PMC Slot 2 */
+ {27, 28, 25, 26} /* IDSEL 18 - PCI Slot 3 */
+ };
+
+ const long min_idsel = 12, max_idsel = 18, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+/* Motorola MTX Plus */
+/* Secondary bus interrupt routing is not supported yet */
+static inline int
+MTXplus_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+ * Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {19, 0, 0, 0}, /* IDSEL 12 - SCSI */
+ { 0, 0, 0, 0}, /* IDSEL 13 - unused */
+ {18, 0, 0, 0}, /* IDSEL 14 - Enet 1 */
+ { 0, 0, 0, 0}, /* IDSEL 15 - unused */
+ {25, 26, 27, 28}, /* IDSEL 16 - PCI Slot 1P */
+ {26, 27, 28, 25}, /* IDSEL 17 - PCI Slot 2P */
+ {27, 28, 25, 26}, /* IDSEL 18 - PCI Slot 3P */
+ {26, 0, 0, 0}, /* IDSEL 19 - Enet 2 */
+ { 0, 0, 0, 0} /* IDSEL 20 - P2P Bridge */
+ };
+
+ const long min_idsel = 12, max_idsel = 20, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static inline int
+Genesis2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ /* 2600
+ * Raven 31
+ * ISA 11
+ * SCSI 12 - IRQ3
+ * Univ 13
+ * eth 14 - IRQ2
+ * VGA 15 - IRQ4
+ * PMC1 16 - IRQ9,10,11,12 = PMC1 A-D
+ * PMC2 17 - IRQ12,9,10,11 = A-D
+ * SCSI2 18 - IRQ11
+ * eth2 19 - IRQ10
+ * PCIX 20 - IRQ9,10,11,12 = PCI A-D
+ */
+
+ /* 2400
+ * Hawk 31
+ * ISA 11
+ * Univ 13
+ * eth 14 - IRQ2
+ * PMC1 16 - IRQ9,10,11,12 = PMC A-D
+ * PMC2 17 - IRQ12,9,10,11 = PMC A-D
+ * PCIX 20 - IRQ9,10,11,12 = PMC A-D
+ */
+
+ /* 2300
+ * Raven 31
+ * ISA 11
+ * Univ 13
+ * eth 14 - IRQ2
+ * PMC1 16 - 9,10,11,12 = A-D
+ * PMC2 17 - 9,10,11,12 = B,C,D,A
+ */
+
+ static char pci_irq_table[][4] =
+ /*
+ * MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+ * Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {19, 0, 0, 0}, /* IDSEL 12 - SCSI */
+ { 0, 0, 0, 0}, /* IDSEL 13 - Universe PCI - VME */
+ {18, 0, 0, 0}, /* IDSEL 14 - Enet 1 */
+ { 0, 0, 0, 0}, /* IDSEL 15 - unused */
+ {25, 26, 27, 28}, /* IDSEL 16 - PCI/PMC Slot 1P */
+ {28, 25, 26, 27}, /* IDSEL 17 - PCI/PMC Slot 2P */
+ {27, 28, 25, 26}, /* IDSEL 18 - PCI Slot 3P */
+ {26, 0, 0, 0}, /* IDSEL 19 - Enet 2 */
+ {25, 26, 27, 28} /* IDSEL 20 - P2P Bridge */
+ };
+
+ const long min_idsel = 12, max_idsel = 20, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+#define MOTOROLA_CPUTYPE_REG 0x800
+#define MOTOROLA_BASETYPE_REG 0x803
+#define MPIC_RAVEN_ID 0x48010000
+#define MPIC_HAWK_ID 0x48030000
+#define MOT_PROC2_BIT 0x800
+
+static u_char pplus_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_SIO */
+ (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE),/*MVME2600_INT_FALCN_ECC_ERR */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/*MVME2600_INT_PCI_ETHERNET */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/*MVME2600_INT_PCI_GRAPHICS */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTA */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTB */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTC */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTD */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),
+};
+
+int mot_entry = -1;
+int prep_keybd_present = 1;
+int mot_multi = 0;
+
+struct brd_info {
+ /* 0x100 mask assumes for Raven and Hawk boards that the level/edge
+ * are set */
+ int cpu_type;
+ /* 0x200 if this board has a Hawk chip. */
+ int base_type;
+ /* or'ed with 0x80 if this board should be checked for multi CPU */
+ int max_cpu;
+ const char *name;
+ int (*map_irq) (struct pci_dev *, unsigned char, unsigned char);
+};
+struct brd_info mot_info[] = {
+ {0x300, 0x00, 0x00, "MVME 2400", Genesis2_map_irq},
+ {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", mesquite_map_irq},
+ {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", sitka_map_irq},
+ {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", mesquite_map_irq},
+ {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_map_irq},
+ {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_map_irq},
+ {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_map_irq},
+ {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_map_irq},
+ {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_map_irq},
+ {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_map_irq},
+ {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_map_irq},
+ {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_map_irq},
+ {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_map_irq},
+ {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_map_irq},
+ {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_map_irq},
+ {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_map_irq},
+ {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_map_irq},
+ {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_map_irq},
+ {0x000, 0x00, 0x00, "", NULL}
+};
+
+void __init pplus_set_board_type(void)
+{
+ unsigned char cpu_type;
+ unsigned char base_mod;
+ int entry;
+ unsigned short devid;
+ unsigned long *ProcInfo = NULL;
+
+ cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
+ base_mod = inb(MOTOROLA_BASETYPE_REG);
+ early_read_config_word(0, 0, 0, PCI_VENDOR_ID, &devid);
+
+ for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
+ /* Check for Hawk chip */
+ if (mot_info[entry].cpu_type & 0x200) {
+ if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK)
+ continue;
+ } else {
+ /* store the system config register for later use. */
+ ProcInfo =
+ (unsigned long *)ioremap(PPLUS_SYS_CONFIG_REG, 4);
+
+ /* Check non hawk boards */
+ if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
+ continue;
+
+ if (mot_info[entry].base_type == 0) {
+ mot_entry = entry;
+ break;
+ }
+
+ if (mot_info[entry].base_type != base_mod)
+ continue;
+ }
+
+ if (!(mot_info[entry].max_cpu & 0x80)) {
+ mot_entry = entry;
+ break;
+ }
+
+ /* processor 1 not present and max processor zero indicated */
+ if ((*ProcInfo & MOT_PROC2_BIT)
+ && !(mot_info[entry].max_cpu & 0x7f)) {
+ mot_entry = entry;
+ break;
+ }
+
+ /* processor 1 present and max processor zero indicated */
+ if (!(*ProcInfo & MOT_PROC2_BIT)
+ && (mot_info[entry].max_cpu & 0x7f)) {
+ mot_entry = entry;
+ break;
+ }
+
+ /* Indicate to system if this is a multiprocessor board */
+ if (!(*ProcInfo & MOT_PROC2_BIT))
+ mot_multi = 1;
+ }
+
+ if (mot_entry == -1)
+ /* No particular cpu type found - assume Mesquite (MCP750) */
+ mot_entry = 1;
+
+ Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
+ ppc_md.pci_map_irq = mot_info[mot_entry].map_irq;
+}
+void __init pplus_pib_init(void)
+{
+ unsigned char reg;
+ unsigned short short_reg;
+
+ struct pci_dev *dev = NULL;
+
+ /*
+ * Perform specific configuration for the Via Tech or
+ * or Winbond PCI-ISA-Bridge part.
+ */
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C586_1, dev))) {
+ /*
+ * PPCBUG does not set the enable bits
+ * for the IDE device. Force them on here.
+ */
+ pci_read_config_byte(dev, 0x40, &reg);
+
+ reg |= 0x03; /* IDE: Chip Enable Bits */
+ pci_write_config_byte(dev, 0x40, reg);
+ }
+
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C586_2,
+ dev)) && (dev->devfn = 0x5a)) {
+ /* Force correct USB interrupt */
+ dev->irq = 11;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ }
+
+ if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_83C553, dev))) {
+ /* Clear PCI Interrupt Routing Control Register. */
+ short_reg = 0x0000;
+ pci_write_config_word(dev, 0x44, short_reg);
+ /* Route IDE interrupts to IRQ 14 */
+ reg = 0xEE;
+ pci_write_config_byte(dev, 0x43, reg);
+ }
+
+ if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_82C105, dev))) {
+ /*
+ * Disable LEGIRQ mode so PCI INTS are routed
+ * directly to the 8259 and enable both channels
+ */
+ pci_write_config_dword(dev, 0x40, 0x10ff0033);
+
+ /* Force correct IDE interrupt */
+ dev->irq = 14;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ }
+ pci_dev_put(dev);
+}
+
+void __init pplus_set_VIA_IDE_legacy(void)
+{
+ unsigned short vend, dev;
+
+ early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
+ early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
+
+ if ((vend == PCI_VENDOR_ID_VIA) &&
+ (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
+ unsigned char temp;
+
+ /* put back original "standard" port base addresses */
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_0, 0x1f1);
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_1, 0x3f5);
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_2, 0x171);
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_3, 0x375);
+ early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+ PCI_BASE_ADDRESS_4, 0xcc01);
+
+ /* put into legacy mode */
+ early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+ &temp);
+ temp &= ~0x05;
+ early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+ temp);
+ }
+}
+
+void pplus_set_VIA_IDE_native(void)
+{
+ unsigned short vend, dev;
+
+ early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
+ early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
+
+ if ((vend == PCI_VENDOR_ID_VIA) &&
+ (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
+ unsigned char temp;
+
+ /* put into native mode */
+ early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+ &temp);
+ temp |= 0x05;
+ early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+ temp);
+ }
+}
+
+void __init pplus_pcibios_fixup(void)
+{
+
+ unsigned char reg;
+ unsigned short devid;
+ unsigned char base_mod;
+
+ printk(KERN_INFO "Setting PCI interrupts for a \"%s\"\n",
+ Motherboard_map_name);
+
+ /* Setup the Winbond or Via PIB */
+ pplus_pib_init();
+
+ /* Set up floppy in PS/2 mode */
+ outb(0x09, SIO_CONFIG_RA);
+ reg = inb(SIO_CONFIG_RD);
+ reg = (reg & 0x3F) | 0x40;
+ outb(reg, SIO_CONFIG_RD);
+ outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
+
+ /* This is a hack. If this is a 2300 or 2400 mot board then there is
+ * no keyboard controller and we have to indicate that.
+ */
+
+ early_read_config_word(0, 0, 0, PCI_VENDOR_ID, &devid);
+ base_mod = inb(MOTOROLA_BASETYPE_REG);
+ if ((devid == PCI_DEVICE_ID_MOTOROLA_HAWK) ||
+ (base_mod == 0xF9) || (base_mod == 0xFA) || (base_mod == 0xE1))
+ prep_keybd_present = 0;
+}
+
+void __init pplus_find_bridges(void)
+{
+ struct pci_controller *hose;
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ hose->pci_mem_offset = PREP_ISA_MEM_BASE;
+ hose->io_base_virt = (void *)PREP_ISA_IO_BASE;
+
+ pci_init_resource(&hose->io_resource, PPLUS_PCI_IO_START,
+ PPLUS_PCI_IO_END, IORESOURCE_IO, "PCI host bridge");
+ pci_init_resource(&hose->mem_resources[0], PPLUS_PROC_PCI_MEM_START,
+ PPLUS_PROC_PCI_MEM_END, IORESOURCE_MEM,
+ "PCI host bridge");
+
+ hose->io_space.start = PPLUS_PCI_IO_START;
+ hose->io_space.end = PPLUS_PCI_IO_END;
+ hose->mem_space.start = PPLUS_PCI_MEM_START;
+ hose->mem_space.end = PPLUS_PCI_MEM_END - HAWK_MPIC_SIZE;
+
+ if (hawk_init(hose, PPLUS_HAWK_PPC_REG_BASE, PPLUS_PROC_PCI_MEM_START,
+ PPLUS_PROC_PCI_MEM_END - HAWK_MPIC_SIZE,
+ PPLUS_PROC_PCI_IO_START, PPLUS_PROC_PCI_IO_END,
+ PPLUS_PROC_PCI_MEM_END - HAWK_MPIC_SIZE + 1)
+ != 0) {
+ printk(KERN_CRIT "Could not initialize host bridge\n");
+
+ }
+
+ pplus_set_VIA_IDE_legacy();
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pcibios_fixup = pplus_pcibios_fixup;
+ ppc_md.pci_swizzle = common_swizzle;
+}
+
+static int pplus_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: Motorola MCG\n");
+ seq_printf(m, "machine\t\t: %s\n", Motherboard_map_name);
+
+ return 0;
+}
+
+static void __init pplus_setup_arch(void)
+{
+ struct pci_controller *hose;
+
+ if (ppc_md.progress)
+ ppc_md.progress("pplus_setup_arch: enter", 0);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000;
+
+ if (ppc_md.progress)
+ ppc_md.progress("pplus_setup_arch: find_bridges", 0);
+
+ /* Setup PCI host bridge */
+ pplus_find_bridges();
+
+ hose = pci_bus_to_hose(0);
+ isa_io_base = (ulong) hose->io_base_virt;
+
+ if (ppc_md.progress)
+ ppc_md.progress("pplus_setup_arch: set_board_type", 0);
+
+ pplus_set_board_type();
+
+ /* Enable L2. Assume we don't need to flush -- Cort */
+ *(unsigned char *)(PPLUS_L2_CONTROL_REG) |= 3;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ printk(KERN_INFO "Motorola PowerPlus Platform\n");
+ printk(KERN_INFO
+ "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+
+#ifdef CONFIG_VGA_CONSOLE
+ /* remap the VGA memory */
+ vgacon_remap_base = (unsigned long)ioremap(PPLUS_ISA_MEM_BASE,
+ 0x08000000);
+ conswitchp = &vga_con;
+#endif
+#ifdef CONFIG_PPCBUG_NVRAM
+ /* Read in NVRAM data */
+ init_prep_nvram();
+
+ /* if no bootargs, look in NVRAM */
+ if (cmd_line[0] == '\0') {
+ char *bootargs;
+ bootargs = prep_nvram_get_var("bootargs");
+ if (bootargs != NULL) {
+ strcpy(cmd_line, bootargs);
+ /* again.. */
+ strcpy(saved_command_line, cmd_line);
+ }
+ }
+#endif
+ if (ppc_md.progress)
+ ppc_md.progress("pplus_setup_arch: exit", 0);
+}
+
+static void pplus_restart(char *cmd)
+{
+ unsigned long i = 10000;
+
+ local_irq_disable();
+
+ /* set VIA IDE controller into native mode */
+ pplus_set_VIA_IDE_native();
+
+ /* set exception prefix high - to the prom */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb(inb(0x92) & ~1L, 0x92);
+ /* signal a reset to system control port A - soft reset */
+ outb(inb(0x92) | 1, 0x92);
+
+ while (i != 0)
+ i++;
+ panic("restart failed\n");
+}
+
+static void pplus_halt(void)
+{
+ /* set exception prefix high - to the prom */
+ _nmask_and_or_msr(MSR_EE, MSR_IP);
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb(inb(0x92) & ~1L, 0x92);
+ /* signal a reset to system control port A - soft reset */
+ outb(inb(0x92) | 1, 0x92);
+
+ while (1) ;
+ /*
+ * Not reached
+ */
+}
+
+static void pplus_power_off(void)
+{
+ pplus_halt();
+}
+
+static unsigned int pplus_irq_canonicalize(u_int irq)
+{
+ if (irq == 2)
+ return 9;
+ else
+ return irq;
+}
+
+static void __init pplus_init_IRQ(void)
+{
+ int i;
+
+ if (ppc_md.progress)
+ ppc_md.progress("init_irq: enter", 0);
+
+ OpenPIC_InitSenses = pplus_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(pplus_openpic_initsenses);
+
+ if (OpenPIC_Addr != NULL) {
+
+ openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000);
+ openpic_init(NUM_8259_INTERRUPTS);
+ openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+ i8259_irq);
+ ppc_md.get_irq = openpic_get_irq;
+ }
+
+ for (i = 0; i < NUM_8259_INTERRUPTS; i++)
+ irq_desc[i].handler = &i8259_pic;
+
+ i8259_init(0);
+
+ if (ppc_md.progress)
+ ppc_md.progress("init_irq: exit", 0);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+static int pplus_ide_default_irq(unsigned long base)
+{
+ switch (base) {
+ case 0x1f0:
+ return 14;
+ case 0x170:
+ return 15;
+ default:
+ return 0;
+ }
+}
+
+static unsigned long pplus_ide_default_io_base(int index)
+{
+ switch (index) {
+ case 0:
+ return 0x1f0;
+ case 1:
+ return 0x170;
+ default:
+ return 0;
+ }
+}
+
+static void __init
+pplus_ide_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
+ unsigned long ctrl_port, int *irq)
+{
+ unsigned long reg = data_port;
+ int i;
+
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hw->io_ports[i] = reg;
+ reg += 1;
+ }
+
+ if (ctrl_port)
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+ else
+ hw->io_ports[IDE_CONTROL_OFFSET] =
+ hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+
+ if (irq != NULL)
+ *irq = pplus_ide_default_irq(data_port);
+}
+#endif
+
+#ifdef CONFIG_SMP
+/* PowerPlus (MTX) support */
+static int __init smp_pplus_probe(void)
+{
+ extern int mot_multi;
+
+ if (mot_multi) {
+ openpic_request_IPIs();
+ smp_hw_index[1] = 1;
+ return 2;
+ }
+
+ return 1;
+}
+
+static void __init smp_pplus_kick_cpu(int nr)
+{
+ *(unsigned long *)KERNELBASE = nr;
+ asm volatile ("dcbf 0,%0"::"r" (KERNELBASE):"memory");
+ printk(KERN_INFO "CPU1 reset, waiting\n");
+}
+
+static void __init smp_pplus_setup_cpu(int cpu_nr)
+{
+ if (OpenPIC_Addr)
+ do_openpic_setup_cpu();
+}
+
+static struct smp_ops_t pplus_smp_ops = {
+ smp_openpic_message_pass,
+ smp_pplus_probe,
+ smp_pplus_kick_cpu,
+ smp_pplus_setup_cpu,
+ .give_timebase = smp_generic_give_timebase,
+ .take_timebase = smp_generic_take_timebase,
+};
+#endif /* CONFIG_SMP */
+
+#ifdef DUMP_DBATS
+static void print_dbat(int idx, u32 bat)
+{
+
+ char str[64];
+
+ sprintf(str, "DBAT%c%c = 0x%08x\n",
+ (char)((idx - DBAT0U) / 2) + '0', (idx & 1) ? 'L' : 'U', bat);
+ ppc_md.progress(str, 0);
+}
+
+#define DUMP_DBAT(x) \
+ do { \
+ u32 __temp = mfspr(x);\
+ print_dbat(x, __temp); \
+ } while (0)
+
+static void dump_dbats(void)
+{
+ if (ppc_md.progress) {
+ DUMP_DBAT(DBAT0U);
+ DUMP_DBAT(DBAT0L);
+ DUMP_DBAT(DBAT1U);
+ DUMP_DBAT(DBAT1L);
+ DUMP_DBAT(DBAT2U);
+ DUMP_DBAT(DBAT2L);
+ DUMP_DBAT(DBAT3U);
+ DUMP_DBAT(DBAT3L);
+ }
+}
+#endif
+
+static unsigned long __init pplus_find_end_of_memory(void)
+{
+ unsigned long total;
+
+ if (ppc_md.progress)
+ ppc_md.progress("pplus_find_end_of_memory", 0);
+
+#ifdef DUMP_DBATS
+ dump_dbats();
+#endif
+
+ total = hawk_get_mem_size(PPLUS_HAWK_SMC_BASE);
+ return (total);
+}
+
+static void __init pplus_map_io(void)
+{
+ io_block_mapping(PPLUS_ISA_IO_BASE, PPLUS_ISA_IO_BASE, 0x10000000,
+ _PAGE_IO);
+ io_block_mapping(0xfef80000, 0xfef80000, 0x00080000, _PAGE_IO);
+}
+
+static void __init pplus_init2(void)
+{
+#ifdef CONFIG_NVRAM
+ request_region(PREP_NVRAM_AS0, 0x8, "nvram");
+#endif
+ request_region(0x20, 0x20, "pic1");
+ request_region(0xa0, 0x20, "pic2");
+ request_region(0x00, 0x20, "dma1");
+ request_region(0x40, 0x20, "timer");
+ request_region(0x80, 0x10, "dma page reg");
+ request_region(0xc0, 0x20, "dma2");
+}
+
+/*
+ * Set BAT 2 to access 0x8000000 so progress messages will work and set BAT 3
+ * to 0xf0000000 to access Falcon/Raven or Hawk registers
+ */
+static __inline__ void pplus_set_bat(void)
+{
+ /* wait for all outstanding memory accesses to complete */
+ mb();
+
+ /* setup DBATs */
+ mtspr(SPRN_DBAT2U, 0x80001ffe);
+ mtspr(SPRN_DBAT2L, 0x8000002a);
+ mtspr(SPRN_DBAT3U, 0xf0001ffe);
+ mtspr(SPRN_DBAT3L, 0xf000002a);
+
+ /* wait for updates */
+ mb();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /* Map in board regs, etc. */
+ pplus_set_bat();
+
+ isa_io_base = PREP_ISA_IO_BASE;
+ isa_mem_base = PREP_ISA_MEM_BASE;
+ pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ ppc_md.setup_arch = pplus_setup_arch;
+ ppc_md.show_cpuinfo = pplus_show_cpuinfo;
+ ppc_md.irq_canonicalize = pplus_irq_canonicalize;
+ ppc_md.init_IRQ = pplus_init_IRQ;
+ /* this gets changed later on if we have an OpenPIC -- Cort */
+ ppc_md.get_irq = i8259_irq;
+ ppc_md.init = pplus_init2;
+
+ ppc_md.restart = pplus_restart;
+ ppc_md.power_off = pplus_power_off;
+ ppc_md.halt = pplus_halt;
+
+ TODC_INIT(TODC_TYPE_MK48T59, PREP_NVRAM_AS0, PREP_NVRAM_AS1,
+ PREP_NVRAM_DATA, 8);
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.calibrate_decr = todc_calibrate_decr;
+ ppc_md.nvram_read_val = todc_m48txx_read_val;
+ ppc_md.nvram_write_val = todc_m48txx_write_val;
+
+ ppc_md.find_end_of_memory = pplus_find_end_of_memory;
+ ppc_md.setup_io_mappings = pplus_map_io;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.default_irq = pplus_ide_default_irq;
+ ppc_ide_md.default_io_base = pplus_ide_default_io_base;
+ ppc_ide_md.ide_init_hwif = pplus_ide_init_hwif_ports;
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#ifdef CONFIG_KGDB
+ ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
+#endif
+#ifdef CONFIG_SMP
+ ppc_md.smp_ops = &pplus_smp_ops;
+#endif /* CONFIG_SMP */
+}
diff --git a/arch/ppc/platforms/pplus.h b/arch/ppc/platforms/pplus.h
new file mode 100644
index 00000000000..90f0cb2d409
--- /dev/null
+++ b/arch/ppc/platforms/pplus.h
@@ -0,0 +1,67 @@
+/*
+ * arch/ppc/platforms/pplus.h
+ *
+ * Definitions for Motorola MCG Falcon/Raven & HAWK North Bridge & Memory ctlr.
+ *
+ * Author: Mark A. Greerinclude/asm-ppc/hawk.h
+ * mgreer@mvista.com
+ *
+ * Modified by Randy Vinson (rvinson@mvista.com)
+ *
+ * 2001-2004 (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_PPLUS_H
+#define __PPC_PPLUS_H
+
+#include <asm/io.h>
+
+/*
+ * Due to limiations imposed by legacy hardware (primaryily IDE controllers),
+ * the PPLUS boards operate using a PReP address map.
+ *
+ * From Processor (physical) -> PCI:
+ * PCI Mem Space: 0xc0000000 - 0xfe000000 -> 0x00000000 - 0x3e000000 (768 MB)
+ * PCI I/O Space: 0x80000000 - 0x90000000 -> 0x00000000 - 0x10000000 (256 MB)
+ * Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area
+ *
+ * From PCI -> Processor (physical):
+ * System Memory: 0x80000000 -> 0x00000000
+ */
+
+#define PPLUS_ISA_MEM_BASE PREP_ISA_MEM_BASE
+#define PPLUS_ISA_IO_BASE PREP_ISA_IO_BASE
+
+/* PCI Memory space mapping info */
+#define PPLUS_PCI_MEM_SIZE 0x30000000U
+#define PPLUS_PROC_PCI_MEM_START PPLUS_ISA_MEM_BASE
+#define PPLUS_PROC_PCI_MEM_END (PPLUS_PROC_PCI_MEM_START + \
+ PPLUS_PCI_MEM_SIZE - 1)
+#define PPLUS_PCI_MEM_START 0x00000000U
+#define PPLUS_PCI_MEM_END (PPLUS_PCI_MEM_START + \
+ PPLUS_PCI_MEM_SIZE - 1)
+
+/* PCI I/O space mapping info */
+#define PPLUS_PCI_IO_SIZE 0x10000000U
+#define PPLUS_PROC_PCI_IO_START PPLUS_ISA_IO_BASE
+#define PPLUS_PROC_PCI_IO_END (PPLUS_PROC_PCI_IO_START + \
+ PPLUS_PCI_IO_SIZE - 1)
+#define PPLUS_PCI_IO_START 0x00000000U
+#define PPLUS_PCI_IO_END (PPLUS_PCI_IO_START + \
+ PPLUS_PCI_IO_SIZE - 1)
+/* System memory mapping info */
+#define PPLUS_PCI_DRAM_OFFSET PREP_PCI_DRAM_OFFSET
+#define PPLUS_PCI_PHY_MEM_OFFSET (PPLUS_ISA_MEM_BASE-PPLUS_PCI_MEM_START)
+
+/* Define base addresses for important sets of registers */
+#define PPLUS_HAWK_SMC_BASE 0xfef80000U
+#define PPLUS_HAWK_PPC_REG_BASE 0xfeff0000U
+#define PPLUS_SYS_CONFIG_REG 0xfef80400U
+#define PPLUS_L2_CONTROL_REG 0x8000081cU
+
+#define PPLUS_VGA_MEM_BASE 0xf0000000U
+
+#endif /* __PPC_PPLUS_H */
diff --git a/arch/ppc/platforms/pq2ads.c b/arch/ppc/platforms/pq2ads.c
new file mode 100644
index 00000000000..6a1475c1e12
--- /dev/null
+++ b/arch/ppc/platforms/pq2ads.c
@@ -0,0 +1,26 @@
+/*
+ * arch/ppc/platforms/pq2ads.c
+ *
+ * PQ2ADS platform support
+ *
+ * Author: Kumar Gala <kumar.gala@freescale.com>
+ * Derived from: est8260_setup.c by Allen Curtis
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+
+#include <asm/mpc8260.h>
+
+void __init
+m82xx_board_setup(void)
+{
+ /* Enable the 2nd UART port */
+ *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_RS232_EN2;
+}
diff --git a/arch/ppc/platforms/pq2ads.h b/arch/ppc/platforms/pq2ads.h
new file mode 100644
index 00000000000..cf5e5dd06d6
--- /dev/null
+++ b/arch/ppc/platforms/pq2ads.h
@@ -0,0 +1,96 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Motorola MPC8260ADS/MPC8266ADS-PCI boards.
+ * Copied from the RPX-Classic and SBS8260 stuff.
+ *
+ * Copyright (c) 2001 Dan Malek (dan@mvista.com)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_ADS8260_DEFS
+#define __MACH_ADS8260_DEFS
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need. The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define CPM_MAP_ADDR ((uint)0xf0000000)
+#define BCSR_ADDR ((uint)0xf4500000)
+#define BCSR_SIZE ((uint)(32 * 1024))
+
+#define BOOTROM_RESTART_ADDR ((uint)0xff000104)
+
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "Motorola"
+#define CPUINFO_MACHINE "PQ2 ADS PowerPC"
+
+/* The ADS8260 has 16, 32-bit wide control/status registers, accessed
+ * only on word boundaries.
+ * Not all are used (yet), or are interesting to us (yet).
+ */
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */
+#define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */
+#define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable */
+#define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */
+#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 == enable */
+#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 == enable */
+#define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable */
+#define BCSR3_FETH2_RST ((uint)0x80000000) /* 0 == reset */
+
+#define PHY_INTERRUPT SIU_INT_IRQ7
+
+#ifdef CONFIG_PCI
+/* PCI interrupt controller */
+#define PCI_INT_STAT_REG 0xF8200000
+#define PCI_INT_MASK_REG 0xF8200004
+#define PIRQA (NR_SIU_INTS + 0)
+#define PIRQB (NR_SIU_INTS + 1)
+#define PIRQC (NR_SIU_INTS + 2)
+#define PIRQD (NR_SIU_INTS + 3)
+
+/*
+ * PCI memory map definitions for MPC8266ADS-PCI.
+ *
+ * processor view
+ * local address PCI address target
+ * 0x80000000-0x9FFFFFFF 0x80000000-0x9FFFFFFF PCI mem with prefetch
+ * 0xA0000000-0xBFFFFFFF 0xA0000000-0xBFFFFFFF PCI mem w/o prefetch
+ * 0xF4000000-0xF7FFFFFF 0x00000000-0x03FFFFFF PCI IO
+ *
+ * PCI master view
+ * local address PCI address target
+ * 0x00000000-0x1FFFFFFF 0x00000000-0x1FFFFFFF MPC8266 local memory
+ */
+
+/* window for a PCI master to access MPC8266 memory */
+#define PCI_SLV_MEM_LOCAL 0x00000000 /* Local base */
+#define PCI_SLV_MEM_BUS 0x00000000 /* PCI base */
+
+/* window for the processor to access PCI memory with prefetching */
+#define PCI_MSTR_MEM_LOCAL 0x80000000 /* Local base */
+#define PCI_MSTR_MEM_BUS 0x80000000 /* PCI base */
+#define PCI_MSTR_MEM_SIZE 0x20000000 /* 512MB */
+
+/* window for the processor to access PCI memory without prefetching */
+#define PCI_MSTR_MEMIO_LOCAL 0xA0000000 /* Local base */
+#define PCI_MSTR_MEMIO_BUS 0xA0000000 /* PCI base */
+#define PCI_MSTR_MEMIO_SIZE 0x20000000 /* 512MB */
+
+/* window for the processor to access PCI I/O */
+#define PCI_MSTR_IO_LOCAL 0xF4000000 /* Local base */
+#define PCI_MSTR_IO_BUS 0x00000000 /* PCI base */
+#define PCI_MSTR_IO_SIZE 0x04000000 /* 64MB */
+
+#define _IO_BASE PCI_MSTR_IO_LOCAL
+#define _ISA_MEM_BASE PCI_MSTR_MEMIO_LOCAL
+#define PCI_DRAM_OFFSET PCI_SLV_MEM_BUS
+#endif /* CONFIG_PCI */
+
+#endif /* __MACH_ADS8260_DEFS */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c
new file mode 100644
index 00000000000..8cd80eb447b
--- /dev/null
+++ b/arch/ppc/platforms/prep_pci.c
@@ -0,0 +1,1336 @@
+/*
+ * PReP pci functions.
+ * Originally by Gary Thomas
+ * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * The motherboard routes/maps will disappear shortly. -- Cort
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/sections.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/residual.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/open_pic.h>
+
+extern void (*setup_ibm_pci)(char *irq_lo, char *irq_hi);
+
+/* Which PCI interrupt line does a given device [slot] use? */
+/* Note: This really should be two dimensional based in slot/pin used */
+static unsigned char *Motherboard_map;
+unsigned char *Motherboard_map_name;
+
+/* How is the 82378 PIRQ mapping setup? */
+static unsigned char *Motherboard_routes;
+
+static void (*Motherboard_non0)(struct pci_dev *);
+
+static void Powerplus_Map_Non0(struct pci_dev *);
+
+/* Used for Motorola to store system config register */
+static unsigned long *ProcInfo;
+
+/* Tables for known hardware */
+
+/* Motorola PowerStackII - Utah */
+static char Utah_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 5, /* Slot 2 - SCSI - NCR825A */
+ 0, /* Slot 3 - unused */
+ 3, /* Slot 4 - Ethernet - DEC2114x */
+ 0, /* Slot 5 - unused */
+ 2, /* Slot 6 - PCI Card slot #1 */
+ 3, /* Slot 7 - PCI Card slot #2 */
+ 5, /* Slot 8 - PCI Card slot #3 */
+ 5, /* Slot 9 - PCI Bridge */
+ /* added here in case we ever support PCI bridges */
+ /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 5, /* Slot 12 - SCSI - NCR825A */
+ 0, /* Slot 13 - unused */
+ 3, /* Slot 14 - enet */
+ 0, /* Slot 15 - unused */
+ 2, /* Slot 16 - unused */
+ 3, /* Slot 17 - unused */
+ 5, /* Slot 18 - unused */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
+};
+
+static char Utah_pci_IRQ_routes[] __prepdata =
+{
+ 0, /* Line 0 - Unused */
+ 9, /* Line 1 */
+ 10, /* Line 2 */
+ 11, /* Line 3 */
+ 14, /* Line 4 */
+ 15, /* Line 5 */
+};
+
+/* Motorola PowerStackII - Omaha */
+/* no integrated SCSI or ethernet */
+static char Omaha_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 3, /* Slot 2 - Winbond EIDE */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 1, /* Slot 6 - PCI slot 1 */
+ 2, /* Slot 7 - PCI slot 2 */
+ 3, /* Slot 8 - PCI slot 3 */
+ 4, /* Slot 9 - PCI slot 4 */ /* needs indirect access */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 0, /* Slot 12 - unused */
+ 0, /* Slot 13 - unused */
+ 0, /* Slot 14 - unused */
+ 0, /* Slot 15 - unused */
+ 1, /* Slot 16 - PCI slot 1 */
+ 2, /* Slot 17 - PCI slot 2 */
+ 3, /* Slot 18 - PCI slot 3 */
+ 4, /* Slot 19 - PCI slot 4 */ /* needs indirect access */
+ 0,
+ 0,
+ 0,
+};
+
+static char Omaha_pci_IRQ_routes[] __prepdata =
+{
+ 0, /* Line 0 - Unused */
+ 9, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+/* Motorola PowerStack */
+static char Blackhawk_pci_IRQ_map[19] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+ 1, /* Slot P7 */
+ 2, /* Slot P6 */
+ 3, /* Slot P5 */
+};
+
+static char Blackhawk_pci_IRQ_routes[] __prepdata =
+{
+ 0, /* Line 0 - Unused */
+ 9, /* Line 1 */
+ 11, /* Line 2 */
+ 15, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+/* Motorola Mesquite */
+static char Mesquite_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 0, /* Slot 12 - unused */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+ 3, /* Slot 16 - PMC */
+ 0, /* Slot 17 - unused */
+ 0, /* Slot 18 - unused */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
+};
+
+/* Motorola Sitka */
+static char Sitka_pci_IRQ_map[21] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 0, /* Slot 12 - unused */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+ 9, /* Slot 16 - PMC 1 */
+ 12, /* Slot 17 - PMC 2 */
+ 0, /* Slot 18 - unused */
+ 0, /* Slot 19 - unused */
+ 4, /* Slot 20 - NT P2P bridge */
+};
+
+/* Motorola MTX */
+static char MTX_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+ 9, /* Slot 16 - PCI/PMC slot 1 */
+ 10, /* Slot 17 - PCI/PMC slot 2 */
+ 11, /* Slot 18 - PCI slot 3 */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
+};
+
+/* Motorola MTX Plus */
+/* Secondary bus interrupt routing is not supported yet */
+static char MTXplus_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - Ethernet 1 */
+ 0, /* Slot 15 - unused */
+ 9, /* Slot 16 - PCI slot 1P */
+ 10, /* Slot 17 - PCI slot 2P */
+ 11, /* Slot 18 - PCI slot 3P */
+ 10, /* Slot 19 - Ethernet 2 */
+ 0, /* Slot 20 - P2P Bridge */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
+};
+
+static char Raven_pci_IRQ_routes[] __prepdata =
+{
+ 0, /* This is a dummy structure */
+};
+
+/* Motorola MVME16xx */
+static char Genesis_pci_IRQ_map[16] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+};
+
+static char Genesis_pci_IRQ_routes[] __prepdata =
+{
+ 0, /* Line 0 - Unused */
+ 10, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+static char Genesis2_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - IDE */
+ 3, /* Slot 12 - SCSI */
+ 5, /* Slot 13 - Universe PCI - VME Bridge */
+ 2, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+ 9, /* Slot 16 - PMC 1 */
+ 12, /* Slot 17 - pci */
+ 11, /* Slot 18 - pci */
+ 10, /* Slot 19 - pci */
+ 0, /* Slot 20 - pci */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
+};
+
+/* Motorola Series-E */
+static char Comet_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+ 1, /* Slot 16 - PCI slot 1 */
+ 2, /* Slot 17 - PCI slot 2 */
+ 3, /* Slot 18 - PCI slot 3 */
+ 4, /* Slot 19 - PCI bridge */
+ 0,
+ 0,
+ 0,
+};
+
+static char Comet_pci_IRQ_routes[] __prepdata =
+{
+ 0, /* Line 0 - Unused */
+ 10, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+/* Motorola Series-EX */
+static char Comet2_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 3, /* Slot 2 - SCSI - NCR825A */
+ 0, /* Slot 3 - unused */
+ 1, /* Slot 4 - Ethernet - DEC2104X */
+ 0, /* Slot 5 - unused */
+ 1, /* Slot 6 - PCI slot 1 */
+ 2, /* Slot 7 - PCI slot 2 */
+ 3, /* Slot 8 - PCI slot 3 */
+ 4, /* Slot 9 - PCI bridge */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI - NCR825A */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet - DEC2104X */
+ 0, /* Slot 15 - unused */
+ 1, /* Slot 16 - PCI slot 1 */
+ 2, /* Slot 17 - PCI slot 2 */
+ 3, /* Slot 18 - PCI slot 3 */
+ 4, /* Slot 19 - PCI bridge */
+ 0,
+ 0,
+ 0,
+};
+
+static char Comet2_pci_IRQ_routes[] __prepdata =
+{
+ 0, /* Line 0 - Unused */
+ 10, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15, /* Line 4 */
+};
+
+/*
+ * ibm 830 (and 850?).
+ * This is actually based on the Carolina motherboard
+ * -- Cort
+ */
+static char ibm8xx_pci_IRQ_map[23] __prepdata = {
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - FireCoral */
+ 4, /* Slot 12 - Ethernet PCIINTD# */
+ 2, /* Slot 13 - PCI Slot #2 */
+ 2, /* Slot 14 - S3 Video PCIINTD# */
+ 0, /* Slot 15 - onboard SCSI (INDI) [1] */
+ 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
+ 0, /* Slot 17 - unused */
+ 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+
+static char ibm8xx_pci_IRQ_routes[] __prepdata = {
+ 0, /* Line 0 - unused */
+ 15, /* Line 1 */
+ 15, /* Line 2 */
+ 15, /* Line 3 */
+ 15, /* Line 4 */
+};
+
+/*
+ * a 6015 ibm board
+ * -- Cort
+ */
+static char ibm6015_pci_IRQ_map[23] __prepdata = {
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - */
+ 1, /* Slot 12 - SCSI */
+ 2, /* Slot 13 - */
+ 2, /* Slot 14 - */
+ 1, /* Slot 15 - */
+ 1, /* Slot 16 - */
+ 0, /* Slot 17 - */
+ 2, /* Slot 18 - */
+ 0, /* Slot 19 - */
+ 0, /* Slot 20 - */
+ 0, /* Slot 21 - */
+ 2, /* Slot 22 - */
+};
+
+static char ibm6015_pci_IRQ_routes[] __prepdata = {
+ 0, /* Line 0 - unused */
+ 13, /* Line 1 */
+ 15, /* Line 2 */
+ 15, /* Line 3 */
+ 15, /* Line 4 */
+};
+
+
+/* IBM Nobis and Thinkpad 850 */
+static char Nobis_pci_IRQ_map[23] __prepdata ={
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 0, /* Slot 14 - unused */
+ 0, /* Slot 15 - unused */
+};
+
+static char Nobis_pci_IRQ_routes[] __prepdata = {
+ 0, /* Line 0 - Unused */
+ 13, /* Line 1 */
+ 13, /* Line 2 */
+ 13, /* Line 3 */
+ 13 /* Line 4 */
+};
+
+/*
+ * IBM RS/6000 43p/140 -- paulus
+ * XXX we should get all this from the residual data
+ */
+static char ibm43p_pci_IRQ_map[23] __prepdata = {
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - FireCoral ISA bridge */
+ 6, /* Slot 12 - Ethernet */
+ 0, /* Slot 13 - openpic */
+ 0, /* Slot 14 - unused */
+ 0, /* Slot 15 - unused */
+ 7, /* Slot 16 - NCR58C825a onboard scsi */
+ 0, /* Slot 17 - unused */
+ 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 1, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+
+static char ibm43p_pci_IRQ_routes[] __prepdata = {
+ 0, /* Line 0 - unused */
+ 15, /* Line 1 */
+ 15, /* Line 2 */
+ 15, /* Line 3 */
+ 15, /* Line 4 */
+};
+
+/* Motorola PowerPlus architecture PCI IRQ tables */
+/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
+
+struct powerplus_irq_list
+{
+ unsigned char primary[4]; /* INT A-D */
+ unsigned char secondary[4]; /* INT A-D */
+};
+
+/*
+ * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
+ * OpenPIC inputs 9-12. PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 5-8. These values are offset by
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Powerplus_pci_IRQ_list __prepdata =
+{
+ {25, 26, 27, 28},
+ {21, 22, 23, 24}
+};
+
+/*
+ * For the MCP750 (system slot board), cPCI INTs A-D are routed to
+ * OpenPIC inputs 8-11 and the PMC INTs A-D are routed to OpenPIC
+ * input 3. On a hot swap MCP750, the companion card PCI INTs A-D
+ * are routed to OpenPIC inputs 12-15. These values are offset by
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Mesquite_pci_IRQ_list __prepdata =
+{
+ {24, 25, 26, 27},
+ {28, 29, 30, 31}
+};
+
+/*
+ * This table represents the standard PCI swizzle defined in the
+ * PCI bus specification.
+ */
+static unsigned char prep_pci_intpins[4][4] __prepdata =
+{
+ { 1, 2, 3, 4}, /* Buses 0, 4, 8, ... */
+ { 2, 3, 4, 1}, /* Buses 1, 5, 9, ... */
+ { 3, 4, 1, 2}, /* Buses 2, 6, 10 ... */
+ { 4, 1, 2, 3}, /* Buses 3, 7, 11 ... */
+};
+
+/* We have to turn on LEVEL mode for changed IRQ's */
+/* All PCI IRQ's need to be level mode, so this should be something
+ * other than hard-coded as well... IRQ's are individually mappable
+ * to either edge or level.
+ */
+
+/*
+ * 8259 edge/level control definitions
+ */
+#define ISA8259_M_ELCR 0x4d0
+#define ISA8259_S_ELCR 0x4d1
+
+#define ELCRS_INT15_LVL 0x80
+#define ELCRS_INT14_LVL 0x40
+#define ELCRS_INT12_LVL 0x10
+#define ELCRS_INT11_LVL 0x08
+#define ELCRS_INT10_LVL 0x04
+#define ELCRS_INT9_LVL 0x02
+#define ELCRS_INT8_LVL 0x01
+#define ELCRM_INT7_LVL 0x80
+#define ELCRM_INT5_LVL 0x20
+
+#if 0
+/*
+ * PCI config space access.
+ */
+#define CFGADDR(dev) ((1<<(dev>>3)) | ((dev&7)<<8))
+#define DEVNO(dev) (dev>>3)
+
+#define MIN_DEVNR 11
+#define MAX_DEVNR 22
+
+static int __prep
+prep_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 *val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ volatile void __iomem *cfg_data;
+
+ if (bus->number != 0 || DEVNO(devfn) < MIN_DEVNR
+ || DEVNO(devfn) > MAX_DEVNR)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ cfg_data = hose->cfg_data + CFGADDR(devfn) + offset;
+ switch (len) {
+ case 1:
+ *val = in_8(cfg_data);
+ break;
+ case 2:
+ *val = in_le16(cfg_data);
+ break;
+ default:
+ *val = in_le32(cfg_data);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int __prep
+prep_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ volatile void __iomem *cfg_data;
+
+ if (bus->number != 0 || DEVNO(devfn) < MIN_DEVNR
+ || DEVNO(devfn) > MAX_DEVNR)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ cfg_data = hose->cfg_data + CFGADDR(devfn) + offset;
+ switch (len) {
+ case 1:
+ out_8(cfg_data, val);
+ break;
+ case 2:
+ out_le16(cfg_data, val);
+ break;
+ default:
+ out_le32(cfg_data, val);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops prep_pci_ops =
+{
+ prep_read_config,
+ prep_write_config
+};
+#endif
+
+#define MOTOROLA_CPUTYPE_REG 0x800
+#define MOTOROLA_BASETYPE_REG 0x803
+#define MPIC_RAVEN_ID 0x48010000
+#define MPIC_HAWK_ID 0x48030000
+#define MOT_PROC2_BIT 0x800
+
+static u_char prep_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_SIO */
+ (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_FALCN_ECC_ERR */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_ETHERNET */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_GRAPHICS */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTA */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTB */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTC */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTD */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG1 */
+};
+
+#define MOT_RAVEN_PRESENT 0x1
+#define MOT_HAWK_PRESENT 0x2
+
+int mot_entry = -1;
+int prep_keybd_present = 1;
+int MotMPIC;
+int mot_multi;
+
+int __init
+raven_init(void)
+{
+ unsigned int devid;
+ unsigned int pci_membase;
+ unsigned char base_mod;
+
+ /* Check to see if the Raven chip exists. */
+ if ( _prep_type != _PREP_Motorola) {
+ OpenPIC_Addr = NULL;
+ return 0;
+ }
+
+ /* Check to see if this board is a type that might have a Raven. */
+ if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
+ OpenPIC_Addr = NULL;
+ return 0;
+ }
+
+ /* Check the first PCI device to see if it is a Raven. */
+ early_read_config_dword(NULL, 0, 0, PCI_VENDOR_ID, &devid);
+
+ switch (devid & 0xffff0000) {
+ case MPIC_RAVEN_ID:
+ MotMPIC = MOT_RAVEN_PRESENT;
+ break;
+ case MPIC_HAWK_ID:
+ MotMPIC = MOT_HAWK_PRESENT;
+ break;
+ default:
+ OpenPIC_Addr = NULL;
+ return 0;
+ }
+
+
+ /* Read the memory base register. */
+ early_read_config_dword(NULL, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+ if (pci_membase == 0) {
+ OpenPIC_Addr = NULL;
+ return 0;
+ }
+
+ /* Map the Raven MPIC registers to virtual memory. */
+ OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000);
+
+ OpenPIC_InitSenses = prep_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
+
+ ppc_md.get_irq = openpic_get_irq;
+
+ /* If raven is present on Motorola store the system config register
+ * for later use.
+ */
+ ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
+
+ /* Indicate to system if this is a multiprocessor board */
+ if (!(*ProcInfo & MOT_PROC2_BIT)) {
+ mot_multi = 1;
+ }
+
+ /* This is a hack. If this is a 2300 or 2400 mot board then there is
+ * no keyboard controller and we have to indicate that.
+ */
+ base_mod = inb(MOTOROLA_BASETYPE_REG);
+ if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
+ (base_mod == 0xFA) || (base_mod == 0xE1))
+ prep_keybd_present = 0;
+
+ return 1;
+}
+
+struct mot_info {
+ int cpu_type; /* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
+ /* 0x200 if this board has a Hawk chip. */
+ int base_type;
+ int max_cpu; /* ored with 0x80 if this board should be checked for multi CPU */
+ const char *name;
+ unsigned char *map;
+ unsigned char *routes;
+ void (*map_non0_bus)(struct pci_dev *); /* For boards with more than bus 0 devices. */
+ struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
+ unsigned char secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */
+} mot_info[] __prepdata = {
+ {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x040, 0x00, 0x00, "Blackhawk (Powerstack)", Blackhawk_pci_IRQ_map, Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)", Omaha_pci_IRQ_map, Omaha_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)", Utah_pci_IRQ_map, Utah_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x0A0, 0x00, 0x00, "Powerstack (Series EX)", Comet2_pci_IRQ_map, Comet2_pci_IRQ_routes, NULL, NULL, 0x00},
+ {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xFF},
+ {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", Sitka_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
+ {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+ {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+ {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+ {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+ {0x000, 0x00, 0x00, "", NULL, NULL, NULL, NULL, 0x00}
+};
+
+void __init
+ibm_prep_init(void)
+{
+ if (have_residual_data) {
+ u32 addr, real_addr, len, offset;
+ PPC_DEVICE *mpic;
+ PnP_TAG_PACKET *pkt;
+
+ /* Use the PReP residual data to determine if an OpenPIC is
+ * present. If so, get the large vendor packet which will
+ * tell us the base address and length in memory.
+ * If we are successful, ioremap the memory area and set
+ * OpenPIC_Addr (this indicates that the OpenPIC was found).
+ */
+ mpic = residual_find_device(-1, NULL, SystemPeripheral,
+ ProgrammableInterruptController, MPIC, 0);
+ if (!mpic)
+ return;
+
+ pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
+ mpic->AllocatedOffset, 9, 0);
+
+ if (!pkt)
+ return;
+
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+ if (p.PPCData[1] == 32) {
+ switch (p.PPCData[0]) {
+ case 1: offset = PREP_ISA_IO_BASE; break;
+ case 2: offset = PREP_ISA_MEM_BASE; break;
+ default: return; /* Not I/O or memory?? */
+ }
+ }
+ else
+ return; /* Not a 32-bit address */
+
+ real_addr = ld_le32((unsigned int *) (p.PPCData + 4));
+ if (real_addr == 0xffffffff)
+ return;
+
+ /* Adjust address to be as seen by CPU */
+ addr = real_addr + offset;
+
+ len = ld_le32((unsigned int *) (p.PPCData + 12));
+ if (!len)
+ return;
+#undef p
+ OpenPIC_Addr = ioremap(addr, len);
+ ppc_md.get_irq = openpic_get_irq;
+
+ OpenPIC_InitSenses = prep_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
+
+ printk(KERN_INFO "MPIC at 0x%08x (0x%08x), length 0x%08x "
+ "mapped to 0x%p\n", addr, real_addr, len, OpenPIC_Addr);
+ }
+}
+
+static void __init
+ibm43p_pci_map_non0(struct pci_dev *dev)
+{
+ unsigned char intpin;
+ static unsigned char bridge_intrs[4] = { 3, 4, 5, 8 };
+
+ if (dev == NULL)
+ return;
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin);
+ if (intpin < 1 || intpin > 4)
+ return;
+ intpin = (PCI_SLOT(dev->devfn) + intpin - 1) & 3;
+ dev->irq = openpic_to_irq(bridge_intrs[intpin]);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+}
+
+void __init
+prep_residual_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+ if (have_residual_data) {
+ Motherboard_map_name = res->VitalProductData.PrintableModel;
+ Motherboard_map = NULL;
+ Motherboard_routes = NULL;
+ residual_irq_mask(irq_edge_mask_lo, irq_edge_mask_hi);
+ }
+}
+
+void __init
+prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+ Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
+ Motherboard_map = ibm6015_pci_IRQ_map;
+ Motherboard_routes = ibm6015_pci_IRQ_routes;
+ *irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+ *irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+}
+
+void __init
+prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+ Motherboard_map_name = "IBM Thinkpad 850/860";
+ Motherboard_map = Nobis_pci_IRQ_map;
+ Motherboard_routes = Nobis_pci_IRQ_routes;
+ *irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+ *irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+}
+
+void __init
+prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+ Motherboard_map_name = "IBM 7248, PowerSeries 830/850 (Carolina)";
+ Motherboard_map = ibm8xx_pci_IRQ_map;
+ Motherboard_routes = ibm8xx_pci_IRQ_routes;
+ *irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+ *irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
+}
+
+void __init
+prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+ Motherboard_map_name = "IBM 43P-140 (Tiger1)";
+ Motherboard_map = ibm43p_pci_IRQ_map;
+ Motherboard_routes = ibm43p_pci_IRQ_routes;
+ Motherboard_non0 = ibm43p_pci_map_non0;
+ *irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+ *irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+}
+
+void __init
+prep_route_pci_interrupts(void)
+{
+ unsigned char *ibc_pirq = (unsigned char *)0x80800860;
+ unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
+ int i;
+
+ if ( _prep_type == _PREP_Motorola)
+ {
+ unsigned short irq_mode;
+ unsigned char cpu_type;
+ unsigned char base_mod;
+ int entry;
+
+ cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
+ base_mod = inb(MOTOROLA_BASETYPE_REG);
+
+ for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
+ if (mot_info[entry].cpu_type & 0x200) { /* Check for Hawk chip */
+ if (!(MotMPIC & MOT_HAWK_PRESENT))
+ continue;
+ } else { /* Check non hawk boards */
+ if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
+ continue;
+
+ if (mot_info[entry].base_type == 0) {
+ mot_entry = entry;
+ break;
+ }
+
+ if (mot_info[entry].base_type != base_mod)
+ continue;
+ }
+
+ if (!(mot_info[entry].max_cpu & 0x80)) {
+ mot_entry = entry;
+ break;
+ }
+
+ /* processor 1 not present and max processor zero indicated */
+ if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
+ mot_entry = entry;
+ break;
+ }
+
+ /* processor 1 present and max processor zero indicated */
+ if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
+ mot_entry = entry;
+ break;
+ }
+ }
+
+ if (mot_entry == -1) /* No particular cpu type found - assume Blackhawk */
+ mot_entry = 3;
+
+ Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
+ Motherboard_map = mot_info[mot_entry].map;
+ Motherboard_routes = mot_info[mot_entry].routes;
+ Motherboard_non0 = mot_info[mot_entry].map_non0_bus;
+
+ if (!(mot_info[entry].cpu_type & 0x100)) {
+ /* AJF adjust level/edge control according to routes */
+ irq_mode = 0;
+ for (i = 1; i <= 4; i++)
+ irq_mode |= ( 1 << Motherboard_routes[i] );
+ outb( irq_mode & 0xff, 0x4d0 );
+ outb( (irq_mode >> 8) & 0xff, 0x4d1 );
+ }
+ } else if ( _prep_type == _PREP_IBM ) {
+ unsigned char irq_edge_mask_lo, irq_edge_mask_hi;
+ unsigned short irq_edge_mask;
+ int i;
+
+ setup_ibm_pci(&irq_edge_mask_lo, &irq_edge_mask_hi);
+
+ outb(inb(0x04d0)|irq_edge_mask_lo, 0x4d0); /* primary 8259 */
+ outb(inb(0x04d1)|irq_edge_mask_hi, 0x4d1); /* cascaded 8259 */
+
+ irq_edge_mask = (irq_edge_mask_hi << 8) | irq_edge_mask_lo;
+ for (i = 0; i < 16; ++i, irq_edge_mask >>= 1)
+ if (irq_edge_mask & 1)
+ irq_desc[i].status |= IRQ_LEVEL;
+ } else {
+ printk("No known machine pci routing!\n");
+ return;
+ }
+
+ /* Set up mapping from slots */
+ if (Motherboard_routes) {
+ for (i = 1; i <= 4; i++)
+ ibc_pirq[i-1] = Motherboard_routes[i];
+
+ /* Enable PCI interrupts */
+ *ibc_pcicon |= 0x20;
+ }
+}
+
+void __init
+prep_pib_init(void)
+{
+ unsigned char reg;
+ unsigned short short_reg;
+
+ struct pci_dev *dev = NULL;
+
+ if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) {
+ /*
+ * Perform specific configuration for the Via Tech or
+ * or Winbond PCI-ISA-Bridge part.
+ */
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C586_1, dev))) {
+ /*
+ * PPCBUG does not set the enable bits
+ * for the IDE device. Force them on here.
+ */
+ pci_read_config_byte(dev, 0x40, &reg);
+
+ reg |= 0x03; /* IDE: Chip Enable Bits */
+ pci_write_config_byte(dev, 0x40, reg);
+ }
+ if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_82C586_2,
+ dev)) && (dev->devfn = 0x5a)) {
+ /* Force correct USB interrupt */
+ dev->irq = 11;
+ pci_write_config_byte(dev,
+ PCI_INTERRUPT_LINE,
+ dev->irq);
+ }
+ if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_83C553, dev))) {
+ /* Clear PCI Interrupt Routing Control Register. */
+ short_reg = 0x0000;
+ pci_write_config_word(dev, 0x44, short_reg);
+ if (OpenPIC_Addr){
+ /* Route IDE interrupts to IRQ 14 */
+ reg = 0xEE;
+ pci_write_config_byte(dev, 0x43, reg);
+ }
+ }
+ pci_dev_put(dev);
+ }
+
+ if ((dev = pci_get_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_82C105, dev))){
+ if (OpenPIC_Addr){
+ /*
+ * Disable LEGIRQ mode so PCI INTS are routed
+ * directly to the 8259 and enable both channels
+ */
+ pci_write_config_dword(dev, 0x40, 0x10ff0033);
+
+ /* Force correct IDE interrupt */
+ dev->irq = 14;
+ pci_write_config_byte(dev,
+ PCI_INTERRUPT_LINE,
+ dev->irq);
+ } else {
+ /* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
+ pci_write_config_dword(dev, 0x40, 0x10ff08a1);
+ }
+ }
+ pci_dev_put(dev);
+}
+
+static void __init
+Powerplus_Map_Non0(struct pci_dev *dev)
+{
+ struct pci_bus *pbus; /* Parent bus structure pointer */
+ struct pci_dev *tdev = dev; /* Temporary device structure */
+ unsigned int devnum; /* Accumulated device number */
+ unsigned char intline; /* Linux interrupt value */
+ unsigned char intpin; /* PCI interrupt pin */
+
+ /* Check for valid PCI dev pointer */
+ if (dev == NULL) return;
+
+ /* Initialize bridge IDSEL variable */
+ devnum = PCI_SLOT(tdev->devfn);
+
+ /* Read the interrupt pin of the device and adjust for indexing */
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin);
+
+ /* If device doesn't request an interrupt, return */
+ if ( (intpin < 1) || (intpin > 4) )
+ return;
+
+ intpin--;
+
+ /*
+ * Walk up to bus 0, adjusting the interrupt pin for the standard
+ * PCI bus swizzle.
+ */
+ do {
+ intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+ pbus = tdev->bus; /* up one level */
+ tdev = pbus->self;
+ devnum = PCI_SLOT(tdev->devfn);
+ } while(tdev->bus->number);
+
+ /* Use the primary interrupt inputs by default */
+ intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+
+ /*
+ * If the board has secondary interrupt inputs, walk the bus and
+ * note the devfn of the bridge from bus 0. If it is the same as
+ * the devfn of the bus bridge with secondary inputs, use those.
+ * Otherwise, assume it's a PMC site and get the interrupt line
+ * value from the interrupt routing table.
+ */
+ if (mot_info[mot_entry].secondary_bridge_devfn) {
+ pbus = dev->bus;
+
+ while (pbus->primary != 0)
+ pbus = pbus->parent;
+
+ if ((pbus->self)->devfn != 0xA0) {
+ if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
+ intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
+ else {
+ if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map)
+ intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16;
+ else {
+ int i;
+ for (i=0;i<3;i++)
+ intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+ intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+ }
+ }
+ }
+ }
+
+ /* Write calculated interrupt value to header and device list */
+ dev->irq = intline;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)dev->irq);
+}
+
+void __init
+prep_pcibios_fixup(void)
+{
+ struct pci_dev *dev = NULL;
+ int irq;
+ int have_openpic = (OpenPIC_Addr != NULL);
+
+ prep_route_pci_interrupts();
+
+ printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+
+ /* Iterate through all the PCI devices, setting the IRQ */
+ for_each_pci_dev(dev) {
+ /*
+ * If we have residual data, then this is easy: query the
+ * residual data for the IRQ line allocated to the device.
+ * This works the same whether we have an OpenPic or not.
+ */
+ if (have_residual_data) {
+ irq = residual_pcidev_irq(dev);
+ dev->irq = have_openpic ? openpic_to_irq(irq) : irq;
+ }
+ /*
+ * If we don't have residual data, then we need to use
+ * tables to determine the IRQ. The table organisation
+ * is different depending on whether there is an OpenPIC
+ * or not. The tables are only used for bus 0, so check
+ * this first.
+ */
+ else if (dev->bus->number == 0) {
+ irq = Motherboard_map[PCI_SLOT(dev->devfn)];
+ dev->irq = have_openpic ? openpic_to_irq(irq)
+ : Motherboard_routes[irq];
+ }
+ /*
+ * Finally, if we don't have residual data and the bus is
+ * non-zero, use the callback (if provided)
+ */
+ else {
+ if (Motherboard_non0 != NULL)
+ Motherboard_non0(dev);
+
+ continue;
+ }
+
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ }
+
+ /* Setup the Winbond or Via PIB */
+ prep_pib_init();
+}
+
+static void __init
+prep_pcibios_after_init(void)
+{
+#if 0
+ struct pci_dev *dev;
+
+ /* If there is a WD 90C, reset the IO BAR to 0x0 (it started that
+ * way, but the PCI layer relocated it because it thought 0x0 was
+ * invalid for a BAR).
+ * If you don't do this, the card's VGA base will be <IO BAR>+0xc0000
+ * instead of 0xc0000. vgacon.c (for example) is completely unaware of
+ * this little quirk.
+ */
+ dev = pci_get_device(PCI_VENDOR_ID_WD, PCI_DEVICE_ID_WD_90C, NULL);
+ if (dev) {
+ dev->resource[1].end -= dev->resource[1].start;
+ dev->resource[1].start = 0;
+ /* tell the hardware */
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0x0);
+ pci_dev_put(dev);
+ }
+#endif
+}
+
+static void __init
+prep_init_resource(struct resource *res, unsigned long start,
+ unsigned long end, int flags)
+{
+ res->flags = flags;
+ res->start = start;
+ res->end = end;
+ res->name = "PCI host bridge";
+ res->parent = NULL;
+ res->sibling = NULL;
+ res->child = NULL;
+}
+
+void __init
+prep_find_bridges(void)
+{
+ struct pci_controller* hose;
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+ hose->pci_mem_offset = PREP_ISA_MEM_BASE;
+ hose->io_base_phys = PREP_ISA_IO_BASE;
+ hose->io_base_virt = ioremap(PREP_ISA_IO_BASE, 0x800000);
+ prep_init_resource(&hose->io_resource, 0, 0x007fffff, IORESOURCE_IO);
+ prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
+ IORESOURCE_MEM);
+ setup_indirect_pci(hose, PREP_ISA_IO_BASE + 0xcf8,
+ PREP_ISA_IO_BASE + 0xcfc);
+
+ printk("PReP architecture\n");
+
+ if (have_residual_data) {
+ PPC_DEVICE *hostbridge;
+
+ hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
+ BridgeController, PCIBridge, -1, 0);
+ if (hostbridge &&
+ ((hostbridge->DeviceId.Interface == PCIBridgeIndirect) ||
+ (hostbridge->DeviceId.Interface == PCIBridgeRS6K))) {
+ PnP_TAG_PACKET * pkt;
+ pkt = PnP_find_large_vendor_packet(
+ res->DevicePnPHeap+hostbridge->AllocatedOffset,
+ 3, 0);
+ if(pkt) {
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+ setup_indirect_pci(hose,
+ ld_le32((unsigned *) (p.PPCData)),
+ ld_le32((unsigned *) (p.PPCData+8)));
+#undef p
+ } else
+ setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
+ }
+ }
+
+ ppc_md.pcibios_fixup = prep_pcibios_fixup;
+ ppc_md.pcibios_after_init = prep_pcibios_after_init;
+}
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
new file mode 100644
index 00000000000..bc926be9547
--- /dev/null
+++ b/arch/ppc/platforms/prep_setup.c
@@ -0,0 +1,1181 @@
+/*
+ * arch/ppc/platforms/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * Support for PReP (Motorola MTX/MVME)
+ * by Troy Benjegerdes (hozer@drgw.net)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#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/console.h>
+#include <linux/timex.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/sections.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/mc146818rtc.h>
+#include <asm/mk48t59.h>
+#include <asm/prep_nvram.h>
+#include <asm/raven.h>
+#include <asm/vga.h>
+#include <asm/time.h>
+#include <asm/mpc10x.h>
+#include <asm/i8259.h>
+#include <asm/open_pic.h>
+#include <asm/pci-bridge.h>
+#include <asm/todc.h>
+
+TODC_ALLOC();
+
+unsigned char ucSystemType;
+unsigned char ucBoardRev;
+unsigned char ucBoardRevMaj, ucBoardRevMin;
+
+extern unsigned char prep_nvram_read_val(int addr);
+extern void prep_nvram_write_val(int addr,
+ unsigned char val);
+extern unsigned char rs_nvram_read_val(int addr);
+extern void rs_nvram_write_val(int addr,
+ unsigned char val);
+extern void ibm_prep_init(void);
+
+extern void prep_find_bridges(void);
+
+int _prep_type;
+
+extern void prep_residual_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+
+
+#define cached_21 (((char *)(ppc_cached_irq_mask))[3])
+#define cached_A1 (((char *)(ppc_cached_irq_mask))[2])
+
+/* for the mac fs */
+dev_t boot_dev;
+
+#ifdef CONFIG_SOUND_CS4232
+long ppc_cs4232_dma, ppc_cs4232_dma2;
+#endif
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_jiffy;
+
+#ifdef CONFIG_SOUND_CS4232
+EXPORT_SYMBOL(ppc_cs4232_dma);
+EXPORT_SYMBOL(ppc_cs4232_dma2);
+#endif
+
+/* useful ISA ports */
+#define PREP_SYSCTL 0x81c
+/* present in the IBM reference design; possibly identical in Mot boxes: */
+#define PREP_IBM_SIMM_ID 0x803 /* SIMM size: 32 or 8 MiB */
+#define PREP_IBM_SIMM_PRESENCE 0x804
+#define PREP_IBM_EQUIPMENT 0x80c
+#define PREP_IBM_L2INFO 0x80d
+#define PREP_IBM_PM1 0x82a /* power management register 1 */
+#define PREP_IBM_PLANAR 0x852 /* planar ID - identifies the motherboard */
+#define PREP_IBM_DISP 0x8c0 /* 4-digit LED display */
+
+/* Equipment Present Register masks: */
+#define PREP_IBM_EQUIPMENT_RESERVED 0x80
+#define PREP_IBM_EQUIPMENT_SCSIFUSE 0x40
+#define PREP_IBM_EQUIPMENT_L2_COPYBACK 0x08
+#define PREP_IBM_EQUIPMENT_L2_256 0x04
+#define PREP_IBM_EQUIPMENT_CPU 0x02
+#define PREP_IBM_EQUIPMENT_L2 0x01
+
+/* planar ID values: */
+/* Sandalfoot/Sandalbow (6015/7020) */
+#define PREP_IBM_SANDALFOOT 0xfc
+/* Woodfield, Thinkpad 850/860 (6042/7249) */
+#define PREP_IBM_THINKPAD 0xff /* planar ID unimplemented */
+/* PowerSeries 830/850 (6050/6070) */
+#define PREP_IBM_CAROLINA_IDE_0 0xf0
+#define PREP_IBM_CAROLINA_IDE_1 0xf1
+#define PREP_IBM_CAROLINA_IDE_2 0xf2
+#define PREP_IBM_CAROLINA_IDE_3 0xf3
+/* 7248-43P */
+#define PREP_IBM_CAROLINA_SCSI_0 0xf4
+#define PREP_IBM_CAROLINA_SCSI_1 0xf5
+#define PREP_IBM_CAROLINA_SCSI_2 0xf6
+#define PREP_IBM_CAROLINA_SCSI_3 0xf7 /* missing from Carolina Tech Spec */
+/* Tiger1 (7043-140) */
+#define PREP_IBM_TIGER1_133 0xd1
+#define PREP_IBM_TIGER1_166 0xd2
+#define PREP_IBM_TIGER1_180 0xd3
+#define PREP_IBM_TIGER1_xxx 0xd4 /* unknown, but probably exists */
+#define PREP_IBM_TIGER1_333 0xd5 /* missing from Tiger Tech Spec */
+
+/* setup_ibm_pci:
+ * set Motherboard_map_name, Motherboard_map, Motherboard_routes.
+ * return 8259 edge/level masks.
+ */
+void (*setup_ibm_pci)(char *irq_lo, char *irq_hi);
+
+extern char *Motherboard_map_name; /* for use in *_cpuinfo */
+
+/*
+ * As found in the PReP reference implementation.
+ * Used by Thinkpad, Sandalfoot (6015/7020), and all Motorola PReP.
+ */
+static void __init
+prep_gen_enable_l2(void)
+{
+ outb(inb(PREP_SYSCTL) | 0x3, PREP_SYSCTL);
+}
+
+/* Used by Carolina and Tiger1 */
+static void __init
+prep_carolina_enable_l2(void)
+{
+ outb(inb(PREP_SYSCTL) | 0xc0, PREP_SYSCTL);
+}
+
+/* cpuinfo code common to all IBM PReP */
+static void __prep
+prep_ibm_cpuinfo(struct seq_file *m)
+{
+ unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+
+ seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+ seq_printf(m, "upgrade cpu\t: ");
+ if (equip_reg & PREP_IBM_EQUIPMENT_CPU) {
+ seq_printf(m, "not ");
+ }
+ seq_printf(m, "present\n");
+
+ /* print info about the SCSI fuse */
+ seq_printf(m, "scsi fuse\t: ");
+ if (equip_reg & PREP_IBM_EQUIPMENT_SCSIFUSE)
+ seq_printf(m, "ok");
+ else
+ seq_printf(m, "bad");
+ seq_printf(m, "\n");
+
+ /* print info about SIMMs */
+ if (have_residual_data) {
+ int i;
+ seq_printf(m, "simms\t\t: ");
+ for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
+ if (res->Memories[i].SIMMSize != 0)
+ seq_printf(m, "%d:%ldMiB ", i,
+ (res->Memories[i].SIMMSize > 1024) ?
+ res->Memories[i].SIMMSize>>20 :
+ res->Memories[i].SIMMSize);
+ }
+ seq_printf(m, "\n");
+ }
+}
+
+static int __prep
+prep_gen_cpuinfo(struct seq_file *m)
+{
+ prep_ibm_cpuinfo(m);
+ return 0;
+}
+
+static int __prep
+prep_sandalfoot_cpuinfo(struct seq_file *m)
+{
+ unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+
+ prep_ibm_cpuinfo(m);
+
+ /* report amount and type of L2 cache present */
+ seq_printf(m, "L2 cache\t: ");
+ if (equip_reg & PREP_IBM_EQUIPMENT_L2) {
+ seq_printf(m, "not present");
+ } else {
+ if (equip_reg & PREP_IBM_EQUIPMENT_L2_256)
+ seq_printf(m, "256KiB");
+ else
+ seq_printf(m, "unknown size");
+
+ if (equip_reg & PREP_IBM_EQUIPMENT_L2_COPYBACK)
+ seq_printf(m, ", copy-back");
+ else
+ seq_printf(m, ", write-through");
+ }
+ seq_printf(m, "\n");
+
+ return 0;
+}
+
+static int __prep
+prep_thinkpad_cpuinfo(struct seq_file *m)
+{
+ unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+ char *cpubus_speed, *pci_speed;
+
+ prep_ibm_cpuinfo(m);
+
+ /* report amount and type of L2 cache present */
+ seq_printf(m, "l2 cache\t: ");
+ if ((equip_reg & 0x1) == 0) {
+ switch ((equip_reg & 0xc) >> 2) {
+ case 0x0:
+ seq_printf(m, "128KiB look-aside 2-way write-through\n");
+ break;
+ case 0x1:
+ seq_printf(m, "512KiB look-aside direct-mapped write-back\n");
+ break;
+ case 0x2:
+ seq_printf(m, "256KiB look-aside 2-way write-through\n");
+ break;
+ case 0x3:
+ seq_printf(m, "256KiB look-aside direct-mapped write-back\n");
+ break;
+ }
+ } else {
+ seq_printf(m, "not present\n");
+ }
+
+ /* report bus speeds because we can */
+ if ((equip_reg & 0x80) == 0) {
+ switch ((equip_reg & 0x30) >> 4) {
+ case 0x1:
+ cpubus_speed = "50";
+ pci_speed = "25";
+ break;
+ case 0x3:
+ cpubus_speed = "66";
+ pci_speed = "33";
+ break;
+ default:
+ cpubus_speed = "unknown";
+ pci_speed = "unknown";
+ break;
+ }
+ } else {
+ switch ((equip_reg & 0x30) >> 4) {
+ case 0x1:
+ cpubus_speed = "25";
+ pci_speed = "25";
+ break;
+ case 0x2:
+ cpubus_speed = "60";
+ pci_speed = "30";
+ break;
+ case 0x3:
+ cpubus_speed = "33";
+ pci_speed = "33";
+ break;
+ default:
+ cpubus_speed = "unknown";
+ pci_speed = "unknown";
+ break;
+ }
+ }
+ seq_printf(m, "60x bus\t\t: %sMHz\n", cpubus_speed);
+ seq_printf(m, "pci bus\t\t: %sMHz\n", pci_speed);
+
+ return 0;
+}
+
+static int __prep
+prep_carolina_cpuinfo(struct seq_file *m)
+{
+ unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+
+ prep_ibm_cpuinfo(m);
+
+ /* report amount and type of L2 cache present */
+ seq_printf(m, "l2 cache\t: ");
+ if ((equip_reg & 0x1) == 0) {
+ unsigned int l2_reg = inb(PREP_IBM_L2INFO);
+
+ /* L2 size */
+ if ((l2_reg & 0x60) == 0)
+ seq_printf(m, "256KiB");
+ else if ((l2_reg & 0x60) == 0x20)
+ seq_printf(m, "512KiB");
+ else
+ seq_printf(m, "unknown size");
+
+ /* L2 type */
+ if ((l2_reg & 0x3) == 0)
+ seq_printf(m, ", async");
+ else if ((l2_reg & 0x3) == 1)
+ seq_printf(m, ", sync");
+ else
+ seq_printf(m, ", unknown type");
+
+ seq_printf(m, "\n");
+ } else {
+ seq_printf(m, "not present\n");
+ }
+
+ return 0;
+}
+
+static int __prep
+prep_tiger1_cpuinfo(struct seq_file *m)
+{
+ unsigned int l2_reg = inb(PREP_IBM_L2INFO);
+
+ prep_ibm_cpuinfo(m);
+
+ /* report amount and type of L2 cache present */
+ seq_printf(m, "l2 cache\t: ");
+ if ((l2_reg & 0xf) == 0xf) {
+ seq_printf(m, "not present\n");
+ } else {
+ if (l2_reg & 0x8)
+ seq_printf(m, "async, ");
+ else
+ seq_printf(m, "sync burst, ");
+
+ if (l2_reg & 0x4)
+ seq_printf(m, "parity, ");
+ else
+ seq_printf(m, "no parity, ");
+
+ switch (l2_reg & 0x3) {
+ case 0x0:
+ seq_printf(m, "256KiB\n");
+ break;
+ case 0x1:
+ seq_printf(m, "512KiB\n");
+ break;
+ case 0x2:
+ seq_printf(m, "1MiB\n");
+ break;
+ default:
+ seq_printf(m, "unknown size\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Used by all Motorola PReP */
+static int __prep
+prep_mot_cpuinfo(struct seq_file *m)
+{
+ unsigned int cachew = *((unsigned char *)CACHECRBA);
+
+ seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+ /* report amount and type of L2 cache present */
+ seq_printf(m, "l2 cache\t: ");
+ switch (cachew & L2CACHE_MASK) {
+ case L2CACHE_512KB:
+ seq_printf(m, "512KiB");
+ break;
+ case L2CACHE_256KB:
+ seq_printf(m, "256KiB");
+ break;
+ case L2CACHE_1MB:
+ seq_printf(m, "1MiB");
+ break;
+ case L2CACHE_NONE:
+ seq_printf(m, "none\n");
+ goto no_l2;
+ break;
+ default:
+ seq_printf(m, "%x\n", cachew);
+ }
+
+ seq_printf(m, ", parity %s",
+ (cachew & L2CACHE_PARITY)? "enabled" : "disabled");
+
+ seq_printf(m, " SRAM:");
+
+ switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
+ case 1: seq_printf(m, "synchronous, parity, flow-through\n");
+ break;
+ case 2: seq_printf(m, "asynchronous, no parity\n");
+ break;
+ case 3: seq_printf(m, "asynchronous, parity\n");
+ break;
+ default:seq_printf(m, "synchronous, pipelined, no parity\n");
+ break;
+ }
+
+no_l2:
+ /* print info about SIMMs */
+ if (have_residual_data) {
+ int i;
+ seq_printf(m, "simms\t\t: ");
+ for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
+ if (res->Memories[i].SIMMSize != 0)
+ seq_printf(m, "%d:%ldM ", i,
+ (res->Memories[i].SIMMSize > 1024) ?
+ res->Memories[i].SIMMSize>>20 :
+ res->Memories[i].SIMMSize);
+ }
+ seq_printf(m, "\n");
+ }
+
+ return 0;
+}
+
+static void __prep
+prep_restart(char *cmd)
+{
+#define PREP_SP92 0x92 /* Special Port 92 */
+ local_irq_disable(); /* no interrupts */
+
+ /* set exception prefix high - to the prom */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb( inb(PREP_SP92) & ~1L , PREP_SP92);
+ /* signal a reset to system control port A - soft reset */
+ outb( inb(PREP_SP92) | 1 , PREP_SP92);
+
+ while ( 1 ) ;
+ /* not reached */
+#undef PREP_SP92
+}
+
+static void __prep
+prep_halt(void)
+{
+ local_irq_disable(); /* no interrupts */
+
+ /* set exception prefix high - to the prom */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ while ( 1 ) ;
+ /* not reached */
+}
+
+/* Carrera is the power manager in the Thinkpads. Unfortunately not much is
+ * known about it, so we can't power down.
+ */
+static void __prep
+prep_carrera_poweroff(void)
+{
+ prep_halt();
+}
+
+/*
+ * On most IBM PReP's, power management is handled by a Signetics 87c750
+ * behind the Utah component on the ISA bus. To access the 750 you must write
+ * a series of nibbles to port 0x82a (decoded by the Utah). This is described
+ * somewhat in the IBM Carolina Technical Specification.
+ * -Hollis
+ */
+static void __prep
+utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
+{
+ /*
+ * byte1: 0 0 0 1 0 d a5 a4
+ * byte2: 0 0 0 1 a3 a2 a1 a0
+ *
+ * d = the bit's value, enabled or disabled
+ * (a5 a4 a3) = the byte number, minus 20
+ * (a2 a1 a0) = the bit number
+ *
+ * example: set the 5th bit of byte 21 (21.5)
+ * a5 a4 a3 = 001 (byte 1)
+ * a2 a1 a0 = 101 (bit 5)
+ *
+ * byte1 = 0001 0100 (0x14)
+ * byte2 = 0001 1101 (0x1d)
+ */
+ unsigned char byte1=0x10, byte2=0x10;
+
+ /* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
+ bytenum -= 20;
+
+ byte1 |= (!!value) << 2; /* set d */
+ byte1 |= (bytenum >> 1) & 0x3; /* set a5, a4 */
+
+ byte2 |= (bytenum & 0x1) << 3; /* set a3 */
+ byte2 |= bitnum & 0x7; /* set a2, a1, a0 */
+
+ outb(byte1, PREP_IBM_PM1); /* first nibble */
+ mb();
+ udelay(100); /* important: let controller recover */
+
+ outb(byte2, PREP_IBM_PM1); /* second nibble */
+ mb();
+ udelay(100); /* important: let controller recover */
+}
+
+static void __prep
+prep_sig750_poweroff(void)
+{
+ /* tweak the power manager found in most IBM PRePs (except Thinkpads) */
+
+ local_irq_disable();
+ /* set exception prefix high - to the prom */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
+
+ while (1) ;
+ /* not reached */
+}
+
+static int __prep
+prep_show_percpuinfo(struct seq_file *m, int i)
+{
+ /* PREP's without residual data will give incorrect values here */
+ seq_printf(m, "clock\t\t: ");
+ if (have_residual_data)
+ seq_printf(m, "%ldMHz\n",
+ (res->VitalProductData.ProcessorHz > 1024) ?
+ res->VitalProductData.ProcessorHz / 1000000 :
+ res->VitalProductData.ProcessorHz);
+ else
+ seq_printf(m, "???\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_SOUND_CS4232
+static long __init masktoint(unsigned int i)
+{
+ int t = -1;
+ while (i >> ++t)
+ ;
+ return (t-1);
+}
+
+/*
+ * ppc_cs4232_dma and ppc_cs4232_dma2 are used in include/asm/dma.h
+ * to distinguish sound dma-channels from others. This is because
+ * blocksize on 16 bit dma-channels 5,6,7 is 128k, but
+ * the cs4232.c uses 64k like on 8 bit dma-channels 0,1,2,3
+ */
+
+static void __init prep_init_sound(void)
+{
+ PPC_DEVICE *audiodevice = NULL;
+
+ /*
+ * Get the needed resource informations from residual data.
+ *
+ */
+ if (have_residual_data)
+ audiodevice = residual_find_device(~0, NULL,
+ MultimediaController, AudioController, -1, 0);
+
+ if (audiodevice != NULL) {
+ PnP_TAG_PACKET *pkt;
+
+ pkt = PnP_find_packet((unsigned char *)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
+ S5_Packet, 0);
+ if (pkt != NULL)
+ ppc_cs4232_dma = masktoint(pkt->S5_Pack.DMAMask);
+ pkt = PnP_find_packet((unsigned char*)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
+ S5_Packet, 1);
+ if (pkt != NULL)
+ ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask);
+ }
+
+ /*
+ * These are the PReP specs' defaults for the cs4231. We use these
+ * as fallback incase we don't have residual data.
+ * At least the IBM Thinkpad 850 with IDE DMA Channels at 6 and 7
+ * will use the other values.
+ */
+ if (audiodevice == NULL) {
+ switch (_prep_type) {
+ case _PREP_IBM:
+ ppc_cs4232_dma = 1;
+ ppc_cs4232_dma2 = -1;
+ break;
+ default:
+ ppc_cs4232_dma = 6;
+ ppc_cs4232_dma2 = 7;
+ }
+ }
+
+ /*
+ * Find a way to push these informations to the cs4232 driver
+ * Give it out with printk, when not in cmd_line?
+ * Append it to cmd_line and saved_command_line?
+ * Format is cs4232=io,irq,dma,dma2
+ */
+}
+#endif /* CONFIG_SOUND_CS4232 */
+
+/*
+ * Fill out screen_info according to the residual data. This allows us to use
+ * at least vesafb.
+ */
+static void __init
+prep_init_vesa(void)
+{
+#if (defined(CONFIG_FB_VGA16) || defined(CONFIG_FB_VGA16_MODULE) || \
+ defined(CONFIG_FB_VESA))
+ PPC_DEVICE *vgadev = NULL;
+
+ if (have_residual_data)
+ vgadev = residual_find_device(~0, NULL, DisplayController,
+ SVGAController, -1, 0);
+
+ if (vgadev != NULL) {
+ PnP_TAG_PACKET *pkt;
+
+ pkt = PnP_find_large_vendor_packet(
+ (unsigned char *)&res->DevicePnPHeap[vgadev->AllocatedOffset],
+ 0x04, 0); /* 0x04 = Display Tag */
+ if (pkt != NULL) {
+ unsigned char *ptr = (unsigned char *)pkt;
+
+ if (ptr[4]) {
+ /* graphics mode */
+ screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
+
+ screen_info.lfb_depth = ptr[4] * 8;
+
+ screen_info.lfb_width = swab16(*(short *)(ptr+6));
+ screen_info.lfb_height = swab16(*(short *)(ptr+8));
+ screen_info.lfb_linelength = swab16(*(short *)(ptr+10));
+
+ screen_info.lfb_base = swab32(*(long *)(ptr+12));
+ screen_info.lfb_size = swab32(*(long *)(ptr+20)) / 65536;
+ }
+ }
+ }
+#endif
+}
+
+/*
+ * Set DBAT 2 to access 0x80000000 so early progress messages will work
+ */
+static __inline__ void
+prep_set_bat(void)
+{
+ /* wait for all outstanding memory access to complete */
+ mb();
+
+ /* setup DBATs */
+ mtspr(SPRN_DBAT2U, 0x80001ffe);
+ mtspr(SPRN_DBAT2L, 0x8000002a);
+
+ /* wait for updates */
+ mb();
+}
+
+/*
+ * IBM 3-digit status LED
+ */
+static unsigned int ibm_statusled_base __prepdata;
+
+static void __prep
+ibm_statusled_progress(char *s, unsigned short hex);
+
+static int __prep
+ibm_statusled_panic(struct notifier_block *dummy1, unsigned long dummy2,
+ void * dummy3)
+{
+ ibm_statusled_progress(NULL, 0x505); /* SOS */
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ibm_statusled_block __prepdata = {
+ ibm_statusled_panic,
+ NULL,
+ INT_MAX /* try to do it first */
+};
+
+static void __prep
+ibm_statusled_progress(char *s, unsigned short hex)
+{
+ static int notifier_installed;
+ /*
+ * Progress uses 4 digits and we have only 3. So, we map 0xffff to
+ * 0xfff for display switch off. Out of range values are mapped to
+ * 0xeff, as I'm told 0xf00 and above are reserved for hardware codes.
+ * Install the panic notifier when the display is first switched off.
+ */
+ if (hex == 0xffff) {
+ hex = 0xfff;
+ if (!notifier_installed) {
+ ++notifier_installed;
+ notifier_chain_register(&panic_notifier_list,
+ &ibm_statusled_block);
+ }
+ }
+ else
+ if (hex > 0xfff)
+ hex = 0xeff;
+
+ mb();
+ outw(hex, ibm_statusled_base);
+}
+
+static void __init
+ibm_statusled_init(void)
+{
+ /*
+ * The IBM 3-digit LED display is specified in the residual data
+ * as an operator panel device, type "System Status LED". Find
+ * that device and determine its address. We validate all the
+ * other parameters on the off-chance another, similar device
+ * exists.
+ */
+ if (have_residual_data) {
+ PPC_DEVICE *led;
+ PnP_TAG_PACKET *pkt;
+
+ led = residual_find_device(~0, NULL, SystemPeripheral,
+ OperatorPanel, SystemStatusLED, 0);
+ if (!led)
+ return;
+
+ pkt = PnP_find_packet((unsigned char *)
+ &res->DevicePnPHeap[led->AllocatedOffset], S8_Packet, 0);
+ if (!pkt)
+ return;
+
+ if (pkt->S8_Pack.IOInfo != ISAAddr16bit)
+ return;
+ if (*(unsigned short *)pkt->S8_Pack.RangeMin !=
+ *(unsigned short *)pkt->S8_Pack.RangeMax)
+ return;
+ if (pkt->S8_Pack.IOAlign != 2)
+ return;
+ if (pkt->S8_Pack.IONum != 2)
+ return;
+
+ ibm_statusled_base = ld_le16((unsigned short *)
+ (pkt->S8_Pack.RangeMin));
+ ppc_md.progress = ibm_statusled_progress;
+ }
+}
+
+static void __init
+prep_setup_arch(void)
+{
+ unsigned char reg;
+ int is_ide=0;
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000;
+
+ /* Lookup PCI host bridges */
+ prep_find_bridges();
+
+ /* Set up floppy in PS/2 mode */
+ outb(0x09, SIO_CONFIG_RA);
+ reg = inb(SIO_CONFIG_RD);
+ reg = (reg & 0x3F) | 0x40;
+ outb(reg, SIO_CONFIG_RD);
+ outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
+
+ switch ( _prep_type )
+ {
+ case _PREP_IBM:
+ reg = inb(PREP_IBM_PLANAR);
+ printk(KERN_INFO "IBM planar ID: %02x", reg);
+ switch (reg) {
+ case PREP_IBM_SANDALFOOT:
+ prep_gen_enable_l2();
+ setup_ibm_pci = prep_sandalfoot_setup_pci;
+ ppc_md.power_off = prep_sig750_poweroff;
+ ppc_md.show_cpuinfo = prep_sandalfoot_cpuinfo;
+ break;
+ case PREP_IBM_THINKPAD:
+ prep_gen_enable_l2();
+ setup_ibm_pci = prep_thinkpad_setup_pci;
+ ppc_md.power_off = prep_carrera_poweroff;
+ ppc_md.show_cpuinfo = prep_thinkpad_cpuinfo;
+ break;
+ default:
+ if (have_residual_data) {
+ prep_gen_enable_l2();
+ setup_ibm_pci = prep_residual_setup_pci;
+ ppc_md.power_off = prep_halt;
+ ppc_md.show_cpuinfo = prep_gen_cpuinfo;
+ break;
+ }
+ else
+ printk(" - unknown! Assuming Carolina");
+ /* fall through */
+ case PREP_IBM_CAROLINA_IDE_0:
+ case PREP_IBM_CAROLINA_IDE_1:
+ case PREP_IBM_CAROLINA_IDE_2:
+ case PREP_IBM_CAROLINA_IDE_3:
+ is_ide = 1;
+ case PREP_IBM_CAROLINA_SCSI_0:
+ case PREP_IBM_CAROLINA_SCSI_1:
+ case PREP_IBM_CAROLINA_SCSI_2:
+ case PREP_IBM_CAROLINA_SCSI_3:
+ prep_carolina_enable_l2();
+ setup_ibm_pci = prep_carolina_setup_pci;
+ ppc_md.power_off = prep_sig750_poweroff;
+ ppc_md.show_cpuinfo = prep_carolina_cpuinfo;
+ break;
+ case PREP_IBM_TIGER1_133:
+ case PREP_IBM_TIGER1_166:
+ case PREP_IBM_TIGER1_180:
+ case PREP_IBM_TIGER1_xxx:
+ case PREP_IBM_TIGER1_333:
+ prep_carolina_enable_l2();
+ setup_ibm_pci = prep_tiger1_setup_pci;
+ ppc_md.power_off = prep_sig750_poweroff;
+ ppc_md.show_cpuinfo = prep_tiger1_cpuinfo;
+ break;
+ }
+ printk("\n");
+
+ /* default root device */
+ if (is_ide)
+ ROOT_DEV = MKDEV(IDE0_MAJOR, 3);
+ else
+ ROOT_DEV = MKDEV(SCSI_DISK0_MAJOR, 3);
+
+ break;
+ case _PREP_Motorola:
+ prep_gen_enable_l2();
+ ppc_md.power_off = prep_halt;
+ ppc_md.show_cpuinfo = prep_mot_cpuinfo;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+ break;
+ }
+
+ /* Read in NVRAM data */
+ init_prep_nvram();
+
+ /* if no bootargs, look in NVRAM */
+ if ( cmd_line[0] == '\0' ) {
+ char *bootargs;
+ bootargs = prep_nvram_get_var("bootargs");
+ if (bootargs != NULL) {
+ strcpy(cmd_line, bootargs);
+ /* again.. */
+ strcpy(saved_command_line, cmd_line);
+ }
+ }
+
+#ifdef CONFIG_SOUND_CS4232
+ prep_init_sound();
+#endif /* CONFIG_SOUND_CS4232 */
+
+ prep_init_vesa();
+
+ switch (_prep_type) {
+ case _PREP_Motorola:
+ raven_init();
+ break;
+ case _PREP_IBM:
+ ibm_prep_init();
+ break;
+ }
+
+#ifdef CONFIG_VGA_CONSOLE
+ /* vgacon.c needs to know where we mapped IO memory in io_block_mapping() */
+ vgacon_remap_base = 0xf0000000;
+ conswitchp = &vga_con;
+#endif
+}
+
+/*
+ * First, see if we can get this information from the residual data.
+ * This is important on some IBM PReP systems. If we cannot, we let the
+ * TODC code handle doing this.
+ */
+static void __init
+prep_calibrate_decr(void)
+{
+ if (have_residual_data) {
+ unsigned long freq, divisor = 4;
+
+ if ( res->VitalProductData.ProcessorBusHz ) {
+ freq = res->VitalProductData.ProcessorBusHz;
+ printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ (freq/divisor)/1000000,
+ (freq/divisor)%1000000);
+ tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+ tb_ticks_per_jiffy = freq / HZ / divisor;
+ }
+ }
+ else
+ todc_calibrate_decr();
+}
+
+static unsigned int __prep
+prep_irq_canonicalize(u_int irq)
+{
+ if (irq == 2)
+ {
+ return 9;
+ }
+ else
+ {
+ return irq;
+ }
+}
+
+static void __init
+prep_init_IRQ(void)
+{
+ int i;
+ unsigned int pci_viddid, pci_did;
+
+ if (OpenPIC_Addr != NULL) {
+ openpic_init(NUM_8259_INTERRUPTS);
+ /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+ openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+ i8259_irq);
+ }
+ for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
+ irq_desc[i].handler = &i8259_pic;
+
+ if (have_residual_data) {
+ i8259_init(residual_isapic_addr());
+ return;
+ }
+
+ /* If we have a Raven PCI bridge or a Hawk PCI bridge / Memory
+ * controller, we poll (as they have a different int-ack address). */
+ early_read_config_dword(NULL, 0, 0, PCI_VENDOR_ID, &pci_viddid);
+ pci_did = (pci_viddid & 0xffff0000) >> 16;
+ if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA)
+ && ((pci_did == PCI_DEVICE_ID_MOTOROLA_RAVEN)
+ || (pci_did == PCI_DEVICE_ID_MOTOROLA_HAWK)))
+ i8259_init(0);
+ else
+ /* PCI interrupt ack address given in section 6.1.8 of the
+ * PReP specification. */
+ i8259_init(MPC10X_MAPA_PCI_INTACK_ADDR);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+static int __prep
+prep_ide_default_irq(unsigned long base)
+{
+ switch (base) {
+ case 0x1f0: return 13;
+ case 0x170: return 13;
+ case 0x1e8: return 11;
+ case 0x168: return 10;
+ case 0xfff0: return 14; /* MCP(N)750 ide0 */
+ case 0xffe0: return 15; /* MCP(N)750 ide1 */
+ default: return 0;
+ }
+}
+
+static unsigned long __prep
+prep_ide_default_io_base(int index)
+{
+ switch (index) {
+ case 0: return 0x1f0;
+ case 1: return 0x170;
+ case 2: return 0x1e8;
+ case 3: return 0x168;
+ default:
+ return 0;
+ }
+}
+#endif
+
+#ifdef CONFIG_SMP
+/* PReP (MTX) support */
+static int __init
+smp_prep_probe(void)
+{
+ extern int mot_multi;
+
+ if (mot_multi) {
+ openpic_request_IPIs();
+ smp_hw_index[1] = 1;
+ return 2;
+ }
+
+ return 1;
+}
+
+static void __init
+smp_prep_kick_cpu(int nr)
+{
+ *(unsigned long *)KERNELBASE = nr;
+ asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+ printk("CPU1 released, waiting\n");
+}
+
+static void __init
+smp_prep_setup_cpu(int cpu_nr)
+{
+ if (OpenPIC_Addr)
+ do_openpic_setup_cpu();
+}
+
+static struct smp_ops_t prep_smp_ops __prepdata = {
+ smp_openpic_message_pass,
+ smp_prep_probe,
+ smp_prep_kick_cpu,
+ smp_prep_setup_cpu,
+ .give_timebase = smp_generic_give_timebase,
+ .take_timebase = smp_generic_take_timebase,
+};
+#endif /* CONFIG_SMP */
+
+/*
+ * Setup the bat mappings we're going to load that cover
+ * the io areas. RAM was mapped by mapin_ram().
+ * -- Cort
+ */
+static void __init
+prep_map_io(void)
+{
+ io_block_mapping(0x80000000, PREP_ISA_IO_BASE, 0x10000000, _PAGE_IO);
+ io_block_mapping(0xf0000000, PREP_ISA_MEM_BASE, 0x08000000, _PAGE_IO);
+}
+
+static int __init
+prep_request_io(void)
+{
+ if (_machine == _MACH_prep) {
+#ifdef CONFIG_NVRAM
+ request_region(PREP_NVRAM_AS0, 0x8, "nvram");
+#endif
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+ }
+
+ return 0;
+}
+
+device_initcall(prep_request_io);
+
+void __init
+prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+#ifdef CONFIG_PREP_RESIDUAL
+ /* make a copy of residual data */
+ if ( r3 ) {
+ memcpy((void *)res,(void *)(r3+KERNELBASE),
+ sizeof(RESIDUAL));
+ }
+#endif
+
+ isa_io_base = PREP_ISA_IO_BASE;
+ isa_mem_base = PREP_ISA_MEM_BASE;
+ pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ /* figure out what kind of prep workstation we are */
+ if (have_residual_data) {
+ if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+ _prep_type = _PREP_IBM;
+ else
+ _prep_type = _PREP_Motorola;
+ }
+ else {
+ /* assume motorola if no residual (netboot?) */
+ _prep_type = _PREP_Motorola;
+ }
+
+#ifdef CONFIG_PREP_RESIDUAL
+ /* Switch off all residual data processing if the user requests it */
+ if (strstr(cmd_line, "noresidual") != NULL)
+ res = NULL;
+#endif
+
+ /* Initialise progress early to get maximum benefit */
+ prep_set_bat();
+ ibm_statusled_init();
+
+ ppc_md.setup_arch = prep_setup_arch;
+ ppc_md.show_percpuinfo = prep_show_percpuinfo;
+ ppc_md.show_cpuinfo = NULL; /* set in prep_setup_arch() */
+ ppc_md.irq_canonicalize = prep_irq_canonicalize;
+ ppc_md.init_IRQ = prep_init_IRQ;
+ /* this gets changed later on if we have an OpenPIC -- Cort */
+ ppc_md.get_irq = i8259_irq;
+
+ ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
+
+ ppc_md.restart = prep_restart;
+ ppc_md.power_off = NULL; /* set in prep_setup_arch() */
+ ppc_md.halt = prep_halt;
+
+ ppc_md.nvram_read_val = prep_nvram_read_val;
+ ppc_md.nvram_write_val = prep_nvram_write_val;
+
+ ppc_md.time_init = todc_time_init;
+ if (_prep_type == _PREP_IBM) {
+ ppc_md.rtc_read_val = todc_mc146818_read_val;
+ ppc_md.rtc_write_val = todc_mc146818_write_val;
+ TODC_INIT(TODC_TYPE_MC146818, RTC_PORT(0), NULL, RTC_PORT(1),
+ 8);
+ } else {
+ TODC_INIT(TODC_TYPE_MK48T59, PREP_NVRAM_AS0, PREP_NVRAM_AS1,
+ PREP_NVRAM_DATA, 8);
+ }
+
+ ppc_md.calibrate_decr = prep_calibrate_decr;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+
+ ppc_md.setup_io_mappings = prep_map_io;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.default_irq = prep_ide_default_irq;
+ ppc_ide_md.default_io_base = prep_ide_default_io_base;
+#endif
+
+#ifdef CONFIG_SMP
+ ppc_md.smp_ops = &prep_smp_ops;
+#endif /* CONFIG_SMP */
+}
diff --git a/arch/ppc/platforms/prpmc750.c b/arch/ppc/platforms/prpmc750.c
new file mode 100644
index 00000000000..c894e1ab593
--- /dev/null
+++ b/arch/ppc/platforms/prpmc750.c
@@ -0,0 +1,364 @@
+/*
+ * arch/ppc/platforms/prpmc750_setup.c
+ *
+ * Board setup routines for Motorola PrPMC750
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * 2001-2004 (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/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/ide.h>
+#include <linux/root_dev.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/uaccess.h>
+#include <asm/time.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/hawk.h>
+
+#include "prpmc750.h"
+
+extern unsigned long loops_per_jiffy;
+
+extern void gen550_progress(char *, unsigned short);
+
+static u_char prpmc750_openpic_initsenses[] __initdata =
+{
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HOSTINT0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UART */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_DEBUGINT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HAWK_WDT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UNUSED */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_ABORT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HOSTINT1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HOSTINT2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_HOSTINT3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_PMC_INTA */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_PMC_INTB */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_PMC_INTC */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_PMC_INTD */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UNUSED */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UNUSED */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC750_INT_UNUSED */
+};
+
+/*
+ * Motorola PrPMC750/PrPMC800 in PrPMCBASE or PrPMC-Carrier
+ * Combined irq tables. Only Base has IDSEL 14, only Carrier has 21 and 22.
+ */
+static inline int
+prpmc_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {12, 0, 0, 0}, /* IDSEL 14 - Ethernet, base */
+ {0, 0, 0, 0}, /* IDSEL 15 - unused */
+ {10, 11, 12, 9}, /* IDSEL 16 - PMC A1, PMC1 */
+ {10, 11, 12, 9}, /* IDSEL 17 - PrPMC-A-B, PMC2-B */
+ {11, 12, 9, 10}, /* IDSEL 18 - PMC A1-B, PMC1-B */
+ {0, 0, 0, 0}, /* IDSEL 19 - unused */
+ {9, 10, 11, 12}, /* IDSEL 20 - P2P Bridge */
+ {11, 12, 9, 10}, /* IDSEL 21 - PMC A2, carrier */
+ {12, 9, 10, 11}, /* IDSEL 22 - PMC A2-B, carrier */
+ };
+ const long min_idsel = 14, max_idsel = 22, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+};
+
+static void __init prpmc750_pcibios_fixup(void)
+{
+ struct pci_dev *dev;
+ unsigned short wtmp;
+
+ /*
+ * Kludge to clean up after PPC6BUG which doesn't
+ * configure the CL5446 VGA card. Also the
+ * resource subsystem doesn't fixup the
+ * PCI mem resources on the CL5446.
+ */
+ if ((dev = pci_get_device(PCI_VENDOR_ID_CIRRUS,
+ PCI_DEVICE_ID_CIRRUS_5446, 0))) {
+ dev->resource[0].start += PRPMC750_PCI_PHY_MEM_OFFSET;
+ dev->resource[0].end += PRPMC750_PCI_PHY_MEM_OFFSET;
+ pci_read_config_word(dev, PCI_COMMAND, &wtmp);
+ pci_write_config_word(dev, PCI_COMMAND, wtmp | 3);
+ /* Enable Color mode in MISC reg */
+ outb(0x03, 0x3c2);
+ /* Select DRAM config reg */
+ outb(0x0f, 0x3c4);
+ /* Set proper DRAM config */
+ outb(0xdf, 0x3c5);
+ pci_dev_put(dev);
+ }
+}
+
+void __init prpmc750_find_bridges(void)
+{
+ struct pci_controller *hose;
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+ hose->io_base_virt = (void *)PRPMC750_ISA_IO_BASE;
+ hose->pci_mem_offset = PRPMC750_PCI_PHY_MEM_OFFSET;
+
+ pci_init_resource(&hose->io_resource,
+ PRPMC750_PCI_IO_START,
+ PRPMC750_PCI_IO_END,
+ IORESOURCE_IO, "PCI host bridge");
+
+ pci_init_resource(&hose->mem_resources[0],
+ PRPMC750_PROC_PCI_MEM_START,
+ PRPMC750_PROC_PCI_MEM_END,
+ IORESOURCE_MEM, "PCI host bridge");
+
+ hose->io_space.start = PRPMC750_PCI_IO_START;
+ hose->io_space.end = PRPMC750_PCI_IO_END;
+ hose->mem_space.start = PRPMC750_PCI_MEM_START;
+ hose->mem_space.end = PRPMC750_PCI_MEM_END - HAWK_MPIC_SIZE;
+
+ if (hawk_init(hose, PRPMC750_HAWK_PPC_REG_BASE,
+ PRPMC750_PROC_PCI_MEM_START,
+ PRPMC750_PROC_PCI_MEM_END - HAWK_MPIC_SIZE,
+ PRPMC750_PROC_PCI_IO_START, PRPMC750_PROC_PCI_IO_END,
+ PRPMC750_PROC_PCI_MEM_END - HAWK_MPIC_SIZE + 1)
+ != 0) {
+ printk(KERN_CRIT "Could not initialize host bridge\n");
+ }
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pcibios_fixup = prpmc750_pcibios_fixup;
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = prpmc_map_irq;
+}
+static int prpmc750_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "machine\t\t: PrPMC750\n");
+
+ return 0;
+}
+
+static void __init prpmc750_setup_arch(void)
+{
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000 / HZ;
+
+ /* Lookup PCI host bridges */
+ prpmc750_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ OpenPIC_InitSenses = prpmc750_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(prpmc750_openpic_initsenses);
+
+ printk(KERN_INFO "Port by MontaVista Software, Inc. "
+ "(source@mvista.com)\n");
+}
+
+/*
+ * Compute the PrPMC750's bus speed using the baud clock as a
+ * reference.
+ */
+static unsigned long __init prpmc750_get_bus_speed(void)
+{
+ unsigned long tbl_start, tbl_end;
+ unsigned long current_state, old_state, bus_speed;
+ unsigned char lcr, dll, dlm;
+ int baud_divisor, count;
+
+ /* Read the UART's baud clock divisor */
+ lcr = readb(PRPMC750_SERIAL_0_LCR);
+ writeb(lcr | UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR);
+ dll = readb(PRPMC750_SERIAL_0_DLL);
+ dlm = readb(PRPMC750_SERIAL_0_DLM);
+ writeb(lcr & ~UART_LCR_DLAB, PRPMC750_SERIAL_0_LCR);
+ baud_divisor = (dlm << 8) | dll;
+
+ /*
+ * Use the baud clock divisor and base baud clock
+ * to determine the baud rate and use that as
+ * the number of baud clock edges we use for
+ * the time base sample. Make it half the baud
+ * rate.
+ */
+ count = PRPMC750_BASE_BAUD / (baud_divisor * 16);
+
+ /* Find the first edge of the baud clock */
+ old_state = readb(PRPMC750_STATUS_REG) & PRPMC750_BAUDOUT_MASK;
+ do {
+ current_state = readb(PRPMC750_STATUS_REG) &
+ PRPMC750_BAUDOUT_MASK;
+ } while (old_state == current_state);
+
+ old_state = current_state;
+
+ /* Get the starting time base value */
+ tbl_start = get_tbl();
+
+ /*
+ * Loop until we have found a number of edges equal
+ * to half the count (half the baud rate)
+ */
+ do {
+ do {
+ current_state = readb(PRPMC750_STATUS_REG) &
+ PRPMC750_BAUDOUT_MASK;
+ } while (old_state == current_state);
+ old_state = current_state;
+ } while (--count);
+
+ /* Get the ending time base value */
+ tbl_end = get_tbl();
+
+ /* Compute bus speed */
+ bus_speed = (tbl_end - tbl_start) * 128;
+
+ return bus_speed;
+}
+
+static void __init prpmc750_calibrate_decr(void)
+{
+ unsigned long freq;
+ int divisor = 4;
+
+ freq = prpmc750_get_bus_speed();
+
+ tb_ticks_per_jiffy = freq / (HZ * divisor);
+ tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
+}
+
+static void prpmc750_restart(char *cmd)
+{
+ local_irq_disable();
+ writeb(PRPMC750_MODRST_MASK, PRPMC750_MODRST_REG);
+ while (1) ;
+}
+
+static void prpmc750_halt(void)
+{
+ local_irq_disable();
+ while (1) ;
+}
+
+static void prpmc750_power_off(void)
+{
+ prpmc750_halt();
+}
+
+static void __init prpmc750_init_IRQ(void)
+{
+ openpic_init(0);
+}
+
+/*
+ * Set BAT 3 to map 0xf0000000 to end of physical memory space.
+ */
+static __inline__ void prpmc750_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT1U, 0xf0001ffe);
+ mtspr(SPRN_DBAT1L, 0xf000002a);
+ mb();
+}
+
+/*
+ * We need to read the Falcon/Hawk memory controller
+ * to properly determine this value
+ */
+static unsigned long __init prpmc750_find_end_of_memory(void)
+{
+ /* Read the memory size from the Hawk SMC */
+ return hawk_get_mem_size(PRPMC750_HAWK_SMC_BASE);
+}
+
+static void __init prpmc750_map_io(void)
+{
+ io_block_mapping(PRPMC750_ISA_IO_BASE, PRPMC750_ISA_IO_BASE,
+ 0x10000000, _PAGE_IO);
+#if 0
+ io_block_mapping(0xf0000000, 0xc0000000, 0x08000000, _PAGE_IO);
+#endif
+ io_block_mapping(0xf8000000, 0xf8000000, 0x08000000, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /* Cover the Hawk registers with a BAT */
+ prpmc750_set_bat();
+
+ isa_io_base = PRPMC750_ISA_IO_BASE;
+ isa_mem_base = PRPMC750_ISA_MEM_BASE;
+ pci_dram_offset = PRPMC750_PCI_DRAM_OFFSET;
+
+ ppc_md.setup_arch = prpmc750_setup_arch;
+ ppc_md.show_cpuinfo = prpmc750_show_cpuinfo;
+ ppc_md.init_IRQ = prpmc750_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.find_end_of_memory = prpmc750_find_end_of_memory;
+ ppc_md.setup_io_mappings = prpmc750_map_io;
+
+ ppc_md.restart = prpmc750_restart;
+ ppc_md.power_off = prpmc750_power_off;
+ ppc_md.halt = prpmc750_halt;
+
+ /* PrPMC750 has no timekeeper part */
+ ppc_md.time_init = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.calibrate_decr = prpmc750_calibrate_decr;
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+}
diff --git a/arch/ppc/platforms/prpmc750.h b/arch/ppc/platforms/prpmc750.h
new file mode 100644
index 00000000000..015b4f52c3e
--- /dev/null
+++ b/arch/ppc/platforms/prpmc750.h
@@ -0,0 +1,95 @@
+/*
+ * include/asm-ppc/platforms/prpmc750.h
+ *
+ * Definitions for Motorola PrPMC750 board support
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * 2001-2004 (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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_PRPMC750_H__
+#define __ASM_PRPMC750_H__
+
+/*
+ * Due to limiations imposed by legacy hardware (primaryily IDE controllers),
+ * the PrPMC750 carrier board operates using a PReP address map.
+ *
+ * From Processor (physical) -> PCI:
+ * PCI Mem Space: 0xc0000000 - 0xfe000000 -> 0x00000000 - 0x3e000000 (768 MB)
+ * PCI I/O Space: 0x80000000 - 0x90000000 -> 0x00000000 - 0x10000000 (256 MB)
+ * Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area
+ *
+ * From PCI -> Processor (physical):
+ * System Memory: 0x80000000 -> 0x00000000
+ */
+
+#define PRPMC750_ISA_IO_BASE PREP_ISA_IO_BASE
+#define PRPMC750_ISA_MEM_BASE PREP_ISA_MEM_BASE
+
+/* PCI Memory space mapping info */
+#define PRPMC750_PCI_MEM_SIZE 0x30000000U
+#define PRPMC750_PROC_PCI_MEM_START PRPMC750_ISA_MEM_BASE
+#define PRPMC750_PROC_PCI_MEM_END (PRPMC750_PROC_PCI_MEM_START + \
+ PRPMC750_PCI_MEM_SIZE - 1)
+#define PRPMC750_PCI_MEM_START 0x00000000U
+#define PRPMC750_PCI_MEM_END (PRPMC750_PCI_MEM_START + \
+ PRPMC750_PCI_MEM_SIZE - 1)
+
+/* PCI I/O space mapping info */
+#define PRPMC750_PCI_IO_SIZE 0x10000000U
+#define PRPMC750_PROC_PCI_IO_START PRPMC750_ISA_IO_BASE
+#define PRPMC750_PROC_PCI_IO_END (PRPMC750_PROC_PCI_IO_START + \
+ PRPMC750_PCI_IO_SIZE - 1)
+#define PRPMC750_PCI_IO_START 0x00000000U
+#define PRPMC750_PCI_IO_END (PRPMC750_PCI_IO_START + \
+ PRPMC750_PCI_IO_SIZE - 1)
+
+/* System memory mapping info */
+#define PRPMC750_PCI_DRAM_OFFSET PREP_PCI_DRAM_OFFSET
+#define PRPMC750_PCI_PHY_MEM_OFFSET (PRPMC750_ISA_MEM_BASE-PRPMC750_PCI_MEM_START)
+
+/* Register address definitions */
+#define PRPMC750_HAWK_SMC_BASE 0xfef80000U
+#define PRPMC750_HAWK_PPC_REG_BASE 0xfeff0000U
+
+#define PRPMC750_BASE_BAUD 1843200
+#define PRPMC750_SERIAL_0 0xfef88000
+#define PRPMC750_SERIAL_0_DLL (PRPMC750_SERIAL_0 + (UART_DLL << 4))
+#define PRPMC750_SERIAL_0_DLM (PRPMC750_SERIAL_0 + (UART_DLM << 4))
+#define PRPMC750_SERIAL_0_LCR (PRPMC750_SERIAL_0 + (UART_LCR << 4))
+
+#define PRPMC750_STATUS_REG 0xfef88080
+#define PRPMC750_BAUDOUT_MASK 0x02
+#define PRPMC750_MONARCH_MASK 0x01
+
+#define PRPMC750_MODRST_REG 0xfef880a0
+#define PRPMC750_MODRST_MASK 0x01
+
+#define PRPMC750_PIRQ_REG 0xfef880b0
+#define PRPMC750_SEL1_MASK 0x02
+#define PRPMC750_SEL0_MASK 0x01
+
+#define PRPMC750_TBEN_REG 0xfef880c0
+#define PRPMC750_TBEN_MASK 0x01
+
+/* UART Defines. */
+#define RS_TABLE_SIZE 4
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define BASE_BAUD (PRPMC750_BASE_BAUD / 16)
+
+#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
+
+#define SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, PRPMC750_SERIAL_0, 1, STD_COM_FLAGS, \
+ iomem_base: (unsigned char *)PRPMC750_SERIAL_0, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM } /* ttyS0 */
+
+#endif /* __ASM_PRPMC750_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/prpmc800.c b/arch/ppc/platforms/prpmc800.c
new file mode 100644
index 00000000000..8b09fa69b35
--- /dev/null
+++ b/arch/ppc/platforms/prpmc800.c
@@ -0,0 +1,477 @@
+/*
+ * arch/ppc/platforms/prpmc800.c
+ *
+ * Author: Dale Farnsworth <dale.farnsworth@mvista.com>
+ *
+ * 2001-2004 (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/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/ide.h>
+#include <linux/root_dev.h>
+#include <linux/harrier_defs.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/harrier.h>
+
+#include "prpmc800.h"
+
+#define HARRIER_REVI_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_REVI_OFF)
+#define HARRIER_UCTL_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_UCTL_OFF)
+#define HARRIER_MISC_CSR_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_MISC_CSR_OFF)
+#define HARRIER_IFEVP_REG (PRPMC800_HARRIER_MPIC_BASE+HARRIER_MPIC_IFEVP_OFF)
+#define HARRIER_IFEDE_REG (PRPMC800_HARRIER_MPIC_BASE+HARRIER_MPIC_IFEDE_OFF)
+#define HARRIER_FEEN_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_FEEN_OFF)
+#define HARRIER_FEMA_REG (PRPMC800_HARRIER_XCSR_BASE+HARRIER_FEMA_OFF)
+
+#define HARRIER_VENI_REG (PRPMC800_HARRIER_XCSR_BASE + HARRIER_VENI_OFF)
+#define HARRIER_MISC_CSR (PRPMC800_HARRIER_XCSR_BASE + \
+ HARRIER_MISC_CSR_OFF)
+
+#define MONARCH (monarch != 0)
+#define NON_MONARCH (monarch == 0)
+
+extern int mpic_init(void);
+extern unsigned long loops_per_jiffy;
+extern void gen550_progress(char *, unsigned short);
+
+static int monarch = 0;
+static int found_self = 0;
+static int self = 0;
+
+static u_char prpmc800_openpic_initsenses[] __initdata =
+{
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HOSTINT0 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_DEBUGINT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HARRIER_WDT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HOSTINT1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HOSTINT2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HOSTINT3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_PMC_INTA */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_PMC_INTB */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_PMC_INTC */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_PMC_INTD */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_UNUSED */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PRPMC800_INT_HARRIER_INT (UARTS, ABORT, DMA) */
+};
+
+/*
+ * Motorola PrPMC750/PrPMC800 in PrPMCBASE or PrPMC-Carrier
+ * Combined irq tables. Only Base has IDSEL 14, only Carrier has 21 and 22.
+ */
+static inline int
+prpmc_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {12, 0, 0, 0}, /* IDSEL 14 - Ethernet, base */
+ {0, 0, 0, 0}, /* IDSEL 15 - unused */
+ {10, 11, 12, 9}, /* IDSEL 16 - PMC A1, PMC1 */
+ {10, 11, 12, 9}, /* IDSEL 17 - PrPMC-A-B, PMC2-B */
+ {11, 12, 9, 10}, /* IDSEL 18 - PMC A1-B, PMC1-B */
+ {0, 0, 0, 0}, /* IDSEL 19 - unused */
+ {9, 10, 11, 12}, /* IDSEL 20 - P2P Bridge */
+ {11, 12, 9, 10}, /* IDSEL 21 - PMC A2, carrier */
+ {12, 9, 10, 11}, /* IDSEL 22 - PMC A2-B, carrier */
+ };
+ const long min_idsel = 14, max_idsel = 22, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+};
+
+static int
+prpmc_read_config_dword(struct pci_controller *hose, u8 bus, u8 devfn,
+ int offset, u32 * val)
+{
+ /* paranoia */
+ if ((hose == NULL) ||
+ (hose->cfg_addr == NULL) || (hose->cfg_data == NULL))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ out_be32(hose->cfg_addr, ((offset & 0xfc) << 24) | (devfn << 16)
+ | ((bus - hose->bus_offset) << 8) | 0x80);
+ *val = in_le32((u32 *) (hose->cfg_data + (offset & 3)));
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+#define HARRIER_PCI_VEND_DEV_ID (PCI_VENDOR_ID_MOTOROLA | \
+ (PCI_DEVICE_ID_MOTOROLA_HARRIER << 16))
+static int prpmc_self(u8 bus, u8 devfn)
+{
+ /*
+ * Harriers always view themselves as being on bus 0. If we're not
+ * looking at bus 0, we're not going to find ourselves.
+ */
+ if (bus != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else {
+ int result;
+ int val;
+ struct pci_controller *hose;
+
+ hose = pci_bus_to_hose(bus);
+
+ /* See if target device is a Harrier */
+ result = prpmc_read_config_dword(hose, bus, devfn,
+ PCI_VENDOR_ID, &val);
+ if ((result != PCIBIOS_SUCCESSFUL) ||
+ (val != HARRIER_PCI_VEND_DEV_ID))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /*
+ * LBA bit is set if target Harrier == initiating Harrier
+ * (i.e. if we are reading our own PCI header).
+ */
+ result = prpmc_read_config_dword(hose, bus, devfn,
+ HARRIER_LBA_OFF, &val);
+ if ((result != PCIBIOS_SUCCESSFUL) ||
+ ((val & HARRIER_LBA_MSK) != HARRIER_LBA_MSK))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /* It's us, save our location for later */
+ self = devfn;
+ found_self = 1;
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+static int prpmc_exclude_device(u8 bus, u8 devfn)
+{
+ /*
+ * Monarch is allowed to access all PCI devices. Non-monarch is
+ * only allowed to access its own Harrier.
+ */
+
+ if (MONARCH)
+ return PCIBIOS_SUCCESSFUL;
+ if (found_self)
+ if ((bus == 0) && (devfn == self))
+ return PCIBIOS_SUCCESSFUL;
+ else
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return prpmc_self(bus, devfn);
+}
+
+void __init prpmc800_find_bridges(void)
+{
+ struct pci_controller *hose;
+ int host_bridge;
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ ppc_md.pci_exclude_device = prpmc_exclude_device;
+ ppc_md.pcibios_fixup = NULL;
+ ppc_md.pcibios_fixup_bus = NULL;
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = prpmc_map_irq;
+
+ setup_indirect_pci(hose,
+ PRPMC800_PCI_CONFIG_ADDR, PRPMC800_PCI_CONFIG_DATA);
+
+ /* Get host bridge vendor/dev id */
+
+ host_bridge = in_be32((uint *) (HARRIER_VENI_REG));
+
+ if (host_bridge != HARRIER_VEND_DEV_ID) {
+ printk(KERN_CRIT "Host bridge 0x%x not supported\n",
+ host_bridge);
+ return;
+ }
+
+ monarch = in_be32((uint *) HARRIER_MISC_CSR) & HARRIER_SYSCON;
+
+ printk(KERN_INFO "Running as %s.\n",
+ MONARCH ? "Monarch" : "Non-Monarch");
+
+ hose->io_space.start = PRPMC800_PCI_IO_START;
+ hose->io_space.end = PRPMC800_PCI_IO_END;
+ hose->io_base_virt = (void *)PRPMC800_ISA_IO_BASE;
+ hose->pci_mem_offset = PRPMC800_PCI_PHY_MEM_OFFSET;
+
+ pci_init_resource(&hose->io_resource,
+ PRPMC800_PCI_IO_START, PRPMC800_PCI_IO_END,
+ IORESOURCE_IO, "PCI host bridge");
+
+ if (MONARCH) {
+ hose->mem_space.start = PRPMC800_PCI_MEM_START;
+ hose->mem_space.end = PRPMC800_PCI_MEM_END;
+
+ pci_init_resource(&hose->mem_resources[0],
+ PRPMC800_PCI_MEM_START,
+ PRPMC800_PCI_MEM_END,
+ IORESOURCE_MEM, "PCI host bridge");
+
+ if (harrier_init(hose,
+ PRPMC800_HARRIER_XCSR_BASE,
+ PRPMC800_PROC_PCI_MEM_START,
+ PRPMC800_PROC_PCI_MEM_END,
+ PRPMC800_PROC_PCI_IO_START,
+ PRPMC800_PROC_PCI_IO_END,
+ PRPMC800_HARRIER_MPIC_BASE) != 0)
+ printk(KERN_CRIT "Could not initialize HARRIER "
+ "bridge\n");
+
+ harrier_release_eready(PRPMC800_HARRIER_XCSR_BASE);
+ harrier_wait_eready(PRPMC800_HARRIER_XCSR_BASE);
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ } else {
+ pci_init_resource(&hose->mem_resources[0],
+ PRPMC800_NM_PCI_MEM_START,
+ PRPMC800_NM_PCI_MEM_END,
+ IORESOURCE_MEM, "PCI host bridge");
+
+ hose->mem_space.start = PRPMC800_NM_PCI_MEM_START;
+ hose->mem_space.end = PRPMC800_NM_PCI_MEM_END;
+
+ if (harrier_init(hose,
+ PRPMC800_HARRIER_XCSR_BASE,
+ PRPMC800_NM_PROC_PCI_MEM_START,
+ PRPMC800_NM_PROC_PCI_MEM_END,
+ PRPMC800_PROC_PCI_IO_START,
+ PRPMC800_PROC_PCI_IO_END,
+ PRPMC800_HARRIER_MPIC_BASE) != 0)
+ printk(KERN_CRIT "Could not initialize HARRIER "
+ "bridge\n");
+
+ harrier_setup_nonmonarch(PRPMC800_HARRIER_XCSR_BASE,
+ HARRIER_ITSZ_1MB);
+ harrier_release_eready(PRPMC800_HARRIER_XCSR_BASE);
+ }
+}
+
+static int prpmc800_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "machine\t\t: PrPMC800\n");
+
+ return 0;
+}
+
+static void __init prpmc800_setup_arch(void)
+{
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000 / HZ;
+
+ /* Lookup PCI host bridges */
+ prpmc800_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA2;
+#endif
+
+ printk(KERN_INFO "Port by MontaVista Software, Inc. "
+ "(source@mvista.com)\n");
+}
+
+/*
+ * Compute the PrPMC800's tbl frequency using the baud clock as a reference.
+ */
+static void __init prpmc800_calibrate_decr(void)
+{
+ unsigned long tbl_start, tbl_end;
+ unsigned long current_state, old_state, tb_ticks_per_second;
+ unsigned int count;
+ unsigned int harrier_revision;
+
+ harrier_revision = readb(HARRIER_REVI_REG);
+ if (harrier_revision < 2) {
+ /* XTAL64 was broken in harrier revision 1 */
+ printk(KERN_INFO "time_init: Harrier revision %d, assuming "
+ "100 Mhz bus\n", harrier_revision);
+ tb_ticks_per_second = 100000000 / 4;
+ tb_ticks_per_jiffy = tb_ticks_per_second / HZ;
+ tb_to_us = mulhwu_scale_factor(tb_ticks_per_second, 1000000);
+ return;
+ }
+
+ /*
+ * The XTAL64 bit oscillates at the 1/64 the base baud clock
+ * Set count to XTAL64 cycles per second. Since we'll count
+ * half-cycles, we'll reach the count in half a second.
+ */
+ count = PRPMC800_BASE_BAUD / 64;
+
+ /* Find the first edge of the baud clock */
+ old_state = readb(HARRIER_UCTL_REG) & HARRIER_XTAL64_MASK;
+ do {
+ current_state = readb(HARRIER_UCTL_REG) & HARRIER_XTAL64_MASK;
+ } while (old_state == current_state);
+
+ old_state = current_state;
+
+ /* Get the starting time base value */
+ tbl_start = get_tbl();
+
+ /*
+ * Loop until we have found a number of edges (half-cycles)
+ * equal to the count (half a second)
+ */
+ do {
+ do {
+ current_state = readb(HARRIER_UCTL_REG) &
+ HARRIER_XTAL64_MASK;
+ } while (old_state == current_state);
+ old_state = current_state;
+ } while (--count);
+
+ /* Get the ending time base value */
+ tbl_end = get_tbl();
+
+ /* We only counted for half a second, so double to get ticks/second */
+ tb_ticks_per_second = (tbl_end - tbl_start) * 2;
+ tb_ticks_per_jiffy = tb_ticks_per_second / HZ;
+ tb_to_us = mulhwu_scale_factor(tb_ticks_per_second, 1000000);
+}
+
+static void prpmc800_restart(char *cmd)
+{
+ ulong temp;
+
+ local_irq_disable();
+ temp = in_be32((uint *) HARRIER_MISC_CSR_REG);
+ temp |= HARRIER_RSTOUT;
+ out_be32((uint *) HARRIER_MISC_CSR_REG, temp);
+ while (1) ;
+}
+
+static void prpmc800_halt(void)
+{
+ local_irq_disable();
+ while (1) ;
+}
+
+static void prpmc800_power_off(void)
+{
+ prpmc800_halt();
+}
+
+static void __init prpmc800_init_IRQ(void)
+{
+ OpenPIC_InitSenses = prpmc800_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(prpmc800_openpic_initsenses);
+
+ /* Setup external interrupt sources. */
+ openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000);
+ /* Setup internal UART interrupt source. */
+ openpic_set_sources(16, 1, OpenPIC_Addr + 0x10200);
+
+ /* Do the MPIC initialization based on the above settings. */
+ openpic_init(0);
+
+ /* enable functional exceptions for uarts and abort */
+ out_8((u8 *) HARRIER_FEEN_REG, (HARRIER_FE_UA0 | HARRIER_FE_UA1));
+ out_8((u8 *) HARRIER_FEMA_REG, ~(HARRIER_FE_UA0 | HARRIER_FE_UA1));
+}
+
+/*
+ * Set BAT 3 to map 0xf0000000 to end of physical memory space.
+ */
+static __inline__ void prpmc800_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT1U, 0xf0001ffe);
+ mtspr(SPRN_DBAT1L, 0xf000002a);
+ mb();
+}
+
+/*
+ * We need to read the Harrier memory controller
+ * to properly determine this value
+ */
+static unsigned long __init prpmc800_find_end_of_memory(void)
+{
+ /* Read the memory size from the Harrier XCSR */
+ return harrier_get_mem_size(PRPMC800_HARRIER_XCSR_BASE);
+}
+
+static void __init prpmc800_map_io(void)
+{
+ io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
+ io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ prpmc800_set_bat();
+
+ isa_io_base = PRPMC800_ISA_IO_BASE;
+ isa_mem_base = PRPMC800_ISA_MEM_BASE;
+ pci_dram_offset = PRPMC800_PCI_DRAM_OFFSET;
+
+ ppc_md.setup_arch = prpmc800_setup_arch;
+ ppc_md.show_cpuinfo = prpmc800_show_cpuinfo;
+ ppc_md.init_IRQ = prpmc800_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.find_end_of_memory = prpmc800_find_end_of_memory;
+ ppc_md.setup_io_mappings = prpmc800_map_io;
+
+ ppc_md.restart = prpmc800_restart;
+ ppc_md.power_off = prpmc800_power_off;
+ ppc_md.halt = prpmc800_halt;
+
+ /* PrPMC800 has no timekeeper part */
+ ppc_md.time_init = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.calibrate_decr = prpmc800_calibrate_decr;
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = gen550_progress;
+#else /* !CONFIG_SERIAL_TEXT_DEBUG */
+ ppc_md.progress = NULL;
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+}
diff --git a/arch/ppc/platforms/prpmc800.h b/arch/ppc/platforms/prpmc800.h
new file mode 100644
index 00000000000..e53ec9b42a3
--- /dev/null
+++ b/arch/ppc/platforms/prpmc800.h
@@ -0,0 +1,82 @@
+/*
+ * include/asm-ppc/platforms/prpmc800.h
+ *
+ * Definitions for Motorola PrPMC800 board support
+ *
+ * Author: Dale Farnsworth <dale.farnsworth@mvista.com>
+ *
+ * 2001-2004 (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.
+ */
+ /*
+ * From Processor to PCI:
+ * PCI Mem Space: 0x80000000 - 0xa0000000 -> 0x80000000 - 0xa0000000 (512 MB)
+ * PCI I/O Space: 0xfe400000 - 0xfeef0000 -> 0x00000000 - 0x00b00000 (11 MB)
+ * Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area
+ *
+ * From PCI to Processor:
+ * System Memory: 0x00000000 -> 0x00000000
+ */
+
+#ifndef __ASMPPC_PRPMC800_H
+#define __ASMPPC_PRPMC800_H
+
+#define PRPMC800_PCI_CONFIG_ADDR 0xfe000cf8
+#define PRPMC800_PCI_CONFIG_DATA 0xfe000cfc
+
+#define PRPMC800_PROC_PCI_IO_START 0xfe400000U
+#define PRPMC800_PROC_PCI_IO_END 0xfeefffffU
+#define PRPMC800_PCI_IO_START 0x00000000U
+#define PRPMC800_PCI_IO_END 0x00afffffU
+
+#define PRPMC800_PROC_PCI_MEM_START 0x80000000U
+#define PRPMC800_PROC_PCI_MEM_END 0x9fffffffU
+#define PRPMC800_PCI_MEM_START 0x80000000U
+#define PRPMC800_PCI_MEM_END 0x9fffffffU
+
+#define PRPMC800_NM_PROC_PCI_MEM_START 0x40000000U
+#define PRPMC800_NM_PROC_PCI_MEM_END 0xdfffffffU
+#define PRPMC800_NM_PCI_MEM_START 0x40000000U
+#define PRPMC800_NM_PCI_MEM_END 0xdfffffffU
+
+#define PRPMC800_PCI_DRAM_OFFSET 0x00000000U
+#define PRPMC800_PCI_PHY_MEM_OFFSET 0x00000000U
+
+#define PRPMC800_ISA_IO_BASE PRPMC800_PROC_PCI_IO_START
+#define PRPMC800_ISA_MEM_BASE 0x00000000U
+
+#define PRPMC800_HARRIER_XCSR_BASE HARRIER_DEFAULT_XCSR_BASE
+#define PRPMC800_HARRIER_MPIC_BASE 0xff000000
+
+#define PRPMC800_SERIAL_1 0xfeff00c0
+
+#define PRPMC800_BASE_BAUD 1843200
+
+/*
+ * interrupt vector number and priority for harrier internal interrupt
+ * sources
+ */
+#define PRPMC800_INT_IRQ 16
+#define PRPMC800_INT_PRI 15
+
+/* UART Defines. */
+#define RS_TABLE_SIZE 4
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define BASE_BAUD (PRPMC800_BASE_BAUD / 16)
+
+#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
+
+/* UARTS are at IRQ 16 */
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, PRPMC800_SERIAL_1, 16, STD_COM_FLAGS, /* ttyS0 */\
+ iomem_base: (unsigned char *)PRPMC800_SERIAL_1, \
+ iomem_reg_shift: 0, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
+
+#endif /* __ASMPPC_PRPMC800_H */
diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c
new file mode 100644
index 00000000000..2a99b43737a
--- /dev/null
+++ b/arch/ppc/platforms/radstone_ppc7d.c
@@ -0,0 +1,1452 @@
+/*
+ * arch/ppc/platforms/radstone_ppc7d.c
+ *
+ * Board setup routines for the Radstone PPC7D boards.
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by - Mark A. Greer <mgreer@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.
+ */
+
+/* Radstone PPC7D boards are rugged VME boards with PPC 7447A CPUs,
+ * Discovery-II, dual gigabit ethernet, dual PMC, USB, keyboard/mouse,
+ * 4 serial ports, 2 high speed serial ports (MPSCs) and optional
+ * SCSI / VGA.
+ */
+
+#include <linux/config.h>
+#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/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/mv643xx.h>
+#include <linux/netdevice.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/vga.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/mpc10x.h>
+#include <asm/pci-bridge.h>
+#include <asm/mv64x60.h>
+#include <asm/i8259.h>
+
+#include "radstone_ppc7d.h"
+
+#undef DEBUG
+
+#define PPC7D_RST_PIN 17 /* GPP17 */
+
+extern u32 mv64360_irq_base;
+
+static struct mv64x60_handle bh;
+static int ppc7d_has_alma;
+
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct uart_port *);
+
+/* residual data */
+unsigned char __res[sizeof(bd_t)];
+
+/*****************************************************************************
+ * Serial port code
+ *****************************************************************************/
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
+static void __init ppc7d_early_serial_map(void)
+{
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ mv64x60_progress_init(CONFIG_MV64X60_NEW_BASE);
+#elif defined(CONFIG_SERIAL_8250)
+ struct uart_port serial_req;
+
+ /* Setup serial port access */
+ memset(&serial_req, 0, sizeof(serial_req));
+ serial_req.uartclk = UART_CLK;
+ serial_req.irq = 4;
+ serial_req.flags = STD_COM_FLAGS;
+ serial_req.iotype = SERIAL_IO_MEM;
+ serial_req.membase = (u_char *) PPC7D_SERIAL_0;
+
+ gen550_init(0, &serial_req);
+ if (early_serial_setup(&serial_req) != 0)
+ printk(KERN_ERR "Early serial init of port 0 failed\n");
+
+ /* Assume early_serial_setup() doesn't modify serial_req */
+ serial_req.line = 1;
+ serial_req.irq = 3;
+ serial_req.membase = (u_char *) PPC7D_SERIAL_1;
+
+ gen550_init(1, &serial_req);
+ if (early_serial_setup(&serial_req) != 0)
+ printk(KERN_ERR "Early serial init of port 1 failed\n");
+#else
+#error CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX
+#endif
+}
+#endif /* CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG */
+
+/*****************************************************************************
+ * Low-level board support code
+ *****************************************************************************/
+
+static unsigned long __init ppc7d_find_end_of_memory(void)
+{
+ bd_t *bp = (bd_t *) __res;
+
+ if (bp->bi_memsize)
+ return bp->bi_memsize;
+
+ return (256 * 1024 * 1024);
+}
+
+static void __init ppc7d_map_io(void)
+{
+ /* remove temporary mapping */
+ mtspr(SPRN_DBAT3U, 0x00000000);
+ mtspr(SPRN_DBAT3L, 0x00000000);
+
+ io_block_mapping(0xe8000000, 0xe8000000, 0x08000000, _PAGE_IO);
+ io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO);
+}
+
+static void ppc7d_restart(char *cmd)
+{
+ u32 data;
+
+ /* Disable GPP17 interrupt */
+ data = mv64x60_read(&bh, MV64x60_GPP_INTR_MASK);
+ data &= ~(1 << PPC7D_RST_PIN);
+ mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, data);
+
+ /* Configure MPP17 as GPP */
+ data = mv64x60_read(&bh, MV64x60_MPP_CNTL_2);
+ data &= ~(0x0000000f << 4);
+ mv64x60_write(&bh, MV64x60_MPP_CNTL_2, data);
+
+ /* Enable pin GPP17 for output */
+ data = mv64x60_read(&bh, MV64x60_GPP_IO_CNTL);
+ data |= (1 << PPC7D_RST_PIN);
+ mv64x60_write(&bh, MV64x60_GPP_IO_CNTL, data);
+
+ /* Toggle GPP9 pin to reset the board */
+ mv64x60_write(&bh, MV64x60_GPP_VALUE_CLR, 1 << PPC7D_RST_PIN);
+ mv64x60_write(&bh, MV64x60_GPP_VALUE_SET, 1 << PPC7D_RST_PIN);
+
+ for (;;) ; /* Spin until reset happens */
+ /* NOTREACHED */
+}
+
+static void ppc7d_power_off(void)
+{
+ u32 data;
+
+ local_irq_disable();
+
+ /* Ensure that internal MV643XX watchdog is disabled.
+ * The Disco watchdog uses MPP17 on this hardware.
+ */
+ data = mv64x60_read(&bh, MV64x60_MPP_CNTL_2);
+ data &= ~(0x0000000f << 4);
+ mv64x60_write(&bh, MV64x60_MPP_CNTL_2, data);
+
+ data = mv64x60_read(&bh, MV64x60_WDT_WDC);
+ if (data & 0x80000000) {
+ mv64x60_write(&bh, MV64x60_WDT_WDC, 1 << 24);
+ mv64x60_write(&bh, MV64x60_WDT_WDC, 2 << 24);
+ }
+
+ for (;;) ; /* No way to shut power off with software */
+ /* NOTREACHED */
+}
+
+static void ppc7d_halt(void)
+{
+ ppc7d_power_off();
+ /* NOTREACHED */
+}
+
+static unsigned long ppc7d_led_no_pulse;
+
+static int __init ppc7d_led_pulse_disable(char *str)
+{
+ ppc7d_led_no_pulse = 1;
+ return 1;
+}
+
+/* This kernel option disables the heartbeat pulsing of a board LED */
+__setup("ledoff", ppc7d_led_pulse_disable);
+
+static void ppc7d_heartbeat(void)
+{
+ u32 data32;
+ u8 data8;
+ static int max706_wdog = 0;
+
+ /* Unfortunately we can't access the LED control registers
+ * during early init because they're on the CPLD which is the
+ * other side of a PCI bridge which goes unreachable during
+ * PCI scan. So write the LEDs only if the MV64360 watchdog is
+ * enabled (i.e. userspace apps are running so kernel is up)..
+ */
+ data32 = mv64x60_read(&bh, MV64x60_WDT_WDC);
+ if (data32 & 0x80000000) {
+ /* Enable MAX706 watchdog if not done already */
+ if (!max706_wdog) {
+ outb(3, PPC7D_CPLD_RESET);
+ max706_wdog = 1;
+ }
+
+ /* Hit the MAX706 watchdog */
+ outb(0, PPC7D_CPLD_WATCHDOG_TRIG);
+
+ /* Pulse LED DS219 if not disabled */
+ if (!ppc7d_led_no_pulse) {
+ static int led_on = 0;
+
+ data8 = inb(PPC7D_CPLD_LEDS);
+ if (led_on)
+ data8 &= ~PPC7D_CPLD_LEDS_DS219_MASK;
+ else
+ data8 |= PPC7D_CPLD_LEDS_DS219_MASK;
+
+ outb(data8, PPC7D_CPLD_LEDS);
+ led_on = !led_on;
+ }
+ }
+ ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+}
+
+static int ppc7d_show_cpuinfo(struct seq_file *m)
+{
+ u8 val;
+ u8 val1, val2;
+ static int flash_sizes[4] = { 64, 32, 0, 16 };
+ static int flash_banks[4] = { 4, 3, 2, 1 };
+ static char *pci_modes[] = { "PCI33", "PCI66",
+ "Unknown", "Unknown",
+ "PCIX33", "PCIX66",
+ "PCIX100", "PCIX133"
+ };
+
+ seq_printf(m, "vendor\t\t: Radstone Technology\n");
+ seq_printf(m, "machine\t\t: PPC7D\n");
+
+ val = inb(PPC7D_CPLD_BOARD_REVISION);
+ val1 = (val & PPC7D_CPLD_BOARD_REVISION_NUMBER_MASK) >> 5;
+ val2 = (val & PPC7D_CPLD_BOARD_REVISION_LETTER_MASK);
+ seq_printf(m, "revision\t: %hd%c%c\n",
+ val1,
+ (val2 <= 0x18) ? 'A' + val2 : 'Y',
+ (val2 > 0x18) ? 'A' + (val2 - 0x19) : ' ');
+
+ val = inb(PPC7D_CPLD_MOTHERBOARD_TYPE);
+ val1 = val & PPC7D_CPLD_MB_TYPE_PLL_MASK;
+ val2 = val & (PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK |
+ PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK);
+ seq_printf(m, "bus speed\t: %dMHz\n",
+ (val1 == PPC7D_CPLD_MB_TYPE_PLL_133) ? 133 :
+ (val1 == PPC7D_CPLD_MB_TYPE_PLL_100) ? 100 :
+ (val1 == PPC7D_CPLD_MB_TYPE_PLL_64) ? 64 : 0);
+
+ val = inb(PPC7D_CPLD_MEM_CONFIG_EXTEND);
+ val1 = val & PPC7D_CPLD_SDRAM_BANK_SIZE_MASK;
+ seq_printf(m, "SDRAM\t\t: %d%c",
+ (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_128M) ? 128 :
+ (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_256M) ? 256 :
+ (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_512M) ? 512 : 1,
+ (val1 == PPC7D_CPLD_SDRAM_BANK_SIZE_1G) ? 'G' : 'M');
+ if (val2 & PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK) {
+ seq_printf(m, " [ECC %sabled]",
+ (val2 & PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK) ? "en" :
+ "dis");
+ }
+ seq_printf(m, "\n");
+
+ val1 = (val & PPC7D_CPLD_FLASH_DEV_SIZE_MASK);
+ val2 = (val & PPC7D_CPLD_FLASH_BANK_NUM_MASK) >> 2;
+ seq_printf(m, "FLASH\t\t: %d banks of %dM, total %dM\n",
+ flash_banks[val2], flash_sizes[val1],
+ flash_banks[val2] * flash_sizes[val1]);
+
+ val = inb(PPC7D_CPLD_FLASH_WRITE_CNTL);
+ val1 = inb(PPC7D_CPLD_SW_FLASH_WRITE_PROTECT);
+ seq_printf(m, " write links\t: %s%s%s%s\n",
+ (val & PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK) ? "WRITE " : "",
+ (val & PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK) ? "BOOT " : "",
+ (val & PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK) ? "USER " : "",
+ (val & (PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK |
+ PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK |
+ PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK)) ==
+ 0 ? "NONE" : "");
+ seq_printf(m, " write sector h/w enables: %s%s%s%s%s\n",
+ (val & PPD7D_CPLD_FLASH_CNTL_RECO_WR_MASK) ? "RECOVERY " :
+ "",
+ (val & PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK) ? "BOOT " : "",
+ (val & PPD7D_CPLD_FLASH_CNTL_USER_WR_MASK) ? "USER " : "",
+ (val1 & PPC7D_CPLD_FLASH_CNTL_NVRAM_PROT_MASK) ? "NVRAM " :
+ "",
+ (((val &
+ (PPD7D_CPLD_FLASH_CNTL_RECO_WR_MASK |
+ PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK |
+ PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK)) == 0)
+ && ((val1 & PPC7D_CPLD_FLASH_CNTL_NVRAM_PROT_MASK) ==
+ 0)) ? "NONE" : "");
+ val1 =
+ inb(PPC7D_CPLD_SW_FLASH_WRITE_PROTECT) &
+ (PPC7D_CPLD_SW_FLASH_WRPROT_SYSBOOT_MASK |
+ PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK);
+ seq_printf(m, " software sector enables: %s%s%s\n",
+ (val1 & PPC7D_CPLD_SW_FLASH_WRPROT_SYSBOOT_MASK) ? "SYSBOOT "
+ : "",
+ (val1 & PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK) ? "USER " : "",
+ (val1 == 0) ? "NONE " : "");
+
+ seq_printf(m, "Boot options\t: %s%s%s%s\n",
+ (val & PPC7D_CPLD_FLASH_CNTL_ALTBOOT_LINK_MASK) ?
+ "ALTERNATE " : "",
+ (val & PPC7D_CPLD_FLASH_CNTL_VMEBOOT_LINK_MASK) ? "VME " :
+ "",
+ (val & PPC7D_CPLD_FLASH_CNTL_RECBOOT_LINK_MASK) ? "RECOVERY "
+ : "",
+ ((val &
+ (PPC7D_CPLD_FLASH_CNTL_ALTBOOT_LINK_MASK |
+ PPC7D_CPLD_FLASH_CNTL_VMEBOOT_LINK_MASK |
+ PPC7D_CPLD_FLASH_CNTL_RECBOOT_LINK_MASK)) ==
+ 0) ? "NONE" : "");
+
+ val = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_1);
+ seq_printf(m, "Fitted modules\t: %s%s%s%s\n",
+ (val & PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK) ? "" : "PMC1 ",
+ (val & PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK) ? "" : "PMC2 ",
+ (val & PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK) ? "AFIX " : "",
+ ((val & (PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK |
+ PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK |
+ PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK)) ==
+ (PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK |
+ PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK)) ? "NONE" : "");
+
+ if (val & PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK) {
+ static const char *ids[] = {
+ "unknown",
+ "1553 (Dual Channel)",
+ "1553 (Single Channel)",
+ "8-bit SCSI + VGA",
+ "16-bit SCSI + VGA",
+ "1553 (Single Channel with sideband)",
+ "1553 (Dual Channel with sideband)",
+ NULL
+ };
+ u8 id = __raw_readb((void *)PPC7D_AFIX_REG_BASE + 0x03);
+ seq_printf(m, "AFIX module\t: 0x%hx [%s]\n", id,
+ id < 7 ? ids[id] : "unknown");
+ }
+
+ val = inb(PPC7D_CPLD_PCI_CONFIG);
+ val1 = (val & PPC7D_CPLD_PCI_CONFIG_PCI0_MASK) >> 4;
+ val2 = (val & PPC7D_CPLD_PCI_CONFIG_PCI1_MASK);
+ seq_printf(m, "PCI#0\t\t: %s\nPCI#1\t\t: %s\n",
+ pci_modes[val1], pci_modes[val2]);
+
+ val = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_2);
+ seq_printf(m, "PMC1\t\t: %s\nPMC2\t\t: %s\n",
+ (val & PPC7D_CPLD_EQPT_PRES_3_PMC1_V_MASK) ? "3.3v" : "5v",
+ (val & PPC7D_CPLD_EQPT_PRES_3_PMC2_V_MASK) ? "3.3v" : "5v");
+ seq_printf(m, "PMC power source: %s\n",
+ (val & PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_MASK) ? "VME" :
+ "internal");
+
+ val = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_4);
+ val2 = inb(PPC7D_CPLD_EQUIPMENT_PRESENT_2);
+ seq_printf(m, "Fit options\t: %s%s%s%s%s%s%s\n",
+ (val & PPC7D_CPLD_EQPT_PRES_4_LPT_MASK) ? "LPT " : "",
+ (val & PPC7D_CPLD_EQPT_PRES_4_PS2_FITTED) ? "PS2 " : "",
+ (val & PPC7D_CPLD_EQPT_PRES_4_USB2_FITTED) ? "USB2 " : "",
+ (val2 & PPC7D_CPLD_EQPT_PRES_2_UNIVERSE_MASK) ? "VME " : "",
+ (val2 & PPC7D_CPLD_EQPT_PRES_2_COM36_MASK) ? "COM3-6 " : "",
+ (val2 & PPC7D_CPLD_EQPT_PRES_2_GIGE_MASK) ? "eth0 " : "",
+ (val2 & PPC7D_CPLD_EQPT_PRES_2_DUALGIGE_MASK) ? "eth1 " :
+ "");
+
+ val = inb(PPC7D_CPLD_ID_LINK);
+ val1 = val & (PPC7D_CPLD_ID_LINK_E6_MASK |
+ PPC7D_CPLD_ID_LINK_E7_MASK |
+ PPC7D_CPLD_ID_LINK_E12_MASK |
+ PPC7D_CPLD_ID_LINK_E13_MASK);
+
+ val = inb(PPC7D_CPLD_FLASH_WRITE_CNTL) &
+ (PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK |
+ PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK |
+ PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK);
+
+ seq_printf(m, "Board links present: %s%s%s%s%s%s%s%s\n",
+ (val1 & PPC7D_CPLD_ID_LINK_E6_MASK) ? "E6 " : "",
+ (val1 & PPC7D_CPLD_ID_LINK_E7_MASK) ? "E7 " : "",
+ (val & PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK) ? "E9 " : "",
+ (val & PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK) ? "E10 " : "",
+ (val & PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK) ? "E11 " : "",
+ (val1 & PPC7D_CPLD_ID_LINK_E12_MASK) ? "E12 " : "",
+ (val1 & PPC7D_CPLD_ID_LINK_E13_MASK) ? "E13 " : "",
+ ((val == 0) && (val1 == 0)) ? "NONE" : "");
+
+ val = inb(PPC7D_CPLD_WDOG_RESETSW_MASK);
+ seq_printf(m, "Front panel reset switch: %sabled\n",
+ (val & PPC7D_CPLD_WDOG_RESETSW_MASK) ? "dis" : "en");
+
+ return 0;
+}
+
+static void __init ppc7d_calibrate_decr(void)
+{
+ ulong freq;
+
+ freq = 100000000 / 4;
+
+ pr_debug("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ freq / 1000000, freq % 1000000);
+
+ tb_ticks_per_jiffy = freq / HZ;
+ tb_to_us = mulhwu_scale_factor(freq, 1000000);
+}
+
+/*****************************************************************************
+ * Interrupt stuff
+ *****************************************************************************/
+
+static irqreturn_t ppc7d_i8259_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ u32 temp = mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE);
+ if (temp & (1 << 28)) {
+ i8259_irq(regs);
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, temp & (~(1 << 28)));
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+/*
+ * Each interrupt cause is assigned an IRQ number.
+ * Southbridge has 16*2 (two 8259's) interrupts.
+ * Discovery-II has 96 interrupts (cause-hi, cause-lo, gpp x 32).
+ * If multiple interrupts are pending, get_irq() returns the
+ * lowest pending irq number first.
+ *
+ *
+ * IRQ # Source Trig Active
+ * =============================================================
+ *
+ * Southbridge
+ * -----------
+ * IRQ # Source Trig
+ * =============================================================
+ * 0 ISA High Resolution Counter Edge
+ * 1 Keyboard Edge
+ * 2 Cascade From (IRQ 8-15) Edge
+ * 3 Com 2 (Uart 2) Edge
+ * 4 Com 1 (Uart 1) Edge
+ * 5 PCI Int D/AFIX IRQZ ID4 (2,7) Level
+ * 6 GPIO Level
+ * 7 LPT Edge
+ * 8 RTC Alarm Edge
+ * 9 PCI Int A/PMC 2/AFIX IRQW ID1 (2,0) Level
+ * 10 PCI Int B/PMC 1/AFIX IRQX ID2 (2,1) Level
+ * 11 USB2 Level
+ * 12 Mouse Edge
+ * 13 Reserved internally by Ali M1535+
+ * 14 PCI Int C/VME/AFIX IRQY ID3 (2,6) Level
+ * 15 COM 5/6 Level
+ *
+ * 16..112 Discovery-II...
+ *
+ * MPP28 Southbridge Edge High
+ *
+ *
+ * Interrupts are cascaded through to the Discovery-II.
+ *
+ * PCI ---
+ * \
+ * CPLD --> ALI1535 -------> DISCOVERY-II
+ * INTF MPP28
+ */
+static void __init ppc7d_init_irq(void)
+{
+ int irq;
+
+ pr_debug("%s\n", __FUNCTION__);
+ i8259_init(0);
+ mv64360_init_irq();
+
+ /* IRQ 0..15 are handled by the cascaded 8259's of the Ali1535 */
+ for (irq = 0; irq < 16; irq++) {
+ irq_desc[irq].handler = &i8259_pic;
+ }
+ /* IRQs 5,6,9,10,11,14,15 are level sensitive */
+ irq_desc[5].status |= IRQ_LEVEL;
+ irq_desc[6].status |= IRQ_LEVEL;
+ irq_desc[9].status |= IRQ_LEVEL;
+ irq_desc[10].status |= IRQ_LEVEL;
+ irq_desc[11].status |= IRQ_LEVEL;
+ irq_desc[14].status |= IRQ_LEVEL;
+ irq_desc[15].status |= IRQ_LEVEL;
+
+ /* GPP28 is edge triggered */
+ irq_desc[mv64360_irq_base + MV64x60_IRQ_GPP28].status &= ~IRQ_LEVEL;
+}
+
+static u32 ppc7d_irq_canonicalize(u32 irq)
+{
+ if ((irq >= 16) && (irq < (16 + 96)))
+ irq -= 16;
+
+ return irq;
+}
+
+static int ppc7d_get_irq(struct pt_regs *regs)
+{
+ int irq;
+
+ irq = mv64360_get_irq(regs);
+ if (irq == (mv64360_irq_base + MV64x60_IRQ_GPP28))
+ irq = i8259_irq(regs);
+ return irq;
+}
+
+/*
+ * 9 PCI Int A/PMC 2/AFIX IRQW ID1 (2,0) Level
+ * 10 PCI Int B/PMC 1/AFIX IRQX ID2 (2,1) Level
+ * 14 PCI Int C/VME/AFIX IRQY ID3 (2,6) Level
+ * 5 PCI Int D/AFIX IRQZ ID4 (2,7) Level
+ */
+static int __init ppc7d_map_irq(struct pci_dev *dev, unsigned char idsel,
+ unsigned char pin)
+{
+ static const char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {10, 14, 5, 9}, /* IDSEL 10 - PMC2 / AFIX IRQW */
+ {9, 10, 14, 5}, /* IDSEL 11 - PMC1 / AFIX IRQX */
+ {5, 9, 10, 14}, /* IDSEL 12 - AFIX IRQY */
+ {14, 5, 9, 10}, /* IDSEL 13 - AFIX IRQZ */
+ };
+ const long min_idsel = 10, max_idsel = 14, irqs_per_slot = 4;
+
+ pr_debug("%s: %04x/%04x/%x: idsel=%hx pin=%hu\n", __FUNCTION__,
+ dev->vendor, dev->device, PCI_FUNC(dev->devfn), idsel, pin);
+
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+void __init ppc7d_intr_setup(void)
+{
+ u32 data;
+
+ /*
+ * Define GPP 28 interrupt polarity as active high
+ * input signal and level triggered
+ */
+ data = mv64x60_read(&bh, MV64x60_GPP_LEVEL_CNTL);
+ data &= ~(1 << 28);
+ mv64x60_write(&bh, MV64x60_GPP_LEVEL_CNTL, data);
+ data = mv64x60_read(&bh, MV64x60_GPP_IO_CNTL);
+ data &= ~(1 << 28);
+ mv64x60_write(&bh, MV64x60_GPP_IO_CNTL, data);
+
+ /* Config GPP intr ctlr to respond to level trigger */
+ data = mv64x60_read(&bh, MV64x60_COMM_ARBITER_CNTL);
+ data |= (1 << 10);
+ mv64x60_write(&bh, MV64x60_COMM_ARBITER_CNTL, data);
+
+ /* XXXX Erranum FEr PCI-#8 */
+ data = mv64x60_read(&bh, MV64x60_PCI0_CMD);
+ data &= ~((1 << 5) | (1 << 9));
+ mv64x60_write(&bh, MV64x60_PCI0_CMD, data);
+ data = mv64x60_read(&bh, MV64x60_PCI1_CMD);
+ data &= ~((1 << 5) | (1 << 9));
+ mv64x60_write(&bh, MV64x60_PCI1_CMD, data);
+
+ /*
+ * Dismiss and then enable interrupt on GPP interrupt cause
+ * for CPU #0
+ */
+ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~(1 << 28));
+ data = mv64x60_read(&bh, MV64x60_GPP_INTR_MASK);
+ data |= (1 << 28);
+ mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, data);
+
+ /*
+ * Dismiss and then enable interrupt on CPU #0 high cause reg
+ * BIT27 summarizes GPP interrupts 23-31
+ */
+ mv64x60_write(&bh, MV64360_IC_MAIN_CAUSE_HI, ~(1 << 27));
+ data = mv64x60_read(&bh, MV64360_IC_CPU0_INTR_MASK_HI);
+ data |= (1 << 27);
+ mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_HI, data);
+}
+
+/*****************************************************************************
+ * Platform device data fixup routines.
+ *****************************************************************************/
+
+#if defined(CONFIG_SERIAL_MPSC)
+static void __init ppc7d_fixup_mpsc_pdata(struct platform_device *pdev)
+{
+ struct mpsc_pdata *pdata;
+
+ pdata = (struct mpsc_pdata *)pdev->dev.platform_data;
+
+ pdata->max_idle = 40;
+ pdata->default_baud = PPC7D_DEFAULT_BAUD;
+ pdata->brg_clk_src = PPC7D_MPSC_CLK_SRC;
+ pdata->brg_clk_freq = PPC7D_MPSC_CLK_FREQ;
+
+ return;
+}
+#endif
+
+#if defined(CONFIG_MV643XX_ETH)
+static void __init ppc7d_fixup_eth_pdata(struct platform_device *pdev)
+{
+ struct mv643xx_eth_platform_data *eth_pd;
+ static u16 phy_addr[] = {
+ PPC7D_ETH0_PHY_ADDR,
+ PPC7D_ETH1_PHY_ADDR,
+ PPC7D_ETH2_PHY_ADDR,
+ };
+ int i;
+
+ eth_pd = pdev->dev.platform_data;
+ eth_pd->force_phy_addr = 1;
+ eth_pd->phy_addr = phy_addr[pdev->id];
+ eth_pd->tx_queue_size = PPC7D_ETH_TX_QUEUE_SIZE;
+ eth_pd->rx_queue_size = PPC7D_ETH_RX_QUEUE_SIZE;
+
+ /* Adjust IRQ by mv64360_irq_base */
+ for (i = 0; i < pdev->num_resources; i++) {
+ struct resource *r = &pdev->resource[i];
+
+ if (r->flags & IORESOURCE_IRQ) {
+ r->start += mv64360_irq_base;
+ r->end += mv64360_irq_base;
+ pr_debug("%s, uses IRQ %d\n", pdev->name,
+ (int)r->start);
+ }
+ }
+
+}
+#endif
+
+#if defined(CONFIG_I2C_MV64XXX)
+static void __init
+ppc7d_fixup_i2c_pdata(struct platform_device *pdev)
+{
+ struct mv64xxx_i2c_pdata *pdata;
+ int i;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL) {
+ pdata = kmalloc(sizeof(*pdata), GFP_KERNEL);
+ if (pdata == NULL)
+ return;
+
+ memset(pdata, 0, sizeof(*pdata));
+ pdev->dev.platform_data = pdata;
+ }
+
+ /* divisors M=8, N=3 for 100kHz I2C from 133MHz system clock */
+ pdata->freq_m = 8;
+ pdata->freq_n = 3;
+ pdata->timeout = 500;
+ pdata->retries = 3;
+
+ /* Adjust IRQ by mv64360_irq_base */
+ for (i = 0; i < pdev->num_resources; i++) {
+ struct resource *r = &pdev->resource[i];
+
+ if (r->flags & IORESOURCE_IRQ) {
+ r->start += mv64360_irq_base;
+ r->end += mv64360_irq_base;
+ pr_debug("%s, uses IRQ %d\n", pdev->name, (int) r->start);
+ }
+ }
+}
+#endif
+
+static int __init ppc7d_platform_notify(struct device *dev)
+{
+ static struct {
+ char *bus_id;
+ void ((*rtn) (struct platform_device * pdev));
+ } dev_map[] = {
+#if defined(CONFIG_SERIAL_MPSC)
+ { MPSC_CTLR_NAME ".0", ppc7d_fixup_mpsc_pdata },
+ { MPSC_CTLR_NAME ".1", ppc7d_fixup_mpsc_pdata },
+#endif
+#if defined(CONFIG_MV643XX_ETH)
+ { MV643XX_ETH_NAME ".0", ppc7d_fixup_eth_pdata },
+ { MV643XX_ETH_NAME ".1", ppc7d_fixup_eth_pdata },
+ { MV643XX_ETH_NAME ".2", ppc7d_fixup_eth_pdata },
+#endif
+#if defined(CONFIG_I2C_MV64XXX)
+ { MV64XXX_I2C_CTLR_NAME ".0", ppc7d_fixup_i2c_pdata },
+#endif
+ };
+ struct platform_device *pdev;
+ int i;
+
+ if (dev && dev->bus_id)
+ for (i = 0; i < ARRAY_SIZE(dev_map); i++)
+ if (!strncmp(dev->bus_id, dev_map[i].bus_id,
+ BUS_ID_SIZE)) {
+
+ pdev = container_of(dev,
+ struct platform_device,
+ dev);
+ dev_map[i].rtn(pdev);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * PCI device fixups.
+ * These aren't really fixups per se. They are used to init devices as they
+ * are found during PCI scan.
+ *
+ * The PPC7D has an HB8 PCI-X bridge which must be set up during a PCI
+ * scan in order to find other devices on its secondary side.
+ *****************************************************************************/
+
+static void __init ppc7d_fixup_hb8(struct pci_dev *dev)
+{
+ u16 val16;
+
+ if (dev->bus->number == 0) {
+ pr_debug("PCI: HB8 init\n");
+
+ pci_write_config_byte(dev, 0x1c,
+ ((PPC7D_PCI0_IO_START_PCI_ADDR & 0xf000)
+ >> 8) | 0x01);
+ pci_write_config_byte(dev, 0x1d,
+ (((PPC7D_PCI0_IO_START_PCI_ADDR +
+ PPC7D_PCI0_IO_SIZE -
+ 1) & 0xf000) >> 8) | 0x01);
+ pci_write_config_word(dev, 0x30,
+ PPC7D_PCI0_IO_START_PCI_ADDR >> 16);
+ pci_write_config_word(dev, 0x32,
+ ((PPC7D_PCI0_IO_START_PCI_ADDR +
+ PPC7D_PCI0_IO_SIZE -
+ 1) >> 16) & 0xffff);
+
+ pci_write_config_word(dev, 0x20,
+ PPC7D_PCI0_MEM0_START_PCI_LO_ADDR >> 16);
+ pci_write_config_word(dev, 0x22,
+ ((PPC7D_PCI0_MEM0_START_PCI_LO_ADDR +
+ PPC7D_PCI0_MEM0_SIZE -
+ 1) >> 16) & 0xffff);
+ pci_write_config_word(dev, 0x24, 0);
+ pci_write_config_word(dev, 0x26, 0);
+ pci_write_config_dword(dev, 0x28, 0);
+ pci_write_config_dword(dev, 0x2c, 0);
+
+ pci_read_config_word(dev, 0x3e, &val16);
+ val16 |= ((1 << 5) | (1 << 1)); /* signal master aborts and
+ * SERR to primary
+ */
+ val16 &= ~(1 << 2); /* ISA disable, so all ISA
+ * ports forwarded to secondary
+ */
+ pci_write_config_word(dev, 0x3e, val16);
+ }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HINT, 0x0028, ppc7d_fixup_hb8);
+
+/* This should perhaps be a separate driver as we're actually initializing
+ * the chip for this board here. It's hardly a fixup...
+ */
+static void __init ppc7d_fixup_ali1535(struct pci_dev *dev)
+{
+ pr_debug("PCI: ALI1535 init\n");
+
+ if (dev->bus->number == 1) {
+ /* Configure the ISA Port Settings */
+ pci_write_config_byte(dev, 0x43, 0x00);
+
+ /* Disable PCI Interrupt polling mode */
+ pci_write_config_byte(dev, 0x45, 0x00);
+
+ /* Multifunction pin select INTFJ -> INTF */
+ pci_write_config_byte(dev, 0x78, 0x00);
+
+ /* Set PCI INT -> IRQ Routing control in for external
+ * pins south bridge.
+ */
+ pci_write_config_byte(dev, 0x48, 0x31); /* [7-4] INT B -> IRQ10
+ * [3-0] INT A -> IRQ9
+ */
+ pci_write_config_byte(dev, 0x49, 0x5D); /* [7-4] INT D -> IRQ5
+ * [3-0] INT C -> IRQ14
+ */
+
+ /* PPC7D setup */
+ /* NEC USB device on IRQ 11 (INTE) - INTF disabled */
+ pci_write_config_byte(dev, 0x4A, 0x09);
+
+ /* GPIO on IRQ 6 */
+ pci_write_config_byte(dev, 0x76, 0x07);
+
+ /* SIRQ I (COMS 5/6) use IRQ line 15.
+ * Positive (not subtractive) address decode.
+ */
+ pci_write_config_byte(dev, 0x44, 0x0f);
+
+ /* SIRQ II disabled */
+ pci_write_config_byte(dev, 0x75, 0x0);
+
+ /* On board USB and RTC disabled */
+ pci_write_config_word(dev, 0x52, (1 << 14));
+ pci_write_config_byte(dev, 0x74, 0x00);
+
+ /* On board IDE disabled */
+ pci_write_config_byte(dev, 0x58, 0x00);
+
+ /* Decode 32-bit addresses */
+ pci_write_config_byte(dev, 0x5b, 0);
+
+ /* Disable docking IO */
+ pci_write_config_word(dev, 0x5c, 0x0000);
+
+ /* Disable modem, enable sound */
+ pci_write_config_byte(dev, 0x77, (1 << 6));
+
+ /* Disable hot-docking mode */
+ pci_write_config_byte(dev, 0x7d, 0x00);
+ }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1533, ppc7d_fixup_ali1535);
+
+static int ppc7d_pci_exclude_device(u8 bus, u8 devfn)
+{
+ /* Early versions of this board were fitted with IBM ALMA
+ * PCI-VME bridge chips. The PCI config space of these devices
+ * was not set up correctly and causes PCI scan problems.
+ */
+ if ((bus == 1) && (PCI_SLOT(devfn) == 4) && ppc7d_has_alma)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return mv64x60_pci_exclude_device(bus, devfn);
+}
+
+/* This hook is called when each PCI bus is probed.
+ */
+static void ppc7d_pci_fixup_bus(struct pci_bus *bus)
+{
+ pr_debug("PCI BUS %hu: %lx/%lx %lx/%lx %lx/%lx %lx/%lx\n",
+ bus->number,
+ bus->resource[0] ? bus->resource[0]->start : 0,
+ bus->resource[0] ? bus->resource[0]->end : 0,
+ bus->resource[1] ? bus->resource[1]->start : 0,
+ bus->resource[1] ? bus->resource[1]->end : 0,
+ bus->resource[2] ? bus->resource[2]->start : 0,
+ bus->resource[2] ? bus->resource[2]->end : 0,
+ bus->resource[3] ? bus->resource[3]->start : 0,
+ bus->resource[3] ? bus->resource[3]->end : 0);
+
+ if ((bus->number == 1) && (bus->resource[2] != NULL)) {
+ /* Hide PCI window 2 of Bus 1 which is used only to
+ * map legacy ISA memory space.
+ */
+ bus->resource[2]->start = 0;
+ bus->resource[2]->end = 0;
+ bus->resource[2]->flags = 0;
+ }
+}
+
+/*****************************************************************************
+ * Board device setup code
+ *****************************************************************************/
+
+void __init ppc7d_setup_peripherals(void)
+{
+ u32 val32;
+
+ /* Set up windows for boot CS */
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN,
+ PPC7D_BOOT_WINDOW_BASE, PPC7D_BOOT_WINDOW_SIZE,
+ 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2BOOT_WIN);
+
+ /* Boot firmware configures the following DevCS addresses.
+ * DevCS0 - board control/status
+ * DevCS1 - test registers
+ * DevCS2 - AFIX port/address registers (for identifying)
+ * DevCS3 - FLASH
+ *
+ * We don't use DevCS0, DevCS1.
+ */
+ val32 = mv64x60_read(&bh, MV64360_CPU_BAR_ENABLE);
+ val32 |= ((1 << 4) | (1 << 5));
+ mv64x60_write(&bh, MV64360_CPU_BAR_ENABLE, val32);
+ mv64x60_write(&bh, MV64x60_CPU2DEV_0_BASE, 0);
+ mv64x60_write(&bh, MV64x60_CPU2DEV_0_SIZE, 0);
+ mv64x60_write(&bh, MV64x60_CPU2DEV_1_BASE, 0);
+ mv64x60_write(&bh, MV64x60_CPU2DEV_1_SIZE, 0);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN,
+ PPC7D_AFIX_REG_BASE, PPC7D_AFIX_REG_SIZE, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_2_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN,
+ PPC7D_FLASH_BASE, PPC7D_FLASH_SIZE_ACTUAL, 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_3_WIN);
+
+ mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN,
+ PPC7D_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE,
+ 0);
+ bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN);
+
+ /* Set up Enet->SRAM window */
+ mv64x60_set_32bit_window(&bh, MV64x60_ENET2MEM_4_WIN,
+ PPC7D_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE,
+ 0x2);
+ bh.ci->enable_window_32bit(&bh, MV64x60_ENET2MEM_4_WIN);
+
+ /* Give enet r/w access to memory region */
+ val32 = mv64x60_read(&bh, MV64360_ENET2MEM_ACC_PROT_0);
+ val32 |= (0x3 << (4 << 1));
+ mv64x60_write(&bh, MV64360_ENET2MEM_ACC_PROT_0, val32);
+ val32 = mv64x60_read(&bh, MV64360_ENET2MEM_ACC_PROT_1);
+ val32 |= (0x3 << (4 << 1));
+ mv64x60_write(&bh, MV64360_ENET2MEM_ACC_PROT_1, val32);
+ val32 = mv64x60_read(&bh, MV64360_ENET2MEM_ACC_PROT_2);
+ val32 |= (0x3 << (4 << 1));
+ mv64x60_write(&bh, MV64360_ENET2MEM_ACC_PROT_2, val32);
+
+ val32 = mv64x60_read(&bh, MV64x60_TIMR_CNTR_0_3_CNTL);
+ val32 &= ~((1 << 0) | (1 << 8) | (1 << 16) | (1 << 24));
+ mv64x60_write(&bh, MV64x60_TIMR_CNTR_0_3_CNTL, val32);
+
+ /* Enumerate pci bus.
+ *
+ * We scan PCI#0 first (the bus with the HB8 and other
+ * on-board peripherals). We must configure the 64360 before
+ * each scan, according to the bus number assignments. Busses
+ * are assigned incrementally, starting at 0. PCI#0 is
+ * usually assigned bus#0, the secondary side of the HB8 gets
+ * bus#1 and PCI#1 (second PMC site) gets bus#2. However, if
+ * any PMC card has a PCI bridge, these bus assignments will
+ * change.
+ */
+
+ /* Turn off PCI retries */
+ val32 = mv64x60_read(&bh, MV64x60_CPU_CONFIG);
+ val32 |= (1 << 17);
+ mv64x60_write(&bh, MV64x60_CPU_CONFIG, val32);
+
+ /* Scan PCI#0 */
+ mv64x60_set_bus(&bh, 0, 0);
+ bh.hose_a->first_busno = 0;
+ bh.hose_a->last_busno = 0xff;
+ bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0);
+ printk(KERN_INFO "PCI#0: first=%d last=%d\n",
+ bh.hose_a->first_busno, bh.hose_a->last_busno);
+
+ /* Scan PCI#1 */
+ bh.hose_b->first_busno = bh.hose_a->last_busno + 1;
+ mv64x60_set_bus(&bh, 1, bh.hose_b->first_busno);
+ bh.hose_b->last_busno = 0xff;
+ bh.hose_b->last_busno = pciauto_bus_scan(bh.hose_b,
+ bh.hose_b->first_busno);
+ printk(KERN_INFO "PCI#1: first=%d last=%d\n",
+ bh.hose_b->first_busno, bh.hose_b->last_busno);
+
+ /* Turn on PCI retries */
+ val32 = mv64x60_read(&bh, MV64x60_CPU_CONFIG);
+ val32 &= ~(1 << 17);
+ mv64x60_write(&bh, MV64x60_CPU_CONFIG, val32);
+
+ /* Setup interrupts */
+ ppc7d_intr_setup();
+}
+
+static void __init ppc7d_setup_bridge(void)
+{
+ struct mv64x60_setup_info si;
+ int i;
+ u32 temp;
+
+ mv64360_irq_base = 16; /* first 16 intrs are 2 x 8259's */
+
+ memset(&si, 0, sizeof(si));
+
+ si.phys_reg_base = CONFIG_MV64X60_NEW_BASE;
+
+ si.pci_0.enable_bus = 1;
+ si.pci_0.pci_io.cpu_base = PPC7D_PCI0_IO_START_PROC_ADDR;
+ si.pci_0.pci_io.pci_base_hi = 0;
+ si.pci_0.pci_io.pci_base_lo = PPC7D_PCI0_IO_START_PCI_ADDR;
+ si.pci_0.pci_io.size = PPC7D_PCI0_IO_SIZE;
+ si.pci_0.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_0.pci_mem[0].cpu_base = PPC7D_PCI0_MEM0_START_PROC_ADDR;
+ si.pci_0.pci_mem[0].pci_base_hi = PPC7D_PCI0_MEM0_START_PCI_HI_ADDR;
+ si.pci_0.pci_mem[0].pci_base_lo = PPC7D_PCI0_MEM0_START_PCI_LO_ADDR;
+ si.pci_0.pci_mem[0].size = PPC7D_PCI0_MEM0_SIZE;
+ si.pci_0.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_0.pci_mem[1].cpu_base = PPC7D_PCI0_MEM1_START_PROC_ADDR;
+ si.pci_0.pci_mem[1].pci_base_hi = PPC7D_PCI0_MEM1_START_PCI_HI_ADDR;
+ si.pci_0.pci_mem[1].pci_base_lo = PPC7D_PCI0_MEM1_START_PCI_LO_ADDR;
+ si.pci_0.pci_mem[1].size = PPC7D_PCI0_MEM1_SIZE;
+ si.pci_0.pci_mem[1].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_0.pci_cmd_bits = 0;
+ si.pci_0.latency_timer = 0x80;
+
+ si.pci_1.enable_bus = 1;
+ si.pci_1.pci_io.cpu_base = PPC7D_PCI1_IO_START_PROC_ADDR;
+ si.pci_1.pci_io.pci_base_hi = 0;
+ si.pci_1.pci_io.pci_base_lo = PPC7D_PCI1_IO_START_PCI_ADDR;
+ si.pci_1.pci_io.size = PPC7D_PCI1_IO_SIZE;
+ si.pci_1.pci_io.swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_mem[0].cpu_base = PPC7D_PCI1_MEM0_START_PROC_ADDR;
+ si.pci_1.pci_mem[0].pci_base_hi = PPC7D_PCI1_MEM0_START_PCI_HI_ADDR;
+ si.pci_1.pci_mem[0].pci_base_lo = PPC7D_PCI1_MEM0_START_PCI_LO_ADDR;
+ si.pci_1.pci_mem[0].size = PPC7D_PCI1_MEM0_SIZE;
+ si.pci_1.pci_mem[0].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_mem[1].cpu_base = PPC7D_PCI1_MEM1_START_PROC_ADDR;
+ si.pci_1.pci_mem[1].pci_base_hi = PPC7D_PCI1_MEM1_START_PCI_HI_ADDR;
+ si.pci_1.pci_mem[1].pci_base_lo = PPC7D_PCI1_MEM1_START_PCI_LO_ADDR;
+ si.pci_1.pci_mem[1].size = PPC7D_PCI1_MEM1_SIZE;
+ si.pci_1.pci_mem[1].swap = MV64x60_CPU2PCI_SWAP_NONE;
+ si.pci_1.pci_cmd_bits = 0;
+ si.pci_1.latency_timer = 0x80;
+
+ /* Don't clear the SRAM window since we use it for debug */
+ si.window_preserve_mask_32_lo = (1 << MV64x60_CPU2SRAM_WIN);
+
+ printk(KERN_INFO "PCI: MV64360 PCI#0 IO at %x, size %x\n",
+ si.pci_0.pci_io.cpu_base, si.pci_0.pci_io.size);
+ printk(KERN_INFO "PCI: MV64360 PCI#1 IO at %x, size %x\n",
+ si.pci_1.pci_io.cpu_base, si.pci_1.pci_io.size);
+
+ for (i = 0; i < MV64x60_CPU2MEM_WINDOWS; i++) {
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ si.cpu_prot_options[i] = 0;
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_NONE;
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_NONE;
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_NONE;
+
+ si.pci_0.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES;
+#else
+ si.cpu_prot_options[i] = 0;
+ /* All PPC7D hardware uses B0 or newer MV64360 silicon which
+ * does not have snoop bugs.
+ */
+ si.enet_options[i] = MV64360_ENET2MEM_SNOOP_WB;
+ si.mpsc_options[i] = MV64360_MPSC2MEM_SNOOP_WB;
+ si.idma_options[i] = MV64360_IDMA2MEM_SNOOP_WB;
+
+ si.pci_0.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_WB |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+
+ si.pci_1.acc_cntl_options[i] =
+ MV64360_PCI_ACC_CNTL_SNOOP_WB |
+ MV64360_PCI_ACC_CNTL_SWAP_NONE |
+ MV64360_PCI_ACC_CNTL_MBURST_32_BYTES |
+ MV64360_PCI_ACC_CNTL_RDSIZE_32_BYTES;
+#endif
+ }
+
+ /* Lookup PCI host bridges */
+ if (mv64x60_init(&bh, &si))
+ printk(KERN_ERR "MV64360 initialization failed.\n");
+
+ pr_debug("MV64360 regs @ %lx/%p\n", bh.p_base, bh.v_base);
+
+ /* Enable WB Cache coherency on SRAM */
+ temp = mv64x60_read(&bh, MV64360_SRAM_CONFIG);
+ pr_debug("SRAM_CONFIG: %x\n", temp);
+#if defined(CONFIG_NOT_COHERENT_CACHE)
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, temp & ~0x2);
+#else
+ mv64x60_write(&bh, MV64360_SRAM_CONFIG, temp | 0x2);
+#endif
+ /* If system operates with internal bus arbiter (CPU master
+ * control bit8) clear AACK Delay bit [25] in CPU
+ * configuration register.
+ */
+ temp = mv64x60_read(&bh, MV64x60_CPU_MASTER_CNTL);
+ if (temp & (1 << 8)) {
+ temp = mv64x60_read(&bh, MV64x60_CPU_CONFIG);
+ mv64x60_write(&bh, MV64x60_CPU_CONFIG, (temp & ~(1 << 25)));
+ }
+
+ /* Data and address parity is enabled */
+ temp = mv64x60_read(&bh, MV64x60_CPU_CONFIG);
+ mv64x60_write(&bh, MV64x60_CPU_CONFIG,
+ (temp | (1 << 26) | (1 << 19)));
+
+ pci_dram_offset = 0; /* sys mem at same addr on PCI & cpu bus */
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = ppc7d_map_irq;
+ ppc_md.pci_exclude_device = ppc7d_pci_exclude_device;
+
+ mv64x60_set_bus(&bh, 0, 0);
+ bh.hose_a->first_busno = 0;
+ bh.hose_a->last_busno = 0xff;
+ bh.hose_a->mem_space.start = PPC7D_PCI0_MEM0_START_PCI_LO_ADDR;
+ bh.hose_a->mem_space.end =
+ PPC7D_PCI0_MEM0_START_PCI_LO_ADDR + PPC7D_PCI0_MEM0_SIZE;
+
+ /* These will be set later, as a result of PCI0 scan */
+ bh.hose_b->first_busno = 0;
+ bh.hose_b->last_busno = 0xff;
+ bh.hose_b->mem_space.start = PPC7D_PCI1_MEM0_START_PCI_LO_ADDR;
+ bh.hose_b->mem_space.end =
+ PPC7D_PCI1_MEM0_START_PCI_LO_ADDR + PPC7D_PCI1_MEM0_SIZE;
+
+ pr_debug("MV64360: PCI#0 IO decode %08x/%08x IO remap %08x\n",
+ mv64x60_read(&bh, 0x48), mv64x60_read(&bh, 0x50),
+ mv64x60_read(&bh, 0xf0));
+}
+
+static void __init ppc7d_setup_arch(void)
+{
+ int port;
+
+ loops_per_jiffy = 100000000 / HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+
+ if ((cur_cpu_spec[0]->cpu_features & CPU_FTR_SPEC7450) ||
+ (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
+ /* 745x is different. We only want to pass along enable. */
+ _set_L2CR(L2CR_L2E);
+ else if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)
+ /* All modules have 1MB of L2. We also assume that an
+ * L2 divisor of 3 will work.
+ */
+ _set_L2CR(L2CR_L2E | L2CR_L2SIZ_1MB | L2CR_L2CLK_DIV3
+ | L2CR_L2RAM_PIPE | L2CR_L2OH_1_0 | L2CR_L2DF);
+
+ if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR)
+ /* No L3 cache */
+ _set_L3CR(0);
+
+#ifdef CONFIG_DUMMY_CONSOLE
+ conswitchp = &dummy_con;
+#endif
+
+ /* Lookup PCI host bridges */
+ if (ppc_md.progress)
+ ppc_md.progress("ppc7d_setup_arch: calling setup_bridge", 0);
+
+ ppc7d_setup_bridge();
+ ppc7d_setup_peripherals();
+
+ /* Disable ethernet. It might have been setup by the bootrom */
+ for (port = 0; port < 3; port++)
+ mv64x60_write(&bh, MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port),
+ 0x0000ff00);
+
+ /* Clear queue pointers to ensure they are all initialized,
+ * otherwise since queues 1-7 are unused, they have random
+ * pointers which look strange in register dumps. Don't bother
+ * with queue 0 since it will be initialized later.
+ */
+ for (port = 0; port < 3; port++) {
+ mv64x60_write(&bh,
+ MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_1(port),
+ 0x00000000);
+ mv64x60_write(&bh,
+ MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_2(port),
+ 0x00000000);
+ mv64x60_write(&bh,
+ MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_3(port),
+ 0x00000000);
+ mv64x60_write(&bh,
+ MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_4(port),
+ 0x00000000);
+ mv64x60_write(&bh,
+ MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_5(port),
+ 0x00000000);
+ mv64x60_write(&bh,
+ MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_6(port),
+ 0x00000000);
+ mv64x60_write(&bh,
+ MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_7(port),
+ 0x00000000);
+ }
+
+ printk(KERN_INFO "Radstone Technology PPC7D\n");
+ if (ppc_md.progress)
+ ppc_md.progress("ppc7d_setup_arch: exit", 0);
+}
+
+/* This kernel command line parameter can be used to have the target
+ * wait for a JTAG debugger to attach. Of course, a JTAG debugger
+ * with hardware breakpoint support can have the target stop at any
+ * location during init, but this is a convenience feature that makes
+ * it easier in the common case of loading the code using the ppcboot
+ * bootloader..
+ */
+static unsigned long ppc7d_wait_debugger;
+
+static int __init ppc7d_waitdbg(char *str)
+{
+ ppc7d_wait_debugger = 1;
+ return 1;
+}
+
+__setup("waitdbg", ppc7d_waitdbg);
+
+/* Second phase board init, called after other (architecture common)
+ * low-level services have been initialized.
+ */
+static void ppc7d_init2(void)
+{
+ unsigned long flags;
+ u32 data;
+ u8 data8;
+
+ pr_debug("%s: enter\n", __FUNCTION__);
+
+ /* Wait for debugger? */
+ if (ppc7d_wait_debugger) {
+ printk("Waiting for debugger...\n");
+
+ while (readl(&ppc7d_wait_debugger)) ;
+ }
+
+ /* Hook up i8259 interrupt which is connected to GPP28 */
+ request_irq(mv64360_irq_base + MV64x60_IRQ_GPP28, ppc7d_i8259_intr,
+ SA_INTERRUPT, "I8259 (GPP28) interrupt", (void *)0);
+
+ /* Configure MPP16 as watchdog NMI, MPP17 as watchdog WDE */
+ spin_lock_irqsave(&mv64x60_lock, flags);
+ data = mv64x60_read(&bh, MV64x60_MPP_CNTL_2);
+ data &= ~(0x0000000f << 0);
+ data |= (0x00000004 << 0);
+ data &= ~(0x0000000f << 4);
+ data |= (0x00000004 << 4);
+ mv64x60_write(&bh, MV64x60_MPP_CNTL_2, data);
+ spin_unlock_irqrestore(&mv64x60_lock, flags);
+
+ /* All LEDs off */
+ data8 = inb(PPC7D_CPLD_LEDS);
+ data8 &= ~0x08;
+ data8 |= 0x07;
+ outb(data8, PPC7D_CPLD_LEDS);
+
+ pr_debug("%s: exit\n", __FUNCTION__);
+}
+
+/* Called from machine_init(), early, before any of the __init functions
+ * have run. We must init software-configurable pins before other functions
+ * such as interrupt controllers are initialised.
+ */
+void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ u8 val8;
+ u8 rev_num;
+
+ /* Map 0xe0000000-0xffffffff early because we need access to SRAM
+ * and the ISA memory space (for serial port) here. This mapping
+ * is redone properly in ppc7d_map_io() later.
+ */
+ mtspr(SPRN_DBAT3U, 0xe0003fff);
+ mtspr(SPRN_DBAT3L, 0xe000002a);
+
+ /*
+ * Zero SRAM. Note that this generates parity errors on
+ * internal data path in SRAM if it's first time accessing it
+ * after reset.
+ *
+ * We do this ASAP to avoid parity errors when reading
+ * uninitialized SRAM.
+ */
+ memset((void *)PPC7D_INTERNAL_SRAM_BASE, 0, MV64360_SRAM_SIZE);
+
+ pr_debug("platform_init: r3-r7: %lx %lx %lx %lx %lx\n",
+ r3, r4, r5, r6, r7);
+
+ parse_bootinfo(find_bootinfo());
+
+ /* ASSUMPTION: If both r3 (bd_t pointer) and r6 (cmdline pointer)
+ * are non-zero, then we should use the board info from the bd_t
+ * structure and the cmdline pointed to by r6 instead of the
+ * information from birecs, if any. Otherwise, use the information
+ * from birecs as discovered by the preceeding call to
+ * parse_bootinfo(). This rule should work with both PPCBoot, which
+ * uses a bd_t board info structure, and the kernel boot wrapper,
+ * which uses birecs.
+ */
+ if (r3 && r6) {
+ bd_t *bp = (bd_t *) __res;
+
+ /* copy board info structure */
+ memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+ /* copy command line */
+ *(char *)(r7 + KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6 + KERNELBASE));
+
+ printk(KERN_INFO "Board info data:-\n");
+ printk(KERN_INFO " Internal freq: %lu MHz, bus freq: %lu MHz\n",
+ bp->bi_intfreq, bp->bi_busfreq);
+ printk(KERN_INFO " Memory: %lx, size %lx\n", bp->bi_memstart,
+ bp->bi_memsize);
+ printk(KERN_INFO " Console baudrate: %lu\n", bp->bi_baudrate);
+ printk(KERN_INFO " Ethernet address: "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ bp->bi_enetaddr[0], bp->bi_enetaddr[1],
+ bp->bi_enetaddr[2], bp->bi_enetaddr[3],
+ bp->bi_enetaddr[4], bp->bi_enetaddr[5]);
+ }
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ printk(KERN_INFO "INITRD @ %lx/%lx\n", initrd_start, initrd_end);
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Map in board regs, etc. */
+ isa_io_base = 0xe8000000;
+ isa_mem_base = 0xe8000000;
+ pci_dram_offset = 0x00000000;
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ ppc_md.setup_arch = ppc7d_setup_arch;
+ ppc_md.init = ppc7d_init2;
+ ppc_md.show_cpuinfo = ppc7d_show_cpuinfo;
+ ppc_md.irq_canonicalize = ppc7d_irq_canonicalize;
+ ppc_md.init_IRQ = ppc7d_init_irq;
+ ppc_md.get_irq = ppc7d_get_irq;
+
+ ppc_md.restart = ppc7d_restart;
+ ppc_md.power_off = ppc7d_power_off;
+ ppc_md.halt = ppc7d_halt;
+
+ ppc_md.find_end_of_memory = ppc7d_find_end_of_memory;
+ ppc_md.setup_io_mappings = ppc7d_map_io;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.calibrate_decr = ppc7d_calibrate_decr;
+ ppc_md.nvram_read_val = NULL;
+ ppc_md.nvram_write_val = NULL;
+
+ ppc_md.heartbeat = ppc7d_heartbeat;
+ ppc_md.heartbeat_reset = HZ;
+ ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
+
+ ppc_md.pcibios_fixup_bus = ppc7d_pci_fixup_bus;
+
+#if defined(CONFIG_SERIAL_MPSC) || defined(CONFIG_MV643XX_ETH) || \
+ defined(CONFIG_I2C_MV64XXX)
+ platform_notify = ppc7d_platform_notify;
+#endif
+
+#ifdef CONFIG_SERIAL_MPSC
+ /* On PPC7D, we must configure MPSC support via CPLD control
+ * registers.
+ */
+ outb(PPC7D_CPLD_RTS_COM4_SCLK |
+ PPC7D_CPLD_RTS_COM56_ENABLED, PPC7D_CPLD_RTS);
+ outb(PPC7D_CPLD_COMS_COM3_TCLKEN |
+ PPC7D_CPLD_COMS_COM3_TXEN |
+ PPC7D_CPLD_COMS_COM4_TCLKEN |
+ PPC7D_CPLD_COMS_COM4_TXEN, PPC7D_CPLD_COMS);
+#endif /* CONFIG_SERIAL_MPSC */
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
+ ppc7d_early_serial_map();
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ ppc_md.progress = mv64x60_mpsc_progress;
+#elif defined(CONFIG_SERIAL_8250)
+ ppc_md.progress = gen550_progress;
+#else
+#error CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG has no supported CONFIG_SERIAL_XXX
+#endif /* CONFIG_SERIAL_8250 */
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#endif /* CONFIG_KGDB || CONFIG_SERIAL_TEXT_DEBUG */
+
+ /* Enable write access to user flash. This is necessary for
+ * flash probe.
+ */
+ val8 = readb((void *)isa_io_base + PPC7D_CPLD_SW_FLASH_WRITE_PROTECT);
+ writeb(val8 | (PPC7D_CPLD_SW_FLASH_WRPROT_ENABLED &
+ PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK),
+ (void *)isa_io_base + PPC7D_CPLD_SW_FLASH_WRITE_PROTECT);
+
+ /* Determine if this board has IBM ALMA VME devices */
+ val8 = readb((void *)isa_io_base + PPC7D_CPLD_BOARD_REVISION);
+ rev_num = (val8 & PPC7D_CPLD_BOARD_REVISION_NUMBER_MASK) >> 5;
+ if (rev_num <= 1)
+ ppc7d_has_alma = 1;
+
+#ifdef DEBUG
+ console_printk[0] = 8;
+#endif
+}
diff --git a/arch/ppc/platforms/radstone_ppc7d.h b/arch/ppc/platforms/radstone_ppc7d.h
new file mode 100644
index 00000000000..4546fff2b0c
--- /dev/null
+++ b/arch/ppc/platforms/radstone_ppc7d.h
@@ -0,0 +1,434 @@
+/*
+ * arch/ppc/platforms/radstone_ppc7d.h
+ *
+ * Board definitions for the Radstone PPC7D boards.
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ *
+ * Based on code done by Rabeeh Khoury - rabeeh@galileo.co.il
+ * Based on code done by - Mark A. Greer <mgreer@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.
+ */
+
+/*
+ * The MV64360 has 2 PCI buses each with 1 window from the CPU bus to
+ * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
+ * We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 1MB
+ * and start on a boundary that is a multiple of the window size):
+ *
+ * 0xff800000-0xffffffff - Boot window
+ * 0xff000000-0xff000fff - AFIX registers (DevCS2)
+ * 0xfef00000-0xfef0ffff - Internal MV64x60 registers
+ * 0xfef40000-0xfef7ffff - Internal SRAM
+ * 0xfef00000-0xfef0ffff - MV64360 Registers
+ * 0x70000000-0x7fffffff - soldered flash (DevCS3)
+ * 0xe8000000-0xe9ffffff - PCI I/O
+ * 0x80000000-0xbfffffff - PCI MEM
+ */
+
+#ifndef __PPC_PLATFORMS_PPC7D_H
+#define __PPC_PLATFORMS_PPC7D_H
+
+#include <asm/ppcboot.h>
+
+/*****************************************************************************
+ * CPU Physical Memory Map setup.
+ *****************************************************************************/
+
+#define PPC7D_BOOT_WINDOW_BASE 0xff800000
+#define PPC7D_AFIX_REG_BASE 0xff000000
+#define PPC7D_INTERNAL_SRAM_BASE 0xfef40000
+#define PPC7D_FLASH_BASE 0x70000000
+
+#define PPC7D_BOOT_WINDOW_SIZE_ACTUAL 0x00800000 /* 8MB */
+#define PPC7D_FLASH_SIZE_ACTUAL 0x10000000 /* 256MB */
+
+#define PPC7D_BOOT_WINDOW_SIZE max(MV64360_WINDOW_SIZE_MIN, \
+ PPC7D_BOOT_WINDOW_SIZE_ACTUAL)
+#define PPC7D_FLASH_SIZE max(MV64360_WINDOW_SIZE_MIN, \
+ PPC7D_FLASH_SIZE_ACTUAL)
+#define PPC7D_AFIX_REG_SIZE max(MV64360_WINDOW_SIZE_MIN, 0xff)
+
+
+#define PPC7D_PCI0_MEM0_START_PROC_ADDR 0x80000000UL
+#define PPC7D_PCI0_MEM0_START_PCI_HI_ADDR 0x00000000UL
+#define PPC7D_PCI0_MEM0_START_PCI_LO_ADDR 0x80000000UL
+#define PPC7D_PCI0_MEM0_SIZE 0x20000000UL
+#define PPC7D_PCI0_MEM1_START_PROC_ADDR 0xe8010000UL
+#define PPC7D_PCI0_MEM1_START_PCI_HI_ADDR 0x00000000UL
+#define PPC7D_PCI0_MEM1_START_PCI_LO_ADDR 0x00000000UL
+#define PPC7D_PCI0_MEM1_SIZE 0x000f0000UL
+#define PPC7D_PCI0_IO_START_PROC_ADDR 0xe8000000UL
+#define PPC7D_PCI0_IO_START_PCI_ADDR 0x00000000UL
+#define PPC7D_PCI0_IO_SIZE 0x00010000UL
+
+#define PPC7D_PCI1_MEM0_START_PROC_ADDR 0xa0000000UL
+#define PPC7D_PCI1_MEM0_START_PCI_HI_ADDR 0x00000000UL
+#define PPC7D_PCI1_MEM0_START_PCI_LO_ADDR 0xa0000000UL
+#define PPC7D_PCI1_MEM0_SIZE 0x20000000UL
+#define PPC7D_PCI1_MEM1_START_PROC_ADDR 0xe9800000UL
+#define PPC7D_PCI1_MEM1_START_PCI_HI_ADDR 0x00000000UL
+#define PPC7D_PCI1_MEM1_START_PCI_LO_ADDR 0x00000000UL
+#define PPC7D_PCI1_MEM1_SIZE 0x00800000UL
+#define PPC7D_PCI1_IO_START_PROC_ADDR 0xe9000000UL
+#define PPC7D_PCI1_IO_START_PCI_ADDR 0x00000000UL
+#define PPC7D_PCI1_IO_SIZE 0x00010000UL
+
+#define PPC7D_DEFAULT_BAUD 9600
+#define PPC7D_MPSC_CLK_SRC 8 /* TCLK */
+#define PPC7D_MPSC_CLK_FREQ 133333333 /* 133.3333... MHz */
+
+#define PPC7D_ETH0_PHY_ADDR 8
+#define PPC7D_ETH1_PHY_ADDR 9
+#define PPC7D_ETH2_PHY_ADDR 0
+
+#define PPC7D_ETH_TX_QUEUE_SIZE 400
+#define PPC7D_ETH_RX_QUEUE_SIZE 400
+
+#define PPC7D_ETH_PORT_CONFIG_VALUE \
+ MV64340_ETH_UNICAST_NORMAL_MODE | \
+ MV64340_ETH_DEFAULT_RX_QUEUE_0 | \
+ MV64340_ETH_DEFAULT_RX_ARP_QUEUE_0 | \
+ MV64340_ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \
+ MV64340_ETH_RECEIVE_BC_IF_IP | \
+ MV64340_ETH_RECEIVE_BC_IF_ARP | \
+ MV64340_ETH_CAPTURE_TCP_FRAMES_DIS | \
+ MV64340_ETH_CAPTURE_UDP_FRAMES_DIS | \
+ MV64340_ETH_DEFAULT_RX_TCP_QUEUE_0 | \
+ MV64340_ETH_DEFAULT_RX_UDP_QUEUE_0 | \
+ MV64340_ETH_DEFAULT_RX_BPDU_QUEUE_0
+
+#define PPC7D_ETH_PORT_CONFIG_EXTEND_VALUE \
+ MV64340_ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \
+ MV64340_ETH_PARTITION_DISABLE
+
+#define GT_ETH_IPG_INT_RX(value) \
+ ((value & 0x3fff) << 8)
+
+#define PPC7D_ETH_PORT_SDMA_CONFIG_VALUE \
+ MV64340_ETH_RX_BURST_SIZE_4_64BIT | \
+ GT_ETH_IPG_INT_RX(0) | \
+ MV64340_ETH_TX_BURST_SIZE_4_64BIT
+
+#define PPC7D_ETH_PORT_SERIAL_CONTROL_VALUE \
+ MV64340_ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \
+ MV64340_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \
+ MV64340_ETH_ADV_SYMMETRIC_FLOW_CTRL | \
+ MV64340_ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \
+ MV64340_ETH_FORCE_BP_MODE_NO_JAM | \
+ (1 << 9) | \
+ MV64340_ETH_DO_NOT_FORCE_LINK_FAIL | \
+ MV64340_ETH_RETRANSMIT_16_ATTEMPTS | \
+ MV64340_ETH_ENABLE_AUTO_NEG_SPEED_GMII | \
+ MV64340_ETH_DTE_ADV_0 | \
+ MV64340_ETH_DISABLE_AUTO_NEG_BYPASS | \
+ MV64340_ETH_AUTO_NEG_NO_CHANGE | \
+ MV64340_ETH_MAX_RX_PACKET_9700BYTE | \
+ MV64340_ETH_CLR_EXT_LOOPBACK | \
+ MV64340_ETH_SET_FULL_DUPLEX_MODE | \
+ MV64340_ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
+
+/*****************************************************************************
+ * Serial defines.
+ *****************************************************************************/
+
+#define PPC7D_SERIAL_0 0xe80003f8
+#define PPC7D_SERIAL_1 0xe80002f8
+
+#define RS_TABLE_SIZE 2
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define UART_CLK 1843200
+#define BASE_BAUD ( UART_CLK / 16 )
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, PPC7D_SERIAL_0, 4, STD_COM_FLAGS, /* ttyS0 */ \
+ iomem_base: (u8 *)PPC7D_SERIAL_0, \
+ io_type: SERIAL_IO_MEM, }, \
+ { 0, BASE_BAUD, PPC7D_SERIAL_1, 3, STD_COM_FLAGS, /* ttyS1 */ \
+ iomem_base: (u8 *)PPC7D_SERIAL_1, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
+
+/*****************************************************************************
+ * CPLD defines.
+ *
+ * Register map:-
+ *
+ * 0000 to 000F South Bridge DMA 1 Control
+ * 0020 and 0021 South Bridge Interrupt 1 Control
+ * 0040 to 0043 South Bridge Counter Control
+ * 0060 Keyboard
+ * 0061 South Bridge NMI Status and Control
+ * 0064 Keyboard
+ * 0071 and 0072 RTC R/W
+ * 0078 to 007B South Bridge BIOS Timer
+ * 0080 to 0090 South Bridge DMA Pages
+ * 00A0 and 00A1 South Bridge Interrupt 2 Control
+ * 00C0 to 00DE South Bridge DMA 2 Control
+ * 02E8 to 02EF COM6 R/W
+ * 02F8 to 02FF South Bridge COM2 R/W
+ * 03E8 to 03EF COM5 R/W
+ * 03F8 to 03FF South Bridge COM1 R/W
+ * 040A South Bridge DMA Scatter/Gather RO
+ * 040B DMA 1 Extended Mode WO
+ * 0410 to 043F South Bridge DMA Scatter/Gather
+ * 0481 to 048B South Bridge DMA High Pages
+ * 04D0 and 04D1 South Bridge Edge/Level Control
+ * 04D6 DMA 2 Extended Mode WO
+ * 0804 Memory Configuration RO
+ * 0806 Memory Configuration Extend RO
+ * 0808 SCSI Activity LED R/W
+ * 080C Equipment Present 1 RO
+ * 080E Equipment Present 2 RO
+ * 0810 Equipment Present 3 RO
+ * 0812 Equipment Present 4 RO
+ * 0818 Key Lock RO
+ * 0820 LEDS R/W
+ * 0824 COMs R/W
+ * 0826 RTS R/W
+ * 0828 Reset R/W
+ * 082C Watchdog Trig R/W
+ * 082E Interrupt R/W
+ * 0830 Interrupt Status RO
+ * 0832 PCI configuration RO
+ * 0854 Board Revision RO
+ * 0858 Extended ID RO
+ * 0864 ID Link RO
+ * 0866 Motherboard Type RO
+ * 0868 FLASH Write control RO
+ * 086A Software FLASH write protect R/W
+ * 086E FLASH Control R/W
+ *****************************************************************************/
+
+#define PPC7D_CPLD_MEM_CONFIG 0x0804
+#define PPC7D_CPLD_MEM_CONFIG_EXTEND 0x0806
+#define PPC7D_CPLD_SCSI_ACTIVITY_LED 0x0808
+#define PPC7D_CPLD_EQUIPMENT_PRESENT_1 0x080C
+#define PPC7D_CPLD_EQUIPMENT_PRESENT_2 0x080E
+#define PPC7D_CPLD_EQUIPMENT_PRESENT_3 0x0810
+#define PPC7D_CPLD_EQUIPMENT_PRESENT_4 0x0812
+#define PPC7D_CPLD_KEY_LOCK 0x0818
+#define PPC7D_CPLD_LEDS 0x0820
+#define PPC7D_CPLD_COMS 0x0824
+#define PPC7D_CPLD_RTS 0x0826
+#define PPC7D_CPLD_RESET 0x0828
+#define PPC7D_CPLD_WATCHDOG_TRIG 0x082C
+#define PPC7D_CPLD_INTR 0x082E
+#define PPC7D_CPLD_INTR_STATUS 0x0830
+#define PPC7D_CPLD_PCI_CONFIG 0x0832
+#define PPC7D_CPLD_BOARD_REVISION 0x0854
+#define PPC7D_CPLD_EXTENDED_ID 0x0858
+#define PPC7D_CPLD_ID_LINK 0x0864
+#define PPC7D_CPLD_MOTHERBOARD_TYPE 0x0866
+#define PPC7D_CPLD_FLASH_WRITE_CNTL 0x0868
+#define PPC7D_CPLD_SW_FLASH_WRITE_PROTECT 0x086A
+#define PPC7D_CPLD_FLASH_CNTL 0x086E
+
+/* MEMORY_CONFIG_EXTEND */
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_MASK 0xc0
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_128M 0
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_256M 0x40
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_512M 0x80
+#define PPC7D_CPLD_SDRAM_BANK_SIZE_1G 0xc0
+#define PPC7D_CPLD_FLASH_DEV_SIZE_MASK 0x03
+#define PPC7D_CPLD_FLASH_BANK_NUM_MASK 0x0c
+#define PPC7D_CPLD_FLASH_DEV_SIZE_64M 0
+#define PPC7D_CPLD_FLASH_DEV_SIZE_32M 1
+#define PPC7D_CPLD_FLASH_DEV_SIZE_16M 3
+#define PPC7D_CPLD_FLASH_BANK_NUM_4 0x00
+#define PPC7D_CPLD_FLASH_BANK_NUM_3 0x04
+#define PPC7D_CPLD_FLASH_BANK_NUM_2 0x08
+#define PPC7D_CPLD_FLASH_BANK_NUM_1 0x0c
+
+/* SCSI_LED */
+#define PPC7D_CPLD_SCSI_ACTIVITY_LED_OFF 0
+#define PPC7D_CPLD_SCSI_ACTIVITY_LED_ON 1
+
+/* EQUIPMENT_PRESENT_1 */
+#define PPC7D_CPLD_EQPT_PRES_1_FITTED 0
+#define PPC7D_CPLD_EQPT_PRES_1_PMC2_MASK (0x80 >> 2)
+#define PPC7D_CPLD_EQPT_PRES_1_PMC1_MASK (0x80 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_1_AFIX_MASK (0x80 >> 4)
+
+/* EQUIPMENT_PRESENT_2 */
+#define PPC7D_CPLD_EQPT_PRES_2_FITTED !0
+#define PPC7D_CPLD_EQPT_PRES_2_UNIVERSE_MASK (0x80 >> 0)
+#define PPC7D_CPLD_EQPT_PRES_2_COM36_MASK (0x80 >> 2)
+#define PPC7D_CPLD_EQPT_PRES_2_GIGE_MASK (0x80 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_2_DUALGIGE_MASK (0x80 >> 4)
+
+/* EQUIPMENT_PRESENT_3 */
+#define PPC7D_CPLD_EQPT_PRES_3_PMC2_V_MASK (0x80 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC2_5V (0 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC2_3V (0x80 >> 3)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC1_V_MASK (0x80 >> 4)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC1_5V (0 >> 4)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC1_3V (0x80 >> 4)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_MASK (0x80 >> 5)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_INTER (0 >> 5)
+#define PPC7D_CPLD_EQPT_PRES_3_PMC_POWER_VME (0x80 >> 5)
+
+/* EQUIPMENT_PRESENT_4 */
+#define PPC7D_CPLD_EQPT_PRES_4_LPT_MASK (0x80 >> 2)
+#define PPC7D_CPLD_EQPT_PRES_4_LPT_FITTED (0x80 >> 2)
+#define PPC7D_CPLD_EQPT_PRES_4_PS2_USB2_MASK (0xc0 >> 6)
+#define PPC7D_CPLD_EQPT_PRES_4_PS2_FITTED (0x40 >> 6)
+#define PPC7D_CPLD_EQPT_PRES_4_USB2_FITTED (0x80 >> 6)
+
+/* CPLD_LEDS */
+#define PPC7D_CPLD_LEDS_ON (!0)
+#define PPC7D_CPLD_LEDS_OFF (0)
+#define PPC7D_CPLD_LEDS_NVRAM_PAGE_MASK (0xc0 >> 2)
+#define PPC7D_CPLD_LEDS_DS201_MASK (0x80 >> 4)
+#define PPC7D_CPLD_LEDS_DS219_MASK (0x80 >> 5)
+#define PPC7D_CPLD_LEDS_DS220_MASK (0x80 >> 6)
+#define PPC7D_CPLD_LEDS_DS221_MASK (0x80 >> 7)
+
+/* CPLD_COMS */
+#define PPC7D_CPLD_COMS_COM3_TCLKEN (0x80 >> 0)
+#define PPC7D_CPLD_COMS_COM3_RTCLKEN (0x80 >> 1)
+#define PPC7D_CPLD_COMS_COM3_MODE_MASK (0x80 >> 2)
+#define PPC7D_CPLD_COMS_COM3_MODE_RS232 (0)
+#define PPC7D_CPLD_COMS_COM3_MODE_RS422 (0x80 >> 2)
+#define PPC7D_CPLD_COMS_COM3_TXEN (0x80 >> 3)
+#define PPC7D_CPLD_COMS_COM4_TCLKEN (0x80 >> 4)
+#define PPC7D_CPLD_COMS_COM4_RTCLKEN (0x80 >> 5)
+#define PPC7D_CPLD_COMS_COM4_MODE_MASK (0x80 >> 6)
+#define PPC7D_CPLD_COMS_COM4_MODE_RS232 (0)
+#define PPC7D_CPLD_COMS_COM4_MODE_RS422 (0x80 >> 6)
+#define PPC7D_CPLD_COMS_COM4_TXEN (0x80 >> 7)
+
+/* CPLD_RTS */
+#define PPC7D_CPLD_RTS_COM36_LOOPBACK (0x80 >> 0)
+#define PPC7D_CPLD_RTS_COM4_SCLK (0x80 >> 1)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_MASK (0xc0 >> 2)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_DISABLED (0 >> 2)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_ENABLED (0x80 >> 2)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_ENABLED_RTG3 (0xc0 >> 2)
+#define PPC7D_CPLD_RTS_COM3_TXFUNC_ENABLED_RTG3S (0xc0 >> 2)
+#define PPC7D_CPLD_RTS_COM56_MODE_MASK (0x80 >> 4)
+#define PPC7D_CPLD_RTS_COM56_MODE_RS232 (0)
+#define PPC7D_CPLD_RTS_COM56_MODE_RS422 (0x80 >> 4)
+#define PPC7D_CPLD_RTS_COM56_ENABLE_MASK (0x80 >> 5)
+#define PPC7D_CPLD_RTS_COM56_DISABLED (0)
+#define PPC7D_CPLD_RTS_COM56_ENABLED (0x80 >> 5)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_MASK (0xc0 >> 6)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_DISABLED (0 >> 6)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_ENABLED (0x80 >> 6)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_ENABLED_RTG3 (0x40 >> 6)
+#define PPC7D_CPLD_RTS_COM4_TXFUNC_ENABLED_RTG3S (0x40 >> 6)
+
+/* WATCHDOG_TRIG */
+#define PPC7D_CPLD_WDOG_CAUSE_MASK (0x80 >> 0)
+#define PPC7D_CPLD_WDOG_CAUSE_NORMAL_RESET (0 >> 0)
+#define PPC7D_CPLD_WDOG_CAUSE_WATCHDOG (0x80 >> 0)
+#define PPC7D_CPLD_WDOG_ENABLE_MASK (0x80 >> 6)
+#define PPC7D_CPLD_WDOG_ENABLE_OFF (0 >> 6)
+#define PPC7D_CPLD_WDOG_ENABLE_ON (0x80 >> 6)
+#define PPC7D_CPLD_WDOG_RESETSW_MASK (0x80 >> 7)
+#define PPC7D_CPLD_WDOG_RESETSW_OFF (0 >> 7)
+#define PPC7D_CPLD_WDOG_RESETSW_ON (0x80 >> 7)
+
+/* Interrupt mask and status bits */
+#define PPC7D_CPLD_INTR_TEMP_MASK (0x80 >> 0)
+#define PPC7D_CPLD_INTR_HB8_MASK (0x80 >> 1)
+#define PPC7D_CPLD_INTR_PHY1_MASK (0x80 >> 2)
+#define PPC7D_CPLD_INTR_PHY0_MASK (0x80 >> 3)
+#define PPC7D_CPLD_INTR_ISANMI_MASK (0x80 >> 5)
+#define PPC7D_CPLD_INTR_CRITTEMP_MASK (0x80 >> 6)
+
+/* CPLD_INTR */
+#define PPC7D_CPLD_INTR_ENABLE_OFF (0)
+#define PPC7D_CPLD_INTR_ENABLE_ON (!0)
+
+/* CPLD_INTR_STATUS */
+#define PPC7D_CPLD_INTR_STATUS_OFF (0)
+#define PPC7D_CPLD_INTR_STATUS_ON (!0)
+
+/* CPLD_PCI_CONFIG */
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_MASK 0x70
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCI33 0x00
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCI66 0x10
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX33 0x40
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX66 0x50
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX100 0x60
+#define PPC7D_CPLD_PCI_CONFIG_PCI0_PCIX133 0x70
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_MASK 0x07
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCI33 0x00
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCI66 0x01
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX33 0x04
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX66 0x05
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX100 0x06
+#define PPC7D_CPLD_PCI_CONFIG_PCI1_PCIX133 0x07
+
+/* CPLD_BOARD_REVISION */
+#define PPC7D_CPLD_BOARD_REVISION_NUMBER_MASK 0xe0
+#define PPC7D_CPLD_BOARD_REVISION_LETTER_MASK 0x1f
+
+/* CPLD_EXTENDED_ID */
+#define PPC7D_CPLD_EXTENDED_ID_PPC7D 0x18
+
+/* CPLD_ID_LINK */
+#define PPC7D_CPLD_ID_LINK_VME64_GAP_MASK (0x80 >> 2)
+#define PPC7D_CPLD_ID_LINK_VME64_GA4_MASK (0x80 >> 3)
+#define PPC7D_CPLD_ID_LINK_E13_MASK (0x80 >> 4)
+#define PPC7D_CPLD_ID_LINK_E12_MASK (0x80 >> 5)
+#define PPC7D_CPLD_ID_LINK_E7_MASK (0x80 >> 6)
+#define PPC7D_CPLD_ID_LINK_E6_MASK (0x80 >> 7)
+
+/* CPLD_MOTHERBOARD_TYPE */
+#define PPC7D_CPLD_MB_TYPE_ECC_ENABLE_MASK (0x80 >> 0)
+#define PPC7D_CPLD_MB_TYPE_ECC_ENABLED (0x80 >> 0)
+#define PPC7D_CPLD_MB_TYPE_ECC_DISABLED (0 >> 0)
+#define PPC7D_CPLD_MB_TYPE_ECC_FITTED_MASK (0x80 >> 3)
+#define PPC7D_CPLD_MB_TYPE_PLL_MASK 0x0c
+#define PPC7D_CPLD_MB_TYPE_PLL_133 0x00
+#define PPC7D_CPLD_MB_TYPE_PLL_100 0x08
+#define PPC7D_CPLD_MB_TYPE_PLL_64 0x04
+#define PPC7D_CPLD_MB_TYPE_HW_ID_MASK 0x03
+
+/* CPLD_FLASH_WRITE_CNTL */
+#define PPD7D_CPLD_FLASH_CNTL_WR_LINK_MASK (0x80 >> 0)
+#define PPD7D_CPLD_FLASH_CNTL_WR_LINK_FITTED (0x80 >> 0)
+#define PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_MASK (0x80 >> 2)
+#define PPD7D_CPLD_FLASH_CNTL_BOOT_LINK_FITTED (0x80 >> 2)
+#define PPD7D_CPLD_FLASH_CNTL_USER_LINK_MASK (0x80 >> 3)
+#define PPD7D_CPLD_FLASH_CNTL_USER_LINK_FITTED (0x80 >> 3)
+#define PPD7D_CPLD_FLASH_CNTL_RECO_WR_MASK (0x80 >> 5)
+#define PPD7D_CPLD_FLASH_CNTL_RECO_WR_ENABLED (0x80 >> 5)
+#define PPD7D_CPLD_FLASH_CNTL_BOOT_WR_MASK (0x80 >> 6)
+#define PPD7D_CPLD_FLASH_CNTL_BOOT_WR_ENABLED (0x80 >> 6)
+#define PPD7D_CPLD_FLASH_CNTL_USER_WR_MASK (0x80 >> 7)
+#define PPD7D_CPLD_FLASH_CNTL_USER_WR_ENABLED (0x80 >> 7)
+
+/* CPLD_SW_FLASH_WRITE_PROTECT */
+#define PPC7D_CPLD_SW_FLASH_WRPROT_ENABLED (!0)
+#define PPC7D_CPLD_SW_FLASH_WRPROT_DISABLED (0)
+#define PPC7D_CPLD_SW_FLASH_WRPROT_SYSBOOT_MASK (0x80 >> 6)
+#define PPC7D_CPLD_SW_FLASH_WRPROT_USER_MASK (0x80 >> 7)
+
+/* CPLD_FLASH_WRITE_CNTL */
+#define PPC7D_CPLD_FLASH_CNTL_NVRAM_PROT_MASK (0x80 >> 0)
+#define PPC7D_CPLD_FLASH_CNTL_NVRAM_DISABLED (0 >> 0)
+#define PPC7D_CPLD_FLASH_CNTL_NVRAM_ENABLED (0x80 >> 0)
+#define PPC7D_CPLD_FLASH_CNTL_ALTBOOT_LINK_MASK (0x80 >> 1)
+#define PPC7D_CPLD_FLASH_CNTL_VMEBOOT_LINK_MASK (0x80 >> 2)
+#define PPC7D_CPLD_FLASH_CNTL_RECBOOT_LINK_MASK (0x80 >> 3)
+
+
+#endif /* __PPC_PLATFORMS_PPC7D_H */
diff --git a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c
new file mode 100644
index 00000000000..0f84ca60361
--- /dev/null
+++ b/arch/ppc/platforms/residual.c
@@ -0,0 +1,1034 @@
+/*
+ * Code to deal with the PReP residual data.
+ *
+ * Written by: Cort Dougan (cort@cs.nmt.edu)
+ * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es)
+ *
+ * This file is based on the following documentation:
+ *
+ * IBM Power Personal Systems Architecture
+ * Residual Data
+ * Document Number: PPS-AR-FW0001
+ *
+ * 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.
+ *
+ */
+
+#include <linux/string.h>
+#include <asm/residual.h>
+#include <asm/pnp.h>
+#include <asm/byteorder.h>
+
+#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/ioport.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/sections.h>
+#include <asm/mmu.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+
+
+unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,};
+RESIDUAL *res = (RESIDUAL *)&__res;
+
+char * PnP_BASE_TYPES[] __initdata = {
+ "Reserved",
+ "MassStorageDevice",
+ "NetworkInterfaceController",
+ "DisplayController",
+ "MultimediaController",
+ "MemoryController",
+ "BridgeController",
+ "CommunicationsDevice",
+ "SystemPeripheral",
+ "InputDevice",
+ "ServiceProcessor"
+ };
+
+/* Device Sub Type Codes */
+
+unsigned char * PnP_SUB_TYPES[] __initdata = {
+ "\001\000SCSIController",
+ "\001\001IDEController",
+ "\001\002FloppyController",
+ "\001\003IPIController",
+ "\001\200OtherMassStorageController",
+ "\002\000EthernetController",
+ "\002\001TokenRingController",
+ "\002\002FDDIController",
+ "\002\0x80OtherNetworkController",
+ "\003\000VGAController",
+ "\003\001SVGAController",
+ "\003\002XGAController",
+ "\003\200OtherDisplayController",
+ "\004\000VideoController",
+ "\004\001AudioController",
+ "\004\200OtherMultimediaController",
+ "\005\000RAM",
+ "\005\001FLASH",
+ "\005\200OtherMemoryDevice",
+ "\006\000HostProcessorBridge",
+ "\006\001ISABridge",
+ "\006\002EISABridge",
+ "\006\003MicroChannelBridge",
+ "\006\004PCIBridge",
+ "\006\005PCMCIABridge",
+ "\006\006VMEBridge",
+ "\006\200OtherBridgeDevice",
+ "\007\000RS232Device",
+ "\007\001ATCompatibleParallelPort",
+ "\007\200OtherCommunicationsDevice",
+ "\010\000ProgrammableInterruptController",
+ "\010\001DMAController",
+ "\010\002SystemTimer",
+ "\010\003RealTimeClock",
+ "\010\004L2Cache",
+ "\010\005NVRAM",
+ "\010\006PowerManagement",
+ "\010\007CMOS",
+ "\010\010OperatorPanel",
+ "\010\011ServiceProcessorClass1",
+ "\010\012ServiceProcessorClass2",
+ "\010\013ServiceProcessorClass3",
+ "\010\014GraphicAssist",
+ "\010\017SystemPlanar",
+ "\010\200OtherSystemPeripheral",
+ "\011\000KeyboardController",
+ "\011\001Digitizer",
+ "\011\002MouseController",
+ "\011\003TabletController",
+ "\011\0x80OtherInputController",
+ "\012\000GeneralMemoryController",
+ NULL
+};
+
+/* Device Interface Type Codes */
+
+unsigned char * PnP_INTERFACES[] __initdata = {
+ "\000\000\000General",
+ "\001\000\000GeneralSCSI",
+ "\001\001\000GeneralIDE",
+ "\001\001\001ATACompatible",
+
+ "\001\002\000GeneralFloppy",
+ "\001\002\001Compatible765",
+ "\001\002\002NS398_Floppy", /* NS Super I/O wired to use index
+ register at port 398 and data
+ register at port 399 */
+ "\001\002\003NS26E_Floppy", /* Ports 26E and 26F */
+ "\001\002\004NS15C_Floppy", /* Ports 15C and 15D */
+ "\001\002\005NS2E_Floppy", /* Ports 2E and 2F */
+ "\001\002\006CHRP_Floppy", /* CHRP Floppy in PR*P system */
+
+ "\001\003\000GeneralIPI",
+
+ "\002\000\000GeneralEther",
+ "\002\001\000GeneralToken",
+ "\002\002\000GeneralFDDI",
+
+ "\003\000\000GeneralVGA",
+ "\003\001\000GeneralSVGA",
+ "\003\002\000GeneralXGA",
+
+ "\004\000\000GeneralVideo",
+ "\004\001\000GeneralAudio",
+ "\004\001\001CS4232Audio", /* CS 4232 Plug 'n Play Configured */
+
+ "\005\000\000GeneralRAM",
+ /* This one is obviously wrong ! */
+ "\005\000\000PCIMemoryController", /* PCI Config Method */
+ "\005\000\001RS6KMemoryController", /* RS6K Config Method */
+ "\005\001\000GeneralFLASH",
+
+ "\006\000\000GeneralHostBridge",
+ "\006\001\000GeneralISABridge",
+ "\006\002\000GeneralEISABridge",
+ "\006\003\000GeneralMCABridge",
+ /* GeneralPCIBridge = 0, */
+ "\006\004\000PCIBridgeDirect",
+ "\006\004\001PCIBridgeIndirect",
+ "\006\004\002PCIBridgeRS6K",
+ "\006\005\000GeneralPCMCIABridge",
+ "\006\006\000GeneralVMEBridge",
+
+ "\007\000\000GeneralRS232",
+ "\007\000\001COMx",
+ "\007\000\002Compatible16450",
+ "\007\000\003Compatible16550",
+ "\007\000\004NS398SerPort", /* NS Super I/O wired to use index
+ register at port 398 and data
+ register at port 399 */
+ "\007\000\005NS26ESerPort", /* Ports 26E and 26F */
+ "\007\000\006NS15CSerPort", /* Ports 15C and 15D */
+ "\007\000\007NS2ESerPort", /* Ports 2E and 2F */
+
+ "\007\001\000GeneralParPort",
+ "\007\001\001LPTx",
+ "\007\001\002NS398ParPort", /* NS Super I/O wired to use index
+ register at port 398 and data
+ register at port 399 */
+ "\007\001\003NS26EParPort", /* Ports 26E and 26F */
+ "\007\001\004NS15CParPort", /* Ports 15C and 15D */
+ "\007\001\005NS2EParPort", /* Ports 2E and 2F */
+
+ "\010\000\000GeneralPIC",
+ "\010\000\001ISA_PIC",
+ "\010\000\002EISA_PIC",
+ "\010\000\003MPIC",
+ "\010\000\004RS6K_PIC",
+
+ "\010\001\000GeneralDMA",
+ "\010\001\001ISA_DMA",
+ "\010\001\002EISA_DMA",
+
+ "\010\002\000GeneralTimer",
+ "\010\002\001ISA_Timer",
+ "\010\002\002EISA_Timer",
+ "\010\003\000GeneralRTC",
+ "\010\003\001ISA_RTC",
+
+ "\010\004\001StoreThruOnly",
+ "\010\004\002StoreInEnabled",
+ "\010\004\003RS6KL2Cache",
+
+ "\010\005\000IndirectNVRAM", /* Indirectly addressed */
+ "\010\005\001DirectNVRAM", /* Memory Mapped */
+ "\010\005\002IndirectNVRAM24", /* Indirectly addressed - 24 bit */
+
+ "\010\006\000GeneralPowerManagement",
+ "\010\006\001EPOWPowerManagement",
+ "\010\006\002PowerControl", // d1378
+
+ "\010\007\000GeneralCMOS",
+
+ "\010\010\000GeneralOPPanel",
+ "\010\010\001HarddiskLight",
+ "\010\010\002CDROMLight",
+ "\010\010\003PowerLight",
+ "\010\010\004KeyLock",
+ "\010\010\005ANDisplay", /* AlphaNumeric Display */
+ "\010\010\006SystemStatusLED", /* 3 digit 7 segment LED */
+ "\010\010\007CHRP_SystemStatusLED", /* CHRP LEDs in PR*P system */
+
+ "\010\011\000GeneralServiceProcessor",
+ "\010\012\000GeneralServiceProcessor",
+ "\010\013\000GeneralServiceProcessor",
+
+ "\010\014\001TransferData",
+ "\010\014\002IGMC32",
+ "\010\014\003IGMC64",
+
+ "\010\017\000GeneralSystemPlanar", /* 10/5/95 */
+ NULL
+ };
+
+static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType,
+ unsigned char SubType) {
+ unsigned char ** s=PnP_SUB_TYPES;
+ while (*s && !((*s)[0]==BaseType
+ && (*s)[1]==SubType)) s++;
+ if (*s) return *s+2;
+ else return("Unknown !");
+};
+
+static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType,
+ unsigned char SubType,
+ unsigned char Interface) {
+ unsigned char ** s=PnP_INTERFACES;
+ while (*s && !((*s)[0]==BaseType
+ && (*s)[1]==SubType
+ && (*s)[2]==Interface)) s++;
+ if (*s) return *s+3;
+ else return NULL;
+};
+
+static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) {
+ int i, c;
+ char decomp[4];
+#define p pkt->S14_Pack.S14_Data.S14_PPCPack
+ switch(p.Type) {
+ case 1:
+ /* Decompress first 3 chars */
+ c = *(unsigned short *)p.PPCData;
+ decomp[0]='A'-1+((c>>10)&0x1F);
+ decomp[1]='A'-1+((c>>5)&0x1F);
+ decomp[2]='A'-1+(c&0x1F);
+ decomp[3]=0;
+ printk(" Chip identification: %s%4.4X\n",
+ decomp, ld_le16((unsigned short *)(p.PPCData+2)));
+ break;
+ default:
+ printk(" Small vendor item type 0x%2.2x, data (hex): ",
+ p.Type);
+ for(i=0; i<size-2; i++) printk("%2.2x ", p.PPCData[i]);
+ printk("\n");
+ break;
+ }
+#undef p
+}
+
+static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) {
+ static const unsigned char * intlevel[] = {"high", "low"};
+ static const unsigned char * intsense[] = {"edge", "level"};
+
+ switch (tag_small_item_name(pkt->S1_Pack.Tag)) {
+ case PnPVersion:
+ printk(" PnPversion 0x%x.%x\n",
+ pkt->S1_Pack.Version[0], /* How to interpret version ? */
+ pkt->S1_Pack.Version[1]);
+ break;
+// case Logicaldevice:
+ break;
+// case CompatibleDevice:
+ break;
+ case IRQFormat:
+#define p pkt->S4_Pack
+ printk(" IRQ Mask 0x%4.4x, %s %s sensitive\n",
+ ld_le16((unsigned short *)p.IRQMask),
+ intlevel[(size>3) ? !(p.IRQInfo&0x05) : 0],
+ intsense[(size>3) ? !(p.IRQInfo&0x03) : 0]);
+#undef p
+ break;
+ case DMAFormat:
+#define p pkt->S5_Pack
+ printk(" DMA channel mask 0x%2.2x, info 0x%2.2x\n",
+ p.DMAMask, p.DMAInfo);
+#undef p
+ break;
+ case StartDepFunc:
+ printk("Start dependent function:\n");
+ break;
+ case EndDepFunc:
+ printk("End dependent function\n");
+ break;
+ case IOPort:
+#define p pkt->S8_Pack
+ printk(" Variable (%d decoded bits) I/O port\n"
+ " from 0x%4.4x to 0x%4.4x, alignment %d, %d ports\n",
+ p.IOInfo&ISAAddr16bit?16:10,
+ ld_le16((unsigned short *)p.RangeMin),
+ ld_le16((unsigned short *)p.RangeMax),
+ p.IOAlign, p.IONum);
+#undef p
+ break;
+ case FixedIOPort:
+#define p pkt->S9_Pack
+ printk(" Fixed (10 decoded bits) I/O port from %3.3x to %3.3x\n",
+ (p.Range[1]<<8)|p.Range[0],
+ ((p.Range[1]<<8)|p.Range[0])+p.IONum-1);
+#undef p
+ break;
+ case Res1:
+ case Res2:
+ case Res3:
+ printk(" Undefined packet type %d!\n",
+ tag_small_item_name(pkt->S1_Pack.Tag));
+ break;
+ case SmallVendorItem:
+ printsmallvendor(pkt,size);
+ break;
+ default:
+ printk(" Type 0x2.2x%d, size=%d\n",
+ pkt->S1_Pack.Tag, size);
+ break;
+ }
+}
+
+static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) {
+ static const unsigned char * addrtype[] = {"I/O", "Memory", "System"};
+ static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"};
+ static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"};
+ static const unsigned char * transtype[] = {"direct", "mapped", "direct-store segment"};
+ static const unsigned char * L2type[] = {"WriteThru", "CopyBack"};
+ static const unsigned char * L2assoc[] = {"DirectMapped", "2-way set"};
+
+ int i;
+ char tmpstr[30], *t;
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+ switch(p.Type) {
+ case 2:
+ printk(" %d K %s %s L2 cache, %d/%d bytes line/sector size\n",
+ ld_le32((unsigned int *)p.PPCData),
+ L2type[p.PPCData[10]-1],
+ L2assoc[p.PPCData[4]-1],
+ ld_le16((unsigned short *)p.PPCData+3),
+ ld_le16((unsigned short *)p.PPCData+4));
+ break;
+ case 3:
+ printk(" PCI Bridge parameters\n"
+ " ConfigBaseAddress %0x\n"
+ " ConfigBaseData %0x\n"
+ " Bus number %d\n",
+ ld_le32((unsigned int *)p.PPCData),
+ ld_le32((unsigned int *)(p.PPCData+8)),
+ p.PPCData[16]);
+ for(i=20; i<size-4; i+=12) {
+ int j, first;
+ if(p.PPCData[i]) printk(" PCI Slot %d", p.PPCData[i]);
+ else printk (" Integrated PCI device");
+ for(j=0, first=1, t=tmpstr; j<4; j++) {
+ int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
+ if(line!=0xffff){
+ if(first) first=0; else *t++='/';
+ *t++='A'+j;
+ }
+ }
+ *t='\0';
+ printk(" DevFunc 0x%x interrupt line(s) %s routed to",
+ p.PPCData[i+1],tmpstr);
+ sprintf(tmpstr,
+ inttype[p.PPCData[i+2]-1],
+ p.PPCData[i+3]);
+ printk(" %s line(s) ",
+ tmpstr);
+ for(j=0, first=1, t=tmpstr; j<4; j++) {
+ int line=ld_le16((unsigned short *)(p.PPCData+i+4)+j);
+ if(line!=0xffff){
+ if(first) first=0; else *t++='/';
+ t+=sprintf(t,"%d(%c)",
+ line&0x7fff,
+ line&0x8000?'E':'L');
+ }
+ }
+ printk("%s\n",tmpstr);
+ }
+ break;
+ case 5:
+ printk(" Bridge address translation, %s decoding:\n"
+ " Processor Bus Size Conversion Translation\n"
+ " 0x%8.8x 0x%8.8x 0x%8.8x %s %s\n",
+ p.PPCData[0]&1 ? "positive" : "subtractive",
+ ld_le32((unsigned int *)p.PPCData+1),
+ ld_le32((unsigned int *)p.PPCData+3),
+ ld_le32((unsigned int *)p.PPCData+5),
+ convtype[p.PPCData[2]-1],
+ transtype[p.PPCData[1]-1]);
+ break;
+ case 6:
+ printk(" Bus speed %d Hz, %d slot(s)\n",
+ ld_le32((unsigned int *)p.PPCData),
+ p.PPCData[4]);
+ break;
+ case 7:
+ printk(" SCSI buses: %d, id(s):", p.PPCData[0]);
+ for(i=1; i<=p.PPCData[0]; i++)
+ printk(" %d%c", p.PPCData[i], i==p.PPCData[0] ? '\n' : ',');
+ break;
+ case 9:
+ printk(" %s address (%d bits), at 0x%x size 0x%x bytes\n",
+ addrtype[p.PPCData[0]-1],
+ p.PPCData[1],
+ ld_le32((unsigned int *)(p.PPCData+4)),
+ ld_le32((unsigned int *)(p.PPCData+12)));
+ break;
+ case 10:
+ sprintf(tmpstr,
+ inttype[p.PPCData[0]-1],
+ p.PPCData[1]);
+
+ printk(" ISA interrupts routed to %s\n"
+ " lines",
+ tmpstr);
+ for(i=0; i<16; i++) {
+ int line=ld_le16((unsigned short *)p.PPCData+i+1);
+ if (line!=0xffff) printk(" %d(IRQ%d)", line, i);
+ }
+ printk("\n");
+ break;
+ default:
+ printk(" Large vendor item type 0x%2.2x\n Data (hex):",
+ p.Type);
+ for(i=0; i<size-4; i++) printk(" %2.2x", p.PPCData[i]);
+ printk("\n");
+#undef p
+ }
+}
+
+static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) {
+ switch (tag_large_item_name(pkt->S1_Pack.Tag)) {
+ case LargeVendorItem:
+ printlargevendor(pkt, size);
+ break;
+ default:
+ printk(" Type 0x2.2x%d, size=%d\n",
+ pkt->S1_Pack.Tag, size);
+ break;
+ }
+}
+
+static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat)
+{
+ if (pkt->S1_Pack.Tag== END_TAG) {
+ printk(" No packets describing %s resources.\n", cat);
+ return;
+ }
+ printk( " Packets describing %s resources:\n",cat);
+ do {
+ int size;
+ if (tag_type(pkt->S1_Pack.Tag)) {
+ size= 3 +
+ pkt->L1_Pack.Count0 +
+ pkt->L1_Pack.Count1*256;
+ printlargepacket(pkt, size);
+ } else {
+ size=tag_small_count(pkt->S1_Pack.Tag)+1;
+ printsmallpacket(pkt, size);
+ }
+ pkt = (PnP_TAG_PACKET *)((unsigned char *) pkt + size);
+ } while (pkt->S1_Pack.Tag != END_TAG);
+}
+
+void __init print_residual_device_info(void)
+{
+ int i;
+ PPC_DEVICE *dev;
+#define did dev->DeviceId
+
+ /* make sure we have residual data first */
+ if (!have_residual_data)
+ return;
+
+ printk("Residual: %ld devices\n", res->ActualNumDevices);
+ for ( i = 0;
+ i < res->ActualNumDevices ;
+ i++)
+ {
+ char decomp[4], sn[20];
+ const char * s;
+ dev = &res->Devices[i];
+ s = PnP_INTERFACE_STR(did.BaseType, did.SubType,
+ did.Interface);
+ if(!s) {
+ sprintf(sn, "interface %d", did.Interface);
+ s=sn;
+ }
+ if ( did.BusId & PCIDEVICE )
+ printk("PCI Device, Bus %d, DevFunc 0x%x:",
+ dev->BusAccess.PCIAccess.BusNumber,
+ dev->BusAccess.PCIAccess.DevFuncNumber);
+ if ( did.BusId & PNPISADEVICE ) printk("PNPISA Device:");
+ if ( did.BusId & ISADEVICE )
+ printk("ISA Device, Slot %d, LogicalDev %d:",
+ dev->BusAccess.ISAAccess.SlotNumber,
+ dev->BusAccess.ISAAccess.LogicalDevNumber);
+ if ( did.BusId & EISADEVICE ) printk("EISA Device:");
+ if ( did.BusId & PROCESSORDEVICE )
+ printk("ProcBus Device, Bus %d, BUID %d: ",
+ dev->BusAccess.ProcBusAccess.BusNumber,
+ dev->BusAccess.ProcBusAccess.BUID);
+ if ( did.BusId & PCMCIADEVICE ) printk("PCMCIA ");
+ if ( did.BusId & VMEDEVICE ) printk("VME ");
+ if ( did.BusId & MCADEVICE ) printk("MCA ");
+ if ( did.BusId & MXDEVICE ) printk("MX ");
+ /* Decompress first 3 chars */
+ decomp[0]='A'-1+((did.DevId>>26)&0x1F);
+ decomp[1]='A'-1+((did.DevId>>21)&0x1F);
+ decomp[2]='A'-1+((did.DevId>>16)&0x1F);
+ decomp[3]=0;
+ printk(" %s%4.4lX, %s, %s, %s\n",
+ decomp, did.DevId&0xffff,
+ PnP_BASE_TYPES[did.BaseType],
+ PnP_SUB_TYPE_STR(did.BaseType,did.SubType),
+ s);
+ if ( dev->AllocatedOffset )
+ printpackets( (union _PnP_TAG_PACKET *)
+ &res->DevicePnPHeap[dev->AllocatedOffset],
+ "allocated");
+ if ( dev->PossibleOffset )
+ printpackets( (union _PnP_TAG_PACKET *)
+ &res->DevicePnPHeap[dev->PossibleOffset],
+ "possible");
+ if ( dev->CompatibleOffset )
+ printpackets( (union _PnP_TAG_PACKET *)
+ &res->DevicePnPHeap[dev->CompatibleOffset],
+ "compatible");
+ }
+}
+
+
+#if 0
+static void __init printVPD(void) {
+#define vpd res->VitalProductData
+ int ps=vpd.PageSize, i, j;
+ static const char* Usage[]={
+ "FirmwareStack", "FirmwareHeap", "FirmwareCode", "BootImage",
+ "Free", "Unpopulated", "ISAAddr", "PCIConfig",
+ "IOMemory", "SystemIO", "SystemRegs", "PCIAddr",
+ "UnPopSystemRom", "SystemROM", "ResumeBlock", "Other"
+ };
+ static const unsigned char *FWMan[]={
+ "IBM", "Motorola", "FirmWorks", "Bull"
+ };
+ static const unsigned char *FWFlags[]={
+ "Conventional", "OpenFirmware", "Diagnostics", "LowDebug",
+ "MultiBoot", "LowClient", "Hex41", "FAT",
+ "ISO9660", "SCSI_ID_Override", "Tape_Boot", "FW_Boot_Path"
+ };
+ static const unsigned char *ESM[]={
+ "Port92", "PCIConfigA8", "FF001030", "????????"
+ };
+ static const unsigned char *SIOM[]={
+ "Port850", "????????", "PCIConfigA8", "????????"
+ };
+
+ printk("Model: %s\n",vpd.PrintableModel);
+ printk("Serial: %s\n", vpd.Serial);
+ printk("FirmwareSupplier: %s\n", FWMan[vpd.FirmwareSupplier]);
+ printk("FirmwareFlags:");
+ for(j=0; j<12; j++) {
+ if (vpd.FirmwareSupports & (1<<j)) {
+ printk(" %s%c", FWFlags[j],
+ vpd.FirmwareSupports&(-2<<j) ? ',' : '\n');
+ }
+ }
+ printk("NVRamSize: %ld\n", vpd.NvramSize);
+ printk("SIMMslots: %ld\n", vpd.NumSIMMSlots);
+ printk("EndianSwitchMethod: %s\n",
+ ESM[vpd.EndianSwitchMethod>2 ? 2 : vpd.EndianSwitchMethod]);
+ printk("SpreadIOMethod: %s\n",
+ SIOM[vpd.SpreadIOMethod>3 ? 3 : vpd.SpreadIOMethod]);
+ printk("Processor/Bus frequencies (Hz): %ld/%ld\n",
+ vpd.ProcessorHz, vpd.ProcessorBusHz);
+ printk("Time Base Divisor: %ld\n", vpd.TimeBaseDivisor);
+ printk("WordWidth, PageSize: %ld, %d\n", vpd.WordWidth, ps);
+ printk("Cache sector size, Lock granularity: %ld, %ld\n",
+ vpd.CoherenceBlockSize, vpd.GranuleSize);
+ for (i=0; i<res->ActualNumMemSegs; i++) {
+ int mask=res->Segs[i].Usage, first, j;
+ printk("%8.8lx-%8.8lx ",
+ res->Segs[i].BasePage*ps,
+ (res->Segs[i].PageCount+res->Segs[i].BasePage)*ps-1);
+ for(j=15, first=1; j>=0; j--) {
+ if (mask&(1<<j)) {
+ if (first) first=0;
+ else printk(", ");
+ printk("%s", Usage[j]);
+ }
+ }
+ printk("\n");
+ }
+}
+
+/*
+ * Spit out some info about residual data
+ */
+void print_residual_device_info(void)
+{
+ int i;
+ union _PnP_TAG_PACKET *pkt;
+ PPC_DEVICE *dev;
+#define did dev->DeviceId
+
+ /* make sure we have residual data first */
+ if (!have_residual_data)
+ return;
+ printk("Residual: %ld devices\n", res->ActualNumDevices);
+ for ( i = 0;
+ i < res->ActualNumDevices ;
+ i++)
+ {
+ dev = &res->Devices[i];
+ /*
+ * pci devices
+ */
+ if ( did.BusId & PCIDEVICE )
+ {
+ printk("PCI Device:");
+ /* unknown vendor */
+ if ( !strncmp( "Unknown", pci_strvendor(did.DevId>>16), 7) )
+ printk(" id %08lx types %d/%d", did.DevId,
+ did.BaseType, did.SubType);
+ /* known vendor */
+ else
+ printk(" %s %s",
+ pci_strvendor(did.DevId>>16),
+ pci_strdev(did.DevId>>16,
+ did.DevId&0xffff)
+ );
+
+ if ( did.BusId & PNPISADEVICE )
+ {
+ printk(" pnp:");
+ /* get pnp info on the device */
+ pkt = (union _PnP_TAG_PACKET *)
+ &res->DevicePnPHeap[dev->AllocatedOffset];
+ for (; pkt->S1_Pack.Tag != DF_END_TAG;
+ pkt++ )
+ {
+ if ( (pkt->S1_Pack.Tag == S4_Packet) ||
+ (pkt->S1_Pack.Tag == S4_Packet_flags) )
+ printk(" irq %02x%02x",
+ pkt->S4_Pack.IRQMask[0],
+ pkt->S4_Pack.IRQMask[1]);
+ }
+ }
+ printk("\n");
+ continue;
+ }
+ /*
+ * isa devices
+ */
+ if ( did.BusId & ISADEVICE )
+ {
+ printk("ISA Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ /*
+ * eisa devices
+ */
+ if ( did.BusId & EISADEVICE )
+ {
+ printk("EISA Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ /*
+ * proc bus devices
+ */
+ if ( did.BusId & PROCESSORDEVICE )
+ {
+ printk("ProcBus Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ /*
+ * pcmcia devices
+ */
+ if ( did.BusId & PCMCIADEVICE )
+ {
+ printk("PCMCIA Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ printk("Unknown bus access device: busid %lx\n",
+ did.BusId);
+ }
+}
+#endif
+
+/* Returns the device index in the residual data,
+ any of the search items may be set as -1 for wildcard,
+ DevID number field (second halfword) is big endian !
+
+ Examples:
+ - search for the Interrupt controller (8259 type), 2 methods:
+ 1) i8259 = residual_find_device(~0,
+ NULL,
+ SystemPeripheral,
+ ProgrammableInterruptController,
+ ISA_PIC,
+ 0);
+ 2) i8259 = residual_find_device(~0, "PNP0000", -1, -1, -1, 0)
+
+ - search for the first two serial devices, whatever their type)
+ iserial1 = residual_find_device(~0,NULL,
+ CommunicationsDevice,
+ RS232Device,
+ -1, 0)
+ iserial2 = residual_find_device(~0,NULL,
+ CommunicationsDevice,
+ RS232Device,
+ -1, 1)
+ - but search for typical COM1 and COM2 is not easy due to the
+ fact that the interface may be anything and the name "PNP0500" or
+ "PNP0501". Quite bad.
+
+*/
+
+/* devid are easier to uncompress than to compress, so to minimize bloat
+in this rarely used area we unencode and compare */
+
+/* in residual data number is big endian in the device table and
+little endian in the heap, so we use two parameters to avoid writing
+two very similar functions */
+
+static int __init same_DevID(unsigned short vendor,
+ unsigned short Number,
+ char * str)
+{
+ static unsigned const char hexdigit[]="0123456789ABCDEF";
+ if (strlen(str)!=7) return 0;
+ if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0]) &&
+ ( ((vendor>>5)&0x1f)+'A'-1 == str[1]) &&
+ ( (vendor&0x1f)+'A'-1 == str[2]) &&
+ (hexdigit[(Number>>12)&0x0f] == str[3]) &&
+ (hexdigit[(Number>>8)&0x0f] == str[4]) &&
+ (hexdigit[(Number>>4)&0x0f] == str[5]) &&
+ (hexdigit[Number&0x0f] == str[6]) ) return 1;
+ return 0;
+}
+
+PPC_DEVICE __init *residual_find_device(unsigned long BusMask,
+ unsigned char * DevID,
+ int BaseType,
+ int SubType,
+ int Interface,
+ int n)
+{
+ int i;
+ if (!have_residual_data) return NULL;
+ for (i=0; i<res->ActualNumDevices; i++) {
+#define Dev res->Devices[i].DeviceId
+ if ( (Dev.BusId&BusMask) &&
+ (BaseType==-1 || Dev.BaseType==BaseType) &&
+ (SubType==-1 || Dev.SubType==SubType) &&
+ (Interface==-1 || Dev.Interface==Interface) &&
+ (DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
+ Dev.DevId&0xffff, DevID)) &&
+ !(n--) ) return res->Devices+i;
+#undef Dev
+ }
+ return NULL;
+}
+
+PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask,
+ unsigned short DevID,
+ int BaseType,
+ int SubType,
+ int Interface,
+ int n)
+{
+ int i;
+ if (!have_residual_data) return NULL;
+ for (i=0; i<res->ActualNumDevices; i++) {
+#define Dev res->Devices[i].DeviceId
+ if ( (Dev.BusId&BusMask) &&
+ (BaseType==-1 || Dev.BaseType==BaseType) &&
+ (SubType==-1 || Dev.SubType==SubType) &&
+ (Interface==-1 || Dev.Interface==Interface) &&
+ (DevID==0xffff || (Dev.DevId&0xffff) == DevID) &&
+ !(n--) ) return res->Devices+i;
+#undef Dev
+ }
+ return NULL;
+}
+
+static int __init
+residual_scan_pcibridge(PnP_TAG_PACKET * pkt, struct pci_dev *dev)
+{
+ int irq = -1;
+
+#define data pkt->L4_Pack.L4_Data.L4_PPCPack.PPCData
+ if (dev->bus->number == data[16]) {
+ int i, size;
+
+ size = 3 + ld_le16((u_short *) (&pkt->L4_Pack.Count0));
+ for (i = 20; i < size - 4; i += 12) {
+ unsigned char pin;
+ int line_irq;
+
+ if (dev->devfn != data[i + 1])
+ continue;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin) {
+ line_irq = ld_le16((unsigned short *)
+ (&data[i + 4 + 2 * (pin - 1)]));
+ irq = (line_irq == 0xffff) ? 0
+ : line_irq & 0x7fff;
+ } else
+ irq = 0;
+
+ break;
+ }
+ }
+#undef data
+
+ return irq;
+}
+
+int __init
+residual_pcidev_irq(struct pci_dev *dev)
+{
+ int i = 0;
+ int irq = -1;
+ PPC_DEVICE *bridge;
+
+ while ((bridge = residual_find_device
+ (-1, NULL, BridgeController, PCIBridge, -1, i++))) {
+
+ PnP_TAG_PACKET *pkt;
+ if (bridge->AllocatedOffset) {
+ pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
+ bridge->AllocatedOffset, 3, 0);
+ if (!pkt)
+ continue;
+
+ irq = residual_scan_pcibridge(pkt, dev);
+ if (irq != -1)
+ break;
+ }
+ }
+
+ return (irq < 0) ? 0 : irq;
+}
+
+void __init residual_irq_mask(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+ PPC_DEVICE *dev;
+ int i = 0;
+ unsigned short irq_mask = 0x000; /* default to edge */
+
+ while ((dev = residual_find_device(-1, NULL, -1, -1, -1, i++))) {
+ PnP_TAG_PACKET *pkt;
+ unsigned short mask;
+ int size;
+ int offset = dev->AllocatedOffset;
+
+ if (!offset)
+ continue;
+
+ pkt = PnP_find_packet(res->DevicePnPHeap + offset,
+ IRQFormat, 0);
+ if (!pkt)
+ continue;
+
+ size = tag_small_count(pkt->S1_Pack.Tag) + 1;
+ mask = ld_le16((unsigned short *)pkt->S4_Pack.IRQMask);
+ if (size > 3 && (pkt->S4_Pack.IRQInfo & 0x0c))
+ irq_mask |= mask;
+ }
+
+ *irq_edge_mask_lo = irq_mask & 0xff;
+ *irq_edge_mask_hi = irq_mask >> 8;
+}
+
+unsigned int __init residual_isapic_addr(void)
+{
+ PPC_DEVICE *isapic;
+ PnP_TAG_PACKET *pkt;
+ unsigned int addr;
+
+ isapic = residual_find_device(~0, NULL, SystemPeripheral,
+ ProgrammableInterruptController,
+ ISA_PIC, 0);
+ if (!isapic)
+ goto unknown;
+
+ pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
+ isapic->AllocatedOffset, 9, 0);
+ if (!pkt)
+ goto unknown;
+
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+ /* Must be 32-bit system address */
+ if (!((p.PPCData[0] == 3) && (p.PPCData[1] == 32)))
+ goto unknown;
+
+ /* It doesn't seem to work where length != 1 (what can I say? :-/ ) */
+ if (ld_le32((unsigned int *)(p.PPCData + 12)) != 1)
+ goto unknown;
+
+ addr = ld_le32((unsigned int *) (p.PPCData + 4));
+#undef p
+ return addr;
+unknown:
+ return 0;
+}
+
+PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
+ unsigned packet_tag,
+ int n)
+{
+ unsigned mask, masked_tag, size;
+ if(!p) return NULL;
+ if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
+ masked_tag = packet_tag&mask;
+ for(; *p != END_TAG; p+=size) {
+ if ((*p & mask) == masked_tag && !(n--))
+ return (PnP_TAG_PACKET *) p;
+ if (tag_type(*p))
+ size=ld_le16((unsigned short *)(p+1))+3;
+ else
+ size=tag_small_count(*p)+1;
+ }
+ return NULL; /* not found */
+}
+
+PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p,
+ unsigned packet_type,
+ int n)
+{
+ int next=0;
+ while (p) {
+ p = (unsigned char *) PnP_find_packet(p, 0x70, next);
+ if (p && p[1]==packet_type && !(n--))
+ return (PnP_TAG_PACKET *) p;
+ next = 1;
+ };
+ return NULL; /* not found */
+}
+
+PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p,
+ unsigned packet_type,
+ int n)
+{
+ int next=0;
+ while (p) {
+ p = (unsigned char *) PnP_find_packet(p, 0x84, next);
+ if (p && p[3]==packet_type && !(n--))
+ return (PnP_TAG_PACKET *) p;
+ next = 1;
+ };
+ return NULL; /* not found */
+}
+
+#ifdef CONFIG_PROC_PREPRESIDUAL
+static int proc_prep_residual_read(char * buf, char ** start, off_t off,
+ int count, int *eof, void *data)
+{
+ int n;
+
+ n = res->ResidualLength - off;
+ if (n < 0) {
+ *eof = 1;
+ n = 0;
+ }
+ else {
+ if (n > count)
+ n = count;
+ else
+ *eof = 1;
+
+ memcpy(buf, (char *)res + off, n);
+ *start = buf;
+ }
+
+ return n;
+}
+
+int __init
+proc_prep_residual_init(void)
+{
+ if (have_residual_data)
+ create_proc_read_entry("residual", S_IRUGO, NULL,
+ proc_prep_residual_read, NULL);
+ return 0;
+}
+
+__initcall(proc_prep_residual_init);
+#endif
diff --git a/arch/ppc/platforms/rpx8260.h b/arch/ppc/platforms/rpx8260.h
new file mode 100644
index 00000000000..843494a50ef
--- /dev/null
+++ b/arch/ppc/platforms/rpx8260.h
@@ -0,0 +1,81 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Embedded Planet RPX6 (or RPX Super) MPC8260 board.
+ * Copied from the RPX-Classic and SBS8260 stuff.
+ *
+ * Copyright (c) 2001 Dan Malek <dan@embeddededge.com>
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_PLATFORMS_RPX8260_H__
+#define __ASM_PLATFORMS_RPX8260_H__
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+ unsigned int bi_memstart; /* Memory start address */
+ unsigned int bi_memsize; /* Memory (end) size in bytes */
+ unsigned int bi_nvsize; /* NVRAM size in bytes (can be 0) */
+ unsigned int bi_intfreq; /* Internal Freq, in Hz */
+ unsigned int bi_busfreq; /* Bus Freq, in MHz */
+ unsigned int bi_cpmfreq; /* CPM Freq, in MHz */
+ unsigned int bi_brgfreq; /* BRG Freq, in MHz */
+ unsigned int bi_vco; /* VCO Out from PLL */
+ unsigned int bi_baudrate; /* Default console baud rate */
+ unsigned int bi_immr; /* IMMR when called from boot rom */
+ unsigned char bi_enetaddr[6];
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need. The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define CPM_MAP_ADDR ((uint)0xf0000000)
+#define RPX_CSR_ADDR ((uint)0xfa000000)
+#define RPX_CSR_SIZE ((uint)(512 * 1024))
+#define RPX_NVRTC_ADDR ((uint)0xfa080000)
+#define RPX_NVRTC_SIZE ((uint)(512 * 1024))
+
+/* The RPX6 has 16, byte wide control/status registers.
+ * Not all are used (yet).
+ */
+extern volatile u_char *rpx6_csr_addr;
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ID_MASK ((u_char)0xf0) /* Read only */
+#define BCSR0_SWITCH_MASK ((u_char)0x0f) /* Read only */
+#define BCSR1_XCVR_SMC1 ((u_char)0x80)
+#define BCSR1_XCVR_SMC2 ((u_char)0x40)
+#define BCSR2_FLASH_WENABLE ((u_char)0x20)
+#define BCSR2_NVRAM_ENABLE ((u_char)0x10)
+#define BCSR2_ALT_IRQ2 ((u_char)0x08)
+#define BCSR2_ALT_IRQ3 ((u_char)0x04)
+#define BCSR2_PRST ((u_char)0x02) /* Force reset */
+#define BCSR2_ENPRST ((u_char)0x01) /* Enable POR */
+#define BCSR3_MODCLK_MASK ((u_char)0xe0)
+#define BCSR3_ENCLKHDR ((u_char)0x10)
+#define BCSR3_LED5 ((u_char)0x04) /* 0 == on */
+#define BCSR3_LED6 ((u_char)0x02) /* 0 == on */
+#define BCSR3_LED7 ((u_char)0x01) /* 0 == on */
+#define BCSR4_EN_PHY ((u_char)0x80) /* Enable PHY */
+#define BCSR4_EN_MII ((u_char)0x40) /* Enable PHY */
+#define BCSR4_MII_READ ((u_char)0x04)
+#define BCSR4_MII_MDC ((u_char)0x02)
+#define BCSR4_MII_MDIO ((u_char)0x01)
+#define BCSR13_FETH_IRQMASK ((u_char)0xf0)
+#define BCSR15_FETH_IRQ ((u_char)0x20)
+
+#define PHY_INTERRUPT SIU_INT_IRQ7
+
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "Embedded Planet"
+#define CPUINFO_MACHINE "EP8260 PowerPC"
+
+/* Warm reset vector. */
+#define BOOTROM_RESTART_ADDR ((uint)0xfff00104)
+
+#endif /* __ASM_PLATFORMS_RPX8260_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/rpxclassic.h b/arch/ppc/platforms/rpxclassic.h
new file mode 100644
index 00000000000..6daa109491c
--- /dev/null
+++ b/arch/ppc/platforms/rpxclassic.h
@@ -0,0 +1,119 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the RPCG RPX-Classic board. Copied from the RPX-Lite stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_RPX_DEFS
+#define __MACH_RPX_DEFS
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+ unsigned int bi_memstart; /* Memory start address */
+ unsigned int bi_memsize; /* Memory (end) size in bytes */
+ unsigned int bi_intfreq; /* Internal Freq, in Hz */
+ unsigned int bi_busfreq; /* Bus Freq, in Hz */
+ unsigned char bi_enetaddr[6];
+ unsigned int bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need. The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define PCI_ISA_IO_ADDR ((unsigned)0x80000000)
+#define PCI_ISA_IO_SIZE ((uint)(512 * 1024 * 1024))
+#define PCI_ISA_MEM_ADDR ((unsigned)0xc0000000)
+#define PCI_ISA_MEM_SIZE ((uint)(512 * 1024 * 1024))
+#define RPX_CSR_ADDR ((uint)0xfa400000)
+#define RPX_CSR_SIZE ((uint)(4 * 1024))
+#define IMAP_ADDR ((uint)0xfa200000)
+#define IMAP_SIZE ((uint)(64 * 1024))
+#define PCI_CSR_ADDR ((uint)0x80000000)
+#define PCI_CSR_SIZE ((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR ((uint)0xe0000000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
+#define PCMCIA_IO_ADDR ((uint)0xe4000000)
+#define PCMCIA_IO_SIZE ((uint)(4 * 1024))
+#define PCMCIA_ATTRB_ADDR ((uint)0xe8000000)
+#define PCMCIA_ATTRB_SIZE ((uint)(4 * 1024))
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ETHEN ((uint)0x80000000)
+#define BCSR0_ETHLPBK ((uint)0x40000000)
+#define BCSR0_COLTESTDIS ((uint)0x20000000)
+#define BCSR0_FULLDPLXDIS ((uint)0x10000000)
+#define BCSR0_ENFLSHSEL ((uint)0x04000000)
+#define BCSR0_FLASH_SEL ((uint)0x02000000)
+#define BCSR0_ENMONXCVR ((uint)0x01000000)
+
+#define BCSR0_PCMCIAVOLT ((uint)0x000f0000) /* CLLF */
+#define BCSR0_PCMCIA3VOLT ((uint)0x000a0000) /* CLLF */
+#define BCSR0_PCMCIA5VOLT ((uint)0x00060000) /* CLLF */
+
+#define BCSR1_IPB5SEL ((uint)0x00100000)
+#define BCSR1_PCVCTL4 ((uint)0x00080000)
+#define BCSR1_PCVCTL5 ((uint)0x00040000)
+#define BCSR1_PCVCTL6 ((uint)0x00020000)
+#define BCSR1_PCVCTL7 ((uint)0x00010000)
+
+#define BCSR2_EN232XCVR ((uint)0x00008000)
+#define BCSR2_QSPACESEL ((uint)0x00004000)
+#define BCSR2_FETHLEDMODE ((uint)0x00000800) /* CLLF */
+
+#if defined(CONFIG_HTDMSOUND)
+#include <platforms/rpxhiox.h>
+#endif
+
+/* define IO_BASE for pcmcia, CLLF only */
+#if !defined(CONFIG_PCI)
+#define _IO_BASE 0x80000000
+#define _IO_BASE_SIZE 0x1000
+
+/* for pcmcia sandisk */
+#ifdef CONFIG_IDE
+# define MAX_HWIFS 1
+#endif
+#endif
+
+/* Interrupt level assignments.
+*/
+#define FEC_INTERRUPT SIU_LEVEL1 /* FEC interrupt */
+
+
+/* CPM Ethernet through SCCx.
+ *
+ * Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD ((ushort)0x0001)
+#define PA_ENET_TXD ((ushort)0x0002)
+#define PA_ENET_TCLK ((ushort)0x0200)
+#define PA_ENET_RCLK ((ushort)0x0800)
+#define PB_ENET_TENA ((uint)0x00001000)
+#define PC_ENET_CLSN ((ushort)0x0010)
+#define PC_ENET_RENA ((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT ((uint)0x0000003d)
+
+/* We don't use the 8259.
+*/
+
+#define NR_8259_INTS 0
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __MACH_RPX_DEFS */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/rpxhiox.h b/arch/ppc/platforms/rpxhiox.h
new file mode 100644
index 00000000000..c3fa5a65376
--- /dev/null
+++ b/arch/ppc/platforms/rpxhiox.h
@@ -0,0 +1,41 @@
+/*
+ * The Embedded Planet HIOX expansion card definitions.
+ * There were a few different versions of these cards, but only
+ * the one that escaped real production is defined here.
+ *
+ * Copyright (c) 2000 Dan Malek (dmalek@jlc.net)
+ */
+#ifndef __MACH_RPX_HIOX_DEFS
+#define __MACH_RPX_HIOX_DEFS
+
+#define HIOX_CSR_ADDR ((uint)0xfac00000)
+#define HIOX_CSR_SIZE ((uint)(4 * 1024))
+#define HIOX_CSR0_ADDR HIOX_CSR_ADDR
+#define HIOX_CSR4_ADDR ((uint)0xfac00004)
+
+#define HIOX_CSR0_DEFAULT ((uint)0x380f3c00)
+#define HIOX_CSR0_ENSCC2 ((uint)0x80000000)
+#define HIOX_CSR0_ENSMC2 ((uint)0x04000000)
+#define HIOX_CSR0_ENVDOCLK ((uint)0x02000000)
+#define HIOX_CSR0_VDORST_HL ((uint)0x01000000)
+#define HIOX_CSR0_RS232SEL ((uint)0x0000c000)
+#define HIOX_CSR0_SCC3SEL ((uint)0x0000c000)
+#define HIOX_CSR0_SMC1SEL ((uint)0x00008000)
+#define HIOX_CSR0_SCC1SEL ((uint)0x00004000)
+#define HIOX_CSR0_ENTOUCH ((uint)0x00000080)
+#define HIOX_CSR0_PDOWN100 ((uint)0x00000060)
+#define HIOX_CSR0_PDOWN10 ((uint)0x00000040)
+#define HIOX_CSR0_PDOWN1 ((uint)0x00000020)
+#define HIOX_CSR0_TSELSPI ((uint)0x00000010)
+#define HIOX_CSR0_TIRQSTAT ((uint)0x00000008)
+#define HIOX_CSR4_DEFAULT ((uint)0x00000000)
+#define HIOX_CSR4_ENTIRQ2 ((uint)0x20000000)
+#define HIOX_CSR4_ENTIRQ3 ((uint)0x10000000)
+#define HIOX_CSR4_ENAUDIO ((uint)0x00000080)
+#define HIOX_CSR4_RSTAUDIO ((uint)0x00000040) /* 0 == reset */
+#define HIOX_CSR4_AUDCLKHI ((uint)0x00000020)
+#define HIOX_CSR4_AUDSPISEL ((uint)0x00000010)
+#define HIOX_CSR4_AUDIRQSTAT ((uint)0x00000008)
+#define HIOX_CSR4_AUDCLKSEL ((uint)0x00000007)
+
+#endif
diff --git a/arch/ppc/platforms/rpxlite.h b/arch/ppc/platforms/rpxlite.h
new file mode 100644
index 00000000000..deee5bd36aa
--- /dev/null
+++ b/arch/ppc/platforms/rpxlite.h
@@ -0,0 +1,96 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the RPCG RPX-Lite board. Copied from the MBX stuff.
+ *
+ * Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ */
+#ifdef __KERNEL__
+#ifndef __MACH_RPX_DEFS
+#define __MACH_RPX_DEFS
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+ unsigned int bi_memstart; /* Memory start address */
+ unsigned int bi_memsize; /* Memory (end) size in bytes */
+ unsigned int bi_intfreq; /* Internal Freq, in Hz */
+ unsigned int bi_busfreq; /* Bus Freq, in Hz */
+ unsigned char bi_enetaddr[6];
+ unsigned int bi_baudrate;
+} bd_t;
+
+extern bd_t m8xx_board_info;
+
+/* Memory map is configured by the PROM startup.
+ * We just map a few things we need. The CSR is actually 4 byte-wide
+ * registers that can be accessed as 8-, 16-, or 32-bit values.
+ */
+#define RPX_CSR_ADDR ((uint)0xfa400000)
+#define RPX_CSR_SIZE ((uint)(4 * 1024))
+#define IMAP_ADDR ((uint)0xfa200000)
+#define IMAP_SIZE ((uint)(64 * 1024))
+#define PCMCIA_MEM_ADDR ((uint)0x04000000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
+#define PCMCIA_IO_ADDR ((uint)0x04400000)
+#define PCMCIA_IO_SIZE ((uint)(4 * 1024))
+
+/* Things of interest in the CSR.
+*/
+#define BCSR0_ETHEN ((uint)0x80000000)
+#define BCSR0_ETHLPBK ((uint)0x40000000)
+#define BCSR0_COLTESTDIS ((uint)0x20000000)
+#define BCSR0_FULLDPLXDIS ((uint)0x10000000)
+#define BCSR0_LEDOFF ((uint)0x08000000)
+#define BCSR0_USBDISABLE ((uint)0x04000000)
+#define BCSR0_USBHISPEED ((uint)0x02000000)
+#define BCSR0_USBPWREN ((uint)0x01000000)
+#define BCSR0_PCMCIAVOLT ((uint)0x000f0000)
+#define BCSR0_PCMCIA3VOLT ((uint)0x000a0000)
+#define BCSR0_PCMCIA5VOLT ((uint)0x00060000)
+
+#define BCSR1_IPB5SEL ((uint)0x00100000)
+#define BCSR1_PCVCTL4 ((uint)0x00080000)
+#define BCSR1_PCVCTL5 ((uint)0x00040000)
+#define BCSR1_PCVCTL6 ((uint)0x00020000)
+#define BCSR1_PCVCTL7 ((uint)0x00010000)
+
+#if defined(CONFIG_HTDMSOUND)
+#include <platforms/rpxhiox.h>
+#endif
+
+/* define IO_BASE for pcmcia */
+#define _IO_BASE 0x80000000
+#define _IO_BASE_SIZE 0x1000
+
+#ifdef CONFIG_IDE
+# define MAX_HWIFS 1
+#endif
+
+/* CPM Ethernet through SCCx.
+ *
+ * This ENET stuff is for the MPC850 with ethernet on SCC2. Some of
+ * this may be unique to the RPX-Lite configuration.
+ * Note TENA is on Port B.
+ */
+#define PA_ENET_RXD ((ushort)0x0004)
+#define PA_ENET_TXD ((ushort)0x0008)
+#define PA_ENET_TCLK ((ushort)0x0200)
+#define PA_ENET_RCLK ((ushort)0x0800)
+#define PB_ENET_TENA ((uint)0x00002000)
+#define PC_ENET_CLSN ((ushort)0x0040)
+#define PC_ENET_RENA ((ushort)0x0080)
+
+#define SICR_ENET_MASK ((uint)0x0000ff00)
+#define SICR_ENET_CLKRT ((uint)0x00003d00)
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __MACH_RPX_DEFS */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c
new file mode 100644
index 00000000000..531bfa0e451
--- /dev/null
+++ b/arch/ppc/platforms/sandpoint.c
@@ -0,0 +1,742 @@
+/*
+ * arch/ppc/platforms/sandpoint_setup.c
+ *
+ * Board setup routines for the Motorola SPS Sandpoint Test Platform.
+ *
+ * Author: Mark A. Greer
+ * mgreer@mvista.com
+ *
+ * 2000-2003 (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.
+ */
+
+/*
+ * This file adds support for the Motorola SPS Sandpoint Test Platform.
+ * These boards have a PPMC slot for the processor so any combination
+ * of cpu and host bridge can be attached. This port is for an 8240 PPMC
+ * module from Motorola SPS and other closely related cpu/host bridge
+ * combinations (e.g., 750/755/7400 with MPC107 host bridge).
+ * The sandpoint itself has a Windbond 83c553 (PCI-ISA bridge, 2 DMA ctlrs, 2
+ * cascaded 8259 interrupt ctlrs, 8254 Timer/Counter, and an IDE ctlr), a
+ * National 87308 (RTC, 2 UARTs, Keyboard & mouse ctlrs, and a floppy ctlr),
+ * and 4 PCI slots (only 2 of which are usable; the other 2 are keyed for 3.3V
+ * but are really 5V).
+ *
+ * The firmware on the sandpoint is called DINK (not my acronym :). This port
+ * depends on DINK to do some basic initialization (e.g., initialize the memory
+ * ctlr) and to ensure that the processor is using MAP B (CHRP map).
+ *
+ * The switch settings for the Sandpoint board MUST be as follows:
+ * S3: down
+ * S4: up
+ * S5: up
+ * S6: down
+ *
+ * 'down' is in the direction from the PCI slots towards the PPMC slot;
+ * 'up' is in the direction from the PPMC slot towards the PCI slots.
+ * Be careful, the way the sandpoint board is installed in XT chasses will
+ * make the directions reversed.
+ *
+ * Since Motorola listened to our suggestions for improvement, we now have
+ * the Sandpoint X3 board. All of the PCI slots are available, it uses
+ * the serial interrupt interface (just a hardware thing we need to
+ * configure properly).
+ *
+ * Use the default X3 switch settings. The interrupts are then:
+ * EPIC Source
+ * 0 SIOINT (8259, active low)
+ * 1 PCI #1
+ * 2 PCI #2
+ * 3 PCI #3
+ * 4 PCI #4
+ * 7 Winbond INTC (IDE interrupt)
+ * 8 Winbond INTD (IDE interrupt)
+ *
+ *
+ * Motorola has finally released a version of DINK32 that correctly
+ * (seemingly) initalizes the memory controller correctly, regardless
+ * of the amount of memory in the system. Once a method of determining
+ * what version of DINK initializes the system for us, if applicable, is
+ * found, we can hopefully stop hardcoding 32MB of RAM.
+ */
+
+#include <linux/config.h>
+#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/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h> /* for linux/serial_core.h */
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/vga.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/mpc10x.h>
+#include <asm/pci-bridge.h>
+#include <asm/kgdb.h>
+
+#include "sandpoint.h"
+
+/* Set non-zero if an X2 Sandpoint detected. */
+static int sandpoint_is_x2;
+
+unsigned char __res[sizeof(bd_t)];
+
+static void sandpoint_halt(void);
+static void sandpoint_probe_type(void);
+
+/*
+ * Define all of the IRQ senses and polarities. Taken from the
+ * Sandpoint X3 User's manual.
+ */
+static u_char sandpoint_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 0: SIOINT */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 2: PCI Slot 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 3: PCI Slot 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 4: PCI Slot 3 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 5: PCI Slot 4 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 8: IDE (INT C) */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE) /* 9: IDE (INT D) */
+};
+
+/*
+ * Motorola SPS Sandpoint interrupt routing.
+ */
+static inline int
+x3_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 16, 0, 0, 0 }, /* IDSEL 11 - i8259 on Winbond */
+ { 0, 0, 0, 0 }, /* IDSEL 12 - unused */
+ { 18, 21, 20, 19 }, /* IDSEL 13 - PCI slot 1 */
+ { 19, 18, 21, 20 }, /* IDSEL 14 - PCI slot 2 */
+ { 20, 19, 18, 21 }, /* IDSEL 15 - PCI slot 3 */
+ { 21, 20, 19, 18 }, /* IDSEL 16 - PCI slot 4 */
+ };
+
+ const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static inline int
+x2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 18, 0, 0, 0 }, /* IDSEL 11 - i8259 on Windbond */
+ { 0, 0, 0, 0 }, /* IDSEL 12 - unused */
+ { 16, 17, 18, 19 }, /* IDSEL 13 - PCI slot 1 */
+ { 17, 18, 19, 16 }, /* IDSEL 14 - PCI slot 2 */
+ { 18, 19, 16, 17 }, /* IDSEL 15 - PCI slot 3 */
+ { 19, 16, 17, 18 }, /* IDSEL 16 - PCI slot 4 */
+ };
+
+ const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static void __init
+sandpoint_setup_winbond_83553(struct pci_controller *hose)
+{
+ int devfn;
+
+ /*
+ * Route IDE interrupts directly to the 8259's IRQ 14 & 15.
+ * We can't route the IDE interrupt to PCI INTC# or INTD# because those
+ * woule interfere with the PMC's INTC# and INTD# lines.
+ */
+ /*
+ * Winbond Fcn 0
+ */
+ devfn = PCI_DEVFN(11,0);
+
+ early_write_config_byte(hose,
+ 0,
+ devfn,
+ 0x43, /* IDE Interrupt Routing Control */
+ 0xef);
+ early_write_config_word(hose,
+ 0,
+ devfn,
+ 0x44, /* PCI Interrupt Routing Control */
+ 0x0000);
+
+ /* Want ISA memory cycles to be forwarded to PCI bus */
+ early_write_config_byte(hose,
+ 0,
+ devfn,
+ 0x48, /* ISA-to-PCI Addr Decoder Control */
+ 0xf0);
+
+ /* Enable Port 92. */
+ early_write_config_byte(hose,
+ 0,
+ devfn,
+ 0x4e, /* AT System Control Register */
+ 0x06);
+ /*
+ * Winbond Fcn 1
+ */
+ devfn = PCI_DEVFN(11,1);
+
+ /* Put IDE controller into native mode. */
+ early_write_config_byte(hose,
+ 0,
+ devfn,
+ 0x09, /* Programming interface Register */
+ 0x8f);
+
+ /* Init IRQ routing, enable both ports, disable fast 16 */
+ early_write_config_dword(hose,
+ 0,
+ devfn,
+ 0x40, /* IDE Control/Status Register */
+ 0x00ff0011);
+ return;
+}
+
+/* On the sandpoint X2, we must avoid sending configuration cycles to
+ * device #12 (IDSEL addr = AD12).
+ */
+static int
+x2_exclude_device(u_char bus, u_char devfn)
+{
+ if ((bus == 0) && (PCI_SLOT(devfn) == SANDPOINT_HOST_BRIDGE_IDSEL))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static void __init
+sandpoint_find_bridges(void)
+{
+ struct pci_controller *hose;
+
+ hose = pcibios_alloc_controller();
+
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ if (mpc10x_bridge_init(hose,
+ MPC10X_MEM_MAP_B,
+ MPC10X_MEM_MAP_B,
+ MPC10X_MAPB_EUMB_BASE) == 0) {
+
+ /* Do early winbond init, then scan PCI bus */
+ sandpoint_setup_winbond_83553(hose);
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pcibios_fixup = NULL;
+ ppc_md.pcibios_fixup_bus = NULL;
+ ppc_md.pci_swizzle = common_swizzle;
+ if (sandpoint_is_x2) {
+ ppc_md.pci_map_irq = x2_map_irq;
+ ppc_md.pci_exclude_device = x2_exclude_device;
+ } else
+ ppc_md.pci_map_irq = x3_map_irq;
+ }
+ else {
+ if (ppc_md.progress)
+ ppc_md.progress("Bridge init failed", 0x100);
+ printk("Host bridge init failed\n");
+ }
+
+ return;
+}
+
+static void __init
+sandpoint_setup_arch(void)
+{
+ /* Probe for Sandpoint model */
+ sandpoint_probe_type();
+ if (sandpoint_is_x2)
+ epic_serial_mode = 0;
+
+ loops_per_jiffy = 100000000 / HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+
+ /* Lookup PCI host bridges */
+ sandpoint_find_bridges();
+
+ printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n");
+ printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+
+ /* DINK32 12.3 and below do not correctly enable any caches.
+ * We will do this now with good known values. Future versions
+ * of DINK32 are supposed to get this correct.
+ */
+ if (cpu_has_feature(CPU_FTR_SPEC7450))
+ /* 745x is different. We only want to pass along enable. */
+ _set_L2CR(L2CR_L2E);
+ else if (cpu_has_feature(CPU_FTR_L2CR))
+ /* All modules have 1MB of L2. We also assume that an
+ * L2 divisor of 3 will work.
+ */
+ _set_L2CR(L2CR_L2E | L2CR_L2SIZ_1MB | L2CR_L2CLK_DIV3
+ | L2CR_L2RAM_PIPE | L2CR_L2OH_1_0 | L2CR_L2DF);
+#if 0
+ /* Untested right now. */
+ if (cpu_has_feature(CPU_FTR_L3CR)) {
+ /* Magic value. */
+ _set_L3CR(0x8f032000);
+ }
+#endif
+}
+
+#define SANDPOINT_87308_CFG_ADDR 0x15c
+#define SANDPOINT_87308_CFG_DATA 0x15d
+
+#define SANDPOINT_87308_CFG_INB(addr, byte) { \
+ outb((addr), SANDPOINT_87308_CFG_ADDR); \
+ (byte) = inb(SANDPOINT_87308_CFG_DATA); \
+}
+
+#define SANDPOINT_87308_CFG_OUTB(addr, byte) { \
+ outb((addr), SANDPOINT_87308_CFG_ADDR); \
+ outb((byte), SANDPOINT_87308_CFG_DATA); \
+}
+
+#define SANDPOINT_87308_SELECT_DEV(dev_num) { \
+ SANDPOINT_87308_CFG_OUTB(0x07, (dev_num)); \
+}
+
+#define SANDPOINT_87308_DEV_ENABLE(dev_num) { \
+ SANDPOINT_87308_SELECT_DEV(dev_num); \
+ SANDPOINT_87308_CFG_OUTB(0x30, 0x01); \
+}
+
+/*
+ * To probe the Sandpoint type, we need to check for a connection between GPIO
+ * pins 6 and 7 on the NS87308 SuperIO.
+ */
+static void __init sandpoint_probe_type(void)
+{
+ u8 x;
+ /* First, ensure that the GPIO pins are enabled. */
+ SANDPOINT_87308_SELECT_DEV(0x07); /* Select GPIO logical device */
+ SANDPOINT_87308_CFG_OUTB(0x60, 0x07); /* Base address 0x700 */
+ SANDPOINT_87308_CFG_OUTB(0x61, 0x00);
+ SANDPOINT_87308_CFG_OUTB(0x30, 0x01); /* Enable */
+
+ /* Now, set pin 7 to output and pin 6 to input. */
+ outb((inb(0x701) | 0x80) & 0xbf, 0x701);
+ /* Set push-pull output */
+ outb(inb(0x702) | 0x80, 0x702);
+ /* Set pull-up on input */
+ outb(inb(0x703) | 0x40, 0x703);
+ /* Set output high and check */
+ x = inb(0x700);
+ outb(x | 0x80, 0x700);
+ x = inb(0x700);
+ sandpoint_is_x2 = ! (x & 0x40);
+ if (ppc_md.progress && sandpoint_is_x2)
+ ppc_md.progress("High output says X2", 0);
+ /* Set output low and check */
+ outb(x & 0x7f, 0x700);
+ sandpoint_is_x2 |= inb(0x700) & 0x40;
+ if (ppc_md.progress && sandpoint_is_x2)
+ ppc_md.progress("Low output says X2", 0);
+ if (ppc_md.progress && ! sandpoint_is_x2)
+ ppc_md.progress("Sandpoint is X3", 0);
+}
+
+/*
+ * Fix IDE interrupts.
+ */
+static int __init
+sandpoint_fix_winbond_83553(void)
+{
+ /* Make some 8259 interrupt level sensitive */
+ outb(0xe0, 0x4d0);
+ outb(0xde, 0x4d1);
+
+ return 0;
+}
+
+arch_initcall(sandpoint_fix_winbond_83553);
+
+/*
+ * Initialize the ISA devices on the Nat'l PC87308VUL SuperIO chip.
+ */
+static int __init
+sandpoint_setup_natl_87308(void)
+{
+ u_char reg;
+
+ /*
+ * Enable all the devices on the Super I/O chip.
+ */
+ SANDPOINT_87308_SELECT_DEV(0x00); /* Select kbd logical device */
+ SANDPOINT_87308_CFG_OUTB(0xf0, 0x00); /* Set KBC clock to 8 Mhz */
+ SANDPOINT_87308_DEV_ENABLE(0x00); /* Enable keyboard */
+ SANDPOINT_87308_DEV_ENABLE(0x01); /* Enable mouse */
+ SANDPOINT_87308_DEV_ENABLE(0x02); /* Enable rtc */
+ SANDPOINT_87308_DEV_ENABLE(0x03); /* Enable fdc (floppy) */
+ SANDPOINT_87308_DEV_ENABLE(0x04); /* Enable parallel */
+ SANDPOINT_87308_DEV_ENABLE(0x05); /* Enable UART 2 */
+ SANDPOINT_87308_CFG_OUTB(0xf0, 0x82); /* Enable bank select regs */
+ SANDPOINT_87308_DEV_ENABLE(0x06); /* Enable UART 1 */
+ SANDPOINT_87308_CFG_OUTB(0xf0, 0x82); /* Enable bank select regs */
+
+ /* Set up floppy in PS/2 mode */
+ outb(0x09, SIO_CONFIG_RA);
+ reg = inb(SIO_CONFIG_RD);
+ reg = (reg & 0x3F) | 0x40;
+ outb(reg, SIO_CONFIG_RD);
+ outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
+
+ return 0;
+}
+
+arch_initcall(sandpoint_setup_natl_87308);
+
+static int __init
+sandpoint_request_io(void)
+{
+ request_region(0x00,0x20,"dma1");
+ request_region(0x20,0x20,"pic1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0xc0,0x20,"dma2");
+
+ return 0;
+}
+
+arch_initcall(sandpoint_request_io);
+
+/*
+ * Interrupt setup and service. Interrrupts on the Sandpoint come
+ * from the four PCI slots plus the 8259 in the Winbond Super I/O (SIO).
+ * The 8259 is cascaded from EPIC IRQ0, IRQ1-4 map to PCI slots 1-4,
+ * IDE is on EPIC 7 and 8.
+ */
+static void __init
+sandpoint_init_IRQ(void)
+{
+ int i;
+
+ OpenPIC_InitSenses = sandpoint_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(sandpoint_openpic_initsenses);
+
+ mpc10x_set_openpic();
+ openpic_hookup_cascade(sandpoint_is_x2 ? 17 : NUM_8259_INTERRUPTS, "82c59 cascade",
+ i8259_irq);
+
+ /*
+ * openpic_init() has set up irq_desc[16-31] to be openpic
+ * interrupts. We need to set irq_desc[0-15] to be i8259
+ * interrupts.
+ */
+ for(i=0; i < NUM_8259_INTERRUPTS; i++)
+ irq_desc[i].handler = &i8259_pic;
+
+ /*
+ * The EPIC allows for a read in the range of 0xFEF00000 ->
+ * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction.
+ */
+ i8259_init(0xfef00000);
+}
+
+static u32
+sandpoint_irq_canonicalize(u32 irq)
+{
+ if (irq == 2)
+ return 9;
+ else
+ return irq;
+}
+
+static unsigned long __init
+sandpoint_find_end_of_memory(void)
+{
+ bd_t *bp = (bd_t *)__res;
+
+ if (bp->bi_memsize)
+ return bp->bi_memsize;
+
+ /* DINK32 13.0 correctly initalizes things, so iff you use
+ * this you _should_ be able to change this instead of a
+ * hardcoded value. */
+#if 0
+ return mpc10x_get_mem_size(MPC10X_MEM_MAP_B);
+#else
+ return 32*1024*1024;
+#endif
+}
+
+static void __init
+sandpoint_map_io(void)
+{
+ io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO);
+}
+
+static void
+sandpoint_restart(char *cmd)
+{
+ local_irq_disable();
+
+ /* Set exception prefix high - to the firmware */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ /* Reset system via Port 92 */
+ outb(0x00, 0x92);
+ outb(0x01, 0x92);
+ for(;;); /* Spin until reset happens */
+}
+
+static void
+sandpoint_power_off(void)
+{
+ local_irq_disable();
+ for(;;); /* No way to shut power off with software */
+ /* NOTREACHED */
+}
+
+static void
+sandpoint_halt(void)
+{
+ sandpoint_power_off();
+ /* NOTREACHED */
+}
+
+static int
+sandpoint_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: Motorola SPS\n");
+ seq_printf(m, "machine\t\t: Sandpoint\n");
+
+ return 0;
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE support.
+ */
+static int sandpoint_ide_ports_known = 0;
+static unsigned long sandpoint_ide_regbase[MAX_HWIFS];
+static unsigned long sandpoint_ide_ctl_regbase[MAX_HWIFS];
+static unsigned long sandpoint_idedma_regbase;
+
+static void
+sandpoint_ide_probe(void)
+{
+ struct pci_dev *pdev = pci_get_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_82C105, NULL);
+
+ if (pdev) {
+ sandpoint_ide_regbase[0]=pdev->resource[0].start;
+ sandpoint_ide_regbase[1]=pdev->resource[2].start;
+ sandpoint_ide_ctl_regbase[0]=pdev->resource[1].start;
+ sandpoint_ide_ctl_regbase[1]=pdev->resource[3].start;
+ sandpoint_idedma_regbase=pdev->resource[4].start;
+ pci_dev_put(pdev);
+ }
+
+ sandpoint_ide_ports_known = 1;
+}
+
+static int
+sandpoint_ide_default_irq(unsigned long base)
+{
+ if (sandpoint_ide_ports_known == 0)
+ sandpoint_ide_probe();
+
+ if (base == sandpoint_ide_regbase[0])
+ return SANDPOINT_IDE_INT0;
+ else if (base == sandpoint_ide_regbase[1])
+ return SANDPOINT_IDE_INT1;
+ else
+ return 0;
+}
+
+static unsigned long
+sandpoint_ide_default_io_base(int index)
+{
+ if (sandpoint_ide_ports_known == 0)
+ sandpoint_ide_probe();
+
+ return sandpoint_ide_regbase[index];
+}
+
+static void __init
+sandpoint_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
+ unsigned long ctrl_port, int *irq)
+{
+ unsigned long reg = data_port;
+ uint alt_status_base;
+ int i;
+
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hw->io_ports[i] = reg++;
+ }
+
+ if (data_port == sandpoint_ide_regbase[0]) {
+ alt_status_base = sandpoint_ide_ctl_regbase[0] + 2;
+ hw->irq = 14;
+ }
+ else if (data_port == sandpoint_ide_regbase[1]) {
+ alt_status_base = sandpoint_ide_ctl_regbase[1] + 2;
+ hw->irq = 15;
+ }
+ else {
+ alt_status_base = 0;
+ hw->irq = 0;
+ }
+
+ if (ctrl_port) {
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+ } else {
+ hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base;
+ }
+
+ if (irq != NULL) {
+ *irq = hw->irq;
+ }
+}
+#endif
+
+/*
+ * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1.
+ */
+static __inline__ void
+sandpoint_set_bat(void)
+{
+ unsigned long bat3u, bat3l;
+
+ __asm__ __volatile__(
+ " lis %0,0xf800\n \
+ ori %1,%0,0x002a\n \
+ ori %0,%0,0x0ffe\n \
+ mtspr 0x21e,%0\n \
+ mtspr 0x21f,%1\n \
+ isync\n \
+ sync "
+ : "=r" (bat3u), "=r" (bat3l));
+}
+
+TODC_ALLOC();
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /* ASSUMPTION: If both r3 (bd_t pointer) and r6 (cmdline pointer)
+ * are non-zero, then we should use the board info from the bd_t
+ * structure and the cmdline pointed to by r6 instead of the
+ * information from birecs, if any. Otherwise, use the information
+ * from birecs as discovered by the preceeding call to
+ * parse_bootinfo(). This rule should work with both PPCBoot, which
+ * uses a bd_t board info structure, and the kernel boot wrapper,
+ * which uses birecs.
+ */
+ if (r3 && r6) {
+ /* copy board info structure */
+ memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+ /* copy command line */
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if (r4) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* Map in board regs, etc. */
+ sandpoint_set_bat();
+
+ isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
+ isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
+ pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ ppc_md.setup_arch = sandpoint_setup_arch;
+ ppc_md.show_cpuinfo = sandpoint_show_cpuinfo;
+ ppc_md.irq_canonicalize = sandpoint_irq_canonicalize;
+ ppc_md.init_IRQ = sandpoint_init_IRQ;
+ ppc_md.get_irq = openpic_get_irq;
+
+ ppc_md.restart = sandpoint_restart;
+ ppc_md.power_off = sandpoint_power_off;
+ ppc_md.halt = sandpoint_halt;
+
+ ppc_md.find_end_of_memory = sandpoint_find_end_of_memory;
+ ppc_md.setup_io_mappings = sandpoint_map_io;
+
+ TODC_INIT(TODC_TYPE_PC97307, 0x70, 0x00, 0x71, 8);
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.calibrate_decr = todc_calibrate_decr;
+
+ ppc_md.nvram_read_val = todc_mc146818_read_val;
+ ppc_md.nvram_write_val = todc_mc146818_write_val;
+
+#ifdef CONFIG_KGDB
+ ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
+#endif
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = gen550_progress;
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.default_irq = sandpoint_ide_default_irq;
+ ppc_ide_md.default_io_base = sandpoint_ide_default_io_base;
+ ppc_ide_md.ide_init_hwif = sandpoint_ide_init_hwif_ports;
+#endif
+}
diff --git a/arch/ppc/platforms/sandpoint.h b/arch/ppc/platforms/sandpoint.h
new file mode 100644
index 00000000000..f4e982cb69d
--- /dev/null
+++ b/arch/ppc/platforms/sandpoint.h
@@ -0,0 +1,80 @@
+/*
+ * arch/ppc/platforms/sandpoint.h
+ *
+ * Definitions for Motorola SPS Sandpoint Test Platform
+ *
+ * Author: Mark A. Greer
+ * mgreer@mvista.com
+ *
+ * 2000-2003 (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.
+ */
+
+/*
+ * Sandpoint uses the CHRP map (Map B).
+ */
+
+#ifndef __PPC_PLATFORMS_SANDPOINT_H
+#define __PPC_PLATFORMS_SANDPOINT_H
+
+#include <asm/ppcboot.h>
+
+#if 0
+/* The Sandpoint X3 allows the IDE interrupt to be directly connected
+ * from the Windbond (PCI INTC or INTD) to the serial EPIC. Someday
+ * we should try this, but it was easier to use the existing 83c553
+ * initialization than change it to route the different interrupts :-).
+ * -- Dan
+ */
+#define SANDPOINT_IDE_INT0 23 /* EPIC 7 */
+#define SANDPOINT_IDE_INT1 24 /* EPIC 8 */
+#else
+#define SANDPOINT_IDE_INT0 14 /* 8259 Test */
+#define SANDPOINT_IDE_INT1 15 /* 8259 Test */
+#endif
+
+/*
+ * The sandpoint boards have processor modules that either have an 8240 or
+ * an MPC107 host bridge on them. These bridges have an IDSEL line that allows
+ * them to respond to PCI transactions as if they were a normal PCI devices.
+ * However, the processor on the processor side of the bridge can not reach
+ * out onto the PCI bus and then select the bridge or bad things will happen
+ * (documented in the 8240 and 107 manuals).
+ * Because of this, we always skip the bridge PCI device when accessing the
+ * PCI bus. The PCI slot that the bridge occupies is defined by the macro
+ * below.
+ */
+#define SANDPOINT_HOST_BRIDGE_IDSEL 12
+
+/*
+ * Serial defines.
+ */
+#define SANDPOINT_SERIAL_0 0xfe0003f8
+#define SANDPOINT_SERIAL_1 0xfe0002f8
+
+#define RS_TABLE_SIZE 2
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define BASE_BAUD ( 1843200 / 16 )
+#define UART_CLK 1843200
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF)
+#endif
+
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, SANDPOINT_SERIAL_0, 4, STD_COM_FLAGS, /* ttyS0 */ \
+ iomem_base: (u8 *)SANDPOINT_SERIAL_0, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, SANDPOINT_SERIAL_1, 3, STD_COM_FLAGS, /* ttyS1 */ \
+ iomem_base: (u8 *)SANDPOINT_SERIAL_1, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
+
+#endif /* __PPC_PLATFORMS_SANDPOINT_H */
diff --git a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c
new file mode 100644
index 00000000000..74c9ff72c3d
--- /dev/null
+++ b/arch/ppc/platforms/sbc82xx.c
@@ -0,0 +1,259 @@
+/*
+ * arch/ppc/platforms/sbc82xx.c
+ *
+ * SBC82XX platform support
+ *
+ * Author: Guy Streeter <streeter@redhat.com>
+ *
+ * Derived from: est8260_setup.c by Allen Curtis, ONZ
+ *
+ * Copyright 2004 Red Hat, 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/config.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/mpc8260.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/todc.h>
+#include <asm/immap_cpm2.h>
+#include <asm/pci.h>
+
+static void (*callback_init_IRQ)(void);
+
+extern unsigned char __res[sizeof(bd_t)];
+
+extern void (*late_time_init)(void);
+
+#ifdef CONFIG_GEN_RTC
+TODC_ALLOC();
+
+/*
+ * Timer init happens before mem_init but after paging init, so we cannot
+ * directly use ioremap() at that time.
+ * late_time_init() is call after paging init.
+ */
+
+static void sbc82xx_time_init(void)
+{
+ volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
+
+ /* Set up CS11 for RTC chip */
+ mc->memc_br11=0;
+ mc->memc_or11=0xffff0836;
+ mc->memc_br11=SBC82xx_TODC_NVRAM_ADDR | 0x0801;
+
+ TODC_INIT(TODC_TYPE_MK48T59, 0, 0, SBC82xx_TODC_NVRAM_ADDR, 0);
+
+ todc_info->nvram_data =
+ (unsigned int)ioremap(todc_info->nvram_data, 0x2000);
+ BUG_ON(!todc_info->nvram_data);
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+ todc_time_init();
+}
+#endif /* CONFIG_GEN_RTC */
+
+static volatile char *sbc82xx_i8259_map;
+static char sbc82xx_i8259_mask = 0xff;
+static DEFINE_SPINLOCK(sbc82xx_i8259_lock);
+
+static void sbc82xx_i8259_mask_and_ack_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ irq_nr -= NR_SIU_INTS;
+
+ spin_lock_irqsave(&sbc82xx_i8259_lock, flags);
+ sbc82xx_i8259_mask |= 1 << irq_nr;
+ (void) sbc82xx_i8259_map[1]; /* Dummy read */
+ sbc82xx_i8259_map[1] = sbc82xx_i8259_mask;
+ sbc82xx_i8259_map[0] = 0x20; /* OCW2: Non-specific EOI */
+ spin_unlock_irqrestore(&sbc82xx_i8259_lock, flags);
+}
+
+static void sbc82xx_i8259_mask_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ irq_nr -= NR_SIU_INTS;
+
+ spin_lock_irqsave(&sbc82xx_i8259_lock, flags);
+ sbc82xx_i8259_mask |= 1 << irq_nr;
+ sbc82xx_i8259_map[1] = sbc82xx_i8259_mask;
+ spin_unlock_irqrestore(&sbc82xx_i8259_lock, flags);
+}
+
+static void sbc82xx_i8259_unmask_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ irq_nr -= NR_SIU_INTS;
+
+ spin_lock_irqsave(&sbc82xx_i8259_lock, flags);
+ sbc82xx_i8259_mask &= ~(1 << irq_nr);
+ sbc82xx_i8259_map[1] = sbc82xx_i8259_mask;
+ spin_unlock_irqrestore(&sbc82xx_i8259_lock, flags);
+}
+
+static void sbc82xx_i8259_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+ && irq_desc[irq].action)
+ sbc82xx_i8259_unmask_irq(irq);
+}
+
+
+struct hw_interrupt_type sbc82xx_i8259_ic = {
+ .typename = " i8259 ",
+ .enable = sbc82xx_i8259_unmask_irq,
+ .disable = sbc82xx_i8259_mask_irq,
+ .ack = sbc82xx_i8259_mask_and_ack_irq,
+ .end = sbc82xx_i8259_end_irq,
+};
+
+static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id, struct pt_regs *regs)
+{
+ spin_lock(&sbc82xx_i8259_lock);
+
+ sbc82xx_i8259_map[0] = 0x0c; /* OCW3: Read IR register on RD# pulse */
+ irq = sbc82xx_i8259_map[0] & 7; /* Read IRR */
+
+ if (irq == 7) {
+ /* Possible spurious interrupt */
+ int isr;
+ sbc82xx_i8259_map[0] = 0x0b; /* OCW3: Read IS register on RD# pulse */
+ isr = sbc82xx_i8259_map[0]; /* Read ISR */
+
+ if (!(isr & 0x80)) {
+ printk(KERN_INFO "Spurious i8259 interrupt\n");
+ return IRQ_HANDLED;
+ }
+ }
+ __do_IRQ(NR_SIU_INTS + irq, regs);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction sbc82xx_i8259_irqaction = {
+ .handler = sbc82xx_i8259_demux,
+ .flags = SA_INTERRUPT,
+ .mask = CPU_MASK_NONE,
+ .name = "i8259 demux",
+};
+
+void __init sbc82xx_init_IRQ(void)
+{
+ volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
+ volatile intctl_cpm2_t *ic = &cpm2_immr->im_intctl;
+ int i;
+
+ callback_init_IRQ();
+
+ /* u-boot doesn't always set the board up correctly */
+ mc->memc_br5 = 0;
+ mc->memc_or5 = 0xfff00856;
+ mc->memc_br5 = 0x22000801;
+
+ sbc82xx_i8259_map = ioremap(0x22008000, 2);
+ if (!sbc82xx_i8259_map) {
+ printk(KERN_CRIT "Mapping i8259 interrupt controller failed\n");
+ return;
+ }
+
+ /* Set up the interrupt handlers for the i8259 IRQs */
+ for (i = NR_SIU_INTS; i < NR_SIU_INTS + 8; i++) {
+ irq_desc[i].handler = &sbc82xx_i8259_ic;
+ irq_desc[i].status |= IRQ_LEVEL;
+ }
+
+ /* make IRQ6 level sensitive */
+ ic->ic_siexr &= ~(1 << (14 - (SIU_INT_IRQ6 - SIU_INT_IRQ1)));
+ irq_desc[SIU_INT_IRQ6].status |= IRQ_LEVEL;
+
+ /* Initialise the i8259 */
+ sbc82xx_i8259_map[0] = 0x1b; /* ICW1: Level, no cascade, ICW4 */
+ sbc82xx_i8259_map[1] = 0x00; /* ICW2: vector base */
+ /* No ICW3 (no cascade) */
+ sbc82xx_i8259_map[1] = 0x01; /* ICW4: 8086 mode, normal EOI */
+
+ sbc82xx_i8259_map[0] = 0x0b; /* OCW3: Read IS register on RD# pulse */
+
+ sbc82xx_i8259_map[1] = sbc82xx_i8259_mask; /* Set interrupt mask */
+
+ /* Request cascade IRQ */
+ if (setup_irq(SIU_INT_IRQ6, &sbc82xx_i8259_irqaction)) {
+ printk("Installation of i8259 IRQ demultiplexer failed.\n");
+ }
+}
+
+static int sbc82xx_pci_map_irq(struct pci_dev *dev, unsigned char idsel,
+ unsigned char pin)
+{
+ static char pci_irq_table[][4] = {
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ { SBC82xx_PIRQA, SBC82xx_PIRQB, SBC82xx_PIRQC, SBC82xx_PIRQD }, /* IDSEL 16 - PMC slot */
+ { SBC82xx_PC_IRQA, SBC82xx_PC_IRQB, -1, -1 }, /* IDSEL 17 - CardBus */
+ { SBC82xx_PIRQA, SBC82xx_PIRQB, SBC82xx_PIRQC, SBC82xx_PIRQD }, /* IDSEL 18 - PCI-X bridge */
+ };
+
+ const long min_idsel = 16, max_idsel = 18, irqs_per_slot = 4;
+
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static void __devinit quirk_sbc8260_cardbus(struct pci_dev *pdev)
+{
+ uint32_t ctrl;
+
+ if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(17, 0))
+ return;
+
+ printk(KERN_INFO "Setting up CardBus controller\n");
+
+ /* Set P2CCLK bit in System Control Register */
+ pci_read_config_dword(pdev, 0x80, &ctrl);
+ ctrl |= (1<<27);
+ pci_write_config_dword(pdev, 0x80, ctrl);
+
+ /* Set MFUNC up for PCI IRQ routing via INTA and INTB, and LEDs. */
+ pci_write_config_dword(pdev, 0x8c, 0x00c01d22);
+
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, quirk_sbc8260_cardbus);
+
+void __init
+m82xx_board_init(void)
+{
+ /* u-boot may be using one of the FCC Ethernet devices.
+ Use the MAC address to the SCC. */
+ __res[offsetof(bd_t, bi_enetaddr[5])] &= ~3;
+
+ /* Anything special for this platform */
+ callback_init_IRQ = ppc_md.init_IRQ;
+
+ ppc_md.init_IRQ = sbc82xx_init_IRQ;
+ ppc_md.pci_map_irq = sbc82xx_pci_map_irq;
+#ifdef CONFIG_GEN_RTC
+ ppc_md.time_init = NULL;
+ ppc_md.get_rtc_time = NULL;
+ ppc_md.set_rtc_time = NULL;
+ ppc_md.nvram_read_val = NULL;
+ ppc_md.nvram_write_val = NULL;
+ late_time_init = sbc82xx_time_init;
+#endif /* CONFIG_GEN_RTC */
+}
diff --git a/arch/ppc/platforms/sbc82xx.h b/arch/ppc/platforms/sbc82xx.h
new file mode 100644
index 00000000000..e4042d4995f
--- /dev/null
+++ b/arch/ppc/platforms/sbc82xx.h
@@ -0,0 +1,36 @@
+/* Board information for the SBCPowerQUICCII, which should be generic for
+ * all 8260 boards. The IMMR is now given to us so the hard define
+ * will soon be removed. All of the clock values are computed from
+ * the configuration SCMR and the Power-On-Reset word.
+ */
+
+#ifndef __PPC_SBC82xx_H__
+#define __PPC_SBC82xx_H__
+
+#include <asm/ppcboot.h>
+
+#define CPM_MAP_ADDR 0xf0000000
+
+#define SBC82xx_TODC_NVRAM_ADDR 0xd0000000
+
+#define SBC82xx_MACADDR_NVRAM_FCC1 0x220000c9 /* JP6B */
+#define SBC82xx_MACADDR_NVRAM_SCC1 0x220000cf /* JP6A */
+#define SBC82xx_MACADDR_NVRAM_FCC2 0x220000d5 /* JP7A */
+#define SBC82xx_MACADDR_NVRAM_FCC3 0x220000db /* JP7B */
+
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "Wind River"
+#define CPUINFO_MACHINE "SBC PowerQUICC II"
+
+#define BOOTROM_RESTART_ADDR ((uint)0x40000104)
+
+#define SBC82xx_PC_IRQA (NR_SIU_INTS+0)
+#define SBC82xx_PC_IRQB (NR_SIU_INTS+1)
+#define SBC82xx_MPC185_IRQ (NR_SIU_INTS+2)
+#define SBC82xx_ATM_IRQ (NR_SIU_INTS+3)
+#define SBC82xx_PIRQA (NR_SIU_INTS+4)
+#define SBC82xx_PIRQB (NR_SIU_INTS+5)
+#define SBC82xx_PIRQC (NR_SIU_INTS+6)
+#define SBC82xx_PIRQD (NR_SIU_INTS+7)
+
+#endif /* __PPC_SBC82xx_H__ */
diff --git a/arch/ppc/platforms/sbs8260.h b/arch/ppc/platforms/sbs8260.h
new file mode 100644
index 00000000000..d51427a0f0d
--- /dev/null
+++ b/arch/ppc/platforms/sbs8260.h
@@ -0,0 +1,28 @@
+#ifndef __ASSEMBLY__
+/* Board information for various SBS 8260 cards, which should be generic for
+ * all 8260 boards. The IMMR is now given to us so the hard define
+ * will soon be removed. All of the clock values are computed from
+ * the configuration SCMR and the Power-On-Reset word.
+ */
+
+#define CPM_MAP_ADDR ((uint)0xfe000000)
+
+
+/* A Board Information structure that is given to a program when
+ * prom starts it up.
+ */
+typedef struct bd_info {
+ unsigned int bi_memstart; /* Memory start address */
+ unsigned int bi_memsize; /* Memory (end) size in bytes */
+ unsigned int bi_intfreq; /* Internal Freq, in Hz */
+ unsigned int bi_busfreq; /* Bus Freq, in MHz */
+ unsigned int bi_cpmfreq; /* CPM Freq, in MHz */
+ unsigned int bi_brgfreq; /* BRG Freq, in MHz */
+ unsigned int bi_vco; /* VCO Out from PLL */
+ unsigned int bi_baudrate; /* Default console baud rate */
+ unsigned int bi_immr; /* IMMR when called from boot rom */
+ unsigned char bi_enetaddr[6];
+} bd_t;
+
+extern bd_t m8xx_board_info;
+#endif /* !__ASSEMBLY__ */
diff --git a/arch/ppc/platforms/spd8xx.h b/arch/ppc/platforms/spd8xx.h
new file mode 100644
index 00000000000..ed48d144f41
--- /dev/null
+++ b/arch/ppc/platforms/spd8xx.h
@@ -0,0 +1,92 @@
+/*
+ * Speech Design SPD8xxTS board specific definitions
+ *
+ * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_SPD8XX_H__
+#define __ASM_SPD8XX_H__
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#ifndef __ASSEMBLY__
+#define SPD_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */
+#define SPD_IMAP_SIZE (64 * 1024) /* size of mapped area */
+
+#define IMAP_ADDR SPD_IMMR_BASE /* physical base address of IMMR area */
+#define IMAP_SIZE SPD_IMAP_SIZE /* mapped size of IMMR area */
+
+#define PCMCIA_MEM_ADDR ((uint)0xFE100000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
+
+#define IDE0_INTERRUPT 10 /* = IRQ5 */
+#define IDE1_INTERRUPT 12 /* = IRQ6 */
+#define CPM_INTERRUPT 13 /* = SIU_LEVEL6 (was: SIU_LEVEL2) */
+
+/* override the default number of IDE hardware interfaces */
+#define MAX_HWIFS 2
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET 0x0000 /* Offset in PCMCIA memory */
+#define IDE0_DATA_REG_OFFSET 0x0000
+#define IDE0_ERROR_REG_OFFSET 0x0081
+#define IDE0_NSECTOR_REG_OFFSET 0x0082
+#define IDE0_SECTOR_REG_OFFSET 0x0083
+#define IDE0_LCYL_REG_OFFSET 0x0084
+#define IDE0_HCYL_REG_OFFSET 0x0085
+#define IDE0_SELECT_REG_OFFSET 0x0086
+#define IDE0_STATUS_REG_OFFSET 0x0087
+#define IDE0_CONTROL_REG_OFFSET 0x0106
+#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */
+
+/*
+ * Definitions for IDE1 Interface
+ */
+#define IDE1_BASE_OFFSET 0x0C00 /* Offset in PCMCIA memory */
+#define IDE1_DATA_REG_OFFSET 0x0000
+#define IDE1_ERROR_REG_OFFSET 0x0081
+#define IDE1_NSECTOR_REG_OFFSET 0x0082
+#define IDE1_SECTOR_REG_OFFSET 0x0083
+#define IDE1_LCYL_REG_OFFSET 0x0084
+#define IDE1_HCYL_REG_OFFSET 0x0085
+#define IDE1_SELECT_REG_OFFSET 0x0086
+#define IDE1_STATUS_REG_OFFSET 0x0087
+#define IDE1_CONTROL_REG_OFFSET 0x0106
+#define IDE1_IRQ_REG_OFFSET 0x000A /* not used */
+
+/* CPM Ethernet through SCCx.
+ *
+ * Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC2 use.
+ */
+#define PA_ENET_MDC ((ushort)0x0001) /* PA 15 !!! */
+#define PA_ENET_MDIO ((ushort)0x0002) /* PA 14 !!! */
+#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */
+#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */
+#define PA_ENET_RCLK ((ushort)0x0200) /* PA 6 */
+#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */
+
+#define PB_ENET_TENA ((uint)0x00002000) /* PB 18 */
+
+#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */
+#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */
+#define PC_ENET_RESET ((ushort)0x0100) /* PC 7 !!! */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK2) to
+ * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x0000ff00)
+#define SICR_ENET_CLKRT ((uint)0x00002E00)
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_SPD8XX_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c
new file mode 100644
index 00000000000..5ad70d357cb
--- /dev/null
+++ b/arch/ppc/platforms/spruce.c
@@ -0,0 +1,325 @@
+/*
+ * arch/ppc/platforms/spruce.c
+ *
+ * Board and PCI setup routines for IBM Spruce
+ *
+ * Author: MontaVista Software <source@mvista.com>
+ *
+ * 2000-2004 (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/config.h>
+#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/types.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/ide.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/kgdb.h>
+
+#include <syslib/cpc700.h>
+
+#include "spruce.h"
+
+static inline int
+spruce_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ {23, 24, 25, 26}, /* IDSEL 1 - PCI slot 3 */
+ {24, 25, 26, 23}, /* IDSEL 2 - PCI slot 2 */
+ {25, 26, 23, 24}, /* IDSEL 3 - PCI slot 1 */
+ {26, 23, 24, 25}, /* IDSEL 4 - PCI slot 0 */
+ };
+
+ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static void __init
+spruce_setup_hose(void)
+{
+ struct pci_controller *hose;
+
+ /* Setup hose */
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ pci_init_resource(&hose->io_resource,
+ SPRUCE_PCI_LOWER_IO,
+ SPRUCE_PCI_UPPER_IO,
+ IORESOURCE_IO,
+ "PCI host bridge");
+
+ pci_init_resource(&hose->mem_resources[0],
+ SPRUCE_PCI_LOWER_MEM,
+ SPRUCE_PCI_UPPER_MEM,
+ IORESOURCE_MEM,
+ "PCI host bridge");
+
+ hose->io_space.start = SPRUCE_PCI_LOWER_IO;
+ hose->io_space.end = SPRUCE_PCI_UPPER_IO;
+ hose->mem_space.start = SPRUCE_PCI_LOWER_MEM;
+ hose->mem_space.end = SPRUCE_PCI_UPPER_MEM;
+ hose->io_base_virt = (void *)SPRUCE_ISA_IO_BASE;
+
+ setup_indirect_pci(hose,
+ SPRUCE_PCI_CONFIG_ADDR,
+ SPRUCE_PCI_CONFIG_DATA);
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = spruce_map_irq;
+}
+
+/*
+ * CPC700 PIC interrupt programming table
+ *
+ * First entry is the sensitivity (level/edge), second is the polarity.
+ */
+unsigned int cpc700_irq_assigns[32][2] = {
+ { 1, 1 }, /* IRQ 0: ECC Correctable Error - rising edge */
+ { 1, 1 }, /* IRQ 1: PCI Write Mem Range - rising edge */
+ { 0, 1 }, /* IRQ 2: PCI Write Command Reg - active high */
+ { 0, 1 }, /* IRQ 3: UART 0 - active high */
+ { 0, 1 }, /* IRQ 4: UART 1 - active high */
+ { 0, 1 }, /* IRQ 5: ICC 0 - active high */
+ { 0, 1 }, /* IRQ 6: ICC 1 - active high */
+ { 0, 1 }, /* IRQ 7: GPT Compare 0 - active high */
+ { 0, 1 }, /* IRQ 8: GPT Compare 1 - active high */
+ { 0, 1 }, /* IRQ 9: GPT Compare 2 - active high */
+ { 0, 1 }, /* IRQ 10: GPT Compare 3 - active high */
+ { 0, 1 }, /* IRQ 11: GPT Compare 4 - active high */
+ { 0, 1 }, /* IRQ 12: GPT Capture 0 - active high */
+ { 0, 1 }, /* IRQ 13: GPT Capture 1 - active high */
+ { 0, 1 }, /* IRQ 14: GPT Capture 2 - active high */
+ { 0, 1 }, /* IRQ 15: GPT Capture 3 - active high */
+ { 0, 1 }, /* IRQ 16: GPT Capture 4 - active high */
+ { 0, 0 }, /* IRQ 17: Reserved */
+ { 0, 0 }, /* IRQ 18: Reserved */
+ { 0, 0 }, /* IRQ 19: Reserved */
+ { 0, 1 }, /* IRQ 20: FPGA EXT_IRQ0 - active high */
+ { 1, 1 }, /* IRQ 21: Mouse - rising edge */
+ { 1, 1 }, /* IRQ 22: Keyboard - rising edge */
+ { 0, 0 }, /* IRQ 23: PCI Slot 3 - active low */
+ { 0, 0 }, /* IRQ 24: PCI Slot 2 - active low */
+ { 0, 0 }, /* IRQ 25: PCI Slot 1 - active low */
+ { 0, 0 }, /* IRQ 26: PCI Slot 0 - active low */
+};
+
+static void __init
+spruce_calibrate_decr(void)
+{
+ int freq, divisor = 4;
+
+ /* determine processor bus speed */
+ freq = SPRUCE_BUS_SPEED;
+ tb_ticks_per_jiffy = freq / HZ / divisor;
+ tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+}
+
+static int
+spruce_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: IBM\n");
+ seq_printf(m, "machine\t\t: Spruce\n");
+
+ return 0;
+}
+
+static void __init
+spruce_early_serial_map(void)
+{
+ u32 uart_clk;
+ struct uart_port serial_req;
+
+ if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A)))
+ uart_clk = SPRUCE_BAUD_33M * 16;
+ else
+ uart_clk = SPRUCE_BAUD_30M * 16;
+
+ /* Setup serial port access */
+ memset(&serial_req, 0, sizeof(serial_req));
+ serial_req.uartclk = uart_clk;
+ serial_req.irq = UART0_INT;
+ serial_req.flags = ASYNC_BOOT_AUTOCONF;
+ serial_req.iotype = SERIAL_IO_MEM;
+ serial_req.membase = (u_char *)UART0_IO_BASE;
+ serial_req.regshift = 0;
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
+ gen550_init(0, &serial_req);
+#endif
+#ifdef CONFIG_SERIAL_8250
+ if (early_serial_setup(&serial_req) != 0)
+ printk("Early serial init of port 0 failed\n");
+#endif
+
+ /* Assume early_serial_setup() doesn't modify serial_req */
+ serial_req.line = 1;
+ serial_req.irq = UART1_INT;
+ serial_req.membase = (u_char *)UART1_IO_BASE;
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
+ gen550_init(1, &serial_req);
+#endif
+#ifdef CONFIG_SERIAL_8250
+ if (early_serial_setup(&serial_req) != 0)
+ printk("Early serial init of port 1 failed\n");
+#endif
+}
+
+TODC_ALLOC();
+
+static void __init
+spruce_setup_arch(void)
+{
+ /* Setup TODC access */
+ TODC_INIT(TODC_TYPE_DS1643, 0, 0, SPRUCE_RTC_BASE_ADDR, 8);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000 / HZ;
+
+ /* Setup PCI host bridge */
+ spruce_setup_hose();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_SDA1;
+#endif
+
+ /* Identify the system */
+ printk(KERN_INFO "System Identification: IBM Spruce\n");
+ printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+}
+
+static void
+spruce_restart(char *cmd)
+{
+ local_irq_disable();
+
+ /* SRR0 has system reset vector, SRR1 has default MSR value */
+ /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+ __asm__ __volatile__
+ ("\n\
+ lis 3,0xfff0 \n\
+ ori 3,3,0x0100 \n\
+ mtspr 26,3 \n\
+ li 3,0 \n\
+ mtspr 27,3 \n\
+ rfi \n\
+ ");
+ for(;;);
+}
+
+static void
+spruce_power_off(void)
+{
+ for(;;);
+}
+
+static void
+spruce_halt(void)
+{
+ spruce_restart(NULL);
+}
+
+static void __init
+spruce_map_io(void)
+{
+ io_block_mapping(SPRUCE_PCI_IO_BASE, SPRUCE_PCI_PHY_IO_BASE,
+ 0x08000000, _PAGE_IO);
+}
+
+/*
+ * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1.
+ */
+static __inline__ void
+spruce_set_bat(void)
+{
+ mb();
+ mtspr(SPRN_DBAT1U, 0xf8000ffe);
+ mtspr(SPRN_DBAT1L, 0xf800002a);
+ mb();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ parse_bootinfo(find_bootinfo());
+
+ /* Map in board regs, etc. */
+ spruce_set_bat();
+
+ isa_io_base = SPRUCE_ISA_IO_BASE;
+ pci_dram_offset = SPRUCE_PCI_SYS_MEM_BASE;
+
+ ppc_md.setup_arch = spruce_setup_arch;
+ ppc_md.show_cpuinfo = spruce_show_cpuinfo;
+ ppc_md.init_IRQ = cpc700_init_IRQ;
+ ppc_md.get_irq = cpc700_get_irq;
+
+ ppc_md.setup_io_mappings = spruce_map_io;
+
+ ppc_md.restart = spruce_restart;
+ ppc_md.power_off = spruce_power_off;
+ ppc_md.halt = spruce_halt;
+
+ ppc_md.time_init = todc_time_init;
+ ppc_md.set_rtc_time = todc_set_rtc_time;
+ ppc_md.get_rtc_time = todc_get_rtc_time;
+ ppc_md.calibrate_decr = spruce_calibrate_decr;
+
+ ppc_md.nvram_read_val = todc_direct_read_val;
+ ppc_md.nvram_write_val = todc_direct_write_val;
+
+ spruce_early_serial_map();
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+ ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#ifdef CONFIG_KGDB
+ ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
+#endif
+}
diff --git a/arch/ppc/platforms/spruce.h b/arch/ppc/platforms/spruce.h
new file mode 100644
index 00000000000..a31ff7ee698
--- /dev/null
+++ b/arch/ppc/platforms/spruce.h
@@ -0,0 +1,71 @@
+/*
+ * include/asm-ppc/platforms/spruce.h
+ *
+ * Definitions for IBM Spruce reference board support
+ *
+ * Authors: Matt Porter and Johnnie Peters
+ * mporter@mvista.com
+ * jpeters@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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_SPRUCE_H__
+#define __ASM_SPRUCE_H__
+
+#define SPRUCE_PCI_CONFIG_ADDR 0xfec00000
+#define SPRUCE_PCI_CONFIG_DATA 0xfec00004
+
+#define SPRUCE_PCI_PHY_IO_BASE 0xf8000000
+#define SPRUCE_PCI_IO_BASE SPRUCE_PCI_PHY_IO_BASE
+
+#define SPRUCE_PCI_SYS_MEM_BASE 0x00000000
+
+#define SPRUCE_PCI_LOWER_MEM 0x80000000
+#define SPRUCE_PCI_UPPER_MEM 0x9fffffff
+#define SPRUCE_PCI_LOWER_IO 0x00000000
+#define SPRUCE_PCI_UPPER_IO 0x03ffffff
+
+#define SPRUCE_ISA_IO_BASE SPRUCE_PCI_IO_BASE
+
+#define SPRUCE_MEM_SIZE 0x04000000
+#define SPRUCE_BUS_SPEED 66666667
+
+#define SPRUCE_NVRAM_BASE_ADDR 0xff800000
+#define SPRUCE_RTC_BASE_ADDR SPRUCE_NVRAM_BASE_ADDR
+
+/*
+ * Serial port defines
+ */
+#define SPRUCE_FPGA_REG_A 0xff820000
+#define SPRUCE_UARTCLK_33M 0x02
+#define SPRUCE_UARTCLK_IS_33M(reg) (reg & SPRUCE_UARTCLK_33M)
+
+#define UART0_IO_BASE 0xff600300
+#define UART1_IO_BASE 0xff600400
+
+#define RS_TABLE_SIZE 2
+
+#define SPRUCE_BAUD_33M (33000000/64)
+#define SPRUCE_BAUD_30M (30000000/64)
+#define BASE_BAUD SPRUCE_BAUD_33M
+
+#define UART0_INT 3
+#define UART1_INT 4
+
+#define STD_UART_OP(num) \
+ { 0, BASE_BAUD, 0, UART##num##_INT, \
+ ASYNC_BOOT_AUTOCONF, \
+ iomem_base: (unsigned char *) UART##num##_IO_BASE, \
+ io_type: SERIAL_IO_MEM},
+
+#define SERIAL_PORT_DFNS \
+ STD_UART_OP(0) \
+ STD_UART_OP(1)
+
+#endif /* __ASM_SPRUCE_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/tqm8260.h b/arch/ppc/platforms/tqm8260.h
new file mode 100644
index 00000000000..c7a78a646c6
--- /dev/null
+++ b/arch/ppc/platforms/tqm8260.h
@@ -0,0 +1,23 @@
+/*
+ * TQM8260 board specific definitions
+ *
+ * Copyright (c) 2001 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifndef __TQM8260_PLATFORM
+#define __TQM8260_PLATFORM
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#define CPM_MAP_ADDR ((uint)0xFFF00000)
+#define PHY_INTERRUPT 25
+
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "IN2 Systems"
+#define CPUINFO_MACHINE "TQM8260 PowerPC"
+
+#define BOOTROM_RESTART_ADDR ((uint)0x40000104)
+
+#endif /* __TQM8260_PLATFORM */
diff --git a/arch/ppc/platforms/tqm8260_setup.c b/arch/ppc/platforms/tqm8260_setup.c
new file mode 100644
index 00000000000..a8880bfc034
--- /dev/null
+++ b/arch/ppc/platforms/tqm8260_setup.c
@@ -0,0 +1,44 @@
+/*
+ * arch/ppc/platforms/tqm8260_setup.c
+ *
+ * TQM8260 platform support
+ *
+ * Author: Allen Curtis <acurtis@onz.com>
+ * Derived from: m8260_setup.c by Dan Malek, MVista
+ *
+ * Copyright 2002 Ones and Zeros, 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 <asm/immap_cpm2.h>
+#include <asm/mpc8260.h>
+#include <asm/machdep.h>
+
+static int
+tqm8260_set_rtc_time(unsigned long time)
+{
+ ((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcnt = time;
+ ((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcntsc = 0x3;
+
+ return(0);
+}
+
+static unsigned long
+tqm8260_get_rtc_time(void)
+{
+ return ((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcnt;
+}
+
+void __init
+m82xx_board_init(void)
+{
+ /* Anything special for this platform */
+ ppc_md.set_rtc_time = tqm8260_set_rtc_time;
+ ppc_md.get_rtc_time = tqm8260_get_rtc_time;
+}
diff --git a/arch/ppc/platforms/tqm8xx.h b/arch/ppc/platforms/tqm8xx.h
new file mode 100644
index 00000000000..2150dc87b18
--- /dev/null
+++ b/arch/ppc/platforms/tqm8xx.h
@@ -0,0 +1,179 @@
+/*
+ * TQM8xx(L) board specific definitions
+ *
+ * Copyright (c) 1999-2002 Wolfgang Denk (wd@denx.de)
+ */
+
+#ifdef __KERNEL__
+#ifndef __MACH_TQM8xx_H
+#define __MACH_TQM8xx_H
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+#ifndef __ASSEMBLY__
+#define TQM_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */
+#define TQM_IMAP_SIZE (64 * 1024) /* size of mapped area */
+
+#define IMAP_ADDR TQM_IMMR_BASE /* physical base address of IMMR area */
+#define IMAP_SIZE TQM_IMAP_SIZE /* mapped size of IMMR area */
+
+/*-----------------------------------------------------------------------
+ * PCMCIA stuff
+ *-----------------------------------------------------------------------
+ *
+ */
+#define PCMCIA_MEM_SIZE ( 64 << 20 )
+
+#ifndef CONFIG_KUP4K
+# define MAX_HWIFS 1 /* overwrite default in include/asm-ppc/ide.h */
+
+#else /* CONFIG_KUP4K */
+
+# define MAX_HWIFS 2 /* overwrite default in include/asm-ppc/ide.h */
+# ifndef __ASSEMBLY__
+# include <asm/8xx_immap.h>
+static __inline__ void ide_led(int on)
+{
+ volatile immap_t *immap = (immap_t *)IMAP_ADDR;
+
+ if (on) {
+ immap->im_ioport.iop_padat &= ~0x80;
+ } else {
+ immap->im_ioport.iop_padat |= 0x80;
+ }
+}
+# endif /* __ASSEMBLY__ */
+# define IDE_LED(x) ide_led((x))
+#endif /* CONFIG_KUP4K */
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET 0
+#define IDE0_DATA_REG_OFFSET (PCMCIA_MEM_SIZE + 0x320)
+#define IDE0_ERROR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 1)
+#define IDE0_NSECTOR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 2)
+#define IDE0_SECTOR_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 3)
+#define IDE0_LCYL_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 4)
+#define IDE0_HCYL_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 5)
+#define IDE0_SELECT_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 6)
+#define IDE0_STATUS_REG_OFFSET (2 * PCMCIA_MEM_SIZE + 0x320 + 7)
+#define IDE0_CONTROL_REG_OFFSET 0x0106
+#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */
+
+/* define IO_BASE for PCMCIA */
+#define _IO_BASE 0x80000000
+#define _IO_BASE_SIZE (64<<10)
+
+#define FEC_INTERRUPT 9 /* = SIU_LEVEL4 */
+#define PHY_INTERRUPT 12 /* = IRQ6 */
+#define IDE0_INTERRUPT 13
+
+#ifdef CONFIG_IDE
+#endif
+
+/*-----------------------------------------------------------------------
+ * CPM Ethernet through SCCx.
+ *-----------------------------------------------------------------------
+ *
+ */
+
+/*** TQM823L, TQM850L ***********************************************/
+
+#if defined(CONFIG_TQM823L) || defined(CONFIG_TQM850L)
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */
+#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */
+#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */
+#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */
+
+#define PB_ENET_TENA ((uint)0x00002000) /* PB 18 */
+
+#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */
+#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x0000ff00)
+#define SICR_ENET_CLKRT ((uint)0x00002600)
+#endif /* CONFIG_TQM823L, CONFIG_TQM850L */
+
+/*** TQM860L ********************************************************/
+
+#ifdef CONFIG_TQM860L
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD ((ushort)0x0001) /* PA 15 */
+#define PA_ENET_TXD ((ushort)0x0002) /* PA 14 */
+#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */
+#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */
+
+#define PC_ENET_TENA ((ushort)0x0001) /* PC 15 */
+#define PC_ENET_CLSN ((ushort)0x0010) /* PC 11 */
+#define PC_ENET_RENA ((ushort)0x0020) /* PC 10 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT ((uint)0x00000026)
+#endif /* CONFIG_TQM860L */
+
+/*** FPS850L *********************************************************/
+
+#ifdef CONFIG_FPS850L
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */
+#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */
+#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */
+#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */
+
+#define PC_ENET_TENA ((ushort)0x0002) /* PC 14 */
+#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */
+#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x0000ff00)
+#define SICR_ENET_CLKRT ((uint)0x00002600)
+#endif /* CONFIG_FPS850L */
+
+/*** SM850 *********************************************************/
+
+/* The SM850 Service Module uses SCC2 for IrDA and SCC3 for Ethernet */
+
+#ifdef CONFIG_SM850
+#define PB_ENET_RXD ((uint)0x00000004) /* PB 29 */
+#define PB_ENET_TXD ((uint)0x00000002) /* PB 30 */
+#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */
+#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */
+
+#define PC_ENET_LBK ((ushort)0x0008) /* PC 12 */
+#define PC_ENET_TENA ((ushort)0x0004) /* PC 13 */
+
+#define PC_ENET_RENA ((ushort)0x0800) /* PC 4 */
+#define PC_ENET_CLSN ((ushort)0x0400) /* PC 5 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) 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)0x00260000)
+#endif /* CONFIG_SM850 */
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS 0
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __MACH_TQM8xx_H */
+#endif /* __KERNEL__ */