1 // SPDX-License-Identifier: ISC
2 /* Copyright (C) 2020 MediaTek Inc.
3 *
4 * Author: Ryder Lee <ryder.lee@mediatek.com>
5 */
6
7 #if defined(__FreeBSD__)
8 #define LINUXKPI_PARAM_PREFIX mt7915_pci_
9 #endif
10
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/pci.h>
14
15 #include "mt7915.h"
16 #include "mac.h"
17 #include "../trace.h"
18
19 #if defined(__linux__)
20 static LIST_HEAD(hif_list);
21 #elif defined(__FreeBSD__)
22 static LINUX_LIST_HEAD(hif_list);
23 #endif
24 static DEFINE_SPINLOCK(hif_lock);
25 static u32 hif_idx;
26
27 static const struct pci_device_id mt7915_pci_device_table[] = {
28 { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7915) },
29 { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7906) },
30 { },
31 };
32
33 static const struct pci_device_id mt7915_hif_device_table[] = {
34 { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7916) },
35 { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x790a) },
36 { },
37 };
38
mt7915_pci_get_hif2(u32 idx)39 static struct mt7915_hif *mt7915_pci_get_hif2(u32 idx)
40 {
41 struct mt7915_hif *hif;
42 u32 val;
43
44 spin_lock_bh(&hif_lock);
45
46 list_for_each_entry(hif, &hif_list, list) {
47 #if defined(__linux__)
48 val = readl(hif->regs + MT_PCIE_RECOG_ID);
49 #elif defined(__FreeBSD__)
50 val = readl((u8 *)hif->regs + MT_PCIE_RECOG_ID);
51 #endif
52 val &= MT_PCIE_RECOG_ID_MASK;
53 if (val != idx)
54 continue;
55
56 get_device(hif->dev);
57 goto out;
58 }
59 hif = NULL;
60
61 out:
62 spin_unlock_bh(&hif_lock);
63
64 return hif;
65 }
66
mt7915_put_hif2(struct mt7915_hif * hif)67 static void mt7915_put_hif2(struct mt7915_hif *hif)
68 {
69 if (!hif)
70 return;
71
72 put_device(hif->dev);
73 }
74
mt7915_pci_init_hif2(struct pci_dev * pdev)75 static struct mt7915_hif *mt7915_pci_init_hif2(struct pci_dev *pdev)
76 {
77 struct pci_dev *tmp_pdev;
78
79 hif_idx++;
80
81 #if defined(__linux__)
82 tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL);
83 #elif defined(__FreeBSD__)
84 tmp_pdev = linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL);
85 #endif
86 if (!tmp_pdev) {
87 #if defined(__linux__)
88 tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x790a, NULL);
89 #elif defined(__FreeBSD__)
90 tmp_pdev = linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x790a, NULL);
91 #endif
92 if (!tmp_pdev)
93 return NULL;
94 }
95 pci_dev_put(tmp_pdev);
96
97 writel(hif_idx | MT_PCIE_RECOG_ID_SEM,
98 #if defined(__linux__)
99 pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID);
100 #elif defined(__FreeBSD__)
101 (u8 *)(pcim_iomap_table(pdev)[0]) + MT_PCIE_RECOG_ID);
102 #endif
103
104 return mt7915_pci_get_hif2(hif_idx);
105 }
106
mt7915_pci_hif2_probe(struct pci_dev * pdev)107 static int mt7915_pci_hif2_probe(struct pci_dev *pdev)
108 {
109 struct mt7915_hif *hif;
110
111 hif = devm_kzalloc(&pdev->dev, sizeof(*hif), GFP_KERNEL);
112 if (!hif)
113 return -ENOMEM;
114
115 hif->dev = &pdev->dev;
116 hif->regs = pcim_iomap_table(pdev)[0];
117 hif->irq = pdev->irq;
118 spin_lock_bh(&hif_lock);
119 list_add(&hif->list, &hif_list);
120 spin_unlock_bh(&hif_lock);
121 pci_set_drvdata(pdev, hif);
122
123 return 0;
124 }
125
mt7915_pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)126 static int mt7915_pci_probe(struct pci_dev *pdev,
127 const struct pci_device_id *id)
128 {
129 struct mt7915_hif *hif2 = NULL;
130 struct mt7915_dev *dev;
131 struct mt76_dev *mdev;
132 int irq;
133 int ret;
134
135 ret = pcim_enable_device(pdev);
136 if (ret)
137 return ret;
138
139 ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
140 if (ret)
141 return ret;
142
143 pci_set_master(pdev);
144
145 ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
146 if (ret)
147 return ret;
148
149 mt76_pci_disable_aspm(pdev);
150
151 if (id->device == 0x7916 || id->device == 0x790a)
152 return mt7915_pci_hif2_probe(pdev);
153
154 dev = mt7915_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0],
155 id->device);
156 if (IS_ERR(dev))
157 return PTR_ERR(dev);
158
159 mdev = &dev->mt76;
160 mt7915_wfsys_reset(dev);
161 hif2 = mt7915_pci_init_hif2(pdev);
162
163 ret = mt7915_mmio_wed_init(dev, pdev, true, &irq);
164 if (ret < 0)
165 goto free_wed_or_irq_vector;
166
167 if (!ret) {
168 hif2 = mt7915_pci_init_hif2(pdev);
169
170 ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
171 if (ret < 0)
172 goto free_device;
173
174 irq = pdev->irq;
175 }
176
177 ret = devm_request_irq(mdev->dev, irq, mt7915_irq_handler,
178 IRQF_SHARED, KBUILD_MODNAME, dev);
179 if (ret)
180 goto free_wed_or_irq_vector;
181
182 /* master switch of PCIe tnterrupt enable */
183 mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
184
185 if (hif2) {
186 dev->hif2 = hif2;
187
188 mt76_wr(dev, MT_INT1_MASK_CSR, 0);
189 /* master switch of PCIe tnterrupt enable */
190 if (is_mt7915(mdev))
191 mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
192 else
193 mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0xff);
194
195 ret = devm_request_irq(mdev->dev, dev->hif2->irq,
196 mt7915_irq_handler, IRQF_SHARED,
197 KBUILD_MODNAME "-hif", dev);
198 if (ret)
199 goto free_hif2;
200 }
201
202 ret = mt7915_register_device(dev);
203 if (ret)
204 goto free_hif2_irq;
205
206 return 0;
207
208 free_hif2_irq:
209 if (dev->hif2)
210 devm_free_irq(mdev->dev, dev->hif2->irq, dev);
211 free_hif2:
212 if (dev->hif2)
213 put_device(dev->hif2->dev);
214 devm_free_irq(mdev->dev, irq, dev);
215 free_wed_or_irq_vector:
216 if (mtk_wed_device_active(&mdev->mmio.wed))
217 mtk_wed_device_detach(&mdev->mmio.wed);
218 else
219 pci_free_irq_vectors(pdev);
220 free_device:
221 mt76_free_device(&dev->mt76);
222
223 return ret;
224 }
225
mt7915_hif_remove(struct pci_dev * pdev)226 static void mt7915_hif_remove(struct pci_dev *pdev)
227 {
228 struct mt7915_hif *hif = pci_get_drvdata(pdev);
229
230 list_del(&hif->list);
231 }
232
mt7915_pci_remove(struct pci_dev * pdev)233 static void mt7915_pci_remove(struct pci_dev *pdev)
234 {
235 struct mt76_dev *mdev;
236 struct mt7915_dev *dev;
237
238 mdev = pci_get_drvdata(pdev);
239 dev = container_of(mdev, struct mt7915_dev, mt76);
240 mt7915_put_hif2(dev->hif2);
241 mt7915_unregister_device(dev);
242 }
243
244 struct pci_driver mt7915_hif_driver = {
245 .name = KBUILD_MODNAME "_hif",
246 .id_table = mt7915_hif_device_table,
247 .probe = mt7915_pci_probe,
248 .remove = mt7915_hif_remove,
249 };
250
251 struct pci_driver mt7915_pci_driver = {
252 .name = KBUILD_MODNAME,
253 .id_table = mt7915_pci_device_table,
254 .probe = mt7915_pci_probe,
255 .remove = mt7915_pci_remove,
256 };
257
258 MODULE_DEVICE_TABLE(pci, mt7915_pci_device_table);
259 MODULE_DEVICE_TABLE(pci, mt7915_hif_device_table);
260 MODULE_FIRMWARE(MT7915_FIRMWARE_WA);
261 MODULE_FIRMWARE(MT7915_FIRMWARE_WM);
262 MODULE_FIRMWARE(MT7915_ROM_PATCH);
263 MODULE_FIRMWARE(MT7916_FIRMWARE_WA);
264 MODULE_FIRMWARE(MT7916_FIRMWARE_WM);
265 MODULE_FIRMWARE(MT7916_ROM_PATCH);
266 #if defined(__FreeBSD__)
267 MODULE_VERSION(mt7915_pci, 1);
268 MODULE_DEPEND(mt7915_pci, linuxkpi, 1, 1, 1);
269 MODULE_DEPEND(mt7915_pci, linuxkpi_wlan, 1, 1, 1);
270 MODULE_DEPEND(mt7915_pci, mt76_core, 1, 1, 1);
271 #endif
272