1 /* 2 * Copyright (C) Freescale Semiconductor, Inc. 2007 3 * 4 * Author: Scott Wood <scottwood@freescale.com>, 5 * with some bits from older board-specific PCI initialization. 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <common.h> 11 #include <pci.h> 12 13 #if defined(CONFIG_OF_LIBFDT) 14 #include <linux/libfdt.h> 15 #include <fdt_support.h> 16 #endif 17 18 #include <asm/mpc8349_pci.h> 19 20 #define MAX_BUSES 2 21 22 DECLARE_GLOBAL_DATA_PTR; 23 24 static struct pci_controller pci_hose[MAX_BUSES]; 25 static int pci_num_buses; 26 27 static void pci_init_bus(int bus, struct pci_region *reg) 28 { 29 volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR; 30 volatile pot83xx_t *pot = immr->ios.pot; 31 volatile pcictrl83xx_t *pci_ctrl = &immr->pci_ctrl[bus]; 32 struct pci_controller *hose = &pci_hose[bus]; 33 u32 dev; 34 u16 reg16; 35 int i; 36 37 if (bus == 1) 38 pot += 3; 39 40 /* Setup outbound translation windows */ 41 for (i = 0; i < 3; i++, reg++, pot++) { 42 if (reg->size == 0) 43 break; 44 45 hose->regions[i] = *reg; 46 hose->region_count++; 47 48 pot->potar = reg->bus_start >> 12; 49 pot->pobar = reg->phys_start >> 12; 50 pot->pocmr = ~(reg->size - 1) >> 12; 51 52 if (reg->flags & PCI_REGION_IO) 53 pot->pocmr |= POCMR_IO; 54 #ifdef CONFIG_83XX_PCI_STREAMING 55 else if (reg->flags & PCI_REGION_PREFETCH) 56 pot->pocmr |= POCMR_SE; 57 #endif 58 59 if (bus == 1) 60 pot->pocmr |= POCMR_DST; 61 62 pot->pocmr |= POCMR_EN; 63 } 64 65 /* Point inbound translation at RAM */ 66 pci_ctrl->pitar1 = 0; 67 pci_ctrl->pibar1 = 0; 68 pci_ctrl->piebar1 = 0; 69 pci_ctrl->piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | 70 PIWAR_WTT_SNOOP | (__ilog2(gd->ram_size - 1)); 71 72 i = hose->region_count++; 73 hose->regions[i].bus_start = 0; 74 hose->regions[i].phys_start = 0; 75 hose->regions[i].size = gd->ram_size; 76 hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_SYS_MEMORY; 77 78 hose->first_busno = pci_last_busno() + 1; 79 hose->last_busno = 0xff; 80 81 pci_setup_indirect(hose, CONFIG_SYS_IMMR + 0x8300 + bus * 0x80, 82 CONFIG_SYS_IMMR + 0x8304 + bus * 0x80); 83 84 pci_register_hose(hose); 85 86 /* 87 * Write to Command register 88 */ 89 reg16 = 0xff; 90 dev = PCI_BDF(hose->first_busno, 0, 0); 91 pci_hose_read_config_word(hose, dev, PCI_COMMAND, ®16); 92 reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; 93 pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16); 94 95 /* 96 * Clear non-reserved bits in status register. 97 */ 98 pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff); 99 pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80); 100 pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08); 101 102 #ifdef CONFIG_PCI_SCAN_SHOW 103 printf("PCI: Bus Dev VenId DevId Class Int\n"); 104 #endif 105 #ifndef CONFIG_PCISLAVE 106 /* 107 * Hose scan. 108 */ 109 hose->last_busno = pci_hose_scan(hose); 110 #endif 111 } 112 113 /* 114 * The caller must have already set OCCR, and the PCI_LAW BARs 115 * must have been set to cover all of the requested regions. 116 * 117 * If fewer than three regions are requested, then the region 118 * list is terminated with a region of size 0. 119 */ 120 void mpc83xx_pci_init(int num_buses, struct pci_region **reg) 121 { 122 volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR; 123 int i; 124 125 if (num_buses > MAX_BUSES) { 126 printf("%d PCI buses requested, %d supported\n", 127 num_buses, MAX_BUSES); 128 129 num_buses = MAX_BUSES; 130 } 131 132 pci_num_buses = num_buses; 133 134 /* 135 * Release PCI RST Output signal. 136 * Power on to RST high must be at least 100 ms as per PCI spec. 137 * On warm boots only 1 ms is required, but we play it safe. 138 */ 139 udelay(100000); 140 141 for (i = 0; i < num_buses; i++) 142 immr->pci_ctrl[i].gcr = 1; 143 144 /* 145 * RST high to first config access must be at least 2^25 cycles 146 * as per PCI spec. This could be cut in half if we know we're 147 * running at 66MHz. This could be insufficiently long if we're 148 * running the PCI bus at significantly less than 33MHz. 149 */ 150 udelay(1020000); 151 152 for (i = 0; i < num_buses; i++) 153 pci_init_bus(i, reg[i]); 154 } 155 156 #ifdef CONFIG_PCISLAVE 157 158 #define PCI_FUNCTION_CONFIG 0x44 159 #define PCI_FUNCTION_CFG_LOCK 0x20 160 161 /* 162 * Unlock the configuration bit so that the host system can begin booting 163 * 164 * This should be used after you have: 165 * 1) Called mpc83xx_pci_init() 166 * 2) Set up your inbound translation windows to the appropriate size 167 */ 168 void mpc83xx_pcislave_unlock(int bus) 169 { 170 struct pci_controller *hose = &pci_hose[bus]; 171 u32 dev; 172 u16 reg16; 173 174 /* Unlock configuration lock in PCI function configuration register */ 175 dev = PCI_BDF(hose->first_busno, 0, 0); 176 pci_hose_read_config_word (hose, dev, PCI_FUNCTION_CONFIG, ®16); 177 reg16 &= ~(PCI_FUNCTION_CFG_LOCK); 178 pci_hose_write_config_word (hose, dev, PCI_FUNCTION_CONFIG, reg16); 179 180 /* The configuration bit is now unlocked, so we can scan the bus */ 181 hose->last_busno = pci_hose_scan(hose); 182 } 183 #endif 184 185 #if defined(CONFIG_OF_LIBFDT) 186 void ft_pci_setup(void *blob, bd_t *bd) 187 { 188 int nodeoffset; 189 int tmp[2]; 190 const char *path; 191 192 if (pci_num_buses < 1) 193 return; 194 195 nodeoffset = fdt_path_offset(blob, "/aliases"); 196 if (nodeoffset >= 0) { 197 path = fdt_getprop(blob, nodeoffset, "pci0", NULL); 198 if (path) { 199 tmp[0] = cpu_to_be32(pci_hose[0].first_busno); 200 tmp[1] = cpu_to_be32(pci_hose[0].last_busno); 201 do_fixup_by_path(blob, path, "bus-range", 202 &tmp, sizeof(tmp), 1); 203 204 tmp[0] = cpu_to_be32(gd->pci_clk); 205 do_fixup_by_path(blob, path, "clock-frequency", 206 &tmp, sizeof(tmp[0]), 1); 207 } 208 209 if (pci_num_buses < 2) 210 return; 211 212 path = fdt_getprop(blob, nodeoffset, "pci1", NULL); 213 if (path) { 214 tmp[0] = cpu_to_be32(pci_hose[1].first_busno); 215 tmp[1] = cpu_to_be32(pci_hose[1].last_busno); 216 do_fixup_by_path(blob, path, "bus-range", 217 &tmp, sizeof(tmp), 1); 218 219 tmp[0] = cpu_to_be32(gd->pci_clk); 220 do_fixup_by_path(blob, path, "clock-frequency", 221 &tmp, sizeof(tmp[0]), 1); 222 } 223 } 224 } 225 #endif /* CONFIG_OF_LIBFDT */ 226