patch-2.4.4 linux/arch/mips/ddb5476/pci.c
Next file: linux/arch/mips/ddb5476/prom.c
Previous file: linux/arch/mips/ddb5476/nile4.c
Back to the patch index
Back to the overall index
- Lines: 496
- Date:
Fri Apr 13 20:26:07 2001
- Orig file:
v2.4.3/linux/arch/mips/ddb5476/pci.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.4.3/linux/arch/mips/ddb5476/pci.c linux/arch/mips/ddb5476/pci.c
@@ -0,0 +1,495 @@
+/*
+ * arch/mips/ddb5476/pci.c -- NEC DDB Vrc-5074 PCI access routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Albert Dorofeev <albert@sonycom.com>
+ * Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+
+#include <asm-mips/nile4.h>
+
+
+static u32 nile4_pre_pci_access0(int slot_num)
+{
+ u32 pci_addr = 0;
+ u32 virt_addr = NILE4_PCI_CFG_BASE;
+
+ /* work around the bug for Vrc5476 */
+ if (slot_num == 13)
+ return NILE4_BASE + NILE4_PCI_BASE;
+
+ /* Set window 1 address 08000000 - 32 bit - 128 MB (PCI config space) */
+ nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x08000000, 32, 0,
+ 0);
+
+ // [jsun] we start scanning from addr:10,
+ // with 128M we can go up to addr:26 (slot 16)
+ if (slot_num <= 16) {
+ virt_addr += 0x00000400 << slot_num;
+ } else {
+ /* for high slot, we have to set higher PCI base addr */
+ pci_addr = 0x00000400 << slot_num;
+ }
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr);
+ return virt_addr;
+}
+
+static void nile4_post_pci_access0(void)
+{
+ /*
+ * Set window 1 back to address 08000000 - 32 bit - 128 MB
+ * (PCI IO space)
+ */
+ nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE),
+ 0x08000000, 32, 1, 1);
+ // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000);
+}
+
+
+static int nile4_pci_read_config_dword(struct pci_dev *dev,
+ int where, u32 * val)
+{
+ int slot_num, func_num;
+ u32 base;
+ u32 addr;
+
+ /*
+ * Do we need to generate type 1 configure transaction?
+ */
+ if (dev->bus->number) {
+ /* FIXME - not working yet */
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ /*
+ * the largest type 1 configuration addr is 16M, < 256M
+ * config space
+ */
+ slot_num = 0;
+ addr =
+ (dev->bus->number << 16) | (dev->devfn <
+ 8) | where | 1;
+ } else {
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ addr = (func_num << 8) + where;
+ }
+
+ base = nile4_pre_pci_access0(slot_num);
+ *val = *(volatile u32 *) (base + addr);
+ nile4_post_pci_access0();
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_write_config_dword(struct pci_dev *dev, int where,
+ u32 val)
+{
+ int slot_num, func_num;
+ u32 base;
+ u32 addr;
+
+ /*
+ * Do we need to generate type 1 configure transaction?
+ */
+ if (dev->bus->number) {
+ /* FIXME - not working yet */
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ /* the largest type 1 configuration addr is 16M, < 256M config space */
+ slot_num = 0;
+ addr =
+ (dev->bus->number << 16) | (dev->devfn <
+ 8) | where | 1;
+ } else {
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ addr = (func_num << 8) + where;
+ }
+
+ base = nile4_pre_pci_access0(slot_num);
+ *(volatile u32 *) (base + addr) = val;
+ nile4_post_pci_access0();
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_read_config_word(struct pci_dev *dev, int where,
+ u16 * val)
+{
+ int status;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xffff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_read_config_byte(struct pci_dev *dev, int where,
+ u8 * val)
+{
+ int status;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 1)
+ result >>= 8;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_write_config_word(struct pci_dev *dev, int where,
+ u16 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ shift += 16;
+ result &= ~(0xffff << shift);
+ result |= val << shift;
+ return nile4_pci_write_config_dword(dev, where & ~3, result);
+}
+
+static int nile4_pci_write_config_byte(struct pci_dev *dev, int where,
+ u8 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ shift += 16;
+ if (where & 1)
+ shift += 8;
+ result &= ~(0xff << shift);
+ result |= val << shift;
+ return nile4_pci_write_config_dword(dev, where & ~3, result);
+}
+
+struct pci_ops nile4_pci_ops = {
+ nile4_pci_read_config_byte,
+ nile4_pci_read_config_word,
+ nile4_pci_read_config_dword,
+ nile4_pci_write_config_byte,
+ nile4_pci_write_config_word,
+ nile4_pci_write_config_dword
+};
+
+struct {
+ struct resource ram;
+ struct resource flash;
+ struct resource isa_io;
+ struct resource pci_io;
+ struct resource isa_mem;
+ struct resource pci_mem;
+ struct resource nile4;
+ struct resource boot;
+} ddb5476_resources = {
+ // { "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
+ {
+ "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM}, {
+ "Flash ROM", 0x04000000, 0x043fffff}, {
+ "Nile4 ISA I/O", 0x06000000, 0x060fffff}, {
+ "Nile4 PCI I/O", 0x06100000, 0x07ffffff}, {
+ "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM}, {
+ "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM},
+ // { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
+ {
+ "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM}, {
+ "Boot ROM", 0x1fc00000, 0x1fffffff}
+};
+
+struct resource M5229_resources[5] = {
+ {"M5229 BAR0", 0x1f0, 0x1f3, IORESOURCE_IO},
+ {"M5229 BAR1", 0x3f4, 0x3f7, IORESOURCE_IO},
+ {"M5229 BAR2", 0x170, 0x173, IORESOURCE_IO},
+ {"M5229 BAR3", 0x374, 0x377, IORESOURCE_IO},
+ {"M5229 BAR4", 0xf000, 0xf00f, IORESOURCE_IO}
+};
+
+static void __init ddb5476_pci_fixup(void)
+{
+ struct pci_dev *dev;
+
+ pci_for_each_dev(dev) {
+ if (dev->vendor == PCI_VENDOR_ID_NEC &&
+ dev->device == PCI_DEVICE_ID_NEC_VRC5476) {
+ /*
+ * The first 64-bit PCI base register should point to
+ * the Nile4 control registers. Unfortunately this
+ * isn't the case, so we fix it ourselves. This allows
+ * the serial driver to find the UART.
+ */
+ dev->resource[0] = ddb5476_resources.nile4;
+ request_resource(&iomem_resource,
+ &dev->resource[0]);
+ /*
+ * The second 64-bit PCI base register points to the
+ * first memory bank. Unfortunately the address is
+ * wrong, so we fix it (again).
+ */
+
+ /* [jsun] We cannot request the resource anymore,
+ * because kernel/setup.c has already reserved "System
+ * RAM" resource at the same spot.
+ * The fundamental problem here is that PCI host
+ * controller should not put system RAM mapping in BAR
+ * and make subject to PCI resource assignement.
+ * Current fix is a total hack. We set parent to 1 so
+ * so that PCI resource assignement code is fooled to
+ * think the resource is assigned, and will not attempt
+ * to mess with it.
+ */
+ dev->resource[2] = ddb5476_resources.ram;
+ if (request_resource(&iomem_resource,
+ &dev->resource[2]) ) {
+ dev->resource[2].parent = 0x1;
+ }
+
+ } else if (dev->vendor == PCI_VENDOR_ID_AL
+ && dev->device == PCI_DEVICE_ID_AL_M7101) {
+ /*
+ * It's nice to have the LEDs on the GPIO pins
+ * available for debugging
+ */
+ 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);
+ } else if (dev->vendor == PCI_VENDOR_ID_AL &&
+ dev->device == 0x5229) {
+ int i;
+ for (i = 0; i < 5; i++) {
+ dev->resource[i] = M5229_resources[i];
+ request_resource(&ioport_resource,
+ &dev->resource[i]);
+ }
+ }
+ }
+}
+
+static void __init pcibios_fixup_irqs(void)
+{
+ struct pci_dev *dev;
+ int slot_num;
+
+ pci_for_each_dev(dev) {
+ slot_num = PCI_SLOT(dev->devfn);
+ switch (slot_num) {
+ case 3: /* re-programmed to USB */
+ dev->irq = 9; /* hard-coded; see irq.c */
+ break;
+ case 4: /* re-programmed to PMU */
+ dev->irq = 10; /* hard-coded; see irq.c */
+ break;
+ case 6: /* on-board pci-pci bridge */
+ dev->irq = 0xff;
+ break;
+ case 7: /* on-board ether */
+ dev->irq = nile4_to_irq(NILE4_INT_INTB);
+ break;
+ case 8: /* ISA-PCI bridge */
+ dev->irq = nile4_to_irq(NILE4_INT_INTC);
+ break;
+ case 9: /* ext slot #3 */
+ dev->irq = nile4_to_irq(NILE4_INT_INTD);
+ break;
+ case 10: /* ext slot #4 */
+ dev->irq = nile4_to_irq(NILE4_INT_INTA);
+ break;
+ case 13: /* Vrc5476 */
+ dev->irq = 0xff;
+ break;
+ case 14: /* HD controller, M5229 */
+ dev->irq = 14;
+ break;
+ default:
+ printk
+ ("JSUN : in pcibios_fixup_irqs - unkown slot %d\n",
+ slot_num);
+ panic
+ ("JSUN : in pcibios_fixup_irqs - unkown slot.\n");
+ }
+ }
+}
+
+void __init pcibios_init(void)
+{
+ printk("PCI: Emulate bios initialization \n");
+ /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */
+ *(long *) (NILE4_BASE + NILE4_BAR0) = 0x8;
+
+ printk("PCI: Probing PCI hardware\n");
+ ioport_resource.end = 0x1ffffff; /* 32 MB */
+ iomem_resource.end = 0x1fffffff; /* 512 MB */
+
+ /* `ram' and `nile4' are requested through the Nile4 pci_dev */
+ request_resource(&iomem_resource, &ddb5476_resources.flash);
+ request_resource(&iomem_resource, &ddb5476_resources.isa_io);
+ request_resource(&iomem_resource, &ddb5476_resources.pci_io);
+ request_resource(&iomem_resource, &ddb5476_resources.isa_mem);
+ request_resource(&iomem_resource, &ddb5476_resources.pci_mem);
+ request_resource(&iomem_resource, &ddb5476_resources.boot);
+
+ pci_scan_bus(0, &nile4_pci_ops, NULL);
+ ddb5476_pci_fixup();
+ pci_assign_unassigned_resources();
+ pcibios_fixup_irqs();
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+ /* [jsun] we don't know how to fix sub-buses yet */
+ if (bus->number == 0) {
+ bus->resource[1] = &ddb5476_resources.pci_mem;
+ }
+}
+
+char *pcibios_setup(char *str)
+{
+ return str;
+}
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
+ struct pbus_set_ranges_data *ranges)
+{
+ /*
+ * our caller figure out range by going through the dev structures.
+ * I guess this is the place to fix things up if the bus is using a
+ * different view of the addressing space.
+ */
+
+#if 0 /* original DDB5074 code */
+ if (bus->number == 0) {
+ ranges->io_start -= bus->resource[0]->start;
+ ranges->io_end -= bus->resource[0]->start;
+ ranges->mem_start -= bus->resource[1]->start;
+ ranges->mem_end -= bus->resource[1]->start;
+ }
+#endif
+}
+
+int pcibios_enable_resources(struct pci_dev *dev)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ /*
+ * Don't touch the Nile 4
+ */
+ if (dev->vendor == PCI_VENDOR_ID_NEC &&
+ dev->device == PCI_DEVICE_ID_NEC_VRC5476) return 0;
+
+ 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)
+{
+ 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;
+ }
+}
+
+struct pci_fixup pcibios_fixups[] = { {0} };
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)