1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * SpacemiT K1 PCIe host driver
4 *
5 * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved.
6 * Copyright (c) 2023, spacemit Corporation.
7 */
8
9 #include <linux/clk.h>
10 #include <linux/delay.h>
11 #include <linux/device.h>
12 #include <linux/err.h>
13 #include <linux/gfp.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/phy/phy.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/reset.h>
19 #include <linux/types.h>
20
21 #include "pcie-designware.h"
22
23 /* Offsets and field definitions for link management registers */
24 #define K1_PHY_AHB_IRQ_EN 0x0000
25 #define PCIE_INTERRUPT_EN BIT(0)
26
27 #define K1_PHY_AHB_LINK_STS 0x0004
28 #define SMLH_LINK_UP BIT(1)
29 #define RDLH_LINK_UP BIT(12)
30
31 #define INTR_ENABLE 0x0014
32 #define MSI_CTRL_INT BIT(11)
33
34 /* Some controls require APMU regmap access */
35 #define SYSCON_APMU "spacemit,apmu"
36
37 /* Offsets and field definitions for APMU registers */
38 #define PCIE_CLK_RESET_CONTROL 0x0000
39 #define LTSSM_EN BIT(6)
40 #define PCIE_AUX_PWR_DET BIT(9)
41 #define PCIE_RC_PERST BIT(12) /* 1: assert PERST# */
42 #define APP_HOLD_PHY_RST BIT(30)
43 #define DEVICE_TYPE_RC BIT(31) /* 0: endpoint; 1: RC */
44
45 #define PCIE_CONTROL_LOGIC 0x0004
46 #define PCIE_SOFT_RESET BIT(0)
47
48 struct k1_pcie {
49 struct dw_pcie pci;
50 struct phy *phy;
51 void __iomem *link;
52 struct regmap *pmu; /* Errors ignored; MMIO-backed regmap */
53 u32 pmu_off;
54 };
55
56 #define to_k1_pcie(dw_pcie) \
57 platform_get_drvdata(to_platform_device((dw_pcie)->dev))
58
k1_pcie_toggle_soft_reset(struct k1_pcie * k1)59 static void k1_pcie_toggle_soft_reset(struct k1_pcie *k1)
60 {
61 u32 offset;
62 u32 val;
63
64 /*
65 * Write, then read back to guarantee it has reached the device
66 * before we start the delay.
67 */
68 offset = k1->pmu_off + PCIE_CONTROL_LOGIC;
69 regmap_set_bits(k1->pmu, offset, PCIE_SOFT_RESET);
70 regmap_read(k1->pmu, offset, &val);
71
72 mdelay(2);
73
74 regmap_clear_bits(k1->pmu, offset, PCIE_SOFT_RESET);
75 }
76
77 /* Enable app clocks, deassert resets */
k1_pcie_enable_resources(struct k1_pcie * k1)78 static int k1_pcie_enable_resources(struct k1_pcie *k1)
79 {
80 struct dw_pcie *pci = &k1->pci;
81 int ret;
82
83 ret = clk_bulk_prepare_enable(ARRAY_SIZE(pci->app_clks), pci->app_clks);
84 if (ret)
85 return ret;
86
87 ret = reset_control_bulk_deassert(ARRAY_SIZE(pci->app_rsts),
88 pci->app_rsts);
89 if (ret)
90 goto err_disable_clks;
91
92 return 0;
93
94 err_disable_clks:
95 clk_bulk_disable_unprepare(ARRAY_SIZE(pci->app_clks), pci->app_clks);
96
97 return ret;
98 }
99
100 /* Assert resets, disable app clocks */
k1_pcie_disable_resources(struct k1_pcie * k1)101 static void k1_pcie_disable_resources(struct k1_pcie *k1)
102 {
103 struct dw_pcie *pci = &k1->pci;
104
105 reset_control_bulk_assert(ARRAY_SIZE(pci->app_rsts), pci->app_rsts);
106 clk_bulk_disable_unprepare(ARRAY_SIZE(pci->app_clks), pci->app_clks);
107 }
108
109 /* FIXME: Disable ASPM L1 to avoid errors reported on some NVMe drives */
k1_pcie_disable_aspm_l1(struct k1_pcie * k1)110 static void k1_pcie_disable_aspm_l1(struct k1_pcie *k1)
111 {
112 struct dw_pcie *pci = &k1->pci;
113 u8 offset;
114 u32 val;
115
116 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
117 offset += PCI_EXP_LNKCAP;
118
119 dw_pcie_dbi_ro_wr_en(pci);
120 val = dw_pcie_readl_dbi(pci, offset);
121 val &= ~PCI_EXP_LNKCAP_ASPM_L1;
122 dw_pcie_writel_dbi(pci, offset, val);
123 dw_pcie_dbi_ro_wr_dis(pci);
124 }
125
k1_pcie_init(struct dw_pcie_rp * pp)126 static int k1_pcie_init(struct dw_pcie_rp *pp)
127 {
128 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
129 struct k1_pcie *k1 = to_k1_pcie(pci);
130 u32 reset_ctrl;
131 u32 val;
132 int ret;
133
134 k1_pcie_toggle_soft_reset(k1);
135
136 ret = k1_pcie_enable_resources(k1);
137 if (ret)
138 return ret;
139
140 /* Set the PCI vendor and device ID */
141 dw_pcie_dbi_ro_wr_en(pci);
142 dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, PCI_VENDOR_ID_SPACEMIT);
143 dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, PCI_DEVICE_ID_SPACEMIT_K1);
144 dw_pcie_dbi_ro_wr_dis(pci);
145
146 /*
147 * Start by asserting fundamental reset (drive PERST# low). The
148 * PCI CEM spec says that PERST# should be deasserted at least
149 * 100ms after the power becomes stable, so we'll insert that
150 * delay first. Write, then read it back to guarantee the write
151 * reaches the device before we start the delay.
152 */
153 reset_ctrl = k1->pmu_off + PCIE_CLK_RESET_CONTROL;
154 regmap_set_bits(k1->pmu, reset_ctrl, PCIE_RC_PERST);
155 regmap_read(k1->pmu, reset_ctrl, &val);
156 mdelay(PCIE_T_PVPERL_MS);
157
158 /*
159 * Put the controller in root complex mode, and indicate that
160 * Vaux (3.3v) is present.
161 */
162 regmap_set_bits(k1->pmu, reset_ctrl, DEVICE_TYPE_RC | PCIE_AUX_PWR_DET);
163
164 ret = phy_init(k1->phy);
165 if (ret) {
166 k1_pcie_disable_resources(k1);
167
168 return ret;
169 }
170
171 /* Deassert fundamental reset (drive PERST# high) */
172 regmap_clear_bits(k1->pmu, reset_ctrl, PCIE_RC_PERST);
173
174 /* Finally, as a workaround, disable ASPM L1 */
175 k1_pcie_disable_aspm_l1(k1);
176
177 return 0;
178 }
179
k1_pcie_deinit(struct dw_pcie_rp * pp)180 static void k1_pcie_deinit(struct dw_pcie_rp *pp)
181 {
182 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
183 struct k1_pcie *k1 = to_k1_pcie(pci);
184
185 /* Assert fundamental reset (drive PERST# low) */
186 regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
187 PCIE_RC_PERST);
188
189 phy_exit(k1->phy);
190
191 k1_pcie_disable_resources(k1);
192 }
193
194 static const struct dw_pcie_host_ops k1_pcie_host_ops = {
195 .init = k1_pcie_init,
196 .deinit = k1_pcie_deinit,
197 };
198
k1_pcie_link_up(struct dw_pcie * pci)199 static bool k1_pcie_link_up(struct dw_pcie *pci)
200 {
201 struct k1_pcie *k1 = to_k1_pcie(pci);
202 u32 val;
203
204 val = readl_relaxed(k1->link + K1_PHY_AHB_LINK_STS);
205
206 return (val & RDLH_LINK_UP) && (val & SMLH_LINK_UP);
207 }
208
k1_pcie_start_link(struct dw_pcie * pci)209 static int k1_pcie_start_link(struct dw_pcie *pci)
210 {
211 struct k1_pcie *k1 = to_k1_pcie(pci);
212 u32 val;
213
214 /* Stop holding the PHY in reset, and enable link training */
215 regmap_update_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
216 APP_HOLD_PHY_RST | LTSSM_EN, LTSSM_EN);
217
218 /* Enable the MSI interrupt */
219 writel_relaxed(MSI_CTRL_INT, k1->link + INTR_ENABLE);
220
221 /* Top-level interrupt enable */
222 val = readl_relaxed(k1->link + K1_PHY_AHB_IRQ_EN);
223 val |= PCIE_INTERRUPT_EN;
224 writel_relaxed(val, k1->link + K1_PHY_AHB_IRQ_EN);
225
226 return 0;
227 }
228
k1_pcie_stop_link(struct dw_pcie * pci)229 static void k1_pcie_stop_link(struct dw_pcie *pci)
230 {
231 struct k1_pcie *k1 = to_k1_pcie(pci);
232 u32 val;
233
234 /* Disable interrupts */
235 val = readl_relaxed(k1->link + K1_PHY_AHB_IRQ_EN);
236 val &= ~PCIE_INTERRUPT_EN;
237 writel_relaxed(val, k1->link + K1_PHY_AHB_IRQ_EN);
238
239 writel_relaxed(0, k1->link + INTR_ENABLE);
240
241 /* Disable the link and hold the PHY in reset */
242 regmap_update_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
243 APP_HOLD_PHY_RST | LTSSM_EN, APP_HOLD_PHY_RST);
244 }
245
246 static const struct dw_pcie_ops k1_pcie_ops = {
247 .link_up = k1_pcie_link_up,
248 .start_link = k1_pcie_start_link,
249 .stop_link = k1_pcie_stop_link,
250 };
251
k1_pcie_parse_port(struct k1_pcie * k1)252 static int k1_pcie_parse_port(struct k1_pcie *k1)
253 {
254 struct device *dev = k1->pci.dev;
255 struct device_node *root_port;
256 struct phy *phy;
257
258 /* We assume only one root port */
259 root_port = of_get_next_available_child(dev_of_node(dev), NULL);
260 if (!root_port)
261 return -EINVAL;
262
263 phy = devm_of_phy_get(dev, root_port, NULL);
264
265 of_node_put(root_port);
266
267 if (IS_ERR(phy))
268 return PTR_ERR(phy);
269
270 k1->phy = phy;
271
272 return 0;
273 }
274
k1_pcie_probe(struct platform_device * pdev)275 static int k1_pcie_probe(struct platform_device *pdev)
276 {
277 struct device *dev = &pdev->dev;
278 struct k1_pcie *k1;
279 int ret;
280
281 k1 = devm_kzalloc(dev, sizeof(*k1), GFP_KERNEL);
282 if (!k1)
283 return -ENOMEM;
284
285 k1->pmu = syscon_regmap_lookup_by_phandle_args(dev_of_node(dev),
286 SYSCON_APMU, 1,
287 &k1->pmu_off);
288 if (IS_ERR(k1->pmu))
289 return dev_err_probe(dev, PTR_ERR(k1->pmu),
290 "failed to lookup PMU registers\n");
291
292 k1->link = devm_platform_ioremap_resource_byname(pdev, "link");
293 if (IS_ERR(k1->link))
294 return dev_err_probe(dev, PTR_ERR(k1->link),
295 "failed to map \"link\" registers\n");
296
297 k1->pci.dev = dev;
298 k1->pci.ops = &k1_pcie_ops;
299 k1->pci.pp.num_vectors = MAX_MSI_IRQS;
300 dw_pcie_cap_set(&k1->pci, REQ_RES);
301
302 k1->pci.pp.ops = &k1_pcie_host_ops;
303
304 /* Hold the PHY in reset until we start the link */
305 regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
306 APP_HOLD_PHY_RST);
307
308 ret = devm_regulator_get_enable(dev, "vpcie3v3");
309 if (ret)
310 return dev_err_probe(dev, ret,
311 "failed to get \"vpcie3v3\" supply\n");
312
313 pm_runtime_set_active(dev);
314 pm_runtime_no_callbacks(dev);
315 devm_pm_runtime_enable(dev);
316
317 platform_set_drvdata(pdev, k1);
318
319 ret = k1_pcie_parse_port(k1);
320 if (ret)
321 return dev_err_probe(dev, ret, "failed to parse root port\n");
322
323 ret = dw_pcie_host_init(&k1->pci.pp);
324 if (ret)
325 return dev_err_probe(dev, ret, "failed to initialize host\n");
326
327 return 0;
328 }
329
k1_pcie_remove(struct platform_device * pdev)330 static void k1_pcie_remove(struct platform_device *pdev)
331 {
332 struct k1_pcie *k1 = platform_get_drvdata(pdev);
333
334 dw_pcie_host_deinit(&k1->pci.pp);
335 }
336
337 static const struct of_device_id k1_pcie_of_match_table[] = {
338 { .compatible = "spacemit,k1-pcie", },
339 { }
340 };
341 MODULE_DEVICE_TABLE(of, k1_pcie_of_match_table);
342
343 static struct platform_driver k1_pcie_driver = {
344 .probe = k1_pcie_probe,
345 .remove = k1_pcie_remove,
346 .driver = {
347 .name = "spacemit-k1-pcie",
348 .of_match_table = k1_pcie_of_match_table,
349 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
350 },
351 };
352 module_platform_driver(k1_pcie_driver);
353 MODULE_LICENSE("GPL");
354 MODULE_DESCRIPTION("SpacemiT K1 PCIe host driver");
355