193a686eeSJean-Christophe PLAGNIOL-VILLARD /* 2715d8f76SEd Swarthout * Copyright 2007-2009 Freescale Semiconductor, Inc. 393a686eeSJean-Christophe PLAGNIOL-VILLARD * 493a686eeSJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 593a686eeSJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License 693a686eeSJean-Christophe PLAGNIOL-VILLARD * Version 2 as published by the Free Software Foundation. 793a686eeSJean-Christophe PLAGNIOL-VILLARD * 893a686eeSJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 993a686eeSJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 1093a686eeSJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1193a686eeSJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 1293a686eeSJean-Christophe PLAGNIOL-VILLARD * 1393a686eeSJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 1493a686eeSJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 1593a686eeSJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 1693a686eeSJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 1793a686eeSJean-Christophe PLAGNIOL-VILLARD */ 1893a686eeSJean-Christophe PLAGNIOL-VILLARD 1993a686eeSJean-Christophe PLAGNIOL-VILLARD #include <common.h> 2093a686eeSJean-Christophe PLAGNIOL-VILLARD 21b9a1fa97SKumar Gala DECLARE_GLOBAL_DATA_PTR; 22b9a1fa97SKumar Gala 2393a686eeSJean-Christophe PLAGNIOL-VILLARD /* 2493a686eeSJean-Christophe PLAGNIOL-VILLARD * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's 2593a686eeSJean-Christophe PLAGNIOL-VILLARD * 2693a686eeSJean-Christophe PLAGNIOL-VILLARD * Initialize controller and call the common driver/pci pci_hose_scan to 2793a686eeSJean-Christophe PLAGNIOL-VILLARD * scan for bridges and devices. 2893a686eeSJean-Christophe PLAGNIOL-VILLARD * 2993a686eeSJean-Christophe PLAGNIOL-VILLARD * Hose fields which need to be pre-initialized by board specific code: 3093a686eeSJean-Christophe PLAGNIOL-VILLARD * regions[] 3193a686eeSJean-Christophe PLAGNIOL-VILLARD * first_busno 3293a686eeSJean-Christophe PLAGNIOL-VILLARD * 3393a686eeSJean-Christophe PLAGNIOL-VILLARD * Fields updated: 3493a686eeSJean-Christophe PLAGNIOL-VILLARD * last_busno 3593a686eeSJean-Christophe PLAGNIOL-VILLARD */ 3693a686eeSJean-Christophe PLAGNIOL-VILLARD 3793a686eeSJean-Christophe PLAGNIOL-VILLARD #include <pci.h> 38ad19e7a5SKumar Gala #include <asm/io.h> 39c8514622SKumar Gala #include <asm/fsl_pci.h> 4093a686eeSJean-Christophe PLAGNIOL-VILLARD 417a897959SPeter Tyser /* Freescale-specific PCI config registers */ 427a897959SPeter Tyser #define FSL_PCI_PBFR 0x44 437a897959SPeter Tyser #define FSL_PCIE_CAP_ID 0x4c 447a897959SPeter Tyser #define FSL_PCIE_CFG_RDY 0x4b0 45715d8f76SEd Swarthout #define FSL_PROG_IF_AGENT 0x1 467a897959SPeter Tyser 4793a686eeSJean-Christophe PLAGNIOL-VILLARD void pciauto_prescan_setup_bridge(struct pci_controller *hose, 4893a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, int sub_bus); 4993a686eeSJean-Christophe PLAGNIOL-VILLARD void pciauto_postscan_setup_bridge(struct pci_controller *hose, 5093a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, int sub_bus); 5193a686eeSJean-Christophe PLAGNIOL-VILLARD void pciauto_config_init(struct pci_controller *hose); 52612ea010SKumar Gala 53b9a1fa97SKumar Gala #ifndef CONFIG_SYS_PCI_MEMORY_BUS 54b9a1fa97SKumar Gala #define CONFIG_SYS_PCI_MEMORY_BUS 0 55b9a1fa97SKumar Gala #endif 56b9a1fa97SKumar Gala 57b9a1fa97SKumar Gala #ifndef CONFIG_SYS_PCI_MEMORY_PHYS 58b9a1fa97SKumar Gala #define CONFIG_SYS_PCI_MEMORY_PHYS 0 59b9a1fa97SKumar Gala #endif 60b9a1fa97SKumar Gala 61b9a1fa97SKumar Gala #if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS) 62b9a1fa97SKumar Gala #define CONFIG_SYS_PCI64_MEMORY_BUS (64ull*1024*1024*1024) 63b9a1fa97SKumar Gala #endif 64b9a1fa97SKumar Gala 65ad19e7a5SKumar Gala /* Setup one inbound ATMU window. 66ad19e7a5SKumar Gala * 67ad19e7a5SKumar Gala * We let the caller decide what the window size should be 68ad19e7a5SKumar Gala */ 69ad19e7a5SKumar Gala static void set_inbound_window(volatile pit_t *pi, 70ad19e7a5SKumar Gala struct pci_region *r, 71ad19e7a5SKumar Gala u64 size) 72b9a1fa97SKumar Gala { 73ad19e7a5SKumar Gala u32 sz = (__ilog2_u64(size) - 1); 74ad19e7a5SKumar Gala u32 flag = PIWAR_EN | PIWAR_LOCAL | 75ad19e7a5SKumar Gala PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; 76ad19e7a5SKumar Gala 77ad19e7a5SKumar Gala out_be32(&pi->pitar, r->phys_start >> 12); 78ad19e7a5SKumar Gala out_be32(&pi->piwbar, r->bus_start >> 12); 79ad19e7a5SKumar Gala #ifdef CONFIG_SYS_PCI_64BIT 80ad19e7a5SKumar Gala out_be32(&pi->piwbear, r->bus_start >> 44); 81ad19e7a5SKumar Gala #else 82ad19e7a5SKumar Gala out_be32(&pi->piwbear, 0); 83ad19e7a5SKumar Gala #endif 84ad19e7a5SKumar Gala if (r->flags & PCI_REGION_PREFETCH) 85ad19e7a5SKumar Gala flag |= PIWAR_PF; 86ad19e7a5SKumar Gala out_be32(&pi->piwar, flag | sz); 87ad19e7a5SKumar Gala } 88ad19e7a5SKumar Gala 89*ee53650dSKumar Gala int fsl_setup_hose(struct pci_controller *hose, unsigned long addr) 90*ee53650dSKumar Gala { 91*ee53650dSKumar Gala volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) addr; 92*ee53650dSKumar Gala 93*ee53650dSKumar Gala pci_setup_indirect(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data); 94*ee53650dSKumar Gala 95*ee53650dSKumar Gala return fsl_is_pci_agent(hose); 96*ee53650dSKumar Gala } 97*ee53650dSKumar Gala 98ad19e7a5SKumar Gala static int fsl_pci_setup_inbound_windows(struct pci_controller *hose, 99ad19e7a5SKumar Gala u64 out_lo, u8 pcie_cap, 100ad19e7a5SKumar Gala volatile pit_t *pi) 101ad19e7a5SKumar Gala { 102ad19e7a5SKumar Gala struct pci_region *r = hose->regions + hose->region_count; 103ad19e7a5SKumar Gala u64 sz = min((u64)gd->ram_size, (1ull << 32)); 104b9a1fa97SKumar Gala 105b9a1fa97SKumar Gala phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS; 106b9a1fa97SKumar Gala pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS; 107ad19e7a5SKumar Gala pci_size_t pci_sz; 108b9a1fa97SKumar Gala 109ad19e7a5SKumar Gala /* we have no space available for inbound memory mapping */ 110ad19e7a5SKumar Gala if (bus_start > out_lo) { 111ad19e7a5SKumar Gala printf ("no space for inbound mapping of memory\n"); 112ad19e7a5SKumar Gala return 0; 113ad19e7a5SKumar Gala } 114ad19e7a5SKumar Gala 115ad19e7a5SKumar Gala /* limit size */ 116ad19e7a5SKumar Gala if ((bus_start + sz) > out_lo) { 117ad19e7a5SKumar Gala sz = out_lo - bus_start; 118ad19e7a5SKumar Gala debug ("limiting size to %llx\n", sz); 119ad19e7a5SKumar Gala } 120ad19e7a5SKumar Gala 121ad19e7a5SKumar Gala pci_sz = 1ull << __ilog2_u64(sz); 122ad19e7a5SKumar Gala /* 123ad19e7a5SKumar Gala * we can overlap inbound/outbound windows on PCI-E since RX & TX 124ad19e7a5SKumar Gala * links a separate 125ad19e7a5SKumar Gala */ 126ad19e7a5SKumar Gala if ((pcie_cap == PCI_CAP_ID_EXP) && (pci_sz < sz)) { 127b9a1fa97SKumar Gala debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n", 128ad19e7a5SKumar Gala (u64)bus_start, (u64)phys_start, (u64)sz); 129ad19e7a5SKumar Gala pci_set_region(r, bus_start, phys_start, sz, 130ff4e66e9SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 131b9a1fa97SKumar Gala PCI_REGION_PREFETCH); 132b9a1fa97SKumar Gala 133ad19e7a5SKumar Gala /* if we aren't an exact power of two match, pci_sz is smaller 134ad19e7a5SKumar Gala * round it up to the next power of two. We report the actual 135ad19e7a5SKumar Gala * size to pci region tracking. 136ad19e7a5SKumar Gala */ 137ad19e7a5SKumar Gala if (pci_sz != sz) 138ad19e7a5SKumar Gala sz = 2ull << __ilog2_u64(sz); 139ad19e7a5SKumar Gala 140ad19e7a5SKumar Gala set_inbound_window(pi--, r++, sz); 141ad19e7a5SKumar Gala sz = 0; /* make sure we dont set the R2 window */ 142ad19e7a5SKumar Gala } else { 143ad19e7a5SKumar Gala debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n", 144ad19e7a5SKumar Gala (u64)bus_start, (u64)phys_start, (u64)pci_sz); 145ad19e7a5SKumar Gala pci_set_region(r, bus_start, phys_start, pci_sz, 146ad19e7a5SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 147ad19e7a5SKumar Gala PCI_REGION_PREFETCH); 148ad19e7a5SKumar Gala set_inbound_window(pi--, r++, pci_sz); 149ad19e7a5SKumar Gala 150b9a1fa97SKumar Gala sz -= pci_sz; 151b9a1fa97SKumar Gala bus_start += pci_sz; 152b9a1fa97SKumar Gala phys_start += pci_sz; 153b9a1fa97SKumar Gala 154b9a1fa97SKumar Gala pci_sz = 1ull << __ilog2_u64(sz); 155b9a1fa97SKumar Gala if (sz) { 156b9a1fa97SKumar Gala debug ("R1 bus_start: %llx phys_start: %llx size: %llx\n", 157b9a1fa97SKumar Gala (u64)bus_start, (u64)phys_start, (u64)pci_sz); 158ad19e7a5SKumar Gala pci_set_region(r, bus_start, phys_start, pci_sz, 159ff4e66e9SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 160b9a1fa97SKumar Gala PCI_REGION_PREFETCH); 161ad19e7a5SKumar Gala set_inbound_window(pi--, r++, pci_sz); 162b9a1fa97SKumar Gala sz -= pci_sz; 163b9a1fa97SKumar Gala bus_start += pci_sz; 164b9a1fa97SKumar Gala phys_start += pci_sz; 165b9a1fa97SKumar Gala } 166ad19e7a5SKumar Gala } 167b9a1fa97SKumar Gala 168b9a1fa97SKumar Gala #if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT) 169cd425162SBecky Bruce /* 170cd425162SBecky Bruce * On 64-bit capable systems, set up a mapping for all of DRAM 171cd425162SBecky Bruce * in high pci address space. 172cd425162SBecky Bruce */ 173b9a1fa97SKumar Gala pci_sz = 1ull << __ilog2_u64(gd->ram_size); 174b9a1fa97SKumar Gala /* round up to the next largest power of two */ 175b9a1fa97SKumar Gala if (gd->ram_size > pci_sz) 176cd425162SBecky Bruce pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1); 177b9a1fa97SKumar Gala debug ("R64 bus_start: %llx phys_start: %llx size: %llx\n", 178cd425162SBecky Bruce (u64)CONFIG_SYS_PCI64_MEMORY_BUS, 179b9a1fa97SKumar Gala (u64)CONFIG_SYS_PCI_MEMORY_PHYS, 180b9a1fa97SKumar Gala (u64)pci_sz); 181ad19e7a5SKumar Gala pci_set_region(r, 182cd425162SBecky Bruce CONFIG_SYS_PCI64_MEMORY_BUS, 183b9a1fa97SKumar Gala CONFIG_SYS_PCI_MEMORY_PHYS, 184b9a1fa97SKumar Gala pci_sz, 185ff4e66e9SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 186b9a1fa97SKumar Gala PCI_REGION_PREFETCH); 187ad19e7a5SKumar Gala set_inbound_window(pi--, r++, pci_sz); 188b9a1fa97SKumar Gala #else 189b9a1fa97SKumar Gala pci_sz = 1ull << __ilog2_u64(sz); 190b9a1fa97SKumar Gala if (sz) { 191b9a1fa97SKumar Gala debug ("R2 bus_start: %llx phys_start: %llx size: %llx\n", 192b9a1fa97SKumar Gala (u64)bus_start, (u64)phys_start, (u64)pci_sz); 193ad19e7a5SKumar Gala pci_set_region(r, bus_start, phys_start, pci_sz, 194ff4e66e9SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 195b9a1fa97SKumar Gala PCI_REGION_PREFETCH); 196b9a1fa97SKumar Gala sz -= pci_sz; 197b9a1fa97SKumar Gala bus_start += pci_sz; 198b9a1fa97SKumar Gala phys_start += pci_sz; 199ad19e7a5SKumar Gala set_inbound_window(pi--, r++, pci_sz); 200b9a1fa97SKumar Gala } 201b9a1fa97SKumar Gala #endif 202b9a1fa97SKumar Gala 2034c253fdbSKumar Gala #ifdef CONFIG_PHYS_64BIT 204b9a1fa97SKumar Gala if (sz && (((u64)gd->ram_size) < (1ull << 32))) 205b9a1fa97SKumar Gala printf("Was not able to map all of memory via " 206b9a1fa97SKumar Gala "inbound windows -- %lld remaining\n", sz); 2074c253fdbSKumar Gala #endif 208b9a1fa97SKumar Gala 209ad19e7a5SKumar Gala hose->region_count = r - hose->regions; 210ad19e7a5SKumar Gala 211ad19e7a5SKumar Gala return 1; 212b9a1fa97SKumar Gala } 213b9a1fa97SKumar Gala 214fb3143b3SKumar Gala void fsl_pci_init(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data) 21593a686eeSJean-Christophe PLAGNIOL-VILLARD { 21693a686eeSJean-Christophe PLAGNIOL-VILLARD u16 temp16; 21793a686eeSJean-Christophe PLAGNIOL-VILLARD u32 temp32; 2188295b944SKumar Gala int enabled, r, inbound = 0; 21993a686eeSJean-Christophe PLAGNIOL-VILLARD u16 ltssm; 2208295b944SKumar Gala u8 temp8, pcie_cap; 221fb3143b3SKumar Gala volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr; 222cb151aa2SKumar Gala struct pci_region *reg = hose->regions + hose->region_count; 2238295b944SKumar Gala pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0); 22493a686eeSJean-Christophe PLAGNIOL-VILLARD 22593a686eeSJean-Christophe PLAGNIOL-VILLARD /* Initialize ATMU registers based on hose regions and flags */ 22693a686eeSJean-Christophe PLAGNIOL-VILLARD volatile pot_t *po = &pci->pot[1]; /* skip 0 */ 227ad19e7a5SKumar Gala volatile pit_t *pi = &pci->pit[2]; /* ranges from: 3 to 1 */ 228ad19e7a5SKumar Gala 229ad19e7a5SKumar Gala u64 out_hi = 0, out_lo = -1ULL; 230ad19e7a5SKumar Gala u32 pcicsrbar, pcicsrbar_sz; 23193a686eeSJean-Christophe PLAGNIOL-VILLARD 23293a686eeSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 23393a686eeSJean-Christophe PLAGNIOL-VILLARD int neg_link_w; 23493a686eeSJean-Christophe PLAGNIOL-VILLARD #endif 23593a686eeSJean-Christophe PLAGNIOL-VILLARD 236fb3143b3SKumar Gala pci_setup_indirect(hose, cfg_addr, cfg_data); 237fb3143b3SKumar Gala 238ad19e7a5SKumar Gala /* Handle setup of outbound windows first */ 23993a686eeSJean-Christophe PLAGNIOL-VILLARD for (r = 0; r < hose->region_count; r++) { 240ad19e7a5SKumar Gala unsigned long flags = hose->regions[r].flags; 241612ea010SKumar Gala u32 sz = (__ilog2_u64((u64)hose->regions[r].size) - 1); 242ad19e7a5SKumar Gala 243ad19e7a5SKumar Gala flags &= PCI_REGION_SYS_MEMORY|PCI_REGION_TYPE; 244ad19e7a5SKumar Gala if (flags != PCI_REGION_SYS_MEMORY) { 245ad19e7a5SKumar Gala u64 start = hose->regions[r].bus_start; 246ad19e7a5SKumar Gala u64 end = start + hose->regions[r].size; 247ad19e7a5SKumar Gala 248ad19e7a5SKumar Gala out_be32(&po->powbar, hose->regions[r].phys_start >> 12); 249ad19e7a5SKumar Gala out_be32(&po->potar, start >> 12); 250612ea010SKumar Gala #ifdef CONFIG_SYS_PCI_64BIT 251ad19e7a5SKumar Gala out_be32(&po->potear, start >> 44); 252612ea010SKumar Gala #else 253ad19e7a5SKumar Gala out_be32(&po->potear, 0); 254612ea010SKumar Gala #endif 255ad19e7a5SKumar Gala if (hose->regions[r].flags & PCI_REGION_IO) { 256ad19e7a5SKumar Gala out_be32(&po->powar, POWAR_EN | sz | 257ad19e7a5SKumar Gala POWAR_IO_READ | POWAR_IO_WRITE); 258ad19e7a5SKumar Gala } else { 259ad19e7a5SKumar Gala out_be32(&po->powar, POWAR_EN | sz | 260ad19e7a5SKumar Gala POWAR_MEM_READ | POWAR_MEM_WRITE); 261ad19e7a5SKumar Gala out_lo = min(start, out_lo); 262ad19e7a5SKumar Gala out_hi = max(end, out_hi); 263ad19e7a5SKumar Gala } 26493a686eeSJean-Christophe PLAGNIOL-VILLARD po++; 26593a686eeSJean-Christophe PLAGNIOL-VILLARD } 26693a686eeSJean-Christophe PLAGNIOL-VILLARD } 267ad19e7a5SKumar Gala debug("Outbound memory range: %llx:%llx\n", out_lo, out_hi); 268ad19e7a5SKumar Gala 269ad19e7a5SKumar Gala /* setup PCSRBAR/PEXCSRBAR */ 270ad19e7a5SKumar Gala pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0xffffffff); 271ad19e7a5SKumar Gala pci_hose_read_config_dword (hose, dev, PCI_BASE_ADDRESS_0, &pcicsrbar_sz); 272ad19e7a5SKumar Gala pcicsrbar_sz = ~pcicsrbar_sz + 1; 273ad19e7a5SKumar Gala 274ad19e7a5SKumar Gala if (out_hi < (0x100000000ull - pcicsrbar_sz) || 275ad19e7a5SKumar Gala (out_lo > 0x100000000ull)) 276ad19e7a5SKumar Gala pcicsrbar = 0x100000000ull - pcicsrbar_sz; 277ad19e7a5SKumar Gala else 278ad19e7a5SKumar Gala pcicsrbar = (out_lo - pcicsrbar_sz) & -pcicsrbar_sz; 279ad19e7a5SKumar Gala pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, pcicsrbar); 280ad19e7a5SKumar Gala 281ad19e7a5SKumar Gala out_lo = min(out_lo, (u64)pcicsrbar); 282ad19e7a5SKumar Gala 283ad19e7a5SKumar Gala debug("PCICSRBAR @ 0x%x\n", pcicsrbar); 284ad19e7a5SKumar Gala 285ad19e7a5SKumar Gala pci_set_region(reg++, pcicsrbar, CONFIG_SYS_CCSRBAR_PHYS, 286ad19e7a5SKumar Gala pcicsrbar_sz, PCI_REGION_SYS_MEMORY); 287ad19e7a5SKumar Gala hose->region_count++; 28893a686eeSJean-Christophe PLAGNIOL-VILLARD 2898295b944SKumar Gala /* see if we are a PCIe or PCI controller */ 2908295b944SKumar Gala pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap); 2918295b944SKumar Gala 292ad19e7a5SKumar Gala /* inbound */ 293ad19e7a5SKumar Gala inbound = fsl_pci_setup_inbound_windows(hose, out_lo, pcie_cap, pi); 294ad19e7a5SKumar Gala 295ad19e7a5SKumar Gala for (r = 0; r < hose->region_count; r++) 296ad19e7a5SKumar Gala debug("PCI reg:%d %016llx:%016llx %016llx %08x\n", r, 297ad19e7a5SKumar Gala (u64)hose->regions[r].phys_start, 298ad19e7a5SKumar Gala hose->regions[r].bus_start, 299ad19e7a5SKumar Gala hose->regions[r].size, 300ad19e7a5SKumar Gala hose->regions[r].flags); 301ad19e7a5SKumar Gala 30293a686eeSJean-Christophe PLAGNIOL-VILLARD pci_register_hose(hose); 30393a686eeSJean-Christophe PLAGNIOL-VILLARD pciauto_config_init(hose); /* grab pci_{mem,prefetch,io} */ 30493a686eeSJean-Christophe PLAGNIOL-VILLARD hose->current_busno = hose->first_busno; 30593a686eeSJean-Christophe PLAGNIOL-VILLARD 306ad19e7a5SKumar Gala out_be32(&pci->pedr, 0xffffffff); /* Clear any errors */ 307ad19e7a5SKumar Gala out_be32(&pci->peer, ~0x20140); /* Enable All Error Interupts except 30893a686eeSJean-Christophe PLAGNIOL-VILLARD * - Master abort (pci) 30993a686eeSJean-Christophe PLAGNIOL-VILLARD * - Master PERR (pci) 31093a686eeSJean-Christophe PLAGNIOL-VILLARD * - ICCA (PCIe) 31193a686eeSJean-Christophe PLAGNIOL-VILLARD */ 31293a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_dword(hose, dev, PCI_DCR, &temp32); 31393a686eeSJean-Christophe PLAGNIOL-VILLARD temp32 |= 0xf000e; /* set URR, FER, NFER (but not CER) */ 31493a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_dword(hose, dev, PCI_DCR, temp32); 31593a686eeSJean-Christophe PLAGNIOL-VILLARD 3168295b944SKumar Gala if (pcie_cap == PCI_CAP_ID_EXP) { 31793a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word(hose, dev, PCI_LTSSM, <ssm); 31893a686eeSJean-Christophe PLAGNIOL-VILLARD enabled = ltssm >= PCI_LTSSM_L0; 31993a686eeSJean-Christophe PLAGNIOL-VILLARD 3208ff3de61SKumar Gala #ifdef CONFIG_FSL_PCIE_RESET 3218ff3de61SKumar Gala if (ltssm == 1) { 3228ff3de61SKumar Gala int i; 323ad19e7a5SKumar Gala debug("....PCIe link error. " "LTSSM=0x%02x.", ltssm); 324ad19e7a5SKumar Gala /* assert PCIe reset */ 325ad19e7a5SKumar Gala setbits_be32(&pci->pdb_stat, 0x08000000); 326ad19e7a5SKumar Gala (void) in_be32(&pci->pdb_stat); 3278ff3de61SKumar Gala udelay(100); 3288ff3de61SKumar Gala debug(" Asserting PCIe reset @%x = %x\n", 329ad19e7a5SKumar Gala &pci->pdb_stat, in_be32(&pci->pdb_stat)); 330ad19e7a5SKumar Gala /* clear PCIe reset */ 331ad19e7a5SKumar Gala clrbits_be32(&pci->pdb_stat, 0x08000000); 3328ff3de61SKumar Gala asm("sync;isync"); 3338ff3de61SKumar Gala for (i=0; i<100 && ltssm < PCI_LTSSM_L0; i++) { 3348ff3de61SKumar Gala pci_hose_read_config_word(hose, dev, PCI_LTSSM, 3358ff3de61SKumar Gala <ssm); 3368ff3de61SKumar Gala udelay(1000); 3378ff3de61SKumar Gala debug("....PCIe link error. " 3388ff3de61SKumar Gala "LTSSM=0x%02x.\n", ltssm); 3398ff3de61SKumar Gala } 3408ff3de61SKumar Gala enabled = ltssm >= PCI_LTSSM_L0; 341ad19e7a5SKumar Gala 342ad19e7a5SKumar Gala /* we need to re-write the bar0 since a reset will 343ad19e7a5SKumar Gala * clear it 344ad19e7a5SKumar Gala */ 345ad19e7a5SKumar Gala pci_hose_write_config_dword(hose, dev, 346ad19e7a5SKumar Gala PCI_BASE_ADDRESS_0, pcicsrbar); 3478ff3de61SKumar Gala } 3488ff3de61SKumar Gala #endif 3498ff3de61SKumar Gala 35093a686eeSJean-Christophe PLAGNIOL-VILLARD if (!enabled) { 35193a686eeSJean-Christophe PLAGNIOL-VILLARD debug("....PCIE link error. Skipping scan." 35293a686eeSJean-Christophe PLAGNIOL-VILLARD "LTSSM=0x%02x\n", ltssm); 35393a686eeSJean-Christophe PLAGNIOL-VILLARD hose->last_busno = hose->first_busno; 35493a686eeSJean-Christophe PLAGNIOL-VILLARD return; 35593a686eeSJean-Christophe PLAGNIOL-VILLARD } 35693a686eeSJean-Christophe PLAGNIOL-VILLARD 357ad19e7a5SKumar Gala out_be32(&pci->pme_msg_det, 0xffffffff); 358ad19e7a5SKumar Gala out_be32(&pci->pme_msg_int_en, 0xffffffff); 35993a686eeSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 36093a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word(hose, dev, PCI_LSR, &temp16); 36193a686eeSJean-Christophe PLAGNIOL-VILLARD neg_link_w = (temp16 & 0x3f0 ) >> 4; 36293a686eeSJean-Christophe PLAGNIOL-VILLARD printf("...PCIE LTSSM=0x%x, Negotiated link width=%d\n", 36393a686eeSJean-Christophe PLAGNIOL-VILLARD ltssm, neg_link_w); 36493a686eeSJean-Christophe PLAGNIOL-VILLARD #endif 36593a686eeSJean-Christophe PLAGNIOL-VILLARD hose->current_busno++; /* Start scan with secondary */ 36693a686eeSJean-Christophe PLAGNIOL-VILLARD pciauto_prescan_setup_bridge(hose, dev, hose->current_busno); 36793a686eeSJean-Christophe PLAGNIOL-VILLARD } 36893a686eeSJean-Christophe PLAGNIOL-VILLARD 36993a686eeSJean-Christophe PLAGNIOL-VILLARD /* Use generic setup_device to initialize standard pci regs, 37093a686eeSJean-Christophe PLAGNIOL-VILLARD * but do not allocate any windows since any BAR found (such 37193a686eeSJean-Christophe PLAGNIOL-VILLARD * as PCSRBAR) is not in this cpu's memory space. 37293a686eeSJean-Christophe PLAGNIOL-VILLARD */ 37393a686eeSJean-Christophe PLAGNIOL-VILLARD pciauto_setup_device(hose, dev, 0, hose->pci_mem, 37493a686eeSJean-Christophe PLAGNIOL-VILLARD hose->pci_prefetch, hose->pci_io); 37593a686eeSJean-Christophe PLAGNIOL-VILLARD 37693a686eeSJean-Christophe PLAGNIOL-VILLARD if (inbound) { 37793a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16); 37893a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_word(hose, dev, PCI_COMMAND, 37993a686eeSJean-Christophe PLAGNIOL-VILLARD temp16 | PCI_COMMAND_MEMORY); 38093a686eeSJean-Christophe PLAGNIOL-VILLARD } 38193a686eeSJean-Christophe PLAGNIOL-VILLARD 38293a686eeSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_PCI_NOSCAN 3836df0efd5SEd Swarthout pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &temp8); 3846df0efd5SEd Swarthout 3856df0efd5SEd Swarthout /* Programming Interface (PCI_CLASS_PROG) 3866df0efd5SEd Swarthout * 0 == pci host or pcie root-complex, 3876df0efd5SEd Swarthout * 1 == pci agent or pcie end-point 3886df0efd5SEd Swarthout */ 3896df0efd5SEd Swarthout if (!temp8) { 3906df0efd5SEd Swarthout printf(" Scanning PCI bus %02x\n", 3916df0efd5SEd Swarthout hose->current_busno); 39293a686eeSJean-Christophe PLAGNIOL-VILLARD hose->last_busno = pci_hose_scan_bus(hose, hose->current_busno); 3936df0efd5SEd Swarthout } else { 3946df0efd5SEd Swarthout debug(" Not scanning PCI bus %02x. PI=%x\n", 3956df0efd5SEd Swarthout hose->current_busno, temp8); 3966df0efd5SEd Swarthout hose->last_busno = hose->current_busno; 3976df0efd5SEd Swarthout } 39893a686eeSJean-Christophe PLAGNIOL-VILLARD 3998295b944SKumar Gala /* if we are PCIe - update limit regs and subordinate busno 4008295b944SKumar Gala * for the virtual P2P bridge 4018295b944SKumar Gala */ 4028295b944SKumar Gala if (pcie_cap == PCI_CAP_ID_EXP) { 40393a686eeSJean-Christophe PLAGNIOL-VILLARD pciauto_postscan_setup_bridge(hose, dev, hose->last_busno); 40493a686eeSJean-Christophe PLAGNIOL-VILLARD } 40593a686eeSJean-Christophe PLAGNIOL-VILLARD #else 40693a686eeSJean-Christophe PLAGNIOL-VILLARD hose->last_busno = hose->current_busno; 40793a686eeSJean-Christophe PLAGNIOL-VILLARD #endif 40893a686eeSJean-Christophe PLAGNIOL-VILLARD 40993a686eeSJean-Christophe PLAGNIOL-VILLARD /* Clear all error indications */ 4108295b944SKumar Gala if (pcie_cap == PCI_CAP_ID_EXP) 411ad19e7a5SKumar Gala out_be32(&pci->pme_msg_det, 0xffffffff); 412ad19e7a5SKumar Gala out_be32(&pci->pedr, 0xffffffff); 41393a686eeSJean-Christophe PLAGNIOL-VILLARD 41493a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16); 41593a686eeSJean-Christophe PLAGNIOL-VILLARD if (temp16) { 4168295b944SKumar Gala pci_hose_write_config_word(hose, dev, PCI_DSR, 0xffff); 41793a686eeSJean-Christophe PLAGNIOL-VILLARD } 41893a686eeSJean-Christophe PLAGNIOL-VILLARD 41993a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16); 42093a686eeSJean-Christophe PLAGNIOL-VILLARD if (temp16) { 42193a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff); 42293a686eeSJean-Christophe PLAGNIOL-VILLARD } 42393a686eeSJean-Christophe PLAGNIOL-VILLARD } 424a2aab460SKumar Gala 425715d8f76SEd Swarthout int fsl_is_pci_agent(struct pci_controller *hose) 426715d8f76SEd Swarthout { 427715d8f76SEd Swarthout u8 prog_if; 428715d8f76SEd Swarthout pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0); 429715d8f76SEd Swarthout 430715d8f76SEd Swarthout pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prog_if); 431715d8f76SEd Swarthout 432715d8f76SEd Swarthout return (prog_if == FSL_PROG_IF_AGENT); 433715d8f76SEd Swarthout } 434715d8f76SEd Swarthout 4350d3d68b2SPoonam Aggrwal int fsl_pci_init_port(struct fsl_pci_info *pci_info, 43601471d53SKumar Gala struct pci_controller *hose, int busno) 4370d3d68b2SPoonam Aggrwal { 4380d3d68b2SPoonam Aggrwal volatile ccsr_fsl_pci_t *pci; 4390d3d68b2SPoonam Aggrwal struct pci_region *r; 4400d3d68b2SPoonam Aggrwal 4410d3d68b2SPoonam Aggrwal pci = (ccsr_fsl_pci_t *) pci_info->regs; 4420d3d68b2SPoonam Aggrwal 4430d3d68b2SPoonam Aggrwal /* on non-PCIe controllers we don't have pme_msg_det so this code 4440d3d68b2SPoonam Aggrwal * should do nothing since the read will return 0 4450d3d68b2SPoonam Aggrwal */ 4460d3d68b2SPoonam Aggrwal if (in_be32(&pci->pme_msg_det)) { 4470d3d68b2SPoonam Aggrwal out_be32(&pci->pme_msg_det, 0xffffffff); 4480d3d68b2SPoonam Aggrwal debug (" with errors. Clearing. Now 0x%08x", 4490d3d68b2SPoonam Aggrwal pci->pme_msg_det); 4500d3d68b2SPoonam Aggrwal } 4510d3d68b2SPoonam Aggrwal 4520d3d68b2SPoonam Aggrwal r = hose->regions + hose->region_count; 4530d3d68b2SPoonam Aggrwal 4540d3d68b2SPoonam Aggrwal /* outbound memory */ 4550d3d68b2SPoonam Aggrwal pci_set_region(r++, 4560d3d68b2SPoonam Aggrwal pci_info->mem_bus, 4570d3d68b2SPoonam Aggrwal pci_info->mem_phys, 4580d3d68b2SPoonam Aggrwal pci_info->mem_size, 4590d3d68b2SPoonam Aggrwal PCI_REGION_MEM); 4600d3d68b2SPoonam Aggrwal 4610d3d68b2SPoonam Aggrwal /* outbound io */ 4620d3d68b2SPoonam Aggrwal pci_set_region(r++, 4630d3d68b2SPoonam Aggrwal pci_info->io_bus, 4640d3d68b2SPoonam Aggrwal pci_info->io_phys, 4650d3d68b2SPoonam Aggrwal pci_info->io_size, 4660d3d68b2SPoonam Aggrwal PCI_REGION_IO); 4670d3d68b2SPoonam Aggrwal 4680d3d68b2SPoonam Aggrwal hose->region_count = r - hose->regions; 4690d3d68b2SPoonam Aggrwal hose->first_busno = busno; 4700d3d68b2SPoonam Aggrwal 4710d3d68b2SPoonam Aggrwal fsl_pci_init(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data); 4720d3d68b2SPoonam Aggrwal 473715d8f76SEd Swarthout if (fsl_is_pci_agent(hose)) { 474715d8f76SEd Swarthout fsl_pci_config_unlock(hose); 475715d8f76SEd Swarthout hose->last_busno = hose->first_busno; 476715d8f76SEd Swarthout } 477715d8f76SEd Swarthout 47893a83872SKumar Gala printf(" PCIE%x on bus %02x - %02x\n", pci_info->pci_num, 4790d3d68b2SPoonam Aggrwal hose->first_busno, hose->last_busno); 4800d3d68b2SPoonam Aggrwal 4810d3d68b2SPoonam Aggrwal return(hose->last_busno + 1); 4820d3d68b2SPoonam Aggrwal } 4830d3d68b2SPoonam Aggrwal 4847a897959SPeter Tyser /* Enable inbound PCI config cycles for agent/endpoint interface */ 4857a897959SPeter Tyser void fsl_pci_config_unlock(struct pci_controller *hose) 4867a897959SPeter Tyser { 4877a897959SPeter Tyser pci_dev_t dev = PCI_BDF(hose->first_busno,0,0); 4887a897959SPeter Tyser u8 agent; 4897a897959SPeter Tyser u8 pcie_cap; 4907a897959SPeter Tyser u16 pbfr; 4917a897959SPeter Tyser 4927a897959SPeter Tyser pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &agent); 4937a897959SPeter Tyser if (!agent) 4947a897959SPeter Tyser return; 4957a897959SPeter Tyser 4967a897959SPeter Tyser pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap); 4977a897959SPeter Tyser if (pcie_cap != 0x0) { 4987a897959SPeter Tyser /* PCIe - set CFG_READY bit of Configuration Ready Register */ 4997a897959SPeter Tyser pci_hose_write_config_byte(hose, dev, FSL_PCIE_CFG_RDY, 0x1); 5007a897959SPeter Tyser } else { 5017a897959SPeter Tyser /* PCI - clear ACL bit of PBFR */ 5027a897959SPeter Tyser pci_hose_read_config_word(hose, dev, FSL_PCI_PBFR, &pbfr); 5037a897959SPeter Tyser pbfr &= ~0x20; 5047a897959SPeter Tyser pci_hose_write_config_word(hose, dev, FSL_PCI_PBFR, pbfr); 5057a897959SPeter Tyser } 5067a897959SPeter Tyser } 5077a897959SPeter Tyser 508a2aab460SKumar Gala #ifdef CONFIG_OF_BOARD_SETUP 509a2aab460SKumar Gala #include <libfdt.h> 510a2aab460SKumar Gala #include <fdt_support.h> 511a2aab460SKumar Gala 512a2aab460SKumar Gala void ft_fsl_pci_setup(void *blob, const char *pci_alias, 513a2aab460SKumar Gala struct pci_controller *hose) 514a2aab460SKumar Gala { 515a2aab460SKumar Gala int off = fdt_path_offset(blob, pci_alias); 516a2aab460SKumar Gala 517a2aab460SKumar Gala if (off >= 0) { 518a2aab460SKumar Gala u32 bus_range[2]; 519a2aab460SKumar Gala 520a2aab460SKumar Gala bus_range[0] = 0; 521a2aab460SKumar Gala bus_range[1] = hose->last_busno - hose->first_busno; 522a2aab460SKumar Gala fdt_setprop(blob, off, "bus-range", &bus_range[0], 2*4); 523a2aab460SKumar Gala fdt_pci_dma_ranges(blob, off, hose); 524a2aab460SKumar Gala } 525a2aab460SKumar Gala } 526a2aab460SKumar Gala #endif 527