blob: 903a544d37f6266b6ea498c3e6c345123d89c44e [file] [log] [blame]
Mason Huo08059f02023-07-25 17:46:48 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * StarFive PLDA PCIe host controller driver
4 *
5 * Copyright (C) 2023 StarFive Technology Co., Ltd.
6 * Author: Mason Huo <mason.huo@starfivetech.com>
7 *
8 */
9
10#include <common.h>
11#include <clk.h>
12#include <dm.h>
13#include <pci.h>
14#include <pci_ids.h>
15#include <power-domain.h>
16#include <regmap.h>
17#include <reset.h>
18#include <syscon.h>
19#include <asm/global_data.h>
20#include <asm/io.h>
21#include <asm-generic/gpio.h>
22#include <dm/device_compat.h>
23#include <dm/pinctrl.h>
24#include <linux/delay.h>
25#include <linux/iopoll.h>
26#include "pcie_plda_common.h"
27
28/* system control */
29#define STG_SYSCON_K_RP_NEP_MASK BIT(8)
30#define STG_SYSCON_AXI4_SLVL_ARFUNC_MASK GENMASK(22, 8)
31#define STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT 8
32#define STG_SYSCON_AXI4_SLVL_AWFUNC_MASK GENMASK(14, 0)
33#define STG_SYSCON_CLKREQ_MASK BIT(22)
34#define STG_SYSCON_CKREF_SRC_SHIFT 18
35#define STG_SYSCON_CKREF_SRC_MASK GENMASK(19, 18)
36
37DECLARE_GLOBAL_DATA_PTR;
38
39struct starfive_pcie {
40 struct pcie_plda plda;
41 struct clk_bulk clks;
42 struct reset_ctl_bulk rsts;
43 struct gpio_desc reset_gpio;
44 struct regmap *regmap;
45 u32 stg_arfun;
46 u32 stg_awfun;
47 u32 stg_rp_nep;
48};
49
50static int starfive_pcie_atr_init(struct starfive_pcie *priv)
51{
52 struct udevice *ctlr = pci_get_controller(priv->plda.dev);
53 struct pci_controller *hose = dev_get_uclass_priv(ctlr);
54 int i, ret;
55
56 /*
57 * As the two host bridges in JH7110 soc have the same default
58 * address translation table, this cause the second root port can't
59 * access it's host bridge config space correctly.
60 * To workaround, config the ATR of host bridge config space by SW.
61 */
62
63 ret = plda_pcie_set_atr_entry(&priv->plda,
64 (phys_addr_t)priv->plda.cfg_base, 0,
65 priv->plda.cfg_size,
66 XR3PCI_ATR_TRSLID_PCIE_CONFIG);
67 if (ret)
68 return ret;
69
70 for (i = 0; i < hose->region_count; i++) {
71 if (hose->regions[i].flags == PCI_REGION_SYS_MEMORY)
72 continue;
73
74 /* Only support identity mappings. */
75 if (hose->regions[i].bus_start !=
76 hose->regions[i].phys_start)
77 return -EINVAL;
78
79 ret = plda_pcie_set_atr_entry(&priv->plda,
80 hose->regions[i].phys_start,
81 hose->regions[i].bus_start,
82 hose->regions[i].size,
83 XR3PCI_ATR_TRSLID_PCIE_MEMORY);
84 if (ret)
85 return ret;
86 }
87
88 return 0;
89}
90
91static int starfive_pcie_get_syscon(struct udevice *dev)
92{
93 struct starfive_pcie *priv = dev_get_priv(dev);
94 struct udevice *syscon;
95 struct ofnode_phandle_args syscfg_phandle;
96 u32 cells[4];
97 int ret;
98
99 /* get corresponding syscon phandle */
100 ret = dev_read_phandle_with_args(dev, "starfive,stg-syscon", NULL, 0, 0,
101 &syscfg_phandle);
102
103 if (ret < 0) {
104 dev_err(dev, "Can't get syscfg phandle: %d\n", ret);
105 return ret;
106 }
107
108 ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, syscfg_phandle.node,
109 &syscon);
110 if (ret) {
111 dev_err(dev, "Unable to find syscon device (%d)\n", ret);
112 return ret;
113 }
114
115 priv->regmap = syscon_get_regmap(syscon);
116 if (!priv->regmap) {
117 dev_err(dev, "Unable to find regmap\n");
118 return -ENODEV;
119 }
120
121 /* get syscon register offset */
122 ret = dev_read_u32_array(dev, "starfive,stg-syscon",
123 cells, ARRAY_SIZE(cells));
124 if (ret) {
125 dev_err(dev, "Get syscon register err %d\n", ret);
126 return -EINVAL;
127 }
128
129 dev_dbg(dev, "Get syscon values: %x, %x, %x\n",
130 cells[1], cells[2], cells[3]);
131 priv->stg_arfun = cells[1];
132 priv->stg_awfun = cells[2];
133 priv->stg_rp_nep = cells[3];
134
135 return 0;
136}
137
138static int starfive_pcie_parse_dt(struct udevice *dev)
139{
140 struct starfive_pcie *priv = dev_get_priv(dev);
141 int ret;
142
143 priv->plda.reg_base = (void *)dev_read_addr_name(dev, "reg");
144 if (priv->plda.reg_base == (void __iomem *)FDT_ADDR_T_NONE) {
145 dev_err(dev, "Missing required reg address range\n");
146 return -EINVAL;
147 }
148
149 priv->plda.cfg_base =
150 (void *)dev_read_addr_size_name(dev,
151 "config",
152 &priv->plda.cfg_size);
153 if (priv->plda.cfg_base == (void __iomem *)FDT_ADDR_T_NONE) {
154 dev_err(dev, "Missing required config address range");
155 return -EINVAL;
156 }
157
158 ret = starfive_pcie_get_syscon(dev);
159 if (ret) {
160 dev_err(dev, "Can't get syscon: %d\n", ret);
161 return ret;
162 }
163
164 ret = reset_get_bulk(dev, &priv->rsts);
165 if (ret) {
166 dev_err(dev, "Can't get reset: %d\n", ret);
167 return ret;
168 }
169
170 ret = clk_get_bulk(dev, &priv->clks);
171 if (ret) {
172 dev_err(dev, "Can't get clock: %d\n", ret);
173 return ret;
174 }
175
176 ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio,
177 GPIOD_IS_OUT);
178 if (ret) {
179 dev_err(dev, "Can't get reset-gpio: %d\n", ret);
180 return ret;
181 }
182
183 if (!dm_gpio_is_valid(&priv->reset_gpio)) {
184 dev_err(dev, "reset-gpio is not valid\n");
185 return -EINVAL;
186 }
187 return 0;
188}
189
190static int starfive_pcie_init_port(struct udevice *dev)
191{
192 int ret, i;
193 struct starfive_pcie *priv = dev_get_priv(dev);
194 struct pcie_plda *plda = &priv->plda;
195
196 ret = clk_enable_bulk(&priv->clks);
197 if (ret) {
198 dev_err(dev, "Failed to enable clks (ret=%d)\n", ret);
199 return ret;
200 }
201
202 ret = reset_deassert_bulk(&priv->rsts);
203 if (ret) {
204 dev_err(dev, "Failed to deassert resets (ret=%d)\n", ret);
205 goto err_deassert_clk;
206 }
207
208 dm_gpio_set_value(&priv->reset_gpio, 1);
209 /* Disable physical functions except #0 */
210 for (i = 1; i < PLDA_FUNC_NUM; i++) {
211 regmap_update_bits(priv->regmap,
212 priv->stg_arfun,
213 STG_SYSCON_AXI4_SLVL_ARFUNC_MASK,
214 (i << PLDA_PHY_FUNC_SHIFT) <<
215 STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT);
216 regmap_update_bits(priv->regmap,
217 priv->stg_awfun,
218 STG_SYSCON_AXI4_SLVL_AWFUNC_MASK,
219 i << PLDA_PHY_FUNC_SHIFT);
220
221 plda_pcie_disable_func(plda);
222 }
223
224 /* Disable physical functions */
225 regmap_update_bits(priv->regmap,
226 priv->stg_arfun,
227 STG_SYSCON_AXI4_SLVL_ARFUNC_MASK,
228 0);
229 regmap_update_bits(priv->regmap,
230 priv->stg_awfun,
231 STG_SYSCON_AXI4_SLVL_AWFUNC_MASK,
232 0);
233
234 plda_pcie_enable_root_port(plda);
235
236 /* PCIe PCI Standard Configuration Identification Settings. */
237 plda_pcie_set_standard_class(plda);
238
239 /*
240 * The LTR message forwarding of PCIe Message Reception was set by core
241 * as default, but the forward id & addr are also need to be reset.
242 * If we do not disable LTR message forwarding here, or set a legal
243 * forwarding address, the kernel will get stuck after this driver probe.
244 * To workaround, disable the LTR message forwarding support on
245 * PCIe Message Reception.
246 */
247 plda_pcie_disable_ltr(plda);
248
249 /* Prefetchable memory window 64-bit addressing support */
250 plda_pcie_set_pref_win_64bit(plda);
251 starfive_pcie_atr_init(priv);
252
253 dm_gpio_set_value(&priv->reset_gpio, 0);
254 /* Ensure that PERST in default at least 300 ms */
255 mdelay(300);
256
257 return 0;
258
259err_deassert_clk:
260 clk_disable_bulk(&priv->clks);
261 return ret;
262}
263
264static int starfive_pcie_probe(struct udevice *dev)
265{
266 struct starfive_pcie *priv = dev_get_priv(dev);
267 int ret;
268
269 priv->plda.atr_table_num = 0;
270 priv->plda.dev = dev;
271
272 ret = starfive_pcie_parse_dt(dev);
273 if (ret)
274 return ret;
275
276 regmap_update_bits(priv->regmap,
277 priv->stg_rp_nep,
278 STG_SYSCON_K_RP_NEP_MASK,
279 STG_SYSCON_K_RP_NEP_MASK);
280
281 regmap_update_bits(priv->regmap,
282 priv->stg_awfun,
283 STG_SYSCON_CKREF_SRC_MASK,
284 2 << STG_SYSCON_CKREF_SRC_SHIFT);
285
286 regmap_update_bits(priv->regmap,
287 priv->stg_awfun,
288 STG_SYSCON_CLKREQ_MASK,
289 STG_SYSCON_CLKREQ_MASK);
290
291 ret = starfive_pcie_init_port(dev);
292 if (ret)
293 return ret;
294
295 dev_err(dev, "Starfive PCIe bus probed.\n");
296
297 return 0;
298}
299
300static const struct dm_pci_ops starfive_pcie_ops = {
301 .read_config = plda_pcie_config_read,
302 .write_config = plda_pcie_config_write,
303};
304
305static const struct udevice_id starfive_pcie_ids[] = {
306 { .compatible = "starfive,jh7110-pcie" },
307 { }
308};
309
310U_BOOT_DRIVER(starfive_pcie_drv) = {
311 .name = "starfive_7110_pcie",
312 .id = UCLASS_PCI,
313 .of_match = starfive_pcie_ids,
314 .ops = &starfive_pcie_ops,
315 .probe = starfive_pcie_probe,
316 .priv_auto = sizeof(struct starfive_pcie),
317};