[U-Boot] [PATCH v4 03/11] pci: xilinx: Add a driver for Xilinx AXI to PCIe bridge

Michal Simek monstr at monstr.eu
Thu Aug 4 11:54:22 CEST 2016


On 1.8.2016 12:06, Paul Burton wrote:
> This patch adds a driver for the Xilinx AXI bridge for PCI express, an
> IP block which can be used on some generations of Xilinx FPGAs. This is
> mostly a case of implementing PCIe ECAM specification, but with some
> quirks about what devices are valid to access.
> 
> Signed-off-by: Paul Burton <paul.burton at imgtec.com>
> Reviewed-by: Simon Glass <sjg at chromium.org>
> 
> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2:
> - Clean up error returns & documentation
> 
>  drivers/pci/Kconfig       |   7 ++
>  drivers/pci/Makefile      |   1 +
>  drivers/pci/pcie_xilinx.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 227 insertions(+)
>  create mode 100644 drivers/pci/pcie_xilinx.c
> 
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index 26aa2b0..1f9ea66 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -38,4 +38,11 @@ config PCI_TEGRA
>  	  with a total of 5 lanes. Some boards require this for Ethernet
>  	  support to work (e.g. beaver, jetson-tk1).
>  
> +config PCI_XILINX
> +	bool "Xilinx AXI Bridge for PCI Express"
> +	depends on DM_PCI

There is also dependency on PCI which should be added to Kconfig.
And it can be compiled only for MB and Mips.
It means you should limit it like that or fix that problem with
ioremap_nocache.

> +	help
> +	  Enable support for the Xilinx AXI bridge for PCI express, an IP block
> +	  which can be used on some generations of Xilinx FPGAs.
> +
>  endmenu
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index f8be9bf..9583e91 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o
>  obj-$(CONFIG_TSI108_PCI) += tsi108_pci.o
>  obj-$(CONFIG_WINBOND_83C553) += w83c553f.o
>  obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o
> +obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o
> diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c
> new file mode 100644
> index 0000000..9fe02be
> --- /dev/null
> +++ b/drivers/pci/pcie_xilinx.c
> @@ -0,0 +1,219 @@
> +/*
> + * Xilinx AXI Bridge for PCI Express Driver
> + *
> + * Copyright (C) 2016 Imagination Technologies
> + *
> + * SPDX-License-Identifier:	GPL-2.0
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <pci.h>
> +
> +#include <asm/io.h>
> +
> +/**
> + * struct xilinx_pcie - Xilinx PCIe controller state
> + * @hose: The parent classes PCI controller state
> + * @cfg_base: The base address of memory mapped configuration space
> + */
> +struct xilinx_pcie {
> +	struct pci_controller hose;
> +	void *cfg_base;
> +};
> +
> +/* Register definitions */
> +#define XILINX_PCIE_REG_PSCR		0x144
> +#define XILINX_PCIE_REG_PSCR_LNKUP	BIT(11)
> +
> +/**
> + * pcie_xilinx_link_up() - Check whether the PCIe link is up
> + * @pcie: Pointer to the PCI controller state
> + *
> + * Checks whether the PCIe link for the given device is up or down.
> + *
> + * Return: true if the link is up, else false
> + */
> +static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie)
> +{
> +	uint32_t pscr = __raw_readl(pcie->cfg_base + XILINX_PCIE_REG_PSCR);
> +
> +	return pscr & XILINX_PCIE_REG_PSCR_LNKUP;
> +}
> +
> +/**
> + * pcie_xilinx_config_address() - Calculate the address of a config access
> + * @pcie: Pointer to the PCI controller state
> + * @bdf: Identifies the PCIe device to access
> + * @offset: The offset into the device's configuration space
> + * @paddress: Pointer to the pointer to write the calculates address to
> + *
> + * Calculates the address that should be accessed to perform a PCIe
> + * configuration space access for a given device identified by the PCIe
> + * controller device @pcie and the bus, device & function numbers in @bdf. If
> + * access to the device is not valid then the function will return an error
> + * code. Otherwise the address to access will be written to the pointer pointed
> + * to by @paddress.
> + *
> + * Return: 0 on success, else -ENODEV
> + */
> +static int pcie_xilinx_config_address(struct xilinx_pcie *pcie, pci_dev_t bdf,
> +				      uint offset, void **paddress)
> +{
> +	unsigned int bus = PCI_BUS(bdf);
> +	unsigned int dev = PCI_DEV(bdf);
> +	unsigned int func = PCI_FUNC(bdf);
> +	void *addr;
> +
> +	if ((bus > 0) && !pcie_xilinx_link_up(pcie))
> +		return -ENODEV;
> +
> +	/*
> +	 * Busses 0 (host-PCIe bridge) & 1 (its immediate child) are
> +	 * limited to a single device each.
> +	 */
> +	if ((bus < 2) && (dev > 0))
> +		return -ENODEV;
> +
> +	addr = pcie->cfg_base;
> +	addr += bus << 20;
> +	addr += dev << 15;
> +	addr += func << 12;
> +	addr += offset;
> +	*paddress = addr;
> +
> +	return 0;
> +}
> +
> +/**
> + * pcie_xilinx_read_config() - Read from configuration space
> + * @pcie: Pointer to the PCI controller state
> + * @bdf: Identifies the PCIe device to access
> + * @offset: The offset into the device's configuration space
> + * @valuep: A pointer at which to store the read value
> + * @size: Indicates the size of access to perform
> + *
> + * Read a value of size @size from offset @offset within the configuration
> + * space of the device identified by the bus, device & function numbers in @bdf
> + * on the PCI bus @bus.
> + *
> + * Return: 0 on success, else -ENODEV or -EINVAL
> + */
> +static int pcie_xilinx_read_config(struct udevice *bus, pci_dev_t bdf,
> +				   uint offset, ulong *valuep,
> +				   enum pci_size_t size)
> +{
> +	struct xilinx_pcie *pcie = dev_get_priv(bus);
> +	void *address;
> +	int err;
> +
> +	err = pcie_xilinx_config_address(pcie, bdf, offset, &address);
> +	if (err < 0) {
> +		*valuep = pci_get_ff(size);
> +		return 0;
> +	}
> +
> +	switch (size) {
> +	case PCI_SIZE_8:
> +		*valuep = __raw_readb(address);
> +		return 0;
> +	case PCI_SIZE_16:
> +		*valuep = __raw_readw(address);
> +		return 0;
> +	case PCI_SIZE_32:
> +		*valuep = __raw_readl(address);
> +		return 0;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +/**
> + * pcie_xilinx_write_config() - Write to configuration space
> + * @pcie: Pointer to the PCI controller state
> + * @bdf: Identifies the PCIe device to access
> + * @offset: The offset into the device's configuration space
> + * @value: The value to write
> + * @size: Indicates the size of access to perform
> + *
> + * Write the value @value of size @size from offset @offset within the
> + * configuration space of the device identified by the bus, device & function
> + * numbers in @bdf on the PCI bus @bus.
> + *
> + * Return: 0 on success, else -ENODEV or -EINVAL
> + */
> +static int pcie_xilinx_write_config(struct udevice *bus, pci_dev_t bdf,
> +				    uint offset, ulong value,
> +				    enum pci_size_t size)
> +{
> +	struct xilinx_pcie *pcie = dev_get_priv(bus);
> +	void *address;
> +	int err;
> +
> +	err = pcie_xilinx_config_address(pcie, bdf, offset, &address);
> +	if (err < 0)
> +		return 0;
> +
> +	switch (size) {
> +	case PCI_SIZE_8:
> +		__raw_writeb(value, address);
> +		return 0;
> +	case PCI_SIZE_16:
> +		__raw_writew(value, address);
> +		return 0;
> +	case PCI_SIZE_32:
> +		__raw_writel(value, address);
> +		return 0;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +/**
> + * pcie_xilinx_ofdata_to_platdata() - Translate from DT to device state
> + * @dev: A pointer to the device being operated on
> + *
> + * Translate relevant data from the device tree pertaining to device @dev into
> + * state that the driver will later make use of. This state is stored in the
> + * device's private data structure.
> + *
> + * Return: 0 on success, else -EINVAL
> + */
> +static int pcie_xilinx_ofdata_to_platdata(struct udevice *dev)
> +{
> +	struct xilinx_pcie *pcie = dev_get_priv(dev);
> +	struct fdt_resource reg_res;
> +	DECLARE_GLOBAL_DATA_PTR;
> +	int err;
> +
> +	err = fdt_get_resource(gd->fdt_blob, dev->of_offset, "reg",
> +			       0, &reg_res);
> +	if (err < 0) {
> +		error("\"reg\" resource not found\n");
> +		return err;
> +	}
> +
> +	pcie->cfg_base = ioremap_nocache(reg_res.start,
> +					 fdt_resource_size(&reg_res));
> +

Getting error here.
  CC      cmd/mem.o
  CC      drivers/net/phy/atheros.o
  CC      drivers/net/xilinx_emaclite.o
drivers/pci/pcie_xilinx.c: In function 'pcie_xilinx_ofdata_to_platdata':
drivers/pci/pcie_xilinx.c:196:17: warning: assignment makes pointer from
integer without a cast
  pcie->cfg_base = ioremap_nocache(reg_res.start,
                 ^
  CC      drivers/net/phy/broadcom.o
  CC      cmd/mfsl.o


Simon: Is this the right place for doing ioremap?
IRC There should be probe function where you call this and this function
will just fill platdata structure.

Thanks,
Michal


-- 
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP SoCs


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: OpenPGP digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160804/3587699b/attachment.sig>


More information about the U-Boot mailing list