summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk_rk3036.c414
-rw-r--r--drivers/core/Kconfig19
-rw-r--r--drivers/core/Makefile4
-rw-r--r--drivers/ddr/fsl/fsl_ddr_gen4.c28
-rw-r--r--drivers/ddr/fsl/main.c1
-rw-r--r--drivers/ddr/fsl/util.c40
-rw-r--r--drivers/gpio/Kconfig11
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/atmel_pio4.c296
-rw-r--r--drivers/i2c/Makefile2
-rw-r--r--drivers/mmc/dw_mmc.c140
-rw-r--r--drivers/mmc/rockchip_dw_mmc.c26
-rw-r--r--drivers/mmc/socfpga_dw_mmc.c29
-rw-r--r--drivers/net/fsl-mc/Makefile3
-rw-r--r--drivers/net/fsl-mc/dpbp.c41
-rw-r--r--drivers/net/fsl-mc/dpio/dpio.c40
-rw-r--r--drivers/net/fsl-mc/dpmac.c222
-rw-r--r--drivers/net/fsl-mc/dpni.c40
-rw-r--r--drivers/net/fsl-mc/dprc.c46
-rw-r--r--drivers/net/fsl-mc/mc.c800
-rw-r--r--drivers/net/fsl-mc/mc_sys.c2
-rw-r--r--drivers/net/ldpaa_eth/Makefile3
-rw-r--r--drivers/net/ldpaa_eth/ldpaa_eth.c295
-rw-r--r--drivers/net/ldpaa_eth/ldpaa_eth.h23
-rw-r--r--drivers/net/ldpaa_eth/ldpaa_wriop.c27
-rw-r--r--drivers/net/ldpaa_eth/ls2080a.c (renamed from drivers/net/ldpaa_eth/ls2085a.c)0
-rw-r--r--drivers/net/phy/aquantia.c15
-rw-r--r--drivers/pci/Kconfig19
-rw-r--r--drivers/pci/Makefile5
-rw-r--r--drivers/pci/pci-uclass.c105
-rw-r--r--drivers/pci/pci_auto_common.c128
-rw-r--r--drivers/pci/pci_auto_old.c (renamed from drivers/pci/pci_auto.c)116
-rw-r--r--drivers/pci/pci_common.c2
-rw-r--r--drivers/pci/pci_tegra.c477
-rw-r--r--drivers/pci/pcie_layerscape.c16
-rw-r--r--drivers/pinctrl/Kconfig9
-rw-r--r--drivers/pinctrl/rockchip/Makefile1
-rw-r--r--drivers/pinctrl/rockchip/pinctrl_rk3036.c276
-rw-r--r--drivers/power/Kconfig5
-rw-r--r--drivers/serial/Kconfig26
-rw-r--r--drivers/serial/Makefile7
-rw-r--r--drivers/serial/ns16550.c46
-rw-r--r--drivers/serial/serial_dw.c39
-rw-r--r--drivers/serial/serial_keystone.c48
-rw-r--r--drivers/serial/serial_omap.c54
-rw-r--r--drivers/serial/serial_ppc.c40
-rw-r--r--drivers/serial/serial_rockchip.c43
-rw-r--r--drivers/serial/serial_tegra.c54
-rw-r--r--drivers/serial/serial_x86.c44
-rw-r--r--drivers/timer/Kconfig19
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/altera_timer.c10
-rw-r--r--drivers/timer/sandbox_timer.c6
-rw-r--r--drivers/timer/timer-uclass.c30
-rw-r--r--drivers/timer/tsc_timer.c389
-rw-r--r--drivers/usb/musb-new/sunxi.c12
-rw-r--r--drivers/video/ipu_disp.c2
-rw-r--r--drivers/video/ipu_regs.h1
59 files changed, 3431 insertions, 1168 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 008ec100a1..4a6a4a8d72 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -6,5 +6,6 @@
#
obj-$(CONFIG_CLK) += clk-uclass.o
+obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o
obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o
obj-$(CONFIG_SANDBOX) += clk_sandbox.o
diff --git a/drivers/clk/clk_rk3036.c b/drivers/clk/clk_rk3036.c
new file mode 100644
index 0000000000..6c802b6283
--- /dev/null
+++ b/drivers/clk/clk_rk3036.c
@@ -0,0 +1,414 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/cru_rk3036.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/periph.h>
+#include <dm/lists.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct rk3036_clk_plat {
+ enum rk_clk_id clk_id;
+};
+
+struct rk3036_clk_priv {
+ struct rk3036_cru *cru;
+ ulong rate;
+};
+
+enum {
+ VCO_MAX_HZ = 2400U * 1000000,
+ VCO_MIN_HZ = 600 * 1000000,
+ OUTPUT_MAX_HZ = 2400U * 1000000,
+ OUTPUT_MIN_HZ = 24 * 1000000,
+};
+
+#define RATE_TO_DIV(input_rate, output_rate) \
+ ((input_rate) / (output_rate) - 1);
+
+#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
+
+#define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
+ .refdiv = _refdiv,\
+ .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
+ .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\
+ _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\
+ OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\
+ #hz "Hz cannot be hit with PLL "\
+ "divisors on line " __stringify(__LINE__));
+
+/* use interge mode*/
+static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1);
+static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1);
+
+static inline unsigned int log2(unsigned int value)
+{
+ return fls(value) - 1;
+}
+
+static int rkclk_set_pll(struct rk3036_cru *cru, enum rk_clk_id clk_id,
+ const struct pll_div *div)
+{
+ int pll_id = rk_pll_id(clk_id);
+ struct rk3036_pll *pll = &cru->pll[pll_id];
+
+ /* All PLLs have same VCO and output frequency range restrictions. */
+ uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000;
+ uint output_hz = vco_hz / div->postdiv1 / div->postdiv2;
+
+ debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, postdiv2=%d,\
+ vco=%u Hz, output=%u Hz\n",
+ pll, div->fbdiv, div->refdiv, div->postdiv1,
+ div->postdiv2, vco_hz, output_hz);
+ assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
+ output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ);
+
+ /* use interger mode */
+ rk_clrreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
+
+ rk_clrsetreg(&pll->con0,
+ PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT | PLL_FBDIV_MASK,
+ (div->postdiv1 << PLL_POSTDIV1_SHIFT) | div->fbdiv);
+ rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT |
+ PLL_REFDIV_MASK << PLL_REFDIV_SHIFT,
+ (div->postdiv2 << PLL_POSTDIV2_SHIFT |
+ div->refdiv << PLL_REFDIV_SHIFT));
+
+ /* waiting for pll lock */
+ while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))
+ udelay(1);
+
+ return 0;
+}
+
+static void rkclk_init(struct rk3036_cru *cru)
+{
+ u32 aclk_div;
+ u32 hclk_div;
+ u32 pclk_div;
+
+ /* pll enter slow-mode */
+ rk_clrsetreg(&cru->cru_mode_con,
+ GPLL_MODE_MASK << GPLL_MODE_SHIFT |
+ APLL_MODE_MASK << APLL_MODE_SHIFT,
+ GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
+ APLL_MODE_SLOW << APLL_MODE_SHIFT);
+
+ /* init pll */
+ rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg);
+ rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
+
+ /*
+ * select apll as core clock pll source and
+ * set up dependent divisors for PCLK/HCLK and ACLK clocks.
+ * core hz : apll = 1:1
+ */
+ aclk_div = APLL_HZ / CORE_ACLK_HZ - 1;
+ assert((aclk_div + 1) * CORE_ACLK_HZ == APLL_HZ && aclk_div < 0x7);
+
+ pclk_div = APLL_HZ / CORE_PERI_HZ - 1;
+ assert((pclk_div + 1) * CORE_PERI_HZ == APLL_HZ && pclk_div < 0xf);
+
+ rk_clrsetreg(&cru->cru_clksel_con[0],
+ CORE_CLK_PLL_SEL_MASK << CORE_CLK_PLL_SEL_SHIFT |
+ CORE_DIV_CON_MASK << CORE_DIV_CON_SHIFT,
+ CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
+ 0 << CORE_DIV_CON_SHIFT);
+
+ rk_clrsetreg(&cru->cru_clksel_con[1],
+ CORE_ACLK_DIV_MASK << CORE_ACLK_DIV_SHIFT |
+ CORE_PERI_DIV_MASK << CORE_PERI_DIV_SHIFT,
+ aclk_div << CORE_ACLK_DIV_SHIFT |
+ pclk_div << CORE_PERI_DIV_SHIFT);
+
+ /*
+ * select apll as cpu clock pll source and
+ * set up dependent divisors for PCLK/HCLK and ACLK clocks.
+ */
+ aclk_div = APLL_HZ / CPU_ACLK_HZ - 1;
+ assert((aclk_div + 1) * CPU_ACLK_HZ == APLL_HZ && aclk_div < 0x1f);
+
+ pclk_div = APLL_HZ / CPU_PCLK_HZ - 1;
+ assert((pclk_div + 1) * CPU_PCLK_HZ == APLL_HZ && pclk_div < 0x7);
+
+ hclk_div = APLL_HZ / CPU_HCLK_HZ - 1;
+ assert((hclk_div + 1) * CPU_HCLK_HZ == APLL_HZ && hclk_div < 0x3);
+
+ rk_clrsetreg(&cru->cru_clksel_con[0],
+ CPU_CLK_PLL_SEL_MASK << CPU_CLK_PLL_SEL_SHIFT |
+ ACLK_CPU_DIV_MASK << ACLK_CPU_DIV_SHIFT,
+ CPU_CLK_PLL_SEL_APLL << CPU_CLK_PLL_SEL_SHIFT |
+ aclk_div << ACLK_CPU_DIV_SHIFT);
+
+ rk_clrsetreg(&cru->cru_clksel_con[1],
+ CPU_PCLK_DIV_MASK << CPU_PCLK_DIV_SHIFT |
+ CPU_HCLK_DIV_MASK << CPU_HCLK_DIV_SHIFT,
+ pclk_div << CPU_PCLK_DIV_SHIFT |
+ hclk_div << CPU_HCLK_DIV_SHIFT);
+
+ /*
+ * select gpll as peri clock pll source and
+ * set up dependent divisors for PCLK/HCLK and ACLK clocks.
+ */
+ aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
+ assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
+
+ hclk_div = log2(PERI_ACLK_HZ / PERI_HCLK_HZ);
+ assert((1 << hclk_div) * PERI_HCLK_HZ ==
+ PERI_ACLK_HZ && (pclk_div < 0x4));
+
+ pclk_div = log2(PERI_ACLK_HZ / PERI_PCLK_HZ);
+ assert((1 << pclk_div) * PERI_PCLK_HZ ==
+ PERI_ACLK_HZ && pclk_div < 0x8);
+
+ rk_clrsetreg(&cru->cru_clksel_con[10],
+ PERI_PLL_SEL_MASK << PERI_PLL_SEL_SHIFT |
+ PERI_PCLK_DIV_MASK << PERI_PCLK_DIV_SHIFT |
+ PERI_HCLK_DIV_MASK << PERI_HCLK_DIV_SHIFT |
+ PERI_ACLK_DIV_MASK << PERI_ACLK_DIV_SHIFT,
+ PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
+ pclk_div << PERI_PCLK_DIV_SHIFT |
+ hclk_div << PERI_HCLK_DIV_SHIFT |
+ aclk_div << PERI_ACLK_DIV_SHIFT);
+
+ /* PLL enter normal-mode */
+ rk_clrsetreg(&cru->cru_mode_con,
+ GPLL_MODE_MASK << GPLL_MODE_SHIFT |
+ APLL_MODE_MASK << APLL_MODE_SHIFT,
+ GPLL_MODE_NORM << GPLL_MODE_SHIFT |
+ APLL_MODE_NORM << APLL_MODE_SHIFT);
+}
+
+/* Get pll rate by id */
+static uint32_t rkclk_pll_get_rate(struct rk3036_cru *cru,
+ enum rk_clk_id clk_id)
+{
+ uint32_t refdiv, fbdiv, postdiv1, postdiv2;
+ uint32_t con;
+ int pll_id = rk_pll_id(clk_id);
+ struct rk3036_pll *pll = &cru->pll[pll_id];
+ static u8 clk_shift[CLK_COUNT] = {
+ 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, 0xff,
+ GPLL_MODE_SHIFT, 0xff
+ };
+ static u8 clk_mask[CLK_COUNT] = {
+ 0xff, APLL_MODE_MASK, DPLL_MODE_MASK, 0xff,
+ GPLL_MODE_MASK, 0xff
+ };
+ uint shift;
+ uint mask;
+
+ con = readl(&cru->cru_mode_con);
+ shift = clk_shift[clk_id];
+ mask = clk_mask[clk_id];
+
+ switch ((con >> shift) & mask) {
+ case GPLL_MODE_SLOW:
+ return OSC_HZ;
+ case GPLL_MODE_NORM:
+
+ /* normal mode */
+ con = readl(&pll->con0);
+ postdiv1 = (con >> PLL_POSTDIV1_SHIFT) & PLL_POSTDIV1_MASK;
+ fbdiv = (con >> PLL_FBDIV_SHIFT) & PLL_FBDIV_MASK;
+ con = readl(&pll->con1);
+ postdiv2 = (con >> PLL_POSTDIV2_SHIFT) & PLL_POSTDIV2_MASK;
+ refdiv = (con >> PLL_REFDIV_SHIFT) & PLL_REFDIV_MASK;
+ return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
+ case GPLL_MODE_DEEP:
+ default:
+ return 32768;
+ }
+}
+
+static ulong rockchip_mmc_get_clk(struct rk3036_cru *cru, uint clk_general_rate,
+ enum periph_id periph)
+{
+ uint src_rate;
+ uint div, mux;
+ u32 con;
+
+ switch (periph) {
+ case PERIPH_ID_EMMC:
+ con = readl(&cru->cru_clksel_con[12]);
+ mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK;
+ div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
+ break;
+ case PERIPH_ID_SDCARD:
+ con = readl(&cru->cru_clksel_con[12]);
+ mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK;
+ div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ src_rate = mux == EMMC_SEL_24M ? OSC_HZ : clk_general_rate;
+ return DIV_TO_RATE(src_rate, div);
+}
+
+static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate,
+ enum periph_id periph, uint freq)
+{
+ int src_clk_div;
+ int mux;
+
+ debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate);
+
+ /* mmc clock auto divide 2 in internal */
+ src_clk_div = (clk_general_rate / 2 + freq - 1) / freq;
+
+ if (src_clk_div > 0x7f) {
+ src_clk_div = (OSC_HZ / 2 + freq - 1) / freq;
+ mux = EMMC_SEL_24M;
+ } else {
+ mux = EMMC_SEL_GPLL;
+ }
+
+ switch (periph) {
+ case PERIPH_ID_EMMC:
+ rk_clrsetreg(&cru->cru_clksel_con[12],
+ EMMC_PLL_MASK << EMMC_PLL_SHIFT |
+ EMMC_DIV_MASK << EMMC_DIV_SHIFT,
+ mux << EMMC_PLL_SHIFT |
+ (src_clk_div - 1) << EMMC_DIV_SHIFT);
+ break;
+ case PERIPH_ID_SDCARD:
+ rk_clrsetreg(&cru->cru_clksel_con[11],
+ MMC0_PLL_MASK << MMC0_PLL_SHIFT |
+ MMC0_DIV_MASK << MMC0_DIV_SHIFT,
+ mux << MMC0_PLL_SHIFT |
+ (src_clk_div - 1) << MMC0_DIV_SHIFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return rockchip_mmc_get_clk(cru, clk_general_rate, periph);
+}
+
+static ulong rk3036_clk_get_rate(struct udevice *dev)
+{
+ struct rk3036_clk_plat *plat = dev_get_platdata(dev);
+ struct rk3036_clk_priv *priv = dev_get_priv(dev);
+
+ debug("%s\n", dev->name);
+ return rkclk_pll_get_rate(priv->cru, plat->clk_id);
+}
+
+static ulong rk3036_clk_set_rate(struct udevice *dev, ulong rate)
+{
+ debug("%s\n", dev->name);
+
+ return 0;
+}
+
+ulong rk3036_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+{
+ struct rk3036_clk_priv *priv = dev_get_priv(dev);
+ ulong new_rate;
+
+ switch (periph) {
+ case PERIPH_ID_EMMC:
+ new_rate = rockchip_mmc_set_clk(priv->cru, clk_get_rate(dev),
+ periph, rate);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return new_rate;
+}
+
+static struct clk_ops rk3036_clk_ops = {
+ .get_rate = rk3036_clk_get_rate,
+ .set_rate = rk3036_clk_set_rate,
+ .set_periph_rate = rk3036_set_periph_rate,
+};
+
+static int rk3036_clk_probe(struct udevice *dev)
+{
+ struct rk3036_clk_plat *plat = dev_get_platdata(dev);
+ struct rk3036_clk_priv *priv = dev_get_priv(dev);
+
+ if (plat->clk_id != CLK_OSC) {
+ struct rk3036_clk_priv *parent_priv = dev_get_priv(dev->parent);
+
+ priv->cru = parent_priv->cru;
+ return 0;
+ }
+ priv->cru = (struct rk3036_cru *)dev_get_addr(dev);
+ rkclk_init(priv->cru);
+
+ return 0;
+}
+
+static const char *const clk_name[] = {
+ "osc",
+ "apll",
+ "dpll",
+ "cpll",
+ "gpll",
+ "mpll",
+};
+
+static int rk3036_clk_bind(struct udevice *dev)
+{
+ struct rk3036_clk_plat *plat = dev_get_platdata(dev);
+ int pll, ret;
+
+ /* We only need to set up the root clock */
+ if (dev->of_offset == -1) {
+ plat->clk_id = CLK_OSC;
+ return 0;
+ }
+
+ /* Create devices for P main clocks */
+ for (pll = 1; pll < CLK_COUNT; pll++) {
+ struct udevice *child;
+ struct rk3036_clk_plat *cplat;
+
+ debug("%s %s\n", __func__, clk_name[pll]);
+ ret = device_bind_driver(dev, "clk_rk3036", clk_name[pll],
+ &child);
+ if (ret)
+ return ret;
+
+ cplat = dev_get_platdata(child);
+ cplat->clk_id = pll;
+ }
+
+ /* The reset driver does not have a device node, so bind it here */
+ ret = device_bind_driver(gd->dm_root, "rk3036_reset", "reset", &dev);
+ if (ret)
+ debug("Warning: No RK3036 reset driver: ret=%d\n", ret);
+
+ return 0;
+}
+
+static const struct udevice_id rk3036_clk_ids[] = {
+ { .compatible = "rockchip,rk3036-cru" },
+ { }
+};
+
+U_BOOT_DRIVER(clk_rk3036) = {
+ .name = "clk_rk3036",
+ .id = UCLASS_CLK,
+ .of_match = rk3036_clk_ids,
+ .priv_auto_alloc_size = sizeof(struct rk3036_clk_priv),
+ .platdata_auto_alloc_size = sizeof(struct rk3036_clk_plat),
+ .ops = &rk3036_clk_ops,
+ .bind = rk3036_clk_bind,
+ .probe = rk3036_clk_probe,
+};
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 15681df6d3..ac681729c0 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -72,6 +72,16 @@ config REGMAP
support any bus type (I2C, SPI) but so far this only supports
direct memory access.
+config SPL_REGMAP
+ bool "Support register maps in SPL"
+ depends on DM
+ help
+ Hardware peripherals tend to have one or more sets of registers
+ which can be accessed to control the hardware. A register map
+ models this with a simple read/write interface. It can in principle
+ support any bus type (I2C, SPI) but so far this only supports
+ direct memory access.
+
config SYSCON
bool "Support system controllers"
depends on REGMAP
@@ -81,6 +91,15 @@ config SYSCON
by this uclass, including accessing registers via regmap and
assigning a unique number to each.
+config SPL_SYSCON
+ bool "Support system controllers in SPL"
+ depends on REGMAP
+ help
+ Many SoCs have a number of system controllers which are dealt with
+ as a group by a single driver. Some common functionality is provided
+ by this uclass, including accessing registers via regmap and
+ assigning a unique number to each.
+
config DEVRES
bool "Managed device resources"
depends on DM
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index f19f67d30f..07adb61c28 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -9,5 +9,5 @@ obj-$(CONFIG_DEVRES) += devres.o
obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE) += device-remove.o
obj-$(CONFIG_$(SPL_)SIMPLE_BUS) += simple-bus.o
obj-$(CONFIG_DM) += dump.o
-obj-$(CONFIG_REGMAP) += regmap.o
-obj-$(CONFIG_SYSCON) += syscon-uclass.o
+obj-$(CONFIG_$(SPL_)REGMAP) += regmap.o
+obj-$(CONFIG_$(SPL_)SYSCON) += syscon-uclass.o
diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c
index 49e4688351..1de7b72b4c 100644
--- a/drivers/ddr/fsl/fsl_ddr_gen4.c
+++ b/drivers/ddr/fsl/fsl_ddr_gen4.c
@@ -107,14 +107,14 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
goto step2;
#ifdef CONFIG_SYS_FSL_ERRATUM_A008336
-#ifdef CONFIG_LS2085A
+#if defined(CONFIG_LS2080A) || defined(CONFIG_LS2085A)
/* A008336 only applies to general DDR controllers */
if ((ctrl_num == 0) || (ctrl_num == 1))
#endif
ddr_out32(eddrtqcr1, 0x63b30002);
#endif
#ifdef CONFIG_SYS_FSL_ERRATUM_A008514
-#ifdef CONFIG_LS2085A
+#if defined(CONFIG_LS2080A) || defined(CONFIG_LS2085A)
/* A008514 only applies to DP-DDR controler */
if (ctrl_num == 2)
#endif
@@ -423,16 +423,16 @@ step2:
if (getenv_f("ddr_bist", buffer, CONFIG_SYS_CBSIZE) >= 0) {
puts("Running BIST test. This will take a while...");
cs0_config = ddr_in32(&ddr->cs0_config);
+ cs0_bnds = ddr_in32(&ddr->cs0_bnds);
+ cs1_bnds = ddr_in32(&ddr->cs1_bnds);
+ cs2_bnds = ddr_in32(&ddr->cs2_bnds);
+ cs3_bnds = ddr_in32(&ddr->cs3_bnds);
if (cs0_config & CTLR_INTLV_MASK) {
- cs0_bnds = ddr_in32(&cs0_bnds);
- cs1_bnds = ddr_in32(&cs1_bnds);
- cs2_bnds = ddr_in32(&cs2_bnds);
- cs3_bnds = ddr_in32(&cs3_bnds);
/* set bnds to non-interleaving */
- ddr_out32(&cs0_bnds, (cs0_bnds & 0xfffefffe) >> 1);
- ddr_out32(&cs1_bnds, (cs1_bnds & 0xfffefffe) >> 1);
- ddr_out32(&cs2_bnds, (cs2_bnds & 0xfffefffe) >> 1);
- ddr_out32(&cs3_bnds, (cs3_bnds & 0xfffefffe) >> 1);
+ ddr_out32(&ddr->cs0_bnds, (cs0_bnds & 0xfffefffe) >> 1);
+ ddr_out32(&ddr->cs1_bnds, (cs1_bnds & 0xfffefffe) >> 1);
+ ddr_out32(&ddr->cs2_bnds, (cs2_bnds & 0xfffefffe) >> 1);
+ ddr_out32(&ddr->cs3_bnds, (cs3_bnds & 0xfffefffe) >> 1);
}
ddr_out32(&ddr->mtp1, BIST_PATTERN1);
ddr_out32(&ddr->mtp2, BIST_PATTERN1);
@@ -469,10 +469,10 @@ step2:
if (cs0_config & CTLR_INTLV_MASK) {
/* restore bnds registers */
- ddr_out32(&cs0_bnds, cs0_bnds);
- ddr_out32(&cs1_bnds, cs1_bnds);
- ddr_out32(&cs2_bnds, cs2_bnds);
- ddr_out32(&cs3_bnds, cs3_bnds);
+ ddr_out32(&ddr->cs0_bnds, cs0_bnds);
+ ddr_out32(&ddr->cs1_bnds, cs1_bnds);
+ ddr_out32(&ddr->cs2_bnds, cs2_bnds);
+ ddr_out32(&ddr->cs3_bnds, cs3_bnds);
}
}
#endif
diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c
index 72ec1be65d..c68663220d 100644
--- a/drivers/ddr/fsl/main.c
+++ b/drivers/ddr/fsl/main.c
@@ -813,6 +813,7 @@ phys_size_t fsl_ddr_sdram(void)
info.board_need_mem_reset = board_need_mem_reset;
info.board_mem_reset = board_assert_mem_reset;
info.board_mem_de_reset = board_deassert_mem_reset;
+ remove_unused_controllers(&info);
return __fsl_ddr_sdram(&info);
}
diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c
index ce55aea1b4..1a49b28f33 100644
--- a/drivers/ddr/fsl/util.c
+++ b/drivers/ddr/fsl/util.c
@@ -385,3 +385,43 @@ void fsl_ddr_sync_memctl_refresh(unsigned int first_ctrl,
ddr_out32(ddrc_debug2_p[i], ddrc_debug2[i]);
}
#endif /* CONFIG_FSL_DDR_SYNC_REFRESH */
+
+void remove_unused_controllers(fsl_ddr_info_t *info)
+{
+#ifdef CONFIG_FSL_LSCH3
+ int i;
+ u64 nodeid;
+ void *hnf_sam_ctrl = (void *)(CCI_HN_F_0_BASE + CCN_HN_F_SAM_CTL);
+ bool ddr0_used = false;
+ bool ddr1_used = false;
+
+ for (i = 0; i < 8; i++) {
+ nodeid = in_le64(hnf_sam_ctrl) & CCN_HN_F_SAM_NODEID_MASK;
+ if (nodeid == CCN_HN_F_SAM_NODEID_DDR0) {
+ ddr0_used = true;
+ } else if (nodeid == CCN_HN_F_SAM_NODEID_DDR1) {
+ ddr1_used = true;
+ } else {
+ printf("Unknown nodeid in HN-F SAM control: 0x%llx\n",
+ nodeid);
+ }
+ hnf_sam_ctrl += (CCI_HN_F_1_BASE - CCI_HN_F_0_BASE);
+ }
+ if (!ddr0_used && !ddr1_used) {
+ printf("Invalid configuration in HN-F SAM control\n");
+ return;
+ }
+
+ if (!ddr0_used && info->first_ctrl == 0) {
+ info->first_ctrl = 1;
+ info->num_ctrls = 1;
+ debug("First DDR controller disabled\n");
+ return;
+ }
+
+ if (!ddr1_used && info->first_ctrl + info->num_ctrls > 1) {
+ info->num_ctrls = 1;
+ debug("Second DDR controller disabled\n");
+ }
+#endif
+}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 9e494713fb..e60e9fd86c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -28,6 +28,17 @@ config DWAPB_GPIO
help
Support for the Designware APB GPIO driver.
+config ATMEL_PIO4
+ bool "ATMEL PIO4 driver"
+ depends on DM
+ default n
+ help
+ Say yes here to support the Atmel PIO4 driver.
+ The PIO4 is new version of Atmel PIO controller, which manages
+ up to 128 fully programmable input/output lines. Each I/O line
+ may be dedicated as a general purpose I/O or be assigned to
+ a function of an embedded peripheral.
+
config LPC32XX_GPIO
bool "LPC32XX GPIO driver"
depends on DM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c58aa4dfd5..fb4fd255df 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -12,6 +12,7 @@ endif
obj-$(CONFIG_DM_GPIO) += gpio-uclass.o
obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
+obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o
obj-$(CONFIG_KONA_GPIO) += kona_gpio.o
diff --git a/drivers/gpio/atmel_pio4.c b/drivers/gpio/atmel_pio4.c
new file mode 100644
index 0000000000..d71f5259a3
--- /dev/null
+++ b/drivers/gpio/atmel_pio4.c
@@ -0,0 +1,296 @@
+/*
+ * Atmel PIO4 device driver
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ * Wenyou.Yang <wenyou.yang@atmel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <dm.h>
+#include <asm/arch/hardware.h>
+#include <mach/gpio.h>
+#include <mach/atmel_pio4.h>
+
+#define ATMEL_PIO4_PINS_PER_BANK 32
+
+/*
+ * Register Field Definitions
+ */
+#define ATMEL_PIO4_CFGR_FUNC (0x7 << 0)
+#define ATMEL_PIO4_CFGR_FUNC_GPIO (0x0 << 0)
+#define ATMEL_PIO4_CFGR_FUNC_PERIPH_A (0x1 << 0)
+#define ATMEL_PIO4_CFGR_FUNC_PERIPH_B (0x2 << 0)
+#define ATMEL_PIO4_CFGR_FUNC_PERIPH_C (0x3 << 0)
+#define ATMEL_PIO4_CFGR_FUNC_PERIPH_D (0x4 << 0)
+#define ATMEL_PIO4_CFGR_FUNC_PERIPH_E (0x5 << 0)
+#define ATMEL_PIO4_CFGR_FUNC_PERIPH_F (0x6 << 0)
+#define ATMEL_PIO4_CFGR_FUNC_PERIPH_G (0x7 << 0)
+#define ATMEL_PIO4_CFGR_DIR (0x1 << 8)
+#define ATMEL_PIO4_CFGR_PUEN (0x1 << 9)
+#define ATMEL_PIO4_CFGR_PDEN (0x1 << 10)
+#define ATMEL_PIO4_CFGR_IFEN (0x1 << 12)
+#define ATMEL_PIO4_CFGR_IFSCEN (0x1 << 13)
+#define ATMEL_PIO4_CFGR_OPD (0x1 << 14)
+#define ATMEL_PIO4_CFGR_SCHMITT (0x1 << 15)
+#define ATMEL_PIO4_CFGR_DRVSTR (0x3 << 16)
+#define ATMEL_PIO4_CFGR_DRVSTR_LOW0 (0x0 << 16)
+#define ATMEL_PIO4_CFGR_DRVSTR_LOW1 (0x1 << 16)
+#define ATMEL_PIO4_CFGR_DRVSTR_MEDIUM (0x2 << 16)
+#define ATMEL_PIO4_CFGR_DRVSTR_HIGH (0x3 << 16)
+#define ATMEL_PIO4_CFGR_EVTSEL (0x7 << 24)
+#define ATMEL_PIO4_CFGR_EVTSEL_FALLING (0x0 << 24)
+#define ATMEL_PIO4_CFGR_EVTSEL_RISING (0x1 << 24)
+#define ATMEL_PIO4_CFGR_EVTSEL_BOTH (0x2 << 24)
+#define ATMEL_PIO4_CFGR_EVTSEL_LOW (0x3 << 24)
+#define ATMEL_PIO4_CFGR_EVTSEL_HIGH (0x4 << 24)
+#define ATMEL_PIO4_CFGR_PCFS (0x1 << 29)
+#define ATMEL_PIO4_CFGR_ICFS (0x1 << 30)
+
+static struct atmel_pio4_port *atmel_pio4_port_base(u32 port)
+{
+ struct atmel_pio4_port *base = NULL;
+
+ switch (port) {
+ case AT91_PIO_PORTA:
+ base = (struct atmel_pio4_port *)ATMEL_BASE_PIOA;
+ break;
+ case AT91_PIO_PORTB:
+ base = (struct atmel_pio4_port *)ATMEL_BASE_PIOB;
+ break;
+ case AT91_PIO_PORTC:
+ base = (struct atmel_pio4_port *)ATMEL_BASE_PIOC;
+ break;
+ case AT91_PIO_PORTD:
+ base = (struct atmel_pio4_port *)ATMEL_BASE_PIOD;
+ break;
+ default:
+ printf("Error: Atmel PIO4: Failed to get PIO base of port#%d!\n",
+ port);
+ break;
+ }
+
+ return base;
+}
+
+static int atmel_pio4_config_io_func(u32 port, u32 pin,
+ u32 func, u32 use_pullup)
+{
+ struct atmel_pio4_port *port_base;
+ u32 reg, mask;
+
+ if (pin >= ATMEL_PIO4_PINS_PER_BANK)
+ return -ENODEV;
+
+ port_base = atmel_pio4_port_base(port);
+ if (!port_base)
+ return -ENODEV;
+
+ mask = 1 << pin;
+ reg = func;
+ reg |= use_pullup ? ATMEL_PIO4_CFGR_PUEN : 0;
+
+ writel(mask, &port_base->mskr);
+ writel(reg, &port_base->cfgr);
+
+ return 0;
+}
+
+int atmel_pio4_set_gpio(u32 port, u32 pin, u32 use_pullup)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO4_CFGR_FUNC_GPIO,
+ use_pullup);
+}
+
+int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 use_pullup)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO4_CFGR_FUNC_PERIPH_A,
+ use_pullup);
+}
+
+int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 use_pullup)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO4_CFGR_FUNC_PERIPH_B,
+ use_pullup);
+}
+
+int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 use_pullup)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO4_CFGR_FUNC_PERIPH_C,
+ use_pullup);
+}
+
+int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 use_pullup)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO4_CFGR_FUNC_PERIPH_D,
+ use_pullup);
+}
+
+int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 use_pullup)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO4_CFGR_FUNC_PERIPH_E,
+ use_pullup);
+}
+
+int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 use_pullup)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO4_CFGR_FUNC_PERIPH_F,
+ use_pullup);
+}
+
+int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 use_pullup)
+{
+ return atmel_pio4_config_io_func(port, pin,
+ ATMEL_PIO4_CFGR_FUNC_PERIPH_G,
+ use_pullup);
+}
+
+int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value)
+{
+ struct atmel_pio4_port *port_base;
+ u32 reg, mask;
+
+ if (pin >= ATMEL_PIO4_PINS_PER_BANK)
+ return -ENODEV;
+
+ port_base = atmel_pio4_port_base(port);
+ if (!port_base)
+ return -ENODEV;
+
+ mask = 0x01 << pin;
+ reg = ATMEL_PIO4_CFGR_FUNC_GPIO | ATMEL_PIO4_CFGR_DIR;
+
+ writel(mask, &port_base->mskr);
+ writel(reg, &port_base->cfgr);
+
+ if (value)
+ writel(mask, &port_base->sodr);
+ else
+ writel(mask, &port_base->codr);
+
+ return 0;
+}
+
+int atmel_pio4_get_pio_input(u32 port, u32 pin)
+{
+ struct atmel_pio4_port *port_base;
+ u32 reg, mask;
+
+ if (pin >= ATMEL_PIO4_PINS_PER_BANK)
+ return -ENODEV;
+
+ port_base = atmel_pio4_port_base(port);
+ if (!port_base)
+ return -ENODEV;
+
+ mask = 0x01 << pin;
+ reg = ATMEL_PIO4_CFGR_FUNC_GPIO;
+
+ writel(mask, &port_base->mskr);
+ writel(reg, &port_base->cfgr);
+
+ return (readl(&port_base->pdsr) & mask) ? 1 : 0;
+}
+
+#ifdef CONFIG_DM_GPIO
+static int atmel_pio4_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct at91_port_platdata *plat = dev_get_platdata(dev);
+ struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
+ u32 mask = 0x01 << offset;
+ u32 reg = ATMEL_PIO4_CFGR_FUNC_GPIO;
+
+ writel(mask, &port_base->mskr);
+ writel(reg, &port_base->cfgr);
+
+ return 0;
+}
+
+static int atmel_pio4_direction_output(struct udevice *dev,
+ unsigned offset, int value)
+{
+ struct at91_port_platdata *plat = dev_get_platdata(dev);
+ struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
+ u32 mask = 0x01 << offset;
+ u32 reg = ATMEL_PIO4_CFGR_FUNC_GPIO | ATMEL_PIO4_CFGR_DIR;
+
+ writel(mask, &port_base->mskr);
+ writel(reg, &port_base->cfgr);
+
+ if (value)
+ writel(mask, &port_base->sodr);
+ else
+ writel(mask, &port_base->codr);
+
+ return 0;
+}
+
+static int atmel_pio4_get_value(struct udevice *dev, unsigned offset)
+{
+ struct at91_port_platdata *plat = dev_get_platdata(dev);
+ struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
+ u32 mask = 0x01 << offset;
+
+ return (readl(&port_base->pdsr) & mask) ? 1 : 0;
+}
+
+static int atmel_pio4_set_value(struct udevice *dev,
+ unsigned offset, int value)
+{
+ struct at91_port_platdata *plat = dev_get_platdata(dev);
+ struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
+ u32 mask = 0x01 << offset;
+
+ if (value)
+ writel(mask, &port_base->sodr);
+ else
+ writel(mask, &port_base->codr);
+
+ return 0;
+}
+
+static int atmel_pio4_get_function(struct udevice *dev, unsigned offset)
+{
+ struct at91_port_platdata *plat = dev_get_platdata(dev);
+ struct atmel_pio4_port *port_base = (atmel_pio4_port *)plat->base_addr;
+ u32 mask = 0x01 << offset;
+
+ writel(mask, &port_base->mskr);
+
+ return (readl(&port_base->cfgr) &
+ ATMEL_PIO4_CFGR_DIR) ? GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops atmel_pio4_ops = {
+ .direction_input = atmel_pio4_direction_input,
+ .direction_output = atmel_pio4_direction_output,
+ .get_value = atmel_pio4_get_value,
+ .set_value = atmel_pio4_set_value,
+ .get_function = atmel_pio4_get_function,
+};
+
+static int atmel_pio4_probe(struct udevice *dev)
+{
+ struct at91_port_platdata *plat = dev_get_platdata(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->bank_name = plat->bank_name;
+ uc_priv->gpio_count = ATMEL_PIO4_PINS_PER_BANK;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gpio_atmel_pio4) = {
+ .name = "gpio_atmel_pio4",
+ .id = UCLASS_GPIO,
+ .ops = &atmel_pio4_ops,
+ .probe = atmel_pio4_probe,
+};
+#endif
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 32198bd5b2..811ad9b72a 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -40,4 +40,4 @@ obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o
-obj-y += muxes/
+obj-$(CONFIG_I2C_MUX) += muxes/
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 4375abc940..909e3caf18 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -94,6 +94,81 @@ static void dwmci_prepare_data(struct dwmci_host *host,
dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks);
}
+static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
+{
+ int ret = 0;
+ u32 timeout = 240000;
+ u32 mask, size, i, len = 0;
+ u32 *buf = NULL;
+ ulong start = get_timer(0);
+ u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >>
+ RX_WMARK_SHIFT) + 1) * 2;
+
+ size = data->blocksize * data->blocks / 4;
+ if (data->flags == MMC_DATA_READ)
+ buf = (unsigned int *)data->dest;
+ else
+ buf = (unsigned int *)data->src;
+
+ for (;;) {
+ mask = dwmci_readl(host, DWMCI_RINTSTS);
+ /* Error during data transfer. */
+ if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) {
+ debug("%s: DATA ERROR!\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (host->fifo_mode && size) {
+ if (data->flags == MMC_DATA_READ) {
+ if ((dwmci_readl(host, DWMCI_RINTSTS) &&
+ DWMCI_INTMSK_RXDR)) {
+ len = dwmci_readl(host, DWMCI_STATUS);
+ len = (len >> DWMCI_FIFO_SHIFT) &
+ DWMCI_FIFO_MASK;
+ for (i = 0; i < len; i++)
+ *buf++ =
+ dwmci_readl(host, DWMCI_DATA);
+ dwmci_writel(host, DWMCI_RINTSTS,
+ DWMCI_INTMSK_RXDR);
+ }
+ } else {
+ if ((dwmci_readl(host, DWMCI_RINTSTS) &&
+ DWMCI_INTMSK_TXDR)) {
+ len = dwmci_readl(host, DWMCI_STATUS);
+ len = fifo_depth - ((len >>
+ DWMCI_FIFO_SHIFT) &
+ DWMCI_FIFO_MASK);
+ for (i = 0; i < len; i++)
+ dwmci_writel(host, DWMCI_DATA,
+ *buf++);
+ dwmci_writel(host, DWMCI_RINTSTS,
+ DWMCI_INTMSK_TXDR);
+ }
+ }
+ size = size > len ? (size - len) : 0;
+ }
+
+ /* Data arrived correctly. */
+ if (mask & DWMCI_INTMSK_DTO) {
+ ret = 0;
+ break;
+ }
+
+ /* Check for timeout. */
+ if (get_timer(start) > timeout) {
+ debug("%s: Timeout waiting for data!\n",
+ __func__);
+ ret = TIMEOUT;
+ break;
+ }
+ }
+
+ dwmci_writel(host, DWMCI_RINTSTS, mask);
+
+ return ret;
+}
+
static int dwmci_set_transfer_mode(struct dwmci_host *host,
struct mmc_data *data)
{
@@ -129,17 +204,24 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);
if (data) {
- if (data->flags == MMC_DATA_READ) {
- bounce_buffer_start(&bbstate, (void*)data->dest,
- data->blocksize *
- data->blocks, GEN_BB_WRITE);
+ if (host->fifo_mode) {
+ dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize);
+ dwmci_writel(host, DWMCI_BYTCNT,
+ data->blocksize * data->blocks);
+ dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET);
} else {
- bounce_buffer_start(&bbstate, (void*)data->src,
- data->blocksize *
- data->blocks, GEN_BB_READ);
+ if (data->flags == MMC_DATA_READ) {
+ bounce_buffer_start(&bbstate, (void*)data->dest,
+ data->blocksize *
+ data->blocks, GEN_BB_WRITE);
+ } else {
+ bounce_buffer_start(&bbstate, (void*)data->src,
+ data->blocksize *
+ data->blocks, GEN_BB_READ);
+ }
+ dwmci_prepare_data(host, data, cur_idmac,
+ bbstate.bounce_buffer);
}
- dwmci_prepare_data(host, data, cur_idmac,
- bbstate.bounce_buffer);
}
dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);
@@ -213,39 +295,15 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
}
if (data) {
- start = get_timer(0);
- timeout = 240000;
- for (;;) {
- mask = dwmci_readl(host, DWMCI_RINTSTS);
- /* Error during data transfer. */
- if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) {
- debug("%s: DATA ERROR!\n", __func__);
- ret = -EINVAL;
- break;
- }
-
- /* Data arrived correctly. */
- if (mask & DWMCI_INTMSK_DTO) {
- ret = 0;
- break;
- }
-
- /* Check for timeout. */
- if (get_timer(start) > timeout) {
- debug("%s: Timeout waiting for data!\n",
- __func__);
- ret = TIMEOUT;
- break;
- }
+ ret = dwmci_data_transfer(host, data);
+
+ /* only dma mode need it */
+ if (!host->fifo_mode) {
+ ctrl = dwmci_readl(host, DWMCI_CTRL);
+ ctrl &= ~(DWMCI_DMA_EN);
+ dwmci_writel(host, DWMCI_CTRL, ctrl);
+ bounce_buffer_stop(&bbstate);
}
-
- dwmci_writel(host, DWMCI_RINTSTS, mask);
-
- ctrl = dwmci_readl(host, DWMCI_CTRL);
- ctrl &= ~(DWMCI_DMA_EN);
- dwmci_writel(host, DWMCI_CTRL, ctrl);
-
- bounce_buffer_stop(&bbstate);
}
udelay(100);
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index f11c8e0039..aeaec6c865 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -50,8 +50,9 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk;
host->priv = dev;
- /* TODO(sjg@chromium.org): Remove the need for this hack */
- host->dev_index = (ulong)host->ioaddr == 0xff0f0000 ? 0 : 1;
+ /* use non-removeable as sdcard and emmc as judgement */
+ if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "non-removable"))
+ host->dev_index = 1;
return 0;
}
@@ -63,6 +64,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
struct dwmci_host *host = &priv->host;
u32 minmax[2];
int ret;
+ int fifo_depth;
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
if (IS_ERR(priv->grf))
@@ -71,10 +73,22 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
if (ret)
return ret;
- ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
- "clock-freq-min-max", minmax, 2);
- if (!ret)
- ret = add_dwmci(host, minmax[1], minmax[0]);
+ if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
+ "clock-freq-min-max", minmax, 2))
+ return -EINVAL;
+
+ fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "fifo-depth", 0);
+ if (fifo_depth < 0)
+ return -EINVAL;
+
+ host->fifoth_val = MSIZE(0x2) |
+ RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2);
+
+ if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "fifo-mode"))
+ host->fifo_mode = true;
+
+ ret = add_dwmci(host, minmax[1], minmax[0]);
if (ret)
return ret;
diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
index 8076761e06..2bd0ebd96c 100644
--- a/drivers/mmc/socfpga_dw_mmc.c
+++ b/drivers/mmc/socfpga_dw_mmc.c
@@ -19,21 +19,23 @@ static const struct socfpga_clock_manager *clock_manager_base =
static const struct socfpga_system_manager *system_manager_base =
(void *)SOCFPGA_SYSMGR_ADDRESS;
-static void socfpga_dwmci_clksel(struct dwmci_host *host)
-{
+/* socfpga implmentation specific drver private data */
+struct dwmci_socfpga_priv_data {
unsigned int drvsel;
unsigned int smplsel;
+};
+
+static void socfpga_dwmci_clksel(struct dwmci_host *host)
+{
+ struct dwmci_socfpga_priv_data *priv = host->priv;
/* Disable SDMMC clock. */
clrbits_le32(&clock_manager_base->per_pll.en,
CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
- /* Configures drv_sel and smpl_sel */
- drvsel = CONFIG_SOCFPGA_DWMMC_DRVSEL;
- smplsel = CONFIG_SOCFPGA_DWMMC_SMPSEL;
-
- debug("%s: drvsel %d smplsel %d\n", __func__, drvsel, smplsel);
- writel(SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel),
+ debug("%s: drvsel %d smplsel %d\n", __func__,
+ priv->drvsel, priv->smplsel);
+ writel(SYSMGR_SDMMC_CTRL_SET(priv->smplsel, priv->drvsel),
&system_manager_base->sdmmcgrp_ctrl);
debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__,
@@ -50,6 +52,7 @@ static int socfpga_dwmci_of_probe(const void *blob, int node, const int idx)
const unsigned long clk = cm_get_mmc_controller_clk_hz();
struct dwmci_host *host;
+ struct dwmci_socfpga_priv_data *priv;
fdt_addr_t reg_base;
int bus_width, fifo_depth;
@@ -83,6 +86,13 @@ static int socfpga_dwmci_of_probe(const void *blob, int node, const int idx)
if (!host)
return -ENOMEM;
+ /* Allocate the priv */
+ priv = calloc(1, sizeof(*priv));
+ if (!priv) {
+ free(host);
+ return -ENOMEM;
+ }
+
host->name = "SOCFPGA DWMMC";
host->ioaddr = (void *)reg_base;
host->buswidth = bus_width;
@@ -92,6 +102,9 @@ static int socfpga_dwmci_of_probe(const void *blob, int node, const int idx)
host->bus_hz = clk;
host->fifoth_val = MSIZE(0x2) |
RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2);
+ priv->drvsel = fdtdec_get_uint(blob, node, "drvsel", 3);
+ priv->smplsel = fdtdec_get_uint(blob, node, "smplsel", 0);
+ host->priv = priv;
return add_dwmci(host, host->bus_hz, 400000);
}
diff --git a/drivers/net/fsl-mc/Makefile b/drivers/net/fsl-mc/Makefile
index 7563a5fdd3..a492388821 100644
--- a/drivers/net/fsl-mc/Makefile
+++ b/drivers/net/fsl-mc/Makefile
@@ -10,5 +10,6 @@ obj-y += mc.o \
dpmng.o \
dprc.o \
dpbp.o \
- dpni.o
+ dpni.o \
+ dpmac.o
obj-y += dpio/
diff --git a/drivers/net/fsl-mc/dpbp.c b/drivers/net/fsl-mc/dpbp.c
index 1517a70083..ba9536d405 100644
--- a/drivers/net/fsl-mc/dpbp.c
+++ b/drivers/net/fsl-mc/dpbp.c
@@ -49,6 +49,47 @@ int dpbp_close(struct fsl_mc_io *mc_io,
return mc_send_command(mc_io, &cmd);
}
+int dpbp_create(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ const struct dpbp_cfg *cfg,
+ uint16_t *token)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ (void)(cfg); /* unused */
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPBP_CMDID_CREATE,
+ cmd_flags,
+ 0);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
+
+ return 0;
+}
+
+int dpbp_destroy(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPBP_CMDID_DESTROY,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
int dpbp_enable(struct fsl_mc_io *mc_io,
uint32_t cmd_flags,
uint16_t token)
diff --git a/drivers/net/fsl-mc/dpio/dpio.c b/drivers/net/fsl-mc/dpio/dpio.c
index cd3fd50fdd..b61df52860 100644
--- a/drivers/net/fsl-mc/dpio/dpio.c
+++ b/drivers/net/fsl-mc/dpio/dpio.c
@@ -48,6 +48,46 @@ int dpio_close(struct fsl_mc_io *mc_io,
return mc_send_command(mc_io, &cmd);
}
+int dpio_create(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ const struct dpio_cfg *cfg,
+ uint16_t *token)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPIO_CMDID_CREATE,
+ cmd_flags,
+ 0);
+ DPIO_CMD_CREATE(cmd, cfg);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
+
+ return 0;
+}
+
+int dpio_destroy(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPIO_CMDID_DESTROY,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
int dpio_enable(struct fsl_mc_io *mc_io,
uint32_t cmd_flags,
uint16_t token)
diff --git a/drivers/net/fsl-mc/dpmac.c b/drivers/net/fsl-mc/dpmac.c
new file mode 100644
index 0000000000..072a90dcae
--- /dev/null
+++ b/drivers/net/fsl-mc/dpmac.c
@@ -0,0 +1,222 @@
+/*
+ * Freescale Layerscape MC I/O wrapper
+ *
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Author: Prabhakar Kushwaha <prabhakar@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <fsl-mc/fsl_mc_sys.h>
+#include <fsl-mc/fsl_mc_cmd.h>
+#include <fsl-mc/fsl_dpmac.h>
+
+int dpmac_open(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ int dpmac_id,
+ uint16_t *token)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_OPEN,
+ cmd_flags,
+ 0);
+ DPMAC_CMD_OPEN(cmd, dpmac_id);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
+
+ return err;
+}
+
+int dpmac_close(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpmac_create(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ const struct dpmac_cfg *cfg,
+ uint16_t *token)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CREATE,
+ cmd_flags,
+ 0);
+ DPMAC_CMD_CREATE(cmd, cfg);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
+
+ return 0;
+}
+
+int dpmac_destroy(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_DESTROY,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpmac_get_attributes(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token,
+ struct dpmac_attr *attr)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_ATTR,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPMAC_RSP_GET_ATTRIBUTES(cmd, attr);
+
+ return 0;
+}
+
+int dpmac_mdio_read(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token,
+ struct dpmac_mdio_cfg *cfg)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_MDIO_READ,
+ cmd_flags,
+ token);
+ DPMAC_CMD_MDIO_READ(cmd, cfg);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPMAC_RSP_MDIO_READ(cmd, cfg->data);
+
+ return 0;
+}
+
+int dpmac_mdio_write(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token,
+ struct dpmac_mdio_cfg *cfg)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_MDIO_WRITE,
+ cmd_flags,
+ token);
+ DPMAC_CMD_MDIO_WRITE(cmd, cfg);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpmac_get_link_cfg(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token,
+ struct dpmac_link_cfg *cfg)
+{
+ struct mc_command cmd = { 0 };
+ int err = 0;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_LINK_CFG,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ DPMAC_RSP_GET_LINK_CFG(cmd, cfg);
+
+ return 0;
+}
+
+int dpmac_set_link_state(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token,
+ struct dpmac_link_state *link_state)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE,
+ cmd_flags,
+ token);
+ DPMAC_CMD_SET_LINK_STATE(cmd, link_state);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpmac_get_counter(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token,
+ enum dpmac_counter type,
+ uint64_t *counter)
+{
+ struct mc_command cmd = { 0 };
+ int err = 0;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_COUNTER,
+ cmd_flags,
+ token);
+ DPMAC_CMD_GET_COUNTER(cmd, type);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ DPMAC_RSP_GET_COUNTER(cmd, *counter);
+
+ return 0;
+}
diff --git a/drivers/net/fsl-mc/dpni.c b/drivers/net/fsl-mc/dpni.c
index 9111f35b70..eacb3c8bb2 100644
--- a/drivers/net/fsl-mc/dpni.c
+++ b/drivers/net/fsl-mc/dpni.c
@@ -48,6 +48,46 @@ int dpni_close(struct fsl_mc_io *mc_io,
return mc_send_command(mc_io, &cmd);
}
+int dpni_create(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ const struct dpni_cfg *cfg,
+ uint16_t *token)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_CREATE,
+ cmd_flags,
+ 0);
+ DPNI_CMD_CREATE(cmd, cfg);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
+
+ return 0;
+}
+
+int dpni_destroy(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_DESTROY,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
int dpni_set_pools(struct fsl_mc_io *mc_io,
uint32_t cmd_flags,
uint16_t token,
diff --git a/drivers/net/fsl-mc/dprc.c b/drivers/net/fsl-mc/dprc.c
index 357aa4808b..7d34355b86 100644
--- a/drivers/net/fsl-mc/dprc.c
+++ b/drivers/net/fsl-mc/dprc.c
@@ -72,6 +72,52 @@ int dprc_close(struct fsl_mc_io *mc_io,
return mc_send_command(mc_io, &cmd);
}
+int dprc_create_container(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token,
+ struct dprc_cfg *cfg,
+ int *child_container_id,
+ uint64_t *child_portal_paddr)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ DPRC_CMD_CREATE_CONTAINER(cmd, cfg);
+
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_CREATE_CONT,
+ cmd_flags,
+ token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPRC_RSP_CREATE_CONTAINER(cmd, *child_container_id,
+ *child_portal_paddr);
+
+ return 0;
+}
+
+int dprc_destroy_container(struct fsl_mc_io *mc_io,
+ uint32_t cmd_flags,
+ uint16_t token,
+ int child_container_id)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_DESTROY_CONT,
+ cmd_flags,
+ token);
+ DPRC_CMD_DESTROY_CONTAINER(cmd, child_container_id);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
int dprc_reset_container(struct fsl_mc_io *mc_io,
uint32_t cmd_flags,
uint16_t token,
diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c
index ea987d79dd..e1a02d1f3d 100644
--- a/drivers/net/fsl-mc/mc.c
+++ b/drivers/net/fsl-mc/mc.c
@@ -14,7 +14,9 @@
#include <fsl-mc/fsl_dpmng.h>
#include <fsl-mc/fsl_dprc.h>
#include <fsl-mc/fsl_dpio.h>
+#include <fsl-mc/fsl_dpni.h>
#include <fsl-mc/fsl_qbman_portal.h>
+#include <fsl-mc/ldpaa_wriop.h>
#define MC_RAM_BASE_ADDR_ALIGNMENT (512UL * 1024 * 1024)
#define MC_RAM_BASE_ADDR_ALIGNMENT_MASK (~(MC_RAM_BASE_ADDR_ALIGNMENT - 1))
@@ -24,12 +26,19 @@
#define MC_BOOT_TIMEOUT_ENV_VAR "mcboottimeout"
DECLARE_GLOBAL_DATA_PTR;
-static int mc_boot_status;
-struct fsl_mc_io *dflt_mc_io = NULL;
+static int mc_boot_status = -1;
+static int mc_dpl_applied = -1;
+#ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
+static int mc_aiop_applied = -1;
+#endif
+struct fsl_mc_io *root_mc_io = NULL;
+struct fsl_mc_io *dflt_mc_io = NULL; /* child container */
+uint16_t root_dprc_handle = 0;
uint16_t dflt_dprc_handle = 0;
+int child_dprc_id;
struct fsl_dpbp_obj *dflt_dpbp = NULL;
struct fsl_dpio_obj *dflt_dpio = NULL;
-uint16_t dflt_dpio_handle = 0;
+struct fsl_dpni_obj *dflt_dpni = NULL;
#ifdef DEBUG
void dump_ram_words(const char *title, void *addr)
@@ -93,7 +102,8 @@ static int mc_copy_image(const char *title,
* Returns 0 on success and a negative errno on error.
* task fail.
**/
-int parse_mc_firmware_fit_image(const void **raw_image_addr,
+int parse_mc_firmware_fit_image(u64 mc_fw_addr,
+ const void **raw_image_addr,
size_t *raw_image_size)
{
int format;
@@ -103,36 +113,31 @@ int parse_mc_firmware_fit_image(const void **raw_image_addr,
size_t size;
const char *uname = "firmware";
- /* Check if the image is in NOR flash */
-#ifdef CONFIG_SYS_LS_MC_FW_IN_NOR
- fit_hdr = (void *)CONFIG_SYS_LS_MC_FW_ADDR;
-#else
-#error "No CONFIG_SYS_LS_MC_FW_IN_xxx defined"
-#endif
+ fit_hdr = (void *)mc_fw_addr;
/* Check if Image is in FIT format */
format = genimg_get_format(fit_hdr);
if (format != IMAGE_FORMAT_FIT) {
- printf("fsl-mc: ERROR: Bad firmware image (not a FIT image)\n");
+ printf("fsl-mc: ERR: Bad firmware image (not a FIT image)\n");
return -EINVAL;
}
if (!fit_check_format(fit_hdr)) {
- printf("fsl-mc: ERROR: Bad firmware image (bad FIT header)\n");
+ printf("fsl-mc: ERR: Bad firmware image (bad FIT header)\n");
return -EINVAL;
}
node_offset = fit_image_get_node(fit_hdr, uname);
if (node_offset < 0) {
- printf("fsl-mc: ERROR: Bad firmware image (missing subimage)\n");
+ printf("fsl-mc: ERR: Bad firmware image (missing subimage)\n");
return -ENOENT;
}
/* Verify MC firmware image */
if (!(fit_image_verify(fit_hdr, node_offset))) {
- printf("fsl-mc: ERROR: Bad firmware image (bad CRC)\n");
+ printf("fsl-mc: ERR: Bad firmware image (bad CRC)\n");
return -EINVAL;
}
@@ -218,7 +223,7 @@ static int mc_fixup_dpc(u64 dpc_addr)
return 0;
}
-static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size)
+static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size, u64 mc_dpc_addr)
{
u64 mc_dpc_offset;
#ifndef CONFIG_SYS_LS_MC_DPC_IN_DDR
@@ -245,11 +250,7 @@ static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size)
/*
* Get address and size of the DPC blob stored in flash:
*/
-#ifdef CONFIG_SYS_LS_MC_DPC_IN_NOR
- dpc_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPC_ADDR;
-#else
-#error "No CONFIG_SYS_LS_MC_DPC_IN_xxx defined"
-#endif
+ dpc_fdt_hdr = (void *)mc_dpc_addr;
error = fdt_check_header(dpc_fdt_hdr);
if (error != 0) {
@@ -279,7 +280,7 @@ static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size)
return 0;
}
-static int load_mc_dpl(u64 mc_ram_addr, size_t mc_ram_size)
+static int load_mc_dpl(u64 mc_ram_addr, size_t mc_ram_size, u64 mc_dpl_addr)
{
u64 mc_dpl_offset;
#ifndef CONFIG_SYS_LS_MC_DPL_IN_DDR
@@ -306,11 +307,7 @@ static int load_mc_dpl(u64 mc_ram_addr, size_t mc_ram_size)
/*
* Get address and size of the DPL blob stored in flash:
*/
-#ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR
- dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR;
-#else
-#error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined"
-#endif
+ dpl_fdt_hdr = (void *)mc_dpl_addr;
error = fdt_check_header(dpl_fdt_hdr);
if (error != 0) {
@@ -357,23 +354,33 @@ static unsigned long get_mc_boot_timeout_ms(void)
return timeout_ms;
}
-#ifdef CONFIG_SYS_LS_MC_AIOP_IMG_IN_NOR
-static int load_mc_aiop_img(u64 mc_ram_addr, size_t mc_ram_size)
+#ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
+static int load_mc_aiop_img(u64 aiop_fw_addr)
{
+ u64 mc_ram_addr = mc_get_dram_addr();
+#ifndef CONFIG_SYS_LS_MC_DPC_IN_DDR
void *aiop_img;
+#endif
/*
* Load the MC AIOP image in the MC private DRAM block:
*/
- aiop_img = (void *)CONFIG_SYS_LS_MC_AIOP_IMG_ADDR;
+#ifdef CONFIG_SYS_LS_MC_DPC_IN_DDR
+ printf("MC AIOP is preloaded to %#llx\n", mc_ram_addr +
+ CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET);
+#else
+ aiop_img = (void *)aiop_fw_addr;
mc_copy_image("MC AIOP image",
(u64)aiop_img, CONFIG_SYS_LS_MC_AIOP_IMG_MAX_LENGTH,
mc_ram_addr + CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET);
+#endif
+ mc_aiop_applied = 0;
return 0;
}
#endif
+
static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr)
{
u32 reg_gsr;
@@ -420,12 +427,12 @@ static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr)
return 0;
}
-int mc_init(void)
+int mc_init(u64 mc_fw_addr, u64 mc_dpc_addr)
{
int error = 0;
int portal_id = 0;
struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR;
- u64 mc_ram_addr;
+ u64 mc_ram_addr = mc_get_dram_addr();
u32 reg_gsr;
u32 reg_mcfbalr;
#ifndef CONFIG_SYS_LS_MC_FW_IN_DDR
@@ -437,17 +444,6 @@ int mc_init(void)
u8 mc_ram_num_256mb_blocks;
size_t mc_ram_size = mc_get_dram_block_size();
- /*
- * The MC private DRAM block was already carved at the end of DRAM
- * by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE:
- */
- if (gd->bd->bi_dram[1].start) {
- mc_ram_addr =
- gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size;
- } else {
- mc_ram_addr =
- gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size;
- }
error = calculate_mc_private_ram_params(mc_ram_addr,
mc_ram_size,
@@ -474,7 +470,8 @@ int mc_init(void)
#ifdef CONFIG_SYS_LS_MC_FW_IN_DDR
printf("MC firmware is preloaded to %#llx\n", mc_ram_addr);
#else
- error = parse_mc_firmware_fit_image(&raw_image_addr, &raw_image_size);
+ error = parse_mc_firmware_fit_image(mc_fw_addr, &raw_image_addr,
+ &raw_image_size);
if (error != 0)
goto out;
/*
@@ -485,20 +482,10 @@ int mc_init(void)
#endif
dump_ram_words("firmware", (void *)mc_ram_addr);
- error = load_mc_dpc(mc_ram_addr, mc_ram_size);
+ error = load_mc_dpc(mc_ram_addr, mc_ram_size, mc_dpc_addr);
if (error != 0)
goto out;
- error = load_mc_dpl(mc_ram_addr, mc_ram_size);
- if (error != 0)
- goto out;
-
-#ifdef CONFIG_SYS_LS_MC_AIOP_IMG_IN_NOR
- error = load_mc_aiop_img(mc_ram_addr, mc_ram_size);
- if (error != 0)
- goto out;
-#endif
-
debug("mc_ccsr_regs %p\n", mc_ccsr_regs);
dump_mc_ccsr_regs(mc_ccsr_regs);
@@ -537,17 +524,17 @@ int mc_init(void)
* Initialize the global default MC portal
* And check that the MC firmware is responding portal commands:
*/
- dflt_mc_io = (struct fsl_mc_io *)malloc(sizeof(struct fsl_mc_io));
- if (!dflt_mc_io) {
+ root_mc_io = (struct fsl_mc_io *)malloc(sizeof(struct fsl_mc_io));
+ if (!root_mc_io) {
printf(" No memory: malloc() failed\n");
return -ENOMEM;
}
- dflt_mc_io->mmio_regs = SOC_MC_PORTAL_ADDR(portal_id);
+ root_mc_io->mmio_regs = SOC_MC_PORTAL_ADDR(portal_id);
debug("Checking access to MC portal of root DPRC container (portal_id %d, portal physical addr %p)\n",
- portal_id, dflt_mc_io->mmio_regs);
+ portal_id, root_mc_io->mmio_regs);
- error = mc_get_version(dflt_mc_io, MC_CMD_NO_FLAGS, &mc_ver_info);
+ error = mc_get_version(root_mc_io, MC_CMD_NO_FLAGS, &mc_ver_info);
if (error != 0) {
printf("fsl-mc: ERROR: Firmware version check failed (error: %d)\n",
error);
@@ -571,20 +558,36 @@ int mc_init(void)
mc_ver_info.major, mc_ver_info.minor, mc_ver_info.revision,
reg_gsr & GSR_FS_MASK);
+out:
+ if (error != 0)
+ mc_boot_status = error;
+ else
+ mc_boot_status = 0;
+
+ return error;
+}
+
+int mc_apply_dpl(u64 mc_dpl_addr)
+{
+ struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR;
+ int error = 0;
+ u32 reg_gsr;
+ u64 mc_ram_addr = mc_get_dram_addr();
+ size_t mc_ram_size = mc_get_dram_block_size();
+
+ error = load_mc_dpl(mc_ram_addr, mc_ram_size, mc_dpl_addr);
+ if (error != 0)
+ return error;
+
/*
* Tell the MC to deploy the DPL:
*/
out_le32(&mc_ccsr_regs->reg_gsr, 0x0);
printf("fsl-mc: Deploying data path layout ... ");
error = wait_for_mc(false, &reg_gsr);
- if (error != 0)
- goto out;
-out:
- if (error != 0)
- mc_boot_status = error;
- else
- mc_boot_status = 0;
+ if (!error)
+ mc_dpl_applied = 0;
return error;
}
@@ -594,6 +597,40 @@ int get_mc_boot_status(void)
return mc_boot_status;
}
+#ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
+int get_aiop_apply_status(void)
+{
+ return mc_aiop_applied;
+}
+#endif
+
+int get_dpl_apply_status(void)
+{
+ return mc_dpl_applied;
+}
+
+/**
+ * Return the MC address of private DRAM block.
+ */
+u64 mc_get_dram_addr(void)
+{
+ u64 mc_ram_addr;
+
+ /*
+ * The MC private DRAM block was already carved at the end of DRAM
+ * by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE:
+ */
+ if (gd->bd->bi_dram[1].start) {
+ mc_ram_addr =
+ gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size;
+ } else {
+ mc_ram_addr =
+ gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size;
+ }
+
+ return mc_ram_addr;
+}
+
/**
* Return the actual size of the MC private DRAM block.
*/
@@ -620,36 +657,57 @@ unsigned long mc_get_dram_block_size(void)
return dram_block_size;
}
-int dpio_init(struct dprc_obj_desc obj_desc)
+int fsl_mc_ldpaa_init(bd_t *bis)
+{
+ int i;
+
+ for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++)
+ if ((wriop_is_enabled_dpmac(i) == 1) &&
+ (wriop_get_phy_address(i) != -1))
+ ldpaa_eth_init(i, wriop_get_enet_if(i));
+ return 0;
+}
+
+static int dpio_init(void)
{
struct qbman_swp_desc p_des;
struct dpio_attr attr;
+ struct dpio_cfg dpio_cfg;
int err = 0;
dflt_dpio = (struct fsl_dpio_obj *)malloc(sizeof(struct fsl_dpio_obj));
if (!dflt_dpio) {
- printf(" No memory: malloc() failed\n");
- return -ENOMEM;
+ printf("No memory: malloc() failed\n");
+ err = -ENOMEM;
+ goto err_malloc;
}
- dflt_dpio->dpio_id = obj_desc.id;
+ dpio_cfg.channel_mode = DPIO_LOCAL_CHANNEL;
+ dpio_cfg.num_priorities = 8;
- err = dpio_open(dflt_mc_io, MC_CMD_NO_FLAGS, obj_desc.id,
- &dflt_dpio_handle);
- if (err) {
- printf("dpio_open() failed\n");
- goto err_open;
+ err = dpio_create(dflt_mc_io, MC_CMD_NO_FLAGS, &dpio_cfg,
+ &dflt_dpio->dpio_handle);
+ if (err < 0) {
+ printf("dpio_create() failed: %d\n", err);
+ err = -ENODEV;
+ goto err_create;
}
+ memset(&attr, 0, sizeof(struct dpio_attr));
err = dpio_get_attributes(dflt_mc_io, MC_CMD_NO_FLAGS,
- dflt_dpio_handle, &attr);
- if (err) {
- printf("dpio_get_attributes() failed %d\n", err);
+ dflt_dpio->dpio_handle, &attr);
+ if (err < 0) {
+ printf("dpio_get_attributes() failed: %d\n", err);
goto err_get_attr;
}
- err = dpio_enable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio_handle);
- if (err) {
+ dflt_dpio->dpio_id = attr.id;
+#ifdef DEBUG
+ printf("Init: DPIO id=0x%d\n", dflt_dpio->dpio_id);
+#endif
+
+ err = dpio_enable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
+ if (err < 0) {
printf("dpio_enable() failed %d\n", err);
goto err_get_enable;
}
@@ -672,176 +730,512 @@ int dpio_init(struct dprc_obj_desc obj_desc)
return 0;
err_get_swp_init:
+ dpio_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
err_get_enable:
- dpio_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio_handle);
-err_get_attr:
- dpio_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio_handle);
-err_open:
free(dflt_dpio);
+err_get_attr:
+ dpio_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
+ dpio_destroy(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
+err_create:
+err_malloc:
return err;
}
-int dpbp_init(struct dprc_obj_desc obj_desc)
+static int dpio_exit(void)
{
- dflt_dpbp = (struct fsl_dpbp_obj *)malloc(sizeof(struct fsl_dpbp_obj));
- if (!dflt_dpbp) {
+ int err;
+
+ err = dpio_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
+ if (err < 0) {
+ printf("dpio_disable() failed: %d\n", err);
+ goto err;
+ }
+
+ err = dpio_destroy(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle);
+ if (err < 0) {
+ printf("dpio_destroy() failed: %d\n", err);
+ goto err;
+ }
+
+#ifdef DEBUG
+ printf("Exit: DPIO id=0x%d\n", dflt_dpio->dpio_id);
+#endif
+
+ if (dflt_dpio)
+ free(dflt_dpio);
+
+ return 0;
+err:
+ return err;
+}
+
+static int dprc_init(void)
+{
+ int err, child_portal_id, container_id;
+ struct dprc_cfg cfg;
+ uint64_t mc_portal_offset;
+
+ /* Open root container */
+ err = dprc_get_container_id(root_mc_io, MC_CMD_NO_FLAGS, &container_id);
+ if (err < 0) {
+ printf("dprc_get_container_id(): Root failed: %d\n", err);
+ goto err_root_container_id;
+ }
+
+#ifdef DEBUG
+ printf("Root container id = %d\n", container_id);
+#endif
+ err = dprc_open(root_mc_io, MC_CMD_NO_FLAGS, container_id,
+ &root_dprc_handle);
+ if (err < 0) {
+ printf("dprc_open(): Root Container failed: %d\n", err);
+ goto err_root_open;
+ }
+
+ if (!root_dprc_handle) {
+ printf("dprc_open(): Root Container Handle is not valid\n");
+ goto err_root_open;
+ }
+
+ cfg.options = DPRC_CFG_OPT_TOPOLOGY_CHANGES_ALLOWED |
+ DPRC_CFG_OPT_OBJ_CREATE_ALLOWED |
+ DPRC_CFG_OPT_ALLOC_ALLOWED;
+ cfg.icid = DPRC_GET_ICID_FROM_POOL;
+ cfg.portal_id = 250;
+ err = dprc_create_container(root_mc_io, MC_CMD_NO_FLAGS,
+ root_dprc_handle,
+ &cfg,
+ &child_dprc_id,
+ &mc_portal_offset);
+ if (err < 0) {
+ printf("dprc_create_container() failed: %d\n", err);
+ goto err_create;
+ }
+
+ dflt_mc_io = (struct fsl_mc_io *)malloc(sizeof(struct fsl_mc_io));
+ if (!dflt_mc_io) {
+ err = -ENOMEM;
printf(" No memory: malloc() failed\n");
- return -ENOMEM;
+ goto err_malloc;
+ }
+
+ child_portal_id = MC_PORTAL_OFFSET_TO_PORTAL_ID(mc_portal_offset);
+ dflt_mc_io->mmio_regs = SOC_MC_PORTAL_ADDR(child_portal_id);
+#ifdef DEBUG
+ printf("MC portal of child DPRC container: %d, physical addr %p)\n",
+ child_dprc_id, dflt_mc_io->mmio_regs);
+#endif
+
+ err = dprc_open(dflt_mc_io, MC_CMD_NO_FLAGS, child_dprc_id,
+ &dflt_dprc_handle);
+ if (err < 0) {
+ printf("dprc_open(): Child container failed: %d\n", err);
+ goto err_child_open;
+ }
+
+ if (!dflt_dprc_handle) {
+ printf("dprc_open(): Child container Handle is not valid\n");
+ goto err_child_open;
}
- dflt_dpbp->dpbp_attr.id = obj_desc.id;
return 0;
+err_child_open:
+ free(dflt_mc_io);
+err_malloc:
+ dprc_destroy_container(root_mc_io, MC_CMD_NO_FLAGS,
+ root_dprc_handle, child_dprc_id);
+err_create:
+ dprc_close(root_mc_io, MC_CMD_NO_FLAGS, root_dprc_handle);
+err_root_open:
+err_root_container_id:
+ return err;
}
-int dprc_init_container_obj(struct dprc_obj_desc obj_desc, uint16_t dprc_handle)
+static int dprc_exit(void)
{
- int error = 0, state = 0;
- struct dprc_endpoint dpni_endpoint, dpmac_endpoint;
- if (!strcmp(obj_desc.type, "dpbp")) {
- if (!dflt_dpbp) {
- error = dpbp_init(obj_desc);
- if (error < 0)
- printf("dpbp_init failed\n");
- }
- } else if (!strcmp(obj_desc.type, "dpio")) {
- if (!dflt_dpio) {
- error = dpio_init(obj_desc);
- if (error < 0)
- printf("dpio_init failed\n");
- }
- } else if (!strcmp(obj_desc.type, "dpni")) {
- strcpy(dpni_endpoint.type, obj_desc.type);
- dpni_endpoint.id = obj_desc.id;
- error = dprc_get_connection(dflt_mc_io, MC_CMD_NO_FLAGS,
- dprc_handle, &dpni_endpoint,
- &dpmac_endpoint, &state);
- if (!strcmp(dpmac_endpoint.type, "dpmac"))
- error = ldpaa_eth_init(obj_desc);
- if (error < 0)
- printf("ldpaa_eth_init failed\n");
+ int err;
+
+ err = dprc_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dprc_handle);
+ if (err < 0) {
+ printf("dprc_close(): Child failed: %d\n", err);
+ goto err;
}
- return error;
+ err = dprc_destroy_container(root_mc_io, MC_CMD_NO_FLAGS,
+ root_dprc_handle, child_dprc_id);
+ if (err < 0) {
+ printf("dprc_destroy_container() failed: %d\n", err);
+ goto err;
+ }
+
+ err = dprc_close(root_mc_io, MC_CMD_NO_FLAGS, root_dprc_handle);
+ if (err < 0) {
+ printf("dprc_close(): Root failed: %d\n", err);
+ goto err;
+ }
+
+ if (dflt_mc_io)
+ free(dflt_mc_io);
+
+ if (root_mc_io)
+ free(root_mc_io);
+
+ return 0;
+
+err:
+ return err;
}
-int dprc_scan_container_obj(uint16_t dprc_handle, char *obj_type, int i)
+static int dpbp_init(void)
{
- int error = 0;
- struct dprc_obj_desc obj_desc;
+ int err;
+ struct dpbp_attr dpbp_attr;
+ struct dpbp_cfg dpbp_cfg;
- memset((void *)&obj_desc, 0x00, sizeof(struct dprc_obj_desc));
+ dflt_dpbp = (struct fsl_dpbp_obj *)malloc(sizeof(struct fsl_dpbp_obj));
+ if (!dflt_dpbp) {
+ printf("No memory: malloc() failed\n");
+ err = -ENOMEM;
+ goto err_malloc;
+ }
- error = dprc_get_obj(dflt_mc_io, MC_CMD_NO_FLAGS, dprc_handle,
- i, &obj_desc);
- if (error < 0) {
- printf("dprc_get_obj(i=%d) failed: %d\n",
- i, error);
- return error;
+ dpbp_cfg.options = 512;
+
+ err = dpbp_create(dflt_mc_io, MC_CMD_NO_FLAGS, &dpbp_cfg,
+ &dflt_dpbp->dpbp_handle);
+
+ if (err < 0) {
+ err = -ENODEV;
+ printf("dpbp_create() failed: %d\n", err);
+ goto err_create;
+ }
+
+ memset(&dpbp_attr, 0, sizeof(struct dpbp_attr));
+ err = dpbp_get_attributes(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpbp->dpbp_handle,
+ &dpbp_attr);
+ if (err < 0) {
+ printf("dpbp_get_attributes() failed: %d\n", err);
+ goto err_get_attr;
}
- if (!strcmp(obj_desc.type, obj_type)) {
- debug("Discovered object: type %s, id %d, req %s\n",
- obj_desc.type, obj_desc.id, obj_type);
+ dflt_dpbp->dpbp_attr.id = dpbp_attr.id;
+#ifdef DEBUG
+ printf("Init: DPBP id=0x%d\n", dflt_dpbp->dpbp_attr.id);
+#endif
- error = dprc_init_container_obj(obj_desc, dprc_handle);
- if (error < 0) {
- printf("dprc_init_container_obj(i=%d) failed: %d\n",
- i, error);
- return error;
- }
+ err = dpbp_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle);
+ if (err < 0) {
+ printf("dpbp_close() failed: %d\n", err);
+ goto err_close;
}
- return error;
+ return 0;
+
+err_close:
+ free(dflt_dpbp);
+err_get_attr:
+ dpbp_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle);
+ dpbp_destroy(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle);
+err_create:
+err_malloc:
+ return err;
}
-int fsl_mc_ldpaa_init(bd_t *bis)
+static int dpbp_exit(void)
{
- int i, error = 0;
- int dprc_opened = 0, container_id;
- int num_child_objects = 0;
+ int err;
- error = mc_init();
- if (error < 0)
- goto error;
+ err = dpbp_open(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_attr.id,
+ &dflt_dpbp->dpbp_handle);
+ if (err < 0) {
+ printf("dpbp_open() failed: %d\n", err);
+ goto err;
+ }
- error = dprc_get_container_id(dflt_mc_io, MC_CMD_NO_FLAGS,
- &container_id);
- if (error < 0) {
- printf("dprc_get_container_id() failed: %d\n", error);
- goto error;
+ err = dpbp_destroy(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpbp->dpbp_handle);
+ if (err < 0) {
+ printf("dpbp_destroy() failed: %d\n", err);
+ goto err;
}
- debug("fsl-mc: Container id=0x%x\n", container_id);
+#ifdef DEBUG
+ printf("Exit: DPBP id=0x%d\n", dflt_dpbp->dpbp_attr.id);
+#endif
+
+ if (dflt_dpbp)
+ free(dflt_dpbp);
+ return 0;
- error = dprc_open(dflt_mc_io, MC_CMD_NO_FLAGS, container_id,
- &dflt_dprc_handle);
- if (error < 0) {
- printf("dprc_open() failed: %d\n", error);
- goto error;
+err:
+ return err;
+}
+
+static int dpni_init(void)
+{
+ int err;
+ struct dpni_attr dpni_attr;
+ struct dpni_cfg dpni_cfg;
+
+ dflt_dpni = (struct fsl_dpni_obj *)malloc(sizeof(struct fsl_dpni_obj));
+ if (!dflt_dpni) {
+ printf("No memory: malloc() failed\n");
+ err = -ENOMEM;
+ goto err_malloc;
}
- dprc_opened = true;
- error = dprc_get_obj_count(dflt_mc_io,
- MC_CMD_NO_FLAGS, dflt_dprc_handle,
- &num_child_objects);
- if (error < 0) {
- printf("dprc_get_obj_count() failed: %d\n", error);
- goto error;
+ memset(&dpni_cfg, 0, sizeof(dpni_cfg));
+ dpni_cfg.adv.options = DPNI_OPT_UNICAST_FILTER |
+ DPNI_OPT_MULTICAST_FILTER;
+
+ err = dpni_create(dflt_mc_io, MC_CMD_NO_FLAGS, &dpni_cfg,
+ &dflt_dpni->dpni_handle);
+
+ if (err < 0) {
+ err = -ENODEV;
+ printf("dpni_create() failed: %d\n", err);
+ goto err_create;
}
- debug("Total child in container %d = %d\n", container_id,
- num_child_objects);
- if (num_child_objects != 0) {
- /*
- * Discover objects currently in the DPRC container in the MC:
- */
- for (i = 0; i < num_child_objects; i++)
- error = dprc_scan_container_obj(dflt_dprc_handle,
- "dpbp", i);
+ memset(&dpni_attr, 0, sizeof(struct dpni_attr));
+ err = dpni_get_attributes(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle,
+ &dpni_attr);
+ if (err < 0) {
+ printf("dpni_get_attributes() failed: %d\n", err);
+ goto err_get_attr;
+ }
- for (i = 0; i < num_child_objects; i++)
- error = dprc_scan_container_obj(dflt_dprc_handle,
- "dpio", i);
+ dflt_dpni->dpni_id = dpni_attr.id;
+#ifdef DEBUG
+ printf("Init: DPNI id=0x%d\n", dflt_dpni->dpni_id);
+#endif
- for (i = 0; i < num_child_objects; i++)
- error = dprc_scan_container_obj(dflt_dprc_handle,
- "dpni", i);
+ err = dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
+ if (err < 0) {
+ printf("dpni_close() failed: %d\n", err);
+ goto err_close;
}
-error:
- if (dprc_opened)
- dprc_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dprc_handle);
- return error;
+ return 0;
+
+err_close:
+ free(dflt_dpni);
+err_get_attr:
+ dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
+ dpni_destroy(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
+err_create:
+err_malloc:
+ return err;
}
-void fsl_mc_ldpaa_exit(bd_t *bis)
+static int dpni_exit(void)
{
int err;
- if (get_mc_boot_status() == 0) {
- err = dpio_disable(dflt_mc_io, MC_CMD_NO_FLAGS,
- dflt_dpio_handle);
- if (err < 0) {
- printf("dpio_disable() failed: %d\n", err);
- return;
- }
- err = dpio_reset(dflt_mc_io, MC_CMD_NO_FLAGS,
- dflt_dpio_handle);
- if (err < 0) {
- printf("dpio_reset() failed: %d\n", err);
- return;
- }
- err = dpio_close(dflt_mc_io, MC_CMD_NO_FLAGS,
- dflt_dpio_handle);
- if (err < 0) {
- printf("dpio_close() failed: %d\n", err);
- return;
- }
+ err = dpni_open(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_id,
+ &dflt_dpni->dpni_handle);
+ if (err < 0) {
+ printf("dpni_open() failed: %d\n", err);
+ goto err;
+ }
- free(dflt_dpio);
- free(dflt_dpbp);
+ err = dpni_destroy(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle);
+ if (err < 0) {
+ printf("dpni_destroy() failed: %d\n", err);
+ goto err;
}
- if (dflt_mc_io)
- free(dflt_mc_io);
+#ifdef DEBUG
+ printf("Exit: DPNI id=0x%d\n", dflt_dpni->dpni_id);
+#endif
+
+ if (dflt_dpni)
+ free(dflt_dpni);
+ return 0;
+
+err:
+ return err;
+}
+
+static int mc_init_object(void)
+{
+ int err = 0;
+
+ err = dprc_init();
+ if (err < 0) {
+ printf("dprc_init() failed: %d\n", err);
+ goto err;
+ }
+
+ err = dpbp_init();
+ if (err < 0) {
+ printf("dpbp_init() failed: %d\n", err);
+ goto err;
+ }
+
+ err = dpio_init();
+ if (err < 0) {
+ printf("dpio_init() failed: %d\n", err);
+ goto err;
+ }
+
+ err = dpni_init();
+ if (err < 0) {
+ printf("dpni_init() failed: %d\n", err);
+ goto err;
+ }
+
+ return 0;
+err:
+ return err;
}
+
+int fsl_mc_ldpaa_exit(bd_t *bd)
+{
+ int err = 0;
+
+ if (bd && get_mc_boot_status() == -1)
+ return 0;
+
+ if (bd && !get_mc_boot_status() && get_dpl_apply_status() == -1) {
+ printf("ERROR: fsl-mc: DPL is not applied\n");
+ err = -ENODEV;
+ return err;
+ }
+
+ if (bd && !get_mc_boot_status() && !get_dpl_apply_status())
+ return err;
+
+ err = dpbp_exit();
+ if (err < 0) {
+ printf("dpni_exit() failed: %d\n", err);
+ goto err;
+ }
+
+ err = dpio_exit();
+ if (err < 0) {
+ printf("dpio_exit() failed: %d\n", err);
+ goto err;
+ }
+
+ err = dpni_exit();
+ if (err < 0) {
+ printf("dpni_exit() failed: %d\n", err);
+ goto err;
+ }
+
+ err = dprc_exit();
+ if (err < 0) {
+ printf("dprc_exit() failed: %d\n", err);
+ goto err;
+ }
+
+ return 0;
+err:
+ return err;
+}
+
+static int do_fsl_mc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int err = 0;
+ if (argc < 3)
+ goto usage;
+
+ switch (argv[1][0]) {
+ case 's': {
+ char sub_cmd;
+ u64 mc_fw_addr, mc_dpc_addr;
+#ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
+ u64 aiop_fw_addr;
+#endif
+
+ sub_cmd = argv[2][0];
+ switch (sub_cmd) {
+ case 'm':
+ if (argc < 5)
+ goto usage;
+
+ if (get_mc_boot_status() == 0) {
+ printf("fsl-mc: MC is already booted");
+ printf("\n");
+ return err;
+ }
+ mc_fw_addr = simple_strtoull(argv[3], NULL, 16);
+ mc_dpc_addr = simple_strtoull(argv[4], NULL,
+ 16);
+
+ if (!mc_init(mc_fw_addr, mc_dpc_addr))
+ err = mc_init_object();
+ break;
+
+#ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
+ case 'a':
+ if (argc < 4)
+ goto usage;
+ if (get_aiop_apply_status() == 0) {
+ printf("fsl-mc: AIOP FW is already");
+ printf(" applied\n");
+ return err;
+ }
+
+ aiop_fw_addr = simple_strtoull(argv[3], NULL,
+ 16);
+
+ err = load_mc_aiop_img(aiop_fw_addr);
+ if (!err)
+ printf("fsl-mc: AIOP FW applied\n");
+ break;
+#endif
+ default:
+ printf("Invalid option: %s\n", argv[2]);
+ goto usage;
+
+ break;
+ }
+ }
+ break;
+
+ case 'a': {
+ u64 mc_dpl_addr;
+
+ if (argc < 4)
+ goto usage;
+
+ if (get_dpl_apply_status() == 0) {
+ printf("fsl-mc: DPL already applied\n");
+ return err;
+ }
+
+ mc_dpl_addr = simple_strtoull(argv[3], NULL,
+ 16);
+
+ if (get_mc_boot_status() != 0) {
+ printf("fsl-mc: Deploying data path layout ..");
+ printf("ERROR (MC is not booted)\n");
+ return -ENODEV;
+ }
+
+ if (!fsl_mc_ldpaa_exit(NULL))
+ err = mc_apply_dpl(mc_dpl_addr);
+ break;
+ }
+ default:
+ printf("Invalid option: %s\n", argv[1]);
+ goto usage;
+ break;
+ }
+ return err;
+ usage:
+ return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(
+ fsl_mc, CONFIG_SYS_MAXARGS, 1, do_fsl_mc,
+ "DPAA2 command to manage Management Complex (MC)",
+ "start mc [FW_addr] [DPC_addr] - Start Management Complex\n"
+ "fsl_mc apply DPL [DPL_addr] - Apply DPL file\n"
+ "fsl_mc start aiop [FW_addr] - Start AIOP\n"
+);
diff --git a/drivers/net/fsl-mc/mc_sys.c b/drivers/net/fsl-mc/mc_sys.c
index 2136670370..71e145649f 100644
--- a/drivers/net/fsl-mc/mc_sys.c
+++ b/drivers/net/fsl-mc/mc_sys.c
@@ -32,7 +32,7 @@ int mc_send_command(struct fsl_mc_io *mc_io,
struct mc_command *cmd)
{
enum mc_cmd_status status;
- int timeout = 6000;
+ int timeout = 12000;
mc_write_command(mc_io->mmio_regs, cmd);
diff --git a/drivers/net/ldpaa_eth/Makefile b/drivers/net/ldpaa_eth/Makefile
index c37633f3ed..74c49165d5 100644
--- a/drivers/net/ldpaa_eth/Makefile
+++ b/drivers/net/ldpaa_eth/Makefile
@@ -6,4 +6,5 @@
obj-y += ldpaa_wriop.o
obj-y += ldpaa_eth.o
-obj-$(CONFIG_LS2085A) += ls2085a.o
+obj-$(CONFIG_LS2080A) += ls2080a.o
+obj-$(CONFIG_LS2085A) += ls2080a.o
diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c
index 99acb7a0c9..69530b11cf 100644
--- a/drivers/net/ldpaa_eth/ldpaa_eth.c
+++ b/drivers/net/ldpaa_eth/ldpaa_eth.c
@@ -12,6 +12,7 @@
#include <hwconfig.h>
#include <phy.h>
#include <linux/compat.h>
+#include <fsl-mc/fsl_dpmac.h>
#include "ldpaa_eth.h"
@@ -23,6 +24,84 @@ static int init_phy(struct eth_device *dev)
return 0;
}
+#ifdef DEBUG
+static void ldpaa_eth_get_dpni_counter(void)
+{
+ int err = 0;
+ u64 value;
+
+ err = dpni_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle,
+ DPNI_CNT_ING_FRAME,
+ &value);
+ if (err < 0) {
+ printf("dpni_get_counter: DPNI_CNT_ING_FRAME failed\n");
+ return;
+ }
+ printf("DPNI_CNT_ING_FRAME=%lld\n", value);
+
+ err = dpni_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle,
+ DPNI_CNT_ING_BYTE,
+ &value);
+ if (err < 0) {
+ printf("dpni_get_counter: DPNI_CNT_ING_BYTE failed\n");
+ return;
+ }
+ printf("DPNI_CNT_ING_BYTE=%lld\n", value);
+
+ err = dpni_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle,
+ DPNI_CNT_ING_FRAME_DROP ,
+ &value);
+ if (err < 0) {
+ printf("dpni_get_counter: DPNI_CNT_ING_FRAME_DROP failed\n");
+ return;
+ }
+ printf("DPNI_CNT_ING_FRAME_DROP =%lld\n", value);
+
+ err = dpni_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle,
+ DPNI_CNT_ING_FRAME_DISCARD,
+ &value);
+ if (err < 0) {
+ printf("dpni_get_counter: DPNI_CNT_ING_FRAME_DISCARD failed\n");
+ return;
+ }
+ printf("DPNI_CNT_ING_FRAME_DISCARD=%lld\n", value);
+
+ err = dpni_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle,
+ DPNI_CNT_EGR_FRAME,
+ &value);
+ if (err < 0) {
+ printf("dpni_get_counter: DPNI_CNT_EGR_FRAME failed\n");
+ return;
+ }
+ printf("DPNI_CNT_EGR_FRAME=%lld\n", value);
+
+ err = dpni_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle,
+ DPNI_CNT_EGR_BYTE ,
+ &value);
+ if (err < 0) {
+ printf("dpni_get_counter: DPNI_CNT_EGR_BYTE failed\n");
+ return;
+ }
+ printf("DPNI_CNT_EGR_BYTE =%lld\n", value);
+
+ err = dpni_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle,
+ DPNI_CNT_EGR_FRAME_DISCARD ,
+ &value);
+ if (err < 0) {
+ printf("dpni_get_counter: DPNI_CNT_EGR_FRAME_DISCARD failed\n");
+ return;
+ }
+ printf("DPNI_CNT_EGR_FRAME_DISCARD =%lld\n", value);
+}
+#endif
+
static void ldpaa_eth_rx(struct ldpaa_eth_priv *priv,
const struct dpaa_fd *fd)
{
@@ -46,7 +125,7 @@ static void ldpaa_eth_rx(struct ldpaa_eth_priv *priv,
/* Read the frame annotation status word and check for errors */
fas = (struct ldpaa_fas *)
((uint8_t *)(fd_addr) +
- priv->buf_layout.private_data_size);
+ dflt_dpni->buf_layout.private_data_size);
status = le32_to_cpu(fas->status);
if (status & LDPAA_ETH_RX_ERR_MASK) {
printf("Rx frame error(s): 0x%08x\n",
@@ -220,11 +299,34 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
{
struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
struct dpni_queue_attr rx_queue_attr;
+ struct dpmac_link_state dpmac_link_state = { 0 };
+#ifdef DEBUG
+ struct dpni_link_state link_state;
+#endif
int err;
if (net_dev->state == ETH_STATE_ACTIVE)
return 0;
+ if (get_mc_boot_status() != 0) {
+ printf("ERROR (MC is not booted)\n");
+ return -ENODEV;
+ }
+
+ if (get_dpl_apply_status() == 0) {
+ printf("ERROR (DPL is deployed. No device available)\n");
+ return -ENODEV;
+ }
+ /* DPMAC initialization */
+ err = ldpaa_dpmac_setup(priv);
+ if (err < 0)
+ goto err_dpmac_setup;
+
+ /* DPMAC binding DPNI */
+ err = ldpaa_dpmac_bind(priv);
+ if (err)
+ goto err_dpamc_bind;
+
/* DPNI initialization */
err = ldpaa_dpni_setup(priv);
if (err < 0)
@@ -237,10 +339,10 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
/* DPNI binding DPBP */
err = ldpaa_dpni_bind(priv);
if (err)
- goto err_bind;
+ goto err_dpni_bind;
err = dpni_add_mac_addr(dflt_mc_io, MC_CMD_NO_FLAGS,
- priv->dpni_handle, net_dev->enetaddr);
+ dflt_dpni->dpni_handle, net_dev->enetaddr);
if (err) {
printf("dpni_add_mac_addr() failed\n");
return err;
@@ -259,15 +361,38 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
priv->phydev->duplex = DUPLEX_FULL;
#endif
- err = dpni_enable(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle);
+ err = dpni_enable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
if (err < 0) {
printf("dpni_enable() failed\n");
return err;
}
+ dpmac_link_state.rate = SPEED_1000;
+ dpmac_link_state.options = DPMAC_LINK_OPT_AUTONEG;
+ dpmac_link_state.up = 1;
+ err = dpmac_set_link_state(dflt_mc_io, MC_CMD_NO_FLAGS,
+ priv->dpmac_handle, &dpmac_link_state);
+ if (err < 0) {
+ printf("dpmac_set_link_state() failed\n");
+ return err;
+ }
+
+#ifdef DEBUG
+ err = dpni_get_link_state(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle, &link_state);
+ if (err < 0) {
+ printf("dpni_get_link_state() failed\n");
+ return err;
+ }
+
+ printf("link status: %d - ", link_state.up);
+ link_state.up == 0 ? printf("down\n") :
+ link_state.up == 1 ? printf("up\n") : printf("error state\n");
+#endif
+
/* TODO: support multiple Rx flows */
- err = dpni_get_rx_flow(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle,
- 0, 0, &rx_queue_attr);
+ err = dpni_get_rx_flow(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle, 0, 0, &rx_queue_attr);
if (err) {
printf("dpni_get_rx_flow() failed\n");
goto err_rx_flow;
@@ -275,7 +400,7 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
priv->rx_dflt_fqid = rx_queue_attr.fqid;
- err = dpni_get_qdid(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle,
+ err = dpni_get_qdid(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle,
&priv->tx_qdid);
if (err) {
printf("dpni_get_qdid() failed\n");
@@ -289,12 +414,14 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
err_qdid:
err_rx_flow:
- dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle);
-err_bind:
+ dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
+err_dpni_bind:
ldpaa_dpbp_free();
err_dpbp_setup:
- dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle);
+err_dpamc_bind:
+ dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
err_dpni_setup:
+err_dpmac_setup:
return err;
}
@@ -306,8 +433,22 @@ static void ldpaa_eth_stop(struct eth_device *net_dev)
if ((net_dev->state == ETH_STATE_PASSIVE) ||
(net_dev->state == ETH_STATE_INIT))
return;
+
+#ifdef DEBUG
+ ldpaa_eth_get_dpni_counter();
+#endif
+
+ err = dprc_disconnect(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dprc_handle, &dpmac_endpoint);
+ if (err < 0)
+ printf("dprc_disconnect() failed dpmac_endpoint\n");
+
+ err = dpmac_destroy(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpmac_handle);
+ if (err < 0)
+ printf("dpmac_destroy() failed\n");
+
/* Stop Tx and Rx traffic */
- err = dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle);
+ err = dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
if (err < 0)
printf("dpni_disable() failed\n");
@@ -316,8 +457,8 @@ static void ldpaa_eth_stop(struct eth_device *net_dev)
#endif
ldpaa_dpbp_free();
- dpni_reset(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle);
- dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle);
+ dpni_reset(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
+ dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
}
static void ldpaa_dpbp_drain_cnt(int count)
@@ -359,7 +500,7 @@ static int ldpaa_bp_add_7(uint16_t bpid)
struct qbman_release_desc rd;
for (i = 0; i < 7; i++) {
- addr = memalign(L1_CACHE_BYTES, LDPAA_ETH_RX_BUFFER_SIZE);
+ addr = memalign(LDPAA_ETH_BUF_ALIGN, LDPAA_ETH_RX_BUFFER_SIZE);
if (!addr) {
printf("addr allocation failed\n");
goto err_alloc;
@@ -458,54 +599,125 @@ static void ldpaa_dpbp_free(void)
dpbp_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle);
}
+static int ldpaa_dpmac_setup(struct ldpaa_eth_priv *priv)
+{
+ int err = 0;
+ struct dpmac_cfg dpmac_cfg;
+
+ dpmac_cfg.mac_id = priv->dpmac_id;
+ err = dpmac_create(dflt_mc_io, MC_CMD_NO_FLAGS, &dpmac_cfg,
+ &priv->dpmac_handle);
+ if (err)
+ printf("dpmac_create() failed\n");
+ return err;
+}
+
+static int ldpaa_dpmac_bind(struct ldpaa_eth_priv *priv)
+{
+ int err = 0;
+ struct dprc_connection_cfg dprc_connection_cfg = {
+ /* If both rates are zero the connection */
+ /* will be configured in "best effort" mode. */
+ .committed_rate = 0,
+ .max_rate = 0
+ };
+
+#ifdef DEBUG
+ struct dprc_endpoint dbg_endpoint;
+ int state = 0;
+#endif
+
+ memset(&dpmac_endpoint, 0, sizeof(struct dprc_endpoint));
+ sprintf(dpmac_endpoint.type, "dpmac");
+ dpmac_endpoint.id = priv->dpmac_id;
+
+ memset(&dpni_endpoint, 0, sizeof(struct dprc_endpoint));
+ sprintf(dpni_endpoint.type, "dpni");
+ dpni_endpoint.id = dflt_dpni->dpni_id;
+
+ err = dprc_connect(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dprc_handle,
+ &dpmac_endpoint,
+ &dpni_endpoint,
+ &dprc_connection_cfg);
+ if (err)
+ printf("dprc_connect() failed\n");
+
+#ifdef DEBUG
+ err = dprc_get_connection(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dprc_handle, &dpni_endpoint,
+ &dbg_endpoint, &state);
+ printf("%s, DPMAC Type= %s\n", __func__, dbg_endpoint.type);
+ printf("%s, DPMAC ID= %d\n", __func__, dbg_endpoint.id);
+ printf("%s, DPMAC State= %d\n", __func__, state);
+
+ memset(&dbg_endpoint, 0, sizeof(struct dprc_endpoint));
+ err = dprc_get_connection(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dprc_handle, &dpmac_endpoint,
+ &dbg_endpoint, &state);
+ printf("%s, DPNI Type= %s\n", __func__, dbg_endpoint.type);
+ printf("%s, DPNI ID= %d\n", __func__, dbg_endpoint.id);
+ printf("%s, DPNI State= %d\n", __func__, state);
+#endif
+ return err;
+}
+
static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv)
{
int err;
/* and get a handle for the DPNI this interface is associate with */
- err = dpni_open(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_id,
- &priv->dpni_handle);
+ err = dpni_open(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_id,
+ &dflt_dpni->dpni_handle);
if (err) {
printf("dpni_open() failed\n");
goto err_open;
}
err = dpni_get_attributes(dflt_mc_io, MC_CMD_NO_FLAGS,
- priv->dpni_handle, &priv->dpni_attrs);
+ dflt_dpni->dpni_handle,
+ &dflt_dpni->dpni_attrs);
if (err) {
printf("dpni_get_attributes() failed (err=%d)\n", err);
goto err_get_attr;
}
/* Configure our buffers' layout */
- priv->buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT |
+ dflt_dpni->buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT |
DPNI_BUF_LAYOUT_OPT_FRAME_STATUS |
- DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE;
- priv->buf_layout.pass_parser_result = true;
- priv->buf_layout.pass_frame_status = true;
- priv->buf_layout.private_data_size = LDPAA_ETH_SWA_SIZE;
+ DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE |
+ DPNI_BUF_LAYOUT_OPT_DATA_ALIGN;
+ dflt_dpni->buf_layout.pass_parser_result = true;
+ dflt_dpni->buf_layout.pass_frame_status = true;
+ dflt_dpni->buf_layout.private_data_size = LDPAA_ETH_SWA_SIZE;
+ /* HW erratum mandates data alignment in multiples of 256 */
+ dflt_dpni->buf_layout.data_align = LDPAA_ETH_BUF_ALIGN;
/* ...rx, ... */
err = dpni_set_rx_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS,
- priv->dpni_handle, &priv->buf_layout);
+ dflt_dpni->dpni_handle,
+ &dflt_dpni->buf_layout);
if (err) {
printf("dpni_set_rx_buffer_layout() failed");
goto err_buf_layout;
}
/* ... tx, ... */
- priv->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PARSER_RESULT;
+ /* remove Rx-only options */
+ dflt_dpni->buf_layout.options &= ~(DPNI_BUF_LAYOUT_OPT_DATA_ALIGN |
+ DPNI_BUF_LAYOUT_OPT_PARSER_RESULT);
err = dpni_set_tx_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS,
- priv->dpni_handle, &priv->buf_layout);
+ dflt_dpni->dpni_handle,
+ &dflt_dpni->buf_layout);
if (err) {
printf("dpni_set_tx_buffer_layout() failed");
goto err_buf_layout;
}
/* ... tx-confirm. */
- priv->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE;
+ dflt_dpni->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE;
err = dpni_set_tx_conf_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS,
- priv->dpni_handle,
- &priv->buf_layout);
+ dflt_dpni->dpni_handle,
+ &dflt_dpni->buf_layout);
if (err) {
printf("dpni_set_tx_conf_buffer_layout() failed");
goto err_buf_layout;
@@ -515,7 +727,8 @@ static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv)
* required tx data offset.
*/
err = dpni_get_tx_data_offset(dflt_mc_io, MC_CMD_NO_FLAGS,
- priv->dpni_handle, &priv->tx_data_offset);
+ dflt_dpni->dpni_handle,
+ &priv->tx_data_offset);
if (err) {
printf("dpni_get_tx_data_offset() failed\n");
goto err_data_offset;
@@ -533,7 +746,7 @@ static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv)
err_data_offset:
err_buf_layout:
err_get_attr:
- dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle);
+ dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle);
err_open:
return err;
}
@@ -547,8 +760,8 @@ static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv)
pools_params.num_dpbp = 1;
pools_params.pools[0].dpbp_id = (uint16_t)dflt_dpbp->dpbp_attr.id;
pools_params.pools[0].buffer_size = LDPAA_ETH_RX_BUFFER_SIZE;
- err = dpni_set_pools(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle,
- &pools_params);
+ err = dpni_set_pools(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle, &pools_params);
if (err) {
printf("dpni_set_pools() failed\n");
return err;
@@ -560,8 +773,9 @@ static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv)
dflt_tx_flow.options = DPNI_TX_FLOW_OPT_ONLY_TX_ERROR;
dflt_tx_flow.conf_err_cfg.use_default_queue = 0;
dflt_tx_flow.conf_err_cfg.errors_only = 1;
- err = dpni_set_tx_flow(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle,
- &priv->tx_flow_id, &dflt_tx_flow);
+ err = dpni_set_tx_flow(dflt_mc_io, MC_CMD_NO_FLAGS,
+ dflt_dpni->dpni_handle, &priv->tx_flow_id,
+ &dflt_tx_flow);
if (err) {
printf("dpni_set_tx_flow() failed\n");
return err;
@@ -570,12 +784,14 @@ static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv)
return 0;
}
-static int ldpaa_eth_netdev_init(struct eth_device *net_dev)
+static int ldpaa_eth_netdev_init(struct eth_device *net_dev,
+ phy_interface_t enet_if)
{
int err;
struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
- sprintf(net_dev->name, "DPNI%d", priv->dpni_id);
+ sprintf(net_dev->name, "DPMAC%d@%s", priv->dpmac_id,
+ phy_interface_strings[enet_if]);
net_dev->iobase = 0;
net_dev->init = ldpaa_eth_open;
@@ -601,7 +817,7 @@ static int ldpaa_eth_netdev_init(struct eth_device *net_dev)
return 0;
}
-int ldpaa_eth_init(struct dprc_obj_desc obj_desc)
+int ldpaa_eth_init(int dpmac_id, phy_interface_t enet_if)
{
struct eth_device *net_dev = NULL;
struct ldpaa_eth_priv *priv = NULL;
@@ -626,9 +842,10 @@ int ldpaa_eth_init(struct dprc_obj_desc obj_desc)
net_dev->priv = (void *)priv;
priv->net_dev = (struct eth_device *)net_dev;
- priv->dpni_id = obj_desc.id;
+ priv->dpmac_id = dpmac_id;
+ debug("%s dpmac_id=%d\n", __func__, dpmac_id);
- err = ldpaa_eth_netdev_init(net_dev);
+ err = ldpaa_eth_netdev_init(net_dev, enet_if);
if (err)
goto err_netdev_init;
diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.h b/drivers/net/ldpaa_eth/ldpaa_eth.h
index b4ef700cb0..af41b27844 100644
--- a/drivers/net/ldpaa_eth/ldpaa_eth.h
+++ b/drivers/net/ldpaa_eth/ldpaa_eth.h
@@ -28,10 +28,10 @@ enum ldpaa_eth_type {
#define LDPAA_ETH_REFILL_THRESH (LDPAA_ETH_NUM_BUFS/2)
#define LDPAA_ETH_RX_BUFFER_SIZE 2048
-/* Hardware requires alignment for ingress/egress buffer addresses
- * and ingress buffer lengths.
+/* Hardware requires alignment for buffer address and length: 256-byte
+ * for ingress, 64-byte for egress. Using 256 for both.
*/
-#define LDPAA_ETH_BUF_ALIGN 64
+#define LDPAA_ETH_BUF_ALIGN 256
/* So far we're only accomodating a skb backpointer in the frame's
* software annotation, but the hardware options are either 0 or 64.
@@ -117,13 +117,9 @@ struct ldpaa_fas {
struct ldpaa_eth_priv {
struct eth_device *net_dev;
- int dpni_id;
- uint16_t dpni_handle;
- struct dpni_attr dpni_attrs;
- /* Insofar as the MC is concerned, we're using one layout on all 3 types
- * of buffers (Rx, Tx, Tx-Conf).
- */
- struct dpni_buffer_layout buf_layout;
+ int dpmac_id;
+ uint16_t dpmac_handle;
+
uint16_t tx_data_offset;
uint32_t rx_dflt_fqid;
@@ -134,9 +130,14 @@ struct ldpaa_eth_priv {
struct phy_device *phydev;
};
+struct dprc_endpoint dpmac_endpoint;
+struct dprc_endpoint dpni_endpoint;
+
extern struct fsl_mc_io *dflt_mc_io;
extern struct fsl_dpbp_obj *dflt_dpbp;
extern struct fsl_dpio_obj *dflt_dpio;
+extern struct fsl_dpni_obj *dflt_dpni;
+extern uint16_t dflt_dprc_handle;
static void ldpaa_dpbp_drain_cnt(int count);
static void ldpaa_dpbp_drain(void);
@@ -145,4 +146,6 @@ static void ldpaa_dpbp_free(void);
static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv);
static int ldpaa_dpbp_setup(void);
static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv);
+static int ldpaa_dpmac_setup(struct ldpaa_eth_priv *priv);
+static int ldpaa_dpmac_bind(struct ldpaa_eth_priv *priv);
#endif /* __LDPAA_H */
diff --git a/drivers/net/ldpaa_eth/ldpaa_wriop.c b/drivers/net/ldpaa_eth/ldpaa_wriop.c
index 926057a8ad..f7f26c275d 100644
--- a/drivers/net/ldpaa_eth/ldpaa_wriop.c
+++ b/drivers/net/ldpaa_eth/ldpaa_wriop.c
@@ -23,17 +23,17 @@ __weak phy_interface_t wriop_dpmac_enet_if(int dpmac_id, int lane_prtc)
void wriop_init_dpmac(int sd, int dpmac_id, int lane_prtcl)
{
phy_interface_t enet_if;
- int index = dpmac_id + sd * 8;
- dpmac_info[index].enabled = 0;
- dpmac_info[index].id = 0;
- dpmac_info[index].enet_if = PHY_INTERFACE_MODE_NONE;
+ dpmac_info[dpmac_id].enabled = 0;
+ dpmac_info[dpmac_id].id = 0;
+ dpmac_info[dpmac_id].phy_addr = -1;
+ dpmac_info[dpmac_id].enet_if = PHY_INTERFACE_MODE_NONE;
- enet_if = wriop_dpmac_enet_if(index, lane_prtcl);
+ enet_if = wriop_dpmac_enet_if(dpmac_id, lane_prtcl);
if (enet_if != PHY_INTERFACE_MODE_NONE) {
- dpmac_info[index].enabled = 1;
- dpmac_info[index].id = index;
- dpmac_info[index].enet_if = enet_if;
+ dpmac_info[dpmac_id].enabled = 1;
+ dpmac_info[dpmac_id].id = dpmac_id;
+ dpmac_info[dpmac_id].enet_if = enet_if;
}
}
@@ -72,6 +72,17 @@ void wriop_enable_dpmac(int dpmac_id)
wriop_dpmac_enable(dpmac_id);
}
+u8 wriop_is_enabled_dpmac(int dpmac_id)
+{
+ int i = wriop_dpmac_to_index(dpmac_id);
+
+ if (i == -1)
+ return -1;
+
+ return dpmac_info[i].enabled;
+}
+
+
void wriop_set_mdio(int dpmac_id, struct mii_dev *bus)
{
int i = wriop_dpmac_to_index(dpmac_id);
diff --git a/drivers/net/ldpaa_eth/ls2085a.c b/drivers/net/ldpaa_eth/ls2080a.c
index 93ed4f18fe..93ed4f18fe 100644
--- a/drivers/net/ldpaa_eth/ls2085a.c
+++ b/drivers/net/ldpaa_eth/ls2080a.c
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index ef4da4e2ec..f90c2ae3bb 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -146,11 +146,26 @@ struct phy_driver aqr105_driver = {
.startup = &aquantia_startup,
.shutdown = &gen10g_shutdown,
};
+
+struct phy_driver aqr405_driver = {
+ .name = "Aquantia AQR405",
+ .uid = 0x3a1b4b2,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS|
+ MDIO_MMD_PHYXS | MDIO_MMD_AN |
+ MDIO_MMD_VEND1),
+ .config = &aquantia_config,
+ .startup = &aquantia_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
int phy_aquantia_init(void)
{
phy_register(&aq1202_driver);
phy_register(&aq2104_driver);
phy_register(&aqr105_driver);
+ phy_register(&aqr405_driver);
return 0;
}
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 167d405918..26aa2b0930 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -9,6 +9,15 @@ config DM_PCI
available PCI devices, allows scanning of PCI buses and provides
device configuration support.
+config DM_PCI_COMPAT
+ bool "Enable compatible functions for PCI"
+ depends on DM_PCI
+ help
+ Enable compatibility functions for PCI so that old code can be used
+ with CONFIG_DM_PCI enabled. This should be used as an interim
+ measure when porting a board to use driver model for PCI. Once the
+ board is fully supported, this option should be disabled.
+
config PCI_SANDBOX
bool "Sandbox PCI support"
depends on SANDBOX && DM_PCI
@@ -19,4 +28,14 @@ config PCI_SANDBOX
the device tree but the normal PCI scan technique is used to find
then.
+config PCI_TEGRA
+ bool "Tegra PCI support"
+ depends on TEGRA
+ help
+ Enable support for the PCIe controller found on some generations of
+ Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has
+ 3 root ports with a total of 6 lanes and Tegra124 has 2 root ports
+ with a total of 5 lanes. Some boards require this for Ethernet
+ support to work (e.g. beaver, jetson-tk1).
+
endmenu
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index bcf8127b98..6b761b453d 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -6,14 +6,15 @@
#
ifneq ($(CONFIG_DM_PCI),)
-obj-$(CONFIG_PCI) += pci-uclass.o pci_compat.o
+obj-$(CONFIG_PCI) += pci-uclass.o
+obj-$(CONFIG_DM_PCI_COMPAT) += pci_compat.o
obj-$(CONFIG_PCI_SANDBOX) += pci_sandbox.o
obj-$(CONFIG_SANDBOX) += pci-emul-uclass.o
obj-$(CONFIG_X86) += pci_x86.o
else
obj-$(CONFIG_PCI) += pci.o
endif
-obj-$(CONFIG_PCI) += pci_common.o pci_auto.o pci_rom.o
+obj-$(CONFIG_PCI) += pci_auto_common.o pci_auto_old.o pci_common.o pci_rom.o
obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 1d93194b67..5fe30723c2 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -53,6 +53,14 @@ struct pci_controller *pci_bus_to_hose(int busnum)
return dev_get_uclass_priv(bus);
}
+struct udevice *pci_get_controller(struct udevice *dev)
+{
+ while (device_is_on_pci_bus(dev))
+ dev = dev->parent;
+
+ return dev;
+}
+
pci_dev_t pci_get_bdf(struct udevice *dev)
{
struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
@@ -680,8 +688,8 @@ static int decode_regions(struct pci_controller *hose, const void *blob,
int parent_node, int node)
{
int pci_addr_cells, addr_cells, size_cells;
+ phys_addr_t base = 0, size;
int cells_per_record;
- phys_addr_t addr;
const u32 *prop;
int len;
int i;
@@ -704,6 +712,7 @@ static int decode_regions(struct pci_controller *hose, const void *blob,
int space_code;
u32 flags;
int type;
+ int pos;
if (len < cells_per_record)
break;
@@ -726,17 +735,26 @@ static int decode_regions(struct pci_controller *hose, const void *blob,
} else {
continue;
}
- debug(" - type=%d\n", type);
- pci_set_region(hose->regions + hose->region_count++, pci_addr,
- addr, size, type);
+ pos = -1;
+ for (i = 0; i < hose->region_count; i++) {
+ if (hose->regions[i].flags == type)
+ pos = i;
+ }
+ if (pos == -1)
+ pos = hose->region_count++;
+ debug(" - type=%d, pos=%d\n", type, pos);
+ pci_set_region(hose->regions + pos, pci_addr, addr, size, type);
}
/* Add a region for our local memory */
- addr = gd->ram_size;
- if (gd->pci_ram_top && gd->pci_ram_top < addr)
- addr = gd->pci_ram_top;
- pci_set_region(hose->regions + hose->region_count++, 0, 0, addr,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ size = gd->ram_size;
+#ifdef CONFIG_SYS_SDRAM_BASE
+ base = CONFIG_SYS_SDRAM_BASE;
+#endif
+ if (gd->pci_ram_top && gd->pci_ram_top < base + size)
+ size = gd->pci_ram_top - base;
+ pci_set_region(hose->regions + hose->region_count++, base, base,
+ size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
return 0;
}
@@ -917,6 +935,75 @@ int pci_find_first_device(struct udevice **devp)
return skip_to_next_device(bus, devp);
}
+ulong pci_conv_32_to_size(ulong value, uint offset, enum pci_size_t size)
+{
+ switch (size) {
+ case PCI_SIZE_8:
+ return (value >> ((offset & 3) * 8)) & 0xff;
+ case PCI_SIZE_16:
+ return (value >> ((offset & 2) * 8)) & 0xffff;
+ default:
+ return value;
+ }
+}
+
+ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
+ enum pci_size_t size)
+{
+ uint off_mask;
+ uint val_mask, shift;
+ ulong ldata, mask;
+
+ switch (size) {
+ case PCI_SIZE_8:
+ off_mask = 3;
+ val_mask = 0xff;
+ break;
+ case PCI_SIZE_16:
+ off_mask = 2;
+ val_mask = 0xffff;
+ break;
+ default:
+ return value;
+ }
+ shift = (offset & off_mask) * 8;
+ ldata = (value & val_mask) << shift;
+ mask = val_mask << shift;
+ value = (old & ~mask) | ldata;
+
+ return value;
+}
+
+int pci_get_regions(struct udevice *dev, struct pci_region **iop,
+ struct pci_region **memp, struct pci_region **prefp)
+{
+ struct udevice *bus = pci_get_controller(dev);
+ struct pci_controller *hose = dev_get_uclass_priv(bus);
+ int i;
+
+ *iop = NULL;
+ *memp = NULL;
+ *prefp = NULL;
+ for (i = 0; i < hose->region_count; i++) {
+ switch (hose->regions[i].flags) {
+ case PCI_REGION_IO:
+ if (!*iop || (*iop)->size < hose->regions[i].size)
+ *iop = hose->regions + i;
+ break;
+ case PCI_REGION_MEM:
+ if (!*memp || (*memp)->size < hose->regions[i].size)
+ *memp = hose->regions + i;
+ break;
+ case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
+ if (!*prefp || (*prefp)->size < hose->regions[i].size)
+ *prefp = hose->regions + i;
+ break;
+ }
+ }
+
+ return (*iop != NULL) + (*memp != NULL) + (*prefp != NULL);
+}
+
UCLASS_DRIVER(pci) = {
.id = UCLASS_PCI,
.name = "pci",
diff --git a/drivers/pci/pci_auto_common.c b/drivers/pci/pci_auto_common.c
new file mode 100644
index 0000000000..85c419e6f4
--- /dev/null
+++ b/drivers/pci/pci_auto_common.c
@@ -0,0 +1,128 @@
+/*
+ * PCI auto-configuration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ *
+ * Modifications for driver model:
+ * Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <pci.h>
+
+void pciauto_region_init(struct pci_region *res)
+{
+ /*
+ * Avoid allocating PCI resources from address 0 -- this is illegal
+ * according to PCI 2.1 and moreover, this is known to cause Linux IDE
+ * drivers to fail. Use a reasonable starting value of 0x1000 instead.
+ */
+ res->bus_lower = res->bus_start ? res->bus_start : 0x1000;
+}
+
+void pciauto_region_align(struct pci_region *res, pci_size_t size)
+{
+ res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1;
+}
+
+int pciauto_region_allocate(struct pci_region *res, pci_size_t size,
+ pci_addr_t *bar)
+{
+ pci_addr_t addr;
+
+ if (!res) {
+ debug("No resource");
+ goto error;
+ }
+
+ addr = ((res->bus_lower - 1) | (size - 1)) + 1;
+
+ if (addr - res->bus_start + size > res->size) {
+ debug("No room in resource");
+ goto error;
+ }
+
+ res->bus_lower = addr + size;
+
+ debug("address=0x%llx bus_lower=0x%llx", (unsigned long long)addr,
+ (unsigned long long)res->bus_lower);
+
+ *bar = addr;
+ return 0;
+
+ error:
+ *bar = (pci_addr_t)-1;
+ return -1;
+}
+
+void pciauto_config_init(struct pci_controller *hose)
+{
+ int i;
+
+ hose->pci_io = NULL;
+ hose->pci_mem = NULL;
+ hose->pci_prefetch = NULL;
+
+ for (i = 0; i < hose->region_count; i++) {
+ switch (hose->regions[i].flags) {
+ case PCI_REGION_IO:
+ if (!hose->pci_io ||
+ hose->pci_io->size < hose->regions[i].size)
+ hose->pci_io = hose->regions + i;
+ break;
+ case PCI_REGION_MEM:
+ if (!hose->pci_mem ||
+ hose->pci_mem->size < hose->regions[i].size)
+ hose->pci_mem = hose->regions + i;
+ break;
+ case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
+ if (!hose->pci_prefetch ||
+ hose->pci_prefetch->size < hose->regions[i].size)
+ hose->pci_prefetch = hose->regions + i;
+ break;
+ }
+ }
+
+
+ if (hose->pci_mem) {
+ pciauto_region_init(hose->pci_mem);
+
+ debug("PCI Autoconfig: Bus Memory region: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory [%llx-%llxx]\n",
+ (u64)hose->pci_mem->bus_start,
+ (u64)(hose->pci_mem->bus_start + hose->pci_mem->size - 1),
+ (u64)hose->pci_mem->phys_start,
+ (u64)(hose->pci_mem->phys_start + hose->pci_mem->size - 1));
+ }
+
+ if (hose->pci_prefetch) {
+ pciauto_region_init(hose->pci_prefetch);
+
+ debug("PCI Autoconfig: Bus Prefetchable Mem: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory [%llx-%llx]\n",
+ (u64)hose->pci_prefetch->bus_start,
+ (u64)(hose->pci_prefetch->bus_start +
+ hose->pci_prefetch->size - 1),
+ (u64)hose->pci_prefetch->phys_start,
+ (u64)(hose->pci_prefetch->phys_start +
+ hose->pci_prefetch->size - 1));
+ }
+
+ if (hose->pci_io) {
+ pciauto_region_init(hose->pci_io);
+
+ debug("PCI Autoconfig: Bus I/O region: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory: [%llx-%llx]\n",
+ (u64)hose->pci_io->bus_start,
+ (u64)(hose->pci_io->bus_start + hose->pci_io->size - 1),
+ (u64)hose->pci_io->phys_start,
+ (u64)(hose->pci_io->phys_start + hose->pci_io->size - 1));
+ }
+}
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto_old.c
index 0412bf3515..932eab85bf 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto_old.c
@@ -23,55 +23,6 @@
*
*/
-void pciauto_region_init(struct pci_region *res)
-{
- /*
- * Avoid allocating PCI resources from address 0 -- this is illegal
- * according to PCI 2.1 and moreover, this is known to cause Linux IDE
- * drivers to fail. Use a reasonable starting value of 0x1000 instead.
- */
- res->bus_lower = res->bus_start ? res->bus_start : 0x1000;
-}
-
-void pciauto_region_align(struct pci_region *res, pci_size_t size)
-{
- res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1;
-}
-
-int pciauto_region_allocate(struct pci_region *res, pci_size_t size,
- pci_addr_t *bar)
-{
- pci_addr_t addr;
-
- if (!res) {
- debug("No resource");
- goto error;
- }
-
- addr = ((res->bus_lower - 1) | (size - 1)) + 1;
-
- if (addr - res->bus_start + size > res->size) {
- debug("No room in resource");
- goto error;
- }
-
- res->bus_lower = addr + size;
-
- debug("address=0x%llx bus_lower=0x%llx", (unsigned long long)addr,
- (unsigned long long)res->bus_lower);
-
- *bar = addr;
- return 0;
-
- error:
- *bar = (pci_addr_t)-1;
- return -1;
-}
-
-/*
- *
- */
-
void pciauto_setup_device(struct pci_controller *hose,
pci_dev_t dev, int bars_num,
struct pci_region *mem,
@@ -385,73 +336,6 @@ void pciauto_postscan_setup_bridge(struct pci_controller *hose,
}
}
-/*
- *
- */
-
-void pciauto_config_init(struct pci_controller *hose)
-{
- int i;
-
- hose->pci_io = hose->pci_mem = hose->pci_prefetch = NULL;
-
- for (i = 0; i < hose->region_count; i++) {
- switch(hose->regions[i].flags) {
- case PCI_REGION_IO:
- if (!hose->pci_io ||
- hose->pci_io->size < hose->regions[i].size)
- hose->pci_io = hose->regions + i;
- break;
- case PCI_REGION_MEM:
- if (!hose->pci_mem ||
- hose->pci_mem->size < hose->regions[i].size)
- hose->pci_mem = hose->regions + i;
- break;
- case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
- if (!hose->pci_prefetch ||
- hose->pci_prefetch->size < hose->regions[i].size)
- hose->pci_prefetch = hose->regions + i;
- break;
- }
- }
-
-
- if (hose->pci_mem) {
- pciauto_region_init(hose->pci_mem);
-
- debug("PCI Autoconfig: Bus Memory region: [0x%llx-0x%llx],\n"
- "\t\tPhysical Memory [%llx-%llxx]\n",
- (u64)hose->pci_mem->bus_start,
- (u64)(hose->pci_mem->bus_start + hose->pci_mem->size - 1),
- (u64)hose->pci_mem->phys_start,
- (u64)(hose->pci_mem->phys_start + hose->pci_mem->size - 1));
- }
-
- if (hose->pci_prefetch) {
- pciauto_region_init(hose->pci_prefetch);
-
- debug("PCI Autoconfig: Bus Prefetchable Mem: [0x%llx-0x%llx],\n"
- "\t\tPhysical Memory [%llx-%llx]\n",
- (u64)hose->pci_prefetch->bus_start,
- (u64)(hose->pci_prefetch->bus_start +
- hose->pci_prefetch->size - 1),
- (u64)hose->pci_prefetch->phys_start,
- (u64)(hose->pci_prefetch->phys_start +
- hose->pci_prefetch->size - 1));
- }
-
- if (hose->pci_io) {
- pciauto_region_init(hose->pci_io);
-
- debug("PCI Autoconfig: Bus I/O region: [0x%llx-0x%llx],\n"
- "\t\tPhysical Memory: [%llx-%llx]\n",
- (u64)hose->pci_io->bus_start,
- (u64)(hose->pci_io->bus_start + hose->pci_io->size - 1),
- (u64)hose->pci_io->phys_start,
- (u64)(hose->pci_io->phys_start + hose->pci_io->size - 1));
-
- }
-}
/*
* HJF: Changed this to return int. I think this is required
diff --git a/drivers/pci/pci_common.c b/drivers/pci/pci_common.c
index a64792f988..2a149022e2 100644
--- a/drivers/pci/pci_common.c
+++ b/drivers/pci/pci_common.c
@@ -268,7 +268,7 @@ int __pci_hose_phys_to_bus(struct pci_controller *hose,
bus_addr = phys_addr - res->phys_start + res->bus_start;
if (bus_addr >= res->bus_start &&
- bus_addr < res->bus_start + res->size) {
+ (bus_addr - res->bus_start) < res->size) {
*ba = bus_addr;
return 0;
}
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
index 690896f9f5..5a7fefed5e 100644
--- a/drivers/pci/pci_tegra.c
+++ b/drivers/pci/pci_tegra.c
@@ -10,10 +10,10 @@
* SPDX-License-Identifier: GPL-2.0
*/
-#define DEBUG
#define pr_fmt(fmt) "tegra-pcie: " fmt
#include <common.h>
+#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
@@ -177,7 +177,12 @@ DECLARE_GLOBAL_DATA_PTR;
#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
-struct tegra_pcie;
+enum tegra_pci_id {
+ TEGRA20_PCIE,
+ TEGRA30_PCIE,
+ TEGRA124_PCIE,
+ TEGRA210_PCIE,
+};
struct tegra_pcie_port {
struct tegra_pcie *pcie;
@@ -207,10 +212,6 @@ struct tegra_pcie {
struct fdt_resource afi;
struct fdt_resource cs;
- struct fdt_resource prefetch;
- struct fdt_resource mem;
- struct fdt_resource io;
-
struct list_head ports;
unsigned long xbar;
@@ -218,11 +219,6 @@ struct tegra_pcie {
struct tegra_xusb_phy *phy;
};
-static inline struct tegra_pcie *to_tegra_pcie(struct pci_controller *hose)
-{
- return container_of(hose, struct tegra_pcie, hose);
-}
-
static void afi_writel(struct tegra_pcie *pcie, unsigned long value,
unsigned long offset)
{
@@ -284,46 +280,54 @@ static int tegra_pcie_conf_address(struct tegra_pcie *pcie, pci_dev_t bdf,
return 0;
}
- return -1;
+ return -EFAULT;
}
-static int tegra_pcie_read_conf(struct pci_controller *hose, pci_dev_t bdf,
- int where, u32 *value)
+static int pci_tegra_read_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong *valuep,
+ enum pci_size_t size)
{
- struct tegra_pcie *pcie = to_tegra_pcie(hose);
- unsigned long address;
+ struct tegra_pcie *pcie = dev_get_priv(bus);
+ unsigned long address, value;
int err;
- err = tegra_pcie_conf_address(pcie, bdf, where, &address);
+ err = tegra_pcie_conf_address(pcie, bdf, offset, &address);
if (err < 0) {
- *value = 0xffffffff;
- return 1;
+ value = 0xffffffff;
+ goto done;
}
- *value = readl(address);
+ value = readl(address);
/* fixup root port class */
if (PCI_BUS(bdf) == 0) {
- if (where == PCI_CLASS_REVISION) {
- *value &= ~0x00ff0000;
- *value |= PCI_CLASS_BRIDGE_PCI << 16;
+ if (offset == PCI_CLASS_REVISION) {
+ value &= ~0x00ff0000;
+ value |= PCI_CLASS_BRIDGE_PCI << 16;
}
}
+done:
+ *valuep = pci_conv_32_to_size(value, offset, size);
+
return 0;
}
-static int tegra_pcie_write_conf(struct pci_controller *hose, pci_dev_t bdf,
- int where, u32 value)
+static int pci_tegra_write_config(struct udevice *bus, pci_dev_t bdf,
+ uint offset, ulong value,
+ enum pci_size_t size)
{
- struct tegra_pcie *pcie = to_tegra_pcie(hose);
+ struct tegra_pcie *pcie = dev_get_priv(bus);
unsigned long address;
+ ulong old;
int err;
- err = tegra_pcie_conf_address(pcie, bdf, where, &address);
+ err = tegra_pcie_conf_address(pcie, bdf, offset, &address);
if (err < 0)
- return 1;
+ return 0;
+ old = readl(address);
+ value = pci_conv_size_to_32(old, value, offset, size);
writel(value, address);
return 0;
@@ -348,12 +352,10 @@ static int tegra_pcie_port_parse_dt(const void *fdt, int node,
}
static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
- unsigned long *xbar)
+ enum tegra_pci_id id, unsigned long *xbar)
{
- enum fdt_compat_id id = fdtdec_lookup(fdt, node);
-
switch (id) {
- case COMPAT_NVIDIA_TEGRA20_PCIE:
+ case TEGRA20_PCIE:
switch (lanes) {
case 0x00000004:
debug("single-mode configuration\n");
@@ -366,8 +368,7 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
return 0;
}
break;
-
- case COMPAT_NVIDIA_TEGRA30_PCIE:
+ case TEGRA30_PCIE:
switch (lanes) {
case 0x00000204:
debug("4x1, 2x1 configuration\n");
@@ -385,9 +386,8 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
return 0;
}
break;
-
- case COMPAT_NVIDIA_TEGRA124_PCIE:
- case COMPAT_NVIDIA_TEGRA210_PCIE:
+ case TEGRA124_PCIE:
+ case TEGRA210_PCIE:
switch (lanes) {
case 0x0000104:
debug("4x1, 1x1 configuration\n");
@@ -400,7 +400,6 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
return 0;
}
break;
-
default:
break;
}
@@ -408,84 +407,6 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
return -FDT_ERR_NOTFOUND;
}
-static int tegra_pcie_parse_dt_ranges(const void *fdt, int node,
- struct tegra_pcie *pcie)
-{
- int parent, na_parent, na_pcie, ns_pcie;
- const u32 *ptr, *end;
- int len;
-
- parent = fdt_parent_offset(fdt, node);
- if (parent < 0) {
- error("Can't find PCI parent node\n");
- return -FDT_ERR_NOTFOUND;
- }
-
- na_parent = fdt_address_cells(fdt, parent);
- if (na_parent < 1) {
- error("bad #address-cells for PCIE parent\n");
- return -FDT_ERR_NOTFOUND;
- }
-
- na_pcie = fdt_address_cells(fdt, node);
- if (na_pcie < 1) {
- error("bad #address-cells for PCIE\n");
- return -FDT_ERR_NOTFOUND;
- }
-
- ns_pcie = fdt_size_cells(fdt, node);
- if (ns_pcie < 1) {
- error("bad #size-cells for PCIE\n");
- return -FDT_ERR_NOTFOUND;
- }
-
- ptr = fdt_getprop(fdt, node, "ranges", &len);
- if (!ptr) {
- error("missing \"ranges\" property");
- return -FDT_ERR_NOTFOUND;
- }
-
- end = ptr + len / 4;
-
- while (ptr < end) {
- struct fdt_resource *res = NULL;
- u32 space = fdt32_to_cpu(*ptr);
-
- switch ((space >> 24) & 0x3) {
- case 0x01:
- res = &pcie->io;
- break;
-
- case 0x02: /* 32 bit */
- case 0x03: /* 64 bit */
- if (space & (1 << 30))
- res = &pcie->prefetch;
- else
- res = &pcie->mem;
-
- break;
- }
-
- if (res) {
- int start_low = na_pcie + (na_parent - 1);
- int size_low = na_pcie + na_parent + (ns_pcie - 1);
- res->start = fdt32_to_cpu(ptr[start_low]);
- res->end = res->start + fdt32_to_cpu(ptr[size_low]);
- }
-
- ptr += na_pcie + na_parent + ns_pcie;
- }
-
- debug("PCI regions:\n");
- debug(" I/O: %pa-%pa\n", &pcie->io.start, &pcie->io.end);
- debug(" non-prefetchable memory: %pa-%pa\n", &pcie->mem.start,
- &pcie->mem.end);
- debug(" prefetchable memory: %pa-%pa\n", &pcie->prefetch.start,
- &pcie->prefetch.end);
-
- return 0;
-}
-
static int tegra_pcie_parse_port_info(const void *fdt, int node,
unsigned int *index,
unsigned int *lanes)
@@ -512,7 +433,12 @@ static int tegra_pcie_parse_port_info(const void *fdt, int node,
return 0;
}
-static int tegra_pcie_parse_dt(const void *fdt, int node,
+int __weak tegra_pcie_board_init(void)
+{
+ return 0;
+}
+
+static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
struct tegra_pcie *pcie)
{
int err, subnode;
@@ -539,6 +465,8 @@ static int tegra_pcie_parse_dt(const void *fdt, int node,
return err;
}
+ tegra_pcie_board_init();
+
pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
if (pcie->phy) {
err = tegra_xusb_phy_prepare(pcie->phy);
@@ -548,12 +476,6 @@ static int tegra_pcie_parse_dt(const void *fdt, int node,
}
}
- err = tegra_pcie_parse_dt_ranges(fdt, node, pcie);
- if (err < 0) {
- error("failed to parse \"ranges\" property");
- return err;
- }
-
fdt_for_each_subnode(fdt, subnode, node) {
unsigned int index = 0, num_lanes = 0;
struct tegra_pcie_port *port;
@@ -588,7 +510,7 @@ static int tegra_pcie_parse_dt(const void *fdt, int node,
port->pcie = pcie;
}
- err = tegra_pcie_get_xbar_config(fdt, node, lanes, &pcie->xbar);
+ err = tegra_pcie_get_xbar_config(fdt, node, lanes, id, &pcie->xbar);
if (err < 0) {
error("invalid lane configuration");
return err;
@@ -597,11 +519,6 @@ static int tegra_pcie_parse_dt(const void *fdt, int node,
return 0;
}
-int __weak tegra_pcie_board_init(void)
-{
- return 0;
-}
-
static int tegra_pcie_power_on(struct tegra_pcie *pcie)
{
const struct tegra_pcie_soc *soc = pcie->soc;
@@ -788,9 +705,12 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
return 0;
}
-static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
+static int tegra_pcie_setup_translations(struct udevice *bus)
{
+ struct tegra_pcie *pcie = dev_get_priv(bus);
unsigned long fpci, axi, size;
+ struct pci_region *io, *mem, *pref;
+ int count;
/* BAR 0: type 1 extended configuration space */
fpci = 0xfe100000;
@@ -801,28 +721,32 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ);
afi_writel(pcie, fpci, AFI_FPCI_BAR0);
+ count = pci_get_regions(bus, &io, &mem, &pref);
+ if (count != 3)
+ return -EINVAL;
+
/* BAR 1: downstream I/O */
fpci = 0xfdfc0000;
- size = fdt_resource_size(&pcie->io);
- axi = pcie->io.start;
+ size = io->size;
+ axi = io->phys_start;
afi_writel(pcie, axi, AFI_AXI_BAR1_START);
afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
afi_writel(pcie, fpci, AFI_FPCI_BAR1);
/* BAR 2: prefetchable memory */
- fpci = (((pcie->prefetch.start >> 12) & 0x0fffffff) << 4) | 0x1;
- size = fdt_resource_size(&pcie->prefetch);
- axi = pcie->prefetch.start;
+ fpci = (((pref->phys_start >> 12) & 0x0fffffff) << 4) | 0x1;
+ size = pref->size;
+ axi = pref->phys_start;
afi_writel(pcie, axi, AFI_AXI_BAR2_START);
afi_writel(pcie, size >> 12, AFI_AXI_BAR2_SZ);
afi_writel(pcie, fpci, AFI_FPCI_BAR2);
/* BAR 3: non-prefetchable memory */
- fpci = (((pcie->mem.start >> 12) & 0x0fffffff) << 4) | 0x1;
- size = fdt_resource_size(&pcie->mem);
- axi = pcie->mem.start;
+ fpci = (((mem->phys_start >> 12) & 0x0fffffff) << 4) | 0x1;
+ size = mem->size;
+ axi = mem->phys_start;
afi_writel(pcie, axi, AFI_AXI_BAR3_START);
afi_writel(pcie, size >> 12, AFI_AXI_BAR3_SZ);
@@ -848,6 +772,8 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
afi_writel(pcie, 0, AFI_MSI_AXI_BAR_ST);
afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
+
+ return 0;
}
static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
@@ -1001,209 +927,116 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie)
return 0;
}
-static const struct tegra_pcie_soc tegra20_pcie_soc = {
- .num_ports = 2,
- .pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
- .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
- .has_pex_clkreq_en = false,
- .has_pex_bias_ctrl = false,
- .has_cml_clk = false,
- .has_gen2 = false,
- .force_pca_enable = false,
-};
-
-static const struct tegra_pcie_soc tegra30_pcie_soc = {
- .num_ports = 3,
- .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
- .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
- .has_pex_clkreq_en = true,
- .has_pex_bias_ctrl = true,
- .has_cml_clk = true,
- .has_gen2 = false,
- .force_pca_enable = false,
-};
-
-static const struct tegra_pcie_soc tegra124_pcie_soc = {
- .num_ports = 2,
- .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
- .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
- .has_pex_clkreq_en = true,
- .has_pex_bias_ctrl = true,
- .has_cml_clk = true,
- .has_gen2 = true,
- .force_pca_enable = false,
-};
-
-static const struct tegra_pcie_soc tegra210_pcie_soc = {
- .num_ports = 2,
- .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
- .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
- .has_pex_clkreq_en = true,
- .has_pex_bias_ctrl = true,
- .has_cml_clk = true,
- .has_gen2 = true,
- .force_pca_enable = true,
+static const struct tegra_pcie_soc pci_tegra_soc[] = {
+ [TEGRA20_PCIE] = {
+ .num_ports = 2,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
+ .has_pex_clkreq_en = false,
+ .has_pex_bias_ctrl = false,
+ .has_cml_clk = false,
+ .has_gen2 = false,
+ },
+ [TEGRA30_PCIE] = {
+ .num_ports = 3,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_cml_clk = true,
+ .has_gen2 = false,
+ },
+ [TEGRA124_PCIE] = {
+ .num_ports = 2,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_cml_clk = true,
+ .has_gen2 = true,
+ },
+ [TEGRA210_PCIE] = {
+ .num_ports = 2,
+ .pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+ .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+ .has_pex_clkreq_en = true,
+ .has_pex_bias_ctrl = true,
+ .has_cml_clk = true,
+ .has_gen2 = true,
+ .force_pca_enable = true,
+ }
};
-static int process_nodes(const void *fdt, int nodes[], unsigned int count)
+static int pci_tegra_ofdata_to_platdata(struct udevice *dev)
{
- unsigned int i;
- uint64_t dram_end;
- uint32_t pci_dram_size;
-
- /* Clip PCI-accessible DRAM to 32-bits */
- dram_end = ((uint64_t)NV_PA_SDRAM_BASE) + gd->ram_size;
- if (dram_end > 0x100000000)
- dram_end = 0x100000000;
- pci_dram_size = dram_end - NV_PA_SDRAM_BASE;
-
- for (i = 0; i < count; i++) {
- const struct tegra_pcie_soc *soc;
- struct tegra_pcie *pcie;
- enum fdt_compat_id id;
- int err;
-
- if (!fdtdec_get_is_enabled(fdt, nodes[i]))
- continue;
-
- id = fdtdec_lookup(fdt, nodes[i]);
- switch (id) {
- case COMPAT_NVIDIA_TEGRA20_PCIE:
- soc = &tegra20_pcie_soc;
- break;
-
- case COMPAT_NVIDIA_TEGRA30_PCIE:
- soc = &tegra30_pcie_soc;
- break;
-
- case COMPAT_NVIDIA_TEGRA124_PCIE:
- soc = &tegra124_pcie_soc;
- break;
-
- case COMPAT_NVIDIA_TEGRA210_PCIE:
- soc = &tegra210_pcie_soc;
- break;
-
- default:
- error("unsupported compatible: %s",
- fdtdec_get_compatible(id));
- continue;
- }
-
- pcie = malloc(sizeof(*pcie));
- if (!pcie) {
- error("failed to allocate controller");
- continue;
- }
-
- memset(pcie, 0, sizeof(*pcie));
- pcie->soc = soc;
-
- INIT_LIST_HEAD(&pcie->ports);
-
- err = tegra_pcie_parse_dt(fdt, nodes[i], pcie);
- if (err < 0) {
- free(pcie);
- continue;
- }
-
- err = tegra_pcie_power_on(pcie);
- if (err < 0) {
- error("failed to power on");
- continue;
- }
+ struct tegra_pcie *pcie = dev_get_priv(dev);
+ enum tegra_pci_id id;
- err = tegra_pcie_enable_controller(pcie);
- if (err < 0) {
- error("failed to enable controller");
- continue;
- }
-
- tegra_pcie_setup_translations(pcie);
-
- err = tegra_pcie_enable(pcie);
- if (err < 0) {
- error("failed to enable PCIe");
- continue;
- }
+ id = dev_get_driver_data(dev);
+ pcie->soc = &pci_tegra_soc[id];
- pcie->hose.first_busno = 0;
- pcie->hose.current_busno = 0;
- pcie->hose.last_busno = 0;
+ INIT_LIST_HEAD(&pcie->ports);
- pci_set_region(&pcie->hose.regions[0], NV_PA_SDRAM_BASE,
- NV_PA_SDRAM_BASE, pci_dram_size,
- PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ if (tegra_pcie_parse_dt(gd->fdt_blob, dev->of_offset, id, pcie))
+ return -EINVAL;
- pci_set_region(&pcie->hose.regions[1], pcie->io.start,
- pcie->io.start, fdt_resource_size(&pcie->io),
- PCI_REGION_IO);
-
- pci_set_region(&pcie->hose.regions[2], pcie->mem.start,
- pcie->mem.start, fdt_resource_size(&pcie->mem),
- PCI_REGION_MEM);
-
- pci_set_region(&pcie->hose.regions[3], pcie->prefetch.start,
- pcie->prefetch.start,
- fdt_resource_size(&pcie->prefetch),
- PCI_REGION_MEM | PCI_REGION_PREFETCH);
+ return 0;
+}
- pcie->hose.region_count = 4;
+static int pci_tegra_probe(struct udevice *dev)
+{
+ struct tegra_pcie *pcie = dev_get_priv(dev);
+ int err;
- pci_set_ops(&pcie->hose,
- pci_hose_read_config_byte_via_dword,
- pci_hose_read_config_word_via_dword,
- tegra_pcie_read_conf,
- pci_hose_write_config_byte_via_dword,
- pci_hose_write_config_word_via_dword,
- tegra_pcie_write_conf);
+ err = tegra_pcie_power_on(pcie);
+ if (err < 0) {
+ error("failed to power on");
+ return err;
+ }
- pci_register_hose(&pcie->hose);
+ err = tegra_pcie_enable_controller(pcie);
+ if (err < 0) {
+ error("failed to enable controller");
+ return err;
+ }
-#ifdef CONFIG_PCI_SCAN_SHOW
- printf("PCI: Enumerating devices...\n");
- printf("---------------------------------------\n");
- printf(" Device ID Description\n");
- printf(" ------ -- -----------\n");
-#endif
+ err = tegra_pcie_setup_translations(dev);
+ if (err < 0) {
+ error("failed to decode ranges");
+ return err;
+ }
- pcie->hose.last_busno = pci_hose_scan(&pcie->hose);
+ err = tegra_pcie_enable(pcie);
+ if (err < 0) {
+ error("failed to enable PCIe");
+ return err;
}
return 0;
}
-void pci_init_board(void)
-{
- const void *fdt = gd->fdt_blob;
- int count, nodes[1];
+static const struct dm_pci_ops pci_tegra_ops = {
+ .read_config = pci_tegra_read_config,
+ .write_config = pci_tegra_write_config,
+};
- tegra_pcie_board_init();
+static const struct udevice_id pci_tegra_ids[] = {
+ { .compatible = "nvidia,tegra20-pcie", .data = TEGRA20_PCIE },
+ { .compatible = "nvidia,tegra30-pcie", .data = TEGRA30_PCIE },
+ { .compatible = "nvidia,tegra124-pcie", .data = TEGRA124_PCIE },
+ { .compatible = "nvidia,tegra210-pcie", .data = TEGRA210_PCIE },
+ { }
+};
- count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
- COMPAT_NVIDIA_TEGRA210_PCIE,
- nodes, ARRAY_SIZE(nodes));
- if (process_nodes(fdt, nodes, count))
- return;
-
- count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
- COMPAT_NVIDIA_TEGRA124_PCIE,
- nodes, ARRAY_SIZE(nodes));
- if (process_nodes(fdt, nodes, count))
- return;
-
- count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
- COMPAT_NVIDIA_TEGRA30_PCIE,
- nodes, ARRAY_SIZE(nodes));
- if (process_nodes(fdt, nodes, count))
- return;
-
- count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
- COMPAT_NVIDIA_TEGRA20_PCIE,
- nodes, ARRAY_SIZE(nodes));
- if (process_nodes(fdt, nodes, count))
- return;
-}
+U_BOOT_DRIVER(pci_tegra) = {
+ .name = "pci_tegra",
+ .id = UCLASS_PCI,
+ .of_match = pci_tegra_ids,
+ .ops = &pci_tegra_ops,
+ .ofdata_to_platdata = pci_tegra_ofdata_to_platdata,
+ .probe = pci_tegra_probe,
+ .priv_auto_alloc_size = sizeof(struct tegra_pcie),
+};
int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
{
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c
index 4cee038ede..58e88ae45e 100644
--- a/drivers/pci/pcie_layerscape.c
+++ b/drivers/pci/pcie_layerscape.c
@@ -11,8 +11,9 @@
#include <asm/io.h>
#include <errno.h>
#include <malloc.h>
-#ifdef CONFIG_FSL_LAYERSCAPE
+#ifndef CONFIG_LS102XA
#include <asm/arch/fdt.h>
+#include <asm/arch/soc.h>
#endif
#ifndef CONFIG_SYS_PCI_MEMORY_BUS
@@ -57,11 +58,6 @@
#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
#define PCIE_ATU_UPPER_TARGET 0x91C
-/* LUT registers */
-#define PCIE_LUT_BASE 0x80000
-#define PCIE_LUT_LCTRL0 0x7F8
-#define PCIE_LUT_DBG 0x7FC
-
#define PCIE_DBI_RO_WR_EN 0x8bc
#define PCIE_LINK_CAP 0x7c
@@ -162,7 +158,7 @@ static int ls_pcie_link_state(struct ls_pcie *pcie)
{
u32 state;
- state = readl(pcie->dbi + PCIE_LUT_BASE + PCIE_LUT_DBG) &
+ state = pex_lut_in32(pcie->dbi + PCIE_LUT_BASE + PCIE_LUT_DBG) &
LTSSM_STATE_MASK;
if (state < LTSSM_PCIE_L0) {
debug("....PCIe link error. LTSSM=0x%02x.\n", state);
@@ -466,16 +462,20 @@ static void ls_pcie_setup_ep(struct ls_pcie *pcie, struct ls_pcie_info *info)
for (pf = 0; pf < PCIE_PF_NUM; pf++) {
for (vf = 0; vf <= PCIE_VF_NUM; vf++) {
+#ifndef CONFIG_LS102XA
writel(PCIE_LCTRL0_VAL(pf, vf),
pcie->dbi + PCIE_LUT_BASE +
PCIE_LUT_LCTRL0);
+#endif
ls_pcie_ep_setup_bars(pcie->dbi);
ls_pcie_ep_setup_atu(pcie, info);
}
}
/* Disable CFG2 */
+#ifndef CONFIG_LS102XA
writel(0, pcie->dbi + PCIE_LUT_BASE + PCIE_LUT_LCTRL0);
+#endif
} else {
ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE);
ls_pcie_ep_setup_atu(pcie, info);
@@ -665,7 +665,7 @@ void ft_pci_setup(void *blob, bd_t *bd)
}
#endif
-#ifdef CONFIG_LS2085A
+#if defined(CONFIG_LS2080A) || defined(CONFIG_LS2085A)
void pcie_set_available_streamids(void *blob, const char *pcie_path,
u32 *stream_ids, int count)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 3b6e3b7060..57e6142c50 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -114,6 +114,15 @@ config ROCKCHIP_PINCTRL
definitions and pin control functions for each available multiplex
function.
+config ROCKCHIP_3036_PINCTRL
+ bool "Rockchip rk3036 pin control driver"
+ depends on DM
+ help
+ Support pin multiplexing control on Rockchip rk3036 SoCs. The driver is
+ controlled by a device tree node which contains both the GPIO
+ definitions and pin control functions for each available multiplex
+ function.
+
config PINCTRL_SANDBOX
bool "Sandbox pinctrl driver"
depends on SANDBOX
diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile
index 251bace797..6fa7d00d0d 100644
--- a/drivers/pinctrl/rockchip/Makefile
+++ b/drivers/pinctrl/rockchip/Makefile
@@ -6,3 +6,4 @@
#
obj-$(CONFIG_ROCKCHIP_PINCTRL) += pinctrl_rk3288.o
+obj-$(CONFIG_ROCKCHIP_3036_PINCTRL) += pinctrl_rk3036.o
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3036.c b/drivers/pinctrl/rockchip/pinctrl_rk3036.c
new file mode 100644
index 0000000000..581b09688c
--- /dev/null
+++ b/drivers/pinctrl/rockchip/pinctrl_rk3036.c
@@ -0,0 +1,276 @@
+/*
+ * Pinctrl driver for Rockchip 3036 SoCs
+ * (C) Copyright 2015 Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/grf_rk3036.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/periph.h>
+#include <dm/pinctrl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct rk3036_pinctrl_priv {
+ struct rk3036_grf *grf;
+};
+
+static void pinctrl_rk3036_pwm_config(struct rk3036_grf *grf, int pwm_id)
+{
+ switch (pwm_id) {
+ case PERIPH_ID_PWM0:
+ rk_clrsetreg(&grf->gpio0d_iomux, GPIO0D2_MASK << GPIO0D2_SHIFT,
+ GPIO0D2_PWM0 << GPIO0D2_SHIFT);
+ break;
+ case PERIPH_ID_PWM1:
+ rk_clrsetreg(&grf->gpio0a_iomux, GPIO0A0_MASK << GPIO0A0_SHIFT,
+ GPIO0A0_PWM1 << GPIO0A0_SHIFT);
+ break;
+ case PERIPH_ID_PWM2:
+ rk_clrsetreg(&grf->gpio0a_iomux, GPIO0A1_MASK << GPIO0A1_SHIFT,
+ GPIO0A1_PWM2 << GPIO0A1_SHIFT);
+ break;
+ case PERIPH_ID_PWM3:
+ rk_clrsetreg(&grf->gpio0a_iomux, GPIO0D3_MASK << GPIO0D3_SHIFT,
+ GPIO0D3_PWM3 << GPIO0D3_SHIFT);
+ break;
+ default:
+ debug("pwm id = %d iomux error!\n", pwm_id);
+ break;
+ }
+}
+
+static void pinctrl_rk3036_i2c_config(struct rk3036_grf *grf, int i2c_id)
+{
+ switch (i2c_id) {
+ case PERIPH_ID_I2C0:
+ rk_clrsetreg(&grf->gpio0a_iomux,
+ GPIO0A1_MASK << GPIO0A1_SHIFT |
+ GPIO0A0_MASK << GPIO0A0_SHIFT,
+ GPIO0A1_I2C0_SDA << GPIO0A1_SHIFT |
+ GPIO0A0_I2C0_SCL << GPIO0A0_SHIFT);
+
+ break;
+ case PERIPH_ID_I2C1:
+ rk_clrsetreg(&grf->gpio0a_iomux,
+ GPIO0A3_MASK << GPIO0A3_SHIFT |
+ GPIO0A2_MASK << GPIO0A2_SHIFT,
+ GPIO0A3_I2C1_SDA << GPIO0A3_SHIFT |
+ GPIO0A2_I2C1_SCL << GPIO0A2_SHIFT);
+ break;
+ case PERIPH_ID_I2C2:
+ rk_clrsetreg(&grf->gpio2c_iomux,
+ GPIO2C5_MASK << GPIO2C5_SHIFT |
+ GPIO2C4_MASK << GPIO2C4_SHIFT,
+ GPIO2C5_I2C2_SCL << GPIO2C5_SHIFT |
+ GPIO2C4_I2C2_SDA << GPIO2C4_SHIFT);
+
+ break;
+ }
+}
+
+static void pinctrl_rk3036_spi_config(struct rk3036_grf *grf, int cs)
+{
+ switch (cs) {
+ case 0:
+ rk_clrsetreg(&grf->gpio1d_iomux,
+ GPIO1D6_MASK << GPIO1D6_SHIFT,
+ GPIO1D6_SPI_CSN0 << GPIO1D6_SHIFT);
+ break;
+ case 1:
+ rk_clrsetreg(&grf->gpio1d_iomux,
+ GPIO1D7_MASK << GPIO1D7_SHIFT,
+ GPIO1D7_SPI_CSN1 << GPIO1D7_SHIFT);
+ break;
+ }
+ rk_clrsetreg(&grf->gpio1d_iomux,
+ GPIO1D5_MASK << GPIO1D5_SHIFT |
+ GPIO1D4_MASK << GPIO1D4_SHIFT,
+ GPIO1D5_SPI_TXD << GPIO1D5_SHIFT |
+ GPIO1D4_SPI_RXD << GPIO1D4_SHIFT);
+
+ rk_clrsetreg(&grf->gpio2a_iomux,
+ GPIO2A0_MASK << GPIO2A0_SHIFT,
+ GPIO2A0_SPI_CLK << GPIO2A0_SHIFT);
+}
+
+static void pinctrl_rk3036_uart_config(struct rk3036_grf *grf, int uart_id)
+{
+ switch (uart_id) {
+ case PERIPH_ID_UART0:
+ rk_clrsetreg(&grf->gpio0c_iomux,
+ GPIO0C3_MASK << GPIO0C3_SHIFT |
+ GPIO0C2_MASK << GPIO0C2_SHIFT |
+ GPIO0C1_MASK << GPIO0C1_SHIFT |
+ GPIO0C0_MASK << GPIO0C0_SHIFT,
+ GPIO0C3_UART0_CTSN << GPIO0C3_SHIFT |
+ GPIO0C2_UART0_RTSN << GPIO0C2_SHIFT |
+ GPIO0C1_UART0_SIN << GPIO0C1_SHIFT |
+ GPIO0C0_UART0_SOUT << GPIO0C0_SHIFT);
+ break;
+ case PERIPH_ID_UART1:
+ rk_clrsetreg(&grf->gpio2c_iomux,
+ GPIO2C7_MASK << GPIO2C7_SHIFT |
+ GPIO2C6_MASK << GPIO2C6_SHIFT,
+ GPIO2C7_UART1_SOUT << GPIO2C7_SHIFT |
+ GPIO2C6_UART1_SIN << GPIO2C6_SHIFT);
+ break;
+ case PERIPH_ID_UART2:
+ rk_clrsetreg(&grf->gpio1c_iomux,
+ GPIO1C3_MASK << GPIO1C3_SHIFT |
+ GPIO1C2_MASK << GPIO1C2_SHIFT,
+ GPIO1C3_UART2_SOUT << GPIO1C3_SHIFT |
+ GPIO1C2_UART2_SIN << GPIO1C2_SHIFT);
+ break;
+ }
+}
+
+static void pinctrl_rk3036_sdmmc_config(struct rk3036_grf *grf, int mmc_id)
+{
+ switch (mmc_id) {
+ case PERIPH_ID_EMMC:
+ rk_clrsetreg(&grf->gpio1d_iomux, 0xffff,
+ GPIO1D7_EMMC_D7 << GPIO1D7_SHIFT |
+ GPIO1D6_EMMC_D6 << GPIO1D6_SHIFT |
+ GPIO1D5_EMMC_D5 << GPIO1D5_SHIFT |
+ GPIO1D4_EMMC_D4 << GPIO1D4_SHIFT |
+ GPIO1D3_EMMC_D3 << GPIO1D3_SHIFT |
+ GPIO1D2_EMMC_D2 << GPIO1D2_SHIFT |
+ GPIO1D1_EMMC_D1 << GPIO1D1_SHIFT |
+ GPIO1D0_EMMC_D0 << GPIO1D0_SHIFT);
+ rk_clrsetreg(&grf->gpio2a_iomux,
+ GPIO2A4_MASK << GPIO2A4_SHIFT |
+ GPIO2A1_MASK << GPIO2A1_SHIFT,
+ GPIO2A4_EMMC_CMD << GPIO2A4_SHIFT |
+ GPIO2A1_EMMC_CLKOUT << GPIO2A1_SHIFT);
+ break;
+ case PERIPH_ID_SDCARD:
+ rk_clrsetreg(&grf->gpio1c_iomux, 0xffff,
+ GPIO1C5_MMC0_D3 << GPIO1C5_SHIFT |
+ GPIO1C4_MMC0_D2 << GPIO1C4_SHIFT |
+ GPIO1C3_MMC0_D1 << GPIO1C3_SHIFT |
+ GPIO1C2_MMC0_D0 << GPIO1C2_SHIFT |
+ GPIO1C1_MMC0_DETN << GPIO1C1_SHIFT |
+ GPIO1C0_MMC0_CLKOUT << GPIO1C0_SHIFT);
+ break;
+ }
+}
+
+static int rk3036_pinctrl_request(struct udevice *dev, int func, int flags)
+{
+ struct rk3036_pinctrl_priv *priv = dev_get_priv(dev);
+
+ debug("%s: func=%x, flags=%x\n", __func__, func, flags);
+ switch (func) {
+ case PERIPH_ID_PWM0:
+ case PERIPH_ID_PWM1:
+ case PERIPH_ID_PWM2:
+ case PERIPH_ID_PWM3:
+ pinctrl_rk3036_pwm_config(priv->grf, func);
+ break;
+ case PERIPH_ID_I2C0:
+ case PERIPH_ID_I2C1:
+ case PERIPH_ID_I2C2:
+ pinctrl_rk3036_i2c_config(priv->grf, func);
+ break;
+ case PERIPH_ID_SPI0:
+ pinctrl_rk3036_spi_config(priv->grf, flags);
+ break;
+ case PERIPH_ID_UART0:
+ case PERIPH_ID_UART1:
+ case PERIPH_ID_UART2:
+ pinctrl_rk3036_uart_config(priv->grf, func);
+ break;
+ case PERIPH_ID_SDMMC0:
+ case PERIPH_ID_SDMMC1:
+ pinctrl_rk3036_sdmmc_config(priv->grf, func);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rk3036_pinctrl_get_periph_id(struct udevice *dev,
+ struct udevice *periph)
+{
+ u32 cell[3];
+ int ret;
+
+ ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset,
+ "interrupts", cell, ARRAY_SIZE(cell));
+ if (ret < 0)
+ return -EINVAL;
+
+ switch (cell[1]) {
+ case 14:
+ return PERIPH_ID_SDCARD;
+ case 16:
+ return PERIPH_ID_EMMC;
+ case 20:
+ return PERIPH_ID_UART0;
+ case 21:
+ return PERIPH_ID_UART1;
+ case 22:
+ return PERIPH_ID_UART2;
+ case 23:
+ return PERIPH_ID_SPI0;
+ case 24:
+ return PERIPH_ID_I2C0;
+ case 25:
+ return PERIPH_ID_I2C1;
+ case 26:
+ return PERIPH_ID_I2C2;
+ case 30:
+ return PERIPH_ID_PWM0;
+ }
+ return -ENOENT;
+}
+
+static int rk3036_pinctrl_set_state_simple(struct udevice *dev,
+ struct udevice *periph)
+{
+ int func;
+
+ func = rk3036_pinctrl_get_periph_id(dev, periph);
+ if (func < 0)
+ return func;
+ return rk3036_pinctrl_request(dev, func, 0);
+}
+
+static struct pinctrl_ops rk3036_pinctrl_ops = {
+ .set_state_simple = rk3036_pinctrl_set_state_simple,
+ .request = rk3036_pinctrl_request,
+ .get_periph_id = rk3036_pinctrl_get_periph_id,
+};
+
+static int rk3036_pinctrl_probe(struct udevice *dev)
+{
+ struct rk3036_pinctrl_priv *priv = dev_get_priv(dev);
+
+ priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ debug("%s: grf=%p\n", __func__, priv->grf);
+ return 0;
+}
+
+static const struct udevice_id rk3036_pinctrl_ids[] = {
+ { .compatible = "rockchip,rk3036-pinctrl" },
+ { }
+};
+
+U_BOOT_DRIVER(pinctrl_rk3036) = {
+ .name = "pinctrl_rk3036",
+ .id = UCLASS_PINCTRL,
+ .of_match = rk3036_pinctrl_ids,
+ .priv_auto_alloc_size = sizeof(struct rk3036_pinctrl_priv),
+ .ops = &rk3036_pinctrl_ops,
+ .probe = rk3036_pinctrl_probe,
+};
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 809f8f1180..1936e5f1fc 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -8,7 +8,8 @@ choice
prompt "Select Sunxi PMIC Variant"
depends on ARCH_SUNXI
default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
- default AXP221_POWER if MACH_SUN6I || MACH_SUN8I
+ default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
+ default SUNXI_NO_PMIC if MACH_SUN8I_H3
config SUNXI_NO_PMIC
boolean "board without a pmic"
@@ -31,7 +32,7 @@ config AXP209_POWER
config AXP221_POWER
boolean "axp221 / axp223 pmic support"
- depends on MACH_SUN6I || MACH_SUN8I
+ depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
---help---
Select this to enable support for the axp221/axp223 pmic found on most
A23 and A31 boards.
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index eba96f4a80..82ad90d9e8 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -53,6 +53,7 @@ config DEBUG_UART
choice
prompt "Select which UART will provide the debug UART"
depends on DEBUG_UART
+ default DEBUG_UART_NS16550
config DEBUG_UART_ALTERA_JTAGUART
bool "Altera JTAG UART"
@@ -185,14 +186,15 @@ config ALTERA_UART
Select this to enable an UART for Altera devices. Please find
details on the "Embedded Peripherals IP User Guide" of Altera.
-config ROCKCHIP_SERIAL
- bool "Rockchip on-chip UART support"
- depends on ARCH_ROCKCHIP && DM_SERIAL
+config SYS_NS16550
+ bool "NS16550 UART or compatible"
help
- Select this to enable a debug UART for Rockchip devices. This uses
- the ns16550 driver. You will need to #define CONFIG_SYS_NS16550 in
- your board config header. The clock input is automatically set to
- use the oscillator (24MHz).
+ Support NS16550 UART or compatible. This can be enabled in the
+ device tree with the correct input clock frequency. If the input
+ clock frequency is not defined in the device tree, the macro
+ CONFIG_SYS_NS16550_CLK defined in a legacy board header file will
+ be used. It can be a constant or a function to get clock, eg,
+ get_serial_clock().
config SANDBOX_SERIAL
bool "Sandbox UART support"
@@ -221,14 +223,4 @@ config UNIPHIER_SERIAL
If you have a UniPhier based board and want to use the on-chip
serial ports, say Y to this option. If unsure, say N.
-config X86_SERIAL
- bool "Support for 16550 serial port on x86 machines"
- depends on X86
- default y
- help
- Most x86 machines have a ns16550 UART or compatible. This can be
- enabled in the device tree with the correct input clock frequency
- provided (default 1843200). Enable this to obtain serial console
- output.
-
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 1818c7c3a6..dd871478ea 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -8,7 +8,6 @@
ifdef CONFIG_DM_SERIAL
obj-y += serial-uclass.o
obj-$(CONFIG_PL01X_SERIAL) += serial_pl01x.o
-obj-$(CONFIG_PPC) += serial_ppc.o
else
obj-y += serial.o
obj-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
@@ -20,12 +19,10 @@ obj-$(CONFIG_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
obj-$(CONFIG_ARM_DCC) += arm_dcc.o
obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
-obj-$(CONFIG_DW_SERIAL) += serial_dw.o
obj-$(CONFIG_EFI_APP) += serial_efi.o
obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o
obj-$(CONFIG_MCFUART) += mcfuart.o
obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o
-obj-$(CONFIG_KEYSTONE_SERIAL) += serial_keystone.o
obj-$(CONFIG_SYS_NS16550) += ns16550.o
obj-$(CONFIG_S5P) += serial_s5p.o
obj-$(CONFIG_IMX_SERIAL) += serial_imx.o
@@ -41,12 +38,8 @@ obj-$(CONFIG_ZYNQ_SERIAL) += serial_zynq.o
obj-$(CONFIG_BFIN_SERIAL) += serial_bfin.o
obj-$(CONFIG_FSL_LPUART) += serial_lpuart.o
obj-$(CONFIG_MXS_AUART) += mxs_auart.o
-obj-$(CONFIG_ROCKCHIP_SERIAL) += serial_rockchip.o
obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
-obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o
obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o
-obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
-obj-$(CONFIG_X86_SERIAL) += serial_x86.o
obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o
ifndef CONFIG_SPL_BUILD
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 6433844f18..166deabcd4 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -8,7 +8,6 @@
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
-#include <mapmem.h>
#include <ns16550.h>
#include <serial.h>
#include <watchdog.h>
@@ -57,6 +56,10 @@ DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_DM_SERIAL
+#ifndef CONFIG_SYS_NS16550_CLK
+#define CONFIG_SYS_NS16550_CLK 0
+#endif
+
static inline void serial_out_shift(void *addr, int shift, int value)
{
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
@@ -97,7 +100,7 @@ static void ns16550_writeb(NS16550_t port, int offset, int value)
unsigned char *addr;
offset *= 1 << plat->reg_shift;
- addr = map_sysmem(plat->base, 0) + offset;
+ addr = map_physmem(plat->base, 0, MAP_NOCACHE) + offset;
/*
* As far as we know it doesn't make sense to support selection of
* these options at run-time, so use the existing CONFIG options.
@@ -111,7 +114,7 @@ static int ns16550_readb(NS16550_t port, int offset)
unsigned char *addr;
offset *= 1 << plat->reg_shift;
- addr = map_sysmem(plat->base, 0) + offset;
+ addr = map_physmem(plat->base, 0, MAP_NOCACHE) + offset;
return serial_in_shift(addr, plat->reg_shift);
}
@@ -401,6 +404,13 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
plat->base = addr;
plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"reg-shift", 1);
+ plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "clock-frequency",
+ CONFIG_SYS_NS16550_CLK);
+ if (!plat->clock) {
+ debug("ns16550 clock not defined\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -412,4 +422,34 @@ const struct dm_serial_ops ns16550_serial_ops = {
.getc = ns16550_serial_getc,
.setbrg = ns16550_serial_setbrg,
};
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static const struct udevice_id ns16550_serial_ids[] = {
+ { .compatible = "ns16550" },
+ { .compatible = "ns16550a" },
+ { .compatible = "nvidia,tegra20-uart" },
+ { .compatible = "rockchip,rk3036-uart" },
+ { .compatible = "snps,dw-apb-uart" },
+ { .compatible = "ti,omap2-uart" },
+ { .compatible = "ti,omap3-uart" },
+ { .compatible = "ti,omap4-uart" },
+ { .compatible = "ti,am3352-uart" },
+ { .compatible = "ti,am4372-uart" },
+ { .compatible = "ti,dra742-uart" },
+ {}
+};
+#endif
+
+U_BOOT_DRIVER(ns16550_serial) = {
+ .name = "ns16550_serial",
+ .id = UCLASS_SERIAL,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+ .of_match = ns16550_serial_ids,
+ .ofdata_to_platdata = ns16550_serial_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
+#endif
+ .priv_auto_alloc_size = sizeof(struct NS16550),
+ .probe = ns16550_serial_probe,
+ .ops = &ns16550_serial_ops,
+};
#endif /* CONFIG_DM_SERIAL */
diff --git a/drivers/serial/serial_dw.c b/drivers/serial/serial_dw.c
deleted file mode 100644
index a348f2956a..0000000000
--- a/drivers/serial/serial_dw.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2014 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <dm.h>
-#include <ns16550.h>
-#include <serial.h>
-
-static const struct udevice_id dw_serial_ids[] = {
- { .compatible = "snps,dw-apb-uart" },
- { }
-};
-
-static int dw_serial_ofdata_to_platdata(struct udevice *dev)
-{
- struct ns16550_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- ret = ns16550_serial_ofdata_to_platdata(dev);
- if (ret)
- return ret;
- plat->clock = CONFIG_SYS_NS16550_CLK;
-
- return 0;
-}
-
-U_BOOT_DRIVER(serial_ns16550) = {
- .name = "serial_dw",
- .id = UCLASS_SERIAL,
- .of_match = dw_serial_ids,
- .ofdata_to_platdata = dw_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
- .priv_auto_alloc_size = sizeof(struct NS16550),
- .probe = ns16550_serial_probe,
- .ops = &ns16550_serial_ops,
-};
diff --git a/drivers/serial/serial_keystone.c b/drivers/serial/serial_keystone.c
deleted file mode 100644
index 7b5ab6c5ca..0000000000
--- a/drivers/serial/serial_keystone.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2015 Texas Instruments, <www.ti.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <dm.h>
-#include <fdtdec.h>
-#include <ns16550.h>
-#include <serial.h>
-#include <asm/arch/clock.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-static const struct udevice_id keystone_serial_ids[] = {
- { .compatible = "ti,keystone-uart" },
- { .compatible = "ns16550a" },
- { }
-};
-
-static int keystone_serial_ofdata_to_platdata(struct udevice *dev)
-{
- struct ns16550_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- ret = ns16550_serial_ofdata_to_platdata(dev);
- if (ret)
- return ret;
- plat->clock = CONFIG_SYS_NS16550_CLK;
- return 0;
-}
-#endif
-
-U_BOOT_DRIVER(serial_keystone_ns16550) = {
- .name = "serial_keystone",
- .id = UCLASS_SERIAL,
-#if CONFIG_IS_ENABLED(OF_CONTROL)
- .of_match = of_match_ptr(keystone_serial_ids),
- .ofdata_to_platdata = of_match_ptr(keystone_serial_ofdata_to_platdata),
- .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
-#endif
- .priv_auto_alloc_size = sizeof(struct NS16550),
- .probe = ns16550_serial_probe,
- .ops = &ns16550_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
-};
diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c
deleted file mode 100644
index 891cd7b7ed..0000000000
--- a/drivers/serial/serial_omap.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2014 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <dm.h>
-#include <fdtdec.h>
-#include <ns16550.h>
-#include <serial.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz */
-
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-static const struct udevice_id omap_serial_ids[] = {
- { .compatible = "ti,omap2-uart" },
- { .compatible = "ti,omap3-uart" },
- { .compatible = "ti,omap4-uart" },
- { .compatible = "ti,am3352-uart" },
- { .compatible = "ti,am4372-uart" },
- { .compatible = "ti,dra742-uart" },
- { }
-};
-
-static int omap_serial_ofdata_to_platdata(struct udevice *dev)
-{
- struct ns16550_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- ret = ns16550_serial_ofdata_to_platdata(dev);
- if (ret)
- return ret;
- plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
- "clock-frequency", DEFAULT_CLK_SPEED);
- plat->reg_shift = 2;
-
- return 0;
-}
-#endif
-
-U_BOOT_DRIVER(serial_omap_ns16550) = {
- .name = "serial_omap",
- .id = UCLASS_SERIAL,
- .of_match = of_match_ptr(omap_serial_ids),
- .ofdata_to_platdata = of_match_ptr(omap_serial_ofdata_to_platdata),
- .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
- .priv_auto_alloc_size = sizeof(struct NS16550),
- .probe = ns16550_serial_probe,
- .ops = &ns16550_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
-};
diff --git a/drivers/serial/serial_ppc.c b/drivers/serial/serial_ppc.c
deleted file mode 100644
index 47141c64eb..0000000000
--- a/drivers/serial/serial_ppc.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2014 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <dm.h>
-#include <ns16550.h>
-#include <serial.h>
-
-static const struct udevice_id ppc_serial_ids[] = {
- { .compatible = "ns16550" },
- { }
-};
-
-static int ppc_serial_ofdata_to_platdata(struct udevice *dev)
-{
- struct ns16550_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- ret = ns16550_serial_ofdata_to_platdata(dev);
- if (ret)
- return ret;
- plat->clock = get_serial_clock();
-
- return 0;
-}
-
-U_BOOT_DRIVER(serial_ns16550) = {
- .name = "serial_ppc",
- .id = UCLASS_SERIAL,
- .of_match = ppc_serial_ids,
- .ofdata_to_platdata = ppc_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
- .priv_auto_alloc_size = sizeof(struct NS16550),
- .probe = ns16550_serial_probe,
- .ops = &ns16550_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
-};
diff --git a/drivers/serial/serial_rockchip.c b/drivers/serial/serial_rockchip.c
deleted file mode 100644
index 0e7bbfc690..0000000000
--- a/drivers/serial/serial_rockchip.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2015 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <dm.h>
-#include <ns16550.h>
-#include <serial.h>
-#include <asm/arch/clock.h>
-
-static const struct udevice_id rockchip_serial_ids[] = {
- { .compatible = "rockchip,rk3288-uart" },
- { }
-};
-
-static int rockchip_serial_ofdata_to_platdata(struct udevice *dev)
-{
- struct ns16550_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- ret = ns16550_serial_ofdata_to_platdata(dev);
- if (ret)
- return ret;
-
- /* Do all Rockchip parts use 24MHz? */
- plat->clock = 24 * 1000000;
-
- return 0;
-}
-
-U_BOOT_DRIVER(serial_ns16550) = {
- .name = "serial_rockchip",
- .id = UCLASS_SERIAL,
- .of_match = rockchip_serial_ids,
- .ofdata_to_platdata = rockchip_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
- .priv_auto_alloc_size = sizeof(struct NS16550),
- .probe = ns16550_serial_probe,
- .ops = &ns16550_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
-};
diff --git a/drivers/serial/serial_tegra.c b/drivers/serial/serial_tegra.c
deleted file mode 100644
index 0c84f0bc91..0000000000
--- a/drivers/serial/serial_tegra.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2014 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <dm.h>
-#include <ns16550.h>
-#include <serial.h>
-
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-static const struct udevice_id tegra_serial_ids[] = {
- { .compatible = "nvidia,tegra20-uart" },
- { }
-};
-
-static int tegra_serial_ofdata_to_platdata(struct udevice *dev)
-{
- struct ns16550_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- ret = ns16550_serial_ofdata_to_platdata(dev);
- if (ret)
- return ret;
- plat->clock = V_NS16550_CLK;
-
- return 0;
-}
-#else
-struct ns16550_platdata tegra_serial = {
- .base = CONFIG_SYS_NS16550_COM1,
- .reg_shift = 2,
- .clock = V_NS16550_CLK,
-};
-
-U_BOOT_DEVICE(ns16550_serial) = {
- "serial_tegra20", &tegra_serial
-};
-#endif
-
-U_BOOT_DRIVER(serial_ns16550) = {
- .name = "serial_tegra20",
- .id = UCLASS_SERIAL,
-#if CONFIG_IS_ENABLED(OF_CONTROL)
- .of_match = tegra_serial_ids,
- .ofdata_to_platdata = tegra_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
-#endif
- .priv_auto_alloc_size = sizeof(struct NS16550),
- .probe = ns16550_serial_probe,
- .ops = &ns16550_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
-};
diff --git a/drivers/serial/serial_x86.c b/drivers/serial/serial_x86.c
deleted file mode 100644
index 4bf6062c64..0000000000
--- a/drivers/serial/serial_x86.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2014 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <dm.h>
-#include <fdtdec.h>
-#include <ns16550.h>
-#include <serial.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-static const struct udevice_id x86_serial_ids[] = {
- { .compatible = "x86-uart" },
- { }
-};
-
-static int x86_serial_ofdata_to_platdata(struct udevice *dev)
-{
- struct ns16550_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- ret = ns16550_serial_ofdata_to_platdata(dev);
- if (ret)
- return ret;
-
- plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
- "clock-frequency", 1843200);
-
- return 0;
-}
-
-U_BOOT_DRIVER(serial_ns16550) = {
- .name = "serial_x86",
- .id = UCLASS_SERIAL,
- .of_match = x86_serial_ids,
- .ofdata_to_platdata = x86_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
- .priv_auto_alloc_size = sizeof(struct NS16550),
- .probe = ns16550_serial_probe,
- .ops = &ns16550_serial_ops,
-};
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 601e493d4f..2b10d2bc6c 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -1,26 +1,33 @@
menu "Timer Support"
config TIMER
- bool "Enable Driver Model for Timer drivers"
+ bool "Enable driver model for timer drivers"
depends on DM
help
- Enable driver model for Timer access. It uses the same API as
- lib/time.c. But now implemented by the uclass. The first timer
+ Enable driver model for timer access. It uses the same API as
+ lib/time.c, but now implemented by the uclass. The first timer
will be used. The timer is usually a 32 bits free-running up
counter. There may be no real tick, and no timer interrupt.
config ALTERA_TIMER
- bool "Altera Timer support"
+ bool "Altera timer support"
depends on TIMER
help
- Select this to enable an timer for Altera devices. Please find
+ Select this to enable a timer for Altera devices. Please find
details on the "Embedded Peripherals IP User Guide" of Altera.
config SANDBOX_TIMER
- bool "Sandbox Timer support"
+ bool "Sandbox timer support"
depends on SANDBOX && TIMER
help
Select this to enable an emulated timer for sandbox. It gets
time from host os.
+config X86_TSC_TIMER
+ bool "x86 Time-Stamp Counter (TSC) timer support"
+ depends on TIMER && X86
+ default y if X86
+ help
+ Select this to enable Time-Stamp Counter (TSC) timer for x86.
+
endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index 300946e8d9..fe954eca9a 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -7,3 +7,4 @@
obj-$(CONFIG_TIMER) += timer-uclass.o
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o
+obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o
diff --git a/drivers/timer/altera_timer.c b/drivers/timer/altera_timer.c
index 971ed38b6b..89fe05b704 100644
--- a/drivers/timer/altera_timer.c
+++ b/drivers/timer/altera_timer.c
@@ -32,10 +32,9 @@ struct altera_timer_regs {
struct altera_timer_platdata {
struct altera_timer_regs *regs;
- unsigned long clock_rate;
};
-static int altera_timer_get_count(struct udevice *dev, unsigned long *count)
+static int altera_timer_get_count(struct udevice *dev, u64 *count)
{
struct altera_timer_platdata *plat = dev->platdata;
struct altera_timer_regs *const regs = plat->regs;
@@ -47,19 +46,16 @@ static int altera_timer_get_count(struct udevice *dev, unsigned long *count)
/* Read timer value */
val = readl(&regs->snapl) & 0xffff;
val |= (readl(&regs->snaph) & 0xffff) << 16;
- *count = ~val;
+ *count = timer_conv_64(~val);
return 0;
}
static int altera_timer_probe(struct udevice *dev)
{
- struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct altera_timer_platdata *plat = dev->platdata;
struct altera_timer_regs *const regs = plat->regs;
- uc_priv->clock_rate = plat->clock_rate;
-
writel(0, &regs->status);
writel(0, &regs->control);
writel(ALTERA_TIMER_STOP, &regs->control);
@@ -78,8 +74,6 @@ static int altera_timer_ofdata_to_platdata(struct udevice *dev)
plat->regs = map_physmem(dev_get_addr(dev),
sizeof(struct altera_timer_regs),
MAP_NOCACHE);
- plat->clock_rate = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
- "clock-frequency", 0);
return 0;
}
diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c
index 38de76365c..00a9944f78 100644
--- a/drivers/timer/sandbox_timer.c
+++ b/drivers/timer/sandbox_timer.c
@@ -18,7 +18,7 @@ void sandbox_timer_add_offset(unsigned long offset)
sandbox_timer_offset += offset;
}
-static int sandbox_timer_get_count(struct udevice *dev, unsigned long *count)
+static int sandbox_timer_get_count(struct udevice *dev, u64 *count)
{
*count = os_get_nsec() / 1000 + sandbox_timer_offset * 1000;
@@ -27,10 +27,6 @@ static int sandbox_timer_get_count(struct udevice *dev, unsigned long *count)
static int sandbox_timer_probe(struct udevice *dev)
{
- struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
-
- uc_priv->clock_rate = 1000000;
-
return 0;
}
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
index 12aee5ba4e..aca421bdea 100644
--- a/drivers/timer/timer-uclass.c
+++ b/drivers/timer/timer-uclass.c
@@ -9,16 +9,18 @@
#include <errno.h>
#include <timer.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/*
- * Implement a Timer uclass to work with lib/time.c. The timer is usually
- * a 32 bits free-running up counter. The get_rate() method is used to get
+ * Implement a timer uclass to work with lib/time.c. The timer is usually
+ * a 32/64 bits free-running up counter. The get_rate() method is used to get
* the input clock frequency of the timer. The get_count() method is used
- * get the current 32 bits count value. If the hardware is counting down,
+ * to get the current 64 bits count value. If the hardware is counting down,
* the value should be inversed inside the method. There may be no real
* tick, and no timer interrupt.
*/
-int timer_get_count(struct udevice *dev, unsigned long *count)
+int timer_get_count(struct udevice *dev, u64 *count)
{
const struct timer_ops *ops = device_get_ops(dev);
@@ -35,8 +37,28 @@ unsigned long timer_get_rate(struct udevice *dev)
return uc_priv->clock_rate;
}
+static int timer_pre_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ uc_priv->clock_rate = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "clock-frequency", 0);
+
+ return 0;
+}
+
+u64 timer_conv_64(u32 count)
+{
+ /* increment tbh if tbl has rolled over */
+ if (count < gd->timebase_l)
+ gd->timebase_h++;
+ gd->timebase_l = count;
+ return ((u64)gd->timebase_h << 32) | gd->timebase_l;
+}
+
UCLASS_DRIVER(timer) = {
.id = UCLASS_TIMER,
.name = "timer",
+ .pre_probe = timer_pre_probe,
.per_device_auto_alloc_size = sizeof(struct timer_dev_priv),
};
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c
new file mode 100644
index 0000000000..6aa243723b
--- /dev/null
+++ b/drivers/timer/tsc_timer.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * TSC calibration codes are adapted from Linux kernel
+ * arch/x86/kernel/tsc_msr.c and arch/x86/kernel/tsc.c
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <timer.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+#include <asm/msr.h>
+#include <asm/u-boot-x86.h>
+
+/* CPU reference clock frequency: in KHz */
+#define FREQ_83 83200
+#define FREQ_100 99840
+#define FREQ_133 133200
+#define FREQ_166 166400
+
+#define MAX_NUM_FREQS 8
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * According to Intel 64 and IA-32 System Programming Guide,
+ * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
+ * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
+ * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
+ * so we need manually differentiate SoC families. This is what the
+ * field msr_plat does.
+ */
+struct freq_desc {
+ u8 x86_family; /* CPU family */
+ u8 x86_model; /* model */
+ /* 2: use 100MHz, 1: use MSR_PLATFORM_INFO, 0: MSR_IA32_PERF_STATUS */
+ u8 msr_plat;
+ u32 freqs[MAX_NUM_FREQS];
+};
+
+static struct freq_desc freq_desc_tables[] = {
+ /* PNW */
+ { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
+ /* CLV+ */
+ { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } },
+ /* TNG */
+ { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
+ /* VLV2 */
+ { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
+ /* Ivybridge */
+ { 6, 0x3a, 2, { 0, 0, 0, 0, 0, 0, 0, 0 } },
+ /* ANN */
+ { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } },
+};
+
+static int match_cpu(u8 family, u8 model)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(freq_desc_tables); i++) {
+ if ((family == freq_desc_tables[i].x86_family) &&
+ (model == freq_desc_tables[i].x86_model))
+ return i;
+ }
+
+ return -1;
+}
+
+/* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */
+#define id_to_freq(cpu_index, freq_id) \
+ (freq_desc_tables[cpu_index].freqs[freq_id])
+
+/*
+ * Do MSR calibration only for known/supported CPUs.
+ *
+ * Returns the calibration value or 0 if MSR calibration failed.
+ */
+static unsigned long __maybe_unused try_msr_calibrate_tsc(void)
+{
+ u32 lo, hi, ratio, freq_id, freq;
+ unsigned long res;
+ int cpu_index;
+
+ cpu_index = match_cpu(gd->arch.x86, gd->arch.x86_model);
+ if (cpu_index < 0)
+ return 0;
+
+ if (freq_desc_tables[cpu_index].msr_plat) {
+ rdmsr(MSR_PLATFORM_INFO, lo, hi);
+ ratio = (lo >> 8) & 0x1f;
+ } else {
+ rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
+ ratio = (hi >> 8) & 0x1f;
+ }
+ debug("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio);
+
+ if (!ratio)
+ goto fail;
+
+ if (freq_desc_tables[cpu_index].msr_plat == 2) {
+ /* TODO: Figure out how best to deal with this */
+ freq = FREQ_100;
+ debug("Using frequency: %u KHz\n", freq);
+ } else {
+ /* Get FSB FREQ ID */
+ rdmsr(MSR_FSB_FREQ, lo, hi);
+ freq_id = lo & 0x7;
+ freq = id_to_freq(cpu_index, freq_id);
+ debug("Resolved frequency ID: %u, frequency: %u KHz\n",
+ freq_id, freq);
+ }
+ if (!freq)
+ goto fail;
+
+ /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
+ res = freq * ratio / 1000;
+ debug("TSC runs at %lu MHz\n", res);
+
+ return res;
+
+fail:
+ debug("Fast TSC calibration using MSR failed\n");
+ return 0;
+}
+
+/*
+ * This reads the current MSB of the PIT counter, and
+ * checks if we are running on sufficiently fast and
+ * non-virtualized hardware.
+ *
+ * Our expectations are:
+ *
+ * - the PIT is running at roughly 1.19MHz
+ *
+ * - each IO is going to take about 1us on real hardware,
+ * but we allow it to be much faster (by a factor of 10) or
+ * _slightly_ slower (ie we allow up to a 2us read+counter
+ * update - anything else implies a unacceptably slow CPU
+ * or PIT for the fast calibration to work.
+ *
+ * - with 256 PIT ticks to read the value, we have 214us to
+ * see the same MSB (and overhead like doing a single TSC
+ * read per MSB value etc).
+ *
+ * - We're doing 2 reads per loop (LSB, MSB), and we expect
+ * them each to take about a microsecond on real hardware.
+ * So we expect a count value of around 100. But we'll be
+ * generous, and accept anything over 50.
+ *
+ * - if the PIT is stuck, and we see *many* more reads, we
+ * return early (and the next caller of pit_expect_msb()
+ * then consider it a failure when they don't see the
+ * next expected value).
+ *
+ * These expectations mean that we know that we have seen the
+ * transition from one expected value to another with a fairly
+ * high accuracy, and we didn't miss any events. We can thus
+ * use the TSC value at the transitions to calculate a pretty
+ * good value for the TSC frequencty.
+ */
+static inline int pit_verify_msb(unsigned char val)
+{
+ /* Ignore LSB */
+ inb(0x42);
+ return inb(0x42) == val;
+}
+
+static inline int pit_expect_msb(unsigned char val, u64 *tscp,
+ unsigned long *deltap)
+{
+ int count;
+ u64 tsc = 0, prev_tsc = 0;
+
+ for (count = 0; count < 50000; count++) {
+ if (!pit_verify_msb(val))
+ break;
+ prev_tsc = tsc;
+ tsc = rdtsc();
+ }
+ *deltap = rdtsc() - prev_tsc;
+ *tscp = tsc;
+
+ /*
+ * We require _some_ success, but the quality control
+ * will be based on the error terms on the TSC values.
+ */
+ return count > 5;
+}
+
+/*
+ * How many MSB values do we want to see? We aim for
+ * a maximum error rate of 500ppm (in practice the
+ * real error is much smaller), but refuse to spend
+ * more than 50ms on it.
+ */
+#define MAX_QUICK_PIT_MS 50
+#define MAX_QUICK_PIT_ITERATIONS (MAX_QUICK_PIT_MS * PIT_TICK_RATE / 1000 / 256)
+
+static unsigned long __maybe_unused quick_pit_calibrate(void)
+{
+ int i;
+ u64 tsc, delta;
+ unsigned long d1, d2;
+
+ /* Set the Gate high, disable speaker */
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+ /*
+ * Counter 2, mode 0 (one-shot), binary count
+ *
+ * NOTE! Mode 2 decrements by two (and then the
+ * output is flipped each time, giving the same
+ * final output frequency as a decrement-by-one),
+ * so mode 0 is much better when looking at the
+ * individual counts.
+ */
+ outb(0xb0, 0x43);
+
+ /* Start at 0xffff */
+ outb(0xff, 0x42);
+ outb(0xff, 0x42);
+
+ /*
+ * The PIT starts counting at the next edge, so we
+ * need to delay for a microsecond. The easiest way
+ * to do that is to just read back the 16-bit counter
+ * once from the PIT.
+ */
+ pit_verify_msb(0);
+
+ if (pit_expect_msb(0xff, &tsc, &d1)) {
+ for (i = 1; i <= MAX_QUICK_PIT_ITERATIONS; i++) {
+ if (!pit_expect_msb(0xff-i, &delta, &d2))
+ break;
+
+ /*
+ * Iterate until the error is less than 500 ppm
+ */
+ delta -= tsc;
+ if (d1+d2 >= delta >> 11)
+ continue;
+
+ /*
+ * Check the PIT one more time to verify that
+ * all TSC reads were stable wrt the PIT.
+ *
+ * This also guarantees serialization of the
+ * last cycle read ('d2') in pit_expect_msb.
+ */
+ if (!pit_verify_msb(0xfe - i))
+ break;
+ goto success;
+ }
+ }
+ debug("Fast TSC calibration failed\n");
+ return 0;
+
+success:
+ /*
+ * Ok, if we get here, then we've seen the
+ * MSB of the PIT decrement 'i' times, and the
+ * error has shrunk to less than 500 ppm.
+ *
+ * As a result, we can depend on there not being
+ * any odd delays anywhere, and the TSC reads are
+ * reliable (within the error).
+ *
+ * kHz = ticks / time-in-seconds / 1000;
+ * kHz = (t2 - t1) / (I * 256 / PIT_TICK_RATE) / 1000
+ * kHz = ((t2 - t1) * PIT_TICK_RATE) / (I * 256 * 1000)
+ */
+ delta *= PIT_TICK_RATE;
+ delta /= (i*256*1000);
+ debug("Fast TSC calibration using PIT\n");
+ return delta / 1000;
+}
+
+/* Get the speed of the TSC timer in MHz */
+unsigned notrace long get_tbclk_mhz(void)
+{
+ return get_tbclk() / 1000000;
+}
+
+static ulong get_ms_timer(void)
+{
+ return (get_ticks() * 1000) / get_tbclk();
+}
+
+ulong get_timer(ulong base)
+{
+ return get_ms_timer() - base;
+}
+
+ulong notrace timer_get_us(void)
+{
+ return get_ticks() / get_tbclk_mhz();
+}
+
+ulong timer_get_boot_us(void)
+{
+ return timer_get_us();
+}
+
+void __udelay(unsigned long usec)
+{
+ u64 now = get_ticks();
+ u64 stop;
+
+ stop = now + usec * get_tbclk_mhz();
+
+ while ((int64_t)(stop - get_ticks()) > 0)
+#if defined(CONFIG_QEMU) && defined(CONFIG_SMP)
+ /*
+ * Add a 'pause' instruction on qemu target,
+ * to give other VCPUs a chance to run.
+ */
+ asm volatile("pause");
+#else
+ ;
+#endif
+}
+
+int timer_init(void)
+{
+#ifdef CONFIG_I8254_TIMER
+ /* Set up the i8254 timer if required */
+ i8254_init();
+#endif
+
+ return 0;
+}
+
+static int tsc_timer_get_count(struct udevice *dev, u64 *count)
+{
+ u64 now_tick = rdtsc();
+
+ *count = now_tick - gd->arch.tsc_base;
+
+ return 0;
+}
+
+static int tsc_timer_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ gd->arch.tsc_base = rdtsc();
+
+ /*
+ * If there is no clock frequency specified in the device tree,
+ * calibrate it by ourselves.
+ */
+ if (!uc_priv->clock_rate) {
+ unsigned long fast_calibrate;
+
+ fast_calibrate = try_msr_calibrate_tsc();
+ if (!fast_calibrate) {
+ fast_calibrate = quick_pit_calibrate();
+ if (!fast_calibrate)
+ panic("TSC frequency is ZERO");
+ }
+
+ uc_priv->clock_rate = fast_calibrate * 1000000;
+ }
+
+ return 0;
+}
+
+static const struct timer_ops tsc_timer_ops = {
+ .get_count = tsc_timer_get_count,
+};
+
+static const struct udevice_id tsc_timer_ids[] = {
+ { .compatible = "x86,tsc-timer", },
+ { }
+};
+
+U_BOOT_DRIVER(tsc_timer) = {
+ .name = "tsc_timer",
+ .id = UCLASS_TIMER,
+ .of_match = tsc_timer_ids,
+ .probe = tsc_timer_probe,
+ .ops = &tsc_timer_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index a146c0861f..5eb8d19b74 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -166,6 +166,17 @@ static void USBC_ConfigFIFO_Base(void)
}
/******************************************************************************
+ * Needed for the DFU polling magic
+ ******************************************************************************/
+
+static u8 last_int_usb;
+
+bool dfu_usb_get_reset(void)
+{
+ return !!(last_int_usb & MUSB_INTR_RESET);
+}
+
+/******************************************************************************
* MUSB Glue code
******************************************************************************/
@@ -176,6 +187,7 @@ static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
/* read and flush interrupts */
musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+ last_int_usb = musb->int_usb;
if (musb->int_usb)
musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
diff --git a/drivers/video/ipu_disp.c b/drivers/video/ipu_disp.c
index 7a87478228..cbac9f72fc 100644
--- a/drivers/video/ipu_disp.c
+++ b/drivers/video/ipu_disp.c
@@ -1117,7 +1117,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
reg &= 0x0000FFFF;
__raw_writel(reg, DI_STP_REP(disp, 6));
__raw_writel(0, DI_STP_REP(disp, 7));
- __raw_writel(0, DI_STP_REP(disp, 9));
+ __raw_writel(0, DI_STP_REP9(disp));
/* Init template microcode */
if (disp) {
diff --git a/drivers/video/ipu_regs.h b/drivers/video/ipu_regs.h
index c2c134a7de..0d3fe069e9 100644
--- a/drivers/video/ipu_regs.h
+++ b/drivers/video/ipu_regs.h
@@ -338,6 +338,7 @@ struct ipu_dmfc {
#define DI_SW_GEN0(di, gen) (&DI_REG(di)->sw_gen0[gen - 1])
#define DI_SW_GEN1(di, gen) (&DI_REG(di)->sw_gen1[gen - 1])
#define DI_STP_REP(di, gen) (&DI_REG(di)->stp_rep[(gen - 1) / 2])
+#define DI_STP_REP9(di) (&DI_REG(di)->stp_rep9)
#define DI_SYNC_AS_GEN(di) (&DI_REG(di)->sync_as)
#define DI_DW_GEN(di, gen) (&DI_REG(di)->dw_gen[gen])
#define DI_DW_SET(di, gen, set) (&DI_REG(di)->dw_set[gen + 12 * set])