|
@@ -0,0 +1,126 @@
|
|
|
+/*
|
|
|
+ * linux/arch/arm/kernel/bios32.c
|
|
|
+ *
|
|
|
+ * PCI bios-type initialisation for PCI machines
|
|
|
+ *
|
|
|
+ * Bits taken from various places.
|
|
|
+ */
|
|
|
+#include <linux/export.h>
|
|
|
+#include <linux/kernel.h>
|
|
|
+#include <linux/pci.h>
|
|
|
+#include <linux/slab.h>
|
|
|
+#include <linux/init.h>
|
|
|
+#include <linux/io.h>
|
|
|
+
|
|
|
+#include <asm/mach-types.h>
|
|
|
+#include <asm/mach/map.h>
|
|
|
+#include <asm/mach/pci.h>
|
|
|
+
|
|
|
+static int debug_pci;
|
|
|
+
|
|
|
+/*
|
|
|
+ * We can't use pci_find_device() here since we are
|
|
|
+ * called from interrupt context.
|
|
|
+ */
|
|
|
+static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, int warn)
|
|
|
+{
|
|
|
+ struct pci_dev *dev;
|
|
|
+
|
|
|
+ list_for_each_entry(dev, &bus->devices, bus_list) {
|
|
|
+ u16 status;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * ignore host bridge - we handle
|
|
|
+ * that separately
|
|
|
+ */
|
|
|
+ if (dev->bus->number == 0 && dev->devfn == 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ pci_read_config_word(dev, PCI_STATUS, &status);
|
|
|
+ if (status == 0xffff)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if ((status & status_mask) == 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /* clear the status errors */
|
|
|
+ pci_write_config_word(dev, PCI_STATUS, status & status_mask);
|
|
|
+
|
|
|
+ if (warn)
|
|
|
+ printk("(%s: %04X) ", pci_name(dev), status);
|
|
|
+ }
|
|
|
+
|
|
|
+ list_for_each_entry(dev, &bus->devices, bus_list)
|
|
|
+ if (dev->subordinate)
|
|
|
+ pcibios_bus_report_status(dev->subordinate, status_mask, warn);
|
|
|
+}
|
|
|
+
|
|
|
+void pcibios_report_status(u_int status_mask, int warn)
|
|
|
+{
|
|
|
+ struct list_head *l;
|
|
|
+
|
|
|
+ list_for_each(l, &pci_root_buses) {
|
|
|
+ struct pci_bus *bus = pci_bus_b(l);
|
|
|
+
|
|
|
+ pcibios_bus_report_status(bus, status_mask, warn);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * We don't use this to fix the device, but initialisation of it.
|
|
|
+ * It's not the correct use for this, but it works.
|
|
|
+ * Note that the arbiter/ISA bridge appears to be buggy, specifically in
|
|
|
+ * the following area:
|
|
|
+ * 1. park on CPU
|
|
|
+ * 2. ISA bridge ping-pong
|
|
|
+ * 3. ISA bridge master handling of target RETRY
|
|
|
+ *
|
|
|
+ * Bug 3 is responsible for the sound DMA grinding to a halt. We now
|
|
|
+ * live with bug 2.
|
|
|
+ */
|
|
|
+static void pci_fixup_83c553(struct pci_dev *dev)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Set memory region to start at address 0, and enable IO
|
|
|
+ */
|
|
|
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_SPACE_MEMORY);
|
|
|
+ pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_IO);
|
|
|
+
|
|
|
+ dev->resource[0].end -= dev->resource[0].start;
|
|
|
+ dev->resource[0].start = 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * All memory requests from ISA to be channelled to PCI
|
|
|
+ */
|
|
|
+ pci_write_config_byte(dev, 0x48, 0xff);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Enable ping-pong on bus master to ISA bridge transactions.
|
|
|
+ * This improves the sound DMA substantially. The fixed
|
|
|
+ * priority arbiter also helps (see below).
|
|
|
+ */
|
|
|
+ pci_write_config_byte(dev, 0x42, 0x01);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Enable PCI retry
|
|
|
+ */
|
|
|
+ pci_write_config_byte(dev, 0x40, 0x22);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We used to set the arbiter to "park on last master" (bit
|
|
|
+ * 1 set), but unfortunately the CyberPro does not park the
|
|
|
+ * bus. We must therefore park on CPU. Unfortunately, this
|
|
|
+ * may trigger yet another bug in the 553.
|
|
|
+ */
|
|
|
+ pci_write_config_byte(dev, 0x83, 0x02);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Make the ISA DMA request lowest priority, and disable
|
|
|
+ * rotating priorities completely.
|
|
|
+ */
|
|
|
+ pci_write_config_byte(dev, 0x80, 0x11);
|
|
|
+ pci_write_config_byte(dev, 0x81, 0x00);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Route INTA input to IRQ 11, and set IRQ11 to be level
|
|
|
+ * sensitive.
|