blob: 3fb34be99715e13eb90740c668147ff54f34b46f [file] [log] [blame]
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +05301/**
Bjorn Helgaas96291d52017-09-01 16:35:50 -05002 * Synopsys DesignWare PCIe Endpoint controller driver
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +05303 *
4 * Copyright (C) 2017 Texas Instruments
5 * Author: Kishon Vijay Abraham I <kishon@ti.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 of
9 * the License as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/of.h>
21
22#include "pcie-designware.h"
23#include <linux/pci-epc.h>
24#include <linux/pci-epf.h>
25
26void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
27{
28 struct pci_epc *epc = ep->epc;
29
30 pci_epc_linkup(epc);
31}
32
33static void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
34{
35 u32 reg;
36
37 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
Niklas Cassel1cab8262017-12-20 00:29:24 +010038 dw_pcie_dbi_ro_wr_en(pci);
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +053039 dw_pcie_writel_dbi2(pci, reg, 0x0);
40 dw_pcie_writel_dbi(pci, reg, 0x0);
Niklas Cassel1cab8262017-12-20 00:29:24 +010041 dw_pcie_dbi_ro_wr_dis(pci);
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +053042}
43
44static int dw_pcie_ep_write_header(struct pci_epc *epc,
45 struct pci_epf_header *hdr)
46{
47 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
48 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
49
Niklas Cassel1cab8262017-12-20 00:29:24 +010050 dw_pcie_dbi_ro_wr_en(pci);
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +053051 dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid);
52 dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid);
53 dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid);
54 dw_pcie_writeb_dbi(pci, PCI_CLASS_PROG, hdr->progif_code);
55 dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE,
56 hdr->subclass_code | hdr->baseclass_code << 8);
57 dw_pcie_writeb_dbi(pci, PCI_CACHE_LINE_SIZE,
58 hdr->cache_line_size);
59 dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_VENDOR_ID,
60 hdr->subsys_vendor_id);
61 dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id);
62 dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN,
63 hdr->interrupt_pin);
Niklas Cassel1cab8262017-12-20 00:29:24 +010064 dw_pcie_dbi_ro_wr_dis(pci);
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +053065
66 return 0;
67}
68
69static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
70 dma_addr_t cpu_addr,
71 enum dw_pcie_as_type as_type)
72{
73 int ret;
74 u32 free_win;
75 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
76
77 free_win = find_first_zero_bit(&ep->ib_window_map,
78 sizeof(ep->ib_window_map));
79 if (free_win >= ep->num_ib_windows) {
80 dev_err(pci->dev, "no free inbound window\n");
81 return -EINVAL;
82 }
83
84 ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr,
85 as_type);
86 if (ret < 0) {
87 dev_err(pci->dev, "Failed to program IB window\n");
88 return ret;
89 }
90
91 ep->bar_to_atu[bar] = free_win;
92 set_bit(free_win, &ep->ib_window_map);
93
94 return 0;
95}
96
97static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
98 u64 pci_addr, size_t size)
99{
100 u32 free_win;
101 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
102
103 free_win = find_first_zero_bit(&ep->ob_window_map,
104 sizeof(ep->ob_window_map));
105 if (free_win >= ep->num_ob_windows) {
106 dev_err(pci->dev, "no free outbound window\n");
107 return -EINVAL;
108 }
109
110 dw_pcie_prog_outbound_atu(pci, free_win, PCIE_ATU_TYPE_MEM,
111 phys_addr, pci_addr, size);
112
113 set_bit(free_win, &ep->ob_window_map);
114 ep->outbound_addr[free_win] = phys_addr;
115
116 return 0;
117}
118
119static void dw_pcie_ep_clear_bar(struct pci_epc *epc, enum pci_barno bar)
120{
121 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
122 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
123 u32 atu_index = ep->bar_to_atu[bar];
124
125 dw_pcie_ep_reset_bar(pci, bar);
126
127 dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND);
128 clear_bit(atu_index, &ep->ib_window_map);
129}
130
131static int dw_pcie_ep_set_bar(struct pci_epc *epc, enum pci_barno bar,
132 dma_addr_t bar_phys, size_t size, int flags)
133{
134 int ret;
135 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
136 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
137 enum dw_pcie_as_type as_type;
138 u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
139
140 if (!(flags & PCI_BASE_ADDRESS_SPACE))
141 as_type = DW_PCIE_AS_MEM;
142 else
143 as_type = DW_PCIE_AS_IO;
144
145 ret = dw_pcie_ep_inbound_atu(ep, bar, bar_phys, as_type);
146 if (ret)
147 return ret;
148
Niklas Cassel1cab8262017-12-20 00:29:24 +0100149 dw_pcie_dbi_ro_wr_en(pci);
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +0530150 dw_pcie_writel_dbi2(pci, reg, size - 1);
151 dw_pcie_writel_dbi(pci, reg, flags);
Niklas Cassel1cab8262017-12-20 00:29:24 +0100152 dw_pcie_dbi_ro_wr_dis(pci);
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +0530153
154 return 0;
155}
156
157static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr,
158 u32 *atu_index)
159{
160 u32 index;
161
162 for (index = 0; index < ep->num_ob_windows; index++) {
163 if (ep->outbound_addr[index] != addr)
164 continue;
165 *atu_index = index;
166 return 0;
167 }
168
169 return -EINVAL;
170}
171
172static void dw_pcie_ep_unmap_addr(struct pci_epc *epc, phys_addr_t addr)
173{
174 int ret;
175 u32 atu_index;
176 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
177 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
178
179 ret = dw_pcie_find_index(ep, addr, &atu_index);
180 if (ret < 0)
181 return;
182
183 dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_OUTBOUND);
184 clear_bit(atu_index, &ep->ob_window_map);
185}
186
187static int dw_pcie_ep_map_addr(struct pci_epc *epc, phys_addr_t addr,
188 u64 pci_addr, size_t size)
189{
190 int ret;
191 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
192 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
193
194 ret = dw_pcie_ep_outbound_atu(ep, addr, pci_addr, size);
195 if (ret) {
196 dev_err(pci->dev, "failed to enable address\n");
197 return ret;
198 }
199
200 return 0;
201}
202
203static int dw_pcie_ep_get_msi(struct pci_epc *epc)
204{
205 int val;
206 u32 lower_addr;
207 u32 upper_addr;
208 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
209 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
210
211 val = dw_pcie_readb_dbi(pci, MSI_MESSAGE_CONTROL);
212 val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT;
213
214 lower_addr = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32);
215 upper_addr = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32);
216
217 if (!(lower_addr || upper_addr))
218 return -EINVAL;
219
220 return val;
221}
222
223static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 encode_int)
224{
225 int val;
226 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
227 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
228
Niklas Cassel099a95f2017-12-20 00:29:23 +0100229 val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
230 val &= ~MSI_CAP_MMC_MASK;
231 val |= (encode_int << MSI_CAP_MMC_SHIFT) & MSI_CAP_MMC_MASK;
Niklas Cassel1cab8262017-12-20 00:29:24 +0100232 dw_pcie_dbi_ro_wr_en(pci);
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +0530233 dw_pcie_writew_dbi(pci, MSI_MESSAGE_CONTROL, val);
Niklas Cassel1cab8262017-12-20 00:29:24 +0100234 dw_pcie_dbi_ro_wr_dis(pci);
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +0530235
236 return 0;
237}
238
239static int dw_pcie_ep_raise_irq(struct pci_epc *epc,
240 enum pci_epc_irq_type type, u8 interrupt_num)
241{
242 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
243
244 if (!ep->ops->raise_irq)
245 return -EINVAL;
246
247 return ep->ops->raise_irq(ep, type, interrupt_num);
248}
249
250static void dw_pcie_ep_stop(struct pci_epc *epc)
251{
252 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
253 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
254
255 if (!pci->ops->stop_link)
256 return;
257
258 pci->ops->stop_link(pci);
259}
260
261static int dw_pcie_ep_start(struct pci_epc *epc)
262{
263 struct dw_pcie_ep *ep = epc_get_drvdata(epc);
264 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
265
266 if (!pci->ops->start_link)
267 return -EINVAL;
268
269 return pci->ops->start_link(pci);
270}
271
272static const struct pci_epc_ops epc_ops = {
273 .write_header = dw_pcie_ep_write_header,
274 .set_bar = dw_pcie_ep_set_bar,
275 .clear_bar = dw_pcie_ep_clear_bar,
276 .map_addr = dw_pcie_ep_map_addr,
277 .unmap_addr = dw_pcie_ep_unmap_addr,
278 .set_msi = dw_pcie_ep_set_msi,
279 .get_msi = dw_pcie_ep_get_msi,
280 .raise_irq = dw_pcie_ep_raise_irq,
281 .start = dw_pcie_ep_start,
282 .stop = dw_pcie_ep_stop,
283};
284
285void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
286{
287 struct pci_epc *epc = ep->epc;
288
289 pci_epc_mem_exit(epc);
290}
291
292int dw_pcie_ep_init(struct dw_pcie_ep *ep)
293{
294 int ret;
295 void *addr;
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +0530296 struct pci_epc *epc;
297 struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
298 struct device *dev = pci->dev;
299 struct device_node *np = dev->of_node;
300
301 if (!pci->dbi_base || !pci->dbi_base2) {
302 dev_err(dev, "dbi_base/deb_base2 is not populated\n");
303 return -EINVAL;
304 }
305
306 ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);
307 if (ret < 0) {
308 dev_err(dev, "unable to read *num-ib-windows* property\n");
309 return ret;
310 }
311
312 ret = of_property_read_u32(np, "num-ob-windows", &ep->num_ob_windows);
313 if (ret < 0) {
314 dev_err(dev, "unable to read *num-ob-windows* property\n");
315 return ret;
316 }
317
318 addr = devm_kzalloc(dev, sizeof(phys_addr_t) * ep->num_ob_windows,
319 GFP_KERNEL);
320 if (!addr)
321 return -ENOMEM;
322 ep->outbound_addr = addr;
323
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +0530324 if (ep->ops->ep_init)
325 ep->ops->ep_init(ep);
326
327 epc = devm_pci_epc_create(dev, &epc_ops);
328 if (IS_ERR(epc)) {
329 dev_err(dev, "failed to create epc device\n");
330 return PTR_ERR(epc);
331 }
332
333 ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
334 if (ret < 0)
335 epc->max_functions = 1;
336
Kishon Vijay Abraham Ia937fe02017-08-18 20:28:02 +0530337 ret = __pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
338 ep->page_size);
Kishon Vijay Abraham If8aed6e2017-03-27 15:15:05 +0530339 if (ret < 0) {
340 dev_err(dev, "Failed to initialize address space\n");
341 return ret;
342 }
343
344 ep->epc = epc;
345 epc_set_drvdata(epc, ep);
346 dw_pcie_setup(pci);
347
348 return 0;
349}