xref: /aosp_15_r20/external/coreboot/payloads/libpayload/drivers/pci_qcom.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <libpayload.h>
4 #include <pci.h>
5 
6 /*
7  * iATU Unroll-specific register definitions
8  */
9 #define PCIE_ATU_UNR_REGION_CTRL1	0x00
10 #define PCIE_ATU_UNR_REGION_CTRL2	0x04
11 #define PCIE_ATU_UNR_LOWER_BASE		0x08
12 #define PCIE_ATU_UNR_UPPER_BASE		0x0C
13 #define PCIE_ATU_UNR_LIMIT		0x10
14 #define PCIE_ATU_UNR_LOWER_TARGET	0x14
15 #define PCIE_ATU_UNR_UPPER_TARGET	0x18
16 #define PCIE_ATU_REGION_INDEX0		0x0
17 #define PCIE_ATU_TYPE_CFG0		0x4
18 #define PCIE_ATU_TYPE_CFG1		0x5
19 #define PCIE_ATU_ENABLE			BIT(31)
20 #define ATU_CTRL2			PCIE_ATU_UNR_REGION_CTRL2
21 #define ATU_ENABLE			PCIE_ATU_ENABLE
22 
23 #define PCIE_ATU_BUS(x)			(((x) & 0xff) << 24)
24 #define PCIE_ATU_DEV(x)			(((x) & 0x1f) << 19)
25 #define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
26 #define LINK_WAIT_IATU_US		1000
27 #define LINK_WAIT_MAX_IATU_RETRIES	5
28 
29 /* Register address builder */
30 #define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((region) << 9)
31 
32 #define lower_32_bits(n)		((u32)(n))
33 #define upper_32_bits(n)		((u32)(((n) >> 16) >> 16))
34 
35 /*
36  * ATU & endpoint config space base address offsets relative to
37  * PCIe controller base address.
38  */
39 #define QCOM_ATU_BASE_OFFSET		0x1000
40 #define QCOM_EP_CFG_OFFSET		0x100000
41 #define QCOM_EP_CFG_SIZE		0x1000    /* 4K */
42 
dw_pcie_writel_iatu(void * atu_base,unsigned short index,uint32_t reg,uint32_t val)43 static void dw_pcie_writel_iatu(void *atu_base, unsigned short index,
44 				uint32_t reg, uint32_t val)
45 {
46 	uint32_t offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
47 
48 	write32(atu_base + offset + reg, val);
49 }
50 
dw_pcie_readl_iatu(void * atu_base,unsigned short index,uint32_t reg)51 static uint32_t dw_pcie_readl_iatu(void *atu_base, unsigned short index,
52 				   uint32_t reg)
53 {
54 	uint32_t offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
55 
56 	return read32(atu_base + offset + reg);
57 }
58 
dw_pcie_prog_outbound_atu(void * atu_base,unsigned short index,unsigned int type,uint64_t cfg_addr,uint64_t pcie_addr,uint32_t cfg_size)59 static void dw_pcie_prog_outbound_atu(void *atu_base, unsigned short index,
60 				      unsigned int type, uint64_t cfg_addr,
61 				      uint64_t pcie_addr, uint32_t cfg_size)
62 {
63 	dw_pcie_writel_iatu(atu_base, index, PCIE_ATU_UNR_LOWER_BASE,
64 			    lower_32_bits(cfg_addr));
65 	dw_pcie_writel_iatu(atu_base, index, PCIE_ATU_UNR_UPPER_BASE,
66 			    upper_32_bits(cfg_addr));
67 	dw_pcie_writel_iatu(atu_base, index, PCIE_ATU_UNR_LIMIT,
68 			    lower_32_bits(cfg_addr + cfg_size - 1));
69 	dw_pcie_writel_iatu(atu_base, index, PCIE_ATU_UNR_LOWER_TARGET,
70 			    lower_32_bits(pcie_addr));
71 	dw_pcie_writel_iatu(atu_base, index, PCIE_ATU_UNR_UPPER_TARGET,
72 			    upper_32_bits(pcie_addr));
73 	dw_pcie_writel_iatu(atu_base, index, PCIE_ATU_UNR_REGION_CTRL1, type);
74 	dw_pcie_writel_iatu(atu_base, index, PCIE_ATU_UNR_REGION_CTRL2,
75 			    PCIE_ATU_ENABLE);
76 	/*
77 	 * Make sure ATU enable takes effect before any subsequent config
78 	 * and I/O accesses.
79 	 */
80 	if (retry(LINK_WAIT_MAX_IATU_RETRIES,
81 		  (dw_pcie_readl_iatu(atu_base, index, ATU_CTRL2) & ATU_ENABLE),
82 		  udelay(LINK_WAIT_IATU_US)))
83 		return;
84 
85 	printf("outbound iATU is couldn't be enabled after 5ms\n");
86 }
87 
88 /* Get PCIe MMIO configuration space base address */
pci_map_bus(pcidev_t dev)89 uintptr_t pci_map_bus(pcidev_t dev)
90 {
91 	unsigned int atu_type, busdev;
92 	uint32_t config_size;
93 	void *cntrlr_base, *config_base, *atu_base;
94 	unsigned int current_bus = PCI_BUS(dev);
95 	unsigned int devfn = (PCI_SLOT(dev) << 3) | PCI_FUNC(dev);
96 	static pcidev_t current_dev;
97 
98 	/*
99 	 * Extract PCIe controller base from coreboot and derive the ATU and
100 	 * endpoint config base addresses from it.
101 	 */
102 	cntrlr_base = (void *)lib_sysinfo.pcie_ctrl_base;
103 	config_base = (void *)cntrlr_base + QCOM_EP_CFG_OFFSET;
104 	config_size = (uint32_t)QCOM_EP_CFG_SIZE;
105 	atu_base = (void *)cntrlr_base + QCOM_ATU_BASE_OFFSET;
106 
107 	/*
108 	 * Cache the dev. For same dev, ATU mapping is not needed for each
109 	 * request.
110 	 */
111 	if (current_dev == dev)
112 		goto out;
113 
114 	current_dev = dev;
115 
116 	busdev = PCIE_ATU_BUS(current_bus)   |
117 		 PCIE_ATU_DEV(PCI_SLOT(dev)) |
118 		 PCIE_ATU_FUNC(PCI_FUNC(dev));
119 
120 	atu_type = current_bus == 1 ? PCIE_ATU_TYPE_CFG0 : PCIE_ATU_TYPE_CFG1;
121 
122 	dw_pcie_prog_outbound_atu(atu_base, PCIE_ATU_REGION_INDEX0, atu_type,
123 				  (uint64_t)config_base, busdev, config_size);
124 out:
125 	return (uintptr_t)config_base + (QCOM_EP_CFG_SIZE * devfn);
126 }
127