new file mode 100644
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "hw.h"
+#include "bus/pci/msg_pci.h"
+#include "bus/pci/tx_pci.h"
+#include "bus/pci/rx_pci.h"
+#include "reg/reg_macsys_gcu.h"
+#include "main.h"
+#include "ela.h"
+#include "debug.h"
+
+struct cl_pci_db {
+ u8 device_cntr;
+ struct pci_dev *dev[CHIP_MAX];
+};
+
+static struct cl_pci_db pci_db;
+
+void cl_pci_get_celeno_device(void)
+{
+ /*
+ * Search the PCI for all Celeno devices.
+ * If there are two devices sort them in ascending order.
+ */
+ struct pci_dev *dev = NULL;
+
+ while ((dev = pci_get_device(CL_VENDOR_ID, PCI_ANY_ID, dev))) {
+ pci_db.dev[pci_db.device_cntr] = dev;
+ pci_db.device_cntr++;
+
+ if (pci_db.device_cntr == CHIP_MAX) {
+ if (pci_db.dev[CHIP0]->device > pci_db.dev[CHIP1]->device)
+ swap(pci_db.dev[CHIP0], pci_db.dev[CHIP1]);
+
+ break;
+ }
+ }
+}
+
+static u8 cl_pci_chip_idx(struct pci_dev *pci_dev)
+{
+ if (pci_db.device_cntr == 0)
+ cl_pci_get_celeno_device();
+
+ if (pci_db.device_cntr == 1)
+ return CHIP0;
+
+ return (pci_db.dev[CHIP0] == pci_dev) ? CHIP0 : CHIP1;
+}
+
+static const struct cl_driver_ops drv_ops = {
+ .msg_fw_send = cl_msg_pci_msg_fw_send,
+ .pkt_fw_send = cl_tx_pci_pkt_fw_send,
+};
+
+static int cl_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ u16 pci_cmd;
+ int ret;
+ u8 chip_idx = cl_pci_chip_idx(pci_dev);
+ u8 step_id;
+ struct cl_chip *chip = cl_chip_alloc(chip_idx);
+
+ if (!chip) {
+ pr_err("Chip [%u] alloc failed\n", chip_idx);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = cl_chip_config_read(chip);
+ if (ret) {
+ cl_chip_dealloc(chip);
+ return 0;
+ }
+
+ chip->pci_dev = pci_dev;
+ chip->dev = &pci_dev->dev;
+ chip->bus_type = CL_BUS_TYPE_PCI;
+
+ pci_set_drvdata(pci_dev, chip);
+
+ /* Hotplug fixups */
+ pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd);
+ pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+ pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd);
+ pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2);
+
+ ret = pci_enable_device(pci_dev);
+ if (ret) {
+ cl_dbg_chip_err(chip, "pci_enable_device failed\n");
+ goto out;
+ }
+
+ if (!dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32))) {
+ cl_dbg_chip_verbose(chip, "Using 32bit DMA\n");
+ } else {
+ cl_dbg_chip_verbose(chip, "No suitable DMA available\n");
+ goto out_disable_device;
+ }
+
+ pci_set_master(pci_dev);
+
+ ret = pci_request_regions(pci_dev, chip->pci_drv.name);
+ if (ret) {
+ cl_dbg_chip_verbose(chip, "pci_request_regions failed\n");
+ goto out_disable_device;
+ }
+
+ chip->pci_bar0_virt_addr = pci_ioremap_bar(pci_dev, 0);
+ if (!chip->pci_bar0_virt_addr) {
+ cl_dbg_chip_verbose(chip, "pci_ioremap_bar 0 failed\n");
+ ret = -ENOMEM;
+ goto out_release_regions;
+ }
+
+#ifdef CONFIG_PCI_MSI
+ if (chip->conf->ci_pci_msi_enable) {
+ ret = pci_enable_msi(pci_dev);
+ if (ret)
+ cl_dbg_chip_err(chip, "pci_enable_msi failed (%d)\n", ret);
+ }
+#endif
+
+ step_id = macsys_gcu_chip_version_step_id_getf(chip);
+ if (step_id != 0xB) {
+ cl_dbg_chip_err(chip, "Invalid Step ID: 0x%X\n", step_id);
+ ret = -EOPNOTSUPP;
+ goto out_release_regions;
+ }
+
+ ret = cl_chip_init(chip);
+ if (ret)
+ goto out_chip_deinit;
+
+ ret = cl_main_init(chip, &drv_ops);
+ if (ret)
+ goto out_chip_deinit;
+
+ if (cl_ela_init(chip))
+ cl_dbg_chip_err(chip, "Non-critical: cl_ela_init failed\n");
+
+ return 0;
+
+out_chip_deinit:
+ cl_chip_deinit(chip);
+#ifdef CONFIG_PCI_MSI
+ if (chip->conf->ci_pci_msi_enable)
+ pci_disable_msi(pci_dev);
+#endif
+ iounmap(chip->pci_bar0_virt_addr);
+out_release_regions:
+ pci_release_regions(pci_dev);
+out_disable_device:
+ pci_disable_device(pci_dev);
+out:
+
+ return ret;
+}
+
+static void cl_pci_remove(struct pci_dev *pci_dev)
+{
+ struct cl_chip *chip = pci_get_drvdata(pci_dev);
+
+ if (!chip) {
+ pr_err("%s: failed to find chip\n", __func__);
+ return;
+ }
+
+ cl_ela_deinit(chip);
+
+ cl_main_deinit(chip);
+
+ cl_chip_deinit(chip);
+
+#ifdef CONFIG_PCI_MSI
+ if (chip->conf->ci_pci_msi_enable) {
+ pci_disable_msi(pci_dev);
+ pr_debug("pci_disable_msi\n");
+ }
+#endif
+
+ iounmap(chip->pci_bar0_virt_addr);
+ cl_chip_dealloc(chip);
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
+}
+
+static const struct pci_device_id cl_pci_id_table[] = {
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8000) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8001) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8040) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8060) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8080) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8046) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8066) },
+ { PCI_DEVICE(CL_VENDOR_ID, 0x8086) },
+ { },
+};
+
+static struct pci_driver cl_pci_driver = {
+ .name = "cl_pci",
+ .id_table = cl_pci_id_table,
+ .probe = cl_pci_probe,
+ .remove = cl_pci_remove,
+};
+
+module_pci_driver(cl_pci_driver);