]> Git Repo - J-u-boot.git/blob - drivers/pci/pcie-xilinx-nwl.c
7ef2bdf57b560b2884d71bb0f62c46cfee6e938e
[J-u-boot.git] / drivers / pci / pcie-xilinx-nwl.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * PCIe host bridge driver for Xilinx / AMD ZynqMP NWL PCIe Bridge
4  *
5  * Based on the Linux driver which is:
6  * (C) Copyright 2014 - 2015, Xilinx, Inc.
7  *
8  * Author: Stefan Roese <[email protected]>
9  */
10
11 #include <clk.h>
12 #include <dm.h>
13 #include <dm/device_compat.h>
14 #include <dm/devres.h>
15 #include <mapmem.h>
16 #include <pci.h>
17 #include <linux/delay.h>
18 #include <linux/io.h>
19 #include <linux/ioport.h>
20
21 /* Bridge core config registers */
22 #define BRCFG_PCIE_RX0                  0x00000000
23 #define BRCFG_PCIE_RX1                  0x00000004
24 #define BRCFG_INTERRUPT                 0x00000010
25 #define BRCFG_PCIE_RX_MSG_FILTER        0x00000020
26
27 /* Egress - Bridge translation registers */
28 #define E_BREG_CAPABILITIES             0x00000200
29 #define E_BREG_CONTROL                  0x00000208
30 #define E_BREG_BASE_LO                  0x00000210
31 #define E_BREG_BASE_HI                  0x00000214
32 #define E_ECAM_CAPABILITIES             0x00000220
33 #define E_ECAM_CONTROL                  0x00000228
34 #define E_ECAM_BASE_LO                  0x00000230
35 #define E_ECAM_BASE_HI                  0x00000234
36
37 #define I_ISUB_CONTROL                  0x000003E8
38 #define SET_ISUB_CONTROL                BIT(0)
39 /* Rxed msg fifo  - Interrupt status registers */
40 #define MSGF_MISC_STATUS                0x00000400
41 #define MSGF_MISC_MASK                  0x00000404
42 #define MSGF_LEG_STATUS                 0x00000420
43 #define MSGF_LEG_MASK                   0x00000424
44 #define MSGF_MSI_STATUS_LO              0x00000440
45 #define MSGF_MSI_STATUS_HI              0x00000444
46 #define MSGF_MSI_MASK_LO                0x00000448
47 #define MSGF_MSI_MASK_HI                0x0000044C
48
49 /* Msg filter mask bits */
50 #define CFG_ENABLE_PM_MSG_FWD           BIT(1)
51 #define CFG_ENABLE_INT_MSG_FWD          BIT(2)
52 #define CFG_ENABLE_ERR_MSG_FWD          BIT(3)
53 #define CFG_ENABLE_MSG_FILTER_MASK      (CFG_ENABLE_PM_MSG_FWD |        \
54                                          CFG_ENABLE_INT_MSG_FWD |       \
55                                          CFG_ENABLE_ERR_MSG_FWD)
56
57 /* Misc interrupt status mask bits */
58 #define MSGF_MISC_SR_RXMSG_AVAIL        BIT(0)
59 #define MSGF_MISC_SR_RXMSG_OVER         BIT(1)
60 #define MSGF_MISC_SR_SLAVE_ERR          BIT(4)
61 #define MSGF_MISC_SR_MASTER_ERR         BIT(5)
62 #define MSGF_MISC_SR_I_ADDR_ERR         BIT(6)
63 #define MSGF_MISC_SR_E_ADDR_ERR         BIT(7)
64 #define MSGF_MISC_SR_FATAL_AER          BIT(16)
65 #define MSGF_MISC_SR_NON_FATAL_AER      BIT(17)
66 #define MSGF_MISC_SR_CORR_AER           BIT(18)
67 #define MSGF_MISC_SR_UR_DETECT          BIT(20)
68 #define MSGF_MISC_SR_NON_FATAL_DEV      BIT(22)
69 #define MSGF_MISC_SR_FATAL_DEV          BIT(23)
70 #define MSGF_MISC_SR_LINK_DOWN          BIT(24)
71 #define MSGF_MSIC_SR_LINK_AUTO_BWIDTH   BIT(25)
72 #define MSGF_MSIC_SR_LINK_BWIDTH        BIT(26)
73
74 #define MSGF_MISC_SR_MASKALL            (MSGF_MISC_SR_RXMSG_AVAIL |     \
75                                          MSGF_MISC_SR_RXMSG_OVER |      \
76                                          MSGF_MISC_SR_SLAVE_ERR |       \
77                                          MSGF_MISC_SR_MASTER_ERR |      \
78                                          MSGF_MISC_SR_I_ADDR_ERR |      \
79                                          MSGF_MISC_SR_E_ADDR_ERR |      \
80                                          MSGF_MISC_SR_FATAL_AER |       \
81                                          MSGF_MISC_SR_NON_FATAL_AER |   \
82                                          MSGF_MISC_SR_CORR_AER |        \
83                                          MSGF_MISC_SR_UR_DETECT |       \
84                                          MSGF_MISC_SR_NON_FATAL_DEV |   \
85                                          MSGF_MISC_SR_FATAL_DEV |       \
86                                          MSGF_MISC_SR_LINK_DOWN |       \
87                                          MSGF_MSIC_SR_LINK_AUTO_BWIDTH | \
88                                          MSGF_MSIC_SR_LINK_BWIDTH)
89
90 /* Legacy interrupt status mask bits */
91 #define MSGF_LEG_SR_INTA                BIT(0)
92 #define MSGF_LEG_SR_INTB                BIT(1)
93 #define MSGF_LEG_SR_INTC                BIT(2)
94 #define MSGF_LEG_SR_INTD                BIT(3)
95 #define MSGF_LEG_SR_MASKALL             (MSGF_LEG_SR_INTA | MSGF_LEG_SR_INTB | \
96                                          MSGF_LEG_SR_INTC | MSGF_LEG_SR_INTD)
97
98 /* MSI interrupt status mask bits */
99 #define MSGF_MSI_SR_LO_MASK             GENMASK(31, 0)
100 #define MSGF_MSI_SR_HI_MASK             GENMASK(31, 0)
101
102 /* Bridge config interrupt mask */
103 #define BRCFG_INTERRUPT_MASK            BIT(0)
104 #define BREG_PRESENT                    BIT(0)
105 #define BREG_ENABLE                     BIT(0)
106 #define BREG_ENABLE_FORCE               BIT(1)
107
108 /* E_ECAM status mask bits */
109 #define E_ECAM_PRESENT                  BIT(0)
110 #define E_ECAM_CR_ENABLE                BIT(0)
111 #define E_ECAM_SIZE_LOC                 GENMASK(20, 16)
112 #define E_ECAM_SIZE_SHIFT               16
113 #define NWL_ECAM_VALUE_DEFAULT          12
114
115 #define CFG_DMA_REG_BAR                 GENMASK(2, 0)
116 #define CFG_PCIE_CACHE                  GENMASK(7, 0)
117
118 /* Readin the PS_LINKUP */
119 #define PS_LINKUP_OFFSET                0x00000238
120 #define PCIE_PHY_LINKUP_BIT             BIT(0)
121 #define PHY_RDY_LINKUP_BIT              BIT(1)
122
123 /* Parameters for the waiting for link up routine */
124 #define LINK_WAIT_MAX_RETRIES          10
125 #define LINK_WAIT_USLEEP_MIN           90000
126 #define LINK_WAIT_USLEEP_MAX           100000
127
128 struct nwl_pcie {
129         struct udevice *dev;
130         void __iomem *breg_base;
131         void __iomem *pcireg_base;
132         void __iomem *ecam_base;
133         phys_addr_t phys_breg_base;     /* Physical Bridge Register Base */
134         phys_addr_t phys_ecam_base;     /* Physical Configuration Base */
135         u32 ecam_value;
136 };
137
138 static int nwl_pcie_config_address(const struct udevice *bus,
139                                    pci_dev_t bdf, uint offset,
140                                    void **paddress)
141 {
142         struct nwl_pcie *pcie = dev_get_priv(bus);
143         void *addr;
144
145         addr = pcie->ecam_base;
146         addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf) - dev_seq(bus),
147                                  PCI_DEV(bdf), PCI_FUNC(bdf), offset);
148         *paddress = addr;
149
150         return 0;
151 }
152
153 static int nwl_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
154                                 uint offset, ulong *valuep,
155                                 enum pci_size_t size)
156 {
157         return pci_generic_mmap_read_config(bus, nwl_pcie_config_address,
158                                             bdf, offset, valuep, size);
159 }
160
161 static int nwl_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
162                                  uint offset, ulong value,
163                                  enum pci_size_t size)
164 {
165         return pci_generic_mmap_write_config(bus, nwl_pcie_config_address,
166                                              bdf, offset, value, size);
167 }
168
169 static const struct dm_pci_ops nwl_pcie_ops = {
170         .read_config = nwl_pcie_read_config,
171         .write_config = nwl_pcie_write_config,
172 };
173
174 static inline u32 nwl_bridge_readl(struct nwl_pcie *pcie, u32 off)
175 {
176         return readl(pcie->breg_base + off);
177 }
178
179 static inline void nwl_bridge_writel(struct nwl_pcie *pcie, u32 val, u32 off)
180 {
181         writel(val, pcie->breg_base + off);
182 }
183
184 static bool nwl_pcie_link_up(struct nwl_pcie *pcie)
185 {
186         if (readl(pcie->pcireg_base + PS_LINKUP_OFFSET) & PCIE_PHY_LINKUP_BIT)
187                 return true;
188         return false;
189 }
190
191 static bool nwl_phy_link_up(struct nwl_pcie *pcie)
192 {
193         if (readl(pcie->pcireg_base + PS_LINKUP_OFFSET) & PHY_RDY_LINKUP_BIT)
194                 return true;
195         return false;
196 }
197
198 static int nwl_wait_for_link(struct nwl_pcie *pcie)
199 {
200         struct udevice *dev = pcie->dev;
201         int retries;
202
203         /* check if the link is up or not */
204         for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
205                 if (nwl_phy_link_up(pcie))
206                         return 0;
207                 udelay(LINK_WAIT_USLEEP_MIN);
208         }
209
210         dev_warn(dev, "PHY link never came up\n");
211         return -ETIMEDOUT;
212 }
213
214 static int nwl_pcie_bridge_init(struct nwl_pcie *pcie)
215 {
216         struct udevice *dev = pcie->dev;
217         u32 breg_val, ecam_val;
218         int err;
219
220         breg_val = nwl_bridge_readl(pcie, E_BREG_CAPABILITIES) & BREG_PRESENT;
221         if (!breg_val) {
222                 dev_err(dev, "BREG is not present\n");
223                 return breg_val;
224         }
225
226         /* Write bridge_off to breg base */
227         nwl_bridge_writel(pcie, lower_32_bits(pcie->phys_breg_base),
228                           E_BREG_BASE_LO);
229         nwl_bridge_writel(pcie, upper_32_bits(pcie->phys_breg_base),
230                           E_BREG_BASE_HI);
231
232         /* Enable BREG */
233         nwl_bridge_writel(pcie, ~BREG_ENABLE_FORCE & BREG_ENABLE,
234                           E_BREG_CONTROL);
235
236         /* Disable DMA channel registers */
237         nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, BRCFG_PCIE_RX0) |
238                           CFG_DMA_REG_BAR, BRCFG_PCIE_RX0);
239
240         /* Enable Ingress subtractive decode translation */
241         nwl_bridge_writel(pcie, SET_ISUB_CONTROL, I_ISUB_CONTROL);
242
243         /* Enable msg filtering details */
244         nwl_bridge_writel(pcie, CFG_ENABLE_MSG_FILTER_MASK,
245                           BRCFG_PCIE_RX_MSG_FILTER);
246
247         err = nwl_wait_for_link(pcie);
248         if (err)
249                 return err;
250
251         ecam_val = nwl_bridge_readl(pcie, E_ECAM_CAPABILITIES) & E_ECAM_PRESENT;
252         if (!ecam_val) {
253                 dev_err(dev, "ECAM is not present\n");
254                 return ecam_val;
255         }
256
257         /* Enable ECAM */
258         nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, E_ECAM_CONTROL) |
259                           E_ECAM_CR_ENABLE, E_ECAM_CONTROL);
260
261         nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, E_ECAM_CONTROL) |
262                           (pcie->ecam_value << E_ECAM_SIZE_SHIFT),
263                           E_ECAM_CONTROL);
264
265         nwl_bridge_writel(pcie, lower_32_bits(pcie->phys_ecam_base),
266                           E_ECAM_BASE_LO);
267         nwl_bridge_writel(pcie, upper_32_bits(pcie->phys_ecam_base),
268                           E_ECAM_BASE_HI);
269
270         if (nwl_pcie_link_up(pcie))
271                 dev_info(dev, "Link is UP\n");
272         else
273                 dev_info(dev, "Link is DOWN\n");
274
275         /* Disable all misc interrupts */
276         nwl_bridge_writel(pcie, (u32)~MSGF_MISC_SR_MASKALL, MSGF_MISC_MASK);
277
278         /* Clear pending misc interrupts */
279         nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, MSGF_MISC_STATUS) &
280                           MSGF_MISC_SR_MASKALL, MSGF_MISC_STATUS);
281
282         /* Disable all legacy interrupts */
283         nwl_bridge_writel(pcie, (u32)~MSGF_LEG_SR_MASKALL, MSGF_LEG_MASK);
284
285         /* Clear pending legacy interrupts */
286         nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, MSGF_LEG_STATUS) &
287                           MSGF_LEG_SR_MASKALL, MSGF_LEG_STATUS);
288
289         return 0;
290 }
291
292 static int nwl_pcie_parse_dt(struct nwl_pcie *pcie)
293 {
294         struct udevice *dev = pcie->dev;
295         struct resource res;
296         int ret;
297
298         ret = dev_read_resource_byname(dev, "breg", &res);
299         if (ret)
300                 return ret;
301         pcie->breg_base = devm_ioremap(dev, res.start, resource_size(&res));
302         if (IS_ERR(pcie->breg_base))
303                 return PTR_ERR(pcie->breg_base);
304         pcie->phys_breg_base = res.start;
305
306         ret = dev_read_resource_byname(dev, "cfg", &res);
307         if (ret)
308                 return ret;
309         pcie->ecam_base = devm_ioremap(dev, res.start, resource_size(&res));
310         if (IS_ERR(pcie->ecam_base))
311                 return PTR_ERR(pcie->ecam_base);
312         pcie->phys_ecam_base = res.start;
313
314         return 0;
315 }
316
317 static int nwl_pcie_probe(struct udevice *dev)
318 {
319         struct nwl_pcie *pcie = dev_get_priv(dev);
320         int err;
321
322         pcie->dev = dev;
323         pcie->ecam_value = NWL_ECAM_VALUE_DEFAULT;
324
325         err = nwl_pcie_parse_dt(pcie);
326         if (err) {
327                 dev_err(dev, "Parsing DT failed\n");
328                 return err;
329         }
330
331         err = nwl_pcie_bridge_init(pcie);
332         if (err) {
333                 dev_err(dev, "HW Initialization failed\n");
334                 return err;
335         }
336
337         return 0;
338 }
339
340 static const struct udevice_id nwl_pcie_of_match[] = {
341         { .compatible = "xlnx,nwl-pcie-2.11", },
342         { /* sentinel */ }
343 };
344
345 U_BOOT_DRIVER(nwl_pcie) = {
346         .name = "nwl-pcie",
347         .id = UCLASS_PCI,
348         .of_match = nwl_pcie_of_match,
349         .probe = nwl_pcie_probe,
350         .priv_auto = sizeof(struct nwl_pcie),
351         .ops = &nwl_pcie_ops,
352 };
This page took 0.044289 seconds and 4 git commands to generate.