aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/core/ofnode.c22
-rw-r--r--drivers/firmware/firmware-zynqmp.c8
-rw-r--r--drivers/gpio/mpc8xxx_gpio.c108
-rw-r--r--drivers/mailbox/zynqmp-ipi.c2
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/mmc/sdhci.c3
-rw-r--r--drivers/mmc/zynq_sdhci.c406
-rw-r--r--drivers/mtd/spi/sf_internal.h2
-rw-r--r--drivers/net/ldpaa_eth/lx2160a.c4
-rw-r--r--drivers/pci/Kconfig12
-rw-r--r--drivers/pci/pcie_fsl.c20
-rw-r--r--drivers/pci/pcie_fsl.h2
-rw-r--r--drivers/pci/pcie_layerscape_fixup.c458
-rw-r--r--drivers/serial/serial_pl01x.c13
-rw-r--r--drivers/spi/xilinx_spi.c8
-rw-r--r--drivers/spi/zynq_qspi.c84
-rw-r--r--drivers/spi/zynq_spi.c35
17 files changed, 1036 insertions, 158 deletions
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 7d1b89514c..a68076bf35 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -476,6 +476,28 @@ ofnode ofnode_get_chosen_node(const char *name)
return ofnode_path(prop);
}
+const void *ofnode_read_aliases_prop(const char *propname, int *sizep)
+{
+ ofnode node;
+
+ node = ofnode_path("/aliases");
+
+ return ofnode_read_prop(node, propname, sizep);
+}
+
+ofnode ofnode_get_aliases_node(const char *name)
+{
+ const char *prop;
+
+ prop = ofnode_read_aliases_prop(name, NULL);
+ if (!prop)
+ return ofnode_null();
+
+ debug("%s: node_path: %s\n", __func__, prop);
+
+ return ofnode_path(prop);
+}
+
int ofnode_get_child_count(ofnode parent)
{
ofnode child;
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index 7583f24a20..d4dc856baf 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -165,6 +165,14 @@ int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
*/
u32 regs[] = {api_id, arg0, arg1, arg2, arg3};
+ if (api_id == PM_FPGA_LOAD) {
+ /* Swap addr_hi/low because of incompatibility */
+ u32 temp = regs[1];
+
+ regs[1] = regs[2];
+ regs[2] = temp;
+ }
+
ipi_req(regs, PAYLOAD_ARG_CNT, ret_payload, PAYLOAD_ARG_CNT);
#else
return -EPERM;
diff --git a/drivers/gpio/mpc8xxx_gpio.c b/drivers/gpio/mpc8xxx_gpio.c
index 1dfd22522c..27881a7322 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/mailbox/zynqmp-ipi.c b/drivers/mailbox/zynqmp-ipi.c
index 9483ed9cef..847a03648b 100644
--- a/drivers/mailbox/zynqmp-ipi.c
+++ b/drivers/mailbox/zynqmp-ipi.c
@@ -56,7 +56,7 @@ static int zynqmp_ipi_send(struct mbox_chan *chan, const void *data)
/* Wait until observation bit is cleared */
ret = wait_for_bit_le32(&ipi_int_apu->obs, IPI_BIT_MASK_PMU0, false,
- 100, false);
+ 1000, false);
debug("%s, send %ld bytes\n", __func__, msg->len);
return ret;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b67e906a76..29432ae7eb 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -376,13 +376,6 @@ config SPL_I2C_EEPROM
This option is an SPL-variant of the I2C_EEPROM option.
See the help of I2C_EEPROM for details.
-config ZYNQ_GEM_I2C_MAC_OFFSET
- hex "Set the I2C MAC offset"
- default 0x0
- depends on DM_I2C
- help
- Set the MAC offset for i2C.
-
if I2C_EEPROM
config SYS_I2C_EEPROM_ADDR
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index d549a264d7..0628934312 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -812,7 +812,8 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
cfg->host_caps &= ~MMC_MODE_HS_52MHz;
}
- if (!(cfg->voltages & MMC_VDD_165_195))
+ if (!(cfg->voltages & MMC_VDD_165_195) ||
+ (host->quirks & SDHCI_QUIRK_NO_1_8_V))
caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50);
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index 775c17baac..147ecc0d70 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -19,6 +19,20 @@
#include <sdhci.h>
#include <zynqmp_tap_delay.h>
+#define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8
+#define SDHCI_ARASAN_OTAPDLY_REGISTER 0xF0FC
+#define SDHCI_ITAPDLY_CHGWIN 0x200
+#define SDHCI_ITAPDLY_ENABLE 0x100
+#define SDHCI_OTAPDLY_ENABLE 0x40
+
+#define SDHCI_TUNING_LOOP_COUNT 40
+#define MMC_BANK2 0x2
+
+struct arasan_sdhci_clk_data {
+ int clk_phase_in[MMC_TIMING_MMC_HS400 + 1];
+ int clk_phase_out[MMC_TIMING_MMC_HS400 + 1];
+};
+
struct arasan_sdhci_plat {
struct mmc_config cfg;
struct mmc mmc;
@@ -26,29 +40,35 @@ struct arasan_sdhci_plat {
struct arasan_sdhci_priv {
struct sdhci_host *host;
+ struct arasan_sdhci_clk_data clk_data;
u8 deviceid;
u8 bank;
+ u8 no_1p8;
};
-#if defined(CONFIG_ARCH_ZYNQMP)
-#define MMC_HS200_BUS_SPEED 5
+#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL)
+/* Default settings for ZynqMP Clock Phases */
+const u32 zynqmp_iclk_phases[] = {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0};
+const u32 zynqmp_oclk_phases[] = {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0};
+
+/* Default settings for Versal Clock Phases */
+const u32 versal_iclk_phases[] = {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0};
+const u32 versal_oclk_phases[] = {0, 60, 48, 0, 48, 72, 90, 36, 60, 90, 0};
static const u8 mode2timing[] = {
- [MMC_LEGACY] = UHS_SDR12_BUS_SPEED,
- [MMC_HS] = HIGH_SPEED_BUS_SPEED,
- [SD_HS] = HIGH_SPEED_BUS_SPEED,
- [MMC_HS_52] = HIGH_SPEED_BUS_SPEED,
- [MMC_DDR_52] = HIGH_SPEED_BUS_SPEED,
- [UHS_SDR12] = UHS_SDR12_BUS_SPEED,
- [UHS_SDR25] = UHS_SDR25_BUS_SPEED,
- [UHS_SDR50] = UHS_SDR50_BUS_SPEED,
- [UHS_DDR50] = UHS_DDR50_BUS_SPEED,
- [UHS_SDR104] = UHS_SDR104_BUS_SPEED,
- [MMC_HS_200] = MMC_HS200_BUS_SPEED,
+ [MMC_LEGACY] = MMC_TIMING_LEGACY,
+ [MMC_HS] = MMC_TIMING_MMC_HS,
+ [SD_HS] = MMC_TIMING_SD_HS,
+ [MMC_HS_52] = MMC_TIMING_UHS_SDR50,
+ [MMC_DDR_52] = MMC_TIMING_UHS_DDR50,
+ [UHS_SDR12] = MMC_TIMING_UHS_SDR12,
+ [UHS_SDR25] = MMC_TIMING_UHS_SDR25,
+ [UHS_SDR50] = MMC_TIMING_UHS_SDR50,
+ [UHS_DDR50] = MMC_TIMING_UHS_DDR50,
+ [UHS_SDR104] = MMC_TIMING_UHS_SDR104,
+ [MMC_HS_200] = MMC_TIMING_MMC_HS200,
};
-#define SDHCI_TUNING_LOOP_COUNT 40
-
static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid)
{
u16 clk;
@@ -156,17 +176,352 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
return 0;
}
+/**
+ * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
+ *
+ * Set the SD Output Clock Tap Delays for Output path
+ *
+ * @host: Pointer to the sdhci_host structure.
+ * @degrees: The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_zynqmp_sdcardclk_set_phase(struct sdhci_host *host,
+ int degrees)
+{
+ struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev);
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u8 tap_delay, tap_max = 0;
+ int ret;
+ int timing = mode2timing[mmc->selected_mode];
+
+ /*
+ * This is applicable for SDHCI_SPEC_300 and above
+ * ZynqMP does not set phase for <=25MHz clock.
+ * If degrees is zero, no need to do anything.
+ */
+ if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 ||
+ timing == MMC_TIMING_LEGACY ||
+ timing == MMC_TIMING_UHS_SDR12 || !degrees)
+ return 0;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ /* For 50MHz clock, 30 Taps are available */
+ tap_max = 30;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ /* For 100MHz clock, 15 Taps are available */
+ tap_max = 15;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ /* For 200MHz clock, 8 Taps are available */
+ tap_max = 8;
+ default:
+ break;
+ }
+
+ tap_delay = (degrees * tap_max) / 360;
+
+ arasan_zynqmp_set_tapdelay(priv->deviceid, 0, tap_delay);
+
+ return ret;
+}
+
+/**
+ * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays
+ *
+ * Set the SD Input Clock Tap Delays for Input path
+ *
+ * @host: Pointer to the sdhci_host structure.
+ * @degrees: The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_zynqmp_sampleclk_set_phase(struct sdhci_host *host,
+ int degrees)
+{
+ struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev);
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u8 tap_delay, tap_max = 0;
+ int ret;
+ int timing = mode2timing[mmc->selected_mode];
+
+ /*
+ * This is applicable for SDHCI_SPEC_300 and above
+ * ZynqMP does not set phase for <=25MHz clock.
+ * If degrees is zero, no need to do anything.
+ */
+ if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 ||
+ timing == MMC_TIMING_LEGACY ||
+ timing == MMC_TIMING_UHS_SDR12 || !degrees)
+ return 0;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ /* For 50MHz clock, 120 Taps are available */
+ tap_max = 120;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ /* For 100MHz clock, 60 Taps are available */
+ tap_max = 60;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ /* For 200MHz clock, 30 Taps are available */
+ tap_max = 30;
+ default:
+ break;
+ }
+
+ tap_delay = (degrees * tap_max) / 360;
+
+ arasan_zynqmp_set_tapdelay(priv->deviceid, tap_delay, 0);
+
+ return ret;
+}
+
+/**
+ * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
+ *
+ * Set the SD Output Clock Tap Delays for Output path
+ *
+ * @host: Pointer to the sdhci_host structure.
+ * @degrees The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_versal_sdcardclk_set_phase(struct sdhci_host *host,
+ int degrees)
+{
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u8 tap_delay, tap_max = 0;
+ int ret;
+ int timing = mode2timing[mmc->selected_mode];
+
+ /*
+ * This is applicable for SDHCI_SPEC_300 and above
+ * Versal does not set phase for <=25MHz clock.
+ * If degrees is zero, no need to do anything.
+ */
+ if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 ||
+ timing == MMC_TIMING_LEGACY ||
+ timing == MMC_TIMING_UHS_SDR12 || !degrees)
+ return 0;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ /* For 50MHz clock, 30 Taps are available */
+ tap_max = 30;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ /* For 100MHz clock, 15 Taps are available */
+ tap_max = 15;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ /* For 200MHz clock, 8 Taps are available */
+ tap_max = 8;
+ default:
+ break;
+ }
+
+ tap_delay = (degrees * tap_max) / 360;
+
+ /* Set the Clock Phase */
+ if (tap_delay) {
+ u32 regval;
+
+ regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER);
+ regval |= SDHCI_OTAPDLY_ENABLE;
+ sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
+ regval |= tap_delay;
+ sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
+ }
+
+ return ret;
+}
+
+/**
+ * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays
+ *
+ * Set the SD Input Clock Tap Delays for Input path
+ *
+ * @host: Pointer to the sdhci_host structure.
+ * @degrees The clock phase shift between 0 - 359.
+ * Return: 0 on success and error value on error
+ */
+static int sdhci_versal_sampleclk_set_phase(struct sdhci_host *host,
+ int degrees)
+{
+ struct mmc *mmc = (struct mmc *)host->mmc;
+ u8 tap_delay, tap_max = 0;
+ int ret;
+ int timing = mode2timing[mmc->selected_mode];
+
+ /*
+ * This is applicable for SDHCI_SPEC_300 and above
+ * Versal does not set phase for <=25MHz clock.
+ * If degrees is zero, no need to do anything.
+ */
+ if (SDHCI_GET_VERSION(host) < SDHCI_SPEC_300 ||
+ timing == MMC_TIMING_LEGACY ||
+ timing == MMC_TIMING_UHS_SDR12 || !degrees)
+ return 0;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_UHS_SDR25:
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ /* For 50MHz clock, 120 Taps are available */
+ tap_max = 120;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ /* For 100MHz clock, 60 Taps are available */
+ tap_max = 60;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ /* For 200MHz clock, 30 Taps are available */
+ tap_max = 30;
+ default:
+ break;
+ }
+
+ tap_delay = (degrees * tap_max) / 360;
+
+ /* Set the Clock Phase */
+ if (tap_delay) {
+ u32 regval;
+
+ regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ regval |= SDHCI_ITAPDLY_CHGWIN;
+ sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ regval |= SDHCI_ITAPDLY_ENABLE;
+ sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ regval |= tap_delay;
+ sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ regval &= ~SDHCI_ITAPDLY_CHGWIN;
+ sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
+ }
+
+ return ret;
+}
+
static void arasan_sdhci_set_tapdelay(struct sdhci_host *host)
{
struct arasan_sdhci_priv *priv = dev_get_priv(host->mmc->dev);
+ struct arasan_sdhci_clk_data *clk_data = &priv->clk_data;
struct mmc *mmc = (struct mmc *)host->mmc;
- u8 uhsmode;
+ struct udevice *dev = mmc->dev;
+ u8 timing = mode2timing[mmc->selected_mode];
+ u32 iclk_phase = clk_data->clk_phase_in[timing];
+ u32 oclk_phase = clk_data->clk_phase_out[timing];
+
+ dev_dbg(dev, "%s, host:%s, mode:%d\n", __func__, host->name, timing);
+
+ if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) &&
+ device_is_compatible(dev, "xlnx,zynqmp-8.9a")) {
+ sdhci_zynqmp_sampleclk_set_phase(host, iclk_phase);
+ sdhci_zynqmp_sdcardclk_set_phase(host, oclk_phase);
+ } else if (IS_ENABLED(CONFIG_ARCH_VERSAL) &&
+ device_is_compatible(dev, "xlnx,versal-8.9a")) {
+ sdhci_versal_sampleclk_set_phase(host, iclk_phase);
+ sdhci_versal_sdcardclk_set_phase(host, oclk_phase);
+ }
+}
- uhsmode = mode2timing[mmc->selected_mode];
+static void arasan_dt_read_clk_phase(struct udevice *dev, unsigned char timing,
+ const char *prop)
+{
+ struct arasan_sdhci_priv *priv = dev_get_priv(dev);
+ struct arasan_sdhci_clk_data *clk_data = &priv->clk_data;
+ u32 clk_phase[2] = {0};
+
+ /*
+ * Read Tap Delay values from DT, if the DT does not contain the
+ * Tap Values then use the pre-defined values
+ */
+ if (dev_read_u32_array(dev, prop, &clk_phase[0], 2)) {
+ dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n",
+ prop, clk_data->clk_phase_in[timing],
+ clk_data->clk_phase_out[timing]);
+ return;
+ }
- if (uhsmode >= UHS_SDR25_BUS_SPEED)
- arasan_zynqmp_set_tapdelay(priv->deviceid, uhsmode,
- priv->bank);
+ /* The values read are Input and Output Clock Delays in order */
+ clk_data->clk_phase_in[timing] = clk_phase[0];
+ clk_data->clk_phase_out[timing] = clk_phase[1];
+}
+
+/**
+ * arasan_dt_parse_clk_phases - Read Tap Delay values from DT
+ *
+ * Called at initialization to parse the values of Tap Delays.
+ *
+ * @dev: Pointer to our struct udevice.
+ */
+static void arasan_dt_parse_clk_phases(struct udevice *dev)
+{
+ struct arasan_sdhci_priv *priv = dev_get_priv(dev);
+ struct arasan_sdhci_clk_data *clk_data = &priv->clk_data;
+ int i;
+
+ if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) &&
+ device_is_compatible(dev, "xlnx,zynqmp-8.9a")) {
+ for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
+ clk_data->clk_phase_in[i] = zynqmp_iclk_phases[i];
+ clk_data->clk_phase_out[i] = zynqmp_oclk_phases[i];
+ }
+
+ if (priv->bank == MMC_BANK2) {
+ clk_data->clk_phase_out[MMC_TIMING_UHS_SDR104] = 90;
+ clk_data->clk_phase_out[MMC_TIMING_MMC_HS200] = 90;
+ }
+ }
+
+ if (IS_ENABLED(CONFIG_ARCH_VERSAL) &&
+ device_is_compatible(dev, "xlnx,versal-8.9a")) {
+ for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
+ clk_data->clk_phase_in[i] = versal_iclk_phases[i];
+ clk_data->clk_phase_out[i] = versal_oclk_phases[i];
+ }
+ }
+
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_LEGACY,
+ "clk-phase-legacy");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS,
+ "clk-phase-mmc-hs");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_SD_HS,
+ "clk-phase-sd-hs");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR12,
+ "clk-phase-uhs-sdr12");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR25,
+ "clk-phase-uhs-sdr25");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR50,
+ "clk-phase-uhs-sdr50");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_SDR104,
+ "clk-phase-uhs-sdr104");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_UHS_DDR50,
+ "clk-phase-uhs-ddr50");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_DDR52,
+ "clk-phase-mmc-ddr52");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS200,
+ "clk-phase-mmc-hs200");
+ arasan_dt_read_clk_phase(dev, MMC_TIMING_MMC_HS400,
+ "clk-phase-mmc-hs400");
}
static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
@@ -184,12 +539,10 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
}
if (mmc->selected_mode > SD_HS &&
- mmc->selected_mode <= UHS_DDR50)
+ mmc->selected_mode <= MMC_HS_200)
sdhci_set_uhs_timing(host);
}
-#endif
-#if defined(CONFIG_ARCH_ZYNQMP)
const struct sdhci_ops arasan_ops = {
.platform_execute_tuning = &arasan_sdhci_execute_tuning,
.set_delay = &arasan_sdhci_set_tapdelay,
@@ -236,6 +589,9 @@ static int arasan_sdhci_probe(struct udevice *dev)
host->quirks |= SDHCI_QUIRK_BROKEN_HISPD_MODE;
#endif
+ if (priv->no_1p8)
+ host->quirks |= SDHCI_QUIRK_NO_1_8_V;
+
plat->cfg.f_max = CONFIG_ZYNQ_SDHCI_MAX_FREQ;
ret = mmc_of_parse(dev, &plat->cfg);
@@ -267,8 +623,9 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
priv->host->name = dev->name;
-#if defined(CONFIG_ARCH_ZYNQMP)
+#if defined(CONFIG_ARCH_ZYNQMP) || defined(CONFIG_ARCH_VERSAL)
priv->host->ops = &arasan_ops;
+ arasan_dt_parse_clk_phases(dev);
#endif
priv->host->ioaddr = (void *)dev_read_addr(dev);
@@ -277,6 +634,7 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
priv->deviceid = dev_read_u32_default(dev, "xlnx,device_id", -1);
priv->bank = dev_read_u32_default(dev, "xlnx,mio-bank", 0);
+ priv->no_1p8 = dev_read_bool(dev, "no-1-8-v");
return 0;
}
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index dabd40a4cc..9ceff0e7c1 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -67,7 +67,7 @@ struct flash_info {
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
#define USE_CLSR BIT(14) /* use CLSR command */
#define SPI_NOR_HAS_SST26LOCK BIT(15) /* Flash supports lock/unlock via BPR */
-#define SPI_NOR_OCTAL_READ BIT(16) /* Flash supports Octal Read */
+#define SPI_NOR_OCTAL_READ BIT(16) /* Flash supports Octal Read */
};
extern const struct flash_info spi_nor_ids[];
diff --git a/drivers/net/ldpaa_eth/lx2160a.c b/drivers/net/ldpaa_eth/lx2160a.c
index 1e62c64203..e57f1a19a5 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 dd1cc65229..af92784950 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 ab33459e28..fb50b8f518 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(&regs->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(&regs->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(&regs->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 dc8368d559..70c5f4e4cf 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 1709cd3d23..c75cf26e0a 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);
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index 2772c25f1d..d9e35c6a2b 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -19,6 +19,7 @@
#include <watchdog.h>
#include <asm/io.h>
#include <serial.h>
+#include <dm/device_compat.h>
#include <dm/platform_data/serial_pl01x.h>
#include <linux/compiler.h>
#include "serial_pl01x_internal.h"
@@ -362,8 +363,18 @@ int pl01x_serial_ofdata_to_platdata(struct udevice *dev)
plat->clock = dev_read_u32_default(dev, "clock", CONFIG_PL011_CLOCK);
ret = clk_get_by_index(dev, 0, &clk);
if (!ret) {
- clk_enable(&clk);
+ ret = clk_enable(&clk);
+ if (ret && ret != -ENOSYS) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+
plat->clock = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(plat->clock)) {
+ dev_err(dev, "failed to get rate\n");
+ return plat->clock;
+ }
+ debug("%s: CLK %d\n", __func__, plat->clock);
}
plat->type = dev_get_driver_data(dev);
plat->skip_init = dev_read_bool(dev, "skip-init");
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 348630faf3..47a5571aec 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -214,7 +214,7 @@ static void xilinx_spi_startup_block(struct udevice *dev, unsigned int bytes,
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
const unsigned char *txp = dout;
unsigned char *rxp = din;
- u32 reg, count;
+ u32 reg;
u32 txbytes = bytes;
u32 rxbytes = bytes;
@@ -224,10 +224,10 @@ static void xilinx_spi_startup_block(struct udevice *dev, unsigned int bytes,
* it sets txp to the initial value for the normal operation.
*/
for ( ; priv->startup < 2; priv->startup++) {
- count = xilinx_spi_fill_txfifo(bus, txp, txbytes);
+ xilinx_spi_fill_txfifo(bus, txp, txbytes);
reg = readl(&regs->spicr) & ~SPICR_MASTER_INHIBIT;
writel(reg, &regs->spicr);
- count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes);
+ xilinx_spi_read_rxfifo(bus, rxp, rxbytes);
txp = din;
if (priv->startup) {
@@ -251,7 +251,7 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
unsigned char *rxp = din;
u32 txbytes = bytes;
u32 rxbytes = bytes;
- u32 reg, count, timeout;
+ u32 reg, count;
int ret;
debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n",
diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c
index 3f39ef05f2..f2eddec950 100644
--- a/drivers/spi/zynq_qspi.c
+++ b/drivers/spi/zynq_qspi.c
@@ -6,8 +6,10 @@
* Xilinx Zynq Quad-SPI(QSPI) controller driver (master mode only)
*/
+#include <clk.h>
#include <common.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <log.h>
#include <malloc.h>
#include <spi.h>
@@ -105,17 +107,29 @@ static int zynq_qspi_ofdata_to_platdata(struct udevice *bus)
plat->regs = (struct zynq_qspi_regs *)fdtdec_get_addr(blob,
node, "reg");
- /* FIXME: Use 166MHz as a suitable default */
- plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
- 166666666);
- plat->speed_hz = plat->frequency / 2;
-
- debug("%s: regs=%p max-frequency=%d\n", __func__,
- plat->regs, plat->frequency);
-
return 0;
}
+/**
+ * zynq_qspi_init_hw - Initialize the hardware
+ * @priv: Pointer to the zynq_qspi_priv structure
+ *
+ * The default settings of the QSPI controller's configurable parameters on
+ * reset are
+ * - Master mode
+ * - Baud rate divisor is set to 2
+ * - Threshold value for TX FIFO not full interrupt is set to 1
+ * - Flash memory interface mode enabled
+ * - Size of the word to be transferred as 8 bit
+ * This function performs the following actions
+ * - Disable and clear all the interrupts
+ * - Enable manual slave select
+ * - Enable auto start
+ * - Deselect all the chip select lines
+ * - Set the size of the word to be transferred as 32 bit
+ * - Set the little endian mode of TX FIFO and
+ * - Enable the QSPI controller
+ */
static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv)
{
struct zynq_qspi_regs *regs = priv->regs;
@@ -159,19 +173,45 @@ static int zynq_qspi_probe(struct udevice *bus)
{
struct zynq_qspi_platdata *plat = dev_get_platdata(bus);
struct zynq_qspi_priv *priv = dev_get_priv(bus);
+ struct clk clk;
+ unsigned long clock;
+ int ret;
priv->regs = plat->regs;
priv->fifo_depth = ZYNQ_QSPI_FIFO_DEPTH;
+ ret = clk_get_by_name(bus, "ref_clk", &clk);
+ if (ret < 0) {
+ dev_err(bus, "failed to get clock\n");
+ return ret;
+ }
+
+ clock = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(clock)) {
+ dev_err(bus, "failed to get rate\n");
+ return clock;
+ }
+
+ ret = clk_enable(&clk);
+ if (ret && ret != -ENOSYS) {
+ dev_err(bus, "failed to enable clock\n");
+ return ret;
+ }
+
/* init the zynq spi hw */
zynq_qspi_init_hw(priv);
+ plat->frequency = clock;
+ plat->speed_hz = plat->frequency / 2;
+
+ debug("%s: max-frequency=%d\n", __func__, plat->speed_hz);
+
return 0;
}
-/*
+/**
* zynq_qspi_read_data - Copy data to RX buffer
- * @zqspi: Pointer to the zynq_qspi structure
+ * @priv: Pointer to the zynq_qspi_priv structure
* @data: The 32 bit variable where data is stored
* @size: Number of bytes to be copied from data to RX buffer
*/
@@ -214,9 +254,9 @@ static void zynq_qspi_read_data(struct zynq_qspi_priv *priv, u32 data, u8 size)
priv->bytes_to_receive = 0;
}
-/*
+/**
* zynq_qspi_write_data - Copy data from TX buffer
- * @zqspi: Pointer to the zynq_qspi structure
+ * @priv: Pointer to the zynq_qspi_priv structure
* @data: Pointer to the 32 bit variable where data is to be copied
* @size: Number of bytes to be copied from TX buffer to data
*/
@@ -263,6 +303,11 @@ static void zynq_qspi_write_data(struct zynq_qspi_priv *priv,
priv->bytes_to_transfer = 0;
}
+/**
+ * zynq_qspi_chipselect - Select or deselect the chip select line
+ * @priv: Pointer to the zynq_qspi_priv structure
+ * @is_on: Select(1) or deselect (0) the chip select line
+ */
static void zynq_qspi_chipselect(struct zynq_qspi_priv *priv, int is_on)
{
u32 confr;
@@ -282,9 +327,10 @@ static void zynq_qspi_chipselect(struct zynq_qspi_priv *priv, int is_on)
writel(confr, &regs->cr);
}
-/*
+/**
* zynq_qspi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible
- * @zqspi: Pointer to the zynq_qspi structure
+ * @priv: Pointer to the zynq_qspi_priv structure
+ * @size: Number of bytes to be copied to fifo
*/
static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size)
{
@@ -322,9 +368,9 @@ static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size)
}
}
-/*
+/**
* zynq_qspi_irq_poll - Interrupt service routine of the QSPI controller
- * @zqspi: Pointer to the zynq_qspi structure
+ * @priv: Pointer to the zynq_qspi structure
*
* This function handles TX empty and Mode Fault interrupts only.
* On TX empty interrupt this function reads the received data from RX FIFO and
@@ -410,11 +456,9 @@ static int zynq_qspi_irq_poll(struct zynq_qspi_priv *priv)
return 0;
}
-/*
+/**
* zynq_qspi_start_transfer - Initiates the QSPI transfer
- * @qspi: Pointer to the spi_device structure
- * @transfer: Pointer to the spi_transfer structure which provide information
- * about next transfer parameters
+ * @priv: Pointer to the zynq_qspi_priv structure
*
* This function fills the TX FIFO, starts the QSPI transfer, and waits for the
* transfer to be completed.
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c
index 9923931e36..cb911c34f6 100644
--- a/drivers/spi/zynq_spi.c
+++ b/drivers/spi/zynq_spi.c
@@ -8,10 +8,12 @@
#include <common.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <log.h>
#include <malloc.h>
#include <spi.h>
#include <time.h>
+#include <clk.h>
#include <asm/io.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@@ -79,17 +81,10 @@ static int zynq_spi_ofdata_to_platdata(struct udevice *bus)
plat->regs = dev_read_addr_ptr(bus);
- /* FIXME: Use 250MHz as a suitable default */
- plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
- 250000000);
plat->deactivate_delay_us = fdtdec_get_int(blob, node,
"spi-deactivate-delay", 0);
plat->activate_delay_us = fdtdec_get_int(blob, node,
"spi-activate-delay", 0);
- plat->speed_hz = plat->frequency / 2;
-
- debug("%s: regs=%p max-frequency=%d\n", __func__,
- plat->regs, plat->frequency);
return 0;
}
@@ -128,13 +123,39 @@ static int zynq_spi_probe(struct udevice *bus)
{
struct zynq_spi_platdata *plat = dev_get_platdata(bus);
struct zynq_spi_priv *priv = dev_get_priv(bus);
+ struct clk clk;
+ unsigned long clock;
+ int ret;
priv->regs = plat->regs;
priv->fifo_depth = ZYNQ_SPI_FIFO_DEPTH;
+ ret = clk_get_by_name(bus, "ref_clk", &clk);
+ if (ret < 0) {
+ dev_err(bus, "failed to get clock\n");
+ return ret;
+ }
+
+ clock = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(clock)) {
+ dev_err(bus, "failed to get rate\n");
+ return clock;
+ }
+
+ ret = clk_enable(&clk);
+ if (ret && ret != -ENOSYS) {
+ dev_err(bus, "failed to enable clock\n");
+ return ret;
+ }
+
/* init the zynq spi hw */
zynq_spi_init_hw(priv);
+ plat->frequency = clock;
+ plat->speed_hz = plat->frequency / 2;
+
+ debug("%s: max-frequency=%d\n", __func__, plat->speed_hz);
+
return 0;
}