From cd3411088f6bb4393d79c50b5f7eef3f11a83435 Mon Sep 17 00:00:00 2001 From: Tudor Florea Date: Fri, 10 Oct 2014 00:31:33 +0200 Subject: initial commit for Enea Linux 4.0-140929 Migrated from the internal git server on the daisy-enea-point-release branch Signed-off-by: Tudor Florea --- .../0009-add-acp3448-PCIe-controller-driver.patch | 1081 ++++++++++++++++++++ 1 file changed, 1081 insertions(+) create mode 100644 recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch (limited to 'recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch') diff --git a/recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch b/recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch new file mode 100644 index 0000000..f97cbc5 --- /dev/null +++ b/recipes-kernel/linux/linux-3.0.6/acp3448v2/0009-add-acp3448-PCIe-controller-driver.patch @@ -0,0 +1,1081 @@ +commit b49648c2950a227edb4832924649485537d5c049 +Author: Jerry Pei +Date: Thu Sep 20 15:14:33 2012 +0800 + + add support for the PCIe controller on ACP34xx + + Extracted from lsi.patch in lsi_acp_linux_3.8.1.28 tarball. + + Signed-off-by: Jerry Pei + +diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c +index 56e8b3c..a4e1c46 100644 +--- a/arch/powerpc/sysdev/ppc4xx_pci.c ++++ b/arch/powerpc/sysdev/ppc4xx_pci.c +@@ -34,8 +34,16 @@ + #include + + #include "ppc4xx_pci.h" ++#ifdef CONFIG_ACP ++#include ++#include "../../../drivers/lsi/acp/ncr.h" ++static int acp_plx; ++#endif + + static int dma_offset_set; ++#ifdef CONFIG_ACP ++static u32 last_mpage = 0; ++#endif + + #define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL)) + #define U64_TO_U32_HIGH(val) ((u32)((val) >> 32)) +@@ -45,6 +53,9 @@ static int dma_offset_set; + #define RES_TO_U32_HIGH(val) \ + ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_HIGH(val) : (0)) + ++#define ACPX1_PCIE_MPAGE_UPPER(n) (0x1010 + (n * 8)) ++#define ACPX1_PCIE_MPAGE_LOWER(n) (0x1014 + (n * 8)) ++ + static inline int ppc440spe_revA(void) + { + /* Catch both 440SPe variants, with and without RAID6 support */ +@@ -87,7 +98,33 @@ static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) + printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n", + pci_name(dev)); + } ++ ++static void __init ++fixup_acp_pci_bridge(struct pci_dev *dev) ++{ ++ /* if we aren't a PCIe don't bother */ ++ if (!pci_find_capability(dev, PCI_CAP_ID_EXP)) ++ return ; ++ ++ /* ++ * Set the class appropriately for a bridge device ++ */ ++ printk(KERN_INFO "PCI: Setting PCI Class to PCI_CLASS_BRIDGE_HOST for %04x:%04x\n", dev->vendor, dev->device); ++ ++ ++ dev->class = PCI_CLASS_BRIDGE_HOST << 8; ++ ++ /* ++ * Make the bridge transparent ++ */ ++ dev->transparent = 1; ++ ++ return ; ++} ++ + DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge); ++DECLARE_PCI_FIXUP_HEADER(0x1000, 0x5101, fixup_acp_pci_bridge); ++DECLARE_PCI_FIXUP_HEADER(0x1000, 0x5108, fixup_acp_pci_bridge); + + static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, + void __iomem *reg, +@@ -646,6 +683,9 @@ struct ppc4xx_pciex_port + struct resource cfg_space; + struct resource utl_regs; + void __iomem *utl_base; ++#ifdef CONFIG_ACP ++ int acpChipType; ++#endif + }; + + static struct ppc4xx_pciex_port *ppc4xx_pciex_ports; +@@ -939,6 +979,35 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = + .check_link = ppc4xx_pciex_check_link_sdr, + }; + ++#if defined(CONFIG_ACP) ++ ++static int __init ++acp_pciex_core_init(struct device_node *np) ++{ ++ return 3; ++} ++ ++static int ++acp_pciex_port_init_hw(struct ppc4xx_pciex_port *port) ++{ ++ return 0; ++} ++ ++static int ++acp_pciex_setup_utl(struct ppc4xx_pciex_port *port) ++{ ++ return 0; ++} ++ ++static struct ppc4xx_pciex_hwops acp_pcie_hwops __initdata = ++{ ++ .core_init = acp_pciex_core_init, ++ .port_init_hw = acp_pciex_port_init_hw, ++ .setup_utl = acp_pciex_setup_utl ++}; ++ ++#endif ++ + static int __init ppc460ex_pciex_core_init(struct device_node *np) + { + /* Nothing to do, return 2 ports */ +@@ -1419,6 +1488,11 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) + if (core_init++) + return 0; + ++#if defined(CONFIG_ACP) ++ if (of_device_is_compatible(np, "lsi,plb-pciex")) ++ ppc4xx_pciex_hwops = &acp_pcie_hwops; ++#endif ++ + #ifdef CONFIG_44x + if (of_device_is_compatible(np, "ibm,plb-pciex-440spe")) { + if (ppc440spe_revA()) +@@ -1578,9 +1652,11 @@ static int ppc4xx_pciex_validate_bdf(struct ppc4xx_pciex_port *port, + PCI_SLOT(devfn) != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + ++#ifndef CONFIG_ACP + /* Check if we have a link */ + if ((bus->number != port->hose->first_busno) && !port->link) + return PCIBIOS_DEVICE_NOT_FOUND; ++#endif + + return 0; + } +@@ -1598,10 +1674,80 @@ static void __iomem *ppc4xx_pciex_get_config_base(struct ppc4xx_pciex_port *port + return (void __iomem *)port->hose->cfg_addr; + + relbus = bus->number - (port->hose->first_busno + 1); ++ ++#ifndef CONFIG_ACP + return (void __iomem *)port->hose->cfg_data + + ((relbus << 20) | (devfn << 12)); ++#else ++ ++ { ++ unsigned mpage; ++ u32 addr; ++ int dev, fn; ++ int cfg_type; ++ ++ /* ++ * Set MPAGE0 to map config access for this BDF ++ */ ++ ++ dev = ( (devfn & 0xf8) >> 3); ++ fn = devfn & 0x7; ++ ++ if (dev > 31) { ++ return NULL; ++ } ++ ++#ifdef CONFIG_ACP_X1V1 ++ /* v1 only supports fn=0 */ ++ if (fn) { ++ return NULL; ++ } ++#else ++ /* v2 only supports fn0-3 and bus0-63 */ ++ if (port->acpChipType == 1) { ++ if ((fn > 3) || (bus->number > 63)) { ++ return NULL; ++ } ++ } ++#endif ++ ++ if (relbus && (bus->number != bus->primary)) { ++ cfg_type = 1; ++ } else { ++ cfg_type = 0; ++ } ++ ++ /* build the mpage register */ ++ mpage = (bus->number << 11) | ++ (dev << 6) | ++ (cfg_type << 5 ); ++ ++ mpage |= 0x10; /* enable MPAGE for configuration access */ ++ ++ if (5 > port->acpChipType) ++ mpage |= 1; ++ ++ /* the function number moved for X2 */ ++ if (port->acpChipType < 2) { ++ mpage |= (fn << 17); ++ } else { ++ mpage |= (fn << 19); ++ } ++ ++ ++ if (mpage != last_mpage) { ++ /* printk("%02x:%02x:%02x setting mpage = 0x%08x\n", bus->number, dev, fn, mpage); */ ++ addr = ((u32) port->hose->cfg_addr) + ACPX1_PCIE_MPAGE_LOWER(7); ++ out_le32((u32 *) addr, mpage); ++ last_mpage = mpage; ++ } ++ ++ return (void __iomem *)port->hose->cfg_data; ++ } ++#endif + } + ++#ifndef CONFIG_ACP + static int ppc4xx_pciex_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int len, u32 *val) + { +@@ -1703,10 +1849,225 @@ static int ppc4xx_pciex_write_config(struct pci_bus *bus, unsigned int devfn, + return PCIBIOS_SUCCESSFUL; + } + ++#else ++static int ++ppc4xx_pciex_acp_read_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 *val) ++{ ++ struct pci_controller *hose = (struct pci_controller *) bus->sysdata; ++ struct ppc4xx_pciex_port *port = ++ &ppc4xx_pciex_ports[hose->indirect_type]; ++ void __iomem *addr; ++ u32 bus_addr; ++ u32 val32; ++ u32 mcsr; ++ int bo = offset & 0x3; ++ int rc = PCIBIOS_SUCCESSFUL; ++ ++ BUG_ON(hose != port->hose); ++ ++ if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ addr = ppc4xx_pciex_get_config_base(port, bus, devfn); ++ ++ if (!addr) { ++ *val = 0; ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ } ++ ++ /* ++ * Reading from configuration space of non-existing device can ++ * generate transaction errors. For the read duration we suppress ++ * assertion of machine check exceptions to avoid those. ++ */ ++ mtmsr( mfmsr() & ~(MSR_ME)); ++ __asm__ __volatile__("msync"); ++ ++ /* ++ * addressing is different for local config access vs. ++ * access through the mapped config space. ++ */ ++ if (bus->number == port->hose->first_busno) { ++ int wo = offset & 0xfffffffc; ++ bus_addr = (u32) addr + wo; ++ ++ } else { ++ ++ /* ++ * mapped config space only supports 32-bit access ++ * ++ * AXI address [3:0] is not used at all. ++ * AXI address[9:4] becomes register number. ++ * AXI address[13:10] becomes Ext. register number ++ * AXI address[17:14] becomes 1st DWBE for configuration read only. ++ * AXI address[29:27] is used to select one of 8 Mpage registers. ++ */ ++ ++ bus_addr = (u32) addr + (offset << 2); ++ ++ switch (len) { ++ case 1: ++ bus_addr |= ((1 << bo) ) << 14; ++ break; ++ case 2: ++ bus_addr |= ((3 << bo) ) << 14; ++ break; ++ default: ++ bus_addr |= ( 0xf ) << 14; ++ break; ++ } ++ ++ } ++ ++ /* ++ * do the read ++ */ ++ ++ val32 = in_le32((u32 *)bus_addr); ++ ++ switch (len) { ++ case 1: ++ *val = (val32 >> (bo * 8)) & 0xff; ++ break; ++ case 2: ++ *val = (val32 >> (bo * 8)) & 0xffff; ++ break; ++ default: ++ *val = val32; ++ break; ++ } ++ ++ __asm__ __volatile__("msync"); ++ ++ mcsr = mfspr(SPRN_MCSR); ++ if ( mcsr != 0) { ++ mtspr(SPRN_MCSR, 0); ++ __asm__ __volatile__("msync"); ++ ++#ifdef PRINT_CONFIG_ACCESSES ++ printk("acp_read_config : %3d [%3d..%3d] fn=0x%04x" ++ " o=0x%04x l=%d a=0x%08x machine check!! 0x%08x\n", ++ bus->number, hose->first_busno, hose->last_busno, ++ devfn, offset, len, bus_addr, mcsr); ++#endif ++ pr_debug("acp_read_config : bus=%3d [%3d..%3d] devfn=0x%04x" ++ " offset=0x%04x len=%d, addr=0x%08x machine check!! " ++ "0x%08x\n", ++ bus->number, hose->first_busno, hose->last_busno, ++ devfn, offset, len, bus_addr, mcsr); ++ *val = 0; ++ rc = PCIBIOS_DEVICE_NOT_FOUND; ++ } else { ++#ifdef PRINT_CONFIG_ACCESSES ++ printk("acp_read_config : %3d [%3d..%3d] fn=0x%04x" ++ " o=0x%04x l=%d a=0x%08x v=0x%08x\n", ++ bus->number, hose->first_busno, hose->last_busno, ++ devfn, offset, len, bus_addr, *val); ++#endif ++ pr_debug("acp_read_config : bus=%3d [%3d..%3d] devfn=0x%04x" ++ " offset=0x%04x len=%d, addr=0x%08x val=0x%08x\n", ++ bus->number, hose->first_busno, hose->last_busno, ++ devfn, offset, len, bus_addr, *val); ++ } ++ ++ /* re-enable machine checks */ ++ mtmsr(mfmsr() | (MSR_ME) ); ++ __asm__ __volatile__("msync"); ++ ++ return rc; ++} ++ ++static int ppc4xx_pciex_acp_write_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 val) ++{ ++ struct pci_controller *hose = (struct pci_controller *) bus->sysdata; ++ struct ppc4xx_pciex_port *port = ++ &ppc4xx_pciex_ports[hose->indirect_type]; ++ void __iomem *addr; ++ u32 bus_addr; ++ u32 val32; ++ ++ if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ addr = ppc4xx_pciex_get_config_base(port, bus, devfn); ++ ++ if (!addr) { ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ } ++ ++ /* ++ * addressing is different for local config access vs. ++ * access through the mapped config space. We need to ++ * translate the offset for mapped config access ++ */ ++ if (bus->number == port->hose->first_busno) { ++ /* the local ACP RC only supports 32-bit dword config access, ++ * so if this is a byte or 16-bit word access we need to ++ * perform a read-modify write ++ */ ++ if (len == 4) { ++ bus_addr = (u32) addr + offset; ++ } else { ++ int bs = ((offset & 0x3) * 8); ++ ++ bus_addr = (u32) addr + (offset & 0xfffffffc); ++ val32 = in_le32((u32 *)bus_addr); ++ ++ ++ if (len == 2) { ++ val32 = (val32 & ~(0xffff << bs) ) | ((val & 0xffff) << bs); ++ } else { ++ val32 = (val32 & ~(0xff << bs) ) | ((val & 0xff) << bs); ++ } ++ ++ val = val32; ++ len = 4; ++ } ++ ++ } else { ++ bus_addr = (u32) addr + (offset << 2) + (offset & 0x3); ++ } ++ ++#ifdef PRINT_CONFIG_ACCESSES ++ printk("acp_write_config: %3d [%3d..%3d] fn=0x%04x" ++ " o=0x%04x l=%d a=0x%08x v=0x%08x\n", ++ bus->number, hose->first_busno, hose->last_busno, ++ devfn, offset, len, bus_addr, val); ++#endif ++ pr_debug("acp_write_config: bus=%3d [%3d..%3d] devfn=0x%04x" ++ " offset=0x%04x len=%d, addr=0x%08x val=0x%08x\n", ++ bus->number, hose->first_busno, hose->last_busno, ++ devfn, offset, len, bus_addr, val); ++ ++ ++ switch (len) { ++ case 1: ++ out_8((u8 *)(bus_addr), val); ++ break; ++ case 2: ++ out_le16((u16 *)(bus_addr), val); ++ break; ++ default: ++ out_le32((u32 *)(bus_addr), val); ++ break; ++ } ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++#endif ++ + static struct pci_ops ppc4xx_pciex_pci_ops = + { ++#ifndef CONFIG_ACP + .read = ppc4xx_pciex_read_config, + .write = ppc4xx_pciex_write_config, ++#else ++ .read = ppc4xx_pciex_acp_read_config, ++ .write = ppc4xx_pciex_acp_write_config, ++#endif + }; + + static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, +@@ -1718,7 +2079,10 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, + unsigned int flags, + int index) + { +- u32 lah, lal, pciah, pcial, sa; ++ u32 pciah, pcial; ++#ifndef CONFIG_ACP ++ u32 lah, lal, sa; ++#endif + + if (!is_power_of_2(size) || + (index < 2 && size < 0x100000) || +@@ -1730,10 +2094,11 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, + } + + /* Calculate register values */ +- lah = RES_TO_U32_HIGH(plb_addr); +- lal = RES_TO_U32_LOW(plb_addr); + pciah = RES_TO_U32_HIGH(pci_addr); + pcial = RES_TO_U32_LOW(pci_addr); ++#ifndef CONFIG_ACP ++ lah = RES_TO_U32_HIGH(plb_addr); ++ lal = RES_TO_U32_LOW(plb_addr); + sa = (0xffffffffu << ilog2(size)) | 0x1; + + /* Program register values */ +@@ -1779,6 +2144,41 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, + | DCRO_PEGPL_OMRxMSKL_VAL); + break; + } ++#else ++ { ++ /* ACP X1 setup MPAGE registers */ ++ ++ int i, num_pages; ++ u32 mpage_lower; ++ ++ printk(KERN_INFO "setting outbound window %d with " ++ "plb_add=0x%012llx, pci_addr=0x%012llx, size=0x%012llx\n", ++ index, plb_addr, pci_addr, size); ++ ++ /* ++ * MPAGE7 is dedicated to config access, so we only ++ * have 7 128MB pages available for memory i/o. ++ * Calculate how many pages we need ++ */ ++ if (size > (7 * 0x08000000)) { ++ printk(KERN_WARNING "%s: Resource size 0x%012llx out of range\n", ++ hose->dn->full_name, size); ++ return -1; ++ } ++ ++ num_pages = ( (size - 1) >> 27) + 1; ++ for (i = 0; i < num_pages; i++) { ++ mpage_lower = (pcial & 0xf8000000); ++ ++ if (5 > port->acpChipType) ++ mpage_lower |= 1; ++ ++ out_le32( mbase + ACPX1_PCIE_MPAGE_UPPER(i), pciah); ++ out_le32( mbase + ACPX1_PCIE_MPAGE_LOWER(i), mpage_lower); ++ pcial += 0x08000000; ++ } ++ } ++#endif + + return 0; + } +@@ -1907,6 +2307,108 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + } + ++#if defined(CONFIG_ACP) ++ ++static void __init ++ppc4xx_configure_acp_pciex_PIMs(struct ppc4xx_pciex_port *port, ++ struct pci_controller *hose, ++ void __iomem *mbase, ++ struct resource *res) ++{ ++ resource_size_t size = res->end - res->start + 1; ++ u64 sa; ++ u32 value = 0; ++ void __iomem *tpage_base = mbase + 0x1050; ++ ++ if (port->endpoint) { ++ resource_size_t ep_addr = 0; ++ resource_size_t ep_size = 32 << 20; ++ ++ /* Currently we map a fixed 64MByte window to PLB address ++ * 0 (SDRAM). This should probably be configurable via a dts ++ * property. ++ */ ++ ++ /* Calculate window size */ ++ sa = (0xffffffffffffffffull << ilog2(ep_size));; ++ ++ /* TODO: */ ++ ++ out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(ep_addr)); ++ out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(ep_addr)); ++ } else { ++ /* Calculate window size */ ++ sa = (0xffffffffffffffffull << ilog2(size));; ++ ++ if (res->flags & IORESOURCE_PREFETCH) ++ sa |= 0x8; ++ ++ printk(KERN_INFO ++ "configure inbound mapping from 0x%012llx-0x%012llx " ++ "(0x%08llx bytes)\n", res->start, res->end, size); ++ ++ if (0 != ncr_read(NCP_REGION_ID(0xa, 0x10), 0x2c, 4, &value)) ++ printk(KERN_WARNING "** Unable to get ACP type!\n"); ++ ++ /* ++ * For ACP we need to set the dema_offset to the size of ++ * inbound window. ++ */ ++ ++ pci_dram_offset = size; ++ hose->dma_window_base_cur = size; ++ ++ out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(size)); ++ out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(size)); ++ ++ if (5 == port->acpChipType) { ++ printk(KERN_WARNING "Setting SIZE for 2500\n"); ++ out_le32(mbase + 0x11f4, 0xf0000000UL); ++ } ++ ++ /* ++ * set up the TPAGE registers ++ * ++ * We set the MSB of each TPAGE to select 128-bit AXI access. ++ * For the address field we simply program an incrementing value ++ * to map consecutive pages ++ */ ++ if (0 == acp_plx) { ++ int i; ++ ++ for (i = 0; i < 8; i++) { ++ out_le32(tpage_base, (0x80000000 + i)); ++ tpage_base += 4; ++ } ++ } else { ++ out_le32(tpage_base, 0x0); /* tpage 0 point to 0x0, not used */ ++ tpage_base +=4; ++ out_le32(tpage_base, 0x0); /* tpage 1 point to 0x0, not used */ ++ tpage_base +=4; ++ out_le32(tpage_base, 0x0); /* tpage 2 point to 0x0, not used */ ++ tpage_base +=4; ++ out_le32(tpage_base, 0x0); /* tpage 3 point to 0x0, not used */ ++ tpage_base +=4; ++ out_le32(tpage_base, 0x0); /* tpage 4 point to 0x0, not used */ ++ tpage_base +=4; ++ out_le32(tpage_base, 0x0); /* tpage 5 point to 0x0, not used */ ++ tpage_base +=4; ++ out_le32(tpage_base, 0x0); /* tpage 6 point to 0x0 for dynamic mapping */ ++ tpage_base +=4; ++ out_le32(tpage_base, 0x80001000); /* tpage 7 point to 0x20,0000,0000 tpage size = 256MB */ ++ } ++ } ++ ++ /* Enable I/O, Mem, and Busmaster cycles */ ++#if 0 ++ out_le16(mbase + PCI_COMMAND, ++ in_le16(mbase + PCI_COMMAND) | ++ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); ++#endif ++} ++ ++#endif ++ + static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) + { + struct resource dma_window; +@@ -2070,6 +2572,439 @@ static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) + iounmap(mbase); + } + ++#if defined(CONFIG_ACP) ++ ++static irqreturn_t ++acp_pcie_isr(int irq, void *arg) ++{ ++ struct pci_controller *hose = (struct pci_controller *) arg; ++ void __iomem *mbase = (void __iomem *)hose->cfg_addr; ++ ++ u32 intr_status; ++ u32 msg_fifo_stat; ++ u32 msg_fifo_info; ++ u8 externalPciIntr = 0; ++ ++ ++ /* read the PEI interrupt status register */ ++ intr_status = in_le32(mbase + 0x10c0); ++#if 0 ++ { ++ u32 intr_enb; ++ intr_enb = in_le32(mbase + 0x10c4); ++ printk("PCIE%d mbase %p intr_status/enb = 0x%08x 0x%08x\n", ++ hose->indirect_type, mbase, intr_status, intr_enb); ++ } ++#else ++ in_le32(mbase + 0x10c4); ++#endif ++ ++ /* check if this is a PCIe message from an external device */ ++ if (intr_status & 0x00000010) { ++ externalPciIntr = 1; ++ ++ msg_fifo_stat = in_le32(mbase + 0x10b4); ++ ++ /* loop until the message fifo is empty */ ++ while ( (msg_fifo_stat & 0x01) == 0) { ++ u8 bus, dev, fn; ++ u8 msg_type; ++ msg_fifo_info = in_le32(mbase + 0x10b0); ++ ++ bus = (msg_fifo_info >> 16 ) & 0xff; ++ dev = (msg_fifo_info >> 11 ) & 0x1f; ++ fn = (msg_fifo_info >> 8 ) & 0x07; ++ msg_type = msg_fifo_info & 0xff; ++ ++ /* print out the BDF and message type. ++ * We ignore the common message types. ++ */ ++ switch (msg_type) { ++ case 0x20: /* assert_INTa */ ++ case 0x21: /* assert_INTb */ ++ case 0x22: /* assert_INTc */ ++ case 0x23: /* assert_INTd */ ++ case 0x24: /* de-assert_INTa */ ++ case 0x25: /* de-assert_INTb */ ++ case 0x26: /* de-assert_INTc */ ++ case 0x27: /* de-assert_INTd */ ++ /* do nothing */ ++ break; ++ default: ++ printk("BDF %02x:%02x.%x sent msgtype 0x%02x\n", ++ bus, dev, fn, msg_type); ++ break; ++ } ++ ++ /* re-read fifo status */ ++ msg_fifo_stat = in_le32(mbase + 0x10b4); ++ ++ } ++ } else { ++ /* ++ Ignore the common interrupts, still need to figure out what ++ they all mean. ++ */ ++ if (intr_status & 0xf3ffffab) { ++ u32 t2a_err_stat; ++ u32 t2a_other_err_stat; ++ u32 int_enb; ++ u32 linkStatus; ++ u32 offset; ++ ++ printk(KERN_ERR "ACP_PCIE_ISR: got PEI error interrupt 0x%08x\n", ++ intr_status); ++ ++ linkStatus = in_le32(mbase + 0x117c); ++ printk(KERN_ERR "link_status (0x117c) = 0x%08x\n", linkStatus); ++ ++ if (intr_status & 0x00020000) { ++ t2a_err_stat = in_le32(mbase + 0x1170); ++ printk(KERN_ERR "t2a_fn_indp_err_stat = 0x%08x\n", t2a_err_stat); ++ int_enb = in_le32(mbase + 0x10c4); ++ int_enb &= 0xfffdffff; ++ out_le32(mbase + 0x10c4, int_enb); ++ } ++ ++ if (intr_status & 0x00040000) { ++ t2a_other_err_stat = in_le32(mbase + 0x1174); ++ printk(KERN_ERR "t2a_fn_indp_other_err_stat = 0x%08x\n", ++ t2a_other_err_stat); ++ int_enb = in_le32(mbase + 0x10c4); ++ int_enb &= 0xfffbffff; ++ out_le32(mbase + 0x10c4, int_enb); ++ } ++ ++ if (intr_status & 0x00000800) { ++ printk("pci_config = 0x%08x\n", in_le32(mbase + 0x1000)); ++ printk("pci_status = 0x%08x\n", in_le32(mbase + 0x1004)); ++ ++ int_enb = in_le32(mbase + 0x10c4); ++ int_enb &= 0xfffff7ff; ++ out_le32(mbase + 0x10c4, int_enb); ++ } ++ ++ /* ++ * dump all the potentially interesting PEI registers ++ */ ++ for (offset = 0x114c; offset <= 0x1180; offset += 4) { ++ printk(" 0x%04x : 0x%08x\n", offset, in_le32(mbase + offset)); ++ } ++ } ++ } ++ ++ /* ++ * We clear all the interrupts in the PEI status, even though ++ * interrupts from external devices have not yet been handled. ++ * That should be okay, since the PCI IRQ in the MPIC won't be ++ * re-enabled until all external handlers have been called. ++ */ ++ out_le32(mbase + 0x10c0, intr_status); ++ ++ return (externalPciIntr ? IRQ_NONE : IRQ_HANDLED); ++} ++ ++static void __init ppc4xx_acp_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) ++{ ++ struct resource dma_window; ++ struct pci_controller *hose = NULL; ++ const int *bus_range; ++ int primary = 0, busses; ++ void __iomem *mbase = NULL, *cfg_data = NULL; ++ int mappedIrq; ++ int err; ++ u32 pci_status; ++ u32 link_state; ++ u32 pci_config; ++ u32 version; ++ ++ /* Check if primary bridge */ ++ if (of_get_property(port->node, "primary", NULL)) ++ primary = 1; ++ ++ /* Get bus range if any */ ++ bus_range = of_get_property(port->node, "bus-range", NULL); ++ ++ /* Allocate the host controller data structure */ ++ hose = pcibios_alloc_controller(port->node); ++ if (!hose) ++ goto fail; ++ ++ /* We stick the port number in "indirect_type" so the config space ++ * ops can retrieve the port data structure easily ++ */ ++ hose->indirect_type = port->index; ++ ++ /* Get bus range */ ++ hose->first_busno = bus_range ? bus_range[0] : 0x0; ++ hose->last_busno = bus_range ? bus_range[1] : 0xff; ++ ++ /* Because of how big mapping the config space is (1M per bus), we ++ * limit how many busses we support. In the long run, we could replace ++ * that with something akin to kmap_atomic instead. We set aside 1 bus ++ * for the host itself too. ++ */ ++ busses = hose->last_busno - hose->first_busno; /* This is off by 1 */ ++ if (busses > MAX_PCIE_BUS_MAPPED) { ++ busses = MAX_PCIE_BUS_MAPPED; ++ hose->last_busno = hose->first_busno + busses; ++ } ++ ++ if (!port->endpoint) { ++ /* ++ * map the bottom page of PCIe memory for config space access ++ */ ++ cfg_data = ioremap(port->cfg_space.start, 0x100000); ++ if (cfg_data == NULL) { ++ printk(KERN_ERR "%s: Can't map external config space !", ++ port->node->full_name); ++ goto fail; ++ } ++ hose->cfg_data = cfg_data; ++ } ++ ++ /* ++ * The internal config space has already been mapped, so ++ * just re-use that virtual address. ++ */ ++ hose->cfg_addr = port->utl_base; ++ ++ pr_debug("PCIE %s, bus %d..%d\n", port->node->full_name, ++ hose->first_busno, hose->last_busno); ++ pr_debug(" config space mapped at: root @0x%p, other @0x%p\n", ++ hose->cfg_addr, hose->cfg_data); ++ ++ /* Setup config space */ ++ hose->ops = &ppc4xx_pciex_pci_ops; ++ port->hose = hose; ++ mbase = (void __iomem *)hose->cfg_addr; ++ ++ if (port->endpoint) { ++ /* if we're an endpoint don't do anything else */ ++ printk(KERN_INFO "PCIE%d: successfully set as endpoint\n", ++ port->index); ++ return; ++ } ++ ++ /* setting up as root complex */ ++ pci_config = in_le32(mbase + 0x1000); ++ ++ pci_status = in_le32(mbase + 0x1004); ++ link_state = (pci_status & 0x3f00) >> 8; ++ printk("PCIE%d status = 0x%08x : PCI link state = 0x%x\n", ++ port->index, pci_status, link_state); ++ ++ /* make sure the ACP device is configured as PCI Root Complex */ ++ if ((pci_status & 0x18) != 0x18) { ++ printk("ACP device is not PCI Root Complex! status = 0x%08x\n", ++ pci_status); ++ goto fail; ++ } ++ ++ /* make sure the link is up */ ++ if (link_state != 0xb) { ++ /* reset */ ++ printk("PCI link in bad state - resetting\n"); ++ pci_config |= 1; ++ out_le32(mbase + 0x1000, pci_config); ++ msleep(1000); ++ ++ pci_status = in_le32(mbase + 0x1004); ++ link_state = (pci_status & 0x3f00) >> 8; ++ ++ printk("PCI link state now = 0x%x\n", link_state); ++ ++ if (link_state != 0xb) { ++ printk("PCI link still in bad state - giving up!\n"); ++ goto fail; ++ } ++ } ++ ++ /* get the device version */ ++ if (0 != ncr_read(NCP_REGION_ID(0xa, 0x10), 0x2c, 4, &version)) { ++ printk(KERN_ERR "Unable to detect ACP revision!\n"); ++ goto fail; ++ } ++ port->acpChipType = (version & 0x1f); ++ printk(KERN_INFO "Using PEI register set for ACP chipType %d\n", ++ port->acpChipType); ++ ++ /* ++ * Set bus numbers on our root port ++ */ ++ out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno); ++ out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1); ++ out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno); ++ ++ ++ /* Parse outbound mapping resources */ ++ pci_process_bridge_OF_ranges(hose, port->node, primary); ++ ++ /* Parse inbound mapping resources */ ++ if (ppc4xx_parse_dma_ranges(hose, mbase, &dma_window) != 0) ++ goto fail; ++ ++ /* Configure outbound ranges POMs */ ++ ppc4xx_configure_pciex_POMs(port, hose, mbase); ++ ++ /* Configure inbound ranges PIMs */ ++ ppc4xx_configure_acp_pciex_PIMs(port, hose, mbase, &dma_window); ++ ++ /* ++ * hook up an interrupt handler ++ */ ++#if 0 ++ mappedIrq = irq_create_mapping(NULL, 29); ++ if (mappedIrq == NO_IRQ) { ++ printk(KERN_ERR "irq_create_mapping failed!!!\n"); ++ goto fail; ++ } ++ ++ err = set_irq_type(mappedIrq, IRQ_TYPE_LEVEL_HIGH); ++ if (err) { ++ printk(KERN_ERR "set_irq_type failed!!!!\n"); ++ goto fail; ++ } ++#endif ++ printk("PCIE%d mapping interrupt\n", port->index); ++ mappedIrq = irq_of_parse_and_map(port->node, 0); ++ ++ err = request_irq(mappedIrq, acp_pcie_isr, IRQF_SHARED, "acp_pcie", hose); ++ if (err) { ++ printk(KERN_ERR "request_irq failed!!!!\n"); ++ goto fail; ++ } ++ ++ /* unmask PEI interrupts */ ++#if 0 ++ out_le32(mbase + 0x10c4, 0xffffffff); ++#else ++ /* for now ignore retry requests, and INT assert/deassert */ ++ out_le32(mbase + 0x10c4, 0xf3fffffd); ++#endif ++ ++ if (port->acpChipType == 1) { ++ /* ++ * for v2 we need to set the 'axi_interface_rdy' bit ++ * this bit didn't exist in X1V1, and means something ++ * else for X2... ++ */ ++ pci_config = in_le32(mbase + 0x1000); ++ pci_config |= 0x00040000; ++ out_le32(mbase + 0x1000, pci_config); ++ } ++ ++ if (!port->endpoint) { ++ printk(KERN_INFO "PCIE%d: successfully set as root-complex\n", ++ port->index); ++ } else { ++ } ++ ++ return; ++ fail: ++ if (hose) ++ pcibios_free_controller(hose); ++ if (cfg_data) ++ iounmap(cfg_data); ++} ++ ++static void __init ppc4xx_probe_acp_pciex_bridge(struct device_node *np) ++{ ++ struct ppc4xx_pciex_port *port; ++ const u32 *pval; ++ int portno; ++ const char *val; ++ const u32 *field; ++ ++ /* First, proceed to core initialization as we assume there's ++ * only one PCIe core in the system ++ */ ++ if (ppc4xx_pciex_check_core_init(np)) ++ return; ++ ++ /* Get the port number from the device-tree */ ++ pval = of_get_property(np, "port", NULL); ++ if (pval == NULL) { ++ printk(KERN_ERR "PCIE: Can't find port number for %s\n", ++ np->full_name); ++ return; ++ } ++ portno = *pval; ++ if (portno >= ppc4xx_pciex_port_count) { ++ printk(KERN_ERR "PCIE: port number out of range for %s\n", ++ np->full_name); ++ return; ++ } ++ port = &ppc4xx_pciex_ports[portno]; ++ port->index = portno; ++ ++ /* ++ * Check if device is enabled ++ */ ++ if (!of_device_is_available(np)) { ++ printk(KERN_INFO "PCIE%d: Port disabled via device-tree\n", ++ port->index); ++ return; ++ } ++ ++ /* Make sure PCIe is enabled in the device tree. */ ++ field = of_get_property(np, "enabled", NULL); ++ ++ if (!field || (field && (0 == *field))) { ++ printk(KERN_INFO "%s: Port disabled via device-tree\n", ++ np->full_name); ++ return; ++ } ++ ++ /* Check for the PLX work-around. */ ++ field = of_get_property(np, "plx", NULL); ++ ++ if (field && (0 != *field)) ++ acp_plx = 1; ++ else ++ acp_plx = 0; ++ ++ port->node = of_node_get(np); ++ ++ /* Check if device_type property is set to "pci" or "pci-endpoint". ++ * Resulting from this setup this PCIe port will be configured ++ * as root-complex or as endpoint. ++ */ ++ val = of_get_property(port->node, "device_type", NULL); ++ if (!strcmp(val, "pci-endpoint")) { ++ port->endpoint = 1; ++ } else if (!strcmp(val, "pci")) { ++ port->endpoint = 0; ++ } else { ++ printk(KERN_ERR "PCIE%d: missing or incorrect device_type for %s\n", ++ portno, np->full_name); ++ return; ++ } ++ ++ /* Fetch config space registers address */ ++ if (of_address_to_resource(np, 0, &port->cfg_space)) { ++ printk(KERN_ERR "%s: Can't get PCI-E config space !", ++ np->full_name); ++ return; ++ } ++ ++ /* Fetch host bridge internal registers address */ ++ if (of_address_to_resource(np, 1, &port->utl_regs)) { ++ printk(KERN_ERR "%s: Can't get UTL register base !", ++ np->full_name); ++ return; ++ } ++ ++ port->utl_base = ioremap(port->utl_regs.start, resource_size(&port->utl_regs)); ++ ++ printk("%s PCIE%d config base = 0x%012llx (0x%08x virtual)\n", np->full_name, port->index, port->utl_regs.start, (u32) port->utl_base); ++ ++ /* Setup the linux hose data structure */ ++ ppc4xx_acp_pciex_port_setup_hose(port); ++} ++ ++#endif /* CONFIG_ACP */ ++ + static void __init ppc4xx_probe_pciex_bridge(struct device_node *np) + { + struct ppc4xx_pciex_port *port; +@@ -2174,6 +3109,11 @@ static int __init ppc4xx_pci_find_bridges(void) + + pci_add_flags(PCI_ENABLE_PROC_DOMAINS | PCI_COMPAT_DOMAIN_0); + ++#if defined(CONFIG_ACP) ++ for_each_compatible_node(np, NULL, "lsi,plb-pciex") ++ ppc4xx_probe_acp_pciex_bridge(np); ++#endif ++ + #ifdef CONFIG_PPC4xx_PCI_EXPRESS + for_each_compatible_node(np, NULL, "ibm,plb-pciex") + ppc4xx_probe_pciex_bridge(np); -- cgit v1.2.3-54-g00ecf