[PATCH] Use IRQ and senses from OF-tree on 8641hpcn.
Benjamin Herrenschmidt
benh at kernel.crashing.org
Fri Jun 23 10:11:37 EST 2006
> -static void __devinit quirk_ali1575(struct pci_dev *dev)
> +static int __init get_pci_irq_from_of(struct pci_controller *hose,
> + int slot, int pin)
> +{
> + struct device_node *node;
> + unsigned long *interrupt, *interrupt_mask;
> + int len, mask_len;
> + int shift, i;
> + int irq = 0;
> +
> + if (!hose) {
> + printk(KERN_ERR "No PCI hose found!\n");
> + return -EFAULT;
> + }
> +
> + node = (struct device_node *)hose->arch_data;
> + interrupt = (unsigned long *)get_property(node,
> + "interrupt-map", &len);
> + interrupt_mask = (unsigned long *)get_property(node,
> + "interrupt-map-mask", &mask_len);
> + if (!interrupt || !interrupt_mask) {
> + printk(KERN_ERR "No PCI interrupt-map or interrupt-map-mask"
> + "property in OpenFirmware device tree!\n");
> + return -EFAULT;
> + }
> + shift = __ilog2((~interrupt_mask[0] + 1) & 0xffff);
Nice hack :)
But not something mergeable as it strictly relies on the specific format
of the interrupt map on that platform :) I have a generic parser on the
way, it's hot and will be released for public consumption later today or
this week-end along with the rest of the irq patches.
I'll need you guys to help porting the few embedded boards already in
arch/powerpc.
Ben.
> + /*
> + * Find matched irq in interrupt-map node of OF-tree.
> + *
> + * interrupt-map entries format:
> + * <slot> <pin> <interrupt-parent> <irq#>
> + * 8800 0 0 1 40000 3 0
> + */
> + pr_debug("PCI slot %x, pin %d ", slot, pin);
> + for (i = 0; i < (len / 7); i++)
> + if (((interrupt[i * 7] & interrupt_mask[0]) == (slot << shift))
> + && (interrupt[i * 7 + 3] == pin))
> + irq = interrupt[i * 7 + 5] & interrupt_mask[3];
> + pr_debug("irq %d\n", irq);
> +
> + if (!irq)
> + printk(KERN_WARNING "PCI Slot %d, Pin %d device "
> + "has no matched irq!\n", slot, pin);
> +
> + return irq;
> +}
> +
> +static int __init mpc86xx_irq_fixup(struct pci_dev *dev)
> +{
> + struct pci_controller *hose = NULL;
> + int pin, slot;
> +
> + hose = pci_bus_to_hose(dev->bus->number);
> + if (!hose) {
> + printk(KERN_ERR "No PCI hose found!\n");
> + return -EFAULT;
> + }
> +
> + pin = dev->pin;
> + if (dev->bus->number != hose->first_busno) {
> + do {
> + pin = ((pin-1) + PCI_SLOT(dev->devfn)) %4 + 1;
> + /* Move up the chain of bridges. */
> + dev = dev->bus->self;
> + } while (dev->bus->self);
> + /* The slot is the idsel of the last bridge. */
> + }
> + slot = PCI_SLOT(dev->devfn);
> +
> + return get_pci_irq_from_of(hose, slot, pin);
> +}
> +
> +void __init mpc86xx_pcibios_fixup(void)
> +{
> + struct pci_dev *dev = NULL;
> +
> + for_each_pci_dev(dev) {
> + dev->irq = mpc86xx_irq_fixup(dev);
> + if (dev->irq < 0)
> + return;
> + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
> + }
> +}
> +
> +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 void __devinit quirk_uli1575(struct pci_dev *dev)
> {
> unsigned short temp;
> + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
> + int i, irq;
> + unsigned char irq2pin[16];
> + unsigned long pirq_map_word = 0;
> +
> + if (!hose) {
> + printk(KERN_ERR "No PCI hose!\n");
> + return;
> + }
>
> /*
> - * ALI1575 interrupts route table setup:
> + * 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 <= 15)
> + irq2pin[irq] = PIRQA + i;
> + }
> +
> + /*
> + * PIRQE -> PIRQF mapping set manually
> *
> * IRQ pin IRQ#
> - * PIRQA ---- 3
> - * PIRQB ---- 4
> - * PIRQC ---- 5
> - * PIRQD ---- 6
> * PIRQE ---- 9
> * PIRQF ---- 10
> * PIRQG ---- 11
> * PIRQH ---- 12
> - *
> - * interrupts for PCI slot0 -- PIRQA / PIRQB / PIRQC / PIRQD
> - * PCI slot1 -- PIRQB / PIRQC / PIRQD / PIRQA
> */
> - pci_write_config_dword(dev, 0x48, 0xb9317542);
> + for (i = 0; i < 4; i++) irq2pin[i + 9] = PIRQE + i;
>
> - /* USB 1.1 OHCI controller 1, interrupt: PIRQE */
> - pci_write_config_byte(dev, 0x86, 0x0c);
> + /* 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);
>
> - /* USB 1.1 OHCI controller 2, interrupt: PIRQF */
> - pci_write_config_byte(dev, 0x87, 0x0d);
> + DBG("Setup ULI1575 IRQ mapping configuration register value = 0x%x\n",
> + pirq_map_word);
> + pci_write_config_dword(dev, 0x48, pirq_map_word);
>
> - /* USB 1.1 OHCI controller 3, interrupt: PIRQH */
> - pci_write_config_byte(dev, 0x88, 0x0f);
> +#define ULI1575_SET_DEV_IRQ(slot, pin, reg) \
> + do { \
> + int irq; \
> + irq = get_pci_irq_from_of(hose, slot, pin); \
> + if (irq >= 0 && irq <=15) \
> + pci_write_config_byte(dev, reg, irq2pin[irq]); \
> + } while(0)
>
> - /* USB 2.0 controller, interrupt: PIRQ7 */
> - pci_write_config_byte(dev, 0x74, 0x06);
> + /* USB 1.1 OHCI controller 1, slot 28, pin 1 */
> + ULI1575_SET_DEV_IRQ(28, 1, 0x86);
>
> - /* Audio controller, interrupt: PIRQE */
> - pci_write_config_byte(dev, 0x8a, 0x0c);
> + /* USB 1.1 OHCI controller 2, slot 28, pin 2 */
> + ULI1575_SET_DEV_IRQ(28, 2, 0x87);
>
> - /* Modem controller, interrupt: PIRQF */
> - pci_write_config_byte(dev, 0x8b, 0x0d);
> + /* USB 1.1 OHCI controller 3, slot 28, pin 3 */
> + ULI1575_SET_DEV_IRQ(28, 3, 0x88);
>
> - /* HD audio controller, interrupt: PIRQG */
> - pci_write_config_byte(dev, 0x8c, 0x0e);
> + /* 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]);
>
> - /* Serial ATA interrupt: PIRQD */
> - pci_write_config_byte(dev, 0x8d, 0x0b);
> + /* Audio controller, slot 29, pin 1 */
> + ULI1575_SET_DEV_IRQ(29, 1, 0x8a);
>
> - /* SMB interrupt: PIRQH */
> - pci_write_config_byte(dev, 0x8e, 0x0f);
> + /* Modem controller, slot 29, pin 2 */
> + ULI1575_SET_DEV_IRQ(29, 2, 0x8b);
>
> - /* PMU ACPI SCI interrupt: PIRQH */
> - pci_write_config_byte(dev, 0x8f, 0x0f);
> + /* 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, 0x3d);
> - pci_write_config_byte(dev, 0x75, 0x0f);
> + 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);
> @@ -277,6 +421,8 @@ static void __devinit quirk_ali1575(stru
> */
> outb(0xfa, 0x4d0);
> outb(0x1e, 0x4d1);
> +
> +#undef ULI1575_SET_DEV_IRQ
> }
>
> static void __devinit quirk_uli5288(struct pci_dev *dev)
> @@ -319,7 +465,7 @@ static void __devinit early_uli5249(stru
> dev->class |= 0x1;
> }
>
> -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_ali1575);
> +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);
More information about the Linuxppc-dev
mailing list