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 goto out; 58 } 59 hif = NULL; 60 61 out: 62 spin_unlock_bh(&hif_lock); 63 64 return hif; 65 } 66 67 static void mt7915_put_hif2(struct mt7915_hif *hif) 68 { 69 if (!hif) 70 return; 71 72 put_device(hif->dev); 73 } 74 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 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 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 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 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