diff options
Diffstat (limited to 'arch/mips/ddb5074')
-rw-r--r-- | arch/mips/ddb5074/irq.c | 2 | ||||
-rw-r--r-- | arch/mips/ddb5074/pci-dma.c | 38 | ||||
-rw-r--r-- | arch/mips/ddb5074/pci.c | 248 |
3 files changed, 167 insertions, 121 deletions
diff --git a/arch/mips/ddb5074/irq.c b/arch/mips/ddb5074/irq.c index 4fee350e2..2f67721da 100644 --- a/arch/mips/ddb5074/irq.c +++ b/arch/mips/ddb5074/irq.c @@ -30,7 +30,7 @@ extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs); extern asmlinkage void do_IRQ(int irq, struct pt_regs * regs); -static void no_action(int cpl, void *dev_id, struct pt_regs *regs) +void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } diff --git a/arch/mips/ddb5074/pci-dma.c b/arch/mips/ddb5074/pci-dma.c new file mode 100644 index 000000000..1309e5eee --- /dev/null +++ b/arch/mips/ddb5074/pci-dma.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> + * + * + * Dynamic DMA mapping support. + * + * swiped from i386, and cloned for MIPS by Geert. + * + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <asm/io.h> + +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + + if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, get_order(size)); +} diff --git a/arch/mips/ddb5074/pci.c b/arch/mips/ddb5074/pci.c index e0f39c666..e0ca01d17 100644 --- a/arch/mips/ddb5074/pci.c +++ b/arch/mips/ddb5074/pci.c @@ -169,162 +169,100 @@ struct pci_ops nile4_pci_ops = { }; -static void __init pcibios_claim_resources(struct list_head *bus_list) +static void __init ddb5074_preassign_resources(void) { - struct list_head *ln, *dn; - struct pci_bus *bus; struct pci_dev *dev; - int idx; - - for (ln = bus_list->next; ln != bus_list; ln = ln->next) { - bus = pci_bus_b(ln); - for (dn = bus->devices.next; dn != &bus->devices; dn = dn->next) { - dev = pci_dev_b(dn); - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { - struct resource *r = &dev->resource[idx]; - struct resource *pr; - if (!r->start) - continue; - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { - printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); - /* We probably should disable the region, shouldn't we? */ - } - } + + pci_for_each_dev(dev) { + if (dev->vendor == PCI_VENDOR_ID_NEC && + dev->device == PCI_DEVICE_ID_NEC_NILE4) { + /* + * Fixup so the serial driver can use the UART + */ + dev->resource[0].start = PHYSADDR(NILE4_BASE); + dev->resource[0].end = dev->resource[0].start+NILE4_SIZE-1; + dev->resource[0].flags = IORESOURCE_MEM | + PCI_BASE_ADDRESS_MEM_TYPE_64; + pci_claim_resource(dev, 0); + /* + * Leave resource[2] (physical memory) alone + */ + pci_claim_resource(dev, 2); + } else if (dev->vendor == PCI_VENDOR_ID_AL && + dev->device == PCI_DEVICE_ID_AL_M7101) { + extern struct pci_dev *pci_pmu; + u8 t8; + + pci_pmu = dev; /* for LEDs D2 and D3 */ + /* Program the lines for LEDs D2 and D3 to output */ + nile4_pci_read_config_byte(dev, 0x7d, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7d, t8); + /* Turn LEDs D2 and D3 off */ + nile4_pci_read_config_byte(dev, 0x7e, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7e, t8); } - pcibios_claim_resources(&bus->children); } } - -void pcibios_init(void) -{ - printk("PCI: Probing PCI hardware\n"); - ioport_resource.end = 0x1ffffff; - pci_scan_bus(0, &nile4_pci_ops, NULL); - pcibios_claim_resources(&pci_root_buses); -} - -void pcibios_fixup_bus(struct pci_bus *bus) +static void __init pcibios_fixup_irqs(void) { - struct list_head *dn; struct pci_dev *dev; - extern struct pci_dev *pci_pmu; /* for LEDs D2 and D3 */ - int slot_num, func_num; - u8 t8; - - /* - * FIXME: PMON doesn't autoconfigure the PCI devices - * For now we just hardcode them for our configuration - */ - printk("PCI: Configuring PCI devices (hardcoded)\n"); - for (dn = bus->devices.next; dn != &bus->devices; dn = dn->next) { - dev = pci_dev_b(dn); + int slot_num; + pci_for_each_dev(dev) { slot_num = PCI_SLOT(dev->devfn); - func_num = PCI_FUNC(dev->devfn); - printk(" Device %2d: ", slot_num); switch (slot_num) { case 0: - printk("[onboard] Acer Labs M1533 Aladdin IV\n"); dev->irq = nile4_to_irq(NILE4_INT_INTE); break; case 1: - printk("[onboard] DEC DC21140\n"); dev->irq = nile4_to_irq(NILE4_INT_INTA); - dev->resource[0].start = 0x100000; - dev->resource[0].end = dev->resource[0].start+0x7f; - nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - dev->resource[0].start); - dev->resource[1].start = 0x1000000; - dev->resource[1].end = dev->resource[1].start+0x7f; - nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - dev->resource[1].start); break; - case 2: - printk("[slot 1] Realtek 8029\n"); + case 2: /* slot 1 */ dev->irq = nile4_to_irq(NILE4_INT_INTA); - dev->resource[0].start = 0x800000; - dev->resource[0].end = dev->resource[0].start+0x1f; - nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - dev->resource[0].start); break; - case 3: - printk("[slot 2] DEC DC21140 (#2)\n"); + case 3: /* slot 2 */ dev->irq = nile4_to_irq(NILE4_INT_INTB); - dev->resource[0].start = 0x1000000; - dev->resource[0].end = dev->resource[0].start+0x7f; - nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - dev->resource[0].start); - dev->resource[1].start = 0x4000000; - dev->resource[1].end = dev->resource[1].start+0x7f; - nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - dev->resource[1].start); break; - case 4: - printk("[slot 3] Promise Technology IDE UltraDMA/33"); - printk(" or 3Com 3c905 :-)\n"); + case 4: /* slot 3 */ dev->irq = nile4_to_irq(NILE4_INT_INTC); - dev->resource[0].start = 0x1800000; - dev->resource[0].end = dev->resource[0].start+0x7fffff; - nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - dev->resource[0].start); break; case 5: - printk("[onboard] NEC Vrc-5074 Nile 4 Host Bridge\n"); /* * Fixup so the serial driver can use the UART */ dev->irq = nile4_to_irq(NILE4_INT_UART); - dev->resource[0].start = PHYSADDR(NILE4_BASE); - dev->resource[0].end = dev->resource[0].start+NILE4_SIZE-1; - dev->resource[0].flags = IORESOURCE_MEM | - PCI_BASE_ADDRESS_MEM_TYPE_64; - - break; - case 10: - printk("[onboard] Acer Labs M7101 PMU\n"); - pci_pmu = dev; - /* Program the lines for LEDs D2 and D3 to output */ - nile4_pci_read_config_byte(dev, 0x7d, &t8); - t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7d, t8); - /* Turn LEDs D2 and D3 off */ - nile4_pci_read_config_byte(dev, 0x7e, &t8); - t8 |= 0xc0; - nile4_pci_write_config_byte(dev, 0x7e, t8); break; case 13: - printk("[onboard] Acer Labs M5237 USB\n"); dev->irq = nile4_to_irq(NILE4_INT_INTE); - dev->resource[0].start = 0x1001000; - dev->resource[0].end = dev->resource[0].start+0xfff; - nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - dev->resource[0].start); break; default: - printk("\n"); break; } } } -char *pcibios_setup (char *str) +void __init pcibios_init(void) { - return str; + printk("PCI: Probing PCI hardware\n"); + ioport_resource.end = 0x1ffffff; /* 32 MB */ + iomem_resource.end = 0x1fffffff; /* 512 MB */ + pci_scan_bus(0, &nile4_pci_ops, NULL); + ddb5074_preassign_resources(); + pci_assign_unassigned_resources(); + pci_set_bus_ranges(); + pcibios_fixup_irqs(); } -void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root, - struct resource *res, int resource) +void __init pcibios_fixup_bus(struct pci_bus *bus) { - unsigned long where, size; - u32 reg; - - where = PCI_BASE_ADDRESS_0 + (resource * 4); - size = res->end - res->start; - pci_read_config_dword(dev, where, ®); - reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); - pci_write_config_dword(dev, where, reg); +} + +char *pcibios_setup (char *str) +{ + return str; } void __init pcibios_update_irq(struct pci_dev *dev, int irq) @@ -341,15 +279,85 @@ void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, ranges->mem_end -= bus->resource[1]->start; } -int __init pcibios_enable_device(struct pci_dev *dev) +int pcibios_enable_resources(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +int pcibios_enable_device(struct pci_dev *dev) { - printk("pcibios_enable_device for %04x:%04x\n", dev->vendor, dev->device); - panic("pcibios_enable_device: not yet implemented\n"); + return pcibios_enable_resources(dev); +} + +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + u32 new, check; + int reg; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } +} + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + /* We need to avoid collisions with `mirrored' VGA ports + and other strange ISA hardware, so we always want the + addresses kilobyte aligned. */ + if (size > 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", dev->slot_name, + dev->resource - res, size); + } + + start = (start + 1024 - 1) & ~(1024 - 1); + res->start = start; + } } -void __init pcibios_align_resource(void *data, struct resource *res, - unsigned long size) -{} struct pci_fixup pcibios_fixups[] = {}; |