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 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 hif->index = idx; 58 goto out; 59 } 60 hif = NULL; 61 62 out: 63 spin_unlock_bh(&hif_lock); 64 65 return hif; 66 } 67 68 static void mt7915_put_hif2(struct mt7915_hif *hif) 69 { 70 if (!hif) 71 return; 72 73 put_device(hif->dev); 74 } 75 76 static struct mt7915_hif *mt7915_pci_init_hif2(struct pci_dev *pdev) 77 { 78 struct pci_dev *tmp_pdev; 79 80 hif_idx++; 81 82 #if defined(__linux__) 83 tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL); 84 #elif defined(__FreeBSD__) 85 tmp_pdev = linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL); 86 #endif 87 if (!tmp_pdev) { 88 #if defined(__linux__) 89 tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x790a, NULL); 90 #elif defined(__FreeBSD__) 91 tmp_pdev = linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x790a, NULL); 92 #endif 93 if (!tmp_pdev) 94 return NULL; 95 } 96 pci_dev_put(tmp_pdev); 97 98 writel(hif_idx | MT_PCIE_RECOG_ID_SEM, 99 #if defined(__linux__) 100 pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID); 101 #elif defined(__FreeBSD__) 102 (u8 *)(pcim_iomap_table(pdev)[0]) + MT_PCIE_RECOG_ID); 103 #endif 104 105 return mt7915_pci_get_hif2(hif_idx); 106 } 107 108 static int mt7915_pci_hif2_probe(struct pci_dev *pdev) 109 { 110 struct mt7915_hif *hif; 111 112 hif = devm_kzalloc(&pdev->dev, sizeof(*hif), GFP_KERNEL); 113 if (!hif) 114 return -ENOMEM; 115 116 hif->dev = &pdev->dev; 117 hif->regs = pcim_iomap_table(pdev)[0]; 118 hif->irq = pdev->irq; 119 spin_lock_bh(&hif_lock); 120 list_add(&hif->list, &hif_list); 121 spin_unlock_bh(&hif_lock); 122 pci_set_drvdata(pdev, hif); 123 124 return 0; 125 } 126 127 static int mt7915_pci_probe(struct pci_dev *pdev, 128 const struct pci_device_id *id) 129 { 130 struct mt7915_hif *hif2 = NULL; 131 struct mt7915_dev *dev; 132 struct mt76_dev *mdev; 133 int irq; 134 int ret; 135 136 ret = pcim_enable_device(pdev); 137 if (ret) 138 return ret; 139 140 ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 141 if (ret) 142 return ret; 143 144 pci_set_master(pdev); 145 146 ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 147 if (ret) 148 return ret; 149 150 mt76_pci_disable_aspm(pdev); 151 152 if (id->device == 0x7916 || id->device == 0x790a) 153 return mt7915_pci_hif2_probe(pdev); 154 155 dev = mt7915_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], 156 id->device); 157 if (IS_ERR(dev)) 158 return PTR_ERR(dev); 159 160 mdev = &dev->mt76; 161 mt7915_wfsys_reset(dev); 162 hif2 = mt7915_pci_init_hif2(pdev); 163 164 ret = mt7915_mmio_wed_init(dev, pdev, true, &irq); 165 if (ret < 0) 166 goto free_wed_or_irq_vector; 167 168 if (!ret) { 169 hif2 = mt7915_pci_init_hif2(pdev); 170 171 ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); 172 if (ret < 0) 173 goto free_device; 174 175 irq = pdev->irq; 176 } 177 178 ret = devm_request_irq(mdev->dev, irq, mt7915_irq_handler, 179 IRQF_SHARED, KBUILD_MODNAME, dev); 180 if (ret) 181 goto free_wed_or_irq_vector; 182 183 /* master switch of PCIe tnterrupt enable */ 184 mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); 185 186 if (hif2) { 187 dev->hif2 = hif2; 188 189 mt76_wr(dev, MT_INT1_MASK_CSR, 0); 190 /* master switch of PCIe tnterrupt enable */ 191 if (is_mt7915(mdev)) 192 mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); 193 else 194 mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0xff); 195 196 ret = devm_request_irq(mdev->dev, dev->hif2->irq, 197 mt7915_irq_handler, IRQF_SHARED, 198 KBUILD_MODNAME "-hif", dev); 199 if (ret) 200 goto free_hif2; 201 } 202 203 ret = mt7915_register_device(dev); 204 if (ret) 205 goto free_hif2_irq; 206 207 return 0; 208 209 free_hif2_irq: 210 if (dev->hif2) 211 devm_free_irq(mdev->dev, dev->hif2->irq, dev); 212 free_hif2: 213 if (dev->hif2) 214 put_device(dev->hif2->dev); 215 devm_free_irq(mdev->dev, irq, dev); 216 free_wed_or_irq_vector: 217 if (mtk_wed_device_active(&mdev->mmio.wed)) 218 mtk_wed_device_detach(&mdev->mmio.wed); 219 else 220 pci_free_irq_vectors(pdev); 221 free_device: 222 mt76_free_device(&dev->mt76); 223 224 return ret; 225 } 226 227 static void mt7915_hif_remove(struct pci_dev *pdev) 228 { 229 struct mt7915_hif *hif = pci_get_drvdata(pdev); 230 231 list_del(&hif->list); 232 } 233 234 static void mt7915_pci_remove(struct pci_dev *pdev) 235 { 236 struct mt76_dev *mdev; 237 struct mt7915_dev *dev; 238 239 mdev = pci_get_drvdata(pdev); 240 dev = container_of(mdev, struct mt7915_dev, mt76); 241 mt7915_put_hif2(dev->hif2); 242 mt7915_unregister_device(dev); 243 } 244 245 struct pci_driver mt7915_hif_driver = { 246 .name = KBUILD_MODNAME "_hif", 247 .id_table = mt7915_hif_device_table, 248 .probe = mt7915_pci_probe, 249 .remove = mt7915_hif_remove, 250 }; 251 252 struct pci_driver mt7915_pci_driver = { 253 .name = KBUILD_MODNAME, 254 .id_table = mt7915_pci_device_table, 255 .probe = mt7915_pci_probe, 256 .remove = mt7915_pci_remove, 257 }; 258 259 MODULE_DEVICE_TABLE(pci, mt7915_pci_device_table); 260 MODULE_DEVICE_TABLE(pci, mt7915_hif_device_table); 261 MODULE_FIRMWARE(MT7915_FIRMWARE_WA); 262 MODULE_FIRMWARE(MT7915_FIRMWARE_WM); 263 MODULE_FIRMWARE(MT7915_ROM_PATCH); 264 MODULE_FIRMWARE(MT7916_FIRMWARE_WA); 265 MODULE_FIRMWARE(MT7916_FIRMWARE_WM); 266 MODULE_FIRMWARE(MT7916_ROM_PATCH); 267 #if defined(__FreeBSD__) 268 MODULE_VERSION(mt7915_pci, 1); 269 MODULE_DEPEND(mt7915_pci, linuxkpi, 1, 1, 1); 270 MODULE_DEPEND(mt7915_pci, linuxkpi_wlan, 1, 1, 1); 271 MODULE_DEPEND(mt7915_pci, mt76_core, 1, 1, 1); 272 #endif 273