1 /* 2 * Copyright 2014-2015 Freescale Semiconductor, Inc. 3 * Layerscape PCIe driver 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <pci.h> 10 #include <asm/arch/fsl_serdes.h> 11 #include <asm/io.h> 12 #include <errno.h> 13 #ifdef CONFIG_OF_BOARD_SETUP 14 #include <libfdt.h> 15 #include <fdt_support.h> 16 #include "pcie_layerscape.h" 17 18 #ifdef CONFIG_FSL_LSCH3 19 /* 20 * Return next available LUT index. 21 */ 22 static int ls_pcie_next_lut_index(struct ls_pcie *pcie) 23 { 24 if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT) 25 return pcie->next_lut_index++; 26 else 27 return -ENOSPC; /* LUT is full */ 28 } 29 30 /* returns the next available streamid for pcie, -errno if failed */ 31 static int ls_pcie_next_streamid(void) 32 { 33 static int next_stream_id = FSL_PEX_STREAM_ID_START; 34 35 if (next_stream_id > FSL_PEX_STREAM_ID_END) 36 return -EINVAL; 37 38 return next_stream_id++; 39 } 40 #endif 41 42 #ifndef CONFIG_DM_PCI 43 44 #ifdef CONFIG_FSL_LSCH3 45 /* 46 * Program a single LUT entry 47 */ 48 static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid, 49 u32 streamid) 50 { 51 void __iomem *lut; 52 53 lut = pcie->dbi + PCIE_LUT_BASE; 54 55 /* leave mask as all zeroes, want to match all bits */ 56 writel((devid << 16), lut + PCIE_LUT_UDR(index)); 57 writel(streamid | PCIE_LUT_ENABLE, lut + PCIE_LUT_LDR(index)); 58 } 59 60 /* 61 * An msi-map is a property to be added to the pci controller 62 * node. It is a table, where each entry consists of 4 fields 63 * e.g.: 64 * 65 * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count] 66 * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>; 67 */ 68 static void fdt_pcie_set_msi_map_entry(void *blob, struct ls_pcie *pcie, 69 u32 devid, u32 streamid) 70 { 71 char pcie_path[19]; 72 u32 *prop; 73 u32 phandle; 74 int nodeoffset; 75 76 /* find pci controller node */ 77 snprintf(pcie_path, sizeof(pcie_path), "/soc/pcie@%llx", 78 (u64)pcie->dbi); 79 nodeoffset = fdt_path_offset(blob, pcie_path); 80 if (nodeoffset < 0) { 81 printf("\n%s: ERROR: unable to update PCIe node: %s\n", 82 __func__, pcie_path); 83 return; 84 } 85 86 /* get phandle to MSI controller */ 87 prop = (u32 *)fdt_getprop(blob, nodeoffset, "msi-parent", 0); 88 if (prop == NULL) { 89 printf("\n%s: ERROR: missing msi-parent: %s\n", __func__, 90 pcie_path); 91 return; 92 } 93 phandle = fdt32_to_cpu(*prop); 94 95 /* set one msi-map row */ 96 fdt_appendprop_u32(blob, nodeoffset, "msi-map", devid); 97 fdt_appendprop_u32(blob, nodeoffset, "msi-map", phandle); 98 fdt_appendprop_u32(blob, nodeoffset, "msi-map", streamid); 99 fdt_appendprop_u32(blob, nodeoffset, "msi-map", 1); 100 } 101 102 static void fdt_fixup_pcie(void *blob) 103 { 104 unsigned int found_multi = 0; 105 unsigned char header_type; 106 int index; 107 u32 streamid; 108 pci_dev_t dev, bdf; 109 int bus; 110 unsigned short id; 111 struct pci_controller *hose; 112 struct ls_pcie *pcie; 113 int i; 114 115 for (i = 0, hose = pci_get_hose_head(); hose; hose = hose->next, i++) { 116 pcie = hose->priv_data; 117 for (bus = hose->first_busno; bus <= hose->last_busno; bus++) { 118 119 for (dev = PCI_BDF(bus, 0, 0); 120 dev < PCI_BDF(bus, PCI_MAX_PCI_DEVICES - 1, 121 PCI_MAX_PCI_FUNCTIONS - 1); 122 dev += PCI_BDF(0, 0, 1)) { 123 124 if (PCI_FUNC(dev) && !found_multi) 125 continue; 126 127 pci_read_config_word(dev, PCI_VENDOR_ID, &id); 128 129 pci_read_config_byte(dev, PCI_HEADER_TYPE, 130 &header_type); 131 132 if ((id == 0xFFFF) || (id == 0x0000)) 133 continue; 134 135 if (!PCI_FUNC(dev)) 136 found_multi = header_type & 0x80; 137 138 streamid = ls_pcie_next_streamid(); 139 if (streamid < 0) { 140 debug("ERROR: no stream ids free\n"); 141 continue; 142 } 143 144 index = ls_pcie_next_lut_index(pcie); 145 if (index < 0) { 146 debug("ERROR: no LUT indexes free\n"); 147 continue; 148 } 149 150 /* the DT fixup must be relative to the hose first_busno */ 151 bdf = dev - PCI_BDF(hose->first_busno, 0, 0); 152 153 /* map PCI b.d.f to streamID in LUT */ 154 ls_pcie_lut_set_mapping(pcie, index, bdf >> 8, 155 streamid); 156 157 /* update msi-map in device tree */ 158 fdt_pcie_set_msi_map_entry(blob, pcie, bdf >> 8, 159 streamid); 160 } 161 } 162 } 163 } 164 #endif 165 166 static void ft_pcie_ls_setup(void *blob, const char *pci_compat, 167 unsigned long ctrl_addr, enum srds_prtcl dev) 168 { 169 int off; 170 171 off = fdt_node_offset_by_compat_reg(blob, pci_compat, 172 (phys_addr_t)ctrl_addr); 173 if (off < 0) 174 return; 175 176 if (!is_serdes_configured(dev)) 177 fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); 178 } 179 180 /* Fixup Kernel DT for PCIe */ 181 void ft_pci_setup(void *blob, bd_t *bd) 182 { 183 #ifdef CONFIG_PCIE1 184 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE1_ADDR, PCIE1); 185 #endif 186 187 #ifdef CONFIG_PCIE2 188 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE2_ADDR, PCIE2); 189 #endif 190 191 #ifdef CONFIG_PCIE3 192 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE3_ADDR, PCIE3); 193 #endif 194 195 #ifdef CONFIG_PCIE4 196 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE4_ADDR, PCIE4); 197 #endif 198 199 #ifdef CONFIG_FSL_LSCH3 200 fdt_fixup_pcie(blob); 201 #endif 202 } 203 204 #else /* CONFIG_DM_PCI */ 205 206 #ifdef CONFIG_FSL_LSCH3 207 static void lut_writel(struct ls_pcie *pcie, unsigned int value, 208 unsigned int offset) 209 { 210 if (pcie->big_endian) 211 out_be32(pcie->lut + offset, value); 212 else 213 out_le32(pcie->lut + offset, value); 214 } 215 216 /* 217 * Program a single LUT entry 218 */ 219 static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid, 220 u32 streamid) 221 { 222 /* leave mask as all zeroes, want to match all bits */ 223 lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index)); 224 lut_writel(pcie, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index)); 225 } 226 227 /* 228 * An msi-map is a property to be added to the pci controller 229 * node. It is a table, where each entry consists of 4 fields 230 * e.g.: 231 * 232 * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count] 233 * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>; 234 */ 235 static void fdt_pcie_set_msi_map_entry(void *blob, struct ls_pcie *pcie, 236 u32 devid, u32 streamid) 237 { 238 u32 *prop; 239 u32 phandle; 240 int nodeoffset; 241 242 /* find pci controller node */ 243 nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", 244 pcie->dbi_res.start); 245 if (nodeoffset < 0) { 246 #ifdef FSL_PCIE_COMPAT /* Compatible with older version of dts node */ 247 nodeoffset = fdt_node_offset_by_compat_reg(blob, 248 FSL_PCIE_COMPAT, pcie->dbi_res.start); 249 if (nodeoffset < 0) 250 return; 251 #else 252 return; 253 #endif 254 } 255 256 /* get phandle to MSI controller */ 257 prop = (u32 *)fdt_getprop(blob, nodeoffset, "msi-parent", 0); 258 if (prop == NULL) { 259 debug("\n%s: ERROR: missing msi-parent: PCIe%d\n", 260 __func__, pcie->idx); 261 return; 262 } 263 phandle = fdt32_to_cpu(*prop); 264 265 /* set one msi-map row */ 266 fdt_appendprop_u32(blob, nodeoffset, "msi-map", devid); 267 fdt_appendprop_u32(blob, nodeoffset, "msi-map", phandle); 268 fdt_appendprop_u32(blob, nodeoffset, "msi-map", streamid); 269 fdt_appendprop_u32(blob, nodeoffset, "msi-map", 1); 270 } 271 272 static void fdt_fixup_pcie(void *blob) 273 { 274 struct udevice *dev, *bus; 275 struct ls_pcie *pcie; 276 int streamid; 277 int index; 278 pci_dev_t bdf; 279 280 /* Scan all known buses */ 281 for (pci_find_first_device(&dev); 282 dev; 283 pci_find_next_device(&dev)) { 284 for (bus = dev; device_is_on_pci_bus(bus);) 285 bus = bus->parent; 286 pcie = dev_get_priv(bus); 287 288 streamid = ls_pcie_next_streamid(); 289 if (streamid < 0) { 290 debug("ERROR: no stream ids free\n"); 291 continue; 292 } 293 294 index = ls_pcie_next_lut_index(pcie); 295 if (index < 0) { 296 debug("ERROR: no LUT indexes free\n"); 297 continue; 298 } 299 300 /* the DT fixup must be relative to the hose first_busno */ 301 bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0); 302 /* map PCI b.d.f to streamID in LUT */ 303 ls_pcie_lut_set_mapping(pcie, index, bdf >> 8, 304 streamid); 305 /* update msi-map in device tree */ 306 fdt_pcie_set_msi_map_entry(blob, pcie, bdf >> 8, 307 streamid); 308 } 309 } 310 #endif 311 312 static void ft_pcie_ls_setup(void *blob, struct ls_pcie *pcie) 313 { 314 int off; 315 316 off = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", 317 pcie->dbi_res.start); 318 if (off < 0) { 319 #ifdef FSL_PCIE_COMPAT /* Compatible with older version of dts node */ 320 off = fdt_node_offset_by_compat_reg(blob, 321 FSL_PCIE_COMPAT, 322 pcie->dbi_res.start); 323 if (off < 0) 324 return; 325 #else 326 return; 327 #endif 328 } 329 330 if (pcie->enabled) 331 fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0); 332 else 333 fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); 334 } 335 336 /* Fixup Kernel DT for PCIe */ 337 void ft_pci_setup(void *blob, bd_t *bd) 338 { 339 struct ls_pcie *pcie; 340 341 list_for_each_entry(pcie, &ls_pcie_list, list) 342 ft_pcie_ls_setup(blob, pcie); 343 344 #ifdef CONFIG_FSL_LSCH3 345 fdt_fixup_pcie(blob); 346 #endif 347 } 348 #endif /* CONFIG_DM_PCI */ 349 350 #else /* !CONFIG_OF_BOARD_SETUP */ 351 void ft_pci_setup(void *blob, bd_t *bd) 352 { 353 } 354 #endif 355