193a686eeSJean-Christophe PLAGNIOL-VILLARD /* 25a85a309SKumar Gala * Copyright 2007-2010 Freescale Semiconductor, Inc. 393a686eeSJean-Christophe PLAGNIOL-VILLARD * 45a85a309SKumar Gala * This program is free software; you can redistribute it and/or modify it 55a85a309SKumar Gala * under the terms of the GNU General Public License as published by the Free 65a85a309SKumar Gala * Software Foundation; either version 2 of the License, or (at your option) 75a85a309SKumar Gala * any later version. 893a686eeSJean-Christophe PLAGNIOL-VILLARD * 993a686eeSJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 1093a686eeSJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 1193a686eeSJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1293a686eeSJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 1393a686eeSJean-Christophe PLAGNIOL-VILLARD * 1493a686eeSJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 1593a686eeSJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 1693a686eeSJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 1793a686eeSJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 1893a686eeSJean-Christophe PLAGNIOL-VILLARD */ 1993a686eeSJean-Christophe PLAGNIOL-VILLARD 2093a686eeSJean-Christophe PLAGNIOL-VILLARD #include <common.h> 2193a686eeSJean-Christophe PLAGNIOL-VILLARD 22b9a1fa97SKumar Gala DECLARE_GLOBAL_DATA_PTR; 23b9a1fa97SKumar Gala 2493a686eeSJean-Christophe PLAGNIOL-VILLARD /* 2593a686eeSJean-Christophe PLAGNIOL-VILLARD * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's 2693a686eeSJean-Christophe PLAGNIOL-VILLARD * 2793a686eeSJean-Christophe PLAGNIOL-VILLARD * Initialize controller and call the common driver/pci pci_hose_scan to 2893a686eeSJean-Christophe PLAGNIOL-VILLARD * scan for bridges and devices. 2993a686eeSJean-Christophe PLAGNIOL-VILLARD * 3093a686eeSJean-Christophe PLAGNIOL-VILLARD * Hose fields which need to be pre-initialized by board specific code: 3193a686eeSJean-Christophe PLAGNIOL-VILLARD * regions[] 3293a686eeSJean-Christophe PLAGNIOL-VILLARD * first_busno 3393a686eeSJean-Christophe PLAGNIOL-VILLARD * 3493a686eeSJean-Christophe PLAGNIOL-VILLARD * Fields updated: 3593a686eeSJean-Christophe PLAGNIOL-VILLARD * last_busno 3693a686eeSJean-Christophe PLAGNIOL-VILLARD */ 3793a686eeSJean-Christophe PLAGNIOL-VILLARD 3893a686eeSJean-Christophe PLAGNIOL-VILLARD #include <pci.h> 39ad19e7a5SKumar Gala #include <asm/io.h> 40c8514622SKumar Gala #include <asm/fsl_pci.h> 4193a686eeSJean-Christophe PLAGNIOL-VILLARD 427a897959SPeter Tyser /* Freescale-specific PCI config registers */ 437a897959SPeter Tyser #define FSL_PCI_PBFR 0x44 447a897959SPeter Tyser #define FSL_PCIE_CAP_ID 0x4c 457a897959SPeter Tyser #define FSL_PCIE_CFG_RDY 0x4b0 46715d8f76SEd Swarthout #define FSL_PROG_IF_AGENT 0x1 477a897959SPeter Tyser 4893a686eeSJean-Christophe PLAGNIOL-VILLARD void pciauto_prescan_setup_bridge(struct pci_controller *hose, 4993a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, int sub_bus); 5093a686eeSJean-Christophe PLAGNIOL-VILLARD void pciauto_postscan_setup_bridge(struct pci_controller *hose, 5193a686eeSJean-Christophe PLAGNIOL-VILLARD pci_dev_t dev, int sub_bus); 5293a686eeSJean-Christophe PLAGNIOL-VILLARD void pciauto_config_init(struct pci_controller *hose); 53612ea010SKumar Gala 54b9a1fa97SKumar Gala #ifndef CONFIG_SYS_PCI_MEMORY_BUS 55b9a1fa97SKumar Gala #define CONFIG_SYS_PCI_MEMORY_BUS 0 56b9a1fa97SKumar Gala #endif 57b9a1fa97SKumar Gala 58b9a1fa97SKumar Gala #ifndef CONFIG_SYS_PCI_MEMORY_PHYS 59b9a1fa97SKumar Gala #define CONFIG_SYS_PCI_MEMORY_PHYS 0 60b9a1fa97SKumar Gala #endif 61b9a1fa97SKumar Gala 62b9a1fa97SKumar Gala #if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS) 63b9a1fa97SKumar Gala #define CONFIG_SYS_PCI64_MEMORY_BUS (64ull*1024*1024*1024) 64b9a1fa97SKumar Gala #endif 65b9a1fa97SKumar Gala 66ad19e7a5SKumar Gala /* Setup one inbound ATMU window. 67ad19e7a5SKumar Gala * 68ad19e7a5SKumar Gala * We let the caller decide what the window size should be 69ad19e7a5SKumar Gala */ 70ad19e7a5SKumar Gala static void set_inbound_window(volatile pit_t *pi, 71ad19e7a5SKumar Gala struct pci_region *r, 72ad19e7a5SKumar Gala u64 size) 73b9a1fa97SKumar Gala { 74ad19e7a5SKumar Gala u32 sz = (__ilog2_u64(size) - 1); 75ad19e7a5SKumar Gala u32 flag = PIWAR_EN | PIWAR_LOCAL | 76ad19e7a5SKumar Gala PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; 77ad19e7a5SKumar Gala 78ad19e7a5SKumar Gala out_be32(&pi->pitar, r->phys_start >> 12); 79ad19e7a5SKumar Gala out_be32(&pi->piwbar, r->bus_start >> 12); 80ad19e7a5SKumar Gala #ifdef CONFIG_SYS_PCI_64BIT 81ad19e7a5SKumar Gala out_be32(&pi->piwbear, r->bus_start >> 44); 82ad19e7a5SKumar Gala #else 83ad19e7a5SKumar Gala out_be32(&pi->piwbear, 0); 84ad19e7a5SKumar Gala #endif 85ad19e7a5SKumar Gala if (r->flags & PCI_REGION_PREFETCH) 86ad19e7a5SKumar Gala flag |= PIWAR_PF; 87ad19e7a5SKumar Gala out_be32(&pi->piwar, flag | sz); 88ad19e7a5SKumar Gala } 89ad19e7a5SKumar Gala 90ee53650dSKumar Gala int fsl_setup_hose(struct pci_controller *hose, unsigned long addr) 91ee53650dSKumar Gala { 92ee53650dSKumar Gala volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) addr; 93ee53650dSKumar Gala 9496d61603SJohn Schmoller /* Reset hose to make sure its in a clean state */ 9596d61603SJohn Schmoller memset(hose, 0, sizeof(struct pci_controller)); 9696d61603SJohn Schmoller 97ee53650dSKumar Gala pci_setup_indirect(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data); 98ee53650dSKumar Gala 99ee53650dSKumar Gala return fsl_is_pci_agent(hose); 100ee53650dSKumar Gala } 101ee53650dSKumar Gala 102ad19e7a5SKumar Gala static int fsl_pci_setup_inbound_windows(struct pci_controller *hose, 103ad19e7a5SKumar Gala u64 out_lo, u8 pcie_cap, 104ad19e7a5SKumar Gala volatile pit_t *pi) 105ad19e7a5SKumar Gala { 106ad19e7a5SKumar Gala struct pci_region *r = hose->regions + hose->region_count; 107ad19e7a5SKumar Gala u64 sz = min((u64)gd->ram_size, (1ull << 32)); 108b9a1fa97SKumar Gala 109b9a1fa97SKumar Gala phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS; 110b9a1fa97SKumar Gala pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS; 111ad19e7a5SKumar Gala pci_size_t pci_sz; 112b9a1fa97SKumar Gala 113ad19e7a5SKumar Gala /* we have no space available for inbound memory mapping */ 114ad19e7a5SKumar Gala if (bus_start > out_lo) { 115ad19e7a5SKumar Gala printf ("no space for inbound mapping of memory\n"); 116ad19e7a5SKumar Gala return 0; 117ad19e7a5SKumar Gala } 118ad19e7a5SKumar Gala 119ad19e7a5SKumar Gala /* limit size */ 120ad19e7a5SKumar Gala if ((bus_start + sz) > out_lo) { 121ad19e7a5SKumar Gala sz = out_lo - bus_start; 122ad19e7a5SKumar Gala debug ("limiting size to %llx\n", sz); 123ad19e7a5SKumar Gala } 124ad19e7a5SKumar Gala 125ad19e7a5SKumar Gala pci_sz = 1ull << __ilog2_u64(sz); 126ad19e7a5SKumar Gala /* 127ad19e7a5SKumar Gala * we can overlap inbound/outbound windows on PCI-E since RX & TX 128ad19e7a5SKumar Gala * links a separate 129ad19e7a5SKumar Gala */ 130ad19e7a5SKumar Gala if ((pcie_cap == PCI_CAP_ID_EXP) && (pci_sz < sz)) { 131b9a1fa97SKumar Gala debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n", 132ad19e7a5SKumar Gala (u64)bus_start, (u64)phys_start, (u64)sz); 133ad19e7a5SKumar Gala pci_set_region(r, bus_start, phys_start, sz, 134ff4e66e9SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 135b9a1fa97SKumar Gala PCI_REGION_PREFETCH); 136b9a1fa97SKumar Gala 137ad19e7a5SKumar Gala /* if we aren't an exact power of two match, pci_sz is smaller 138ad19e7a5SKumar Gala * round it up to the next power of two. We report the actual 139ad19e7a5SKumar Gala * size to pci region tracking. 140ad19e7a5SKumar Gala */ 141ad19e7a5SKumar Gala if (pci_sz != sz) 142ad19e7a5SKumar Gala sz = 2ull << __ilog2_u64(sz); 143ad19e7a5SKumar Gala 144ad19e7a5SKumar Gala set_inbound_window(pi--, r++, sz); 145ad19e7a5SKumar Gala sz = 0; /* make sure we dont set the R2 window */ 146ad19e7a5SKumar Gala } else { 147ad19e7a5SKumar Gala debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n", 148ad19e7a5SKumar Gala (u64)bus_start, (u64)phys_start, (u64)pci_sz); 149ad19e7a5SKumar Gala pci_set_region(r, bus_start, phys_start, pci_sz, 150ad19e7a5SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 151ad19e7a5SKumar Gala PCI_REGION_PREFETCH); 152ad19e7a5SKumar Gala set_inbound_window(pi--, r++, pci_sz); 153ad19e7a5SKumar Gala 154b9a1fa97SKumar Gala sz -= pci_sz; 155b9a1fa97SKumar Gala bus_start += pci_sz; 156b9a1fa97SKumar Gala phys_start += pci_sz; 157b9a1fa97SKumar Gala 158b9a1fa97SKumar Gala pci_sz = 1ull << __ilog2_u64(sz); 159b9a1fa97SKumar Gala if (sz) { 160b9a1fa97SKumar Gala debug ("R1 bus_start: %llx phys_start: %llx size: %llx\n", 161b9a1fa97SKumar Gala (u64)bus_start, (u64)phys_start, (u64)pci_sz); 162ad19e7a5SKumar Gala pci_set_region(r, bus_start, phys_start, pci_sz, 163ff4e66e9SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 164b9a1fa97SKumar Gala PCI_REGION_PREFETCH); 165ad19e7a5SKumar Gala set_inbound_window(pi--, r++, pci_sz); 166b9a1fa97SKumar Gala sz -= pci_sz; 167b9a1fa97SKumar Gala bus_start += pci_sz; 168b9a1fa97SKumar Gala phys_start += pci_sz; 169b9a1fa97SKumar Gala } 170ad19e7a5SKumar Gala } 171b9a1fa97SKumar Gala 172b9a1fa97SKumar Gala #if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT) 173cd425162SBecky Bruce /* 174cd425162SBecky Bruce * On 64-bit capable systems, set up a mapping for all of DRAM 175cd425162SBecky Bruce * in high pci address space. 176cd425162SBecky Bruce */ 177b9a1fa97SKumar Gala pci_sz = 1ull << __ilog2_u64(gd->ram_size); 178b9a1fa97SKumar Gala /* round up to the next largest power of two */ 179b9a1fa97SKumar Gala if (gd->ram_size > pci_sz) 180cd425162SBecky Bruce pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1); 181b9a1fa97SKumar Gala debug ("R64 bus_start: %llx phys_start: %llx size: %llx\n", 182cd425162SBecky Bruce (u64)CONFIG_SYS_PCI64_MEMORY_BUS, 183b9a1fa97SKumar Gala (u64)CONFIG_SYS_PCI_MEMORY_PHYS, 184b9a1fa97SKumar Gala (u64)pci_sz); 185ad19e7a5SKumar Gala pci_set_region(r, 186cd425162SBecky Bruce CONFIG_SYS_PCI64_MEMORY_BUS, 187b9a1fa97SKumar Gala CONFIG_SYS_PCI_MEMORY_PHYS, 188b9a1fa97SKumar Gala pci_sz, 189ff4e66e9SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 190b9a1fa97SKumar Gala PCI_REGION_PREFETCH); 191ad19e7a5SKumar Gala set_inbound_window(pi--, r++, pci_sz); 192b9a1fa97SKumar Gala #else 193b9a1fa97SKumar Gala pci_sz = 1ull << __ilog2_u64(sz); 194b9a1fa97SKumar Gala if (sz) { 195b9a1fa97SKumar Gala debug ("R2 bus_start: %llx phys_start: %llx size: %llx\n", 196b9a1fa97SKumar Gala (u64)bus_start, (u64)phys_start, (u64)pci_sz); 197ad19e7a5SKumar Gala pci_set_region(r, bus_start, phys_start, pci_sz, 198ff4e66e9SKumar Gala PCI_REGION_MEM | PCI_REGION_SYS_MEMORY | 199b9a1fa97SKumar Gala PCI_REGION_PREFETCH); 200b9a1fa97SKumar Gala sz -= pci_sz; 201b9a1fa97SKumar Gala bus_start += pci_sz; 202b9a1fa97SKumar Gala phys_start += pci_sz; 203ad19e7a5SKumar Gala set_inbound_window(pi--, r++, pci_sz); 204b9a1fa97SKumar Gala } 205b9a1fa97SKumar Gala #endif 206b9a1fa97SKumar Gala 2074c253fdbSKumar Gala #ifdef CONFIG_PHYS_64BIT 208b9a1fa97SKumar Gala if (sz && (((u64)gd->ram_size) < (1ull << 32))) 209b9a1fa97SKumar Gala printf("Was not able to map all of memory via " 210b9a1fa97SKumar Gala "inbound windows -- %lld remaining\n", sz); 2114c253fdbSKumar Gala #endif 212b9a1fa97SKumar Gala 213ad19e7a5SKumar Gala hose->region_count = r - hose->regions; 214ad19e7a5SKumar Gala 215ad19e7a5SKumar Gala return 1; 216b9a1fa97SKumar Gala } 217b9a1fa97SKumar Gala 218fb3143b3SKumar Gala void fsl_pci_init(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data) 21993a686eeSJean-Christophe PLAGNIOL-VILLARD { 22093a686eeSJean-Christophe PLAGNIOL-VILLARD u16 temp16; 22193a686eeSJean-Christophe PLAGNIOL-VILLARD u32 temp32; 2228295b944SKumar Gala int enabled, r, inbound = 0; 22393a686eeSJean-Christophe PLAGNIOL-VILLARD u16 ltssm; 2248295b944SKumar Gala u8 temp8, pcie_cap; 225fb3143b3SKumar Gala volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr; 226cb151aa2SKumar Gala struct pci_region *reg = hose->regions + hose->region_count; 2278295b944SKumar Gala pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0); 22893a686eeSJean-Christophe PLAGNIOL-VILLARD 22993a686eeSJean-Christophe PLAGNIOL-VILLARD /* Initialize ATMU registers based on hose regions and flags */ 23093a686eeSJean-Christophe PLAGNIOL-VILLARD volatile pot_t *po = &pci->pot[1]; /* skip 0 */ 231ad19e7a5SKumar Gala volatile pit_t *pi = &pci->pit[2]; /* ranges from: 3 to 1 */ 232ad19e7a5SKumar Gala 233ad19e7a5SKumar Gala u64 out_hi = 0, out_lo = -1ULL; 234ad19e7a5SKumar Gala u32 pcicsrbar, pcicsrbar_sz; 23593a686eeSJean-Christophe PLAGNIOL-VILLARD 23693a686eeSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 23793a686eeSJean-Christophe PLAGNIOL-VILLARD int neg_link_w; 23893a686eeSJean-Christophe PLAGNIOL-VILLARD #endif 23993a686eeSJean-Christophe PLAGNIOL-VILLARD 240fb3143b3SKumar Gala pci_setup_indirect(hose, cfg_addr, cfg_data); 241fb3143b3SKumar Gala 242ad19e7a5SKumar Gala /* Handle setup of outbound windows first */ 24393a686eeSJean-Christophe PLAGNIOL-VILLARD for (r = 0; r < hose->region_count; r++) { 244ad19e7a5SKumar Gala unsigned long flags = hose->regions[r].flags; 245612ea010SKumar Gala u32 sz = (__ilog2_u64((u64)hose->regions[r].size) - 1); 246ad19e7a5SKumar Gala 247ad19e7a5SKumar Gala flags &= PCI_REGION_SYS_MEMORY|PCI_REGION_TYPE; 248ad19e7a5SKumar Gala if (flags != PCI_REGION_SYS_MEMORY) { 249ad19e7a5SKumar Gala u64 start = hose->regions[r].bus_start; 250ad19e7a5SKumar Gala u64 end = start + hose->regions[r].size; 251ad19e7a5SKumar Gala 252ad19e7a5SKumar Gala out_be32(&po->powbar, hose->regions[r].phys_start >> 12); 253ad19e7a5SKumar Gala out_be32(&po->potar, start >> 12); 254612ea010SKumar Gala #ifdef CONFIG_SYS_PCI_64BIT 255ad19e7a5SKumar Gala out_be32(&po->potear, start >> 44); 256612ea010SKumar Gala #else 257ad19e7a5SKumar Gala out_be32(&po->potear, 0); 258612ea010SKumar Gala #endif 259ad19e7a5SKumar Gala if (hose->regions[r].flags & PCI_REGION_IO) { 260ad19e7a5SKumar Gala out_be32(&po->powar, POWAR_EN | sz | 261ad19e7a5SKumar Gala POWAR_IO_READ | POWAR_IO_WRITE); 262ad19e7a5SKumar Gala } else { 263ad19e7a5SKumar Gala out_be32(&po->powar, POWAR_EN | sz | 264ad19e7a5SKumar Gala POWAR_MEM_READ | POWAR_MEM_WRITE); 265ad19e7a5SKumar Gala out_lo = min(start, out_lo); 266ad19e7a5SKumar Gala out_hi = max(end, out_hi); 267ad19e7a5SKumar Gala } 26893a686eeSJean-Christophe PLAGNIOL-VILLARD po++; 26993a686eeSJean-Christophe PLAGNIOL-VILLARD } 27093a686eeSJean-Christophe PLAGNIOL-VILLARD } 271ad19e7a5SKumar Gala debug("Outbound memory range: %llx:%llx\n", out_lo, out_hi); 272ad19e7a5SKumar Gala 273ad19e7a5SKumar Gala /* setup PCSRBAR/PEXCSRBAR */ 274ad19e7a5SKumar Gala pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0xffffffff); 275ad19e7a5SKumar Gala pci_hose_read_config_dword (hose, dev, PCI_BASE_ADDRESS_0, &pcicsrbar_sz); 276ad19e7a5SKumar Gala pcicsrbar_sz = ~pcicsrbar_sz + 1; 277ad19e7a5SKumar Gala 278ad19e7a5SKumar Gala if (out_hi < (0x100000000ull - pcicsrbar_sz) || 279ad19e7a5SKumar Gala (out_lo > 0x100000000ull)) 280ad19e7a5SKumar Gala pcicsrbar = 0x100000000ull - pcicsrbar_sz; 281ad19e7a5SKumar Gala else 282ad19e7a5SKumar Gala pcicsrbar = (out_lo - pcicsrbar_sz) & -pcicsrbar_sz; 283ad19e7a5SKumar Gala pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, pcicsrbar); 284ad19e7a5SKumar Gala 285ad19e7a5SKumar Gala out_lo = min(out_lo, (u64)pcicsrbar); 286ad19e7a5SKumar Gala 287ad19e7a5SKumar Gala debug("PCICSRBAR @ 0x%x\n", pcicsrbar); 288ad19e7a5SKumar Gala 289ad19e7a5SKumar Gala pci_set_region(reg++, pcicsrbar, CONFIG_SYS_CCSRBAR_PHYS, 290ad19e7a5SKumar Gala pcicsrbar_sz, PCI_REGION_SYS_MEMORY); 291ad19e7a5SKumar Gala hose->region_count++; 29293a686eeSJean-Christophe PLAGNIOL-VILLARD 2938295b944SKumar Gala /* see if we are a PCIe or PCI controller */ 2948295b944SKumar Gala pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap); 2958295b944SKumar Gala 296ad19e7a5SKumar Gala /* inbound */ 297ad19e7a5SKumar Gala inbound = fsl_pci_setup_inbound_windows(hose, out_lo, pcie_cap, pi); 298ad19e7a5SKumar Gala 299ad19e7a5SKumar Gala for (r = 0; r < hose->region_count; r++) 300ad19e7a5SKumar Gala debug("PCI reg:%d %016llx:%016llx %016llx %08x\n", r, 301ad19e7a5SKumar Gala (u64)hose->regions[r].phys_start, 302ad19e7a5SKumar Gala hose->regions[r].bus_start, 303ad19e7a5SKumar Gala hose->regions[r].size, 304ad19e7a5SKumar Gala hose->regions[r].flags); 305ad19e7a5SKumar Gala 30693a686eeSJean-Christophe PLAGNIOL-VILLARD pci_register_hose(hose); 30793a686eeSJean-Christophe PLAGNIOL-VILLARD pciauto_config_init(hose); /* grab pci_{mem,prefetch,io} */ 30893a686eeSJean-Christophe PLAGNIOL-VILLARD hose->current_busno = hose->first_busno; 30993a686eeSJean-Christophe PLAGNIOL-VILLARD 310ad19e7a5SKumar Gala out_be32(&pci->pedr, 0xffffffff); /* Clear any errors */ 311ad19e7a5SKumar Gala out_be32(&pci->peer, ~0x20140); /* Enable All Error Interupts except 31293a686eeSJean-Christophe PLAGNIOL-VILLARD * - Master abort (pci) 31393a686eeSJean-Christophe PLAGNIOL-VILLARD * - Master PERR (pci) 31493a686eeSJean-Christophe PLAGNIOL-VILLARD * - ICCA (PCIe) 31593a686eeSJean-Christophe PLAGNIOL-VILLARD */ 31693a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_dword(hose, dev, PCI_DCR, &temp32); 31793a686eeSJean-Christophe PLAGNIOL-VILLARD temp32 |= 0xf000e; /* set URR, FER, NFER (but not CER) */ 31893a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_dword(hose, dev, PCI_DCR, temp32); 31993a686eeSJean-Christophe PLAGNIOL-VILLARD 3208295b944SKumar Gala if (pcie_cap == PCI_CAP_ID_EXP) { 32193a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word(hose, dev, PCI_LTSSM, <ssm); 32293a686eeSJean-Christophe PLAGNIOL-VILLARD enabled = ltssm >= PCI_LTSSM_L0; 32393a686eeSJean-Christophe PLAGNIOL-VILLARD 3248ff3de61SKumar Gala #ifdef CONFIG_FSL_PCIE_RESET 3258ff3de61SKumar Gala if (ltssm == 1) { 3268ff3de61SKumar Gala int i; 327ad19e7a5SKumar Gala debug("....PCIe link error. " "LTSSM=0x%02x.", ltssm); 328ad19e7a5SKumar Gala /* assert PCIe reset */ 329ad19e7a5SKumar Gala setbits_be32(&pci->pdb_stat, 0x08000000); 330ad19e7a5SKumar Gala (void) in_be32(&pci->pdb_stat); 3318ff3de61SKumar Gala udelay(100); 3328ff3de61SKumar Gala debug(" Asserting PCIe reset @%x = %x\n", 333ad19e7a5SKumar Gala &pci->pdb_stat, in_be32(&pci->pdb_stat)); 334ad19e7a5SKumar Gala /* clear PCIe reset */ 335ad19e7a5SKumar Gala clrbits_be32(&pci->pdb_stat, 0x08000000); 3368ff3de61SKumar Gala asm("sync;isync"); 3378ff3de61SKumar Gala for (i=0; i<100 && ltssm < PCI_LTSSM_L0; i++) { 3388ff3de61SKumar Gala pci_hose_read_config_word(hose, dev, PCI_LTSSM, 3398ff3de61SKumar Gala <ssm); 3408ff3de61SKumar Gala udelay(1000); 3418ff3de61SKumar Gala debug("....PCIe link error. " 3428ff3de61SKumar Gala "LTSSM=0x%02x.\n", ltssm); 3438ff3de61SKumar Gala } 3448ff3de61SKumar Gala enabled = ltssm >= PCI_LTSSM_L0; 345ad19e7a5SKumar Gala 346ad19e7a5SKumar Gala /* we need to re-write the bar0 since a reset will 347ad19e7a5SKumar Gala * clear it 348ad19e7a5SKumar Gala */ 349ad19e7a5SKumar Gala pci_hose_write_config_dword(hose, dev, 350ad19e7a5SKumar Gala PCI_BASE_ADDRESS_0, pcicsrbar); 3518ff3de61SKumar Gala } 3528ff3de61SKumar Gala #endif 3538ff3de61SKumar Gala 35493a686eeSJean-Christophe PLAGNIOL-VILLARD if (!enabled) { 35593a686eeSJean-Christophe PLAGNIOL-VILLARD debug("....PCIE link error. Skipping scan." 35693a686eeSJean-Christophe PLAGNIOL-VILLARD "LTSSM=0x%02x\n", ltssm); 35793a686eeSJean-Christophe PLAGNIOL-VILLARD hose->last_busno = hose->first_busno; 35893a686eeSJean-Christophe PLAGNIOL-VILLARD return; 35993a686eeSJean-Christophe PLAGNIOL-VILLARD } 36093a686eeSJean-Christophe PLAGNIOL-VILLARD 361ad19e7a5SKumar Gala out_be32(&pci->pme_msg_det, 0xffffffff); 362ad19e7a5SKumar Gala out_be32(&pci->pme_msg_int_en, 0xffffffff); 36393a686eeSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG 36493a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word(hose, dev, PCI_LSR, &temp16); 36593a686eeSJean-Christophe PLAGNIOL-VILLARD neg_link_w = (temp16 & 0x3f0 ) >> 4; 36693a686eeSJean-Christophe PLAGNIOL-VILLARD printf("...PCIE LTSSM=0x%x, Negotiated link width=%d\n", 36793a686eeSJean-Christophe PLAGNIOL-VILLARD ltssm, neg_link_w); 36893a686eeSJean-Christophe PLAGNIOL-VILLARD #endif 36993a686eeSJean-Christophe PLAGNIOL-VILLARD hose->current_busno++; /* Start scan with secondary */ 37093a686eeSJean-Christophe PLAGNIOL-VILLARD pciauto_prescan_setup_bridge(hose, dev, hose->current_busno); 37193a686eeSJean-Christophe PLAGNIOL-VILLARD } 37293a686eeSJean-Christophe PLAGNIOL-VILLARD 37393a686eeSJean-Christophe PLAGNIOL-VILLARD /* Use generic setup_device to initialize standard pci regs, 37493a686eeSJean-Christophe PLAGNIOL-VILLARD * but do not allocate any windows since any BAR found (such 37593a686eeSJean-Christophe PLAGNIOL-VILLARD * as PCSRBAR) is not in this cpu's memory space. 37693a686eeSJean-Christophe PLAGNIOL-VILLARD */ 37793a686eeSJean-Christophe PLAGNIOL-VILLARD pciauto_setup_device(hose, dev, 0, hose->pci_mem, 37893a686eeSJean-Christophe PLAGNIOL-VILLARD hose->pci_prefetch, hose->pci_io); 37993a686eeSJean-Christophe PLAGNIOL-VILLARD 38093a686eeSJean-Christophe PLAGNIOL-VILLARD if (inbound) { 38193a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16); 38293a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_word(hose, dev, PCI_COMMAND, 38393a686eeSJean-Christophe PLAGNIOL-VILLARD temp16 | PCI_COMMAND_MEMORY); 38493a686eeSJean-Christophe PLAGNIOL-VILLARD } 38593a686eeSJean-Christophe PLAGNIOL-VILLARD 38693a686eeSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_PCI_NOSCAN 3876df0efd5SEd Swarthout pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &temp8); 3886df0efd5SEd Swarthout 3896df0efd5SEd Swarthout /* Programming Interface (PCI_CLASS_PROG) 3906df0efd5SEd Swarthout * 0 == pci host or pcie root-complex, 3916df0efd5SEd Swarthout * 1 == pci agent or pcie end-point 3926df0efd5SEd Swarthout */ 3936df0efd5SEd Swarthout if (!temp8) { 3946df0efd5SEd Swarthout printf(" Scanning PCI bus %02x\n", 3956df0efd5SEd Swarthout hose->current_busno); 39693a686eeSJean-Christophe PLAGNIOL-VILLARD hose->last_busno = pci_hose_scan_bus(hose, hose->current_busno); 3976df0efd5SEd Swarthout } else { 3986df0efd5SEd Swarthout debug(" Not scanning PCI bus %02x. PI=%x\n", 3996df0efd5SEd Swarthout hose->current_busno, temp8); 4006df0efd5SEd Swarthout hose->last_busno = hose->current_busno; 4016df0efd5SEd Swarthout } 40293a686eeSJean-Christophe PLAGNIOL-VILLARD 4038295b944SKumar Gala /* if we are PCIe - update limit regs and subordinate busno 4048295b944SKumar Gala * for the virtual P2P bridge 4058295b944SKumar Gala */ 4068295b944SKumar Gala if (pcie_cap == PCI_CAP_ID_EXP) { 40793a686eeSJean-Christophe PLAGNIOL-VILLARD pciauto_postscan_setup_bridge(hose, dev, hose->last_busno); 40893a686eeSJean-Christophe PLAGNIOL-VILLARD } 40993a686eeSJean-Christophe PLAGNIOL-VILLARD #else 41093a686eeSJean-Christophe PLAGNIOL-VILLARD hose->last_busno = hose->current_busno; 41193a686eeSJean-Christophe PLAGNIOL-VILLARD #endif 41293a686eeSJean-Christophe PLAGNIOL-VILLARD 41393a686eeSJean-Christophe PLAGNIOL-VILLARD /* Clear all error indications */ 4148295b944SKumar Gala if (pcie_cap == PCI_CAP_ID_EXP) 415ad19e7a5SKumar Gala out_be32(&pci->pme_msg_det, 0xffffffff); 416ad19e7a5SKumar Gala out_be32(&pci->pedr, 0xffffffff); 41793a686eeSJean-Christophe PLAGNIOL-VILLARD 41893a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16); 41993a686eeSJean-Christophe PLAGNIOL-VILLARD if (temp16) { 4208295b944SKumar Gala pci_hose_write_config_word(hose, dev, PCI_DSR, 0xffff); 42193a686eeSJean-Christophe PLAGNIOL-VILLARD } 42293a686eeSJean-Christophe PLAGNIOL-VILLARD 42393a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16); 42493a686eeSJean-Christophe PLAGNIOL-VILLARD if (temp16) { 42593a686eeSJean-Christophe PLAGNIOL-VILLARD pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff); 42693a686eeSJean-Christophe PLAGNIOL-VILLARD } 42793a686eeSJean-Christophe PLAGNIOL-VILLARD } 428a2aab460SKumar Gala 429715d8f76SEd Swarthout int fsl_is_pci_agent(struct pci_controller *hose) 430715d8f76SEd Swarthout { 431715d8f76SEd Swarthout u8 prog_if; 432715d8f76SEd Swarthout pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0); 433715d8f76SEd Swarthout 434715d8f76SEd Swarthout pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prog_if); 435715d8f76SEd Swarthout 436715d8f76SEd Swarthout return (prog_if == FSL_PROG_IF_AGENT); 437715d8f76SEd Swarthout } 438715d8f76SEd Swarthout 4390d3d68b2SPoonam Aggrwal int fsl_pci_init_port(struct fsl_pci_info *pci_info, 44001471d53SKumar Gala struct pci_controller *hose, int busno) 4410d3d68b2SPoonam Aggrwal { 4420d3d68b2SPoonam Aggrwal volatile ccsr_fsl_pci_t *pci; 4430d3d68b2SPoonam Aggrwal struct pci_region *r; 444*a72dbae2SPeter Tyser pci_dev_t dev = PCI_BDF(busno,0,0); 445*a72dbae2SPeter Tyser u8 pcie_cap; 4460d3d68b2SPoonam Aggrwal 4470d3d68b2SPoonam Aggrwal pci = (ccsr_fsl_pci_t *) pci_info->regs; 4480d3d68b2SPoonam Aggrwal 4490d3d68b2SPoonam Aggrwal /* on non-PCIe controllers we don't have pme_msg_det so this code 4500d3d68b2SPoonam Aggrwal * should do nothing since the read will return 0 4510d3d68b2SPoonam Aggrwal */ 4520d3d68b2SPoonam Aggrwal if (in_be32(&pci->pme_msg_det)) { 4530d3d68b2SPoonam Aggrwal out_be32(&pci->pme_msg_det, 0xffffffff); 4540d3d68b2SPoonam Aggrwal debug (" with errors. Clearing. Now 0x%08x", 4550d3d68b2SPoonam Aggrwal pci->pme_msg_det); 4560d3d68b2SPoonam Aggrwal } 4570d3d68b2SPoonam Aggrwal 4580d3d68b2SPoonam Aggrwal r = hose->regions + hose->region_count; 4590d3d68b2SPoonam Aggrwal 4600d3d68b2SPoonam Aggrwal /* outbound memory */ 4610d3d68b2SPoonam Aggrwal pci_set_region(r++, 4620d3d68b2SPoonam Aggrwal pci_info->mem_bus, 4630d3d68b2SPoonam Aggrwal pci_info->mem_phys, 4640d3d68b2SPoonam Aggrwal pci_info->mem_size, 4650d3d68b2SPoonam Aggrwal PCI_REGION_MEM); 4660d3d68b2SPoonam Aggrwal 4670d3d68b2SPoonam Aggrwal /* outbound io */ 4680d3d68b2SPoonam Aggrwal pci_set_region(r++, 4690d3d68b2SPoonam Aggrwal pci_info->io_bus, 4700d3d68b2SPoonam Aggrwal pci_info->io_phys, 4710d3d68b2SPoonam Aggrwal pci_info->io_size, 4720d3d68b2SPoonam Aggrwal PCI_REGION_IO); 4730d3d68b2SPoonam Aggrwal 4740d3d68b2SPoonam Aggrwal hose->region_count = r - hose->regions; 4750d3d68b2SPoonam Aggrwal hose->first_busno = busno; 4760d3d68b2SPoonam Aggrwal 4770d3d68b2SPoonam Aggrwal fsl_pci_init(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data); 4780d3d68b2SPoonam Aggrwal 479715d8f76SEd Swarthout if (fsl_is_pci_agent(hose)) { 480715d8f76SEd Swarthout fsl_pci_config_unlock(hose); 481715d8f76SEd Swarthout hose->last_busno = hose->first_busno; 482715d8f76SEd Swarthout } 483715d8f76SEd Swarthout 484*a72dbae2SPeter Tyser pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap); 485*a72dbae2SPeter Tyser printf(" PCI%s%x on bus %02x - %02x\n", pcie_cap == PCI_CAP_ID_EXP ? 486*a72dbae2SPeter Tyser "E" : "", pci_info->pci_num, 4870d3d68b2SPoonam Aggrwal hose->first_busno, hose->last_busno); 4880d3d68b2SPoonam Aggrwal 4890d3d68b2SPoonam Aggrwal return(hose->last_busno + 1); 4900d3d68b2SPoonam Aggrwal } 4910d3d68b2SPoonam Aggrwal 4927a897959SPeter Tyser /* Enable inbound PCI config cycles for agent/endpoint interface */ 4937a897959SPeter Tyser void fsl_pci_config_unlock(struct pci_controller *hose) 4947a897959SPeter Tyser { 4957a897959SPeter Tyser pci_dev_t dev = PCI_BDF(hose->first_busno,0,0); 4967a897959SPeter Tyser u8 agent; 4977a897959SPeter Tyser u8 pcie_cap; 4987a897959SPeter Tyser u16 pbfr; 4997a897959SPeter Tyser 5007a897959SPeter Tyser pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &agent); 5017a897959SPeter Tyser if (!agent) 5027a897959SPeter Tyser return; 5037a897959SPeter Tyser 5047a897959SPeter Tyser pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap); 5057a897959SPeter Tyser if (pcie_cap != 0x0) { 5067a897959SPeter Tyser /* PCIe - set CFG_READY bit of Configuration Ready Register */ 5077a897959SPeter Tyser pci_hose_write_config_byte(hose, dev, FSL_PCIE_CFG_RDY, 0x1); 5087a897959SPeter Tyser } else { 5097a897959SPeter Tyser /* PCI - clear ACL bit of PBFR */ 5107a897959SPeter Tyser pci_hose_read_config_word(hose, dev, FSL_PCI_PBFR, &pbfr); 5117a897959SPeter Tyser pbfr &= ~0x20; 5127a897959SPeter Tyser pci_hose_write_config_word(hose, dev, FSL_PCI_PBFR, pbfr); 5137a897959SPeter Tyser } 5147a897959SPeter Tyser } 5157a897959SPeter Tyser 516a2aab460SKumar Gala #ifdef CONFIG_OF_BOARD_SETUP 517a2aab460SKumar Gala #include <libfdt.h> 518a2aab460SKumar Gala #include <fdt_support.h> 519a2aab460SKumar Gala 5206525d51fSKumar Gala void ft_fsl_pci_setup(void *blob, const char *pci_compat, 5216525d51fSKumar Gala struct pci_controller *hose, unsigned long ctrl_addr) 522a2aab460SKumar Gala { 5236525d51fSKumar Gala int off; 524a2aab460SKumar Gala u32 bus_range[2]; 5256525d51fSKumar Gala phys_addr_t p_ctrl_addr = (phys_addr_t)ctrl_addr; 5266525d51fSKumar Gala 5276525d51fSKumar Gala /* convert ctrl_addr to true physical address */ 5286525d51fSKumar Gala p_ctrl_addr = (phys_addr_t)ctrl_addr - CONFIG_SYS_CCSRBAR; 5296525d51fSKumar Gala p_ctrl_addr += CONFIG_SYS_CCSRBAR_PHYS; 5306525d51fSKumar Gala 5316525d51fSKumar Gala off = fdt_node_offset_by_compat_reg(blob, pci_compat, p_ctrl_addr); 532a2aab460SKumar Gala 5335a85a309SKumar Gala if (off < 0) 5345a85a309SKumar Gala return; 5355a85a309SKumar Gala 5365a85a309SKumar Gala /* We assume a cfg_addr not being set means we didn't setup the controller */ 5375a85a309SKumar Gala if ((hose == NULL) || (hose->cfg_addr == NULL)) { 5386525d51fSKumar Gala fdt_del_node(blob, off); 5395a85a309SKumar Gala } else { 540a2aab460SKumar Gala bus_range[0] = 0; 541a2aab460SKumar Gala bus_range[1] = hose->last_busno - hose->first_busno; 542a2aab460SKumar Gala fdt_setprop(blob, off, "bus-range", &bus_range[0], 2*4); 543a2aab460SKumar Gala fdt_pci_dma_ranges(blob, off, hose); 544a2aab460SKumar Gala } 545a2aab460SKumar Gala } 546a2aab460SKumar Gala #endif 547