blob: f2edea9899a4004e9c188a288fa772d64f220a39 [file] [log] [blame]
Kunihiko Hayashi741a1f92021-07-06 19:01:09 +09001// SPDX-License-Identifier: GPL-2.0
2/*
3 * pcie_uniphier.c - Socionext UniPhier PCIe driver
4 * Copyright 2019-2021 Socionext, Inc.
5 */
6
7#include <clk.h>
8#include <common.h>
9#include <dm.h>
10#include <dm/device_compat.h>
11#include <generic-phy.h>
12#include <linux/bitfield.h>
13#include <linux/bitops.h>
14#include <linux/compat.h>
15#include <linux/delay.h>
16#include <linux/io.h>
17#include <pci.h>
18#include <reset.h>
19
20DECLARE_GLOBAL_DATA_PTR;
21
22/* DBI registers */
23#define PCIE_LINK_STATUS_REG 0x0080
24#define PCIE_LINK_STATUS_WIDTH_MASK GENMASK(25, 20)
25#define PCIE_LINK_STATUS_SPEED_MASK GENMASK(19, 16)
26
27#define PCIE_MISC_CONTROL_1_OFF 0x08BC
28#define PCIE_DBI_RO_WR_EN BIT(0)
29
30/* DBI iATU registers */
31#define PCIE_ATU_VIEWPORT 0x0900
32#define PCIE_ATU_REGION_INBOUND BIT(31)
33#define PCIE_ATU_REGION_OUTBOUND 0
34#define PCIE_ATU_REGION_INDEX_MASK GENMASK(3, 0)
35
36#define PCIE_ATU_CR1 0x0904
37#define PCIE_ATU_TYPE_MEM 0
38#define PCIE_ATU_TYPE_IO 2
39#define PCIE_ATU_TYPE_CFG0 4
40#define PCIE_ATU_TYPE_CFG1 5
41
42#define PCIE_ATU_CR2 0x0908
43#define PCIE_ATU_ENABLE BIT(31)
44#define PCIE_ATU_MATCH_MODE BIT(30)
45#define PCIE_ATU_BAR_NUM_MASK GENMASK(10, 8)
46
47#define PCIE_ATU_LOWER_BASE 0x090C
48#define PCIE_ATU_UPPER_BASE 0x0910
49#define PCIE_ATU_LIMIT 0x0914
50#define PCIE_ATU_LOWER_TARGET 0x0918
51#define PCIE_ATU_BUS(x) FIELD_PREP(GENMASK(31, 24), x)
52#define PCIE_ATU_DEV(x) FIELD_PREP(GENMASK(23, 19), x)
53#define PCIE_ATU_FUNC(x) FIELD_PREP(GENMASK(18, 16), x)
54#define PCIE_ATU_UPPER_TARGET 0x091C
55
56/* Link Glue registers */
57#define PCL_PINCTRL0 0x002c
58#define PCL_PERST_PLDN_REGEN BIT(12)
59#define PCL_PERST_NOE_REGEN BIT(11)
60#define PCL_PERST_OUT_REGEN BIT(8)
61#define PCL_PERST_PLDN_REGVAL BIT(4)
62#define PCL_PERST_NOE_REGVAL BIT(3)
63#define PCL_PERST_OUT_REGVAL BIT(0)
64
65#define PCL_MODE 0x8000
66#define PCL_MODE_REGEN BIT(8)
67#define PCL_MODE_REGVAL BIT(0)
68
69#define PCL_APP_READY_CTRL 0x8008
70#define PCL_APP_LTSSM_ENABLE BIT(0)
71
72#define PCL_APP_PM0 0x8078
73#define PCL_SYS_AUX_PWR_DET BIT(8)
74
75#define PCL_STATUS_LINK 0x8140
76#define PCL_RDLH_LINK_UP BIT(1)
77#define PCL_XMLH_LINK_UP BIT(0)
78
79#define LINK_UP_TIMEOUT_MS 100
80
81struct uniphier_pcie_priv {
82 void *base;
83 void *dbi_base;
84 void *cfg_base;
85 fdt_size_t cfg_size;
86 struct fdt_resource link_res;
87 struct fdt_resource dbi_res;
88 struct fdt_resource cfg_res;
89
90 struct clk clk;
91 struct reset_ctl rst;
92 struct phy phy;
93
94 struct pci_region io;
95 struct pci_region mem;
96};
97
98static int pcie_dw_get_link_speed(struct uniphier_pcie_priv *priv)
99{
100 u32 val = readl(priv->dbi_base + PCIE_LINK_STATUS_REG);
101
102 return FIELD_GET(PCIE_LINK_STATUS_SPEED_MASK, val);
103}
104
105static int pcie_dw_get_link_width(struct uniphier_pcie_priv *priv)
106{
107 u32 val = readl(priv->dbi_base + PCIE_LINK_STATUS_REG);
108
109 return FIELD_GET(PCIE_LINK_STATUS_WIDTH_MASK, val);
110}
111
112static void pcie_dw_prog_outbound_atu(struct uniphier_pcie_priv *priv,
113 int index, int type, u64 cpu_addr,
114 u64 pci_addr, u32 size)
115{
116 writel(PCIE_ATU_REGION_OUTBOUND
117 | FIELD_PREP(PCIE_ATU_REGION_INDEX_MASK, index),
118 priv->dbi_base + PCIE_ATU_VIEWPORT);
119 writel(lower_32_bits(cpu_addr),
120 priv->dbi_base + PCIE_ATU_LOWER_BASE);
121 writel(upper_32_bits(cpu_addr),
122 priv->dbi_base + PCIE_ATU_UPPER_BASE);
123 writel(lower_32_bits(cpu_addr + size - 1),
124 priv->dbi_base + PCIE_ATU_LIMIT);
125 writel(lower_32_bits(pci_addr),
126 priv->dbi_base + PCIE_ATU_LOWER_TARGET);
127 writel(upper_32_bits(pci_addr),
128 priv->dbi_base + PCIE_ATU_UPPER_TARGET);
129
130 writel(type, priv->dbi_base + PCIE_ATU_CR1);
131 writel(PCIE_ATU_ENABLE, priv->dbi_base + PCIE_ATU_CR2);
132}
133
134static int uniphier_pcie_addr_valid(pci_dev_t bdf, int first_busno)
135{
136 /* accept only device {0,1} on first bus */
137 if ((PCI_BUS(bdf) != first_busno) || (PCI_DEV(bdf) > 1))
138 return -EINVAL;
139
140 return 0;
141}
142
143static int uniphier_pcie_conf_address(const struct udevice *dev, pci_dev_t bdf,
144 uint offset, void **paddr)
145{
146 struct uniphier_pcie_priv *priv = dev_get_priv(dev);
147 u32 busdev;
148 int seq = dev_seq(dev);
149 int ret;
150
151 ret = uniphier_pcie_addr_valid(bdf, seq);
152 if (ret)
153 return ret;
154
155 if ((PCI_BUS(bdf) == seq) && !PCI_DEV(bdf)) {
156 *paddr = (void *)(priv->dbi_base + offset);
157 return 0;
158 }
159
160 busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - seq)
161 | PCIE_ATU_DEV(PCI_DEV(bdf))
162 | PCIE_ATU_FUNC(PCI_FUNC(bdf));
163
164 pcie_dw_prog_outbound_atu(priv, 0,
165 PCIE_ATU_TYPE_CFG0, (u64)priv->cfg_base,
166 busdev, priv->cfg_size);
167 *paddr = (void *)(priv->cfg_base + offset);
168
169 return 0;
170}
171
172static int uniphier_pcie_read_config(const struct udevice *dev, pci_dev_t bdf,
173 uint offset, ulong *valp,
174 enum pci_size_t size)
175{
176 return pci_generic_mmap_read_config(dev, uniphier_pcie_conf_address,
177 bdf, offset, valp, size);
178}
179
180static int uniphier_pcie_write_config(struct udevice *dev, pci_dev_t bdf,
181 uint offset, ulong val,
182 enum pci_size_t size)
183{
184 return pci_generic_mmap_write_config(dev, uniphier_pcie_conf_address,
185 bdf, offset, val, size);
186}
187
188static void uniphier_pcie_ltssm_enable(struct uniphier_pcie_priv *priv,
189 bool enable)
190{
191 u32 val;
192
193 val = readl(priv->base + PCL_APP_READY_CTRL);
194 if (enable)
195 val |= PCL_APP_LTSSM_ENABLE;
196 else
197 val &= ~PCL_APP_LTSSM_ENABLE;
198 writel(val, priv->base + PCL_APP_READY_CTRL);
199}
200
201static int uniphier_pcie_link_up(struct uniphier_pcie_priv *priv)
202{
203 u32 val, mask;
204
205 val = readl(priv->base + PCL_STATUS_LINK);
206 mask = PCL_RDLH_LINK_UP | PCL_XMLH_LINK_UP;
207
208 return (val & mask) == mask;
209}
210
211static int uniphier_pcie_wait_link(struct uniphier_pcie_priv *priv)
212{
213 unsigned long timeout;
214
215 timeout = get_timer(0) + LINK_UP_TIMEOUT_MS;
216
217 while (get_timer(0) < timeout) {
218 if (uniphier_pcie_link_up(priv))
219 return 0;
220 }
221
222 return -ETIMEDOUT;
223}
224
225static int uniphier_pcie_establish_link(struct uniphier_pcie_priv *priv)
226{
227 if (uniphier_pcie_link_up(priv))
228 return 0;
229
230 uniphier_pcie_ltssm_enable(priv, true);
231
232 return uniphier_pcie_wait_link(priv);
233}
234
235static void uniphier_pcie_init_rc(struct uniphier_pcie_priv *priv)
236{
237 u32 val;
238
239 /* set RC mode */
240 val = readl(priv->base + PCL_MODE);
241 val |= PCL_MODE_REGEN;
242 val &= ~PCL_MODE_REGVAL;
243 writel(val, priv->base + PCL_MODE);
244
245 /* use auxiliary power detection */
246 val = readl(priv->base + PCL_APP_PM0);
247 val |= PCL_SYS_AUX_PWR_DET;
248 writel(val, priv->base + PCL_APP_PM0);
249
250 /* assert PERST# */
251 val = readl(priv->base + PCL_PINCTRL0);
252 val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL
253 | PCL_PERST_PLDN_REGVAL);
254 val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN
255 | PCL_PERST_PLDN_REGEN;
256 writel(val, priv->base + PCL_PINCTRL0);
257
258 uniphier_pcie_ltssm_enable(priv, false);
259
260 mdelay(100);
261
262 /* deassert PERST# */
263 val = readl(priv->base + PCL_PINCTRL0);
264 val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN;
265 writel(val, priv->base + PCL_PINCTRL0);
266}
267
268static void uniphier_pcie_setup_rc(struct uniphier_pcie_priv *priv,
269 struct pci_controller *hose)
270{
271 /* Store the IO and MEM windows settings for future use by the ATU */
272 priv->io.phys_start = hose->regions[0].phys_start; /* IO base */
273 priv->io.bus_start = hose->regions[0].bus_start; /* IO_bus_addr */
274 priv->io.size = hose->regions[0].size; /* IO size */
275 priv->mem.phys_start = hose->regions[1].phys_start; /* MEM base */
276 priv->mem.bus_start = hose->regions[1].bus_start; /* MEM_bus_addr */
277 priv->mem.size = hose->regions[1].size; /* MEM size */
278
279 /* outbound: IO */
280 pcie_dw_prog_outbound_atu(priv, 0,
281 PCIE_ATU_TYPE_IO, priv->io.phys_start,
282 priv->io.bus_start, priv->io.size);
283
284 /* outbound: MEM */
285 pcie_dw_prog_outbound_atu(priv, 1,
286 PCIE_ATU_TYPE_MEM, priv->mem.phys_start,
287 priv->mem.bus_start, priv->mem.size);
288}
289
290static int uniphier_pcie_probe(struct udevice *dev)
291{
292 struct uniphier_pcie_priv *priv = dev_get_priv(dev);
293 struct udevice *ctlr = pci_get_controller(dev);
294 struct pci_controller *hose = dev_get_uclass_priv(ctlr);
295 int ret;
296
297 priv->base = map_physmem(priv->link_res.start,
298 fdt_resource_size(&priv->link_res),
299 MAP_NOCACHE);
300 priv->dbi_base = map_physmem(priv->dbi_res.start,
301 fdt_resource_size(&priv->dbi_res),
302 MAP_NOCACHE);
303 priv->cfg_size = fdt_resource_size(&priv->cfg_res);
304 priv->cfg_base = map_physmem(priv->cfg_res.start,
305 priv->cfg_size, MAP_NOCACHE);
306
307 ret = clk_enable(&priv->clk);
308 if (ret) {
309 dev_err(dev, "Failed to enable clk: %d\n", ret);
310 return ret;
311 }
312 ret = reset_deassert(&priv->rst);
313 if (ret) {
314 dev_err(dev, "Failed to deassert reset: %d\n", ret);
315 goto out_clk_release;
316 }
317
318 ret = generic_phy_init(&priv->phy);
319 if (ret) {
320 dev_err(dev, "Failed to initialize phy: %d\n", ret);
321 goto out_reset_release;
322 }
323
324 ret = generic_phy_power_on(&priv->phy);
325 if (ret) {
326 dev_err(dev, "Failed to power on phy: %d\n", ret);
327 goto out_phy_exit;
328 }
329
330 uniphier_pcie_init_rc(priv);
331
332 /* set DBI to read only */
333 writel(0, priv->dbi_base + PCIE_MISC_CONTROL_1_OFF);
334
335 uniphier_pcie_setup_rc(priv, hose);
336
337 if (uniphier_pcie_establish_link(priv)) {
338 printf("PCIE-%d: Link down\n", dev_seq(dev));
339 } else {
340 printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
341 dev_seq(dev), pcie_dw_get_link_speed(priv),
342 pcie_dw_get_link_width(priv), hose->first_busno);
343 }
344
345 return 0;
346
347out_phy_exit:
348 generic_phy_exit(&priv->phy);
349out_reset_release:
350 reset_release_all(&priv->rst, 1);
351out_clk_release:
352 clk_release_all(&priv->clk, 1);
353
354 return ret;
355}
356
357static int uniphier_pcie_of_to_plat(struct udevice *dev)
358{
359 struct uniphier_pcie_priv *priv = dev_get_priv(dev);
360 const void *fdt = gd->fdt_blob;
361 int node = dev_of_offset(dev);
362 int ret;
363
364 ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
365 "link", &priv->link_res);
366 if (ret) {
367 dev_err(dev, "Failed to get link regs: %d\n", ret);
368 return ret;
369 }
370
371 ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
372 "dbi", &priv->dbi_res);
373 if (ret) {
374 dev_err(dev, "Failed to get dbi regs: %d\n", ret);
375 return ret;
376 }
377
378 ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
379 "config", &priv->cfg_res);
380 if (ret) {
381 dev_err(dev, "Failed to get config regs: %d\n", ret);
382 return ret;
383 }
384
385 ret = clk_get_by_index(dev, 0, &priv->clk);
386 if (ret) {
387 dev_err(dev, "Failed to get clocks property: %d\n", ret);
388 return ret;
389 }
390
391 ret = reset_get_by_index(dev, 0, &priv->rst);
392 if (ret) {
393 dev_err(dev, "Failed to get resets property: %d\n", ret);
394 return ret;
395 }
396
397 ret = generic_phy_get_by_index(dev, 0, &priv->phy);
398 if (ret) {
399 dev_err(dev, "Failed to get phy property: %d\n", ret);
400 return ret;
401 }
402
403 return 0;
404}
405
406static const struct dm_pci_ops uniphier_pcie_ops = {
407 .read_config = uniphier_pcie_read_config,
408 .write_config = uniphier_pcie_write_config,
409};
410
411static const struct udevice_id uniphier_pcie_ids[] = {
412 { .compatible = "socionext,uniphier-pcie", },
413 { /* Sentinel */ }
414};
415
416U_BOOT_DRIVER(pcie_uniphier) = {
417 .name = "uniphier-pcie",
418 .id = UCLASS_PCI,
419 .of_match = uniphier_pcie_ids,
420 .probe = uniphier_pcie_probe,
421 .ops = &uniphier_pcie_ops,
422 .of_to_plat = uniphier_pcie_of_to_plat,
423 .priv_auto = sizeof(struct uniphier_pcie_priv),
424};