1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-09-23     GuEe-GUI     first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 
14 #define DBG_TAG "pcie.dw.platfrom"
15 #define DBG_LVL DBG_INFO
16 #include <rtdbg.h>
17 
18 #include "pcie-dw.h"
19 
20 struct dw_dw_platform_pcie_soc_data
21 {
22     enum dw_pcie_device_mode mode;
23 };
24 
25 struct dw_platform_pcie
26 {
27     struct dw_pcie *pci;
28     struct rt_syscon *regmap;
29     const struct dw_dw_platform_pcie_soc_data *soc_data;
30 };
31 
dw_platform_pcie_host_init(struct dw_pcie_port * port)32 static rt_err_t dw_platform_pcie_host_init(struct dw_pcie_port *port)
33 {
34     struct dw_pcie *pci = to_dw_pcie_from_port(port);
35 
36     dw_pcie_setup_rc(port);
37     dw_pcie_wait_for_link(pci);
38     dw_pcie_msi_init(port);
39 
40     return RT_EOK;
41 }
42 
dw_platform_set_irq_count(struct dw_pcie_port * pp)43 static void dw_platform_set_irq_count(struct dw_pcie_port *pp)
44 {
45     pp->irq_count = MAX_MSI_IRQS;
46 }
47 
48 static const struct dw_pcie_host_ops dw_platform_pcie_host_ops =
49 {
50     .host_init = dw_platform_pcie_host_init,
51     .set_irq_count = dw_platform_set_irq_count,
52 };
53 
dw_platform_pcie_establish_link(struct dw_pcie * pci)54 static rt_err_t dw_platform_pcie_establish_link(struct dw_pcie *pci)
55 {
56     return RT_EOK;
57 }
58 
59 static const struct dw_pcie_ops dw_platform_pcie_ops =
60 {
61     .start_link = dw_platform_pcie_establish_link,
62 };
63 
dw_platform_pcie_ep_init(struct dw_pcie_ep * ep)64 static rt_err_t dw_platform_pcie_ep_init(struct dw_pcie_ep *ep)
65 {
66     struct dw_pcie *pci = to_dw_pcie_from_endpoint(ep);
67 
68     for (int bar = 0; bar < PCI_STD_NUM_BARS; ++bar)
69     {
70         dw_pcie_ep_reset_bar(pci, bar);
71     }
72 
73     return RT_EOK;
74 }
75 
dw_platform_pcie_ep_raise_irq(struct dw_pcie_ep * ep,rt_uint8_t func_no,enum rt_pci_ep_irq type,unsigned irq)76 static rt_err_t dw_platform_pcie_ep_raise_irq(struct dw_pcie_ep *ep,
77         rt_uint8_t func_no, enum rt_pci_ep_irq type, unsigned irq)
78 {
79     switch (type)
80     {
81     case RT_PCI_EP_IRQ_LEGACY:
82         return dw_pcie_ep_raise_legacy_irq(ep, func_no);
83 
84     case RT_PCI_EP_IRQ_MSI:
85         return dw_pcie_ep_raise_msi_irq(ep, func_no, irq);
86 
87     case RT_PCI_EP_IRQ_MSIX:
88         return dw_pcie_ep_raise_msix_irq(ep, func_no, irq);
89 
90     default:
91         LOG_E("Unknown IRQ type = %d", type);
92     }
93 
94     return RT_EOK;
95 }
96 
97 static const struct dw_pcie_ep_ops dw_platform_pcie_ep_ops =
98 {
99     .ep_init = dw_platform_pcie_ep_init,
100     .raise_irq = dw_platform_pcie_ep_raise_irq,
101 };
102 
dw_platform_add_pcie_port(struct dw_platform_pcie * plat_pcie,struct rt_device * dev)103 static rt_err_t dw_platform_add_pcie_port(struct dw_platform_pcie *plat_pcie,
104         struct rt_device *dev)
105 {
106     rt_err_t err;
107     struct dw_pcie *pci = plat_pcie->pci;
108     struct dw_pcie_port *port = &pci->port;
109 
110     port->sys_irq = rt_dm_dev_get_irq(dev, 1);
111 
112     if (port->sys_irq < 0)
113     {
114         return port->sys_irq;
115     }
116 
117 #ifdef RT_PCI_MSI
118     port->msi_irq = rt_dm_dev_get_irq(dev, 0);
119 
120     if (port->msi_irq < 0)
121     {
122         return port->msi_irq;
123     }
124 #endif
125 
126     port->ops = &dw_platform_pcie_host_ops;
127 
128     if ((err = dw_pcie_host_init(port)))
129     {
130         LOG_E("Failed to initialize host");
131         return err;
132     }
133 
134     return RT_EOK;
135 }
136 
dw_platform_add_pcie_ep(struct dw_platform_pcie * plat_pcie,struct rt_device * dev)137 static rt_err_t dw_platform_add_pcie_ep(struct dw_platform_pcie *plat_pcie,
138         struct rt_device *dev)
139 {
140     rt_err_t err;
141     struct dw_pcie *pci = plat_pcie->pci;
142     struct dw_pcie_ep *ep = &pci->endpoint;
143 
144     pci->dbi_base2 = rt_dm_dev_iomap_by_name(dev, "dbi2");
145 
146     if (!pci->dbi_base2)
147     {
148         return -RT_EIO;
149     }
150 
151     err = rt_dm_dev_get_address_by_name(dev, "addr_space", &ep->aspace, &ep->aspace_size);
152 
153     if (err)
154     {
155         rt_iounmap(pci->dbi_base2);
156         return err;
157     }
158 
159     ep->ops = &dw_platform_pcie_ep_ops;
160 
161     if ((err = dw_pcie_ep_init(ep)))
162     {
163         LOG_E("Failed to initialize endpoint");
164         return err;
165     }
166 
167     return RT_EOK;
168 }
169 
dw_platform_pcie_probe(struct rt_platform_device * pdev)170 static rt_err_t dw_platform_pcie_probe(struct rt_platform_device *pdev)
171 {
172     rt_err_t err;
173     struct dw_pcie *pci = RT_NULL;
174     struct dw_platform_pcie *plat_pcie;
175     struct rt_device *dev = &pdev->parent;
176 
177     if (!(plat_pcie = rt_calloc(1, sizeof(*plat_pcie))))
178     {
179         return -RT_ENOMEM;
180     }
181 
182     if (!(pci = rt_calloc(1, sizeof(*pci))))
183     {
184         err = -RT_ENOMEM;
185         goto _fail;
186     }
187 
188     plat_pcie->pci = pci;
189     plat_pcie->soc_data = pdev->id->data;
190 
191     pci->dev = dev;
192     pci->ops = &dw_platform_pcie_ops;
193     pci->dbi_base = rt_dm_dev_iomap_by_name(dev, "dbi");
194 
195     if (!pci->dbi_base)
196     {
197         err = -RT_EIO;
198         goto _fail;
199     }
200 
201     dev->user_data = plat_pcie;
202 
203     switch (plat_pcie->soc_data->mode)
204     {
205     case DW_PCIE_RC_TYPE:
206         if (!RT_KEY_ENABLED(RT_PCI_DW_HOST))
207         {
208             err = -RT_ENOSYS;
209             goto _fail;
210         }
211 
212         if ((err = dw_platform_add_pcie_port(plat_pcie, dev)))
213         {
214             goto _fail;
215         }
216         break;
217 
218     case DW_PCIE_EP_TYPE:
219         if (!RT_KEY_ENABLED(RT_PCI_DW_EP))
220         {
221             err = -RT_ENOSYS;
222             goto _fail;
223         }
224 
225         if ((err = dw_platform_add_pcie_ep(plat_pcie, dev)))
226         {
227             goto _fail;
228         }
229         break;
230 
231     default:
232         LOG_E("Invalid device type %d", plat_pcie->soc_data->mode);
233         err = -RT_EINVAL;
234         goto _fail;
235     }
236 
237     return RT_EOK;
238 
239 _fail:
240     if (pci)
241     {
242         if (pci->dbi_base)
243         {
244             rt_iounmap(pci->dbi_base);
245         }
246 
247         rt_free(pci);
248     }
249 
250     rt_free(plat_pcie);
251 
252     return err;
253 }
254 
dw_platform_pcie_remove(struct rt_platform_device * pdev)255 static rt_err_t dw_platform_pcie_remove(struct rt_platform_device *pdev)
256 {
257     struct dw_platform_pcie *plat_pcie = pdev->parent.user_data;
258 
259     rt_pci_host_bridge_remove(plat_pcie->pci->port.bridge);
260     dw_pcie_host_free(&plat_pcie->pci->port);
261 
262     rt_iounmap(plat_pcie->pci->dbi_base);
263     rt_free(plat_pcie->pci);
264 
265     rt_free(plat_pcie);
266 
267     return RT_EOK;
268 }
269 
270 static const struct dw_dw_platform_pcie_soc_data dw_platform_pcie_rc_soc_data =
271 {
272     .mode = DW_PCIE_RC_TYPE,
273 };
274 
275 static const struct dw_dw_platform_pcie_soc_data dw_platform_pcie_ep_soc_data =
276 {
277     .mode = DW_PCIE_EP_TYPE,
278 };
279 
280 static const struct rt_ofw_node_id dw_platform_pcie_ofw_ids[] =
281 {
282     { .compatible = "snps,dw-pcie", .data = &dw_platform_pcie_rc_soc_data },
283     { .compatible = "snps,dw-pcie-ep", .data = &dw_platform_pcie_ep_soc_data },
284     { /* sentinel */ }
285 };
286 
287 static struct rt_platform_driver dw_platform_pcie_driver =
288 {
289     .name = "dw-pcie",
290     .ids = dw_platform_pcie_ofw_ids,
291 
292     .probe = dw_platform_pcie_probe,
293     .remove = dw_platform_pcie_remove,
294 };
295 RT_PLATFORM_DRIVER_EXPORT(dw_platform_pcie_driver);
296