diff --git a/MAINTAINERS b/MAINTAINERS index a310b8478f..4a8b32cc28 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -701,6 +701,11 @@ S: Maintained F: drivers/pci_endpoint/ F: include/pci_ep.h +PCI MPC85xx +M: Heiko Schocher +S: Maintained +F: drivers/pci/pci_mpc85xx.c + POWER M: Jaehoon Chung S: Maintained diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 19e7b50046..71aab85ed3 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -68,6 +68,13 @@ config PCIE_FSL PowerPC MPC85xx, MPC86xx, B series, P series and T series SoCs. This driver does not support SRIO_PCIE_BOOT feature. +config PCI_MPC85XX + bool "MPC85XX PowerPC PCI support" + depends on DM_PCI + help + Say Y here if you want to enable PCI controller support on FSL + PowerPC MPC85xx SoC. + config PCI_RCAR_GEN2 bool "Renesas RCar Gen2 PCIe driver" depends on DM_PCI diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index b1d3dc8610..856ac71a1c 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_PCIE_ECAM_GENERIC) += pcie_ecam_generic.o obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o +obj-$(CONFIG_PCI_MPC85XX) += pci_mpc85xx.o obj-$(CONFIG_PCI_MSC01) += pci_msc01.o obj-$(CONFIG_PCIE_IMX) += pcie_imx.o obj-$(CONFIG_FTPCI100) += pci_ftpci100.o diff --git a/drivers/pci/pci_mpc85xx.c b/drivers/pci/pci_mpc85xx.c new file mode 100644 index 0000000000..e58ab60ee0 --- /dev/null +++ b/drivers/pci/pci_mpc85xx.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2019 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + */ +#include +#include +#include +#include +#include + +struct mpc85xx_pci_priv { + void __iomem *cfg_addr; + void __iomem *cfg_data; +}; + +static int mpc85xx_pci_dm_read_config(struct udevice *dev, pci_dev_t bdf, + uint offset, ulong *value, + enum pci_size_t size) +{ + struct mpc85xx_pci_priv *priv = dev_get_priv(dev); + u32 addr; + + addr = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; + out_be32(priv->cfg_addr, addr); + sync(); + *value = pci_conv_32_to_size(in_le32(priv->cfg_data), offset, size); + + return 0; +} + +static int mpc85xx_pci_dm_write_config(struct udevice *dev, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + struct mpc85xx_pci_priv *priv = dev_get_priv(dev); + u32 addr; + + addr = bdf | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; + out_be32(priv->cfg_addr, addr); + sync(); + out_le32(priv->cfg_data, pci_conv_size_to_32(0, value, offset, size)); + + return 0; +} + +static int +mpc85xx_pci_dm_setup_laws(struct pci_region *io, struct pci_region *mem, + struct pci_region *pre) +{ + /* + * Unfortunately we have defines for this addresse, + * as we have to setup the TLB, and at this stage + * we have no access to DT ... may we check here + * if the value in the define is the same ? + */ + if (mem) + set_next_law(mem->phys_start, law_size_bits(mem->size), + LAW_TRGT_IF_PCI); + if (io) + set_next_law(io->phys_start, law_size_bits(io->size), + LAW_TRGT_IF_PCI); + if (pre) + set_next_law(pre->phys_start, law_size_bits(pre->size), + LAW_TRGT_IF_PCI); + + return 0; +} + +static int mpc85xx_pci_dm_probe(struct udevice *dev) +{ + struct mpc85xx_pci_priv *priv = dev_get_priv(dev); + struct pci_region *io; + struct pci_region *mem; + struct pci_region *pre; + int count; + ccsr_pcix_t *pcix; + + count = pci_get_regions(dev, &io, &mem, &pre); + if (count != 2) { + printf("%s: wrong count of regions %d only 2 allowed\n", + __func__, count); + return -EINVAL; + } + + mpc85xx_pci_dm_setup_laws(io, mem, pre); + + pcix = priv->cfg_addr; + /* BAR 1: memory */ + out_be32(&pcix->potar1, (mem->bus_start >> 12) & 0x000fffff); + out_be32(&pcix->potear1, 0); + out_be32(&pcix->powbar1, (mem->phys_start >> 12) & 0x000fffff); + out_be32(&pcix->powbear1, 0); + out_be32(&pcix->powar1, (POWAR_EN | POWAR_MEM_READ | + POWAR_MEM_WRITE | (__ilog2(mem->size) - 1))); + + /* BAR 1: IO */ + out_be32(&pcix->potar2, (io->bus_start >> 12) & 0x000fffff); + out_be32(&pcix->potear2, 0); + out_be32(&pcix->powbar2, (io->phys_start >> 12) & 0x000fffff); + out_be32(&pcix->powbear2, 0); + out_be32(&pcix->powar2, (POWAR_EN | POWAR_IO_READ | + POWAR_IO_WRITE | (__ilog2(io->size) - 1))); + + out_be32(&pcix->pitar1, 0); + out_be32(&pcix->piwbar1, 0); + out_be32(&pcix->piwar1, (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL | + PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G)); + + out_be32(&pcix->powar3, 0); + out_be32(&pcix->powar4, 0); + out_be32(&pcix->piwar2, 0); + out_be32(&pcix->piwar3, 0); + + return 0; +} + +static int mpc85xx_pci_dm_remove(struct udevice *dev) +{ + return 0; +} + +static int mpc85xx_pci_ofdata_to_platdata(struct udevice *dev) +{ + struct mpc85xx_pci_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + + addr = devfdt_get_addr_index(dev, 0); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + priv->cfg_addr = (void __iomem *)addr; + addr += 4; + priv->cfg_data = (void __iomem *)addr; + + return 0; +} + +static const struct dm_pci_ops mpc85xx_pci_ops = { + .read_config = mpc85xx_pci_dm_read_config, + .write_config = mpc85xx_pci_dm_write_config, +}; + +static const struct udevice_id mpc85xx_pci_ids[] = { + { .compatible = "fsl,mpc8540-pci" }, + { } +}; + +U_BOOT_DRIVER(mpc85xx_pci) = { + .name = "mpc85xx_pci", + .id = UCLASS_PCI, + .of_match = mpc85xx_pci_ids, + .ops = &mpc85xx_pci_ops, + .probe = mpc85xx_pci_dm_probe, + .remove = mpc85xx_pci_dm_remove, + .ofdata_to_platdata = mpc85xx_pci_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct mpc85xx_pci_priv), +};