1// SPDX-License-Identifier: ISC
2/*
3 * Copyright (C) 2022 MediaTek Inc.
4 */
5
6#if defined(__FreeBSD__)
7#define	LINUXKPI_PARAM_PREFIX   mt7996_pci_
8#endif
9
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/pci.h>
13
14#include "mt7996.h"
15#include "mac.h"
16#include "../trace.h"
17
18static LIST_HEAD(hif_list);
19static DEFINE_SPINLOCK(hif_lock);
20static u32 hif_idx;
21
22static const struct pci_device_id mt7996_pci_device_table[] = {
23	{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7990) },
24	{ },
25};
26
27static const struct pci_device_id mt7996_hif_device_table[] = {
28	{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7991) },
29	{ },
30};
31
32static struct mt7996_hif *mt7996_pci_get_hif2(u32 idx)
33{
34	struct mt7996_hif *hif;
35	u32 val;
36
37	spin_lock_bh(&hif_lock);
38
39	list_for_each_entry(hif, &hif_list, list) {
40#if defined(__linux__)
41		val = readl(hif->regs + MT_PCIE_RECOG_ID);
42#elif defined(__FreeBSD__)
43		val = readl((u8 *)hif->regs + MT_PCIE_RECOG_ID);
44#endif
45		val &= MT_PCIE_RECOG_ID_MASK;
46		if (val != idx)
47			continue;
48
49		get_device(hif->dev);
50		goto out;
51	}
52	hif = NULL;
53
54out:
55	spin_unlock_bh(&hif_lock);
56
57	return hif;
58}
59
60static void mt7996_put_hif2(struct mt7996_hif *hif)
61{
62	if (!hif)
63		return;
64
65	put_device(hif->dev);
66}
67
68static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev)
69{
70	hif_idx++;
71#if defined(__linux__)
72	if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL))
73#elif defined(__FreeBSD__)
74	if (!linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL))
75#endif
76		return NULL;
77
78	writel(hif_idx | MT_PCIE_RECOG_ID_SEM,
79#if defined(__linux__)
80	       pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID);
81#elif defined(__FreeBSD__)
82	       (u8 *)(pcim_iomap_table(pdev)[0]) + MT_PCIE_RECOG_ID);
83#endif
84
85	return mt7996_pci_get_hif2(hif_idx);
86}
87
88static int mt7996_pci_hif2_probe(struct pci_dev *pdev)
89{
90	struct mt7996_hif *hif;
91
92	hif = devm_kzalloc(&pdev->dev, sizeof(*hif), GFP_KERNEL);
93	if (!hif)
94		return -ENOMEM;
95
96	hif->dev = &pdev->dev;
97	hif->regs = pcim_iomap_table(pdev)[0];
98	hif->irq = pdev->irq;
99	spin_lock_bh(&hif_lock);
100	list_add(&hif->list, &hif_list);
101	spin_unlock_bh(&hif_lock);
102	pci_set_drvdata(pdev, hif);
103
104	return 0;
105}
106
107static int mt7996_pci_probe(struct pci_dev *pdev,
108			    const struct pci_device_id *id)
109{
110	struct pci_dev *hif2_dev;
111	struct mt7996_dev *dev;
112	struct mt76_dev *mdev;
113	struct mt7996_hif *hif2;
114	int irq, ret;
115
116	ret = pcim_enable_device(pdev);
117	if (ret)
118		return ret;
119
120	ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
121	if (ret)
122		return ret;
123
124	pci_set_master(pdev);
125
126	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
127	if (ret)
128		return ret;
129
130	mt76_pci_disable_aspm(pdev);
131
132	if (id->device == 0x7991)
133		return mt7996_pci_hif2_probe(pdev);
134
135	dev = mt7996_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0],
136				id->device);
137	if (IS_ERR(dev))
138		return PTR_ERR(dev);
139
140	mdev = &dev->mt76;
141	mt7996_wfsys_reset(dev);
142	hif2 = mt7996_pci_init_hif2(pdev);
143
144	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
145	if (ret < 0)
146		goto free_device;
147
148	irq = pdev->irq;
149	ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler,
150			       IRQF_SHARED, KBUILD_MODNAME, dev);
151	if (ret)
152		goto free_irq_vector;
153
154	mt76_wr(dev, MT_INT_MASK_CSR, 0);
155	/* master switch of PCIe tnterrupt enable */
156	mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
157
158	if (hif2) {
159		hif2_dev = container_of(hif2->dev, struct pci_dev, dev);
160		dev->hif2 = hif2;
161
162		ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES);
163		if (ret < 0)
164			goto free_hif2;
165
166		dev->hif2->irq = hif2_dev->irq;
167		ret = devm_request_irq(mdev->dev, dev->hif2->irq,
168				       mt7996_irq_handler, IRQF_SHARED,
169				       KBUILD_MODNAME "-hif", dev);
170		if (ret)
171			goto free_hif2_irq_vector;
172
173		mt76_wr(dev, MT_INT1_MASK_CSR, 0);
174		/* master switch of PCIe tnterrupt enable */
175		mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
176	}
177
178	ret = mt7996_register_device(dev);
179	if (ret)
180		goto free_hif2_irq;
181
182	return 0;
183
184free_hif2_irq:
185	if (dev->hif2)
186		devm_free_irq(mdev->dev, dev->hif2->irq, dev);
187free_hif2_irq_vector:
188	if (dev->hif2)
189		pci_free_irq_vectors(hif2_dev);
190free_hif2:
191	if (dev->hif2)
192		put_device(dev->hif2->dev);
193	devm_free_irq(mdev->dev, irq, dev);
194free_irq_vector:
195	pci_free_irq_vectors(pdev);
196free_device:
197	mt76_free_device(&dev->mt76);
198
199	return ret;
200}
201
202static void mt7996_hif_remove(struct pci_dev *pdev)
203{
204	struct mt7996_hif *hif = pci_get_drvdata(pdev);
205
206	list_del(&hif->list);
207}
208
209static void mt7996_pci_remove(struct pci_dev *pdev)
210{
211	struct mt76_dev *mdev;
212	struct mt7996_dev *dev;
213
214	mdev = pci_get_drvdata(pdev);
215	dev = container_of(mdev, struct mt7996_dev, mt76);
216	mt7996_put_hif2(dev->hif2);
217	mt7996_unregister_device(dev);
218}
219
220struct pci_driver mt7996_hif_driver = {
221	.name		= KBUILD_MODNAME "_hif",
222	.id_table	= mt7996_hif_device_table,
223	.probe		= mt7996_pci_probe,
224	.remove		= mt7996_hif_remove,
225};
226
227struct pci_driver mt7996_pci_driver = {
228	.name		= KBUILD_MODNAME,
229	.id_table	= mt7996_pci_device_table,
230	.probe		= mt7996_pci_probe,
231	.remove		= mt7996_pci_remove,
232};
233
234MODULE_DEVICE_TABLE(pci, mt7996_pci_device_table);
235MODULE_DEVICE_TABLE(pci, mt7996_hif_device_table);
236MODULE_FIRMWARE(MT7996_FIRMWARE_WA);
237MODULE_FIRMWARE(MT7996_FIRMWARE_WM);
238MODULE_FIRMWARE(MT7996_FIRMWARE_DSP);
239MODULE_FIRMWARE(MT7996_ROM_PATCH);
240#if defined(__FreeBSD__)
241MODULE_VERSION(mt7996_pci, 1);
242MODULE_DEPEND(mt7996_pci, linuxkpi, 1, 1, 1);
243MODULE_DEPEND(mt7996_pci, linuxkpi_wlan, 1, 1, 1);
244MODULE_DEPEND(mt7996_pci, mt76_core, 1, 1, 1);
245#endif
246