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