diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpio/mpc8xxx_gpio.c | 108 | ||||
| -rw-r--r-- | drivers/net/ldpaa_eth/lx2160a.c | 4 | ||||
| -rw-r--r-- | drivers/pci/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/pci/pcie_fsl.c | 20 | ||||
| -rw-r--r-- | drivers/pci/pcie_fsl.h | 2 | ||||
| -rw-r--r-- | drivers/pci/pcie_layerscape_fixup.c | 458 | 
6 files changed, 512 insertions, 92 deletions
| diff --git a/drivers/gpio/mpc8xxx_gpio.c b/drivers/gpio/mpc8xxx_gpio.c index 1dfd22522c7..27881a73224 100644 --- a/drivers/gpio/mpc8xxx_gpio.c +++ b/drivers/gpio/mpc8xxx_gpio.c @@ -6,12 +6,15 @@   * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is   *   * Copyright 2010 eXMeritus, A Boeing Company + * Copyright 2020 NXP   */  #include <common.h>  #include <dm.h>  #include <mapmem.h>  #include <asm/gpio.h> +#include <asm/io.h> +#include <dm/of_access.h>  struct ccsr_gpio {  	u32	gpdir; @@ -20,6 +23,7 @@ struct ccsr_gpio {  	u32	gpier;  	u32	gpimr;  	u32	gpicr; +	u32	gpibe;  };  struct mpc8xxx_gpio_data { @@ -35,6 +39,7 @@ struct mpc8xxx_gpio_data {  	 */  	u32 dat_shadow;  	ulong type; +	bool  little_endian;  };  enum { @@ -47,33 +52,56 @@ inline u32 gpio_mask(uint gpio)  	return (1U << (31 - (gpio)));  } -static inline u32 mpc8xxx_gpio_get_val(struct ccsr_gpio *base, u32 mask) +static inline u32 mpc8xxx_gpio_get_val(struct udevice *dev, u32 mask)  { -	return in_be32(&base->gpdat) & mask; +	struct mpc8xxx_gpio_data *data = dev_get_priv(dev); + +	if (data->little_endian) +		return in_le32(&data->base->gpdat) & mask; +	else +		return in_be32(&data->base->gpdat) & mask;  } -static inline u32 mpc8xxx_gpio_get_dir(struct ccsr_gpio *base, u32 mask) +static inline u32 mpc8xxx_gpio_get_dir(struct udevice *dev, u32 mask)  { -	return in_be32(&base->gpdir) & mask; +	struct mpc8xxx_gpio_data *data = dev_get_priv(dev); + +	if (data->little_endian) +		return in_le32(&data->base->gpdir) & mask; +	else +		return in_be32(&data->base->gpdir) & mask;  } -static inline int mpc8xxx_gpio_open_drain_val(struct ccsr_gpio *base, u32 mask) +static inline int mpc8xxx_gpio_open_drain_val(struct udevice *dev, u32 mask)  { -	return in_be32(&base->gpodr) & mask; +	struct mpc8xxx_gpio_data *data = dev_get_priv(dev); + +	if (data->little_endian) +		return in_le32(&data->base->gpodr) & mask; +	else +		return in_be32(&data->base->gpodr) & mask;  } -static inline void mpc8xxx_gpio_open_drain_on(struct ccsr_gpio *base, u32 +static inline void mpc8xxx_gpio_open_drain_on(struct udevice *dev, u32  					      gpios)  { +	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);  	/* GPODR register 1 -> open drain on */ -	setbits_be32(&base->gpodr, gpios); +	if (data->little_endian) +		setbits_le32(&data->base->gpodr, gpios); +	else +		setbits_be32(&data->base->gpodr, gpios);  } -static inline void mpc8xxx_gpio_open_drain_off(struct ccsr_gpio *base, +static inline void mpc8xxx_gpio_open_drain_off(struct udevice *dev,  					       u32 gpios)  { +	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);  	/* GPODR register 0 -> open drain off (actively driven) */ -	clrbits_be32(&base->gpodr, gpios); +	if (data->little_endian) +		clrbits_le32(&data->base->gpodr, gpios); +	else +		clrbits_be32(&data->base->gpodr, gpios);  }  static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio) @@ -82,7 +110,10 @@ static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio)  	u32 mask = gpio_mask(gpio);  	/* GPDIR register 0 -> input */ -	clrbits_be32(&data->base->gpdir, mask); +	if (data->little_endian) +		clrbits_le32(&data->base->gpdir, mask); +	else +		clrbits_be32(&data->base->gpdir, mask);  	return 0;  } @@ -100,10 +131,20 @@ static int mpc8xxx_gpio_set_value(struct udevice *dev, uint gpio, int value)  		data->dat_shadow &= ~mask;  	} -	gpdir = in_be32(&base->gpdir); +	if (data->little_endian) +		gpdir = in_le32(&base->gpdir); +	else +		gpdir = in_be32(&base->gpdir); +  	gpdir |= gpio_mask(gpio); -	out_be32(&base->gpdat, gpdir & data->dat_shadow); -	out_be32(&base->gpdir, gpdir); + +	if (data->little_endian) { +		out_le32(&base->gpdat, gpdir & data->dat_shadow); +		out_le32(&base->gpdir, gpdir); +	} else { +		out_be32(&base->gpdat, gpdir & data->dat_shadow); +		out_be32(&base->gpdir, gpdir); +	}  	return 0;  } @@ -124,21 +165,20 @@ static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio)  {  	struct mpc8xxx_gpio_data *data = dev_get_priv(dev); -	if (!!mpc8xxx_gpio_get_dir(data->base, gpio_mask(gpio))) { +	if (!!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio))) {  		/* Output -> use shadowed value */  		return !!(data->dat_shadow & gpio_mask(gpio));  	}  	/* Input -> read value from GPDAT register */ -	return !!mpc8xxx_gpio_get_val(data->base, gpio_mask(gpio)); +	return !!mpc8xxx_gpio_get_val(dev, gpio_mask(gpio));  }  static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio)  { -	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);  	int dir; -	dir = !!mpc8xxx_gpio_get_dir(data->base, gpio_mask(gpio)); +	dir = !!mpc8xxx_gpio_get_dir(dev, gpio_mask(gpio));  	return dir ? GPIOF_OUTPUT : GPIOF_INPUT;  } @@ -146,14 +186,33 @@ static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio)  static int mpc8xxx_gpio_ofdata_to_platdata(struct udevice *dev)  {  	struct mpc8xxx_gpio_plat *plat = dev_get_platdata(dev); +	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);  	fdt_addr_t addr; -	u32 reg[2]; +	u32 i; +	u32 reg[4]; + +	if (ofnode_read_bool(dev->node, "little-endian")) +		data->little_endian = true; + +	if (data->little_endian) +		dev_read_u32_array(dev, "reg", reg, 4); +	else +		dev_read_u32_array(dev, "reg", reg, 2); + +	if (data->little_endian) { +		for (i = 0; i < 2; i++) +			reg[i] = be32_to_cpu(reg[i]); +	} -	dev_read_u32_array(dev, "reg", reg, 2);  	addr = dev_translate_address(dev, reg);  	plat->addr = addr; -	plat->size = reg[1]; + +	if (data->little_endian) +		plat->size = reg[3]; +	else +		plat->size = reg[1]; +  	plat->ngpios = dev_read_u32_default(dev, "ngpios", 32);  	return 0; @@ -198,6 +257,13 @@ static int mpc8xxx_gpio_probe(struct udevice *dev)  	if (!str)  		return -ENOMEM; +	if (ofnode_device_is_compatible(dev->node, "fsl,qoriq-gpio")) { +		unsigned long gpibe = data->addr + sizeof(struct ccsr_gpio) +			- sizeof(u32); + +		out_be32((unsigned int *)gpibe, 0xffffffff); +	} +  	uc_priv->bank_name = str;  	uc_priv->gpio_count = data->gpio_count; diff --git a/drivers/net/ldpaa_eth/lx2160a.c b/drivers/net/ldpaa_eth/lx2160a.c index 1e62c642039..e57f1a19a59 100644 --- a/drivers/net/ldpaa_eth/lx2160a.c +++ b/drivers/net/ldpaa_eth/lx2160a.c @@ -92,7 +92,7 @@ void fsl_rgmii_init(void)  		& FSL_CHASSIS3_EC1_REGSR_PRTCL_MASK;  	ec >>= FSL_CHASSIS3_EC1_REGSR_PRTCL_SHIFT; -	if (!ec && (wriop_is_enabled_dpmac(17) == -ENODEV)) +	if (!ec)  		wriop_init_dpmac_enet_if(17, PHY_INTERFACE_MODE_RGMII_ID);  #endif @@ -101,7 +101,7 @@ void fsl_rgmii_init(void)  		& FSL_CHASSIS3_EC2_REGSR_PRTCL_MASK;  	ec >>= FSL_CHASSIS3_EC2_REGSR_PRTCL_SHIFT; -	if (!ec && (wriop_is_enabled_dpmac(18) == -ENODEV)) +	if (!ec)  		wriop_init_dpmac_enet_if(18, PHY_INTERFACE_MODE_RGMII_ID);  #endif  } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index dd1cc652290..af927849508 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -179,6 +179,18 @@ config PCIE_LAYERSCAPE_RC  	  configured to Root Complex mode by clearing the corresponding bit of  	  RCW[HOST_AGT_PEX]. +config PCI_IOMMU_EXTRA_MAPPINGS +	bool "Support for specifying extra IOMMU mappings for PCI" +	depends on PCIE_LAYERSCAPE_RC +	help +	  Enable support for specifying extra IOMMU mappings for PCI +	  controllers through a special env var called "pci_iommu_extra" or +	  through a device tree property named "pci-iommu-extra" placed in +	  the node describing the PCI controller. +	  The intent is to cover SR-IOV scenarios which need mappings for VFs +	  and PCI hot-plug scenarios. More documentation can be found under: +	    arch/arm/cpu/armv8/fsl-layerscape/doc/README.pci_iommu_extra +  config PCIE_LAYERSCAPE_EP  	bool "Layerscape PCIe Endpoint mode support"  	depends on DM_PCI diff --git a/drivers/pci/pcie_fsl.c b/drivers/pci/pcie_fsl.c index ab33459e28e..fb50b8f5180 100644 --- a/drivers/pci/pcie_fsl.c +++ b/drivers/pci/pcie_fsl.c @@ -396,6 +396,19 @@ static int fsl_pcie_init_atmu(struct fsl_pcie *pcie)  	return 0;  } +static void fsl_pcie_dbi_read_only_reg_write_enable(struct fsl_pcie *pcie, +						    bool enable) +{ +	u32 val; + +	fsl_pcie_hose_read_config_dword(pcie, DBI_RO_WR_EN, &val); +	if (enable) +		val |= 1; +	else +		val &= ~1; +	fsl_pcie_hose_write_config_dword(pcie, DBI_RO_WR_EN, val); +} +  static int fsl_pcie_init_port(struct fsl_pcie *pcie)  {  	ccsr_fsl_pci_t *regs = pcie->regs; @@ -470,7 +483,7 @@ static int fsl_pcie_init_port(struct fsl_pcie *pcie)  	 * Set to 0 to protect the read-only registers.  	 */  #ifdef CONFIG_SYS_FSL_ERRATUM_A007815 -	clrbits_be32(®s->dbi_ro_wr_en, 0x01); +	fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);  #endif  	/* @@ -504,13 +517,12 @@ static int fsl_pcie_init_port(struct fsl_pcie *pcie)  static int fsl_pcie_fixup_classcode(struct fsl_pcie *pcie)  { -	ccsr_fsl_pci_t *regs = pcie->regs;  	u32 classcode_reg;  	u32 val;  	if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) {  		classcode_reg = PCI_CLASS_REVISION; -		setbits_be32(®s->dbi_ro_wr_en, 0x01); +		fsl_pcie_dbi_read_only_reg_write_enable(pcie, true);  	} else {  		classcode_reg = CSR_CLASSCODE;  	} @@ -521,7 +533,7 @@ static int fsl_pcie_fixup_classcode(struct fsl_pcie *pcie)  	fsl_pcie_hose_write_config_dword(pcie, classcode_reg, val);  	if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) -		clrbits_be32(®s->dbi_ro_wr_en, 0x01); +		fsl_pcie_dbi_read_only_reg_write_enable(pcie, false);  	return 0;  } diff --git a/drivers/pci/pcie_fsl.h b/drivers/pci/pcie_fsl.h index dc8368d5592..70c5f4e4cff 100644 --- a/drivers/pci/pcie_fsl.h +++ b/drivers/pci/pcie_fsl.h @@ -26,6 +26,8 @@  /* PCIe Link Status Register */  #define PCI_LSR				(FSL_PCIE_CAP_ID + 0x12) +#define DBI_RO_WR_EN			0x8bc +  #ifndef CONFIG_SYS_PCI_MEMORY_BUS  #define CONFIG_SYS_PCI_MEMORY_BUS	0  #endif diff --git a/drivers/pci/pcie_layerscape_fixup.c b/drivers/pci/pcie_layerscape_fixup.c index 1709cd3d230..c75cf26e0a5 100644 --- a/drivers/pci/pcie_layerscape_fixup.c +++ b/drivers/pci/pcie_layerscape_fixup.c @@ -19,9 +19,39 @@  #ifdef CONFIG_ARM  #include <asm/arch/clock.h>  #endif +#include <malloc.h> +#include <env.h>  #include "pcie_layerscape.h"  #include "pcie_layerscape_fixup_common.h" +static int fdt_pcie_get_nodeoffset(void *blob, struct ls_pcie_rc *pcie_rc) +{ +	int nodeoffset; +	uint svr; +	char *compat = NULL; + +	/* find pci controller node */ +	nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", +						   pcie_rc->dbi_res.start); +	if (nodeoffset < 0) { +#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ +		svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; +		if (svr == SVR_LS2088A || svr == SVR_LS2084A || +		    svr == SVR_LS2048A || svr == SVR_LS2044A || +		    svr == SVR_LS2081A || svr == SVR_LS2041A) +			compat = "fsl,ls2088a-pcie"; +		else +			compat = CONFIG_FSL_PCIE_COMPAT; + +		nodeoffset = +			fdt_node_offset_by_compat_reg(blob, compat, +						      pcie_rc->dbi_res.start); +#endif +	} + +	return nodeoffset; +} +  #if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2)  /*   * Return next available LUT index. @@ -127,30 +157,11 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob,  	u32 iommu_map[4];  	int nodeoffset;  	int lenp; -	uint svr; -	char *compat = NULL;  	struct ls_pcie *pcie = pcie_rc->pcie; -	/* find pci controller node */ -	nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", -						   pcie_rc->dbi_res.start); -	if (nodeoffset < 0) { -#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ -		svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; -		if (svr == SVR_LS2088A || svr == SVR_LS2084A || -		    svr == SVR_LS2048A || svr == SVR_LS2044A || -		    svr == SVR_LS2081A || svr == SVR_LS2041A) -			compat = "fsl,ls2088a-pcie"; -		else -			compat = CONFIG_FSL_PCIE_COMPAT; - -		if (compat) -			nodeoffset = fdt_node_offset_by_compat_reg(blob, -						compat, pcie_rc->dbi_res.start); -#endif -		if (nodeoffset < 0) -			return; -	} +	nodeoffset = fdt_pcie_get_nodeoffset(blob, pcie_rc); +	if (nodeoffset < 0) +		return;  	/* get phandle to iommu controller */  	prop = fdt_getprop_w(blob, nodeoffset, "iommu-map", &lenp); @@ -174,13 +185,323 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob,  	}  } +static int fdt_fixup_pcie_device_ls(void *blob, pci_dev_t bdf, +				    struct ls_pcie_rc *pcie_rc) +{ +	int streamid, index; + +	streamid = pcie_next_streamid(pcie_rc->stream_id_cur, +				      pcie_rc->pcie->idx); +	if (streamid < 0) { +		printf("ERROR: out of stream ids for BDF %d.%d.%d\n", +		       PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); +		return -ENOENT; +	} +	pcie_rc->stream_id_cur++; + +	index = ls_pcie_next_lut_index(pcie_rc); +	if (index < 0) { +		printf("ERROR: out of LUT indexes for BDF %d.%d.%d\n", +		       PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); +		return -ENOENT; +	} + +	/* map PCI b.d.f to streamID in LUT */ +	ls_pcie_lut_set_mapping(pcie_rc, index, bdf >> 8, streamid); +	/* update msi-map in device tree */ +	fdt_pcie_set_msi_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid); +	/* update iommu-map in device tree */ +	fdt_pcie_set_iommu_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid); + +	return 0; +} + +struct extra_iommu_entry { +	int action; +	pci_dev_t bdf; +	int num_vfs; +	bool noari; +}; + +#define EXTRA_IOMMU_ENTRY_HOTPLUG	1 +#define EXTRA_IOMMU_ENTRY_VFS		2 + +static struct extra_iommu_entry *get_extra_iommu_ents(void *blob, +						      int nodeoffset, +						      phys_addr_t addr, +						      int *cnt) +{ +	const char *s, *p, *tok; +	struct extra_iommu_entry *entries; +	int i = 0, b, d, f; + +	/* +	 * Retrieve extra IOMMU configuration from env var or from device tree. +	 * Env var is given priority. +	 */ +	s = env_get("pci_iommu_extra"); +	if (!s) { +		s = fdt_getprop(blob, nodeoffset, "pci-iommu-extra", NULL); +	} else { +		phys_addr_t pci_base; +		char *endp; + +		/* +		 * In env var case the config string has "pci@0x..." in +		 * addition. Parse this part and match it by address against +		 * the input pci controller's registers base address. +		 */ +		tok = s; +		p = strchrnul(s + 1, ','); +		s = NULL; +		do { +			if (!strncmp(tok, "pci", 3)) { +				pci_base = simple_strtoul(tok  + 4, &endp, 0); +				if (pci_base == addr) { +					s = endp + 1; +					break; +				} +			} +			p = strchrnul(p + 1, ','); +			tok = p + 1; +		} while (*p); +	} + +	/* +	 * If no env var or device tree property found or pci register base +	 * address mismatches, bail out +	 */ +	if (!s) +		return NULL; + +	/* +	 * In order to find how many action entries to allocate, count number +	 * of actions by interating through the pairs of bdfs and actions. +	 */ +	*cnt = 0; +	p = s; +	while (*p && strncmp(p, "pci", 3)) { +		if (*p == ',') +			(*cnt)++; +		p++; +	} +	if (!(*p)) +		(*cnt)++; + +	if (!(*cnt) || (*cnt) % 2) { +		printf("ERROR: invalid or odd extra iommu token count %d\n", +		       *cnt); +		return NULL; +	} +	*cnt = (*cnt) / 2; + +	entries = malloc((*cnt) * sizeof(*entries)); +	if (!entries) { +		printf("ERROR: fail to allocate extra iommu entries\n"); +		return NULL; +	} + +	/* +	 * Parse action entries one by one and store the information in the +	 * newly allocated actions array. +	 */ +	p = s; +	while (p) { +		/* Extract BDF */ +		b = simple_strtoul(p, (char **)&p, 0); p++; +		d = simple_strtoul(p, (char **)&p, 0); p++; +		f = simple_strtoul(p, (char **)&p, 0); p++; +		entries[i].bdf = PCI_BDF(b, d, f); + +		/* Parse action */ +		if (!strncmp(p, "hp", 2)) { +			/* Hot-plug entry */ +			entries[i].action = EXTRA_IOMMU_ENTRY_HOTPLUG; +			p += 2; +		} else if (!strncmp(p, "vfs", 3) || +			   !strncmp(p, "noari_vfs", 9)) { +			/* VFs or VFs with ARI disabled entry */ +			entries[i].action = EXTRA_IOMMU_ENTRY_VFS; +			entries[i].noari = !strncmp(p, "noari_vfs", 9); + +			/* +			 * Parse and store total number of VFs to allocate +			 * IOMMU entries for. +			 */ +			p = strchr(p, '='); +			entries[i].num_vfs = simple_strtoul(p + 1, (char **)&p, +							    0); +			if (*p) +				p++; +		} else { +			printf("ERROR: invalid action in extra iommu entry\n"); +			free(entries); + +			return NULL; +		} + +		if (!(*p) || !strncmp(p, "pci", 3)) +			break; + +		i++; +	} + +	return entries; +} + +static void get_vf_offset_and_stride(struct udevice *dev, int sriov_pos, +				     struct extra_iommu_entry *entry, +				     u16 *offset, u16 *stride) +{ +	u16 tmp16; +	u32 tmp32; +	bool have_ari = false; +	int pos; +	struct udevice *pf_dev; + +	dm_pci_read_config16(dev, sriov_pos + PCI_SRIOV_TOTAL_VF, &tmp16); +	if (entry->num_vfs > tmp16) { +		printf("WARN: requested no. of VFs %d exceeds total of %d\n", +		       entry->num_vfs, tmp16); +	} + +	/* +	 * The code below implements the VF Discovery recomandations specified +	 * in PCIe base spec "9.2.1.2 VF Discovery", quoted below: +	 * +	 * VF Discovery +	 * +	 * The First VF Offset and VF Stride fields in the SR-IOV extended +	 * capability are 16-bit Routing ID offsets. These offsets are used to +	 * compute the Routing IDs for the VFs with the following restrictions: +	 *  - The value in NumVFs in a PF (Section 9.3.3.7) may affect the +	 *    values in First VF Offset (Section 9.3.3.9) and VF Stride +	 *    (Section 9.3.3.10) of that PF. +	 *  - The value in ARI Capable Hierarchy (Section 9.3.3.3.5) in the +	 *    lowest-numbered PF of the Device (for example PF0) may affect +	 *    the values in First VF Offset and VF Stride in all PFs of the +	 *    Device. +	 *  - NumVFs of a PF may only be changed when VF Enable +	 *    (Section 9.3.3.3.1) of that PF is Clear. +	 *  - ARI Capable Hierarchy (Section 9.3.3.3.5) may only be changed +	 *    when VF Enable is Clear in all PFs of a Device. +	 */ + +	/* Clear VF enable for all PFs */ +	device_foreach_child(pf_dev, dev->parent) { +		dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, +				     &tmp16); +		tmp16 &= ~PCI_SRIOV_CTRL_VFE; +		dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, +				      tmp16); +	} + +	/* Obtain a reference to PF0 device */ +	if (dm_pci_bus_find_bdf(PCI_BDF(PCI_BUS(entry->bdf), +					PCI_DEV(entry->bdf), 0), &pf_dev)) { +		printf("WARN: failed to get PF0\n"); +	} + +	if (entry->noari) +		goto skip_ari; + +	/* Check that connected downstream port supports ARI Forwarding */ +	pos = dm_pci_find_capability(dev->parent, PCI_CAP_ID_EXP); +	dm_pci_read_config32(dev->parent, pos + PCI_EXP_DEVCAP2, &tmp32); +	if (!(tmp32 & PCI_EXP_DEVCAP2_ARI)) +		goto skip_ari; + +	/* Check that PF supports Alternate Routing ID */ +	if (!dm_pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) +		goto skip_ari; + +	/* Set ARI Capable Hierarcy for PF0 */ +	dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, &tmp16); +	tmp16 |= PCI_SRIOV_CTRL_ARI; +	dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, tmp16); +	have_ari = true; + +skip_ari: +	if (!have_ari) { +		/* +		 * No ARI support or disabled so clear ARI Capable Hierarcy +		 * for PF0 +		 */ +		dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, +				     &tmp16); +		tmp16 &= ~PCI_SRIOV_CTRL_ARI; +		dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, +				      tmp16); +	} + +	/* Set requested number of VFs */ +	dm_pci_write_config16(dev, sriov_pos + PCI_SRIOV_NUM_VF, +			      entry->num_vfs); + +	/* Read VF stride and offset with the configs just made */ +	dm_pci_read_config16(dev, sriov_pos + PCI_SRIOV_VF_OFFSET, offset); +	dm_pci_read_config16(dev, sriov_pos + PCI_SRIOV_VF_STRIDE, stride); + +	if (have_ari) { +		/* Reset to default ARI Capable Hierarcy bit for PF0 */ +		dm_pci_read_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, +				     &tmp16); +		tmp16 &= ~PCI_SRIOV_CTRL_ARI; +		dm_pci_write_config16(pf_dev, sriov_pos + PCI_SRIOV_CTRL, +				      tmp16); +	} +	/* Reset to default the number of VFs */ +	dm_pci_write_config16(dev, sriov_pos + PCI_SRIOV_NUM_VF, 0); +} + +static int fdt_fixup_pci_vfs(void *blob, struct extra_iommu_entry *entry, +			     struct ls_pcie_rc *pcie_rc) +{ +	struct udevice *dev, *bus; +	u16 vf_offset, vf_stride; +	int i, sriov_pos; +	pci_dev_t bdf; + +	if (dm_pci_bus_find_bdf(entry->bdf, &dev)) { +		printf("ERROR: BDF %d.%d.%d not found\n", PCI_BUS(entry->bdf), +		       PCI_DEV(entry->bdf), PCI_FUNC(entry->bdf)); +		return 0; +	} + +	sriov_pos = dm_pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); +	if (!sriov_pos) { +		printf("WARN: trying to set VFs on non-SRIOV dev\n"); +		return 0; +	} + +	get_vf_offset_and_stride(dev, sriov_pos, entry, &vf_offset, &vf_stride); + +	for (bus = dev; device_is_on_pci_bus(bus);) +		bus = bus->parent; + +	bdf = entry->bdf - PCI_BDF(bus->seq, 0, 0) + (vf_offset << 8); + +	for (i = 0; i < entry->num_vfs; i++) { +		if (fdt_fixup_pcie_device_ls(blob, bdf, pcie_rc) < 0) +			return -1; +		bdf += vf_stride << 8; +	} + +	printf("Added %d iommu VF mappings for PF %d.%d.%d\n", +	       entry->num_vfs, PCI_BUS(entry->bdf), +	       PCI_DEV(entry->bdf), PCI_FUNC(entry->bdf)); + +	return 0; +} +  static void fdt_fixup_pcie_ls(void *blob)  {  	struct udevice *dev, *bus;  	struct ls_pcie_rc *pcie_rc; -	int streamid; -	int index;  	pci_dev_t bdf; +	struct extra_iommu_entry *entries; +	int i, cnt, nodeoffset; +  	/* Scan all known buses */  	for (pci_find_first_device(&dev); @@ -196,33 +517,57 @@ static void fdt_fixup_pcie_ls(void *blob)  		pcie_rc = dev_get_priv(bus); -		streamid = pcie_next_streamid(pcie_rc->stream_id_cur, -					      pcie_rc->pcie->idx); -		if (streamid < 0) { -			debug("ERROR: no stream ids free\n"); +		/* the DT fixup must be relative to the hose first_busno */ +		bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0); + +		if (fdt_fixup_pcie_device_ls(blob, bdf, pcie_rc) < 0) +			break; +	} + +	if (!IS_ENABLED(CONFIG_PCI_IOMMU_EXTRA_MAPPINGS)) +		goto skip; + +	list_for_each_entry(pcie_rc, &ls_pcie_list, list) { +		nodeoffset = fdt_pcie_get_nodeoffset(blob, pcie_rc); +		if (nodeoffset < 0) { +			printf("ERROR: couldn't find pci node\n");  			continue; -		} else { -			pcie_rc->stream_id_cur++;  		} -		index = ls_pcie_next_lut_index(pcie_rc); -		if (index < 0) { -			debug("ERROR: no LUT indexes free\n"); +		entries = get_extra_iommu_ents(blob, nodeoffset, +					       pcie_rc->dbi_res.start, &cnt); +		if (!entries)  			continue; -		} -		/* the DT fixup must be relative to the hose first_busno */ -		bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0); -		/* map PCI b.d.f to streamID in LUT */ -		ls_pcie_lut_set_mapping(pcie_rc, index, bdf >> 8, -					streamid); -		/* update msi-map in device tree */ -		fdt_pcie_set_msi_map_entry_ls(blob, pcie_rc, bdf >> 8, -					      streamid); -		/* update iommu-map in device tree */ -		fdt_pcie_set_iommu_map_entry_ls(blob, pcie_rc, bdf >> 8, -						streamid); +		for (i = 0; i < cnt; i++) { +			if (entries[i].action == EXTRA_IOMMU_ENTRY_HOTPLUG) { +				bdf = entries[i].bdf; +				printf("Added iommu map for hotplug %d.%d.%d\n", +				       PCI_BUS(bdf), PCI_DEV(bdf), +				       PCI_FUNC(bdf)); +				if (fdt_fixup_pcie_device_ls(blob, bdf, +							     pcie_rc) < 0) { +					free(entries); +					return; +				} +			} else if (entries[i].action == EXTRA_IOMMU_ENTRY_VFS) { +				if (fdt_fixup_pci_vfs(blob, &entries[i], +						      pcie_rc) < 0) { +					free(entries); +					return; +				} +			} else { +				printf("Invalid action %d for BDF %d.%d.%d\n", +				       entries[i].action, +				       PCI_BUS(entries[i].bdf), +				       PCI_DEV(entries[i].bdf), +				       PCI_FUNC(entries[i].bdf)); +			} +		} +		free(entries);  	} + +skip:  	pcie_board_fix_fdt(blob);  }  #endif @@ -230,28 +575,11 @@ static void fdt_fixup_pcie_ls(void *blob)  static void ft_pcie_rc_fix(void *blob, struct ls_pcie_rc *pcie_rc)  {  	int off; -	uint svr; -	char *compat = NULL;  	struct ls_pcie *pcie = pcie_rc->pcie; -	off = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", -					    pcie_rc->dbi_res.start); -	if (off < 0) { -#ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ -		svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; -		if (svr == SVR_LS2088A || svr == SVR_LS2084A || -		    svr == SVR_LS2048A || svr == SVR_LS2044A || -		    svr == SVR_LS2081A || svr == SVR_LS2041A) -			compat = "fsl,ls2088a-pcie"; -		else -			compat = CONFIG_FSL_PCIE_COMPAT; -		if (compat) -			off = fdt_node_offset_by_compat_reg(blob, -					compat, pcie_rc->dbi_res.start); -#endif -		if (off < 0) -			return; -	} +	off = fdt_pcie_get_nodeoffset(blob, pcie_rc); +	if (off < 0) +		return;  	if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE)  		fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0); | 
