* [PATCH 5/9 v3] Add the MPC8641 HPCN platform files.
@ 2006-06-17 22:52 Jon Loeliger
2006-06-18 3:07 ` Benjamin Herrenschmidt
` (2 more replies)
0 siblings, 3 replies; 14+ messages in thread
From: Jon Loeliger @ 2006-06-17 22:52 UTC (permalink / raw)
To: linuxppc-dev
Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
Signed-off-by: Haiying Wang <Haiying.Wang@freescale.com>
Signed-off-by: Wei Zhang <Wei.Zhang@freescale.com>
Signed-off-by: Jon Loeliger <jdl@freescale.com>
---
arch/powerpc/platforms/86xx/mpc8641_hpcn.h | 54 +++++
arch/powerpc/platforms/86xx/mpc86xx.h | 28 ++
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 326 ++++++++++++++++++++++++++++
arch/powerpc/platforms/86xx/mpc86xx_smp.c | 117 ++++++++++
4 files changed, 525 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h
new file mode 100644
index 0000000..5042253
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h
@@ -0,0 +1,54 @@
+/*
+ * 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/config.h>
+#include <linux/init.h>
+
+/* PCI interrupt controller */
+#define PIRQA 3
+#define PIRQB 4
+#define PIRQC 5
+#define PIRQD 6
+#define PIRQ7 7
+#define PIRQE 9
+#define PIRQF 10
+#define PIRQG 11
+#define PIRQH 12
+
+/* PCI-Express memory map */
+#define MPC86XX_PCIE_LOWER_IO 0x00000000
+#define MPC86XX_PCIE_UPPER_IO 0x00ffffff
+
+#define MPC86XX_PCIE_LOWER_MEM 0x80000000
+#define MPC86XX_PCIE_UPPER_MEM 0x9fffffff
+
+#define MPC86XX_PCIE_IO_BASE 0xe2000000
+#define MPC86XX_PCIE_MEM_OFFSET 0x00000000
+
+#define MPC86XX_PCIE_IO_SIZE 0x01000000
+
+#define PCIE1_CFG_ADDR_OFFSET (0x8000)
+#define PCIE1_CFG_DATA_OFFSET (0x8004)
+
+#define PCIE2_CFG_ADDR_OFFSET (0x9000)
+#define PCIE2_CFG_DATA_OFFSET (0x9004)
+
+#define MPC86xx_PCIE_OFFSET PCIE1_CFG_ADDR_OFFSET
+#define MPC86xx_PCIE_SIZE (0x1000)
+
+#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
new file mode 100644
index 0000000..e3c9e4f
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/mpc86xx.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#ifndef __MPC86XX_H__
+#define __MPC86XX_H__
+
+/*
+ * Declaration for the various functions exported by the
+ * mpc86xx_* files. Mostly for use by mpc86xx_setup().
+ */
+
+extern int __init add_bridge(struct device_node *dev);
+
+extern void __init setup_indirect_pcie(struct pci_controller *hose,
+ u32 cfg_addr, u32 cfg_data);
+extern void __init setup_indirect_pcie_nomap(struct pci_controller *hose,
+ void __iomem *cfg_addr,
+ void __iomem *cfg_data);
+
+extern void __init mpc86xx_smp_init(void);
+
+#endif /* __MPC86XX_H__ */
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
new file mode 100644
index 0000000..483c21d
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -0,0 +1,326 @@
+/*
+ * MPC86xx HPCN board specific routines
+ *
+ * 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/config.h>
+#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/root_dev.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/mpic.h>
+
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+
+#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 u_char mpc86xx_hpcn_openpic_initsenses[] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: Reserved */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: MCM */
+ (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: PCIE1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: PCIE2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: Reserved */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: Reserved */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: DUART2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 1 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 1 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: TSEC 3 transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: TSEC 3 receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: TSEC 3 error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 1 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 2 Transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 2 Receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: TSEC 4 transmit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: TSEC 4 receive */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: TSEC 4 error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 2 Receive/Transmit Error */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART1 */
+ (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: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 32: SRIO error/write-port unit */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 33: SRIO outbound doorbell */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 34: SRIO inbound doorbell */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 35: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 36: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 37: SRIO outbound message unit 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 38: SRIO inbound message unit 1 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 39: SRIO outbound message unit 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 40: SRIO inbound message unit 2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 41: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 42: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 43: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 44: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 45: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 46: Unused */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 47: Unused */
+ 0x0, /* External 0: */
+ 0x0, /* External 1: */
+ 0x0, /* External 2: */
+ 0x0, /* External 3: */
+ 0x0, /* External 4: */
+ 0x0, /* External 5: */
+ 0x0, /* External 6: */
+ 0x0, /* External 7: */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 8: Pixis FPGA */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* External 9: ULI 8259 INTR Cascade */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 10: Quad ETH PHY */
+ 0x0, /* External 11: */
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+};
+
+
+void __init
+mpc86xx_hpcn_init_irq(void)
+{
+ struct mpic *mpic1;
+ phys_addr_t openpic_paddr;
+
+ /* Determine the Physical Address of the OpenPIC regs */
+ openpic_paddr = get_immrbase() + MPC86xx_OPENPIC_OFFSET;
+
+ /* Alloc mpic structure and per isu has 16 INT entries. */
+ mpic1 = mpic_alloc(openpic_paddr,
+ MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+ 16, MPC86xx_OPENPIC_IRQ_OFFSET, 0, 250,
+ mpc86xx_hpcn_openpic_initsenses,
+ sizeof(mpc86xx_hpcn_openpic_initsenses),
+ " MPIC ");
+ BUG_ON(mpic1 == NULL);
+
+ /* 48 Internal Interrupts */
+ mpic_assign_isu(mpic1, 0, openpic_paddr + 0x10200);
+ mpic_assign_isu(mpic1, 1, openpic_paddr + 0x10400);
+ mpic_assign_isu(mpic1, 2, openpic_paddr + 0x10600);
+
+ /* 16 External interrupts */
+ mpic_assign_isu(mpic1, 3, openpic_paddr + 0x10000);
+
+ mpic_init(mpic1);
+
+#ifdef CONFIG_PCI
+ mpic_setup_cascade(MPC86xx_IRQ_EXT9, i8259_irq_cascade, NULL);
+ i8259_init(0, I8259_OFFSET);
+#endif
+}
+
+
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+
+int
+mpc86xx_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}, /* IDSEL 17 -- PCI Slot 1 */
+ {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 18 -- PCI Slot 2 */
+ {0, 0, 0, 0}, /* IDSEL 19 */
+ {0, 0, 0, 0}, /* IDSEL 20 */
+ {0, 0, 0, 0}, /* IDSEL 21 */
+ {0, 0, 0, 0}, /* IDSEL 22 */
+ {0, 0, 0, 0}, /* IDSEL 23 */
+ {0, 0, 0, 0}, /* IDSEL 24 */
+ {0, 0, 0, 0}, /* IDSEL 25 */
+ {PIRQD, PIRQA, PIRQB, PIRQC}, /* IDSEL 26 -- PCI Bridge*/
+ {PIRQC, 0, 0, 0}, /* IDSEL 27 -- LAN */
+ {PIRQE, PIRQF, PIRQH, PIRQ7}, /* IDSEL 28 -- USB 1.1 */
+ {PIRQE, PIRQF, PIRQG, 0}, /* IDSEL 29 -- Audio & Modem */
+ {PIRQH, 0, 0, 0}, /* IDSEL 30 -- LPC & PMU*/
+ {PIRQD, 0, 0, 0}, /* IDSEL 31 -- ATA */
+ };
+
+ const long min_idsel = 17, max_idsel = 31, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP + I8259_OFFSET;
+}
+
+
+int
+mpc86xx_exclude_device(u_char bus, u_char devfn)
+{
+#if !defined(CONFIG_PCI)
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+#endif
+
+ return PCIBIOS_SUCCESSFUL;
+}
+#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) {
+ unsigned int *fp;
+
+ fp = (int *)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_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = mpc86xx_map_irq;
+ ppc_md.pci_exclude_device = mpc86xx_exclude_device;
+#endif
+
+ printk("MPC86xx HPCN board from Freescale Semiconductor\n");
+
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+
+#ifdef CONFIG_SMP
+ mpc86xx_smp_init();
+#endif
+}
+
+
+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 = 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));
+}
+
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc86xx_hpcn_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (of_flat_dt_is_compatible(root, "mpc86xx"))
+ 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);
+
+ /* not reached */
+}
+
+
+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_hpcn) {
+ .name = "MPC86xx HPCN",
+ .probe = mpc86xx_hpcn_probe,
+ .setup_arch = mpc86xx_hpcn_setup_arch,
+ .init_IRQ = mpc86xx_hpcn_init_irq,
+ .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo,
+ .get_irq = mpic_get_irq,
+ .restart = mpc86xx_restart,
+ .time_init = mpc86xx_time_init,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
new file mode 100644
index 0000000..944ec4b
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -0,0 +1,117 @@
+/*
+ * Author: Xianghua Xiao <x.xiao@freescale.com>
+ * Zhang Wei <wei.zhang@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/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/pci-bridge.h>
+#include <asm-powerpc/mpic.h>
+#include <asm/mpc86xx.h>
+#include <asm/cacheflush.h>
+
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+
+extern void __secondary_start_mpc86xx(void);
+extern unsigned long __secondary_hold_acknowledge;
+
+
+static void __init
+smp_86xx_release_core(int nr)
+{
+ void *mcm_vaddr;
+ unsigned long vaddr, pcr;
+
+ if (nr < 0 || nr >= NR_CPUS)
+ return;
+
+ /*
+ * Startup Core #nr.
+ */
+ mcm_vaddr = ioremap(get_immrbase() + MPC86xx_MCM_OFFSET,
+ MPC86xx_MCM_SIZE);
+ vaddr = (unsigned long)mcm_vaddr + MCM_PORT_CONFIG_OFFSET;
+ pcr = in_be32((volatile unsigned *)vaddr);
+ pcr |= 1 << (nr + 24);
+ out_be32((volatile unsigned *)vaddr, pcr);
+}
+
+
+static void __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);
+
+ if (nr < 0 || nr >= NR_CPUS)
+ return;
+
+ pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr);
+
+ local_irq_save(flags);
+ local_irq_disable();
+
+ /* Save reset vector */
+ save_vector = *vector;
+
+ /* Setup fake reset vector to call __secondary_start_mpc86xx. */
+ target = (unsigned long) __secondary_start_mpc86xx;
+ create_branch((unsigned long)vector, target, BRANCH_SET_LINK);
+
+ /* Kick that CPU */
+ smp_86xx_release_core(nr);
+
+ /* Wait a bit for the CPU to take the exception. */
+ while ((__secondary_hold_acknowledge != nr) && (n++, n < 1000))
+ mdelay(1);
+
+ /* Restore the exception vector */
+ *vector = save_vector;
+ flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+ local_irq_restore(flags);
+
+ pr_debug("wait CPU #%d for %d msecs.\n", nr, n);
+}
+
+
+static void __init
+smp_86xx_setup_cpu(int cpu_nr)
+{
+ mpic_setup_this_cpu();
+}
+
+
+struct smp_ops_t smp_86xx_ops = {
+ .message_pass = smp_mpic_message_pass,
+ .probe = smp_mpic_probe,
+ .kick_cpu = smp_86xx_kick_cpu,
+ .setup_cpu = smp_86xx_setup_cpu,
+ .take_timebase = smp_generic_take_timebase,
+ .give_timebase = smp_generic_give_timebase,
+};
+
+
+void __init
+mpc86xx_smp_init(void)
+{
+ smp_ops = &smp_86xx_ops;
+}
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-17 22:52 [PATCH 5/9 v3] Add the MPC8641 HPCN platform files Jon Loeliger @ 2006-06-18 3:07 ` Benjamin Herrenschmidt 2006-06-19 14:04 ` Jon Loeliger 2006-06-18 3:14 ` Benjamin Herrenschmidt 2006-06-18 14:28 ` Kumar Gala 2 siblings, 1 reply; 14+ messages in thread From: Benjamin Herrenschmidt @ 2006-06-18 3:07 UTC (permalink / raw) To: Jon Loeliger; +Cc: linuxppc-dev > struct smp_ops_t smp_86xx_ops = { > + .message_pass = smp_mpic_message_pass, > + .probe = smp_mpic_probe, > + .kick_cpu = smp_86xx_kick_cpu, > + .setup_cpu = smp_86xx_setup_cpu, > + .take_timebase = smp_generic_take_timebase, > + .give_timebase = smp_generic_give_timebase, > +}; You don't have any way to freeze the timebase ? (No GPIO controlling TBEN ?) It's pretty nasty to rely on software sync, especially if it's supposed to be an example design ... Ben. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-18 3:07 ` Benjamin Herrenschmidt @ 2006-06-19 14:04 ` Jon Loeliger 2006-06-19 22:06 ` Segher Boessenkool 0 siblings, 1 reply; 14+ messages in thread From: Jon Loeliger @ 2006-06-19 14:04 UTC (permalink / raw) To: Benjamin Herrenschmidt; +Cc: linuxppc-dev@ozlabs.org, Jon Loeliger On Sat, 2006-06-17 at 22:07, Benjamin Herrenschmidt wrote: > > You don't have any way to freeze the timebase ? (No GPIO controlling > TBEN ?) It's pretty nasty to rely on software sync, I will investigate this option and follow up with a patch, assuming that there is a HW solution for your suggestion. > especially if it's supposed to be an example design ... Who said that? ;-) jdl ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-19 14:04 ` Jon Loeliger @ 2006-06-19 22:06 ` Segher Boessenkool 2006-06-19 22:38 ` Jon Loeliger 0 siblings, 1 reply; 14+ messages in thread From: Segher Boessenkool @ 2006-06-19 22:06 UTC (permalink / raw) To: Jon Loeliger; +Cc: Jon Loeliger, linuxppc-dev@ozlabs.org On 19-jun-2006, at 16:04, Jon Loeliger wrote: > On Sat, 2006-06-17 at 22:07, Benjamin Herrenschmidt wrote: > >> >> You don't have any way to freeze the timebase ? (No GPIO controlling >> TBEN ?) It's pretty nasty to rely on software sync, Btw, IMNSHO, it should be the firmware's job to synchronise the timebases, even before the kernel gets started; at least as the default. We don't want to have millions of separate GPIO thingies, one for every board, unless really necessary, I think? Segher ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-19 22:06 ` Segher Boessenkool @ 2006-06-19 22:38 ` Jon Loeliger 2006-06-19 22:44 ` Segher Boessenkool 0 siblings, 1 reply; 14+ messages in thread From: Jon Loeliger @ 2006-06-19 22:38 UTC (permalink / raw) To: Segher Boessenkool; +Cc: linuxppc-dev@ozlabs.org So, like, the other day Segher Boessenkool mumbled: > > Btw, IMNSHO, it should be the firmware's job to synchronise > the timebases, even before the kernel gets started; at least > as the default. We don't want to have millions of separate > GPIO thingies, one for every board, unless really necessary, > I think? The second CPU isn't even running in the firmware. It is in hard-reset until Linux says "Hey, start that secondary CPU for me!". Thanks, jdl ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-19 22:38 ` Jon Loeliger @ 2006-06-19 22:44 ` Segher Boessenkool 2006-06-19 23:11 ` Jon Loeliger 0 siblings, 1 reply; 14+ messages in thread From: Segher Boessenkool @ 2006-06-19 22:44 UTC (permalink / raw) To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org >> Btw, IMNSHO, it should be the firmware's job to synchronise >> the timebases, even before the kernel gets started; at least >> as the default. We don't want to have millions of separate >> GPIO thingies, one for every board, unless really necessary, >> I think? > > The second CPU isn't even running in the firmware. > It is in hard-reset until Linux says "Hey, start that > secondary CPU for me!". In that case you obviously need to sync the timebases, sure. The firmware could be smart and do the sync at CPU start-up time though. On other boards, all CPUs are always running (not a desirable situation, but outside of our control, heh). In either case, the knowledge about how to sync the timebases more properly belongs in the firmware than in the kernel. In some cases the kernel explicitly tells the firmware to start/ stop the timebases, that's better than the kernel having to handle the nitty-gritty details itself already. Thoughts? Segher ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-19 22:44 ` Segher Boessenkool @ 2006-06-19 23:11 ` Jon Loeliger 2006-06-19 23:18 ` Segher Boessenkool 0 siblings, 1 reply; 14+ messages in thread From: Jon Loeliger @ 2006-06-19 23:11 UTC (permalink / raw) To: Segher Boessenkool; +Cc: linuxppc-dev@ozlabs.org So, like, the other day Segher Boessenkool mumbled: > > In that case you obviously need to sync the timebases, sure. > The firmware could be smart and do the sync at CPU start-up > time though. I am investigating this and, as I indicated to Ben, submit a follow up patch to implement it if I figure out to do it. > In > some cases the kernel explicitly tells the firmware to start/ > stop the timebases, that's better than the kernel having to > handle the nitty-gritty details itself already. > > Thoughts? Well, by the time Linux is running, there is no more firmware available. Linux is essentially autononomous at this stage, and I think it will have to arrange for the TB sync itself. jdl ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-19 23:11 ` Jon Loeliger @ 2006-06-19 23:18 ` Segher Boessenkool 2006-06-19 23:32 ` Jon Loeliger 0 siblings, 1 reply; 14+ messages in thread From: Segher Boessenkool @ 2006-06-19 23:18 UTC (permalink / raw) To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org >> In that case you obviously need to sync the timebases, sure. >> The firmware could be smart and do the sync at CPU start-up >> time though. > > I am investigating this and, as I indicated to Ben, submit > a follow up patch to implement it if I figure out to do it. Great. >> In >> some cases the kernel explicitly tells the firmware to start/ >> stop the timebases, that's better than the kernel having to >> handle the nitty-gritty details itself already. >> >> Thoughts? > > Well, by the time Linux is running, there is no more firmware > available. Linux is essentially autononomous at this stage, > and I think it will have to arrange for the TB sync itself. I'm confused now. So are or arent't all CPUs running at the time Linux is started? Are you saying Linux manually starts all non-boot CPUs?!? Segher ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-19 23:18 ` Segher Boessenkool @ 2006-06-19 23:32 ` Jon Loeliger 2006-06-19 23:36 ` Segher Boessenkool 0 siblings, 1 reply; 14+ messages in thread From: Jon Loeliger @ 2006-06-19 23:32 UTC (permalink / raw) To: linuxppc-dev@ozlabs.org So, like, the other day Segher Boessenkool mumbled: > > I'm confused now. So are or arent't all CPUs running at the > time Linux is started? Only the boot CPU is running. The others are not. > Are you saying Linux manually starts > all non-boot CPUs?!? Right. The secondary CPUs are not clocking, not able to fetch memory, not nothing until Linux gets a shot at smp_secondary_kick()'ing them into motion. And then we have the ability to start the scondary CPUs one at a time. jdl ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-19 23:32 ` Jon Loeliger @ 2006-06-19 23:36 ` Segher Boessenkool 2006-06-19 23:52 ` Jon Loeliger 0 siblings, 1 reply; 14+ messages in thread From: Segher Boessenkool @ 2006-06-19 23:36 UTC (permalink / raw) To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org >> Are you saying Linux manually starts >> all non-boot CPUs?!? > > Right. The secondary CPUs are not clocking, not able to > fetch memory, not nothing until Linux gets a shot at > smp_secondary_kick()'ing them into motion. And then we > have the ability to start the scondary CPUs one at a time. So you start them with a GPIO? Would it be feasible to sync the time bases right there? Constrain the ugliness to just that one spot, as it were. Although it ends up with the same complexity, sigh. Segher ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-19 23:36 ` Segher Boessenkool @ 2006-06-19 23:52 ` Jon Loeliger 0 siblings, 0 replies; 14+ messages in thread From: Jon Loeliger @ 2006-06-19 23:52 UTC (permalink / raw) To: linuxppc-dev@ozlabs.org So, like, the other day Segher Boessenkool mumbled: > So you start them with a GPIO? Yeah, magic system register write. > Would it be feasible to > sync the time bases right there? Constrain the ugliness > to just that one spot, as it were. Although it ends up > with the same complexity, sigh. That's the sort of thing I will be investigating, yep... jdl ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-17 22:52 [PATCH 5/9 v3] Add the MPC8641 HPCN platform files Jon Loeliger 2006-06-18 3:07 ` Benjamin Herrenschmidt @ 2006-06-18 3:14 ` Benjamin Herrenschmidt 2006-06-19 14:09 ` Jon Loeliger 2006-06-18 14:28 ` Kumar Gala 2 siblings, 1 reply; 14+ messages in thread From: Benjamin Herrenschmidt @ 2006-06-18 3:14 UTC (permalink / raw) To: Jon Loeliger; +Cc: linuxppc-dev > +/* > + * Internal interrupts are all Level Sensitive, and Positive Polarity > + */ > + > +static u_char mpc86xx_hpcn_openpic_initsenses[] __initdata = { > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: Reserved */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: MCM */ > + (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: PCIE1 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: PCIE2 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: Reserved */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: Reserved */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: DUART2 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 1 Transmit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 1 Receive */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: TSEC 3 transmit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: TSEC 3 receive */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: TSEC 3 error */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 1 Receive/Transmit Error */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 2 Transmit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 2 Receive */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: TSEC 4 transmit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: TSEC 4 receive */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: TSEC 4 error */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 2 Receive/Transmit Error */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART1 */ > + (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: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 32: SRIO error/write-port unit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 33: SRIO outbound doorbell */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 34: SRIO inbound doorbell */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 35: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 36: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 37: SRIO outbound message unit 1 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 38: SRIO inbound message unit 1 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 39: SRIO outbound message unit 2 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 40: SRIO inbound message unit 2 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 41: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 42: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 43: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 44: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 45: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 46: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 47: Unused */ > + 0x0, /* External 0: */ > + 0x0, /* External 1: */ > + 0x0, /* External 2: */ > + 0x0, /* External 3: */ > + 0x0, /* External 4: */ > + 0x0, /* External 5: */ > + 0x0, /* External 6: */ > + 0x0, /* External 7: */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 8: Pixis FPGA */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* External 9: ULI 8259 INTR Cascade */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 10: Quad ETH PHY */ > + 0x0, /* External 11: */ > + 0x0, > + 0x0, > + 0x0, > + 0x0, > +}; So what I suggest you do with the above, rather than having this big array in the kernel, is to have a property in the interrupt controller node, let's call it "default-senses", which contains a cell for every interrupt source with the default sense value. The interrupt mapping code that I'm working on will allow individual interrupts to carry their sense value through the device-tree, but it's useful to have some sane defaults, either because you don't have a device-tree entry for a given interrupt (oops, happens ...) or because... you don't have my new code yet :) I'm not too fan of the big table in the kernel however. I'd rather have it in the device-tree. I'm not forcing you here, do as you prefer, but if you decide to go toward the "default-senses" property in the DT, then I think we should add a couple of sections to my proposed patch to the booting-without-of.txt file about interrupt that describes a set of optional properties for interrupt controllers, and describe that there. I'm toying with creating a "generic" create_interrupt_controller() function in fact that takes a device-node and would instanciate known interrupt controller types (i8259, OpenPIC, for now, maybe more later) entire based on device-tree properties (big-endian, maybe that one for default sense codes, etc...). Cheers, Ben. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-18 3:14 ` Benjamin Herrenschmidt @ 2006-06-19 14:09 ` Jon Loeliger 0 siblings, 0 replies; 14+ messages in thread From: Jon Loeliger @ 2006-06-19 14:09 UTC (permalink / raw) To: Benjamin Herrenschmidt; +Cc: linuxppc-dev@ozlabs.org, Jon Loeliger On Sat, 2006-06-17 at 22:14, Benjamin Herrenschmidt wrote: > I'm not too fan of the big table in the kernel however. I'd rather have > it in the device-tree. We are waiting for this release to get into the mainline, and for your proposed rewrite to be accepted. We have folks here who are on deck to totally modify this to accommodate your proposal via the Device Tree file. But we're not going to read your mind to get there. :-) jdl ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9 v3] Add the MPC8641 HPCN platform files. 2006-06-17 22:52 [PATCH 5/9 v3] Add the MPC8641 HPCN platform files Jon Loeliger 2006-06-18 3:07 ` Benjamin Herrenschmidt 2006-06-18 3:14 ` Benjamin Herrenschmidt @ 2006-06-18 14:28 ` Kumar Gala 2 siblings, 0 replies; 14+ messages in thread From: Kumar Gala @ 2006-06-18 14:28 UTC (permalink / raw) To: Jon Loeliger; +Cc: linuxppc-dev On Jun 17, 2006, at 5:52 PM, Jon Loeliger wrote: > Signed-off-by: Xianghua Xiao <x.xiao@freescale.com> > Signed-off-by: Haiying Wang <Haiying.Wang@freescale.com> > Signed-off-by: Wei Zhang <Wei.Zhang@freescale.com> > Signed-off-by: Jon Loeliger <jdl@freescale.com> > > --- > > arch/powerpc/platforms/86xx/mpc8641_hpcn.h | 54 +++++ > arch/powerpc/platforms/86xx/mpc86xx.h | 28 ++ > arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 326 +++++++++++++++++ > +++++++++++ > arch/powerpc/platforms/86xx/mpc86xx_smp.c | 117 ++++++++++ > 4 files changed, 525 insertions(+), 0 deletions(-) > > diff --git a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h b/arch/ > powerpc/platforms/86xx/mpc8641_hpcn.h > new file mode 100644 > index 0000000..5042253 > --- /dev/null > +++ b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h > @@ -0,0 +1,54 @@ > +/* > + * 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/config.h> > +#include <linux/init.h> > + > +/* PCI interrupt controller */ > +#define PIRQA 3 > +#define PIRQB 4 > +#define PIRQC 5 > +#define PIRQD 6 > +#define PIRQ7 7 > +#define PIRQE 9 > +#define PIRQF 10 > +#define PIRQG 11 > +#define PIRQH 12 > + > +/* PCI-Express memory map */ > +#define MPC86XX_PCIE_LOWER_IO 0x00000000 > +#define MPC86XX_PCIE_UPPER_IO 0x00ffffff > + > +#define MPC86XX_PCIE_LOWER_MEM 0x80000000 > +#define MPC86XX_PCIE_UPPER_MEM 0x9fffffff > + > +#define MPC86XX_PCIE_IO_BASE 0xe2000000 > +#define MPC86XX_PCIE_MEM_OFFSET 0x00000000 > + > +#define MPC86XX_PCIE_IO_SIZE 0x01000000 > + > +#define PCIE1_CFG_ADDR_OFFSET (0x8000) > +#define PCIE1_CFG_DATA_OFFSET (0x8004) > + > +#define PCIE2_CFG_ADDR_OFFSET (0x9000) > +#define PCIE2_CFG_DATA_OFFSET (0x9004) > + > +#define MPC86xx_PCIE_OFFSET PCIE1_CFG_ADDR_OFFSET > +#define MPC86xx_PCIE_SIZE (0x1000) > + > +#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 > new file mode 100644 > index 0000000..e3c9e4f > --- /dev/null > +++ b/arch/powerpc/platforms/86xx/mpc86xx.h > @@ -0,0 +1,28 @@ > +/* > + * 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. > + */ > + > +#ifndef __MPC86XX_H__ > +#define __MPC86XX_H__ > + > +/* > + * Declaration for the various functions exported by the > + * mpc86xx_* files. Mostly for use by mpc86xx_setup(). > + */ > + > +extern int __init add_bridge(struct device_node *dev); > + > +extern void __init setup_indirect_pcie(struct pci_controller *hose, > + u32 cfg_addr, u32 cfg_data); > +extern void __init setup_indirect_pcie_nomap(struct pci_controller > *hose, > + void __iomem *cfg_addr, > + void __iomem *cfg_data); > + > +extern void __init mpc86xx_smp_init(void); > + > +#endif /* __MPC86XX_H__ */ > diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/ > powerpc/platforms/86xx/mpc86xx_hpcn.c > new file mode 100644 > index 0000000..483c21d > --- /dev/null > +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c > @@ -0,0 +1,326 @@ > +/* > + * MPC86xx HPCN board specific routines > + * > + * 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/config.h> > +#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/root_dev.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/mpic.h> > + > +#include <sysdev/fsl_soc.h> > + > +#include "mpc86xx.h" > + > +#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 u_char mpc86xx_hpcn_openpic_initsenses[] __initdata = { > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: > Reserved */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: MCM */ > + (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: PCIE1 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: PCIE2 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: > Reserved */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: > Reserved */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: DUART2 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 1 > Transmit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 1 > Receive */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: TSEC 3 > transmit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: TSEC 3 > receive */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: TSEC 3 > error */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 1 > Receive/Transmit Error */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 2 > Transmit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 2 > Receive */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: TSEC 4 > transmit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: TSEC 4 > receive */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: TSEC 4 > error */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 2 > Receive/Transmit Error */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART1 */ > + (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: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 32: SRIO > error/write-port unit */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 33: SRIO > outbound doorbell */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 34: SRIO > inbound doorbell */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 35: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 36: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 37: SRIO > outbound message unit 1 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 38: SRIO > inbound message unit 1 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 39: SRIO > outbound message unit 2 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 40: SRIO > inbound message unit 2 */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 41: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 42: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 43: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 44: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 45: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 46: Unused */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 47: Unused */ > + 0x0, /* External 0: */ > + 0x0, /* External 1: */ > + 0x0, /* External 2: */ > + 0x0, /* External 3: */ > + 0x0, /* External 4: */ > + 0x0, /* External 5: */ > + 0x0, /* External 6: */ > + 0x0, /* External 7: */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 8: Pixis > FPGA */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* External 9: ULI > 8259 INTR Cascade */ > + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 10: Quad > ETH PHY */ > + 0x0, /* External 11: */ > + 0x0, > + 0x0, > + 0x0, > + 0x0, > +}; > + > + > +void __init > +mpc86xx_hpcn_init_irq(void) > +{ > + struct mpic *mpic1; > + phys_addr_t openpic_paddr; > + > + /* Determine the Physical Address of the OpenPIC regs */ > + openpic_paddr = get_immrbase() + MPC86xx_OPENPIC_OFFSET; > + > + /* Alloc mpic structure and per isu has 16 INT entries. */ > + mpic1 = mpic_alloc(openpic_paddr, > + MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, > + 16, MPC86xx_OPENPIC_IRQ_OFFSET, 0, 250, > + mpc86xx_hpcn_openpic_initsenses, > + sizeof(mpc86xx_hpcn_openpic_initsenses), > + " MPIC "); > + BUG_ON(mpic1 == NULL); > + > + /* 48 Internal Interrupts */ > + mpic_assign_isu(mpic1, 0, openpic_paddr + 0x10200); > + mpic_assign_isu(mpic1, 1, openpic_paddr + 0x10400); > + mpic_assign_isu(mpic1, 2, openpic_paddr + 0x10600); > + > + /* 16 External interrupts */ > + mpic_assign_isu(mpic1, 3, openpic_paddr + 0x10000); > + > + mpic_init(mpic1); > + > +#ifdef CONFIG_PCI > + mpic_setup_cascade(MPC86xx_IRQ_EXT9, i8259_irq_cascade, NULL); > + i8259_init(0, I8259_OFFSET); > +#endif > +} > + > + > + > +#ifdef CONFIG_PCI > +/* > + * interrupt routing > + */ > + > +int > +mpc86xx_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}, /* IDSEL 17 -- PCI Slot 1 */ > + {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 18 -- PCI Slot 2 */ > + {0, 0, 0, 0}, /* IDSEL 19 */ > + {0, 0, 0, 0}, /* IDSEL 20 */ > + {0, 0, 0, 0}, /* IDSEL 21 */ > + {0, 0, 0, 0}, /* IDSEL 22 */ > + {0, 0, 0, 0}, /* IDSEL 23 */ > + {0, 0, 0, 0}, /* IDSEL 24 */ > + {0, 0, 0, 0}, /* IDSEL 25 */ > + {PIRQD, PIRQA, PIRQB, PIRQC}, /* IDSEL 26 -- PCI Bridge*/ > + {PIRQC, 0, 0, 0}, /* IDSEL 27 -- LAN */ > + {PIRQE, PIRQF, PIRQH, PIRQ7}, /* IDSEL 28 -- USB 1.1 */ > + {PIRQE, PIRQF, PIRQG, 0}, /* IDSEL 29 -- Audio & Modem */ > + {PIRQH, 0, 0, 0}, /* IDSEL 30 -- LPC & PMU*/ > + {PIRQD, 0, 0, 0}, /* IDSEL 31 -- ATA */ > + }; > + > + const long min_idsel = 17, max_idsel = 31, irqs_per_slot = 4; > + return PCI_IRQ_TABLE_LOOKUP + I8259_OFFSET; > +} > + > + > +int > +mpc86xx_exclude_device(u_char bus, u_char devfn) > +{ > +#if !defined(CONFIG_PCI) > + if (bus == 0 && PCI_SLOT(devfn) == 0) > + return PCIBIOS_DEVICE_NOT_FOUND; > +#endif > + > + return PCIBIOS_SUCCESSFUL; > +} any reason not to put this in pci.c its generic enough. Also, loose the #if, its pointless ;) > +#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) { > + unsigned int *fp; > + > + fp = (int *)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_swizzle = common_swizzle; > + ppc_md.pci_map_irq = mpc86xx_map_irq; > + ppc_md.pci_exclude_device = mpc86xx_exclude_device; > +#endif > + > + printk("MPC86xx HPCN board from Freescale Semiconductor\n"); > + > +#ifdef CONFIG_ROOT_NFS > + ROOT_DEV = Root_NFS; > +#else > + ROOT_DEV = Root_HDA1; > +#endif > + > +#ifdef CONFIG_SMP > + mpc86xx_smp_init(); > +#endif > +} > + > + > +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 = 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)); > +} > + > + > +/* > + * Called very early, device-tree isn't unflattened > + */ > +static int __init mpc86xx_hpcn_probe(void) > +{ > + unsigned long root = of_get_flat_dt_root(); > + > + if (of_flat_dt_is_compatible(root, "mpc86xx")) > + return 1; /* Looks good */ > + > + return 0; > +} You should make this probe actually check model or something more specific than mpc86xx. I didn't do this on 85xx or 83xx since we had pre-existing .dts that didn't setup model in a consistent way. > + > + > +void > +mpc86xx_restart(char *cmd) > +{ > + void __iomem *rstcr; > + > + rstcr = ioremap(get_immrbase() + MPC86XX_RSTCR_OFFSET, 0x100); > + > + local_irq_disable(); > + > + /* Assert reset request to Reset Control Register */ > + out_be32(rstcr, 0x2); > + > + /* not reached */ > +} > + > + > +long __init > +mpc86xx_time_init(void) > +{ > + 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_hpcn) { > + .name = "MPC86xx HPCN", > + .probe = mpc86xx_hpcn_probe, > + .setup_arch = mpc86xx_hpcn_setup_arch, > + .init_IRQ = mpc86xx_hpcn_init_irq, > + .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo, > + .get_irq = mpic_get_irq, > + .restart = mpc86xx_restart, > + .time_init = mpc86xx_time_init, > + .calibrate_decr = generic_calibrate_decr, > + .progress = udbg_progress, > +}; > diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/ > powerpc/platforms/86xx/mpc86xx_smp.c > new file mode 100644 > index 0000000..944ec4b > --- /dev/null > +++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c a nit, but any reason to not call this just smp.c? > @@ -0,0 +1,117 @@ > +/* > + * Author: Xianghua Xiao <x.xiao@freescale.com> > + * Zhang Wei <wei.zhang@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/config.h> > +#include <linux/stddef.h> > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/delay.h> > + > +#include <asm/pgtable.h> > +#include <asm/page.h> > +#include <asm/pci-bridge.h> > +#include <asm-powerpc/mpic.h> > +#include <asm/mpc86xx.h> > +#include <asm/cacheflush.h> > + > +#include <sysdev/fsl_soc.h> > + > +#include "mpc86xx.h" > + > +extern void __secondary_start_mpc86xx(void); > +extern unsigned long __secondary_hold_acknowledge; > + > + > +static void __init > +smp_86xx_release_core(int nr) > +{ > + void *mcm_vaddr; > + unsigned long vaddr, pcr; > + > + if (nr < 0 || nr >= NR_CPUS) > + return; > + > + /* > + * Startup Core #nr. > + */ > + mcm_vaddr = ioremap(get_immrbase() + MPC86xx_MCM_OFFSET, > + MPC86xx_MCM_SIZE); > + vaddr = (unsigned long)mcm_vaddr + MCM_PORT_CONFIG_OFFSET; > + pcr = in_be32((volatile unsigned *)vaddr); > + pcr |= 1 << (nr + 24); > + out_be32((volatile unsigned *)vaddr, pcr); > +} > + > + > +static void __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); > + > + if (nr < 0 || nr >= NR_CPUS) > + return; > + > + pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); > + > + local_irq_save(flags); > + local_irq_disable(); > + > + /* Save reset vector */ > + save_vector = *vector; > + > + /* Setup fake reset vector to call __secondary_start_mpc86xx. */ > + target = (unsigned long) __secondary_start_mpc86xx; > + create_branch((unsigned long)vector, target, BRANCH_SET_LINK); > + > + /* Kick that CPU */ > + smp_86xx_release_core(nr); > + > + /* Wait a bit for the CPU to take the exception. */ > + while ((__secondary_hold_acknowledge != nr) && (n++, n < 1000)) > + mdelay(1); > + > + /* Restore the exception vector */ > + *vector = save_vector; > + flush_icache_range((unsigned long) vector, (unsigned long) vector > + 4); > + > + local_irq_restore(flags); > + > + pr_debug("wait CPU #%d for %d msecs.\n", nr, n); > +} > + > + > +static void __init > +smp_86xx_setup_cpu(int cpu_nr) > +{ > + mpic_setup_this_cpu(); > +} > + > + > +struct smp_ops_t smp_86xx_ops = { > + .message_pass = smp_mpic_message_pass, > + .probe = smp_mpic_probe, > + .kick_cpu = smp_86xx_kick_cpu, > + .setup_cpu = smp_86xx_setup_cpu, > + .take_timebase = smp_generic_take_timebase, > + .give_timebase = smp_generic_give_timebase, > +}; > + > + > +void __init > +mpc86xx_smp_init(void) > +{ > + smp_ops = &smp_86xx_ops; > +} > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@ozlabs.org > https://ozlabs.org/mailman/listinfo/linuxppc-dev ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2006-06-19 23:52 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-06-17 22:52 [PATCH 5/9 v3] Add the MPC8641 HPCN platform files Jon Loeliger 2006-06-18 3:07 ` Benjamin Herrenschmidt 2006-06-19 14:04 ` Jon Loeliger 2006-06-19 22:06 ` Segher Boessenkool 2006-06-19 22:38 ` Jon Loeliger 2006-06-19 22:44 ` Segher Boessenkool 2006-06-19 23:11 ` Jon Loeliger 2006-06-19 23:18 ` Segher Boessenkool 2006-06-19 23:32 ` Jon Loeliger 2006-06-19 23:36 ` Segher Boessenkool 2006-06-19 23:52 ` Jon Loeliger 2006-06-18 3:14 ` Benjamin Herrenschmidt 2006-06-19 14:09 ` Jon Loeliger 2006-06-18 14:28 ` Kumar Gala
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).