diff options
Diffstat (limited to 'drivers')
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, ®_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(®s->snapl) & 0xffff; val |= (readl(®s->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, ®s->status); writel(0, ®s->control); writel(ALTERA_TIMER_STOP, ®s->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]) |