162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2022 MediaTek Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "mt7996.h" 1162306a36Sopenharmony_ci#include "mac.h" 1262306a36Sopenharmony_ci#include "../trace.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic LIST_HEAD(hif_list); 1562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(hif_lock); 1662306a36Sopenharmony_cistatic u32 hif_idx; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic const struct pci_device_id mt7996_pci_device_table[] = { 1962306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7990) }, 2062306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7992) }, 2162306a36Sopenharmony_ci { }, 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic const struct pci_device_id mt7996_hif_device_table[] = { 2562306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7991) }, 2662306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x799a) }, 2762306a36Sopenharmony_ci { }, 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic struct mt7996_hif *mt7996_pci_get_hif2(u32 idx) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct mt7996_hif *hif; 3362306a36Sopenharmony_ci u32 val; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci spin_lock_bh(&hif_lock); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci list_for_each_entry(hif, &hif_list, list) { 3862306a36Sopenharmony_ci val = readl(hif->regs + MT_PCIE_RECOG_ID); 3962306a36Sopenharmony_ci val &= MT_PCIE_RECOG_ID_MASK; 4062306a36Sopenharmony_ci if (val != idx) 4162306a36Sopenharmony_ci continue; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci get_device(hif->dev); 4462306a36Sopenharmony_ci goto out; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci hif = NULL; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ciout: 4962306a36Sopenharmony_ci spin_unlock_bh(&hif_lock); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return hif; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void mt7996_put_hif2(struct mt7996_hif *hif) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci if (!hif) 5762306a36Sopenharmony_ci return; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci put_device(hif->dev); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci hif_idx++; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL) && 6762306a36Sopenharmony_ci !pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x799a, NULL)) 6862306a36Sopenharmony_ci return NULL; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci writel(hif_idx | MT_PCIE_RECOG_ID_SEM, 7162306a36Sopenharmony_ci pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return mt7996_pci_get_hif2(hif_idx); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int mt7996_pci_hif2_probe(struct pci_dev *pdev) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct mt7996_hif *hif; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci hif = devm_kzalloc(&pdev->dev, sizeof(*hif), GFP_KERNEL); 8162306a36Sopenharmony_ci if (!hif) 8262306a36Sopenharmony_ci return -ENOMEM; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci hif->dev = &pdev->dev; 8562306a36Sopenharmony_ci hif->regs = pcim_iomap_table(pdev)[0]; 8662306a36Sopenharmony_ci hif->irq = pdev->irq; 8762306a36Sopenharmony_ci spin_lock_bh(&hif_lock); 8862306a36Sopenharmony_ci list_add(&hif->list, &hif_list); 8962306a36Sopenharmony_ci spin_unlock_bh(&hif_lock); 9062306a36Sopenharmony_ci pci_set_drvdata(pdev, hif); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int mt7996_pci_probe(struct pci_dev *pdev, 9662306a36Sopenharmony_ci const struct pci_device_id *id) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct pci_dev *hif2_dev; 9962306a36Sopenharmony_ci struct mt7996_dev *dev; 10062306a36Sopenharmony_ci struct mt76_dev *mdev; 10162306a36Sopenharmony_ci struct mt7996_hif *hif2; 10262306a36Sopenharmony_ci int irq, ret; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci ret = pcim_enable_device(pdev); 10562306a36Sopenharmony_ci if (ret) 10662306a36Sopenharmony_ci return ret; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 10962306a36Sopenharmony_ci if (ret) 11062306a36Sopenharmony_ci return ret; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci pci_set_master(pdev); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 11562306a36Sopenharmony_ci if (ret) 11662306a36Sopenharmony_ci return ret; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci mt76_pci_disable_aspm(pdev); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (id->device == 0x7991 || id->device == 0x799a) 12162306a36Sopenharmony_ci return mt7996_pci_hif2_probe(pdev); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci dev = mt7996_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], 12462306a36Sopenharmony_ci id->device); 12562306a36Sopenharmony_ci if (IS_ERR(dev)) 12662306a36Sopenharmony_ci return PTR_ERR(dev); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci mdev = &dev->mt76; 12962306a36Sopenharmony_ci mt7996_wfsys_reset(dev); 13062306a36Sopenharmony_ci hif2 = mt7996_pci_init_hif2(pdev); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); 13362306a36Sopenharmony_ci if (ret < 0) 13462306a36Sopenharmony_ci goto free_device; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci irq = pdev->irq; 13762306a36Sopenharmony_ci ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler, 13862306a36Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, dev); 13962306a36Sopenharmony_ci if (ret) 14062306a36Sopenharmony_ci goto free_irq_vector; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, 0); 14362306a36Sopenharmony_ci /* master switch of PCIe tnterrupt enable */ 14462306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (hif2) { 14762306a36Sopenharmony_ci hif2_dev = container_of(hif2->dev, struct pci_dev, dev); 14862306a36Sopenharmony_ci dev->hif2 = hif2; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES); 15162306a36Sopenharmony_ci if (ret < 0) 15262306a36Sopenharmony_ci goto free_hif2; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci dev->hif2->irq = hif2_dev->irq; 15562306a36Sopenharmony_ci ret = devm_request_irq(mdev->dev, dev->hif2->irq, 15662306a36Sopenharmony_ci mt7996_irq_handler, IRQF_SHARED, 15762306a36Sopenharmony_ci KBUILD_MODNAME "-hif", dev); 15862306a36Sopenharmony_ci if (ret) 15962306a36Sopenharmony_ci goto free_hif2_irq_vector; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci mt76_wr(dev, MT_INT1_MASK_CSR, 0); 16262306a36Sopenharmony_ci /* master switch of PCIe tnterrupt enable */ 16362306a36Sopenharmony_ci mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci ret = mt7996_register_device(dev); 16762306a36Sopenharmony_ci if (ret) 16862306a36Sopenharmony_ci goto free_hif2_irq; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cifree_hif2_irq: 17362306a36Sopenharmony_ci if (dev->hif2) 17462306a36Sopenharmony_ci devm_free_irq(mdev->dev, dev->hif2->irq, dev); 17562306a36Sopenharmony_cifree_hif2_irq_vector: 17662306a36Sopenharmony_ci if (dev->hif2) 17762306a36Sopenharmony_ci pci_free_irq_vectors(hif2_dev); 17862306a36Sopenharmony_cifree_hif2: 17962306a36Sopenharmony_ci if (dev->hif2) 18062306a36Sopenharmony_ci put_device(dev->hif2->dev); 18162306a36Sopenharmony_ci devm_free_irq(mdev->dev, irq, dev); 18262306a36Sopenharmony_cifree_irq_vector: 18362306a36Sopenharmony_ci pci_free_irq_vectors(pdev); 18462306a36Sopenharmony_cifree_device: 18562306a36Sopenharmony_ci mt76_free_device(&dev->mt76); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return ret; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic void mt7996_hif_remove(struct pci_dev *pdev) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct mt7996_hif *hif = pci_get_drvdata(pdev); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci list_del(&hif->list); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void mt7996_pci_remove(struct pci_dev *pdev) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct mt76_dev *mdev; 20062306a36Sopenharmony_ci struct mt7996_dev *dev; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci mdev = pci_get_drvdata(pdev); 20362306a36Sopenharmony_ci dev = container_of(mdev, struct mt7996_dev, mt76); 20462306a36Sopenharmony_ci mt7996_put_hif2(dev->hif2); 20562306a36Sopenharmony_ci mt7996_unregister_device(dev); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistruct pci_driver mt7996_hif_driver = { 20962306a36Sopenharmony_ci .name = KBUILD_MODNAME "_hif", 21062306a36Sopenharmony_ci .id_table = mt7996_hif_device_table, 21162306a36Sopenharmony_ci .probe = mt7996_pci_probe, 21262306a36Sopenharmony_ci .remove = mt7996_hif_remove, 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistruct pci_driver mt7996_pci_driver = { 21662306a36Sopenharmony_ci .name = KBUILD_MODNAME, 21762306a36Sopenharmony_ci .id_table = mt7996_pci_device_table, 21862306a36Sopenharmony_ci .probe = mt7996_pci_probe, 21962306a36Sopenharmony_ci .remove = mt7996_pci_remove, 22062306a36Sopenharmony_ci}; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mt7996_pci_device_table); 22362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mt7996_hif_device_table); 22462306a36Sopenharmony_ciMODULE_FIRMWARE(MT7996_FIRMWARE_WA); 22562306a36Sopenharmony_ciMODULE_FIRMWARE(MT7996_FIRMWARE_WM); 22662306a36Sopenharmony_ciMODULE_FIRMWARE(MT7996_FIRMWARE_DSP); 22762306a36Sopenharmony_ciMODULE_FIRMWARE(MT7996_ROM_PATCH); 228