blob: 6de9355645d87c600828e5a10c864bb24e6ea13b [file] [log] [blame]
Hou Zhiqianga7294ab2016-12-13 14:54:16 +08001/*
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 */
22static 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 */
31static 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 */
44static 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 */
64static 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
98static 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
162static 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 */
177void 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 */
201void ft_pci_setup(void *blob, bd_t *bd)
202{
203}
204#endif