diff options
Diffstat (limited to 'target/linux/coldfire/patches/039-Add-PCI-bus-driver-for-M54455EVB-and-M547X_8X.patch')
-rw-r--r-- | target/linux/coldfire/patches/039-Add-PCI-bus-driver-for-M54455EVB-and-M547X_8X.patch | 3051 |
1 files changed, 3051 insertions, 0 deletions
diff --git a/target/linux/coldfire/patches/039-Add-PCI-bus-driver-for-M54455EVB-and-M547X_8X.patch b/target/linux/coldfire/patches/039-Add-PCI-bus-driver-for-M54455EVB-and-M547X_8X.patch new file mode 100644 index 0000000000..6b462fee58 --- /dev/null +++ b/target/linux/coldfire/patches/039-Add-PCI-bus-driver-for-M54455EVB-and-M547X_8X.patch @@ -0,0 +1,3051 @@ +From 3f21ef5f7b72937a1ae293e8ba6ebd0bb0b175e3 Mon Sep 17 00:00:00 2001 +From: Jingchang Lu <b35083@freescale.com> +Date: Thu, 4 Aug 2011 09:59:49 +0800 +Subject: [PATCH 39/52] Add PCI bus driver for M54455EVB and M547X_8X + +Signed-off-by: Jingchang Lu <b35083@freescale.com> +--- + arch/m68k/coldfire/m5445x/devices.c | 9 + + arch/m68k/coldfire/m5445x/mcf5445x-pci.c | 721 +++++++++++++++++++++ + arch/m68k/coldfire/m5445x/pci.c | 247 +++++++ + arch/m68k/coldfire/m547x/pci.c | 1023 ++++++++++++++++++++++++++++++ + arch/m68k/coldfire/m547x/pci_dummy.S | 45 ++ + arch/m68k/include/asm/5445x_pci.h | 111 ++++ + arch/m68k/include/asm/548x_pci.h | 99 +++ + arch/m68k/include/asm/pci.h | 6 + + arch/m68k/kernel/bios32_mcf548x.c | 632 ++++++++++++++++++ + drivers/pci/Makefile | 1 + + drivers/pci/access.c | 18 + + drivers/pci/setup-bus.c | 6 + + lib/iomap.c | 4 + + 13 files changed, 2922 insertions(+), 0 deletions(-) + create mode 100644 arch/m68k/coldfire/m5445x/mcf5445x-pci.c + create mode 100644 arch/m68k/coldfire/m5445x/pci.c + create mode 100644 arch/m68k/coldfire/m547x/pci.c + create mode 100644 arch/m68k/coldfire/m547x/pci_dummy.S + create mode 100644 arch/m68k/include/asm/5445x_pci.h + create mode 100644 arch/m68k/include/asm/548x_pci.h + create mode 100644 arch/m68k/kernel/bios32_mcf548x.c + +--- a/arch/m68k/coldfire/m5445x/devices.c ++++ b/arch/m68k/coldfire/m5445x/devices.c +@@ -25,12 +25,15 @@ + #include <linux/spi/mmc_spi.h> + #endif + ++#include <linux/pci.h> ++ + #include <asm/coldfire.h> + #include <asm/mcfsim.h> + #include <asm/mcfuart.h> + #include <asm/mcfqspi.h> + #include <asm/mcfdspi.h> + #include <asm/cf_io.h> ++#include <asm/pci.h> + + /* ATA Interrupt */ + #define IRQ_ATA (64 + 64 + 54) +@@ -517,6 +520,12 @@ void m5445x_uarts_init(void) + + static int __init init_BSP(void) + { ++#ifndef CONFIG_M54455_PCI_initcall ++#if defined(CONFIG_M54455) && defined(CONFIG_PCI) ++ pci_init(); ++ pcibios_init(); ++#endif ++#endif + m5445x_uarts_init(); + platform_add_devices(m5445x_devices, ARRAY_SIZE(m5445x_devices)); + return 0; +--- /dev/null ++++ b/arch/m68k/coldfire/m5445x/mcf5445x-pci.c +@@ -0,0 +1,721 @@ ++/* ++ * arch/m68k/coldfire/m5445x/mcf5445x-pci.c ++ * ++ * Coldfire M5445x specific PCI implementation. ++ * ++ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Kurt Mahan <kmahan@freescale.com> ++ */ ++ ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/pci.h> ++ ++#include <asm/mcfsim.h> ++#include <asm/pci.h> ++#include <asm/irq.h> ++#include <asm/mcf5445x_pciarb.h> ++#include <asm/mcf5445x_pci.h> ++#include <asm/cf_io.h> ++/* ++ * Layout MCF5445x to PCI memory mappings: ++ * ++ * WIN MCF5445x PCI TYPE ++ * --- -------- --- ---- ++ * [0] 0xA0000000 -> 0xACFFFFFF 0xA0000000 -> 0xACFFFFFF MEM ++ * [1] 0xAC000000 -> 0xAEFFFFFF 0xAC000000 -> 0xAEFFFFFF IO ++ * [2] 0xAF000000 -> 0xAFFFFFFF 0xAF000000 -> 0xAFFFFFFF CONFIG ++ */ ++ ++void __iomem *pci_mem_map; ++unsigned long pci_mem_mapsize = 256 * 1024 * 1024; ++ ++#define MCF5445X_PCI_MEM_BASE ((unsigned int)pci_mem_map) ++#define MCF5445X_PCI_MEM_BASE_PHY 0xA0000000 ++#define MCF5445X_PCI_MEM_SIZE 0x0C000000 ++ ++#define MCF5445X_PCI_IO_BASE \ ++ (MCF5445X_PCI_MEM_BASE + MCF5445X_PCI_MEM_SIZE) ++#define MCF5445X_PCI_IO_SIZE 0x03000000 ++ ++#define MCF5445X_PCI_CONFIG_BASE \ ++ (MCF5445X_PCI_IO_BASE + MCF5445X_PCI_IO_SIZE) ++#define MCF5445X_PCI_CONFIG_SIZE 0x01000000 ++ ++#define HOST_IO_BASE \ ++ (MCF5445X_PCI_MEM_BASE + MCF5445X_PCI_MEM_SIZE) ++#define PCI_IO_MASK (MCF5445X_PCI_IO_SIZE - 1) ++ ++#undef DEBUG ++#ifdef DEBUG ++# define DBG(x...) printk(x) ++#else ++# define DBG(x...) ++#endif ++ ++/* PCI Bus memory resource block */ ++struct resource pci_iomem_resource = { ++ .name = "PCI memory space", ++ .flags = IORESOURCE_MEM, ++}; ++ ++/* PCI Bus ioport resource block */ ++struct resource pci_ioport_resource = { ++ .name = "PCI I/O space", ++ .flags = IORESOURCE_IO, ++}; ++ ++/* ++ * The M54455EVB multiplexes all the PCI interrupts via ++ * the FPGA and routes them to a single interrupt. The ++ * PCI spec requires all PCI interrupt routines be smart ++ * enough to sort out their own interrupts. ++ * The interrupt source from the FPGA is configured ++ * to EPORT 3. ++ */ ++#define MCF5445X_PCI_IRQ 0x43 ++ ++#define PCI_SLOTS 4 ++ ++/* ++ * FPGA Info ++ */ ++#define FPGA_PCI_IRQ_ENABLE (u32 *)0x09000000 ++#define FPGA_PCI_IRQ_STATUS (u32 *)0x09000004 ++#define FPGA_PCI_IRQ_ROUTE (u32 *)0x0900000c ++#define FPGA_SEVEN_LED (u32 *)0x09000014 ++ ++ ++/* ++ * mcf5445x_conf_device(struct pci_dev *dev) ++ * ++ * Machine dependent Configure the given device. ++ * ++ * Parameters: ++ * ++ * dev - the pci device. ++ */ ++void ++mcf5445x_conf_device(struct pci_dev *dev) ++{ ++ set_fpga(FPGA_PCI_IRQ_ENABLE, 0x0f); ++} ++ ++/* ++ * int mcf5445x_pci_config_read(unsigned int seg, unsigned int bus, ++ * unsigned int devfn, int reg, ++ * u32 *value) ++ * ++ * Read from PCI configuration space. ++ * ++ */ ++int mcf5445x_pci_config_read(unsigned int seg, unsigned int bus, ++ unsigned int devfn, int reg, int len, u32 *value) ++{ ++ u32 addr = MCF_PCI_PCICAR_BUSNUM(bus) | ++ MCF_PCI_PCICAR_DEVNUM(PCI_SLOT(devfn)) | ++ MCF_PCI_PCICAR_FUNCNUM(PCI_FUNC(devfn)) | ++ MCF_PCI_PCICAR_DWORD(reg) | ++ MCF_PCI_PCICAR_E; ++ ++ if ((bus > 255) || (devfn > 255) || (reg > 255)) { ++ *value = -1; ++ return -EINVAL; ++ } ++ ++ /* setup for config mode */ ++ MCF_PCI_PCICAR = addr; ++ __asm__ __volatile__("nop"); ++ ++ switch (len) { ++ case 1: ++ *value = *(volatile u8 *)(MCF5445X_PCI_CONFIG_BASE+(reg&3)); ++ break; ++ case 2: ++ *value = le16_to_cpu(*(volatile u16 *) ++ (MCF5445X_PCI_CONFIG_BASE + (reg&2))); ++ break; ++ case 4: ++ *value = le32_to_cpu(*(volatile u32 *) ++ (MCF5445X_PCI_CONFIG_BASE)); ++ break; ++ } ++ ++ /* clear config mode */ ++ MCF_PCI_PCICAR = ~MCF_PCI_PCICAR_E; ++ __asm__ __volatile__("nop"); ++ ++ return 0; ++} ++ ++/* ++ * int mcf5445x_pci_config_write(unsigned int seg, unsigned int bus, ++ * unsigned int devfn, int reg, ++ * u32 *value) ++ * ++ * Write to PCI configuration space ++ */ ++int mcf5445x_pci_config_write(unsigned int seg, unsigned int bus, ++ unsigned int devfn, int reg, int len, u32 value) ++{ ++ u32 addr = MCF_PCI_PCICAR_BUSNUM(bus) | ++ MCF_PCI_PCICAR_DEVNUM(PCI_SLOT(devfn)) | ++ MCF_PCI_PCICAR_FUNCNUM(PCI_FUNC(devfn)) | ++ MCF_PCI_PCICAR_DWORD(reg) | ++ MCF_PCI_PCICAR_E; ++ ++ if ((bus > 255) || (devfn > 255) || (reg > 255)) ++ return -EINVAL; ++ ++ /* setup for config mode */ ++ MCF_PCI_PCICAR = addr; ++ __asm__ __volatile__("nop"); ++ ++ switch (len) { ++ case 1: ++ *(volatile u8 *)(MCF5445X_PCI_CONFIG_BASE+(reg&3)) = (u8)value; ++ break; ++ case 2: ++ *(volatile u16 *)(MCF5445X_PCI_CONFIG_BASE+(reg&2)) = ++ cpu_to_le16((u16)value); ++ break; ++ case 4: ++ *(volatile u32 *)(MCF5445X_PCI_CONFIG_BASE) = ++ cpu_to_le32(value); ++ break; ++ } ++ ++ /* clear config mode */ ++ MCF_PCI_PCICAR = ~MCF_PCI_PCICAR_E; ++ __asm__ __volatile__("nop"); ++ ++ return 0; ++} ++ ++/* hardware operations */ ++static struct pci_raw_ops mcf5445x_pci_ops = { ++ .read = mcf5445x_pci_config_read, ++ .write = mcf5445x_pci_config_write, ++}; ++ ++/************************************************************************/ ++ ++/* ++ * u8 pci_inb() ++ * ++ * Read a byte at specified address from I/O space ++ */ ++unsigned char pci_inb(long addr) ++{ ++ char value; ++ ++ value = *(volatile unsigned char *) (HOST_IO_BASE | ++ (addr & PCI_IO_MASK)); ++ DBG("PCI: inb addr=0x%08X, value=0x%02X\n", addr, value); ++ ++ return (unsigned char) value; ++} ++ ++ ++/* ++ * u16 pci_inw() ++ * ++ * Read a word at specified address from I/O space ++ */ ++unsigned short pci_inw(long addr) ++{ ++ short value; ++ volatile unsigned short *ptr; ++ ++ ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ value = le16_to_cpu(*ptr); ++ ++ DBG("PCI: inw addr=0x%08X, value=0x%04X\n", addr, value); ++ return (unsigned short) value; ++} ++ ++/* ++ * u16 pci_raw_inw() ++ * ++ * Read a raw word at specified address from I/O space ++ */ ++unsigned short pci_raw_inw(long addr) ++{ ++ short value; ++ volatile unsigned short *ptr; ++ ++ ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ value = *ptr; ++ ++ DBG("PCI: raw_inw addr=0x%08X, value=0x%04X\n", addr, value); ++ return (unsigned short) value; ++} ++ ++/* ++ * u32 pci_inl() ++ * ++ * Read a dword at specified address from I/O space ++ */ ++unsigned long pci_inl(long addr) ++{ ++ long value; ++ volatile unsigned long *ptr; ++ ++ ptr = (volatile unsigned long *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ value = le32_to_cpu(*ptr); ++ ++ DBG("PCI: inl addr=0x%08X, value=0x%08X\n", addr, value); ++ return (unsigned long) value; ++} ++ ++/* ++ * u32 pci_raw_inl() ++ * ++ * Read a raw dword at specified address from I/O space ++ */ ++unsigned long pci_raw_inl(long addr) ++{ ++ long value; ++ volatile unsigned long *ptr; ++ ++ ptr = (volatile unsigned long *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ value = *ptr; ++ ++ DBG("PCI: raw_inl addr=0x%08X, value=0x%08X\n", addr, value); ++ return (unsigned long) value; ++} ++ ++/* ++ * void pci_outb() ++ * ++ * Write a byte value at specified address to I/O space ++ */ ++void pci_outb(unsigned char value, long addr) ++{ ++ ++ *(volatile unsigned char *) (HOST_IO_BASE | (addr & PCI_IO_MASK)) \ ++ = value; ++ DBG("PCI: outb addr=0x%08X, value=0x%02X\n", addr, value); ++} ++ ++ ++/* ++ * void pci_outw() ++ * ++ * Write a word value at specified address to I/O space ++ */ ++void pci_outw(volatile unsigned short value, volatile long addr) ++{ ++ volatile unsigned short *ptr; ++ ++ ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ *ptr = cpu_to_le16(value); ++ DBG("PCI: outw addr=0x%08X, value=0x%04X\n", addr, value); ++} ++ ++/* ++ * void pci_raw_outw() ++ * ++ * Write a raw word value at specified address to I/O space ++ */ ++void pci_raw_outw(volatile unsigned short value, volatile long addr) ++{ ++ volatile unsigned short *ptr; ++ ++ ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ *ptr = value; ++ DBG("PCI: raw_outw addr=0x%08X, value=0x%04X\n", addr, value); ++} ++ ++/* ++ * void pci_outl() ++ * ++ * Write a long word value at specified address to I/O space ++ */ ++void pci_outl(volatile unsigned long value, volatile long addr) ++{ ++ volatile unsigned long *ptr; ++ ++ ptr = (volatile unsigned long *)(HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ *ptr = cpu_to_le32(value); ++ DBG("PCI: outl addr=0x%08X, value=0x%08X\n", addr, value); ++} ++ ++/* ++ * void pci_raw_outl() ++ * ++ * Write a raw long word value at specified address to I/O space ++ */ ++void pci_raw_outl(volatile unsigned long value, volatile long addr) ++{ ++ volatile unsigned long *ptr; ++ ++ ptr = (volatile unsigned long *)(HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ *ptr = value; ++ DBG("PCI: raw_outl addr=0x%08X, value=0x%08X\n", addr, value); ++} ++ ++/* ++ * void pci_insb() ++ * ++ * Read several byte values from specified I/O port ++ */ ++void pci_insb(volatile unsigned char *addr, unsigned char *buf, int len) ++{ ++ for (; len--; buf++) ++ *buf = pci_inb((unsigned long)addr); ++ DBG("PCI: pci_insb addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++ ++/* ++ * void pci_insw() ++ * ++ * Read several word values from specified I/O port ++ */ ++void pci_insw(volatile unsigned short *addr, unsigned short *buf, int len) ++{ ++ for (; len--; buf++) ++ *buf = pci_inw((unsigned long)addr); ++ DBG("PCI: pci_insw addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++/* ++ * void pci_insl() ++ * ++ * Read several dword values from specified I/O port ++ */ ++void pci_insl(volatile unsigned long *addr, unsigned long *buf, int len) ++{ ++ for (; len--; buf++) ++ *buf = pci_inl((unsigned long)addr); ++ DBG("PCI: pci_insl addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++/* ++ * void pci_outsb() ++ * ++ * Write several byte values to specified I/O port ++ */ ++void pci_outsb(volatile unsigned char *addr, const unsigned char *buf, int len) ++{ ++ for (; len--; buf++) ++ pci_outb((unsigned long)addr, *buf); ++ DBG("PCI: pci_outsb addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++/* ++ * void pci_outsw() ++ * ++ * Write several word values to specified I/O port ++ */ ++void ++pci_outsw(volatile unsigned short *addr, const unsigned short *buf, int len) ++{ ++ for (; len--; buf++) ++ pci_outw((unsigned long)addr, *buf); ++ DBG("PCI: pci_outsw addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++/* ++ * void pci_outsl() ++ * ++ * Write several dword values to specified I/O port ++ */ ++void pci_outsl(volatile unsigned long *addr, const unsigned long *buf, int len) ++{ ++ for (; len--; buf++) ++ pci_outl((unsigned long)addr, *buf); ++ DBG("PCI: pci_outsl addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++/* ++ * irqreturn_t mcf5445x_pci_interrupt( int irq, void *dev) ++ * ++ * PCI controller interrupt handler. ++ */ ++static irqreturn_t ++mcf5445x_pci_interrupt(int irq, void *dev) ++{ ++ u32 status = MCF_PCI_PCIGSCR; ++#ifdef DEBUG ++ printk(KERN_INFO "PCI: Controller irq status=0x%08x\n", status); ++#endif ++ /* clear */ ++ MCF_PCI_PCIGSCR = status; ++ ++ return IRQ_HANDLED; ++} ++ ++/* ++ * irqreturn_t mcf5445x_pci_arb_interrupt( int irq, void *dev) ++ * ++ * PCI Arbiter interrupt handler. ++ */ ++static irqreturn_t ++mcf5445x_pci_arb_interrupt(int irq, void *dev) ++{ ++ u32 status = MCF_PCIARB_PASR; ++#ifdef DEBUG ++ printk(KERN_INFO "PCI: Arbiter irq status=0x%08x\n", status); ++#endif ++ /* clear */ ++ MCF_PCIARB_PASR = status; ++ return IRQ_HANDLED; ++} ++ ++/* ++ * struct pci_bus_info *init_mcf5445x_pci(void) ++ * ++ * Machine specific initialisation: ++ * ++ * - Allocate and initialise a 'pci_bus_info' structure ++ * - Initialize hardware ++ * ++ * Result: pointer to 'pci_bus_info' structure. ++ */ ++int __init ++init_mcf5445x_pci(void) ++{ ++ /* ++ * Initialize the PCI core ++ */ ++ printk(KERN_INFO "init_mcf5445x_pci\n"); ++ ++ /* pci memory mapping */ ++ pci_mem_map = ioremap(MCF5445X_PCI_MEM_BASE_PHY, pci_mem_mapsize); ++ if (!pci_mem_map) { ++ printk(KERN_ERR "PCI memory map failed by ioremap!\n"); ++ return -ENOMEM; ++ } ++ printk(KERN_INFO "MCF5445X_PCI_MEM_BASE value is 0x%x\n", \ ++ MCF5445X_PCI_MEM_BASE); ++ ++ /* Initialize pci resource */ ++ pci_iomem_resource.start = MCF5445X_PCI_MEM_BASE; ++ pci_iomem_resource.end = MCF5445X_PCI_MEM_BASE + \ ++ MCF5445X_PCI_MEM_SIZE - 1; ++ ++ pci_ioport_resource.start = MCF5445X_PCI_IO_BASE; ++ pci_ioport_resource.end = MCF5445X_PCI_IO_BASE + \ ++ MCF5445X_PCI_IO_SIZE - 1; ++ ++ /* ++ * Must Reset!!! If bootloader has PCI enabled, it will cause ++ * problem in linux when it tries to configure/find resources ++ * for the pci devices ++ */ ++ MCF_PCI_PCIGSCR = 1; ++ ++ /* arbitration controller */ ++ MCF_PCIARB_PACR = MCF_PCIARB_PACR_INTMPRI | ++ MCF_PCIARB_PACR_EXTMPRI(0x0f) | ++ MCF_PCIARB_PACR_INTMINTEN | ++ MCF_PCIARB_PACR_EXTMINTEN(0x0f); ++ ++ /* pci pin assignment regs */ ++#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE) ++ MCF_GPIO_PAR_PCI = MCF_GPIO_PAR_PCI_GNT0 | ++ MCF_GPIO_PAR_PCI_GNT1 | ++ MCF_GPIO_PAR_PCI_GNT2 | ++ MCF_GPIO_PAR_PCI_GNT3_GNT3 | ++ MCF_GPIO_PAR_PCI_REQ0 | ++ MCF_GPIO_PAR_PCI_REQ1 | ++ MCF_GPIO_PAR_PCI_REQ2 | ++ MCF_GPIO_PAR_PCI_REQ3_REQ3; ++ ++ MCF_GPIO_PAR_PCI = (MCF_GPIO_PAR_PCI & ++ (MCF_GPIO_PAR_PCI_GNT3_MASK & ++ MCF_GPIO_PAR_PCI_REQ3_MASK)) | ++ MCF_GPIO_PAR_PCI_GNT3_ATA_DMACK | ++ MCF_GPIO_PAR_PCI_REQ3_ATA_INTRQ; ++#else ++ MCF_GPIO_PAR_PCI = MCF_GPIO_PAR_PCI_GNT0 | ++ MCF_GPIO_PAR_PCI_GNT1 | ++ MCF_GPIO_PAR_PCI_GNT2 | ++ MCF_GPIO_PAR_PCI_GNT3_GNT3 | ++ MCF_GPIO_PAR_PCI_REQ0 | ++ MCF_GPIO_PAR_PCI_REQ1 | ++ MCF_GPIO_PAR_PCI_REQ2 | ++ MCF_GPIO_PAR_PCI_REQ3_REQ3; ++#endif ++ /* target control reg */ ++ MCF_PCI_PCITCR = MCF_PCI_PCITCR_P | ++ MCF_PCI_PCITCR_WCT(8); ++ ++ /* PCI MEM address */ ++ MCF_PCI_PCIIW0BTAR = MCF5445X_PCI_MEM_BASE_PHY | ++ (MCF5445X_PCI_MEM_BASE >> 16); ++ ++ /* PCI MEM address */ ++ MCF_PCI_PCIIW1BTAR = (MCF5445X_PCI_MEM_BASE_PHY + ++ MCF5445X_PCI_MEM_SIZE) ++ | (MCF5445X_PCI_IO_BASE >> 16); ++ ++ /* PCI IO address */ ++ MCF_PCI_PCIIW2BTAR = (MCF5445X_PCI_MEM_BASE_PHY + ++ MCF5445X_PCI_MEM_SIZE + MCF5445X_PCI_IO_SIZE) ++ | (MCF5445X_PCI_CONFIG_BASE >> 16); ++ ++ /* window control */ ++ MCF_PCI_PCIIWCR = MCF_PCI_PCIIWCR_WINCTRL0_ENABLE | ++ MCF_PCI_PCIIWCR_WINCTRL0_MEMREAD | ++ MCF_PCI_PCIIWCR_WINCTRL1_ENABLE | ++ MCF_PCI_PCIIWCR_WINCTRL1_IO | ++ MCF_PCI_PCIIWCR_WINCTRL2_ENABLE | ++ MCF_PCI_PCIIWCR_WINCTRL2_IO; ++ ++ /* initiator control reg */ ++ MCF_PCI_PCIICR = 0; ++ ++ /* type 0 - command */ ++ MCF_PCI_PCISCR = MCF_PCI_PCISCR_MW | /* mem write/inval */ ++ MCF_PCI_PCISCR_B | /* bus master enable */ ++ MCF_PCI_PCISCR_MA | /* clear master abort error */ ++ MCF_PCI_PCISCR_M; /* mem access enable */ ++ ++ /* type 0 - config reg */ ++ MCF_PCI_PCICR1 = MCF_PCI_PCICR1_CACHELINESIZE(4) | ++ MCF_PCI_PCICR1_LATTIMER(0xFF); ++ /* type 0 - config 2 reg */ ++ MCF_PCI_PCICR2 = 0; ++ ++ /* target control reg */ ++ MCF_PCI_PCITCR2 = MCF_PCI_PCITCR2_B0E | MCF_PCI_PCITCR2_B5E; ++ ++ /* translate addresses from PCI[0] to CF[SDRAM] */ ++ MCF_PCI_PCITBATR0 = 0xFC000000 | MCF_PCI_PCITBATR5_EN; ++ MCF_PCI_PCITBATR5 = MCF_RAMBAR1 | MCF_PCI_PCITBATR5_EN; ++ ++ /* inbound window for memory */ ++ MCF_PCI_PCIBAR0 = 0xFC000000; ++ MCF_PCI_PCIBAR5 = MCF_RAMBAR1; ++ ++ /* setup controller interrupt handlers */ ++ if (request_irq(55+128, mcf5445x_pci_interrupt, IRQF_SHARED, ++ "PCI Controller", NULL)) ++ printk(KERN_ERR "PCI: Unable to register controller irq\n"); ++ ++ if (request_irq(56+128, mcf5445x_pci_arb_interrupt, IRQF_SHARED, ++ "PCI Arbiter", NULL)) ++ printk(KERN_ERR "PCI: Unable to register arbiter irq\n"); ++ ++ /* global control - clear reset bit */ ++ MCF_PCI_PCIGSCR = MCF_PCI_PCIGSCR_SEE | ++ MCF_PCI_PCIGSCR_PEE; ++ ++ /* let everything settle */ ++ udelay(1000); ++ ++ /* allocate bus ioport resource */ ++ if (request_resource(&ioport_resource, &pci_ioport_resource) < 0) ++ printk(KERN_ERR "PCI: Unable to alloc ioport resource\n"); ++ ++ /* allocate bus iomem resource */ ++ if (request_resource(&iomem_resource, &pci_iomem_resource) < 0) ++ printk(KERN_ERR "PCI: Unable to alloc iomem resource\n"); ++ ++ /* setup FPGA to route PCI to IRQ3(67), SW7 to IRQ7, SW6 to IRQ4 */ ++ set_fpga(FPGA_PCI_IRQ_ENABLE, 0x00000000); ++ set_fpga(FPGA_PCI_IRQ_ROUTE, 0x00000039); ++ set_fpga(FPGA_SEVEN_LED, 0x000000FF); ++ ++ raw_pci_ops = &mcf5445x_pci_ops; ++#ifdef DEBUG ++ mcf5445x_pci_dumpregs(); ++#endif ++ return 0; ++} ++ ++/* ++ * DEBUGGING ++ */ ++ ++#ifdef DEBUG ++struct regdump { ++ u32 addr; ++ char regname[16]; ++}; ++ ++struct regdump type0regs[] = { ++ { 0xfc0a8000, "PCIIDR" }, ++ { 0xfc0a8004, "PCISCR" }, ++ { 0xfc0a8008, "PCICCRIR" }, ++ { 0xfc0a800c, "PCICR1" }, ++ { 0xfc0a8010, "PCIBAR0" }, ++ { 0xfc0a8014, "PCIBAR1" }, ++ { 0xfc0a8018, "PCIBAR2" }, ++ { 0xfc0a801c, "PCIBAR3" }, ++ { 0xfc0a8020, "PCIBAR4" }, ++ { 0xfc0a8024, "PCIBAR5" }, ++ { 0xfc0a8028, "PCICCPR" }, ++ { 0xfc0a802c, "PCISID" }, ++ { 0xfc0a8030, "PCIERBAR" }, ++ { 0xfc0a8034, "PCICPR" }, ++ { 0xfc0a803c, "PCICR2" }, ++ { 0, "" } ++}; ++ ++struct regdump genregs[] = { ++ { 0xfc0a8060, "PCIGSCR" }, ++ { 0xfc0a8064, "PCITBATR0" }, ++ { 0xfc0a8068, "PCITBATR1" }, ++ { 0xfc0a806c, "PCITCR1" }, ++ { 0xfc0a8070, "PCIIW0BTAR" }, ++ { 0xfc0a8074, "PCIIW1BTAR" }, ++ { 0xfc0a8078, "PCIIW2BTAR" }, ++ { 0xfc0a8080, "PCIIWCR" }, ++ { 0xfc0a8084, "PCIICR" }, ++ { 0xfc0a8088, "PCIISR" }, ++ { 0xfc0a808c, "PCITCR2" }, ++ { 0xfc0a8090, "PCITBATR0" }, ++ { 0xfc0a8094, "PCITBATR1" }, ++ { 0xfc0a8098, "PCITBATR2" }, ++ { 0xfc0a809c, "PCITBATR3" }, ++ { 0xfc0a80a0, "PCITBATR4" }, ++ { 0xfc0a80a4, "PCITBATR5" }, ++ { 0xfc0a80a8, "PCIINTR" }, ++ { 0xfc0a80f8, "PCICAR" }, ++ { 0, "" } ++}; ++ ++struct regdump arbregs[] = { ++ { 0xfc0ac000, "PACR" }, ++ { 0xfc0ac004, "PASR" }, /* documentation error */ ++ { 0, "" } ++}; ++ ++/* ++ * void mcf5445x_pci_dumpregs() ++ * ++ * Dump out all the PCI registers ++ */ ++void ++mcf5445x_pci_dumpregs(void) ++{ ++ struct regdump *reg; ++ ++ printk(KERN_INFO "*** MCF5445x PCI TARGET 0 REGISTERS ***\n"); ++ ++ reg = type0regs; ++ while (reg->addr) { ++ printk(KERN_INFO "0x%08x 0x%08x %s\n", reg->addr, ++ *((u32 *)reg->addr), reg->regname); ++ reg++; ++ } ++ ++ printk(KERN_INFO "\n*** MCF5445x PCI GENERAL REGISTERS ***\n"); ++ reg = genregs; ++ while (reg->addr) { ++ printk(KERN_INFO "0x%08x 0x%08x %s\n", reg->addr, ++ *((u32 *)reg->addr), reg->regname); ++ reg++; ++ } ++ printk(KERN_INFO "\n*** MCF5445x PCI ARBITER REGISTERS ***\n"); ++ reg = arbregs; ++ while (reg->addr) { ++ printk(KERN_INFO "0x%08x 0x%08x %s\n", reg->addr, ++ *((u32 *)reg->addr), reg->regname); ++ reg++; ++ } ++} ++#endif /* DEBUG */ +--- /dev/null ++++ b/arch/m68k/coldfire/m5445x/pci.c +@@ -0,0 +1,247 @@ ++/* ++ * linux/arch/m68k/coldfire/m5445x/pci.c ++ * ++ * PCI initialization for Coldfire architectures. ++ * ++ * Currently Supported: ++ * M5445x ++ * ++ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Kurt Mahan <kmahan@freescale.com> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/pci.h> ++ ++#include <asm/mcfsim.h> ++#include <asm/pci.h> ++ ++/* pci ops for reading/writing config */ ++struct pci_raw_ops *raw_pci_ops; ++ ++/* pci debug flag */ ++static int debug_pci; ++ ++static int ++pci_read(struct pci_bus *bus, unsigned int devfn, int where, ++ int size, u32 *value) ++{ ++ return raw_pci_ops->read(0, bus->number, devfn, where, size, value); ++} ++ ++static int ++pci_write(struct pci_bus *bus, unsigned int devfn, int where, ++ int size, u32 value) ++{ ++ return raw_pci_ops->write(0, bus->number, devfn, where, size, value); ++} ++ ++struct pci_ops pci_root_ops = { ++ .read = pci_read, ++ .write = pci_write, ++}; ++ ++/* ++ * pcibios_setup(char *) ++ * ++ * Initialize the pcibios based on cmd line params. ++ */ ++char * ++pcibios_setup(char *str) ++{ ++ if (!strcmp(str, "debug")) { ++ debug_pci = 1; ++ return NULL; ++ } ++ return str; ++} ++ ++/* ++ * We need to avoid collisions with `mirrored' VGA ports ++ * and other strange ISA hardware, so we always want the ++ * addresses to be allocated in the 0x000-0x0ff region ++ * modulo 0x400. ++ * ++ * Why? Because some silly external IO cards only decode ++ * the low 10 bits of the IO address. The 0x00-0xff region ++ * is reserved for motherboard devices that decode all 16 ++ * bits, so it's ok to allocate at, say, 0x2800-0x28ff, ++ * but we want to try to avoid allocating at 0x2900-0x2bff ++ * which might have be mirrored at 0x0100-0x03ff.. ++ */ ++resource_size_t ++pcibios_align_resource(void *data, const struct resource *res, ++ resource_size_t size, resource_size_t align) ++{ ++ struct pci_dev *dev = data; ++ resource_size_t start = res->start; ++ ++ if (res->flags & IORESOURCE_IO) { ++ if (size > 0x100) ++ printk(KERN_ERR "PCI: I/O Region %s/%d too large" ++ " (%ld bytes)\n", pci_name(dev), ++ dev->resource - res, (long int)size); ++ ++ if (start & 0x3ff) ++ start = (start + 0x3ff) & ~0x3ff; ++ } ++ ++ return start; ++} ++EXPORT_SYMBOL(pcibios_align_resource); ++ ++/* ++ * Swizzle the device pin each time we cross a bridge ++ * and return the slot number. ++ */ ++static u8 __devinit ++pcibios_swizzle(struct pci_dev *dev, u8 *pin) ++{ ++ return 0; ++} ++ ++/* ++ * Map a slot/pin to an IRQ. ++ */ ++static int ++pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ return 0x43; ++} ++ ++/* ++ * pcibios_update_irq(struct pci_dev *dev, int irq) ++ * ++ * Update a PCI interrupt. ++ */ ++void ++pcibios_update_irq(struct pci_dev *dev, int irq) ++{ ++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); ++} ++ ++/* ++ * pcibios_enable_device(struct pci_dev *dev, int mask) ++ * ++ * Enable a device on the PCI bus. ++ */ ++int ++pcibios_enable_device(struct pci_dev *dev, int mask) ++{ ++ u16 cmd, old_cmd; ++ int idx; ++ struct resource *r; ++ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ old_cmd = cmd; ++ for (idx = 0; idx < DEVICE_COUNT_RESOURCE; idx++) { ++ r = &dev->resource[idx]; ++ if (!r->start && r->end) { ++ printk(KERN_ERR "PCI: Device %s not available because " ++ "of resource collisions\n", pci_name(dev)); ++ 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", ++ pci_name(dev), old_cmd, cmd); ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++#ifdef CONFIG_M54455 ++ mcf5445x_conf_device(dev); ++#endif ++ } ++ ++ return 0; ++} ++ ++/* ++ * pcibios_fixup_bus(struct pci_bus *bus) ++ */ ++void ++pcibios_fixup_bus(struct pci_bus *bus) ++{ ++ struct pci_dev *dev = bus->self; ++ ++ if (!dev) { ++ /* Root bus. */ ++#ifdef CONFIG_M54455 ++ bus->resource[0] = &pci_ioport_resource; ++ bus->resource[1] = &pci_iomem_resource; ++#endif ++ } ++} ++ ++/* ++ * pcibios_init(void) ++ * ++ * Allocate/initialize low level pci bus/devices. ++ */ ++#ifdef CONFIG_M54455_PCI_initcall ++static int __init ++#else ++int __init ++#endif ++pcibios_init(void) ++{ ++ struct pci_bus *bus; ++ ++ if (!raw_pci_ops) { ++ printk(KERN_WARNING "PCIBIOS: FATAL: NO PCI Hardware found\n"); ++ return 0; ++ } ++ ++ /* allocate and scan the (only) bus */ ++ bus = pci_scan_bus_parented(NULL, 0, &pci_root_ops, NULL); ++ ++ /* setup everything */ ++ if (bus) { ++ /* compute the bridge window sizes */ ++ pci_bus_size_bridges(bus); ++ ++ /* (re)assign device resources */ ++ pci_bus_assign_resources(bus); ++ ++ /* add the bus to the system */ ++ pci_bus_add_devices(bus); ++ ++ /* fixup irqs */ ++ pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); ++ } ++ ++ return 0; ++} ++ ++/* ++ * pci_init(void) ++ * ++ * Initialize the PCI Hardware. ++ */ ++#ifdef CONFIG_M54455_PCI_initcall ++static int __init ++#else ++int __init ++#endif ++pci_init(void) ++{ ++ printk(KERN_INFO "pci_init\n"); ++#if defined(CONFIG_M54455) ++ init_mcf5445x_pci(); ++#endif ++ if (!raw_pci_ops) ++ printk(KERN_ERR "PCI: FATAL: NO PCI Detected\n"); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_M54455_PCI_initcall ++/* low level hardware (first) */ ++arch_initcall(pci_init); ++ ++/* basic bios init (second) */ ++subsys_initcall(pcibios_init); ++#endif +--- /dev/null ++++ b/arch/m68k/coldfire/m547x/pci.c +@@ -0,0 +1,1023 @@ ++/* ++ * ColdFire 547x/548x PCI Host Controller functions ++ * ++ * Copyright (C) 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Shrek Wu b16972@freescale.com ++ * This code is based on the 2.6.10 version of pci.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/string.h> ++#include <linux/pci.h> ++#include <linux/ioport.h> ++#include <linux/slab.h> ++#include <linux/version.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++ ++#include <linux/dma-mapping.h> ++#include <asm/coldfire.h> ++#include <linux/io.h> ++#include <asm/m5485sim.h> ++#include <asm/m5485pci.h> ++#include <asm/irq.h> ++#include <linux/pci.h> ++#include <asm/virtconvert.h> ++ ++ ++#undef DEBUG ++/*define DEBUG*/ ++#ifdef DEBUG ++/*#define DBG(x...) printk(KERN_DEBUG x)*/ ++#define DBG(x...) printk(x) ++#else ++#define DBG(x...) ++#endif ++ ++/* ++ * Bridge configration dafaults ++ */ ++#define PCI_RETRIES 0 ++#define PCI_CACHE_LINE 8 ++#define PCI_MINGNT 1 ++#define PCI_MAXLAT 42 ++ ++ ++/* ++ * Initiator windows setting ++ */ ++#define HOST_MEM_BASE 0xD0000000 ++/* ColdFire Memory window base */ ++#define PCI_MEM_BASE 0xD0000000 ++/* PCI Memory window base */ ++#define PCI_MEM_SIZE 0x08000000 ++/* Memory window size (128M) */ ++#define HOST_IO_BASE 0xD8000000 ++/* ColdFire I/O window base */ ++#define PCI_IO_BASE_ADDR 0x00000000 ++/* PCI I/O window base */ ++#define PCI_IO_SIZE 0x00010000 ++/* I/O window size (64K) */ ++/*#define HOST_CFG_BASE 0xD8000000*/ ++#define HOST_CFG_BASE 0xD8008000 ++/* ColdFire config window base */ ++#define HOST_DMA_BASE CONFIG_SDRAM_BASE ++/* ColdFire PCI-DMA window base */ ++#define PCI_HDR_BASE (MCF_MBAR+0xB00) ++/* ColdFire config registers */ ++ ++#define PCI_MEM_MASK (PCI_MEM_SIZE-1) ++#define PCI_IO_MASK (PCI_IO_SIZE-1) ++ ++/* Macro to set initiator window */ ++#define WxBAR(host_address, pci_address, size) \ ++ (((host_address) & 0xff000000) | \ ++ ((((size)-1) & 0xff000000) >> 8) | \ ++ ((pci_address) & 0xff000000) >> 16) ++ ++/* ++ * BIOS internal data ++ */ ++static u8 revision; /* controller revision */ ++ ++/* ++ * Board specific setting ++ */ ++const unsigned int irq_lines[] = { 5, 7 }; ++ ++#define N_SLOTS (sizeof(board_info) / sizeof(board_info[0])) ++#define N_IRQS (sizeof(irq_lines) / sizeof(irq_lines[0])) ++#define BRIDGE_SLOT 0 ++ ++const struct slotinfo { ++ unsigned char idsel; /* device number */ ++ unsigned char irq; /* external IRQ */ ++ unsigned char req; /* REQ line number */ ++ unsigned char gnt; /* GNT line number */ ++} board_info[] = { ++ {0, 0, 0, 0}, /* Bridge */ ++ {17, 5, 1, 1}, /* Slot #1 */ ++ {18, 5, 2, 2}, /* Slot #2 */ ++ {20, 7, 3, 3}, /* Slot #3 */ ++ {21, 7, 4, 4}, /* Slot #4 */ ++}; ++ ++/************************************************************************/ ++ ++/* ++ * static int mk_conf_addr() ++ * ++ * Return type0 or type1 configuration address ++ * by the means of device address and PCI dword location ++ * 0 - for not existing slots ++ */ ++static int mk_conf_addr(/*struct pci_dev *dev*/ ++ struct pci_bus *bus, unsigned int devfn, int where) ++{ ++ int slot, func, address, idsel, dev_fn; ++ ++ if (bus->number) { ++ address = MCF_PCICAR_E | (bus->number << 16) | ++ (devfn << 8) | (where & 0xfc); ++ } else { ++ slot = PCI_SLOT(devfn); ++ if (slot > N_SLOTS || slot == BRIDGE_SLOT) ++ return 0; ++ else { ++ func = PCI_FUNC(devfn); ++ idsel = board_info[slot].idsel; ++ ++ dev_fn = PCI_DEVFN(idsel, func); ++ address = MCF_PCICAR_E | (bus->number << 16) | ++ (dev_fn << 8) | (where & 0xfc); ++ } ++ } ++ ++ return address; ++} ++ ++/* ++ * static int read_config_byte() ++ * ++ * Read a byte from configuration space of specified device ++ */ ++static int read_config_byte(/*struct pci_dev *dev*/ ++ struct pci_bus *bus, unsigned int devfn, int where, u8 *value) ++{ ++ int slot; ++ int address; ++ int result; ++ ++ *value = 0xff; ++ result = PCIBIOS_SUCCESSFUL; ++ ++ slot = PCI_SLOT(devfn); ++ if (slot == BRIDGE_SLOT) { ++ if (where <= 0x40) ++ *value = *(volatile u8 *) (PCI_HDR_BASE + ++ (where & 0xfc) + (where & 3)); ++ else ++ *value = 0; ++ } else { ++ address = mk_conf_addr(bus, devfn, where); ++ if (!address) ++ result = PCIBIOS_DEVICE_NOT_FOUND; ++ else { ++ MCF_PCICAR = address; ++ __asm__ __volatile__("nop"); ++ *value = *(volatile u8 *) (HOST_CFG_BASE + (where & 3)); ++ } ++ } ++ __asm("tpf"); ++ MCF_PCICAR &= ~MCF_PCICAR_E; ++ DBG("PCI: read_config_byte bus=%d, dev=%d, fn=%d," ++ " addr=0x%02X, val=0x%02X, ret=%02X\n", ++ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, *value, result); ++ ++ return result; ++} ++ ++/* ++ * static int read_config_word() ++ * ++ * Read a word from configuration space of specified device ++ */ ++static int read_config_word(/*struct pci_dev *dev*/ ++ struct pci_bus *bus, unsigned int devfn, int where, u16 *value) ++{ ++ int slot; ++ int address; ++ int result; ++ ++ *value = 0xffff; ++ result = PCIBIOS_SUCCESSFUL; ++ ++ if (where & 0x1) ++ result = PCIBIOS_BAD_REGISTER_NUMBER; ++ else { ++ slot = PCI_SLOT(devfn); ++ if (slot == BRIDGE_SLOT) { ++ if (where <= 0x3f) ++ *value = ++ *(volatile u16 *) (PCI_HDR_BASE + ++ (where & 0xfc) + (where & 2)); ++ else ++ *value = 0; ++ } else { ++ address = mk_conf_addr(bus, devfn, where); ++ if (!address) ++ result = PCIBIOS_DEVICE_NOT_FOUND; ++ else { ++ MCF_PCICAR = address; ++ __asm__ __volatile__("nop"); ++ *value = le16_to_cpu(*(volatile u16 *) ++ (HOST_CFG_BASE + ++ (where & 2))); ++ } ++ } ++ } ++ __asm("tpf"); ++ MCF_PCICAR &= ~MCF_PCICAR_E; ++ DBG("PCI: read_config_word bus=%d, dev=%d, fn=%d," ++ " addr=0x%02X, val=0x%04X ret=%02X\n", ++ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, *value, result); ++ ++ return result; ++} ++ ++/* ++ * static int read_config_dword() ++ * ++ * Read a long word from configuration space of specified device ++ */ ++static int read_config_dword(/*struct pci_dev *dev*/ ++ struct pci_bus *bus, unsigned int devfn, int where, u32 *value) ++{ ++ int slot; ++ int address; ++ int result; ++ ++ *value = 0xffffffff; ++ result = PCIBIOS_SUCCESSFUL; ++ ++ if (where & 0x3) ++ result = PCIBIOS_BAD_REGISTER_NUMBER; ++ else { ++ slot = PCI_SLOT(devfn); ++ if (slot == BRIDGE_SLOT) { ++ if (where <= 0x3d) ++ *value = ++ *(volatile u32 *) (PCI_HDR_BASE + where); ++ else ++ *value = 0; ++ __asm("tpf"); ++ } else { ++ address = mk_conf_addr(bus, devfn, where); ++ if (!address) ++ result = PCIBIOS_DEVICE_NOT_FOUND; ++ else { ++ MCF_PCICAR = address; ++ __asm__ __volatile__("nop"); ++ *value = le32_to_cpu(*(volatile u32 *) ++ (HOST_CFG_BASE)); ++ __asm("tpf"); ++ if (bus->number != 0 && revision < 1) { ++ volatile u32 temp; ++ MCF_PCICAR |= 0xff0000; ++ temp = *(volatile u32 *) ++ (HOST_CFG_BASE); ++ } ++ } ++ } ++ } ++ ++ MCF_PCICAR &= ~MCF_PCICAR_E; ++ DBG("PCI: read_config_dword bus=%d, dev=%d, fn=%d, " ++ "addr=0x%02X, value=0x%08X ret=%02X\n", ++ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, *value, result); ++ ++ return result; ++} ++ ++ ++ ++/* ++ * static int write_config_byte() ++ * ++ * Write a byte to configuration space of specified device ++ */ ++static int write_config_byte(/*struct pci_dev *dev*/ ++ struct pci_bus *bus, unsigned int devfn, int where, u8 value) ++{ ++ int slot; ++ int address; ++ int result; ++ ++ result = PCIBIOS_SUCCESSFUL; ++ ++ slot = PCI_SLOT(devfn); ++ if (slot == BRIDGE_SLOT) { ++ if (where <= 0x40) ++ *(volatile u8 *) (PCI_HDR_BASE + (where & 0xfc) ++ + (where & 3)) = value; ++ } else { ++ address = mk_conf_addr(bus, devfn, where); ++ if (!address) ++ result = PCIBIOS_DEVICE_NOT_FOUND; ++ else { ++ MCF_PCICAR = address; ++ __asm__ __volatile__("tpf"); ++ *(volatile u8 *) (HOST_CFG_BASE + (where & 3)) = value; ++ } ++ } ++ __asm("tpf"); ++ MCF_PCICAR &= ~MCF_PCICAR_E; ++ pci_dummy_function(); ++ ++ DBG("PCI: write_config_byte bus=%d, dev=%d, fn=%d, " ++ "addr=0x%02X, value=0x%02X ret=%02X\n", ++ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, value, result); ++ ++ return result; ++} ++ ++/* ++ * static int write_config_word() ++ * ++ * Write a word to configuration space of specified device ++ */ ++static int write_config_word(/*struct pci_dev *dev*/ ++ struct pci_bus *bus, unsigned int devfn, int where, u16 value) ++{ ++ int slot; ++ int address; ++ int result; ++ ++ result = PCIBIOS_SUCCESSFUL; ++ ++ if (where & 0x1) ++ result = PCIBIOS_BAD_REGISTER_NUMBER; ++ else { ++ slot = PCI_SLOT(devfn); ++ if (slot == BRIDGE_SLOT) { ++ if (where <= 0x3f) ++ *(volatile u16 *) (PCI_HDR_BASE + ++ (where & 0xfc) + (where & 2)) = value; ++ } else { ++ address = mk_conf_addr(bus, devfn, where); ++ if (!address) ++ result = PCIBIOS_DEVICE_NOT_FOUND; ++ else { ++ MCF_PCICAR = address; ++ __asm__ __volatile__("tpf"); ++ *(volatile u16 *) (HOST_CFG_BASE ++ + (where & 2)) = ++ cpu_to_le16(value); ++ } ++ } ++ } ++ __asm("tpf"); ++ MCF_PCICAR &= ~MCF_PCICAR_E; ++ pci_dummy_function(); ++ ++ DBG("PCI: write_config_word bus=%d, dev=%d, fn=%d, " ++ "addr=0x%02X, value=0x%04X ret=%02X\n", ++ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, value, result); ++ ++ return result; ++} ++ ++/* ++ * static int write_config_dword() ++ * ++ * Write a long word to configuration space of specified device ++ */ ++static int write_config_dword(/*struct pci_dev *dev*/ ++ struct pci_bus *bus, unsigned int devfn, int where, u32 value) ++{ ++ int slot; ++ int address; ++ int result; ++ ++ result = PCIBIOS_SUCCESSFUL; ++ ++ if (where & 0x3) ++ result = PCIBIOS_BAD_REGISTER_NUMBER; ++ else { ++ slot = PCI_SLOT(devfn); ++ if (slot == BRIDGE_SLOT) { ++ if (where <= 0x3d) ++ *(volatile u32 *) (PCI_HDR_BASE + where) = ++ value; ++ } else { ++ address = mk_conf_addr(bus, devfn, where); ++ if (!address) ++ result = PCIBIOS_DEVICE_NOT_FOUND; ++ else { ++ MCF_PCICAR = address; ++ __asm__ __volatile__("tpf"); ++ *(volatile u32 *) (HOST_CFG_BASE) = ++ cpu_to_le32(value); ++ } ++ } ++ } ++ __asm("tpf"); ++ MCF_PCICAR &= ~MCF_PCICAR_E; ++ pci_dummy_function(); ++ ++ DBG("PCI: write_config_dword dev=%d, fn=%d," ++ "addr=0x%02X, value=0x%08X ret=%02X\n", ++ PCI_SLOT(devfn), PCI_FUNC(devfn), where, value, result); ++ ++ return result; ++} ++ ++static int config_read(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 *val) ++{ ++ switch (size) { ++ case 1: ++ return read_config_byte(bus, devfn, where, (u8 *) val); ++ case 2: ++ return read_config_word(bus, devfn, where, (u16 *) val); ++ default: ++ return read_config_dword(bus, devfn, where, val); ++ } ++} ++ ++static int config_write(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) ++{ ++ switch (size) { ++ case 1: ++ return write_config_byte(bus, devfn, where, (u8) val); ++ case 2: ++ return write_config_word(bus, devfn, where, (u16) val); ++ default: ++ return write_config_dword(bus, devfn, where, val); ++ } ++} ++ ++/* ++ * configuration routines entry points ++ */ ++static struct pci_ops bus_ops = { ++ .read = config_read, ++ .write = config_write, ++}; ++ ++/************************************************************************/ ++ ++/* ++ * u8 pci_inb() ++ * ++ * Read a byte at specified address from I/O space ++ */ ++unsigned char pci_inb(long addr) ++{ ++ char value; ++ ++ value = *(volatile unsigned char *)(HOST_IO_BASE | ++ (addr & PCI_IO_MASK)); ++ DBG("PCI: inb addr=0x%08X, value=0x%02X\n", addr, value); ++ ++ return (unsigned char) value; ++} ++ ++ ++/* ++ * u16 pci_inw() ++ * ++ * Read a word at specified address from I/O space ++ */ ++unsigned short pci_inw(long addr) ++{ ++ short value; ++ volatile unsigned short *ptr; ++ ++ ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ value = le16_to_cpu(*ptr); ++ ++ DBG("PCI: inw addr=0x%08X, value=0x%04X\n", addr, value); ++ return (unsigned short) value; ++} ++ ++/* ++ * u16 pci_raw_inw() ++ * ++ * Read a raw word at specified address from I/O space ++ */ ++unsigned short pci_raw_inw(long addr) ++{ ++ short value; ++ volatile unsigned short *ptr; ++ ++ ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ value = *ptr; ++ ++ DBG("PCI: raw_inw addr=0x%08X, value=0x%04X\n", addr, value); ++ return (unsigned short) value; ++} ++ ++/* ++ * u32 pci_inl() ++ * ++ * Read a dword at specified address from I/O space ++ */ ++unsigned long pci_inl(long addr) ++{ ++ long value; ++ volatile unsigned long *ptr; ++ ++ ptr = (volatile unsigned long *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ value = le32_to_cpu(*ptr); ++ ++ DBG("PCI: inl addr=0x%08X, value=0x%08X\n", addr, value); ++ return (unsigned long) value; ++} ++ ++/* ++ * u32 pci_raw_inl() ++ * ++ * Read a raw dword at specified address from I/O space ++ */ ++unsigned long pci_raw_inl(long addr) ++{ ++ long value; ++ volatile unsigned long *ptr; ++ ++ ptr = (volatile unsigned long *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ value = *ptr; ++ ++ DBG("PCI: raw_inl addr=0x%08X, value=0x%08X\n", addr, value); ++ return (unsigned long) value; ++} ++ ++/* ++ * void pci_outb() ++ * ++ * Write a byte value at specified address to I/O space ++ */ ++void pci_outb(unsigned char value, long addr) ++{ ++ ++ *(volatile unsigned char *)(HOST_IO_BASE | (addr & PCI_IO_MASK)) ++ = value; ++ DBG("PCI: outb addr=0x%08X, value=0x%02X\n", addr, value); ++} ++ ++ ++/* ++ * void pci_outw() ++ * ++ * Write a word value at specified address to I/O space ++ */ ++void pci_outw(volatile unsigned short value, volatile long addr) ++{ ++ volatile unsigned short *ptr; ++ ++ ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ *ptr = cpu_to_le16(value); ++ DBG("PCI: outw addr=0x%08X, value=0x%04X\n", addr, value); ++} ++ ++/* ++ * void pci_raw_outw() ++ * ++ * Write a raw word value at specified address to I/O space ++ */ ++void pci_raw_outw(volatile unsigned short value, volatile long addr) ++{ ++ volatile unsigned short *ptr; ++ ++ ptr = (volatile unsigned short *) (HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ *ptr = value; ++ DBG("PCI: raw_outw addr=0x%08X, value=0x%04X\n", addr, value); ++} ++ ++/* ++ * void pci_outl() ++ * ++ * Write a long word value at specified address to I/O space ++ */ ++void pci_outl(volatile unsigned long value, volatile long addr) ++{ ++ volatile unsigned long *ptr; ++ ++ ptr = (volatile unsigned long *)(HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ *ptr = cpu_to_le32(value); ++ DBG("PCI: outl addr=0x%08X, value=0x%08X\n", addr, value); ++} ++ ++/* ++ * void pci_raw_outl() ++ * ++ * Write a raw long word value at specified address to I/O space ++ */ ++void pci_raw_outl(volatile unsigned long value, volatile long addr) ++{ ++ volatile unsigned long *ptr; ++ ++ ptr = (volatile unsigned long *)(HOST_IO_BASE | (addr & PCI_IO_MASK)); ++ *ptr = value; ++ DBG("PCI: raw_outl addr=0x%08X, value=0x%08X\n", addr, value); ++} ++ ++/* ++ * void pci_insb() ++ * ++ * Read several byte values from specified I/O port ++ */ ++void pci_insb(volatile unsigned char *addr, unsigned char *buf, int len) ++{ ++ for (; len--; buf++) ++ *buf = pci_inb((unsigned long)addr); ++ DBG("PCI: pci_insb addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++ ++/* ++ * void pci_insw() ++ * ++ * Read several word values from specified I/O port ++ */ ++void pci_insw(volatile unsigned short *addr, unsigned short *buf, int len) ++{ ++ for (; len--; buf++) ++ *buf = pci_inw((unsigned long)addr); ++ DBG("PCI: pci_insw addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++/* ++ * void pci_insl() ++ * ++ * Read several dword values from specified I/O port ++ */ ++void pci_insl(volatile unsigned long *addr, unsigned long *buf, int len) ++{ ++ for (; len--; buf++) ++ *buf = pci_inl((unsigned long)addr); ++ DBG("PCI: pci_insl addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++/* ++ * void pci_outsb() ++ * ++ * Write several byte values to specified I/O port ++ */ ++void pci_outsb(volatile unsigned char *addr, const unsigned char *buf, int len) ++{ ++ for (; len--; buf++) ++ pci_outb((unsigned long)addr, *buf); ++ DBG("PCI: pci_outsb addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++/* ++ * void pci_outsw() ++ * ++ * Write several word values to specified I/O port ++ */ ++void pci_outsw(volatile unsigned short *addr, ++ const unsigned short *buf, int len) ++{ ++ for (; len--; buf++) ++ pci_outw((unsigned long)addr, *buf); ++ DBG("PCI: pci_outsw addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++/* ++ * void pci_outsl() ++ * ++ * Write several dword values to specified I/O port ++ */ ++void pci_outsl(volatile unsigned long *addr, const unsigned long *buf, int len) ++{ ++ for (; len--; buf++) ++ pci_outl((unsigned long)addr, *buf); ++ DBG("PCI: pci_outsl addr=0x%08X, buf=%p, len=%d\n", addr, buf, len); ++} ++ ++/* ++ * void pci_xlb_handler() ++ * ++ * PCI XLB interrupt handler ++ */ ++irqreturn_t xlb_interrupt(int irq, void *dev) ++{ ++ volatile int xlb_error = MCF_PCIISR; ++ ++ /* Acknowlege interrupt */ ++ MCF_PCIISR = xlb_error; ++ ++ /* Dump interrupt reason */ ++ if (xlb_error & MCF_PCIISR_RE) ++ DBG("PCI: Retry Error Received\n"); ++ ++ if (xlb_error & MCF_PCIISR_IA) ++ DBG("PCI: Initiator Abort Received\n"); ++ ++ if (xlb_error & MCF_PCIISR_TA) ++ DBG("PCI: Target Abort Received\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++/* ++ * void pci_arbiter_handler() ++ * ++ * PCI arbiter interrupt handler ++ */ ++irqreturn_t arb_interrupt(int irq, void *dev) ++{ ++ volatile unsigned long arb_error = MCF_PCIARB_PASR; ++ ++ /* Acknowlege interrupt */ ++ printk(KERN_ERR "%s\n", __func__); ++ MCF_PCIARB_PASR = arb_error; ++ ++ if (arb_error & MCF_PCIARB_PASR_ITLMBK) { ++ DBG("PCI: coldfire master time-out\n"); ++ ++ /* Set infinite number of retries */ ++ MCF_PCIICR &= ~0xFF; ++ } ++ ++ if (arb_error & MCF_PCIARB_PASR_EXTMBK(0x1F)) { ++ arb_error >>= 17; ++ DBG("PCI: external master time-out (mask = 0x%X)\n", arb_error); ++ ++ /* raise arbitration priority level */ ++ MCF_PCIARB_PACR = MCF_PCIARB_PACR_EXTMPRI(arb_error); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++ ++/* ++ * void pci_eint_handler() ++ * ++ * Eport interrupt handler ++ */ ++irqreturn_t eint_handler(int irq, void *dev) ++{ ++ /* Just acknowlege interrupt and exit */ ++ MCF_EPFR = 0x1 << (irq - 64); ++ return IRQ_HANDLED; ++} ++ ++resource_size_t ++pcibios_align_resource(void *data, const struct resource *res, ++ resource_size_t size, resource_size_t align) ++{ ++ struct pci_dev *dev = data; ++ resource_size_t start = res->start; ++ ++ if (res->flags & IORESOURCE_IO) { ++ if (size > 0x100) ++ printk(KERN_ERR "PCI: I/O Region %s/%d too large" ++ " (%ld bytes)\n", pci_name(dev), ++ dev->resource - res, (long int)size); ++ ++ if (start & 0x3ff) ++ start = (start + 0x3ff) & ~0x3ff; ++ } ++ ++ return start; ++} ++EXPORT_SYMBOL(pcibios_align_resource); ++ ++/* ++ * void __init coldfire_fixup(int pci_modify) ++ * ++ * Assign IRQ numbers as used by Linux to the interrupt pins ++ * of the PCI cards. ++ */ ++static void __init coldfire_fixup(int pci_modify) ++{ ++ struct pci_dev *dev; ++ unsigned char slot, pin; ++ ++ DBG("%s\n", __func__); ++#ifdef NL_ORIGINAL ++ pci_for_each_dev(dev) { ++#else ++ dev = NULL; ++ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { ++#endif ++ if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) { ++ slot = PCI_SLOT(dev->devfn); ++ dev->irq = 64 + board_info[slot].irq; ++ ++ /* Check if device needs interrupt */ ++#ifdef NL_ORIGINAL ++ pcibios_read_config_byte( ++ dev->bus->number, dev->devfn, ++ PCI_INTERRUPT_PIN, &pin); ++ ++ if (pin) { ++ pcibios_write_config_byte( ++ dev->bus->number, dev->devfn, ++ PCI_INTERRUPT_LINE, dev->irq); ++ } ++#else ++ pci_read_config_byte(dev, ++ PCI_INTERRUPT_PIN, &pin); ++ ++ if (pin) { ++ pci_write_config_byte(dev, ++ PCI_INTERRUPT_LINE, dev->irq); ++ } ++#endif ++ } ++ } ++} ++ ++static void __init configure_device(struct pci_dev *dev) ++{ ++ /* TODO: This should depend from disable_pci_burst setting */ ++ DBG("%s\n", __func__); ++#ifdef NL_ORIGINAL ++ pcibios_write_config_byte(bus, devfn, ++ PCI_CACHE_LINE_SIZE, PCI_CACHE_LINE); ++#else ++ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, PCI_CACHE_LINE); ++ ++ MCF_PCICR1 = MCF_PCICR1_LATTIMER(0xF8) | ++ MCF_PCICR1_CACHELINESIZE(PCI_CACHE_LINE); ++ ++#endif ++} ++ ++ ++struct pci_bus_info *__init init_coldfire_pci(void) ++{ ++ struct pci_bus_info *bus; ++ int i; ++ unsigned long pci_mem_va; ++ static char irq_name[N_IRQS][15]; ++ ++ MCF_SPCR |= 0x02; /*Enable the PCI clock*/ ++ ++ /* Get controller revision */ ++ revision = MCF_PCICCRIR; ++ printk(KERN_INFO "ColdFire PCI Host Bridge " ++ "(Rev. %d) detected:" ++ "MEMBase %x,MEMLen %x,IOBase %x,IOLen %x\n", ++ revision, HOST_MEM_BASE, ++ PCI_MEM_SIZE - 1, 0, PCI_IO_SIZE - 1); ++ ++ bus = (struct pci_bus_info *)kmalloc(sizeof(struct pci_bus_info), ++ GFP_KERNEL); ++ if (!bus) { ++ printk(KERN_ERR "can not alloc mem for pci bus!\n"); ++ return NULL; ++ } ++ ++ /* Setup bus info structure. */ ++ memset(bus, 0, sizeof(struct pci_bus_info)); ++ ++ /* Request intiator memory resource */ ++ bus->mem_space.start = PCI_MEM_BASE;/*HOST_MEM_BASE;*/ ++ bus->mem_space.end = bus->mem_space.start + PCI_MEM_SIZE - 1; ++ bus->mem_space.name = "PCI Bus #0"; ++ if (request_resource(&iomem_resource, ++ &(bus->mem_space)) != 0) { ++ printk(KERN_ERR "Failed to request bridge iomem resource\n"); ++ return NULL; ++ } ++ ++ /* Request intiator memory resource */ ++ /*bus->io_space.start = 0;*/ ++ bus->io_space.start = HOST_IO_BASE; ++ bus->io_space.end = bus->io_space.start + PCI_IO_SIZE - 1; ++ bus->io_space.name = "PCI Bus #0"; ++ if (request_resource(&ioport_resource, ++ &(bus->io_space)) != 0) { ++ printk(KERN_ERR "Failed to request bridge " ++ "ioport resource\n"); ++ return NULL; ++ } ++ ++ /* Must Reset!!! If bootloader has PCI enabled, it will cause ++ * problem in linux when it tries to configure/find resources ++ * for the pci devices. Both registers need to be reset. ++ */ ++ /*MCF_PCIGSCR |= 0x1;*/ ++ MCF_PCIGSCR = 0x1; ++ MCF_PCITCR = 0x00000000; ++ ++ /* Set up the arbiter */ ++ MCF_PCIARB_PACR = 0; /*MCF_PCIARB_PACR_PKMD*/ ++ ++ /* GNT and REQ */ ++ MCF_PAR_PCIBG = 0x3FF; ++ MCF_PAR_PCIBR = 0x3FF; ++ ++ /* Enable bus mastering, memory access and MWI */ ++ MCF_PCISCR = (MCF_PCISCR_B | MCF_PCISCR_M); ++ ++ /* Setup burst parameters */ ++ /*The offset 0x0e normally was header_type, set it to 0 and fix later*/ ++ MCF_PCICR1 = MCF_PCICR1_LATTIMER(0x00) | ++ MCF_PCICR1_CACHELINESIZE(PCI_CACHE_LINE); ++ ++ MCF_PCICR2 = 0; ++ /*MCF_PCICR2_MINGNT(PCI_MINGNT) | ++ MCF_PCICR2_MAXLAT(PCI_MAXLAT); ++ */ ++ /* Turn on error signaling */ ++ MCF_PCIICR = MCF_PCIICR_TAE | MCF_PCIICR_IAE | PCI_RETRIES; ++ MCF_PCIGSCR |= MCF_PCIGSCR_SEE; ++ /* ++ * Configure Initiator Windows ++ * Window 0: 128M PCI Memory @ HOST_MEM_BASE, 1:1 mapping ++ * Window 1: 64K I/O Memory @ HOST_IO_BASE, 1:0 mapping ++ */ ++ MCF_PCIIW0BTAR = WxBAR(HOST_MEM_BASE, PCI_MEM_BASE, PCI_MEM_SIZE); ++ MCF_PCIIW1BTAR = WxBAR(HOST_IO_BASE, PCI_IO_BASE_ADDR, PCI_IO_SIZE); ++ ++ MCF_PCIIWCR = MCF_PCIIWCR_WINCTRL1_IO | ++ MCF_PCIIWCR_WINCTRL0_MEMREAD; ++ ++ /* Target PCI DMA Windows */ ++ MCF_PCIBAR1 = PCI_DMA_BASE; ++ MCF_PCITBATR1 = HOST_DMA_BASE | MCF_PCITBATR1_EN; ++ ++ /* Enable internal PCI controller interrupts */ ++ MCF_ICR(ISC_PCI_XLB) = ILP_PCI_XLB; ++ /*request_irq(64+ISC_PCI_XLB, xlb_interrupt, ++ SA_INTERRUPT, "PCI XL Bus", (void*)-1); ++ enable_irq (64+ISC_PCI_XLB); ++ */ ++ if (request_irq(64+ISC_PCI_XLB, xlb_interrupt, ++ IRQF_DISABLED, "PCI XL Bus", (void *)-1)) { ++ printk(KERN_ERR "Cannot allocate " ++ "ISC_PCI_XLB IRQ\n"); ++ return (struct pci_bus_info *)-EBUSY; ++ } ++ ++ MCF_ICR(ISC_PCI_ARB) = ILP_PCI_ARB; ++ /*request_irq(64+ISC_PCI_ARB, arb_interrupt, ++ SA_INTERRUPT, "PCI Arbiter", (void*)-1); ++ enable_irq (64+ISC_PCI_ARB); ++ */ ++ if (request_irq(64 + ISC_PCI_ARB, arb_interrupt, ++ IRQF_DISABLED, "PCI Arbiter", (void *)-1)) { ++ printk(KERN_ERR "Cannot allocate " ++ "ISC_PCI_ARB IRQ\n"); ++ return (struct pci_bus_info *)-EBUSY; ++ } ++ ++ /* Set slots interrupt setting */ ++ for (i = 0; i < N_IRQS; i++) { ++ /* Set trailing edge for PCI interrupts */ ++ MCF_EPPAR &= ~MCF_EPPAR_EPPA(irq_lines[i], 0x3); ++ if (irq_lines[i] == 5) ++ MCF_EPPAR |= MCF_EPPAR_EPPA(irq_lines[i], ++ MCF_EPPAR_EPPAx_FALLING); ++ else ++ MCF_EPPAR |= MCF_EPPAR_EPPA(irq_lines[i], ++ 0/*MCF_EPPAR_EPPAx_FALLING*/); ++ /* Turn on irq line in eport */ ++ MCF_EPIER |= MCF_EPIER_EPIE(irq_lines[i]); ++ ++ /* Enable irq in gpio */ ++ if (irq_lines[i] == 5) ++ MCF_PAR_FECI2CIRQ |= 1; ++ ++ if (irq_lines[i] == 6) ++ MCF_PAR_FECI2CIRQ |= 2; ++ ++ /* Register external interrupt handlers */ ++ sprintf(irq_name[i], "PCI IRQ%d", irq_lines[i]); ++ /*request_irq(64 + irq_lines[i], eint_handler, ++ SA_SHIRQ, irq_name[i], (void*)-1); ++ enable_irq(64 + irq_lines[i]);*/ ++ if (request_irq(64 + irq_lines[i], eint_handler, ++ IRQF_SHARED, irq_name[i], (void *)-1)) { ++ printk(KERN_ERR "Cannot allocate " ++ "irq_lines[%d] IRQ\n", ++ irq_lines[i]); ++ return (struct pci_bus_info *)-EBUSY; ++ } ++ } ++ ++ /* Clear PCI Reset and wait for devices to reset */ ++ MCF_PCIGSCR &= ~MCF_PCIGSCR_PR; ++ schedule_timeout((5 * HZ)); ++ /* Remap initiator windows (should be 1:1 to the physical memory) */ ++ pci_mem_va = (int) ioremap_nocache(HOST_MEM_BASE, ++ PCI_MEM_SIZE + PCI_IO_SIZE); ++ udelay(1000); /* let every thing effect */ ++#if 1 ++ printk(KERN_INFO "%s: MEMBase_phy %x, Virt %x, len %x\n", ++ __func__, HOST_MEM_BASE, pci_mem_va, ++ PCI_MEM_SIZE + PCI_IO_SIZE); ++#endif ++ BUG_ON(pci_mem_va != HOST_MEM_BASE); ++ ++ /* Setup bios32 and pci bus driver callbacks */ ++ bus->m68k_pci_ops = &bus_ops; ++ bus->fixup = coldfire_fixup; ++ bus->conf_device = configure_device; ++ ++ return bus; ++} +--- /dev/null ++++ b/arch/m68k/coldfire/m547x/pci_dummy.S +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Author: Jason Jin <Jason.jin@freescale.com> ++ * ++ * This routine is the dummy function for PCI errata ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++.global _pci_dummy_function ++.global pci_dummy_function ++.text ++ ++pci_dummy_function: ++_pci_dummy_function: ++ ++/* force function start to 16-byte boundary.Can be done in linker file also */ ++.align 16 ++clr.l %d0 ++move.l %d0, 0xF0000F0C ++/* Must use direct addressing. write to EPORT module ++* xlbus -> slavebus -> eport, writing '0' to register has no ++* effect ++*/ ++ ++rts ++tpf.l #0x0 ++tpf.l #0x0 ++tpf.l #0x0 ++tpf.l #0x0 ++tpf.l #0x0 ++.end +--- /dev/null ++++ b/arch/m68k/include/asm/5445x_pci.h +@@ -0,0 +1,111 @@ ++/* ++ * asm-m68k/pci.h - m68k specific PCI declarations. ++ * ++ * Copyright (C) 2007, 2009-2011 Freescale Semiconductor, Inc. ++ * All Rights Reserved. ++ * Kurt Mahan <kmahan@freescale.com> ++ */ ++#ifndef _ASM_M68K_5445X_PCI_H ++#define _ASM_M68K_5445x_PCI_H ++ ++#ifndef CONFIG_PCI ++/* ++ * The PCI address space does equal the physical memory ++ * address space. The networking and block device layers use ++ * this boolean for bounce buffer decisions. ++ */ ++#define PCI_DMA_BUS_IS_PHYS (1) ++#else ++#include <asm-generic/pci-dma-compat.h> ++ ++#define PCI_DMA_BASE 0 /* PCI-DMA window base */ ++#define NL_ORIGINAL ++/* ++ * The PCI address space does equal the physical memory ++ * address space. The networking and block device layers use ++ * this boolean for bounce buffer decisions. ++ */ ++#define PCI_DMA_BUS_IS_PHYS (1) ++ ++#define PCIBIOS_MIN_IO 0x00004000 ++#define PCIBIOS_MIN_MEM 0x02000000 ++ ++#define pcibios_assign_all_busses() 0 ++#define pcibios_scan_all_fns(a, b) 0 ++ ++struct pci_raw_ops { ++ int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn, ++ int reg, int len, u32 *val); ++ int (*write)(unsigned int domain, unsigned int bus, unsigned int devfn, ++ int reg, int len, u32 val); ++}; ++ ++extern struct pci_raw_ops *raw_pci_ops; ++ ++static inline void ++pcibios_set_master(struct pci_dev *dev) ++{ ++ /* no special bus mastering setup handling */ ++} ++ ++static inline void ++pcibios_penalize_isa_irq(int irq, int active) ++{ ++ /* no dynamic PCI IRQ allocation */ ++} ++ ++#if 0 ++static inline void ++pcibios_add_platform_entries(struct pci_dev *dev) ++{ ++ /* no special handling */ ++} ++#endif ++ ++static inline void ++pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, ++ struct resource *res) ++{ ++ region->start = res->start; ++ region->end = res->end; ++} ++ ++static inline void ++pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, ++ struct pci_bus_region *region) ++{ ++ res->start = region->start; ++ res->end = region->end; ++} ++ ++static inline struct resource * ++pcibios_select_root(struct pci_dev *pdev, struct resource *res) ++{ ++ struct resource *root = NULL; ++ ++ if (res->flags & IORESOURCE_IO) ++ root = &ioport_resource; ++ if (res->flags & IORESOURCE_MEM) ++ root = &iomem_resource; ++ ++ return root; ++} ++ ++#ifndef CONFIG_M54455_PCI_initcall ++extern int pci_init(void); ++extern int pcibios_init(void); ++#endif ++ ++extern void set_fpga(u32 *addr, u32 val); ++ ++#ifdef CONFIG_M54455 ++extern int init_mcf5445x_pci(void); ++extern void mcf5445x_conf_device(struct pci_dev *dev); ++extern void mcf5445x_pci_dumpregs(void); ++ ++extern struct resource pci_ioport_resource; ++extern struct resource pci_iomem_resource; ++#endif ++ ++#endif /* CONFIG_PCI */ ++#endif /* _ASM_M68K_5445X_PCI_H */ +--- /dev/null ++++ b/arch/m68k/include/asm/548x_pci.h +@@ -0,0 +1,99 @@ ++/* ++ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Written by Wout Klaren. ++ */ ++ ++#ifndef _ASM_M68K_548X_PCI_H ++#define _ASM_M68K_548X_PCI_H ++ ++#include <linux/mm.h> ++#include <asm/scatterlist.h> ++ ++#include <asm-generic/pci.h> ++ ++struct pci_ops; ++ ++/* ++ * Structure with hardware dependent information and functions of the ++ * PCI bus. ++ */ ++ ++struct pci_bus_info { ++ /* ++ * Resources of the PCI bus. ++ */ ++ ++ struct resource mem_space; ++ struct resource io_space; ++ ++ /* ++ * System dependent functions. ++ */ ++ ++ struct pci_ops *m68k_pci_ops; ++ ++ void (*fixup)(int pci_modify); ++ void (*conf_device)(struct pci_dev *dev); ++}; ++ ++#define pcibios_assign_all_busses() 0 ++#define pcibios_scan_all_fns(a, b) 0 ++ ++static inline void pcibios_set_master(struct pci_dev *dev) ++{ ++ /* No special bus mastering setup handling */ ++} ++ ++static inline void pcibios_penalize_isa_irq(int irq) ++{ ++ /* We don't do dynamic PCI IRQ allocation */ ++} ++ ++#ifndef CONFIG_COLDFIRE ++/* The PCI address space does equal the physical memory ++ * address space. The networking and block device layers use ++ * this boolean for bounce buffer decisions. ++ */ ++#define PCI_DMA_BUS_IS_PHYS (1) ++ ++#define PCIBIOS_MIN_IO 0x00004000 ++#define PCIBIOS_MIN_MEM 0x04000000 ++ ++#else /* !CONFIG_COLDFIRE */ ++#include <asm-generic/pci-dma-compat.h> ++#define PCI_DMA_BASE /*0x40000000*/0 ++/* PCI-DMA window base */ ++ ++extern struct pci_bus_info *__init init_coldfire_pci(void); ++extern void *pci_alloc_son(struct pci_dev *, size_t, ++ dma_addr_t *, int); ++/* ++ * The PCI address space equal the virtual memory ++ * address space on m547X/m548X. ++ */ ++#define PCI_DMA_BUS_IS_PHYS (1) ++ ++#define PCIBIOS_MIN_IO 0x00000100 ++#define PCIBIOS_MIN_MEM 0x02000000 ++ ++struct scatterlist; ++ ++ ++/* This is always fine. */ ++#define pci_dac_dma_supported(pci_dev, mask) (1) ++ ++ ++/* These macros should be used after a pci_map_sg call has been done ++ * to get bus addresses of each of the SG entries and their lengths. ++ * You should only work with the number of sg entries pci_map_sg ++ * returns. ++ */ ++#define sg_dma_address(sg) ((sg)->dma_address) ++#define sg_dma_len(sg) ((sg)->length) ++ ++extern void pci_dummy_function(void); ++/*Declarations of hardware specific initialisation functions*/ ++extern struct pci_bus_info *init_hades_pci(void); ++ ++#endif /* !CONFIG_COLDFIRE*/ ++#endif /* _ASM_M68K_548X_PCI_H */ +--- a/arch/m68k/include/asm/pci.h ++++ b/arch/m68k/include/asm/pci.h +@@ -1,7 +1,13 @@ + #ifndef _ASM_M68K_PCI_H + #define _ASM_M68K_PCI_H + ++#if defined(CONFIG_M5445X) ++#include "5445x_pci.h" ++#elif defined(CONFIG_M547X_8X) ++#include "548x_pci.h" ++#else + #include <asm-generic/pci-dma-compat.h> ++#endif + + /* The PCI address space does equal the physical memory + * address space. The networking and block device layers use +--- /dev/null ++++ b/arch/m68k/kernel/bios32_mcf548x.c +@@ -0,0 +1,632 @@ ++/* ++ * bios32.c - PCI BIOS functions for m68k systems. ++ * ++ * Written by Wout Klaren. ++ * ++ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Shrek Wu B16972@freescale.com ++ * ++ * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger. ++ */ ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/device.h> ++#include <linux/delay.h> ++ ++# define DBG_DEVS(args) ++ ++#ifdef CONFIG_PCI ++ ++/* ++ * PCI support for Linux/m68k. Currently only the Hades is supported. ++ * ++ * The support for PCI bridges in the DEC Alpha version has ++ * been removed in this version. ++ */ ++ ++#include <linux/pci.h> ++#include <linux/slab.h> ++#include <linux/mm.h> ++ ++#include <asm/io.h> ++#include <asm/pci.h> ++#include <asm/uaccess.h> ++ ++#define KB 1024 ++#define MB (1024*KB) ++#define GB (1024*MB) ++ ++#define MAJOR_REV 0 ++#define MINOR_REV 5 ++ ++/* ++ * Align VAL to ALIGN, which must be a power of two. ++ */ ++ ++#define MAX(val1, val2) (((val1) > (val2)) ? val1 : val2) ++ ++/* ++ * Offsets relative to the I/O and memory base addresses from where resources ++ * are allocated. ++ */ ++ ++#ifdef CONFIG_COLDFIRE ++#define IO_ALLOC_OFFSET 0x00000100 ++#define MEM_ALLOC_OFFSET 0x00000000 ++#else /* CONFIG_COLDFIRE */ ++#define IO_ALLOC_OFFSET 0x00004000 ++#define MEM_ALLOC_OFFSET 0x04000000 ++#endif /* CONFIG_COLDFIRE */ ++ ++/* ++ * Bus info structure of the PCI bus. A pointer to this structure is ++ * put in the sysdata member of the pci_bus structure. ++ */ ++ ++static struct pci_bus_info *bus_info; ++ ++static int pci_modify = 1; ++/* If set, layout the PCI bus ourself. */ ++static int skip_vga; ++/* If set do not modify base addresses of vga cards.*/ ++static int disable_pci_burst; ++/* If set do not allow PCI bursts. */ ++ ++static volatile unsigned int io_base; ++static volatile unsigned int mem_base; ++ ++/* ++ * static void disable_dev(struct pci_dev *dev) ++ * ++ * Disable PCI device DEV so that it does not respond to I/O or memory ++ * accesses. ++ * ++ * Parameters: ++ * ++ * dev - device to disable. ++ */ ++ ++static void __init disable_dev(struct pci_dev *dev) ++{ ++ unsigned short cmd; ++ ++ if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) || ++ (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) || ++ (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga) ++ return; ++ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ ++ cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++} ++ ++/* Stolen from pcibios_enable_resources/i386 */ ++int pcibios_enable_device(struct pci_dev *dev, int mask) ++{ ++ 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++) { ++ /* Only set up the requested stuff */ ++ if (!(mask & (1<<idx))) ++ continue; ++ ++ r = &dev->resource[idx]; ++ if (!r->start && r->end) { ++ printk(KERN_ERR "PCI: Device %s not" ++ " available because" ++ " of resource collisions\n", ++ dev_name(&(dev->dev))); ++ return -EINVAL; ++ } ++ if (r->flags & IORESOURCE_IO) ++ cmd |= PCI_COMMAND_IO; ++ if (r->flags & IORESOURCE_MEM) ++ cmd |= PCI_COMMAND_MEMORY; ++ } ++ if (dev->resource[PCI_ROM_RESOURCE].start) ++ cmd |= PCI_COMMAND_MEMORY; ++ if (cmd != old_cmd) { ++ printk(KERN_ERR "PCI: Enabling device " ++ "%s (%04x -> %04x)\n", ++ dev_name(&(dev->dev)), old_cmd, cmd); ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ } ++ return 0; ++} ++ ++/* ++ * static void layout_dev(struct pci_dev *dev) ++ * ++ * Layout memory and I/O for a device. ++ * ++ * Parameters: ++ * ++ * device - device to layout memory and I/O for. ++ */ ++ ++static void __init layout_dev(struct pci_dev *dev) ++{ ++ unsigned short cmd; ++ unsigned int base, mask, size, reg; ++ unsigned int alignto; ++ int i; ++ ++ /* ++ * Skip video cards if requested. ++ */ ++ if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) || ++ (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) || ++ (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga) { ++ printk(KERN_ERR "%s: VGA\n", __func__); ++ return; ++ } ++ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ ++ for (reg = PCI_BASE_ADDRESS_0, i = 0; ++ reg <= PCI_BASE_ADDRESS_5; reg += 4, i++) { ++ /* ++ * Figure out how much space and of what type this ++ * device wants. ++ */ ++ ++ pci_write_config_dword(dev, reg, 0xffffffff); ++ pci_read_config_dword(dev, reg, &base); ++ if (!base) { ++ /* this base-address register is unused */ ++ dev->resource[i].start = 0; ++ dev->resource[i].end = 0; ++ dev->resource[i].flags = 0; ++ continue; ++ } ++ ++ /* ++ * We've read the base address register back after ++ * writing all ones and so now we must decode it. ++ */ ++ if (base & PCI_BASE_ADDRESS_SPACE_IO) { ++ /* ++ * I/O space base address register. ++ */ ++ ++ cmd |= PCI_COMMAND_IO; ++ ++ base &= PCI_BASE_ADDRESS_IO_MASK; ++ mask = (~base << 1) | 0x1; ++ size = (mask & base) & 0xffffffff; ++ ++ /* ++ * Align to multiple of size of minimum base. ++ */ ++ ++#ifdef CONFIG_COLDFIRE ++ alignto = MAX(PAGE_SIZE, size) ; ++#else /* !CONFIG_COLDFIRE */ ++ alignto = MAX(0x040, size) ; ++#endif /* CONFIG_COLDFIRE */ ++ base = ALIGN(io_base, alignto); ++ io_base = base + size; ++ pci_write_config_dword(dev, reg, ++ base | PCI_BASE_ADDRESS_SPACE_IO); ++ dev->resource[i].start = base; ++ dev->resource[i].end = ++ dev->resource[i].start + size - 1; ++ dev->resource[i].flags = ++ IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO; ++ ++ DBG_DEVS(("layout_dev: IO address: %x\n", base)); ++ } else { ++ unsigned int type; ++ ++ /* ++ * Memory space base address register. ++ */ ++ cmd |= PCI_COMMAND_MEMORY; ++ ++ type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK; ++ base &= PCI_BASE_ADDRESS_MEM_MASK; ++ mask = (~base << 1) | 0x1; ++ size = (mask & base) & 0xffffffff; ++ switch (type) { ++ case PCI_BASE_ADDRESS_MEM_TYPE_32: ++ case PCI_BASE_ADDRESS_MEM_TYPE_64: ++ break; ++ ++ case PCI_BASE_ADDRESS_MEM_TYPE_1M: ++ printk(KERN_INFO "bios32 WARNING: slot %d," ++ " function %d " ++ "requests memory below 1MB---don't " ++ "know how to do that.\n", ++ PCI_SLOT(dev->devfn), ++ PCI_FUNC(dev->devfn)); ++ continue; ++ } ++ DBG_DEVS(("%s MEM: base %x,type %x,mask %x,size %x\n", ++ __func__, base, type, mask, size)); ++ /* ++ * Align to multiple of size of minimum base. ++ */ ++ ++ alignto = max_t(unsigned int, 0x1000, size); ++ base = ALIGN(mem_base, alignto); ++ mem_base = base + size; ++ pci_write_config_dword(dev, reg, base); ++ dev->resource[i].start = base; ++ dev->resource[i].end = ++ dev->resource[i].start + size - 1; ++ dev->resource[i].flags = IORESOURCE_MEM; ++ ++ DBG_DEVS(("%s MEM :base %x,size %x\n", ++ __func__, base, size)); ++ if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) { ++ /* ++ * 64-bit address, set the highest 32 bits ++ * to zero. ++ */ ++ ++ reg += 4; ++ pci_write_config_dword(dev, reg, 0); ++ ++ i++; ++ dev->resource[i].start = 0; ++ dev->resource[i].end = 0; ++ dev->resource[i].flags = 0; ++ printk(KERN_ERR "%s:type == 64\n", __func__); ++ } ++ } ++ } ++ /* ++ * Enable device: ++ */ ++ if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED || ++ dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || ++ dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || ++ dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) { ++ /* ++ * All of these (may) have I/O scattered all around ++ * and may not use i/o-base address registers at all. ++ * So we just have to always enable I/O to these ++ * devices. ++ */ ++ cmd |= PCI_COMMAND_IO; ++ pci_write_config_word(dev, PCI_COMMAND, ++ cmd | PCI_COMMAND_MASTER); ++ } ++ ++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, ++ (disable_pci_burst) ? 0 : 32); ++ ++ if (bus_info != NULL) ++ bus_info->conf_device(dev); ++ /* Machine dependent configuration. */ ++ ++ printk(KERN_INFO "layout_dev: bus %d slot 0x%x " ++ "VID 0x%x DID 0x%x class 0x%x\n", ++ dev->bus->number, PCI_SLOT(dev->devfn), ++ dev->vendor, dev->device, dev->class); ++} ++ ++/* ++ * static void layout_bus(struct pci_bus *bus) ++ * ++ * Layout memory and I/O for all devices on the given bus. ++ * ++ * Parameters: ++ * ++ * bus - bus. ++ */ ++ ++static void __init layout_bus(struct pci_bus *bus) ++{ ++ unsigned int bio, bmem; ++ struct pci_dev *dev; ++ ++ DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); ++ ++ if (list_empty(&bus->devices) && list_empty(&bus->children)) ++ return; ++ ++ /* ++ * Align the current bases on appropriate boundaries (4K for ++ * IO and 1MB for memory). ++ */ ++ ++ bio = io_base = ALIGN(io_base, 4*KB); ++ bmem = mem_base = ALIGN(mem_base, 1*MB); ++ ++ /* ++ * PCI devices might have been setup by a PCI BIOS emulation ++ * running under TOS. In these cases there is a ++ * window during which two devices may have an overlapping ++ * address range. To avoid this causing trouble, we first ++ * turn off the I/O and memory address decoders for all PCI ++ * devices. They'll be re-enabled only once all address ++ * decoders are programmed consistently. ++ */ ++ ++ DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number)); ++ ++#ifdef NL_ORIGINAL ++ for (dev = bus->devices; dev; dev = dev->sibling) { ++#else ++ dev = NULL; ++ while ((dev = pci_get_device( ++ PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { ++#endif ++ if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || ++ (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) ++ disable_dev(dev); ++ } ++ ++ /* ++ * Allocate space to each device: ++ */ ++ ++ DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number)); ++ ++#ifdef NL_ORIGINAL ++ for (dev = bus->devices; dev; dev = dev->sibling) { ++#else ++ dev = NULL; ++ while ((dev = pci_get_device( ++ PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { ++#endif ++ ++ if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || ++ (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) ++ layout_dev(dev); ++ } ++ ++ DBG_DEVS(("layout_bus: bus %d finished\n", bus->number)); ++} ++ ++/* ++ * static void pcibios_fixup(void) ++ * ++ * Layout memory and I/O of all devices on the PCI bus if 'pci_modify' is ++ * true. This might be necessary because not every m68k machine with a PCI ++ * bus has a PCI BIOS. This function should be called right after ++ * pci_scan_bus() in pcibios_init(). ++ */ ++ ++static void __init pcibios_fixup(void) ++{ ++ DBG_DEVS(("%s\n", __func__)); ++ if (pci_modify) { ++ /* ++ * Set base addresses for allocation of I/O and memory space. ++ */ ++ ++ io_base = bus_info->io_space.start + IO_ALLOC_OFFSET; ++ mem_base = bus_info->mem_space.start + MEM_ALLOC_OFFSET; ++ ++ /* ++ * Scan the tree, allocating PCI memory and I/O space. ++ */ ++ ++#ifdef NL_ORIGINAL ++ layout_bus(pci_bus_b(pci_root.next)); ++#else ++ layout_bus(pci_bus_b(pci_root_buses.next)); ++#endif ++ } ++ ++ /* ++ * Fix interrupt assignments, etc. ++ */ ++ ++ bus_info->fixup(pci_modify); ++} ++ ++/* ++ * static void pcibios_claim_resources(struct pci_bus *bus) ++ * ++ * Claim all resources that are assigned to devices on the given bus. ++ * ++ * Parameters: ++ * ++ * bus - bus. ++ */ ++ ++static void __init pcibios_claim_resources(struct pci_bus *bus) ++{ ++ struct pci_dev *dev; ++ int i; ++ DBG_DEVS(("%s\n", __func__)); ++#ifdef NL_ORIGINAL ++ while (bus) { ++#else ++ while ((bus = pci_find_next_bus(bus)) != NULL) { ++#endif ++ ++#ifdef NL_ORIGINAL ++ for (dev = bus->devices; (dev != NULL); ++ dev = dev->sibling) { ++#else ++ dev = NULL; ++ while ((dev = pci_get_device( ++ PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { ++#endif ++ for (i = 0; i < PCI_NUM_RESOURCES; i++) { ++ struct resource *r = &dev->resource[i]; ++ struct resource *pr; ++ struct pci_bus_info *bus_info = ++ (struct pci_bus_info *)dev->sysdata; ++ ++ if ((r->start == 0) || (r->parent != NULL)) ++ continue; ++ ++#ifdef CONFIG_COLDFIRE ++ if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) ++ continue; ++#endif /* CONFIG_COLDFIRE */ ++#if 1 ++ if (r->flags & IORESOURCE_IO) ++ pr = &bus_info->io_space; ++ else ++ pr = &bus_info->mem_space; ++#else ++ if (r->flags & IORESOURCE_IO) ++ pr = &ioport_resource; ++ else ++ pr = &iomem_resource; ++#endif ++ if (request_resource(pr, r) < 0) { ++#ifdef NL_ORIGINAL ++ DBG_DEVS(("PCI: Address space" ++ " collision on " ++ "region %d of device %s\n", ++ i, dev->name)); ++#else ++ printk(KERN_INFO "PCI: Address space" ++ " collision on region %d of" ++ " device %s\n", ++ i, dev_name(&(dev->dev))); ++#endif ++ } ++ } ++ ++#ifdef NL_ORIGINAL ++ } ++ if (bus->children) ++ pcibios_claim_resources(bus->children); ++#else ++ } ++ if (!list_empty(&bus->children)) ++ pcibios_claim_resources(pci_bus_b(bus->children.next)); ++#endif ++ ++#ifdef NL_ORIGINAL ++ bus = bus->next; ++#endif ++ } ++} ++ ++/* ++ * int pcibios_assign_resource(struct pci_dev *dev, int i) ++ * ++ * Assign a new address to a PCI resource. ++ * ++ * Parameters: ++ * ++ * dev - device. ++ * i - resource. ++ * ++ * Result: 0 if successful. ++ */ ++ ++int __init pcibios_assign_resource(struct pci_dev *dev, int i) ++{ ++ struct resource *r = &dev->resource[i]; ++ struct resource *pr = pci_find_parent_resource(dev, r); ++ unsigned long size = r->end + 1; ++ DBG_DEVS(("%s:IO_ALLOC_OFFSET %x\n", __func__, IO_ALLOC_OFFSET)); ++ if (!pr) ++ return -EINVAL; ++ ++ if (r->flags & IORESOURCE_IO) { ++ DBG_DEVS(("%s:IORESOURCE_IO:start %x, size %lx\n", ++ __func__, bus_info->io_space.start, size)); ++ if (size > 0x100) ++ return -EFBIG; ++ ++#ifdef NL_ORIGINAL ++ if (allocate_resource(pr, r, size, bus_info->io_space.start + ++ IO_ALLOC_OFFSET, ++ bus_info->io_space.end, ++ 1024)) ++#else ++ if (allocate_resource(pr, r, size, bus_info->io_space.start + ++ IO_ALLOC_OFFSET, ++ bus_info->io_space.end, ++ 1024, NULL, NULL)) ++#endif ++ return -EBUSY; ++ } else { ++ DBG_DEVS(("%s:IORESOURCE_MEM:start %x, size %lx\n", ++ __func__, bus_info->mem_space.start, size)); ++#ifdef NL_ORIGINAL ++ if (allocate_resource(pr, r, size, bus_info->mem_space.start + ++ MEM_ALLOC_OFFSET, ++ bus_info->mem_space.end, size)) ++#else ++ if (allocate_resource(pr, r, size, bus_info->io_space.start + ++ IO_ALLOC_OFFSET, bus_info->io_space.end, ++ 1024, NULL, NULL)) ++#endif ++ return -EBUSY; ++ } ++ ++ if (i < 6) ++ pci_write_config_dword(dev, ++ PCI_BASE_ADDRESS_0 + 4 * i, r->start); ++ ++ return 0; ++} ++ ++void pcibios_fixup_bus(struct pci_bus *bus) ++{ ++ struct pci_dev *dev; ++ void *sysdata; ++ ++ sysdata = (bus->parent) ? bus->parent->sysdata : bus->sysdata; ++ ++#ifdef NL_ORIGINAL ++ for (dev = bus->devices; (dev != NULL); dev = dev->sibling) ++#else ++ dev = NULL; ++ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) ++#endif ++ dev->sysdata = sysdata; ++} ++ ++int __init pcibios_init(void) ++{ ++ printk(KERN_INFO "Linux/m68k PCI BIOS32 " ++ "revision %x.%02x\n", MAJOR_REV, MINOR_REV); ++ ++ bus_info = NULL; ++#ifdef CONFIG_COLDFIRE ++ bus_info = init_coldfire_pci(); ++#endif /* CONFIG_COLDFIRE */ ++#ifdef CONFIG_HADES ++ if (MACH_IS_HADES) ++ bus_info = init_hades_pci(); ++#endif ++ if (bus_info != NULL) { ++ printk(KERN_ERR "PCI: Probing PCI hardware\n"); ++ pci_scan_bus(0, bus_info->m68k_pci_ops, bus_info); ++ pcibios_fixup(); ++#ifdef NL_ORIGINAL ++ pcibios_claim_resources(pci_root); ++#else ++ pcibios_claim_resources(pci_bus_b(pci_root_buses.next)); ++#endif ++ } else ++ printk(KERN_ERR "PCI: No PCI bus detected\n"); ++ return 0; ++} ++ ++subsys_initcall(pcibios_init); ++ ++char *pcibios_setup(char *str) ++{ ++ if (!strcmp(str, "nomodify")) { ++ pci_modify = 0; ++ return NULL; ++ } else if (!strcmp(str, "skipvga")) { ++ skip_vga = 1; ++ return NULL; ++ } else if (!strcmp(str, "noburst")) { ++ disable_pci_burst = 1; ++ return NULL; ++ } ++ ++ return str; ++} ++#endif /* CONFIG_PCI */ +--- a/drivers/pci/Makefile ++++ b/drivers/pci/Makefile +@@ -50,6 +50,7 @@ obj-$(CONFIG_X86_VISWS) += setup-irq.o + obj-$(CONFIG_MN10300) += setup-bus.o + obj-$(CONFIG_MICROBLAZE) += setup-bus.o + obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o ++obj-$(CONFIG_M54455) += setup-bus.o setup-irq.o + + # + # ACPI Related PCI FW Functions +--- a/drivers/pci/access.c ++++ b/drivers/pci/access.c +@@ -25,6 +25,7 @@ static DEFINE_RAW_SPINLOCK(pci_lock); + #define PCI_word_BAD (pos & 1) + #define PCI_dword_BAD (pos & 3) + ++#ifdef NL_ORIGINAL + #define PCI_OP_READ(size,type,len) \ + int pci_bus_read_config_##size \ + (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ +@@ -39,6 +40,23 @@ int pci_bus_read_config_##size \ + raw_spin_unlock_irqrestore(&pci_lock, flags); \ + return res; \ + } ++#else /* NL_ORIGINAL */ ++#define PCI_OP_READ(size, type, len) \ ++ int pci_bus_read_config_##size \ ++ (struct pci_bus *bus, unsigned int devfn, \ ++ int pos, type * value) \ ++{ \ ++ int res; \ ++ unsigned long flags; \ ++ if (PCI_##size##_BAD) \ ++ return PCIBIOS_BAD_REGISTER_NUMBER; \ ++ raw_spin_lock_irqsave(&pci_lock, flags); \ ++ res = bus->ops->read( \ ++ bus, devfn, pos, len, (u32 *)value); \ ++ raw_spin_unlock_irqrestore(&pci_lock, flags); \ ++ return res; \ ++} ++#endif /* NL_ORIGINAL */ + + #define PCI_OP_WRITE(size,type,len) \ + int pci_bus_write_config_##size \ +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -77,7 +77,13 @@ static void __dev_sort_resources(struct + u16 class = dev->class >> 8; + + /* Don't touch classless devices or host bridges or ioapics. */ ++#ifdef CONFIG_M5445X ++ if (class == PCI_CLASS_NOT_DEFINED || \ ++ class == PCI_CLASS_BRIDGE_HOST || \ ++ class == PCI_CLASS_BRIDGE_OTHER) ++#else + if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST) ++#endif + return; + + /* Don't touch ioapic devices already enabled by firmware */ +--- a/lib/iomap.c ++++ b/lib/iomap.c +@@ -227,9 +227,13 @@ EXPORT_SYMBOL(iowrite32_rep); + /* Create a virtual mapping cookie for an IO port range */ + void __iomem *ioport_map(unsigned long port, unsigned int nr) + { ++#ifndef CONFIG_M54455 + if (port > PIO_MASK) + return NULL; + return (void __iomem *) (unsigned long) (port + PIO_OFFSET); ++#else ++ return (void __iomem *) (unsigned long) port; ++#endif + } + + void ioport_unmap(void __iomem *addr) |