]> Git Repo - J-u-boot.git/blob - drivers/pci/pcie_uniphier.c
Subtree merge tag 'v6.11-dts' of dts repo [1] into dts/upstream
[J-u-boot.git] / drivers / pci / pcie_uniphier.c
1 // 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 <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
19 DECLARE_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
80 struct 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
97 static 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
104 static 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
111 static 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
133 static 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
142 static 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
171 static 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
179 static 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
187 static 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
200 static 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
210 static 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
224 static 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
234 static 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
267 static 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
289 static 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
346 out_phy_exit:
347         generic_phy_exit(&priv->phy);
348 out_reset_release:
349         reset_release_all(&priv->rst, 1);
350 out_clk_release:
351         clk_release_all(&priv->clk, 1);
352
353         return ret;
354 }
355
356 static 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
405 static const struct dm_pci_ops uniphier_pcie_ops = {
406         .read_config    = uniphier_pcie_read_config,
407         .write_config   = uniphier_pcie_write_config,
408 };
409
410 static const struct udevice_id uniphier_pcie_ids[] = {
411         { .compatible = "socionext,uniphier-pcie", },
412         { /* Sentinel */ }
413 };
414
415 U_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 };
This page took 0.053502 seconds and 4 git commands to generate.