|  | @@ -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.
 |