diff options
Diffstat (limited to 'drivers')
120 files changed, 5636 insertions, 2474 deletions
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 1ad638e..5efa821 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -818,7 +818,7 @@ static int ata_scsiop_read_capacity10(ccb *pccb) if (!ataid[pccb->target]) { printf("scsi_ahci: SCSI READ CAPACITY10 command failure. " "\tNo ATA info!\n" - "\tPlease run SCSI commmand INQUIRY firstly!\n"); + "\tPlease run SCSI command INQUIRY first!\n"); return -EPERM; } @@ -847,7 +847,7 @@ static int ata_scsiop_read_capacity16(ccb *pccb) if (!ataid[pccb->target]) { printf("scsi_ahci: SCSI READ CAPACITY16 command failure. " "\tNo ATA info!\n" - "\tPlease run SCSI commmand INQUIRY firstly!\n"); + "\tPlease run SCSI command INQUIRY first!\n"); return -EPERM; } diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c index 208a0ae..e000ebf 100644 --- a/drivers/block/fsl_sata.c +++ b/drivers/block/fsl_sata.c @@ -398,7 +398,7 @@ static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis debug("attribute = %08x\n\r", val32); cmd_hdr->attribute = cpu_to_le32(val32); - /* Make sure cmd desc and cmd slot valid before commmand issue */ + /* Make sure cmd desc and cmd slot valid before command issue */ sync(); /* PMP*/ diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 008ec10..4a6a4a8 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 0000000..6c802b6 --- /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 15681df..f332480 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 @@ -115,7 +134,7 @@ config SIMPLE_BUS config SPL_SIMPLE_BUS bool "Support simple-bus driver in SPL" depends on SPL_DM && SPL_OF_CONTROL - default n + default y help Supports the 'simple-bus' driver, which is used on some systems in SPL. @@ -136,7 +155,7 @@ config OF_TRANSLATE smaller in size than fdt_translate_address(). config SPL_OF_TRANSLATE - bool "Translate addresses using fdt_translate_address" + bool "Translate addresses using fdt_translate_address in SPL" depends on SPL_DM && SPL_OF_CONTROL default n help diff --git a/drivers/core/Makefile b/drivers/core/Makefile index f19f67d..07adb61 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/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index f63eacb..b553e3c 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -470,17 +470,13 @@ static void kick_trng(int ent_delay) sec_out32(&rng->rtfreqmin, ent_delay >> 2); /* disable maximum frequency count */ sec_out32(&rng->rtfreqmax, RTFRQMAX_DISABLE); - /* read the control register */ - val = sec_in32(&rng->rtmctl); /* * select raw sampling in both entropy shifter * and statistical checker */ - sec_setbits32(&val, RTMCTL_SAMP_MODE_RAW_ES_SC); + sec_setbits32(&rng->rtmctl, RTMCTL_SAMP_MODE_RAW_ES_SC); /* put RNG4 into run mode */ - sec_clrbits32(&val, RTMCTL_PRGM); - /* write back the control register */ - sec_out32(&rng->rtmctl, val); + sec_clrbits32(&rng->rtmctl, RTMCTL_PRGM); } static int rng_init(void) diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index 8543679..0bfcd34 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -317,7 +317,24 @@ static void set_timing_cfg_0(const unsigned int ctrl_num, /* for faster clock, need more time for data setup */ trwt_mclk = (data_rate/1000000 > 1900) ? 3 : 2; - twrt_mclk = 1; + + /* + * for single quad-rank DIMM and two-slot DIMMs + * to avoid ODT overlap + */ + switch (avoid_odt_overlap(dimm_params)) { + case 2: + twrt_mclk = 2; + twwt_mclk = 2; + trrt_mclk = 2; + break; + default: + twrt_mclk = 1; + twwt_mclk = 1; + trrt_mclk = 0; + break; + } + act_pd_exit_mclk = picos_to_mclk(ctrl_num, txp); pre_pd_exit_mclk = act_pd_exit_mclk; /* @@ -1117,10 +1134,18 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr, unsigned short esdmode4 = 0; /* Extended SDRAM mode 4 */ unsigned short esdmode5; /* Extended SDRAM mode 5 */ int rtt_park = 0; - + bool four_cs = false; + +#if CONFIG_CHIP_SELECTS_PER_CTRL == 4 + if ((ddr->cs[0].config & SDRAM_CS_CONFIG_EN) && + (ddr->cs[1].config & SDRAM_CS_CONFIG_EN) && + (ddr->cs[2].config & SDRAM_CS_CONFIG_EN) && + (ddr->cs[3].config & SDRAM_CS_CONFIG_EN)) + four_cs = true; +#endif if (ddr->cs[0].config & SDRAM_CS_CONFIG_EN) { esdmode5 = 0x00000500; /* Data mask enable, RTT_PARK CS0 */ - rtt_park = 1; + rtt_park = four_cs ? 0 : 1; } else { esdmode5 = 0x00000400; /* Data mask enabled */ } @@ -1130,7 +1155,10 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr, | ((esdmode5 & 0xffff) << 0) ); - /* only mode_9 use 0x500, others use 0x400 */ + /* Normally only the first enabled CS use 0x500, others use 0x400 + * But when four chip-selects are all enabled, all mode registers + * need 0x500 to park. + */ debug("FSLDDR: ddr_sdram_mode_9) = 0x%08x\n", ddr->ddr_sdram_mode_9); if (unq_mrs_en) { /* unique mode registers are supported */ @@ -1138,7 +1166,7 @@ static void set_ddr_sdram_mode_9(fsl_ddr_cfg_regs_t *ddr, if (!rtt_park && (ddr->cs[i].config & SDRAM_CS_CONFIG_EN)) { esdmode5 |= 0x00000500; /* RTT_PARK */ - rtt_park = 1; + rtt_park = four_cs ? 0 : 1; } else { esdmode5 = 0x00000400; } @@ -1186,6 +1214,9 @@ static void set_ddr_sdram_mode_10(const unsigned int ctrl_num, esdmode6 = ((tccdl_min - 4) & 0x7) << 10; + if (popts->ddr_cdr2 & DDR_CDR2_VREF_RANGE_2) + esdmode6 |= 1 << 6; /* Range 2 */ + ddr->ddr_sdram_mode_10 = (0 | ((esdmode6 & 0xffff) << 16) | ((esdmode7 & 0xffff) << 0) @@ -1808,6 +1839,7 @@ static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr, unsigned int wrt = 0; /* Write-to-read turnaround for same CS */ unsigned int rrt = 0; /* Read-to-read turnaround for same CS */ unsigned int wwt = 0; /* Write-to-write turnaround for same CS */ + unsigned int trwt_mclk = 0; /* ext_rwt */ unsigned int dll_lock = 0; /* DDR SDRAM DLL Lock Time */ #if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) @@ -1821,17 +1853,21 @@ static void set_timing_cfg_4(fsl_ddr_cfg_regs_t *ddr, wwt = 2; /* BL/2 + 2 clocks */ } #endif - #ifdef CONFIG_SYS_FSL_DDR4 dll_lock = 2; /* tDLLK = 1024 clocks */ #elif defined(CONFIG_SYS_FSL_DDR3) dll_lock = 1; /* tDLLK = 512 clocks from spec */ #endif + + if (popts->trwt_override) + trwt_mclk = popts->trwt; + ddr->timing_cfg_4 = (0 | ((rwt & 0xf) << 28) | ((wrt & 0xf) << 24) | ((rrt & 0xf) << 20) | ((wwt & 0xf) << 16) + | ((trwt_mclk & 0xc) << 12) | (dll_lock & 0x3) ); debug("FSLDDR: timing_cfg_4 = 0x%08x\n", ddr->timing_cfg_4); diff --git a/drivers/ddr/fsl/fsl_ddr_gen4.c b/drivers/ddr/fsl/fsl_ddr_gen4.c index 49e4688..3fca5c2 100644 --- a/drivers/ddr/fsl/fsl_ddr_gen4.c +++ b/drivers/ddr/fsl/fsl_ddr_gen4.c @@ -10,6 +10,7 @@ #include <asm/processor.h> #include <fsl_immap.h> #include <fsl_ddr.h> +#include <fsl_errata.h> #ifdef CONFIG_SYS_FSL_ERRATUM_A008511 static void set_wait_for_bits_clear(void *ptr, u32 value, u32 bits) @@ -48,12 +49,11 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, u32 temp_sdram_cfg; u32 total_gb_size_per_controller; int timeout; -#if defined(CONFIG_SYS_FSL_ERRATUM_A008336) || \ - defined(CONFIG_SYS_FSL_ERRATUM_A008514) - u32 *eddrtqcr1; -#endif #ifdef CONFIG_SYS_FSL_ERRATUM_A008511 u32 temp32, mr6; + u32 vref_seq1[3] = {0x80, 0x96, 0x16}; /* for range 1 */ + u32 vref_seq2[3] = {0xc0, 0xf0, 0x70}; /* for range 2 */ + u32 *vref_seq = vref_seq1; #endif #ifdef CONFIG_FSL_DDR_BIST u32 mtcr, err_detect, err_sbe; @@ -66,36 +66,20 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, switch (ctrl_num) { case 0: ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; -#if defined(CONFIG_SYS_FSL_ERRATUM_A008336) || \ - defined(CONFIG_SYS_FSL_ERRATUM_A008514) - eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR_ADDR + 0x800; -#endif break; #if defined(CONFIG_SYS_FSL_DDR2_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 1) case 1: ddr = (void *)CONFIG_SYS_FSL_DDR2_ADDR; -#if defined(CONFIG_SYS_FSL_ERRATUM_A008336) || \ - defined(CONFIG_SYS_FSL_ERRATUM_A008514) - eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR2_ADDR + 0x800; -#endif break; #endif #if defined(CONFIG_SYS_FSL_DDR3_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 2) case 2: ddr = (void *)CONFIG_SYS_FSL_DDR3_ADDR; -#if defined(CONFIG_SYS_FSL_ERRATUM_A008336) || \ - defined(CONFIG_SYS_FSL_ERRATUM_A008514) - eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR3_ADDR + 0x800; -#endif break; #endif #if defined(CONFIG_SYS_FSL_DDR4_ADDR) && (CONFIG_NUM_DDR_CONTROLLERS > 3) case 3: ddr = (void *)CONFIG_SYS_FSL_DDR4_ADDR; -#if defined(CONFIG_SYS_FSL_ERRATUM_A008336) || \ - defined(CONFIG_SYS_FSL_ERRATUM_A008514) - eddrtqcr1 = (void *)CONFIG_SYS_FSL_DCSR_DDR4_ADDR + 0x800; -#endif break; #endif default: @@ -106,20 +90,6 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, if (step == 2) goto step2; -#ifdef CONFIG_SYS_FSL_ERRATUM_A008336 -#ifdef 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 - /* A008514 only applies to DP-DDR controler */ - if (ctrl_num == 2) -#endif - ddr_out32(eddrtqcr1, 0x63b20002); -#endif if (regs->ddr_eor) ddr_out32(&ddr->eor, regs->ddr_eor); @@ -235,9 +205,11 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, /* Erratum applies when accumulated ECC is used, or DBI is enabled */ #define IS_ACC_ECC_EN(v) ((v) & 0x4) #define IS_DBI(v) ((((v) >> 12) & 0x3) == 0x2) - if (IS_ACC_ECC_EN(regs->ddr_sdram_cfg) || - IS_DBI(regs->ddr_sdram_cfg_3)) - ddr_setbits32(ddr->debug[28], 0x9 << 20); + if (has_erratum_a008378()) { + if (IS_ACC_ECC_EN(regs->ddr_sdram_cfg) || + IS_DBI(regs->ddr_sdram_cfg_3)) + ddr_setbits32(&ddr->debug[28], 0x9 << 20); + } #endif #ifdef CONFIG_SYS_FSL_ERRATUM_A008511 @@ -307,16 +279,21 @@ step2: /* This erraum only applies to verion 5.2.0 */ if (fsl_ddr_get_version(ctrl_num) == 0x50200) { /* Wait for idle */ - timeout = 200; + timeout = 40; while (!(ddr_in32(&ddr->debug[1]) & 0x2) && (timeout > 0)) { - udelay(100); + udelay(1000); timeout--; } if (timeout <= 0) { printf("Controler %d timeout, debug_2 = %x\n", ctrl_num, ddr_in32(&ddr->debug[1])); } + + /* The vref setting sequence is different for range 2 */ + if (regs->ddr_cdr2 & DDR_CDR2_VREF_RANGE_2) + vref_seq = vref_seq2; + /* Set VREF */ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { if (!(regs->cs[i].config & SDRAM_CS_CONFIG_EN)) @@ -327,17 +304,17 @@ step2: MD_CNTL_CS_SEL(i) | MD_CNTL_MD_SEL(6) | 0x00200000; - temp32 = mr6 | 0xc0; + temp32 = mr6 | vref_seq[0]; set_wait_for_bits_clear(&ddr->sdram_md_cntl, temp32, MD_CNTL_MD_EN); udelay(1); debug("MR6 = 0x%08x\n", temp32); - temp32 = mr6 | 0xf0; + temp32 = mr6 | vref_seq[1]; set_wait_for_bits_clear(&ddr->sdram_md_cntl, temp32, MD_CNTL_MD_EN); udelay(1); debug("MR6 = 0x%08x\n", temp32); - temp32 = mr6 | 0x70; + temp32 = mr6 | vref_seq[2]; set_wait_for_bits_clear(&ddr->sdram_md_cntl, temp32, MD_CNTL_MD_EN); udelay(1); @@ -347,10 +324,10 @@ step2: ddr_out32(&ddr->debug[28], 0); /* Enable deskew */ ddr_out32(&ddr->debug[1], 0x400); /* restart deskew */ /* wait for idle */ - timeout = 200; + timeout = 40; while (!(ddr_in32(&ddr->debug[1]) & 0x2) && (timeout > 0)) { - udelay(100); + udelay(1000); timeout--; } if (timeout <= 0) { @@ -423,16 +400,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 +446,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 72ec1be..c686632 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/options.c b/drivers/ddr/fsl/options.c index 3c09c64..791d644 100644 --- a/drivers/ddr/fsl/options.c +++ b/drivers/ddr/fsl/options.c @@ -29,7 +29,240 @@ struct dynamic_odt { unsigned int odt_rtt_wr; }; -#if defined(CONFIG_SYS_FSL_DDR3) || defined(CONFIG_SYS_FSL_DDR4) +#ifdef CONFIG_SYS_FSL_DDR4 +/* Quad rank is not verified yet due availability. + * Replacing 20 OHM with 34 OHM since DDR4 doesn't have 20 OHM option + */ +static const struct dynamic_odt single_Q[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS_AND_OTHER_DIMM, + DDR4_RTT_34_OHM, /* unverified */ + DDR4_RTT_120_OHM + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR4_RTT_OFF, + DDR4_RTT_120_OHM + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS_AND_OTHER_DIMM, + DDR4_RTT_34_OHM, + DDR4_RTT_120_OHM + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, /* tied high */ + DDR4_RTT_OFF, + DDR4_RTT_120_OHM + } +}; + +static const struct dynamic_odt single_D[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR4_RTT_40_OHM, + DDR4_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR4_RTT_OFF, + DDR4_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt single_S[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_ALL, + DDR4_RTT_40_OHM, + DDR4_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, +}; + +static const struct dynamic_odt dual_DD[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR4_RTT_120_OHM, + DDR4_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR4_RTT_34_OHM, + DDR4_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR4_RTT_120_OHM, + DDR4_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR4_RTT_34_OHM, + DDR4_RTT_OFF + } +}; + +static const struct dynamic_odt dual_DS[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR4_RTT_120_OHM, + DDR4_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR4_RTT_34_OHM, + DDR4_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR4_RTT_34_OHM, + DDR4_RTT_120_OHM + }, + {0, 0, 0, 0} +}; +static const struct dynamic_odt dual_SD[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR4_RTT_34_OHM, + DDR4_RTT_120_OHM + }, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR4_RTT_120_OHM, + DDR4_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_OTHER_DIMM, + DDR4_RTT_34_OHM, + DDR4_RTT_OFF + } +}; + +static const struct dynamic_odt dual_SS[4] = { + { /* cs0 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR4_RTT_34_OHM, + DDR4_RTT_120_OHM + }, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_OTHER_DIMM, + FSL_DDR_ODT_ALL, + DDR4_RTT_34_OHM, + DDR4_RTT_120_OHM + }, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt dual_D0[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR4_RTT_40_OHM, + DDR4_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR4_RTT_OFF, + DDR4_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; + +static const struct dynamic_odt dual_0D[4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_SAME_DIMM, + DDR4_RTT_40_OHM, + DDR4_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_NEVER, + DDR4_RTT_OFF, + DDR4_RTT_OFF + } +}; + +static const struct dynamic_odt dual_S0[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR4_RTT_40_OHM, + DDR4_RTT_OFF + }, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + +}; + +static const struct dynamic_odt dual_0S[4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR4_RTT_40_OHM, + DDR4_RTT_OFF + }, + {0, 0, 0, 0} + +}; + +static const struct dynamic_odt odt_unknown[4] = { + { /* cs0 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR4_RTT_120_OHM, + DDR4_RTT_OFF + }, + { /* cs1 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR4_RTT_120_OHM, + DDR4_RTT_OFF + }, + { /* cs2 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR4_RTT_120_OHM, + DDR4_RTT_OFF + }, + { /* cs3 */ + FSL_DDR_ODT_NEVER, + FSL_DDR_ODT_CS, + DDR4_RTT_120_OHM, + DDR4_RTT_OFF + } +}; +#elif defined(CONFIG_SYS_FSL_DDR3) static const struct dynamic_odt single_Q[4] = { { /* cs0 */ FSL_DDR_ODT_NEVER, @@ -259,7 +492,7 @@ static const struct dynamic_odt odt_unknown[4] = { DDR3_RTT_OFF } }; -#else /* CONFIG_SYS_FSL_DDR3 || CONFIG_SYS_FSL_DDR4 */ +#else /* CONFIG_SYS_FSL_DDR3 */ static const struct dynamic_odt single_Q[4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, diff --git a/drivers/ddr/fsl/util.c b/drivers/ddr/fsl/util.c index ce55aea..1a49b28 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 9e49471..e60e9fd 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 c58aa4d..fb4fd25 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 0000000..d71f525 --- /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/gpio/stm32_gpio.c b/drivers/gpio/stm32_gpio.c index d7a194e..75a84e1 100644 --- a/drivers/gpio/stm32_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -3,7 +3,7 @@ * Yuri Tikhonov, Emcraft Systems, yur@emcraft.com * * (C) Copyright 2015 - * Kamil Lulko, <rev13@wp.pl> + * Kamil Lulko, <kamil.lulko@gmail.com> * * Copyright 2015 ATS Advanced Telematics Systems GmbH * Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 32198bd..811ad9b 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/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index bd3e078..913093d 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -1,5 +1,5 @@ config I2C_MUX - bool "Suport I2C multiplexers" + bool "Support I2C multiplexers" depends on DM_I2C help This enables I2C buses to be multiplexed, so that you can select @@ -8,10 +8,10 @@ config I2C_MUX using a suitable I2C MUX driver. config I2C_ARB_GPIO_CHALLENGE - bool "GPIO-based I2C arbitration" - depends on I2C_MUX - help - If you say yes to this option, support will be included for an - I2C multimaster arbitration scheme using GPIOs and a challenge & - response mechanism where masters have to claim the bus by asserting - a GPIO. + bool "GPIO-based I2C arbitration" + depends on I2C_MUX + help + If you say yes to this option, support will be included for an + I2C multimaster arbitration scheme using GPIOs and a challenge & + response mechanism where masters have to claim the bus by asserting + a GPIO. diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 4375abc..909e3ca 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/mmc.c b/drivers/mmc/mmc.c index 2a58702..3a34028 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1469,7 +1469,9 @@ static int mmc_startup(struct mmc *mmc) mmc->block_dev.blksz = mmc->read_bl_len; mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz); mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_SPL_BUILD) || \ + (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ + !defined(CONFIG_USE_TINY_PRINTF)) sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x", mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), (mmc->cid[3] >> 16) & 0xffff); diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index f11c8e0..aeaec6c 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 8076761..43a7e7e 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -5,36 +5,44 @@ */ #include <common.h> -#include <malloc.h> -#include <fdtdec.h> -#include <libfdt.h> -#include <dwmmc.h> -#include <errno.h> -#include <asm/arch/dwmmc.h> #include <asm/arch/clock_manager.h> +#include <asm/arch/dwmmc.h> #include <asm/arch/system_manager.h> +#include <dm.h> +#include <dwmmc.h> +#include <errno.h> +#include <fdtdec.h> +#include <libfdt.h> +#include <linux/err.h> +#include <malloc.h> + +DECLARE_GLOBAL_DATA_PTR; static const struct socfpga_clock_manager *clock_manager_base = (void *)SOCFPGA_CLKMGR_ADDRESS; static const struct socfpga_system_manager *system_manager_base = (void *)SOCFPGA_SYSMGR_ADDRESS; +/* socfpga implmentation specific driver private data */ +struct dwmci_socfpga_priv_data { + struct dwmci_host host; + unsigned int drvsel; + unsigned int smplsel; +}; + static void socfpga_dwmci_clksel(struct dwmci_host *host) { - unsigned int drvsel; - unsigned int smplsel; + struct dwmci_socfpga_priv_data *priv = host->priv; + u32 sdmmc_mask = ((priv->smplsel & 0x7) << SYSMGR_SDMMC_SMPLSEL_SHIFT) | + ((priv->drvsel & 0x7) << SYSMGR_SDMMC_DRVSEL_SHIFT); /* 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), - &system_manager_base->sdmmcgrp_ctrl); + debug("%s: drvsel %d smplsel %d\n", __func__, + priv->drvsel, priv->smplsel); + writel(sdmmc_mask, &system_manager_base->sdmmcgrp_ctrl); debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__, readl(&system_manager_base->sdmmcgrp_ctrl)); @@ -44,87 +52,77 @@ static void socfpga_dwmci_clksel(struct dwmci_host *host) CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); } -static int socfpga_dwmci_of_probe(const void *blob, int node, const int idx) +static int socfpga_dwmmc_ofdata_to_platdata(struct udevice *dev) { /* FIXME: probe from DT eventually too/ */ const unsigned long clk = cm_get_mmc_controller_clk_hz(); - struct dwmci_host *host; - fdt_addr_t reg_base; - int bus_width, fifo_depth; + struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + int fifo_depth; if (clk == 0) { - printf("DWMMC%d: MMC clock is zero!", idx); + printf("DWMMC: MMC clock is zero!"); return -EINVAL; } - /* Get the register address from the device node */ - reg_base = fdtdec_get_addr(blob, node, "reg"); - if (!reg_base) { - printf("DWMMC%d: Can't get base address\n", idx); - return -EINVAL; - } - - /* Get the bus width from the device node */ - bus_width = fdtdec_get_int(blob, node, "bus-width", 0); - if (bus_width <= 0) { - printf("DWMMC%d: Can't get bus-width\n", idx); - return -EINVAL; - } - - fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0); + fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "fifo-depth", 0); if (fifo_depth < 0) { - printf("DWMMC%d: Can't get FIFO depth\n", idx); + printf("DWMMC: Can't get FIFO depth\n"); return -EINVAL; } - /* Allocate the host */ - host = calloc(1, sizeof(*host)); - if (!host) - return -ENOMEM; - - host->name = "SOCFPGA DWMMC"; - host->ioaddr = (void *)reg_base; - host->buswidth = bus_width; + host->name = dev->name; + host->ioaddr = (void *)dev_get_addr(dev); + host->buswidth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "bus-width", 4); host->clksel = socfpga_dwmci_clksel; - host->dev_index = idx; + + /* + * TODO(sjg@chromium.org): Remove the need for this hack. + * We only have one dwmmc block on gen5 SoCFPGA. + */ + host->dev_index = 0; /* Fixed clock divide by 4 which due to the SDMMC wrapper */ 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(gd->fdt_blob, dev->of_offset, + "drvsel", 3); + priv->smplsel = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, + "smplsel", 0); + host->priv = priv; - return add_dwmci(host, host->bus_hz, 400000); -} - -static int socfpga_dwmci_process_node(const void *blob, int nodes[], - int count) -{ - int i, node, ret; - - for (i = 0; i < count; i++) { - node = nodes[i]; - if (node <= 0) - continue; - - ret = socfpga_dwmci_of_probe(blob, node, i); - if (ret) { - printf("%s: failed to decode dev %d\n", __func__, i); - return ret; - } - } return 0; } -int socfpga_dwmmc_init(const void *blob) +static int socfpga_dwmmc_probe(struct udevice *dev) { - int nodes[2]; /* Max. two controllers. */ - int ret, count; + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + int ret; - count = fdtdec_find_aliases_for_id(blob, "mmc", - COMPAT_ALTERA_SOCFPGA_DWMMC, - nodes, ARRAY_SIZE(nodes)); + ret = add_dwmci(host, host->bus_hz, 400000); + if (ret) + return ret; - ret = socfpga_dwmci_process_node(blob, nodes, count); + upriv->mmc = host->mmc; - return ret; + return 0; } + +static const struct udevice_id socfpga_dwmmc_ids[] = { + { .compatible = "altr,socfpga-dw-mshc" }, + { } +}; + +U_BOOT_DRIVER(socfpga_dwmmc_drv) = { + .name = "socfpga_dwmmc", + .id = UCLASS_MMC, + .of_match = socfpga_dwmmc_ids, + .ofdata_to_platdata = socfpga_dwmmc_ofdata_to_platdata, + .probe = socfpga_dwmmc_probe, + .priv_auto_alloc_size = sizeof(struct dwmci_socfpga_priv_data), +}; diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index e169b77..4fe3da9 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2013 Inc. + * (C) Copyright 2013 - 2015 Xilinx, Inc. * * Xilinx Zynq SD Host Controller Interface * @@ -7,55 +7,48 @@ */ #include <common.h> +#include <dm.h> #include <fdtdec.h> #include <libfdt.h> #include <malloc.h> #include <sdhci.h> -#include <asm/arch/sys_proto.h> -int zynq_sdhci_init(phys_addr_t regbase) +static int arasan_sdhci_probe(struct udevice *dev) { - struct sdhci_host *host = NULL; + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct sdhci_host *host = dev_get_priv(dev); - host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); - if (!host) { - printf("zynq_sdhci_init: sdhci_host malloc fail\n"); - return 1; - } - - host->name = "zynq_sdhci"; - host->ioaddr = (void *)regbase; host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B; host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - add_sdhci(host, CONFIG_ZYNQ_SDHCI_MAX_FREQ, 52000000 >> 9); + add_sdhci(host, CONFIG_ZYNQ_SDHCI_MAX_FREQ, 0); + + upriv->mmc = host->mmc; + return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) -int zynq_sdhci_of_init(const void *blob) +static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) { - int offset = 0; - u32 ret = 0; - phys_addr_t reg; - - debug("ZYNQ SDHCI: Initialization\n"); - - do { - offset = fdt_node_offset_by_compatible(blob, offset, - "arasan,sdhci-8.9a"); - if (offset != -1) { - reg = fdtdec_get_addr(blob, offset, "reg"); - if (reg != FDT_ADDR_T_NONE) { - ret |= zynq_sdhci_init(reg); - } else { - debug("ZYNQ SDHCI: Can't get base address\n"); - return -1; - } - } - } while (offset != -1); - - return ret; + struct sdhci_host *host = dev_get_priv(dev); + + host->name = (char *)dev->name; + host->ioaddr = (void *)dev_get_addr(dev); + + return 0; } -#endif + +static const struct udevice_id arasan_sdhci_ids[] = { + { .compatible = "arasan,sdhci-8.9a" }, + { } +}; + +U_BOOT_DRIVER(arasan_sdhci_drv) = { + .name = "arasan_sdhci", + .id = UCLASS_MMC, + .of_match = arasan_sdhci_ids, + .ofdata_to_platdata = arasan_sdhci_ofdata_to_platdata, + .probe = arasan_sdhci_probe, + .priv_auto_alloc_size = sizeof(struct sdhci_host), +}; diff --git a/drivers/mtd/altera_qspi.c b/drivers/mtd/altera_qspi.c index 50c6e0e..a9148a7 100644 --- a/drivers/mtd/altera_qspi.c +++ b/drivers/mtd/altera_qspi.c @@ -5,6 +5,7 @@ */ #include <common.h> +#include <console.h> #include <dm.h> #include <errno.h> #include <fdt_support.h> @@ -14,6 +15,14 @@ DECLARE_GLOBAL_DATA_PTR; +/* The STATUS register */ +#define QUADSPI_SR_BP0 BIT(2) +#define QUADSPI_SR_BP1 BIT(3) +#define QUADSPI_SR_BP2 BIT(4) +#define QUADSPI_SR_BP2_0 GENMASK(4, 2) +#define QUADSPI_SR_BP3 BIT(6) +#define QUADSPI_SR_TB BIT(5) + /* * The QUADSPI_MEM_OP register is used to do memory protect and erase operations */ @@ -44,12 +53,32 @@ struct altera_qspi_platdata { unsigned long size; }; +static uint flash_verbose; flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* FLASH chips info */ +static void altera_qspi_get_locked_range(struct mtd_info *mtd, loff_t *ofs, + uint64_t *len); + void flash_print_info(flash_info_t *info) { + struct mtd_info *mtd = info->mtd; + loff_t ofs; + u64 len; + printf("Altera QSPI flash Size: %ld MB in %d Sectors\n", info->size >> 20, info->sector_count); + altera_qspi_get_locked_range(mtd, &ofs, &len); + printf(" %08lX +%lX", info->start[0], info->size); + if (len) { + printf(", protected %08llX +%llX", + info->start[0] + ofs, len); + } + putc('\n'); +} + +void flash_set_verbose(uint v) +{ + flash_verbose = v; } int flash_erase(flash_info_t *info, int s_first, int s_last) @@ -59,12 +88,16 @@ int flash_erase(flash_info_t *info, int s_first, int s_last) int ret; memset(&instr, 0, sizeof(instr)); + instr.mtd = mtd; instr.addr = mtd->erasesize * s_first; instr.len = mtd->erasesize * (s_last + 1 - s_first); + flash_set_verbose(1); ret = mtd_erase(mtd, &instr); + flash_set_verbose(0); if (ret) - return ERR_NOT_ERASED; + return ERR_PROTECTED; + puts(" done\n"); return 0; } @@ -80,7 +113,7 @@ int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt) ret = mtd_write(mtd, to, cnt, &retlen, src); if (ret) - return ERR_NOT_ERASED; + return ERR_PROTECTED; return 0; } @@ -108,23 +141,49 @@ static int altera_qspi_erase(struct mtd_info *mtd, struct erase_info *instr) size_t end = addr + len; u32 sect; u32 stat; + u32 *flash, *last; instr->state = MTD_ERASING; addr &= ~(mtd->erasesize - 1); /* get lower aligned address */ while (addr < end) { - sect = addr / mtd->erasesize; - sect <<= 8; - sect |= QUADSPI_MEM_OP_SECTOR_ERASE; - debug("erase %08x\n", sect); - writel(sect, ®s->mem_op); - stat = readl(®s->isr); - if (stat & QUADSPI_ISR_ILLEGAL_ERASE) { - /* erase failed, sector might be protected */ - debug("erase %08x fail %x\n", sect, stat); - writel(stat, ®s->isr); /* clear isr */ + if (ctrlc()) { + if (flash_verbose) + putc('\n'); + instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; instr->state = MTD_ERASE_FAILED; + mtd_erase_callback(instr); return -EIO; } + flash = pdata->base + addr; + last = pdata->base + addr + mtd->erasesize; + /* skip erase if sector is blank */ + while (flash < last) { + if (readl(flash) != 0xffffffff) + break; + flash++; + } + if (flash < last) { + sect = addr / mtd->erasesize; + sect <<= 8; + sect |= QUADSPI_MEM_OP_SECTOR_ERASE; + debug("erase %08x\n", sect); + writel(sect, ®s->mem_op); + stat = readl(®s->isr); + if (stat & QUADSPI_ISR_ILLEGAL_ERASE) { + /* erase failed, sector might be protected */ + debug("erase %08x fail %x\n", sect, stat); + writel(stat, ®s->isr); /* clear isr */ + instr->fail_addr = addr; + instr->state = MTD_ERASE_FAILED; + mtd_erase_callback(instr); + return -EIO; + } + if (flash_verbose) + putc('.'); + } else { + if (flash_verbose) + putc(','); + } addr += mtd->erasesize; } instr->state = MTD_ERASE_DONE; @@ -171,6 +230,77 @@ static void altera_qspi_sync(struct mtd_info *mtd) { } +static void altera_qspi_get_locked_range(struct mtd_info *mtd, loff_t *ofs, + uint64_t *len) +{ + struct udevice *dev = mtd->dev; + struct altera_qspi_platdata *pdata = dev_get_platdata(dev); + struct altera_qspi_regs *regs = pdata->regs; + int shift0 = ffs(QUADSPI_SR_BP2_0) - 1; + int shift3 = ffs(QUADSPI_SR_BP3) - 1 - 3; + u32 stat = readl(®s->rd_status); + unsigned pow = ((stat & QUADSPI_SR_BP2_0) >> shift0) | + ((stat & QUADSPI_SR_BP3) >> shift3); + + *ofs = 0; + *len = 0; + if (pow) { + *len = mtd->erasesize << (pow - 1); + if (*len > mtd->size) + *len = mtd->size; + if (!(stat & QUADSPI_SR_TB)) + *ofs = mtd->size - *len; + } +} + +static int altera_qspi_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct udevice *dev = mtd->dev; + struct altera_qspi_platdata *pdata = dev_get_platdata(dev); + struct altera_qspi_regs *regs = pdata->regs; + u32 sector_start, sector_end; + u32 num_sectors; + u32 mem_op; + u32 sr_bp; + u32 sr_tb; + + num_sectors = mtd->size / mtd->erasesize; + sector_start = ofs / mtd->erasesize; + sector_end = (ofs + len) / mtd->erasesize; + + if (sector_start >= num_sectors / 2) { + sr_bp = fls(num_sectors - 1 - sector_start) + 1; + sr_tb = 0; + } else if (sector_end < num_sectors / 2) { + sr_bp = fls(sector_end) + 1; + sr_tb = 1; + } else { + sr_bp = 15; + sr_tb = 0; + } + + mem_op = (sr_tb << 12) | (sr_bp << 8); + mem_op |= QUADSPI_MEM_OP_SECTOR_PROTECT; + debug("lock %08x\n", mem_op); + writel(mem_op, ®s->mem_op); + + return 0; +} + +static int altera_qspi_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct udevice *dev = mtd->dev; + struct altera_qspi_platdata *pdata = dev_get_platdata(dev); + struct altera_qspi_regs *regs = pdata->regs; + u32 mem_op; + + mem_op = QUADSPI_MEM_OP_SECTOR_PROTECT; + debug("unlock %08x\n", mem_op); + writel(mem_op, ®s->mem_op); + + return 0; +} + static int altera_qspi_probe(struct udevice *dev) { struct altera_qspi_platdata *pdata = dev_get_platdata(dev); @@ -196,6 +326,8 @@ static int altera_qspi_probe(struct udevice *dev) mtd->_read = altera_qspi_read; mtd->_write = altera_qspi_write; mtd->_sync = altera_qspi_sync; + mtd->_lock = altera_qspi_lock; + mtd->_unlock = altera_qspi_unlock; mtd->numeraseregions = 0; mtd->erasesize = 0x10000; if (add_mtd_device(mtd)) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 1565a9a..f65b499 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -451,7 +451,7 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info, } /** - * NOTE: it is a must to set ND_RUN firstly, then write + * NOTE: it is a must to set ND_RUN first, then write * command buffer, otherwise, it does not work. * We enable all the interrupt at the same time, and * let pxa3xx_nand_irq to handle all logic. diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index cf4e7e1..c665836 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -12,11 +12,7 @@ obj-$(CONFIG_SPL_SPI_LOAD) += spi_spl_load.o obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o endif -#ifndef CONFIG_DM_SPI -obj-$(CONFIG_SPI_FLASH) += sf_probe.o -#endif -obj-$(CONFIG_CMD_SF) += sf.o -obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.o +obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o sf_params.o sf.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 85c8a89..ed5c391 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -44,13 +44,10 @@ enum { #endif SECT_32K = 1 << 1, E_FSR = 1 << 2, - SST_BP = 1 << 3, - SST_WP = 1 << 4, - WR_QPP = 1 << 5, + SST_WR = 1 << 3, + WR_QPP = 1 << 4, }; -#define SST_WR (SST_BP | SST_WP) - enum spi_nor_option_flags { SNOR_F_SST_WR = (1 << 0), SNOR_F_USE_FSR = (1 << 1), @@ -66,6 +63,7 @@ enum spi_nor_option_flags { #define SPI_FLASH_CFI_MFR_MACRONIX 0xc2 #define SPI_FLASH_CFI_MFR_SST 0xbf #define SPI_FLASH_CFI_MFR_WINBOND 0xef +#define SPI_FLASH_CFI_MFR_ATMEL 0x1f /* Erase commands */ #define CMD_ERASE_4K 0x20 @@ -171,12 +169,6 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, /* Flash erase(sectors) operation, support all possible erase commands */ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); -/* Read the status register */ -int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); - -/* Program the status register */ -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); - /* Lock stmicro spi flash region */ int stm_lock(struct spi_flash *flash, u32 ofs, size_t len); @@ -186,12 +178,6 @@ int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len); /* Check if a stmicro spi flash region is completely locked */ int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len); -/* Read the config register */ -int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc); - -/* Program the config register */ -int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc); - /* Enable writing on the SPI flash */ static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) { @@ -205,12 +191,6 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) } /* - * Send the read status command to the device and wait for the wip - * (write-in-progress) bit to clear itself. - */ -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); - -/* * Used for spi_flash write operation * - SPI claim * - spi_flash_cmd_write_enable @@ -245,4 +225,16 @@ int spi_flash_mtd_register(struct spi_flash *flash); void spi_flash_mtd_unregister(void); #endif +/** + * spi_flash_scan - scan the SPI FLASH + * @flash: the spi flash structure + * + * The drivers can use this fuction to scan the SPI FLASH. + * In the scanning, it will try to get all the necessary information to + * fill the spi_flash{}. + * + * Return: 0 for success, others for failure. + */ +int spi_flash_scan(struct spi_flash *flash); + #endif /* _SF_INTERNAL_H_ */ diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index a619182..0cafc29 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -11,327 +11,21 @@ #include <common.h> #include <dm.h> #include <errno.h> -#include <fdtdec.h> #include <malloc.h> -#include <mapmem.h> #include <spi.h> #include <spi_flash.h> -#include <asm/io.h> #include "sf_internal.h" -DECLARE_GLOBAL_DATA_PTR; - -/* Read commands array */ -static u8 spi_read_cmds_array[] = { - CMD_READ_ARRAY_SLOW, - CMD_READ_ARRAY_FAST, - CMD_READ_DUAL_OUTPUT_FAST, - CMD_READ_DUAL_IO_FAST, - CMD_READ_QUAD_OUTPUT_FAST, - CMD_READ_QUAD_IO_FAST, -}; - -#ifdef CONFIG_SPI_FLASH_MACRONIX -static int spi_flash_set_qeb_mxic(struct spi_flash *flash) -{ - u8 qeb_status; - int ret; - - ret = spi_flash_cmd_read_status(flash, &qeb_status); - if (ret < 0) - return ret; - - if (qeb_status & STATUS_QEB_MXIC) { - debug("SF: mxic: QEB is already set\n"); - } else { - ret = spi_flash_cmd_write_status(flash, STATUS_QEB_MXIC); - if (ret < 0) - return ret; - } - - return ret; -} -#endif - -#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) -static int spi_flash_set_qeb_winspan(struct spi_flash *flash) -{ - u8 qeb_status; - int ret; - - ret = spi_flash_cmd_read_config(flash, &qeb_status); - if (ret < 0) - return ret; - - if (qeb_status & STATUS_QEB_WINSPAN) { - debug("SF: winspan: QEB is already set\n"); - } else { - ret = spi_flash_cmd_write_config(flash, STATUS_QEB_WINSPAN); - if (ret < 0) - return ret; - } - - return ret; -} -#endif - -static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) -{ - switch (idcode0) { -#ifdef CONFIG_SPI_FLASH_MACRONIX - case SPI_FLASH_CFI_MFR_MACRONIX: - return spi_flash_set_qeb_mxic(flash); -#endif -#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) - case SPI_FLASH_CFI_MFR_SPANSION: - case SPI_FLASH_CFI_MFR_WINBOND: - return spi_flash_set_qeb_winspan(flash); -#endif -#ifdef CONFIG_SPI_FLASH_STMICRO - case SPI_FLASH_CFI_MFR_STMICRO: - debug("SF: QEB is volatile for %02x flash\n", idcode0); - return 0; -#endif - default: - printf("SF: Need set QEB func for %02x flash\n", idcode0); - return -1; - } -} - -#ifdef CONFIG_SPI_FLASH_BAR -static int spi_flash_read_bank(struct spi_flash *flash, u8 idcode0) -{ - u8 curr_bank = 0; - int ret; - - if (flash->size <= SPI_FLASH_16MB_BOUN) - goto bank_end; - - switch (idcode0) { - case SPI_FLASH_CFI_MFR_SPANSION: - flash->bank_read_cmd = CMD_BANKADDR_BRRD; - flash->bank_write_cmd = CMD_BANKADDR_BRWR; - default: - flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; - flash->bank_write_cmd = CMD_EXTNADDR_WREAR; - } - - ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, - &curr_bank, 1); - if (ret) { - debug("SF: fail to read bank addr register\n"); - return ret; - } - -bank_end: - flash->bank_curr = curr_bank; - return 0; -} -#endif - -static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, - struct spi_flash *flash) -{ - const struct spi_flash_params *params; - u8 cmd; - u16 jedec = idcode[1] << 8 | idcode[2]; - u16 ext_jedec = idcode[3] << 8 | idcode[4]; - - /* Validate params from spi_flash_params table */ - params = spi_flash_params_table; - for (; params->name != NULL; params++) { - if ((params->jedec >> 16) == idcode[0]) { - if ((params->jedec & 0xFFFF) == jedec) { - if (params->ext_jedec == 0) - break; - else if (params->ext_jedec == ext_jedec) - break; - } - } - } - - if (!params->name) { - printf("SF: Unsupported flash IDs: "); - printf("manuf %02x, jedec %04x, ext_jedec %04x\n", - idcode[0], jedec, ext_jedec); - return -EPROTONOSUPPORT; - } - - /* Assign spi data */ - flash->spi = spi; - flash->name = params->name; - flash->memory_map = spi->memory_map; - flash->dual_flash = flash->spi->option; - - /* Assign spi flash flags */ - if (params->flags & SST_WR) - flash->flags |= SNOR_F_SST_WR; - - /* Assign spi_flash ops */ -#ifndef CONFIG_DM_SPI_FLASH - flash->write = spi_flash_cmd_write_ops; -#if defined(CONFIG_SPI_FLASH_SST) - if (flash->flags & SNOR_F_SST_WR) { - if (flash->spi->op_mode_tx & SPI_OPM_TX_BP) - flash->write = sst_write_bp; - else - flash->write = sst_write_wp; - } -#endif - flash->erase = spi_flash_cmd_erase_ops; - flash->read = spi_flash_cmd_read_ops; -#endif - - /* lock hooks are flash specific - assign them based on idcode0 */ - switch (idcode[0]) { -#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) - case SPI_FLASH_CFI_MFR_STMICRO: - case SPI_FLASH_CFI_MFR_SST: - flash->flash_lock = stm_lock; - flash->flash_unlock = stm_unlock; - flash->flash_is_locked = stm_is_locked; -#endif - break; - default: - debug("SF: Lock ops not supported for %02x flash\n", idcode[0]); - } - - /* Compute the flash size */ - flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; - /* - * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the - * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with - * the 0x4d00 Extended JEDEC code have 512b pages. All of the others - * have 256b pages. - */ - if (ext_jedec == 0x4d00) { - if ((jedec == 0x0215) || (jedec == 0x216)) - flash->page_size = 256; - else - flash->page_size = 512; - } else { - flash->page_size = 256; - } - flash->page_size <<= flash->shift; - flash->sector_size = params->sector_size << flash->shift; - flash->size = flash->sector_size * params->nr_sectors << flash->shift; -#ifdef CONFIG_SF_DUAL_FLASH - if (flash->dual_flash & SF_DUAL_STACKED_FLASH) - flash->size <<= 1; -#endif - - /* Compute erase sector and command */ - if (params->flags & SECT_4K) { - flash->erase_cmd = CMD_ERASE_4K; - flash->erase_size = 4096 << flash->shift; - } else if (params->flags & SECT_32K) { - flash->erase_cmd = CMD_ERASE_32K; - flash->erase_size = 32768 << flash->shift; - } else { - flash->erase_cmd = CMD_ERASE_64K; - flash->erase_size = flash->sector_size; - } - - /* Now erase size becomes valid sector size */ - flash->sector_size = flash->erase_size; - - /* Look for the fastest read cmd */ - cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); - if (cmd) { - cmd = spi_read_cmds_array[cmd - 1]; - flash->read_cmd = cmd; - } else { - /* Go for default supported read cmd */ - flash->read_cmd = CMD_READ_ARRAY_FAST; - } - - /* Not require to look for fastest only two write cmds yet */ - if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) - flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; - else - /* Go for default supported write cmd */ - flash->write_cmd = CMD_PAGE_PROGRAM; - - /* Read dummy_byte: dummy byte is determined based on the - * dummy cycles of a particular command. - * Fast commands - dummy_byte = dummy_cycles/8 - * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 - * For I/O commands except cmd[0] everything goes on no.of lines - * based on particular command but incase of fast commands except - * data all go on single line irrespective of command. - */ - switch (flash->read_cmd) { - case CMD_READ_QUAD_IO_FAST: - flash->dummy_byte = 2; - break; - case CMD_READ_ARRAY_SLOW: - flash->dummy_byte = 0; - break; - default: - flash->dummy_byte = 1; - } - -#ifdef CONFIG_SPI_FLASH_STMICRO - if (params->flags & E_FSR) - flash->flags |= SNOR_F_USE_FSR; -#endif - - /* Configure the BAR - discover bank cmds and read current bank */ -#ifdef CONFIG_SPI_FLASH_BAR - int ret = spi_flash_read_bank(flash, idcode[0]); - if (ret < 0) - return ret; -#endif - - /* Flash powers up read-only, so clear BP# bits */ -#if defined(CONFIG_SPI_FLASH_ATMEL) || \ - defined(CONFIG_SPI_FLASH_MACRONIX) || \ - defined(CONFIG_SPI_FLASH_SST) - spi_flash_cmd_write_status(flash, 0); -#endif - - return 0; -} - -#if CONFIG_IS_ENABLED(OF_CONTROL) -int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) -{ - fdt_addr_t addr; - fdt_size_t size; - int node; - - /* If there is no node, do nothing */ - node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); - if (node < 0) - return 0; - - addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); - if (addr == FDT_ADDR_T_NONE) { - debug("%s: Cannot decode address\n", __func__); - return 0; - } - - if (flash->size != size) { - debug("%s: Memory map must cover entire device\n", __func__); - return -1; - } - flash->memory_map = map_sysmem(addr, size); - - return 0; -} -#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ - /** * spi_flash_probe_slave() - Probe for a SPI flash device on a bus * - * @spi: Bus to probe * @flashp: Pointer to place to put flash info, which may be NULL if the * space should be allocated */ -int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) +static int spi_flash_probe_slave(struct spi_flash *flash) { - u8 idcode[5]; + struct spi_slave *spi = flash->spi; int ret; /* Setup spi_slave */ @@ -347,59 +41,12 @@ int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash) return ret; } - /* Read the ID codes */ - ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + ret = spi_flash_scan(flash); if (ret) { - printf("SF: Failed to get idcodes\n"); - goto err_read_id; - } - -#ifdef DEBUG - printf("SF: Got idcodes\n"); - print_buffer(0, idcode, 1, sizeof(idcode), 0); -#endif - - if (spi_flash_validate_params(spi, idcode, flash)) { ret = -EINVAL; goto err_read_id; } - /* Set the quad enable bit - only for quad commands */ - if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || - (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || - (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { - if (spi_flash_set_qeb(flash, idcode[0])) { - debug("SF: Fail to set QEB for %02x\n", idcode[0]); - ret = -EINVAL; - goto err_read_id; - } - } - -#if CONFIG_IS_ENABLED(OF_CONTROL) - if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { - debug("SF: FDT decode error\n"); - ret = -EINVAL; - goto err_read_id; - } -#endif -#ifndef CONFIG_SPL_BUILD - printf("SF: Detected %s with page size ", flash->name); - print_size(flash->page_size, ", erase size "); - print_size(flash->erase_size, ", total "); - print_size(flash->size, ""); - if (flash->memory_map) - printf(", mapped at %p", flash->memory_map); - puts("\n"); -#endif -#ifndef CONFIG_SPI_FLASH_BAR - if (((flash->dual_flash == SF_SINGLE_FLASH) && - (flash->size > SPI_FLASH_16MB_BOUN)) || - ((flash->dual_flash > SF_SINGLE_FLASH) && - (flash->size > SPI_FLASH_16MB_BOUN << 1))) { - puts("SF: Warning - Only lower 16MiB accessible,"); - puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); - } -#endif #ifdef CONFIG_SPI_FLASH_MTD ret = spi_flash_mtd_register(flash); #endif @@ -410,7 +57,7 @@ err_read_id: } #ifndef CONFIG_DM_SPI_FLASH -struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) +static struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) { struct spi_flash *flash; @@ -421,7 +68,8 @@ struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus) return NULL; } - if (spi_flash_probe_slave(bus, flash)) { + flash->spi = bus; + if (spi_flash_probe_slave(flash)) { spi_free_slave(bus); free(flash); return NULL; @@ -473,7 +121,7 @@ static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len, return spi_flash_cmd_read_ops(flash, offset, len, buf); } -int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, +static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, const void *buf) { struct spi_flash *flash = dev_get_uclass_priv(dev); @@ -490,14 +138,14 @@ int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, return spi_flash_cmd_write_ops(flash, offset, len, buf); } -int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) +static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) { struct spi_flash *flash = dev_get_uclass_priv(dev); return spi_flash_cmd_erase_ops(flash, offset, len); } -int spi_flash_std_probe(struct udevice *dev) +static int spi_flash_std_probe(struct udevice *dev) { struct spi_slave *slave = dev_get_parent_priv(dev); struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); @@ -505,8 +153,9 @@ int spi_flash_std_probe(struct udevice *dev) flash = dev_get_uclass_priv(dev); flash->dev = dev; + flash->spi = slave; debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs); - return spi_flash_probe_slave(slave, flash); + return spi_flash_probe_slave(flash); } static const struct dm_spi_flash_ops spi_flash_std_ops = { diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/spi_flash.c index 3a56d7f..7ffa136 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/spi_flash.c @@ -1,9 +1,10 @@ /* - * SPI flash operations + * SPI Flash Core * - * Copyright (C) 2008 Atmel Corporation - * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * Copyright (C) 2015 Jagan Teki <jteki@openedev.com> * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * Copyright (C) 2008 Atmel Corporation * * SPDX-License-Identifier: GPL-2.0+ */ @@ -11,14 +12,15 @@ #include <common.h> #include <errno.h> #include <malloc.h> +#include <mapmem.h> #include <spi.h> #include <spi_flash.h> -#include <watchdog.h> -#include <linux/compiler.h> #include <linux/log2.h> #include "sf_internal.h" +DECLARE_GLOBAL_DATA_PTR; + static void spi_flash_addr(u32 addr, u8 *cmd) { /* cmd[0] is actual command */ @@ -27,7 +29,17 @@ static void spi_flash_addr(u32 addr, u8 *cmd) cmd[3] = addr >> 0; } -int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs) +/* Read commands array */ +static u8 spi_read_cmds_array[] = { + CMD_READ_ARRAY_SLOW, + CMD_READ_ARRAY_FAST, + CMD_READ_DUAL_OUTPUT_FAST, + CMD_READ_DUAL_IO_FAST, + CMD_READ_QUAD_OUTPUT_FAST, + CMD_READ_QUAD_IO_FAST, +}; + +static int read_sr(struct spi_flash *flash, u8 *rs) { int ret; u8 cmd; @@ -56,7 +68,7 @@ static int read_fsr(struct spi_flash *flash, u8 *fsr) return 0; } -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws) +static int write_sr(struct spi_flash *flash, u8 ws) { u8 cmd; int ret; @@ -72,7 +84,7 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws) } #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) -int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc) +static int read_cr(struct spi_flash *flash, u8 *rc) { int ret; u8 cmd; @@ -87,13 +99,13 @@ int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc) return 0; } -int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) +static int write_cr(struct spi_flash *flash, u8 wc) { u8 data[2]; u8 cmd; int ret; - ret = spi_flash_cmd_read_status(flash, &data[0]); + ret = read_sr(flash, &data[0]); if (ret < 0) return ret; @@ -110,7 +122,7 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) #endif #ifdef CONFIG_SPI_FLASH_BAR -static int spi_flash_write_bank(struct spi_flash *flash, u32 offset) +static int spi_flash_write_bar(struct spi_flash *flash, u32 offset) { u8 cmd, bank_sel; int ret; @@ -130,10 +142,40 @@ bar_end: flash->bank_curr = bank_sel; return flash->bank_curr; } + +static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0) +{ + u8 curr_bank = 0; + int ret; + + if (flash->size <= SPI_FLASH_16MB_BOUN) + goto bank_end; + + switch (idcode0) { + case SPI_FLASH_CFI_MFR_SPANSION: + flash->bank_read_cmd = CMD_BANKADDR_BRRD; + flash->bank_write_cmd = CMD_BANKADDR_BRWR; + break; + default: + flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; + flash->bank_write_cmd = CMD_EXTNADDR_WREAR; + } + + ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, + &curr_bank, 1); + if (ret) { + debug("SF: fail to read bank addr register\n"); + return ret; + } + +bank_end: + flash->bank_curr = curr_bank; + return 0; +} #endif #ifdef CONFIG_SF_DUAL_FLASH -static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr) +static void spi_flash_dual(struct spi_flash *flash, u32 *addr) { switch (flash->dual_flash) { case SF_DUAL_STACKED_FLASH: @@ -159,7 +201,7 @@ static int spi_flash_sr_ready(struct spi_flash *flash) u8 sr; int ret; - ret = spi_flash_cmd_read_status(flash, &sr); + ret = read_sr(flash, &sr); if (ret < 0) return ret; @@ -196,7 +238,8 @@ static int spi_flash_ready(struct spi_flash *flash) return sr && fsr; } -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +static int spi_flash_cmd_wait_ready(struct spi_flash *flash, + unsigned long timeout) { int timebase, ret; @@ -282,10 +325,10 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) #ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash > SF_SINGLE_FLASH) - spi_flash_dual_flash(flash, &erase_addr); + spi_flash_dual(flash, &erase_addr); #endif #ifdef CONFIG_SPI_FLASH_BAR - ret = spi_flash_write_bank(flash, erase_addr); + ret = spi_flash_write_bar(flash, erase_addr); if (ret < 0) return ret; #endif @@ -332,10 +375,10 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, #ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash > SF_SINGLE_FLASH) - spi_flash_dual_flash(flash, &write_addr); + spi_flash_dual(flash, &write_addr); #endif #ifdef CONFIG_SPI_FLASH_BAR - ret = spi_flash_write_bank(flash, write_addr); + ret = spi_flash_write_bar(flash, write_addr); if (ret < 0) return ret; #endif @@ -427,10 +470,10 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, #ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash > SF_SINGLE_FLASH) - spi_flash_dual_flash(flash, &read_addr); + spi_flash_dual(flash, &read_addr); #endif #ifdef CONFIG_SPI_FLASH_BAR - ret = spi_flash_write_bank(flash, read_addr); + ret = spi_flash_write_bar(flash, read_addr); if (ret < 0) return ret; bank_sel = flash->bank_curr; @@ -628,7 +671,7 @@ int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len) int status; u8 sr; - status = spi_flash_cmd_read_status(flash, &sr); + status = read_sr(flash, &sr); if (status < 0) return status; @@ -665,7 +708,7 @@ int stm_lock(struct spi_flash *flash, u32 ofs, size_t len) u8 shift = ffs(mask) - 1, pow, val; int ret; - ret = spi_flash_cmd_read_status(flash, &status_old); + ret = read_sr(flash, &status_old); if (ret < 0) return ret; @@ -702,7 +745,7 @@ int stm_lock(struct spi_flash *flash, u32 ofs, size_t len) if ((status_new & mask) <= (status_old & mask)) return -EINVAL; - spi_flash_cmd_write_status(flash, status_new); + write_sr(flash, status_new); return 0; } @@ -719,7 +762,7 @@ int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len) u8 shift = ffs(mask) - 1, pow, val; int ret; - ret = spi_flash_cmd_read_status(flash, &status_old); + ret = read_sr(flash, &status_old); if (ret < 0) return ret; @@ -752,8 +795,321 @@ int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len) if ((status_new & mask) >= (status_old & mask)) return -EINVAL; - spi_flash_cmd_write_status(flash, status_new); + write_sr(flash, status_new); return 0; } #endif + + +#ifdef CONFIG_SPI_FLASH_MACRONIX +static int spi_flash_set_qeb_mxic(struct spi_flash *flash) +{ + u8 qeb_status; + int ret; + + ret = read_sr(flash, &qeb_status); + if (ret < 0) + return ret; + + if (qeb_status & STATUS_QEB_MXIC) { + debug("SF: mxic: QEB is already set\n"); + } else { + ret = write_sr(flash, STATUS_QEB_MXIC); + if (ret < 0) + return ret; + } + + return ret; +} +#endif + +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) +static int spi_flash_set_qeb_winspan(struct spi_flash *flash) +{ + u8 qeb_status; + int ret; + + ret = read_cr(flash, &qeb_status); + if (ret < 0) + return ret; + + if (qeb_status & STATUS_QEB_WINSPAN) { + debug("SF: winspan: QEB is already set\n"); + } else { + ret = write_cr(flash, STATUS_QEB_WINSPAN); + if (ret < 0) + return ret; + } + + return ret; +} +#endif + +static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0) +{ + switch (idcode0) { +#ifdef CONFIG_SPI_FLASH_MACRONIX + case SPI_FLASH_CFI_MFR_MACRONIX: + return spi_flash_set_qeb_mxic(flash); +#endif +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) + case SPI_FLASH_CFI_MFR_SPANSION: + case SPI_FLASH_CFI_MFR_WINBOND: + return spi_flash_set_qeb_winspan(flash); +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO + case SPI_FLASH_CFI_MFR_STMICRO: + debug("SF: QEB is volatile for %02x flash\n", idcode0); + return 0; +#endif + default: + printf("SF: Need set QEB func for %02x flash\n", idcode0); + return -1; + } +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) +{ + fdt_addr_t addr; + fdt_size_t size; + int node; + + /* If there is no node, do nothing */ + node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); + if (node < 0) + return 0; + + addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); + if (addr == FDT_ADDR_T_NONE) { + debug("%s: Cannot decode address\n", __func__); + return 0; + } + + if (flash->size != size) { + debug("%s: Memory map must cover entire device\n", __func__); + return -1; + } + flash->memory_map = map_sysmem(addr, size); + + return 0; +} +#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ + +int spi_flash_scan(struct spi_flash *flash) +{ + struct spi_slave *spi = flash->spi; + const struct spi_flash_params *params; + u16 jedec, ext_jedec; + u8 idcode[5]; + u8 cmd; + int ret; + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) { + printf("SF: Failed to get idcodes\n"); + return -EINVAL; + } + +#ifdef DEBUG + printf("SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + jedec = idcode[1] << 8 | idcode[2]; + ext_jedec = idcode[3] << 8 | idcode[4]; + + /* Validate params from spi_flash_params table */ + params = spi_flash_params_table; + for (; params->name != NULL; params++) { + if ((params->jedec >> 16) == idcode[0]) { + if ((params->jedec & 0xFFFF) == jedec) { + if (params->ext_jedec == 0) + break; + else if (params->ext_jedec == ext_jedec) + break; + } + } + } + + if (!params->name) { + printf("SF: Unsupported flash IDs: "); + printf("manuf %02x, jedec %04x, ext_jedec %04x\n", + idcode[0], jedec, ext_jedec); + return -EPROTONOSUPPORT; + } + + /* Flash powers up read-only, so clear BP# bits */ + if (idcode[0] == SPI_FLASH_CFI_MFR_ATMEL || + idcode[0] == SPI_FLASH_CFI_MFR_MACRONIX || + idcode[0] == SPI_FLASH_CFI_MFR_SST) + write_sr(flash, 0); + + /* Assign spi data */ + flash->name = params->name; + flash->memory_map = spi->memory_map; + flash->dual_flash = flash->spi->option; + + /* Assign spi flash flags */ + if (params->flags & SST_WR) + flash->flags |= SNOR_F_SST_WR; + + /* Assign spi_flash ops */ +#ifndef CONFIG_DM_SPI_FLASH + flash->write = spi_flash_cmd_write_ops; +#if defined(CONFIG_SPI_FLASH_SST) + if (flash->flags & SNOR_F_SST_WR) { + if (flash->spi->op_mode_tx & SPI_OPM_TX_BP) + flash->write = sst_write_bp; + else + flash->write = sst_write_wp; + } +#endif + flash->erase = spi_flash_cmd_erase_ops; + flash->read = spi_flash_cmd_read_ops; +#endif + + /* lock hooks are flash specific - assign them based on idcode0 */ + switch (idcode[0]) { +#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) + case SPI_FLASH_CFI_MFR_STMICRO: + case SPI_FLASH_CFI_MFR_SST: + flash->flash_lock = stm_lock; + flash->flash_unlock = stm_unlock; + flash->flash_is_locked = stm_is_locked; +#endif + break; + default: + debug("SF: Lock ops not supported for %02x flash\n", idcode[0]); + } + + /* Compute the flash size */ + flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; + /* + * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the + * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with + * the 0x4d00 Extended JEDEC code have 512b pages. All of the others + * have 256b pages. + */ + if (ext_jedec == 0x4d00) { + if ((jedec == 0x0215) || (jedec == 0x216)) + flash->page_size = 256; + else + flash->page_size = 512; + } else { + flash->page_size = 256; + } + flash->page_size <<= flash->shift; + flash->sector_size = params->sector_size << flash->shift; + flash->size = flash->sector_size * params->nr_sectors << flash->shift; +#ifdef CONFIG_SF_DUAL_FLASH + if (flash->dual_flash & SF_DUAL_STACKED_FLASH) + flash->size <<= 1; +#endif + + /* Compute erase sector and command */ + if (params->flags & SECT_4K) { + flash->erase_cmd = CMD_ERASE_4K; + flash->erase_size = 4096 << flash->shift; + } else if (params->flags & SECT_32K) { + flash->erase_cmd = CMD_ERASE_32K; + flash->erase_size = 32768 << flash->shift; + } else { + flash->erase_cmd = CMD_ERASE_64K; + flash->erase_size = flash->sector_size; + } + + /* Now erase size becomes valid sector size */ + flash->sector_size = flash->erase_size; + + /* Look for the fastest read cmd */ + cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx); + if (cmd) { + cmd = spi_read_cmds_array[cmd - 1]; + flash->read_cmd = cmd; + } else { + /* Go for default supported read cmd */ + flash->read_cmd = CMD_READ_ARRAY_FAST; + } + + /* Not require to look for fastest only two write cmds yet */ + if (params->flags & WR_QPP && flash->spi->op_mode_tx & SPI_OPM_TX_QPP) + flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; + else + /* Go for default supported write cmd */ + flash->write_cmd = CMD_PAGE_PROGRAM; + + /* Set the quad enable bit - only for quad commands */ + if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || + (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || + (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { + ret = spi_flash_set_qeb(flash, idcode[0]); + if (ret) { + debug("SF: Fail to set QEB for %02x\n", idcode[0]); + return -EINVAL; + } + } + + /* Read dummy_byte: dummy byte is determined based on the + * dummy cycles of a particular command. + * Fast commands - dummy_byte = dummy_cycles/8 + * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 + * For I/O commands except cmd[0] everything goes on no.of lines + * based on particular command but incase of fast commands except + * data all go on single line irrespective of command. + */ + switch (flash->read_cmd) { + case CMD_READ_QUAD_IO_FAST: + flash->dummy_byte = 2; + break; + case CMD_READ_ARRAY_SLOW: + flash->dummy_byte = 0; + break; + default: + flash->dummy_byte = 1; + } + +#ifdef CONFIG_SPI_FLASH_STMICRO + if (params->flags & E_FSR) + flash->flags |= SNOR_F_USE_FSR; +#endif + + /* Configure the BAR - discover bank cmds and read current bank */ +#ifdef CONFIG_SPI_FLASH_BAR + ret = spi_flash_read_bar(flash, idcode[0]); + if (ret < 0) + return ret; +#endif + +#if CONFIG_IS_ENABLED(OF_CONTROL) + ret = spi_flash_decode_fdt(gd->fdt_blob, flash); + if (ret) { + debug("SF: FDT decode error\n"); + return -EINVAL; + } +#endif + +#ifndef CONFIG_SPL_BUILD + printf("SF: Detected %s with page size ", flash->name); + print_size(flash->page_size, ", erase size "); + print_size(flash->erase_size, ", total "); + print_size(flash->size, ""); + if (flash->memory_map) + printf(", mapped at %p", flash->memory_map); + puts("\n"); +#endif + +#ifndef CONFIG_SPI_FLASH_BAR + if (((flash->dual_flash == SF_SINGLE_FLASH) && + (flash->size > SPI_FLASH_16MB_BOUN)) || + ((flash->dual_flash > SF_SINGLE_FLASH) && + (flash->size > SPI_FLASH_16MB_BOUN << 1))) { + puts("SF: Warning - Only lower 16MiB accessible,"); + puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); + } +#endif + + return ret; +} diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index a03a95d..de54ca8 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -88,6 +88,7 @@ config ETH_SANDBOX_RAW config ETH_DESIGNWARE bool "Synopsys Designware Ethernet MAC" + select PHYLIB help This MAC is present in SoCs from various vendors. It supports 100Mbit and 1 Gbit operation. You must enable CONFIG_PHYLIB to @@ -101,4 +102,11 @@ config PCH_GBE This MAC is present in Intel Platform Controller Hub EG20T. It supports 10/100/1000 Mbps operation. +config ZYNQ_GEM + depends on DM_ETH && (ARCH_ZYNQ || ARCH_ZYNQMP) + select PHYLIB + bool "Xilinx Ethernet GEM" + help + This MAC is present in Xilinx Zynq and ZynqMP SoCs. + endif # NETDEVICES diff --git a/drivers/net/designware.c b/drivers/net/designware.c index a6c39c3..04114a1 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -22,10 +22,6 @@ DECLARE_GLOBAL_DATA_PTR; -#if !defined(CONFIG_PHYLIB) -# error "DesignWare Ether MAC requires PHYLIB - missing CONFIG_PHYLIB" -#endif - static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) { struct eth_mac_regs *mac_p = bus->priv; @@ -107,8 +103,8 @@ static void tx_descs_init(struct dw_eth_dev *priv) #if defined(CONFIG_DW_ALTDESCRIPTOR) desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST | - DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \ - DESC_TXSTS_TXCHECKINSCTRL | \ + DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | + DESC_TXSTS_TXCHECKINSCTRL | DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS); desc_p->txrx_status |= DESC_TXSTS_TXCHAIN; @@ -155,7 +151,7 @@ static void rx_descs_init(struct dw_eth_dev *priv) desc_p->dmamac_next = &desc_table_p[idx + 1]; desc_p->dmamac_cntl = - (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \ + (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | DESC_RXCTRL_RXCHAIN; desc_p->txrx_status = DESC_RXSTS_OWNBYDMA; @@ -321,14 +317,14 @@ static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length) #if defined(CONFIG_DW_ALTDESCRIPTOR) desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST; - desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \ + desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & DESC_TXCTRL_SIZE1MASK; desc_p->txrx_status &= ~(DESC_TXSTS_MSK); desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA; #else - desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \ - DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \ + desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & + DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | DESC_TXCTRL_TXFIRST; desc_p->txrx_status = DESC_TXSTS_OWNBYDMA; @@ -368,7 +364,7 @@ static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp) /* Check if the owner is the CPU */ if (!(status & DESC_RXSTS_OWNBYDMA)) { - length = (status & DESC_RXSTS_FRMLENMSK) >> \ + length = (status & DESC_RXSTS_FRMLENMSK) >> DESC_RXSTS_FRMLENSHFT; /* Invalidate received data */ diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c index 3a1de59..7e312f1 100644 --- a/drivers/net/fm/init.c +++ b/drivers/net/fm/init.c @@ -242,8 +242,10 @@ int ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop) int off; uint32_t ph; phys_addr_t paddr = CONFIG_SYS_CCSRBAR_PHYS + info->compat_offset; +#ifndef CONFIG_SYS_FMAN_V3 u64 dtsec1_addr = (u64)CONFIG_SYS_CCSRBAR_PHYS + CONFIG_SYS_FSL_FM1_DTSEC1_OFFSET; +#endif off = fdt_node_offset_by_compat_reg(blob, prop, paddr); if (off == -FDT_ERR_NOTFOUND) @@ -295,8 +297,10 @@ int ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop) /* board code might have caused offset to change */ off = fdt_node_offset_by_compat_reg(blob, prop, paddr); +#ifndef CONFIG_SYS_FMAN_V3 /* Don't disable FM1-DTSEC1 MAC as its used for MDIO */ if (paddr != dtsec1_addr) +#endif fdt_status_disabled(blob, off); /* disable the MAC node */ /* disable the fsl,dpa-ethernet node that points to the MAC */ diff --git a/drivers/net/fm/ls1043.c b/drivers/net/fm/ls1043.c index cf2cc95..93ba318 100644 --- a/drivers/net/fm/ls1043.c +++ b/drivers/net/fm/ls1043.c @@ -54,11 +54,8 @@ phy_interface_t fman_port_enet_if(enum fm_port port) struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); u32 rcwsr13 = in_be32(&gur->rcwsr[13]); - if (is_device_disabled(port)) { - printf("%s:%d: port(%d) is disabled\n", __func__, - __LINE__, port); + if (is_device_disabled(port)) return PHY_INTERFACE_MODE_NONE; - } if ((port == FM1_10GEC1) && (is_serdes_configured(XFI_FM1_MAC9))) return PHY_INTERFACE_MODE_XGMII; @@ -69,15 +66,11 @@ phy_interface_t fman_port_enet_if(enum fm_port port) if (port == FM1_DTSEC3) if ((rcwsr13 & FSL_CHASSIS2_RCWSR13_EC1) == FSL_CHASSIS2_RCWSR13_EC1_DTSEC3_RGMII) { - printf("%s:%d: port(FM1_DTSEC3) is OK\n", - __func__, __LINE__); return PHY_INTERFACE_MODE_RGMII; } if (port == FM1_DTSEC4) if ((rcwsr13 & FSL_CHASSIS2_RCWSR13_EC2) == FSL_CHASSIS2_RCWSR13_EC2_DTSEC4_RGMII) { - printf("%s:%d: port(FM1_DTSEC4) is OK\n", - __func__, __LINE__); return PHY_INTERFACE_MODE_RGMII; } diff --git a/drivers/net/fsl-mc/Makefile b/drivers/net/fsl-mc/Makefile index 7563a5f..a492388 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 1517a70..ba9536d 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 cd3fd50..b61df52 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/dpio/qbman_portal.c b/drivers/net/fsl-mc/dpio/qbman_portal.c index 5fa8d95..449ff8a 100644 --- a/drivers/net/fsl-mc/dpio/qbman_portal.c +++ b/drivers/net/fsl-mc/dpio/qbman_portal.c @@ -117,7 +117,7 @@ void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, uint32_t cmd_verb) { uint32_t *v = cmd; #ifdef QBMAN_CHECKING - BUG_ON(!p->mc.check != swp_mc_can_submit); + BUG_ON(p->mc.check != swp_mc_can_submit); #endif lwsync(); /* TBD: "|=" is going to hurt performance. Need to move as many fields diff --git a/drivers/net/fsl-mc/dpmac.c b/drivers/net/fsl-mc/dpmac.c new file mode 100644 index 0000000..072a90d --- /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 9111f35..eacb3c8 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 357aa48..7d34355 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 ea987d7..bac4610 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,54 +524,57 @@ 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); goto out; } - if (MC_VER_MAJOR != mc_ver_info.major) { - printf("fsl-mc: ERROR: Firmware major version mismatch (found: %d, expected: %d)\n", - mc_ver_info.major, MC_VER_MAJOR); - printf("fsl-mc: Update the Management Complex firmware\n"); - - error = -ENODEV; - goto out; - } - - if (MC_VER_MINOR != mc_ver_info.minor) - printf("fsl-mc: WARNING: Firmware minor version mismatch (found: %d, expected: %d)\n", - mc_ver_info.minor, MC_VER_MINOR); - printf("fsl-mc: Management Complex booted (version: %d.%d.%d, boot status: %#x)\n", 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 +584,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 +644,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 +717,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; } - 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); + 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; + } - 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; - } + dflt_dpbp->dpbp_attr.id = dpbp_attr.id; +#ifdef DEBUG + printf("Init: DPBP id=0x%d\n", dflt_dpbp->dpbp_attr.id); +#endif + + 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; + +err: + return err; +} - 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; +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 2136670..71e1456 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/greth.c b/drivers/net/greth.c index 0624eb8..088cb22 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -245,7 +245,7 @@ int greth_init_phy(greth_priv * dev, bd_t * bis) debug("GRETH PHY ADDRESS: %d\n", phyaddr); /* X msecs to ticks */ - timeout = usec2ticks(GRETH_PHY_TIMEOUT_MS * 1000); + timeout = GRETH_PHY_TIMEOUT_MS * 1000; /* Get system timer0 current value * Total timeout is 5s diff --git a/drivers/net/ldpaa_eth/Makefile b/drivers/net/ldpaa_eth/Makefile index c37633f..74c4916 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 99acb7a..69530b1 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 b4ef700..af41b27 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 926057a..f7f26c2 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 93ed4f1..93ed4f1 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 ef4da4e..f90c2ae 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/net/phy/micrel.c b/drivers/net/phy/micrel.c index 5e49666..19b6bc7 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -9,9 +9,14 @@ */ #include <config.h> #include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> #include <micrel.h> #include <phy.h> +DECLARE_GLOBAL_DATA_PTR; + static struct phy_driver KSZ804_driver = { .name = "Micrel KSZ804", .uid = 0x221510, @@ -174,6 +179,73 @@ static int ksz90xx_startup(struct phy_device *phydev) return 0; } +/* Common OF config bits for KSZ9021 and KSZ9031 */ +#if defined(CONFIG_PHY_MICREL_KSZ9021) || defined(CONFIG_PHY_MICREL_KSZ9031) +#ifdef CONFIG_DM_ETH +struct ksz90x1_reg_field { + const char *name; + const u8 size; /* Size of the bitfield, in bits */ + const u8 off; /* Offset from bit 0 */ + const u8 dflt; /* Default value */ +}; + +struct ksz90x1_ofcfg { + const u16 reg; + const u16 devad; + const struct ksz90x1_reg_field *grp; + const u16 grpsz; +}; + +static const struct ksz90x1_reg_field ksz90x1_rxd_grp[] = { + { "rxd0-skew-ps", 4, 0, 0x7 }, { "rxd1-skew-ps", 4, 4, 0x7 }, + { "rxd2-skew-ps", 4, 8, 0x7 }, { "rxd3-skew-ps", 4, 12, 0x7 } +}; + +static const struct ksz90x1_reg_field ksz90x1_txd_grp[] = { + { "txd0-skew-ps", 4, 0, 0x7 }, { "txd1-skew-ps", 4, 4, 0x7 }, + { "txd2-skew-ps", 4, 8, 0x7 }, { "txd3-skew-ps", 4, 12, 0x7 }, +}; + +static int ksz90x1_of_config_group(struct phy_device *phydev, + struct ksz90x1_ofcfg *ofcfg) +{ + struct udevice *dev = phydev->dev; + struct phy_driver *drv = phydev->drv; + const int ps_to_regval = 200; + int val[4]; + int i, changed = 0, offset, max; + u16 regval = 0; + + if (!drv || !drv->writeext) + return -EOPNOTSUPP; + + for (i = 0; i < ofcfg->grpsz; i++) { + val[i] = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, + ofcfg->grp[i].name, -1); + offset = ofcfg->grp[i].off; + if (val[i] == -1) { + /* Default register value for KSZ9021 */ + regval |= ofcfg->grp[i].dflt << offset; + } else { + changed = 1; /* Value was changed in OF */ + /* Calculate the register value and fix corner cases */ + if (val[i] > ps_to_regval * 0xf) { + max = (1 << ofcfg->grp[i].size) - 1; + regval |= max << offset; + } else { + regval |= (val[i] / ps_to_regval) << offset; + } + } + } + + if (!changed) + return 0; + + return drv->writeext(phydev, 0, ofcfg->devad, ofcfg->reg, regval); +} +#endif +#endif + #ifdef CONFIG_PHY_MICREL_KSZ9021 /* * KSZ9021 @@ -188,6 +260,35 @@ static int ksz90xx_startup(struct phy_device *phydev) #define CTRL1000_CONFIG_MASTER (1 << 11) #define CTRL1000_MANUAL_CONFIG (1 << 12) +#ifdef CONFIG_DM_ETH +static const struct ksz90x1_reg_field ksz9021_clk_grp[] = { + { "txen-skew-ps", 4, 0, 0x7 }, { "txc-skew-ps", 4, 4, 0x7 }, + { "rxdv-skew-ps", 4, 8, 0x7 }, { "rxc-skew-ps", 4, 12, 0x7 }, +}; + +static int ksz9021_of_config(struct phy_device *phydev) +{ + struct ksz90x1_ofcfg ofcfg[] = { + { MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW, 0, ksz90x1_rxd_grp, 4 }, + { MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW, 0, ksz90x1_txd_grp, 4 }, + { MII_KSZ9021_EXT_RGMII_CLOCK_SKEW, 0, ksz9021_clk_grp, 4 }, + }; + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(ofcfg); i++) + ret = ksz90x1_of_config_group(phydev, &(ofcfg[i])); + if (ret) + return ret; + + return 0; +} +#else +static int ksz9021_of_config(struct phy_device *phydev) +{ + return 0; +} +#endif + int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val) { /* extended registers */ @@ -224,6 +325,11 @@ static int ksz9021_config(struct phy_device *phydev) const unsigned master = CTRL1000_PREFER_MASTER | CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG; unsigned features = phydev->drv->features; + int ret; + + ret = ksz9021_of_config(phydev); + if (ret) + return ret; if (getenv("disable_giga")) features &= ~(SUPPORTED_1000baseT_Half | @@ -260,6 +366,36 @@ static struct phy_driver ksz9021_driver = { #define MII_KSZ9031_MMD_ACCES_CTRL 0x0d #define MII_KSZ9031_MMD_REG_DATA 0x0e +#ifdef CONFIG_DM_ETH +static const struct ksz90x1_reg_field ksz9031_ctl_grp[] = + { { "txen-skew-ps", 4, 0, 0x7 }, { "rxdv-skew-ps", 4, 4, 0x7 } }; +static const struct ksz90x1_reg_field ksz9031_clk_grp[] = + { { "rxc-skew-ps", 5, 0, 0xf }, { "txc-skew-ps", 5, 5, 0xf } }; + +static int ksz9031_of_config(struct phy_device *phydev) +{ + struct ksz90x1_ofcfg ofcfg[] = { + { MII_KSZ9031_EXT_RGMII_CTRL_SIG_SKEW, 2, ksz9031_ctl_grp, 2 }, + { MII_KSZ9031_EXT_RGMII_RX_DATA_SKEW, 2, ksz90x1_rxd_grp, 4 }, + { MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW, 2, ksz90x1_txd_grp, 4 }, + { MII_KSZ9031_EXT_RGMII_CLOCK_SKEW, 2, ksz9031_clk_grp, 2 }, + }; + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(ofcfg); i++) + ret = ksz90x1_of_config_group(phydev, &(ofcfg[i])); + if (ret) + return ret; + + return 0; +} +#else +static int ksz9031_of_config(struct phy_device *phydev) +{ + return 0; +} +#endif + /* Accessors to extended registers*/ int ksz9031_phy_extended_write(struct phy_device *phydev, int devaddr, int regnum, u16 mode, u16 val) @@ -304,13 +440,21 @@ static int ksz9031_phy_extwrite(struct phy_device *phydev, int addr, MII_KSZ9031_MOD_DATA_POST_INC_RW, val); }; +static int ksz9031_config(struct phy_device *phydev) +{ + int ret; + ret = ksz9031_of_config(phydev); + if (ret) + return ret; + return genphy_config(phydev); +} static struct phy_driver ksz9031_driver = { .name = "Micrel ksz9031", .uid = 0x221620, .mask = 0xfffff0, .features = PHY_GBIT_FEATURES, - .config = &genphy_config, + .config = &ksz9031_config, .startup = &ksz90xx_startup, .shutdown = &genphy_shutdown, .writeext = &ksz9031_phy_extwrite, diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 858093f..7059c84 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -10,11 +10,11 @@ */ #include <common.h> +#include <dm.h> #include <net.h> #include <netdev.h> #include <config.h> -#include <fdtdec.h> -#include <libfdt.h> +#include <console.h> #include <malloc.h> #include <asm/io.h> #include <phy.h> @@ -25,9 +25,7 @@ #include <asm/arch/sys_proto.h> #include <asm-generic/errno.h> -#if !defined(CONFIG_PHYLIB) -# error XILINX_GEM_ETHERNET requires PHYLIB -#endif +DECLARE_GLOBAL_DATA_PTR; /* Bit/mask specification */ #define ZYNQ_GEM_PHYMNTNC_OP_MASK 0x40020000 /* operation mask bits */ @@ -167,14 +165,14 @@ struct zynq_gem_priv { int phyaddr; u32 emio; int init; + struct zynq_gem_regs *iobase; phy_interface_t interface; struct phy_device *phydev; struct mii_dev *bus; }; -static inline int mdio_wait(struct eth_device *dev) +static inline int mdio_wait(struct zynq_gem_regs *regs) { - struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; u32 timeout = 20000; /* Wait till MDIO interface is ready to accept a new transaction. */ @@ -192,13 +190,13 @@ static inline int mdio_wait(struct eth_device *dev) return 0; } -static u32 phy_setup_op(struct eth_device *dev, u32 phy_addr, u32 regnum, - u32 op, u16 *data) +static u32 phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum, + u32 op, u16 *data) { u32 mgtcr; - struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + struct zynq_gem_regs *regs = priv->iobase; - if (mdio_wait(dev)) + if (mdio_wait(regs)) return 1; /* Construct mgtcr mask for the operation */ @@ -209,7 +207,7 @@ static u32 phy_setup_op(struct eth_device *dev, u32 phy_addr, u32 regnum, /* Write mgtcr and wait for completion */ writel(mgtcr, ®s->phymntnc); - if (mdio_wait(dev)) + if (mdio_wait(regs)) return 1; if (op == ZYNQ_GEM_PHYMNTNC_OP_R_MASK) @@ -218,12 +216,13 @@ static u32 phy_setup_op(struct eth_device *dev, u32 phy_addr, u32 regnum, return 0; } -static u32 phyread(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 *val) +static u32 phyread(struct zynq_gem_priv *priv, u32 phy_addr, + u32 regnum, u16 *val) { u32 ret; - ret = phy_setup_op(dev, phy_addr, regnum, - ZYNQ_GEM_PHYMNTNC_OP_R_MASK, val); + ret = phy_setup_op(priv, phy_addr, regnum, + ZYNQ_GEM_PHYMNTNC_OP_R_MASK, val); if (!ret) debug("%s: phy_addr %d, regnum 0x%x, val 0x%x\n", __func__, @@ -232,29 +231,30 @@ static u32 phyread(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 *val) return ret; } -static u32 phywrite(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 data) +static u32 phywrite(struct zynq_gem_priv *priv, u32 phy_addr, + u32 regnum, u16 data) { debug("%s: phy_addr %d, regnum 0x%x, data 0x%x\n", __func__, phy_addr, regnum, data); - return phy_setup_op(dev, phy_addr, regnum, - ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data); + return phy_setup_op(priv, phy_addr, regnum, + ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data); } -static void phy_detection(struct eth_device *dev) +static int phy_detection(struct udevice *dev) { int i; u16 phyreg; struct zynq_gem_priv *priv = dev->priv; if (priv->phyaddr != -1) { - phyread(dev, priv->phyaddr, PHY_DETECT_REG, &phyreg); + phyread(priv, priv->phyaddr, PHY_DETECT_REG, &phyreg); if ((phyreg != 0xFFFF) && ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { /* Found a valid PHY address */ debug("Default phy address %d is valid\n", priv->phyaddr); - return; + return 0; } else { debug("PHY address is not setup correctly %d\n", priv->phyaddr); @@ -266,33 +266,36 @@ static void phy_detection(struct eth_device *dev) if (priv->phyaddr == -1) { /* detect the PHY address */ for (i = 31; i >= 0; i--) { - phyread(dev, i, PHY_DETECT_REG, &phyreg); + phyread(priv, i, PHY_DETECT_REG, &phyreg); if ((phyreg != 0xFFFF) && ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { /* Found a valid PHY address */ priv->phyaddr = i; debug("Found valid phy address, %d\n", i); - return; + return 0; } } } printf("PHY is not detected\n"); + return -1; } -static int zynq_gem_setup_mac(struct eth_device *dev) +static int zynq_gem_setup_mac(struct udevice *dev) { u32 i, macaddrlow, macaddrhigh; - struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + struct eth_pdata *pdata = dev_get_platdata(dev); + struct zynq_gem_priv *priv = dev_get_priv(dev); + struct zynq_gem_regs *regs = priv->iobase; /* Set the MAC bits [31:0] in BOT */ - macaddrlow = dev->enetaddr[0]; - macaddrlow |= dev->enetaddr[1] << 8; - macaddrlow |= dev->enetaddr[2] << 16; - macaddrlow |= dev->enetaddr[3] << 24; + macaddrlow = pdata->enetaddr[0]; + macaddrlow |= pdata->enetaddr[1] << 8; + macaddrlow |= pdata->enetaddr[2] << 16; + macaddrlow |= pdata->enetaddr[3] << 24; /* Set MAC bits [47:32] in TOP */ - macaddrhigh = dev->enetaddr[4]; - macaddrhigh |= dev->enetaddr[5] << 8; + macaddrhigh = pdata->enetaddr[4]; + macaddrhigh |= pdata->enetaddr[5] << 8; for (i = 0; i < 4; i++) { writel(0, ®s->laddr[i][LADDR_LOW]); @@ -307,15 +310,11 @@ static int zynq_gem_setup_mac(struct eth_device *dev) return 0; } -static int zynq_gem_init(struct eth_device *dev, bd_t * bis) +static int zynq_phy_init(struct udevice *dev) { - u32 i; - unsigned long clk_rate = 0; - struct phy_device *phydev; - struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; - struct zynq_gem_priv *priv = dev->priv; - struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; - struct emac_bd *dummy_rx_bd = &priv->tx_bd[TX_FREE_DESC + 2]; + int ret; + struct zynq_gem_priv *priv = dev_get_priv(dev); + struct zynq_gem_regs *regs = priv->iobase; const u32 supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | @@ -323,6 +322,37 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; + /* Enable only MDIO bus */ + writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, ®s->nwctrl); + + ret = phy_detection(dev); + if (ret) { + printf("GEM PHY init failed\n"); + return ret; + } + + priv->phydev = phy_connect(priv->bus, priv->phyaddr, dev, + priv->interface); + if (!priv->phydev) + return -ENODEV; + + priv->phydev->supported = supported | ADVERTISED_Pause | + ADVERTISED_Asym_Pause; + priv->phydev->advertising = priv->phydev->supported; + phy_config(priv->phydev); + + return 0; +} + +static int zynq_gem_init(struct udevice *dev) +{ + u32 i; + unsigned long clk_rate = 0; + struct zynq_gem_priv *priv = dev_get_priv(dev); + struct zynq_gem_regs *regs = priv->iobase; + struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; + struct emac_bd *dummy_rx_bd = &priv->tx_bd[TX_FREE_DESC + 2]; + if (!priv->init) { /* Disable all interrupts */ writel(0xFFFFFFFF, ®s->idr); @@ -384,25 +414,14 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) priv->init++; } - phy_detection(dev); - - /* interface - look at tsec */ - phydev = phy_connect(priv->bus, priv->phyaddr, dev, - priv->interface); + phy_startup(priv->phydev); - phydev->supported = supported | ADVERTISED_Pause | - ADVERTISED_Asym_Pause; - phydev->advertising = phydev->supported; - priv->phydev = phydev; - phy_config(phydev); - phy_startup(phydev); - - if (!phydev->link) { - printf("%s: No link.\n", phydev->dev->name); + if (!priv->phydev->link) { + printf("%s: No link.\n", priv->phydev->dev->name); return -1; } - switch (phydev->speed) { + switch (priv->phydev->speed) { case SPEED_1000: writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000, ®s->nwcfg); @@ -420,7 +439,7 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) /* Change the rclk and clk only not using EMIO interface */ if (!priv->emio) - zynq_slcr_gem_clk_setup(dev->iobase != + zynq_slcr_gem_clk_setup((ulong)priv->iobase != ZYNQ_GEM_BASEADDR0, clk_rate); setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | @@ -447,6 +466,11 @@ static int wait_for_bit(const char *func, u32 *reg, const u32 mask, if (get_timer(start) > timeout) break; + if (ctrlc()) { + puts("Abort\n"); + return -EINTR; + } + udelay(1); } @@ -456,11 +480,11 @@ static int wait_for_bit(const char *func, u32 *reg, const u32 mask, return -ETIMEDOUT; } -static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) +static int zynq_gem_send(struct udevice *dev, void *ptr, int len) { u32 addr, size; - struct zynq_gem_priv *priv = dev->priv; - struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + struct zynq_gem_priv *priv = dev_get_priv(dev); + struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *current_bd = &priv->tx_bd[1]; /* Setup Tx BD */ @@ -501,94 +525,95 @@ static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) } /* Do not check frame_recd flag in rx_status register 0x20 - just poll BD */ -static int zynq_gem_recv(struct eth_device *dev) +static int zynq_gem_recv(struct udevice *dev, int flags, uchar **packetp) { int frame_len; - struct zynq_gem_priv *priv = dev->priv; + u32 addr; + struct zynq_gem_priv *priv = dev_get_priv(dev); struct emac_bd *current_bd = &priv->rx_bd[priv->rxbd_current]; - struct emac_bd *first_bd; if (!(current_bd->addr & ZYNQ_GEM_RXBUF_NEW_MASK)) - return 0; + return -1; if (!(current_bd->status & (ZYNQ_GEM_RXBUF_SOF_MASK | ZYNQ_GEM_RXBUF_EOF_MASK))) { printf("GEM: SOF or EOF not set for last buffer received!\n"); - return 0; + return -1; } frame_len = current_bd->status & ZYNQ_GEM_RXBUF_LEN_MASK; - if (frame_len) { - u32 addr = current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK; - addr &= ~(ARCH_DMA_MINALIGN - 1); + if (!frame_len) { + printf("%s: Zero size packet?\n", __func__); + return -1; + } - net_process_received_packet((u8 *)(ulong)addr, frame_len); + addr = current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK; + addr &= ~(ARCH_DMA_MINALIGN - 1); + *packetp = (uchar *)(uintptr_t)addr; - if (current_bd->status & ZYNQ_GEM_RXBUF_SOF_MASK) - priv->rx_first_buf = priv->rxbd_current; - else { - current_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK; - current_bd->status = 0xF0000000; /* FIXME */ - } + return frame_len; +} - if (current_bd->status & ZYNQ_GEM_RXBUF_EOF_MASK) { - first_bd = &priv->rx_bd[priv->rx_first_buf]; - first_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK; - first_bd->status = 0xF0000000; - } +static int zynq_gem_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct zynq_gem_priv *priv = dev_get_priv(dev); + struct emac_bd *current_bd = &priv->rx_bd[priv->rxbd_current]; + struct emac_bd *first_bd; - if ((++priv->rxbd_current) >= RX_BUF) - priv->rxbd_current = 0; + if (current_bd->status & ZYNQ_GEM_RXBUF_SOF_MASK) { + priv->rx_first_buf = priv->rxbd_current; + } else { + current_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK; + current_bd->status = 0xF0000000; /* FIXME */ } - return frame_len; + if (current_bd->status & ZYNQ_GEM_RXBUF_EOF_MASK) { + first_bd = &priv->rx_bd[priv->rx_first_buf]; + first_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK; + first_bd->status = 0xF0000000; + } + + if ((++priv->rxbd_current) >= RX_BUF) + priv->rxbd_current = 0; + + return 0; } -static void zynq_gem_halt(struct eth_device *dev) +static void zynq_gem_halt(struct udevice *dev) { - struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; + struct zynq_gem_priv *priv = dev_get_priv(dev); + struct zynq_gem_regs *regs = priv->iobase; clrsetbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK, 0); } -static int zynq_gem_miiphyread(const char *devname, uchar addr, - uchar reg, ushort *val) +static int zynq_gem_miiphy_read(struct mii_dev *bus, int addr, + int devad, int reg) { - struct eth_device *dev = eth_get_dev(); + struct zynq_gem_priv *priv = bus->priv; int ret; + u16 val; - ret = phyread(dev, addr, reg, val); - debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, *val); - return ret; + ret = phyread(priv, addr, reg, &val); + debug("%s 0x%x, 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, val, ret); + return val; } -static int zynq_gem_miiphy_write(const char *devname, uchar addr, - uchar reg, ushort val) +static int zynq_gem_miiphy_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value) { - struct eth_device *dev = eth_get_dev(); + struct zynq_gem_priv *priv = bus->priv; - debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, val); - return phywrite(dev, addr, reg, val); + debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, value); + return phywrite(priv, addr, reg, value); } -int zynq_gem_initialize(bd_t *bis, phys_addr_t base_addr, - int phy_addr, u32 emio) +static int zynq_gem_probe(struct udevice *dev) { - struct eth_device *dev; - struct zynq_gem_priv *priv; void *bd_space; - - dev = calloc(1, sizeof(*dev)); - if (dev == NULL) - return -1; - - dev->priv = calloc(1, sizeof(struct zynq_gem_priv)); - if (dev->priv == NULL) { - free(dev); - return -1; - } - priv = dev->priv; + struct zynq_gem_priv *priv = dev_get_priv(dev); + int ret; /* Align rxbuffers to ARCH_DMA_MINALIGN */ priv->rxbuffers = memalign(ARCH_DMA_MINALIGN, RX_BUF * PKTSIZE_ALIGN); @@ -603,69 +628,89 @@ int zynq_gem_initialize(bd_t *bis, phys_addr_t base_addr, priv->tx_bd = (struct emac_bd *)bd_space; priv->rx_bd = (struct emac_bd *)((ulong)bd_space + BD_SEPRN_SPACE); - priv->phyaddr = phy_addr; - priv->emio = emio; + priv->bus = mdio_alloc(); + priv->bus->read = zynq_gem_miiphy_read; + priv->bus->write = zynq_gem_miiphy_write; + priv->bus->priv = priv; + strcpy(priv->bus->name, "gem"); -#ifndef CONFIG_ZYNQ_GEM_INTERFACE - priv->interface = PHY_INTERFACE_MODE_MII; -#else - priv->interface = CONFIG_ZYNQ_GEM_INTERFACE; -#endif + ret = mdio_register(priv->bus); + if (ret) + return ret; - sprintf(dev->name, "Gem.%lx", base_addr); + zynq_phy_init(dev); - dev->iobase = base_addr; - - dev->init = zynq_gem_init; - dev->halt = zynq_gem_halt; - dev->send = zynq_gem_send; - dev->recv = zynq_gem_recv; - dev->write_hwaddr = zynq_gem_setup_mac; + return 0; +} - eth_register(dev); +static int zynq_gem_remove(struct udevice *dev) +{ + struct zynq_gem_priv *priv = dev_get_priv(dev); - miiphy_register(dev->name, zynq_gem_miiphyread, zynq_gem_miiphy_write); - priv->bus = miiphy_get_dev_by_name(dev->name); + free(priv->phydev); + mdio_unregister(priv->bus); + mdio_free(priv->bus); - return 1; + return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) -int zynq_gem_of_init(const void *blob) +static const struct eth_ops zynq_gem_ops = { + .start = zynq_gem_init, + .send = zynq_gem_send, + .recv = zynq_gem_recv, + .free_pkt = zynq_gem_free_pkt, + .stop = zynq_gem_halt, + .write_hwaddr = zynq_gem_setup_mac, +}; + +static int zynq_gem_ofdata_to_platdata(struct udevice *dev) { + struct eth_pdata *pdata = dev_get_platdata(dev); + struct zynq_gem_priv *priv = dev_get_priv(dev); int offset = 0; - u32 ret = 0; - u32 reg, phy_reg; - - debug("ZYNQ GEM: Initialization\n"); - - do { - offset = fdt_node_offset_by_compatible(blob, offset, - "xlnx,ps7-ethernet-1.00.a"); - if (offset != -1) { - reg = fdtdec_get_addr(blob, offset, "reg"); - if (reg != FDT_ADDR_T_NONE) { - offset = fdtdec_lookup_phandle(blob, offset, - "phy-handle"); - if (offset != -1) - phy_reg = fdtdec_get_addr(blob, offset, - "reg"); - else - phy_reg = 0; - - debug("ZYNQ GEM: addr %x, phyaddr %x\n", - reg, phy_reg); - - ret |= zynq_gem_initialize(NULL, reg, - phy_reg, 0); - - } else { - debug("ZYNQ GEM: Can't get base address\n"); - return -1; - } - } - } while (offset != -1); + const char *phy_mode; + + pdata->iobase = (phys_addr_t)dev_get_addr(dev); + priv->iobase = (struct zynq_gem_regs *)pdata->iobase; + /* Hardcode for now */ + priv->emio = 0; + priv->phyaddr = -1; + + offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset, + "phy-handle"); + if (offset > 0) + priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1); + + phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL); + if (phy_mode) + pdata->phy_interface = phy_get_interface_by_name(phy_mode); + if (pdata->phy_interface == -1) { + debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); + return -EINVAL; + } + priv->interface = pdata->phy_interface; - return ret; + printf("ZYNQ GEM: %lx, phyaddr %d, interface %s\n", (ulong)priv->iobase, + priv->phyaddr, phy_string_for_interface(priv->interface)); + + return 0; } -#endif + +static const struct udevice_id zynq_gem_ids[] = { + { .compatible = "cdns,zynqmp-gem" }, + { .compatible = "cdns,zynq-gem" }, + { .compatible = "cdns,gem" }, + { } +}; + +U_BOOT_DRIVER(zynq_gem) = { + .name = "zynq_gem", + .id = UCLASS_ETH, + .of_match = zynq_gem_ids, + .ofdata_to_platdata = zynq_gem_ofdata_to_platdata, + .probe = zynq_gem_probe, + .remove = zynq_gem_remove, + .ops = &zynq_gem_ops, + .priv_auto_alloc_size = sizeof(struct zynq_gem_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 167d405..26aa2b0 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 bcf8127..6b761b4 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 1d93194..5fe3072 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 0000000..85c419e --- /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 0412bf3..932eab8 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 a64792f..2a14902 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_rom.c b/drivers/pci/pci_rom.c index d244543..ad1167e 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -33,10 +33,6 @@ #include <video_fb.h> #include <linux/screen_info.h> -#ifdef CONFIG_HAVE_ACPI_RESUME -#include <asm/acpi.h> -#endif - __weak bool board_should_run_oprom(pci_dev_t dev) { return true; @@ -44,10 +40,6 @@ __weak bool board_should_run_oprom(pci_dev_t dev) static bool should_load_oprom(pci_dev_t dev) { -#ifdef CONFIG_HAVE_ACPI_RESUME - if (acpi_get_slp_type() == 3) - return false; -#endif if (IS_ENABLED(CONFIG_ALWAYS_LOAD_OPROM)) return 1; if (board_should_run_oprom(dev)) diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 690896f..5a7fefe 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 4cee038..58e88ae 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 3b6e3b7..57e6142 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 251bace..6fa7d00 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 0000000..581b096 --- /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 809f8f1..e86dd72 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -8,7 +8,9 @@ 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 AXP818_POWER if MACH_SUN8I_A83T + default SUNXI_NO_PMIC if MACH_SUN8I_H3 config SUNXI_NO_PMIC boolean "board without a pmic" @@ -31,27 +33,37 @@ 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. +config AXP818_POWER + boolean "axp818 pmic support" + depends on MACH_SUN8I_A83T + ---help--- + Say y here to enable support for the axp818 pmic found on + A83T dev board. + endchoice config AXP_DCDC1_VOLT int "axp pmic dcdc1 voltage" - depends on AXP221_POWER + depends on AXP221_POWER || AXP818_POWER + default 3300 if AXP818_POWER default 3000 if MACH_SUN6I || MACH_SUN8I ---help--- Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to disable dcdc1. On A23 / A31 / A33 (axp221) boards dcdc1 is used for generic 3.3V IO voltage for external devices like the lcd-panal and sdcard interfaces, etc. On most boards dcdc1 is undervolted to 3.0V to - safe battery. On A31 devices dcdc1 is also used for VCC-IO. + safe battery. On A31 devices dcdc1 is also used for VCC-IO. On A83T + dcdc1 is used for VCC-IO, nand, usb0, sd , etc. config AXP_DCDC2_VOLT int "axp pmic dcdc2 voltage" - depends on AXP152_POWER || AXP209_POWER || AXP221_POWER + depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP818_POWER + default 900 if AXP818_POWER default 1400 if AXP152_POWER || AXP209_POWER default 1200 if MACH_SUN6I default 1100 if MACH_SUN8I @@ -61,10 +73,12 @@ config AXP_DCDC2_VOLT On A10(s) / A13 / A20 boards dcdc2 is VDD-CPU and should be 1.4V. On A31 boards dcdc2 is used for VDD-GPU and should be 1.2V. On A23/A33 boards dcdc2 is used for VDD-SYS and should be 1.1V. + On A83T boards dcdc2 is used for VDD-CPUA(cluster 0) and should be 0.9V. config AXP_DCDC3_VOLT int "axp pmic dcdc3 voltage" - depends on AXP152_POWER || AXP209_POWER || AXP221_POWER + depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP818_POWER + default 900 if AXP818_POWER default 1500 if AXP152_POWER default 1250 if AXP209_POWER default 1200 if MACH_SUN6I || MACH_SUN8I @@ -75,10 +89,11 @@ config AXP_DCDC3_VOLT should be 1.25V. On A10s boards with an axp152 dcdc3 is VCC-DRAM and should be 1.5V. On A23 / A31 / A33 boards dcdc3 is VDD-CPU and should be 1.2V. + On A83T boards dcdc3 is used for VDD-CPUB(cluster 1) and should be 0.9V. config AXP_DCDC4_VOLT int "axp pmic dcdc4 voltage" - depends on AXP152_POWER || AXP221_POWER + depends on AXP152_POWER || AXP221_POWER || AXP818_POWER default 1250 if AXP152_POWER default 1200 if MACH_SUN6I default 0 if MACH_SUN8I @@ -88,15 +103,18 @@ config AXP_DCDC4_VOLT On A10s boards with an axp152 dcdc4 is VDD-INT-DLL and should be 1.25V. On A31 boards dcdc4 is used for VDD-SYS and should be 1.2V. On A23 / A33 boards dcdc4 is unused and should be disabled. + On A83T boards dcdc4 is used for VDD-GPU. config AXP_DCDC5_VOLT int "axp pmic dcdc5 voltage" - depends on AXP221_POWER + depends on AXP221_POWER || AXP818_POWER + default 1800 if AXP818_POWER default 1500 if MACH_SUN6I || MACH_SUN8I ---help--- Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to disable dcdc5. - On A23 / A31 / A33 boards dcdc5 is VCC-DRAM and should be 1.5V. + On A23 / A31 / A33 / A83T boards dcdc5 is VCC-DRAM and should be 1.5V, + 1.8V for A83T. config AXP_ALDO1_VOLT int "axp pmic (a)ldo1 voltage" @@ -111,7 +129,7 @@ config AXP_ALDO1_VOLT config AXP_ALDO2_VOLT int "axp pmic (a)ldo2 voltage" - depends on AXP152_POWER || AXP209_POWER || AXP221_POWER + depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP818_POWER default 3000 if AXP152_POWER || AXP209_POWER default 0 if MACH_SUN6I default 2500 if MACH_SUN8I @@ -125,14 +143,15 @@ config AXP_ALDO2_VOLT config AXP_ALDO3_VOLT int "axp pmic (a)ldo3 voltage" - depends on AXP209_POWER || AXP221_POWER - default 0 if AXP209_POWER + depends on AXP209_POWER || AXP221_POWER || AXP818_POWER + default 0 if AXP209_POWER || AXP818_POWER default 3000 if MACH_SUN6I || MACH_SUN8I ---help--- Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to disable aldo3. On A10(s) / A13 / A20 boards aldo3 should be 2.8V. On A23 / A31 / A33 boards aldo3 is VCC-PLL and AVCC and should be 3.0V. + On A83T aldo3 is used for LVDS, DSI, MIPI, HDMI, etc. config AXP_ALDO4_VOLT int "axp pmic (a)ldo4 voltage" @@ -171,7 +190,7 @@ config AXP_DLDO3_VOLT config AXP_DLDO4_VOLT int "axp pmic dldo4 voltage" - depends on AXP221_POWER + depends on AXP221_POWER || AXP818_POWER default 0 ---help--- Set the voltage (mV) to program the axp pmic dldo4 at, set to 0 to diff --git a/drivers/power/Makefile b/drivers/power/Makefile index a2d3c04..0fdbca3 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_AS3722_POWER) += as3722.o obj-$(CONFIG_AXP152_POWER) += axp152.o obj-$(CONFIG_AXP209_POWER) += axp209.o obj-$(CONFIG_AXP221_POWER) += axp221.o +obj-$(CONFIG_AXP818_POWER) += axp818.o obj-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o obj-$(CONFIG_FTPMU010_POWER) += ftpmu010.o obj-$(CONFIG_TPS6586X_POWER) += tps6586x.o diff --git a/drivers/power/axp818.c b/drivers/power/axp818.c new file mode 100644 index 0000000..4b21a83 --- /dev/null +++ b/drivers/power/axp818.c @@ -0,0 +1,132 @@ +/* + * AXP818 driver based on AXP221 driver + * + * + * (C) Copyright 2015 Vishnu Patekar <vishnuptekar0510@gmail.com> + * + * Based on axp221.c + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com> + * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <asm/arch/gpio.h> +#include <asm/arch/pmic_bus.h> +#include <axp_pmic.h> + +static u8 axp818_mvolt_to_cfg(int mvolt, int min, int max, int div) +{ + if (mvolt < min) + mvolt = min; + else if (mvolt > max) + mvolt = max; + + return (mvolt - min) / div; +} + +int axp_set_dcdc1(unsigned int mvolt) +{ + int ret; + u8 cfg = axp818_mvolt_to_cfg(mvolt, 1600, 3400, 100); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1, + AXP818_OUTPUT_CTRL1_DCDC1_EN); + + ret = pmic_bus_write(AXP818_DCDC1_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP818_OUTPUT_CTRL1, + AXP818_OUTPUT_CTRL1_DCDC1_EN); +} + +int axp_set_dcdc2(unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (mvolt >= 1220) + cfg = 70 + axp818_mvolt_to_cfg(mvolt, 1220, 1300, 20); + else + cfg = axp818_mvolt_to_cfg(mvolt, 500, 1200, 10); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1, + AXP818_OUTPUT_CTRL1_DCDC2_EN); + + ret = pmic_bus_write(AXP818_DCDC2_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP818_OUTPUT_CTRL1, + AXP818_OUTPUT_CTRL1_DCDC2_EN); +} + +int axp_set_dcdc3(unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (mvolt >= 1220) + cfg = 70 + axp818_mvolt_to_cfg(mvolt, 1220, 1300, 20); + else + cfg = axp818_mvolt_to_cfg(mvolt, 500, 1200, 10); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1, + AXP818_OUTPUT_CTRL1_DCDC3_EN); + + ret = pmic_bus_write(AXP818_DCDC3_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP818_OUTPUT_CTRL1, + AXP818_OUTPUT_CTRL1_DCDC3_EN); +} + +int axp_set_dcdc5(unsigned int mvolt) +{ + int ret; + u8 cfg; + + if (mvolt >= 1140) + cfg = 32 + axp818_mvolt_to_cfg(mvolt, 1140, 1840, 20); + else + cfg = axp818_mvolt_to_cfg(mvolt, 800, 1120, 10); + + if (mvolt == 0) + return pmic_bus_clrbits(AXP818_OUTPUT_CTRL1, + AXP818_OUTPUT_CTRL1_DCDC5_EN); + + ret = pmic_bus_write(AXP818_DCDC5_CTRL, cfg); + if (ret) + return ret; + + return pmic_bus_setbits(AXP818_OUTPUT_CTRL1, + AXP818_OUTPUT_CTRL1_DCDC5_EN); +} + +int axp_init(void) +{ + u8 axp_chip_id; + int ret; + + ret = pmic_bus_init(); + if (ret) + return ret; + + ret = pmic_bus_read(AXP818_CHIP_ID, &axp_chip_id); + if (ret) + return ret; + + if (!(axp_chip_id == 0x51)) + return -ENODEV; + else + return ret; + + return 0; +} diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c index a421e12..200cf61 100644 --- a/drivers/remoteproc/rproc-uclass.c +++ b/drivers/remoteproc/rproc-uclass.c @@ -66,7 +66,7 @@ static int _rproc_name_is_unique(struct udevice *dev, const char *check_name = data; /* devices not yet populated with data - so skip them */ - if (!uc_pdata->name && check_name) + if (!uc_pdata->name || !check_name) return 0; /* Return 0 to search further if we dont match */ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index eba96f4..1fc287e 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" @@ -94,7 +95,7 @@ config DEBUG_UART_S5P config DEBUG_UART_ZYNQ bool "Xilinx Zynq" help - Select this to enable a debug UART using the serial_s5p driver. You + Select this to enable a debug UART using the serial_zynq driver. You will need to provide parameters to make this work. The driver will be available until the real driver-model serial is running. @@ -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 1818c7c..dd87147 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 6433844..3fab3f1 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); } @@ -400,7 +403,14 @@ 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); + "reg-shift", 0); + 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,35 @@ 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, + .flags = DM_FLAG_PRE_RELOC, +}; #endif /* CONFIG_DM_SERIAL */ diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 842f78b..4bf9a5c 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -64,9 +64,9 @@ static void serial_find_console_or_panic(void) } /* - * If the console is not marked to be bound before relocation, - * bind it anyway. - */ + * If the console is not marked to be bound before relocation, + * bind it anyway. + */ if (node > 0 && !lists_bind_fdt(gd->dm_root, blob, node, &dev)) { if (!device_probe(dev)) { @@ -77,13 +77,13 @@ static void serial_find_console_or_panic(void) } if (!SPL_BUILD || !CONFIG_IS_ENABLED(OF_CONTROL) || !blob) { /* - * Try to use CONFIG_CONS_INDEX if available (it is numbered - * from 1!). - * - * Failing that, get the device with sequence number 0, or in - * extremis just the first serial device we can find. But we - * insist on having a console (even if it is silent). - */ + * Try to use CONFIG_CONS_INDEX if available (it is numbered + * from 1!). + * + * Failing that, get the device with sequence number 0, or in + * extremis just the first serial device we can find. But we + * insist on having a console (even if it is silent). + */ #ifdef CONFIG_CONS_INDEX #define INDEX (CONFIG_CONS_INDEX - 1) #else diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 422d3ae..f1bd15b 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -527,7 +527,7 @@ static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE; * * Do a loopback test of the currently selected serial port. This * function is only useful in the context of the POST testing framwork. - * The serial port is firstly configured into loopback mode and then + * The serial port is first configured into loopback mode and then * characters are sent through it. * * Returns 0 on success, value otherwise. diff --git a/drivers/serial/serial_dw.c b/drivers/serial/serial_dw.c deleted file mode 100644 index a348f29..0000000 --- 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 7b5ab6c..0000000 --- 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 891cd7b..0000000 --- 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 47141c6..0000000 --- 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 0e7bbfc..0000000 --- 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_stm32.c b/drivers/serial/serial_stm32.c index 8b2830b..91a5dde 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -1,45 +1,18 @@ /* * (C) Copyright 2015 - * Kamil Lulko, <rev13@wp.pl> + * Kamil Lulko, <kamil.lulko@gmail.com> * * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <dm.h> #include <asm/io.h> #include <serial.h> #include <asm/arch/stm32.h> +#include <dm/platform_data/serial_stm32.h> -/* - * Set up the usart port - */ -#if (CONFIG_STM32_USART >= 1) && (CONFIG_STM32_USART <= 6) -#define USART_PORT (CONFIG_STM32_USART - 1) -#else -#define USART_PORT 0 -#endif -/* - * Set up the usart base address - * - * --STM32_USARTD_BASE means default setting - */ -#define STM32_USART1_BASE (STM32_APB2PERIPH_BASE + 0x1000) -#define STM32_USART2_BASE (STM32_APB1PERIPH_BASE + 0x4400) -#define STM32_USART3_BASE (STM32_APB1PERIPH_BASE + 0x4800) -#define STM32_USART6_BASE (STM32_APB2PERIPH_BASE + 0x1400) -#define STM32_USARTD_BASE STM32_USART1_BASE -/* - * RCC USART specific definitions - * - * --RCC_ENR_USARTDEN means default setting - */ -#define RCC_ENR_USART1EN (1 << 4) -#define RCC_ENR_USART2EN (1 << 17) -#define RCC_ENR_USART3EN (1 << 18) -#define RCC_ENR_USART6EN (1 << 5) -#define RCC_ENR_USARTDEN RCC_ENR_USART1EN - -struct stm32_serial { +struct stm32_usart { u32 sr; u32 dr; u32 brr; @@ -49,120 +22,136 @@ struct stm32_serial { u32 gtpr; }; -#define USART_CR1_RE (1 << 2) -#define USART_CR1_TE (1 << 3) -#define USART_CR1_UE (1 << 13) +#define USART_CR1_RE (1 << 2) +#define USART_CR1_TE (1 << 3) +#define USART_CR1_UE (1 << 13) #define USART_SR_FLAG_RXNE (1 << 5) -#define USART_SR_FLAG_TXE (1 << 7) +#define USART_SR_FLAG_TXE (1 << 7) -#define USART_BRR_F_MASK 0xF +#define USART_BRR_F_MASK 0xF #define USART_BRR_M_SHIFT 4 #define USART_BRR_M_MASK 0xFFF0 DECLARE_GLOBAL_DATA_PTR; -static const unsigned long usart_base[] = { - STM32_USART1_BASE, - STM32_USART2_BASE, - STM32_USART3_BASE, - STM32_USARTD_BASE, - STM32_USARTD_BASE, - STM32_USART6_BASE -}; +#define MAX_SERIAL_PORTS 4 -static const unsigned long rcc_enr_en[] = { - RCC_ENR_USART1EN, - RCC_ENR_USART2EN, - RCC_ENR_USART3EN, - RCC_ENR_USARTDEN, - RCC_ENR_USARTDEN, - RCC_ENR_USART6EN +/* + * RCC USART specific definitions + */ +#define RCC_ENR_USART1EN (1 << 4) +#define RCC_ENR_USART2EN (1 << 17) +#define RCC_ENR_USART3EN (1 << 18) +#define RCC_ENR_USART6EN (1 << 5) + +/* Array used to figure out which RCC bit needs to be set */ +static const unsigned long usart_port_rcc_pairs[MAX_SERIAL_PORTS][2] = { + { STM32_USART1_BASE, RCC_ENR_USART1EN }, + { STM32_USART2_BASE, RCC_ENR_USART2EN }, + { STM32_USART3_BASE, RCC_ENR_USART3EN }, + { STM32_USART6_BASE, RCC_ENR_USART6EN } }; -static void stm32_serial_setbrg(void) +static int stm32_serial_setbrg(struct udevice *dev, int baudrate) { - serial_init(); -} + struct stm32_serial_platdata *plat = dev->platdata; + struct stm32_usart *const usart = plat->base; + u32 clock, int_div, frac_div, tmp; -static int stm32_serial_init(void) -{ - struct stm32_serial *usart = - (struct stm32_serial *)usart_base[USART_PORT]; - u32 clock, int_div, frac_div, tmp; - - if ((usart_base[USART_PORT] & STM32_BUS_MASK) == - STM32_APB1PERIPH_BASE) { - setbits_le32(&STM32_RCC->apb1enr, rcc_enr_en[USART_PORT]); + if (((u32)usart & STM32_BUS_MASK) == STM32_APB1PERIPH_BASE) clock = clock_get(CLOCK_APB1); - } else if ((usart_base[USART_PORT] & STM32_BUS_MASK) == - STM32_APB2PERIPH_BASE) { - setbits_le32(&STM32_RCC->apb2enr, rcc_enr_en[USART_PORT]); + else if (((u32)usart & STM32_BUS_MASK) == STM32_APB2PERIPH_BASE) clock = clock_get(CLOCK_APB2); - } else { - return -1; - } + else + return -EINVAL; - int_div = (25 * clock) / (4 * gd->baudrate); + int_div = (25 * clock) / (4 * baudrate); tmp = ((int_div / 100) << USART_BRR_M_SHIFT) & USART_BRR_M_MASK; frac_div = int_div - (100 * (tmp >> USART_BRR_M_SHIFT)); tmp |= (((frac_div * 16) + 50) / 100) & USART_BRR_F_MASK; - writel(tmp, &usart->brr); - setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); return 0; } -static int stm32_serial_getc(void) +static int stm32_serial_getc(struct udevice *dev) { - struct stm32_serial *usart = - (struct stm32_serial *)usart_base[USART_PORT]; - while ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0) - ; + struct stm32_serial_platdata *plat = dev->platdata; + struct stm32_usart *const usart = plat->base; + + if ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0) + return -EAGAIN; + return readl(&usart->dr); } -static void stm32_serial_putc(const char c) +static int stm32_serial_putc(struct udevice *dev, const char c) { - struct stm32_serial *usart = - (struct stm32_serial *)usart_base[USART_PORT]; + struct stm32_serial_platdata *plat = dev->platdata; + struct stm32_usart *const usart = plat->base; - if (c == '\n') - stm32_serial_putc('\r'); + if ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0) + return -EAGAIN; - while ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0) - ; writel(c, &usart->dr); + + return 0; } -static int stm32_serial_tstc(void) +static int stm32_serial_pending(struct udevice *dev, bool input) { - struct stm32_serial *usart = - (struct stm32_serial *)usart_base[USART_PORT]; - u8 ret; + struct stm32_serial_platdata *plat = dev->platdata; + struct stm32_usart *const usart = plat->base; - ret = readl(&usart->sr) & USART_SR_FLAG_RXNE; - return ret; + if (input) + return readl(&usart->sr) & USART_SR_FLAG_RXNE ? 1 : 0; + else + return readl(&usart->sr) & USART_SR_FLAG_TXE ? 0 : 1; } -static struct serial_device stm32_serial_drv = { - .name = "stm32_serial", - .start = stm32_serial_init, - .stop = NULL, - .setbrg = stm32_serial_setbrg, - .putc = stm32_serial_putc, - .puts = default_serial_puts, - .getc = stm32_serial_getc, - .tstc = stm32_serial_tstc, -}; - -void stm32_serial_initialize(void) +static int stm32_serial_probe(struct udevice *dev) { - serial_register(&stm32_serial_drv); -} + struct stm32_serial_platdata *plat = dev->platdata; + struct stm32_usart *const usart = plat->base; + int usart_port = -1; + int i; + + for (i = 0; i < MAX_SERIAL_PORTS; i++) { + if ((u32)usart == usart_port_rcc_pairs[i][0]) { + usart_port = i; + break; + } + } -__weak struct serial_device *default_serial_console(void) -{ - return &stm32_serial_drv; + if (usart_port == -1) + return -EINVAL; + + if (((u32)usart & STM32_BUS_MASK) == STM32_APB1PERIPH_BASE) + setbits_le32(&STM32_RCC->apb1enr, + usart_port_rcc_pairs[usart_port][1]); + else if (((u32)usart & STM32_BUS_MASK) == STM32_APB2PERIPH_BASE) + setbits_le32(&STM32_RCC->apb2enr, + usart_port_rcc_pairs[usart_port][1]); + else + return -EINVAL; + + setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); + + return 0; } + +static const struct dm_serial_ops stm32_serial_ops = { + .putc = stm32_serial_putc, + .pending = stm32_serial_pending, + .getc = stm32_serial_getc, + .setbrg = stm32_serial_setbrg, +}; + +U_BOOT_DRIVER(serial_stm32) = { + .name = "serial_stm32", + .id = UCLASS_SERIAL, + .ops = &stm32_serial_ops, + .probe = stm32_serial_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/serial/serial_tegra.c b/drivers/serial/serial_tegra.c deleted file mode 100644 index 0c84f0b..0000000 --- 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 4bf6062..0000000 --- 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/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index 88bebed..b2b98de 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -180,7 +180,7 @@ static const struct udevice_id zynq_serial_ids[] = { { } }; -U_BOOT_DRIVER(serial_s5p) = { +U_BOOT_DRIVER(serial_zynq) = { .name = "serial_zynq", .id = UCLASS_SERIAL, .of_match = zynq_serial_ids, @@ -192,9 +192,6 @@ U_BOOT_DRIVER(serial_s5p) = { }; #ifdef CONFIG_DEBUG_UART_ZYNQ - -#include <debug_uart.h> - void _debug_uart_init(void) { struct uart_zynq *regs = (struct uart_zynq *)CONFIG_DEBUG_UART_BASE; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a0dbd8b..2cdb110 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -140,7 +140,7 @@ config XILINX_SPI config ZYNQ_SPI bool "Zynq SPI driver" - depends on ARCH_ZYNQ || TARGET_XILINX_ZYNQMP + depends on ARCH_ZYNQ || ARCH_ZYNQMP help Enable the Zynq SPI driver. This driver can be used to access the SPI NOR flash on platforms embedding this Zynq diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index ed39114..feec3e8 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -13,6 +13,7 @@ #include <linux/sizes.h> #include <dm.h> #include <errno.h> +#include <watchdog.h> #include "fsl_qspi.h" DECLARE_GLOBAL_DATA_PTR; @@ -527,6 +528,8 @@ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) to_or_from = priv->sf_addr + priv->cur_amba_base; while (len > 0) { + WATCHDOG_RESET(); + qspi_write32(priv->flags, ®s->sfar, to_or_from); size = (len > RX_BUFFER_SIZE) ? @@ -574,6 +577,8 @@ static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) status_reg = 0; while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) { + WATCHDOG_RESET(); + qspi_write32(priv->flags, ®s->ipcr, (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 3c7d64a..e0f6b25 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -378,6 +378,8 @@ int spi_slave_ofdata_to_platdata(const void *blob, int node, mode |= SPI_CPHA; if (fdtdec_get_bool(blob, node, "spi-cs-high")) mode |= SPI_CS_HIGH; + if (fdtdec_get_bool(blob, node, "spi-3wire")) + mode |= SPI_3WIRE; if (fdtdec_get_bool(blob, node, "spi-half-duplex")) mode |= SPI_PREAMBLE; plat->mode = mode; diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index 646dd89..5747ed1 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -293,7 +293,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, qslave->cmd = 0; qslave->cmd |= QSPI_WLEN(8); qslave->cmd |= QSPI_EN_CS(slave->cs); - if (flags & SPI_3WIRE) + if (qslave->mode & SPI_3WIRE) qslave->cmd |= QSPI_3_PIN; qslave->cmd |= 0xfff; diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 0713714..a951a77 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -287,7 +287,8 @@ static const struct dm_spi_ops xilinx_spi_ops = { }; static const struct udevice_id xilinx_spi_ids[] = { - { .compatible = "xlnx,xilinx-spi" }, + { .compatible = "xlnx,xps-spi-2.00.a" }, + { .compatible = "xlnx,xps-spi-2.00.b" }, { } }; diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c index 5825c6d..b98663c 100644 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@ -30,6 +30,7 @@ DECLARE_GLOBAL_DATA_PTR; #define ZYNQ_QSPI_IXR_TXOW_MASK BIT(2) /* TX_FIFO_not_full */ #define ZYNQ_QSPI_IXR_ALL_MASK GENMASK(6, 0) /* All IXR bits */ #define ZYNQ_QSPI_ENR_SPI_EN_MASK BIT(0) /* SPI Enable */ +#define ZYNQ_QSPI_LQSPICFG_LQMODE_MASK BIT(31) /* Linear QSPI Mode */ /* zynq qspi Transmit Data Register */ #define ZYNQ_QSPI_TXD_00_00_OFFSET 0x1C /* Transmit 4-byte inst */ @@ -68,6 +69,9 @@ struct zynq_qspi_regs { u32 txd1r; /* 0x80 */ u32 txd2r; /* 0x84 */ u32 txd3r; /* 0x88 */ + u32 reserved1[5]; + u32 lqspicfg; /* 0xA0 */ + u32 lqspists; /* 0xA4 */ }; /* zynq qspi platform data */ @@ -143,6 +147,11 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv) ZYNQ_QSPI_CR_MSTREN_MASK; writel(confr, ®s->cr); + /* Disable the LQSPI feature */ + confr = readl(®s->lqspicfg); + confr &= ~ZYNQ_QSPI_LQSPICFG_LQMODE_MASK; + writel(confr, ®s->lqspicfg); + /* Enable SPI */ writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, ®s->enr); } diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 6ed2165..09ae1be 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -313,6 +313,7 @@ static const struct dm_spi_ops zynq_spi_ops = { static const struct udevice_id zynq_spi_ids[] = { { .compatible = "xlnx,zynq-spi-r1p6" }, + { .compatible = "cdns,spi-r1p6" }, { } }; diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 601e493..2b10d2b 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 300946e..fe954ec 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 971ed38..89fe05b 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 38de763..00a9944 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 12aee5b..aca421b 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 0000000..5c4ec00 --- /dev/null +++ b/drivers/timer/tsc_timer.c @@ -0,0 +1,379 @@ +/* + * 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 +} + +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/dwc3/core.c b/drivers/usb/dwc3/core.c index 0ae3de5..85cc96a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -613,7 +613,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) int dwc3_uboot_init(struct dwc3_device *dwc3_dev) { struct dwc3 *dwc; - struct device *dev; + struct device *dev = NULL; u8 lpm_nyet_threshold; u8 tx_de_emphasis; u8 hird_threshold; diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index ac9a856..3dcc2f4 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -374,7 +374,7 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap, int utmi_mode) int dwc3_omap_uboot_init(struct dwc3_omap_device *omap_dev) { u32 reg; - struct device *dev; + struct device *dev = NULL; struct dwc3_omap *omap; omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 6288ecf..c915c79 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -13,8 +13,8 @@ ifdef CONFIG_USB_GADGET obj-$(CONFIG_USB_GADGET_AT91) += at91_udc.o obj-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_GADGET_BCM_UDC_OTG_PHY) += bcm_udc_otg_phy.o -obj-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o -obj-$(CONFIG_USB_GADGET_S3C_UDC_OTG_PHY) += s3c_udc_otg_phy.o +obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_udc_otg.o +obj-$(CONFIG_USB_GADGET_DWC2_OTG_PHY) += dwc2_udc_otg_phy.o obj-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o obj-$(CONFIG_CI_UDC) += ci_udc.o obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o diff --git a/drivers/usb/gadget/bcm_udc_otg_phy.c b/drivers/usb/gadget/bcm_udc_otg_phy.c index f8690b0..10b2e13 100644 --- a/drivers/usb/gadget/bcm_udc_otg_phy.c +++ b/drivers/usb/gadget/bcm_udc_otg_phy.c @@ -9,10 +9,10 @@ #include <asm/io.h> #include <asm/arch/sysmap.h> -#include <usb/s3c_udc.h> +#include "dwc2_udc_otg_priv.h" #include "bcm_udc_otg.h" -void otg_phy_init(struct s3c_udc *dev) +void otg_phy_init(struct dwc2_udc *dev) { /* set Phy to driving mode */ wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET, @@ -37,7 +37,7 @@ void otg_phy_init(struct s3c_udc *dev) HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK); } -void otg_phy_off(struct s3c_udc *dev) +void otg_phy_off(struct dwc2_udc *dev) { /* Soft Disconnect */ wfld_set(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET, diff --git a/drivers/usb/gadget/s3c_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 7a2d1e7..ffe2952 100644 --- a/drivers/usb/gadget/s3c_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -1,6 +1,6 @@ /* - * drivers/usb/gadget/s3c_udc_otg.c - * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers + * drivers/usb/gadget/dwc2_udc_otg.c + * Designware DWC2 on-chip full/high speed USB OTG 2.0 device controllers * * Copyright (C) 2008 for Samsung Electronics * @@ -32,7 +32,8 @@ #include <asm/mach-types.h> -#include "regs-otg.h" +#include "dwc2_udc_otg_regs.h" +#include "dwc2_udc_otg_priv.h" #include <usb/lin_gadget_compat.h> /***********************************************************/ @@ -45,7 +46,7 @@ #define DEBUG_OUT_EP 0 #define DEBUG_IN_EP 0 -#include <usb/s3c_udc.h> +#include <usb/dwc2_udc.h> #define EP0_CON 0 #define EP_MASK 0xF @@ -62,12 +63,12 @@ static char *state_names[] = { "WAIT_FOR_NULL_COMPLETE", }; -#define DRIVER_DESC "S3C HS USB OTG Device Driver, (c) Samsung Electronics" +#define DRIVER_DESC "DWC2 HS USB OTG Device Driver, (c) Samsung Electronics" #define DRIVER_VERSION "15 March 2009" -struct s3c_udc *the_controller; +struct dwc2_udc *the_controller; -static const char driver_name[] = "s3c-udc"; +static const char driver_name[] = "dwc2-udc"; static const char driver_desc[] = DRIVER_DESC; static const char ep0name[] = "ep0-control"; @@ -83,32 +84,32 @@ static dma_addr_t usb_ctrl_dma_addr; /* Local declarations. */ -static int s3c_ep_enable(struct usb_ep *ep, +static int dwc2_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *); -static int s3c_ep_disable(struct usb_ep *ep); -static struct usb_request *s3c_alloc_request(struct usb_ep *ep, +static int dwc2_ep_disable(struct usb_ep *ep); +static struct usb_request *dwc2_alloc_request(struct usb_ep *ep, gfp_t gfp_flags); -static void s3c_free_request(struct usb_ep *ep, struct usb_request *); - -static int s3c_queue(struct usb_ep *ep, struct usb_request *, gfp_t gfp_flags); -static int s3c_dequeue(struct usb_ep *ep, struct usb_request *); -static int s3c_fifo_status(struct usb_ep *ep); -static void s3c_fifo_flush(struct usb_ep *ep); -static void s3c_ep0_read(struct s3c_udc *dev); -static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep); -static void s3c_handle_ep0(struct s3c_udc *dev); -static int s3c_ep0_write(struct s3c_udc *dev); -static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req); -static void done(struct s3c_ep *ep, struct s3c_request *req, int status); -static void stop_activity(struct s3c_udc *dev, +static void dwc2_free_request(struct usb_ep *ep, struct usb_request *); + +static int dwc2_queue(struct usb_ep *ep, struct usb_request *, gfp_t gfp_flags); +static int dwc2_dequeue(struct usb_ep *ep, struct usb_request *); +static int dwc2_fifo_status(struct usb_ep *ep); +static void dwc2_fifo_flush(struct usb_ep *ep); +static void dwc2_ep0_read(struct dwc2_udc *dev); +static void dwc2_ep0_kick(struct dwc2_udc *dev, struct dwc2_ep *ep); +static void dwc2_handle_ep0(struct dwc2_udc *dev); +static int dwc2_ep0_write(struct dwc2_udc *dev); +static int write_fifo_ep0(struct dwc2_ep *ep, struct dwc2_request *req); +static void done(struct dwc2_ep *ep, struct dwc2_request *req, int status); +static void stop_activity(struct dwc2_udc *dev, struct usb_gadget_driver *driver); -static int udc_enable(struct s3c_udc *dev); -static void udc_set_address(struct s3c_udc *dev, unsigned char address); -static void reconfig_usbd(struct s3c_udc *dev); -static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed); -static void nuke(struct s3c_ep *ep, int status); -static int s3c_udc_set_halt(struct usb_ep *_ep, int value); -static void s3c_udc_set_nak(struct s3c_ep *ep); +static int udc_enable(struct dwc2_udc *dev); +static void udc_set_address(struct dwc2_udc *dev, unsigned char address); +static void reconfig_usbd(struct dwc2_udc *dev); +static void set_max_pktsize(struct dwc2_udc *dev, enum usb_device_speed speed); +static void nuke(struct dwc2_ep *ep, int status); +static int dwc2_udc_set_halt(struct usb_ep *_ep, int value); +static void dwc2_udc_set_nak(struct dwc2_ep *ep); void set_udc_gadget_private_data(void *p) { @@ -123,19 +124,19 @@ void *get_udc_gadget_private_data(struct usb_gadget *gadget) return gadget->dev.device_data; } -static struct usb_ep_ops s3c_ep_ops = { - .enable = s3c_ep_enable, - .disable = s3c_ep_disable, +static struct usb_ep_ops dwc2_ep_ops = { + .enable = dwc2_ep_enable, + .disable = dwc2_ep_disable, - .alloc_request = s3c_alloc_request, - .free_request = s3c_free_request, + .alloc_request = dwc2_alloc_request, + .free_request = dwc2_free_request, - .queue = s3c_queue, - .dequeue = s3c_dequeue, + .queue = dwc2_queue, + .dequeue = dwc2_dequeue, - .set_halt = s3c_udc_set_halt, - .fifo_status = s3c_fifo_status, - .fifo_flush = s3c_fifo_flush, + .set_halt = dwc2_udc_set_halt, + .fifo_status = dwc2_fifo_status, + .fifo_flush = dwc2_fifo_flush, }; #define create_proc_files() do {} while (0) @@ -144,24 +145,24 @@ static struct usb_ep_ops s3c_ep_ops = { /***********************************************************/ void __iomem *regs_otg; -struct s3c_usbotg_reg *reg; +struct dwc2_usbotg_reg *reg; bool dfu_usb_get_reset(void) { return !!(readl(®->gintsts) & INT_RESET); } -__weak void otg_phy_init(struct s3c_udc *dev) {} -__weak void otg_phy_off(struct s3c_udc *dev) {} +__weak void otg_phy_init(struct dwc2_udc *dev) {} +__weak void otg_phy_off(struct dwc2_udc *dev) {} /***********************************************************/ -#include "s3c_udc_otg_xfer_dma.c" +#include "dwc2_udc_otg_xfer_dma.c" /* * udc_disable - disable USB device controller */ -static void udc_disable(struct s3c_udc *dev) +static void udc_disable(struct dwc2_udc *dev) { debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); @@ -177,7 +178,7 @@ static void udc_disable(struct s3c_udc *dev) /* * udc_reinit - initialize software state */ -static void udc_reinit(struct s3c_udc *dev) +static void udc_reinit(struct dwc2_udc *dev) { unsigned int i; @@ -189,8 +190,8 @@ static void udc_reinit(struct s3c_udc *dev) dev->ep0state = WAIT_FOR_SETUP; /* basic endpoint records init */ - for (i = 0; i < S3C_MAX_ENDPOINTS; i++) { - struct s3c_ep *ep = &dev->ep[i]; + for (i = 0; i < DWC2_MAX_ENDPOINTS; i++) { + struct dwc2_ep *ep = &dev->ep[i]; if (i != 0) list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); @@ -210,7 +211,7 @@ static void udc_reinit(struct s3c_udc *dev) /* until it's enabled, this UDC should be completely invisible * to any USB host. */ -static int udc_enable(struct s3c_udc *dev) +static int udc_enable(struct dwc2_udc *dev) { debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); @@ -218,7 +219,7 @@ static int udc_enable(struct s3c_udc *dev) reconfig_usbd(dev); debug_cond(DEBUG_SETUP != 0, - "S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n", + "DWC2 USB 2.0 OTG Controller Core Initialized : 0x%x\n", readl(®->gintmsk)); dev->gadget.speed = USB_SPEED_UNKNOWN; @@ -231,7 +232,7 @@ static int udc_enable(struct s3c_udc *dev) */ int usb_gadget_register_driver(struct usb_gadget_driver *driver) { - struct s3c_udc *dev = the_controller; + struct dwc2_udc *dev = the_controller; int retval = 0; unsigned long flags = 0; @@ -280,7 +281,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) */ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { - struct s3c_udc *dev = the_controller; + struct dwc2_udc *dev = the_controller; unsigned long flags = 0; if (!dev) @@ -304,7 +305,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) /* * done - retire a request; caller blocked irqs */ -static void done(struct s3c_ep *ep, struct s3c_request *req, int status) +static void done(struct dwc2_ep *ep, struct dwc2_request *req, int status) { unsigned int stopped = ep->stopped; @@ -355,20 +356,20 @@ static void done(struct s3c_ep *ep, struct s3c_request *req, int status) /* * nuke - dequeue ALL requests */ -static void nuke(struct s3c_ep *ep, int status) +static void nuke(struct dwc2_ep *ep, int status) { - struct s3c_request *req; + struct dwc2_request *req; debug("%s: %s %p\n", __func__, ep->ep.name, ep); /* called with irqs blocked */ while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct s3c_request, queue); + req = list_entry(ep->queue.next, struct dwc2_request, queue); done(ep, req, status); } } -static void stop_activity(struct s3c_udc *dev, +static void stop_activity(struct dwc2_udc *dev, struct usb_gadget_driver *driver) { int i; @@ -379,8 +380,8 @@ static void stop_activity(struct s3c_udc *dev, dev->gadget.speed = USB_SPEED_UNKNOWN; /* prevent new request submissions, kill any outstanding requests */ - for (i = 0; i < S3C_MAX_ENDPOINTS; i++) { - struct s3c_ep *ep = &dev->ep[i]; + for (i = 0; i < DWC2_MAX_ENDPOINTS; i++) { + struct dwc2_ep *ep = &dev->ep[i]; ep->stopped = 1; nuke(ep, -ESHUTDOWN); } @@ -396,7 +397,7 @@ static void stop_activity(struct s3c_udc *dev, udc_reinit(dev); } -static void reconfig_usbd(struct s3c_udc *dev) +static void reconfig_usbd(struct dwc2_udc *dev) { /* 2. Soft-reset OTG Core and then unreset again. */ int i; @@ -447,7 +448,7 @@ static void reconfig_usbd(struct s3c_udc *dev) writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[EP0_CON].doepctl); writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[EP0_CON].diepctl); - for (i = 1; i < S3C_MAX_ENDPOINTS; i++) { + for (i = 1; i < DWC2_MAX_ENDPOINTS; i++) { writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[i].doepctl); writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[i].diepctl); } @@ -469,7 +470,7 @@ static void reconfig_usbd(struct s3c_udc *dev) writel((NPTX_FIFO_SIZE >> 2) << 16 | ((RX_FIFO_SIZE >> 2)) << 0, ®->gnptxfsiz); - for (i = 1; i < S3C_MAX_HW_ENDPOINTS; i++) + for (i = 1; i < DWC2_MAX_HW_ENDPOINTS; i++) writel((PTX_FIFO_SIZE >> 2) << 16 | ((RX_FIFO_SIZE + NPTX_FIFO_SIZE + PTX_FIFO_SIZE*(i-1)) >> 2) << 0, @@ -478,13 +479,13 @@ static void reconfig_usbd(struct s3c_udc *dev) /* Flush the RX FIFO */ writel(RX_FIFO_FLUSH, ®->grstctl); while (readl(®->grstctl) & RX_FIFO_FLUSH) - debug("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__); + debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__); /* Flush all the Tx FIFO's */ writel(TX_FIFO_FLUSH_ALL, ®->grstctl); writel(TX_FIFO_FLUSH_ALL | TX_FIFO_FLUSH, ®->grstctl); while (readl(®->grstctl) & TX_FIFO_FLUSH) - debug("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__); + debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__); /* 13. Clear NAK bit of EP0, EP1, EP2*/ /* For Slave mode*/ @@ -496,7 +497,7 @@ static void reconfig_usbd(struct s3c_udc *dev) writel(GAHBCFG_INIT, ®->gahbcfg); } -static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed) +static void set_max_pktsize(struct dwc2_udc *dev, enum usb_device_speed speed) { unsigned int ep_ctrl; int i; @@ -514,7 +515,7 @@ static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed) } dev->ep[0].ep.maxpacket = ep0_fifo_size; - for (i = 1; i < S3C_MAX_ENDPOINTS; i++) + for (i = 1; i < DWC2_MAX_ENDPOINTS; i++) dev->ep[i].ep.maxpacket = ep_fifo_size; /* EP0 - Control IN (64 bytes)*/ @@ -526,16 +527,16 @@ static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed) writel(ep_ctrl|(0<<0), ®->out_endp[EP0_CON].doepctl); } -static int s3c_ep_enable(struct usb_ep *_ep, +static int dwc2_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { - struct s3c_ep *ep; - struct s3c_udc *dev; + struct dwc2_ep *ep; + struct dwc2_udc *dev; unsigned long flags = 0; debug("%s: %p\n", __func__, _ep); - ep = container_of(_ep, struct s3c_ep, ep); + ep = container_of(_ep, struct dwc2_ep, ep); if (!_ep || !desc || ep->desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || ep->bEndpointAddress != desc->bEndpointAddress @@ -577,11 +578,11 @@ static int s3c_ep_enable(struct usb_ep *_ep, ep->ep.maxpacket = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); /* Reset halt state */ - s3c_udc_set_nak(ep); - s3c_udc_set_halt(_ep, 0); + dwc2_udc_set_nak(ep); + dwc2_udc_set_halt(_ep, 0); spin_lock_irqsave(&ep->dev->lock, flags); - s3c_udc_ep_activate(ep); + dwc2_udc_ep_activate(ep); spin_unlock_irqrestore(&ep->dev->lock, flags); debug("%s: enabled %s, stopped = %d, maxpacket = %d\n", @@ -592,14 +593,14 @@ static int s3c_ep_enable(struct usb_ep *_ep, /* * Disable EP */ -static int s3c_ep_disable(struct usb_ep *_ep) +static int dwc2_ep_disable(struct usb_ep *_ep) { - struct s3c_ep *ep; + struct dwc2_ep *ep; unsigned long flags = 0; debug("%s: %p\n", __func__, _ep); - ep = container_of(_ep, struct s3c_ep, ep); + ep = container_of(_ep, struct dwc2_ep, ep); if (!_ep || !ep->desc) { debug("%s: %s not enabled\n", __func__, _ep ? ep->ep.name : NULL); @@ -620,10 +621,10 @@ static int s3c_ep_disable(struct usb_ep *_ep) return 0; } -static struct usb_request *s3c_alloc_request(struct usb_ep *ep, +static struct usb_request *dwc2_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { - struct s3c_request *req; + struct dwc2_request *req; debug("%s: %s %p\n", __func__, ep->name, ep); @@ -637,27 +638,27 @@ static struct usb_request *s3c_alloc_request(struct usb_ep *ep, return &req->req; } -static void s3c_free_request(struct usb_ep *ep, struct usb_request *_req) +static void dwc2_free_request(struct usb_ep *ep, struct usb_request *_req) { - struct s3c_request *req; + struct dwc2_request *req; debug("%s: %p\n", __func__, ep); - req = container_of(_req, struct s3c_request, req); + req = container_of(_req, struct dwc2_request, req); WARN_ON(!list_empty(&req->queue)); kfree(req); } /* dequeue JUST ONE request */ -static int s3c_dequeue(struct usb_ep *_ep, struct usb_request *_req) +static int dwc2_dequeue(struct usb_ep *_ep, struct usb_request *_req) { - struct s3c_ep *ep; - struct s3c_request *req; + struct dwc2_ep *ep; + struct dwc2_request *req; unsigned long flags = 0; debug("%s: %p\n", __func__, _ep); - ep = container_of(_ep, struct s3c_ep, ep); + ep = container_of(_ep, struct dwc2_ep, ep); if (!_ep || ep->ep.name == ep0name) return -EINVAL; @@ -682,12 +683,12 @@ static int s3c_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* * Return bytes in EP FIFO */ -static int s3c_fifo_status(struct usb_ep *_ep) +static int dwc2_fifo_status(struct usb_ep *_ep) { int count = 0; - struct s3c_ep *ep; + struct dwc2_ep *ep; - ep = container_of(_ep, struct s3c_ep, ep); + ep = container_of(_ep, struct dwc2_ep, ep); if (!_ep) { debug("%s: bad ep\n", __func__); return -ENODEV; @@ -705,11 +706,11 @@ static int s3c_fifo_status(struct usb_ep *_ep) /* * Flush EP FIFO */ -static void s3c_fifo_flush(struct usb_ep *_ep) +static void dwc2_fifo_flush(struct usb_ep *_ep) { - struct s3c_ep *ep; + struct dwc2_ep *ep; - ep = container_of(_ep, struct s3c_ep, ep); + ep = container_of(_ep, struct dwc2_ep, ep); if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { debug("%s: bad ep\n", __func__); return; @@ -718,14 +719,14 @@ static void s3c_fifo_flush(struct usb_ep *_ep) debug("%s: %d\n", __func__, ep_index(ep)); } -static const struct usb_gadget_ops s3c_udc_ops = { +static const struct usb_gadget_ops dwc2_udc_ops = { /* current versions must always be self-powered */ }; -static struct s3c_udc memory = { +static struct dwc2_udc memory = { .usb_address = 0, .gadget = { - .ops = &s3c_udc_ops, + .ops = &dwc2_udc_ops, .ep0 = &memory.ep[0].ep, .name = driver_name, }, @@ -734,7 +735,7 @@ static struct s3c_udc memory = { .ep[0] = { .ep = { .name = ep0name, - .ops = &s3c_ep_ops, + .ops = &dwc2_ep_ops, .maxpacket = EP0_FIFO_SIZE, }, .dev = &memory, @@ -749,7 +750,7 @@ static struct s3c_udc memory = { .ep[1] = { .ep = { .name = "ep1in-bulk", - .ops = &s3c_ep_ops, + .ops = &dwc2_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, @@ -764,7 +765,7 @@ static struct s3c_udc memory = { .ep[2] = { .ep = { .name = "ep2out-bulk", - .ops = &s3c_ep_ops, + .ops = &dwc2_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, @@ -779,7 +780,7 @@ static struct s3c_udc memory = { .ep[3] = { .ep = { .name = "ep3in-int", - .ops = &s3c_ep_ops, + .ops = &dwc2_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, @@ -796,16 +797,16 @@ static struct s3c_udc memory = { * probe - binds to the platform device */ -int s3c_udc_probe(struct s3c_plat_otg_data *pdata) +int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata) { - struct s3c_udc *dev = &memory; + struct dwc2_udc *dev = &memory; int retval = 0; debug("%s: %p\n", __func__, pdata); dev->pdata = pdata; - reg = (struct s3c_usbotg_reg *)pdata->regs_otg; + reg = (struct dwc2_usbotg_reg *)pdata->regs_otg; /* regs_otg = (void *)pdata->regs_otg; */ @@ -839,6 +840,6 @@ int usb_gadget_handle_interrupts(int index) u32 gintmsk = readl(®->gintmsk); if (intr_status & gintmsk) - return s3c_udc_irq(1, (void *)the_controller); + return dwc2_udc_irq(1, (void *)the_controller); return 0; } diff --git a/drivers/usb/gadget/s3c_udc_otg_phy.c b/drivers/usb/gadget/dwc2_udc_otg_phy.c index f13cb89..e0cbbc0 100644 --- a/drivers/usb/gadget/s3c_udc_otg_phy.c +++ b/drivers/usb/gadget/dwc2_udc_otg_phy.c @@ -1,6 +1,6 @@ /* - * drivers/usb/gadget/s3c_udc_otg.c - * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers + * drivers/usb/gadget/dwc2_udc_otg.c + * Designware DWC2 on-chip full/high speed USB OTG 2.0 device controllers * * Copyright (C) 2008 for Samsung Electronics * @@ -32,16 +32,17 @@ #include <asm/mach-types.h> -#include "regs-otg.h" +#include "dwc2_udc_otg_regs.h" +#include "dwc2_udc_otg_priv.h" #include <usb/lin_gadget_compat.h> -#include <usb/s3c_udc.h> +#include <usb/dwc2_udc.h> -void otg_phy_init(struct s3c_udc *dev) +void otg_phy_init(struct dwc2_udc *dev) { unsigned int usb_phy_ctrl = dev->pdata->usb_phy_ctrl; - struct s3c_usbotg_phy *phy = - (struct s3c_usbotg_phy *)dev->pdata->regs_phy; + struct dwc2_usbotg_phy *phy = + (struct dwc2_usbotg_phy *)dev->pdata->regs_phy; dev->pdata->phy_control(1); @@ -75,11 +76,11 @@ void otg_phy_init(struct s3c_udc *dev) udelay(10); } -void otg_phy_off(struct s3c_udc *dev) +void otg_phy_off(struct dwc2_udc *dev) { unsigned int usb_phy_ctrl = dev->pdata->usb_phy_ctrl; - struct s3c_usbotg_phy *phy = - (struct s3c_usbotg_phy *)dev->pdata->regs_phy; + struct dwc2_usbotg_phy *phy = + (struct dwc2_usbotg_phy *)dev->pdata->regs_phy; /* reset controller just in case */ writel(PHY_SW_RST0, &phy->rstcon); diff --git a/drivers/usb/gadget/dwc2_udc_otg_priv.h b/drivers/usb/gadget/dwc2_udc_otg_priv.h new file mode 100644 index 0000000..b2c1fc4 --- /dev/null +++ b/drivers/usb/gadget/dwc2_udc_otg_priv.h @@ -0,0 +1,98 @@ +/* + * Designware DWC2 on-chip full/high speed USB device controllers + * Copyright (C) 2005 for Samsung Electronics + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __DWC2_UDC_OTG_PRIV__ +#define __DWC2_UDC_OTG_PRIV__ + +#include <asm/errno.h> +#include <linux/sizes.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/list.h> +#include <usb/lin_gadget_compat.h> +#include <usb/dwc2_udc.h> + +/*-------------------------------------------------------------------------*/ +/* DMA bounce buffer size, 16K is enough even for mass storage */ +#define DMA_BUFFER_SIZE (16*SZ_1K) + +#define EP0_FIFO_SIZE 64 +#define EP_FIFO_SIZE 512 +#define EP_FIFO_SIZE2 1024 +/* ep0-control, ep1in-bulk, ep2out-bulk, ep3in-int */ +#define DWC2_MAX_ENDPOINTS 4 +#define DWC2_MAX_HW_ENDPOINTS 16 + +#define WAIT_FOR_SETUP 0 +#define DATA_STATE_XMIT 1 +#define DATA_STATE_NEED_ZLP 2 +#define WAIT_FOR_OUT_STATUS 3 +#define DATA_STATE_RECV 4 +#define WAIT_FOR_COMPLETE 5 +#define WAIT_FOR_OUT_COMPLETE 6 +#define WAIT_FOR_IN_COMPLETE 7 +#define WAIT_FOR_NULL_COMPLETE 8 + +#define TEST_J_SEL 0x1 +#define TEST_K_SEL 0x2 +#define TEST_SE0_NAK_SEL 0x3 +#define TEST_PACKET_SEL 0x4 +#define TEST_FORCE_ENABLE_SEL 0x5 + +/* ************************************************************************* */ +/* IO + */ + +enum ep_type { + ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt +}; + +struct dwc2_ep { + struct usb_ep ep; + struct dwc2_udc *dev; + + const struct usb_endpoint_descriptor *desc; + struct list_head queue; + unsigned long pio_irqs; + int len; + void *dma_buf; + + u8 stopped; + u8 bEndpointAddress; + u8 bmAttributes; + + enum ep_type ep_type; + int fifo_num; +}; + +struct dwc2_request { + struct usb_request req; + struct list_head queue; +}; + +struct dwc2_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + + struct dwc2_plat_otg_data *pdata; + + int ep0state; + struct dwc2_ep ep[DWC2_MAX_ENDPOINTS]; + + unsigned char usb_address; + + unsigned req_pending:1, req_std:1; +}; + +#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN) == USB_DIR_IN) +#define ep_index(EP) ((EP)->bEndpointAddress&0xF) +#define ep_maxpacket(EP) ((EP)->ep.maxpacket) + +void otg_phy_init(struct dwc2_udc *dev); +void otg_phy_off(struct dwc2_udc *dev); + +#endif /* __DWC2_UDC_OTG_PRIV__ */ diff --git a/drivers/usb/gadget/regs-otg.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index ac5d112..78ec90e 100644 --- a/drivers/usb/gadget/regs-otg.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -12,14 +12,14 @@ #define __ASM_ARCH_REGS_USB_OTG_HS_H /* USB2.0 OTG Controller register */ -struct s3c_usbotg_phy { +struct dwc2_usbotg_phy { u32 phypwr; u32 phyclk; u32 rstcon; }; /* Device Logical IN Endpoint-Specific Registers */ -struct s3c_dev_in_endp { +struct dwc2_dev_in_endp { u32 diepctl; u8 res1[4]; u32 diepint; @@ -31,7 +31,7 @@ struct s3c_dev_in_endp { }; /* Device Logical OUT Endpoint-Specific Registers */ -struct s3c_dev_out_endp { +struct dwc2_dev_out_endp { u32 doepctl; u8 res1[4]; u32 doepint; @@ -48,7 +48,7 @@ struct ep_fifo { }; /* USB2.0 OTG Controller register */ -struct s3c_usbotg_reg { +struct dwc2_usbotg_reg { /* Core Global Registers */ u32 gotgctl; /* OTG Control & Status */ u32 gotgint; /* OTG Interrupt */ @@ -74,8 +74,8 @@ struct s3c_usbotg_reg { u32 daint; /* Device All Endpoints Interrupt */ u32 daintmsk; /* Device All Endpoints Interrupt Mask */ u8 res4[224]; - struct s3c_dev_in_endp in_endp[16]; - struct s3c_dev_out_endp out_endp[16]; + struct dwc2_dev_in_endp in_endp[16]; + struct dwc2_dev_out_endp out_endp[16]; u8 res5[768]; struct ep_fifo ep[16]; }; @@ -83,11 +83,11 @@ struct s3c_usbotg_reg { /*===================================================================== */ /*definitions related to CSR setting */ -/* S3C_UDC_OTG_GOTGCTL */ +/* DWC2_UDC_OTG_GOTGCTL */ #define B_SESSION_VALID (0x1<<19) #define A_SESSION_VALID (0x1<<18) -/* S3C_UDC_OTG_GAHBCFG */ +/* DWC2_UDC_OTG_GAHBCFG */ #define PTXFE_HALF (0<<8) #define PTXFE_ZERO (1<<8) #define NPTXFE_HALF (0<<7) @@ -102,11 +102,11 @@ struct s3c_usbotg_reg { #define GBL_INT_UNMASK (1<<0) #define GBL_INT_MASK (0<<0) -/* S3C_UDC_OTG_GRSTCTL */ +/* DWC2_UDC_OTG_GRSTCTL */ #define AHB_MASTER_IDLE (1u<<31) #define CORE_SOFT_RESET (0x1<<0) -/* S3C_UDC_OTG_GINTSTS/S3C_UDC_OTG_GINTMSK core interrupt register */ +/* DWC2_UDC_OTG_GINTSTS/DWC2_UDC_OTG_GINTMSK core interrupt register */ #define INT_RESUME (1u<<31) #define INT_DISCONN (0x1<<29) #define INT_CONN_ID_STS_CNG (0x1<<28) @@ -146,22 +146,22 @@ struct s3c_usbotg_reg { #define USB_LOW_6MHZ (0x2<<1) #define USB_FULL_48MHZ (0x3<<1) -/* S3C_UDC_OTG_GRXSTSP STATUS */ +/* DWC2_UDC_OTG_GRXSTSP STATUS */ #define OUT_PKT_RECEIVED (0x2<<17) #define OUT_TRANSFER_COMPLELTED (0x3<<17) #define SETUP_TRANSACTION_COMPLETED (0x4<<17) #define SETUP_PKT_RECEIVED (0x6<<17) #define GLOBAL_OUT_NAK (0x1<<17) -/* S3C_UDC_OTG_DCTL device control register */ +/* DWC2_UDC_OTG_DCTL device control register */ #define NORMAL_OPERATION (0x1<<0) #define SOFT_DISCONNECT (0x1<<1) -/* S3C_UDC_OTG_DAINT device all endpoint interrupt register */ +/* DWC2_UDC_OTG_DAINT device all endpoint interrupt register */ #define DAINT_OUT_BIT (16) #define DAINT_MASK (0xFFFF) -/* S3C_UDC_OTG_DIEPCTL0/DOEPCTL0 device +/* DWC2_UDC_OTG_DIEPCTL0/DOEPCTL0 device control IN/OUT endpoint 0 control register */ #define DEPCTL_EPENA (0x1<<31) #define DEPCTL_EPDIS (0x1<<30) @@ -191,9 +191,9 @@ struct s3c_usbotg_reg { #define DIEPCTL0_NEXT_EP_BIT (11) -/* S3C_UDC_OTG_DIEPMSK/DOEPMSK device IN/OUT endpoint +/* DWC2_UDC_OTG_DIEPMSK/DOEPMSK device IN/OUT endpoint common interrupt mask register */ -/* S3C_UDC_OTG_DIEPINTn/DOEPINTn device IN/OUT endpoint interrupt register */ +/* DWC2_UDC_OTG_DIEPINTn/DOEPINTn device IN/OUT endpoint interrupt register */ #define BACK2BACK_SETUP_RECEIVED (0x1<<6) #define INTKNEPMIS (0x1<<5) #define INTKN_TXFEMP (0x1<<4) diff --git a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index 7e7a2c2..bce9c30 100644 --- a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -1,6 +1,6 @@ /* - * drivers/usb/gadget/s3c_udc_otg_xfer_dma.c - * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers + * drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c + * Designware DWC2 on-chip full/high speed USB OTG 2.0 device controllers * * Copyright (C) 2009 for Samsung Electronics * @@ -25,7 +25,7 @@ int clear_feature_flag; #define GET_MAX_LUN_REQUEST 0xFE #define BOT_RESET_REQUEST 0xFF -static inline void s3c_udc_ep0_zlp(struct s3c_udc *dev) +static inline void dwc2_udc_ep0_zlp(struct dwc2_udc *dev) { u32 ep_ctrl; @@ -41,7 +41,7 @@ static inline void s3c_udc_ep0_zlp(struct s3c_udc *dev) dev->ep0state = WAIT_FOR_IN_COMPLETE; } -void s3c_udc_pre_setup(void) +static void dwc2_udc_pre_setup(void) { u32 ep_ctrl; @@ -62,7 +62,7 @@ void s3c_udc_pre_setup(void) } -static inline void s3c_ep0_complete_out(void) +static inline void dwc2_ep0_complete_out(void) { u32 ep_ctrl; @@ -90,7 +90,7 @@ static inline void s3c_ep0_complete_out(void) } -static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req) +static int setdma_rx(struct dwc2_ep *ep, struct dwc2_request *req) { u32 *buf, ctrl; u32 length, pktcnt; @@ -128,7 +128,7 @@ static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req) } -int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) +static int setdma_tx(struct dwc2_ep *ep, struct dwc2_request *req) { u32 *buf, ctrl = 0; u32 length, pktcnt; @@ -186,10 +186,10 @@ int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) return length; } -static void complete_rx(struct s3c_udc *dev, u8 ep_num) +static void complete_rx(struct dwc2_udc *dev, u8 ep_num) { - struct s3c_ep *ep = &dev->ep[ep_num]; - struct s3c_request *req = NULL; + struct dwc2_ep *ep = &dev->ep[ep_num]; + struct dwc2_request *req = NULL; u32 ep_tsr = 0, xfer_size = 0, is_short = 0; if (list_empty(&ep->queue)) { @@ -200,7 +200,7 @@ static void complete_rx(struct s3c_udc *dev, u8 ep_num) } - req = list_entry(ep->queue.next, struct s3c_request, queue); + req = list_entry(ep->queue.next, struct dwc2_request, queue); ep_tsr = readl(®->out_endp[ep_num].doeptsiz); if (ep_num == EP0_CON) @@ -240,7 +240,7 @@ static void complete_rx(struct s3c_udc *dev, u8 ep_num) if (is_short || req->req.actual == req->req.length) { if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) { debug_cond(DEBUG_OUT_EP != 0, " => Send ZLP\n"); - s3c_udc_ep0_zlp(dev); + dwc2_udc_ep0_zlp(dev); /* packet will be completed in complete_tx() */ dev->ep0state = WAIT_FOR_IN_COMPLETE; } else { @@ -248,7 +248,7 @@ static void complete_rx(struct s3c_udc *dev, u8 ep_num) if (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, - struct s3c_request, queue); + struct dwc2_request, queue); debug_cond(DEBUG_OUT_EP != 0, "%s: Next Rx request start...\n", __func__); @@ -259,16 +259,16 @@ static void complete_rx(struct s3c_udc *dev, u8 ep_num) setdma_rx(ep, req); } -static void complete_tx(struct s3c_udc *dev, u8 ep_num) +static void complete_tx(struct dwc2_udc *dev, u8 ep_num) { - struct s3c_ep *ep = &dev->ep[ep_num]; - struct s3c_request *req; + struct dwc2_ep *ep = &dev->ep[ep_num]; + struct dwc2_request *req; u32 ep_tsr = 0, xfer_size = 0, is_short = 0; u32 last; if (dev->ep0state == WAIT_FOR_NULL_COMPLETE) { dev->ep0state = WAIT_FOR_OUT_COMPLETE; - s3c_ep0_complete_out(); + dwc2_ep0_complete_out(); return; } @@ -280,7 +280,7 @@ static void complete_tx(struct s3c_udc *dev, u8 ep_num) } - req = list_entry(ep->queue.next, struct s3c_request, queue); + req = list_entry(ep->queue.next, struct dwc2_request, queue); ep_tsr = readl(®->in_endp[ep_num].dieptsiz); @@ -315,7 +315,7 @@ static void complete_tx(struct s3c_udc *dev, u8 ep_num) __func__, ep_num); done(ep, req, 0); dev->ep0state = WAIT_FOR_OUT_COMPLETE; - s3c_ep0_complete_out(); + dwc2_ep0_complete_out(); } else { debug_cond(DEBUG_IN_EP, "%s: ep_num = %d, invalid ep state\n", @@ -328,23 +328,23 @@ static void complete_tx(struct s3c_udc *dev, u8 ep_num) done(ep, req, 0); if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct s3c_request, queue); + req = list_entry(ep->queue.next, struct dwc2_request, queue); debug_cond(DEBUG_IN_EP, "%s: Next Tx request start...\n", __func__); setdma_tx(ep, req); } } -static inline void s3c_udc_check_tx_queue(struct s3c_udc *dev, u8 ep_num) +static inline void dwc2_udc_check_tx_queue(struct dwc2_udc *dev, u8 ep_num) { - struct s3c_ep *ep = &dev->ep[ep_num]; - struct s3c_request *req; + struct dwc2_ep *ep = &dev->ep[ep_num]; + struct dwc2_request *req; debug_cond(DEBUG_IN_EP, "%s: Check queue, ep_num = %d\n", __func__, ep_num); if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct s3c_request, queue); + req = list_entry(ep->queue.next, struct dwc2_request, queue); debug_cond(DEBUG_IN_EP, "%s: Next Tx request(0x%p) start...\n", __func__, req); @@ -362,7 +362,7 @@ static inline void s3c_udc_check_tx_queue(struct s3c_udc *dev, u8 ep_num) } -static void process_ep_in_intr(struct s3c_udc *dev) +static void process_ep_in_intr(struct dwc2_udc *dev) { u32 ep_intr, ep_intr_status; u8 ep_num = 0; @@ -392,12 +392,12 @@ static void process_ep_in_intr(struct s3c_udc *dev) dev->ep0state = WAIT_FOR_SETUP; if (dev->ep0state == WAIT_FOR_SETUP) - s3c_udc_pre_setup(); + dwc2_udc_pre_setup(); /* continue transfer after set_clear_halt for DMA mode */ if (clear_feature_flag == 1) { - s3c_udc_check_tx_queue(dev, + dwc2_udc_check_tx_queue(dev, clear_feature_num); clear_feature_flag = 0; } @@ -409,7 +409,7 @@ static void process_ep_in_intr(struct s3c_udc *dev) } } -static void process_ep_out_intr(struct s3c_udc *dev) +static void process_ep_out_intr(struct dwc2_udc *dev) { u32 ep_intr, ep_intr_status; u8 ep_num = 0; @@ -438,7 +438,7 @@ static void process_ep_out_intr(struct s3c_udc *dev) complete_rx(dev, ep_num); else { dev->ep0state = WAIT_FOR_SETUP; - s3c_udc_pre_setup(); + dwc2_udc_pre_setup(); } } @@ -446,7 +446,7 @@ static void process_ep_out_intr(struct s3c_udc *dev) CTRL_OUT_EP_SETUP_PHASE_DONE) { debug_cond(DEBUG_OUT_EP != 0, "SETUP packet arrived\n"); - s3c_handle_ep0(dev); + dwc2_handle_ep0(dev); } } else { if (ep_intr_status & TRANSFER_DONE) @@ -461,9 +461,9 @@ static void process_ep_out_intr(struct s3c_udc *dev) /* * usb client interrupt handler. */ -static int s3c_udc_irq(int irq, void *_dev) +static int dwc2_udc_irq(int irq, void *_dev) { - struct s3c_udc *dev = _dev; + struct dwc2_udc *dev = _dev; u32 intr_status; u32 usb_status, gintmsk; unsigned long flags = 0; @@ -554,7 +554,7 @@ static int s3c_udc_irq(int irq, void *_dev) reconfig_usbd(dev); dev->ep0state = WAIT_FOR_SETUP; reset_available = 0; - s3c_udc_pre_setup(); + dwc2_udc_pre_setup(); } else reset_available = 1; @@ -579,16 +579,16 @@ static int s3c_udc_irq(int irq, void *_dev) /** Queue one request * Kickstart transfer if needed */ -static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req, +static int dwc2_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { - struct s3c_request *req; - struct s3c_ep *ep; - struct s3c_udc *dev; + struct dwc2_request *req; + struct dwc2_ep *ep; + struct dwc2_udc *dev; unsigned long flags = 0; u32 ep_num, gintsts; - req = container_of(_req, struct s3c_request, req); + req = container_of(_req, struct dwc2_request, req); if (unlikely(!_req || !_req->complete || !_req->buf || !list_empty(&req->queue))) { @@ -596,7 +596,7 @@ static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req, return -EINVAL; } - ep = container_of(_ep, struct s3c_ep, ep); + ep = container_of(_ep, struct dwc2_ep, ep); if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { @@ -646,20 +646,20 @@ static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req, if (ep_num == 0) { /* EP0 */ list_add_tail(&req->queue, &ep->queue); - s3c_ep0_kick(dev, ep); + dwc2_ep0_kick(dev, ep); req = 0; } else if (ep_is_in(ep)) { gintsts = readl(®->gintsts); debug_cond(DEBUG_IN_EP, - "%s: ep_is_in, S3C_UDC_OTG_GINTSTS=0x%x\n", + "%s: ep_is_in, DWC2_UDC_OTG_GINTSTS=0x%x\n", __func__, gintsts); setdma_tx(ep, req); } else { gintsts = readl(®->gintsts); debug_cond(DEBUG_OUT_EP != 0, - "%s:ep_is_out, S3C_UDC_OTG_GINTSTS=0x%x\n", + "%s:ep_is_out, DWC2_UDC_OTG_GINTSTS=0x%x\n", __func__, gintsts); setdma_rx(ep, req); @@ -680,7 +680,7 @@ static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req, /****************************************************************/ /* return: 0 = still running, 1 = completed, negative = errno */ -static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req) +static int write_fifo_ep0(struct dwc2_ep *ep, struct dwc2_request *req) { u32 max; unsigned count; @@ -718,7 +718,7 @@ static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req) return 0; } -int s3c_fifo_read(struct s3c_ep *ep, u32 *cp, int max) +static int dwc2_fifo_read(struct dwc2_ep *ep, u32 *cp, int max) { invalidate_dcache_range((unsigned long)cp, (unsigned long)cp + ROUND(max, CONFIG_SYS_CACHELINE_SIZE)); @@ -737,12 +737,12 @@ int s3c_fifo_read(struct s3c_ep *ep, u32 *cp, int max) * Called from control endpoint function * after it decodes a set address setup packet. */ -static void udc_set_address(struct s3c_udc *dev, unsigned char address) +static void udc_set_address(struct dwc2_udc *dev, unsigned char address) { u32 ctrl = readl(®->dcfg); writel(DEVICE_ADDRESS(address) | ctrl, ®->dcfg); - s3c_udc_ep0_zlp(dev); + dwc2_udc_ep0_zlp(dev); debug_cond(DEBUG_EP0 != 0, "%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n", @@ -751,9 +751,9 @@ static void udc_set_address(struct s3c_udc *dev, unsigned char address) dev->usb_address = address; } -static inline void s3c_udc_ep0_set_stall(struct s3c_ep *ep) +static inline void dwc2_udc_ep0_set_stall(struct dwc2_ep *ep) { - struct s3c_udc *dev; + struct dwc2_udc *dev; u32 ep_ctrl = 0; dev = ep->dev; @@ -776,16 +776,16 @@ static inline void s3c_udc_ep0_set_stall(struct s3c_ep *ep) */ dev->ep0state = WAIT_FOR_SETUP; - s3c_udc_pre_setup(); + dwc2_udc_pre_setup(); } -static void s3c_ep0_read(struct s3c_udc *dev) +static void dwc2_ep0_read(struct dwc2_udc *dev) { - struct s3c_request *req; - struct s3c_ep *ep = &dev->ep[0]; + struct dwc2_request *req; + struct dwc2_ep *ep = &dev->ep[0]; if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct s3c_request, queue); + req = list_entry(ep->queue.next, struct dwc2_request, queue); } else { debug("%s: ---> BUG\n", __func__); @@ -802,7 +802,7 @@ static void s3c_ep0_read(struct s3c_udc *dev) * or Bulk-Only mass storge reset */ ep->len = 0; - s3c_udc_ep0_zlp(dev); + dwc2_udc_ep0_zlp(dev); debug_cond(DEBUG_EP0 != 0, "%s: req.length = 0, bRequest = %d\n", @@ -816,16 +816,16 @@ static void s3c_ep0_read(struct s3c_udc *dev) /* * DATA_STATE_XMIT */ -static int s3c_ep0_write(struct s3c_udc *dev) +static int dwc2_ep0_write(struct dwc2_udc *dev) { - struct s3c_request *req; - struct s3c_ep *ep = &dev->ep[0]; + struct dwc2_request *req; + struct dwc2_ep *ep = &dev->ep[0]; int ret, need_zlp = 0; if (list_empty(&ep->queue)) req = 0; else - req = list_entry(ep->queue.next, struct s3c_request, queue); + req = list_entry(ep->queue.next, struct dwc2_request, queue); if (!req) { debug_cond(DEBUG_EP0 != 0, "%s: NULL REQ\n", __func__); @@ -859,7 +859,7 @@ static int s3c_ep0_write(struct s3c_udc *dev) return 1; } -int s3c_udc_get_status(struct s3c_udc *dev, +static int dwc2_udc_get_status(struct dwc2_udc *dev, struct usb_ctrlrequest *crq) { u8 ep_num = crq->wIndex & 0x7F; @@ -920,7 +920,7 @@ int s3c_udc_get_status(struct s3c_udc *dev, return 0; } -static void s3c_udc_set_nak(struct s3c_ep *ep) +static void dwc2_udc_set_nak(struct dwc2_ep *ep) { u8 ep_num; u32 ep_ctrl = 0; @@ -946,7 +946,7 @@ static void s3c_udc_set_nak(struct s3c_ep *ep) } -void s3c_udc_ep_set_stall(struct s3c_ep *ep) +static void dwc2_udc_ep_set_stall(struct dwc2_ep *ep) { u8 ep_num; u32 ep_ctrl = 0; @@ -981,7 +981,7 @@ void s3c_udc_ep_set_stall(struct s3c_ep *ep) return; } -void s3c_udc_ep_clear_stall(struct s3c_ep *ep) +static void dwc2_udc_ep_clear_stall(struct dwc2_ep *ep) { u8 ep_num; u32 ep_ctrl = 0; @@ -1029,14 +1029,14 @@ void s3c_udc_ep_clear_stall(struct s3c_ep *ep) return; } -static int s3c_udc_set_halt(struct usb_ep *_ep, int value) +static int dwc2_udc_set_halt(struct usb_ep *_ep, int value) { - struct s3c_ep *ep; - struct s3c_udc *dev; + struct dwc2_ep *ep; + struct dwc2_udc *dev; unsigned long flags = 0; u8 ep_num; - ep = container_of(_ep, struct s3c_ep, ep); + ep = container_of(_ep, struct dwc2_ep, ep); ep_num = ep_index(ep); if (unlikely(!_ep || !ep->desc || ep_num == EP0_CON || @@ -1050,7 +1050,7 @@ static int s3c_udc_set_halt(struct usb_ep *_ep, int value) if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { debug("%s: %s queue not empty, req = %p\n", __func__, ep->ep.name, - list_entry(ep->queue.next, struct s3c_request, queue)); + list_entry(ep->queue.next, struct dwc2_request, queue)); return -EAGAIN; } @@ -1062,13 +1062,13 @@ static int s3c_udc_set_halt(struct usb_ep *_ep, int value) if (value == 0) { ep->stopped = 0; - s3c_udc_ep_clear_stall(ep); + dwc2_udc_ep_clear_stall(ep); } else { if (ep_num == 0) dev->ep0state = WAIT_FOR_SETUP; ep->stopped = 1; - s3c_udc_ep_set_stall(ep); + dwc2_udc_ep_set_stall(ep); } spin_unlock_irqrestore(&dev->lock, flags); @@ -1076,7 +1076,7 @@ static int s3c_udc_set_halt(struct usb_ep *_ep, int value) return 0; } -void s3c_udc_ep_activate(struct s3c_ep *ep) +static void dwc2_udc_ep_activate(struct dwc2_ep *ep) { u8 ep_num; u32 ep_ctrl = 0, daintmsk = 0; @@ -1123,13 +1123,13 @@ void s3c_udc_ep_activate(struct s3c_ep *ep) } -static int s3c_udc_clear_feature(struct usb_ep *_ep) +static int dwc2_udc_clear_feature(struct usb_ep *_ep) { - struct s3c_udc *dev; - struct s3c_ep *ep; + struct dwc2_udc *dev; + struct dwc2_ep *ep; u8 ep_num; - ep = container_of(_ep, struct s3c_ep, ep); + ep = container_of(_ep, struct dwc2_ep, ep); ep_num = ep_index(ep); dev = ep->dev; @@ -1158,7 +1158,7 @@ static int s3c_udc_clear_feature(struct usb_ep *_ep) break; } - s3c_udc_ep0_zlp(dev); + dwc2_udc_ep0_zlp(dev); break; case USB_RECIP_ENDPOINT: @@ -1168,14 +1168,14 @@ static int s3c_udc_clear_feature(struct usb_ep *_ep) if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { if (ep_num == 0) { - s3c_udc_ep0_set_stall(ep); + dwc2_udc_ep0_set_stall(ep); return 0; } - s3c_udc_ep0_zlp(dev); + dwc2_udc_ep0_zlp(dev); - s3c_udc_ep_clear_stall(ep); - s3c_udc_ep_activate(ep); + dwc2_udc_ep_clear_stall(ep); + dwc2_udc_ep_activate(ep); ep->stopped = 0; clear_feature_num = ep_num; @@ -1187,13 +1187,13 @@ static int s3c_udc_clear_feature(struct usb_ep *_ep) return 0; } -static int s3c_udc_set_feature(struct usb_ep *_ep) +static int dwc2_udc_set_feature(struct usb_ep *_ep) { - struct s3c_udc *dev; - struct s3c_ep *ep; + struct dwc2_udc *dev; + struct dwc2_ep *ep; u8 ep_num; - ep = container_of(_ep, struct s3c_ep, ep); + ep = container_of(_ep, struct dwc2_ep, ep); ep_num = ep_index(ep); dev = ep->dev; @@ -1232,7 +1232,7 @@ static int s3c_udc_set_feature(struct usb_ep *_ep) break; } - s3c_udc_ep0_zlp(dev); + dwc2_udc_ep0_zlp(dev); return 0; case USB_RECIP_INTERFACE: @@ -1245,14 +1245,14 @@ static int s3c_udc_set_feature(struct usb_ep *_ep) "\tSET_FEATURE: USB_RECIP_ENDPOINT\n"); if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { if (ep_num == 0) { - s3c_udc_ep0_set_stall(ep); + dwc2_udc_ep0_set_stall(ep); return 0; } ep->stopped = 1; - s3c_udc_ep_set_stall(ep); + dwc2_udc_ep_set_stall(ep); } - s3c_udc_ep0_zlp(dev); + dwc2_udc_ep0_zlp(dev); return 0; } @@ -1262,9 +1262,9 @@ static int s3c_udc_set_feature(struct usb_ep *_ep) /* * WAIT_FOR_SETUP (OUT_PKT_RDY) */ -void s3c_ep0_setup(struct s3c_udc *dev) +static void dwc2_ep0_setup(struct dwc2_udc *dev) { - struct s3c_ep *ep = &dev->ep[0]; + struct dwc2_ep *ep = &dev->ep[0]; int i; u8 ep_num; @@ -1272,7 +1272,7 @@ void s3c_ep0_setup(struct s3c_udc *dev) nuke(ep, -EPROTO); /* read control req from fifo (8 bytes) */ - s3c_fifo_read(ep, (u32 *)usb_ctrl, 8); + dwc2_fifo_read(ep, (u32 *)usb_ctrl, 8); debug_cond(DEBUG_SETUP != 0, "%s: bRequestType = 0x%x(%s), bRequest = 0x%x" @@ -1306,7 +1306,7 @@ void s3c_ep0_setup(struct s3c_udc *dev) "wLength = %d, setup returned\n", usb_ctrl->wLength); - s3c_udc_ep0_set_stall(ep); + dwc2_udc_ep0_set_stall(ep); dev->ep0state = WAIT_FOR_SETUP; return; @@ -1317,7 +1317,7 @@ void s3c_ep0_setup(struct s3c_udc *dev) "%s:BOT Rest:invalid wLength =%d, setup returned\n", __func__, usb_ctrl->wLength); - s3c_udc_ep0_set_stall(ep); + dwc2_udc_ep0_set_stall(ep); dev->ep0state = WAIT_FOR_SETUP; return; @@ -1384,7 +1384,7 @@ void s3c_ep0_setup(struct s3c_udc *dev) break; case USB_REQ_GET_STATUS: - if (!s3c_udc_get_status(dev, usb_ctrl)) + if (!dwc2_udc_get_status(dev, usb_ctrl)) return; break; @@ -1392,7 +1392,7 @@ void s3c_ep0_setup(struct s3c_udc *dev) case USB_REQ_CLEAR_FEATURE: ep_num = usb_ctrl->wIndex & 0x7f; - if (!s3c_udc_clear_feature(&dev->ep[ep_num].ep)) + if (!dwc2_udc_clear_feature(&dev->ep[ep_num].ep)) return; break; @@ -1400,7 +1400,7 @@ void s3c_ep0_setup(struct s3c_udc *dev) case USB_REQ_SET_FEATURE: ep_num = usb_ctrl->wIndex & 0x7f; - if (!s3c_udc_set_feature(&dev->ep[ep_num].ep)) + if (!dwc2_udc_set_feature(&dev->ep[ep_num].ep)) return; break; @@ -1427,7 +1427,7 @@ void s3c_ep0_setup(struct s3c_udc *dev) if (i < 0) { /* setup processing failed, force stall */ - s3c_udc_ep0_set_stall(ep); + dwc2_udc_ep0_set_stall(ep); dev->ep0state = WAIT_FOR_SETUP; debug_cond(DEBUG_SETUP != 0, @@ -1451,12 +1451,12 @@ void s3c_ep0_setup(struct s3c_udc *dev) /* * handle ep0 interrupt */ -static void s3c_handle_ep0(struct s3c_udc *dev) +static void dwc2_handle_ep0(struct dwc2_udc *dev) { if (dev->ep0state == WAIT_FOR_SETUP) { debug_cond(DEBUG_OUT_EP != 0, "%s: WAIT_FOR_SETUP\n", __func__); - s3c_ep0_setup(dev); + dwc2_ep0_setup(dev); } else { debug_cond(DEBUG_OUT_EP != 0, @@ -1465,16 +1465,16 @@ static void s3c_handle_ep0(struct s3c_udc *dev) } } -static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep) +static void dwc2_ep0_kick(struct dwc2_udc *dev, struct dwc2_ep *ep) { debug_cond(DEBUG_EP0 != 0, "%s: ep_is_in = %d\n", __func__, ep_is_in(ep)); if (ep_is_in(ep)) { dev->ep0state = DATA_STATE_XMIT; - s3c_ep0_write(dev); + dwc2_ep0_write(dev); } else { dev->ep0state = DATA_STATE_RECV; - s3c_ep0_read(dev); + dwc2_ep0_read(dev); } } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 2a2bffe..39f7185 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -26,6 +26,14 @@ config USB_XHCI_UNIPHIER endif +config USB_OHCI_GENERIC + bool "Support for generic OHCI USB controller" + depends on OF_CONTROL + depends on DM_USB + default n + ---help--- + Enables support for generic OHCI controller. + config USB_EHCI_HCD bool "EHCI HCD (USB 2.0) support" ---help--- @@ -73,4 +81,12 @@ config USB_EHCI_UNIPHIER ---help--- Enables support for the on-chip EHCI controller on UniPhier SoCs. +config USB_EHCI_GENERIC + bool "Support for generic EHCI USB controller" + depends on OF_CONTROL + depends on DM_USB + default n + ---help--- + Enables support for generic EHCI controller. + endif diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index f70f38c..6183b80 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_OHCI_S3C24XX) += ohci-s3c24xx.o obj-$(CONFIG_USB_OHCI_EP93XX) += ohci-ep93xx.o obj-$(CONFIG_USB_OHCI_SUNXI) += ohci-sunxi.o obj-$(CONFIG_USB_OHCI_LPC32XX) += ohci-lpc32xx.o +obj-$(CONFIG_USB_OHCI_GENERIC) += ohci-generic.o # echi obj-$(CONFIG_USB_EHCI) += ehci-hcd.o @@ -32,6 +33,7 @@ else obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o endif obj-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o +obj-$(CONFIG_USB_EHCI_GENERIC) += ehci-generic.o obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o obj-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o @@ -54,6 +56,7 @@ obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o # xhci obj-$(CONFIG_USB_XHCI) += xhci.o xhci-mem.o xhci-ring.o obj-$(CONFIG_USB_XHCI_DWC3) += xhci-dwc3.o +obj-$(CONFIG_USB_XHCI_ZYNQMP) += xhci-zynqmp.o obj-$(CONFIG_USB_XHCI_KEYSTONE) += xhci-keystone.o obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 541c0f9..5ef6deb 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -823,12 +823,13 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, (*pid << DWC2_HCTSIZ_PID_OFFSET), &hc_regs->hctsiz); - if (!in) { - memcpy(priv->aligned_buffer, (char *)buffer + done, len); + if (!in && xfer_len) { + memcpy(priv->aligned_buffer, (char *)buffer + done, + xfer_len); flush_dcache_range((unsigned long)priv->aligned_buffer, (unsigned long)((void *)priv->aligned_buffer + - roundup(len, ARCH_DMA_MINALIGN))); + roundup(xfer_len, ARCH_DMA_MINALIGN))); } writel(phys_to_bus((unsigned long)priv->aligned_buffer), diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 18e9251..bede04b 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -219,14 +219,14 @@ static int ehci_usb_probe(struct udevice *dev) ctx->hcd = (struct ehci_hccr *)plat->hcd_base; ctx->usb = (struct exynos_usb_phy *)plat->phy_base; - hcor = (struct ehci_hcor *)((uint32_t)ctx->hcd + - HC_LENGTH(ehci_readl(&ctx->hcd->cr_capbase))); /* setup the Vbus gpio here */ if (dm_gpio_is_valid(&plat->vbus_gpio)) dm_gpio_set_value(&plat->vbus_gpio, 1); setup_usb_phy(ctx->usb); + hcor = (struct ehci_hcor *)((uint32_t)ctx->hcd + + HC_LENGTH(ehci_readl(&ctx->hcd->cr_capbase))); return ehci_register(dev, ctx->hcd, hcor, NULL, 0, USB_INIT_HOST); } diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c new file mode 100644 index 0000000..1292caa --- /dev/null +++ b/drivers/usb/host/ehci-generic.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include "ehci.h" + +/* + * Even though here we don't explicitly use "struct ehci_ctrl" + * ehci_register() expects it to be the first thing that resides in + * device's private data. + */ +struct generic_ehci { + struct ehci_ctrl ctrl; +}; + +static int ehci_usb_probe(struct udevice *dev) +{ + struct ehci_hccr *hccr = (struct ehci_hccr *)dev_get_addr(dev); + struct ehci_hcor *hcor; + + hcor = (struct ehci_hcor *)((uintptr_t)hccr + + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + + return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); +} + +static int ehci_usb_remove(struct udevice *dev) +{ + return ehci_deregister(dev); +} + +static const struct udevice_id ehci_usb_ids[] = { + { .compatible = "generic-ehci" }, + { } +}; + +U_BOOT_DRIVER(ehci_generic) = { + .name = "ehci_generic", + .id = UCLASS_USB, + .of_match = ehci_usb_ids, + .probe = ehci_usb_probe, + .remove = ehci_usb_remove, + .ops = &ehci_usb_ops, + .priv_auto_alloc_size = sizeof(struct generic_ehci), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c85dbce..c664b16 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -279,56 +279,16 @@ static inline u8 ehci_encode_speed(enum usb_device_speed speed) static void ehci_update_endpt2_dev_n_port(struct usb_device *udev, struct QH *qh) { - struct usb_device *ttdev; - int parent_devnum; + uint8_t portnr = 0; + uint8_t hubaddr = 0; if (udev->speed != USB_SPEED_LOW && udev->speed != USB_SPEED_FULL) return; - /* - * For full / low speed devices we need to get the devnum and portnr of - * the tt, so of the first upstream usb-2 hub, there may be usb-1 hubs - * in the tree before that one! - */ -#ifdef CONFIG_DM_USB - /* - * When called from usb-uclass.c: usb_scan_device() udev->dev points - * to the parent udevice, not the actual udevice belonging to the - * udev as the device is not instantiated yet. So when searching - * for the first usb-2 parent start with udev->dev not - * udev->dev->parent . - */ - struct udevice *parent; - struct usb_device *uparent; - - ttdev = udev; - parent = udev->dev; - uparent = dev_get_parent_priv(parent); - - while (uparent->speed != USB_SPEED_HIGH) { - struct udevice *dev = parent; - - if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) { - printf("ehci: Error cannot find high-speed parent of usb-1 device\n"); - return; - } - - ttdev = dev_get_parent_priv(dev); - parent = dev->parent; - uparent = dev_get_parent_priv(parent); - } - parent_devnum = uparent->devnum; -#else - ttdev = udev; - while (ttdev->parent && ttdev->parent->speed != USB_SPEED_HIGH) - ttdev = ttdev->parent; - if (!ttdev->parent) - return; - parent_devnum = ttdev->parent->devnum; -#endif + usb_find_usb2_hub_address_port(udev, &hubaddr, &portnr); - qh->qh_endpt2 |= cpu_to_hc32(QH_ENDPT2_PORTNUM(ttdev->portnr) | - QH_ENDPT2_HUBADDR(parent_devnum)); + qh->qh_endpt2 |= cpu_to_hc32(QH_ENDPT2_PORTNUM(portnr) | + QH_ENDPT2_HUBADDR(hubaddr)); } static int diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c index 38d5f92..d494ca1 100644 --- a/drivers/usb/host/ehci-sunxi.c +++ b/drivers/usb/host/ehci-sunxi.c @@ -87,7 +87,7 @@ static const struct udevice_id ehci_usb_ids[] = { { } }; -U_BOOT_DRIVER(usb_ehci) = { +U_BOOT_DRIVER(ehci_sunxi) = { .name = "ehci_sunxi", .id = UCLASS_USB, .of_match = ehci_usb_ids, diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c new file mode 100644 index 0000000..f3307f4 --- /dev/null +++ b/drivers/usb/host/ohci-generic.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include "ohci.h" + +#if !defined(CONFIG_USB_OHCI_NEW) +# error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW" +#endif + +struct generic_ohci { + ohci_t ohci; +}; + +static int ohci_usb_probe(struct udevice *dev) +{ + struct ohci_regs *regs = (struct ohci_regs *)dev_get_addr(dev); + + return ohci_register(dev, regs); +} + +static int ohci_usb_remove(struct udevice *dev) +{ + return ohci_deregister(dev); +} + +static const struct udevice_id ohci_usb_ids[] = { + { .compatible = "generic-ohci" }, + { } +}; + +U_BOOT_DRIVER(ohci_generic) = { + .name = "ohci_generic", + .id = UCLASS_USB, + .of_match = ohci_usb_ids, + .probe = ohci_usb_probe, + .remove = ohci_usb_remove, + .ops = &ohci_usb_ops, + .priv_auto_alloc_size = sizeof(struct generic_ohci), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index c722c50..33961cd 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -44,6 +44,8 @@ void dwc3_core_soft_reset(struct dwc3 *dwc3_reg) /* reset USB3 phy - if required */ dwc3_phy_reset(dwc3_reg); + mdelay(100); + /* After PHYs are stable we can take Core out of reset state */ clrbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET); } diff --git a/drivers/usb/host/xhci-fsl.c b/drivers/usb/host/xhci-fsl.c index 6481e07..05f09d7 100644 --- a/drivers/usb/host/xhci-fsl.c +++ b/drivers/usb/host/xhci-fsl.c @@ -27,23 +27,6 @@ __weak int __board_usb_init(int index, enum usb_init_type init) return 0; } -void usb_phy_reset(struct dwc3 *dwc3_reg) -{ - /* Assert USB3 PHY reset */ - setbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST); - - /* Assert USB2 PHY reset */ - setbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST); - - mdelay(200); - - /* Clear USB3 PHY reset */ - clrbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST); - - /* Clear USB2 PHY reset */ - clrbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST); -} - static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci) { int ret = 0; diff --git a/drivers/usb/host/xhci-omap.c b/drivers/usb/host/xhci-omap.c index 104e7a7..fd19f79 100644 --- a/drivers/usb/host/xhci-omap.c +++ b/drivers/usb/host/xhci-omap.c @@ -27,7 +27,7 @@ DECLARE_GLOBAL_DATA_PTR; static struct omap_xhci omap; -inline int __board_usb_init(int index, enum usb_init_type init) +__weak int __board_usb_init(int index, enum usb_init_type init) { return 0; } diff --git a/drivers/usb/host/xhci-zynqmp.c b/drivers/usb/host/xhci-zynqmp.c new file mode 100644 index 0000000..a735369 --- /dev/null +++ b/drivers/usb/host/xhci-zynqmp.c @@ -0,0 +1,126 @@ +/* + * Copyright 2015 Xilinx, Inc. + * + * Zynq USB HOST xHCI Controller + * + * Author: Siva Durga Prasad Paladugu<sivadur@xilinx.com> + * + * This file was reused from Freescale USB xHCI + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <usb.h> +#include <asm-generic/errno.h> +#include <asm/arch-zynqmp/hardware.h> +#include <linux/compat.h> +#include <linux/usb/dwc3.h> +#include "xhci.h" + +/* Declare global data pointer */ +DECLARE_GLOBAL_DATA_PTR; + +/* Default to the ZYNQMP XHCI defines */ +#define USB3_PWRCTL_CLK_CMD_MASK 0x3FE000 +#define USB3_PWRCTL_CLK_FREQ_MASK 0xFFC +#define USB3_PHY_PARTIAL_RX_POWERON BIT(6) +#define USB3_PHY_RX_POWERON BIT(14) +#define USB3_PHY_TX_POWERON BIT(15) +#define USB3_PHY_TX_RX_POWERON (USB3_PHY_RX_POWERON | USB3_PHY_TX_POWERON) +#define USB3_PWRCTL_CLK_CMD_SHIFT 14 +#define USB3_PWRCTL_CLK_FREQ_SHIFT 22 + +/* USBOTGSS_WRAPPER definitions */ +#define USBOTGSS_WRAPRESET BIT(17) +#define USBOTGSS_DMADISABLE BIT(16) +#define USBOTGSS_STANDBYMODE_NO_STANDBY BIT(4) +#define USBOTGSS_STANDBYMODE_SMRT BIT(5) +#define USBOTGSS_STANDBYMODE_SMRT_WKUP (0x3 << 4) +#define USBOTGSS_IDLEMODE_NOIDLE BIT(2) +#define USBOTGSS_IDLEMODE_SMRT BIT(3) +#define USBOTGSS_IDLEMODE_SMRT_WKUP (0x3 << 2) + +/* USBOTGSS_IRQENABLE_SET_0 bit */ +#define USBOTGSS_COREIRQ_EN BIT(1) + +/* USBOTGSS_IRQENABLE_SET_1 bits */ +#define USBOTGSS_IRQ_SET_1_IDPULLUP_FALL_EN BIT(1) +#define USBOTGSS_IRQ_SET_1_DISCHRGVBUS_FALL_EN BIT(3) +#define USBOTGSS_IRQ_SET_1_CHRGVBUS_FALL_EN BIT(4) +#define USBOTGSS_IRQ_SET_1_DRVVBUS_FALL_EN BIT(5) +#define USBOTGSS_IRQ_SET_1_IDPULLUP_RISE_EN BIT(8) +#define USBOTGSS_IRQ_SET_1_DISCHRGVBUS_RISE_EN BIT(11) +#define USBOTGSS_IRQ_SET_1_CHRGVBUS_RISE_EN BIT(12) +#define USBOTGSS_IRQ_SET_1_DRVVBUS_RISE_EN BIT(13) +#define USBOTGSS_IRQ_SET_1_OEVT_EN BIT(16) +#define USBOTGSS_IRQ_SET_1_DMADISABLECLR_EN BIT(17) + +struct zynqmp_xhci { + struct xhci_hccr *hcd; + struct dwc3 *dwc3_reg; +}; + +static struct zynqmp_xhci zynqmp_xhci; + +unsigned long ctr_addr[] = CONFIG_ZYNQMP_XHCI_LIST; + +static int zynqmp_xhci_core_init(struct zynqmp_xhci *zynqmp_xhci) +{ + int ret = 0; + + ret = dwc3_core_init(zynqmp_xhci->dwc3_reg); + if (ret) { + debug("%s:failed to initialize core\n", __func__); + return ret; + } + + /* We are hard-coding DWC3 core to Host Mode */ + dwc3_set_mode(zynqmp_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); + + return ret; +} + +int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) +{ + struct zynqmp_xhci *ctx = &zynqmp_xhci; + int ret = 0; + uint32_t hclen; + + if (index < 0 || index >= ARRAY_SIZE(ctr_addr)) + return -EINVAL; + + ctx->hcd = (struct xhci_hccr *)ctr_addr[index]; + ctx->dwc3_reg = (struct dwc3 *)((void *)ctx->hcd + DWC3_REG_OFFSET); + + ret = board_usb_init(index, USB_INIT_HOST); + if (ret != 0) { + puts("Failed to initialize board for USB\n"); + return ret; + } + + ret = zynqmp_xhci_core_init(ctx); + if (ret < 0) { + puts("Failed to initialize xhci\n"); + return ret; + } + + *hccr = (struct xhci_hccr *)ctx->hcd; + hclen = HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)); + *hcor = (struct xhci_hcor *)((uintptr_t) *hccr + hclen); + + debug("zynqmp-xhci: init hccr %p and hcor %p hc_length %d\n", + *hccr, *hcor, hclen); + + return ret; +} + +void xhci_hcd_stop(int index) +{ + /* + * Currently zynqmp socs do not support PHY shutdown from + * sw. But this support may be added in future socs. + */ + + return; +} diff --git a/drivers/usb/musb-new/musb_host.c b/drivers/usb/musb-new/musb_host.c index 40b9c66..2515447 100644 --- a/drivers/usb/musb-new/musb_host.c +++ b/drivers/usb/musb-new/musb_host.c @@ -2092,9 +2092,13 @@ int musb_urb_enqueue( } #else if (tt_needed(musb, urb->dev)) { - u16 hub_port = find_tt(urb->dev); - qh->h_addr_reg = (u8) (hub_port >> 8); - qh->h_port_reg = (u8) (hub_port & 0xff); + uint8_t portnr = 0; + uint8_t hubaddr = 0; + usb_find_usb2_hub_address_port(urb->dev, + &hubaddr, + &portnr); + qh->h_addr_reg = hubaddr; + qh->h_port_reg = portnr; } #endif } diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c index a146c08..5eb8d19 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/usb/musb-new/usb-compat.h b/drivers/usb/musb-new/usb-compat.h index 1c41e2a..760bd78 100644 --- a/drivers/usb/musb-new/usb-compat.h +++ b/drivers/usb/musb-new/usb-compat.h @@ -68,38 +68,6 @@ static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, } #ifdef CONFIG_DM_USB -static inline u16 find_tt(struct usb_device *udev) -{ - struct udevice *parent; - struct usb_device *uparent, *ttdev; - - /* - * When called from usb-uclass.c: usb_scan_device() udev->dev points - * to the parent udevice, not the actual udevice belonging to the - * udev as the device is not instantiated yet. So when searching - * for the first usb-2 parent start with udev->dev not - * udev->dev->parent . - */ - ttdev = udev; - parent = udev->dev; - uparent = dev_get_parent_priv(parent); - - while (uparent->speed != USB_SPEED_HIGH) { - struct udevice *dev = parent; - - if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) { - printf("musb: Error cannot find high speed parent of usb-1 device\n"); - return 0; - } - - ttdev = dev_get_parent_priv(dev); - parent = dev->parent; - uparent = dev_get_parent_priv(parent); - } - - return (uparent->devnum << 8) | (ttdev->portnr - 1); -} - static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev) { struct udevice *parent = udev->dev->parent; @@ -129,27 +97,6 @@ static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev) return NULL; } #else -static inline u16 find_tt(struct usb_device *dev) -{ - u8 chid; - u8 hub; - - /* Find out the nearest parent which is high speed */ - while (dev->parent->parent != NULL) - if (dev->parent->speed != USB_SPEED_HIGH) - dev = dev->parent; - else - break; - - /* determine the port address at that hub */ - hub = dev->parent->devnum; - for (chid = 0; chid < USB_MAXCHILDREN; chid++) - if (dev->parent->children[chid] == dev) - break; - - return (hub << 8) | chid; -} - static inline struct usb_device *usb_dev_get_parent(struct usb_device *dev) { return dev->parent; diff --git a/drivers/video/ipu_disp.c b/drivers/video/ipu_disp.c index 7a87478..cbac9f7 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 c2c134a..0d3fe06 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]) |