diff options
Diffstat (limited to 'arch/powerpc/platforms/86xx')
| -rw-r--r-- | arch/powerpc/platforms/86xx/Kconfig | 75 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/Makefile | 7 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/gef_ppc9a.c | 246 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/gef_sbc310.c | 233 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/gef_sbc610.c | 223 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/mpc8610_hpcd.c | 359 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/mpc8641_hpcn.h | 21 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/mpc86xx.h | 13 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 387 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/mpc86xx_smp.c | 23 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/pci.c | 205 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/pic.c | 71 | ||||
| -rw-r--r-- | arch/powerpc/platforms/86xx/sbc8641d.c | 124 |
13 files changed, 1390 insertions, 597 deletions
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index d1bcff50046..1afd1e4a2dd 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -1,21 +1,80 @@ -choice - prompt "Machine Type" - depends on PPC_86xx - default MPC8641_HPCN +config PPC_86xx +menuconfig PPC_86xx + bool "86xx-based boards" + depends on 6xx + select FSL_SOC + select ALTIVEC + select ARCH_WANT_OPTIONAL_GPIOLIB + help + The Freescale E600 SoCs have 74xx cores. + +if PPC_86xx config MPC8641_HPCN bool "Freescale MPC8641 HPCN" select PPC_I8259 select DEFAULT_UIMAGE + select FSL_ULI1575 if PCI + select HAS_RAPIDIO + select SWIOTLB help This option enables support for the MPC8641 HPCN board. -endchoice +config SBC8641D + bool "Wind River SBC8641D" + select DEFAULT_UIMAGE + help + This option enables support for the WRS SBC8641D board. + +config MPC8610_HPCD + bool "Freescale MPC8610 HPCD" + select DEFAULT_UIMAGE + select FSL_ULI1575 if PCI + help + This option enables support for the MPC8610 HPCD board. + +config GEF_PPC9A + bool "GE PPC9A" + select DEFAULT_UIMAGE + select MMIO_NVRAM + select ARCH_REQUIRE_GPIOLIB + select GE_FPGA + help + This option enables support for the GE PPC9A. + +config GEF_SBC310 + bool "GE SBC310" + select DEFAULT_UIMAGE + select MMIO_NVRAM + select ARCH_REQUIRE_GPIOLIB + select GE_FPGA + help + This option enables support for the GE SBC310. + +config GEF_SBC610 + bool "GE SBC610" + select DEFAULT_UIMAGE + select MMIO_NVRAM + select ARCH_REQUIRE_GPIOLIB + select GE_FPGA + select HAS_RAPIDIO + help + This option enables support for the GE SBC610. + +endif config MPC8641 bool - select PPC_INDIRECT_PCI - select PPC_INDIRECT_PCI_BE + select PPC_PCI_CHOICE + select FSL_PCI if PCI + select PPC_UDBG_16550 + select MPIC + default y if MPC8641_HPCN || SBC8641D || GEF_SBC610 || GEF_SBC310 || GEF_PPC9A + +config MPC8610 + bool + select PPC_PCI_CHOICE + select FSL_PCI if PCI select PPC_UDBG_16550 select MPIC - default y if MPC8641_HPCN + default y if MPC8610_HPCD diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 418fd8f4d26..ede815d6489 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -2,6 +2,11 @@ # Makefile for the PowerPC 86xx linux kernel. # +obj-y := pic.o obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o -obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_SBC8641D) += sbc8641d.o +obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o +obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o +obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o +obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c new file mode 100644 index 00000000000..c23f3443880 --- /dev/null +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -0,0 +1,246 @@ +/* + * GE PPC9A board support + * + * Author: Martyn Welch <martyn.welch@ge.com> + * + * Copyright 2008 GE Intelligent Platforms Embedded Systems, 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. + * + * Based on: mpc86xx_hpcn.c (MPC86xx HPCN board specific routines) + * Copyright 2006 Freescale Semiconductor Inc. + * + * NEC fixup adapted from arch/mips/pci/fixup-lm2e.c + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/of_platform.h> + +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/prom.h> +#include <mm/mmu_decl.h> +#include <asm/udbg.h> + +#include <asm/mpic.h> +#include <asm/nvram.h> + +#include <sysdev/fsl_pci.h> +#include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h> + +#include "mpc86xx.h" + +#undef DEBUG + +#ifdef DEBUG +#define DBG (fmt...) do { printk(KERN_ERR "PPC9A: " fmt); } while (0) +#else +#define DBG (fmt...) do { } while (0) +#endif + +void __iomem *ppc9a_regs; + +static void __init gef_ppc9a_init_irq(void) +{ + struct device_node *cascade_node = NULL; + + mpc86xx_init_irq(); + + /* + * There is a simple interrupt handler in the main FPGA, this needs + * to be cascaded into the MPIC + */ + cascade_node = of_find_compatible_node(NULL, NULL, "gef,fpga-pic-1.00"); + if (!cascade_node) { + printk(KERN_WARNING "PPC9A: No FPGA PIC\n"); + return; + } + + gef_pic_init(cascade_node); + of_node_put(cascade_node); +} + +static void __init gef_ppc9a_setup_arch(void) +{ + struct device_node *regs; + + printk(KERN_INFO "GE Intelligent Platforms PPC9A 6U VME SBC\n"); + +#ifdef CONFIG_SMP + mpc86xx_smp_init(); +#endif + + fsl_pci_assign_primary(); + + /* Remap basic board registers */ + regs = of_find_compatible_node(NULL, NULL, "gef,ppc9a-fpga-regs"); + if (regs) { + ppc9a_regs = of_iomap(regs, 0); + if (ppc9a_regs == NULL) + printk(KERN_WARNING "Unable to map board registers\n"); + of_node_put(regs); + } + +#if defined(CONFIG_MMIO_NVRAM) + mmio_nvram_init(); +#endif +} + +/* Return the PCB revision */ +static unsigned int gef_ppc9a_get_pcb_rev(void) +{ + unsigned int reg; + + reg = ioread32be(ppc9a_regs); + return (reg >> 16) & 0xff; +} + +/* Return the board (software) revision */ +static unsigned int gef_ppc9a_get_board_rev(void) +{ + unsigned int reg; + + reg = ioread32be(ppc9a_regs); + return (reg >> 8) & 0xff; +} + +/* Return the FPGA revision */ +static unsigned int gef_ppc9a_get_fpga_rev(void) +{ + unsigned int reg; + + reg = ioread32be(ppc9a_regs); + return reg & 0xf; +} + +/* Return VME Geographical Address */ +static unsigned int gef_ppc9a_get_vme_geo_addr(void) +{ + unsigned int reg; + + reg = ioread32be(ppc9a_regs + 0x4); + return reg & 0x1f; +} + +/* Return VME System Controller Status */ +static unsigned int gef_ppc9a_get_vme_is_syscon(void) +{ + unsigned int reg; + + reg = ioread32be(ppc9a_regs + 0x4); + return (reg >> 9) & 0x1; +} + +static void gef_ppc9a_show_cpuinfo(struct seq_file *m) +{ + uint svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n"); + + seq_printf(m, "Revision\t: %u%c\n", gef_ppc9a_get_pcb_rev(), + ('A' + gef_ppc9a_get_board_rev())); + seq_printf(m, "FPGA Revision\t: %u\n", gef_ppc9a_get_fpga_rev()); + + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + + seq_printf(m, "VME geo. addr\t: %u\n", gef_ppc9a_get_vme_geo_addr()); + + seq_printf(m, "VME syscon\t: %s\n", + gef_ppc9a_get_vme_is_syscon() ? "yes" : "no"); +} + +static void gef_ppc9a_nec_fixup(struct pci_dev *pdev) +{ + unsigned int val; + + /* Do not do the fixup on other platforms! */ + if (!machine_is(gef_ppc9a)) + return; + + printk(KERN_INFO "Running NEC uPD720101 Fixup\n"); + + /* Ensure ports 1, 2, 3, 4 & 5 are enabled */ + pci_read_config_dword(pdev, 0xe0, &val); + pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x5); + + /* System clock is 48-MHz Oscillator and EHCI Enabled. */ + pci_write_config_dword(pdev, 0xe4, 1 << 5); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, + gef_ppc9a_nec_fixup); + +/* + * Called very early, device-tree isn't unflattened + * + * This function is called to determine whether the BSP is compatible with the + * supplied device-tree, which is assumed to be the correct one for the actual + * board. It is expected thati, in the future, a kernel may support multiple + * boards. + */ +static int __init gef_ppc9a_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "gef,ppc9a")) + return 1; + + return 0; +} + +static long __init mpc86xx_time_init(void) +{ + unsigned int temp; + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + temp = mfspr(SPRN_HID0); + temp |= HID0_TBEN; + mtspr(SPRN_HID0, temp); + asm volatile("isync"); + + return 0; +} + +static __initdata struct of_device_id of_bus_ids[] = { + { .compatible = "simple-bus", }, + { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + printk(KERN_DEBUG "Probe platform devices\n"); + of_platform_bus_probe(NULL, of_bus_ids, NULL); + + return 0; +} +machine_arch_initcall(gef_ppc9a, declare_of_platform_devices); + +define_machine(gef_ppc9a) { + .name = "GE PPC9A", + .probe = gef_ppc9a_probe, + .setup_arch = gef_ppc9a_setup_arch, + .init_IRQ = gef_ppc9a_init_irq, + .show_cpuinfo = gef_ppc9a_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .time_init = mpc86xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif +}; diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c new file mode 100644 index 00000000000..8a6ac20686e --- /dev/null +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -0,0 +1,233 @@ +/* + * GE SBC310 board support + * + * Author: Martyn Welch <martyn.welch@ge.com> + * + * Copyright 2008 GE Intelligent Platforms Embedded Systems, 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. + * + * Based on: mpc86xx_hpcn.c (MPC86xx HPCN board specific routines) + * Copyright 2006 Freescale Semiconductor Inc. + * + * NEC fixup adapted from arch/mips/pci/fixup-lm2e.c + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/of_platform.h> + +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/prom.h> +#include <mm/mmu_decl.h> +#include <asm/udbg.h> + +#include <asm/mpic.h> +#include <asm/nvram.h> + +#include <sysdev/fsl_pci.h> +#include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h> + +#include "mpc86xx.h" + +#undef DEBUG + +#ifdef DEBUG +#define DBG (fmt...) do { printk(KERN_ERR "SBC310: " fmt); } while (0) +#else +#define DBG (fmt...) do { } while (0) +#endif + +void __iomem *sbc310_regs; + +static void __init gef_sbc310_init_irq(void) +{ + struct device_node *cascade_node = NULL; + + mpc86xx_init_irq(); + + /* + * There is a simple interrupt handler in the main FPGA, this needs + * to be cascaded into the MPIC + */ + cascade_node = of_find_compatible_node(NULL, NULL, "gef,fpga-pic"); + if (!cascade_node) { + printk(KERN_WARNING "SBC310: No FPGA PIC\n"); + return; + } + + gef_pic_init(cascade_node); + of_node_put(cascade_node); +} + +static void __init gef_sbc310_setup_arch(void) +{ + struct device_node *regs; + printk(KERN_INFO "GE Intelligent Platforms SBC310 6U VPX SBC\n"); + +#ifdef CONFIG_SMP + mpc86xx_smp_init(); +#endif + + fsl_pci_assign_primary(); + + /* Remap basic board registers */ + regs = of_find_compatible_node(NULL, NULL, "gef,fpga-regs"); + if (regs) { + sbc310_regs = of_iomap(regs, 0); + if (sbc310_regs == NULL) + printk(KERN_WARNING "Unable to map board registers\n"); + of_node_put(regs); + } + +#if defined(CONFIG_MMIO_NVRAM) + mmio_nvram_init(); +#endif +} + +/* Return the PCB revision */ +static unsigned int gef_sbc310_get_board_id(void) +{ + unsigned int reg; + + reg = ioread32(sbc310_regs); + return reg & 0xff; +} + +/* Return the PCB revision */ +static unsigned int gef_sbc310_get_pcb_rev(void) +{ + unsigned int reg; + + reg = ioread32(sbc310_regs); + return (reg >> 8) & 0xff; +} + +/* Return the board (software) revision */ +static unsigned int gef_sbc310_get_board_rev(void) +{ + unsigned int reg; + + reg = ioread32(sbc310_regs); + return (reg >> 16) & 0xff; +} + +/* Return the FPGA revision */ +static unsigned int gef_sbc310_get_fpga_rev(void) +{ + unsigned int reg; + + reg = ioread32(sbc310_regs); + return (reg >> 24) & 0xf; +} + +static void gef_sbc310_show_cpuinfo(struct seq_file *m) +{ + uint svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n"); + + seq_printf(m, "Board ID\t: 0x%2.2x\n", gef_sbc310_get_board_id()); + seq_printf(m, "Revision\t: %u%c\n", gef_sbc310_get_pcb_rev(), + ('A' + gef_sbc310_get_board_rev() - 1)); + seq_printf(m, "FPGA Revision\t: %u\n", gef_sbc310_get_fpga_rev()); + + seq_printf(m, "SVR\t\t: 0x%x\n", svid); + +} + +static void gef_sbc310_nec_fixup(struct pci_dev *pdev) +{ + unsigned int val; + + /* Do not do the fixup on other platforms! */ + if (!machine_is(gef_sbc310)) + return; + + printk(KERN_INFO "Running NEC uPD720101 Fixup\n"); + + /* Ensure only ports 1 & 2 are enabled */ + pci_read_config_dword(pdev, 0xe0, &val); + pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x2); + + /* System clock is 48-MHz Oscillator and EHCI Enabled. */ + pci_write_config_dword(pdev, 0xe4, 1 << 5); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, + gef_sbc310_nec_fixup); + +/* + * Called very early, device-tree isn't unflattened + * + * This function is called to determine whether the BSP is compatible with the + * supplied device-tree, which is assumed to be the correct one for the actual + * board. It is expected thati, in the future, a kernel may support multiple + * boards. + */ +static int __init gef_sbc310_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "gef,sbc310")) + return 1; + + return 0; +} + +static long __init mpc86xx_time_init(void) +{ + unsigned int temp; + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + temp = mfspr(SPRN_HID0); + temp |= HID0_TBEN; + mtspr(SPRN_HID0, temp); + asm volatile("isync"); + + return 0; +} + +static __initdata struct of_device_id of_bus_ids[] = { + { .compatible = "simple-bus", }, + { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + printk(KERN_DEBUG "Probe platform devices\n"); + of_platform_bus_probe(NULL, of_bus_ids, NULL); + + return 0; +} +machine_arch_initcall(gef_sbc310, declare_of_platform_devices); + +define_machine(gef_sbc310) { + .name = "GE SBC310", + .probe = gef_sbc310_probe, + .setup_arch = gef_sbc310_setup_arch, + .init_IRQ = gef_sbc310_init_irq, + .show_cpuinfo = gef_sbc310_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .time_init = mpc86xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif +}; diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c new file mode 100644 index 00000000000..06c72636f29 --- /dev/null +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -0,0 +1,223 @@ +/* + * GE SBC610 board support + * + * Author: Martyn Welch <martyn.welch@ge.com> + * + * Copyright 2008 GE Intelligent Platforms Embedded Systems, 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. + * + * Based on: mpc86xx_hpcn.c (MPC86xx HPCN board specific routines) + * Copyright 2006 Freescale Semiconductor Inc. + * + * NEC fixup adapted from arch/mips/pci/fixup-lm2e.c + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/of_platform.h> + +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/prom.h> +#include <mm/mmu_decl.h> +#include <asm/udbg.h> + +#include <asm/mpic.h> +#include <asm/nvram.h> + +#include <sysdev/fsl_pci.h> +#include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h> + +#include "mpc86xx.h" + +#undef DEBUG + +#ifdef DEBUG +#define DBG (fmt...) do { printk(KERN_ERR "SBC610: " fmt); } while (0) +#else +#define DBG (fmt...) do { } while (0) +#endif + +void __iomem *sbc610_regs; + +static void __init gef_sbc610_init_irq(void) +{ + struct device_node *cascade_node = NULL; + + mpc86xx_init_irq(); + + /* + * There is a simple interrupt handler in the main FPGA, this needs + * to be cascaded into the MPIC + */ + cascade_node = of_find_compatible_node(NULL, NULL, "gef,fpga-pic"); + if (!cascade_node) { + printk(KERN_WARNING "SBC610: No FPGA PIC\n"); + return; + } + + gef_pic_init(cascade_node); + of_node_put(cascade_node); +} + +static void __init gef_sbc610_setup_arch(void) +{ + struct device_node *regs; + + printk(KERN_INFO "GE Intelligent Platforms SBC610 6U VPX SBC\n"); + +#ifdef CONFIG_SMP + mpc86xx_smp_init(); +#endif + + fsl_pci_assign_primary(); + + /* Remap basic board registers */ + regs = of_find_compatible_node(NULL, NULL, "gef,fpga-regs"); + if (regs) { + sbc610_regs = of_iomap(regs, 0); + if (sbc610_regs == NULL) + printk(KERN_WARNING "Unable to map board registers\n"); + of_node_put(regs); + } + +#if defined(CONFIG_MMIO_NVRAM) + mmio_nvram_init(); +#endif +} + +/* Return the PCB revision */ +static unsigned int gef_sbc610_get_pcb_rev(void) +{ + unsigned int reg; + + reg = ioread32(sbc610_regs); + return (reg >> 8) & 0xff; +} + +/* Return the board (software) revision */ +static unsigned int gef_sbc610_get_board_rev(void) +{ + unsigned int reg; + + reg = ioread32(sbc610_regs); + return (reg >> 16) & 0xff; +} + +/* Return the FPGA revision */ +static unsigned int gef_sbc610_get_fpga_rev(void) +{ + unsigned int reg; + + reg = ioread32(sbc610_regs); + return (reg >> 24) & 0xf; +} + +static void gef_sbc610_show_cpuinfo(struct seq_file *m) +{ + uint svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n"); + + seq_printf(m, "Revision\t: %u%c\n", gef_sbc610_get_pcb_rev(), + ('A' + gef_sbc610_get_board_rev() - 1)); + seq_printf(m, "FPGA Revision\t: %u\n", gef_sbc610_get_fpga_rev()); + + seq_printf(m, "SVR\t\t: 0x%x\n", svid); +} + +static void gef_sbc610_nec_fixup(struct pci_dev *pdev) +{ + unsigned int val; + + /* Do not do the fixup on other platforms! */ + if (!machine_is(gef_sbc610)) + return; + + printk(KERN_INFO "Running NEC uPD720101 Fixup\n"); + + /* Ensure ports 1, 2, 3, 4 & 5 are enabled */ + pci_read_config_dword(pdev, 0xe0, &val); + pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x5); + + /* System clock is 48-MHz Oscillator and EHCI Enabled. */ + pci_write_config_dword(pdev, 0xe4, 1 << 5); +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, + gef_sbc610_nec_fixup); + +/* + * Called very early, device-tree isn't unflattened + * + * This function is called to determine whether the BSP is compatible with the + * supplied device-tree, which is assumed to be the correct one for the actual + * board. It is expected thati, in the future, a kernel may support multiple + * boards. + */ +static int __init gef_sbc610_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "gef,sbc610")) + return 1; + + return 0; +} + +static long __init mpc86xx_time_init(void) +{ + unsigned int temp; + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + temp = mfspr(SPRN_HID0); + temp |= HID0_TBEN; + mtspr(SPRN_HID0, temp); + asm volatile("isync"); + + return 0; +} + +static __initdata struct of_device_id of_bus_ids[] = { + { .compatible = "simple-bus", }, + { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + printk(KERN_DEBUG "Probe platform devices\n"); + of_platform_bus_probe(NULL, of_bus_ids, NULL); + + return 0; +} +machine_arch_initcall(gef_sbc610, declare_of_platform_devices); + +define_machine(gef_sbc610) { + .name = "GE SBC610", + .probe = gef_sbc610_probe, + .setup_arch = gef_sbc610_setup_arch, + .init_IRQ = gef_sbc610_init_irq, + .show_cpuinfo = gef_sbc610_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .time_init = mpc86xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif +}; diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c new file mode 100644 index 00000000000..d479d68fbb2 --- /dev/null +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -0,0 +1,359 @@ +/* + * MPC8610 HPCD board specific routines + * + * Initial author: Xianghua Xiao <x.xiao@freescale.com> + * Recode: Jason Jin <jason.jin@freescale.com> + * York Sun <yorksun@freescale.com> + * + * Rewrite the interrupt routing. remove the 8259PIC support, + * All the integrated device in ULI use sideband interrupt. + * + * Copyright 2008 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/of.h> + +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/prom.h> +#include <mm/mmu_decl.h> +#include <asm/udbg.h> + +#include <asm/mpic.h> + +#include <linux/of_platform.h> +#include <sysdev/fsl_pci.h> +#include <sysdev/fsl_soc.h> +#include <sysdev/simple_gpio.h> +#include <asm/fsl_guts.h> + +#include "mpc86xx.h" + +static struct device_node *pixis_node; +static unsigned char *pixis_bdcfg0, *pixis_arch; + +/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */ +#define CLKDVDR_PXCKEN 0x80000000 +#define CLKDVDR_PXCKINV 0x10000000 +#define CLKDVDR_PXCKDLY 0x06000000 +#define CLKDVDR_PXCLK_MASK 0x001F0000 + +#ifdef CONFIG_SUSPEND +static irqreturn_t mpc8610_sw9_irq(int irq, void *data) +{ + pr_debug("%s: PIXIS' event (sw9/wakeup) IRQ handled\n", __func__); + return IRQ_HANDLED; +} + +static void __init mpc8610_suspend_init(void) +{ + int irq; + int ret; + + if (!pixis_node) + return; + + irq = irq_of_parse_and_map(pixis_node, 0); + if (!irq) { + pr_err("%s: can't map pixis event IRQ.\n", __func__); + return; + } + + ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9:wakeup", NULL); + if (ret) { + pr_err("%s: can't request pixis event IRQ: %d\n", + __func__, ret); + irq_dispose_mapping(irq); + } + + enable_irq_wake(irq); +} +#else +static inline void mpc8610_suspend_init(void) { } +#endif /* CONFIG_SUSPEND */ + +static struct of_device_id __initdata mpc8610_ids[] = { + { .compatible = "fsl,mpc8610-immr", }, + { .compatible = "fsl,mpc8610-guts", }, + { .compatible = "simple-bus", }, + /* So that the DMA channel nodes can be probed individually: */ + { .compatible = "fsl,eloplus-dma", }, + /* PCI controllers */ + { .compatible = "fsl,mpc8610-pci", }, + { .compatible = "fsl,mpc8641-pcie", }, + {} +}; + +static int __init mpc8610_declare_of_platform_devices(void) +{ + /* Firstly, register PIXIS GPIOs. */ + simple_gpiochip_init("fsl,fpga-pixis-gpio-bank"); + + /* Enable wakeup on PIXIS' event IRQ. */ + mpc8610_suspend_init(); + + /* Without this call, the SSI device driver won't get probed. */ + of_platform_bus_probe(NULL, mpc8610_ids, NULL); + + return 0; +} +machine_arch_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); + +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + +/* + * DIU Area Descriptor + * + * The MPC8610 reference manual shows the bits of the AD register in + * little-endian order, which causes the BLUE_C field to be split into two + * parts. To simplify the definition of the MAKE_AD() macro, we define the + * fields in big-endian order and byte-swap the result. + * + * So even though the registers don't look like they're in the + * same bit positions as they are on the P1022, the same value is written to + * the AD register on the MPC8610 and on the P1022. + */ +#define AD_BYTE_F 0x10000000 +#define AD_ALPHA_C_MASK 0x0E000000 +#define AD_ALPHA_C_SHIFT 25 +#define AD_BLUE_C_MASK 0x01800000 +#define AD_BLUE_C_SHIFT 23 +#define AD_GREEN_C_MASK 0x00600000 +#define AD_GREEN_C_SHIFT 21 +#define AD_RED_C_MASK 0x00180000 +#define AD_RED_C_SHIFT 19 +#define AD_PALETTE 0x00040000 +#define AD_PIXEL_S_MASK 0x00030000 +#define AD_PIXEL_S_SHIFT 16 +#define AD_COMP_3_MASK 0x0000F000 +#define AD_COMP_3_SHIFT 12 +#define AD_COMP_2_MASK 0x00000F00 +#define AD_COMP_2_SHIFT 8 +#define AD_COMP_1_MASK 0x000000F0 +#define AD_COMP_1_SHIFT 4 +#define AD_COMP_0_MASK 0x0000000F +#define AD_COMP_0_SHIFT 0 + +#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \ + cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \ + (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \ + (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \ + (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ + (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) + +u32 mpc8610hpcd_get_pixel_format(enum fsl_diu_monitor_port port, + unsigned int bits_per_pixel) +{ + static const u32 pixelformat[][3] = { + { + MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8), + MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0), + MAKE_AD(4, 0, 2, 1, 1, 5, 6, 5, 0) + }, + { + MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8), + MAKE_AD(4, 0, 2, 1, 2, 8, 8, 8, 0), + MAKE_AD(4, 2, 0, 1, 1, 5, 6, 5, 0) + }, + }; + unsigned int arch_monitor; + + /* The DVI port is mis-wired on revision 1 of this board. */ + arch_monitor = + ((*pixis_arch == 0x01) && (port == FSL_DIU_PORT_DVI)) ? 0 : 1; + + switch (bits_per_pixel) { + case 32: + return pixelformat[arch_monitor][0]; + case 24: + return pixelformat[arch_monitor][1]; + case 16: + return pixelformat[arch_monitor][2]; + default: + pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel); + return 0; + } +} + +void mpc8610hpcd_set_gamma_table(enum fsl_diu_monitor_port port, + char *gamma_table_base) +{ + int i; + if (port == FSL_DIU_PORT_DLVDS) { + for (i = 0; i < 256*3; i++) + gamma_table_base[i] = (gamma_table_base[i] << 2) | + ((gamma_table_base[i] >> 6) & 0x03); + } +} + +#define PX_BRDCFG0_DVISEL (1 << 3) +#define PX_BRDCFG0_DLINK (1 << 4) +#define PX_BRDCFG0_DIU_MASK (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK) + +void mpc8610hpcd_set_monitor_port(enum fsl_diu_monitor_port port) +{ + switch (port) { + case FSL_DIU_PORT_DVI: + clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK, + PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK); + break; + case FSL_DIU_PORT_LVDS: + clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK, + PX_BRDCFG0_DLINK); + break; + case FSL_DIU_PORT_DLVDS: + clrbits8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK); + break; + } +} + +/** + * mpc8610hpcd_set_pixel_clock: program the DIU's clock + * + * @pixclock: the wavelength, in picoseconds, of the clock + */ +void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) +{ + struct device_node *guts_np = NULL; + struct ccsr_guts __iomem *guts; + unsigned long freq; + u64 temp; + u32 pxclk; + + /* Map the global utilities registers. */ + guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); + if (!guts_np) { + pr_err("mpc8610hpcd: missing global utilities device node\n"); + return; + } + + guts = of_iomap(guts_np, 0); + of_node_put(guts_np); + if (!guts) { + pr_err("mpc8610hpcd: could not map global utilities device\n"); + return; + } + + /* Convert pixclock from a wavelength to a frequency */ + temp = 1000000000000ULL; + do_div(temp, pixclock); + freq = temp; + + /* + * 'pxclk' is the ratio of the platform clock to the pixel clock. + * On the MPC8610, the value programmed into CLKDVDR is the ratio + * minus one. The valid range of values is 2-31. + */ + pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq) - 1; + pxclk = clamp_t(u32, pxclk, 2, 31); + + /* Disable the pixel clock, and set it to non-inverted and no delay */ + clrbits32(&guts->clkdvdr, + CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK); + + /* Enable the clock and set the pxclk */ + setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16)); + + iounmap(guts); +} + +enum fsl_diu_monitor_port +mpc8610hpcd_valid_monitor_port(enum fsl_diu_monitor_port port) +{ + return port; +} + +#endif + +static void __init mpc86xx_hpcd_setup_arch(void) +{ + struct resource r; + unsigned char *pixis; + + if (ppc_md.progress) + ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0); + + fsl_pci_assign_primary(); + +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format; + diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table; + diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port; + diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock; + diu_ops.valid_monitor_port = mpc8610hpcd_valid_monitor_port; +#endif + + pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis"); + if (pixis_node) { + of_address_to_resource(pixis_node, 0, &r); + of_node_put(pixis_node); + pixis = ioremap(r.start, 32); + if (!pixis) { + printk(KERN_ERR "Err: can't map FPGA cfg register!\n"); + return; + } + pixis_bdcfg0 = pixis + 8; + pixis_arch = pixis + 1; + } else + printk(KERN_ERR "Err: " + "can't find device node 'fsl,fpga-pixis'\n"); + + printk("MPC86xx HPCD board from Freescale Semiconductor\n"); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc86xx_hpcd_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "fsl,MPC8610HPCD")) + return 1; /* Looks good */ + + return 0; +} + +static long __init mpc86xx_time_init(void) +{ + unsigned int temp; + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + temp = mfspr(SPRN_HID0); + temp |= HID0_TBEN; + mtspr(SPRN_HID0, temp); + asm volatile("isync"); + + return 0; +} + +define_machine(mpc86xx_hpcd) { + .name = "MPC86xx HPCD", + .probe = mpc86xx_hpcd_probe, + .setup_arch = mpc86xx_hpcd_setup_arch, + .init_IRQ = mpc86xx_init_irq, + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .time_init = mpc86xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif +}; diff --git a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h deleted file mode 100644 index 41e554c4af9..00000000000 --- a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * MPC8641 HPCN board definitions - * - * Copyright 2006 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Author: Xianghua Xiao <x.xiao@freescale.com> - */ - -#ifndef __MPC8641_HPCN_H__ -#define __MPC8641_HPCN_H__ - -#include <linux/init.h> - -#define MPC86XX_RSTCR_OFFSET (0xe00b0) /* Reset Control Register */ - -#endif /* __MPC8641_HPCN_H__ */ diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h index 2834462590b..08efb57559d 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx.h +++ b/arch/powerpc/platforms/86xx/mpc86xx.h @@ -15,16 +15,7 @@ * mpc86xx_* files. Mostly for use by mpc86xx_setup(). */ -extern int add_bridge(struct device_node *dev); - -extern int mpc86xx_exclude_device(u_char bus, u_char devfn); - -extern void setup_indirect_pcie(struct pci_controller *hose, - u32 cfg_addr, u32 cfg_data); -extern void setup_indirect_pcie_nomap(struct pci_controller *hose, - void __iomem *cfg_addr, - void __iomem *cfg_data); - -extern void __init mpc86xx_smp_init(void); +extern void mpc86xx_smp_init(void); +extern void mpc86xx_init_irq(void); #endif /* __MPC86XX_H__ */ diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 1051702c8d4..e8bf3fae560 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -18,23 +18,22 @@ #include <linux/kdev_t.h> #include <linux/delay.h> #include <linux/seq_file.h> +#include <linux/of_platform.h> -#include <asm/system.h> #include <asm/time.h> #include <asm/machdep.h> #include <asm/pci-bridge.h> -#include <asm/mpc86xx.h> #include <asm/prom.h> #include <mm/mmu_decl.h> #include <asm/udbg.h> -#include <asm/i8259.h> +#include <asm/swiotlb.h> #include <asm/mpic.h> +#include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> #include "mpc86xx.h" -#include "mpc8641_hpcn.h" #undef DEBUG @@ -44,328 +43,28 @@ #define DBG(fmt...) do { } while(0) #endif -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -unsigned long pci_dram_offset = 0; -#endif - - #ifdef CONFIG_PCI -static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) -{ - unsigned int cascade_irq = i8259_irq(); - if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq); - desc->chip->eoi(irq); -} -#endif /* CONFIG_PCI */ +extern int uli_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn); -void __init -mpc86xx_hpcn_init_irq(void) +static int mpc86xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { - struct mpic *mpic1; - struct device_node *np; - struct resource res; -#ifdef CONFIG_PCI - struct device_node *cascade_node = NULL; - int cascade_irq; -#endif - - /* Determine PIC address. */ - np = of_find_node_by_type(NULL, "open-pic"); - if (np == NULL) - return; - of_address_to_resource(np, 0, &res); - - /* Alloc mpic structure and per isu has 16 INT entries. */ - mpic1 = mpic_alloc(np, res.start, - MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 16, NR_IRQS - 4, - " MPIC "); - BUG_ON(mpic1 == NULL); - - mpic_assign_isu(mpic1, 0, res.start + 0x10000); - - /* 48 Internal Interrupts */ - mpic_assign_isu(mpic1, 1, res.start + 0x10200); - mpic_assign_isu(mpic1, 2, res.start + 0x10400); - mpic_assign_isu(mpic1, 3, res.start + 0x10600); - - /* 16 External interrupts - * Moving them from [0 - 15] to [64 - 79] - */ - mpic_assign_isu(mpic1, 4, res.start + 0x10000); - - mpic_init(mpic1); - -#ifdef CONFIG_PCI - /* Initialize i8259 controller */ - for_each_node_by_type(np, "interrupt-controller") - if (of_device_is_compatible(np, "chrp,iic")) { - cascade_node = np; - break; - } - if (cascade_node == NULL) { - printk(KERN_DEBUG "mpc86xxhpcn: no ISA interrupt controller\n"); - return; - } - - cascade_irq = irq_of_parse_and_map(cascade_node, 0); - if (cascade_irq == NO_IRQ) { - printk(KERN_ERR "mpc86xxhpcn: failed to map cascade interrupt"); - return; - } - DBG("mpc86xxhpcn: cascade mapped to irq %d\n", cascade_irq); - - i8259_init(cascade_node, 0); - of_node_put(cascade_node); + if (hose->dn == fsl_pci_primary) + return uli_exclude_device(hose, bus, devfn); - set_irq_chained_handler(cascade_irq, mpc86xx_8259_cascade); -#endif -} - -#ifdef CONFIG_PCI - -enum pirq{PIRQA = 8, PIRQB, PIRQC, PIRQD, PIRQE, PIRQF, PIRQG, PIRQH}; -const unsigned char uli1575_irq_route_table[16] = { - 0, /* 0: Reserved */ - 0x8, /* 1: 0b1000 */ - 0, /* 2: Reserved */ - 0x2, /* 3: 0b0010 */ - 0x4, /* 4: 0b0100 */ - 0x5, /* 5: 0b0101 */ - 0x7, /* 6: 0b0111 */ - 0x6, /* 7: 0b0110 */ - 0, /* 8: Reserved */ - 0x1, /* 9: 0b0001 */ - 0x3, /* 10: 0b0011 */ - 0x9, /* 11: 0b1001 */ - 0xb, /* 12: 0b1011 */ - 0, /* 13: Reserved */ - 0xd, /* 14, 0b1101 */ - 0xf, /* 15, 0b1111 */ -}; - -static int __devinit -get_pci_irq_from_of(struct pci_controller *hose, int slot, int pin) -{ - struct of_irq oirq; - u32 laddr[3]; - struct device_node *hosenode = hose ? hose->arch_data : NULL; - - if (!hosenode) return -EINVAL; - - laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(slot, 0) << 8); - laddr[1] = laddr[2] = 0; - of_irq_map_raw(hosenode, &pin, 1, laddr, &oirq); - DBG("mpc86xx_hpcn: pci irq addr %x, slot %d, pin %d, irq %d\n", - laddr[0], slot, pin, oirq.specifier[0]); - return oirq.specifier[0]; -} - -static void __devinit quirk_uli1575(struct pci_dev *dev) -{ - unsigned short temp; - struct pci_controller *hose = pci_bus_to_host(dev->bus); - unsigned char irq2pin[16], c; - unsigned long pirq_map_word = 0; - u32 irq; - int i; - - /* - * ULI1575 interrupts route setup - */ - memset(irq2pin, 0, 16); /* Initialize default value 0 */ - - /* - * PIRQA -> PIRQD mapping read from OF-tree - * - * interrupts for PCI slot0 -- PIRQA / PIRQB / PIRQC / PIRQD - * PCI slot1 -- PIRQB / PIRQC / PIRQD / PIRQA - */ - for (i = 0; i < 4; i++){ - irq = get_pci_irq_from_of(hose, 17, i + 1); - if (irq > 0 && irq < 16) - irq2pin[irq] = PIRQA + i; - else - printk(KERN_WARNING "ULI1575 device" - "(slot %d, pin %d) irq %d is invalid.\n", - 17, i, irq); - } - - /* - * PIRQE -> PIRQF mapping set manually - * - * IRQ pin IRQ# - * PIRQE ---- 9 - * PIRQF ---- 10 - * PIRQG ---- 11 - * PIRQH ---- 12 - */ - for (i = 0; i < 4; i++) irq2pin[i + 9] = PIRQE + i; - - /* Set IRQ-PIRQ Mapping to ULI1575 */ - for (i = 0; i < 16; i++) - if (irq2pin[i]) - pirq_map_word |= (uli1575_irq_route_table[i] & 0xf) - << ((irq2pin[i] - PIRQA) * 4); - - /* ULI1575 IRQ mapping conf register default value is 0xb9317542 */ - DBG("Setup ULI1575 IRQ mapping configuration register value = 0x%x\n", - pirq_map_word); - pci_write_config_dword(dev, 0x48, pirq_map_word); - -#define ULI1575_SET_DEV_IRQ(slot, pin, reg) \ - do { \ - int irq; \ - irq = get_pci_irq_from_of(hose, slot, pin); \ - if (irq > 0 && irq < 16) \ - pci_write_config_byte(dev, reg, irq2pin[irq]); \ - else \ - printk(KERN_WARNING "ULI1575 device" \ - "(slot %d, pin %d) irq %d is invalid.\n", \ - slot, pin, irq); \ - } while(0) - - /* USB 1.1 OHCI controller 1, slot 28, pin 1 */ - ULI1575_SET_DEV_IRQ(28, 1, 0x86); - - /* USB 1.1 OHCI controller 2, slot 28, pin 2 */ - ULI1575_SET_DEV_IRQ(28, 2, 0x87); - - /* USB 1.1 OHCI controller 3, slot 28, pin 3 */ - ULI1575_SET_DEV_IRQ(28, 3, 0x88); - - /* USB 2.0 controller, slot 28, pin 4 */ - irq = get_pci_irq_from_of(hose, 28, 4); - if (irq >= 0 && irq <=15) - pci_write_config_dword(dev, 0x74, uli1575_irq_route_table[irq]); - - /* Audio controller, slot 29, pin 1 */ - ULI1575_SET_DEV_IRQ(29, 1, 0x8a); - - /* Modem controller, slot 29, pin 2 */ - ULI1575_SET_DEV_IRQ(29, 2, 0x8b); - - /* HD audio controller, slot 29, pin 3 */ - ULI1575_SET_DEV_IRQ(29, 3, 0x8c); - - /* SMB interrupt: slot 30, pin 1 */ - ULI1575_SET_DEV_IRQ(30, 1, 0x8e); - - /* PMU ACPI SCI interrupt: slot 30, pin 2 */ - ULI1575_SET_DEV_IRQ(30, 2, 0x8f); - - /* Serial ATA interrupt: slot 31, pin 1 */ - ULI1575_SET_DEV_IRQ(31, 1, 0x8d); - - /* Primary PATA IDE IRQ: 14 - * Secondary PATA IDE IRQ: 15 - */ - pci_write_config_byte(dev, 0x44, 0x30 | uli1575_irq_route_table[14]); - pci_write_config_byte(dev, 0x75, uli1575_irq_route_table[15]); - - /* Set IRQ14 and IRQ15 to legacy IRQs */ - pci_read_config_word(dev, 0x46, &temp); - temp |= 0xc000; - pci_write_config_word(dev, 0x46, temp); - - /* Set i8259 interrupt trigger - * IRQ 3: Level - * IRQ 4: Level - * IRQ 5: Level - * IRQ 6: Level - * IRQ 7: Level - * IRQ 9: Level - * IRQ 10: Level - * IRQ 11: Level - * IRQ 12: Level - * IRQ 14: Edge - * IRQ 15: Edge - */ - outb(0xfa, 0x4d0); - outb(0x1e, 0x4d1); - -#undef ULI1575_SET_DEV_IRQ - - /* Disable the HD interface and enable the AC97 interface. */ - pci_read_config_byte(dev, 0xb8, &c); - c &= 0x7f; - pci_write_config_byte(dev, 0xb8, c); + return PCIBIOS_SUCCESSFUL; } - -static void __devinit quirk_uli5288(struct pci_dev *dev) -{ - unsigned char c; - - pci_read_config_byte(dev,0x83,&c); - c |= 0x80; - pci_write_config_byte(dev, 0x83, c); - - pci_write_config_byte(dev, 0x09, 0x01); - pci_write_config_byte(dev, 0x0a, 0x06); - - pci_read_config_byte(dev,0x83,&c); - c &= 0x7f; - pci_write_config_byte(dev, 0x83, c); - - pci_read_config_byte(dev,0x84,&c); - c |= 0x01; - pci_write_config_byte(dev, 0x84, c); -} - -static void __devinit quirk_uli5229(struct pci_dev *dev) -{ - unsigned short temp; - pci_write_config_word(dev, 0x04, 0x0405); - pci_read_config_word(dev, 0x4a, &temp); - temp |= 0x1000; - pci_write_config_word(dev, 0x4a, temp); -} - -static void __devinit early_uli5249(struct pci_dev *dev) -{ - unsigned char temp; - pci_write_config_word(dev, 0x04, 0x0007); - pci_read_config_byte(dev, 0x7c, &temp); - pci_write_config_byte(dev, 0x7c, 0x80); - pci_write_config_byte(dev, 0x09, 0x01); - pci_write_config_byte(dev, 0x7c, temp); - dev->class |= 0x1; -} - -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_uli1575); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, quirk_uli5288); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, 0x5249, early_uli5249); #endif /* CONFIG_PCI */ static void __init mpc86xx_hpcn_setup_arch(void) { - struct device_node *np; - if (ppc_md.progress) ppc_md.progress("mpc86xx_hpcn_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np != 0) { - const unsigned int *fp; - - fp = of_get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } - #ifdef CONFIG_PCI - for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); - ppc_md.pci_exclude_device = mpc86xx_exclude_device; #endif @@ -374,27 +73,21 @@ mpc86xx_hpcn_setup_arch(void) #ifdef CONFIG_SMP mpc86xx_smp_init(); #endif + + fsl_pci_assign_primary(); + + swiotlb_detect_4g(); } -void +static void mpc86xx_hpcn_show_cpuinfo(struct seq_file *m) { - struct device_node *root; - uint memsize = total_memory; - const char *model = ""; uint svid = mfspr(SPRN_SVR); seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - root = of_find_node_by_path("/"); - if (root) - model = of_get_property(root, "model", NULL); - seq_printf(m, "Machine\t\t: %s\n", model); - of_node_put(root); - seq_printf(m, "SVR\t\t: 0x%x\n", svid); - seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); } @@ -405,30 +98,19 @@ static int __init mpc86xx_hpcn_probe(void) { unsigned long root = of_get_flat_dt_root(); - if (of_flat_dt_is_compatible(root, "mpc86xx")) + if (of_flat_dt_is_compatible(root, "fsl,mpc8641hpcn")) return 1; /* Looks good */ - return 0; -} - - -void -mpc86xx_restart(char *cmd) -{ - void __iomem *rstcr; - - rstcr = ioremap(get_immrbase() + MPC86XX_RSTCR_OFFSET, 0x100); - - local_irq_disable(); - - /* Assert reset request to Reset Control Register */ - out_be32(rstcr, 0x2); + /* Be nice and don't give silent boot death. Delete this in 2.6.27 */ + if (of_flat_dt_is_compatible(root, "mpc86xx")) { + pr_warning("WARNING: your dts/dtb is old. You must update before the next kernel release\n"); + return 1; + } - /* not reached */ + return 0; } - -long __init +static long __init mpc86xx_time_init(void) { unsigned int temp; @@ -445,16 +127,35 @@ mpc86xx_time_init(void) return 0; } +static __initdata struct of_device_id of_bus_ids[] = { + { .compatible = "simple-bus", }, + { .compatible = "fsl,srio", }, + { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + + return 0; +} +machine_arch_initcall(mpc86xx_hpcn, declare_of_platform_devices); +machine_arch_initcall(mpc86xx_hpcn, swiotlb_setup_bus_notifier); define_machine(mpc86xx_hpcn) { .name = "MPC86xx HPCN", .probe = mpc86xx_hpcn_probe, .setup_arch = mpc86xx_hpcn_setup_arch, - .init_IRQ = mpc86xx_hpcn_init_irq, + .init_IRQ = mpc86xx_init_irq, .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo, .get_irq = mpic_get_irq, - .restart = mpc86xx_restart, + .restart = fsl_rstcr_restart, .time_init = mpc86xx_time_init, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif }; diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c index ba55b0ff0f7..af09baee22c 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c @@ -15,11 +15,11 @@ #include <linux/init.h> #include <linux/delay.h> +#include <asm/code-patching.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/pci-bridge.h> -#include <asm-powerpc/mpic.h> -#include <asm/mpc86xx.h> +#include <asm/mpic.h> #include <asm/cacheflush.h> #include <sysdev/fsl_soc.h> @@ -27,8 +27,12 @@ #include "mpc86xx.h" extern void __secondary_start_mpc86xx(void); -extern unsigned long __secondary_hold_acknowledge; +#define MCM_PORT_CONFIG_OFFSET 0x10 + +/* Offset from CCSRBAR */ +#define MPC86xx_MCM_OFFSET (0x1000) +#define MPC86xx_MCM_SIZE (0x1000) static void __init smp_86xx_release_core(int nr) @@ -47,20 +51,21 @@ smp_86xx_release_core(int nr) pcr = in_be32(mcm_vaddr + (MCM_PORT_CONFIG_OFFSET >> 2)); pcr |= 1 << (nr + 24); out_be32(mcm_vaddr + (MCM_PORT_CONFIG_OFFSET >> 2), pcr); + + iounmap(mcm_vaddr); } -static void __init +static int __init smp_86xx_kick_cpu(int nr) { unsigned int save_vector; unsigned long target, flags; int n = 0; - volatile unsigned int *vector - = (volatile unsigned int *)(KERNELBASE + 0x100); + unsigned int *vector = (unsigned int *)(KERNELBASE + 0x100); if (nr < 0 || nr >= NR_CPUS) - return; + return -ENOENT; pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); @@ -71,7 +76,7 @@ smp_86xx_kick_cpu(int nr) /* Setup fake reset vector to call __secondary_start_mpc86xx. */ target = (unsigned long) __secondary_start_mpc86xx; - create_branch((unsigned long)vector, target, BRANCH_SET_LINK); + patch_branch(vector, target, BRANCH_SET_LINK); /* Kick that CPU */ smp_86xx_release_core(nr); @@ -87,6 +92,8 @@ smp_86xx_kick_cpu(int nr) local_irq_restore(flags); pr_debug("wait CPU #%d for %d msecs.\n", nr, n); + + return 0; } diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c deleted file mode 100644 index 8235c562661..00000000000 --- a/arch/powerpc/platforms/86xx/pci.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * MPC86XX pci setup code - * - * Recode: ZHANG WEI <wei.zhang@freescale.com> - * Initial author: Xianghua Xiao <x.xiao@freescale.com> - * - * Copyright 2006 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/serial.h> - -#include <asm/system.h> -#include <asm/atomic.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <sysdev/fsl_soc.h> -#include <sysdev/fsl_pcie.h> - -#include "mpc86xx.h" - -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) -#else -#define DBG(fmt, args...) -#endif - -struct pcie_outbound_window_regs { - uint pexotar; /* 0x.0 - PCI Express outbound translation address register */ - uint pexotear; /* 0x.4 - PCI Express outbound translation extended address register */ - uint pexowbar; /* 0x.8 - PCI Express outbound window base address register */ - char res1[4]; - uint pexowar; /* 0x.10 - PCI Express outbound window attributes register */ - char res2[12]; -}; - -struct pcie_inbound_window_regs { - uint pexitar; /* 0x.0 - PCI Express inbound translation address register */ - char res1[4]; - uint pexiwbar; /* 0x.8 - PCI Express inbound window base address register */ - uint pexiwbear; /* 0x.c - PCI Express inbound window base extended address register */ - uint pexiwar; /* 0x.10 - PCI Express inbound window attributes register */ - char res2[12]; -}; - -static void __init setup_pcie_atmu(struct pci_controller *hose, struct resource *rsrc) -{ - volatile struct ccsr_pex *pcie; - volatile struct pcie_outbound_window_regs *pcieow; - volatile struct pcie_inbound_window_regs *pcieiw; - int i = 0; - - DBG("PCIE memory map start 0x%x, size 0x%x\n", rsrc->start, - rsrc->end - rsrc->start + 1); - pcie = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); - - /* Disable all windows (except pexowar0 since its ignored) */ - pcie->pexowar1 = 0; - pcie->pexowar2 = 0; - pcie->pexowar3 = 0; - pcie->pexowar4 = 0; - pcie->pexiwar1 = 0; - pcie->pexiwar2 = 0; - pcie->pexiwar3 = 0; - - pcieow = (struct pcie_outbound_window_regs *)&pcie->pexotar1; - pcieiw = (struct pcie_inbound_window_regs *)&pcie->pexitar1; - - /* Setup outbound MEM window */ - for(i = 0; i < 3; i++) - if (hose->mem_resources[i].flags & IORESOURCE_MEM){ - DBG("PCIE MEM resource start 0x%08x, size 0x%08x.\n", - hose->mem_resources[i].start, - hose->mem_resources[i].end - - hose->mem_resources[i].start + 1); - pcieow->pexotar = (hose->mem_resources[i].start) >> 12 - & 0x000fffff; - pcieow->pexotear = 0; - pcieow->pexowbar = (hose->mem_resources[i].start) >> 12 - & 0x000fffff; - /* Enable, Mem R/W */ - pcieow->pexowar = 0x80044000 | - (__ilog2(hose->mem_resources[i].end - - hose->mem_resources[i].start + 1) - - 1); - pcieow++; - } - - /* Setup outbound IO window */ - if (hose->io_resource.flags & IORESOURCE_IO){ - DBG("PCIE IO resource start 0x%08x, size 0x%08x, phy base 0x%08x.\n", - hose->io_resource.start, - hose->io_resource.end - hose->io_resource.start + 1, - hose->io_base_phys); - pcieow->pexotar = (hose->io_resource.start) >> 12 & 0x000fffff; - pcieow->pexotear = 0; - pcieow->pexowbar = (hose->io_base_phys) >> 12 & 0x000fffff; - /* Enable, IO R/W */ - pcieow->pexowar = 0x80088000 | (__ilog2(hose->io_resource.end - - hose->io_resource.start + 1) - 1); - } - - /* Setup 2G inbound Memory Window @ 0 */ - pcieiw->pexitar = 0x00000000; - pcieiw->pexiwbar = 0x00000000; - /* Enable, Prefetch, Local Mem, Snoop R/W, 2G */ - pcieiw->pexiwar = 0xa0f5501e; -} - -static void __init -mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) -{ - u16 cmd; - unsigned int temps; - - DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n", - pcie_offset, pcie_size); - - early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY - | PCI_COMMAND_IO; - early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd); - - early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); - - /* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */ - early_read_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, &temps); - temps = (temps & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16); - early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps); -} - -int mpc86xx_exclude_device(u_char bus, u_char devfn) -{ - if (bus == 0 && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; - - return PCIBIOS_SUCCESSFUL; -} - -int __init add_bridge(struct device_node *dev) -{ - int len; - struct pci_controller *hose; - struct resource rsrc; - const int *bus_range; - int has_address = 0; - int primary = 0; - - DBG("Adding PCIE host bridge %s\n", dev->full_name); - - /* Fetch host bridge registers address */ - has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); - - /* Get bus range if any */ - bus_range = of_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->set_cfg_type = 1; - - /* last_busno = 0xfe cause by MPC8641 PCIE bug */ - hose->first_busno = bus_range ? bus_range[0] : 0x0; - hose->last_busno = bus_range ? bus_range[1] : 0xfe; - - setup_indirect_pcie(hose, rsrc.start, rsrc.start + 0x4); - - /* Setup the PCIE host controller. */ - mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1); - - if ((rsrc.start & 0xfffff) == 0x8000) - primary = 1; - - printk(KERN_INFO "Found MPC86xx PCIE host bridge at 0x%08lx. " - "Firmware bus number: %d->%d\n", - (unsigned long) rsrc.start, - 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); - - /* Setup PEX window registers */ - setup_pcie_atmu(hose, &rsrc); - - return 0; -} diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c new file mode 100644 index 00000000000..d5b98c0f958 --- /dev/null +++ b/arch/powerpc/platforms/86xx/pic.c @@ -0,0 +1,71 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> + +#include <asm/mpic.h> +#include <asm/i8259.h> + +#ifdef CONFIG_PPC_I8259 +static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int cascade_irq = i8259_irq(); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); + + chip->irq_eoi(&desc->irq_data); +} +#endif /* CONFIG_PPC_I8259 */ + +void __init mpc86xx_init_irq(void) +{ +#ifdef CONFIG_PPC_I8259 + struct device_node *np; + struct device_node *cascade_node = NULL; + int cascade_irq; +#endif + + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, + 0, 256, " MPIC "); + BUG_ON(mpic == NULL); + + mpic_init(mpic); + +#ifdef CONFIG_PPC_I8259 + /* Initialize i8259 controller */ + for_each_node_by_type(np, "interrupt-controller") + if (of_device_is_compatible(np, "chrp,iic")) { + cascade_node = np; + break; + } + + if (cascade_node == NULL) { + printk(KERN_DEBUG "Could not find i8259 PIC\n"); + return; + } + + cascade_irq = irq_of_parse_and_map(cascade_node, 0); + if (cascade_irq == NO_IRQ) { + printk(KERN_ERR "Failed to map cascade interrupt\n"); + return; + } + + i8259_init(cascade_node, 0); + of_node_put(cascade_node); + + irq_set_chained_handler(cascade_irq, mpc86xx_8259_cascade); +#endif +} diff --git a/arch/powerpc/platforms/86xx/sbc8641d.c b/arch/powerpc/platforms/86xx/sbc8641d.c new file mode 100644 index 00000000000..b47a8fd0f3d --- /dev/null +++ b/arch/powerpc/platforms/86xx/sbc8641d.c @@ -0,0 +1,124 @@ +/* + * SBC8641D board specific routines + * + * Copyright 2008 Wind River Systems Inc. + * + * By Paul Gortmaker (see MAINTAINERS for contact information) + * + * Based largely on the 8641 HPCN support by Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/of_platform.h> + +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <asm/prom.h> +#include <mm/mmu_decl.h> +#include <asm/udbg.h> + +#include <asm/mpic.h> + +#include <sysdev/fsl_pci.h> +#include <sysdev/fsl_soc.h> + +#include "mpc86xx.h" + +static void __init +sbc8641_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("sbc8641_setup_arch()", 0); + + printk("SBC8641 board from Wind River\n"); + +#ifdef CONFIG_SMP + mpc86xx_smp_init(); +#endif + + fsl_pci_assign_primary(); +} + + +static void +sbc8641_show_cpuinfo(struct seq_file *m) +{ + uint svid = mfspr(SPRN_SVR); + + seq_printf(m, "Vendor\t\t: Wind River Systems\n"); + + seq_printf(m, "SVR\t\t: 0x%x\n", svid); +} + + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init sbc8641_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "wind,sbc8641")) + return 1; /* Looks good */ + + return 0; +} + +static long __init +mpc86xx_time_init(void) +{ + unsigned int temp; + + /* Set the time base to zero */ + mtspr(SPRN_TBWL, 0); + mtspr(SPRN_TBWU, 0); + + temp = mfspr(SPRN_HID0); + temp |= HID0_TBEN; + mtspr(SPRN_HID0, temp); + asm volatile("isync"); + + return 0; +} + +static __initdata struct of_device_id of_bus_ids[] = { + { .compatible = "simple-bus", }, + { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, + {}, +}; + +static int __init declare_of_platform_devices(void) +{ + of_platform_bus_probe(NULL, of_bus_ids, NULL); + + return 0; +} +machine_arch_initcall(sbc8641, declare_of_platform_devices); + +define_machine(sbc8641) { + .name = "SBC8641D", + .probe = sbc8641_probe, + .setup_arch = sbc8641_setup_arch, + .init_IRQ = mpc86xx_init_irq, + .show_cpuinfo = sbc8641_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .time_init = mpc86xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif +}; |
