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

Paul Burton paul.burton at imgtec.com
Thu Aug 4 12:24:28 CEST 2016



On 04/08/16 10:54, Michal Simek wrote:
> 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,
>                  ^

Thanks, I'll switch to map_physmem.

>   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.

ofdata_to_platdata is called right before probe, so I'm not sure there's 
any point in passing the physical address via the private data struct 
just to map it very shortly after & ignore it forevermore.

Thanks,
     Paul

> Thanks,
> Michal
>
>


More information about the U-Boot mailing list