linux/drivers/pci/controller/pci-loongson.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Loongson PCI Host Controller Driver
 *
 * Copyright (C) 2020 Jiaxun Yang <[email protected]>
 */

#include <linux/of.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>

#include "../pci.h"

/* Device IDs */
#define DEV_LS2K_PCIE_PORT0
#define DEV_LS7A_PCIE_PORT0
#define DEV_LS7A_PCIE_PORT1
#define DEV_LS7A_PCIE_PORT2
#define DEV_LS7A_PCIE_PORT3
#define DEV_LS7A_PCIE_PORT4
#define DEV_LS7A_PCIE_PORT5
#define DEV_LS7A_PCIE_PORT6

#define DEV_LS2K_APB
#define DEV_LS7A_GMAC
#define DEV_LS7A_DC1
#define DEV_LS7A_LPC
#define DEV_LS7A_AHCI
#define DEV_LS7A_CONF
#define DEV_LS7A_GNET
#define DEV_LS7A_EHCI
#define DEV_LS7A_DC2
#define DEV_LS7A_HDMI

#define FLAG_CFG0
#define FLAG_CFG1
#define FLAG_DEV_FIX
#define FLAG_DEV_HIDDEN

struct loongson_pci_data {};

struct loongson_pci {};

/* Fixup wrong class code in PCIe bridges */
static void bridge_class_quirk(struct pci_dev *dev)
{}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT0, bridge_class_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT1, bridge_class_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT2, bridge_class_quirk);

static void system_bus_quirk(struct pci_dev *pdev)
{}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS2K_APB, system_bus_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_CONF, system_bus_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_LPC, system_bus_quirk);

/*
 * Some Loongson PCIe ports have hardware limitations on their Maximum Read
 * Request Size. They can't handle anything larger than this.  Sane
 * firmware will set proper MRRS at boot, so we only need no_inc_mrrs for
 * bridges. However, some MIPS Loongson firmware doesn't set MRRS properly,
 * so we have to enforce maximum safe MRRS, which is 256 bytes.
 */
#ifdef CONFIG_MIPS
static void loongson_set_min_mrrs_quirk(struct pci_dev *pdev)
{
	struct pci_bus *bus = pdev->bus;
	struct pci_dev *bridge;
	static const struct pci_device_id bridge_devids[] = {
		{ PCI_VDEVICE(LOONGSON, DEV_LS2K_PCIE_PORT0) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT0) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT1) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT2) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT3) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT4) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT5) },
		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT6) },
		{ 0, },
	};

	/* look for the matching bridge */
	while (!pci_is_root_bus(bus)) {
		bridge = bus->self;
		bus = bus->parent;

		if (pci_match_id(bridge_devids, bridge)) {
			if (pcie_get_readrq(pdev) > 256) {
				pci_info(pdev, "limiting MRRS to 256\n");
				pcie_set_readrq(pdev, 256);
			}
			break;
		}
	}
}
DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_set_min_mrrs_quirk);
#endif

static void loongson_mrrs_quirk(struct pci_dev *pdev)
{}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS2K_PCIE_PORT0, loongson_mrrs_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT0, loongson_mrrs_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT1, loongson_mrrs_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT2, loongson_mrrs_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT3, loongson_mrrs_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT4, loongson_mrrs_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT5, loongson_mrrs_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_PCIE_PORT6, loongson_mrrs_quirk);

static void loongson_pci_pin_quirk(struct pci_dev *pdev)
{}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_DC1, loongson_pci_pin_quirk);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_DC2, loongson_pci_pin_quirk);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_GMAC, loongson_pci_pin_quirk);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_AHCI, loongson_pci_pin_quirk);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_EHCI, loongson_pci_pin_quirk);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_GNET, loongson_pci_pin_quirk);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
			DEV_LS7A_HDMI, loongson_pci_pin_quirk);

static void loongson_pci_msi_quirk(struct pci_dev *dev)
{}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, DEV_LS7A_PCIE_PORT5, loongson_pci_msi_quirk);

static struct loongson_pci *pci_bus_to_loongson_pci(struct pci_bus *bus)
{}

static void __iomem *cfg0_map(struct loongson_pci *priv, struct pci_bus *bus,
			      unsigned int devfn, int where)
{}

static void __iomem *cfg1_map(struct loongson_pci *priv, struct pci_bus *bus,
			      unsigned int devfn, int where)
{}

static bool pdev_may_exist(struct pci_bus *bus, unsigned int device,
			   unsigned int function)
{}

static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
					  unsigned int devfn, int where)
{}

#ifdef CONFIG_OF

static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{}

/* LS2K/LS7A accept 8/16/32-bit PCI config operations */
static struct pci_ops loongson_pci_ops =;

/* RS780/SR5690 only accept 32-bit PCI config operations */
static struct pci_ops loongson_pci_ops32 =;

static const struct loongson_pci_data ls2k_pci_data =;

static const struct loongson_pci_data ls7a_pci_data =;

static const struct loongson_pci_data rs780e_pci_data =;

static const struct of_device_id loongson_pci_of_match[] =;

static int loongson_pci_probe(struct platform_device *pdev)
{}

static struct platform_driver loongson_pci_driver =;
builtin_platform_driver();

#endif

#ifdef CONFIG_ACPI

static int loongson_pci_ecam_init(struct pci_config_window *cfg)
{}

const struct pci_ecam_ops loongson_pci_ecam_ops =;

#endif