From b66510cb9992d204f216049e9c01d432c7635f6c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 16 Aug 2007 23:55:55 -0500 Subject: [POWERPC] Fix interrupt routing and setup of ULI M1575 on FSL boards The interrupt routing in the device trees for the ULI M1575 was inproperly using the interrupt line field as pci function. Fixed up the device tree's to actual conform for to specification and changed the interrupt mapping code so it just uses a static mapping setup as follows: PIRQA - IRQ9 PIRQB - IRQ10 PIRQC - IRQ11 PIRQD - IRQ12 USB 1.1 OCHI (1c.0) - IRQ12 USB 1.1 OCHI (1c.1) - IRQ9 USB 1.1 OCHI (1c.2) - IRQ10 USB 1.1 ECHI (1c.3) - IRQ11 LAN (1b.0) - IRQ6 AC97 (1d.0) - IRQ6 Modem (1d.1) - IRQ6 HD Audio (1d.2) - IRQ6 SATA (1f.1) - IRQ5 SMB (1e.1) - IRQ7 PMU (1e.2) - IRQ7 PATA (1f.0) - IRQ14/15 Took the oppurtunity to refactor the code into a single file so we don't have to duplicate these fixes on the two current boards in the tree and several forth coming boards that will also need the code. Fixed RTC support that requires a dummy memory read on the P2P bridge to unlock the RTC and setup the default of the RTC alarm registers to match with a basic x86 style CMOS RTC. Moved code that poked ISA registers to a FIXUP_FINAL quirk to ensure the PCI IO space has been setup properly before we start poking ISA registers at random locations. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/Kconfig | 1 + arch/powerpc/platforms/85xx/mpc8544_ds.c | 214 ++---------------------- arch/powerpc/platforms/86xx/Kconfig | 1 + arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 224 ++----------------------- arch/powerpc/platforms/Kconfig | 8 + arch/powerpc/platforms/Makefile | 3 + arch/powerpc/platforms/fsl_uli1575.c | 255 +++++++++++++++++++++++++++++ 7 files changed, 299 insertions(+), 407 deletions(-) create mode 100644 arch/powerpc/platforms/fsl_uli1575.c (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index f58184086c8..f620171ad6b 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -33,6 +33,7 @@ config MPC8544_DS bool "Freescale MPC8544 DS" select PPC_I8259 select DEFAULT_UIMAGE + select FSL_ULI1575 help This option enables support for the MPC8544 DS board diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc8544_ds.c index 4905f6f8903..0f834d8be44 100644 --- a/arch/powerpc/platforms/85xx/mpc8544_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8544_ds.c @@ -114,211 +114,25 @@ void __init mpc8544_ds_pic_init(void) } #ifdef CONFIG_PCI -enum pirq { PIRQA = 8, PIRQB, PIRQC, PIRQD, PIRQE, PIRQF, PIRQG, PIRQH }; +extern int uses_fsl_uli_m1575; +extern int uli_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn); -/* - * Value in table -- IRQ number - */ -const unsigned char uli1575_irq_route_table[16] = { - 0, /* 0: Reserved */ - 0x8, - 0, /* 2: Reserved */ - 0x2, - 0x4, - 0x5, - 0x7, - 0x6, - 0, /* 8: Reserved */ - 0x1, - 0x3, - 0x9, - 0xb, - 0, /* 13: Reserved */ - 0xd, - 0xf, -}; - -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("mpc8544_ds: pci irq addr %x, slot %d, pin %d, irq %d\n", - laddr[0], slot, pin, oirq.specifier[0]); - return oirq.specifier[0]; -} - -/*8259*/ -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]; - unsigned long pirq_map_word = 0; - u32 irq; - int i; - - /* - * ULI1575 interrupts route setup - */ - memset(irq2pin, 0, 16); /* Initialize default value 0 */ - - irq2pin[6]=PIRQA+3; /* enabled mapping for IRQ6 to PIRQD, used by SATA */ - - /* - * 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); - - pirq_map_word |= 1<<26; /* disable INTx in EP mode*/ - - /* ULI1575 IRQ mapping conf register default value is 0xb9317542 */ - DBG("Setup ULI1575 IRQ mapping configuration register value = 0x%x\n", - (int)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 -} - -/* SATA */ -static void __devinit quirk_uli5288(struct pci_dev *dev) +static int mpc85xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { - unsigned char c; - - pci_read_config_byte(dev, 0x83, &c); - c |= 0x80; /* read/write lock */ - pci_write_config_byte(dev, 0x83, c); - - pci_write_config_byte(dev, 0x09, 0x01); /* Base class code: storage */ - pci_write_config_byte(dev, 0x0a, 0x06); /* IDE disk */ + struct device_node* node; + struct resource rsrc; - 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; /* emulated PATA mode enabled */ - pci_write_config_byte(dev, 0x84, c); -} + node = (struct device_node *)hose->arch_data; + of_address_to_resource(node, 0, &rsrc); -/* PATA */ -static void __devinit quirk_uli5229(struct pci_dev *dev) -{ - unsigned short temp; - pci_write_config_word(dev, 0x04, 0x0405); /* MEM IO MSI */ - pci_read_config_word(dev, 0x4a, &temp); - temp |= 0x1000; /* Enable Native IRQ 14/15 */ - pci_write_config_word(dev, 0x4a, temp); -} + if ((rsrc.start & 0xfffff) == 0xb000) { + return uli_exclude_device(hose, bus, devfn); + } -/*Bridge*/ -static void __devinit early_uli5249(struct pci_dev *dev) -{ - unsigned char temp; - pci_write_config_word(dev, 0x04, 0x0007); /* mem access */ - pci_read_config_byte(dev, 0x7c, &temp); - pci_write_config_byte(dev, 0x7c, 0x80); /* R/W lock control */ - pci_write_config_byte(dev, 0x09, 0x01); /* set as pci-pci bridge */ - pci_write_config_byte(dev, 0x7c, temp); /* restore pci bus debug control */ - dev->class |= 0x1; + return PCIBIOS_SUCCESSFUL; } - -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 */ /* @@ -342,6 +156,8 @@ static void __init mpc8544_ds_setup_arch(void) else fsl_add_bridge(np, 0); } + uses_fsl_uli_m1575 = 1; + ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif printk("MPC8544 DS board from Freescale Semiconductor\n"); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 343b76d0d79..685b2fbbbe0 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -7,6 +7,7 @@ config MPC8641_HPCN bool "Freescale MPC8641 HPCN" select PPC_I8259 select DEFAULT_UIMAGE + select FSL_ULI1575 help This option enables support for the MPC8641 HPCN board. diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index e9eaa0749ae..56b27caf7a2 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -107,220 +107,25 @@ mpc86xx_hpcn_init_irq(void) } #ifdef CONFIG_PCI +extern int uses_fsl_uli_m1575; +extern int uli_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn); -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); -} - -static void __devinit quirk_uli5288(struct pci_dev *dev) +static int mpc86xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { - unsigned char c; + struct device_node* node; + struct resource rsrc; - pci_read_config_byte(dev,0x83,&c); - c |= 0x80; - pci_write_config_byte(dev, 0x83, c); + node = (struct device_node *)hose->arch_data; + of_address_to_resource(node, 0, &rsrc); - 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); - dev->class &= ~0x5; - pci_read_config_word(dev, 0x4a, &temp); - temp |= 0x1000; - pci_write_config_word(dev, 0x4a, temp); -} + if ((rsrc.start & 0xfffff) == 0x8000) { + return uli_exclude_device(hose, bus, devfn); + } -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; + return PCIBIOS_SUCCESSFUL; } - -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 */ @@ -353,6 +158,9 @@ mpc86xx_hpcn_setup_arch(void) else fsl_add_bridge(np, 0); } + uses_fsl_uli_m1575 = 1; + ppc_md.pci_exclude_device = mpc86xx_exclude_device; + #endif printk("MPC86xx HPCN board from Freescale Semiconductor\n"); diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 932538a93c2..cfc24974159 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -282,4 +282,12 @@ config AXON_RAM minor numbers are available in /proc/devices, /proc/partitions or in /sys/block/axonram?/dev. +config FSL_ULI1575 + bool + default n + help + Supports for the ULI1575 PCIe south bridge that exists on some + Freescale reference boards. The boards all use the ULI in pretty + much the same way. + endmenu diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index d6e041a46d2..d44e832b01f 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -1,3 +1,6 @@ + +obj-$(CONFIG_FSL_ULI1575) += fsl_uli1575.o + ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_PMAC) += powermac/ else diff --git a/arch/powerpc/platforms/fsl_uli1575.c b/arch/powerpc/platforms/fsl_uli1575.c new file mode 100644 index 00000000000..afc9141be63 --- /dev/null +++ b/arch/powerpc/platforms/fsl_uli1575.c @@ -0,0 +1,255 @@ +/* + * ULI M1575 setup code - specific to Freescale boards + * + * Copyright 2007 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define ULI_PIRQA 0x08 +#define ULI_PIRQB 0x09 +#define ULI_PIRQC 0x0a +#define ULI_PIRQD 0x0b +#define ULI_PIRQE 0x0c +#define ULI_PIRQF 0x0d +#define ULI_PIRQG 0x0e + +#define ULI_8259_NONE 0x00 +#define ULI_8259_IRQ1 0x08 +#define ULI_8259_IRQ3 0x02 +#define ULI_8259_IRQ4 0x04 +#define ULI_8259_IRQ5 0x05 +#define ULI_8259_IRQ6 0x07 +#define ULI_8259_IRQ7 0x06 +#define ULI_8259_IRQ9 0x01 +#define ULI_8259_IRQ10 0x03 +#define ULI_8259_IRQ11 0x09 +#define ULI_8259_IRQ12 0x0b +#define ULI_8259_IRQ14 0x0d +#define ULI_8259_IRQ15 0x0f + +u8 uli_pirq_to_irq[8] = { + ULI_8259_IRQ9, /* PIRQA */ + ULI_8259_IRQ10, /* PIRQB */ + ULI_8259_IRQ11, /* PIRQC */ + ULI_8259_IRQ12, /* PIRQD */ + ULI_8259_IRQ5, /* PIRQE */ + ULI_8259_IRQ6, /* PIRQF */ + ULI_8259_IRQ7, /* PIRQG */ + ULI_8259_NONE, /* PIRQH */ +}; + +/* set in board code if you want this quirks to do something */ +int uses_fsl_uli_m1575; + +/* Bridge */ +static void __devinit early_uli5249(struct pci_dev *dev) +{ + unsigned char temp; + + if (!uses_fsl_uli_m1575) + return; + + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + /* read/write lock */ + pci_read_config_byte(dev, 0x7c, &temp); + pci_write_config_byte(dev, 0x7c, 0x80); + + /* set as P2P bridge */ + pci_write_config_byte(dev, PCI_CLASS_PROG, 0x01); + dev->class |= 0x1; + + /* restore lock */ + pci_write_config_byte(dev, 0x7c, temp); +} + + +static void __devinit quirk_uli1575(struct pci_dev *dev) +{ + int i; + + if (!uses_fsl_uli_m1575) + return; + + /* + * ULI1575 interrupts route setup + */ + + /* ULI1575 IRQ mapping conf register maps PIRQx to IRQn */ + for (i = 0; i < 4; i++) { + u8 val = uli_pirq_to_irq[i*2] | (uli_pirq_to_irq[i*2+1] << 4); + pci_write_config_byte(dev, 0x48 + i, val); + } + + /* USB 1.1 OHCI controller 1: dev 28, func 0 - IRQ12 */ + pci_write_config_byte(dev, 0x86, ULI_PIRQD); + + /* USB 1.1 OHCI controller 2: dev 28, func 1 - IRQ9 */ + pci_write_config_byte(dev, 0x87, ULI_PIRQA); + + /* USB 1.1 OHCI controller 3: dev 28, func 2 - IRQ10 */ + pci_write_config_byte(dev, 0x88, ULI_PIRQB); + + /* Lan controller: dev 27, func 0 - IRQ6 */ + pci_write_config_byte(dev, 0x89, ULI_PIRQF); + + /* AC97 Audio controller: dev 29, func 0 - IRQ6 */ + pci_write_config_byte(dev, 0x8a, ULI_PIRQF); + + /* Modem controller: dev 29, func 1 - IRQ6 */ + pci_write_config_byte(dev, 0x8b, ULI_PIRQF); + + /* HD Audio controller: dev 29, func 2 - IRQ6 */ + pci_write_config_byte(dev, 0x8c, ULI_PIRQF); + + /* SATA controller: dev 31, func 1 - IRQ5 */ + pci_write_config_byte(dev, 0x8d, ULI_PIRQE); + + /* SMB interrupt: dev 30, func 1 - IRQ7 */ + pci_write_config_byte(dev, 0x8e, ULI_PIRQG); + + /* PMU ACPI SCI interrupt: dev 30, func 2 - IRQ7 */ + pci_write_config_byte(dev, 0x8f, ULI_PIRQG); + + /* USB 2.0 controller: dev 28, func 3 */ + pci_write_config_byte(dev, 0x74, ULI_8259_IRQ11); + + /* Primary PATA IDE IRQ: 14 + * Secondary PATA IDE IRQ: 15 + */ + pci_write_config_byte(dev, 0x44, 0x30 | ULI_8259_IRQ14); + pci_write_config_byte(dev, 0x75, ULI_8259_IRQ15); +} + +static void __devinit quirk_final_uli1575(struct pci_dev *dev) +{ + /* 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 + */ + if (!uses_fsl_uli_m1575) + return; + + outb(0xfa, 0x4d0); + outb(0x1e, 0x4d1); + + /* setup RTC */ + CMOS_WRITE(RTC_SET, RTC_CONTROL); + CMOS_WRITE(RTC_24H, RTC_CONTROL); + + /* ensure month, date, and week alarm fields are ignored */ + CMOS_WRITE(0, RTC_VALID); + + outb_p(0x7c, 0x72); + outb_p(RTC_ALARM_DONT_CARE, 0x73); + + outb_p(0x7d, 0x72); + outb_p(RTC_ALARM_DONT_CARE, 0x73); +} + +/* SATA */ +static void __devinit quirk_uli5288(struct pci_dev *dev) +{ + unsigned char c; + unsigned int d; + + if (!uses_fsl_uli_m1575) + return; + + /* read/write lock */ + pci_read_config_byte(dev, 0x83, &c); + pci_write_config_byte(dev, 0x83, c|0x80); + + pci_read_config_dword(dev, PCI_CLASS_REVISION, &d); + d = (d & 0xff) | (PCI_CLASS_STORAGE_SATA_AHCI << 8); + pci_write_config_dword(dev, PCI_CLASS_REVISION, d); + + /* restore lock */ + pci_write_config_byte(dev, 0x83, c); + + /* disable emulated PATA mode enabled */ + pci_read_config_byte(dev, 0x84, &c); + pci_write_config_byte(dev, 0x84, c & ~0x01); +} + +/* PATA */ +static void __devinit quirk_uli5229(struct pci_dev *dev) +{ + unsigned short temp; + + if (!uses_fsl_uli_m1575) + return; + + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE | + PCI_COMMAND_MASTER | PCI_COMMAND_IO); + + /* Enable Native IRQ 14/15 */ + pci_read_config_word(dev, 0x4a, &temp); + pci_write_config_word(dev, 0x4a, temp | 0x1000); +} + +/* We have to do a dummy read on the P2P for the RTC to work, WTF */ +static void __devinit quirk_final_uli5249(struct pci_dev *dev) +{ + int i; + u8 *dummy; + struct pci_bus *bus = dev->bus; + + for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { + if ((bus->resource[i]) && + (bus->resource[i]->flags & IORESOURCE_MEM)) { + dummy = ioremap(bus->resource[i]->start, 0x4); + if (dummy) { + in_8(dummy); + iounmap(dummy); + } + break; + } + } +} + +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, 0x5249, early_uli5249); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_uli1575); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, quirk_uli5288); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5249, quirk_final_uli5249); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x1575, quirk_final_uli1575); + +int uli_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) +{ + if (bus == (hose->first_busno + 2)) { + /* exclude Modem controller */ + if ((PCI_SLOT(devfn) == 29) && (PCI_FUNC(devfn) == 1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + /* exclude HD Audio controller */ + if ((PCI_SLOT(devfn) == 29) && (PCI_FUNC(devfn) == 2)) + return PCIBIOS_DEVICE_NOT_FOUND; + } + + return PCIBIOS_SUCCESSFUL; +} -- cgit v1.2.3 From dfa70f81a05fa857fb1428ac2a88da84ecd50dd9 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 17 Aug 2007 13:57:39 +1000 Subject: [POWERPC] pasemi: Another IOMMU bugfix for 64K PAGE_SIZE More fallout from the switch from PAGE_SIZE based IOMMU to the native page size for the driver. By pure luck it happened to work most of the time, since we end up invalidating the wrong entries in the TLB. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/iommu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index f33b21b9f5d..9014d55c717 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -93,7 +93,7 @@ static void iobmap_build(struct iommu_table *tbl, long index, pr_debug("iobmap: build at: %lx, %lx, addr: %lx\n", index, npages, uaddr); - bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; + bus_addr = (tbl->it_offset + index) << IOBMAP_PAGE_SHIFT; ip = ((u32 *)tbl->it_base) + index; @@ -118,7 +118,7 @@ static void iobmap_free(struct iommu_table *tbl, long index, pr_debug("iobmap: free at: %lx, %lx\n", index, npages); - bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; + bus_addr = (tbl->it_offset + index) << IOBMAP_PAGE_SHIFT; ip = ((u32 *)tbl->it_base) + index; @@ -137,7 +137,7 @@ static void iommu_table_iobmap_setup(void) iommu_table_iobmap.it_busno = 0; iommu_table_iobmap.it_offset = 0; /* it_size is in number of entries */ - iommu_table_iobmap.it_size = 0x80000000 >> PAGE_SHIFT; + iommu_table_iobmap.it_size = 0x80000000 >> IOBMAP_PAGE_SHIFT; /* Initialize the common IOMMU code */ iommu_table_iobmap.it_base = (unsigned long)iob_l2_base; -- cgit v1.2.3 From fa7f374bbf6d8e5fc7dd281a62498041066aaf43 Mon Sep 17 00:00:00 2001 From: Christian Krafft Date: Thu, 23 Aug 2007 03:01:25 +1000 Subject: [POWERPC] spu_manage: Use newer physical-id attribute Legacy device tree used the reg property for the physical id of an spe. On newer device tree layouts the reg property contains the "correct" value in the reg attribute. So there has been intoduced the "physical-id" on newer devicetree layouts. The id is stored by spu_manage into the spu struct as spe_id. cbe_thermal has been changed to use the spu->spe_id. There's no need for the thermal code to check devicetree attributes for itself. Signed-off-by: Christian Krafft Cc: Jeremy Kerr Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/cbe_thermal.c | 6 +----- arch/powerpc/platforms/cell/spu_manage.c | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c index e4132f8f51b..fb5eda48467 100644 --- a/arch/powerpc/platforms/cell/cbe_thermal.c +++ b/arch/powerpc/platforms/cell/cbe_thermal.c @@ -88,17 +88,13 @@ static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev) /* returns the value for a given spu in a given register */ static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg) { - const unsigned int *id; union spe_reg value; struct spu *spu; - /* getting the id from the reg attribute will not work on future device-tree layouts - * in future we should store the id to the spu struct and use it here */ spu = container_of(sysdev, struct spu, sysdev); - id = of_get_property(spu_devnode(spu), "reg", NULL); value.val = in_be64(®->val); - return value.spe[*id]; + return value.spe[spu->spe_id]; } static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf) diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index 5eb88346181..7c0668a9dcc 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -48,7 +48,7 @@ static u64 __init find_spu_unit_number(struct device_node *spe) { const unsigned int *prop; int proplen; - prop = of_get_property(spe, "unit-id", &proplen); + prop = of_get_property(spe, "physical-id", &proplen); if (proplen == 4) return (u64)*prop; -- cgit v1.2.3 From 3addf55c9415f9da039947b33d064332137e49fe Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 23 Aug 2007 03:01:26 +1000 Subject: [POWERPC] cell: Support pinhole-reset on IBM cell blades The Cell Broadband Engine has a method of injecting a system-reset-exception from an external source into the operating system, which should trigger the regular behaviour of entering xmon or kdump. Unfortunately, the exception handler cannot distinguish it from other interrupt causes by the SRR1 register, which gets used for this on Power 6 and others. IBM Blade servers that want to support triggering the system reset exception using a pinhole button in the front panel therefore use an extra register to determine the reset cause. Signed-off-by: Arnd Bergmann -- Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/cbe_regs.h | 8 ++++++-- arch/powerpc/platforms/cell/pervasive.c | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h index 17d59714487..b24025f2ac7 100644 --- a/arch/powerpc/platforms/cell/cbe_regs.h +++ b/arch/powerpc/platforms/cell/cbe_regs.h @@ -113,10 +113,14 @@ struct cbe_pmd_regs { u64 checkstop_fir; /* 0x0c00 */ u64 recoverable_fir; /* 0x0c08 */ u64 spec_att_mchk_fir; /* 0x0c10 */ - u64 fir_mode_reg; /* 0x0c18 */ + u32 fir_mode_reg; /* 0x0c18 */ + u8 pad_0x0c1c_0x0c20 [4]; /* 0x0c1c */ +#define CBE_PMD_FIR_MODE_M8 0x00800 u64 fir_enable_mask; /* 0x0c20 */ - u8 pad_0x0c28_0x1000 [0x1000 - 0x0c28]; /* 0x0c28 */ + u8 pad_0x0c28_0x0ca8 [0x0ca8 - 0x0c28]; /* 0x0c28 */ + u64 ras_esc_0; /* 0x0ca8 */ + u8 pad_0x0cb0_0x1000 [0x1000 - 0x0cb0]; /* 0x0cb0 */ }; extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np); diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 812bf563ed6..4ede22d363f 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c @@ -38,6 +38,8 @@ #include "pervasive.h" #include "cbe_regs.h" +static int sysreset_hack; + static void cbe_power_save(void) { unsigned long ctrl, thread_switch_control; @@ -85,6 +87,9 @@ static void cbe_power_save(void) static int cbe_system_reset_exception(struct pt_regs *regs) { + int cpu; + struct cbe_pmd_regs __iomem *pmd; + switch (regs->msr & SRR1_WAKEMASK) { case SRR1_WAKEEE: do_IRQ(regs); @@ -93,6 +98,18 @@ static int cbe_system_reset_exception(struct pt_regs *regs) timer_interrupt(regs); break; case SRR1_WAKEMT: + /* + * The BMC can inject user triggered system reset exceptions, + * but cannot set the system reset reason in srr1, + * so check an extra register here. + */ + if (sysreset_hack && (cpu = smp_processor_id()) == 0) { + pmd = cbe_get_cpu_pmd_regs(cpu); + if (in_be64(&pmd->ras_esc_0) & 0xffff) { + out_be64(&pmd->ras_esc_0, 0); + return 0; + } + } break; #ifdef CONFIG_CBE_RAS case SRR1_WAKESYSERR: @@ -113,9 +130,12 @@ static int cbe_system_reset_exception(struct pt_regs *regs) void __init cbe_pervasive_init(void) { int cpu; + if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) return; + sysreset_hack = machine_is_compatible("IBM,CBPLUS-1.0"); + for_each_possible_cpu(cpu) { struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu); if (!regs) @@ -124,6 +144,12 @@ void __init cbe_pervasive_init(void) /* Enable Pause(0) control bit */ out_be64(®s->pmcr, in_be64(®s->pmcr) | CBE_PMD_PAUSE_ZERO_CONTROL); + + /* Enable JTAG system-reset hack */ + if (sysreset_hack) + out_be32(®s->fir_mode_reg, + in_be32(®s->fir_mode_reg) | + CBE_PMD_FIR_MODE_M8); } ppc_md.power_save = cbe_power_save; -- cgit v1.2.3