ipq40xx: add PCIe magic hack to improve VRX518 compatibility
[openwrt/staging/jow.git] / target / linux / ipq40xx / patches-5.15 / 997-pcie-qcom-host-magic.patch
1 This hack is based on code from the FRITZ!Box 7530 GPL archive for
2 firmware version 07.50.
3
4 If the device tree contains the "avm,host_magic" property, it changes
5 the PCIe vendor/device ID to the values from Lantiq GRX500 SoCs. It also
6 programs the ATU to present a buffer containing a magic value to PCIe
7 devices. This appears to emulate a Lantiq CPU ID register.
8
9 Without this hack, some VRX518 modems fail to initialize properly (error
10 "dc_ep_clk_on failed"), and the DSL data path doesn't work.
11 --- a/drivers/pci/controller/dwc/pcie-qcom.c
12 +++ b/drivers/pci/controller/dwc/pcie-qcom.c
13 @@ -27,6 +27,7 @@
14 #include <linux/reset.h>
15 #include <linux/slab.h>
16 #include <linux/types.h>
17 +#include <linux/version.h>
18
19 #include "../../pci.h"
20 #include "pcie-designware.h"
21 @@ -102,6 +103,8 @@
22
23 #define QCOM_PCIE_CRC8_POLYNOMIAL (BIT(2) | BIT(1) | BIT(0))
24
25 +#define PCIE_MAGIC_SIZE 0x10000
26 +
27 struct qcom_pcie_resources_2_1_0 {
28 struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
29 struct reset_control *pci_reset;
30 @@ -197,6 +200,8 @@ struct qcom_pcie {
31 struct phy *phy;
32 struct gpio_desc *reset;
33 const struct qcom_pcie_ops *ops;
34 + void *magic_cpu_addr;
35 + dma_addr_t magic_dma_handle;
36 };
37
38 #define to_qcom_pcie(x) dev_get_drvdata((x)->dev)
39 @@ -1388,8 +1393,141 @@ err_deinit:
40 return ret;
41 }
42
43 +static int qcom_pcie_magic_prog_atu(struct qcom_pcie *pcie,
44 + u32 addr, u32 limit, u32 phys)
45 +{
46 + struct dw_pcie *pci = pcie->pci;
47 + struct device *dev = pci->dev;
48 + u32 retries, val;
49 + int index;
50 +
51 + if (!pci->num_ib_windows) {
52 + dev_err(dev, "No inbound ATU window available for magic\n");
53 + return -1;
54 + }
55 +
56 + /*
57 + * Use highest window index and reduce window count so the driver
58 + * won't overwrite the entry later.
59 + */
60 + index = --pci->num_ib_windows;
61 +
62 +#if LINUX_VERSION_CODE < KERNEL_VERSION(6,0,0)
63 + if (pci->iatu_unroll_enabled) {
64 + dev_err(dev, "Programming ATU for magic not implemented for this hardware\n");
65 + return -1;
66 + }
67 +
68 + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT,
69 + PCIE_ATU_REGION_INBOUND | index);
70 +
71 + dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE, addr);
72 + dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE, 0);
73 + dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, limit);
74 + dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, phys);
75 + dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, 0);
76 +
77 + dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, PCIE_ATU_TYPE_MEM);
78 + dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
79 +
80 + for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
81 + val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
82 + if (val & PCIE_ATU_ENABLE)
83 + return 0;
84 +
85 + mdelay(LINK_WAIT_IATU);
86 + }
87 +#else
88 + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_BASE, addr);
89 + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_BASE, 0);
90 + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LIMIT, limit);
91 + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET, phys);
92 + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET, 0);
93 +
94 + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1,
95 + PCIE_ATU_TYPE_MEM);
96 + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2,
97 + PCIE_ATU_ENABLE);
98 +
99 + for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
100 + val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
101 + if (val & PCIE_ATU_ENABLE)
102 + return 0;
103 +
104 + mdelay(LINK_WAIT_IATU);
105 + }
106 +#endif
107 +
108 + dev_err(dev, "Failed to program ATU for magic\n");
109 + return -1;
110 +}
111 +
112 +static void qcom_pcie_magic_deinit(struct qcom_pcie *pcie)
113 +{
114 + struct dw_pcie *pci = pcie->pci;
115 + struct device *dev = pci->dev;
116 +
117 + if (pcie->magic_cpu_addr) {
118 + dma_free_coherent(dev, PCIE_MAGIC_SIZE,
119 + pcie->magic_cpu_addr,
120 + pcie->magic_dma_handle);
121 +
122 + pcie->magic_cpu_addr = NULL;
123 + }
124 +}
125 +
126 +static void qcom_pcie_magic_init(struct qcom_pcie *pcie)
127 +{
128 + struct dw_pcie *pci = pcie->pci;
129 + struct device *dev = pci->dev;
130 + u32 *virt;
131 + u32 phys;
132 + int ret;
133 +
134 + if (!of_property_read_bool(dev->of_node, "avm,host_magic"))
135 + return;
136 +
137 + dev_info(dev, "Applying PCIe host magic\n");
138 +
139 + virt = dma_alloc_coherent(dev, PCIE_MAGIC_SIZE, &phys, GFP_ATOMIC);
140 + BUG_ON(virt == NULL);
141 +
142 + pcie->magic_cpu_addr = virt;
143 + pcie->magic_dma_handle = phys;
144 +
145 + /*
146 + * This value is the manufacturer ID of Lantiq. The address where
147 + * it will be visible for the PCIe device matches the location of
148 + * CPU ID registers on Lantiq SocS (MPS base address is 0x1f107000).
149 + */
150 + virt[0x7340/4] = 0x389 << 5;
151 +
152 + /* Make it visible to PCIe devices using address translation unit */
153 + ret = qcom_pcie_magic_prog_atu(pcie, 0x1f100000, 0x1f10ffff, phys);
154 +
155 + dw_pcie_dbi_ro_wr_en(pci);
156 +
157 + /* Set vendor/device ID of GRX500 PCIe host */
158 + dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x1bef);
159 + dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0x0030);
160 +
161 + dw_pcie_dbi_ro_wr_dis(pci);
162 +
163 + if (ret)
164 + qcom_pcie_magic_deinit(pcie);
165 +}
166 +
167 +static void qcom_pcie_atu_hack(struct pcie_port *pp)
168 +{
169 + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
170 + struct qcom_pcie *pcie = to_qcom_pcie(pci);
171 +
172 + qcom_pcie_magic_init(pcie);
173 +}
174 +
175 static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
176 .host_init = qcom_pcie_host_init,
177 + .atu_hack = qcom_pcie_atu_hack,
178 };
179
180 /* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */
181 @@ -1536,6 +1674,7 @@ static int qcom_pcie_probe(struct platfo
182
183 err_phy_exit:
184 phy_exit(pcie->phy);
185 + qcom_pcie_magic_deinit(pcie);
186 err_pm_runtime_put:
187 pm_runtime_put(dev);
188 pm_runtime_disable(dev);
189 --- a/drivers/pci/controller/dwc/pcie-designware-host.c
190 +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
191 @@ -400,6 +400,14 @@ int dw_pcie_host_init(struct pcie_port *
192 }
193 dw_pcie_iatu_detect(pci);
194
195 + /*
196 + * This needs to be called after ATU detection, but before the driver
197 + * sets up any ATU entries, to avoid any ATU entry programmed in the
198 + * hack being overwritten by the driver later.
199 + */
200 + if (pp->ops->atu_hack)
201 + pp->ops->atu_hack(pp);
202 +
203 dw_pcie_setup_rc(pp);
204
205 if (!dw_pcie_link_up(pci) && pci->ops && pci->ops->start_link) {
206 --- a/drivers/pci/controller/dwc/pcie-designware.h
207 +++ b/drivers/pci/controller/dwc/pcie-designware.h
208 @@ -174,6 +174,7 @@ enum dw_pcie_device_mode {
209
210 struct dw_pcie_host_ops {
211 int (*host_init)(struct pcie_port *pp);
212 + void (*atu_hack)(struct pcie_port *pp);
213 int (*msi_host_init)(struct pcie_port *pp);
214 };
215