/* * MPC86xx HPCN board specific routines * * Recode: ZHANG WEI * Initial author: Xianghua Xiao * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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, };