File Index
Files and directories
Sign in
FILE

pcie-cadence-host.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/controller/cadence/pcie-cadence-host.c C
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (c) 2017 Cadence
  3// Cadence PCIe host controller driver.
  4// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
  5
  6#include <linux/delay.h>
  7#include <linux/kernel.h>
  8#include <linux/module.h>
  9#include <linux/list_sort.h>
 10#include <linux/of_address.h>
 11#include <linux/of_pci.h>
 12#include <linux/platform_device.h>
 13
 14#include "pcie-cadence.h"
 15#include "pcie-cadence-host-common.h"
 16
 17static u8 bar_aperture_mask[] = {
 18	[RP_BAR0] = 0x1F,
 19	[RP_BAR1] = 0xF,
 20};
 21
 22void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
 23			       int where)
 24{
 25	struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
 26	struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
 27	struct cdns_pcie *pcie = &rc->pcie;
 28	unsigned int busn = bus->number;
 29	u32 addr0, desc0;
 30
 31	if (pci_is_root_bus(bus)) {
 32		/*
 33		 * Only the root port (devfn == 0) is connected to this bus.
 34		 * All other PCI devices are behind some bridge hence on another
 35		 * bus.
 36		 */
 37		if (devfn)
 38			return NULL;
 39
 40		return pcie->reg_base + (where & 0xfff);
 41	}
 42	/* Check that the link is up */
 43	if (!(cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1))
 44		return NULL;
 45	/* Clear AXI link-down status */
 46	cdns_pcie_writel(pcie, CDNS_PCIE_AT_LINKDOWN, 0x0);
 47
 48	/* Update Output registers for AXI region 0. */
 49	addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
 50		CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
 51		CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
 52	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
 53
 54	/* Configuration Type 0 or Type 1 access. */
 55	desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
 56		CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
 57	/*
 58	 * The bus number was already set once for all in desc1 by
 59	 * cdns_pcie_host_init_address_translation().
 60	 */
 61	if (busn == bridge->busnr + 1)
 62		desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
 63	else
 64		desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
 65	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
 66
 67	return rc->cfg_base + (where & 0xfff);
 68}
 69EXPORT_SYMBOL_GPL(cdns_pci_map_bus);
 70
 71static struct pci_ops cdns_pcie_host_ops = {
 72	.map_bus	= cdns_pci_map_bus,
 73	.read		= pci_generic_config_read,
 74	.write		= pci_generic_config_write,
 75};
 76
 77static void cdns_pcie_host_disable_ptm_response(struct cdns_pcie *pcie)
 78{
 79	u32 val;
 80
 81	val = cdns_pcie_readl(pcie, CDNS_PCIE_LM_PTM_CTRL);
 82	cdns_pcie_writel(pcie, CDNS_PCIE_LM_PTM_CTRL, val & ~CDNS_PCIE_LM_TPM_CTRL_PTMRSEN);
 83}
 84
 85static void cdns_pcie_host_enable_ptm_response(struct cdns_pcie *pcie)
 86{
 87	u32 val;
 88
 89	val = cdns_pcie_readl(pcie, CDNS_PCIE_LM_PTM_CTRL);
 90	cdns_pcie_writel(pcie, CDNS_PCIE_LM_PTM_CTRL, val | CDNS_PCIE_LM_TPM_CTRL_PTMRSEN);
 91}
 92
 93static void cdns_pcie_host_deinit_root_port(struct cdns_pcie_rc *rc)
 94{
 95	struct cdns_pcie *pcie = &rc->pcie;
 96	u32 value, ctrl;
 97
 98	cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, 0xffff);
 99	cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0xff);
100	cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0xff);
101	cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, 0xffffffff);
102	cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, 0xffff);
103	ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
104	value = ~(CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
105		CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
106		CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
107		CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
108		CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
109		CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS);
110	cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
111}
112
113static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
114{
115	struct cdns_pcie *pcie = &rc->pcie;
116	u32 value, ctrl;
117	u32 id;
118
119	/*
120	 * Set the root complex BAR configuration register:
121	 * - disable both BAR0 and BAR1.
122	 * - enable Prefetchable Memory Base and Limit registers in type 1
123	 *   config space (64 bits).
124	 * - enable IO Base and Limit registers in type 1 config
125	 *   space (32 bits).
126	 */
127	ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
128	value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
129		CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
130		CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
131		CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
132		CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
133		CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
134	cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
135
136	/* Set root port configuration space */
137	if (rc->vendor_id != 0xffff) {
138		id = CDNS_PCIE_LM_ID_VENDOR(rc->vendor_id) |
139			CDNS_PCIE_LM_ID_SUBSYS(rc->vendor_id);
140		cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
141	}
142
143	if (rc->device_id != 0xffff)
144		cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
145
146	cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
147	cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
148	cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
149
150	return 0;
151}
152
153int cdns_pcie_host_bar_ib_config(struct cdns_pcie_rc *rc,
154				 enum cdns_pcie_rp_bar bar,
155				 u64 cpu_addr,
156				 u64 size,
157				 unsigned long flags)
158{
159	struct cdns_pcie *pcie = &rc->pcie;
160	u32 addr0, addr1, aperture, value;
161
162	if (!rc->avail_ib_bar[bar])
163		return -EBUSY;
164
165	rc->avail_ib_bar[bar] = false;
166
167	aperture = ilog2(size);
168	addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(aperture) |
169		(lower_32_bits(cpu_addr) & GENMASK(31, 8));
170	addr1 = upper_32_bits(cpu_addr);
171	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar), addr0);
172	cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar), addr1);
173
174	if (bar == RP_NO_BAR)
175		return 0;
176
177	value = cdns_pcie_readl(pcie, CDNS_PCIE_LM_RC_BAR_CFG);
178	value &= ~(LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) |
179		   LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) |
180		   LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) |
181		   LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) |
182		   LM_RC_BAR_CFG_APERTURE(bar, bar_aperture_mask[bar] + 2));
183	if (size + cpu_addr >= SZ_4G) {
184		if (!(flags & IORESOURCE_PREFETCH))
185			value |= LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar);
186		value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar);
187	} else {
188		if (!(flags & IORESOURCE_PREFETCH))
189			value |= LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar);
190		value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar);
191	}
192
193	value |= LM_RC_BAR_CFG_APERTURE(bar, aperture);
194	cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
195
196	return 0;
197}
198
199static void cdns_pcie_host_unmap_dma_ranges(struct cdns_pcie_rc *rc)
200{
201	struct cdns_pcie *pcie = &rc->pcie;
202	enum cdns_pcie_rp_bar bar;
203	u32 value;
204
205	/* Reset inbound configuration for all BARs which were being used */
206	for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
207		if (rc->avail_ib_bar[bar])
208			continue;
209
210		cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar), 0);
211		cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar), 0);
212
213		if (bar == RP_NO_BAR)
214			continue;
215
216		value = ~(LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) |
217			  LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) |
218			  LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) |
219			  LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) |
220			  LM_RC_BAR_CFG_APERTURE(bar, bar_aperture_mask[bar] + 2));
221		cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
222	}
223}
224
225static void cdns_pcie_host_deinit_address_translation(struct cdns_pcie_rc *rc)
226{
227	struct cdns_pcie *pcie = &rc->pcie;
228	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
229	struct resource_entry *entry;
230	int r;
231
232	cdns_pcie_host_unmap_dma_ranges(rc);
233
234	/*
235	 * Reset outbound region 0 which was reserved for configuration space
236	 * accesses.
237	 */
238	cdns_pcie_reset_outbound_region(pcie, 0);
239
240	/* Reset rest of the outbound regions */
241	r = 1;
242	resource_list_for_each_entry(entry, &bridge->windows) {
243		cdns_pcie_reset_outbound_region(pcie, r);
244		r++;
245	}
246}
247
248static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
249{
250	struct cdns_pcie *pcie = &rc->pcie;
251	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
252	struct resource *cfg_res = rc->cfg_res;
253	struct resource_entry *entry;
254	u64 cpu_addr = cfg_res->start;
255	u32 addr0, addr1, desc1;
256	int r, busnr = 0;
257
258	entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
259	if (entry)
260		busnr = entry->res->start;
261
262	/*
263	 * Reserve region 0 for PCI configure space accesses:
264	 * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
265	 * cdns_pci_map_bus(), other region registers are set here once for all.
266	 */
267	addr1 = 0; /* Should be programmed to zero. */
268	desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr);
269	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
270	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
271
272	if (pcie->ops && pcie->ops->cpu_addr_fixup)
273		cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
274
275	addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
276		(lower_32_bits(cpu_addr) & GENMASK(31, 8));
277	addr1 = upper_32_bits(cpu_addr);
278	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
279	cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
280
281	r = 1;
282	resource_list_for_each_entry(entry, &bridge->windows) {
283		struct resource *res = entry->res;
284		u64 pci_addr = res->start - entry->offset;
285
286		if (resource_type(res) == IORESOURCE_IO)
287			cdns_pcie_set_outbound_region(pcie, busnr, 0, r,
288						      true,
289						      pci_pio_to_address(res->start),
290						      pci_addr,
291						      resource_size(res));
292		else
293			cdns_pcie_set_outbound_region(pcie, busnr, 0, r,
294						      false,
295						      res->start,
296						      pci_addr,
297						      resource_size(res));
298
299		r++;
300	}
301
302	return cdns_pcie_host_map_dma_ranges(rc, cdns_pcie_host_bar_ib_config);
303}
304
305static void cdns_pcie_host_deinit(struct cdns_pcie_rc *rc)
306{
307	cdns_pcie_host_deinit_address_translation(rc);
308	cdns_pcie_host_deinit_root_port(rc);
309}
310
311int cdns_pcie_host_init(struct cdns_pcie_rc *rc)
312{
313	int err;
314
315	err = cdns_pcie_host_init_root_port(rc);
316	if (err)
317		return err;
318
319	return cdns_pcie_host_init_address_translation(rc);
320}
321EXPORT_SYMBOL_GPL(cdns_pcie_host_init);
322
323static void cdns_pcie_host_link_disable(struct cdns_pcie_rc *rc)
324{
325	struct cdns_pcie *pcie = &rc->pcie;
326
327	cdns_pcie_stop_link(pcie);
328	cdns_pcie_host_disable_ptm_response(pcie);
329}
330
331int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc)
332{
333	struct cdns_pcie *pcie = &rc->pcie;
334	struct device *dev = rc->pcie.dev;
335	int ret;
336
337	if (rc->quirk_detect_quiet_flag)
338		cdns_pcie_detect_quiet_min_delay_set(&rc->pcie);
339
340	cdns_pcie_host_enable_ptm_response(pcie);
341
342	ret = cdns_pcie_start_link(pcie);
343	if (ret) {
344		dev_err(dev, "Failed to start link\n");
345		return ret;
346	}
347
348	ret = cdns_pcie_host_start_link(rc, cdns_pcie_link_up);
349	if (ret)
350		dev_dbg(dev, "PCIe link never came up\n");
351
352	return 0;
353}
354EXPORT_SYMBOL_GPL(cdns_pcie_host_link_setup);
355
356void cdns_pcie_host_disable(struct cdns_pcie_rc *rc)
357{
358	struct pci_host_bridge *bridge;
359
360	bridge = pci_host_bridge_from_priv(rc);
361	pci_stop_root_bus(bridge->bus);
362	pci_remove_root_bus(bridge->bus);
363
364	cdns_pcie_host_deinit(rc);
365	cdns_pcie_host_link_disable(rc);
366}
367EXPORT_SYMBOL_GPL(cdns_pcie_host_disable);
368
369int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
370{
371	struct device *dev = rc->pcie.dev;
372	struct platform_device *pdev = to_platform_device(dev);
373	struct device_node *np = dev->of_node;
374	struct pci_host_bridge *bridge;
375	enum cdns_pcie_rp_bar bar;
376	struct cdns_pcie *pcie;
377	struct resource *res;
378	int ret;
379
380	bridge = pci_host_bridge_from_priv(rc);
381	if (!bridge)
382		return -ENOMEM;
383
384	pcie = &rc->pcie;
385	pcie->is_rc = true;
386
387	rc->vendor_id = 0xffff;
388	of_property_read_u32(np, "vendor-id", &rc->vendor_id);
389
390	rc->device_id = 0xffff;
391	of_property_read_u32(np, "device-id", &rc->device_id);
392
393	pcie->reg_base = devm_platform_ioremap_resource_byname(pdev, "reg");
394	if (IS_ERR(pcie->reg_base)) {
395		dev_err(dev, "missing \"reg\"\n");
396		return PTR_ERR(pcie->reg_base);
397	}
398
399	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
400	rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
401	if (IS_ERR(rc->cfg_base))
402		return PTR_ERR(rc->cfg_base);
403	rc->cfg_res = res;
404
405	ret = cdns_pcie_host_link_setup(rc);
406	if (ret)
407		return ret;
408
409	for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
410		rc->avail_ib_bar[bar] = true;
411
412	ret = cdns_pcie_host_init(rc);
413	if (ret)
414		return ret;
415
416	if (!bridge->ops)
417		bridge->ops = &cdns_pcie_host_ops;
418
419	return pci_host_probe(bridge);
420}
421EXPORT_SYMBOL_GPL(cdns_pcie_host_setup);
422
423MODULE_LICENSE("GPL");
424MODULE_DESCRIPTION("Cadence PCIe host controller driver");
425MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@free-electrons.com>");
~/ Read-only file preview.