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