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 41 /* 42 * Program a single LUT entry 43 */ 44 static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid, 45 u32 streamid) 46 { 47 void __iomem *lut; 48 49 lut = pcie->dbi + PCIE_LUT_BASE; 50 51 /* leave mask as all zeroes, want to match all bits */ 52 writel((devid << 16), lut + PCIE_LUT_UDR(index)); 53 writel(streamid | PCIE_LUT_ENABLE, lut + PCIE_LUT_LDR(index)); 54 } 55 56 /* 57 * An msi-map is a property to be added to the pci controller 58 * node. It is a table, where each entry consists of 4 fields 59 * e.g.: 60 * 61 * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count] 62 * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>; 63 */ 64 static void fdt_pcie_set_msi_map_entry(void *blob, struct ls_pcie *pcie, 65 u32 devid, u32 streamid) 66 { 67 char pcie_path[19]; 68 u32 *prop; 69 u32 phandle; 70 int nodeoffset; 71 72 /* find pci controller node */ 73 snprintf(pcie_path, sizeof(pcie_path), "/soc/pcie@%llx", 74 (u64)pcie->dbi); 75 nodeoffset = fdt_path_offset(blob, pcie_path); 76 if (nodeoffset < 0) { 77 printf("\n%s: ERROR: unable to update PCIe node: %s\n", 78 __func__, pcie_path); 79 return; 80 } 81 82 /* get phandle to MSI controller */ 83 prop = (u32 *)fdt_getprop(blob, nodeoffset, "msi-parent", 0); 84 if (prop == NULL) { 85 printf("\n%s: ERROR: missing msi-parent: %s\n", __func__, 86 pcie_path); 87 return; 88 } 89 phandle = fdt32_to_cpu(*prop); 90 91 /* set one msi-map row */ 92 fdt_appendprop_u32(blob, nodeoffset, "msi-map", devid); 93 fdt_appendprop_u32(blob, nodeoffset, "msi-map", phandle); 94 fdt_appendprop_u32(blob, nodeoffset, "msi-map", streamid); 95 fdt_appendprop_u32(blob, nodeoffset, "msi-map", 1); 96 } 97 98 static void fdt_fixup_pcie(void *blob) 99 { 100 unsigned int found_multi = 0; 101 unsigned char header_type; 102 int index; 103 u32 streamid; 104 pci_dev_t dev, bdf; 105 int bus; 106 unsigned short id; 107 struct pci_controller *hose; 108 struct ls_pcie *pcie; 109 int i; 110 111 for (i = 0, hose = pci_get_hose_head(); hose; hose = hose->next, i++) { 112 pcie = hose->priv_data; 113 for (bus = hose->first_busno; bus <= hose->last_busno; bus++) { 114 115 for (dev = PCI_BDF(bus, 0, 0); 116 dev < PCI_BDF(bus, PCI_MAX_PCI_DEVICES - 1, 117 PCI_MAX_PCI_FUNCTIONS - 1); 118 dev += PCI_BDF(0, 0, 1)) { 119 120 if (PCI_FUNC(dev) && !found_multi) 121 continue; 122 123 pci_read_config_word(dev, PCI_VENDOR_ID, &id); 124 125 pci_read_config_byte(dev, PCI_HEADER_TYPE, 126 &header_type); 127 128 if ((id == 0xFFFF) || (id == 0x0000)) 129 continue; 130 131 if (!PCI_FUNC(dev)) 132 found_multi = header_type & 0x80; 133 134 streamid = ls_pcie_next_streamid(); 135 if (streamid < 0) { 136 debug("ERROR: no stream ids free\n"); 137 continue; 138 } 139 140 index = ls_pcie_next_lut_index(pcie); 141 if (index < 0) { 142 debug("ERROR: no LUT indexes free\n"); 143 continue; 144 } 145 146 /* the DT fixup must be relative to the hose first_busno */ 147 bdf = dev - PCI_BDF(hose->first_busno, 0, 0); 148 149 /* map PCI b.d.f to streamID in LUT */ 150 ls_pcie_lut_set_mapping(pcie, index, bdf >> 8, 151 streamid); 152 153 /* update msi-map in device tree */ 154 fdt_pcie_set_msi_map_entry(blob, pcie, bdf >> 8, 155 streamid); 156 } 157 } 158 } 159 } 160 #endif 161 162 static void ft_pcie_ls_setup(void *blob, const char *pci_compat, 163 unsigned long ctrl_addr, enum srds_prtcl dev) 164 { 165 int off; 166 167 off = fdt_node_offset_by_compat_reg(blob, pci_compat, 168 (phys_addr_t)ctrl_addr); 169 if (off < 0) 170 return; 171 172 if (!is_serdes_configured(dev)) 173 fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); 174 } 175 176 /* Fixup Kernel DT for PCIe */ 177 void ft_pci_setup(void *blob, bd_t *bd) 178 { 179 #ifdef CONFIG_PCIE1 180 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE1_ADDR, PCIE1); 181 #endif 182 183 #ifdef CONFIG_PCIE2 184 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE2_ADDR, PCIE2); 185 #endif 186 187 #ifdef CONFIG_PCIE3 188 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE3_ADDR, PCIE3); 189 #endif 190 191 #ifdef CONFIG_PCIE4 192 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE4_ADDR, PCIE4); 193 #endif 194 195 #ifdef CONFIG_FSL_LSCH3 196 fdt_fixup_pcie(blob); 197 #endif 198 } 199 200 #else /* !CONFIG_OF_BOARD_SETUP */ 201 void ft_pci_setup(void *blob, bd_t *bd) 202 { 203 } 204 #endif 205