diff options
Diffstat (limited to 'drivers')
168 files changed, 7807 insertions, 956 deletions
diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index e5335f7234b..80944205481 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -28,3 +28,12 @@ config ADC_SANDBOX - 4 analog input channels - 16-bit resolution - single and multi-channel conversion mode + +config SARADC_ROCKCHIP + bool "Enable Rockchip SARADC driver" + help + This enables driver for Rockchip SARADC. + It provides: + - 2~6 analog input channels + - 1O or 12 bits resolution + - Up to 1MSPS of sample rate diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index cebf26de078..4b5aa693ec1 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_ADC) += adc-uclass.o obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o obj-$(CONFIG_ADC_SANDBOX) += sandbox.o +obj-$(CONFIG_SARADC_ROCKCHIP) += rockchip-saradc.o diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c index a5ef722d213..a4c20f4d352 100644 --- a/drivers/adc/adc-uclass.c +++ b/drivers/adc/adc-uclass.c @@ -64,7 +64,7 @@ static int adc_supply_enable(struct udevice *dev) } if (ret) - error("%s: can't enable %s-supply!", dev->name, supply_type); + pr_err("%s: can't enable %s-supply!", dev->name, supply_type); return ret; } @@ -389,12 +389,12 @@ static int adc_pre_probe(struct udevice *dev) /* Set ADC VDD platdata: polarity, uV, regulator (phandle). */ ret = adc_vdd_platdata_set(dev); if (ret) - error("%s: Can't update Vdd. Error: %d", dev->name, ret); + pr_err("%s: Can't update Vdd. Error: %d", dev->name, ret); /* Set ADC VSS platdata: polarity, uV, regulator (phandle). */ ret = adc_vss_platdata_set(dev); if (ret) - error("%s: Can't update Vss. Error: %d", dev->name, ret); + pr_err("%s: Can't update Vss. Error: %d", dev->name, ret); return 0; } diff --git a/drivers/adc/exynos-adc.c b/drivers/adc/exynos-adc.c index 324d72f3a95..3bb065d2155 100644 --- a/drivers/adc/exynos-adc.c +++ b/drivers/adc/exynos-adc.c @@ -22,7 +22,7 @@ int exynos_adc_channel_data(struct udevice *dev, int channel, struct exynos_adc_v2 *regs = priv->regs; if (channel != priv->active_channel) { - error("Requested channel is not active!"); + pr_err("Requested channel is not active!"); return -EINVAL; } @@ -80,7 +80,7 @@ int exynos_adc_probe(struct udevice *dev) /* Check HW version */ if (readl(®s->version) != ADC_V2_VERSION) { - error("This driver supports only ADC v2!"); + pr_err("This driver supports only ADC v2!"); return -ENXIO; } @@ -109,7 +109,7 @@ int exynos_adc_ofdata_to_platdata(struct udevice *dev) priv->regs = (struct exynos_adc_v2 *)devfdt_get_addr(dev); if (priv->regs == (struct exynos_adc_v2 *)FDT_ADDR_T_NONE) { - error("Dev: %s - can't get address!", dev->name); + pr_err("Dev: %s - can't get address!", dev->name); return -ENODATA; } diff --git a/drivers/adc/rockchip-saradc.c b/drivers/adc/rockchip-saradc.c new file mode 100644 index 00000000000..a2856db497d --- /dev/null +++ b/drivers/adc/rockchip-saradc.c @@ -0,0 +1,183 @@ +/* + * (C) Copyright 2017, Fuzhou Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Rockchip SARADC driver for U-Boot + */ + +#include <common.h> +#include <adc.h> +#include <clk.h> +#include <dm.h> +#include <errno.h> +#include <asm/io.h> + +#define SARADC_CTRL_CHN_MASK GENMASK(2, 0) +#define SARADC_CTRL_POWER_CTRL BIT(3) +#define SARADC_CTRL_IRQ_ENABLE BIT(5) +#define SARADC_CTRL_IRQ_STATUS BIT(6) + +#define SARADC_TIMEOUT (100 * 1000) + +struct rockchip_saradc_regs { + unsigned int data; + unsigned int stas; + unsigned int ctrl; + unsigned int dly_pu_soc; +}; + +struct rockchip_saradc_data { + int num_bits; + int num_channels; + unsigned long clk_rate; +}; + +struct rockchip_saradc_priv { + struct rockchip_saradc_regs *regs; + int active_channel; + const struct rockchip_saradc_data *data; +}; + +int rockchip_saradc_channel_data(struct udevice *dev, int channel, + unsigned int *data) +{ + struct rockchip_saradc_priv *priv = dev_get_priv(dev); + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + + if (channel != priv->active_channel) { + pr_err("Requested channel is not active!"); + return -EINVAL; + } + + if ((readl(&priv->regs->ctrl) & SARADC_CTRL_IRQ_STATUS) != + SARADC_CTRL_IRQ_STATUS) + return -EBUSY; + + /* Read value */ + *data = readl(&priv->regs->data); + *data &= uc_pdata->data_mask; + + /* Power down adc */ + writel(0, &priv->regs->ctrl); + + return 0; +} + +int rockchip_saradc_start_channel(struct udevice *dev, int channel) +{ + struct rockchip_saradc_priv *priv = dev_get_priv(dev); + + if (channel < 0 || channel >= priv->data->num_channels) { + pr_err("Requested channel is invalid!"); + return -EINVAL; + } + + /* 8 clock periods as delay between power up and start cmd */ + writel(8, &priv->regs->dly_pu_soc); + + /* Select the channel to be used and trigger conversion */ + writel(SARADC_CTRL_POWER_CTRL | (channel & SARADC_CTRL_CHN_MASK) | + SARADC_CTRL_IRQ_ENABLE, &priv->regs->ctrl); + + priv->active_channel = channel; + + return 0; +} + +int rockchip_saradc_stop(struct udevice *dev) +{ + struct rockchip_saradc_priv *priv = dev_get_priv(dev); + + /* Power down adc */ + writel(0, &priv->regs->ctrl); + + priv->active_channel = -1; + + return 0; +} + +int rockchip_saradc_probe(struct udevice *dev) +{ + struct rockchip_saradc_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_set_rate(&clk, priv->data->clk_rate); + if (IS_ERR_VALUE(ret)) + return ret; + + priv->active_channel = -1; + + return 0; +} + +int rockchip_saradc_ofdata_to_platdata(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + struct rockchip_saradc_priv *priv = dev_get_priv(dev); + struct rockchip_saradc_data *data; + + data = (struct rockchip_saradc_data *)dev_get_driver_data(dev); + priv->regs = (struct rockchip_saradc_regs *)dev_read_addr(dev); + if (priv->regs == (struct rockchip_saradc_regs *)FDT_ADDR_T_NONE) { + pr_err("Dev: %s - can't get address!", dev->name); + return -ENODATA; + } + + priv->data = data; + uc_pdata->data_mask = (1 << priv->data->num_bits) - 1;; + uc_pdata->data_format = ADC_DATA_FORMAT_BIN; + uc_pdata->data_timeout_us = SARADC_TIMEOUT / 5; + uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1; + + return 0; +} + +static const struct adc_ops rockchip_saradc_ops = { + .start_channel = rockchip_saradc_start_channel, + .channel_data = rockchip_saradc_channel_data, + .stop = rockchip_saradc_stop, +}; + +static const struct rockchip_saradc_data saradc_data = { + .num_bits = 10, + .num_channels = 3, + .clk_rate = 1000000, +}; + +static const struct rockchip_saradc_data rk3066_tsadc_data = { + .num_bits = 12, + .num_channels = 2, + .clk_rate = 50000, +}; + +static const struct rockchip_saradc_data rk3399_saradc_data = { + .num_bits = 10, + .num_channels = 6, + .clk_rate = 1000000, +}; + +static const struct udevice_id rockchip_saradc_ids[] = { + { .compatible = "rockchip,saradc", + .data = (ulong)&saradc_data }, + { .compatible = "rockchip,rk3066-tsadc", + .data = (ulong)&rk3066_tsadc_data }, + { .compatible = "rockchip,rk3399-saradc", + .data = (ulong)&rk3399_saradc_data }, + { } +}; + +U_BOOT_DRIVER(rockchip_saradc) = { + .name = "rockchip_saradc", + .id = UCLASS_ADC, + .of_match = rockchip_saradc_ids, + .ops = &rockchip_saradc_ops, + .probe = rockchip_saradc_probe, + .ofdata_to_platdata = rockchip_saradc_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct rockchip_saradc_priv), +}; diff --git a/drivers/adc/sandbox.c b/drivers/adc/sandbox.c index 371892237aa..80e8e3701a3 100644 --- a/drivers/adc/sandbox.c +++ b/drivers/adc/sandbox.c @@ -61,7 +61,7 @@ int sandbox_adc_channel_data(struct udevice *dev, int channel, /* For single-channel conversion mode, check if channel was selected */ if ((priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) && !(priv->active_channel_mask & (1 << channel))) { - error("Request for an inactive channel!"); + pr_err("Request for an inactive channel!"); return -EINVAL; } @@ -82,12 +82,12 @@ int sandbox_adc_channels_data(struct udevice *dev, unsigned int channel_mask, /* Return error for single-channel conversion mode */ if (priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) { - error("ADC in single-channel mode!"); + pr_err("ADC in single-channel mode!"); return -EPERM; } /* Check channel selection */ if (!(priv->active_channel_mask & channel_mask)) { - error("Request for an inactive channel!"); + pr_err("Request for an inactive channel!"); return -EINVAL; } /* The conversion must be started before reading the data */ diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c index f6147989b1c..b16304baedb 100644 --- a/drivers/ata/dwc_ahci.c +++ b/drivers/ata/dwc_ahci.c @@ -58,19 +58,19 @@ static int dwc_ahci_probe(struct udevice *dev) ret = generic_phy_get_by_name(dev, "sata-phy", &phy); if (ret) { - error("can't get the phy from DT\n"); + pr_err("can't get the phy from DT\n"); return ret; } ret = generic_phy_init(&phy); if (ret) { - error("unable to initialize the sata phy\n"); + pr_err("unable to initialize the sata phy\n"); return ret; } ret = generic_phy_power_on(&phy); if (ret) { - error("unable to power on the sata phy\n"); + pr_err("unable to power on the sata phy\n"); return ret; } diff --git a/drivers/bios_emulator/include/x86emu/x86emui.h b/drivers/bios_emulator/include/x86emu/x86emui.h index a74957d992a..3537255539f 100644 --- a/drivers/bios_emulator/include/x86emu/x86emui.h +++ b/drivers/bios_emulator/include/x86emu/x86emui.h @@ -72,9 +72,6 @@ #include <string.h> #endif -#define printk printf - - /*--------------------------- Inline Functions ----------------------------*/ #ifdef __cplusplus diff --git a/drivers/clk/clk_boston.c b/drivers/clk/clk_boston.c index 78f1b759d83..5c05e3d78d5 100644 --- a/drivers/clk/clk_boston.c +++ b/drivers/clk/clk_boston.c @@ -67,13 +67,13 @@ static int clk_boston_ofdata_to_platdata(struct udevice *dev) err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "regmap", &syscon); if (err) { - error("unable to find syscon device\n"); + pr_err("unable to find syscon device\n"); return err; } state->regmap = syscon_get_regmap(syscon); if (!state->regmap) { - error("unable to find regmap\n"); + pr_err("unable to find regmap\n"); return -ENODEV; } diff --git a/drivers/clk/clk_stm32f7.c b/drivers/clk/clk_stm32f7.c index 255a583c954..96a06b8f8cb 100644 --- a/drivers/clk/clk_stm32f7.c +++ b/drivers/clk/clk_stm32f7.c @@ -224,7 +224,7 @@ static unsigned long stm32_clk_get_rate(struct clk *clk) return sysclk >>= shift; break; default: - error("clock index %ld out of range\n", clk->id); + pr_err("clock index %ld out of range\n", clk->id); return -EINVAL; break; } @@ -310,10 +310,11 @@ static const struct udevice_id stm32_clk_ids[] = { }; U_BOOT_DRIVER(stm32f7_clk) = { - .name = "stm32f7_clk", - .id = UCLASS_CLK, - .of_match = stm32_clk_ids, - .ops = &stm32_clk_ops, - .probe = stm32_clk_probe, - .flags = DM_FLAG_PRE_RELOC, + .name = "stm32f7_clk", + .id = UCLASS_CLK, + .of_match = stm32_clk_ids, + .ops = &stm32_clk_ops, + .probe = stm32_clk_probe, + .priv_auto_alloc_size = sizeof(struct stm32_clk), + .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/clk/clk_stm32h7.c b/drivers/clk/clk_stm32h7.c index fd0e3ab1005..931e5ef904e 100644 --- a/drivers/clk/clk_stm32h7.c +++ b/drivers/clk/clk_stm32h7.c @@ -472,13 +472,13 @@ static ulong stm32_get_rate(struct stm32_rcc_regs *regs, enum pllsrc pllsrc) clk.id = 0; ret = uclass_get_device_by_name(UCLASS_CLK, name, &fixed_clock_dev); if (ret) { - error("Can't find clk %s (%d)", name, ret); + pr_err("Can't find clk %s (%d)", name, ret); return 0; } ret = clk_request(fixed_clock_dev, &clk); if (ret) { - error("Can't request %s clk (%d)", name, ret); + pr_err("Can't request %s clk (%d)", name, ret); return 0; } @@ -518,7 +518,7 @@ static u32 stm32_get_PLL1_rate(struct stm32_rcc_regs *regs, break; case RCC_PLLCKSELR_PLLSRC_NO_CLK: /* shouldn't happen */ - error("wrong value for RCC_PLLCKSELR register\n"); + pr_err("wrong value for RCC_PLLCKSELR register\n"); pllsrc = 0; break; } @@ -695,7 +695,7 @@ static ulong stm32_clk_get_rate(struct clk *clk) break; default: - error("unexpected gate_offset value (0x%x)\n", gate_offset); + pr_err("unexpected gate_offset value (0x%x)\n", gate_offset); return -EINVAL; break; } @@ -739,13 +739,13 @@ static int stm32_clk_probe(struct udevice *dev) "st,syscfg", &syscon); if (err) { - error("unable to find syscon device\n"); + pr_err("unable to find syscon device\n"); return err; } priv->pwr_regmap = syscon_get_regmap(syscon); if (!priv->pwr_regmap) { - error("unable to find regmap\n"); + pr_err("unable to find regmap\n"); return -ENODEV; } diff --git a/drivers/clk/rockchip/clk_rk322x.c b/drivers/clk/rockchip/clk_rk322x.c index d7f6a3c313e..e87267d239f 100644 --- a/drivers/clk/rockchip/clk_rk322x.c +++ b/drivers/clk/rockchip/clk_rk322x.c @@ -117,16 +117,16 @@ static void rkclk_init(struct rk322x_cru *cru) pclk_div << CORE_PERI_DIV_SHIFT); /* - * select apll as pd_bus bus clock source and + * select gpll as pd_bus bus clock source and * set up dependent divisors for PCLK/HCLK and ACLK clocks. */ aclk_div = GPLL_HZ / BUS_ACLK_HZ - 1; assert((aclk_div + 1) * BUS_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f); - pclk_div = GPLL_HZ / BUS_PCLK_HZ - 1; + pclk_div = BUS_ACLK_HZ / BUS_PCLK_HZ - 1; assert((pclk_div + 1) * BUS_PCLK_HZ == GPLL_HZ && pclk_div <= 0x7); - hclk_div = GPLL_HZ / BUS_HCLK_HZ - 1; + hclk_div = BUS_ACLK_HZ / BUS_HCLK_HZ - 1; assert((hclk_div + 1) * BUS_HCLK_HZ == GPLL_HZ && hclk_div <= 0x3); rk_clrsetreg(&cru->cru_clksel_con[0], @@ -389,7 +389,7 @@ static int rk322x_clk_bind(struct udevice *dev) /* The reset driver does not have a device node, so bind it here */ ret = device_bind_driver(gd->dm_root, "rk322x_sysreset", "reset", &dev); if (ret) - debug("Warning: No RK3036 reset driver: ret=%d\n", ret); + debug("Warning: No RK322x reset driver: ret=%d\n", ret); return 0; } diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c index 478195b10b0..a133810bf60 100644 --- a/drivers/clk/rockchip/clk_rk3288.c +++ b/drivers/clk/rockchip/clk_rk3288.c @@ -5,6 +5,7 @@ */ #include <common.h> +#include <bitfield.h> #include <clk-uclass.h> #include <dm.h> #include <dt-structs.h> @@ -111,6 +112,15 @@ enum { PERI_ACLK_DIV_SHIFT = 0, PERI_ACLK_DIV_MASK = 0x1f << PERI_ACLK_DIV_SHIFT, + /* + * CLKSEL24 + * saradc_div_con: + * clk_saradc=24MHz/(saradc_div_con+1) + */ + CLK_SARADC_DIV_CON_SHIFT = 8, + CLK_SARADC_DIV_CON_MASK = GENMASK(15, 8), + CLK_SARADC_DIV_CON_WIDTH = 8, + SOCSTS_DPLL_LOCK = 1 << 5, SOCSTS_APLL_LOCK = 1 << 6, SOCSTS_CPLL_LOCK = 1 << 7, @@ -634,6 +644,31 @@ static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint gclk_rate, return rockchip_spi_get_clk(cru, gclk_rate, periph); } +static ulong rockchip_saradc_get_clk(struct rk3288_cru *cru) +{ + u32 div, val; + + val = readl(&cru->cru_clksel_con[24]); + div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT, + CLK_SARADC_DIV_CON_WIDTH); + + return DIV_TO_RATE(OSC_HZ, div); +} + +static ulong rockchip_saradc_set_clk(struct rk3288_cru *cru, uint hz) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1; + assert(src_clk_div < 128); + + rk_clrsetreg(&cru->cru_clksel_con[24], + CLK_SARADC_DIV_CON_MASK, + src_clk_div << CLK_SARADC_DIV_CON_SHIFT); + + return rockchip_saradc_get_clk(cru); +} + static ulong rk3288_clk_get_rate(struct clk *clk) { struct rk3288_clk_priv *priv = dev_get_priv(clk->dev); @@ -666,6 +701,9 @@ static ulong rk3288_clk_get_rate(struct clk *clk) return gclk_rate; case PCLK_PWM: return PD_BUS_PCLK_HZ; + case SCLK_SARADC: + new_rate = rockchip_saradc_get_clk(priv->cru); + break; default: return -ENOENT; } @@ -756,6 +794,9 @@ static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate) new_rate = rate; break; #endif + case SCLK_SARADC: + new_rate = rockchip_saradc_set_clk(priv->cru, rate); + break; default: return -ENOENT; } diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c index c3a6650de03..540d9104c3c 100644 --- a/drivers/clk/rockchip/clk_rk3328.c +++ b/drivers/clk/rockchip/clk_rk3328.c @@ -5,6 +5,7 @@ */ #include <common.h> +#include <bitfield.h> #include <clk-uclass.h> #include <dm.h> #include <errno.h> @@ -114,7 +115,8 @@ enum { /* CLKSEL_CON23 */ CLK_SARADC_DIV_CON_SHIFT = 0, - CLK_SARADC_DIV_CON_MASK = 0x3ff << CLK_SARADC_DIV_CON_SHIFT, + CLK_SARADC_DIV_CON_MASK = GENMASK(9, 0), + CLK_SARADC_DIV_CON_WIDTH = 10, /* CLKSEL_CON24 */ CLK_PWM_PLL_SEL_CPLL = 0, @@ -478,6 +480,31 @@ static ulong rk3328_pwm_set_clk(struct rk3328_cru *cru, uint hz) return DIV_TO_RATE(GPLL_HZ, div); } +static ulong rk3328_saradc_get_clk(struct rk3328_cru *cru) +{ + u32 div, val; + + val = readl(&cru->clksel_con[23]); + div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT, + CLK_SARADC_DIV_CON_WIDTH); + + return DIV_TO_RATE(OSC_HZ, div); +} + +static ulong rk3328_saradc_set_clk(struct rk3328_cru *cru, uint hz) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1; + assert(src_clk_div < 128); + + rk_clrsetreg(&cru->clksel_con[23], + CLK_SARADC_DIV_CON_MASK, + src_clk_div << CLK_SARADC_DIV_CON_SHIFT); + + return rk3328_saradc_get_clk(cru); +} + static ulong rk3328_clk_get_rate(struct clk *clk) { struct rk3328_clk_priv *priv = dev_get_priv(clk->dev); @@ -501,6 +528,9 @@ static ulong rk3328_clk_get_rate(struct clk *clk) case SCLK_PWM: rate = rk3328_pwm_get_clk(priv->cru); break; + case SCLK_SARADC: + rate = rk3328_saradc_get_clk(priv->cru); + break; default: return -ENOENT; } @@ -531,6 +561,9 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate) case SCLK_PWM: ret = rk3328_pwm_set_clk(priv->cru, rate); break; + case SCLK_SARADC: + ret = rk3328_saradc_set_clk(priv->cru, rate); + break; default: return -ENOENT; } diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c index e2747816b9c..3661769748f 100644 --- a/drivers/clk/rockchip/clk_rk3368.c +++ b/drivers/clk/rockchip/clk_rk3368.c @@ -12,6 +12,7 @@ #include <errno.h> #include <mapmem.h> #include <syscon.h> +#include <bitfield.h> #include <asm/arch/clock.h> #include <asm/arch/cru_rk3368.h> #include <asm/arch/hardware.h> @@ -301,7 +302,7 @@ static ulong rk3368_ddr_set_clk(struct rk3368_cru *cru, ulong set_rate) dpll_cfg = &dpll_1600; break; default: - error("Unsupported SDRAM frequency!,%ld\n", set_rate); + pr_err("Unsupported SDRAM frequency!,%ld\n", set_rate); } rkclk_set_pll(cru, DPLL, dpll_cfg); @@ -359,7 +360,7 @@ static ulong rk3368_spi_get_clk(struct rk3368_cru *cru, ulong clk_id) break; default: - error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); + pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id); return -EINVAL; } @@ -384,7 +385,7 @@ static ulong rk3368_spi_set_clk(struct rk3368_cru *cru, ulong clk_id, uint hz) break; default: - error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); + pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id); return -EINVAL; } @@ -397,6 +398,31 @@ static ulong rk3368_spi_set_clk(struct rk3368_cru *cru, ulong clk_id, uint hz) return rk3368_spi_get_clk(cru, clk_id); } +static ulong rk3368_saradc_get_clk(struct rk3368_cru *cru) +{ + u32 div, val; + + val = readl(&cru->clksel_con[25]); + div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT, + CLK_SARADC_DIV_CON_WIDTH); + + return DIV_TO_RATE(OSC_HZ, div); +} + +static ulong rk3368_saradc_set_clk(struct rk3368_cru *cru, uint hz) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1; + assert(src_clk_div < 128); + + rk_clrsetreg(&cru->clksel_con[25], + CLK_SARADC_DIV_CON_MASK, + src_clk_div << CLK_SARADC_DIV_CON_SHIFT); + + return rk3368_saradc_get_clk(cru); +} + static ulong rk3368_clk_get_rate(struct clk *clk) { struct rk3368_clk_priv *priv = dev_get_priv(clk->dev); @@ -419,6 +445,9 @@ static ulong rk3368_clk_get_rate(struct clk *clk) rate = rk3368_mmc_get_clk(priv->cru, clk->id); break; #endif + case SCLK_SARADC: + rate = rk3368_saradc_get_clk(priv->cru); + break; default: return -ENOENT; } @@ -453,6 +482,9 @@ static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate) ret = rk3368_gmac_set_clk(priv->cru, clk->id, rate); break; #endif + case SCLK_SARADC: + ret = rk3368_saradc_set_clk(priv->cru, rate); + break; default: return -ENOENT; } @@ -498,7 +530,7 @@ static int rk3368_clk_bind(struct udevice *dev) /* The reset driver does not have a device node, so bind it here */ ret = device_bind_driver(gd->dm_root, "rk3368_sysreset", "reset", &dev); if (ret) - error("bind RK3368 reset driver failed: ret=%d\n", ret); + pr_err("bind RK3368 reset driver failed: ret=%d\n", ret); return ret; } diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index 9d963be5529..f45bba44f13 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -12,6 +12,7 @@ #include <errno.h> #include <mapmem.h> #include <syscon.h> +#include <bitfield.h> #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/cru_rk3399.h> @@ -181,7 +182,8 @@ enum { /* CLKSEL_CON26 */ CLK_SARADC_DIV_CON_SHIFT = 8, - CLK_SARADC_DIV_CON_MASK = 0xff << CLK_SARADC_DIV_CON_SHIFT, + CLK_SARADC_DIV_CON_MASK = GENMASK(15, 8), + CLK_SARADC_DIV_CON_WIDTH = 8, /* CLKSEL_CON27 */ CLK_TSADC_SEL_X24M = 0x0, @@ -661,7 +663,7 @@ static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id) break; default: - error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); + pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id); return -EINVAL; } @@ -685,7 +687,7 @@ static ulong rk3399_spi_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz) break; default: - error("%s: SPI clk-id %ld not supported\n", __func__, clk_id); + pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id); return -EINVAL; } @@ -854,12 +856,38 @@ static ulong rk3399_ddr_set_clk(struct rk3399_cru *cru, {.refdiv = 1, .fbdiv = 116, .postdiv1 = 3, .postdiv2 = 1}; break; default: - error("Unsupported SDRAM frequency!,%ld\n", set_rate); + pr_err("Unsupported SDRAM frequency!,%ld\n", set_rate); } rkclk_set_pll(&cru->dpll_con[0], &dpll_cfg); return set_rate; } + +static ulong rk3399_saradc_get_clk(struct rk3399_cru *cru) +{ + u32 div, val; + + val = readl(&cru->clksel_con[26]); + div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT, + CLK_SARADC_DIV_CON_WIDTH); + + return DIV_TO_RATE(OSC_HZ, div); +} + +static ulong rk3399_saradc_set_clk(struct rk3399_cru *cru, uint hz) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1; + assert(src_clk_div < 128); + + rk_clrsetreg(&cru->clksel_con[26], + CLK_SARADC_DIV_CON_MASK, + src_clk_div << CLK_SARADC_DIV_CON_SHIFT); + + return rk3399_saradc_get_clk(cru); +} + static ulong rk3399_clk_get_rate(struct clk *clk) { struct rk3399_clk_priv *priv = dev_get_priv(clk->dev); @@ -895,6 +923,9 @@ static ulong rk3399_clk_get_rate(struct clk *clk) break; case PCLK_EFUSE1024NS: break; + case SCLK_SARADC: + rate = rk3399_saradc_get_clk(priv->cru); + break; default: return -ENOENT; } @@ -943,6 +974,9 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate) break; case PCLK_EFUSE1024NS: break; + case SCLK_SARADC: + ret = rk3399_saradc_set_clk(priv->cru, rate); + break; default: return -ENOENT; } diff --git a/drivers/clk/rockchip/clk_rv1108.c b/drivers/clk/rockchip/clk_rv1108.c index cf966bbdc33..55741c3a1e2 100644 --- a/drivers/clk/rockchip/clk_rv1108.c +++ b/drivers/clk/rockchip/clk_rv1108.c @@ -5,6 +5,7 @@ */ #include <common.h> +#include <bitfield.h> #include <clk-uclass.h> #include <dm.h> #include <errno.h> @@ -36,7 +37,7 @@ enum { #hz "Hz cannot be hit with PLL "\ "divisors on line " __stringify(__LINE__)); -/* use interge mode*/ +/* use integer mode */ static inline int rv1108_pll_id(enum rk_clk_id clk_id) { int id = 0; @@ -130,6 +131,31 @@ static int rv1108_sfc_set_clk(struct rv1108_cru *cru, uint rate) return DIV_TO_RATE(pll_rate, div); } +static ulong rv1108_saradc_get_clk(struct rv1108_cru *cru) +{ + u32 div, val; + + val = readl(&cru->clksel_con[22]); + div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT, + CLK_SARADC_DIV_CON_WIDTH); + + return DIV_TO_RATE(OSC_HZ, div); +} + +static ulong rv1108_saradc_set_clk(struct rv1108_cru *cru, uint hz) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1; + assert(src_clk_div < 128); + + rk_clrsetreg(&cru->clksel_con[22], + CLK_SARADC_DIV_CON_MASK, + src_clk_div << CLK_SARADC_DIV_CON_SHIFT); + + return rv1108_saradc_get_clk(cru); +} + static ulong rv1108_clk_get_rate(struct clk *clk) { struct rv1108_clk_priv *priv = dev_get_priv(clk->dev); @@ -137,6 +163,8 @@ static ulong rv1108_clk_get_rate(struct clk *clk) switch (clk->id) { case 0 ... 63: return rkclk_pll_get_rate(priv->cru, clk->id); + case SCLK_SARADC: + return rv1108_saradc_get_clk(priv->cru); default: return -ENOENT; } @@ -154,6 +182,9 @@ static ulong rv1108_clk_set_rate(struct clk *clk, ulong rate) case SCLK_SFC: new_rate = rv1108_sfc_set_clk(priv->cru, rate); break; + case SCLK_SARADC: + new_rate = rv1108_saradc_set_clk(priv->cru, rate); + break; default: return -ENOENT; } @@ -196,7 +227,7 @@ static int rv1108_clk_bind(struct udevice *dev) /* The reset driver does not have a device node, so bind it here */ ret = device_bind_driver(gd->dm_root, "rv1108_sysreset", "reset", &dev); if (ret) - error("No Rv1108 reset driver: ret=%d\n", ret); + pr_err("No Rv1108 reset driver: ret=%d\n", ret); return 0; } diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 7afef1f9a3f..e8ba20ca82d 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -45,6 +45,12 @@ config DM_WARN This will cause dm_warn() to be compiled out - it will do nothing when called. +config DM_DEBUG + bool "Enable debug messages in driver model core" + depends on DM + help + Say Y here if you want to compile in debug messages in DM core. + config DM_DEVICE_REMOVE bool "Support device removal" depends on DM diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 3d68c70b57c..a5039c5bd31 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -16,3 +16,5 @@ ifndef CONFIG_DM_DEV_READ_INLINE obj-$(CONFIG_OF_CONTROL) += read.o endif obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o + +ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG diff --git a/drivers/core/device.c b/drivers/core/device.c index 5463d1ffa50..9a46a7bbe5e 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -161,7 +161,7 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, } if (parent) - dm_dbg("Bound device %s to %s\n", dev->name, parent->name); + pr_debug("Bound device %s to %s\n", dev->name, parent->name); if (devp) *devp = dev; @@ -254,6 +254,7 @@ static void *alloc_priv(int size, uint flags) void *priv; if (flags & DM_FLAG_ALLOC_PRIV_DMA) { + size = ROUND(size, ARCH_DMA_MINALIGN); priv = memalign(ARCH_DMA_MINALIGN, size); if (priv) { memset(priv, '\0', size); diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 6067914e811..6fa5d1090ab 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -139,12 +139,13 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp) if (devp) *devp = NULL; name = ofnode_get_name(node); - dm_dbg("bind node %s\n", name); + pr_debug("bind node %s\n", name); compat_list = ofnode_get_property(node, "compatible", &compat_length); if (!compat_list) { if (compat_length == -FDT_ERR_NOTFOUND) { - dm_dbg("Device '%s' has no compatible string\n", name); + pr_debug("Device '%s' has no compatible string\n", + name); return 0; } @@ -159,8 +160,8 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp) */ for (i = 0; i < compat_length; i += strlen(compat) + 1) { compat = compat_list + i; - dm_dbg(" - attempt to match compatible string '%s'\n", - compat); + pr_debug(" - attempt to match compatible string '%s'\n", + compat); for (entry = driver; entry != driver + n_ents; entry++) { ret = driver_check_compatible(entry->of_match, &id, @@ -171,11 +172,11 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp) if (entry == driver + n_ents) continue; - dm_dbg(" - found match at '%s'\n", entry->name); + pr_debug(" - found match at '%s'\n", entry->name); ret = device_bind_with_driver_data(parent, entry, name, id->data, node, &dev); if (ret == -ENODEV) { - dm_dbg("Driver '%s' refuses to bind\n", entry->name); + pr_debug("Driver '%s' refuses to bind\n", entry->name); continue; } if (ret) { @@ -191,7 +192,7 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp) } if (!found && !result && ret != -ENODEV) - dm_dbg("No match for node '%s'\n", name); + pr_debug("No match for node '%s'\n", name); return result; } diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index c6ca13fabf1..0030ab962ef 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -468,8 +468,10 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property, int na, ns; int psize; const struct device_node *np = ofnode_to_np(node); - const __be32 *prop = of_get_property(np, "reg", &psize); + const __be32 *prop = of_get_property(np, property, &psize); + if (!prop) + return FDT_ADDR_T_NONE; na = of_n_addr_cells(np); ns = of_n_addr_cells(np); *sizep = of_read_number(prop + na, ns); diff --git a/drivers/core/read.c b/drivers/core/read.c index 065589a6abc..eacf1716fd7 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -81,6 +81,17 @@ int dev_read_stringlist_search(struct udevice *dev, const char *property, return ofnode_stringlist_search(dev_ofnode(dev), property, string); } +int dev_read_string_index(struct udevice *dev, const char *propname, int index, + const char **outp) +{ + return ofnode_read_string_index(dev_ofnode(dev), propname, index, outp); +} + +int dev_read_string_count(struct udevice *dev, const char *propname) +{ + return ofnode_read_string_count(dev_ofnode(dev), propname); +} + int dev_read_phandle_with_args(struct udevice *dev, const char *list_name, const char *cells_name, int cell_count, int index, diff --git a/drivers/core/root.c b/drivers/core/root.c index 757d109e57a..976e2c4fdd9 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -227,7 +227,7 @@ static int dm_scan_fdt_live(struct udevice *parent, !of_find_property(np, "u-boot,dm-pre-reloc", NULL)) continue; if (!of_device_is_available(np)) { - dm_dbg(" - ignoring disabled device\n"); + pr_debug(" - ignoring disabled device\n"); continue; } err = lists_bind_fdt(parent, np_to_ofnode(np), NULL); @@ -270,7 +270,7 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob, !dm_fdt_pre_reloc(blob, offset)) continue; if (!fdtdec_get_is_enabled(blob, offset)) { - dm_dbg(" - ignoring disabled device\n"); + pr_debug(" - ignoring disabled device\n"); continue; } err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL); diff --git a/drivers/core/util.c b/drivers/core/util.c index 2e232d57a14..aaaed4ec022 100644 --- a/drivers/core/util.c +++ b/drivers/core/util.c @@ -20,17 +20,6 @@ void dm_warn(const char *fmt, ...) } #endif -#ifdef DEBUG -void dm_dbg(const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); -} -#endif - int list_count_items(struct list_head *head) { struct list_head *node; diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index ff732ac309f..2c22b625b8b 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -64,14 +64,14 @@ int dfu_init_env_entities(char *interface, char *devstr) #endif str_env = env_get("dfu_alt_info"); if (!str_env) { - error("\"dfu_alt_info\" env variable not defined!\n"); + pr_err("\"dfu_alt_info\" env variable not defined!\n"); return -EINVAL; } env_bkp = strdup(str_env); ret = dfu_config_entities(env_bkp, interface, devstr); if (ret) { - error("DFU entities configuration failed!\n"); + pr_err("DFU entities configuration failed!\n"); return ret; } @@ -132,7 +132,7 @@ static char *dfu_get_hash_algo(void) return s; } - error("DFU hash method: %s not supported!\n", s); + pr_err("DFU hash method: %s not supported!\n", s); return NULL; } @@ -273,7 +273,7 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) /* we should be in buffer now (if not then size too large) */ if ((dfu->i_buf + size) > dfu->i_buf_end) { - error("Buffer overflow! (0x%p + 0x%x > 0x%p)\n", dfu->i_buf, + pr_err("Buffer overflow! (0x%p + 0x%x > 0x%p)\n", dfu->i_buf, size, dfu->i_buf_end); dfu_transaction_cleanup(dfu); return -1; @@ -451,7 +451,7 @@ int dfu_config_entities(char *env, char *interface, char *devstr) if (s) { ret = hash_lookup_algo(s, &dfu_hash_algo); if (ret) - error("Hash algorithm %s not supported\n", s); + pr_err("Hash algorithm %s not supported\n", s); } dfu = calloc(sizeof(*dfu), dfu_alt_num); @@ -576,7 +576,7 @@ int dfu_write_from_mem_addr(struct dfu_entity *dfu, void *buf, int size) dp, left, write); ret = dfu_write(dfu, dp, write, i); if (ret) { - error("DFU write failed\n"); + pr_err("DFU write failed\n"); return ret; } @@ -586,7 +586,7 @@ int dfu_write_from_mem_addr(struct dfu_entity *dfu, void *buf, int size) ret = dfu_flush(dfu, NULL, 0, i); if (ret) - error("DFU flush failed!"); + pr_err("DFU flush failed!"); return ret; } diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index 39e10b1a5a6..47948d369d9 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -29,7 +29,7 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu, mmc = find_mmc_device(dfu->data.mmc.dev_num); if (!mmc) { - error("Device MMC %d - not found!", dfu->data.mmc.dev_num); + pr_err("Device MMC %d - not found!", dfu->data.mmc.dev_num); return -ENODEV; } @@ -69,11 +69,11 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu, buf); break; default: - error("Operation not supported\n"); + pr_err("Operation not supported\n"); } if (n != blk_count) { - error("MMC operation failed"); + pr_err("MMC operation failed"); if (dfu->data.mmc.hw_partition >= 0) blk_select_hwpart_devnum(IF_TYPE_MMC, dfu->data.mmc.dev_num, @@ -312,7 +312,7 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) { *parg = strsep(&s, " "); if (*parg == NULL) { - error("Invalid number of arguments.\n"); + pr_err("Invalid number of arguments.\n"); return -ENODEV; } } @@ -327,13 +327,13 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) mmc = find_mmc_device(dfu->data.mmc.dev_num); if (mmc == NULL) { - error("Couldn't find MMC device no. %d.\n", + pr_err("Couldn't find MMC device no. %d.\n", dfu->data.mmc.dev_num); return -ENODEV; } if (mmc_init(mmc)) { - error("Couldn't init MMC device.\n"); + pr_err("Couldn't init MMC device.\n"); return -ENODEV; } @@ -360,7 +360,7 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) int mmcpart = third_arg; if (part_get_info(blk_dev, mmcpart, &partinfo) != 0) { - error("Couldn't find part #%d on mmc device #%d\n", + pr_err("Couldn't find part #%d on mmc device #%d\n", mmcpart, mmcdev); return -ENODEV; } @@ -374,7 +374,7 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) } else if (!strcmp(entity_type, "ext4")) { dfu->layout = DFU_FS_EXT4; } else { - error("Memory layout (%s) not supported!\n", entity_type); + pr_err("Memory layout (%s) not supported!\n", entity_type); return -ENODEV; } @@ -397,7 +397,7 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) dfu_file_buf = memalign(CONFIG_SYS_CACHELINE_SIZE, CONFIG_SYS_DFU_MAX_FILE_SIZE); if (!dfu_file_buf) { - error("Could not memalign 0x%x bytes", + pr_err("Could not memalign 0x%x bytes", CONFIG_SYS_DFU_MAX_FILE_SIZE); return -ENOMEM; } diff --git a/drivers/dfu/dfu_ram.c b/drivers/dfu/dfu_ram.c index 6e3f5316f5a..2b5e05a913e 100644 --- a/drivers/dfu/dfu_ram.c +++ b/drivers/dfu/dfu_ram.c @@ -18,12 +18,12 @@ static int dfu_transfer_medium_ram(enum dfu_op op, struct dfu_entity *dfu, u64 offset, void *buf, long *len) { if (dfu->layout != DFU_RAM_ADDR) { - error("unsupported layout: %s\n", dfu_get_layout(dfu->layout)); + pr_err("unsupported layout: %s\n", dfu_get_layout(dfu->layout)); return -EINVAL; } if (offset > dfu->data.ram.size) { - error("request exceeds allowed area\n"); + pr_err("request exceeds allowed area\n"); return -EINVAL; } @@ -62,14 +62,14 @@ int dfu_fill_entity_ram(struct dfu_entity *dfu, char *devstr, char *s) for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) { *parg = strsep(&s, " "); if (*parg == NULL) { - error("Invalid number of arguments.\n"); + pr_err("Invalid number of arguments.\n"); return -ENODEV; } } dfu->dev_type = DFU_DEV_RAM; if (strcmp(argv[0], "ram")) { - error("unsupported device: %s\n", argv[0]); + pr_err("unsupported device: %s\n", argv[0]); return -ENODEV; } diff --git a/drivers/dfu/dfu_tftp.c b/drivers/dfu/dfu_tftp.c index cd71708231f..62bf797dac9 100644 --- a/drivers/dfu/dfu_tftp.c +++ b/drivers/dfu/dfu_tftp.c @@ -43,7 +43,7 @@ int dfu_tftp_write(char *dfu_entity_name, unsigned int addr, unsigned int len, alt_setting_num = dfu_get_alt(sb); free(sb); if (alt_setting_num < 0) { - error("Alt setting [%d] to write not found!", + pr_err("Alt setting [%d] to write not found!", alt_setting_num); ret = -ENODEV; goto done; @@ -51,7 +51,7 @@ int dfu_tftp_write(char *dfu_entity_name, unsigned int addr, unsigned int len, dfu = dfu_get_entity(alt_setting_num); if (!dfu) { - error("DFU entity for alt: %d not found!", alt_setting_num); + pr_err("DFU entity for alt: %d not found!", alt_setting_num); ret = -ENODEV; goto done; } diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c index ea21fd9c6fe..3d0ce22fbc2 100644 --- a/drivers/dma/dma-uclass.c +++ b/drivers/dma/dma-uclass.c @@ -33,7 +33,7 @@ int dma_get_device(u32 transfer_type, struct udevice **devp) } if (!dev) { - error("No DMA device found that supports %x type\n", + pr_err("No DMA device found that supports %x type\n", transfer_type); return -EPROTONOSUPPORT; } diff --git a/drivers/dma/lpc32xx_dma.c b/drivers/dma/lpc32xx_dma.c index 955adfeccda..63a8a2f3408 100644 --- a/drivers/dma/lpc32xx_dma.c +++ b/drivers/dma/lpc32xx_dma.c @@ -96,7 +96,7 @@ int lpc32xx_dma_start_xfer(unsigned int channel, { if (unlikely(((BIT_MASK(channel) & alloc_ch) == 0) || (channel >= DMA_NO_OF_CHANNELS))) { - error("Request for xfer on unallocated channel %d", channel); + pr_err("Request for xfer on unallocated channel %d", channel); return -1; } writel(BIT_MASK(channel), &dma->int_tc_clear); @@ -117,7 +117,7 @@ int lpc32xx_dma_wait_status(unsigned int channel) /* Check if given channel is valid */ if (unlikely(channel >= DMA_NO_OF_CHANNELS)) { - error("Request for status on unallocated channel %d", channel); + pr_err("Request for status on unallocated channel %d", channel); return -1; } @@ -129,7 +129,7 @@ int lpc32xx_dma_wait_status(unsigned int channel) break; if (get_timer(start) > CONFIG_SYS_HZ) { - error("DMA status timeout channel %d\n", channel); + pr_err("DMA status timeout channel %d\n", channel); return -ETIMEDOUT; } udelay(1); @@ -138,7 +138,7 @@ int lpc32xx_dma_wait_status(unsigned int channel) if (unlikely(readl(&dma->raw_err_stat) & BIT_MASK(channel))) { setbits_le32(&dma->int_err_clear, BIT_MASK(channel)); setbits_le32(&dma->raw_err_stat, BIT_MASK(channel)); - error("DMA error on channel %d\n", channel); + pr_err("DMA error on channel %d\n", channel); return -1; } setbits_le32(&dma->int_tc_clear, BIT_MASK(channel)); diff --git a/drivers/dma/ti-edma3.c b/drivers/dma/ti-edma3.c index 39e97930135..635eb7876d5 100644 --- a/drivers/dma/ti-edma3.c +++ b/drivers/dma/ti-edma3.c @@ -491,7 +491,7 @@ static int ti_edma3_transfer(struct udevice *dev, int direction, void *dst, __edma3_transfer(priv->base, 1, dst, src, len); break; default: - error("Transfer type not implemented in DMA driver\n"); + pr_err("Transfer type not implemented in DMA driver\n"); break; } diff --git a/drivers/gpio/adi_gpio2.c b/drivers/gpio/adi_gpio2.c index 4db08a344ad..1012f2d8eb8 100644 --- a/drivers/gpio/adi_gpio2.c +++ b/drivers/gpio/adi_gpio2.c @@ -138,7 +138,7 @@ int peripheral_request(unsigned short per, const char *label) return 0; if (!(per & P_DEFINED)) - return -ENODEV; + return -EINVAL; BUG_ON(ident >= MAX_RESOURCES); diff --git a/drivers/gpio/atmel_pio4.c b/drivers/gpio/atmel_pio4.c index f3689467f01..30bc4296e3a 100644 --- a/drivers/gpio/atmel_pio4.c +++ b/drivers/gpio/atmel_pio4.c @@ -50,11 +50,11 @@ static int atmel_pio4_config_io_func(u32 port, u32 pin, u32 reg, mask; if (pin >= ATMEL_PIO_NPINS_PER_BANK) - return -ENODEV; + return -EINVAL; port_base = atmel_pio4_port_base(port); if (!port_base) - return -ENODEV; + return -EINVAL; mask = 1 << pin; reg = func; @@ -128,11 +128,11 @@ int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value) u32 reg, mask; if (pin >= ATMEL_PIO_NPINS_PER_BANK) - return -ENODEV; + return -EINVAL; port_base = atmel_pio4_port_base(port); if (!port_base) - return -ENODEV; + return -EINVAL; mask = 0x01 << pin; reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK; @@ -154,11 +154,11 @@ int atmel_pio4_get_pio_input(u32 port, u32 pin) u32 reg, mask; if (pin >= ATMEL_PIO_NPINS_PER_BANK) - return -ENODEV; + return -EINVAL; port_base = atmel_pio4_port_base(port); if (!port_base) - return -ENODEV; + return -EINVAL; mask = 0x01 << pin; reg = ATMEL_PIO_CFGR_FUNC_GPIO; diff --git a/drivers/gpio/imx_rgpio2p.c b/drivers/gpio/imx_rgpio2p.c index 5abc88ba547..7825714e800 100644 --- a/drivers/gpio/imx_rgpio2p.c +++ b/drivers/gpio/imx_rgpio2p.c @@ -168,13 +168,18 @@ static int imx_rgpio2p_bind(struct udevice *dev) addr = devfdt_get_addr_index(dev, 1); if (addr == FDT_ADDR_T_NONE) - return -ENODEV; + return -EINVAL; /* * TODO: * When every board is converted to driver model and DT is supported, * this can be done by auto-alloc feature, but not using calloc * to alloc memory for platdata. + * + * For example imx_rgpio2p_plat uses platform data rather than device + * tree. + * + * NOTE: DO NOT COPY this code if you are using device tree. */ plat = calloc(1, sizeof(*plat)); if (!plat) diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c index 0eb6c600f1e..c480eba9407 100644 --- a/drivers/gpio/mxc_gpio.c +++ b/drivers/gpio/mxc_gpio.c @@ -304,13 +304,18 @@ static int mxc_gpio_bind(struct udevice *dev) addr = devfdt_get_addr(dev); if (addr == FDT_ADDR_T_NONE) - return -ENODEV; + return -EINVAL; /* * TODO: * When every board is converted to driver model and DT is supported, * this can be done by auto-alloc feature, but not using calloc * to alloc memory for platdata. + * + * For example mxc_plat below uses platform data rather than device + * tree. + * + * NOTE: DO NOT COPY this code if you are using device tree. */ plat = calloc(1, sizeof(*plat)); if (!plat) diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c index b423e34ca4b..7243100219a 100644 --- a/drivers/gpio/omap_gpio.c +++ b/drivers/gpio/omap_gpio.c @@ -299,7 +299,7 @@ static int omap_gpio_probe(struct udevice *dev) static int omap_gpio_bind(struct udevice *dev) { - struct omap_gpio_platdata *plat = dev->platdata; + struct omap_gpio_platdata *plat = dev_get_platdata(dev); fdt_addr_t base_addr; if (plat) @@ -307,13 +307,17 @@ static int omap_gpio_bind(struct udevice *dev) base_addr = devfdt_get_addr(dev); if (base_addr == FDT_ADDR_T_NONE) - return -ENODEV; + return -EINVAL; /* * TODO: * When every board is converted to driver model and DT is * supported, this can be done by auto-alloc feature, but * not using calloc to alloc memory for platdata. + * + * For example am33xx_gpio uses platform data rather than device tree. + * + * NOTE: DO NOT COPY this code if you are using device tree. */ plat = calloc(1, sizeof(*plat)); if (!plat) diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c index 4962f252308..791d1d15166 100644 --- a/drivers/gpio/pca953x_gpio.c +++ b/drivers/gpio/pca953x_gpio.c @@ -249,22 +249,11 @@ static int pca953x_probe(struct udevice *dev) { struct pca953x_info *info = dev_get_platdata(dev); struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); - struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); char name[32], *str; int addr; ulong driver_data; int ret; - if (!info) { - dev_err(dev, "platdata not ready\n"); - return -ENOMEM; - } - - if (!chip) { - dev_err(dev, "i2c not ready\n"); - return -ENODEV; - } - addr = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", 0); if (addr == 0) return -ENODEV; diff --git a/drivers/gpio/tegra186_gpio.c b/drivers/gpio/tegra186_gpio.c index c5a7e13cceb..deb59e8b320 100644 --- a/drivers/gpio/tegra186_gpio.c +++ b/drivers/gpio/tegra186_gpio.c @@ -181,7 +181,7 @@ static int tegra186_gpio_bind(struct udevice *parent) regs = (uint32_t *)devfdt_get_addr_name(parent, "gpio"); if (regs == (uint32_t *)FDT_ADDR_T_NONE) - return -ENODEV; + return -EINVAL; for (port = 0; port < ctlr_data->port_count; port++) { struct tegra186_gpio_platdata *plat; diff --git a/drivers/gpio/vybrid_gpio.c b/drivers/gpio/vybrid_gpio.c index 89918e48ddc..030e8d08a45 100644 --- a/drivers/gpio/vybrid_gpio.c +++ b/drivers/gpio/vybrid_gpio.c @@ -105,32 +105,18 @@ static int vybrid_gpio_probe(struct udevice *dev) return 0; } -static int vybrid_gpio_bind(struct udevice *dev) +static int vybrid_gpio_odata_to_platdata(struct udevice *dev) { - struct vybrid_gpio_platdata *plat = dev->platdata; + struct vybrid_gpio_platdata *plat = dev_get_platdata(dev); fdt_addr_t base_addr; - if (plat) - return 0; - base_addr = devfdt_get_addr(dev); if (base_addr == FDT_ADDR_T_NONE) - return -ENODEV; - - /* - * TODO: - * When every board is converted to driver model and DT is - * supported, this can be done by auto-alloc feature, but - * not using calloc to alloc memory for platdata. - */ - plat = calloc(1, sizeof(*plat)); - if (!plat) - return -ENOMEM; + return -EINVAL; plat->base = base_addr; plat->chip = dev->req_seq; plat->port_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), NULL); - dev->platdata = plat; return 0; } @@ -144,8 +130,9 @@ U_BOOT_DRIVER(gpio_vybrid) = { .name = "gpio_vybrid", .id = UCLASS_GPIO, .ops = &gpio_vybrid_ops, + .of_match = vybrid_gpio_ids, + .ofdata_to_platdata = vybrid_gpio_odata_to_platdata, .probe = vybrid_gpio_probe, .priv_auto_alloc_size = sizeof(struct vybrid_gpios), - .of_match = vybrid_gpio_ids, - .bind = vybrid_gpio_bind, + .platdata_auto_alloc_size = sizeof(struct vybrid_gpio_platdata), }; diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c index aeeb304a876..4e8fa214739 100644 --- a/drivers/i2c/i2c-gpio.c +++ b/drivers/i2c/i2c-gpio.c @@ -322,7 +322,7 @@ static int i2c_gpio_ofdata_to_platdata(struct udevice *dev) return 0; error: - error("Can't get %s gpios! Error: %d", dev->name, ret); + pr_err("Can't get %s gpios! Error: %d", dev->name, ret); return ret; } diff --git a/drivers/i2c/imx_lpi2c.c b/drivers/i2c/imx_lpi2c.c index aa97196e237..e7ec17fe9e1 100644 --- a/drivers/i2c/imx_lpi2c.c +++ b/drivers/i2c/imx_lpi2c.c @@ -412,7 +412,7 @@ static int imx_lpi2c_probe(struct udevice *bus) addr = devfdt_get_addr(bus); if (addr == FDT_ADDR_T_NONE) - return -ENODEV; + return -EINVAL; i2c_bus->base = addr; i2c_bus->index = bus->seq; diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index b7bb76c0ed0..abf1da2ae3e 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -176,7 +176,7 @@ static int bus_i2c_set_bus_speed(struct mxc_i2c_bus *i2c_bus, int speed) int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT; if (!base) - return -ENODEV; + return -EINVAL; /* Store divider value */ writeb(idx, base + (IFDR << reg_shift)); @@ -239,7 +239,7 @@ static int tx_byte(struct mxc_i2c_bus *i2c_bus, u8 byte) if (ret < 0) return ret; if (ret & I2SR_RX_NO_AK) - return -ENODEV; + return -EREMOTEIO; return 0; } @@ -418,14 +418,14 @@ static int i2c_init_transfer(struct mxc_i2c_bus *i2c_bus, u8 chip, VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT; if (!i2c_bus->base) - return -ENODEV; + return -EINVAL; for (retry = 0; retry < 3; retry++) { ret = i2c_init_transfer_(i2c_bus, chip, addr, alen); if (ret >= 0) return 0; i2c_imx_stop(i2c_bus); - if (ret == -ENODEV) + if (ret == -EREMOTEIO) return ret; printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip, @@ -754,7 +754,7 @@ static int mxc_i2c_probe(struct udevice *bus) addr = devfdt_get_addr(bus); if (addr == FDT_ADDR_T_NONE) - return -ENODEV; + return -EINVAL; i2c_bus->base = addr; i2c_bus->index = bus->seq; @@ -783,7 +783,7 @@ static int mxc_i2c_probe(struct udevice *bus) !dm_gpio_is_valid(&i2c_bus->scl_gpio) | ret | ret2) { dev_err(dev, "i2c bus %d at %lu, fail to request scl/sda gpio\n", bus->seq, i2c_bus->base); - return -ENODEV; + return -EINVAL; } } diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index c98c6276ddb..5d338151462 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -755,7 +755,7 @@ static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed) ret = __omap24_i2c_setspeed(i2c_base, speed, &adap->waitdelay); if (ret) { - error("%s: set i2c speed failed\n", __func__); + pr_err("%s: set i2c speed failed\n", __func__); return ret; } diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c index 840b3f6046b..332280c220e 100644 --- a/drivers/i2c/rk_i2c.c +++ b/drivers/i2c/rk_i2c.c @@ -396,6 +396,7 @@ static const struct udevice_id rockchip_i2c_ids[] = { { .compatible = "rockchip,rk3066-i2c" }, { .compatible = "rockchip,rk3188-i2c" }, { .compatible = "rockchip,rk3288-i2c" }, + { .compatible = "rockchip,rk3328-i2c" }, { .compatible = "rockchip,rk3399-i2c" }, { } }; diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index bf5fefab7bf..196f2365ea5 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -549,7 +549,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, } if (list_empty(solutions)) { - error("%s: no Prescaler solution\n", __func__); + pr_err("%s: no Prescaler solution\n", __func__); ret = -EPERM; } @@ -627,7 +627,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, } if (!s) { - error("%s: no solution at all\n", __func__); + pr_err("%s: no solution at all\n", __func__); ret = -EPERM; } @@ -643,14 +643,14 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, int ret; if (setup->speed >= STM32_I2C_SPEED_END) { - error("%s: speed out of bound {%d/%d}\n", __func__, + pr_err("%s: speed out of bound {%d/%d}\n", __func__, setup->speed, STM32_I2C_SPEED_END - 1); return -EINVAL; } if ((setup->rise_time > i2c_specs[setup->speed].rise_max) || (setup->fall_time > i2c_specs[setup->speed].fall_max)) { - error("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", + pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", __func__, setup->rise_time, i2c_specs[setup->speed].rise_max, setup->fall_time, i2c_specs[setup->speed].fall_max); @@ -658,13 +658,13 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, } if (setup->dnf > STM32_I2C_DNF_MAX) { - error("%s: DNF out of bound %d/%d\n", __func__, + pr_err("%s: DNF out of bound %d/%d\n", __func__, setup->dnf, STM32_I2C_DNF_MAX); return -EINVAL; } if (setup->speed_freq > i2c_specs[setup->speed].rate) { - error("%s: Freq {%d/%d}\n", __func__, + pr_err("%s: Freq {%d/%d}\n", __func__, setup->speed_freq, i2c_specs[setup->speed].rate); return -EINVAL; } @@ -711,7 +711,7 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, setup->clock_src = clk_get_rate(&i2c_priv->clk); if (!setup->clock_src) { - error("%s: clock rate is 0\n", __func__); + pr_err("%s: clock rate is 0\n", __func__); return -EINVAL; } @@ -734,7 +734,7 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, } while (ret); if (ret) { - error("%s: impossible to compute I2C timings.\n", __func__); + pr_err("%s: impossible to compute I2C timings.\n", __func__); return ret; } diff --git a/drivers/i2c/tegra186_bpmp_i2c.c b/drivers/i2c/tegra186_bpmp_i2c.c index 931c6de508c..b46a09a4e07 100644 --- a/drivers/i2c/tegra186_bpmp_i2c.c +++ b/drivers/i2c/tegra186_bpmp_i2c.c @@ -94,7 +94,7 @@ static int tegra186_bpmp_i2c_probe(struct udevice *dev) "nvidia,bpmp-bus-id", U32_MAX); if (priv->bpmp_bus_id == U32_MAX) { debug("%s: could not parse nvidia,bpmp-bus-id\n", __func__); - return -ENODEV; + return -EINVAL; } return 0; diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index 3255e8ed370..7d23e51b69d 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -372,12 +372,12 @@ static int tegra_i2c_probe(struct udevice *dev) ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl); if (ret) { - error("reset_get_by_name() failed: %d\n", ret); + pr_err("reset_get_by_name() failed: %d\n", ret); return ret; } ret = clk_get_by_name(dev, "div-clk", &i2c_bus->clk); if (ret) { - error("clk_get_by_name() failed: %d\n", ret); + pr_err("clk_get_by_name() failed: %d\n", ret); return ret; } diff --git a/drivers/misc/tegra186_bpmp.c b/drivers/misc/tegra186_bpmp.c index d61bacfc44f..1fdf8efff3b 100644 --- a/drivers/misc/tegra186_bpmp.c +++ b/drivers/misc/tegra186_bpmp.c @@ -44,7 +44,7 @@ static int tegra186_bpmp_call(struct udevice *dev, int mrq, void *tx_msg, ret = tegra_ivc_write_get_next_frame(&priv->ivc, &ivc_frame); if (ret) { - error("tegra_ivc_write_get_next_frame() failed: %d\n", ret); + pr_err("tegra_ivc_write_get_next_frame() failed: %d\n", ret); return ret; } @@ -55,7 +55,7 @@ static int tegra186_bpmp_call(struct udevice *dev, int mrq, void *tx_msg, ret = tegra_ivc_write_advance(&priv->ivc); if (ret) { - error("tegra_ivc_write_advance() failed: %d\n", ret); + pr_err("tegra_ivc_write_advance() failed: %d\n", ret); return ret; } @@ -63,7 +63,7 @@ static int tegra186_bpmp_call(struct udevice *dev, int mrq, void *tx_msg, for (;;) { ret = tegra_ivc_channel_notified(&priv->ivc); if (ret) { - error("tegra_ivc_channel_notified() failed: %d\n", ret); + pr_err("tegra_ivc_channel_notified() failed: %d\n", ret); return ret; } @@ -73,7 +73,7 @@ static int tegra186_bpmp_call(struct udevice *dev, int mrq, void *tx_msg, /* Timeout 20ms; roughly 10x current max observed duration */ if ((timer_get_us() - start_time) > 20 * 1000) { - error("tegra_ivc_read_get_next_frame() timed out (%d)\n", + pr_err("tegra_ivc_read_get_next_frame() timed out (%d)\n", ret); return -ETIMEDOUT; } @@ -86,12 +86,12 @@ static int tegra186_bpmp_call(struct udevice *dev, int mrq, void *tx_msg, ret = tegra_ivc_read_advance(&priv->ivc); if (ret) { - error("tegra_ivc_write_advance() failed: %d\n", ret); + pr_err("tegra_ivc_write_advance() failed: %d\n", ret); return ret; } if (err) { - error("BPMP responded with error %d\n", err); + pr_err("BPMP responded with error %d\n", err); /* err isn't a U-Boot error code, so don't that */ return -EIO; } @@ -144,14 +144,14 @@ static ulong tegra186_bpmp_get_shmem(struct udevice *dev, int index) ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), "shmem", NULL, 0, index, &args); if (ret < 0) { - error("fdtdec_parse_phandle_with_args() failed: %d\n", ret); + pr_err("fdtdec_parse_phandle_with_args() failed: %d\n", ret); return ret; } reg = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, args.node, "reg", 0, NULL, true); if (reg == FDT_ADDR_T_NONE) { - error("fdtdec_get_addr_size_auto_noparent() failed\n"); + pr_err("fdtdec_get_addr_size_auto_noparent() failed\n"); return -ENODEV; } @@ -166,7 +166,7 @@ static void tegra186_bpmp_ivc_notify(struct tegra_ivc *ivc) ret = mbox_send(&priv->mbox, NULL); if (ret) - error("mbox_send() failed: %d\n", ret); + pr_err("mbox_send() failed: %d\n", ret); } static int tegra186_bpmp_probe(struct udevice *dev) @@ -179,18 +179,18 @@ static int tegra186_bpmp_probe(struct udevice *dev) ret = mbox_get_by_index(dev, 0, &priv->mbox); if (ret) { - error("mbox_get_by_index() failed: %d\n", ret); + pr_err("mbox_get_by_index() failed: %d\n", ret); return ret; } tx_base = tegra186_bpmp_get_shmem(dev, 0); if (IS_ERR_VALUE(tx_base)) { - error("tegra186_bpmp_get_shmem failed for tx_base\n"); + pr_err("tegra186_bpmp_get_shmem failed for tx_base\n"); return tx_base; } rx_base = tegra186_bpmp_get_shmem(dev, 1); if (IS_ERR_VALUE(rx_base)) { - error("tegra186_bpmp_get_shmem failed for rx_base\n"); + pr_err("tegra186_bpmp_get_shmem failed for rx_base\n"); return rx_base; } debug("shmem: rx=%lx, tx=%lx\n", rx_base, tx_base); @@ -198,7 +198,7 @@ static int tegra186_bpmp_probe(struct udevice *dev) ret = tegra_ivc_init(&priv->ivc, rx_base, tx_base, BPMP_IVC_FRAME_COUNT, BPMP_IVC_FRAME_SIZE, tegra186_bpmp_ivc_notify); if (ret) { - error("tegra_ivc_init() failed: %d\n", ret); + pr_err("tegra_ivc_init() failed: %d\n", ret); return ret; } @@ -211,7 +211,7 @@ static int tegra186_bpmp_probe(struct udevice *dev) /* Timeout 100ms */ if ((timer_get_us() - start_time) > 100 * 1000) { - error("Initial IVC reset timed out (%d)\n", ret); + pr_err("Initial IVC reset timed out (%d)\n", ret); ret = -ETIMEDOUT; goto err_free_mbox; } diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 6de927b8c6c..940508364a5 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -136,6 +136,7 @@ config MMC_PCI config MMC_OMAP_HS bool "TI OMAP High Speed Multimedia Card Interface support" select DM_REGULATOR_PBIAS if DM_MMC && DM_REGULATOR + select DM_REGULATOR_PBIAS if DM_MMC && DM_REGULATOR help This selects the TI OMAP High Speed Multimedia card Interface. If you have an omap2plus board with a Multimedia Card slot, @@ -162,12 +163,13 @@ config SH_SDHI Support for the on-chip SDHI host controller on SuperH/Renesas ARM SoCs platform config MMC_UNIPHIER - bool "UniPhier SD/MMC Host Controller support" - depends on ARCH_UNIPHIER + bool "UniPhier/RCar SD/MMC Host Controller support" + depends on ARCH_UNIPHIER || ARCH_RMOBILE depends on BLK && DM_MMC depends on OF_CONTROL help - This selects support for the SD/MMC Host Controller on UniPhier SoCs. + This selects support for the Matsushita SD/MMC Host Controller on + SocioNext UniPhier and Renesas RCar SoCs. config MMC_SANDBOX bool "Sandbox MMC support" @@ -382,6 +384,14 @@ config GENERIC_ATMEL_MCI the SD Memory Card Specification V2.0, the SDIO V2.0 specification and CE-ATA V1.1. +config STM32_SDMMC2 + bool "STMicroelectronics STM32H7 SD/MMC Host Controller support" + depends on DM_MMC && BLK && OF_CONTROL + help + This selects support for the SD/MMC controller on STM32H7 SoCs. + If you have a board based on such a SoC and with a SD/MMC slot, + say Y or M here. + endif config TEGRA124_MMC_DISABLE_EXT_LOOPBACK diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index a6becb23090..d505f37f019 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o obj-$(CONFIG_MMC_SANDBOX) += sandbox_mmc.o obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_SH_SDHI) += sh_sdhi.o +obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o # SDHCI obj-$(CONFIG_MMC_SDHCI) += sdhci.o diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index 40f7892ac80..5edd383c684 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -155,7 +155,7 @@ static int exynos_dwmci_get_config(const void *blob, int node, priv = malloc(sizeof(struct dwmci_exynos_priv_data)); if (!priv) { - error("dwmci_exynos_priv_data malloc fail!\n"); + pr_err("dwmci_exynos_priv_data malloc fail!\n"); return -ENOMEM; } diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index d795198534b..44a8ef825f3 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -44,7 +44,7 @@ int hi6220_dwmci_add_port(int index, u32 regbase, int bus_width) host = calloc(1, sizeof(struct dwmci_host)); if (!host) { - error("dwmci_host calloc failed!\n"); + pr_err("dwmci_host calloc failed!\n"); return -ENOMEM; } diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index f83c1d72410..72d1c646a2b 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -23,6 +23,18 @@ #define SDHCI_CDNS_HRS04_WDATA_SHIFT 8 #define SDHCI_CDNS_HRS04_ADDR_SHIFT 0 +#define SDHCI_CDNS_HRS06 0x18 /* eMMC control */ +#define SDHCI_CDNS_HRS06_TUNE_UP BIT(15) +#define SDHCI_CDNS_HRS06_TUNE_SHIFT 8 +#define SDHCI_CDNS_HRS06_TUNE_MASK 0x3f +#define SDHCI_CDNS_HRS06_MODE_MASK 0x7 +#define SDHCI_CDNS_HRS06_MODE_SD 0x0 +#define SDHCI_CDNS_HRS06_MODE_MMC_SDR 0x2 +#define SDHCI_CDNS_HRS06_MODE_MMC_DDR 0x3 +#define SDHCI_CDNS_HRS06_MODE_MMC_HS200 0x4 +#define SDHCI_CDNS_HRS06_MODE_MMC_HS400 0x5 +#define SDHCI_CDNS_HRS06_MODE_MMC_HS400ES 0x6 + /* SRS - Slot Register Set (SDHCI-compatible) */ #define SDHCI_CDNS_SRS_BASE 0x200 @@ -111,6 +123,44 @@ static int sdhci_cdns_phy_init(struct sdhci_cdns_plat *plat, return 0; } +static void sdhci_cdns_set_control_reg(struct sdhci_host *host) +{ + struct mmc *mmc = host->mmc; + struct sdhci_cdns_plat *plat = dev_get_platdata(mmc->dev); + unsigned int clock = mmc->clock; + u32 mode, tmp; + + /* + * REVISIT: + * The mode should be decided by MMC_TIMING_* like Linux, but + * U-Boot does not support timing. Use the clock frequency instead. + */ + if (clock <= 26000000) + mode = SDHCI_CDNS_HRS06_MODE_SD; /* use this for Legacy */ + else if (clock <= 52000000) { + if (mmc->ddr_mode) + mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR; + else + mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR; + } else { + /* + * REVISIT: + * The IP supports HS200/HS400, revisit once U-Boot support it + */ + printf("unsupported frequency %d\n", clock); + return; + } + + tmp = readl(plat->hrs_addr + SDHCI_CDNS_HRS06); + tmp &= ~SDHCI_CDNS_HRS06_MODE_MASK; + tmp |= mode; + writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS06); +} + +static const struct sdhci_ops sdhci_cdns_ops = { + .set_control_reg = sdhci_cdns_set_control_reg, +}; + static int sdhci_cdns_bind(struct udevice *dev) { struct sdhci_cdns_plat *plat = dev_get_platdata(dev); @@ -137,6 +187,7 @@ static int sdhci_cdns_probe(struct udevice *dev) host->name = dev->name; host->ioaddr = plat->hrs_addr + SDHCI_CDNS_SRS_BASE; + host->ops = &sdhci_cdns_ops; host->quirks |= SDHCI_QUIRK_WAIT_SEND_CMD; ret = sdhci_cdns_phy_init(plat, gd->fdt_blob, dev_of_offset(dev)); diff --git a/drivers/mmc/sti_sdhci.c b/drivers/mmc/sti_sdhci.c index d8b5888b7ce..a98c1eba0f6 100644 --- a/drivers/mmc/sti_sdhci.c +++ b/drivers/mmc/sti_sdhci.c @@ -43,7 +43,7 @@ static int sti_mmc_core_config(struct udevice *dev) if (plat->instance) { ret = reset_deassert(&plat->reset); if (ret < 0) { - error("MMC1 deassert failed: %d", ret); + pr_err("MMC1 deassert failed: %d", ret); return ret; } } diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c new file mode 100644 index 00000000000..0bf7135b4ff --- /dev/null +++ b/drivers/mmc/stm32_sdmmc2.c @@ -0,0 +1,608 @@ +/* + * Copyright (C) STMicroelectronics SA 2017 + * Author(s): Patrice CHOTARD, <patrice.chotard@st.com> for STMicroelectronics. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <fdtdec.h> +#include <libfdt.h> +#include <mmc.h> +#include <reset.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <linux/iopoll.h> + +struct stm32_sdmmc2_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +struct stm32_sdmmc2_priv { + fdt_addr_t base; + struct clk clk; + struct reset_ctl reset_ctl; + struct gpio_desc cd_gpio; + u32 clk_reg_msk; + u32 pwr_reg_msk; +}; + +struct stm32_sdmmc2_ctx { + u32 cache_start; + u32 cache_end; + u32 data_length; + bool dpsm_abort; +}; + +/* SDMMC REGISTERS OFFSET */ +#define SDMMC_POWER 0x00 /* SDMMC power control */ +#define SDMMC_CLKCR 0x04 /* SDMMC clock control */ +#define SDMMC_ARG 0x08 /* SDMMC argument */ +#define SDMMC_CMD 0x0C /* SDMMC command */ +#define SDMMC_RESP1 0x14 /* SDMMC response 1 */ +#define SDMMC_RESP2 0x18 /* SDMMC response 2 */ +#define SDMMC_RESP3 0x1C /* SDMMC response 3 */ +#define SDMMC_RESP4 0x20 /* SDMMC response 4 */ +#define SDMMC_DTIMER 0x24 /* SDMMC data timer */ +#define SDMMC_DLEN 0x28 /* SDMMC data length */ +#define SDMMC_DCTRL 0x2C /* SDMMC data control */ +#define SDMMC_DCOUNT 0x30 /* SDMMC data counter */ +#define SDMMC_STA 0x34 /* SDMMC status */ +#define SDMMC_ICR 0x38 /* SDMMC interrupt clear */ +#define SDMMC_MASK 0x3C /* SDMMC mask */ +#define SDMMC_IDMACTRL 0x50 /* SDMMC DMA control */ +#define SDMMC_IDMABASE0 0x58 /* SDMMC DMA buffer 0 base address */ + +/* SDMMC_POWER register */ +#define SDMMC_POWER_PWRCTRL GENMASK(1, 0) +#define SDMMC_POWER_VSWITCH BIT(2) +#define SDMMC_POWER_VSWITCHEN BIT(3) +#define SDMMC_POWER_DIRPOL BIT(4) + +/* SDMMC_CLKCR register */ +#define SDMMC_CLKCR_CLKDIV GENMASK(9, 0) +#define SDMMC_CLKCR_CLKDIV_MAX SDMMC_CLKCR_CLKDIV +#define SDMMC_CLKCR_PWRSAV BIT(12) +#define SDMMC_CLKCR_WIDBUS_4 BIT(14) +#define SDMMC_CLKCR_WIDBUS_8 BIT(15) +#define SDMMC_CLKCR_NEGEDGE BIT(16) +#define SDMMC_CLKCR_HWFC_EN BIT(17) +#define SDMMC_CLKCR_DDR BIT(18) +#define SDMMC_CLKCR_BUSSPEED BIT(19) +#define SDMMC_CLKCR_SELCLKRX GENMASK(21, 20) + +/* SDMMC_CMD register */ +#define SDMMC_CMD_CMDINDEX GENMASK(5, 0) +#define SDMMC_CMD_CMDTRANS BIT(6) +#define SDMMC_CMD_CMDSTOP BIT(7) +#define SDMMC_CMD_WAITRESP GENMASK(9, 8) +#define SDMMC_CMD_WAITRESP_0 BIT(8) +#define SDMMC_CMD_WAITRESP_1 BIT(9) +#define SDMMC_CMD_WAITINT BIT(10) +#define SDMMC_CMD_WAITPEND BIT(11) +#define SDMMC_CMD_CPSMEN BIT(12) +#define SDMMC_CMD_DTHOLD BIT(13) +#define SDMMC_CMD_BOOTMODE BIT(14) +#define SDMMC_CMD_BOOTEN BIT(15) +#define SDMMC_CMD_CMDSUSPEND BIT(16) + +/* SDMMC_DCTRL register */ +#define SDMMC_DCTRL_DTEN BIT(0) +#define SDMMC_DCTRL_DTDIR BIT(1) +#define SDMMC_DCTRL_DTMODE GENMASK(3, 2) +#define SDMMC_DCTRL_DBLOCKSIZE GENMASK(7, 4) +#define SDMMC_DCTRL_DBLOCKSIZE_SHIFT 4 +#define SDMMC_DCTRL_RWSTART BIT(8) +#define SDMMC_DCTRL_RWSTOP BIT(9) +#define SDMMC_DCTRL_RWMOD BIT(10) +#define SDMMC_DCTRL_SDMMCEN BIT(11) +#define SDMMC_DCTRL_BOOTACKEN BIT(12) +#define SDMMC_DCTRL_FIFORST BIT(13) + +/* SDMMC_STA register */ +#define SDMMC_STA_CCRCFAIL BIT(0) +#define SDMMC_STA_DCRCFAIL BIT(1) +#define SDMMC_STA_CTIMEOUT BIT(2) +#define SDMMC_STA_DTIMEOUT BIT(3) +#define SDMMC_STA_TXUNDERR BIT(4) +#define SDMMC_STA_RXOVERR BIT(5) +#define SDMMC_STA_CMDREND BIT(6) +#define SDMMC_STA_CMDSENT BIT(7) +#define SDMMC_STA_DATAEND BIT(8) +#define SDMMC_STA_DHOLD BIT(9) +#define SDMMC_STA_DBCKEND BIT(10) +#define SDMMC_STA_DABORT BIT(11) +#define SDMMC_STA_DPSMACT BIT(12) +#define SDMMC_STA_CPSMACT BIT(13) +#define SDMMC_STA_TXFIFOHE BIT(14) +#define SDMMC_STA_RXFIFOHF BIT(15) +#define SDMMC_STA_TXFIFOF BIT(16) +#define SDMMC_STA_RXFIFOF BIT(17) +#define SDMMC_STA_TXFIFOE BIT(18) +#define SDMMC_STA_RXFIFOE BIT(19) +#define SDMMC_STA_BUSYD0 BIT(20) +#define SDMMC_STA_BUSYD0END BIT(21) +#define SDMMC_STA_SDMMCIT BIT(22) +#define SDMMC_STA_ACKFAIL BIT(23) +#define SDMMC_STA_ACKTIMEOUT BIT(24) +#define SDMMC_STA_VSWEND BIT(25) +#define SDMMC_STA_CKSTOP BIT(26) +#define SDMMC_STA_IDMATE BIT(27) +#define SDMMC_STA_IDMABTC BIT(28) + +/* SDMMC_ICR register */ +#define SDMMC_ICR_CCRCFAILC BIT(0) +#define SDMMC_ICR_DCRCFAILC BIT(1) +#define SDMMC_ICR_CTIMEOUTC BIT(2) +#define SDMMC_ICR_DTIMEOUTC BIT(3) +#define SDMMC_ICR_TXUNDERRC BIT(4) +#define SDMMC_ICR_RXOVERRC BIT(5) +#define SDMMC_ICR_CMDRENDC BIT(6) +#define SDMMC_ICR_CMDSENTC BIT(7) +#define SDMMC_ICR_DATAENDC BIT(8) +#define SDMMC_ICR_DHOLDC BIT(9) +#define SDMMC_ICR_DBCKENDC BIT(10) +#define SDMMC_ICR_DABORTC BIT(11) +#define SDMMC_ICR_BUSYD0ENDC BIT(21) +#define SDMMC_ICR_SDMMCITC BIT(22) +#define SDMMC_ICR_ACKFAILC BIT(23) +#define SDMMC_ICR_ACKTIMEOUTC BIT(24) +#define SDMMC_ICR_VSWENDC BIT(25) +#define SDMMC_ICR_CKSTOPC BIT(26) +#define SDMMC_ICR_IDMATEC BIT(27) +#define SDMMC_ICR_IDMABTCC BIT(28) +#define SDMMC_ICR_STATIC_FLAGS ((GENMASK(28, 21)) | (GENMASK(11, 0))) + +/* SDMMC_MASK register */ +#define SDMMC_MASK_CCRCFAILIE BIT(0) +#define SDMMC_MASK_DCRCFAILIE BIT(1) +#define SDMMC_MASK_CTIMEOUTIE BIT(2) +#define SDMMC_MASK_DTIMEOUTIE BIT(3) +#define SDMMC_MASK_TXUNDERRIE BIT(4) +#define SDMMC_MASK_RXOVERRIE BIT(5) +#define SDMMC_MASK_CMDRENDIE BIT(6) +#define SDMMC_MASK_CMDSENTIE BIT(7) +#define SDMMC_MASK_DATAENDIE BIT(8) +#define SDMMC_MASK_DHOLDIE BIT(9) +#define SDMMC_MASK_DBCKENDIE BIT(10) +#define SDMMC_MASK_DABORTIE BIT(11) +#define SDMMC_MASK_TXFIFOHEIE BIT(14) +#define SDMMC_MASK_RXFIFOHFIE BIT(15) +#define SDMMC_MASK_RXFIFOFIE BIT(17) +#define SDMMC_MASK_TXFIFOEIE BIT(18) +#define SDMMC_MASK_BUSYD0ENDIE BIT(21) +#define SDMMC_MASK_SDMMCITIE BIT(22) +#define SDMMC_MASK_ACKFAILIE BIT(23) +#define SDMMC_MASK_ACKTIMEOUTIE BIT(24) +#define SDMMC_MASK_VSWENDIE BIT(25) +#define SDMMC_MASK_CKSTOPIE BIT(26) +#define SDMMC_MASK_IDMABTCIE BIT(28) + +/* SDMMC_IDMACTRL register */ +#define SDMMC_IDMACTRL_IDMAEN BIT(0) + +#define SDMMC_CMD_TIMEOUT 0xFFFFFFFF + +DECLARE_GLOBAL_DATA_PTR; + +static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, + struct mmc_data *data, + struct stm32_sdmmc2_ctx *ctx) +{ + u32 data_ctrl, idmabase0; + + /* Configure the SDMMC DPSM (Data Path State Machine) */ + data_ctrl = (__ilog2(data->blocksize) << + SDMMC_DCTRL_DBLOCKSIZE_SHIFT) & + SDMMC_DCTRL_DBLOCKSIZE; + + if (data->flags & MMC_DATA_READ) { + data_ctrl |= SDMMC_DCTRL_DTDIR; + idmabase0 = (u32)data->dest; + } else { + idmabase0 = (u32)data->src; + } + + /* Set the SDMMC Data TimeOut value */ + writel(SDMMC_CMD_TIMEOUT, priv->base + SDMMC_DTIMER); + + /* Set the SDMMC DataLength value */ + writel(ctx->data_length, priv->base + SDMMC_DLEN); + + /* Write to SDMMC DCTRL */ + writel(data_ctrl, priv->base + SDMMC_DCTRL); + + /* Cache align */ + ctx->cache_start = rounddown(idmabase0, ARCH_DMA_MINALIGN); + ctx->cache_end = roundup(idmabase0 + ctx->data_length, + ARCH_DMA_MINALIGN); + + /* + * Flush data cache before DMA start (clean and invalidate) + * Clean also needed for read + * Avoid issue on buffer not cached-aligned + */ + flush_dcache_range(ctx->cache_start, ctx->cache_end); + + /* Enable internal DMA */ + writel(idmabase0, priv->base + SDMMC_IDMABASE0); + writel(SDMMC_IDMACTRL_IDMAEN, priv->base + SDMMC_IDMACTRL); +} + +static void stm32_sdmmc2_start_cmd(struct stm32_sdmmc2_priv *priv, + struct mmc_cmd *cmd, u32 cmd_param) +{ + if (readl(priv->base + SDMMC_ARG) & SDMMC_CMD_CPSMEN) + writel(0, priv->base + SDMMC_ARG); + + cmd_param |= cmd->cmdidx | SDMMC_CMD_CPSMEN; + if (cmd->resp_type & MMC_RSP_PRESENT) { + if (cmd->resp_type & MMC_RSP_136) + cmd_param |= SDMMC_CMD_WAITRESP; + else if (cmd->resp_type & MMC_RSP_CRC) + cmd_param |= SDMMC_CMD_WAITRESP_0; + else + cmd_param |= SDMMC_CMD_WAITRESP_1; + } + + /* Clear flags */ + writel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR); + + /* Set SDMMC argument value */ + writel(cmd->cmdarg, priv->base + SDMMC_ARG); + + /* Set SDMMC command parameters */ + writel(cmd_param, priv->base + SDMMC_CMD); +} + +static int stm32_sdmmc2_end_cmd(struct stm32_sdmmc2_priv *priv, + struct mmc_cmd *cmd, + struct stm32_sdmmc2_ctx *ctx) +{ + u32 mask = SDMMC_STA_CTIMEOUT; + u32 status; + int ret; + + if (cmd->resp_type & MMC_RSP_PRESENT) { + mask |= SDMMC_STA_CMDREND; + if (cmd->resp_type & MMC_RSP_CRC) + mask |= SDMMC_STA_CCRCFAIL; + } else { + mask |= SDMMC_STA_CMDSENT; + } + + /* Polling status register */ + ret = readl_poll_timeout(priv->base + SDMMC_STA, status, status & mask, + 300); + + if (ret < 0) { + debug("%s: timeout reading SDMMC_STA register\n", __func__); + ctx->dpsm_abort = true; + return ret; + } + + /* Check status */ + if (status & SDMMC_STA_CTIMEOUT) { + debug("%s: error SDMMC_STA_CTIMEOUT (0x%x) for cmd %d\n", + __func__, status, cmd->cmdidx); + ctx->dpsm_abort = true; + return -ETIMEDOUT; + } + + if (status & SDMMC_STA_CCRCFAIL && cmd->resp_type & MMC_RSP_CRC) { + debug("%s: error SDMMC_STA_CCRCFAIL (0x%x) for cmd %d\n", + __func__, status, cmd->cmdidx); + ctx->dpsm_abort = true; + return -EILSEQ; + } + + if (status & SDMMC_STA_CMDREND && cmd->resp_type & MMC_RSP_PRESENT) { + cmd->response[0] = readl(priv->base + SDMMC_RESP1); + if (cmd->resp_type & MMC_RSP_136) { + cmd->response[1] = readl(priv->base + SDMMC_RESP2); + cmd->response[2] = readl(priv->base + SDMMC_RESP3); + cmd->response[3] = readl(priv->base + SDMMC_RESP4); + } + } + + return 0; +} + +static int stm32_sdmmc2_end_data(struct stm32_sdmmc2_priv *priv, + struct mmc_cmd *cmd, + struct mmc_data *data, + struct stm32_sdmmc2_ctx *ctx) +{ + u32 mask = SDMMC_STA_DCRCFAIL | SDMMC_STA_DTIMEOUT | + SDMMC_STA_IDMATE | SDMMC_STA_DATAEND; + u32 status; + + if (data->flags & MMC_DATA_READ) + mask |= SDMMC_STA_RXOVERR; + else + mask |= SDMMC_STA_TXUNDERR; + + status = readl(priv->base + SDMMC_STA); + while (!(status & mask)) + status = readl(priv->base + SDMMC_STA); + + /* + * Need invalidate the dcache again to avoid any + * cache-refill during the DMA operations (pre-fetching) + */ + if (data->flags & MMC_DATA_READ) + invalidate_dcache_range(ctx->cache_start, ctx->cache_end); + + if (status & SDMMC_STA_DCRCFAIL) { + debug("%s: error SDMMC_STA_DCRCFAIL (0x%x) for cmd %d\n", + __func__, status, cmd->cmdidx); + if (readl(priv->base + SDMMC_DCOUNT)) + ctx->dpsm_abort = true; + return -EILSEQ; + } + + if (status & SDMMC_STA_DTIMEOUT) { + debug("%s: error SDMMC_STA_DTIMEOUT (0x%x) for cmd %d\n", + __func__, status, cmd->cmdidx); + ctx->dpsm_abort = true; + return -ETIMEDOUT; + } + + if (status & SDMMC_STA_TXUNDERR) { + debug("%s: error SDMMC_STA_TXUNDERR (0x%x) for cmd %d\n", + __func__, status, cmd->cmdidx); + ctx->dpsm_abort = true; + return -EIO; + } + + if (status & SDMMC_STA_RXOVERR) { + debug("%s: error SDMMC_STA_RXOVERR (0x%x) for cmd %d\n", + __func__, status, cmd->cmdidx); + ctx->dpsm_abort = true; + return -EIO; + } + + if (status & SDMMC_STA_IDMATE) { + debug("%s: error SDMMC_STA_IDMATE (0x%x) for cmd %d\n", + __func__, status, cmd->cmdidx); + ctx->dpsm_abort = true; + return -EIO; + } + + return 0; +} + +static int stm32_sdmmc2_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct stm32_sdmmc2_priv *priv = dev_get_priv(dev); + struct stm32_sdmmc2_ctx ctx; + u32 cmdat = data ? SDMMC_CMD_CMDTRANS : 0; + int ret, retry = 3; + +retry_cmd: + ctx.data_length = 0; + ctx.dpsm_abort = false; + + if (data) { + ctx.data_length = data->blocks * data->blocksize; + stm32_sdmmc2_start_data(priv, data, &ctx); + } + + stm32_sdmmc2_start_cmd(priv, cmd, cmdat); + + debug("%s: send cmd %d data: 0x%x @ 0x%x\n", + __func__, cmd->cmdidx, + data ? ctx.data_length : 0, (unsigned int)data); + + ret = stm32_sdmmc2_end_cmd(priv, cmd, &ctx); + + if (data && !ret) + ret = stm32_sdmmc2_end_data(priv, cmd, data, &ctx); + + /* Clear flags */ + writel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR); + if (data) + writel(0x0, priv->base + SDMMC_IDMACTRL); + + /* + * To stop Data Path State Machine, a stop_transmission command + * shall be send on cmd or data errors. + */ + if (ctx.dpsm_abort && (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION)) { + struct mmc_cmd stop_cmd; + + stop_cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; + stop_cmd.cmdarg = 0; + stop_cmd.resp_type = MMC_RSP_R1b; + + debug("%s: send STOP command to abort dpsm treatments\n", + __func__); + + stm32_sdmmc2_start_cmd(priv, &stop_cmd, SDMMC_CMD_CMDSTOP); + stm32_sdmmc2_end_cmd(priv, &stop_cmd, &ctx); + + writel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR); + } + + if ((ret != -ETIMEDOUT) && (ret != 0) && retry) { + printf("%s: cmd %d failed, retrying ...\n", + __func__, cmd->cmdidx); + retry--; + goto retry_cmd; + } + + debug("%s: end for CMD %d, ret = %d\n", __func__, cmd->cmdidx, ret); + + return ret; +} + +static void stm32_sdmmc2_pwron(struct stm32_sdmmc2_priv *priv) +{ + /* Reset */ + reset_assert(&priv->reset_ctl); + udelay(2); + reset_deassert(&priv->reset_ctl); + + udelay(1000); + + /* Set Power State to ON */ + writel(SDMMC_POWER_PWRCTRL | priv->pwr_reg_msk, priv->base + SDMMC_POWER); + + /* + * 1ms: required power up waiting time before starting the + * SD initialization sequence + */ + udelay(1000); +} + +#define IS_RISING_EDGE(reg) (reg & SDMMC_CLKCR_NEGEDGE ? 0 : 1) +static int stm32_sdmmc2_set_ios(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct stm32_sdmmc2_priv *priv = dev_get_priv(dev); + struct stm32_sdmmc2_plat *plat = dev_get_platdata(dev); + struct mmc_config *cfg = &plat->cfg; + u32 desired = mmc->clock; + u32 sys_clock = clk_get_rate(&priv->clk); + u32 clk = 0; + + debug("%s: bus_with = %d, clock = %d\n", __func__, + mmc->bus_width, mmc->clock); + + if ((mmc->bus_width == 1) && (desired == cfg->f_min)) + stm32_sdmmc2_pwron(priv); + + /* + * clk_div = 0 => command and data generated on SDMMCCLK falling edge + * clk_div > 0 and NEGEDGE = 0 => command and data generated on + * SDMMCCLK rising edge + * clk_div > 0 and NEGEDGE = 1 => command and data generated on + * SDMMCCLK falling edge + */ + if (desired && ((sys_clock > desired) || + IS_RISING_EDGE(priv->clk_reg_msk))) { + clk = DIV_ROUND_UP(sys_clock, 2 * desired); + if (clk > SDMMC_CLKCR_CLKDIV_MAX) + clk = SDMMC_CLKCR_CLKDIV_MAX; + } + + if (mmc->bus_width == 4) + clk |= SDMMC_CLKCR_WIDBUS_4; + if (mmc->bus_width == 8) + clk |= SDMMC_CLKCR_WIDBUS_8; + + writel(clk | priv->clk_reg_msk, priv->base + SDMMC_CLKCR); + + return 0; +} + +static int stm32_sdmmc2_getcd(struct udevice *dev) +{ + struct stm32_sdmmc2_priv *priv = dev_get_priv(dev); + + debug("stm32_sdmmc2_getcd called\n"); + + if (dm_gpio_is_valid(&priv->cd_gpio)) + return dm_gpio_get_value(&priv->cd_gpio); + + return 1; +} + +static const struct dm_mmc_ops stm32_sdmmc2_ops = { + .send_cmd = stm32_sdmmc2_send_cmd, + .set_ios = stm32_sdmmc2_set_ios, + .get_cd = stm32_sdmmc2_getcd, +}; + +static int stm32_sdmmc2_probe(struct udevice *dev) +{ + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct stm32_sdmmc2_plat *plat = dev_get_platdata(dev); + struct stm32_sdmmc2_priv *priv = dev_get_priv(dev); + struct mmc_config *cfg = &plat->cfg; + int ret; + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + if (dev_read_bool(dev, "st,negedge")) + priv->clk_reg_msk |= SDMMC_CLKCR_NEGEDGE; + if (dev_read_bool(dev, "st,dirpol")) + priv->pwr_reg_msk |= SDMMC_POWER_DIRPOL; + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + goto clk_free; + + ret = reset_get_by_index(dev, 0, &priv->reset_ctl); + if (ret) + goto clk_disable; + + gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, + GPIOD_IS_IN); + + cfg->f_min = 400000; + cfg->f_max = dev_read_u32_default(dev, "max-frequency", 52000000); + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + cfg->name = "STM32 SDMMC2"; + + cfg->host_caps = 0; + if (cfg->f_max > 25000000) + cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + + switch (dev_read_u32_default(dev, "bus-width", 1)) { + case 8: + cfg->host_caps |= MMC_MODE_8BIT; + case 4: + cfg->host_caps |= MMC_MODE_4BIT; + break; + case 1: + break; + default: + pr_err("invalid \"bus-width\" property, force to 1\n"); + } + + upriv->mmc = &plat->mmc; + + return 0; + +clk_disable: + clk_disable(&priv->clk); +clk_free: + clk_free(&priv->clk); + + return ret; +} + +int stm32_sdmmc_bind(struct udevice *dev) +{ + struct stm32_sdmmc2_plat *plat = dev_get_platdata(dev); + + return mmc_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id stm32_sdmmc2_ids[] = { + { .compatible = "st,stm32-sdmmc2" }, + { } +}; + +U_BOOT_DRIVER(stm32_sdmmc2) = { + .name = "stm32_sdmmc2", + .id = UCLASS_MMC, + .of_match = stm32_sdmmc2_ids, + .ops = &stm32_sdmmc2_ops, + .probe = stm32_sdmmc2_probe, + .bind = stm32_sdmmc_bind, + .priv_auto_alloc_size = sizeof(struct stm32_sdmmc2_priv), + .platdata_auto_alloc_size = sizeof(struct stm32_sdmmc2_plat), +}; diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 721b75fddac..0d1203cb766 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -14,6 +14,7 @@ #include <linux/dma-direction.h> #include <linux/io.h> #include <linux/sizes.h> +#include <power/regulator.h> #include <asm/unaligned.h> DECLARE_GLOBAL_DATA_PTR; @@ -132,8 +133,43 @@ struct uniphier_sd_priv { #define UNIPHIER_SD_CAP_NONREMOVABLE BIT(0) /* Nonremovable e.g. eMMC */ #define UNIPHIER_SD_CAP_DMA_INTERNAL BIT(1) /* have internal DMA engine */ #define UNIPHIER_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */ +#define UNIPHIER_SD_CAP_64BIT BIT(3) /* Controller is 64bit */ }; +static u64 uniphier_sd_readq(struct uniphier_sd_priv *priv, unsigned int reg) +{ + if (priv->caps & UNIPHIER_SD_CAP_64BIT) + return readq(priv->regbase + (reg << 1)); + else + return readq(priv->regbase + reg); +} + +static void uniphier_sd_writeq(struct uniphier_sd_priv *priv, + u64 val, unsigned int reg) +{ + if (priv->caps & UNIPHIER_SD_CAP_64BIT) + writeq(val, priv->regbase + (reg << 1)); + else + writeq(val, priv->regbase + reg); +} + +static u32 uniphier_sd_readl(struct uniphier_sd_priv *priv, unsigned int reg) +{ + if (priv->caps & UNIPHIER_SD_CAP_64BIT) + return readl(priv->regbase + (reg << 1)); + else + return readl(priv->regbase + reg); +} + +static void uniphier_sd_writel(struct uniphier_sd_priv *priv, + u32 val, unsigned int reg) +{ + if (priv->caps & UNIPHIER_SD_CAP_64BIT) + writel(val, priv->regbase + (reg << 1)); + else + writel(val, priv->regbase + reg); +} + static dma_addr_t __dma_map_single(void *ptr, size_t size, enum dma_data_direction dir) { @@ -157,7 +193,7 @@ static void __dma_unmap_single(dma_addr_t addr, size_t size, static int uniphier_sd_check_error(struct udevice *dev) { struct uniphier_sd_priv *priv = dev_get_priv(dev); - u32 info2 = readl(priv->regbase + UNIPHIER_SD_INFO2); + u32 info2 = uniphier_sd_readl(priv, UNIPHIER_SD_INFO2); if (info2 & UNIPHIER_SD_INFO2_ERR_RTO) { /* @@ -195,7 +231,7 @@ static int uniphier_sd_wait_for_irq(struct udevice *dev, unsigned int reg, long wait = 1000000; int ret; - while (!(readl(priv->regbase + reg) & flag)) { + while (!(uniphier_sd_readl(priv, reg) & flag)) { if (wait-- < 0) { dev_err(dev, "timeout\n"); return -ETIMEDOUT; @@ -211,7 +247,7 @@ static int uniphier_sd_wait_for_irq(struct udevice *dev, unsigned int reg, return 0; } -static int uniphier_sd_pio_read_one_block(struct udevice *dev, u32 **pbuf, +static int uniphier_sd_pio_read_one_block(struct udevice *dev, char *pbuf, uint blocksize) { struct uniphier_sd_priv *priv = dev_get_priv(dev); @@ -227,22 +263,44 @@ static int uniphier_sd_pio_read_one_block(struct udevice *dev, u32 **pbuf, * Clear the status flag _before_ read the buffer out because * UNIPHIER_SD_INFO2_BRE is edge-triggered, not level-triggered. */ - writel(0, priv->regbase + UNIPHIER_SD_INFO2); - - if (likely(IS_ALIGNED((unsigned long)*pbuf, 4))) { - for (i = 0; i < blocksize / 4; i++) - *(*pbuf)++ = readl(priv->regbase + UNIPHIER_SD_BUF); + uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO2); + + if (priv->caps & UNIPHIER_SD_CAP_64BIT) { + u64 *buf = (u64 *)pbuf; + if (likely(IS_ALIGNED((uintptr_t)buf, 8))) { + for (i = 0; i < blocksize / 8; i++) { + *buf++ = uniphier_sd_readq(priv, + UNIPHIER_SD_BUF); + } + } else { + for (i = 0; i < blocksize / 8; i++) { + u64 data; + data = uniphier_sd_readq(priv, + UNIPHIER_SD_BUF); + put_unaligned(data, buf++); + } + } } else { - for (i = 0; i < blocksize / 4; i++) - put_unaligned(readl(priv->regbase + UNIPHIER_SD_BUF), - (*pbuf)++); + u32 *buf = (u32 *)pbuf; + if (likely(IS_ALIGNED((uintptr_t)buf, 4))) { + for (i = 0; i < blocksize / 4; i++) { + *buf++ = uniphier_sd_readl(priv, + UNIPHIER_SD_BUF); + } + } else { + for (i = 0; i < blocksize / 4; i++) { + u32 data; + data = uniphier_sd_readl(priv, UNIPHIER_SD_BUF); + put_unaligned(data, buf++); + } + } } return 0; } static int uniphier_sd_pio_write_one_block(struct udevice *dev, - const u32 **pbuf, uint blocksize) + const char *pbuf, uint blocksize) { struct uniphier_sd_priv *priv = dev_get_priv(dev); int i, ret; @@ -253,15 +311,36 @@ static int uniphier_sd_pio_write_one_block(struct udevice *dev, if (ret) return ret; - writel(0, priv->regbase + UNIPHIER_SD_INFO2); - - if (likely(IS_ALIGNED((unsigned long)*pbuf, 4))) { - for (i = 0; i < blocksize / 4; i++) - writel(*(*pbuf)++, priv->regbase + UNIPHIER_SD_BUF); + uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO2); + + if (priv->caps & UNIPHIER_SD_CAP_64BIT) { + const u64 *buf = (const u64 *)pbuf; + if (likely(IS_ALIGNED((uintptr_t)buf, 8))) { + for (i = 0; i < blocksize / 8; i++) { + uniphier_sd_writeq(priv, *buf++, + UNIPHIER_SD_BUF); + } + } else { + for (i = 0; i < blocksize / 8; i++) { + u64 data = get_unaligned(buf++); + uniphier_sd_writeq(priv, data, + UNIPHIER_SD_BUF); + } + } } else { - for (i = 0; i < blocksize / 4; i++) - writel(get_unaligned((*pbuf)++), - priv->regbase + UNIPHIER_SD_BUF); + const u32 *buf = (const u32 *)pbuf; + if (likely(IS_ALIGNED((uintptr_t)buf, 4))) { + for (i = 0; i < blocksize / 4; i++) { + uniphier_sd_writel(priv, *buf++, + UNIPHIER_SD_BUF); + } + } else { + for (i = 0; i < blocksize / 4; i++) { + u32 data = get_unaligned(buf++); + uniphier_sd_writel(priv, data, + UNIPHIER_SD_BUF); + } + } } return 0; @@ -269,19 +348,24 @@ static int uniphier_sd_pio_write_one_block(struct udevice *dev, static int uniphier_sd_pio_xfer(struct udevice *dev, struct mmc_data *data) { - u32 *dest = (u32 *)data->dest; - const u32 *src = (const u32 *)data->src; + const char *src = data->src; + char *dest = data->dest; int i, ret; for (i = 0; i < data->blocks; i++) { if (data->flags & MMC_DATA_READ) - ret = uniphier_sd_pio_read_one_block(dev, &dest, + ret = uniphier_sd_pio_read_one_block(dev, dest, data->blocksize); else - ret = uniphier_sd_pio_write_one_block(dev, &src, + ret = uniphier_sd_pio_write_one_block(dev, src, data->blocksize); if (ret) return ret; + + if (data->flags & MMC_DATA_READ) + dest += data->blocksize; + else + src += data->blocksize; } return 0; @@ -292,22 +376,22 @@ static void uniphier_sd_dma_start(struct uniphier_sd_priv *priv, { u32 tmp; - writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO1); - writel(0, priv->regbase + UNIPHIER_SD_DMA_INFO2); + uniphier_sd_writel(priv, 0, UNIPHIER_SD_DMA_INFO1); + uniphier_sd_writel(priv, 0, UNIPHIER_SD_DMA_INFO2); /* enable DMA */ - tmp = readl(priv->regbase + UNIPHIER_SD_EXTMODE); + tmp = uniphier_sd_readl(priv, UNIPHIER_SD_EXTMODE); tmp |= UNIPHIER_SD_EXTMODE_DMA_EN; - writel(tmp, priv->regbase + UNIPHIER_SD_EXTMODE); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_EXTMODE); - writel(dma_addr & U32_MAX, priv->regbase + UNIPHIER_SD_DMA_ADDR_L); + uniphier_sd_writel(priv, dma_addr & U32_MAX, UNIPHIER_SD_DMA_ADDR_L); /* suppress the warning "right shift count >= width of type" */ dma_addr >>= min_t(int, 32, 8 * sizeof(dma_addr)); - writel(dma_addr & U32_MAX, priv->regbase + UNIPHIER_SD_DMA_ADDR_H); + uniphier_sd_writel(priv, dma_addr & U32_MAX, UNIPHIER_SD_DMA_ADDR_H); - writel(UNIPHIER_SD_DMA_CTL_START, priv->regbase + UNIPHIER_SD_DMA_CTL); + uniphier_sd_writel(priv, UNIPHIER_SD_DMA_CTL_START, UNIPHIER_SD_DMA_CTL); } static int uniphier_sd_dma_wait_for_irq(struct udevice *dev, u32 flag, @@ -316,7 +400,7 @@ static int uniphier_sd_dma_wait_for_irq(struct udevice *dev, u32 flag, struct uniphier_sd_priv *priv = dev_get_priv(dev); long wait = 1000000 + 10 * blocks; - while (!(readl(priv->regbase + UNIPHIER_SD_DMA_INFO1) & flag)) { + while (!(uniphier_sd_readl(priv, UNIPHIER_SD_DMA_INFO1) & flag)) { if (wait-- < 0) { dev_err(dev, "timeout during DMA\n"); return -ETIMEDOUT; @@ -325,7 +409,7 @@ static int uniphier_sd_dma_wait_for_irq(struct udevice *dev, u32 flag, udelay(10); } - if (readl(priv->regbase + UNIPHIER_SD_DMA_INFO2)) { + if (uniphier_sd_readl(priv, UNIPHIER_SD_DMA_INFO2)) { dev_err(dev, "error during DMA\n"); return -EIO; } @@ -343,7 +427,7 @@ static int uniphier_sd_dma_xfer(struct udevice *dev, struct mmc_data *data) u32 poll_flag, tmp; int ret; - tmp = readl(priv->regbase + UNIPHIER_SD_DMA_MODE); + tmp = uniphier_sd_readl(priv, UNIPHIER_SD_DMA_MODE); if (data->flags & MMC_DATA_READ) { buf = data->dest; @@ -357,7 +441,7 @@ static int uniphier_sd_dma_xfer(struct udevice *dev, struct mmc_data *data) tmp &= ~UNIPHIER_SD_DMA_MODE_DIR_RD; } - writel(tmp, priv->regbase + UNIPHIER_SD_DMA_MODE); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_DMA_MODE); dma_addr = __dma_map_single(buf, len, dir); @@ -396,27 +480,27 @@ static int uniphier_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, int ret; u32 tmp; - if (readl(priv->regbase + UNIPHIER_SD_INFO2) & UNIPHIER_SD_INFO2_CBSY) { + if (uniphier_sd_readl(priv, UNIPHIER_SD_INFO2) & UNIPHIER_SD_INFO2_CBSY) { dev_err(dev, "command busy\n"); return -EBUSY; } /* clear all status flags */ - writel(0, priv->regbase + UNIPHIER_SD_INFO1); - writel(0, priv->regbase + UNIPHIER_SD_INFO2); + uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO1); + uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO2); /* disable DMA once */ - tmp = readl(priv->regbase + UNIPHIER_SD_EXTMODE); + tmp = uniphier_sd_readl(priv, UNIPHIER_SD_EXTMODE); tmp &= ~UNIPHIER_SD_EXTMODE_DMA_EN; - writel(tmp, priv->regbase + UNIPHIER_SD_EXTMODE); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_EXTMODE); - writel(cmd->cmdarg, priv->regbase + UNIPHIER_SD_ARG); + uniphier_sd_writel(priv, cmd->cmdarg, UNIPHIER_SD_ARG); tmp = cmd->cmdidx; if (data) { - writel(data->blocksize, priv->regbase + UNIPHIER_SD_SIZE); - writel(data->blocks, priv->regbase + UNIPHIER_SD_SECCNT); + uniphier_sd_writel(priv, data->blocksize, UNIPHIER_SD_SIZE); + uniphier_sd_writel(priv, data->blocks, UNIPHIER_SD_SECCNT); /* Do not send CMD12 automatically */ tmp |= UNIPHIER_SD_CMD_NOSTOP | UNIPHIER_SD_CMD_DATA; @@ -457,7 +541,7 @@ static int uniphier_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, dev_dbg(dev, "sending CMD%d (SD_CMD=%08x, SD_ARG=%08x)\n", cmd->cmdidx, tmp, cmd->cmdarg); - writel(tmp, priv->regbase + UNIPHIER_SD_CMD); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CMD); ret = uniphier_sd_wait_for_irq(dev, UNIPHIER_SD_INFO1, UNIPHIER_SD_INFO1_RSP); @@ -465,10 +549,10 @@ static int uniphier_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, return ret; if (cmd->resp_type & MMC_RSP_136) { - u32 rsp_127_104 = readl(priv->regbase + UNIPHIER_SD_RSP76); - u32 rsp_103_72 = readl(priv->regbase + UNIPHIER_SD_RSP54); - u32 rsp_71_40 = readl(priv->regbase + UNIPHIER_SD_RSP32); - u32 rsp_39_8 = readl(priv->regbase + UNIPHIER_SD_RSP10); + u32 rsp_127_104 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP76); + u32 rsp_103_72 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP54); + u32 rsp_71_40 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP32); + u32 rsp_39_8 = uniphier_sd_readl(priv, UNIPHIER_SD_RSP10); cmd->response[0] = ((rsp_127_104 & 0x00ffffff) << 8) | ((rsp_103_72 & 0xff000000) >> 24); @@ -479,7 +563,7 @@ static int uniphier_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, cmd->response[3] = (rsp_39_8 & 0xffffff) << 8; } else { /* bit 39-8 */ - cmd->response[0] = readl(priv->regbase + UNIPHIER_SD_RSP10); + cmd->response[0] = uniphier_sd_readl(priv, UNIPHIER_SD_RSP10); } if (data) { @@ -518,10 +602,10 @@ static int uniphier_sd_set_bus_width(struct uniphier_sd_priv *priv, return -EINVAL; } - tmp = readl(priv->regbase + UNIPHIER_SD_OPTION); + tmp = uniphier_sd_readl(priv, UNIPHIER_SD_OPTION); tmp &= ~UNIPHIER_SD_OPTION_WIDTH_MASK; tmp |= val; - writel(tmp, priv->regbase + UNIPHIER_SD_OPTION); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_OPTION); return 0; } @@ -531,12 +615,12 @@ static void uniphier_sd_set_ddr_mode(struct uniphier_sd_priv *priv, { u32 tmp; - tmp = readl(priv->regbase + UNIPHIER_SD_IF_MODE); + tmp = uniphier_sd_readl(priv, UNIPHIER_SD_IF_MODE); if (mmc->ddr_mode) tmp |= UNIPHIER_SD_IF_MODE_DDR; else tmp &= ~UNIPHIER_SD_IF_MODE_DDR; - writel(tmp, priv->regbase + UNIPHIER_SD_IF_MODE); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_IF_MODE); } static void uniphier_sd_set_clk_rate(struct uniphier_sd_priv *priv, @@ -573,21 +657,21 @@ static void uniphier_sd_set_clk_rate(struct uniphier_sd_priv *priv, else val = UNIPHIER_SD_CLKCTL_DIV1024; - tmp = readl(priv->regbase + UNIPHIER_SD_CLKCTL); + tmp = uniphier_sd_readl(priv, UNIPHIER_SD_CLKCTL); if (tmp & UNIPHIER_SD_CLKCTL_SCLKEN && (tmp & UNIPHIER_SD_CLKCTL_DIV_MASK) == val) return; /* stop the clock before changing its rate to avoid a glitch signal */ tmp &= ~UNIPHIER_SD_CLKCTL_SCLKEN; - writel(tmp, priv->regbase + UNIPHIER_SD_CLKCTL); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CLKCTL); tmp &= ~UNIPHIER_SD_CLKCTL_DIV_MASK; tmp |= val | UNIPHIER_SD_CLKCTL_OFFEN; - writel(tmp, priv->regbase + UNIPHIER_SD_CLKCTL); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CLKCTL); tmp |= UNIPHIER_SD_CLKCTL_SCLKEN; - writel(tmp, priv->regbase + UNIPHIER_SD_CLKCTL); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_CLKCTL); udelay(1000); } @@ -617,7 +701,7 @@ static int uniphier_sd_get_cd(struct udevice *dev) if (priv->caps & UNIPHIER_SD_CAP_NONREMOVABLE) return 1; - return !!(readl(priv->regbase + UNIPHIER_SD_INFO1) & + return !!(uniphier_sd_readl(priv, UNIPHIER_SD_INFO1) & UNIPHIER_SD_INFO1_CD); } @@ -632,28 +716,28 @@ static void uniphier_sd_host_init(struct uniphier_sd_priv *priv) u32 tmp; /* soft reset of the host */ - tmp = readl(priv->regbase + UNIPHIER_SD_SOFT_RST); + tmp = uniphier_sd_readl(priv, UNIPHIER_SD_SOFT_RST); tmp &= ~UNIPHIER_SD_SOFT_RST_RSTX; - writel(tmp, priv->regbase + UNIPHIER_SD_SOFT_RST); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_SOFT_RST); tmp |= UNIPHIER_SD_SOFT_RST_RSTX; - writel(tmp, priv->regbase + UNIPHIER_SD_SOFT_RST); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_SOFT_RST); /* FIXME: implement eMMC hw_reset */ - writel(UNIPHIER_SD_STOP_SEC, priv->regbase + UNIPHIER_SD_STOP); + uniphier_sd_writel(priv, UNIPHIER_SD_STOP_SEC, UNIPHIER_SD_STOP); /* * Connected to 32bit AXI. * This register dropped backward compatibility at version 0x10. * Write an appropriate value depending on the IP version. */ - writel(priv->version >= 0x10 ? 0x00000101 : 0x00000000, - priv->regbase + UNIPHIER_SD_HOST_MODE); + uniphier_sd_writel(priv, priv->version >= 0x10 ? 0x00000101 : 0x00000000, + UNIPHIER_SD_HOST_MODE); if (priv->caps & UNIPHIER_SD_CAP_DMA_INTERNAL) { - tmp = readl(priv->regbase + UNIPHIER_SD_DMA_MODE); + tmp = uniphier_sd_readl(priv, UNIPHIER_SD_DMA_MODE); tmp |= UNIPHIER_SD_DMA_MODE_ADDR_INC; - writel(tmp, priv->regbase + UNIPHIER_SD_DMA_MODE); + uniphier_sd_writel(priv, tmp, UNIPHIER_SD_DMA_MODE); } } @@ -669,9 +753,13 @@ static int uniphier_sd_probe(struct udevice *dev) struct uniphier_sd_plat *plat = dev_get_platdata(dev); struct uniphier_sd_priv *priv = dev_get_priv(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + const u32 quirks = dev_get_driver_data(dev); fdt_addr_t base; struct clk clk; int ret; +#ifdef CONFIG_DM_REGULATOR + struct udevice *vqmmc_dev; +#endif base = devfdt_get_addr(dev); if (base == FDT_ADDR_T_NONE) @@ -681,6 +769,15 @@ static int uniphier_sd_probe(struct udevice *dev) if (!priv->regbase) return -ENOMEM; +#ifdef CONFIG_DM_REGULATOR + ret = device_get_supply_regulator(dev, "vqmmc-supply", &vqmmc_dev); + if (!ret) { + /* Set the regulator to 3.3V until we support 1.8V modes */ + regulator_set_value(vqmmc_dev, 3300000); + regulator_set_enable(vqmmc_dev, true); + } +#endif + ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) { dev_err(dev, "failed to get host clock\n"); @@ -720,18 +817,22 @@ static int uniphier_sd_probe(struct udevice *dev) return -EINVAL; } + if (quirks) { + priv->caps = quirks; + } else { + priv->version = uniphier_sd_readl(priv, UNIPHIER_SD_VERSION) & + UNIPHIER_SD_VERSION_IP; + dev_dbg(dev, "version %x\n", priv->version); + if (priv->version >= 0x10) { + priv->caps |= UNIPHIER_SD_CAP_DMA_INTERNAL; + priv->caps |= UNIPHIER_SD_CAP_DIV1024; + } + } + if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable", NULL)) priv->caps |= UNIPHIER_SD_CAP_NONREMOVABLE; - priv->version = readl(priv->regbase + UNIPHIER_SD_VERSION) & - UNIPHIER_SD_VERSION_IP; - dev_dbg(dev, "version %x\n", priv->version); - if (priv->version >= 0x10) { - priv->caps |= UNIPHIER_SD_CAP_DMA_INTERNAL; - priv->caps |= UNIPHIER_SD_CAP_DIV1024; - } - uniphier_sd_host_init(priv); plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; @@ -746,7 +847,9 @@ static int uniphier_sd_probe(struct udevice *dev) } static const struct udevice_id uniphier_sd_match[] = { - { .compatible = "socionext,uniphier-sdhc" }, + { .compatible = "renesas,sdhi-r8a7795", .data = UNIPHIER_SD_CAP_64BIT }, + { .compatible = "renesas,sdhi-r8a7796", .data = UNIPHIER_SD_CAP_64BIT }, + { .compatible = "socionext,uniphier-sdhc", .data = 0 }, { /* sentinel */ } }; diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c index 2b7cb7f6b66..490a01f9bdb 100644 --- a/drivers/mmc/xenon_sdhci.c +++ b/drivers/mmc/xenon_sdhci.c @@ -159,7 +159,7 @@ static int xenon_mmc_phy_init(struct sdhci_host *host) } if (time <= 0) { - error("Failed to enable MMC internal clock in time\n"); + pr_err("Failed to enable MMC internal clock in time\n"); return -ETIMEDOUT; } @@ -187,7 +187,7 @@ static int xenon_mmc_phy_init(struct sdhci_host *host) } if (time <= 0) { - error("Failed to init MMC PHY in time\n"); + pr_err("Failed to init MMC PHY in time\n"); return -ETIMEDOUT; } diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index f3bb72788a9..8a5babea7b3 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -111,11 +111,9 @@ static void cfi_flash_init_dm(void) } } -static phys_addr_t cfi_flash_base[CFI_MAX_FLASH_BANKS]; - phys_addr_t cfi_flash_bank_addr(int i) { - return cfi_flash_base[i]; + return flash_info[i].base; } #else __weak phys_addr_t cfi_flash_bank_addr(int i) @@ -546,7 +544,16 @@ static int flash_is_busy (flash_info_t * info, flash_sect_t sect) #ifdef CONFIG_FLASH_CFI_LEGACY case CFI_CMDSET_AMD_LEGACY: #endif - retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); + if (info->sr_supported) { + flash_write_cmd (info, sect, info->addr_unlock1, + FLASH_CMD_READ_STATUS); + retval = !flash_isset (info, sect, 0, + FLASH_STATUS_DONE); + } else { + retval = flash_toggle (info, sect, 0, + AMD_STATUS_TOGGLE); + } + break; default: retval = 0; @@ -1687,6 +1694,7 @@ static void cmdset_amd_read_jedec_ids(flash_info_t *info) { ushort bankId = 0; uchar manuId; + uchar lsbits; flash_write_cmd(info, 0, 0, AMD_CMD_RESET); flash_unlock_seq(info, 0); @@ -1702,6 +1710,9 @@ static void cmdset_amd_read_jedec_ids(flash_info_t *info) } info->manufacturer_id = manuId; + lsbits = flash_read_uchar(info, FLASH_OFFSET_LOWER_SW_BITS); + info->sr_supported = lsbits & BIT(0); + switch (info->chipwidth){ case FLASH_CFI_8BIT: info->device_id = flash_read_uchar (info, @@ -2458,10 +2469,12 @@ static int cfi_flash_probe(struct udevice *dev) while (idx < len) { addr = fdt_translate_address((void *)blob, node, cell + idx); - cfi_flash_base[cfi_flash_num_flash_banks++] = addr; + flash_info[cfi_flash_num_flash_banks].dev = dev; + flash_info[cfi_flash_num_flash_banks].base = addr; + cfi_flash_num_flash_banks++; idx += addrc + sizec; } - gd->bd->bi_flashstart = cfi_flash_base[0]; + gd->bd->bi_flashstart = flash_info[0].base; return 0; } diff --git a/drivers/mtd/nand/lpc32xx_nand_mlc.c b/drivers/mtd/nand/lpc32xx_nand_mlc.c index 3af7e6dfac6..e1b36706cab 100644 --- a/drivers/mtd/nand/lpc32xx_nand_mlc.c +++ b/drivers/mtd/nand/lpc32xx_nand_mlc.c @@ -583,21 +583,21 @@ void board_nand_init(void) /* identify chip */ ret = nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL); if (ret) { - error("nand_scan_ident returned %i", ret); + pr_err("nand_scan_ident returned %i", ret); return; } /* finish scanning the chip */ ret = nand_scan_tail(mtd); if (ret) { - error("nand_scan_tail returned %i", ret); + pr_err("nand_scan_tail returned %i", ret); return; } /* chip is good, register it */ ret = nand_register(0, mtd); if (ret) - error("nand_register returned %i", ret); + pr_err("nand_register returned %i", ret); } #else /* defined(CONFIG_SPL_BUILD) */ diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 0042a7ba11d..6ab3c8a25ad 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1559,7 +1559,7 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info) pdata->num_cs = fdtdec_get_int(blob, node, "num-cs", 1); if (pdata->num_cs != 1) { - error("pxa3xx driver supports single CS only\n"); + pr_err("pxa3xx driver supports single CS only\n"); break; } diff --git a/drivers/mtd/spi/spi_flash_ids.c b/drivers/mtd/spi/spi_flash_ids.c index b2ab43920ab..13f64e773fe 100644 --- a/drivers/mtd/spi/spi_flash_ids.c +++ b/drivers/mtd/spi/spi_flash_ids.c @@ -92,7 +92,7 @@ const struct spi_flash_info spi_flash_ids[] = { {"s25fl016a", INFO(0x010214, 0x0, 64 * 1024, 32, 0) }, {"s25fl032a", INFO(0x010215, 0x0, 64 * 1024, 64, 0) }, {"s25fl064a", INFO(0x010216, 0x0, 64 * 1024, 128, 0) }, - {"s25fl116k", INFO(0x014015, 0x0, 64 * 1024, 128, 0) }, + {"s25fl116k", INFO(0x014015, 0x0, 64 * 1024, 32, 0) }, {"s25fl164k", INFO(0x014017, 0x0140, 64 * 1024, 128, 0) }, {"s25fl128p_256k", INFO(0x012018, 0x0300, 256 * 1024, 64, RD_FULL | WR_QPP) }, {"s25fl128p_64k", INFO(0x012018, 0x0301, 64 * 1024, 256, RD_FULL | WR_QPP) }, @@ -101,8 +101,8 @@ const struct spi_flash_info spi_flash_ids[] = { {"s25fl128s_256k", INFO(0x012018, 0x4d00, 256 * 1024, 64, RD_FULL | WR_QPP) }, {"s25fl128s_64k", INFO(0x012018, 0x4d01, 64 * 1024, 256, RD_FULL | WR_QPP) }, {"s25fl256s_256k", INFO(0x010219, 0x4d00, 256 * 1024, 128, RD_FULL | WR_QPP) }, - {"s25fl256s_64k", INFO(0x010219, 0x4d01, 64 * 1024, 512, RD_FULL | WR_QPP) }, {"s25fs256s_64k", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) }, + {"s25fl256s_64k", INFO(0x010219, 0x4d01, 64 * 1024, 512, RD_FULL | WR_QPP) }, {"s25fs512s", INFO6(0x010220, 0x4d0081, 128 * 1024, 512, RD_FULL | WR_QPP | SECT_4K) }, {"s25fl512s_256k", INFO(0x010220, 0x4d00, 256 * 1024, 256, RD_FULL | WR_QPP) }, {"s25fl512s_64k", INFO(0x010220, 0x4d01, 64 * 1024, 1024, RD_FULL | WR_QPP) }, @@ -135,6 +135,7 @@ const struct spi_flash_info spi_flash_ids[] = { {"n25q1024a", INFO(0x20bb21, 0x0, 64 * 1024, 2048, RD_FULL | WR_QPP | E_FSR | SECT_4K) }, {"mt25qu02g", INFO(0x20bb22, 0x0, 64 * 1024, 4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) }, {"mt25ql02g", INFO(0x20ba22, 0x0, 64 * 1024, 4096, RD_FULL | WR_QPP | E_FSR | SECT_4K) }, + {"mt35xu512g", INFO6(0x2c5b1a, 0x104100, 128 * 1024, 512, E_FSR | SECT_4K) }, #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ {"sst25vf040b", INFO(0xbf258d, 0x0, 64 * 1024, 8, SECT_4K | SST_WR) }, diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5ceea44c605..d67927cd3b8 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -159,6 +159,14 @@ config FTMAC100 help This MAC is present in Andestech SoCs. +config MVNETA + bool "Marvell Armada 385 network interface support" + depends on ARMADA_XP || ARMADA_38X + select PHYLIB + help + This driver supports the network interface units in the + Marvell ARMADA XP and 38X SoCs + config MVPP2 bool "Marvell Armada 375/7K/8K network interface support" depends on ARMADA_375 || ARMADA_8K diff --git a/drivers/net/bcm-sf2-eth-gmac.c b/drivers/net/bcm-sf2-eth-gmac.c index 9ff72fa1edc..a2b594ed739 100644 --- a/drivers/net/bcm-sf2-eth-gmac.c +++ b/drivers/net/bcm-sf2-eth-gmac.c @@ -610,7 +610,7 @@ int gmac_miiphy_read(struct mii_dev *bus, int phyaddr, int devad, int reg) /* Busy wait timeout is 1ms */ if (gmac_mii_busywait(1000)) { - error("%s: Prepare MII read: MII/MDIO busy\n", __func__); + pr_err("%s: Prepare MII read: MII/MDIO busy\n", __func__); return -1; } @@ -622,7 +622,7 @@ int gmac_miiphy_read(struct mii_dev *bus, int phyaddr, int devad, int reg) writel(tmp, GMAC_MII_DATA_ADDR); if (gmac_mii_busywait(1000)) { - error("%s: MII read failure: MII/MDIO busy\n", __func__); + pr_err("%s: MII read failure: MII/MDIO busy\n", __func__); return -1; } @@ -638,7 +638,7 @@ int gmac_miiphy_write(struct mii_dev *bus, int phyaddr, int devad, int reg, /* Busy wait timeout is 1ms */ if (gmac_mii_busywait(1000)) { - error("%s: Prepare MII write: MII/MDIO busy\n", __func__); + pr_err("%s: Prepare MII write: MII/MDIO busy\n", __func__); return -1; } @@ -651,7 +651,7 @@ int gmac_miiphy_write(struct mii_dev *bus, int phyaddr, int devad, int reg, writel(tmp, GMAC_MII_DATA_ADDR); if (gmac_mii_busywait(1000)) { - error("%s: MII write failure: MII/MDIO busy\n", __func__); + pr_err("%s: MII write failure: MII/MDIO busy\n", __func__); return -1; } @@ -742,7 +742,7 @@ int gmac_set_speed(int speed, int duplex) } else if (speed == 10) { speed_cfg = 0; } else { - error("%s: Invalid GMAC speed(%d)!\n", __func__, speed); + pr_err("%s: Invalid GMAC speed(%d)!\n", __func__, speed); return -1; } @@ -820,7 +820,7 @@ int gmac_mac_init(struct eth_device *dev) writel(0, GMAC0_INT_STATUS_ADDR); if (dma_init(dma) < 0) { - error("%s: GMAC dma_init failed\n", __func__); + pr_err("%s: GMAC dma_init failed\n", __func__); goto err_exit; } @@ -855,7 +855,7 @@ int gmac_mac_init(struct eth_device *dev) writel(tmp, GMAC_MII_CTRL_ADDR); if (gmac_mii_busywait(1000)) { - error("%s: Configure MDIO: MII/MDIO busy\n", __func__); + pr_err("%s: Configure MDIO: MII/MDIO busy\n", __func__); goto err_exit; } diff --git a/drivers/net/bcm-sf2-eth.c b/drivers/net/bcm-sf2-eth.c index e2747365a20..9056f71b9ac 100644 --- a/drivers/net/bcm-sf2-eth.c +++ b/drivers/net/bcm-sf2-eth.c @@ -40,7 +40,7 @@ static int bcm_sf2_eth_init(struct eth_device *dev) rc = eth->mac_init(dev); if (rc) { - error("%s: Couldn't cofigure MAC!\n", __func__); + pr_err("%s: Couldn't cofigure MAC!\n", __func__); return rc; } @@ -90,7 +90,7 @@ static int bcm_sf2_eth_send(struct eth_device *dev, void *packet, int length) debug("."); i++; if (i > 20) { - error("%s: Tx timeout: retried 20 times\n", __func__); + pr_err("%s: Tx timeout: retried 20 times\n", __func__); rc = -1; break; } @@ -117,7 +117,7 @@ static int bcm_sf2_eth_receive(struct eth_device *dev) debug("\nNO More Rx\n"); break; } else if ((rcvlen == 0) || (rcvlen > RX_BUF_SIZE)) { - error("%s: Wrong Ethernet packet size (%d B), skip!\n", + pr_err("%s: Wrong Ethernet packet size (%d B), skip!\n", __func__, rcvlen); break; } else { @@ -166,9 +166,9 @@ static int bcm_sf2_eth_open(struct eth_device *dev, bd_t *bt) */ for (i = 0; i < eth->port_num; i++) { if (phy_startup(eth->port[i])) { - error("%s: PHY %d startup failed!\n", __func__, i); + pr_err("%s: PHY %d startup failed!\n", __func__, i); if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) { - error("%s: No default port %d!\n", __func__, i); + pr_err("%s: No default port %d!\n", __func__, i); return -1; } } @@ -205,13 +205,13 @@ int bcm_sf2_eth_register(bd_t *bis, u8 dev_num) dev = (struct eth_device *)malloc(sizeof(struct eth_device)); if (dev == NULL) { - error("%s: Not enough memory!\n", __func__); + pr_err("%s: Not enough memory!\n", __func__); return -1; } eth = (struct eth_info *)malloc(sizeof(struct eth_info)); if (eth == NULL) { - error("%s: Not enough memory!\n", __func__); + pr_err("%s: Not enough memory!\n", __func__); return -1; } @@ -234,7 +234,7 @@ int bcm_sf2_eth_register(bd_t *bis, u8 dev_num) if (gmac_add(dev)) { free(eth); free(dev); - error("%s: Adding GMAC failed!\n", __func__); + pr_err("%s: Adding GMAC failed!\n", __func__); return -1; } #else @@ -263,7 +263,7 @@ int bcm_sf2_eth_register(bd_t *bis, u8 dev_num) rc = bcm_sf2_eth_init(dev); if (rc != 0) { - error("%s: configuration failed!\n", __func__); + pr_err("%s: configuration failed!\n", __func__); return -1; } diff --git a/drivers/net/cpsw-common.c b/drivers/net/cpsw-common.c index 8970ee00af3..0dc83ab8205 100644 --- a/drivers/net/cpsw-common.c +++ b/drivers/net/cpsw-common.c @@ -29,14 +29,14 @@ static int davinci_emac_3517_get_macid(struct udevice *dev, u16 offset, syscon = fdtdec_lookup_phandle(fdt, node, "syscon"); if (syscon < 0) { - error("Syscon offset not found\n"); + pr_err("Syscon offset not found\n"); return -ENOENT; } addr = (u32)map_physmem(fdt_translate_address(fdt, syscon, &gmii), sizeof(u32), MAP_NOCACHE); if (addr == FDT_ADDR_T_NONE) { - error("Not able to get syscon address to get mac efuse address\n"); + pr_err("Not able to get syscon address to get mac efuse address\n"); return -ENOENT; } @@ -69,14 +69,14 @@ static int cpsw_am33xx_cm_get_macid(struct udevice *dev, u16 offset, int slave, syscon = fdtdec_lookup_phandle(fdt, node, "syscon"); if (syscon < 0) { - error("Syscon offset not found\n"); + pr_err("Syscon offset not found\n"); return -ENOENT; } addr = (u32)map_physmem(fdt_translate_address(fdt, syscon, &gmii), sizeof(u32), MAP_NOCACHE); if (addr == FDT_ADDR_T_NONE) { - error("Not able to get syscon address to get mac efuse address\n"); + pr_err("Not able to get syscon address to get mac efuse address\n"); return -ENOENT; } diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index d7db0fc432f..b72258f83bf 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -1368,7 +1368,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) mdio_base = cpsw_get_addr_by_node(fdt, subnode); if (mdio_base == FDT_ADDR_T_NONE) { - error("Not able to get MDIO address space\n"); + pr_err("Not able to get MDIO address space\n"); return -ENOENT; } priv->data.mdio_base = mdio_base; @@ -1407,7 +1407,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) subnode); if (priv->data.gmii_sel == FDT_ADDR_T_NONE) { - error("Not able to get gmii_sel reg address\n"); + pr_err("Not able to get gmii_sel reg address\n"); return -ENOENT; } @@ -1418,7 +1418,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) phy_sel_compat = fdt_getprop(fdt, subnode, "compatible", NULL); if (!phy_sel_compat) { - error("Not able to get gmii_sel compatible\n"); + pr_err("Not able to get gmii_sel compatible\n"); return -ENOENT; } } @@ -1434,7 +1434,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) ret = ti_cm_get_macid(dev, active_slave, pdata->enetaddr); if (ret < 0) { - error("cpsw read efuse mac failed\n"); + pr_err("cpsw read efuse mac failed\n"); return ret; } diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 5c4315ffeaa..00076cffbed 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -377,7 +377,7 @@ static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, ret = eqos_mdio_wait_idle(eqos); if (ret) { - error("MDIO not idle at entry"); + pr_err("MDIO not idle at entry"); return ret; } @@ -397,7 +397,7 @@ static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, ret = eqos_mdio_wait_idle(eqos); if (ret) { - error("MDIO read didn't complete"); + pr_err("MDIO read didn't complete"); return ret; } @@ -421,7 +421,7 @@ static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, ret = eqos_mdio_wait_idle(eqos); if (ret) { - error("MDIO not idle at entry"); + pr_err("MDIO not idle at entry"); return ret; } @@ -443,7 +443,7 @@ static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, ret = eqos_mdio_wait_idle(eqos); if (ret) { - error("MDIO read didn't complete"); + pr_err("MDIO read didn't complete"); return ret; } @@ -459,37 +459,37 @@ static int eqos_start_clks_tegra186(struct udevice *dev) ret = clk_enable(&eqos->clk_slave_bus); if (ret < 0) { - error("clk_enable(clk_slave_bus) failed: %d", ret); + pr_err("clk_enable(clk_slave_bus) failed: %d", ret); goto err; } ret = clk_enable(&eqos->clk_master_bus); if (ret < 0) { - error("clk_enable(clk_master_bus) failed: %d", ret); + pr_err("clk_enable(clk_master_bus) failed: %d", ret); goto err_disable_clk_slave_bus; } ret = clk_enable(&eqos->clk_rx); if (ret < 0) { - error("clk_enable(clk_rx) failed: %d", ret); + pr_err("clk_enable(clk_rx) failed: %d", ret); goto err_disable_clk_master_bus; } ret = clk_enable(&eqos->clk_ptp_ref); if (ret < 0) { - error("clk_enable(clk_ptp_ref) failed: %d", ret); + pr_err("clk_enable(clk_ptp_ref) failed: %d", ret); goto err_disable_clk_rx; } ret = clk_set_rate(&eqos->clk_ptp_ref, 125 * 1000 * 1000); if (ret < 0) { - error("clk_set_rate(clk_ptp_ref) failed: %d", ret); + pr_err("clk_set_rate(clk_ptp_ref) failed: %d", ret); goto err_disable_clk_ptp_ref; } ret = clk_enable(&eqos->clk_tx); if (ret < 0) { - error("clk_enable(clk_tx) failed: %d", ret); + pr_err("clk_enable(clk_tx) failed: %d", ret); goto err_disable_clk_ptp_ref; } @@ -533,7 +533,7 @@ static int eqos_start_resets_tegra186(struct udevice *dev) ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); if (ret < 0) { - error("dm_gpio_set_value(phy_reset, assert) failed: %d", ret); + pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", ret); return ret; } @@ -541,13 +541,13 @@ static int eqos_start_resets_tegra186(struct udevice *dev) ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0); if (ret < 0) { - error("dm_gpio_set_value(phy_reset, deassert) failed: %d", ret); + pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", ret); return ret; } ret = reset_assert(&eqos->reset_ctl); if (ret < 0) { - error("reset_assert() failed: %d", ret); + pr_err("reset_assert() failed: %d", ret); return ret; } @@ -555,7 +555,7 @@ static int eqos_start_resets_tegra186(struct udevice *dev) ret = reset_deassert(&eqos->reset_ctl); if (ret < 0) { - error("reset_deassert() failed: %d", ret); + pr_err("reset_deassert() failed: %d", ret); return ret; } @@ -591,14 +591,14 @@ static int eqos_calibrate_pads_tegra186(struct udevice *dev) ret = wait_for_bit(__func__, &eqos->tegra186_regs->auto_cal_status, EQOS_AUTO_CAL_STATUS_ACTIVE, true, 10, false); if (ret) { - error("calibrate didn't start"); + pr_err("calibrate didn't start"); goto failed; } ret = wait_for_bit(__func__, &eqos->tegra186_regs->auto_cal_status, EQOS_AUTO_CAL_STATUS_ACTIVE, false, 10, false); if (ret) { - error("calibrate didn't finish"); + pr_err("calibrate didn't finish"); goto failed; } @@ -713,13 +713,13 @@ static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev) rate = 2.5 * 1000 * 1000; break; default: - error("invalid speed %d", eqos->phy->speed); + pr_err("invalid speed %d", eqos->phy->speed); return -EINVAL; } ret = clk_set_rate(&eqos->clk_tx, rate); if (ret < 0) { - error("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret); + pr_err("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret); return ret; } @@ -739,7 +739,7 @@ static int eqos_adjust_link(struct udevice *dev) else ret = eqos_set_half_duplex(dev); if (ret < 0) { - error("eqos_set_*_duplex() failed: %d", ret); + pr_err("eqos_set_*_duplex() failed: %d", ret); return ret; } @@ -757,24 +757,24 @@ static int eqos_adjust_link(struct udevice *dev) ret = eqos_set_mii_speed_10(dev); break; default: - error("invalid speed %d", eqos->phy->speed); + pr_err("invalid speed %d", eqos->phy->speed); return -EINVAL; } if (ret < 0) { - error("eqos_set_*mii_speed*() failed: %d", ret); + pr_err("eqos_set_*mii_speed*() failed: %d", ret); return ret; } if (en_calibration) { ret = eqos_calibrate_pads_tegra186(dev); if (ret < 0) { - error("eqos_calibrate_pads_tegra186() failed: %d", ret); + pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret); return ret; } } else { ret = eqos_disable_calibration_tegra186(dev); if (ret < 0) { - error("eqos_disable_calibration_tegra186() failed: %d", + pr_err("eqos_disable_calibration_tegra186() failed: %d", ret); return ret; } @@ -782,7 +782,7 @@ static int eqos_adjust_link(struct udevice *dev) ret = eqos_set_tx_clk_speed_tegra186(dev); if (ret < 0) { - error("eqos_set_tx_clk_speed_tegra186() failed: %d", ret); + pr_err("eqos_set_tx_clk_speed_tegra186() failed: %d", ret); return ret; } @@ -848,13 +848,13 @@ static int eqos_start(struct udevice *dev) ret = eqos_start_clks_tegra186(dev); if (ret < 0) { - error("eqos_start_clks_tegra186() failed: %d", ret); + pr_err("eqos_start_clks_tegra186() failed: %d", ret); goto err; } ret = eqos_start_resets_tegra186(dev); if (ret < 0) { - error("eqos_start_resets_tegra186() failed: %d", ret); + pr_err("eqos_start_resets_tegra186() failed: %d", ret); goto err_stop_clks; } @@ -865,13 +865,13 @@ static int eqos_start(struct udevice *dev) ret = wait_for_bit(__func__, &eqos->dma_regs->mode, EQOS_DMA_MODE_SWR, false, 10, false); if (ret) { - error("EQOS_DMA_MODE_SWR stuck"); + pr_err("EQOS_DMA_MODE_SWR stuck"); goto err_stop_resets; } ret = eqos_calibrate_pads_tegra186(dev); if (ret < 0) { - error("eqos_calibrate_pads_tegra186() failed: %d", ret); + pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret); goto err_stop_resets; } @@ -881,28 +881,28 @@ static int eqos_start(struct udevice *dev) eqos->phy = phy_connect(eqos->mii, 0, dev, 0); if (!eqos->phy) { - error("phy_connect() failed"); + pr_err("phy_connect() failed"); goto err_stop_resets; } ret = phy_config(eqos->phy); if (ret < 0) { - error("phy_config() failed: %d", ret); + pr_err("phy_config() failed: %d", ret); goto err_shutdown_phy; } ret = phy_startup(eqos->phy); if (ret < 0) { - error("phy_startup() failed: %d", ret); + pr_err("phy_startup() failed: %d", ret); goto err_shutdown_phy; } if (!eqos->phy->link) { - error("No link"); + pr_err("No link"); goto err_shutdown_phy; } ret = eqos_adjust_link(dev); if (ret < 0) { - error("eqos_adjust_link() failed: %d", ret); + pr_err("eqos_adjust_link() failed: %d", ret); goto err_shutdown_phy; } @@ -1119,7 +1119,7 @@ err_stop_resets: err_stop_clks: eqos_stop_clks_tegra186(dev); err: - error("FAILED: %d", ret); + pr_err("FAILED: %d", ret); return ret; } @@ -1361,7 +1361,7 @@ static int eqos_probe_resources_tegra186(struct udevice *dev) ret = reset_get_by_name(dev, "eqos", &eqos->reset_ctl); if (ret) { - error("reset_get_by_name(rst) failed: %d", ret); + pr_err("reset_get_by_name(rst) failed: %d", ret); return ret; } @@ -1369,38 +1369,38 @@ static int eqos_probe_resources_tegra186(struct udevice *dev) &eqos->phy_reset_gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); if (ret) { - error("gpio_request_by_name(phy reset) failed: %d", ret); + pr_err("gpio_request_by_name(phy reset) failed: %d", ret); goto err_free_reset_eqos; } ret = clk_get_by_name(dev, "slave_bus", &eqos->clk_slave_bus); if (ret) { - error("clk_get_by_name(slave_bus) failed: %d", ret); + pr_err("clk_get_by_name(slave_bus) failed: %d", ret); goto err_free_gpio_phy_reset; } ret = clk_get_by_name(dev, "master_bus", &eqos->clk_master_bus); if (ret) { - error("clk_get_by_name(master_bus) failed: %d", ret); + pr_err("clk_get_by_name(master_bus) failed: %d", ret); goto err_free_clk_slave_bus; } ret = clk_get_by_name(dev, "rx", &eqos->clk_rx); if (ret) { - error("clk_get_by_name(rx) failed: %d", ret); + pr_err("clk_get_by_name(rx) failed: %d", ret); goto err_free_clk_master_bus; } ret = clk_get_by_name(dev, "ptp_ref", &eqos->clk_ptp_ref); if (ret) { - error("clk_get_by_name(ptp_ref) failed: %d", ret); + pr_err("clk_get_by_name(ptp_ref) failed: %d", ret); goto err_free_clk_rx; return ret; } ret = clk_get_by_name(dev, "tx", &eqos->clk_tx); if (ret) { - error("clk_get_by_name(tx) failed: %d", ret); + pr_err("clk_get_by_name(tx) failed: %d", ret); goto err_free_clk_ptp_ref; } @@ -1454,7 +1454,7 @@ static int eqos_probe(struct udevice *dev) eqos->regs = devfdt_get_addr(dev); if (eqos->regs == FDT_ADDR_T_NONE) { - error("devfdt_get_addr() failed"); + pr_err("devfdt_get_addr() failed"); return -ENODEV; } eqos->mac_regs = (void *)(eqos->regs + EQOS_MAC_REGS_BASE); @@ -1464,19 +1464,19 @@ static int eqos_probe(struct udevice *dev) ret = eqos_probe_resources_core(dev); if (ret < 0) { - error("eqos_probe_resources_core() failed: %d", ret); + pr_err("eqos_probe_resources_core() failed: %d", ret); return ret; } ret = eqos_probe_resources_tegra186(dev); if (ret < 0) { - error("eqos_probe_resources_tegra186() failed: %d", ret); + pr_err("eqos_probe_resources_tegra186() failed: %d", ret); goto err_remove_resources_core; } eqos->mii = mdio_alloc(); if (!eqos->mii) { - error("mdio_alloc() failed"); + pr_err("mdio_alloc() failed"); goto err_remove_resources_tegra; } eqos->mii->read = eqos_mdio_read; @@ -1486,7 +1486,7 @@ static int eqos_probe(struct udevice *dev) ret = mdio_register(eqos->mii); if (ret < 0) { - error("mdio_register() failed: %d", ret); + pr_err("mdio_register() failed: %d", ret); goto err_free_mdio; } diff --git a/drivers/net/ep93xx_eth.c b/drivers/net/ep93xx_eth.c index a94191b9e67..bc457062433 100644 --- a/drivers/net/ep93xx_eth.c +++ b/drivers/net/ep93xx_eth.c @@ -324,7 +324,7 @@ static int ep93xx_eth_rcv_packet(struct eth_device *dev) debug("reporting %d bytes...\n", len); } else { /* Do we have an erroneous packet? */ - error("packet rx error, status %08X %08X", + pr_err("packet rx error, status %08X %08X", priv->rx_sq.current->word1, priv->rx_sq.current->word2); dump_rx_descriptor_queue(dev); @@ -401,7 +401,7 @@ static int ep93xx_eth_send_packet(struct eth_device *dev, ; /* noop */ if (!TX_STATUS_TXWE(priv->tx_sq.current)) { - error("packet tx error, status %08X", + pr_err("packet tx error, status %08X", priv->tx_sq.current->word1); dump_tx_descriptor_queue(dev); dump_tx_status_queue(dev); @@ -452,7 +452,7 @@ int ep93xx_eth_initialize(u8 dev_num, int base_addr) priv = malloc(sizeof(*priv)); if (!priv) { - error("malloc() failed"); + pr_err("malloc() failed"); goto eth_init_failed_0; } memset(priv, 0, sizeof(*priv)); @@ -462,34 +462,34 @@ int ep93xx_eth_initialize(u8 dev_num, int base_addr) priv->tx_dq.base = calloc(NUMTXDESC, sizeof(struct tx_descriptor)); if (priv->tx_dq.base == NULL) { - error("calloc() failed"); + pr_err("calloc() failed"); goto eth_init_failed_1; } priv->tx_sq.base = calloc(NUMTXDESC, sizeof(struct tx_status)); if (priv->tx_sq.base == NULL) { - error("calloc() failed"); + pr_err("calloc() failed"); goto eth_init_failed_2; } priv->rx_dq.base = calloc(NUMRXDESC, sizeof(struct rx_descriptor)); if (priv->rx_dq.base == NULL) { - error("calloc() failed"); + pr_err("calloc() failed"); goto eth_init_failed_3; } priv->rx_sq.base = calloc(NUMRXDESC, sizeof(struct rx_status)); if (priv->rx_sq.base == NULL) { - error("calloc() failed"); + pr_err("calloc() failed"); goto eth_init_failed_4; } dev = malloc(sizeof *dev); if (dev == NULL) { - error("malloc() failed"); + pr_err("malloc() failed"); goto eth_init_failed_5; } memset(dev, 0, sizeof *dev); diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c index 72ef42cca88..21ccab47ae2 100644 --- a/drivers/net/keystone_net.c +++ b/drivers/net/keystone_net.c @@ -757,7 +757,7 @@ static int ks2_eth_start(struct udevice *dev) qm_init(); if (ksnav_init(priv->netcp_pktdma, &priv->net_rx_buffs)) { - error("ksnav_init failed\n"); + pr_err("ksnav_init failed\n"); goto err_knav_init; } @@ -773,7 +773,7 @@ static int ks2_eth_start(struct udevice *dev) phy_startup(priv->phydev); if (priv->phydev->link == 0) { - error("phy startup failed\n"); + pr_err("phy startup failed\n"); goto err_phy_start; } } @@ -923,7 +923,7 @@ static int ks2_eth_probe(struct udevice *dev) */ mdio_bus = mdio_alloc(); if (!mdio_bus) { - error("MDIO alloc failed\n"); + pr_err("MDIO alloc failed\n"); return -ENOMEM; } priv->mdio_bus = mdio_bus; @@ -935,7 +935,7 @@ static int ks2_eth_probe(struct udevice *dev) ret = mdio_register(mdio_bus); if (ret) { - error("MDIO bus register failed\n"); + pr_err("MDIO bus register failed\n"); return ret; } } else { @@ -1011,7 +1011,7 @@ static int ks2_eth_bind_slaves(struct udevice *dev, int gbe, int *gbe_0) slave_name, offset_to_ofnode(slave), &sl_dev); if (ret) { - error("ks2_net - not able to bind slave interfaces\n"); + pr_err("ks2_net - not able to bind slave interfaces\n"); return ret; } } @@ -1031,7 +1031,7 @@ static int ks2_eth_bind_slaves(struct udevice *dev, int gbe, int *gbe_0) ret = device_bind_driver_to_node(dev, "eth_ks2_sl", slave_name, offset_to_ofnode(slave), &sl_dev); if (ret) { - error("ks2_net - not able to bind slave interfaces\n"); + pr_err("ks2_net - not able to bind slave interfaces\n"); return ret; } } @@ -1074,7 +1074,7 @@ static int ks2_eth_parse_slave_interface(int netcp, int slave, mdio = fdt_parent_offset(fdt, phy); if (mdio < 0) { - error("mdio dt not found\n"); + pr_err("mdio dt not found\n"); return -ENODEV; } priv->mdio_base = (void *)fdtdec_get_addr(fdt, mdio, "reg"); diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8af24702683..58f128d8a62 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -33,6 +33,14 @@ config PCI_PNP help Enable PCI memory and I/O space resource allocation and assignment. +config PCIE_ECAM_GENERIC + bool "Generic ECAM-based PCI host controller support" + default n + depends on DM_PCI + help + Say Y here if you want to enable support for generic ECAM-based + PCIe host controllers, such as the one emulated by QEMU. + config PCIE_DW_MVEBU bool "Enable Armada-8K PCIe driver (DesignWare core)" depends on DM_PCI diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index ad44e83996c..5eb12efbf5f 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PCI) += pci.o pci_auto_old.o endif obj-$(CONFIG_PCI) += pci_auto_common.o pci_common.o +obj-$(CONFIG_PCIE_ECAM_GENERIC) += pcie_ecam_generic.o obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 86df141d607..5a24eb6428f 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -518,6 +518,64 @@ int pci_auto_config_devices(struct udevice *bus) return sub_bus; } +int pci_generic_mmap_write_config( + struct udevice *bus, + int (*addr_f)(struct udevice *bus, pci_dev_t bdf, uint offset, void **addrp), + pci_dev_t bdf, + uint offset, + ulong value, + enum pci_size_t size) +{ + void *address; + + if (addr_f(bus, bdf, offset, &address) < 0) + return 0; + + switch (size) { + case PCI_SIZE_8: + writeb(value, address); + return 0; + case PCI_SIZE_16: + writew(value, address); + return 0; + case PCI_SIZE_32: + writel(value, address); + return 0; + default: + return -EINVAL; + } +} + +int pci_generic_mmap_read_config( + struct udevice *bus, + int (*addr_f)(struct udevice *bus, pci_dev_t bdf, uint offset, void **addrp), + pci_dev_t bdf, + uint offset, + ulong *valuep, + enum pci_size_t size) +{ + void *address; + + if (addr_f(bus, bdf, offset, &address) < 0) { + *valuep = pci_get_ff(size); + return 0; + } + + switch (size) { + case PCI_SIZE_8: + *valuep = readb(address); + return 0; + case PCI_SIZE_16: + *valuep = readw(address); + return 0; + case PCI_SIZE_32: + *valuep = readl(address); + return 0; + default: + return -EINVAL; + } +} + int dm_pci_hose_probe_bus(struct udevice *bus) { int sub_bus; diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 7d920d423d9..b5bd25ec563 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -369,7 +369,7 @@ static int tegra_pcie_port_parse_dt(ofnode node, struct tegra_pcie_port *port) addr = ofnode_get_property(node, "assigned-addresses", &len); if (!addr) { - error("property \"assigned-addresses\" not found"); + pr_err("property \"assigned-addresses\" not found"); return -FDT_ERR_NOTFOUND; } @@ -460,7 +460,7 @@ static int tegra_pcie_parse_port_info(ofnode node, uint *index, uint *lanes) err = ofnode_read_u32_default(node, "nvidia,num-lanes", -1); if (err < 0) { - error("failed to parse \"nvidia,num-lanes\" property"); + pr_err("failed to parse \"nvidia,num-lanes\" property"); return err; } @@ -468,7 +468,7 @@ static int tegra_pcie_parse_port_info(ofnode node, uint *index, uint *lanes) err = ofnode_read_pci_addr(node, 0, "reg", &addr); if (err < 0) { - error("failed to parse \"reg\" property"); + pr_err("failed to parse \"reg\" property"); return err; } @@ -491,25 +491,25 @@ static int tegra_pcie_parse_dt(struct udevice *dev, enum tegra_pci_id id, err = dev_read_resource(dev, 0, &pcie->pads); if (err < 0) { - error("resource \"pads\" not found"); + pr_err("resource \"pads\" not found"); return err; } err = dev_read_resource(dev, 1, &pcie->afi); if (err < 0) { - error("resource \"afi\" not found"); + pr_err("resource \"afi\" not found"); return err; } err = dev_read_resource(dev, 2, &pcie->cs); if (err < 0) { - error("resource \"cs\" not found"); + pr_err("resource \"cs\" not found"); return err; } err = tegra_pcie_board_init(); if (err < 0) { - error("tegra_pcie_board_init() failed: err=%d", err); + pr_err("tegra_pcie_board_init() failed: err=%d", err); return err; } @@ -518,7 +518,7 @@ static int tegra_pcie_parse_dt(struct udevice *dev, enum tegra_pci_id id, if (pcie->phy) { err = tegra_xusb_phy_prepare(pcie->phy); if (err < 0) { - error("failed to prepare PHY: %d", err); + pr_err("failed to prepare PHY: %d", err); return err; } } @@ -530,7 +530,7 @@ static int tegra_pcie_parse_dt(struct udevice *dev, enum tegra_pci_id id, err = tegra_pcie_parse_port_info(subnode, &index, &num_lanes); if (err < 0) { - error("failed to obtain root port info"); + pr_err("failed to obtain root port info"); continue; } @@ -560,7 +560,7 @@ static int tegra_pcie_parse_dt(struct udevice *dev, enum tegra_pci_id id, err = tegra_pcie_get_xbar_config(dev_ofnode(dev), lanes, id, &pcie->xbar); if (err < 0) { - error("invalid lane configuration"); + pr_err("invalid lane configuration"); return err; } @@ -574,31 +574,31 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) ret = power_domain_on(&pcie->pwrdom); if (ret) { - error("power_domain_on() failed: %d\n", ret); + pr_err("power_domain_on() failed: %d\n", ret); return ret; } ret = clk_enable(&pcie->clk_afi); if (ret) { - error("clk_enable(afi) failed: %d\n", ret); + pr_err("clk_enable(afi) failed: %d\n", ret); return ret; } ret = clk_enable(&pcie->clk_pex); if (ret) { - error("clk_enable(pex) failed: %d\n", ret); + pr_err("clk_enable(pex) failed: %d\n", ret); return ret; } ret = reset_deassert(&pcie->reset_afi); if (ret) { - error("reset_deassert(afi) failed: %d\n", ret); + pr_err("reset_deassert(afi) failed: %d\n", ret); return ret; } ret = reset_deassert(&pcie->reset_pex); if (ret) { - error("reset_deassert(pex) failed: %d\n", ret); + pr_err("reset_deassert(pex) failed: %d\n", ret); return ret; } @@ -618,14 +618,14 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) err = tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); if (err < 0) { - error("failed to power off PCIe partition: %d", err); + pr_err("failed to power off PCIe partition: %d", err); return err; } err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, PERIPH_ID_PCIE); if (err < 0) { - error("failed to power up PCIe partition: %d", err); + pr_err("failed to power up PCIe partition: %d", err); return err; } @@ -645,7 +645,7 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) err = tegra_plle_enable(); if (err < 0) { - error("failed to enable PLLE: %d\n", err); + pr_err("failed to enable PLLE: %d\n", err); return err; } @@ -705,7 +705,7 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie) /* wait for the PLL to lock */ err = tegra_pcie_pll_wait(pcie, 500); if (err < 0) { - error("PLL failed to lock: %d", err); + pr_err("PLL failed to lock: %d", err); return err; } @@ -769,7 +769,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) err = tegra_pcie_phy_enable(pcie); if (err < 0) { - error("failed to power on PHY: %d\n", err); + pr_err("failed to power on PHY: %d\n", err); return err; } #endif @@ -778,7 +778,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) #ifdef CONFIG_TEGRA186 err = reset_deassert(&pcie->reset_pcie_x); if (err) { - error("reset_deassert(pcie_x) failed: %d\n", err); + pr_err("reset_deassert(pcie_x) failed: %d\n", err); return err; } #else @@ -1143,25 +1143,25 @@ static int pci_tegra_probe(struct udevice *dev) err = tegra_pcie_power_on(pcie); if (err < 0) { - error("failed to power on"); + pr_err("failed to power on"); return err; } err = tegra_pcie_enable_controller(pcie); if (err < 0) { - error("failed to enable controller"); + pr_err("failed to enable controller"); return err; } err = tegra_pcie_setup_translations(dev); if (err < 0) { - error("failed to decode ranges"); + pr_err("failed to decode ranges"); return err; } err = tegra_pcie_enable(pcie); if (err < 0) { - error("failed to enable PCIe"); + pr_err("failed to enable PCIe"); return err; } diff --git a/drivers/pci/pcie_ecam_generic.c b/drivers/pci/pcie_ecam_generic.c new file mode 100644 index 00000000000..c7540ff80e8 --- /dev/null +++ b/drivers/pci/pcie_ecam_generic.c @@ -0,0 +1,143 @@ +/* + * Generic PCIE host provided by e.g. QEMU + * + * Heavily based on drivers/pci/pcie_xilinx.c + * + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <pci.h> + +#include <asm/io.h> + +/** + * struct generic_ecam_pcie - generic_ecam PCIe controller state + * @cfg_base: The base address of memory mapped configuration space + */ +struct generic_ecam_pcie { + void *cfg_base; +}; + +/** + * pci_generic_ecam_conf_address() - Calculate the address of a config access + * @bus: Pointer to the PCI bus + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @paddress: Pointer to the pointer to write the calculates address to + * + * Calculates the address that should be accessed to perform a PCIe + * configuration space access for a given device identified by the PCIe + * controller device @pcie and the bus, device & function numbers in @bdf. If + * access to the device is not valid then the function will return an error + * code. Otherwise the address to access will be written to the pointer pointed + * to by @paddress. + */ +static int pci_generic_ecam_conf_address(struct udevice *bus, pci_dev_t bdf, + uint offset, void **paddress) +{ + struct generic_ecam_pcie *pcie = dev_get_priv(bus); + void *addr; + + addr = pcie->cfg_base; + addr += PCI_BUS(bdf) << 20; + addr += PCI_DEV(bdf) << 15; + addr += PCI_FUNC(bdf) << 12; + addr += offset; + *paddress = addr; + + return 0; +} + +/** + * pci_generic_ecam_read_config() - Read from configuration space + * @bus: Pointer to the PCI bus + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @valuep: A pointer at which to store the read value + * @size: Indicates the size of access to perform + * + * Read a value of size @size from offset @offset within the configuration + * space of the device identified by the bus, device & function numbers in @bdf + * on the PCI bus @bus. + */ +static int pci_generic_ecam_read_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + return pci_generic_mmap_read_config(bus, pci_generic_ecam_conf_address, + bdf, offset, valuep, size); +} + +/** + * pci_generic_ecam_write_config() - Write to configuration space + * @bus: Pointer to the PCI bus + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @value: The value to write + * @size: Indicates the size of access to perform + * + * Write the value @value of size @size from offset @offset within the + * configuration space of the device identified by the bus, device & function + * numbers in @bdf on the PCI bus @bus. + */ +static int pci_generic_ecam_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + return pci_generic_mmap_write_config(bus, pci_generic_ecam_conf_address, + bdf, offset, value, size); +} + +/** + * pci_generic_ecam_ofdata_to_platdata() - Translate from DT to device state + * @dev: A pointer to the device being operated on + * + * Translate relevant data from the device tree pertaining to device @dev into + * state that the driver will later make use of. This state is stored in the + * device's private data structure. + * + * Return: 0 on success, else -EINVAL + */ +static int pci_generic_ecam_ofdata_to_platdata(struct udevice *dev) +{ + struct generic_ecam_pcie *pcie = dev_get_priv(dev); + struct fdt_resource reg_res; + DECLARE_GLOBAL_DATA_PTR; + int err; + + err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", + 0, ®_res); + if (err < 0) { + pr_err("\"reg\" resource not found\n"); + return err; + } + + pcie->cfg_base = map_physmem(reg_res.start, + fdt_resource_size(®_res), + MAP_NOCACHE); + + return 0; +} + +static const struct dm_pci_ops pci_generic_ecam_ops = { + .read_config = pci_generic_ecam_read_config, + .write_config = pci_generic_ecam_write_config, +}; + +static const struct udevice_id pci_generic_ecam_ids[] = { + { .compatible = "pci-host-ecam-generic" }, + { } +}; + +U_BOOT_DRIVER(pci_generic_ecam) = { + .name = "pci_generic_ecam", + .id = UCLASS_PCI, + .of_match = pci_generic_ecam_ids, + .ops = &pci_generic_ecam_ops, + .ofdata_to_platdata = pci_generic_ecam_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct generic_ecam_pcie), +}; diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 610f85c4e8e..0cb7f6d5643 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -241,14 +241,19 @@ static int ls_pcie_addr_valid(struct ls_pcie *pcie, pci_dev_t bdf) return 0; } -void *ls_pcie_conf_address(struct ls_pcie *pcie, pci_dev_t bdf, - int offset) +int ls_pcie_conf_address(struct udevice *bus, pci_dev_t bdf, + uint offset, void **paddress) { - struct udevice *bus = pcie->bus; + struct ls_pcie *pcie = dev_get_priv(bus); u32 busdev; - if (PCI_BUS(bdf) == bus->seq) - return pcie->dbi + offset; + if (ls_pcie_addr_valid(pcie, bdf)) + return -EINVAL; + + if (PCI_BUS(bdf) == bus->seq) { + *paddress = pcie->dbi + offset; + return 0; + } busdev = PCIE_ATU_BUS(PCI_BUS(bdf)) | PCIE_ATU_DEV(PCI_DEV(bdf)) | @@ -256,67 +261,28 @@ void *ls_pcie_conf_address(struct ls_pcie *pcie, pci_dev_t bdf, if (PCI_BUS(bdf) == bus->seq + 1) { ls_pcie_cfg0_set_busdev(pcie, busdev); - return pcie->cfg0 + offset; + *paddress = pcie->cfg0 + offset; } else { ls_pcie_cfg1_set_busdev(pcie, busdev); - return pcie->cfg1 + offset; + *paddress = pcie->cfg1 + offset; } + return 0; } static int ls_pcie_read_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep, enum pci_size_t size) { - struct ls_pcie *pcie = dev_get_priv(bus); - void *address; - - if (ls_pcie_addr_valid(pcie, bdf)) { - *valuep = pci_get_ff(size); - return 0; - } - - address = ls_pcie_conf_address(pcie, bdf, offset); - - switch (size) { - case PCI_SIZE_8: - *valuep = readb(address); - return 0; - case PCI_SIZE_16: - *valuep = readw(address); - return 0; - case PCI_SIZE_32: - *valuep = readl(address); - return 0; - default: - return -EINVAL; - } + return pci_generic_mmap_read_config(bus, ls_pcie_conf_address, + bdf, offset, valuep, size); } static int ls_pcie_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value, enum pci_size_t size) { - struct ls_pcie *pcie = dev_get_priv(bus); - void *address; - - if (ls_pcie_addr_valid(pcie, bdf)) - return 0; - - address = ls_pcie_conf_address(pcie, bdf, offset); - - switch (size) { - case PCI_SIZE_8: - writeb(value, address); - return 0; - case PCI_SIZE_16: - writew(value, address); - return 0; - case PCI_SIZE_32: - writel(value, address); - return 0; - default: - return -EINVAL; - } + return pci_generic_mmap_write_config(bus, ls_pcie_conf_address, + bdf, offset, value, size); } /* Clear multi-function bit */ diff --git a/drivers/pci/pcie_layerscape_fixup.c b/drivers/pci/pcie_layerscape_fixup.c index 9e6c2f5dfcf..3dae20103da 100644 --- a/drivers/pci/pcie_layerscape_fixup.c +++ b/drivers/pci/pcie_layerscape_fixup.c @@ -130,19 +130,28 @@ static void fdt_pcie_set_iommu_map_entry(void *blob, struct ls_pcie *pcie, u32 iommu_map[4]; int nodeoffset; int lenp; + uint svr; + char *compat = NULL; /* find pci controller node */ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", pcie->dbi_res.start); if (nodeoffset < 0) { #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ - nodeoffset = fdt_node_offset_by_compat_reg(blob, - CONFIG_FSL_PCIE_COMPAT, pcie->dbi_res.start); + svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; + if (svr == SVR_LS2088A || svr == SVR_LS2084A || + svr == SVR_LS2048A || svr == SVR_LS2044A || + svr == SVR_LS2081A || svr == SVR_LS2041A) + compat = "fsl,ls2088a-pcie"; + else + compat = CONFIG_FSL_PCIE_COMPAT; + + if (compat) + nodeoffset = fdt_node_offset_by_compat_reg(blob, + compat, pcie->dbi_res.start); +#endif if (nodeoffset < 0) return; -#else - return; -#endif } /* get phandle to iommu controller */ diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c index 4ba32df5169..57112f5333e 100644 --- a/drivers/pci/pcie_xilinx.c +++ b/drivers/pci/pcie_xilinx.c @@ -41,7 +41,7 @@ static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie) /** * pcie_xilinx_config_address() - Calculate the address of a config access - * @pcie: Pointer to the PCI controller state + * @udev: Pointer to the PCI bus * @bdf: Identifies the PCIe device to access * @offset: The offset into the device's configuration space * @paddress: Pointer to the pointer to write the calculates address to @@ -55,9 +55,10 @@ static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie) * * Return: 0 on success, else -ENODEV */ -static int pcie_xilinx_config_address(struct xilinx_pcie *pcie, pci_dev_t bdf, +static int pcie_xilinx_config_address(struct udevice *udev, pci_dev_t bdf, uint offset, void **paddress) { + struct xilinx_pcie *pcie = dev_get_priv(udev); unsigned int bus = PCI_BUS(bdf); unsigned int dev = PCI_DEV(bdf); unsigned int func = PCI_FUNC(bdf); @@ -101,29 +102,8 @@ static int pcie_xilinx_read_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep, enum pci_size_t size) { - struct xilinx_pcie *pcie = dev_get_priv(bus); - void *address; - int err; - - err = pcie_xilinx_config_address(pcie, bdf, offset, &address); - if (err < 0) { - *valuep = pci_get_ff(size); - return 0; - } - - switch (size) { - case PCI_SIZE_8: - *valuep = __raw_readb(address); - return 0; - case PCI_SIZE_16: - *valuep = __raw_readw(address); - return 0; - case PCI_SIZE_32: - *valuep = __raw_readl(address); - return 0; - default: - return -EINVAL; - } + return pci_generic_mmap_read_config(bus, pcie_xilinx_config_address, + bdf, offset, valuep, size); } /** @@ -144,27 +124,8 @@ static int pcie_xilinx_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value, enum pci_size_t size) { - struct xilinx_pcie *pcie = dev_get_priv(bus); - void *address; - int err; - - err = pcie_xilinx_config_address(pcie, bdf, offset, &address); - if (err < 0) - return 0; - - switch (size) { - case PCI_SIZE_8: - __raw_writeb(value, address); - return 0; - case PCI_SIZE_16: - __raw_writew(value, address); - return 0; - case PCI_SIZE_32: - __raw_writel(value, address); - return 0; - default: - return -EINVAL; - } + return pci_generic_mmap_write_config(bus, pcie_xilinx_config_address, + bdf, offset, value, size); } /** @@ -187,7 +148,7 @@ static int pcie_xilinx_ofdata_to_platdata(struct udevice *dev) err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", 0, ®_res); if (err < 0) { - error("\"reg\" resource not found\n"); + pr_err("\"reg\" resource not found\n"); return err; } diff --git a/drivers/phy/marvell/comphy_cp110.c b/drivers/phy/marvell/comphy_cp110.c index 3ac405a9be6..37187885fa0 100644 --- a/drivers/phy/marvell/comphy_cp110.c +++ b/drivers/phy/marvell/comphy_cp110.c @@ -509,7 +509,7 @@ static int comphy_pcie_power_up(u32 lane, u32 pcie_width, bool clk_src, debug("Read from reg = %p - value = 0x%x\n", hpipe_addr + HPIPE_LANE_STATUS1_REG, data); - error("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n"); + pr_err("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n"); ret = 0; } } @@ -633,7 +633,7 @@ static int comphy_usb3_power_up(u32 lane, void __iomem *hpipe_base, if (data != 0) { debug("Read from reg = %p - value = 0x%x\n", hpipe_addr + HPIPE_LANE_STATUS1_REG, data); - error("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n"); + pr_err("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n"); ret = 0; } @@ -666,14 +666,14 @@ static int comphy_sata_power_up(u32 lane, void __iomem *hpipe_base, gd->fdt_blob, sata_node, "marvell,armada-8k-ahci"); if (sata_node == 0) { - error("SATA node not found in FDT\n"); + pr_err("SATA node not found in FDT\n"); return 0; } sata_base = (void __iomem *)fdtdec_get_addr_size_auto_noparent( gd->fdt_blob, sata_node, "reg", 0, NULL, true); if (sata_base == NULL) { - error("SATA address not found in FDT\n"); + pr_err("SATA address not found in FDT\n"); return 0; } @@ -976,7 +976,7 @@ static int comphy_sata_power_up(u32 lane, void __iomem *hpipe_base, if (data != 0) { debug("Read from reg = %p - value = 0x%x\n", hpipe_addr + HPIPE_LANE_STATUS1_REG, data); - error("SD_EXTERNAL_STATUS0_PLL_TX is %d, SD_EXTERNAL_STATUS0_PLL_RX is %d\n", + pr_err("SD_EXTERNAL_STATUS0_PLL_TX is %d, SD_EXTERNAL_STATUS0_PLL_RX is %d\n", (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK), (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK)); ret = 0; @@ -1099,7 +1099,7 @@ static int comphy_sgmii_power_up(u32 lane, u32 sgmii_speed, if (data != 0) { debug("Read from reg = %p - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); - error("SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", + pr_err("SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK), (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)); ret = 0; @@ -1117,7 +1117,7 @@ static int comphy_sgmii_power_up(u32 lane, u32 sgmii_speed, data = polling_with_timeout(addr, data, mask, 100); if (data != 0) { debug("Read from reg = %p - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); - error("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); + pr_err("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); ret = 0; } @@ -1398,7 +1398,7 @@ static int comphy_sfi_power_up(u32 lane, void __iomem *hpipe_base, data = polling_with_timeout(addr, data, mask, 15000); if (data != 0) { debug("Read from reg = %p - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); - error("SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", + pr_err("SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK), (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)); ret = 0; @@ -1418,7 +1418,7 @@ static int comphy_sfi_power_up(u32 lane, void __iomem *hpipe_base, if (data != 0) { debug("Read from reg = %p - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); - error("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); + pr_err("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); ret = 0; } @@ -1577,7 +1577,7 @@ static int comphy_rxauii_power_up(u32 lane, void __iomem *hpipe_base, if (data != 0) { debug("Read from reg = %p - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); - error("SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", + pr_err("SD_EXTERNAL_STATUS0_PLL_RX is %d, SD_EXTERNAL_STATUS0_PLL_TX is %d\n", (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK), (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)); ret = 0; @@ -1596,7 +1596,7 @@ static int comphy_rxauii_power_up(u32 lane, void __iomem *hpipe_base, if (data != 0) { debug("Read from reg = %p - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); - error("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); + pr_err("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); ret = 0; } @@ -1742,7 +1742,7 @@ static int comphy_utmi_power_up(u32 utmi_index, void __iomem *utmi_base_addr, mask = data; data = polling_with_timeout(addr, data, mask, 100); if (data != 0) { - error("Impedance calibration is not done\n"); + pr_err("Impedance calibration is not done\n"); debug("Read from reg = %p - value = 0x%x\n", addr, data); ret = 0; } @@ -1751,7 +1751,7 @@ static int comphy_utmi_power_up(u32 utmi_index, void __iomem *utmi_base_addr, mask = data; data = polling_with_timeout(addr, data, mask, 100); if (data != 0) { - error("PLL calibration is not done\n"); + pr_err("PLL calibration is not done\n"); debug("Read from reg = %p - value = 0x%x\n", addr, data); ret = 0; } @@ -1761,7 +1761,7 @@ static int comphy_utmi_power_up(u32 utmi_index, void __iomem *utmi_base_addr, mask = data; data = polling_with_timeout(addr, data, mask, 100); if (data != 0) { - error("PLL is not ready\n"); + pr_err("PLL is not ready\n"); debug("Read from reg = %p - value = 0x%x\n", addr, data); ret = 0; } @@ -1818,7 +1818,7 @@ static void comphy_utmi_phy_init(u32 utmi_phy_count, cp110_utmi_data[i].usb_cfg_addr, cp110_utmi_data[i].utmi_cfg_addr, cp110_utmi_data[i].utmi_phy_port)) { - error("Failed to initialize UTMI PHY %d\n", i); + pr_err("Failed to initialize UTMI PHY %d\n", i); continue; } printf("UTMI PHY %d initialized to ", i); @@ -1864,7 +1864,7 @@ void comphy_dedicated_phys_init(void) (void __iomem *)fdtdec_get_addr_size_auto_noparent( gd->fdt_blob, node, "reg", 0, NULL, true); if (cp110_utmi_data[i].utmi_base_addr == NULL) { - error("UTMI PHY base address is invalid\n"); + pr_err("UTMI PHY base address is invalid\n"); i++; continue; } @@ -1874,7 +1874,7 @@ void comphy_dedicated_phys_init(void) (void __iomem *)fdtdec_get_addr_size_auto_noparent( gd->fdt_blob, node, "reg", 1, NULL, true); if (cp110_utmi_data[i].usb_cfg_addr == NULL) { - error("UTMI PHY base address is invalid\n"); + pr_err("UTMI PHY base address is invalid\n"); i++; continue; } @@ -1884,7 +1884,7 @@ void comphy_dedicated_phys_init(void) (void __iomem *)fdtdec_get_addr_size_auto_noparent( gd->fdt_blob, node, "reg", 2, NULL, true); if (cp110_utmi_data[i].utmi_cfg_addr == NULL) { - error("UTMI PHY base address is invalid\n"); + pr_err("UTMI PHY base address is invalid\n"); i++; continue; } @@ -1896,7 +1896,7 @@ void comphy_dedicated_phys_init(void) cp110_utmi_data[i].utmi_phy_port = fdtdec_get_int( gd->fdt_blob, node, "utmi-port", UTMI_PHY_INVALID); if (cp110_utmi_data[i].utmi_phy_port == UTMI_PHY_INVALID) { - error("UTMI PHY port type is invalid\n"); + pr_err("UTMI PHY port type is invalid\n"); i++; continue; } @@ -2049,7 +2049,7 @@ int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg, * PHY_TYPE_UNCONNECTED state. */ ptr_comphy_map->type = PHY_TYPE_UNCONNECTED; - error("PLL is not locked - Failed to initialize lane %d\n", + pr_err("PLL is not locked - Failed to initialize lane %d\n", lane); } } diff --git a/drivers/phy/sti_usb_phy.c b/drivers/phy/sti_usb_phy.c index 0e0b1c02d2e..88fcfbb3e5b 100644 --- a/drivers/phy/sti_usb_phy.c +++ b/drivers/phy/sti_usb_phy.c @@ -47,13 +47,13 @@ static int sti_usb_phy_deassert(struct sti_usb_phy *phy) ret = reset_deassert(&phy->global_ctl); if (ret < 0) { - error("PHY global deassert failed: %d", ret); + pr_err("PHY global deassert failed: %d", ret); return ret; } ret = reset_deassert(&phy->port_ctl); if (ret < 0) - error("PHY port deassert failed: %d", ret); + pr_err("PHY port deassert failed: %d", ret); return ret; } @@ -85,13 +85,13 @@ static int sti_usb_phy_exit(struct phy *usb_phy) ret = reset_assert(&phy->port_ctl); if (ret < 0) { - error("PHY port assert failed: %d", ret); + pr_err("PHY port assert failed: %d", ret); return ret; } ret = reset_assert(&phy->global_ctl); if (ret < 0) - error("PHY global assert failed: %d", ret); + pr_err("PHY global assert failed: %d", ret); return ret; } @@ -114,20 +114,20 @@ int sti_usb_phy_probe(struct udevice *dev) &syscfg_phandle); if (ret < 0) { - error("Can't get syscfg phandle: %d\n", ret); + pr_err("Can't get syscfg phandle: %d\n", ret); return ret; } ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, syscfg_phandle.node, &syscon); if (ret) { - error("unable to find syscon device (%d)\n", ret); + pr_err("unable to find syscon device (%d)\n", ret); return ret; } priv->regmap = syscon_get_regmap(syscon); if (!priv->regmap) { - error("unable to find regmap\n"); + pr_err("unable to find regmap\n"); return -ENODEV; } @@ -137,12 +137,12 @@ int sti_usb_phy_probe(struct udevice *dev) ARRAY_SIZE(cells)); if (count < 0) { - error("Bad PHY st,syscfg property %d\n", count); + pr_err("Bad PHY st,syscfg property %d\n", count); return -EINVAL; } if (count > PHYPARAM_NB) { - error("Unsupported PHY param count %d\n", count); + pr_err("Unsupported PHY param count %d\n", count); return -EINVAL; } @@ -152,14 +152,14 @@ int sti_usb_phy_probe(struct udevice *dev) /* get global reset control */ ret = reset_get_by_name(dev, "global", &priv->global_ctl); if (ret) { - error("can't get global reset for %s (%d)", dev->name, ret); + pr_err("can't get global reset for %s (%d)", dev->name, ret); return ret; } /* get port reset control */ ret = reset_get_by_name(dev, "port", &priv->port_ctl); if (ret) { - error("can't get port reset for %s (%d)", dev->name, ret); + pr_err("can't get port reset for %s (%d)", dev->name, ret); return ret; } diff --git a/drivers/phy/ti-pipe3-phy.c b/drivers/phy/ti-pipe3-phy.c index 680e32f3ea6..babf2ffe393 100644 --- a/drivers/phy/ti-pipe3-phy.c +++ b/drivers/phy/ti-pipe3-phy.c @@ -261,7 +261,7 @@ static int pipe3_exit(struct phy *phy) } while (--timeout); if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) { - error("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n", + pr_err("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n", __func__, val); return -EBUSY; } @@ -284,14 +284,14 @@ static void *get_reg(struct udevice *dev, const char *name) err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, name, &syscon); if (err) { - error("unable to find syscon device for %s (%d)\n", + pr_err("unable to find syscon device for %s (%d)\n", name, err); return NULL; } regmap = syscon_get_regmap(syscon); if (IS_ERR(regmap)) { - error("unable to find regmap for %s (%ld)\n", + pr_err("unable to find regmap for %s (%ld)\n", name, PTR_ERR(regmap)); return NULL; } @@ -299,7 +299,7 @@ static void *get_reg(struct udevice *dev, const char *name) cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), name, &len); if (len < 2*sizeof(fdt32_t)) { - error("offset not available for %s\n", name); + pr_err("offset not available for %s\n", name); return NULL; } @@ -318,13 +318,13 @@ static int pipe3_phy_probe(struct udevice *dev) addr = devfdt_get_addr_size_index(dev, 2, &sz); if (addr == FDT_ADDR_T_NONE) { - error("missing pll ctrl address\n"); + pr_err("missing pll ctrl address\n"); return -EINVAL; } pipe3->pll_ctrl_base = map_physmem(addr, sz, MAP_NOCACHE); if (!pipe3->pll_ctrl_base) { - error("unable to remap pll ctrl\n"); + pr_err("unable to remap pll ctrl\n"); return -EINVAL; } diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index 27165b00077..2bf853eba13 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -578,7 +578,7 @@ int armada_37xx_pinctrl_probe(struct udevice *dev) info->base = (void __iomem *)devfdt_get_addr(dev); if (!info->base) { - error("unable to find regmap\n"); + pr_err("unable to find regmap\n"); return -ENODEV; } diff --git a/drivers/pinctrl/pinctrl-sti.c b/drivers/pinctrl/pinctrl-sti.c index 40341b4eeb7..735e412f608 100644 --- a/drivers/pinctrl/pinctrl-sti.c +++ b/drivers/pinctrl/pinctrl-sti.c @@ -142,7 +142,7 @@ void sti_pin_configure(struct udevice *dev, struct sti_pin_desc *pin_desc) break; default: - error("%s invalid direction value: 0x%x\n", + pr_err("%s invalid direction value: 0x%x\n", __func__, pin_desc->dir); BUG(); break; @@ -237,14 +237,14 @@ static int sti_pinctrl_set_state(struct udevice *dev, struct udevice *config) prop_name, "#gpio-cells", 0, 0, &args); if (ret < 0) { - error("Can't get the gpio bank phandle: %d\n", ret); + pr_err("Can't get the gpio bank phandle: %d\n", ret); return ret; } bank_name = fdt_getprop(blob, args.node, "st,bank-name", &count); if (count < 0) { - error("Can't find bank-name property %d\n", count); + pr_err("Can't find bank-name property %d\n", count); return -EINVAL; } @@ -254,12 +254,12 @@ static int sti_pinctrl_set_state(struct udevice *dev, struct udevice *config) prop_name, cells, ARRAY_SIZE(cells)); if (count < 0) { - error("Bad pin configuration array %d\n", count); + pr_err("Bad pin configuration array %d\n", count); return -EINVAL; } if (count > MAX_STI_PINCONF_ENTRIES) { - error("Unsupported pinconf array count %d\n", count); + pr_err("Unsupported pinconf array count %d\n", count); return -EINVAL; } @@ -284,13 +284,13 @@ static int sti_pinctrl_probe(struct udevice *dev) err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "st,syscfg", &syscon); if (err) { - error("unable to find syscon device\n"); + pr_err("unable to find syscon device\n"); return err; } plat->regmap = syscon_get_regmap(syscon); if (!plat->regmap) { - error("unable to find regmap\n"); + pr_err("unable to find regmap\n"); return -ENODEV; } diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index bf2a86c6364..51fdfb3851c 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -160,7 +160,7 @@ static int stm32_pinctrl_set_state_simple(struct udevice *dev, config_node = fdt_node_offset_by_phandle(fdt, phandle); if (config_node < 0) { - error("prop pinctrl-0 index %d invalid phandle\n", i); + pr_err("prop pinctrl-0 index %d invalid phandle\n", i); return -EINVAL; } diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3368.c b/drivers/pinctrl/rockchip/pinctrl_rk3368.c index b1f57041642..25249e377a6 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3368.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3368.c @@ -208,6 +208,29 @@ enum { GPIO2A0_FLASH_CSN0 = (1 << GPIO2A0_SHIFT), }; +/*GRF_GPIO2B_IOMUX*/ +enum { + GPIO2B3_SHIFT = 6, + GPIO2B3_MASK = GENMASK(GPIO2B3_SHIFT + 1, GPIO2B3_SHIFT), + GPIO2B3_GPIO = 0, + GPIO2B3_SDMMC0_DTECTN = (1 << GPIO2B3_SHIFT), + + GPIO2B2_SHIFT = 4, + GPIO2B2_MASK = GENMASK(GPIO2B2_SHIFT + 1, GPIO2B2_SHIFT), + GPIO2B2_GPIO = 0, + GPIO2B2_SDMMC0_CMD = (1 << GPIO2B2_SHIFT), + + GPIO2B1_SHIFT = 2, + GPIO2B1_MASK = GENMASK(GPIO2B1_SHIFT + 1, GPIO2B1_SHIFT), + GPIO2B1_GPIO = 0, + GPIO2B1_SDMMC0_CLKOUT = (1 << GPIO2B1_SHIFT), + + GPIO2B0_SHIFT = 0, + GPIO2B0_MASK = GENMASK(GPIO2B0_SHIFT + 1, GPIO2B0_SHIFT), + GPIO2B0_GPIO = 0, + GPIO2B0_SDMMC0_D3 = (1 << GPIO2B0_SHIFT), +}; + /*GRF_GPIO2D_IOMUX*/ enum { GPIO2D7_SHIFT = 14, @@ -580,11 +603,17 @@ static void pinctrl_rk3368_sdmmc_config(struct rk3368_grf *grf, int mmc_id) GPIO2A4_EMMC_CLKOUT); break; case PERIPH_ID_SDCARD: - /* - * We assume that the BROM has already set this up - * correctly for us and that there's nothing to do - * here. - */ + debug("mmc id = %d setting registers!\n", mmc_id); + rk_clrsetreg(&grf->gpio2a_iomux, + GPIO2A5_MASK | GPIO2A7_MASK | + GPIO2A7_MASK, + GPIO2A5_SDMMC0_D0 | GPIO2A6_SDMMC0_D1 | + GPIO2A7_SDMMC0_D2); + rk_clrsetreg(&grf->gpio2b_iomux, + GPIO2B0_MASK | GPIO2B1_MASK | + GPIO2B2_MASK | GPIO2B3_MASK, + GPIO2B0_SDMMC0_D3 | GPIO2B1_SDMMC0_CLKOUT | + GPIO2B2_SDMMC0_CMD | GPIO2B3_SDMMC0_DTECTN); break; default: debug("mmc id = %d iomux error!\n", mmc_id); diff --git a/drivers/power/pmic/as3722.c b/drivers/power/pmic/as3722.c index 4efe8ee183d..3b0427e0b91 100644 --- a/drivers/power/pmic/as3722.c +++ b/drivers/power/pmic/as3722.c @@ -46,14 +46,14 @@ static int as3722_read_id(struct udevice *dev, uint *idp, uint *revisionp) ret = pmic_reg_read(dev, AS3722_ASIC_ID1); if (ret < 0) { - error("failed to read ID1 register: %d", ret); + pr_err("failed to read ID1 register: %d", ret); return ret; } *idp = ret; ret = pmic_reg_read(dev, AS3722_ASIC_ID2); if (ret < 0) { - error("failed to read ID2 register: %d", ret); + pr_err("failed to read ID2 register: %d", ret); return ret; } *revisionp = ret; @@ -71,7 +71,7 @@ int as3722_sd_set_voltage(struct udevice *dev, unsigned int sd, u8 value) ret = pmic_reg_write(dev, AS3722_SD_VOLTAGE(sd), value); if (ret < 0) { - error("failed to write SD%u voltage register: %d", sd, ret); + pr_err("failed to write SD%u voltage register: %d", sd, ret); return ret; } @@ -87,7 +87,7 @@ int as3722_ldo_set_voltage(struct udevice *dev, unsigned int ldo, u8 value) ret = pmic_reg_write(dev, AS3722_LDO_VOLTAGE(ldo), value); if (ret < 0) { - error("failed to write LDO%u voltage register: %d", ldo, + pr_err("failed to write LDO%u voltage register: %d", ldo, ret); return ret; } @@ -102,12 +102,12 @@ static int as3722_probe(struct udevice *dev) ret = as3722_read_id(dev, &id, &revision); if (ret < 0) { - error("failed to read ID: %d", ret); + pr_err("failed to read ID: %d", ret); return ret; } if (id != AS3722_DEVICE_ID) { - error("unknown device"); + pr_err("unknown device"); return -ENOENT; } diff --git a/drivers/power/pmic/as3722_gpio.c b/drivers/power/pmic/as3722_gpio.c index d0b681ca4ab..5cf4cb6b518 100644 --- a/drivers/power/pmic/as3722_gpio.c +++ b/drivers/power/pmic/as3722_gpio.c @@ -26,7 +26,7 @@ int as3722_gpio_configure(struct udevice *pmic, unsigned int gpio, err = pmic_reg_write(pmic, AS3722_GPIO_CONTROL(gpio), value); if (err) { - error("failed to configure GPIO#%u: %d", gpio, err); + pr_err("failed to configure GPIO#%u: %d", gpio, err); return err; } @@ -46,7 +46,7 @@ static int as3722_gpio_set_value(struct udevice *dev, unsigned int gpio, err = pmic_reg_read(pmic, AS3722_GPIO_SIGNAL_OUT); if (err < 0) { - error("failed to read GPIO signal out register: %d", err); + pr_err("failed to read GPIO signal out register: %d", err); return err; } value = err; @@ -61,7 +61,7 @@ static int as3722_gpio_set_value(struct udevice *dev, unsigned int gpio, err = pmic_reg_write(pmic, AS3722_GPIO_SIGNAL_OUT, value); if (err) { - error("failed to set GPIO#%u %s: %d", gpio, l, err); + pr_err("failed to set GPIO#%u %s: %d", gpio, l, err); return err; } @@ -84,13 +84,13 @@ int as3722_gpio_direction_output(struct udevice *dev, unsigned int gpio, err = pmic_reg_write(pmic, AS3722_GPIO_CONTROL(gpio), value); if (err) { - error("failed to configure GPIO#%u as output: %d", gpio, err); + pr_err("failed to configure GPIO#%u as output: %d", gpio, err); return err; } err = as3722_gpio_set_value(pmic, gpio, value); if (err < 0) { - error("failed to set GPIO#%u high: %d", gpio, err); + pr_err("failed to set GPIO#%u high: %d", gpio, err); return err; } diff --git a/drivers/power/pmic/i2c_pmic_emul.c b/drivers/power/pmic/i2c_pmic_emul.c index 2d35d09d454..38a2a04f177 100644 --- a/drivers/power/pmic/i2c_pmic_emul.c +++ b/drivers/power/pmic/i2c_pmic_emul.c @@ -31,7 +31,7 @@ static int sandbox_i2c_pmic_read_data(struct udevice *emul, uchar chip, struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) { - error("Request exceeds PMIC register range! Max register: %#x", + pr_err("Request exceeds PMIC register range! Max register: %#x", SANDBOX_PMIC_REG_COUNT); return -EFAULT; } @@ -68,7 +68,7 @@ static int sandbox_i2c_pmic_write_data(struct udevice *emul, uchar chip, len--; if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) { - error("Request exceeds PMIC register range! Max register: %#x", + pr_err("Request exceeds PMIC register range! Max register: %#x", SANDBOX_PMIC_REG_COUNT); } @@ -111,7 +111,7 @@ static int sandbox_i2c_pmic_ofdata_to_platdata(struct udevice *emul) SANDBOX_PMIC_REG_COUNT); if (!reg_defaults) { - error("Property \"reg-defaults\" not found for device: %s!", + pr_err("Property \"reg-defaults\" not found for device: %s!", emul->name); return -EINVAL; } diff --git a/drivers/power/pmic/lp873x.c b/drivers/power/pmic/lp873x.c index f5054683139..95c2b7e8c74 100644 --- a/drivers/power/pmic/lp873x.c +++ b/drivers/power/pmic/lp873x.c @@ -27,7 +27,7 @@ static int lp873x_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return -EIO; } @@ -37,7 +37,7 @@ static int lp873x_write(struct udevice *dev, uint reg, const uint8_t *buff, static int lp873x_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return -EIO; } diff --git a/drivers/power/pmic/lp87565.c b/drivers/power/pmic/lp87565.c index 782a46c4cc3..506769e3626 100644 --- a/drivers/power/pmic/lp87565.c +++ b/drivers/power/pmic/lp87565.c @@ -29,7 +29,7 @@ static int lp87565_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return ret; } @@ -40,7 +40,7 @@ static int lp87565_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return ret; } diff --git a/drivers/power/pmic/max77686.c b/drivers/power/pmic/max77686.c index ceca9f96a7f..b3ed84992ff 100644 --- a/drivers/power/pmic/max77686.c +++ b/drivers/power/pmic/max77686.c @@ -31,7 +31,7 @@ static int max77686_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return -EIO; } @@ -41,7 +41,7 @@ static int max77686_write(struct udevice *dev, uint reg, const uint8_t *buff, static int max77686_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return -EIO; } diff --git a/drivers/power/pmic/max8997.c b/drivers/power/pmic/max8997.c index f749d7debfc..5ebeb8a316b 100644 --- a/drivers/power/pmic/max8997.c +++ b/drivers/power/pmic/max8997.c @@ -26,7 +26,7 @@ static int max8997_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return ret; } @@ -37,7 +37,7 @@ static int max8997_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return ret; } diff --git a/drivers/power/pmic/max8998.c b/drivers/power/pmic/max8998.c index 7c4773c7b3a..a7e04699e8b 100644 --- a/drivers/power/pmic/max8998.c +++ b/drivers/power/pmic/max8998.c @@ -26,7 +26,7 @@ static int max8998_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return ret; } @@ -37,7 +37,7 @@ static int max8998_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return ret; } diff --git a/drivers/power/pmic/palmas.c b/drivers/power/pmic/palmas.c index 804c0d13a0c..1e1ecb382e3 100644 --- a/drivers/power/pmic/palmas.c +++ b/drivers/power/pmic/palmas.c @@ -27,7 +27,7 @@ static int palmas_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return -EIO; } @@ -37,7 +37,7 @@ static int palmas_write(struct udevice *dev, uint reg, const uint8_t *buff, static int palmas_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return -EIO; } diff --git a/drivers/power/pmic/pfuze100.c b/drivers/power/pmic/pfuze100.c index 5f361c7696f..a06cbc07d49 100644 --- a/drivers/power/pmic/pfuze100.c +++ b/drivers/power/pmic/pfuze100.c @@ -33,7 +33,7 @@ static int pfuze100_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return -EIO; } @@ -43,7 +43,7 @@ static int pfuze100_write(struct udevice *dev, uint reg, const uint8_t *buff, static int pfuze100_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return -EIO; } diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c index 9d83059c403..522105e5ff0 100644 --- a/drivers/power/pmic/s2mps11.c +++ b/drivers/power/pmic/s2mps11.c @@ -27,7 +27,7 @@ static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return ret; } @@ -38,7 +38,7 @@ static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return ret; } diff --git a/drivers/power/pmic/s5m8767.c b/drivers/power/pmic/s5m8767.c index f8ae5ea2dba..3812e240ab0 100644 --- a/drivers/power/pmic/s5m8767.c +++ b/drivers/power/pmic/s5m8767.c @@ -30,7 +30,7 @@ static int s5m8767_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return -EIO; } @@ -40,7 +40,7 @@ static int s5m8767_write(struct udevice *dev, uint reg, const uint8_t *buff, static int s5m8767_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return -EIO; } diff --git a/drivers/power/pmic/sandbox.c b/drivers/power/pmic/sandbox.c index 6763303c667..e8d6faca160 100644 --- a/drivers/power/pmic/sandbox.c +++ b/drivers/power/pmic/sandbox.c @@ -31,7 +31,7 @@ static int sandbox_pmic_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return -EIO; } @@ -42,7 +42,7 @@ static int sandbox_pmic_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - error("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!", dev, reg); return -EIO; } @@ -52,7 +52,7 @@ static int sandbox_pmic_read(struct udevice *dev, uint reg, static int sandbox_pmic_bind(struct udevice *dev) { if (!pmic_bind_children(dev, dev_ofnode(dev), pmic_children_info)) - error("%s:%d PMIC: %s - no child found!", __func__, __LINE__, + pr_err("%s:%d PMIC: %s - no child found!", __func__, __LINE__, dev->name); /* Always return success for this device - allows for PMIC I/O */ diff --git a/drivers/power/pmic/tps65090.c b/drivers/power/pmic/tps65090.c index 4565e3b54c1..ee5358bcedc 100644 --- a/drivers/power/pmic/tps65090.c +++ b/drivers/power/pmic/tps65090.c @@ -29,7 +29,7 @@ static int tps65090_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - error("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!", dev, reg); return -EIO; } @@ -42,7 +42,7 @@ static int tps65090_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) { - error("read error %d from device: %p register: %#x!", ret, dev, + pr_err("read error %d from device: %p register: %#x!", ret, dev, reg); return -EIO; } diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index c82a936e8af..8892fa14e02 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -77,6 +77,13 @@ config DM_REGULATOR_FIXED features for fixed value regulators. The driver implements get/set api for enable and get only for voltage value. +config SPL_DM_REGULATOR_FIXED + bool "Enable Driver Model for REGULATOR Fixed value in SPL" + depends on DM_REGULATOR_FIXED + ---help--- + This config enables implementation of driver-model regulator uclass + features for fixed value regulators in SPL. + config DM_REGULATOR_GPIO bool "Enable Driver Model for GPIO REGULATOR" depends on DM_REGULATOR @@ -151,6 +158,19 @@ config DM_REGULATOR_PALMAS features for REGULATOR PALMAS and the family of PALMAS PMICs. The driver implements get/set api for: value and enable. +config DM_REGULATOR_PBIAS + bool "Enable driver for PBIAS regulator" + depends on DM_REGULATOR + select REGMAP + select SYSCON + ---help--- + This enables implementation of driver-model regulator uclass + features for pseudo-regulator PBIAS found in the OMAP SOCs. + This pseudo-regulator is used to provide a BIAS voltage to MMC1 + signal pads and must be configured properly during a voltage switch. + Voltage switching is required by some operating modes of SDcards and + eMMC. + config DM_REGULATOR_LP873X bool "Enable driver for LP873X PMIC regulators" depends on PMIC_LP873X diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 18fb870e430..6c149a92634 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -18,5 +18,6 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index 35c292222b9..97b4a98bf0b 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -117,7 +117,7 @@ static int fixed_regulator_set_enable(struct udevice *dev, bool enable) ret = dm_gpio_set_value(&dev_pdata->gpio, enable); if (ret) { - error("Can't set regulator : %s gpio to: %d\n", dev->name, + pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, enable); return ret; } diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c index 42391c69b43..1031a0362b6 100644 --- a/drivers/power/regulator/gpio-regulator.c +++ b/drivers/power/regulator/gpio-regulator.c @@ -109,7 +109,7 @@ static int gpio_regulator_set_value(struct udevice *dev, int uV) ret = dm_gpio_set_value(&dev_pdata->gpio, enable); if (ret) { - error("Can't set regulator : %s gpio to: %d\n", dev->name, + pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, enable); return ret; } diff --git a/drivers/power/regulator/max77686.c b/drivers/power/regulator/max77686.c index 8780806cff0..2212d36ed6a 100644 --- a/drivers/power/regulator/max77686.c +++ b/drivers/power/regulator/max77686.c @@ -98,7 +98,7 @@ static int max77686_buck_volt2hex(int buck, int uV) if (hex >= 0 && hex <= hex_max) return hex; - error("Value: %d uV is wrong for BUCK%d", uV, buck); + pr_err("Value: %d uV is wrong for BUCK%d", uV, buck); return -EINVAL; } @@ -134,7 +134,7 @@ static int max77686_buck_hex2volt(int buck, int hex) return uV; bad_hex: - error("Value: %#x is wrong for BUCK%d", hex, buck); + pr_err("Value: %#x is wrong for BUCK%d", hex, buck); return -EINVAL; } @@ -160,7 +160,7 @@ static int max77686_ldo_volt2hex(int ldo, int uV) if (hex >= 0 && hex <= MAX77686_LDO_VOLT_MAX_HEX) return hex; - error("Value: %d uV is wrong for LDO%d", uV, ldo); + pr_err("Value: %d uV is wrong for LDO%d", uV, ldo); return -EINVAL; } @@ -189,7 +189,7 @@ static int max77686_ldo_hex2volt(int ldo, int hex) return uV; bad_hex: - error("Value: %#x is wrong for ldo%d", hex, ldo); + pr_err("Value: %#x is wrong for ldo%d", hex, ldo); return -EINVAL; } @@ -328,7 +328,7 @@ static int max77686_ldo_val(struct udevice *dev, int op, int *uV) ldo = dev->driver_data; if (ldo < 1 || ldo > MAX77686_LDO_NUM) { - error("Wrong ldo number: %d", ldo); + pr_err("Wrong ldo number: %d", ldo); return -EINVAL; } @@ -366,7 +366,7 @@ static int max77686_buck_val(struct udevice *dev, int op, int *uV) buck = dev->driver_data; if (buck < 1 || buck > MAX77686_BUCK_NUM) { - error("Wrong buck number: %d", buck); + pr_err("Wrong buck number: %d", buck); return -EINVAL; } @@ -423,7 +423,7 @@ static int max77686_ldo_mode(struct udevice *dev, int op, int *opmode) ldo = dev->driver_data; if (ldo < 1 || ldo > MAX77686_LDO_NUM) { - error("Wrong ldo number: %d", ldo); + pr_err("Wrong ldo number: %d", ldo); return -EINVAL; } @@ -493,7 +493,7 @@ static int max77686_ldo_mode(struct udevice *dev, int op, int *opmode) } if (mode == 0xff) { - error("Wrong mode: %d for ldo%d", *opmode, ldo); + pr_err("Wrong mode: %d for ldo%d", *opmode, ldo); return -EINVAL; } @@ -545,7 +545,7 @@ static int max77686_buck_mode(struct udevice *dev, int op, int *opmode) buck = dev->driver_data; if (buck < 1 || buck > MAX77686_BUCK_NUM) { - error("Wrong buck number: %d", buck); + pr_err("Wrong buck number: %d", buck); return -EINVAL; } @@ -614,7 +614,7 @@ static int max77686_buck_mode(struct udevice *dev, int op, int *opmode) } if (mode == 0xff) { - error("Wrong mode: %d for buck: %d\n", *opmode, buck); + pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck); return -EINVAL; } diff --git a/drivers/power/regulator/pbias_regulator.c b/drivers/power/regulator/pbias_regulator.c new file mode 100644 index 00000000000..116b7f480a7 --- /dev/null +++ b/drivers/power/regulator/pbias_regulator.c @@ -0,0 +1,301 @@ +/* + * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com> + * Jean-Jacques Hiblot <jjhiblot@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <regmap.h> +#include <syscon.h> +#include <linux/bitops.h> +#include <linux/ioport.h> +#include <dm/read.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct pbias_reg_info { + u32 enable; + u32 enable_mask; + u32 disable_val; + u32 vmode; + unsigned int enable_time; + char *name; +}; + +struct pbias_priv { + struct regmap *regmap; + int offset; +}; + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "pbias", .driver = "pbias_regulator"}, + { }, +}; + +static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + struct pbias_priv *priv = dev_get_priv(dev); + u32 val = *(u32 *)buff; + + if (len != 4) + return -EINVAL; + + return regmap_write(priv->regmap, priv->offset, val); +} + +static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + struct pbias_priv *priv = dev_get_priv(dev); + + if (len != 4) + return -EINVAL; + + return regmap_read(priv->regmap, priv->offset, (u32 *)buff); +} + +static int pbias_ofdata_to_platdata(struct udevice *dev) +{ + struct pbias_priv *priv = dev_get_priv(dev); + struct udevice *syscon; + struct regmap *regmap; + struct resource res; + int err; + + err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, + "syscon", &syscon); + if (err) { + pr_err("%s: unable to find syscon device (%d)\n", __func__, + err); + return err; + } + + regmap = syscon_get_regmap(syscon); + if (IS_ERR(regmap)) { + pr_err("%s: unable to find regmap (%ld)\n", __func__, + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + priv->regmap = regmap; + + err = dev_read_resource(dev, 0, &res); + if (err) { + pr_err("%s: unable to find offset (%d)\n", __func__, err); + return err; + } + priv->offset = res.start; + + return 0; +} + +static int pbias_bind(struct udevice *dev) +{ + int children; + + children = pmic_bind_children(dev, dev->node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + return 0; +} + +static struct dm_pmic_ops pbias_ops = { + .read = pbias_read, + .write = pbias_write, +}; + +static const struct udevice_id pbias_ids[] = { + { .compatible = "ti,pbias-dra7" }, + { } +}; + +U_BOOT_DRIVER(pbias_pmic) = { + .name = "pbias_pmic", + .id = UCLASS_PMIC, + .of_match = pbias_ids, + .bind = pbias_bind, + .ops = &pbias_ops, + .ofdata_to_platdata = pbias_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct pbias_priv), +}; + +static const struct pbias_reg_info pbias_mmc_omap2430 = { + .enable = BIT(1), + .enable_mask = BIT(1), + .vmode = BIT(0), + .disable_val = 0, + .enable_time = 100, + .name = "pbias_mmc_omap2430" +}; + +static const struct pbias_reg_info pbias_sim_omap3 = { + .enable = BIT(9), + .enable_mask = BIT(9), + .vmode = BIT(8), + .enable_time = 100, + .name = "pbias_sim_omap3" +}; + +static const struct pbias_reg_info pbias_mmc_omap4 = { + .enable = BIT(26) | BIT(22), + .enable_mask = BIT(26) | BIT(25) | BIT(22), + .disable_val = BIT(25), + .vmode = BIT(21), + .enable_time = 100, + .name = "pbias_mmc_omap4" +}; + +static const struct pbias_reg_info pbias_mmc_omap5 = { + .enable = BIT(27) | BIT(26), + .enable_mask = BIT(27) | BIT(25) | BIT(26), + .disable_val = BIT(25), + .vmode = BIT(21), + .enable_time = 100, + .name = "pbias_mmc_omap5" +}; + +static const struct pbias_reg_info *pbias_reg_infos[] = { + &pbias_mmc_omap5, + &pbias_mmc_omap4, + &pbias_sim_omap3, + &pbias_mmc_omap2430, + NULL +}; + +static int pbias_regulator_probe(struct udevice *dev) +{ + const struct pbias_reg_info **p = pbias_reg_infos; + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + while (*p) { + int rc; + + rc = dev_read_stringlist_search(dev, "regulator-name", + (*p)->name); + if (rc >= 0) { + debug("found regulator %s\n", (*p)->name); + break; + } else if (rc != -ENODATA) { + return rc; + } + p++; + } + if (!*p) { + int i = 0; + const char *s; + + debug("regulator "); + while (dev_read_string_index(dev, "regulator-name", i++, &s) >= 0) + debug("%s'%s' ", (i > 1) ? ", " : "", s); + debug("%s not supported\n", (i > 2) ? "are" : "is"); + return -EINVAL; + } + + uc_pdata->type = REGULATOR_TYPE_OTHER; + dev->priv = (void *)*p; + + return 0; +} + +static int pbias_regulator_get_value(struct udevice *dev) +{ + const struct pbias_reg_info *p = dev_get_priv(dev); + int rc; + u32 reg; + + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); + if (rc) + return rc; + + debug("%s voltage id %s\n", p->name, + (reg & p->vmode) ? "3.0v" : "1.8v"); + return (reg & p->vmode) ? 3000000 : 1800000; +} + +static int pbias_regulator_set_value(struct udevice *dev, int uV) +{ + const struct pbias_reg_info *p = dev_get_priv(dev); + int rc; + u32 reg; + + debug("Setting %s voltage to %s\n", p->name, + (reg & p->vmode) ? "3.0v" : "1.8v"); + + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); + if (rc) + return rc; + + if (uV == 3000000) + reg |= p->vmode; + else if (uV == 1800000) + reg &= ~p->vmode; + else + return -EINVAL; + + return pmic_write(dev->parent, 0, (uint8_t *)®, sizeof(reg)); +} + +static int pbias_regulator_get_enable(struct udevice *dev) +{ + const struct pbias_reg_info *p = dev_get_priv(dev); + int rc; + u32 reg; + + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); + if (rc) + return rc; + + debug("%s id %s\n", p->name, + (reg & p->enable_mask) == (p->disable_val) ? "on" : "off"); + + return (reg & p->enable_mask) == (p->disable_val); +} + +static int pbias_regulator_set_enable(struct udevice *dev, bool enable) +{ + const struct pbias_reg_info *p = dev_get_priv(dev); + int rc; + u32 reg; + + debug("Turning %s %s\n", enable ? "on" : "off", p->name); + + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); + if (rc) + return rc; + + reg &= ~p->enable_mask; + if (enable) + reg |= p->enable; + else + reg |= p->disable_val; + + rc = pmic_write(dev->parent, 0, (uint8_t *)®, sizeof(reg)); + if (rc) + return rc; + + if (enable) + udelay(p->enable_time); + + return 0; +} + +static const struct dm_regulator_ops pbias_regulator_ops = { + .get_value = pbias_regulator_get_value, + .set_value = pbias_regulator_set_value, + .get_enable = pbias_regulator_get_enable, + .set_enable = pbias_regulator_set_enable, +}; + +U_BOOT_DRIVER(pbias_regulator) = { + .name = "pbias_regulator", + .id = UCLASS_REGULATOR, + .ops = &pbias_regulator_ops, + .probe = pbias_regulator_probe, +}; diff --git a/drivers/power/regulator/sandbox.c b/drivers/power/regulator/sandbox.c index 06c09fd0515..f980a17389e 100644 --- a/drivers/power/regulator/sandbox.c +++ b/drivers/power/regulator/sandbox.c @@ -87,7 +87,7 @@ int out_get_value(struct udevice *dev, int output_count, int reg_type, int ret; if (dev->driver_data > output_count) { - error("Unknown regulator number: %lu for PMIC %s!", + pr_err("Unknown regulator number: %lu for PMIC %s!", dev->driver_data, dev->name); return -EINVAL; } @@ -95,7 +95,7 @@ int out_get_value(struct udevice *dev, int output_count, int reg_type, reg = (dev->driver_data - 1) * OUT_REG_COUNT + reg_type; ret = pmic_read(dev->parent, reg, ®_val, 1); if (ret) { - error("PMIC read failed: %d\n", ret); + pr_err("PMIC read failed: %d\n", ret); return ret; } @@ -115,14 +115,14 @@ static int out_set_value(struct udevice *dev, int output_count, int reg_type, int max_value; if (dev->driver_data > output_count) { - error("Unknown regulator number: %lu for PMIC %s!", + pr_err("Unknown regulator number: %lu for PMIC %s!", dev->driver_data, dev->name); return -EINVAL; } max_value = range[dev->driver_data - 1].max; if (value > max_value) { - error("Wrong value for %s: %lu. Max is: %d.", + pr_err("Wrong value for %s: %lu. Max is: %d.", dev->name, dev->driver_data, max_value); return -EINVAL; } @@ -134,7 +134,7 @@ static int out_set_value(struct udevice *dev, int output_count, int reg_type, reg = (dev->driver_data - 1) * OUT_REG_COUNT + reg_type; ret = pmic_write(dev->parent, reg, ®_val, 1); if (ret) { - error("PMIC write failed: %d\n", ret); + pr_err("PMIC write failed: %d\n", ret); return ret; } @@ -154,7 +154,7 @@ static int out_get_mode(struct udevice *dev) reg = (dev->driver_data - 1) * OUT_REG_COUNT + OUT_REG_OM; ret = pmic_read(dev->parent, reg, ®_val, 1); if (ret) { - error("PMIC read failed: %d\n", ret); + pr_err("PMIC read failed: %d\n", ret); return ret; } @@ -163,7 +163,7 @@ static int out_get_mode(struct udevice *dev) return uc_pdata->mode[i].id; } - error("Unknown operation mode for %s!", dev->name); + pr_err("Unknown operation mode for %s!", dev->name); return -EINVAL; } @@ -188,14 +188,14 @@ static int out_set_mode(struct udevice *dev, int mode) } if (reg_val == -1) { - error("Unknown operation mode for %s!", dev->name); + pr_err("Unknown operation mode for %s!", dev->name); return -EINVAL; } reg = (dev->driver_data - 1) * OUT_REG_COUNT + OUT_REG_OM; ret = pmic_write(dev->parent, reg, (uint8_t *)®_val, 1); if (ret) { - error("PMIC write failed: %d\n", ret); + pr_err("PMIC write failed: %d\n", ret); return ret; } diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index b09d03c2c9d..45b5fe72471 100644 --- a/drivers/ram/rockchip/Makefile +++ b/drivers/ram/rockchip/Makefile @@ -5,3 +5,8 @@ # obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o +obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o +obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o +obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o +obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o +obj-$(CONFIG_ROCKCHIP_RK3399) = sdram_rk3399.o diff --git a/drivers/ram/rockchip/dmc-rk3368.c b/drivers/ram/rockchip/dmc-rk3368.c index 7577ff0363d..bfcb1ddefe3 100644 --- a/drivers/ram/rockchip/dmc-rk3368.c +++ b/drivers/ram/rockchip/dmc-rk3368.c @@ -230,7 +230,7 @@ static int memory_init(struct rk3368_ddr_pctl *pctl, tmp = get_timer(0); do { if (get_timer(tmp) > timeout_ms) { - error("%s: POWER_UP_START did not complete in %ld ms\n", + pr_err("%s: POWER_UP_START did not complete in %ld ms\n", __func__, timeout_ms); return -ETIME; } @@ -422,7 +422,7 @@ static int dfi_cfg(struct rk3368_ddr_pctl *pctl) tmp = get_timer(0); do { if (get_timer(tmp) > timeout_ms) { - error("%s: DFI init did not complete within %ld ms\n", + pr_err("%s: DFI init did not complete within %ld ms\n", __func__, timeout_ms); return -ETIME; } @@ -457,7 +457,7 @@ static int pctl_calc_timings(struct rk3368_sdram_params *params, u32 tfaw_as_ps; if (params->ddr_speed_bin != DDR3_1600K) { - error("%s: unimplemented DDR3 speed bin %d\n", + pr_err("%s: unimplemented DDR3 speed bin %d\n", __func__, params->ddr_speed_bin); return -1; } @@ -585,7 +585,7 @@ static int ddrphy_data_training(struct rk3368_ddr_pctl *pctl, tmp = get_timer(0); do { if (get_timer(tmp) > timeout_ms) { - error("%s: did not complete within %ld ms\n", + pr_err("%s: did not complete within %ld ms\n", __func__, timeout_ms); return -ETIME; } @@ -625,7 +625,7 @@ static int sdram_col_row_detect(struct udevice *dev) } if (col == 8) { - error("%s: col detect error\n", __func__); + pr_err("%s: col detect error\n", __func__); return -EINVAL; } @@ -644,7 +644,7 @@ static int sdram_col_row_detect(struct udevice *dev) } if (row == 11) { - error("%s: row detect error\n", __func__); + pr_err("%s: row detect error\n", __func__); return -EINVAL; } @@ -764,7 +764,7 @@ static int msch_niu_config(struct rk3368_msch *msch, } } - error("%s: ddrconf (NIU config) not found\n", __func__); + pr_err("%s: ddrconf (NIU config) not found\n", __func__); return -EINVAL; } diff --git a/drivers/ram/rockchip/sdram_rk3188.c b/drivers/ram/rockchip/sdram_rk3188.c new file mode 100644 index 00000000000..365d00ef542 --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk3188.c @@ -0,0 +1,960 @@ +/* + * (C) Copyright 2015 Google, Inc + * Copyright 2014 Rockchip Inc. + * + * SPDX-License-Identifier: GPL-2.0 + * + * Adapted from the very similar rk3288 ddr init. + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <dt-structs.h> +#include <errno.h> +#include <ram.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk3188.h> +#include <asm/arch/ddr_rk3188.h> +#include <asm/arch/grf_rk3188.h> +#include <asm/arch/pmu_rk3188.h> +#include <asm/arch/sdram.h> +#include <asm/arch/sdram_common.h> +#include <linux/err.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct chan_info { + struct rk3288_ddr_pctl *pctl; + struct rk3288_ddr_publ *publ; + struct rk3188_msch *msch; +}; + +struct dram_info { + struct chan_info chan[1]; + struct ram_info info; + struct clk ddr_clk; + struct rk3188_cru *cru; + struct rk3188_grf *grf; + struct rk3188_sgrf *sgrf; + struct rk3188_pmu *pmu; +}; + +struct rk3188_sdram_params { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3188_dmc of_plat; +#endif + struct rk3288_sdram_channel ch[2]; + struct rk3288_sdram_pctl_timing pctl_timing; + struct rk3288_sdram_phy_timing phy_timing; + struct rk3288_base_params base; + int num_channels; + struct regmap *map; +}; + +const int ddrconf_table[] = { + /* + * [5:4] row(13+n) + * [1:0] col(9+n), assume bw=2 + * row col,bw + */ + 0, + ((2 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT), + ((1 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT), + ((0 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT), + ((2 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT), + ((1 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT), + ((0 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT), + ((1 << DDRCONF_ROW_SHIFT) | 0 << DDRCONF_COL_SHIFT), + ((0 << DDRCONF_ROW_SHIFT) | 0 << DDRCONF_COL_SHIFT), + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +#define TEST_PATTEN 0x5aa5f00f +#define DQS_GATE_TRAINING_ERROR_RANK0 (1 << 4) +#define DQS_GATE_TRAINING_ERROR_RANK1 (2 << 4) + +#ifdef CONFIG_SPL_BUILD +static void copy_to_reg(u32 *dest, const u32 *src, u32 n) +{ + int i; + + for (i = 0; i < n / sizeof(u32); i++) { + writel(*src, dest); + src++; + dest++; + } +} + +static void ddr_reset(struct rk3188_cru *cru, u32 ch, u32 ctl, u32 phy) +{ + u32 phy_ctl_srstn_shift = 13; + u32 ctl_psrstn_shift = 11; + u32 ctl_srstn_shift = 10; + u32 phy_psrstn_shift = 9; + u32 phy_srstn_shift = 8; + + rk_clrsetreg(&cru->cru_softrst_con[5], + 1 << phy_ctl_srstn_shift | 1 << ctl_psrstn_shift | + 1 << ctl_srstn_shift | 1 << phy_psrstn_shift | + 1 << phy_srstn_shift, + phy << phy_ctl_srstn_shift | ctl << ctl_psrstn_shift | + ctl << ctl_srstn_shift | phy << phy_psrstn_shift | + phy << phy_srstn_shift); +} + +static void ddr_phy_ctl_reset(struct rk3188_cru *cru, u32 ch, u32 n) +{ + u32 phy_ctl_srstn_shift = 13; + + rk_clrsetreg(&cru->cru_softrst_con[5], + 1 << phy_ctl_srstn_shift, n << phy_ctl_srstn_shift); +} + +static void phy_pctrl_reset(struct rk3188_cru *cru, + struct rk3288_ddr_publ *publ, + int channel) +{ + int i; + + ddr_reset(cru, channel, 1, 1); + udelay(1); + clrbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST); + for (i = 0; i < 4; i++) + clrbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST); + + udelay(10); + setbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST); + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST); + + udelay(10); + ddr_reset(cru, channel, 1, 0); + udelay(10); + ddr_reset(cru, channel, 0, 0); + udelay(10); +} + +static void phy_dll_bypass_set(struct rk3288_ddr_publ *publ, + u32 freq) +{ + int i; + + if (freq <= 250000000) { + if (freq <= 150000000) + clrbits_le32(&publ->dllgcr, SBIAS_BYPASS); + else + setbits_le32(&publ->dllgcr, SBIAS_BYPASS); + setbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS); + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxdllcr, + DXDLLCR_DLLDIS); + + setbits_le32(&publ->pir, PIR_DLLBYP); + } else { + clrbits_le32(&publ->dllgcr, SBIAS_BYPASS); + clrbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS); + for (i = 0; i < 4; i++) { + clrbits_le32(&publ->datx8[i].dxdllcr, + DXDLLCR_DLLDIS); + } + + clrbits_le32(&publ->pir, PIR_DLLBYP); + } +} + +static void dfi_cfg(struct rk3288_ddr_pctl *pctl, u32 dramtype) +{ + writel(DFI_INIT_START, &pctl->dfistcfg0); + writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, + &pctl->dfistcfg1); + writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2); + writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN, + &pctl->dfilpcfg0); + + writel(2 << TCTRL_DELAY_TIME_SHIFT, &pctl->dfitctrldelay); + writel(1 << TPHY_WRDATA_TIME_SHIFT, &pctl->dfitphywrdata); + writel(0xf << TPHY_RDLAT_TIME_SHIFT, &pctl->dfitphyrdlat); + writel(2 << TDRAM_CLK_DIS_TIME_SHIFT, &pctl->dfitdramclkdis); + writel(2 << TDRAM_CLK_EN_TIME_SHIFT, &pctl->dfitdramclken); + writel(1, &pctl->dfitphyupdtype0); + + /* cs0 and cs1 write odt enable */ + writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL), + &pctl->dfiodtcfg); + /* odt write length */ + writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1); + /* phyupd and ctrlupd disabled */ + writel(0, &pctl->dfiupdcfg); +} + +static void ddr_set_enable(struct rk3188_grf *grf, uint channel, bool enable) +{ + uint val = 0; + + if (enable) + val = 1 << DDR_16BIT_EN_SHIFT; + + rk_clrsetreg(&grf->ddrc_con0, 1 << DDR_16BIT_EN_SHIFT, val); +} + +static void ddr_set_ddr3_mode(struct rk3188_grf *grf, uint channel, + bool ddr3_mode) +{ + uint mask, val; + + mask = MSCH4_MAINDDR3_MASK << MSCH4_MAINDDR3_SHIFT; + val = ddr3_mode << MSCH4_MAINDDR3_SHIFT; + rk_clrsetreg(&grf->soc_con2, mask, val); +} + +static void ddr_rank_2_row15en(struct rk3188_grf *grf, bool enable) +{ + uint mask, val; + + mask = RANK_TO_ROW15_EN_MASK << RANK_TO_ROW15_EN_SHIFT; + val = enable << RANK_TO_ROW15_EN_SHIFT; + rk_clrsetreg(&grf->soc_con2, mask, val); +} + +static void pctl_cfg(int channel, struct rk3288_ddr_pctl *pctl, + struct rk3188_sdram_params *sdram_params, + struct rk3188_grf *grf) +{ + copy_to_reg(&pctl->togcnt1u, &sdram_params->pctl_timing.togcnt1u, + sizeof(sdram_params->pctl_timing)); + switch (sdram_params->base.dramtype) { + case DDR3: + if (sdram_params->phy_timing.mr[1] & DDR3_DLL_DISABLE) { + writel(sdram_params->pctl_timing.tcl - 3, + &pctl->dfitrddataen); + } else { + writel(sdram_params->pctl_timing.tcl - 2, + &pctl->dfitrddataen); + } + writel(sdram_params->pctl_timing.tcwl - 1, + &pctl->dfitphywrlat); + writel(0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT | DDR3_EN | + DDR2_DDR3_BL_8 | (6 - 4) << TFAW_SHIFT | PD_EXIT_SLOW | + 1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT, + &pctl->mcfg); + ddr_set_ddr3_mode(grf, channel, true); + ddr_set_enable(grf, channel, true); + break; + } + + setbits_le32(&pctl->scfg, 1); +} + +static void phy_cfg(const struct chan_info *chan, int channel, + struct rk3188_sdram_params *sdram_params) +{ + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3188_msch *msch = chan->msch; + uint ddr_freq_mhz = sdram_params->base.ddr_freq / 1000000; + u32 dinit2; + int i; + + dinit2 = DIV_ROUND_UP(ddr_freq_mhz * 200000, 1000); + /* DDR PHY Timing */ + copy_to_reg(&publ->dtpr[0], &sdram_params->phy_timing.dtpr0, + sizeof(sdram_params->phy_timing)); + writel(sdram_params->base.noc_timing, &msch->ddrtiming); + writel(0x3f, &msch->readlatency); + writel(DIV_ROUND_UP(ddr_freq_mhz * 5120, 1000) << PRT_DLLLOCK_SHIFT | + DIV_ROUND_UP(ddr_freq_mhz * 50, 1000) << PRT_DLLSRST_SHIFT | + 8 << PRT_ITMSRST_SHIFT, &publ->ptr[0]); + writel(DIV_ROUND_UP(ddr_freq_mhz * 500000, 1000) << PRT_DINIT0_SHIFT | + DIV_ROUND_UP(ddr_freq_mhz * 400, 1000) << PRT_DINIT1_SHIFT, + &publ->ptr[1]); + writel(min(dinit2, 0x1ffffU) << PRT_DINIT2_SHIFT | + DIV_ROUND_UP(ddr_freq_mhz * 1000, 1000) << PRT_DINIT3_SHIFT, + &publ->ptr[2]); + + switch (sdram_params->base.dramtype) { + case DDR3: + clrbits_le32(&publ->pgcr, 0x1f); + clrsetbits_le32(&publ->dcr, DDRMD_MASK << DDRMD_SHIFT, + DDRMD_DDR3 << DDRMD_SHIFT); + break; + } + if (sdram_params->base.odt) { + /*dynamic RTT enable */ + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT); + } else { + /*dynamic RTT disable */ + for (i = 0; i < 4; i++) + clrbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT); + } +} + +static void phy_init(struct rk3288_ddr_publ *publ) +{ + setbits_le32(&publ->pir, PIR_INIT | PIR_DLLSRST + | PIR_DLLLOCK | PIR_ZCAL | PIR_ITMSRST | PIR_CLRSR); + udelay(1); + while ((readl(&publ->pgsr) & + (PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE)) != + (PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE)) + ; +} + +static void send_command(struct rk3288_ddr_pctl *pctl, u32 rank, + u32 cmd, u32 arg) +{ + writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd); + udelay(1); + while (readl(&pctl->mcmd) & START_CMD) + ; +} + +static inline void send_command_op(struct rk3288_ddr_pctl *pctl, + u32 rank, u32 cmd, u32 ma, u32 op) +{ + send_command(pctl, rank, cmd, (ma & LPDDR2_MA_MASK) << LPDDR2_MA_SHIFT | + (op & LPDDR2_OP_MASK) << LPDDR2_OP_SHIFT); +} + +static void memory_init(struct rk3288_ddr_publ *publ, + u32 dramtype) +{ + setbits_le32(&publ->pir, + (PIR_INIT | PIR_DRAMINIT | PIR_LOCKBYP + | PIR_ZCALBYP | PIR_CLRSR | PIR_ICPC + | (dramtype == DDR3 ? PIR_DRAMRST : 0))); + udelay(1); + while ((readl(&publ->pgsr) & (PGSR_IDONE | PGSR_DLDONE)) + != (PGSR_IDONE | PGSR_DLDONE)) + ; +} + +static void move_to_config_state(struct rk3288_ddr_publ *publ, + struct rk3288_ddr_pctl *pctl) +{ + unsigned int state; + + while (1) { + state = readl(&pctl->stat) & PCTL_STAT_MSK; + + switch (state) { + case LOW_POWER: + writel(WAKEUP_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) + != ACCESS) + ; + /* wait DLL lock */ + while ((readl(&publ->pgsr) & PGSR_DLDONE) + != PGSR_DLDONE) + ; + /* + * if at low power state,need wakeup first, + * and then enter the config, so + * fallthrough + */ + case ACCESS: + /* fallthrough */ + case INIT_MEM: + writel(CFG_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG) + ; + break; + case CONFIG: + return; + default: + break; + } + } +} + +static void set_bandwidth_ratio(const struct chan_info *chan, int channel, + u32 n, struct rk3188_grf *grf) +{ + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3188_msch *msch = chan->msch; + + if (n == 1) { + setbits_le32(&pctl->ppcfg, 1); + ddr_set_enable(grf, channel, 1); + setbits_le32(&msch->ddrtiming, 1 << 31); + /* Data Byte disable*/ + clrbits_le32(&publ->datx8[2].dxgcr, 1); + clrbits_le32(&publ->datx8[3].dxgcr, 1); + /* disable DLL */ + setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS); + setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS); + } else { + clrbits_le32(&pctl->ppcfg, 1); + ddr_set_enable(grf, channel, 0); + clrbits_le32(&msch->ddrtiming, 1 << 31); + /* Data Byte enable*/ + setbits_le32(&publ->datx8[2].dxgcr, 1); + setbits_le32(&publ->datx8[3].dxgcr, 1); + + /* enable DLL */ + clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS); + clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS); + /* reset DLL */ + clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST); + clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST); + udelay(10); + setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST); + setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST); + } + setbits_le32(&pctl->dfistcfg0, 1 << 2); +} + +static int data_training(const struct chan_info *chan, int channel, + struct rk3188_sdram_params *sdram_params) +{ + unsigned int j; + int ret = 0; + u32 rank; + int i; + u32 step[2] = { PIR_QSTRN, PIR_RVTRN }; + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3288_ddr_pctl *pctl = chan->pctl; + + /* disable auto refresh */ + writel(0, &pctl->trefi); + + if (sdram_params->base.dramtype != LPDDR3) + setbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT); + rank = sdram_params->ch[channel].rank | 1; + for (j = 0; j < ARRAY_SIZE(step); j++) { + /* + * trigger QSTRN and RVTRN + * clear DTDONE status + */ + setbits_le32(&publ->pir, PIR_CLRSR); + + /* trigger DTT */ + setbits_le32(&publ->pir, + PIR_INIT | step[j] | PIR_LOCKBYP | PIR_ZCALBYP | + PIR_CLRSR); + udelay(1); + /* wait echo byte DTDONE */ + while ((readl(&publ->datx8[0].dxgsr[0]) & rank) + != rank) + ; + while ((readl(&publ->datx8[1].dxgsr[0]) & rank) + != rank) + ; + if (!(readl(&pctl->ppcfg) & 1)) { + while ((readl(&publ->datx8[2].dxgsr[0]) + & rank) != rank) + ; + while ((readl(&publ->datx8[3].dxgsr[0]) + & rank) != rank) + ; + } + if (readl(&publ->pgsr) & + (PGSR_DTERR | PGSR_RVERR | PGSR_RVEIRR)) { + ret = -1; + break; + } + } + /* send some auto refresh to complement the lost while DTT */ + for (i = 0; i < (rank > 1 ? 8 : 4); i++) + send_command(pctl, rank, REF_CMD, 0); + + if (sdram_params->base.dramtype != LPDDR3) + clrbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT); + + /* resume auto refresh */ + writel(sdram_params->pctl_timing.trefi, &pctl->trefi); + + return ret; +} + +static void move_to_access_state(const struct chan_info *chan) +{ + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3288_ddr_pctl *pctl = chan->pctl; + unsigned int state; + + while (1) { + state = readl(&pctl->stat) & PCTL_STAT_MSK; + + switch (state) { + case LOW_POWER: + if (((readl(&pctl->stat) >> LP_TRIG_SHIFT) & + LP_TRIG_MASK) == 1) + return; + + writel(WAKEUP_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) != ACCESS) + ; + /* wait DLL lock */ + while ((readl(&publ->pgsr) & PGSR_DLDONE) + != PGSR_DLDONE) + ; + break; + case INIT_MEM: + writel(CFG_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG) + ; + /* fallthrough */ + case CONFIG: + writel(GO_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) == CONFIG) + ; + break; + case ACCESS: + return; + default: + break; + } + } +} + +static void dram_cfg_rbc(const struct chan_info *chan, u32 chnum, + struct rk3188_sdram_params *sdram_params) +{ + struct rk3288_ddr_publ *publ = chan->publ; + + if (sdram_params->ch[chnum].bk == 3) + clrsetbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT, + 1 << PDQ_SHIFT); + else + clrbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT); + + writel(sdram_params->base.ddrconfig, &chan->msch->ddrconf); +} + +static void dram_all_config(const struct dram_info *dram, + struct rk3188_sdram_params *sdram_params) +{ + unsigned int chan; + u32 sys_reg = 0; + + sys_reg |= sdram_params->base.dramtype << SYS_REG_DDRTYPE_SHIFT; + sys_reg |= (sdram_params->num_channels - 1) << SYS_REG_NUM_CH_SHIFT; + for (chan = 0; chan < sdram_params->num_channels; chan++) { + const struct rk3288_sdram_channel *info = + &sdram_params->ch[chan]; + + sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(chan); + sys_reg |= 1 << SYS_REG_CHINFO_SHIFT(chan); + sys_reg |= (info->rank - 1) << SYS_REG_RANK_SHIFT(chan); + sys_reg |= (info->col - 9) << SYS_REG_COL_SHIFT(chan); + sys_reg |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(chan); + sys_reg |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(chan); + sys_reg |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(chan); + sys_reg |= (2 >> info->bw) << SYS_REG_BW_SHIFT(chan); + sys_reg |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(chan); + + dram_cfg_rbc(&dram->chan[chan], chan, sdram_params); + } + if (sdram_params->ch[0].rank == 2) + ddr_rank_2_row15en(dram->grf, 0); + else + ddr_rank_2_row15en(dram->grf, 1); + + writel(sys_reg, &dram->pmu->sys_reg[2]); +} + +static int sdram_rank_bw_detect(struct dram_info *dram, int channel, + struct rk3188_sdram_params *sdram_params) +{ + int reg; + int need_trainig = 0; + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_publ *publ = chan->publ; + + ddr_rank_2_row15en(dram->grf, 0); + + if (data_training(chan, channel, sdram_params) < 0) { + printf("first data training fail!\n"); + reg = readl(&publ->datx8[0].dxgsr[0]); + /* Check the result for rank 0 */ + if ((channel == 0) && (reg & DQS_GATE_TRAINING_ERROR_RANK0)) { + printf("data training fail!\n"); + return -EIO; + } + + /* Check the result for rank 1 */ + if (reg & DQS_GATE_TRAINING_ERROR_RANK1) { + sdram_params->ch[channel].rank = 1; + clrsetbits_le32(&publ->pgcr, 0xF << 18, + sdram_params->ch[channel].rank << 18); + need_trainig = 1; + } + reg = readl(&publ->datx8[2].dxgsr[0]); + if (reg & (1 << 4)) { + sdram_params->ch[channel].bw = 1; + set_bandwidth_ratio(chan, channel, + sdram_params->ch[channel].bw, + dram->grf); + need_trainig = 1; + } + } + /* Assume the Die bit width are the same with the chip bit width */ + sdram_params->ch[channel].dbw = sdram_params->ch[channel].bw; + + if (need_trainig && + (data_training(chan, channel, sdram_params) < 0)) { + if (sdram_params->base.dramtype == LPDDR3) { + ddr_phy_ctl_reset(dram->cru, channel, 1); + udelay(10); + ddr_phy_ctl_reset(dram->cru, channel, 0); + udelay(10); + } + printf("2nd data training failed!"); + return -EIO; + } + + return 0; +} + +/* + * Detect ram columns and rows. + * @dram: dram info struct + * @channel: channel number to handle + * @sdram_params: sdram parameters, function will fill in col and row values + * + * Returns 0 or negative on error. + */ +static int sdram_col_row_detect(struct dram_info *dram, int channel, + struct rk3188_sdram_params *sdram_params) +{ + int row, col; + unsigned int addr; + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + int ret = 0; + + /* Detect col */ + for (col = 11; col >= 9; col--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + + (1 << (col + sdram_params->ch[channel].bw - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (col == 8) { + printf("Col detect error\n"); + ret = -EINVAL; + goto out; + } else { + sdram_params->ch[channel].col = col; + } + + ddr_rank_2_row15en(dram->grf, 1); + move_to_config_state(publ, pctl); + writel(1, &chan->msch->ddrconf); + move_to_access_state(chan); + /* Detect row, max 15,min13 in rk3188*/ + for (row = 16; row >= 13; row--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + (1 << (row + 15 - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (row == 12) { + printf("Row detect error\n"); + ret = -EINVAL; + } else { + sdram_params->ch[channel].cs1_row = row; + sdram_params->ch[channel].row_3_4 = 0; + debug("chn %d col %d, row %d\n", channel, col, row); + sdram_params->ch[channel].cs0_row = row; + } + +out: + return ret; +} + +static int sdram_get_niu_config(struct rk3188_sdram_params *sdram_params) +{ + int i, tmp, size, row, ret = 0; + + row = sdram_params->ch[0].cs0_row; + /* + * RK3188 share the rank and row bit15, we use same ddr config for 15bit + * and 16bit row + */ + if (row == 16) + row = 15; + tmp = sdram_params->ch[0].col - 9; + tmp -= (sdram_params->ch[0].bw == 2) ? 0 : 1; + tmp |= ((row - 13) << 4); + size = sizeof(ddrconf_table)/sizeof(ddrconf_table[0]); + for (i = 0; i < size; i++) + if (tmp == ddrconf_table[i]) + break; + if (i >= size) { + printf("niu config not found\n"); + ret = -EINVAL; + } else { + debug("niu config %d\n", i); + sdram_params->base.ddrconfig = i; + } + + return ret; +} + +static int sdram_init(struct dram_info *dram, + struct rk3188_sdram_params *sdram_params) +{ + int channel; + int zqcr; + int ret; + + if ((sdram_params->base.dramtype == DDR3 && + sdram_params->base.ddr_freq > 800000000)) { + printf("SDRAM frequency is too high!"); + return -E2BIG; + } + + ret = clk_set_rate(&dram->ddr_clk, sdram_params->base.ddr_freq); + if (ret) { + printf("Could not set DDR clock\n"); + return ret; + } + + for (channel = 0; channel < 1; channel++) { + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + + phy_pctrl_reset(dram->cru, publ, channel); + phy_dll_bypass_set(publ, sdram_params->base.ddr_freq); + + dfi_cfg(pctl, sdram_params->base.dramtype); + + pctl_cfg(channel, pctl, sdram_params, dram->grf); + + phy_cfg(chan, channel, sdram_params); + + phy_init(publ); + + writel(POWER_UP_START, &pctl->powctl); + while (!(readl(&pctl->powstat) & POWER_UP_DONE)) + ; + + memory_init(publ, sdram_params->base.dramtype); + move_to_config_state(publ, pctl); + + /* Using 32bit bus width for detect */ + sdram_params->ch[channel].bw = 2; + set_bandwidth_ratio(chan, channel, + sdram_params->ch[channel].bw, dram->grf); + /* + * set cs, using n=3 for detect + * CS0, n=1 + * CS1, n=2 + * CS0 & CS1, n = 3 + */ + sdram_params->ch[channel].rank = 2, + clrsetbits_le32(&publ->pgcr, 0xF << 18, + (sdram_params->ch[channel].rank | 1) << 18); + + /* DS=40ohm,ODT=155ohm */ + zqcr = 1 << ZDEN_SHIFT | 2 << PU_ONDIE_SHIFT | + 2 << PD_ONDIE_SHIFT | 0x19 << PU_OUTPUT_SHIFT | + 0x19 << PD_OUTPUT_SHIFT; + writel(zqcr, &publ->zq1cr[0]); + writel(zqcr, &publ->zq0cr[0]); + + /* Detect the rank and bit-width with data-training */ + writel(1, &chan->msch->ddrconf); + sdram_rank_bw_detect(dram, channel, sdram_params); + + if (sdram_params->base.dramtype == LPDDR3) { + u32 i; + writel(0, &pctl->mrrcfg0); + for (i = 0; i < 17; i++) + send_command_op(pctl, 1, MRR_CMD, i, 0); + } + writel(4, &chan->msch->ddrconf); + move_to_access_state(chan); + /* DDR3 and LPDDR3 are always 8 bank, no need detect */ + sdram_params->ch[channel].bk = 3; + /* Detect Col and Row number*/ + ret = sdram_col_row_detect(dram, channel, sdram_params); + if (ret) + goto error; + } + /* Find NIU DDR configuration */ + ret = sdram_get_niu_config(sdram_params); + if (ret) + goto error; + + dram_all_config(dram, sdram_params); + debug("%s done\n", __func__); + + return 0; +error: + printf("DRAM init failed!\n"); + hang(); +} + +static int setup_sdram(struct udevice *dev) +{ + struct dram_info *priv = dev_get_priv(dev); + struct rk3188_sdram_params *params = dev_get_platdata(dev); + + return sdram_init(priv, params); +} + +static int rk3188_dmc_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3188_sdram_params *params = dev_get_platdata(dev); + int ret; + + /* rk3188 supports only one-channel */ + params->num_channels = 1; + ret = dev_read_u32_array(dev, "rockchip,pctl-timing", + (u32 *)¶ms->pctl_timing, + sizeof(params->pctl_timing) / sizeof(u32)); + if (ret) { + printf("%s: Cannot read rockchip,pctl-timing\n", __func__); + return -EINVAL; + } + ret = dev_read_u32_array(dev, "rockchip,phy-timing", + (u32 *)¶ms->phy_timing, + sizeof(params->phy_timing) / sizeof(u32)); + if (ret) { + printf("%s: Cannot read rockchip,phy-timing\n", __func__); + return -EINVAL; + } + ret = dev_read_u32_array(dev, "rockchip,sdram-params", + (u32 *)¶ms->base, + sizeof(params->base) / sizeof(u32)); + if (ret) { + printf("%s: Cannot read rockchip,sdram-params\n", __func__); + return -EINVAL; + } + ret = regmap_init_mem(dev, ¶ms->map); + if (ret) + return ret; +#endif + + return 0; +} +#endif /* CONFIG_SPL_BUILD */ + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +static int conv_of_platdata(struct udevice *dev) +{ + struct rk3188_sdram_params *plat = dev_get_platdata(dev); + struct dtd_rockchip_rk3188_dmc *of_plat = &plat->of_plat; + int ret; + + memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing, + sizeof(plat->pctl_timing)); + memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing, + sizeof(plat->phy_timing)); + memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base)); + /* rk3188 supports dual-channel, set default channel num to 2 */ + plat->num_channels = 1; + ret = regmap_init_mem_platdata(dev, of_plat->reg, + ARRAY_SIZE(of_plat->reg) / 2, + &plat->map); + if (ret) + return ret; + + return 0; +} +#endif + +static int rk3188_dmc_probe(struct udevice *dev) +{ +#ifdef CONFIG_SPL_BUILD + struct rk3188_sdram_params *plat = dev_get_platdata(dev); + struct regmap *map; + struct udevice *dev_clk; + int ret; +#endif + struct dram_info *priv = dev_get_priv(dev); + + priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU); + +#ifdef CONFIG_SPL_BUILD +#if CONFIG_IS_ENABLED(OF_PLATDATA) + ret = conv_of_platdata(dev); + if (ret) + return ret; +#endif + map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC); + if (IS_ERR(map)) + return PTR_ERR(map); + priv->chan[0].msch = regmap_get_range(map, 0); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + priv->chan[0].pctl = regmap_get_range(plat->map, 0); + priv->chan[0].publ = regmap_get_range(plat->map, 1); + + ret = rockchip_get_clk(&dev_clk); + if (ret) + return ret; + priv->ddr_clk.id = CLK_DDR; + ret = clk_request(dev_clk, &priv->ddr_clk); + if (ret) + return ret; + + priv->cru = rockchip_get_cru(); + if (IS_ERR(priv->cru)) + return PTR_ERR(priv->cru); + ret = setup_sdram(dev); + if (ret) + return ret; +#else + priv->info.base = CONFIG_SYS_SDRAM_BASE; + priv->info.size = rockchip_sdram_size( + (phys_addr_t)&priv->pmu->sys_reg[2]); +#endif + + return 0; +} + +static int rk3188_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + struct dram_info *priv = dev_get_priv(dev); + + *info = priv->info; + + return 0; +} + +static struct ram_ops rk3188_dmc_ops = { + .get_info = rk3188_dmc_get_info, +}; + +static const struct udevice_id rk3188_dmc_ids[] = { + { .compatible = "rockchip,rk3188-dmc" }, + { } +}; + +U_BOOT_DRIVER(dmc_rk3188) = { + .name = "rockchip_rk3188_dmc", + .id = UCLASS_RAM, + .of_match = rk3188_dmc_ids, + .ops = &rk3188_dmc_ops, +#ifdef CONFIG_SPL_BUILD + .ofdata_to_platdata = rk3188_dmc_ofdata_to_platdata, +#endif + .probe = rk3188_dmc_probe, + .priv_auto_alloc_size = sizeof(struct dram_info), +#ifdef CONFIG_SPL_BUILD + .platdata_auto_alloc_size = sizeof(struct rk3188_sdram_params), +#endif +}; diff --git a/drivers/ram/rockchip/sdram_rk322x.c b/drivers/ram/rockchip/sdram_rk322x.c new file mode 100644 index 00000000000..cc3138b21db --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk322x.c @@ -0,0 +1,855 @@ +/* + * (C) Copyright 2017 Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0 + */ +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <dt-structs.h> +#include <errno.h> +#include <ram.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk322x.h> +#include <asm/arch/grf_rk322x.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sdram_rk322x.h> +#include <asm/arch/timer.h> +#include <asm/arch/uart.h> +#include <asm/arch/sdram_common.h> +#include <asm/types.h> +#include <linux/err.h> + +DECLARE_GLOBAL_DATA_PTR; +struct chan_info { + struct rk322x_ddr_pctl *pctl; + struct rk322x_ddr_phy *phy; + struct rk322x_service_sys *msch; +}; + +struct dram_info { + struct chan_info chan[1]; + struct ram_info info; + struct clk ddr_clk; + struct rk322x_cru *cru; + struct rk322x_grf *grf; +}; + +struct rk322x_sdram_params { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3228_dmc of_plat; +#endif + struct rk322x_sdram_channel ch[1]; + struct rk322x_pctl_timing pctl_timing; + struct rk322x_phy_timing phy_timing; + struct rk322x_base_params base; + int num_channels; + struct regmap *map; +}; + +#ifdef CONFIG_TPL_BUILD +/* + * [7:6] bank(n:n bit bank) + * [5:4] row(13+n) + * [3] cs(0:1 cs, 1:2 cs) + * [2:1] bank(n:n bit bank) + * [0] col(10+n) + */ +const char ddr_cfg_2_rbc[] = { + ((0 << 6) | (0 << 4) | (0 << 3) | (1 << 2) | 1), + ((0 << 6) | (1 << 4) | (0 << 3) | (1 << 2) | 1), + ((0 << 6) | (2 << 4) | (0 << 3) | (1 << 2) | 1), + ((0 << 6) | (3 << 4) | (0 << 3) | (1 << 2) | 1), + ((0 << 6) | (1 << 4) | (0 << 3) | (1 << 2) | 2), + ((0 << 6) | (2 << 4) | (0 << 3) | (1 << 2) | 2), + ((0 << 6) | (3 << 4) | (0 << 3) | (1 << 2) | 2), + ((0 << 6) | (0 << 4) | (0 << 3) | (1 << 2) | 0), + ((0 << 6) | (1 << 4) | (0 << 3) | (1 << 2) | 0), + ((0 << 6) | (2 << 4) | (0 << 3) | (1 << 2) | 0), + ((0 << 6) | (3 << 4) | (0 << 3) | (1 << 2) | 0), + ((0 << 6) | (2 << 4) | (0 << 3) | (0 << 2) | 1), + ((1 << 6) | (1 << 4) | (0 << 3) | (0 << 2) | 2), + ((1 << 6) | (1 << 4) | (0 << 3) | (0 << 2) | 1), + ((0 << 6) | (3 << 4) | (1 << 3) | (1 << 2) | 1), + ((0 << 6) | (3 << 4) | (1 << 3) | (1 << 2) | 0), +}; + +static void copy_to_reg(u32 *dest, const u32 *src, u32 n) +{ + int i; + + for (i = 0; i < n / sizeof(u32); i++) { + writel(*src, dest); + src++; + dest++; + } +} + +void phy_pctrl_reset(struct rk322x_cru *cru, + struct rk322x_ddr_phy *ddr_phy) +{ + rk_clrsetreg(&cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT | + 1 << DDRCTRL_SRST_SHIFT | 1 << DDRPHY_PSRST_SHIFT | + 1 << DDRPHY_SRST_SHIFT, + 1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT | + 1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT); + + rockchip_udelay(10); + + rk_clrreg(&cru->cru_softrst_con[5], 1 << DDRPHY_PSRST_SHIFT | + 1 << DDRPHY_SRST_SHIFT); + rockchip_udelay(10); + + rk_clrreg(&cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT | + 1 << DDRCTRL_SRST_SHIFT); + rockchip_udelay(10); + + clrbits_le32(&ddr_phy->ddrphy_reg[0], + SOFT_RESET_MASK << SOFT_RESET_SHIFT); + rockchip_udelay(10); + setbits_le32(&ddr_phy->ddrphy_reg[0], + SOFT_DERESET_ANALOG); + rockchip_udelay(5); + setbits_le32(&ddr_phy->ddrphy_reg[0], + SOFT_DERESET_DIGITAL); + + rockchip_udelay(1); +} + +void phy_dll_bypass_set(struct rk322x_ddr_phy *ddr_phy, u32 freq) +{ + u32 tmp; + + setbits_le32(&ddr_phy->ddrphy_reg[0x13], 0x10); + setbits_le32(&ddr_phy->ddrphy_reg[0x26], 0x10); + setbits_le32(&ddr_phy->ddrphy_reg[0x36], 0x10); + setbits_le32(&ddr_phy->ddrphy_reg[0x46], 0x10); + setbits_le32(&ddr_phy->ddrphy_reg[0x56], 0x10); + + clrbits_le32(&ddr_phy->ddrphy_reg[0x14], 0x8); + clrbits_le32(&ddr_phy->ddrphy_reg[0x27], 0x8); + clrbits_le32(&ddr_phy->ddrphy_reg[0x37], 0x8); + clrbits_le32(&ddr_phy->ddrphy_reg[0x47], 0x8); + clrbits_le32(&ddr_phy->ddrphy_reg[0x57], 0x8); + + if (freq <= 400) + setbits_le32(&ddr_phy->ddrphy_reg[0xa4], 0x1f); + else + clrbits_le32(&ddr_phy->ddrphy_reg[0xa4], 0x1f); + + if (freq <= 680) + tmp = 3; + else + tmp = 2; + + writel(tmp, &ddr_phy->ddrphy_reg[0x28]); + writel(tmp, &ddr_phy->ddrphy_reg[0x38]); + writel(tmp, &ddr_phy->ddrphy_reg[0x48]); + writel(tmp, &ddr_phy->ddrphy_reg[0x58]); +} + +static void send_command(struct rk322x_ddr_pctl *pctl, + u32 rank, u32 cmd, u32 arg) +{ + writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd); + rockchip_udelay(1); + while (readl(&pctl->mcmd) & START_CMD) + ; +} + +static void memory_init(struct chan_info *chan, + struct rk322x_sdram_params *sdram_params) +{ + struct rk322x_ddr_pctl *pctl = chan->pctl; + u32 dramtype = sdram_params->base.dramtype; + + if (dramtype == DDR3) { + send_command(pctl, 3, DESELECT_CMD, 0); + rockchip_udelay(1); + send_command(pctl, 3, PREA_CMD, 0); + send_command(pctl, 3, MRS_CMD, + (0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | + (sdram_params->phy_timing.mr[2] & CMD_ADDR_MASK) << + CMD_ADDR_SHIFT); + + send_command(pctl, 3, MRS_CMD, + (0x03 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | + (sdram_params->phy_timing.mr[3] & CMD_ADDR_MASK) << + CMD_ADDR_SHIFT); + + send_command(pctl, 3, MRS_CMD, + (0x01 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | + (sdram_params->phy_timing.mr[1] & CMD_ADDR_MASK) << + CMD_ADDR_SHIFT); + + send_command(pctl, 3, MRS_CMD, + (0x00 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | + ((sdram_params->phy_timing.mr[0] | + DDR3_DLL_RESET) & + CMD_ADDR_MASK) << CMD_ADDR_SHIFT); + + send_command(pctl, 3, ZQCL_CMD, 0); + } else { + send_command(pctl, 3, MRS_CMD, + (0x63 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT | + (0 & LPDDR23_OP_MASK) << + LPDDR23_OP_SHIFT); + rockchip_udelay(10); + send_command(pctl, 3, MRS_CMD, + (0x10 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT | + (0xff & LPDDR23_OP_MASK) << + LPDDR23_OP_SHIFT); + rockchip_udelay(1); + send_command(pctl, 3, MRS_CMD, + (0x10 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT | + (0xff & LPDDR23_OP_MASK) << + LPDDR23_OP_SHIFT); + rockchip_udelay(1); + send_command(pctl, 3, MRS_CMD, + (1 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT | + (sdram_params->phy_timing.mr[1] & + LPDDR23_OP_MASK) << LPDDR23_OP_SHIFT); + send_command(pctl, 3, MRS_CMD, + (2 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT | + (sdram_params->phy_timing.mr[2] & + LPDDR23_OP_MASK) << LPDDR23_OP_SHIFT); + send_command(pctl, 3, MRS_CMD, + (3 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT | + (sdram_params->phy_timing.mr[3] & + LPDDR23_OP_MASK) << LPDDR23_OP_SHIFT); + if (dramtype == LPDDR3) + send_command(pctl, 3, MRS_CMD, (11 & LPDDR23_MA_MASK) << + LPDDR23_MA_SHIFT | + (sdram_params->phy_timing.mr11 & + LPDDR23_OP_MASK) << LPDDR23_OP_SHIFT); + } +} + +static u32 data_training(struct chan_info *chan) +{ + struct rk322x_ddr_phy *ddr_phy = chan->phy; + struct rk322x_ddr_pctl *pctl = chan->pctl; + u32 value; + u32 bw = (readl(&ddr_phy->ddrphy_reg[0]) >> 4) & 0xf; + u32 ret; + + /* disable auto refresh */ + value = readl(&pctl->trefi) | (1 << 31); + writel(1 << 31, &pctl->trefi); + + clrsetbits_le32(&ddr_phy->ddrphy_reg[2], 0x30, + DQS_SQU_CAL_SEL_CS0); + setbits_le32(&ddr_phy->ddrphy_reg[2], DQS_SQU_CAL_START); + + rockchip_udelay(30); + ret = readl(&ddr_phy->ddrphy_reg[0xff]); + + clrbits_le32(&ddr_phy->ddrphy_reg[2], + DQS_SQU_CAL_START); + + /* + * since data training will take about 20us, so send some auto + * refresh(about 7.8us) to complement the lost time + */ + send_command(pctl, 3, PREA_CMD, 0); + send_command(pctl, 3, REF_CMD, 0); + + writel(value, &pctl->trefi); + + if (ret & 0x10) { + ret = -1; + } else { + ret = (ret & 0xf) ^ bw; + ret = (ret == 0) ? 0 : -1; + } + return ret; +} + +static void move_to_config_state(struct rk322x_ddr_pctl *pctl) +{ + unsigned int state; + + while (1) { + state = readl(&pctl->stat) & PCTL_STAT_MASK; + switch (state) { + case LOW_POWER: + writel(WAKEUP_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MASK) + != ACCESS) + ; + /* + * If at low power state, need wakeup first, and then + * enter the config, so fallthrough + */ + case ACCESS: + /* fallthrough */ + case INIT_MEM: + writel(CFG_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG) + ; + break; + case CONFIG: + return; + default: + break; + } + } +} + +static void move_to_access_state(struct rk322x_ddr_pctl *pctl) +{ + unsigned int state; + + while (1) { + state = readl(&pctl->stat) & PCTL_STAT_MASK; + switch (state) { + case LOW_POWER: + writel(WAKEUP_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS) + ; + break; + case INIT_MEM: + writel(CFG_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG) + ; + /* fallthrough */ + case CONFIG: + writel(GO_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS) + ; + break; + case ACCESS: + return; + default: + break; + } + } +} + +static void move_to_lowpower_state(struct rk322x_ddr_pctl *pctl) +{ + unsigned int state; + + while (1) { + state = readl(&pctl->stat) & PCTL_STAT_MASK; + switch (state) { + case INIT_MEM: + writel(CFG_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG) + ; + /* fallthrough */ + case CONFIG: + writel(GO_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS) + ; + break; + case ACCESS: + writel(SLEEP_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MASK) != + LOW_POWER) + ; + break; + case LOW_POWER: + return; + default: + break; + } + } +} + +/* pctl should in low power mode when call this function */ +static void phy_softreset(struct dram_info *dram) +{ + struct rk322x_ddr_phy *ddr_phy = dram->chan[0].phy; + struct rk322x_grf *grf = dram->grf; + + writel(GRF_DDRPHY_BUFFEREN_CORE_EN, &grf->soc_con[0]); + clrbits_le32(&ddr_phy->ddrphy_reg[0], 0x3 << 2); + rockchip_udelay(1); + setbits_le32(&ddr_phy->ddrphy_reg[0], 1 << 2); + rockchip_udelay(5); + setbits_le32(&ddr_phy->ddrphy_reg[0], 1 << 3); + writel(GRF_DDRPHY_BUFFEREN_CORE_DIS, &grf->soc_con[0]); +} + +/* bw: 2: 32bit, 1:16bit */ +static void set_bw(struct dram_info *dram, u32 bw) +{ + struct rk322x_ddr_pctl *pctl = dram->chan[0].pctl; + struct rk322x_ddr_phy *ddr_phy = dram->chan[0].phy; + struct rk322x_grf *grf = dram->grf; + + if (bw == 1) { + setbits_le32(&pctl->ppcfg, 1); + clrbits_le32(&ddr_phy->ddrphy_reg[0], 0xc << 4); + writel(GRF_MSCH_NOC_16BIT_EN, &grf->soc_con[0]); + clrbits_le32(&ddr_phy->ddrphy_reg[0x46], 0x8); + clrbits_le32(&ddr_phy->ddrphy_reg[0x56], 0x8); + } else { + clrbits_le32(&pctl->ppcfg, 1); + setbits_le32(&ddr_phy->ddrphy_reg[0], 0xf << 4); + writel(GRF_DDR_32BIT_EN | GRF_MSCH_NOC_32BIT_EN, + &grf->soc_con[0]); + setbits_le32(&ddr_phy->ddrphy_reg[0x46], 0x8); + setbits_le32(&ddr_phy->ddrphy_reg[0x56], 0x8); + } +} + +static void pctl_cfg(struct rk322x_ddr_pctl *pctl, + struct rk322x_sdram_params *sdram_params, + struct rk322x_grf *grf) +{ + u32 burst_len; + u32 bw; + u32 dramtype = sdram_params->base.dramtype; + + if (sdram_params->ch[0].bw == 2) + bw = GRF_DDR_32BIT_EN | GRF_MSCH_NOC_32BIT_EN; + else + bw = GRF_MSCH_NOC_16BIT_EN; + + writel(DFI_INIT_START | DFI_DATA_BYTE_DISABLE_EN, &pctl->dfistcfg0); + writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, &pctl->dfistcfg1); + writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2); + writel(0x51010, &pctl->dfilpcfg0); + + writel(1, &pctl->dfitphyupdtype0); + writel(0x0d, &pctl->dfitphyrdlat); + writel(0, &pctl->dfitphywrdata); + + writel(0, &pctl->dfiupdcfg); + copy_to_reg(&pctl->togcnt1u, &sdram_params->pctl_timing.togcnt1u, + sizeof(struct rk322x_pctl_timing)); + if (dramtype == DDR3) { + writel((1 << 3) | (1 << 11), + &pctl->dfiodtcfg); + writel(7 << 16, &pctl->dfiodtcfg1); + writel((readl(&pctl->tcl) - 1) / 2 - 1, &pctl->dfitrddataen); + writel((readl(&pctl->tcwl) - 1) / 2 - 1, &pctl->dfitphywrlat); + writel(500, &pctl->trsth); + writel(0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT | DDR3_EN | + DDR2_DDR3_BL_8 | (6 - 4) << TFAW_SHIFT | PD_EXIT_SLOW | + 1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT, + &pctl->mcfg); + writel(bw | GRF_DDR3_EN, &grf->soc_con[0]); + } else { + if (sdram_params->phy_timing.bl & PHT_BL_8) + burst_len = MDDR_LPDDR2_BL_8; + else + burst_len = MDDR_LPDDR2_BL_4; + + writel(readl(&pctl->tcl) / 2 - 1, &pctl->dfitrddataen); + writel(readl(&pctl->tcwl) / 2 - 1, &pctl->dfitphywrlat); + writel(0, &pctl->trsth); + if (dramtype == LPDDR2) { + writel(0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT | + LPDDR2_S4 | LPDDR2_EN | burst_len | + (6 - 4) << TFAW_SHIFT | PD_EXIT_FAST | + 1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT, + &pctl->mcfg); + writel(0, &pctl->dfiodtcfg); + writel(0, &pctl->dfiodtcfg1); + } else { + writel(0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT | + LPDDR2_S4 | LPDDR3_EN | burst_len | + (6 - 4) << TFAW_SHIFT | PD_EXIT_FAST | + 1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT, + &pctl->mcfg); + writel((1 << 3) | (1 << 2), &pctl->dfiodtcfg); + writel((7 << 16) | 4, &pctl->dfiodtcfg1); + } + writel(bw | GRF_LPDDR2_3_EN, &grf->soc_con[0]); + } + setbits_le32(&pctl->scfg, 1); +} + +static void phy_cfg(struct chan_info *chan, + struct rk322x_sdram_params *sdram_params) +{ + struct rk322x_ddr_phy *ddr_phy = chan->phy; + struct rk322x_service_sys *axi_bus = chan->msch; + struct rk322x_msch_timings *noc_timing = &sdram_params->base.noc_timing; + struct rk322x_phy_timing *phy_timing = &sdram_params->phy_timing; + struct rk322x_pctl_timing *pctl_timing = &sdram_params->pctl_timing; + u32 cmd_drv, clk_drv, dqs_drv, dqs_odt; + + writel(noc_timing->ddrtiming, &axi_bus->ddrtiming); + writel(noc_timing->ddrmode, &axi_bus->ddrmode); + writel(noc_timing->readlatency, &axi_bus->readlatency); + writel(noc_timing->activate, &axi_bus->activate); + writel(noc_timing->devtodev, &axi_bus->devtodev); + + switch (sdram_params->base.dramtype) { + case DDR3: + writel(PHY_DDR3 | phy_timing->bl, &ddr_phy->ddrphy_reg[1]); + break; + case LPDDR2: + writel(PHY_LPDDR2 | phy_timing->bl, &ddr_phy->ddrphy_reg[1]); + break; + default: + writel(PHY_LPDDR2 | phy_timing->bl, &ddr_phy->ddrphy_reg[1]); + break; + } + + writel(phy_timing->cl_al, &ddr_phy->ddrphy_reg[0xb]); + writel(pctl_timing->tcwl, &ddr_phy->ddrphy_reg[0xc]); + + cmd_drv = PHY_RON_RTT_34OHM; + clk_drv = PHY_RON_RTT_45OHM; + dqs_drv = PHY_RON_RTT_34OHM; + if (sdram_params->base.dramtype == LPDDR2) + dqs_odt = PHY_RON_RTT_DISABLE; + else + dqs_odt = PHY_RON_RTT_225OHM; + + writel(cmd_drv, &ddr_phy->ddrphy_reg[0x11]); + clrsetbits_le32(&ddr_phy->ddrphy_reg[0x12], (0x1f << 3), cmd_drv << 3); + writel(clk_drv, &ddr_phy->ddrphy_reg[0x16]); + writel(clk_drv, &ddr_phy->ddrphy_reg[0x18]); + + writel(dqs_drv, &ddr_phy->ddrphy_reg[0x20]); + writel(dqs_drv, &ddr_phy->ddrphy_reg[0x2f]); + writel(dqs_drv, &ddr_phy->ddrphy_reg[0x30]); + writel(dqs_drv, &ddr_phy->ddrphy_reg[0x3f]); + writel(dqs_drv, &ddr_phy->ddrphy_reg[0x40]); + writel(dqs_drv, &ddr_phy->ddrphy_reg[0x4f]); + writel(dqs_drv, &ddr_phy->ddrphy_reg[0x50]); + writel(dqs_drv, &ddr_phy->ddrphy_reg[0x5f]); + + writel(dqs_odt, &ddr_phy->ddrphy_reg[0x21]); + writel(dqs_odt, &ddr_phy->ddrphy_reg[0x2e]); + writel(dqs_odt, &ddr_phy->ddrphy_reg[0x31]); + writel(dqs_odt, &ddr_phy->ddrphy_reg[0x3e]); + writel(dqs_odt, &ddr_phy->ddrphy_reg[0x41]); + writel(dqs_odt, &ddr_phy->ddrphy_reg[0x4e]); + writel(dqs_odt, &ddr_phy->ddrphy_reg[0x51]); + writel(dqs_odt, &ddr_phy->ddrphy_reg[0x5e]); +} + +void dram_cfg_rbc(struct chan_info *chan, + struct rk322x_sdram_params *sdram_params) +{ + char noc_config; + int i = 0; + struct rk322x_sdram_channel *config = &sdram_params->ch[0]; + struct rk322x_service_sys *axi_bus = chan->msch; + + move_to_config_state(chan->pctl); + + if ((config->rank == 2) && (config->cs1_row == config->cs0_row)) { + if ((config->col + config->bw) == 12) { + i = 14; + goto finish; + } else if ((config->col + config->bw) == 11) { + i = 15; + goto finish; + } + } + noc_config = ((config->cs0_row - 13) << 4) | ((config->bk - 2) << 2) | + (config->col + config->bw - 11); + for (i = 0; i < 11; i++) { + if (noc_config == ddr_cfg_2_rbc[i]) + break; + } + + if (i < 11) + goto finish; + + noc_config = ((config->bk - 2) << 6) | ((config->cs0_row - 13) << 4) | + (config->col + config->bw - 11); + + for (i = 11; i < 14; i++) { + if (noc_config == ddr_cfg_2_rbc[i]) + break; + } + if (i < 14) + goto finish; + else + i = 0; + +finish: + writel(i, &axi_bus->ddrconf); + move_to_access_state(chan->pctl); +} + +static void dram_all_config(const struct dram_info *dram, + struct rk322x_sdram_params *sdram_params) +{ + struct rk322x_sdram_channel *info = &sdram_params->ch[0]; + u32 sys_reg = 0; + + sys_reg |= sdram_params->base.dramtype << SYS_REG_DDRTYPE_SHIFT; + sys_reg |= (1 - 1) << SYS_REG_NUM_CH_SHIFT; + sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(0); + sys_reg |= 1 << SYS_REG_CHINFO_SHIFT(0); + sys_reg |= (info->rank - 1) << SYS_REG_RANK_SHIFT(0); + sys_reg |= (info->col - 9) << SYS_REG_COL_SHIFT(0); + sys_reg |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(0); + sys_reg |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(0); + sys_reg |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(0); + sys_reg |= (2 >> info->bw) << SYS_REG_BW_SHIFT(0); + sys_reg |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(0); + + writel(sys_reg, &dram->grf->os_reg[2]); +} + +#define TEST_PATTEN 0x5aa5f00f + +static int dram_cap_detect(struct dram_info *dram, + struct rk322x_sdram_params *sdram_params) +{ + u32 bw, row, col, addr; + u32 ret = 0; + struct rk322x_service_sys *axi_bus = dram->chan[0].msch; + + if (sdram_params->base.dramtype == DDR3) + sdram_params->ch[0].dbw = 1; + else + sdram_params->ch[0].dbw = 2; + + move_to_config_state(dram->chan[0].pctl); + /* bw detect */ + set_bw(dram, 2); + if (data_training(&dram->chan[0]) == 0) { + bw = 2; + } else { + bw = 1; + set_bw(dram, 1); + move_to_lowpower_state(dram->chan[0].pctl); + phy_softreset(dram); + move_to_config_state(dram->chan[0].pctl); + if (data_training(&dram->chan[0])) { + printf("BW detect error\n"); + ret = -EINVAL; + } + } + sdram_params->ch[0].bw = bw; + sdram_params->ch[0].bk = 3; + + if (bw == 2) + writel(6, &axi_bus->ddrconf); + else + writel(3, &axi_bus->ddrconf); + move_to_access_state(dram->chan[0].pctl); + for (col = 11; col >= 9; col--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + + (1 << (col + bw - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (col == 8) { + printf("Col detect error\n"); + ret = -EINVAL; + goto out; + } else { + sdram_params->ch[0].col = col; + } + + writel(10, &axi_bus->ddrconf); + + /* Detect row*/ + for (row = 16; row >= 12; row--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + (1u << (row + 11 + 3 - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (row == 11) { + printf("Row detect error\n"); + ret = -EINVAL; + } else { + sdram_params->ch[0].cs1_row = row; + sdram_params->ch[0].row_3_4 = 0; + sdram_params->ch[0].cs0_row = row; + } + /* cs detect */ + writel(0, CONFIG_SYS_SDRAM_BASE); + writel(TEST_PATTEN, CONFIG_SYS_SDRAM_BASE + (1u << 30)); + writel(~TEST_PATTEN, CONFIG_SYS_SDRAM_BASE + (1u << 30) + 4); + if ((readl(CONFIG_SYS_SDRAM_BASE + (1u << 30)) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + sdram_params->ch[0].rank = 2; + else + sdram_params->ch[0].rank = 1; +out: + return ret; +} + +static int sdram_init(struct dram_info *dram, + struct rk322x_sdram_params *sdram_params) +{ + int ret; + + ret = clk_set_rate(&dram->ddr_clk, + sdram_params->base.ddr_freq * MHz * 2); + if (ret < 0) { + printf("Could not set DDR clock\n"); + return ret; + } + + phy_pctrl_reset(dram->cru, dram->chan[0].phy); + phy_dll_bypass_set(dram->chan[0].phy, sdram_params->base.ddr_freq); + pctl_cfg(dram->chan[0].pctl, sdram_params, dram->grf); + phy_cfg(&dram->chan[0], sdram_params); + writel(POWER_UP_START, &dram->chan[0].pctl->powctl); + while (!(readl(&dram->chan[0].pctl->powstat) & POWER_UP_DONE)) + ; + memory_init(&dram->chan[0], sdram_params); + move_to_access_state(dram->chan[0].pctl); + ret = dram_cap_detect(dram, sdram_params); + if (ret) + goto out; + dram_cfg_rbc(&dram->chan[0], sdram_params); + dram_all_config(dram, sdram_params); +out: + return ret; +} + +static int rk322x_dmc_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk322x_sdram_params *params = dev_get_platdata(dev); + const void *blob = gd->fdt_blob; + int node = dev_of_offset(dev); + int ret; + + params->num_channels = 1; + + ret = fdtdec_get_int_array(blob, node, "rockchip,pctl-timing", + (u32 *)¶ms->pctl_timing, + sizeof(params->pctl_timing) / sizeof(u32)); + if (ret) { + printf("%s: Cannot read rockchip,pctl-timing\n", __func__); + return -EINVAL; + } + ret = fdtdec_get_int_array(blob, node, "rockchip,phy-timing", + (u32 *)¶ms->phy_timing, + sizeof(params->phy_timing) / sizeof(u32)); + if (ret) { + printf("%s: Cannot read rockchip,phy-timing\n", __func__); + return -EINVAL; + } + ret = fdtdec_get_int_array(blob, node, "rockchip,sdram-params", + (u32 *)¶ms->base, + sizeof(params->base) / sizeof(u32)); + if (ret) { + printf("%s: Cannot read rockchip,sdram-params\n", __func__); + return -EINVAL; + } + ret = regmap_init_mem(dev, ¶ms->map); + if (ret) + return ret; +#endif + + return 0; +} +#endif /* CONFIG_TPL_BUILD */ + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +static int conv_of_platdata(struct udevice *dev) +{ + struct rk322x_sdram_params *plat = dev_get_platdata(dev); + struct dtd_rockchip_rk322x_dmc *of_plat = &plat->of_plat; + int ret; + + memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing, + sizeof(plat->pctl_timing)); + memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing, + sizeof(plat->phy_timing)); + memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base)); + + plat->num_channels = 1; + ret = regmap_init_mem_platdata(dev, of_plat->reg, + ARRAY_SIZE(of_plat->reg) / 2, + &plat->map); + if (ret) + return ret; + + return 0; +} +#endif + +static int rk322x_dmc_probe(struct udevice *dev) +{ +#ifdef CONFIG_TPL_BUILD + struct rk322x_sdram_params *plat = dev_get_platdata(dev); + int ret; + struct udevice *dev_clk; +#endif + struct dram_info *priv = dev_get_priv(dev); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); +#ifdef CONFIG_TPL_BUILD +#if CONFIG_IS_ENABLED(OF_PLATDATA) + ret = conv_of_platdata(dev); + if (ret) + return ret; +#endif + + priv->chan[0].msch = syscon_get_first_range(ROCKCHIP_SYSCON_MSCH); + priv->chan[0].pctl = regmap_get_range(plat->map, 0); + priv->chan[0].phy = regmap_get_range(plat->map, 1); + ret = rockchip_get_clk(&dev_clk); + if (ret) + return ret; + priv->ddr_clk.id = CLK_DDR; + ret = clk_request(dev_clk, &priv->ddr_clk); + if (ret) + return ret; + + priv->cru = rockchip_get_cru(); + if (IS_ERR(priv->cru)) + return PTR_ERR(priv->cru); + ret = sdram_init(priv, plat); + if (ret) + return ret; +#else + priv->info.base = CONFIG_SYS_SDRAM_BASE; + priv->info.size = rockchip_sdram_size( + (phys_addr_t)&priv->grf->os_reg[2]); +#endif + + return 0; +} + +static int rk322x_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + struct dram_info *priv = dev_get_priv(dev); + + *info = priv->info; + + return 0; +} + +static struct ram_ops rk322x_dmc_ops = { + .get_info = rk322x_dmc_get_info, +}; + +static const struct udevice_id rk322x_dmc_ids[] = { + { .compatible = "rockchip,rk3228-dmc" }, + { } +}; + +U_BOOT_DRIVER(dmc_rk322x) = { + .name = "rockchip_rk322x_dmc", + .id = UCLASS_RAM, + .of_match = rk322x_dmc_ids, + .ops = &rk322x_dmc_ops, +#ifdef CONFIG_TPL_BUILD + .ofdata_to_platdata = rk322x_dmc_ofdata_to_platdata, +#endif + .probe = rk322x_dmc_probe, + .priv_auto_alloc_size = sizeof(struct dram_info), +#ifdef CONFIG_TPL_BUILD + .platdata_auto_alloc_size = sizeof(struct rk322x_sdram_params), +#endif +}; + diff --git a/drivers/ram/rockchip/sdram_rk3288.c b/drivers/ram/rockchip/sdram_rk3288.c new file mode 100644 index 00000000000..95efb117fc1 --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk3288.c @@ -0,0 +1,1125 @@ +/* + * (C) Copyright 2015 Google, Inc + * Copyright 2014 Rockchip Inc. + * + * SPDX-License-Identifier: GPL-2.0 + * + * Adapted from coreboot. + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <dt-structs.h> +#include <errno.h> +#include <ram.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/cru_rk3288.h> +#include <asm/arch/ddr_rk3288.h> +#include <asm/arch/grf_rk3288.h> +#include <asm/arch/pmu_rk3288.h> +#include <asm/arch/sdram.h> +#include <asm/arch/sdram_common.h> +#include <linux/err.h> +#include <power/regulator.h> +#include <power/rk8xx_pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct chan_info { + struct rk3288_ddr_pctl *pctl; + struct rk3288_ddr_publ *publ; + struct rk3288_msch *msch; +}; + +struct dram_info { + struct chan_info chan[2]; + struct ram_info info; + struct clk ddr_clk; + struct rk3288_cru *cru; + struct rk3288_grf *grf; + struct rk3288_sgrf *sgrf; + struct rk3288_pmu *pmu; + bool is_veyron; +}; + +struct rk3288_sdram_params { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3288_dmc of_plat; +#endif + struct rk3288_sdram_channel ch[2]; + struct rk3288_sdram_pctl_timing pctl_timing; + struct rk3288_sdram_phy_timing phy_timing; + struct rk3288_base_params base; + int num_channels; + struct regmap *map; +}; + +const int ddrconf_table[] = { + /* row col,bw */ + 0, + ((1 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT), + ((2 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT), + ((3 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT), + ((4 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT), + ((1 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT), + ((2 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT), + ((3 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT), + ((1 << DDRCONF_ROW_SHIFT) | 0 << DDRCONF_COL_SHIFT), + ((2 << DDRCONF_ROW_SHIFT) | 0 << DDRCONF_COL_SHIFT), + ((3 << DDRCONF_ROW_SHIFT) | 0 << DDRCONF_COL_SHIFT), + 0, + 0, + 0, + 0, + ((4 << 4) | 2), +}; + +#define TEST_PATTEN 0x5aa5f00f +#define DQS_GATE_TRAINING_ERROR_RANK0 (1 << 4) +#define DQS_GATE_TRAINING_ERROR_RANK1 (2 << 4) + +#ifdef CONFIG_SPL_BUILD +static void copy_to_reg(u32 *dest, const u32 *src, u32 n) +{ + int i; + + for (i = 0; i < n / sizeof(u32); i++) { + writel(*src, dest); + src++; + dest++; + } +} + +static void ddr_reset(struct rk3288_cru *cru, u32 ch, u32 ctl, u32 phy) +{ + u32 phy_ctl_srstn_shift = 4 + 5 * ch; + u32 ctl_psrstn_shift = 3 + 5 * ch; + u32 ctl_srstn_shift = 2 + 5 * ch; + u32 phy_psrstn_shift = 1 + 5 * ch; + u32 phy_srstn_shift = 5 * ch; + + rk_clrsetreg(&cru->cru_softrst_con[10], + 1 << phy_ctl_srstn_shift | 1 << ctl_psrstn_shift | + 1 << ctl_srstn_shift | 1 << phy_psrstn_shift | + 1 << phy_srstn_shift, + phy << phy_ctl_srstn_shift | ctl << ctl_psrstn_shift | + ctl << ctl_srstn_shift | phy << phy_psrstn_shift | + phy << phy_srstn_shift); +} + +static void ddr_phy_ctl_reset(struct rk3288_cru *cru, u32 ch, u32 n) +{ + u32 phy_ctl_srstn_shift = 4 + 5 * ch; + + rk_clrsetreg(&cru->cru_softrst_con[10], + 1 << phy_ctl_srstn_shift, n << phy_ctl_srstn_shift); +} + +static void phy_pctrl_reset(struct rk3288_cru *cru, + struct rk3288_ddr_publ *publ, + int channel) +{ + int i; + + ddr_reset(cru, channel, 1, 1); + udelay(1); + clrbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST); + for (i = 0; i < 4; i++) + clrbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST); + + udelay(10); + setbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST); + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST); + + udelay(10); + ddr_reset(cru, channel, 1, 0); + udelay(10); + ddr_reset(cru, channel, 0, 0); + udelay(10); +} + +static void phy_dll_bypass_set(struct rk3288_ddr_publ *publ, + u32 freq) +{ + int i; + + if (freq <= 250000000) { + if (freq <= 150000000) + clrbits_le32(&publ->dllgcr, SBIAS_BYPASS); + else + setbits_le32(&publ->dllgcr, SBIAS_BYPASS); + setbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS); + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxdllcr, + DXDLLCR_DLLDIS); + + setbits_le32(&publ->pir, PIR_DLLBYP); + } else { + clrbits_le32(&publ->dllgcr, SBIAS_BYPASS); + clrbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS); + for (i = 0; i < 4; i++) { + clrbits_le32(&publ->datx8[i].dxdllcr, + DXDLLCR_DLLDIS); + } + + clrbits_le32(&publ->pir, PIR_DLLBYP); + } +} + +static void dfi_cfg(struct rk3288_ddr_pctl *pctl, u32 dramtype) +{ + writel(DFI_INIT_START, &pctl->dfistcfg0); + writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, + &pctl->dfistcfg1); + writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2); + writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN, + &pctl->dfilpcfg0); + + writel(2 << TCTRL_DELAY_TIME_SHIFT, &pctl->dfitctrldelay); + writel(1 << TPHY_WRDATA_TIME_SHIFT, &pctl->dfitphywrdata); + writel(0xf << TPHY_RDLAT_TIME_SHIFT, &pctl->dfitphyrdlat); + writel(2 << TDRAM_CLK_DIS_TIME_SHIFT, &pctl->dfitdramclkdis); + writel(2 << TDRAM_CLK_EN_TIME_SHIFT, &pctl->dfitdramclken); + writel(1, &pctl->dfitphyupdtype0); + + /* cs0 and cs1 write odt enable */ + writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL), + &pctl->dfiodtcfg); + /* odt write length */ + writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1); + /* phyupd and ctrlupd disabled */ + writel(0, &pctl->dfiupdcfg); +} + +static void ddr_set_enable(struct rk3288_grf *grf, uint channel, bool enable) +{ + uint val = 0; + + if (enable) { + val = 1 << (channel ? DDR1_16BIT_EN_SHIFT : + DDR0_16BIT_EN_SHIFT); + } + rk_clrsetreg(&grf->soc_con0, + 1 << (channel ? DDR1_16BIT_EN_SHIFT : DDR0_16BIT_EN_SHIFT), + val); +} + +static void ddr_set_ddr3_mode(struct rk3288_grf *grf, uint channel, + bool ddr3_mode) +{ + uint mask, val; + + mask = 1 << (channel ? MSCH1_MAINDDR3_SHIFT : MSCH0_MAINDDR3_SHIFT); + val = ddr3_mode << (channel ? MSCH1_MAINDDR3_SHIFT : + MSCH0_MAINDDR3_SHIFT); + rk_clrsetreg(&grf->soc_con0, mask, val); +} + +static void ddr_set_en_bst_odt(struct rk3288_grf *grf, uint channel, + bool enable, bool enable_bst, bool enable_odt) +{ + uint mask; + bool disable_bst = !enable_bst; + + mask = channel ? + (1 << LPDDR3_EN1_SHIFT | 1 << UPCTL1_BST_DIABLE_SHIFT | + 1 << UPCTL1_LPDDR3_ODT_EN_SHIFT) : + (1 << LPDDR3_EN0_SHIFT | 1 << UPCTL0_BST_DIABLE_SHIFT | + 1 << UPCTL0_LPDDR3_ODT_EN_SHIFT); + rk_clrsetreg(&grf->soc_con2, mask, + enable << (channel ? LPDDR3_EN1_SHIFT : LPDDR3_EN0_SHIFT) | + disable_bst << (channel ? UPCTL1_BST_DIABLE_SHIFT : + UPCTL0_BST_DIABLE_SHIFT) | + enable_odt << (channel ? UPCTL1_LPDDR3_ODT_EN_SHIFT : + UPCTL0_LPDDR3_ODT_EN_SHIFT)); +} + +static void pctl_cfg(int channel, struct rk3288_ddr_pctl *pctl, + struct rk3288_sdram_params *sdram_params, + struct rk3288_grf *grf) +{ + unsigned int burstlen; + + burstlen = (sdram_params->base.noc_timing >> 18) & 0x7; + copy_to_reg(&pctl->togcnt1u, &sdram_params->pctl_timing.togcnt1u, + sizeof(sdram_params->pctl_timing)); + switch (sdram_params->base.dramtype) { + case LPDDR3: + writel(sdram_params->pctl_timing.tcl - 1, + &pctl->dfitrddataen); + writel(sdram_params->pctl_timing.tcwl, + &pctl->dfitphywrlat); + burstlen >>= 1; + writel(LPDDR2_S4 | 0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT | + LPDDR2_EN | burstlen << BURSTLENGTH_SHIFT | + (6 - 4) << TFAW_SHIFT | PD_EXIT_FAST | + 1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT, + &pctl->mcfg); + ddr_set_ddr3_mode(grf, channel, false); + ddr_set_enable(grf, channel, true); + ddr_set_en_bst_odt(grf, channel, true, false, + sdram_params->base.odt); + break; + case DDR3: + if (sdram_params->phy_timing.mr[1] & DDR3_DLL_DISABLE) { + writel(sdram_params->pctl_timing.tcl - 3, + &pctl->dfitrddataen); + } else { + writel(sdram_params->pctl_timing.tcl - 2, + &pctl->dfitrddataen); + } + writel(sdram_params->pctl_timing.tcwl - 1, + &pctl->dfitphywrlat); + writel(0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT | DDR3_EN | + DDR2_DDR3_BL_8 | (6 - 4) << TFAW_SHIFT | PD_EXIT_SLOW | + 1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT, + &pctl->mcfg); + ddr_set_ddr3_mode(grf, channel, true); + ddr_set_enable(grf, channel, true); + + ddr_set_en_bst_odt(grf, channel, false, true, false); + break; + } + + setbits_le32(&pctl->scfg, 1); +} + +static void phy_cfg(const struct chan_info *chan, int channel, + struct rk3288_sdram_params *sdram_params) +{ + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3288_msch *msch = chan->msch; + uint ddr_freq_mhz = sdram_params->base.ddr_freq / 1000000; + u32 dinit2, tmp; + int i; + + dinit2 = DIV_ROUND_UP(ddr_freq_mhz * 200000, 1000); + /* DDR PHY Timing */ + copy_to_reg(&publ->dtpr[0], &sdram_params->phy_timing.dtpr0, + sizeof(sdram_params->phy_timing)); + writel(sdram_params->base.noc_timing, &msch->ddrtiming); + writel(0x3f, &msch->readlatency); + writel(sdram_params->base.noc_activate, &msch->activate); + writel(2 << BUSWRTORD_SHIFT | 2 << BUSRDTOWR_SHIFT | + 1 << BUSRDTORD_SHIFT, &msch->devtodev); + writel(DIV_ROUND_UP(ddr_freq_mhz * 5120, 1000) << PRT_DLLLOCK_SHIFT | + DIV_ROUND_UP(ddr_freq_mhz * 50, 1000) << PRT_DLLSRST_SHIFT | + 8 << PRT_ITMSRST_SHIFT, &publ->ptr[0]); + writel(DIV_ROUND_UP(ddr_freq_mhz * 500000, 1000) << PRT_DINIT0_SHIFT | + DIV_ROUND_UP(ddr_freq_mhz * 400, 1000) << PRT_DINIT1_SHIFT, + &publ->ptr[1]); + writel(min(dinit2, 0x1ffffU) << PRT_DINIT2_SHIFT | + DIV_ROUND_UP(ddr_freq_mhz * 1000, 1000) << PRT_DINIT3_SHIFT, + &publ->ptr[2]); + + switch (sdram_params->base.dramtype) { + case LPDDR3: + clrsetbits_le32(&publ->pgcr, 0x1F, + 0 << PGCR_DFTLMT_SHIFT | + 0 << PGCR_DFTCMP_SHIFT | + 1 << PGCR_DQSCFG_SHIFT | + 0 << PGCR_ITMDMD_SHIFT); + /* DDRMODE select LPDDR3 */ + clrsetbits_le32(&publ->dcr, DDRMD_MASK << DDRMD_SHIFT, + DDRMD_LPDDR2_LPDDR3 << DDRMD_SHIFT); + clrsetbits_le32(&publ->dxccr, + DQSNRES_MASK << DQSNRES_SHIFT | + DQSRES_MASK << DQSRES_SHIFT, + 4 << DQSRES_SHIFT | 0xc << DQSNRES_SHIFT); + tmp = readl(&publ->dtpr[1]); + tmp = ((tmp >> TDQSCKMAX_SHIFT) & TDQSCKMAX_MASK) - + ((tmp >> TDQSCK_SHIFT) & TDQSCK_MASK); + clrsetbits_le32(&publ->dsgcr, + DQSGE_MASK << DQSGE_SHIFT | + DQSGX_MASK << DQSGX_SHIFT, + tmp << DQSGE_SHIFT | tmp << DQSGX_SHIFT); + break; + case DDR3: + clrbits_le32(&publ->pgcr, 0x1f); + clrsetbits_le32(&publ->dcr, DDRMD_MASK << DDRMD_SHIFT, + DDRMD_DDR3 << DDRMD_SHIFT); + break; + } + if (sdram_params->base.odt) { + /*dynamic RTT enable */ + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT); + } else { + /*dynamic RTT disable */ + for (i = 0; i < 4; i++) + clrbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT); + } +} + +static void phy_init(struct rk3288_ddr_publ *publ) +{ + setbits_le32(&publ->pir, PIR_INIT | PIR_DLLSRST + | PIR_DLLLOCK | PIR_ZCAL | PIR_ITMSRST | PIR_CLRSR); + udelay(1); + while ((readl(&publ->pgsr) & + (PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE)) != + (PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE)) + ; +} + +static void send_command(struct rk3288_ddr_pctl *pctl, u32 rank, + u32 cmd, u32 arg) +{ + writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd); + udelay(1); + while (readl(&pctl->mcmd) & START_CMD) + ; +} + +static inline void send_command_op(struct rk3288_ddr_pctl *pctl, + u32 rank, u32 cmd, u32 ma, u32 op) +{ + send_command(pctl, rank, cmd, (ma & LPDDR2_MA_MASK) << LPDDR2_MA_SHIFT | + (op & LPDDR2_OP_MASK) << LPDDR2_OP_SHIFT); +} + +static void memory_init(struct rk3288_ddr_publ *publ, + u32 dramtype) +{ + setbits_le32(&publ->pir, + (PIR_INIT | PIR_DRAMINIT | PIR_LOCKBYP + | PIR_ZCALBYP | PIR_CLRSR | PIR_ICPC + | (dramtype == DDR3 ? PIR_DRAMRST : 0))); + udelay(1); + while ((readl(&publ->pgsr) & (PGSR_IDONE | PGSR_DLDONE)) + != (PGSR_IDONE | PGSR_DLDONE)) + ; +} + +static void move_to_config_state(struct rk3288_ddr_publ *publ, + struct rk3288_ddr_pctl *pctl) +{ + unsigned int state; + + while (1) { + state = readl(&pctl->stat) & PCTL_STAT_MSK; + + switch (state) { + case LOW_POWER: + writel(WAKEUP_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) + != ACCESS) + ; + /* wait DLL lock */ + while ((readl(&publ->pgsr) & PGSR_DLDONE) + != PGSR_DLDONE) + ; + /* + * if at low power state,need wakeup first, + * and then enter the config + * so here no break. + */ + case ACCESS: + /* no break */ + case INIT_MEM: + writel(CFG_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG) + ; + break; + case CONFIG: + return; + default: + break; + } + } +} + +static void set_bandwidth_ratio(const struct chan_info *chan, int channel, + u32 n, struct rk3288_grf *grf) +{ + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3288_msch *msch = chan->msch; + + if (n == 1) { + setbits_le32(&pctl->ppcfg, 1); + rk_setreg(&grf->soc_con0, 1 << (8 + channel)); + setbits_le32(&msch->ddrtiming, 1 << 31); + /* Data Byte disable*/ + clrbits_le32(&publ->datx8[2].dxgcr, 1); + clrbits_le32(&publ->datx8[3].dxgcr, 1); + /* disable DLL */ + setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS); + setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS); + } else { + clrbits_le32(&pctl->ppcfg, 1); + rk_clrreg(&grf->soc_con0, 1 << (8 + channel)); + clrbits_le32(&msch->ddrtiming, 1 << 31); + /* Data Byte enable*/ + setbits_le32(&publ->datx8[2].dxgcr, 1); + setbits_le32(&publ->datx8[3].dxgcr, 1); + + /* enable DLL */ + clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS); + clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS); + /* reset DLL */ + clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST); + clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST); + udelay(10); + setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST); + setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST); + } + setbits_le32(&pctl->dfistcfg0, 1 << 2); +} + +static int data_training(const struct chan_info *chan, int channel, + struct rk3288_sdram_params *sdram_params) +{ + unsigned int j; + int ret = 0; + u32 rank; + int i; + u32 step[2] = { PIR_QSTRN, PIR_RVTRN }; + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3288_ddr_pctl *pctl = chan->pctl; + + /* disable auto refresh */ + writel(0, &pctl->trefi); + + if (sdram_params->base.dramtype != LPDDR3) + setbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT); + rank = sdram_params->ch[channel].rank | 1; + for (j = 0; j < ARRAY_SIZE(step); j++) { + /* + * trigger QSTRN and RVTRN + * clear DTDONE status + */ + setbits_le32(&publ->pir, PIR_CLRSR); + + /* trigger DTT */ + setbits_le32(&publ->pir, + PIR_INIT | step[j] | PIR_LOCKBYP | PIR_ZCALBYP | + PIR_CLRSR); + udelay(1); + /* wait echo byte DTDONE */ + while ((readl(&publ->datx8[0].dxgsr[0]) & rank) + != rank) + ; + while ((readl(&publ->datx8[1].dxgsr[0]) & rank) + != rank) + ; + if (!(readl(&pctl->ppcfg) & 1)) { + while ((readl(&publ->datx8[2].dxgsr[0]) + & rank) != rank) + ; + while ((readl(&publ->datx8[3].dxgsr[0]) + & rank) != rank) + ; + } + if (readl(&publ->pgsr) & + (PGSR_DTERR | PGSR_RVERR | PGSR_RVEIRR)) { + ret = -1; + break; + } + } + /* send some auto refresh to complement the lost while DTT */ + for (i = 0; i < (rank > 1 ? 8 : 4); i++) + send_command(pctl, rank, REF_CMD, 0); + + if (sdram_params->base.dramtype != LPDDR3) + clrbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT); + + /* resume auto refresh */ + writel(sdram_params->pctl_timing.trefi, &pctl->trefi); + + return ret; +} + +static void move_to_access_state(const struct chan_info *chan) +{ + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3288_ddr_pctl *pctl = chan->pctl; + unsigned int state; + + while (1) { + state = readl(&pctl->stat) & PCTL_STAT_MSK; + + switch (state) { + case LOW_POWER: + if (((readl(&pctl->stat) >> LP_TRIG_SHIFT) & + LP_TRIG_MASK) == 1) + return; + + writel(WAKEUP_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) != ACCESS) + ; + /* wait DLL lock */ + while ((readl(&publ->pgsr) & PGSR_DLDONE) + != PGSR_DLDONE) + ; + break; + case INIT_MEM: + writel(CFG_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG) + ; + case CONFIG: + writel(GO_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) == CONFIG) + ; + break; + case ACCESS: + return; + default: + break; + } + } +} + +static void dram_cfg_rbc(const struct chan_info *chan, u32 chnum, + struct rk3288_sdram_params *sdram_params) +{ + struct rk3288_ddr_publ *publ = chan->publ; + + if (sdram_params->ch[chnum].bk == 3) + clrsetbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT, + 1 << PDQ_SHIFT); + else + clrbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT); + + writel(sdram_params->base.ddrconfig, &chan->msch->ddrconf); +} + +static void dram_all_config(const struct dram_info *dram, + struct rk3288_sdram_params *sdram_params) +{ + unsigned int chan; + u32 sys_reg = 0; + + sys_reg |= sdram_params->base.dramtype << SYS_REG_DDRTYPE_SHIFT; + sys_reg |= (sdram_params->num_channels - 1) << SYS_REG_NUM_CH_SHIFT; + for (chan = 0; chan < sdram_params->num_channels; chan++) { + const struct rk3288_sdram_channel *info = + &sdram_params->ch[chan]; + + sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(chan); + sys_reg |= 1 << SYS_REG_CHINFO_SHIFT(chan); + sys_reg |= (info->rank - 1) << SYS_REG_RANK_SHIFT(chan); + sys_reg |= (info->col - 9) << SYS_REG_COL_SHIFT(chan); + sys_reg |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(chan); + sys_reg |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(chan); + sys_reg |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(chan); + sys_reg |= (2 >> info->bw) << SYS_REG_BW_SHIFT(chan); + sys_reg |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(chan); + + dram_cfg_rbc(&dram->chan[chan], chan, sdram_params); + } + writel(sys_reg, &dram->pmu->sys_reg[2]); + rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, sdram_params->base.stride); +} + +static int sdram_rank_bw_detect(struct dram_info *dram, int channel, + struct rk3288_sdram_params *sdram_params) +{ + int reg; + int need_trainig = 0; + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_publ *publ = chan->publ; + + if (data_training(chan, channel, sdram_params) < 0) { + reg = readl(&publ->datx8[0].dxgsr[0]); + /* Check the result for rank 0 */ + if ((channel == 0) && (reg & DQS_GATE_TRAINING_ERROR_RANK0)) { + debug("data training fail!\n"); + return -EIO; + } else if ((channel == 1) && + (reg & DQS_GATE_TRAINING_ERROR_RANK0)) { + sdram_params->num_channels = 1; + } + + /* Check the result for rank 1 */ + if (reg & DQS_GATE_TRAINING_ERROR_RANK1) { + sdram_params->ch[channel].rank = 1; + clrsetbits_le32(&publ->pgcr, 0xF << 18, + sdram_params->ch[channel].rank << 18); + need_trainig = 1; + } + reg = readl(&publ->datx8[2].dxgsr[0]); + if (reg & (1 << 4)) { + sdram_params->ch[channel].bw = 1; + set_bandwidth_ratio(chan, channel, + sdram_params->ch[channel].bw, + dram->grf); + need_trainig = 1; + } + } + /* Assume the Die bit width are the same with the chip bit width */ + sdram_params->ch[channel].dbw = sdram_params->ch[channel].bw; + + if (need_trainig && + (data_training(chan, channel, sdram_params) < 0)) { + if (sdram_params->base.dramtype == LPDDR3) { + ddr_phy_ctl_reset(dram->cru, channel, 1); + udelay(10); + ddr_phy_ctl_reset(dram->cru, channel, 0); + udelay(10); + } + debug("2nd data training failed!"); + return -EIO; + } + + return 0; +} + +static int sdram_col_row_detect(struct dram_info *dram, int channel, + struct rk3288_sdram_params *sdram_params) +{ + int row, col; + unsigned int addr; + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + int ret = 0; + + /* Detect col */ + for (col = 11; col >= 9; col--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + + (1 << (col + sdram_params->ch[channel].bw - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (col == 8) { + printf("Col detect error\n"); + ret = -EINVAL; + goto out; + } else { + sdram_params->ch[channel].col = col; + } + + move_to_config_state(publ, pctl); + writel(4, &chan->msch->ddrconf); + move_to_access_state(chan); + /* Detect row*/ + for (row = 16; row >= 12; row--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + (1 << (row + 15 - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (row == 11) { + printf("Row detect error\n"); + ret = -EINVAL; + } else { + sdram_params->ch[channel].cs1_row = row; + sdram_params->ch[channel].row_3_4 = 0; + debug("chn %d col %d, row %d\n", channel, col, row); + sdram_params->ch[channel].cs0_row = row; + } + +out: + return ret; +} + +static int sdram_get_niu_config(struct rk3288_sdram_params *sdram_params) +{ + int i, tmp, size, ret = 0; + + tmp = sdram_params->ch[0].col - 9; + tmp -= (sdram_params->ch[0].bw == 2) ? 0 : 1; + tmp |= ((sdram_params->ch[0].cs0_row - 12) << 4); + size = sizeof(ddrconf_table)/sizeof(ddrconf_table[0]); + for (i = 0; i < size; i++) + if (tmp == ddrconf_table[i]) + break; + if (i >= size) { + printf("niu config not found\n"); + ret = -EINVAL; + } else { + sdram_params->base.ddrconfig = i; + } + + return ret; +} + +static int sdram_get_stride(struct rk3288_sdram_params *sdram_params) +{ + int stride = -1; + int ret = 0; + long cap = sdram_params->num_channels * (1u << + (sdram_params->ch[0].cs0_row + + sdram_params->ch[0].col + + (sdram_params->ch[0].rank - 1) + + sdram_params->ch[0].bw + + 3 - 20)); + + switch (cap) { + case 512: + stride = 0; + break; + case 1024: + stride = 5; + break; + case 2048: + stride = 9; + break; + case 4096: + stride = 0xd; + break; + default: + stride = -1; + printf("could not find correct stride, cap error!\n"); + ret = -EINVAL; + break; + } + sdram_params->base.stride = stride; + + return ret; +} + +static int sdram_init(struct dram_info *dram, + struct rk3288_sdram_params *sdram_params) +{ + int channel; + int zqcr; + int ret; + + debug("%s start\n", __func__); + if ((sdram_params->base.dramtype == DDR3 && + sdram_params->base.ddr_freq > 800000000) || + (sdram_params->base.dramtype == LPDDR3 && + sdram_params->base.ddr_freq > 533000000)) { + debug("SDRAM frequency is too high!"); + return -E2BIG; + } + + debug("ddr clk dpll\n"); + ret = clk_set_rate(&dram->ddr_clk, sdram_params->base.ddr_freq); + debug("ret=%d\n", ret); + if (ret) { + debug("Could not set DDR clock\n"); + return ret; + } + + for (channel = 0; channel < 2; channel++) { + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + + /* map all the 4GB space to the current channel */ + if (channel) + rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, 0x17); + else + rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, 0x1a); + phy_pctrl_reset(dram->cru, publ, channel); + phy_dll_bypass_set(publ, sdram_params->base.ddr_freq); + + dfi_cfg(pctl, sdram_params->base.dramtype); + + pctl_cfg(channel, pctl, sdram_params, dram->grf); + + phy_cfg(chan, channel, sdram_params); + + phy_init(publ); + + writel(POWER_UP_START, &pctl->powctl); + while (!(readl(&pctl->powstat) & POWER_UP_DONE)) + ; + + memory_init(publ, sdram_params->base.dramtype); + move_to_config_state(publ, pctl); + + if (sdram_params->base.dramtype == LPDDR3) { + send_command(pctl, 3, DESELECT_CMD, 0); + udelay(1); + send_command(pctl, 3, PREA_CMD, 0); + udelay(1); + send_command_op(pctl, 3, MRS_CMD, 63, 0xfc); + udelay(1); + send_command_op(pctl, 3, MRS_CMD, 1, + sdram_params->phy_timing.mr[1]); + udelay(1); + send_command_op(pctl, 3, MRS_CMD, 2, + sdram_params->phy_timing.mr[2]); + udelay(1); + send_command_op(pctl, 3, MRS_CMD, 3, + sdram_params->phy_timing.mr[3]); + udelay(1); + } + + /* Using 32bit bus width for detect */ + sdram_params->ch[channel].bw = 2; + set_bandwidth_ratio(chan, channel, + sdram_params->ch[channel].bw, dram->grf); + /* + * set cs, using n=3 for detect + * CS0, n=1 + * CS1, n=2 + * CS0 & CS1, n = 3 + */ + sdram_params->ch[channel].rank = 2, + clrsetbits_le32(&publ->pgcr, 0xF << 18, + (sdram_params->ch[channel].rank | 1) << 18); + + /* DS=40ohm,ODT=155ohm */ + zqcr = 1 << ZDEN_SHIFT | 2 << PU_ONDIE_SHIFT | + 2 << PD_ONDIE_SHIFT | 0x19 << PU_OUTPUT_SHIFT | + 0x19 << PD_OUTPUT_SHIFT; + writel(zqcr, &publ->zq1cr[0]); + writel(zqcr, &publ->zq0cr[0]); + + if (sdram_params->base.dramtype == LPDDR3) { + /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */ + udelay(10); + send_command_op(pctl, + sdram_params->ch[channel].rank | 1, + MRS_CMD, 11, + sdram_params->base.odt ? 3 : 0); + if (channel == 0) { + writel(0, &pctl->mrrcfg0); + send_command_op(pctl, 1, MRR_CMD, 8, 0); + /* S8 */ + if ((readl(&pctl->mrrstat0) & 0x3) != 3) { + debug("failed!"); + return -EREMOTEIO; + } + } + } + + /* Detect the rank and bit-width with data-training */ + sdram_rank_bw_detect(dram, channel, sdram_params); + + if (sdram_params->base.dramtype == LPDDR3) { + u32 i; + writel(0, &pctl->mrrcfg0); + for (i = 0; i < 17; i++) + send_command_op(pctl, 1, MRR_CMD, i, 0); + } + writel(15, &chan->msch->ddrconf); + move_to_access_state(chan); + /* DDR3 and LPDDR3 are always 8 bank, no need detect */ + sdram_params->ch[channel].bk = 3; + /* Detect Col and Row number*/ + ret = sdram_col_row_detect(dram, channel, sdram_params); + if (ret) + goto error; + } + /* Find NIU DDR configuration */ + ret = sdram_get_niu_config(sdram_params); + if (ret) + goto error; + /* Find stride setting */ + ret = sdram_get_stride(sdram_params); + if (ret) + goto error; + + dram_all_config(dram, sdram_params); + debug("%s done\n", __func__); + + return 0; +error: + printf("DRAM init failed!\n"); + hang(); +} + +# ifdef CONFIG_ROCKCHIP_FAST_SPL +static int veyron_init(struct dram_info *priv) +{ + struct udevice *pmic; + int ret; + + ret = uclass_first_device_err(UCLASS_PMIC, &pmic); + if (ret) + return ret; + + /* Slowly raise to max CPU voltage to prevent overshoot */ + ret = rk8xx_spl_configure_buck(pmic, 1, 1200000); + if (ret) + return ret; + udelay(175);/* Must wait for voltage to stabilize, 2mV/us */ + ret = rk8xx_spl_configure_buck(pmic, 1, 1400000); + if (ret) + return ret; + udelay(100);/* Must wait for voltage to stabilize, 2mV/us */ + + rk3288_clk_configure_cpu(priv->cru, priv->grf); + + return 0; +} +# endif + +static int setup_sdram(struct udevice *dev) +{ + struct dram_info *priv = dev_get_priv(dev); + struct rk3288_sdram_params *params = dev_get_platdata(dev); + +# ifdef CONFIG_ROCKCHIP_FAST_SPL + if (priv->is_veyron) { + int ret; + + ret = veyron_init(priv); + if (ret) + return ret; + } +# endif + + return sdram_init(priv, params); +} + +static int rk3288_dmc_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3288_sdram_params *params = dev_get_platdata(dev); + int ret; + + /* Rk3288 supports dual-channel, set default channel num to 2 */ + params->num_channels = 2; + ret = dev_read_u32_array(dev, "rockchip,pctl-timing", + (u32 *)¶ms->pctl_timing, + sizeof(params->pctl_timing) / sizeof(u32)); + if (ret) { + debug("%s: Cannot read rockchip,pctl-timing\n", __func__); + return -EINVAL; + } + ret = dev_read_u32_array(dev, "rockchip,phy-timing", + (u32 *)¶ms->phy_timing, + sizeof(params->phy_timing) / sizeof(u32)); + if (ret) { + debug("%s: Cannot read rockchip,phy-timing\n", __func__); + return -EINVAL; + } + ret = dev_read_u32_array(dev, "rockchip,sdram-params", + (u32 *)¶ms->base, + sizeof(params->base) / sizeof(u32)); + if (ret) { + debug("%s: Cannot read rockchip,sdram-params\n", __func__); + return -EINVAL; + } +#ifdef CONFIG_ROCKCHIP_FAST_SPL + struct dram_info *priv = dev_get_priv(dev); + + priv->is_veyron = !fdt_node_check_compatible(blob, 0, "google,veyron"); +#endif + ret = regmap_init_mem(dev, ¶ms->map); + if (ret) + return ret; +#endif + + return 0; +} +#endif /* CONFIG_SPL_BUILD */ + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +static int conv_of_platdata(struct udevice *dev) +{ + struct rk3288_sdram_params *plat = dev_get_platdata(dev); + struct dtd_rockchip_rk3288_dmc *of_plat = &plat->of_plat; + int ret; + + memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing, + sizeof(plat->pctl_timing)); + memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing, + sizeof(plat->phy_timing)); + memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base)); + /* Rk3288 supports dual-channel, set default channel num to 2 */ + plat->num_channels = 2; + ret = regmap_init_mem_platdata(dev, of_plat->reg, + ARRAY_SIZE(of_plat->reg) / 2, + &plat->map); + if (ret) + return ret; + + return 0; +} +#endif + +static int rk3288_dmc_probe(struct udevice *dev) +{ +#ifdef CONFIG_SPL_BUILD + struct rk3288_sdram_params *plat = dev_get_platdata(dev); + struct udevice *dev_clk; + struct regmap *map; + int ret; +#endif + struct dram_info *priv = dev_get_priv(dev); + + priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU); +#ifdef CONFIG_SPL_BUILD +#if CONFIG_IS_ENABLED(OF_PLATDATA) + ret = conv_of_platdata(dev); + if (ret) + return ret; +#endif + map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC); + if (IS_ERR(map)) + return PTR_ERR(map); + priv->chan[0].msch = regmap_get_range(map, 0); + priv->chan[1].msch = (struct rk3288_msch *) + (regmap_get_range(map, 0) + 0x80); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + priv->sgrf = syscon_get_first_range(ROCKCHIP_SYSCON_SGRF); + + priv->chan[0].pctl = regmap_get_range(plat->map, 0); + priv->chan[0].publ = regmap_get_range(plat->map, 1); + priv->chan[1].pctl = regmap_get_range(plat->map, 2); + priv->chan[1].publ = regmap_get_range(plat->map, 3); + + ret = rockchip_get_clk(&dev_clk); + if (ret) + return ret; + priv->ddr_clk.id = CLK_DDR; + ret = clk_request(dev_clk, &priv->ddr_clk); + if (ret) + return ret; + + priv->cru = rockchip_get_cru(); + if (IS_ERR(priv->cru)) + return PTR_ERR(priv->cru); + ret = setup_sdram(dev); + if (ret) + return ret; +#else + priv->info.base = CONFIG_SYS_SDRAM_BASE; + priv->info.size = rockchip_sdram_size( + (phys_addr_t)&priv->pmu->sys_reg[2]); +#endif + + return 0; +} + +static int rk3288_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + struct dram_info *priv = dev_get_priv(dev); + + *info = priv->info; + + return 0; +} + +static struct ram_ops rk3288_dmc_ops = { + .get_info = rk3288_dmc_get_info, +}; + +static const struct udevice_id rk3288_dmc_ids[] = { + { .compatible = "rockchip,rk3288-dmc" }, + { } +}; + +U_BOOT_DRIVER(dmc_rk3288) = { + .name = "rockchip_rk3288_dmc", + .id = UCLASS_RAM, + .of_match = rk3288_dmc_ids, + .ops = &rk3288_dmc_ops, +#ifdef CONFIG_SPL_BUILD + .ofdata_to_platdata = rk3288_dmc_ofdata_to_platdata, +#endif + .probe = rk3288_dmc_probe, + .priv_auto_alloc_size = sizeof(struct dram_info), +#ifdef CONFIG_SPL_BUILD + .platdata_auto_alloc_size = sizeof(struct rk3288_sdram_params), +#endif +}; diff --git a/drivers/ram/rockchip/sdram_rk3328.c b/drivers/ram/rockchip/sdram_rk3328.c new file mode 100644 index 00000000000..9637a35e231 --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk3328.c @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2017 Rockchip Electronics Co., Ltd. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <ram.h> +#include <syscon.h> +#include <asm/arch/clock.h> +#include <asm/arch/grf_rk3328.h> +#include <asm/arch/sdram_common.h> + +DECLARE_GLOBAL_DATA_PTR; +struct dram_info { + struct ram_info info; + struct rk3328_grf_regs *grf; +}; + +static int rk3328_dmc_probe(struct udevice *dev) +{ + struct dram_info *priv = dev_get_priv(dev); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + debug("%s: grf=%p\n", __func__, priv->grf); + priv->info.base = CONFIG_SYS_SDRAM_BASE; + priv->info.size = rockchip_sdram_size( + (phys_addr_t)&priv->grf->os_reg[2]); + + return 0; +} + +static int rk3328_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + struct dram_info *priv = dev_get_priv(dev); + + *info = priv->info; + + return 0; +} + +static struct ram_ops rk3328_dmc_ops = { + .get_info = rk3328_dmc_get_info, +}; + + +static const struct udevice_id rk3328_dmc_ids[] = { + { .compatible = "rockchip,rk3328-dmc" }, + { } +}; + +U_BOOT_DRIVER(dmc_rk3328) = { + .name = "rockchip_rk3328_dmc", + .id = UCLASS_RAM, + .of_match = rk3328_dmc_ids, + .ops = &rk3328_dmc_ops, + .probe = rk3328_dmc_probe, + .priv_auto_alloc_size = sizeof(struct dram_info), +}; diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c new file mode 100644 index 00000000000..76c1fe80a7f --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -0,0 +1,1238 @@ +/* + * (C) Copyright 2016-2017 Rockchip Inc. + * + * SPDX-License-Identifier: GPL-2.0 + * + * Adapted from coreboot. + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <dt-structs.h> +#include <ram.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/sdram_common.h> +#include <asm/arch/sdram_rk3399.h> +#include <asm/arch/cru_rk3399.h> +#include <asm/arch/grf_rk3399.h> +#include <asm/arch/hardware.h> +#include <linux/err.h> +#include <time.h> + +DECLARE_GLOBAL_DATA_PTR; +struct chan_info { + struct rk3399_ddr_pctl_regs *pctl; + struct rk3399_ddr_pi_regs *pi; + struct rk3399_ddr_publ_regs *publ; + struct rk3399_msch_regs *msch; +}; + +struct dram_info { +#ifdef CONFIG_SPL_BUILD + struct chan_info chan[2]; + struct clk ddr_clk; + struct rk3399_cru *cru; + struct rk3399_pmucru *pmucru; + struct rk3399_pmusgrf_regs *pmusgrf; + struct rk3399_ddr_cic_regs *cic; +#endif + struct ram_info info; + struct rk3399_pmugrf_regs *pmugrf; +}; + +#define PRESET_SGRF_HOLD(n) ((0x1 << (6 + 16)) | ((n) << 6)) +#define PRESET_GPIO0_HOLD(n) ((0x1 << (7 + 16)) | ((n) << 7)) +#define PRESET_GPIO1_HOLD(n) ((0x1 << (8 + 16)) | ((n) << 8)) + +#define PHY_DRV_ODT_Hi_Z 0x0 +#define PHY_DRV_ODT_240 0x1 +#define PHY_DRV_ODT_120 0x8 +#define PHY_DRV_ODT_80 0x9 +#define PHY_DRV_ODT_60 0xc +#define PHY_DRV_ODT_48 0xd +#define PHY_DRV_ODT_40 0xe +#define PHY_DRV_ODT_34_3 0xf + +#ifdef CONFIG_SPL_BUILD + +struct rockchip_dmc_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3399_dmc dtplat; +#else + struct rk3399_sdram_params sdram_params; +#endif + struct regmap *map; +}; + +static void copy_to_reg(u32 *dest, const u32 *src, u32 n) +{ + int i; + + for (i = 0; i < n / sizeof(u32); i++) { + writel(*src, dest); + src++; + dest++; + } +} + +static void phy_dll_bypass_set(struct rk3399_ddr_publ_regs *ddr_publ_regs, + u32 freq) +{ + u32 *denali_phy = ddr_publ_regs->denali_phy; + + /* From IP spec, only freq small than 125 can enter dll bypass mode */ + if (freq <= 125) { + /* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */ + setbits_le32(&denali_phy[86], (0x3 << 2) << 8); + setbits_le32(&denali_phy[214], (0x3 << 2) << 8); + setbits_le32(&denali_phy[342], (0x3 << 2) << 8); + setbits_le32(&denali_phy[470], (0x3 << 2) << 8); + + /* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */ + setbits_le32(&denali_phy[547], (0x3 << 2) << 16); + setbits_le32(&denali_phy[675], (0x3 << 2) << 16); + setbits_le32(&denali_phy[803], (0x3 << 2) << 16); + } else { + /* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */ + clrbits_le32(&denali_phy[86], (0x3 << 2) << 8); + clrbits_le32(&denali_phy[214], (0x3 << 2) << 8); + clrbits_le32(&denali_phy[342], (0x3 << 2) << 8); + clrbits_le32(&denali_phy[470], (0x3 << 2) << 8); + + /* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */ + clrbits_le32(&denali_phy[547], (0x3 << 2) << 16); + clrbits_le32(&denali_phy[675], (0x3 << 2) << 16); + clrbits_le32(&denali_phy[803], (0x3 << 2) << 16); + } +} + +static void set_memory_map(const struct chan_info *chan, u32 channel, + const struct rk3399_sdram_params *sdram_params) +{ + const struct rk3399_sdram_channel *sdram_ch = + &sdram_params->ch[channel]; + u32 *denali_ctl = chan->pctl->denali_ctl; + u32 *denali_pi = chan->pi->denali_pi; + u32 cs_map; + u32 reduc; + u32 row; + + /* Get row number from ddrconfig setting */ + if (sdram_ch->ddrconfig < 2 || sdram_ch->ddrconfig == 4) + row = 16; + else if (sdram_ch->ddrconfig == 3) + row = 14; + else + row = 15; + + cs_map = (sdram_ch->rank > 1) ? 3 : 1; + reduc = (sdram_ch->bw == 2) ? 0 : 1; + + /* Set the dram configuration to ctrl */ + clrsetbits_le32(&denali_ctl[191], 0xF, (12 - sdram_ch->col)); + clrsetbits_le32(&denali_ctl[190], (0x3 << 16) | (0x7 << 24), + ((3 - sdram_ch->bk) << 16) | + ((16 - row) << 24)); + + clrsetbits_le32(&denali_ctl[196], 0x3 | (1 << 16), + cs_map | (reduc << 16)); + + /* PI_199 PI_COL_DIFF:RW:0:4 */ + clrsetbits_le32(&denali_pi[199], 0xF, (12 - sdram_ch->col)); + + /* PI_155 PI_ROW_DIFF:RW:24:3 PI_BANK_DIFF:RW:16:2 */ + clrsetbits_le32(&denali_pi[155], (0x3 << 16) | (0x7 << 24), + ((3 - sdram_ch->bk) << 16) | + ((16 - row) << 24)); + /* PI_41 PI_CS_MAP:RW:24:4 */ + clrsetbits_le32(&denali_pi[41], 0xf << 24, cs_map << 24); + if ((sdram_ch->rank == 1) && (sdram_params->base.dramtype == DDR3)) + writel(0x2EC7FFFF, &denali_pi[34]); +} + +static void set_ds_odt(const struct chan_info *chan, + const struct rk3399_sdram_params *sdram_params) +{ + u32 *denali_phy = chan->publ->denali_phy; + + u32 tsel_idle_en, tsel_wr_en, tsel_rd_en; + u32 tsel_idle_select_p, tsel_wr_select_p, tsel_rd_select_p; + u32 ca_tsel_wr_select_p, ca_tsel_wr_select_n; + u32 tsel_idle_select_n, tsel_wr_select_n, tsel_rd_select_n; + u32 reg_value; + + if (sdram_params->base.dramtype == LPDDR4) { + tsel_rd_select_p = PHY_DRV_ODT_Hi_Z; + tsel_wr_select_p = PHY_DRV_ODT_40; + ca_tsel_wr_select_p = PHY_DRV_ODT_40; + tsel_idle_select_p = PHY_DRV_ODT_Hi_Z; + + tsel_rd_select_n = PHY_DRV_ODT_240; + tsel_wr_select_n = PHY_DRV_ODT_40; + ca_tsel_wr_select_n = PHY_DRV_ODT_40; + tsel_idle_select_n = PHY_DRV_ODT_240; + } else if (sdram_params->base.dramtype == LPDDR3) { + tsel_rd_select_p = PHY_DRV_ODT_240; + tsel_wr_select_p = PHY_DRV_ODT_34_3; + ca_tsel_wr_select_p = PHY_DRV_ODT_48; + tsel_idle_select_p = PHY_DRV_ODT_240; + + tsel_rd_select_n = PHY_DRV_ODT_Hi_Z; + tsel_wr_select_n = PHY_DRV_ODT_34_3; + ca_tsel_wr_select_n = PHY_DRV_ODT_48; + tsel_idle_select_n = PHY_DRV_ODT_Hi_Z; + } else { + tsel_rd_select_p = PHY_DRV_ODT_240; + tsel_wr_select_p = PHY_DRV_ODT_34_3; + ca_tsel_wr_select_p = PHY_DRV_ODT_34_3; + tsel_idle_select_p = PHY_DRV_ODT_240; + + tsel_rd_select_n = PHY_DRV_ODT_240; + tsel_wr_select_n = PHY_DRV_ODT_34_3; + ca_tsel_wr_select_n = PHY_DRV_ODT_34_3; + tsel_idle_select_n = PHY_DRV_ODT_240; + } + + if (sdram_params->base.odt == 1) + tsel_rd_en = 1; + else + tsel_rd_en = 0; + + tsel_wr_en = 0; + tsel_idle_en = 0; + + /* + * phy_dq_tsel_select_X 24bits DENALI_PHY_6/134/262/390 offset_0 + * sets termination values for read/idle cycles and drive strength + * for write cycles for DQ/DM + */ + reg_value = tsel_rd_select_n | (tsel_rd_select_p << 0x4) | + (tsel_wr_select_n << 8) | (tsel_wr_select_p << 12) | + (tsel_idle_select_n << 16) | (tsel_idle_select_p << 20); + clrsetbits_le32(&denali_phy[6], 0xffffff, reg_value); + clrsetbits_le32(&denali_phy[134], 0xffffff, reg_value); + clrsetbits_le32(&denali_phy[262], 0xffffff, reg_value); + clrsetbits_le32(&denali_phy[390], 0xffffff, reg_value); + + /* + * phy_dqs_tsel_select_X 24bits DENALI_PHY_7/135/263/391 offset_0 + * sets termination values for read/idle cycles and drive strength + * for write cycles for DQS + */ + clrsetbits_le32(&denali_phy[7], 0xffffff, reg_value); + clrsetbits_le32(&denali_phy[135], 0xffffff, reg_value); + clrsetbits_le32(&denali_phy[263], 0xffffff, reg_value); + clrsetbits_le32(&denali_phy[391], 0xffffff, reg_value); + + /* phy_adr_tsel_select_ 8bits DENALI_PHY_544/672/800 offset_0 */ + reg_value = ca_tsel_wr_select_n | (ca_tsel_wr_select_p << 0x4); + clrsetbits_le32(&denali_phy[544], 0xff, reg_value); + clrsetbits_le32(&denali_phy[672], 0xff, reg_value); + clrsetbits_le32(&denali_phy[800], 0xff, reg_value); + + /* phy_pad_addr_drive 8bits DENALI_PHY_928 offset_0 */ + clrsetbits_le32(&denali_phy[928], 0xff, reg_value); + + /* phy_pad_rst_drive 8bits DENALI_PHY_937 offset_0 */ + clrsetbits_le32(&denali_phy[937], 0xff, reg_value); + + /* phy_pad_cke_drive 8bits DENALI_PHY_935 offset_0 */ + clrsetbits_le32(&denali_phy[935], 0xff, reg_value); + + /* phy_pad_cs_drive 8bits DENALI_PHY_939 offset_0 */ + clrsetbits_le32(&denali_phy[939], 0xff, reg_value); + + /* phy_pad_clk_drive 8bits DENALI_PHY_929 offset_0 */ + clrsetbits_le32(&denali_phy[929], 0xff, reg_value); + + /* phy_pad_fdbk_drive 23bit DENALI_PHY_924/925 */ + clrsetbits_le32(&denali_phy[924], 0xff, + tsel_wr_select_n | (tsel_wr_select_p << 4)); + clrsetbits_le32(&denali_phy[925], 0xff, + tsel_rd_select_n | (tsel_rd_select_p << 4)); + + /* phy_dq_tsel_enable_X 3bits DENALI_PHY_5/133/261/389 offset_16 */ + reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2)) + << 16; + clrsetbits_le32(&denali_phy[5], 0x7 << 16, reg_value); + clrsetbits_le32(&denali_phy[133], 0x7 << 16, reg_value); + clrsetbits_le32(&denali_phy[261], 0x7 << 16, reg_value); + clrsetbits_le32(&denali_phy[389], 0x7 << 16, reg_value); + + /* phy_dqs_tsel_enable_X 3bits DENALI_PHY_6/134/262/390 offset_24 */ + reg_value = (tsel_rd_en | (tsel_wr_en << 1) | (tsel_idle_en << 2)) + << 24; + clrsetbits_le32(&denali_phy[6], 0x7 << 24, reg_value); + clrsetbits_le32(&denali_phy[134], 0x7 << 24, reg_value); + clrsetbits_le32(&denali_phy[262], 0x7 << 24, reg_value); + clrsetbits_le32(&denali_phy[390], 0x7 << 24, reg_value); + + /* phy_adr_tsel_enable_ 1bit DENALI_PHY_518/646/774 offset_8 */ + reg_value = tsel_wr_en << 8; + clrsetbits_le32(&denali_phy[518], 0x1 << 8, reg_value); + clrsetbits_le32(&denali_phy[646], 0x1 << 8, reg_value); + clrsetbits_le32(&denali_phy[774], 0x1 << 8, reg_value); + + /* phy_pad_addr_term tsel 1bit DENALI_PHY_933 offset_17 */ + reg_value = tsel_wr_en << 17; + clrsetbits_le32(&denali_phy[933], 0x1 << 17, reg_value); + /* + * pad_rst/cke/cs/clk_term tsel 1bits + * DENALI_PHY_938/936/940/934 offset_17 + */ + clrsetbits_le32(&denali_phy[938], 0x1 << 17, reg_value); + clrsetbits_le32(&denali_phy[936], 0x1 << 17, reg_value); + clrsetbits_le32(&denali_phy[940], 0x1 << 17, reg_value); + clrsetbits_le32(&denali_phy[934], 0x1 << 17, reg_value); + + /* phy_pad_fdbk_term 1bit DENALI_PHY_930 offset_17 */ + clrsetbits_le32(&denali_phy[930], 0x1 << 17, reg_value); +} + +static int phy_io_config(const struct chan_info *chan, + const struct rk3399_sdram_params *sdram_params) +{ + u32 *denali_phy = chan->publ->denali_phy; + u32 vref_mode_dq, vref_value_dq, vref_mode_ac, vref_value_ac; + u32 mode_sel; + u32 reg_value; + u32 drv_value, odt_value; + u32 speed; + + /* vref setting */ + if (sdram_params->base.dramtype == LPDDR4) { + /* LPDDR4 */ + vref_mode_dq = 0x6; + vref_value_dq = 0x1f; + vref_mode_ac = 0x6; + vref_value_ac = 0x1f; + } else if (sdram_params->base.dramtype == LPDDR3) { + if (sdram_params->base.odt == 1) { + vref_mode_dq = 0x5; /* LPDDR3 ODT */ + drv_value = (readl(&denali_phy[6]) >> 12) & 0xf; + odt_value = (readl(&denali_phy[6]) >> 4) & 0xf; + if (drv_value == PHY_DRV_ODT_48) { + switch (odt_value) { + case PHY_DRV_ODT_240: + vref_value_dq = 0x16; + break; + case PHY_DRV_ODT_120: + vref_value_dq = 0x26; + break; + case PHY_DRV_ODT_60: + vref_value_dq = 0x36; + break; + default: + debug("Invalid ODT value.\n"); + return -EINVAL; + } + } else if (drv_value == PHY_DRV_ODT_40) { + switch (odt_value) { + case PHY_DRV_ODT_240: + vref_value_dq = 0x19; + break; + case PHY_DRV_ODT_120: + vref_value_dq = 0x23; + break; + case PHY_DRV_ODT_60: + vref_value_dq = 0x31; + break; + default: + debug("Invalid ODT value.\n"); + return -EINVAL; + } + } else if (drv_value == PHY_DRV_ODT_34_3) { + switch (odt_value) { + case PHY_DRV_ODT_240: + vref_value_dq = 0x17; + break; + case PHY_DRV_ODT_120: + vref_value_dq = 0x20; + break; + case PHY_DRV_ODT_60: + vref_value_dq = 0x2e; + break; + default: + debug("Invalid ODT value.\n"); + return -EINVAL; + } + } else { + debug("Invalid DRV value.\n"); + return -EINVAL; + } + } else { + vref_mode_dq = 0x2; /* LPDDR3 */ + vref_value_dq = 0x1f; + } + vref_mode_ac = 0x2; + vref_value_ac = 0x1f; + } else if (sdram_params->base.dramtype == DDR3) { + /* DDR3L */ + vref_mode_dq = 0x1; + vref_value_dq = 0x1f; + vref_mode_ac = 0x1; + vref_value_ac = 0x1f; + } else { + debug("Unknown DRAM type.\n"); + return -EINVAL; + } + + reg_value = (vref_mode_dq << 9) | (0x1 << 8) | vref_value_dq; + + /* PHY_913 PHY_PAD_VREF_CTRL_DQ_0 12bits offset_8 */ + clrsetbits_le32(&denali_phy[913], 0xfff << 8, reg_value << 8); + /* PHY_914 PHY_PAD_VREF_CTRL_DQ_1 12bits offset_0 */ + clrsetbits_le32(&denali_phy[914], 0xfff, reg_value); + /* PHY_914 PHY_PAD_VREF_CTRL_DQ_2 12bits offset_16 */ + clrsetbits_le32(&denali_phy[914], 0xfff << 16, reg_value << 16); + /* PHY_915 PHY_PAD_VREF_CTRL_DQ_3 12bits offset_0 */ + clrsetbits_le32(&denali_phy[915], 0xfff, reg_value); + + reg_value = (vref_mode_ac << 9) | (0x1 << 8) | vref_value_ac; + + /* PHY_915 PHY_PAD_VREF_CTRL_AC 12bits offset_16 */ + clrsetbits_le32(&denali_phy[915], 0xfff << 16, reg_value << 16); + + if (sdram_params->base.dramtype == LPDDR4) + mode_sel = 0x6; + else if (sdram_params->base.dramtype == LPDDR3) + mode_sel = 0x0; + else if (sdram_params->base.dramtype == DDR3) + mode_sel = 0x1; + else + return -EINVAL; + + /* PHY_924 PHY_PAD_FDBK_DRIVE */ + clrsetbits_le32(&denali_phy[924], 0x7 << 15, mode_sel << 15); + /* PHY_926 PHY_PAD_DATA_DRIVE */ + clrsetbits_le32(&denali_phy[926], 0x7 << 6, mode_sel << 6); + /* PHY_927 PHY_PAD_DQS_DRIVE */ + clrsetbits_le32(&denali_phy[927], 0x7 << 6, mode_sel << 6); + /* PHY_928 PHY_PAD_ADDR_DRIVE */ + clrsetbits_le32(&denali_phy[928], 0x7 << 14, mode_sel << 14); + /* PHY_929 PHY_PAD_CLK_DRIVE */ + clrsetbits_le32(&denali_phy[929], 0x7 << 14, mode_sel << 14); + /* PHY_935 PHY_PAD_CKE_DRIVE */ + clrsetbits_le32(&denali_phy[935], 0x7 << 14, mode_sel << 14); + /* PHY_937 PHY_PAD_RST_DRIVE */ + clrsetbits_le32(&denali_phy[937], 0x7 << 14, mode_sel << 14); + /* PHY_939 PHY_PAD_CS_DRIVE */ + clrsetbits_le32(&denali_phy[939], 0x7 << 14, mode_sel << 14); + + + /* speed setting */ + if (sdram_params->base.ddr_freq < 400) + speed = 0x0; + else if (sdram_params->base.ddr_freq < 800) + speed = 0x1; + else if (sdram_params->base.ddr_freq < 1200) + speed = 0x2; + else + speed = 0x3; + + /* PHY_924 PHY_PAD_FDBK_DRIVE */ + clrsetbits_le32(&denali_phy[924], 0x3 << 21, speed << 21); + /* PHY_926 PHY_PAD_DATA_DRIVE */ + clrsetbits_le32(&denali_phy[926], 0x3 << 9, speed << 9); + /* PHY_927 PHY_PAD_DQS_DRIVE */ + clrsetbits_le32(&denali_phy[927], 0x3 << 9, speed << 9); + /* PHY_928 PHY_PAD_ADDR_DRIVE */ + clrsetbits_le32(&denali_phy[928], 0x3 << 17, speed << 17); + /* PHY_929 PHY_PAD_CLK_DRIVE */ + clrsetbits_le32(&denali_phy[929], 0x3 << 17, speed << 17); + /* PHY_935 PHY_PAD_CKE_DRIVE */ + clrsetbits_le32(&denali_phy[935], 0x3 << 17, speed << 17); + /* PHY_937 PHY_PAD_RST_DRIVE */ + clrsetbits_le32(&denali_phy[937], 0x3 << 17, speed << 17); + /* PHY_939 PHY_PAD_CS_DRIVE */ + clrsetbits_le32(&denali_phy[939], 0x3 << 17, speed << 17); + + return 0; +} + +static int pctl_cfg(const struct chan_info *chan, u32 channel, + const struct rk3399_sdram_params *sdram_params) +{ + u32 *denali_ctl = chan->pctl->denali_ctl; + u32 *denali_pi = chan->pi->denali_pi; + u32 *denali_phy = chan->publ->denali_phy; + const u32 *params_ctl = sdram_params->pctl_regs.denali_ctl; + const u32 *params_phy = sdram_params->phy_regs.denali_phy; + u32 tmp, tmp1, tmp2; + u32 pwrup_srefresh_exit; + int ret; + const ulong timeout_ms = 200; + + /* + * work around controller bug: + * Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed + */ + copy_to_reg(&denali_ctl[1], ¶ms_ctl[1], + sizeof(struct rk3399_ddr_pctl_regs) - 4); + writel(params_ctl[0], &denali_ctl[0]); + copy_to_reg(denali_pi, &sdram_params->pi_regs.denali_pi[0], + sizeof(struct rk3399_ddr_pi_regs)); + /* rank count need to set for init */ + set_memory_map(chan, channel, sdram_params); + + writel(sdram_params->phy_regs.denali_phy[910], &denali_phy[910]); + writel(sdram_params->phy_regs.denali_phy[911], &denali_phy[911]); + writel(sdram_params->phy_regs.denali_phy[912], &denali_phy[912]); + + pwrup_srefresh_exit = readl(&denali_ctl[68]) & PWRUP_SREFRESH_EXIT; + clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT); + + /* PHY_DLL_RST_EN */ + clrsetbits_le32(&denali_phy[957], 0x3 << 24, 1 << 24); + + setbits_le32(&denali_pi[0], START); + setbits_le32(&denali_ctl[0], START); + + /* Wating for phy DLL lock */ + while (1) { + tmp = readl(&denali_phy[920]); + tmp1 = readl(&denali_phy[921]); + tmp2 = readl(&denali_phy[922]); + if ((((tmp >> 16) & 0x1) == 0x1) && + (((tmp1 >> 16) & 0x1) == 0x1) && + (((tmp1 >> 0) & 0x1) == 0x1) && + (((tmp2 >> 0) & 0x1) == 0x1)) + break; + } + + copy_to_reg(&denali_phy[896], ¶ms_phy[896], (958 - 895) * 4); + copy_to_reg(&denali_phy[0], ¶ms_phy[0], (90 - 0 + 1) * 4); + copy_to_reg(&denali_phy[128], ¶ms_phy[128], (218 - 128 + 1) * 4); + copy_to_reg(&denali_phy[256], ¶ms_phy[256], (346 - 256 + 1) * 4); + copy_to_reg(&denali_phy[384], ¶ms_phy[384], (474 - 384 + 1) * 4); + copy_to_reg(&denali_phy[512], ¶ms_phy[512], (549 - 512 + 1) * 4); + copy_to_reg(&denali_phy[640], ¶ms_phy[640], (677 - 640 + 1) * 4); + copy_to_reg(&denali_phy[768], ¶ms_phy[768], (805 - 768 + 1) * 4); + set_ds_odt(chan, sdram_params); + + /* + * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_84/212/340/468 offset_8 + * dqs_tsel_wr_end[7:4] add Half cycle + */ + tmp = (readl(&denali_phy[84]) >> 8) & 0xff; + clrsetbits_le32(&denali_phy[84], 0xff << 8, (tmp + 0x10) << 8); + tmp = (readl(&denali_phy[212]) >> 8) & 0xff; + clrsetbits_le32(&denali_phy[212], 0xff << 8, (tmp + 0x10) << 8); + tmp = (readl(&denali_phy[340]) >> 8) & 0xff; + clrsetbits_le32(&denali_phy[340], 0xff << 8, (tmp + 0x10) << 8); + tmp = (readl(&denali_phy[468]) >> 8) & 0xff; + clrsetbits_le32(&denali_phy[468], 0xff << 8, (tmp + 0x10) << 8); + + /* + * phy_dqs_tsel_wr_timing_X 8bits DENALI_PHY_83/211/339/467 offset_8 + * dq_tsel_wr_end[7:4] add Half cycle + */ + tmp = (readl(&denali_phy[83]) >> 16) & 0xff; + clrsetbits_le32(&denali_phy[83], 0xff << 16, (tmp + 0x10) << 16); + tmp = (readl(&denali_phy[211]) >> 16) & 0xff; + clrsetbits_le32(&denali_phy[211], 0xff << 16, (tmp + 0x10) << 16); + tmp = (readl(&denali_phy[339]) >> 16) & 0xff; + clrsetbits_le32(&denali_phy[339], 0xff << 16, (tmp + 0x10) << 16); + tmp = (readl(&denali_phy[467]) >> 16) & 0xff; + clrsetbits_le32(&denali_phy[467], 0xff << 16, (tmp + 0x10) << 16); + + ret = phy_io_config(chan, sdram_params); + if (ret) + return ret; + + /* PHY_DLL_RST_EN */ + clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24); + + /* Wating for PHY and DRAM init complete */ + tmp = get_timer(0); + do { + if (get_timer(tmp) > timeout_ms) { + pr_err("DRAM (%s): phy failed to lock within %ld ms\n", + __func__, timeout_ms); + return -ETIME; + } + } while (!(readl(&denali_ctl[203]) & (1 << 3))); + debug("DRAM (%s): phy locked after %ld ms\n", __func__, get_timer(tmp)); + + clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT, + pwrup_srefresh_exit); + return 0; +} + +static void select_per_cs_training_index(const struct chan_info *chan, + u32 rank) +{ + u32 *denali_phy = chan->publ->denali_phy; + + /* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */ + if ((readl(&denali_phy[84])>>16) & 1) { + /* + * PHY_8/136/264/392 + * phy_per_cs_training_index_X 1bit offset_24 + */ + clrsetbits_le32(&denali_phy[8], 0x1 << 24, rank << 24); + clrsetbits_le32(&denali_phy[136], 0x1 << 24, rank << 24); + clrsetbits_le32(&denali_phy[264], 0x1 << 24, rank << 24); + clrsetbits_le32(&denali_phy[392], 0x1 << 24, rank << 24); + } +} + +static void override_write_leveling_value(const struct chan_info *chan) +{ + u32 *denali_ctl = chan->pctl->denali_ctl; + u32 *denali_phy = chan->publ->denali_phy; + u32 byte; + + /* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */ + setbits_le32(&denali_phy[896], 1); + + /* + * PHY_8/136/264/392 + * phy_per_cs_training_multicast_en_X 1bit offset_16 + */ + clrsetbits_le32(&denali_phy[8], 0x1 << 16, 1 << 16); + clrsetbits_le32(&denali_phy[136], 0x1 << 16, 1 << 16); + clrsetbits_le32(&denali_phy[264], 0x1 << 16, 1 << 16); + clrsetbits_le32(&denali_phy[392], 0x1 << 16, 1 << 16); + + for (byte = 0; byte < 4; byte++) + clrsetbits_le32(&denali_phy[63 + (128 * byte)], 0xffff << 16, + 0x200 << 16); + + /* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */ + clrbits_le32(&denali_phy[896], 1); + + /* CTL_200 ctrlupd_req 1bit offset_8 */ + clrsetbits_le32(&denali_ctl[200], 0x1 << 8, 0x1 << 8); +} + +static int data_training_ca(const struct chan_info *chan, u32 channel, + const struct rk3399_sdram_params *sdram_params) +{ + u32 *denali_pi = chan->pi->denali_pi; + u32 *denali_phy = chan->publ->denali_phy; + u32 i, tmp; + u32 obs_0, obs_1, obs_2, obs_err = 0; + u32 rank = sdram_params->ch[channel].rank; + + for (i = 0; i < rank; i++) { + select_per_cs_training_index(chan, i); + /* PI_100 PI_CALVL_EN:RW:8:2 */ + clrsetbits_le32(&denali_pi[100], 0x3 << 8, 0x2 << 8); + /* PI_92 PI_CALVL_REQ:WR:16:1,PI_CALVL_CS:RW:24:2 */ + clrsetbits_le32(&denali_pi[92], + (0x1 << 16) | (0x3 << 24), + (0x1 << 16) | (i << 24)); + + /* Waiting for training complete */ + while (1) { + /* PI_174 PI_INT_STATUS:RD:8:18 */ + tmp = readl(&denali_pi[174]) >> 8; + /* + * check status obs + * PHY_532/660/789 phy_adr_calvl_obs1_:0:32 + */ + obs_0 = readl(&denali_phy[532]); + obs_1 = readl(&denali_phy[660]); + obs_2 = readl(&denali_phy[788]); + if (((obs_0 >> 30) & 0x3) || + ((obs_1 >> 30) & 0x3) || + ((obs_2 >> 30) & 0x3)) + obs_err = 1; + if ((((tmp >> 11) & 0x1) == 0x1) && + (((tmp >> 13) & 0x1) == 0x1) && + (((tmp >> 5) & 0x1) == 0x0) && + (obs_err == 0)) + break; + else if ((((tmp >> 5) & 0x1) == 0x1) || + (obs_err == 1)) + return -EIO; + } + /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + } + clrbits_le32(&denali_pi[100], 0x3 << 8); + + return 0; +} + +static int data_training_wl(const struct chan_info *chan, u32 channel, + const struct rk3399_sdram_params *sdram_params) +{ + u32 *denali_pi = chan->pi->denali_pi; + u32 *denali_phy = chan->publ->denali_phy; + u32 i, tmp; + u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0; + u32 rank = sdram_params->ch[channel].rank; + + for (i = 0; i < rank; i++) { + select_per_cs_training_index(chan, i); + /* PI_60 PI_WRLVL_EN:RW:8:2 */ + clrsetbits_le32(&denali_pi[60], 0x3 << 8, 0x2 << 8); + /* PI_59 PI_WRLVL_REQ:WR:8:1,PI_WRLVL_CS:RW:16:2 */ + clrsetbits_le32(&denali_pi[59], + (0x1 << 8) | (0x3 << 16), + (0x1 << 8) | (i << 16)); + + /* Waiting for training complete */ + while (1) { + /* PI_174 PI_INT_STATUS:RD:8:18 */ + tmp = readl(&denali_pi[174]) >> 8; + + /* + * check status obs, if error maybe can not + * get leveling done PHY_40/168/296/424 + * phy_wrlvl_status_obs_X:0:13 + */ + obs_0 = readl(&denali_phy[40]); + obs_1 = readl(&denali_phy[168]); + obs_2 = readl(&denali_phy[296]); + obs_3 = readl(&denali_phy[424]); + if (((obs_0 >> 12) & 0x1) || + ((obs_1 >> 12) & 0x1) || + ((obs_2 >> 12) & 0x1) || + ((obs_3 >> 12) & 0x1)) + obs_err = 1; + if ((((tmp >> 10) & 0x1) == 0x1) && + (((tmp >> 13) & 0x1) == 0x1) && + (((tmp >> 4) & 0x1) == 0x0) && + (obs_err == 0)) + break; + else if ((((tmp >> 4) & 0x1) == 0x1) || + (obs_err == 1)) + return -EIO; + } + /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + } + + override_write_leveling_value(chan); + clrbits_le32(&denali_pi[60], 0x3 << 8); + + return 0; +} + +static int data_training_rg(const struct chan_info *chan, u32 channel, + const struct rk3399_sdram_params *sdram_params) +{ + u32 *denali_pi = chan->pi->denali_pi; + u32 *denali_phy = chan->publ->denali_phy; + u32 i, tmp; + u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0; + u32 rank = sdram_params->ch[channel].rank; + + for (i = 0; i < rank; i++) { + select_per_cs_training_index(chan, i); + /* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */ + clrsetbits_le32(&denali_pi[80], 0x3 << 24, 0x2 << 24); + /* + * PI_74 PI_RDLVL_GATE_REQ:WR:16:1 + * PI_RDLVL_CS:RW:24:2 + */ + clrsetbits_le32(&denali_pi[74], + (0x1 << 16) | (0x3 << 24), + (0x1 << 16) | (i << 24)); + + /* Waiting for training complete */ + while (1) { + /* PI_174 PI_INT_STATUS:RD:8:18 */ + tmp = readl(&denali_pi[174]) >> 8; + + /* + * check status obs + * PHY_43/171/299/427 + * PHY_GTLVL_STATUS_OBS_x:16:8 + */ + obs_0 = readl(&denali_phy[43]); + obs_1 = readl(&denali_phy[171]); + obs_2 = readl(&denali_phy[299]); + obs_3 = readl(&denali_phy[427]); + if (((obs_0 >> (16 + 6)) & 0x3) || + ((obs_1 >> (16 + 6)) & 0x3) || + ((obs_2 >> (16 + 6)) & 0x3) || + ((obs_3 >> (16 + 6)) & 0x3)) + obs_err = 1; + if ((((tmp >> 9) & 0x1) == 0x1) && + (((tmp >> 13) & 0x1) == 0x1) && + (((tmp >> 3) & 0x1) == 0x0) && + (obs_err == 0)) + break; + else if ((((tmp >> 3) & 0x1) == 0x1) || + (obs_err == 1)) + return -EIO; + } + /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + } + clrbits_le32(&denali_pi[80], 0x3 << 24); + + return 0; +} + +static int data_training_rl(const struct chan_info *chan, u32 channel, + const struct rk3399_sdram_params *sdram_params) +{ + u32 *denali_pi = chan->pi->denali_pi; + u32 i, tmp; + u32 rank = sdram_params->ch[channel].rank; + + for (i = 0; i < rank; i++) { + select_per_cs_training_index(chan, i); + /* PI_80 PI_RDLVL_EN:RW:16:2 */ + clrsetbits_le32(&denali_pi[80], 0x3 << 16, 0x2 << 16); + /* PI_74 PI_RDLVL_REQ:WR:8:1,PI_RDLVL_CS:RW:24:2 */ + clrsetbits_le32(&denali_pi[74], + (0x1 << 8) | (0x3 << 24), + (0x1 << 8) | (i << 24)); + + /* Waiting for training complete */ + while (1) { + /* PI_174 PI_INT_STATUS:RD:8:18 */ + tmp = readl(&denali_pi[174]) >> 8; + + /* + * make sure status obs not report error bit + * PHY_46/174/302/430 + * phy_rdlvl_status_obs_X:16:8 + */ + if ((((tmp >> 8) & 0x1) == 0x1) && + (((tmp >> 13) & 0x1) == 0x1) && + (((tmp >> 2) & 0x1) == 0x0)) + break; + else if (((tmp >> 2) & 0x1) == 0x1) + return -EIO; + } + /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + } + clrbits_le32(&denali_pi[80], 0x3 << 16); + + return 0; +} + +static int data_training_wdql(const struct chan_info *chan, u32 channel, + const struct rk3399_sdram_params *sdram_params) +{ + u32 *denali_pi = chan->pi->denali_pi; + u32 i, tmp; + u32 rank = sdram_params->ch[channel].rank; + + for (i = 0; i < rank; i++) { + select_per_cs_training_index(chan, i); + /* + * disable PI_WDQLVL_VREF_EN before wdq leveling? + * PI_181 PI_WDQLVL_VREF_EN:RW:8:1 + */ + clrbits_le32(&denali_pi[181], 0x1 << 8); + /* PI_124 PI_WDQLVL_EN:RW:16:2 */ + clrsetbits_le32(&denali_pi[124], 0x3 << 16, 0x2 << 16); + /* PI_121 PI_WDQLVL_REQ:WR:8:1,PI_WDQLVL_CS:RW:16:2 */ + clrsetbits_le32(&denali_pi[121], + (0x1 << 8) | (0x3 << 16), + (0x1 << 8) | (i << 16)); + + /* Waiting for training complete */ + while (1) { + /* PI_174 PI_INT_STATUS:RD:8:18 */ + tmp = readl(&denali_pi[174]) >> 8; + if ((((tmp >> 12) & 0x1) == 0x1) && + (((tmp >> 13) & 0x1) == 0x1) && + (((tmp >> 6) & 0x1) == 0x0)) + break; + else if (((tmp >> 6) & 0x1) == 0x1) + return -EIO; + } + /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + } + clrbits_le32(&denali_pi[124], 0x3 << 16); + + return 0; +} + +static int data_training(const struct chan_info *chan, u32 channel, + const struct rk3399_sdram_params *sdram_params, + u32 training_flag) +{ + u32 *denali_phy = chan->publ->denali_phy; + + /* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */ + setbits_le32(&denali_phy[927], (1 << 22)); + + if (training_flag == PI_FULL_TRAINING) { + if (sdram_params->base.dramtype == LPDDR4) { + training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING | + PI_READ_GATE_TRAINING | + PI_READ_LEVELING | PI_WDQ_LEVELING; + } else if (sdram_params->base.dramtype == LPDDR3) { + training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING | + PI_READ_GATE_TRAINING; + } else if (sdram_params->base.dramtype == DDR3) { + training_flag = PI_WRITE_LEVELING | + PI_READ_GATE_TRAINING | + PI_READ_LEVELING; + } + } + + /* ca training(LPDDR4,LPDDR3 support) */ + if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) + data_training_ca(chan, channel, sdram_params); + + /* write leveling(LPDDR4,LPDDR3,DDR3 support) */ + if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) + data_training_wl(chan, channel, sdram_params); + + /* read gate training(LPDDR4,LPDDR3,DDR3 support) */ + if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) + data_training_rg(chan, channel, sdram_params); + + /* read leveling(LPDDR4,LPDDR3,DDR3 support) */ + if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) + data_training_rl(chan, channel, sdram_params); + + /* wdq leveling(LPDDR4 support) */ + if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) + data_training_wdql(chan, channel, sdram_params); + + /* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */ + clrbits_le32(&denali_phy[927], (1 << 22)); + + return 0; +} + +static void set_ddrconfig(const struct chan_info *chan, + const struct rk3399_sdram_params *sdram_params, + unsigned char channel, u32 ddrconfig) +{ + /* only need to set ddrconfig */ + struct rk3399_msch_regs *ddr_msch_regs = chan->msch; + unsigned int cs0_cap = 0; + unsigned int cs1_cap = 0; + + cs0_cap = (1 << (sdram_params->ch[channel].cs0_row + + sdram_params->ch[channel].col + + sdram_params->ch[channel].bk + + sdram_params->ch[channel].bw - 20)); + if (sdram_params->ch[channel].rank > 1) + cs1_cap = cs0_cap >> (sdram_params->ch[channel].cs0_row + - sdram_params->ch[channel].cs1_row); + if (sdram_params->ch[channel].row_3_4) { + cs0_cap = cs0_cap * 3 / 4; + cs1_cap = cs1_cap * 3 / 4; + } + + writel(ddrconfig | (ddrconfig << 8), &ddr_msch_regs->ddrconf); + writel(((cs0_cap / 32) & 0xff) | (((cs1_cap / 32) & 0xff) << 8), + &ddr_msch_regs->ddrsize); +} + +static void dram_all_config(struct dram_info *dram, + const struct rk3399_sdram_params *sdram_params) +{ + u32 sys_reg = 0; + unsigned int channel, idx; + + sys_reg |= sdram_params->base.dramtype << SYS_REG_DDRTYPE_SHIFT; + sys_reg |= (sdram_params->base.num_channels - 1) + << SYS_REG_NUM_CH_SHIFT; + for (channel = 0, idx = 0; + (idx < sdram_params->base.num_channels) && (channel < 2); + channel++) { + const struct rk3399_sdram_channel *info = + &sdram_params->ch[channel]; + struct rk3399_msch_regs *ddr_msch_regs; + const struct rk3399_msch_timings *noc_timing; + + if (sdram_params->ch[channel].col == 0) + continue; + idx++; + sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(channel); + sys_reg |= 1 << SYS_REG_CHINFO_SHIFT(channel); + sys_reg |= (info->rank - 1) << SYS_REG_RANK_SHIFT(channel); + sys_reg |= (info->col - 9) << SYS_REG_COL_SHIFT(channel); + sys_reg |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(channel); + sys_reg |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(channel); + sys_reg |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(channel); + sys_reg |= (2 >> info->bw) << SYS_REG_BW_SHIFT(channel); + sys_reg |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(channel); + + ddr_msch_regs = dram->chan[channel].msch; + noc_timing = &sdram_params->ch[channel].noc_timings; + writel(noc_timing->ddrtiminga0, + &ddr_msch_regs->ddrtiminga0); + writel(noc_timing->ddrtimingb0, + &ddr_msch_regs->ddrtimingb0); + writel(noc_timing->ddrtimingc0, + &ddr_msch_regs->ddrtimingc0); + writel(noc_timing->devtodev0, + &ddr_msch_regs->devtodev0); + writel(noc_timing->ddrmode, + &ddr_msch_regs->ddrmode); + + /* rank 1 memory clock disable (dfi_dram_clk_disable = 1) */ + if (sdram_params->ch[channel].rank == 1) + setbits_le32(&dram->chan[channel].pctl->denali_ctl[276], + 1 << 17); + } + + writel(sys_reg, &dram->pmugrf->os_reg2); + rk_clrsetreg(&dram->pmusgrf->soc_con4, 0x1f << 10, + sdram_params->base.stride << 10); + + /* reboot hold register set */ + writel(PRESET_SGRF_HOLD(0) | PRESET_GPIO0_HOLD(1) | + PRESET_GPIO1_HOLD(1), + &dram->pmucru->pmucru_rstnhold_con[1]); + clrsetbits_le32(&dram->cru->glb_rst_con, 0x3, 0x3); +} + +static int switch_to_phy_index1(struct dram_info *dram, + const struct rk3399_sdram_params *sdram_params) +{ + u32 channel; + u32 *denali_phy; + u32 ch_count = sdram_params->base.num_channels; + int ret; + int i = 0; + + writel(RK_CLRSETBITS(0x03 << 4 | 1 << 2 | 1, + 1 << 4 | 1 << 2 | 1), + &dram->cic->cic_ctrl0); + while (!(readl(&dram->cic->cic_status0) & (1 << 2))) { + mdelay(10); + i++; + if (i > 10) { + debug("index1 frequency change overtime\n"); + return -ETIME; + } + } + + i = 0; + writel(RK_CLRSETBITS(1 << 1, 1 << 1), &dram->cic->cic_ctrl0); + while (!(readl(&dram->cic->cic_status0) & (1 << 0))) { + mdelay(10); + if (i > 10) { + debug("index1 frequency done overtime\n"); + return -ETIME; + } + } + + for (channel = 0; channel < ch_count; channel++) { + denali_phy = dram->chan[channel].publ->denali_phy; + clrsetbits_le32(&denali_phy[896], (0x3 << 8) | 1, 1 << 8); + ret = data_training(&dram->chan[channel], channel, + sdram_params, PI_FULL_TRAINING); + if (ret) { + debug("index1 training failed\n"); + return ret; + } + } + + return 0; +} + +static int sdram_init(struct dram_info *dram, + const struct rk3399_sdram_params *sdram_params) +{ + unsigned char dramtype = sdram_params->base.dramtype; + unsigned int ddr_freq = sdram_params->base.ddr_freq; + int channel; + + debug("Starting SDRAM initialization...\n"); + + if ((dramtype == DDR3 && ddr_freq > 933) || + (dramtype == LPDDR3 && ddr_freq > 933) || + (dramtype == LPDDR4 && ddr_freq > 800)) { + debug("SDRAM frequency is to high!"); + return -E2BIG; + } + + for (channel = 0; channel < 2; channel++) { + const struct chan_info *chan = &dram->chan[channel]; + struct rk3399_ddr_publ_regs *publ = chan->publ; + + phy_dll_bypass_set(publ, ddr_freq); + + if (channel >= sdram_params->base.num_channels) + continue; + + if (pctl_cfg(chan, channel, sdram_params) != 0) { + printf("pctl_cfg fail, reset\n"); + return -EIO; + } + + /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */ + if (dramtype == LPDDR3) + udelay(10); + + if (data_training(chan, channel, + sdram_params, PI_FULL_TRAINING)) { + printf("SDRAM initialization failed, reset\n"); + return -EIO; + } + + set_ddrconfig(chan, sdram_params, channel, + sdram_params->ch[channel].ddrconfig); + } + dram_all_config(dram, sdram_params); + switch_to_phy_index1(dram, sdram_params); + + debug("Finish SDRAM initialization...\n"); + return 0; +} + +static int rk3399_dmc_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rockchip_dmc_plat *plat = dev_get_platdata(dev); + int ret; + + ret = dev_read_u32_array(dev, "rockchip,sdram-params", + (u32 *)&plat->sdram_params, + sizeof(plat->sdram_params) / sizeof(u32)); + if (ret) { + printf("%s: Cannot read rockchip,sdram-params %d\n", + __func__, ret); + return ret; + } + ret = regmap_init_mem(dev, &plat->map); + if (ret) + printf("%s: regmap failed %d\n", __func__, ret); + +#endif + return 0; +} + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +static int conv_of_platdata(struct udevice *dev) +{ + struct rockchip_dmc_plat *plat = dev_get_platdata(dev); + struct dtd_rockchip_rk3399_dmc *dtplat = &plat->dtplat; + int ret; + + ret = regmap_init_mem_platdata(dev, dtplat->reg, + ARRAY_SIZE(dtplat->reg) / 2, + &plat->map); + if (ret) + return ret; + + return 0; +} +#endif + +static int rk3399_dmc_init(struct udevice *dev) +{ + struct dram_info *priv = dev_get_priv(dev); + struct rockchip_dmc_plat *plat = dev_get_platdata(dev); + int ret; +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3399_sdram_params *params = &plat->sdram_params; +#else + struct dtd_rockchip_rk3399_dmc *dtplat = &plat->dtplat; + struct rk3399_sdram_params *params = + (void *)dtplat->rockchip_sdram_params; + + ret = conv_of_platdata(dev); + if (ret) + return ret; +#endif + + priv->cic = syscon_get_first_range(ROCKCHIP_SYSCON_CIC); + priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); + priv->pmusgrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUSGRF); + priv->pmucru = rockchip_get_pmucru(); + priv->cru = rockchip_get_cru(); + priv->chan[0].pctl = regmap_get_range(plat->map, 0); + priv->chan[0].pi = regmap_get_range(plat->map, 1); + priv->chan[0].publ = regmap_get_range(plat->map, 2); + priv->chan[0].msch = regmap_get_range(plat->map, 3); + priv->chan[1].pctl = regmap_get_range(plat->map, 4); + priv->chan[1].pi = regmap_get_range(plat->map, 5); + priv->chan[1].publ = regmap_get_range(plat->map, 6); + priv->chan[1].msch = regmap_get_range(plat->map, 7); + + debug("con reg %p %p %p %p %p %p %p %p\n", + priv->chan[0].pctl, priv->chan[0].pi, + priv->chan[0].publ, priv->chan[0].msch, + priv->chan[1].pctl, priv->chan[1].pi, + priv->chan[1].publ, priv->chan[1].msch); + debug("cru %p, cic %p, grf %p, sgrf %p, pmucru %p\n", priv->cru, + priv->cic, priv->pmugrf, priv->pmusgrf, priv->pmucru); +#if CONFIG_IS_ENABLED(OF_PLATDATA) + ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->ddr_clk); +#else + ret = clk_get_by_index(dev, 0, &priv->ddr_clk); +#endif + if (ret) { + printf("%s clk get failed %d\n", __func__, ret); + return ret; + } + ret = clk_set_rate(&priv->ddr_clk, params->base.ddr_freq * MHz); + if (ret < 0) { + printf("%s clk set failed %d\n", __func__, ret); + return ret; + } + ret = sdram_init(priv, params); + if (ret < 0) { + printf("%s DRAM init failed%d\n", __func__, ret); + return ret; + } + + return 0; +} +#endif + +static int rk3399_dmc_probe(struct udevice *dev) +{ +#ifdef CONFIG_SPL_BUILD + if (rk3399_dmc_init(dev)) + return 0; +#else + struct dram_info *priv = dev_get_priv(dev); + + priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); + debug("%s: pmugrf=%p\n", __func__, priv->pmugrf); + priv->info.base = CONFIG_SYS_SDRAM_BASE; + priv->info.size = rockchip_sdram_size( + (phys_addr_t)&priv->pmugrf->os_reg2); +#endif + return 0; +} + +static int rk3399_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + struct dram_info *priv = dev_get_priv(dev); + + *info = priv->info; + + return 0; +} + +static struct ram_ops rk3399_dmc_ops = { + .get_info = rk3399_dmc_get_info, +}; + + +static const struct udevice_id rk3399_dmc_ids[] = { + { .compatible = "rockchip,rk3399-dmc" }, + { } +}; + +U_BOOT_DRIVER(dmc_rk3399) = { + .name = "rockchip_rk3399_dmc", + .id = UCLASS_RAM, + .of_match = rk3399_dmc_ids, + .ops = &rk3399_dmc_ops, +#ifdef CONFIG_SPL_BUILD + .ofdata_to_platdata = rk3399_dmc_ofdata_to_platdata, +#endif + .probe = rk3399_dmc_probe, + .priv_auto_alloc_size = sizeof(struct dram_info), +#ifdef CONFIG_SPL_BUILD + .platdata_auto_alloc_size = sizeof(struct rockchip_dmc_plat), +#endif +}; diff --git a/drivers/ram/stm32_sdram.c b/drivers/ram/stm32_sdram.c index b1b0289a1b0..fdf088e7833 100644 --- a/drivers/ram/stm32_sdram.c +++ b/drivers/ram/stm32_sdram.c @@ -262,7 +262,7 @@ static int stm32_fmc_ofdata_to_platdata(struct udevice *dev) bank_name = (char *)ofnode_get_name(bank_node); strsep(&bank_name, "@"); if (!bank_name) { - error("missing sdram bank index"); + pr_err("missing sdram bank index"); return -EINVAL; } @@ -271,7 +271,7 @@ static int stm32_fmc_ofdata_to_platdata(struct udevice *dev) (long unsigned int *)&bank_params->target_bank); if (bank_params->target_bank >= MAX_SDRAM_BANK) { - error("Found bank %d , but only bank 0 and 1 are supported", + pr_err("Found bank %d , but only bank 0 and 1 are supported", bank_params->target_bank); return -EINVAL; } @@ -285,7 +285,7 @@ static int stm32_fmc_ofdata_to_platdata(struct udevice *dev) sizeof(struct stm32_sdram_control)); if (!params->bank_params[bank].sdram_control) { - error("st,sdram-control not found for %s", + pr_err("st,sdram-control not found for %s", ofnode_get_name(bank_node)); return -EINVAL; } @@ -298,7 +298,7 @@ static int stm32_fmc_ofdata_to_platdata(struct udevice *dev) sizeof(struct stm32_sdram_timing)); if (!params->bank_params[bank].sdram_timing) { - error("st,sdram-timing not found for %s", + pr_err("st,sdram-timing not found for %s", ofnode_get_name(bank_node)); return -EINVAL; } diff --git a/drivers/reset/sti-reset.c b/drivers/reset/sti-reset.c index a79708cde28..024b996f0c1 100644 --- a/drivers/reset/sti-reset.c +++ b/drivers/reset/sti-reset.c @@ -201,20 +201,20 @@ phys_addr_t sti_reset_get_regmap(const char *compatible) node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, compatible); if (node < 0) { - error("unable to find %s node\n", compatible); + pr_err("unable to find %s node\n", compatible); return node; } ret = uclass_get_device_by_of_offset(UCLASS_SYSCON, node, &syscon); if (ret) { - error("%s: uclass_get_device_by_of_offset failed: %d\n", + pr_err("%s: uclass_get_device_by_of_offset failed: %d\n", __func__, ret); return ret; } regmap = syscon_get_regmap(syscon); if (!regmap) { - error("unable to get regmap for %s\n", syscon->name); + pr_err("unable to get regmap for %s\n", syscon->name); return -ENODEV; } @@ -251,7 +251,7 @@ static int sti_reset_program_hw(struct reset_ctl *reset_ctl, int assert) if (ch->deassert_cnt > 0) return 0; } else - error("Reset balancing error: reset_ctl=%p dev=%p id=%lu\n", + pr_err("Reset balancing error: reset_ctl=%p dev=%p id=%lu\n", reset_ctl, reset_ctl->dev, reset_ctl->id); } @@ -268,7 +268,7 @@ static int sti_reset_program_hw(struct reset_ctl *reset_ctl, int assert) reg = (void __iomem *)base + ch->ack_offset; if (wait_for_bit(__func__, reg, BIT(ch->ack_bit), ctrl_val, 1000, false)) { - error("Stuck on waiting ack reset_ctl=%p dev=%p id=%lu\n", + pr_err("Stuck on waiting ack reset_ctl=%p dev=%p id=%lu\n", reset_ctl, reset_ctl->dev, reset_ctl->id); return -ETIMEDOUT; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 9bf2e26e9d1..7c54a49bb32 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -531,9 +531,9 @@ config STI_ASC_SERIAL config STM32X7_SERIAL bool "STMicroelectronics STM32 SoCs on-chip UART" - depends on DM_SERIAL && (STM32F7 || STM32H7) + depends on DM_SERIAL && (STM32F4 || STM32F7 || STM32H7) help - If you have a machine based on a STM32 F7 or H7 SoC you can + If you have a machine based on a STM32 F4, F7 or H7 SoC you can enable its onboard serial ports, say Y to this option. If unsure, say N. diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c index 2f4eafa885a..a5d529cab28 100644 --- a/drivers/serial/serial_stm32x7.c +++ b/drivers/serial/serial_stm32x7.c @@ -17,71 +17,81 @@ DECLARE_GLOBAL_DATA_PTR; static int stm32_serial_setbrg(struct udevice *dev, int baudrate) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + bool stm32f4 = plat->uart_info->stm32f4; + fdt_addr_t base = plat->base; u32 int_div, mantissa, fraction, oversampling; int_div = DIV_ROUND_CLOSEST(plat->clock_rate, baudrate); if (int_div < 16) { oversampling = 8; - setbits_le32(&usart->cr1, USART_CR1_OVER8); + setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8); } else { oversampling = 16; - clrbits_le32(&usart->cr1, USART_CR1_OVER8); + clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8); } mantissa = (int_div / oversampling) << USART_BRR_M_SHIFT; fraction = int_div % oversampling; - writel(mantissa | fraction, &usart->brr); + writel(mantissa | fraction, base + BRR_OFFSET(stm32f4)); return 0; } static int stm32_serial_getc(struct udevice *dev) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + bool stm32f4 = plat->uart_info->stm32f4; + fdt_addr_t base = plat->base; - if ((readl(&usart->sr) & USART_SR_FLAG_RXNE) == 0) + if ((readl(base + ISR_OFFSET(stm32f4)) & USART_SR_FLAG_RXNE) == 0) return -EAGAIN; - return readl(&usart->rd_dr); + return readl(base + RDR_OFFSET(stm32f4)); } static int stm32_serial_putc(struct udevice *dev, const char c) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + bool stm32f4 = plat->uart_info->stm32f4; + fdt_addr_t base = plat->base; - if ((readl(&usart->sr) & USART_SR_FLAG_TXE) == 0) + if ((readl(base + ISR_OFFSET(stm32f4)) & USART_SR_FLAG_TXE) == 0) return -EAGAIN; - writel(c, &usart->tx_dr); + writel(c, base + TDR_OFFSET(stm32f4)); return 0; } static int stm32_serial_pending(struct udevice *dev, bool input) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); + bool stm32f4 = plat->uart_info->stm32f4; + fdt_addr_t base = plat->base; if (input) - return readl(&usart->sr) & USART_SR_FLAG_RXNE ? 1 : 0; + return readl(base + ISR_OFFSET(stm32f4)) & + USART_SR_FLAG_RXNE ? 1 : 0; else - return readl(&usart->sr) & USART_SR_FLAG_TXE ? 0 : 1; + return readl(base + ISR_OFFSET(stm32f4)) & + USART_SR_FLAG_TXE ? 0 : 1; } static int stm32_serial_probe(struct udevice *dev) { - struct stm32x7_serial_platdata *plat = dev->platdata; - struct stm32_usart *const usart = plat->base; - -#ifdef CONFIG_CLK - int ret; + struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); struct clk clk; + fdt_addr_t base = plat->base; + int ret; + bool stm32f4; + u8 uart_enable_bit; + + plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev); + stm32f4 = plat->uart_info->stm32f4; + uart_enable_bit = plat->uart_info->uart_enable_bit; ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) @@ -92,7 +102,6 @@ static int stm32_serial_probe(struct udevice *dev) dev_err(dev, "failed to enable clock\n"); return ret; } -#endif plat->clock_rate = clk_get_rate(&clk); if (plat->clock_rate < 0) { @@ -100,37 +109,36 @@ static int stm32_serial_probe(struct udevice *dev) return plat->clock_rate; }; - /* Disable usart-> disable overrun-> enable usart */ - clrbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); - setbits_le32(&usart->cr3, USART_CR3_OVRDIS); - setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); + /* Disable uart-> disable overrun-> enable uart */ + clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | + BIT(uart_enable_bit)); + if (plat->uart_info->has_overrun_disable) + setbits_le32(base + CR3_OFFSET(stm32f4), USART_CR3_OVRDIS); + if (plat->uart_info->has_fifo) + setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_FIFOEN); + setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE | + BIT(uart_enable_bit)); return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) static const struct udevice_id stm32_serial_id[] = { - {.compatible = "st,stm32f7-usart"}, - {.compatible = "st,stm32f7-uart"}, - {.compatible = "st,stm32h7-usart"}, - {.compatible = "st,stm32h7-uart"}, + { .compatible = "st,stm32-uart", .data = (ulong)&stm32f4_info}, + { .compatible = "st,stm32f7-uart", .data = (ulong)&stm32f7_info}, + { .compatible = "st,stm32h7-uart", .data = (ulong)&stm32h7_info}, {} }; static int stm32_serial_ofdata_to_platdata(struct udevice *dev) { struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); - fdt_addr_t addr; - addr = devfdt_get_addr(dev); - if (addr == FDT_ADDR_T_NONE) + plat->base = devfdt_get_addr(dev); + if (plat->base == FDT_ADDR_T_NONE) return -EINVAL; - plat->base = (struct stm32_usart *)addr; - return 0; } -#endif static const struct dm_serial_ops stm32_serial_ops = { .putc = stm32_serial_putc, diff --git a/drivers/serial/serial_stm32x7.h b/drivers/serial/serial_stm32x7.h index 9fe37af5cc9..b914edf28a1 100644 --- a/drivers/serial/serial_stm32x7.h +++ b/drivers/serial/serial_stm32x7.h @@ -8,38 +8,65 @@ #ifndef _SERIAL_STM32_X7_ #define _SERIAL_STM32_X7_ -struct stm32_usart { - u32 cr1; - u32 cr2; - u32 cr3; - u32 brr; - u32 gtpr; - u32 rtor; - u32 rqr; - u32 sr; - u32 icr; - u32 rd_dr; - u32 tx_dr; +#define CR1_OFFSET(x) (x ? 0x0c : 0x00) +#define CR3_OFFSET(x) (x ? 0x14 : 0x08) +#define BRR_OFFSET(x) (x ? 0x08 : 0x0c) +#define ISR_OFFSET(x) (x ? 0x00 : 0x1c) +/* + * STM32F4 has one Data Register (DR) for received or transmitted + * data, so map Receive Data Register (RDR) and Transmit Data + * Register (TDR) at the same offset + */ +#define RDR_OFFSET(x) (x ? 0x04 : 0x24) +#define TDR_OFFSET(x) (x ? 0x04 : 0x28) + +struct stm32_uart_info { + u8 uart_enable_bit; /* UART_CR1_UE */ + bool stm32f4; /* true for STM32F4, false otherwise */ + bool has_overrun_disable; + bool has_fifo; +}; + +struct stm32_uart_info stm32f4_info = { + .stm32f4 = true, + .uart_enable_bit = 13, + .has_overrun_disable = false, + .has_fifo = false, +}; + +struct stm32_uart_info stm32f7_info = { + .uart_enable_bit = 0, + .stm32f4 = false, + .has_overrun_disable = true, + .has_fifo = false, +}; + +struct stm32_uart_info stm32h7_info = { + .uart_enable_bit = 0, + .stm32f4 = false, + .has_overrun_disable = true, + .has_fifo = true, }; /* Information about a serial port */ struct stm32x7_serial_platdata { - struct stm32_usart *base; /* address of registers in physical memory */ + fdt_addr_t base; /* address of registers in physical memory */ + struct stm32_uart_info *uart_info; unsigned long int clock_rate; }; -#define USART_CR1_OVER8 (1 << 15) -#define USART_CR1_TE (1 << 3) -#define USART_CR1_RE (1 << 2) -#define USART_CR1_UE (1 << 0) +#define USART_CR1_FIFOEN BIT(29) +#define USART_CR1_OVER8 BIT(15) +#define USART_CR1_TE BIT(3) +#define USART_CR1_RE BIT(2) -#define USART_CR3_OVRDIS (1 << 12) +#define USART_CR3_OVRDIS BIT(12) -#define USART_SR_FLAG_RXNE (1 << 5) -#define USART_SR_FLAG_TXE (1 << 7) +#define USART_SR_FLAG_RXNE BIT(5) +#define USART_SR_FLAG_TXE BIT(7) -#define USART_BRR_F_MASK 0xFF +#define USART_BRR_F_MASK GENMASK(7, 0) #define USART_BRR_M_SHIFT 4 -#define USART_BRR_M_MASK 0xFFF0 +#define USART_BRR_M_MASK GENMASK(15, 4) #endif diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index e2f8342e887..228e714e093 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -474,7 +474,7 @@ static int atmel_spi_probe(struct udevice *bus) ret = gpio_request_list_by_name(bus, "cs-gpios", priv->cs_gpios, ARRAY_SIZE(priv->cs_gpios), 0); if (ret < 0) { - error("Can't get %s gpios! Error: %d", bus->name, ret); + pr_err("Can't get %s gpios! Error: %d", bus->name, ret); return ret; } diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 291ef9576ad..eda252d0b30 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -563,6 +563,7 @@ static const struct dm_spi_ops davinci_spi_ops = { static const struct udevice_id davinci_spi_ids[] = { { .compatible = "ti,keystone-spi" }, { .compatible = "ti,dm6441-spi" }, + { .compatible = "ti,da830-spi" }, { } }; diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index 1dfa89afc9c..0f3f7d97f01 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -14,6 +14,7 @@ #include <dm.h> #include <errno.h> #include <watchdog.h> +#include <wait_bit.h> #include "fsl_qspi.h" DECLARE_GLOBAL_DATA_PTR; @@ -663,22 +664,20 @@ static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) tx_size = (len > TX_BUFFER_SIZE) ? TX_BUFFER_SIZE : len; - size = tx_size / 4; - for (i = 0; i < size; i++) { + size = tx_size / 16; + /* + * There must be atleast 128bit data + * available in TX FIFO for any pop operation + */ + if (tx_size % 16) + size++; + for (i = 0; i < size * 4; i++) { memcpy(&data, txbuf, 4); data = qspi_endian_xchg(data); qspi_write32(priv->flags, ®s->tbdr, data); txbuf += 4; } - size = tx_size % 4; - if (size) { - data = 0; - memcpy(&data, txbuf, size); - data = qspi_endian_xchg(data); - qspi_write32(priv->flags, ®s->tbdr, data); - } - qspi_write32(priv->flags, ®s->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) @@ -991,7 +990,7 @@ static int fsl_qspi_probe(struct udevice *bus) struct fsl_qspi_platdata *plat = dev_get_platdata(bus); struct fsl_qspi_priv *priv = dev_get_priv(bus); struct dm_spi_bus *dm_spi_bus; - int i; + int i, ret; dm_spi_bus = bus->uclass_priv; @@ -1011,6 +1010,18 @@ static int fsl_qspi_probe(struct udevice *bus) priv->flash_num = plat->flash_num; priv->num_chipselect = plat->num_chipselect; + /* make sure controller is not busy anywhere */ + ret = wait_for_bit(__func__, &priv->regs->sr, + QSPI_SR_BUSY_MASK | + QSPI_SR_AHB_ACC_MASK | + QSPI_SR_IP_ACC_MASK, + false, 100, false); + + if (ret) { + debug("ERROR : The controller is busy\n"); + return ret; + } + mcr_val = qspi_read32(priv->flags, &priv->regs->mcr); qspi_write32(priv->flags, &priv->regs->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK | @@ -1156,10 +1167,23 @@ static int fsl_qspi_claim_bus(struct udevice *dev) struct fsl_qspi_priv *priv; struct udevice *bus; struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); + int ret; bus = dev->parent; priv = dev_get_priv(bus); + /* make sure controller is not busy anywhere */ + ret = wait_for_bit(__func__, &priv->regs->sr, + QSPI_SR_BUSY_MASK | + QSPI_SR_AHB_ACC_MASK | + QSPI_SR_IP_ACC_MASK, + false, 100, false); + + if (ret) { + debug("ERROR : The controller is busy\n"); + return ret; + } + priv->cur_amba_base = priv->amba_base[slave_plat->cs]; qspi_module_disable(priv, 0); diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h index 6cb361018b4..e468eb2529b 100644 --- a/drivers/spi/fsl_qspi.h +++ b/drivers/spi/fsl_qspi.h @@ -105,6 +105,10 @@ struct fsl_qspi_regs { #define QSPI_RBCT_RXBRD_SHIFT 8 #define QSPI_RBCT_RXBRD_USEIPS (1 << QSPI_RBCT_RXBRD_SHIFT) +#define QSPI_SR_AHB_ACC_SHIFT 2 +#define QSPI_SR_AHB_ACC_MASK (1 << QSPI_SR_AHB_ACC_SHIFT) +#define QSPI_SR_IP_ACC_SHIFT 1 +#define QSPI_SR_IP_ACC_MASK (1 << QSPI_SR_IP_ACC_SHIFT) #define QSPI_SR_BUSY_SHIFT 0 #define QSPI_SR_BUSY_MASK (1 << QSPI_SR_BUSY_SHIFT) diff --git a/drivers/spi/lpc32xx_ssp.c b/drivers/spi/lpc32xx_ssp.c index c5b766c0dd0..e2a593b9344 100644 --- a/drivers/spi/lpc32xx_ssp.c +++ b/drivers/spi/lpc32xx_ssp.c @@ -66,17 +66,17 @@ struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) /* we only set up SSP0 for now, so ignore bus */ if (mode & SPI_3WIRE) { - error("3-wire mode not supported"); + pr_err("3-wire mode not supported"); return NULL; } if (mode & SPI_SLAVE) { - error("slave mode not supported\n"); + pr_err("slave mode not supported\n"); return NULL; } if (mode & SPI_PREAMBLE) { - error("preamble byte skipping not supported\n"); + pr_err("preamble byte skipping not supported\n"); return NULL; } diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index e1562c36b7a..41f0cfcd6b7 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -5,6 +5,7 @@ */ #include <common.h> +#include <dm.h> #include <malloc.h> #include <spi.h> #include <linux/errno.h> @@ -14,6 +15,8 @@ #include <asm/arch/clock.h> #include <asm/mach-imx/spi.h> +DECLARE_GLOBAL_DATA_PTR; + #ifdef CONFIG_MX27 /* i.MX27 has a completely wrong register layout and register definitions in the * datasheet, the correct one is in the Freescale's Linux driver */ @@ -22,10 +25,6 @@ "See linux mxc_spi driver from Freescale for details." #endif -static unsigned long spi_bases[] = { - MXC_SPI_BASE_ADDRESSES -}; - __weak int board_spi_cs_gpio(unsigned bus, unsigned cs) { return -1; @@ -51,6 +50,7 @@ struct mxc_spi_slave { int ss_pol; unsigned int max_hz; unsigned int mode; + struct gpio_desc ss; }; static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) @@ -58,19 +58,24 @@ static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) return container_of(slave, struct mxc_spi_slave, slave); } -void spi_cs_activate(struct spi_slave *slave) +static void mxc_spi_cs_activate(struct mxc_spi_slave *mxcs) { - struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); - if (mxcs->gpio > 0) - gpio_set_value(mxcs->gpio, mxcs->ss_pol); + if (CONFIG_IS_ENABLED(DM_SPI)) { + dm_gpio_set_value(&mxcs->ss, mxcs->ss_pol); + } else { + if (mxcs->gpio > 0) + gpio_set_value(mxcs->gpio, mxcs->ss_pol); + } } -void spi_cs_deactivate(struct spi_slave *slave) +static void mxc_spi_cs_deactivate(struct mxc_spi_slave *mxcs) { - struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); - if (mxcs->gpio > 0) - gpio_set_value(mxcs->gpio, - !(mxcs->ss_pol)); + if (CONFIG_IS_ENABLED(DM_SPI)) { + dm_gpio_set_value(&mxcs->ss, !(mxcs->ss_pol)); + } else { + if (mxcs->gpio > 0) + gpio_set_value(mxcs->gpio, !(mxcs->ss_pol)); + } } u32 get_cspi_div(u32 div) @@ -211,10 +216,9 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs) } #endif -int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, +int spi_xchg_single(struct mxc_spi_slave *mxcs, unsigned int bitlen, const u8 *dout, u8 *din, unsigned long flags) { - struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); int nbytes = DIV_ROUND_UP(bitlen, 8); u32 data, cnt, i; struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; @@ -327,8 +331,9 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, } -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, - void *din, unsigned long flags) +static int mxc_spi_xfer_internal(struct mxc_spi_slave *mxcs, + unsigned int bitlen, const void *dout, + void *din, unsigned long flags) { int n_bytes = DIV_ROUND_UP(bitlen, 8); int n_bits; @@ -337,11 +342,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, u8 *p_outbuf = (u8 *)dout; u8 *p_inbuf = (u8 *)din; - if (!slave) - return -1; + if (!mxcs) + return -EINVAL; if (flags & SPI_XFER_BEGIN) - spi_cs_activate(slave); + mxc_spi_cs_activate(mxcs); while (n_bytes > 0) { if (n_bytes < MAX_SPI_BYTES) @@ -351,7 +356,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, n_bits = blk_size * 8; - ret = spi_xchg_single(slave, n_bits, p_outbuf, p_inbuf, 0); + ret = spi_xchg_single(mxcs, n_bits, p_outbuf, p_inbuf, 0); if (ret) return ret; @@ -363,12 +368,39 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, } if (flags & SPI_XFER_END) { - spi_cs_deactivate(slave); + mxc_spi_cs_deactivate(mxcs); } return 0; } +static int mxc_spi_claim_bus_internal(struct mxc_spi_slave *mxcs, int cs) +{ + struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; + int ret; + + reg_write(®s->rxdata, 1); + udelay(1); + ret = spi_cfg_mxc(mxcs, cs); + if (ret) { + printf("mxc_spi: cannot setup SPI controller\n"); + return ret; + } + reg_write(®s->period, MXC_CSPIPERIOD_32KHZ); + reg_write(®s->intr, 0); + + return 0; +} + +#ifndef CONFIG_DM_SPI +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + + return mxc_spi_xfer_internal(mxcs, bitlen, dout, din, flags); +} + void spi_init(void) { } @@ -390,6 +422,7 @@ static int setup_cs_gpio(struct mxc_spi_slave *mxcs, if (mxcs->gpio == -1) return 0; + gpio_request(mxcs->gpio, "spi-cs"); ret = gpio_direction_output(mxcs->gpio, !(mxcs->ss_pol)); if (ret) { printf("mxc_spi: cannot setup gpio %d\n", mxcs->gpio); @@ -399,6 +432,10 @@ static int setup_cs_gpio(struct mxc_spi_slave *mxcs, return 0; } +static unsigned long spi_bases[] = { + MXC_SPI_BASE_ADDRESSES +}; + struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { @@ -443,24 +480,104 @@ void spi_free_slave(struct spi_slave *slave) int spi_claim_bus(struct spi_slave *slave) { - int ret; struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); - struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; - reg_write(®s->rxdata, 1); - udelay(1); - ret = spi_cfg_mxc(mxcs, slave->cs); + return mxc_spi_claim_bus_internal(mxcs, slave->cs); +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* TODO: Shut the controller down */ +} +#else + +static int mxc_spi_probe(struct udevice *bus) +{ + struct mxc_spi_slave *plat = bus->platdata; + struct mxc_spi_slave *mxcs = dev_get_platdata(bus); + int node = dev_of_offset(bus); + const void *blob = gd->fdt_blob; + int ret; + + if (gpio_request_by_name(bus, "cs-gpios", 0, &plat->ss, + GPIOD_IS_OUT)) { + dev_err(bus, "No cs-gpios property\n"); + return -EINVAL; + } + + plat->base = dev_get_addr(bus); + if (plat->base == FDT_ADDR_T_NONE) + return -ENODEV; + + ret = dm_gpio_set_value(&plat->ss, !(mxcs->ss_pol)); if (ret) { - printf("mxc_spi: cannot setup SPI controller\n"); + dev_err(bus, "Setting cs error\n"); return ret; } - reg_write(®s->period, MXC_CSPIPERIOD_32KHZ); - reg_write(®s->intr, 0); + + mxcs->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", + 20000000); return 0; } -void spi_release_bus(struct spi_slave *slave) +static int mxc_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) { - /* TODO: Shut the controller down */ + struct mxc_spi_slave *mxcs = dev_get_platdata(dev->parent); + + + return mxc_spi_xfer_internal(mxcs, bitlen, dout, din, flags); +} + +static int mxc_spi_claim_bus(struct udevice *dev) +{ + struct mxc_spi_slave *mxcs = dev_get_platdata(dev->parent); + struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); + + return mxc_spi_claim_bus_internal(mxcs, slave_plat->cs); } + +static int mxc_spi_release_bus(struct udevice *dev) +{ + return 0; +} + +static int mxc_spi_set_speed(struct udevice *bus, uint speed) +{ + /* Nothing to do */ + return 0; +} + +static int mxc_spi_set_mode(struct udevice *bus, uint mode) +{ + struct mxc_spi_slave *mxcs = dev_get_platdata(bus); + + mxcs->mode = mode; + mxcs->ss_pol = (mode & SPI_CS_HIGH) ? 1 : 0; + + return 0; +} + +static const struct dm_spi_ops mxc_spi_ops = { + .claim_bus = mxc_spi_claim_bus, + .release_bus = mxc_spi_release_bus, + .xfer = mxc_spi_xfer, + .set_speed = mxc_spi_set_speed, + .set_mode = mxc_spi_set_mode, +}; + +static const struct udevice_id mxc_spi_ids[] = { + { .compatible = "fsl,imx51-ecspi" }, + { } +}; + +U_BOOT_DRIVER(mxc_spi) = { + .name = "mxc_spi", + .id = UCLASS_SPI, + .of_match = mxc_spi_ids, + .ops = &mxc_spi_ops, + .platdata_auto_alloc_size = sizeof(struct mxc_spi_slave), + .probe = mxc_spi_probe, +}; +#endif diff --git a/drivers/sysreset/sysreset_sti.c b/drivers/sysreset/sysreset_sti.c index 9b58aa8e97b..bf698a737bd 100644 --- a/drivers/sysreset/sysreset_sti.c +++ b/drivers/sysreset/sysreset_sti.c @@ -39,7 +39,7 @@ static int sti_sysreset_probe(struct udevice *dev) "st,syscfg", NULL, 0, 0, &syscfg_phandle); if (ret < 0) { - error("Can't get syscfg phandle: %d\n", ret); + pr_err("Can't get syscfg phandle: %d\n", ret); return ret; } @@ -47,14 +47,14 @@ static int sti_sysreset_probe(struct udevice *dev) syscfg_phandle.node, &syscon); if (ret) { - error("%s: uclass_get_device_by_of_offset failed: %d\n", + pr_err("%s: uclass_get_device_by_of_offset failed: %d\n", __func__, ret); return ret; } regmap = syscon_get_regmap(syscon); if (!regmap) { - error("unable to get regmap for %s\n", syscon->name); + pr_err("unable to get regmap for %s\n", syscon->name); return -ENODEV; } diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c index 3818faeb462..3abce7f6786 100644 --- a/drivers/sysreset/sysreset_syscon.c +++ b/drivers/sysreset/sysreset_syscon.c @@ -45,13 +45,13 @@ int syscon_reboot_probe(struct udevice *dev) err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "regmap", &syscon); if (err) { - error("unable to find syscon device\n"); + pr_err("unable to find syscon device\n"); return err; } priv->regmap = syscon_get_regmap(syscon); if (!priv->regmap) { - error("unable to find regmap\n"); + pr_err("unable to find regmap\n"); return -ENODEV; } diff --git a/drivers/sysreset/sysreset_watchdog.c b/drivers/sysreset/sysreset_watchdog.c index 304ed052a2c..ab250aea292 100644 --- a/drivers/sysreset/sysreset_watchdog.c +++ b/drivers/sysreset/sysreset_watchdog.c @@ -38,7 +38,7 @@ int wdt_reboot_probe(struct udevice *dev) err = uclass_get_device_by_phandle(UCLASS_WDT, dev, "wdt", &priv->wdt); if (err) { - error("unable to find wdt device\n"); + pr_err("unable to find wdt device\n"); return err; } diff --git a/drivers/tpm/tpm_tis_infineon.c b/drivers/tpm/tpm_tis_infineon.c index ef3ff0dbf67..e3e20d89968 100644 --- a/drivers/tpm/tpm_tis_infineon.c +++ b/drivers/tpm/tpm_tis_infineon.c @@ -539,7 +539,7 @@ static int tpm_tis_i2c_init(struct udevice *dev) } if (chip->chip_type != UNKNOWN && vendor != expected_did_vid) { - error("Vendor id did not match! ID was %08x\n", vendor); + pr_err("Vendor id did not match! ID was %08x\n", vendor); return -ENODEV; } diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 62126aad2fb..e7658b4d95c 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -75,7 +75,7 @@ if USB_KEYBOARD choice prompt "USB keyboard polling" - optional + default SYS_USB_EVENT_POLL ---help--- Enable a polling mechanism for USB keyboard. diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index 35c2dc18d95..e8432bb016e 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -28,7 +28,7 @@ enum usb_dr_mode usb_get_dr_mode(int node) dr_mode = fdt_getprop(fdt, node, "dr_mode", NULL); if (!dr_mode) { - error("usb dr_mode not found\n"); + pr_err("usb dr_mode not found\n"); return USB_DR_MODE_UNKNOWN; } diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index a291ceb6ae0..ae7fc1c6304 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -37,6 +37,13 @@ config USB_DWC3_OMAP Say 'Y' here if you have one such device +config USB_DWC3_UNIPHIER + bool "DesignWare USB3 Host Support on UniPhier Platforms" + depends on ARCH_UNIPHIER && USB_XHCI_DWC3 + help + Support of USB2/3 functionality in Socionext UniPhier platforms. + Say 'Y' here if you have one such device. + menu "PHY Subsystem" config USB_DWC3_PHY_OMAP diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 2964bae0d8f..51497768b21 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -9,5 +9,6 @@ dwc3-y := core.o obj-$(CONFIG_USB_DWC3_GADGET) += gadget.o ep0.o obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o +obj-$(CONFIG_USB_DWC3_UNIPHIER) += dwc3-uniphier.o obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG) += samsung_usb_phy.o diff --git a/drivers/usb/dwc3/dwc3-uniphier.c b/drivers/usb/dwc3/dwc3-uniphier.c new file mode 100644 index 00000000000..0d13770d40e --- /dev/null +++ b/drivers/usb/dwc3/dwc3-uniphier.c @@ -0,0 +1,120 @@ +/* + * UniPhier Specific Glue Layer for DWC3 + * + * Copyright (C) 2016-2017 Socionext Inc. + * Author: Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/sizes.h> + +#define UNIPHIER_PRO4_DWC3_RESET 0x40 +#define UNIPHIER_PRO4_DWC3_RESET_XIOMMU BIT(5) +#define UNIPHIER_PRO4_DWC3_RESET_XLINK BIT(4) +#define UNIPHIER_PRO4_DWC3_RESET_PHY_SS BIT(2) + +#define UNIPHIER_PRO5_DWC3_RESET 0x00 +#define UNIPHIER_PRO5_DWC3_RESET_PHY_S1 BIT(17) +#define UNIPHIER_PRO5_DWC3_RESET_PHY_S0 BIT(16) +#define UNIPHIER_PRO5_DWC3_RESET_XLINK BIT(15) +#define UNIPHIER_PRO5_DWC3_RESET_XIOMMU BIT(14) + +#define UNIPHIER_PXS2_DWC3_RESET 0x00 +#define UNIPHIER_PXS2_DWC3_RESET_XLINK BIT(15) + +static int uniphier_pro4_dwc3_init(void __iomem *regs) +{ + u32 tmp; + + tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET); + tmp &= ~UNIPHIER_PRO4_DWC3_RESET_PHY_SS; + tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK; + writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET); + + return 0; +} + +static int uniphier_pro5_dwc3_init(void __iomem *regs) +{ + u32 tmp; + + tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET); + tmp &= ~(UNIPHIER_PRO5_DWC3_RESET_PHY_S1 | + UNIPHIER_PRO5_DWC3_RESET_PHY_S0); + tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU; + writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET); + + return 0; +} + +static int uniphier_pxs2_dwc3_init(void __iomem *regs) +{ + u32 tmp; + + tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET); + tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK; + writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET); + + return 0; +} + +static int uniphier_dwc3_probe(struct udevice *dev) +{ + fdt_addr_t base; + void __iomem *regs; + int (*init)(void __iomem *regs); + int ret; + + base = devfdt_get_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + regs = ioremap(base, SZ_32K); + if (!regs) + return -ENOMEM; + + init = (typeof(init))dev_get_driver_data(dev); + ret = init(regs); + if (ret) + dev_err(dev, "failed to init glue layer\n"); + + iounmap(regs); + + return ret; +} + +static const struct udevice_id uniphier_dwc3_match[] = { + { + .compatible = "socionext,uniphier-pro4-dwc3", + .data = (ulong)uniphier_pro4_dwc3_init, + }, + { + .compatible = "socionext,uniphier-pro5-dwc3", + .data = (ulong)uniphier_pro5_dwc3_init, + }, + { + .compatible = "socionext,uniphier-pxs2-dwc3", + .data = (ulong)uniphier_pxs2_dwc3_init, + }, + { + .compatible = "socionext,uniphier-ld20-dwc3", + .data = (ulong)uniphier_pxs2_dwc3_init, + }, + { + .compatible = "socionext,uniphier-pxs3-dwc3", + .data = (ulong)uniphier_pxs2_dwc3_init, + }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(usb_xhci) = { + .name = "uniphier-dwc3", + .id = UCLASS_SIMPLE_BUS, + .of_match = uniphier_dwc3_match, + .probe = uniphier_dwc3_probe, +}; diff --git a/drivers/usb/dwc3/linux-compat.h b/drivers/usb/dwc3/linux-compat.h index 9e944a31be1..5cbe377e3cd 100644 --- a/drivers/usb/dwc3/linux-compat.h +++ b/drivers/usb/dwc3/linux-compat.h @@ -12,10 +12,8 @@ #ifndef __DWC3_LINUX_COMPAT__ #define __DWC3_LINUX_COMPAT__ -#define pr_debug(format) debug(format) #define WARN(val, format, arg...) debug(format, ##arg) #define dev_WARN(dev, format, arg...) debug(format, ##arg) -#define WARN_ON_ONCE(val) debug("Error %d\n", val) static inline size_t strlcat(char *dest, const char *src, size_t n) { diff --git a/drivers/usb/emul/sandbox_flash.c b/drivers/usb/emul/sandbox_flash.c index 98d20c0bc15..2f84b360ec6 100644 --- a/drivers/usb/emul/sandbox_flash.c +++ b/drivers/usb/emul/sandbox_flash.c @@ -390,8 +390,7 @@ static int sandbox_flash_bind(struct udevice *dev) fs[2].id = STRINGID_SERIAL; fs[2].s = dev->name; - return usb_emul_setup_device(dev, PACKET_SIZE_64, plat->flash_strings, - flash_desc_list); + return usb_emul_setup_device(dev, plat->flash_strings, flash_desc_list); } static int sandbox_flash_probe(struct udevice *dev) diff --git a/drivers/usb/emul/sandbox_hub.c b/drivers/usb/emul/sandbox_hub.c index 1432858fd59..9a0f47b81c4 100644 --- a/drivers/usb/emul/sandbox_hub.c +++ b/drivers/usb/emul/sandbox_hub.c @@ -121,9 +121,12 @@ struct sandbox_hub_priv { int change[SANDBOX_NUM_PORTS]; }; -static struct udevice *hub_find_device(struct udevice *hub, int port) +static struct udevice *hub_find_device(struct udevice *hub, int port, + enum usb_device_speed *speed) { struct udevice *dev; + struct usb_generic_descriptor **gen_desc; + struct usb_device_descriptor **dev_desc; for (device_find_first_child(hub, &dev); dev; @@ -131,8 +134,27 @@ static struct udevice *hub_find_device(struct udevice *hub, int port) struct sandbox_hub_platdata *plat; plat = dev_get_parent_platdata(dev); - if (plat->port == port) + if (plat->port == port) { + gen_desc = plat->plat.desc_list; + gen_desc = usb_emul_find_descriptor(gen_desc, + USB_DT_DEVICE, 0); + dev_desc = (struct usb_device_descriptor **)gen_desc; + + switch (le16_to_cpu((*dev_desc)->bcdUSB)) { + case 0x0100: + *speed = USB_SPEED_LOW; + break; + case 0x0101: + *speed = USB_SPEED_FULL; + break; + case 0x0200: + default: + *speed = USB_SPEED_HIGH; + break; + } + return dev; + } } return NULL; @@ -146,7 +168,8 @@ static int clrset_post_state(struct udevice *hub, int port, int clear, int set) int ret = 0; if ((clear | set) & USB_PORT_STAT_POWER) { - struct udevice *dev = hub_find_device(hub, port); + enum usb_device_speed speed; + struct udevice *dev = hub_find_device(hub, port, &speed); if (dev) { if (set & USB_PORT_STAT_POWER) { @@ -156,6 +179,10 @@ static int clrset_post_state(struct udevice *hub, int port, int clear, int set) if (!ret) { set |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE; + if (speed == USB_SPEED_LOW) + set |= USB_PORT_STAT_LOW_SPEED; + else if (speed == USB_SPEED_HIGH) + set |= USB_PORT_STAT_HIGH_SPEED; } } else if (clear & USB_PORT_STAT_POWER) { @@ -274,15 +301,16 @@ static int sandbox_hub_submit_control_msg(struct udevice *bus, static int sandbox_hub_bind(struct udevice *dev) { - return usb_emul_setup_device(dev, PACKET_SIZE_64, hub_strings, - hub_desc_list); + return usb_emul_setup_device(dev, hub_strings, hub_desc_list); } static int sandbox_child_post_bind(struct udevice *dev) { struct sandbox_hub_platdata *plat = dev_get_parent_platdata(dev); + struct usb_emul_platdata *emul = dev_get_uclass_platdata(dev); plat->port = dev_read_u32_default(dev, "reg", -1); + emul->port1 = plat->port + 1; return 0; } diff --git a/drivers/usb/emul/sandbox_keyb.c b/drivers/usb/emul/sandbox_keyb.c index 27359851df8..cff017668f2 100644 --- a/drivers/usb/emul/sandbox_keyb.c +++ b/drivers/usb/emul/sandbox_keyb.c @@ -208,8 +208,7 @@ static int sandbox_keyb_bind(struct udevice *dev) fs[2].id = STRINGID_SERIAL; fs[2].s = dev->name; - return usb_emul_setup_device(dev, PACKET_SIZE_8, plat->keyb_strings, - keyb_desc_list); + return usb_emul_setup_device(dev, plat->keyb_strings, keyb_desc_list); } static int sandbox_keyb_probe(struct udevice *dev) diff --git a/drivers/usb/emul/usb-emul-uclass.c b/drivers/usb/emul/usb-emul-uclass.c index 6e03c1e0d9e..fbe11f31353 100644 --- a/drivers/usb/emul/usb-emul-uclass.c +++ b/drivers/usb/emul/usb-emul-uclass.c @@ -52,7 +52,7 @@ static int usb_emul_get_string(struct usb_string *strings, int index, return -EINVAL; } -static struct usb_generic_descriptor **find_descriptor( +struct usb_generic_descriptor **usb_emul_find_descriptor( struct usb_generic_descriptor **ptr, int type, int index) { debug("%s: type=%x, index=%d\n", __func__, type, index); @@ -91,8 +91,7 @@ static int usb_emul_get_descriptor(struct usb_dev_platdata *plat, int value, length); } - ptr = find_descriptor((struct usb_generic_descriptor **)plat->desc_list, - type, index); + ptr = usb_emul_find_descriptor(plat->desc_list, type, index); if (!ptr) { debug("%s: Could not find descriptor type %d, index %d\n", __func__, type, index); @@ -107,7 +106,7 @@ static int usb_emul_get_descriptor(struct usb_dev_platdata *plat, int value, return upto ? upto : length ? -EIO : 0; } -static int usb_emul_find_devnum(int devnum, struct udevice **emulp) +static int usb_emul_find_devnum(int devnum, int port1, struct udevice **emulp) { struct udevice *dev; struct uclass *uc; @@ -120,7 +119,37 @@ static int usb_emul_find_devnum(int devnum, struct udevice **emulp) uclass_foreach_dev(dev, uc) { struct usb_dev_platdata *udev = dev_get_parent_platdata(dev); - if (udev->devnum == devnum) { + /* + * devnum is initialzied to zero at the beginning of the + * enumeration process in usb_setup_device(). At this + * point, udev->devnum has not been assigned to any valid + * USB address either, so we can't rely on the comparison + * result between udev->devnum and devnum to select an + * emulator device. + */ + if (!devnum) { + struct usb_emul_platdata *plat; + + /* + * If the parent is sandbox USB controller, we are + * the root hub. And there is only one root hub + * in the system. + */ + if (device_get_uclass_id(dev->parent) == UCLASS_USB) { + debug("%s: Found emulator '%s'\n", + __func__, dev->name); + *emulp = dev; + return 0; + } + + plat = dev_get_uclass_platdata(dev); + if (plat->port1 == port1) { + debug("%s: Found emulator '%s', port %d\n", + __func__, dev->name, port1); + *emulp = dev; + return 0; + } + } else if (udev->devnum == devnum) { debug("%s: Found emulator '%s', addr %d\n", __func__, dev->name, udev->devnum); *emulp = dev; @@ -132,18 +161,19 @@ static int usb_emul_find_devnum(int devnum, struct udevice **emulp) return -ENOENT; } -int usb_emul_find(struct udevice *bus, ulong pipe, struct udevice **emulp) +int usb_emul_find(struct udevice *bus, ulong pipe, int port1, + struct udevice **emulp) { int devnum = usb_pipedevice(pipe); - return usb_emul_find_devnum(devnum, emulp); + return usb_emul_find_devnum(devnum, port1, emulp); } int usb_emul_find_for_dev(struct udevice *dev, struct udevice **emulp) { struct usb_dev_platdata *udev = dev_get_parent_platdata(dev); - return usb_emul_find_devnum(udev->devnum, emulp); + return usb_emul_find_devnum(udev->devnum, 0, emulp); } int usb_emul_control(struct udevice *emul, struct usb_device *udev, @@ -229,8 +259,8 @@ int usb_emul_int(struct udevice *emul, struct usb_device *udev, return ops->interrupt(emul, udev, pipe, buffer, length, interval); } -int usb_emul_setup_device(struct udevice *dev, int maxpacketsize, - struct usb_string *strings, void **desc_list) +int usb_emul_setup_device(struct udevice *dev, struct usb_string *strings, + void **desc_list) { struct usb_dev_platdata *plat = dev_get_parent_platdata(dev); struct usb_generic_descriptor **ptr; @@ -264,18 +294,11 @@ int usb_emul_setup_device(struct udevice *dev, int maxpacketsize, return 0; } -void usb_emul_reset(struct udevice *dev) -{ - struct usb_dev_platdata *plat = dev_get_parent_platdata(dev); - - plat->devnum = 0; - plat->configno = 0; -} - UCLASS_DRIVER(usb_emul) = { .id = UCLASS_USB_EMUL, .name = "usb_emul", .post_bind = dm_scan_fdt_dev, + .per_device_platdata_auto_alloc_size = sizeof(struct usb_emul_platdata), .per_child_auto_alloc_size = sizeof(struct usb_device), .per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata), }; diff --git a/drivers/usb/eth/mcs7830.c b/drivers/usb/eth/mcs7830.c index 4abef5d5c88..941d612a68a 100644 --- a/drivers/usb/eth/mcs7830.c +++ b/drivers/usb/eth/mcs7830.c @@ -418,25 +418,25 @@ static int mcs7830_basic_reset(struct usb_device *udev, rc = mcs7830_set_autoneg(udev); if (rc < 0) { - error("setting autoneg failed\n"); + pr_err("setting autoneg failed\n"); return rc; } rc = mcs7830_write_mchash(udev, priv); if (rc < 0) { - error("failed to set multicast hash\n"); + pr_err("failed to set multicast hash\n"); return rc; } rc = mcs7830_write_config(udev, priv); if (rc < 0) { - error("failed to set configuration\n"); + pr_err("failed to set configuration\n"); return rc; } rc = mcs7830_apply_fixup(udev); if (rc < 0) { - error("fixup application failed\n"); + pr_err("fixup application failed\n"); return rc; } @@ -541,11 +541,11 @@ static int mcs7830_recv_common(struct ueth_data *ueth, uint8_t *buf) debug("%s() RX want len %d, got len %d, rc %d\n", __func__, wantlen, gotlen, rc); if (rc != 0) { - error("RX: failed to receive\n"); + pr_err("RX: failed to receive\n"); return rc; } if (gotlen > wantlen) { - error("RX: got too many bytes (%d)\n", gotlen); + pr_err("RX: got too many bytes (%d)\n", gotlen); return -EIO; } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 225b66bc95f..102a63b8eeb 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -36,6 +36,30 @@ menuconfig USB_GADGET if USB_GADGET +config USB_GADGET_MANUFACTURER + string "Vendor name of the USB device" + default "Allwinner Technology" if ARCH_SUNXI + default "U-Boot" + help + Vendor name of the USB device emulated, reported to the host device. + This is usually either the manufacturer of the device or the SoC. + +config USB_GADGET_VENDOR_NUM + hex "Vendor ID of the USB device" + default 0x1f3a if ARCH_SUNXI + default 0x0 + help + Vendor ID of the USB device emulated, reported to the host device. + This is usually the board or SoC vendor's, unless you've registered + for one. + +config USB_GADGET_PRODUCT_NUM + hex "Product ID of the USB device" + default 0x1010 if ARCH_SUNXI + default 0x0 + help + Product ID of the USB device emulated, reported to the host device. + config USB_GADGET_ATMEL_USBA bool "Atmel USBA" select USB_GADGET_DUALSPEED @@ -110,19 +134,63 @@ config USB_FUNCTION_SDP allows to download images into memory and execute (jump to) them using the same protocol as implemented by the i.MX family's boot ROM. -config G_DNL_MANUFACTURER - string "Vendor name of USB device" +endif # USB_GADGET_DOWNLOAD -config G_DNL_VENDOR_NUM - hex "Vendor ID of USB device" +config USB_ETHER + bool "USB Ethernet Gadget" + default y if ARCH_SUNXI && USB_MUSB_GADGET + help + Creates an Ethernet network device through a USB peripheral + controller. This will create a network interface on both the device + (U-Boot) and the host (remote device) that can be used just like any + other nework interface. + It will bind on the peripheral USB controller, ignoring the USB hosts + controllers in the system. + +if USB_ETHER + +choice + prompt "USB Ethernet Gadget Model" + default USB_ETH_RNDIS + help + There is several models (protocols) to implement Ethernet over USB + devices. The main ones are Microsoft's RNDIS and USB's CDC-Ethernet + (also called CDC-ECM). RNDIS is obviously compatible with Windows, + while CDC-ECM is not. Most other operating systems support both, so + if inter-operability is a concern, RNDIS is to be preferred. + +config USB_ETH_CDC + bool "CDC-ECM Protocol" + help + CDC (Communications Device Class) is the standard for Ethernet over + USB devices. While there's several alternatives, the most widely used + protocol is ECM (Ethernet Control Model). However, compatibility with + Windows is not that great. + +config USB_ETH_RNDIS + bool "RNDIS Protocol" + help + The RNDIS (Remote Network Driver Interface Specification) is a + Microsoft proprietary protocol to create an Ethernet device over USB. + Windows obviously supports it, as well as all the major operating + systems, so it's the best option for compatibility. -config G_DNL_PRODUCT_NUM - hex "Product ID of USB device" +endchoice config USBNET_DEVADDR string "USB Gadget Ethernet device mac address" default "de:ad:be:ef:00:01" + help + Ethernet MAC address of the device-side (ie. local board's) MAC + address of the usb_ether interface -endif # USB_GADGET_DOWNLOAD +config USBNET_HOST_ADDR + string "USB Gadget Ethernet host mac address" + default "de:ad:be:ef:00:00" + help + Ethernet MAC address of the host-side (ie. remote device's) MAC + address of the usb_ether interface + +endif # USB_ETHER endif # USB_GADGET diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 9df6d32c65f..ad2f606b78b 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1456,7 +1456,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) ret = driver->bind(&udc->gadget); if (ret) { - error("driver->bind() returned %d\n", ret); + pr_err("driver->bind() returned %d\n", ret); udc->driver = NULL; } @@ -1468,7 +1468,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) struct at91_udc *udc = controller; if (!driver || !driver->unbind || !driver->disconnect) { - error("bad paramter\n"); + pr_err("bad paramter\n"); return -EINVAL; } diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index ad31703c737..c0a95a97c9f 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1228,7 +1228,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) ret = driver->bind(&udc->gadget); if (ret) { - error("driver->bind() returned %d\n", ret); + pr_err("driver->bind() returned %d\n", ret); udc->driver = NULL; } @@ -1240,7 +1240,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) struct usba_udc *udc = &controller; if (!driver || !driver->unbind || !driver->disconnect) { - error("bad paramter\n"); + pr_err("bad paramter\n"); return -EINVAL; } @@ -1261,7 +1261,7 @@ static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata, eps = malloc(sizeof(struct usba_ep) * pdata->num_ep); if (!eps) { - error("failed to alloc eps\n"); + pr_err("failed to alloc eps\n"); return NULL; } diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index cb44374e81a..088811c1913 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -835,7 +835,7 @@ int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata) ROUND(sizeof(struct usb_ctrlrequest), CONFIG_SYS_CACHELINE_SIZE)); if (!usb_ctrl) { - error("No memory available for UDC!\n"); + pr_err("No memory available for UDC!\n"); return -ENOMEM; } diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index 0d6d2fba8a0..b6164afa924 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -111,7 +111,8 @@ static int setdma_rx(struct dwc2_ep *ep, struct dwc2_request *req) ctrl = readl(®->out_endp[ep_num].doepctl); invalidate_dcache_range((unsigned long) ep->dma_buf, - (unsigned long) ep->dma_buf + ep->len); + (unsigned long) ep->dma_buf + + ROUND(ep->len, CONFIG_SYS_CACHELINE_SIZE)); writel((unsigned int) ep->dma_buf, ®->out_endp[ep_num].doepdma); writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length), diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 2cf5c8d31e2..a80486e91f1 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -273,8 +273,8 @@ static inline int BITRATE(struct usb_gadget *g) * static ushort idProduct; */ -#if defined(CONFIG_USBNET_MANUFACTURER) -static char *iManufacturer = CONFIG_USBNET_MANUFACTURER; +#if defined(CONFIG_USB_GADGET_MANUFACTURER) +static char *iManufacturer = CONFIG_USB_GADGET_MANUFACTURER; #else static char *iManufacturer = "U-Boot"; #endif @@ -1059,7 +1059,7 @@ static int eth_set_config(struct eth_dev *dev, unsigned number, && dev->config && dev->tx_qlen != 0) { /* tx fifo is full, but we can't clear it...*/ - error("can't change configurations"); + pr_err("can't change configurations"); return -ESPIPE; } eth_reset_config(dev); @@ -1233,7 +1233,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ status = rndis_msg_parser(dev->rndis_config, (u8 *) req->buf); if (status < 0) - error("%s: rndis parse error %d", __func__, status); + pr_err("%s: rndis parse error %d", __func__, status); } #endif /* RNDIS */ @@ -1554,7 +1554,7 @@ static int rx_submit(struct eth_dev *dev, struct usb_request *req, retval = usb_ep_queue(dev->out_ep, req, gfp_flags); if (retval) - error("rx submit --> %d", retval); + pr_err("rx submit --> %d", retval); return retval; } @@ -1624,7 +1624,7 @@ static int alloc_requests(struct eth_dev *dev, unsigned n, gfp_t gfp_flags) fail2: usb_ep_free_request(dev->in_ep, dev->tx_req); fail1: - error("can't alloc requests"); + pr_err("can't alloc requests"); return -1; } @@ -2060,7 +2060,7 @@ static int eth_bind(struct usb_gadget *gadget) * anything less functional on CDC-capable hardware, * so we fail in this case. */ - error("controller '%s' not recognized", + pr_err("controller '%s' not recognized", gadget->name); return -ENODEV; } @@ -2073,11 +2073,11 @@ static int eth_bind(struct usb_gadget *gadget) * to choose the right configuration otherwise. */ if (rndis) { -#if defined(CONFIG_USB_RNDIS_VENDOR_ID) && defined(CONFIG_USB_RNDIS_PRODUCT_ID) +#if defined(CONFIG_USB_GADGET_VENDOR_NUM) && defined(CONFIG_USB_GADGET_PRODUCT_NUM) device_desc.idVendor = - __constant_cpu_to_le16(CONFIG_USB_RNDIS_VENDOR_ID); + __constant_cpu_to_le16(CONFIG_USB_GADGET_VENDOR_NUM); device_desc.idProduct = - __constant_cpu_to_le16(CONFIG_USB_RNDIS_PRODUCT_ID); + __constant_cpu_to_le16(CONFIG_USB_GADGET_PRODUCT_NUM); #else device_desc.idVendor = __constant_cpu_to_le16(RNDIS_VENDOR_NUM); @@ -2092,9 +2092,9 @@ static int eth_bind(struct usb_gadget *gadget) * supporting one submode of the "SAFE" variant of MDLM.) */ } else { -#if defined(CONFIG_USB_CDC_VENDOR_ID) && defined(CONFIG_USB_CDC_PRODUCT_ID) - device_desc.idVendor = cpu_to_le16(CONFIG_USB_CDC_VENDOR_ID); - device_desc.idProduct = cpu_to_le16(CONFIG_USB_CDC_PRODUCT_ID); +#if defined(CONFIG_USB_GADGET_VENDOR_NUM) && defined(CONFIG_USB_GADGET_PRODUCT_NUM) + device_desc.idVendor = cpu_to_le16(CONFIG_USB_GADGET_VENDOR_NUM); + device_desc.idProduct = cpu_to_le16(CONFIG_USB_GADGET_PRODUCT_NUM); #else if (!cdc) { device_desc.idVendor = @@ -2121,7 +2121,7 @@ static int eth_bind(struct usb_gadget *gadget) in_ep = usb_ep_autoconfig(gadget, &fs_source_desc); if (!in_ep) { autoconf_fail: - error("can't autoconfigure on %s\n", + pr_err("can't autoconfigure on %s\n", gadget->name); return -ENODEV; } @@ -2142,7 +2142,7 @@ autoconf_fail: if (status_ep) { status_ep->driver_data = status_ep; /* claim */ } else if (rndis) { - error("can't run RNDIS on %s", gadget->name); + pr_err("can't run RNDIS on %s", gadget->name); return -ENODEV; #ifdef CONFIG_USB_ETH_CDC } else if (cdc) { @@ -2244,7 +2244,7 @@ autoconf_fail: if (rndis) { status = rndis_init(); if (status < 0) { - error("can't init RNDIS, %d", status); + pr_err("can't init RNDIS, %d", status); goto fail; } } @@ -2335,7 +2335,7 @@ fail0: return 0; fail: - error("%s failed, status = %d", __func__, status); + pr_err("%s failed, status = %d", __func__, status); eth_unbind(gadget); return status; } @@ -2350,7 +2350,7 @@ int dm_usb_init(struct eth_dev *e_dev) ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev); if (!dev || ret) { - error("No USB device found\n"); + pr_err("No USB device found\n"); return -ENODEV; } @@ -2369,7 +2369,7 @@ static int _usb_eth_init(struct ether_priv *priv) #ifdef CONFIG_DM_USB if (dm_usb_init(dev)) { - error("USB ether not found\n"); + pr_err("USB ether not found\n"); return -ENODEV; } #else @@ -2393,11 +2393,11 @@ static int _usb_eth_init(struct ether_priv *priv) sizeof(host_addr)); if (!is_eth_addr_valid(dev_addr)) { - error("Need valid 'usbnet_devaddr' to be set"); + pr_err("Need valid 'usbnet_devaddr' to be set"); goto fail; } if (!is_eth_addr_valid(host_addr)) { - error("Need valid 'usbnet_hostaddr' to be set"); + pr_err("Need valid 'usbnet_hostaddr' to be set"); goto fail; } @@ -2427,7 +2427,7 @@ static int _usb_eth_init(struct ether_priv *priv) while (!dev->network_started) { /* Handle control-c and timeouts */ if (ctrlc() || (get_timer(ts) > timeout)) { - error("The remote end did not respond in time."); + pr_err("The remote end did not respond in time."); goto fail; } usb_gadget_handle_interrupts(0); @@ -2456,7 +2456,7 @@ static int _usb_eth_send(struct ether_priv *priv, void *packet, int length) rndis_pkt = malloc(length + sizeof(struct rndis_packet_msg_type)); if (!rndis_pkt) { - error("No memory to alloc RNDIS packet"); + pr_err("No memory to alloc RNDIS packet"); goto drop; } rndis_add_hdr(rndis_pkt, length); @@ -2574,7 +2574,7 @@ static int usb_eth_recv(struct eth_device *netdev) ret = _usb_eth_recv(priv); if (ret) { - error("error packet receive\n"); + pr_err("error packet receive\n"); return ret; } @@ -2585,7 +2585,7 @@ static int usb_eth_recv(struct eth_device *netdev) net_process_received_packet(net_rx_packets[0], dev->rx_req->length); } else { - error("dev->rx_req invalid"); + pr_err("dev->rx_req invalid"); } packet_received = 0; rx_submit(dev, dev->rx_req, 0); @@ -2641,7 +2641,7 @@ static int usb_eth_recv(struct udevice *dev, int flags, uchar **packetp) ret = _usb_eth_recv(priv); if (ret) { - error("error packet receive\n"); + pr_err("error packet receive\n"); return ret; } @@ -2650,7 +2650,7 @@ static int usb_eth_recv(struct udevice *dev, int flags, uchar **packetp) *packetp = (uchar *)net_rx_packets[0]; return ethdev->rx_req->length; } else { - error("dev->rx_req invalid"); + pr_err("dev->rx_req invalid"); return -EFAULT; } } @@ -2706,13 +2706,13 @@ int usb_ether_init(void) ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &usb_dev); if (!usb_dev || ret) { - error("No USB device found\n"); + pr_err("No USB device found\n"); return ret; } ret = device_bind_driver(usb_dev, "usb_ether", "usb_ether", &dev); if (!dev || ret) { - error("usb - not able to bind usb_ether device\n"); + pr_err("usb - not able to bind usb_ether device\n"); return ret; } diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index f3382a965be..7acffb6c87e 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -410,7 +410,7 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req) strsep(&cmd, ":"); if (!cmd) { - error("missing variable"); + pr_err("missing variable"); fastboot_tx_write_str("FAILmissing var"); return; } @@ -593,7 +593,7 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) strsep(&cmd, ":"); if (!cmd) { - error("missing partition name"); + pr_err("missing partition name"); fastboot_tx_write_str("FAILmissing partition name"); return; } @@ -645,7 +645,7 @@ static void cb_erase(struct usb_ep *ep, struct usb_request *req) strsep(&cmd, ":"); if (!cmd) { - error("missing partition name"); + pr_err("missing partition name"); fastboot_tx_write_str("FAILmissing partition name"); return; } @@ -718,7 +718,7 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) } if (!func_cb) { - error("unknown command: %.*s", req->actual, cmdbuf); + pr_err("unknown command: %.*s", req->actual, cmdbuf); fastboot_tx_write_str("FAILunknown command"); } else { if (req->actual < req->length) { @@ -726,7 +726,7 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) buf[req->actual] = 0; func_cb(ep, req); } else { - error("buffer overflow"); + pr_err("buffer overflow"); fastboot_tx_write_str("FAILbuffer overflow"); } } diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index 0fae66beaba..fd3da922a69 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -237,12 +237,12 @@ static void sdp_rx_command_complete(struct usb_ep *ep, struct usb_request *req) u8 report = data[0]; if (status != 0) { - error("Status: %d", status); + pr_err("Status: %d", status); return; } if (report != 1) { - error("Unexpected report %d", report); + pr_err("Unexpected report %d", report); return; } @@ -309,7 +309,7 @@ static void sdp_rx_command_complete(struct usb_ep *ep, struct usb_request *req) sdp->next_state = SDP_STATE_IDLE; break; default: - error("Unknown command: %04x\n", be16_to_cpu(cmd->cmd)); + pr_err("Unknown command: %04x\n", be16_to_cpu(cmd->cmd)); } } @@ -322,12 +322,12 @@ static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request *req) int datalen = req->length - 1; if (status != 0) { - error("Status: %d", status); + pr_err("Status: %d", status); return; } if (report != 2) { - error("Unexpected report %d", report); + pr_err("Unexpected report %d", report); return; } @@ -360,7 +360,7 @@ static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request *req) sdp->state = SDP_STATE_TX_SEC_CONF; break; default: - error("Invalid state: %d", sdp->state); + pr_err("Invalid state: %d", sdp->state); } } @@ -370,7 +370,7 @@ static void sdp_tx_complete(struct usb_ep *ep, struct usb_request *req) int status = req->status; if (status != 0) { - error("Status: %d", status); + pr_err("Status: %d", status); return; } @@ -393,7 +393,7 @@ static void sdp_tx_complete(struct usb_ep *ep, struct usb_request *req) sdp->state = SDP_STATE_IDLE; break; default: - error("Wrong State: %d", sdp->state); + pr_err("Wrong State: %d", sdp->state); sdp->state = SDP_STATE_IDLE; break; } diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index cd4d9e659a3..18f233ab587 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -174,7 +174,7 @@ static long long int download_head(unsigned long long total, transfer_buffer, THOR_STORE_UNIT_SIZE, (*cnt)++); if (ret) { - error("DFU write failed [%d] cnt: %d", + pr_err("DFU write failed [%d] cnt: %d", ret, *cnt); return ret; } @@ -218,20 +218,20 @@ static int download_tail(long long int left, int cnt) dfu_entity = dfu_get_entity(alt_setting_num); if (!dfu_entity) { - error("Alt setting: %d entity not found!\n", alt_setting_num); + pr_err("Alt setting: %d entity not found!\n", alt_setting_num); return -ENOENT; } transfer_buffer = dfu_get_buf(dfu_entity); if (!transfer_buffer) { - error("Transfer buffer not allocated!"); + pr_err("Transfer buffer not allocated!"); return -ENXIO; } if (left) { ret = dfu_write(dfu_entity, transfer_buffer, left, cnt++); if (ret) { - error("DFU write failed [%d]: left: %llu", ret, left); + pr_err("DFU write failed [%d]: left: %llu", ret, left); return ret; } } @@ -245,7 +245,7 @@ static int download_tail(long long int left, int cnt) */ ret = dfu_flush(dfu_entity, transfer_buffer, 0, cnt); if (ret) - error("DFU flush failed!"); + pr_err("DFU flush failed!"); return ret; } @@ -285,7 +285,7 @@ static long long int process_rqt_download(const struct rqt_box *rqt) alt_setting_num = dfu_get_alt(f_name); if (alt_setting_num < 0) { - error("Alt setting [%d] to write not found!", + pr_err("Alt setting [%d] to write not found!", alt_setting_num); rsp->ack = -ENODEV; ret = rsp->ack; @@ -311,7 +311,7 @@ static long long int process_rqt_download(const struct rqt_box *rqt) debug("DL EXIT\n"); break; default: - error("Operation not supported: %d", rqt->rqt_data); + pr_err("Operation not supported: %d", rqt->rqt_data); ret = -ENOTSUPP; } @@ -342,7 +342,7 @@ static int process_data(void) puts("RQT: UPLOAD not supported!\n"); break; default: - error("unknown request (%d)", rqt->rqt); + pr_err("unknown request (%d)", rqt->rqt); } return ret; @@ -541,7 +541,7 @@ static int thor_rx_data(void) status = usb_ep_queue(dev->out_ep, dev->out_req, 0); if (status) { - error("kill %s: resubmit %d bytes --> %d", + pr_err("kill %s: resubmit %d bytes --> %d", dev->out_ep->name, dev->out_req->length, status); usb_ep_set_halt(dev->out_ep); return -EAGAIN; @@ -575,7 +575,7 @@ static void thor_tx_data(unsigned char *data, int len) status = usb_ep_queue(dev->in_ep, dev->in_req, 0); if (status) { - error("kill %s: resubmit %d bytes --> %d", + pr_err("kill %s: resubmit %d bytes --> %d", dev->in_ep->name, dev->in_req->length, status); usb_ep_set_halt(dev->in_ep); } @@ -608,7 +608,7 @@ static void thor_rx_tx_complete(struct usb_ep *ep, struct usb_request *req) case -ESHUTDOWN: /* disconnect from host */ case -EREMOTEIO: /* short read */ case -EOVERFLOW: - error("ERROR:%d", status); + pr_err("ERROR:%d", status); break; } @@ -664,7 +664,7 @@ thor_func_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) break; default: - error("thor_setup: unknown request: %d", ctrl->bRequest); + pr_err("thor_setup: unknown request: %d", ctrl->bRequest); } if (value >= 0) { @@ -973,7 +973,7 @@ static int thor_func_set_alt(struct usb_function *f, debug("Communication Data interface\n"); result = thor_eps_setup(f); if (result) - error("%s: EPs setup failed!", __func__); + pr_err("%s: EPs setup failed!", __func__); dev->configuration_done = 1; break; } diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c index 039331a5afd..99d500a6af4 100644 --- a/drivers/usb/gadget/g_dnl.c +++ b/drivers/usb/gadget/g_dnl.c @@ -26,9 +26,9 @@ /* * One needs to define the following: - * CONFIG_G_DNL_VENDOR_NUM - * CONFIG_G_DNL_PRODUCT_NUM - * CONFIG_G_DNL_MANUFACTURER + * CONFIG_USB_GADGET_VENDOR_NUM + * CONFIG_USB_GADGET_PRODUCT_NUM + * CONFIG_USB_GADGET_MANUFACTURER * at e.g. ./configs/<board>_defconfig */ @@ -46,7 +46,7 @@ static const char product[] = "USB download gadget"; static char g_dnl_serial[MAX_STRING_SERIAL]; -static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER; +static const char manufacturer[] = CONFIG_USB_GADGET_MANUFACTURER; void g_dnl_set_serialnumber(char *s) { @@ -62,8 +62,8 @@ static struct usb_device_descriptor device_desc = { .bDeviceClass = USB_CLASS_PER_INTERFACE, .bDeviceSubClass = 0, /*0x02:CDC-modem , 0x00:CDC-serial*/ - .idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM), + .idVendor = __constant_cpu_to_le16(CONFIG_USB_GADGET_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16(CONFIG_USB_GADGET_PRODUCT_NUM), /* .iProduct = DYNAMIC */ /* .iSerialNumber = DYNAMIC */ .bNumConfigurations = 1, diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 64c42ac4715..1293e18f75e 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -179,7 +179,7 @@ static int dwc_vbus_supply_init(struct udevice *dev) ret = regulator_set_enable(vbus_supply, true); if (ret) { - error("Error enabling vbus supply\n"); + pr_err("Error enabling vbus supply\n"); return ret; } @@ -1245,7 +1245,7 @@ static int dwc2_usb_ofdata_to_platdata(struct udevice *dev) struct dwc2_priv *priv = dev_get_priv(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; priv->regs = (struct dwc2_core_regs *)addr; diff --git a/drivers/usb/host/dwc3-sti-glue.c b/drivers/usb/host/dwc3-sti-glue.c index 02ad3115df4..6dc656af89b 100644 --- a/drivers/usb/host/dwc3-sti-glue.c +++ b/drivers/usb/host/dwc3-sti-glue.c @@ -71,7 +71,7 @@ static int sti_dwc3_glue_drd_init(struct sti_dwc3_glue_platdata *plat) break; default: - error("Unsupported mode of operation %d\n", plat->mode); + pr_err("Unsupported mode of operation %d\n", plat->mode); return -EINVAL; } writel(val, plat->syscfg_base + plat->syscfg_offset); @@ -113,7 +113,7 @@ static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev) ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), "reg", reg, ARRAY_SIZE(reg)); if (ret) { - error("unable to find st,stih407-dwc3 reg property(%d)\n", ret); + pr_err("unable to find st,stih407-dwc3 reg property(%d)\n", ret); return ret; } @@ -124,14 +124,14 @@ static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev) ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "st,syscfg", &syscon); if (ret) { - error("unable to find syscon device (%d)\n", ret); + pr_err("unable to find syscon device (%d)\n", ret); return ret; } /* get syscfg-reg base address */ regmap = syscon_get_regmap(syscon); if (!regmap) { - error("unable to find regmap\n"); + pr_err("unable to find regmap\n"); return -ENODEV; } plat->syscfg_base = regmap->base; @@ -139,14 +139,14 @@ static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev) /* get powerdown reset */ ret = reset_get_by_name(dev, "powerdown", &plat->powerdown_ctl); if (ret) { - error("can't get powerdown reset for %s (%d)", dev->name, ret); + pr_err("can't get powerdown reset for %s (%d)", dev->name, ret); return ret; } /* get softreset reset */ ret = reset_get_by_name(dev, "softreset", &plat->softreset_ctl); if (ret) - error("can't get soft reset for %s (%d)", dev->name, ret); + pr_err("can't get soft reset for %s (%d)", dev->name, ret); return ret; }; @@ -159,14 +159,14 @@ static int sti_dwc3_glue_bind(struct udevice *dev) /* check if one subnode is present */ dwc3_node = fdt_first_subnode(gd->fdt_blob, dev_of_offset(dev)); if (dwc3_node <= 0) { - error("Can't find subnode for %s\n", dev->name); + pr_err("Can't find subnode for %s\n", dev->name); return -ENODEV; } /* check if the subnode compatible string is the dwc3 one*/ if (fdt_node_check_compatible(gd->fdt_blob, dwc3_node, "snps,dwc3") != 0) { - error("Can't find dwc3 subnode for %s\n", dev->name); + pr_err("Can't find dwc3 subnode for %s\n", dev->name); return -ENODEV; } @@ -187,13 +187,13 @@ static int sti_dwc3_glue_probe(struct udevice *dev) /* deassert both powerdown and softreset */ ret = reset_deassert(&plat->powerdown_ctl); if (ret < 0) { - error("DWC3 powerdown reset deassert failed: %d", ret); + pr_err("DWC3 powerdown reset deassert failed: %d", ret); return ret; } ret = reset_deassert(&plat->softreset_ctl); if (ret < 0) { - error("DWC3 soft reset deassert failed: %d", ret); + pr_err("DWC3 soft reset deassert failed: %d", ret); goto softreset_err; } @@ -208,14 +208,14 @@ static int sti_dwc3_glue_probe(struct udevice *dev) init_err: ret = reset_assert(&plat->softreset_ctl); if (ret < 0) { - error("DWC3 soft reset deassert failed: %d", ret); + pr_err("DWC3 soft reset deassert failed: %d", ret); return ret; } softreset_err: ret = reset_assert(&plat->powerdown_ctl); if (ret < 0) - error("DWC3 powerdown reset deassert failed: %d", ret); + pr_err("DWC3 powerdown reset deassert failed: %d", ret); return ret; } @@ -228,13 +228,13 @@ static int sti_dwc3_glue_remove(struct udevice *dev) /* assert both powerdown and softreset */ ret = reset_assert(&plat->powerdown_ctl); if (ret < 0) { - error("DWC3 powerdown reset deassert failed: %d", ret); + pr_err("DWC3 powerdown reset deassert failed: %d", ret); return ret; } ret = reset_assert(&plat->softreset_ctl); if (ret < 0) - error("DWC3 soft reset deassert failed: %d", ret); + pr_err("DWC3 soft reset deassert failed: %d", ret); return ret; } diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index 03f8d321af1..1cb92c03387 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -51,7 +51,7 @@ static int ehci_usb_probe(struct udevice *dev) break; err = clk_enable(&priv->clocks[i]); if (err) { - error("failed to enable clock %d\n", i); + pr_err("failed to enable clock %d\n", i); clk_free(&priv->clocks[i]); goto clk_err; } @@ -59,7 +59,7 @@ static int ehci_usb_probe(struct udevice *dev) } } else { if (clock_nb != -ENOENT) { - error("failed to get clock phandle(%d)\n", clock_nb); + pr_err("failed to get clock phandle(%d)\n", clock_nb); return clock_nb; } } @@ -80,7 +80,7 @@ static int ehci_usb_probe(struct udevice *dev) break; if (reset_deassert(&priv->resets[i])) { - error("failed to deassert reset %d\n", i); + pr_err("failed to deassert reset %d\n", i); reset_free(&priv->resets[i]); goto reset_err; } @@ -88,7 +88,7 @@ static int ehci_usb_probe(struct udevice *dev) } } else { if (reset_nb != -ENOENT) { - error("failed to get reset phandle(%d)\n", reset_nb); + pr_err("failed to get reset phandle(%d)\n", reset_nb); goto clk_err; } } @@ -96,19 +96,19 @@ static int ehci_usb_probe(struct udevice *dev) err = generic_phy_get_by_index(dev, 0, &priv->phy); if (err) { if (err != -ENOENT) { - error("failed to get usb phy\n"); + pr_err("failed to get usb phy\n"); goto reset_err; } } else { err = generic_phy_init(&priv->phy); if (err) { - error("failed to init usb phy\n"); + pr_err("failed to init usb phy\n"); goto reset_err; } } - hccr = map_physmem(devfdt_get_addr(dev), 0x100, MAP_NOCACHE); + hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); hcor = (struct ehci_hcor *)((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); @@ -122,17 +122,17 @@ phy_err: if (generic_phy_valid(&priv->phy)) { ret = generic_phy_exit(&priv->phy); if (ret) - error("failed to release phy\n"); + pr_err("failed to release phy\n"); } reset_err: ret = reset_release_all(priv->resets, priv->reset_count); if (ret) - error("failed to assert all resets\n"); + pr_err("failed to assert all resets\n"); clk_err: ret = clk_release_all(priv->clocks, priv->clock_count); if (ret) - error("failed to disable all clocks\n"); + pr_err("failed to disable all clocks\n"); return err; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 3243c1d1cf2..be3e842dcc3 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1596,6 +1596,17 @@ static int ehci_destroy_int_queue(struct udevice *dev, struct usb_device *udev, return _ehci_destroy_int_queue(udev, queue); } +static int ehci_get_max_xfer_size(struct udevice *dev, size_t *size) +{ + /* + * EHCD can handle any transfer length as long as there is enough + * free heap space left, hence set the theoretical max number here. + */ + *size = SIZE_MAX; + + return 0; +} + int ehci_register(struct udevice *dev, struct ehci_hccr *hccr, struct ehci_hcor *hcor, const struct ehci_ops *ops, uint tweaks, enum usb_init_type init) @@ -1658,6 +1669,7 @@ struct dm_usb_ops ehci_usb_ops = { .create_int_queue = ehci_create_int_queue, .poll_int_queue = ehci_poll_int_queue, .destroy_int_queue = ehci_destroy_int_queue, + .get_max_xfer_size = ehci_get_max_xfer_size, }; #endif diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index e22ee979391..bf55a71d66c 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -47,14 +47,14 @@ static int ohci_usb_probe(struct udevice *dev) err = clk_enable(&priv->clocks[i]); if (err) { - error("failed to enable clock %d\n", i); + pr_err("failed to enable clock %d\n", i); clk_free(&priv->clocks[i]); goto clk_err; } priv->clock_count++; } } else if (clock_nb != -ENOENT) { - error("failed to get clock phandle(%d)\n", clock_nb); + pr_err("failed to get clock phandle(%d)\n", clock_nb); return clock_nb; } @@ -74,28 +74,28 @@ static int ohci_usb_probe(struct udevice *dev) err = reset_deassert(&priv->resets[i]); if (err) { - error("failed to deassert reset %d\n", i); + pr_err("failed to deassert reset %d\n", i); reset_free(&priv->resets[i]); goto reset_err; } priv->reset_count++; } } else if (reset_nb != -ENOENT) { - error("failed to get reset phandle(%d)\n", reset_nb); + pr_err("failed to get reset phandle(%d)\n", reset_nb); goto clk_err; } err = generic_phy_get_by_index(dev, 0, &priv->phy); if (err) { if (err != -ENOENT) { - error("failed to get usb phy\n"); + pr_err("failed to get usb phy\n"); goto reset_err; } } else { err = generic_phy_init(&priv->phy); if (err) { - error("failed to init usb phy\n"); + pr_err("failed to init usb phy\n"); goto reset_err; } } @@ -110,17 +110,17 @@ phy_err: if (generic_phy_valid(&priv->phy)) { ret = generic_phy_exit(&priv->phy); if (ret) - error("failed to release phy\n"); + pr_err("failed to release phy\n"); } reset_err: ret = reset_release_all(priv->resets, priv->reset_count); if (ret) - error("failed to assert all resets\n"); + pr_err("failed to assert all resets\n"); clk_err: ret = clk_release_all(priv->clocks, priv->clock_count); if (ret) - error("failed to disable all clocks\n"); + pr_err("failed to disable all clocks\n"); return err; } diff --git a/drivers/usb/host/usb-sandbox.c b/drivers/usb/host/usb-sandbox.c index 5e3d96c208e..15055b351a5 100644 --- a/drivers/usb/host/usb-sandbox.c +++ b/drivers/usb/host/usb-sandbox.c @@ -12,6 +12,10 @@ DECLARE_GLOBAL_DATA_PTR; +struct sandbox_usb_ctrl { + int rootdev; +}; + static void usbmon_trace(struct udevice *bus, ulong pipe, struct devrequest *setup, struct udevice *emul) { @@ -40,15 +44,24 @@ static int sandbox_submit_control(struct udevice *bus, void *buffer, int length, struct devrequest *setup) { + struct sandbox_usb_ctrl *ctrl = dev_get_priv(bus); struct udevice *emul; int ret; /* Just use child of dev as emulator? */ debug("%s: bus=%s\n", __func__, bus->name); - ret = usb_emul_find(bus, pipe, &emul); + ret = usb_emul_find(bus, pipe, udev->portnr, &emul); usbmon_trace(bus, pipe, setup, emul); if (ret) return ret; + + if (usb_pipedevice(pipe) == ctrl->rootdev) { + if (setup->request == USB_REQ_SET_ADDRESS) { + debug("%s: Set root hub's USB address\n", __func__); + ctrl->rootdev = le16_to_cpu(setup->value); + } + } + ret = usb_emul_control(emul, udev, pipe, buffer, length, setup); if (ret < 0) { debug("ret=%d\n", ret); @@ -70,7 +83,7 @@ static int sandbox_submit_bulk(struct udevice *bus, struct usb_device *udev, /* Just use child of dev as emulator? */ debug("%s: bus=%s\n", __func__, bus->name); - ret = usb_emul_find(bus, pipe, &emul); + ret = usb_emul_find(bus, pipe, udev->portnr, &emul); usbmon_trace(bus, pipe, NULL, emul); if (ret) return ret; @@ -96,7 +109,7 @@ static int sandbox_submit_int(struct udevice *bus, struct usb_device *udev, /* Just use child of dev as emulator? */ debug("%s: bus=%s\n", __func__, bus->name); - ret = usb_emul_find(bus, pipe, &emul); + ret = usb_emul_find(bus, pipe, udev->portnr, &emul); usbmon_trace(bus, pipe, NULL, emul); if (ret) return ret; @@ -107,6 +120,16 @@ static int sandbox_submit_int(struct udevice *bus, struct usb_device *udev, static int sandbox_alloc_device(struct udevice *dev, struct usb_device *udev) { + struct sandbox_usb_ctrl *ctrl = dev_get_priv(dev); + + /* + * Root hub will be the first device to be initailized. + * If this device is a root hub, initialize its device speed + * to high speed as we are a USB 2.0 controller. + */ + if (ctrl->rootdev == 0) + udev->speed = USB_SPEED_HIGH; + return 0; } @@ -133,4 +156,5 @@ U_BOOT_DRIVER(usb_sandbox) = { .of_match = sandbox_usb_ids, .probe = sandbox_usb_probe, .ops = &sandbox_usb_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_usb_ctrl), }; diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 0b8a501ce88..4e40f4bc3d2 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -150,9 +150,21 @@ int usb_update_hub_device(struct usb_device *udev) return ops->update_hub_device(bus, udev); } +int usb_get_max_xfer_size(struct usb_device *udev, size_t *size) +{ + struct udevice *bus = udev->controller_dev; + struct dm_usb_ops *ops = usb_get_ops(bus); + + if (!ops->get_max_xfer_size) + return -ENOSYS; + + return ops->get_max_xfer_size(bus, size); +} + int usb_stop(void) { struct udevice *bus; + struct udevice *rh; struct uclass *uc; struct usb_uclass_priv *uc_priv; int err = 0, ret; @@ -168,23 +180,20 @@ int usb_stop(void) ret = device_remove(bus, DM_REMOVE_NORMAL); if (ret && !err) err = ret; - } -#ifdef CONFIG_BLK - ret = blk_unbind_all(IF_TYPE_USB); - if (ret && !err) - err = ret; -#endif -#ifdef CONFIG_SANDBOX - struct udevice *dev; - /* Reset all enulation devices */ - ret = uclass_get(UCLASS_USB_EMUL, &uc); - if (ret) - return ret; + /* Locate root hub device */ + device_find_first_child(bus, &rh); + if (rh) { + /* + * All USB devices are children of root hub. + * Unbinding root hub will unbind all of its children. + */ + ret = device_unbind(rh); + if (ret && !err) + err = ret; + } + } - uclass_foreach_dev(dev, uc) - usb_emul_reset(dev); -#endif #ifdef CONFIG_USB_STORAGE usb_stor_reset(); #endif @@ -251,6 +260,21 @@ int usb_init(void) /* init low_level USB */ printf("USB%d: ", count); count++; + +#ifdef CONFIG_SANDBOX + /* + * For Sandbox, we need scan the device tree each time when we + * start the USB stack, in order to re-create the emulated USB + * devices and bind drivers for them before we actually do the + * driver probe. + */ + ret = dm_scan_fdt_dev(bus); + if (ret) { + printf("Sandbox USB device scan failed (%d)\n", ret); + continue; + } +#endif + ret = device_probe(bus); if (ret == -ENODEV) { /* No such device. */ puts("Port not available.\n"); diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 4191a894218..258d1cd00a0 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -128,13 +128,13 @@ static int xhci_dwc3_probe(struct udevice *dev) ret = generic_phy_get_by_index(dev, 0, &plat->usb_phy); if (ret) { if (ret != -ENOENT) { - error("Failed to get USB PHY for %s\n", dev->name); + pr_err("Failed to get USB PHY for %s\n", dev->name); return ret; } } else { ret = generic_phy_init(&plat->usb_phy); if (ret) { - error("Can't init USB PHY for %s\n", dev->name); + pr_err("Can't init USB PHY for %s\n", dev->name); return ret; } } @@ -161,7 +161,7 @@ static int xhci_dwc3_remove(struct udevice *dev) if (generic_phy_valid(&plat->usb_phy)) { ret = generic_phy_exit(&plat->usb_phy); if (ret) { - error("Can't deinit USB PHY for %s\n", dev->name); + pr_err("Can't deinit USB PHY for %s\n", dev->name); return ret; } } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d5eab3a6154..0582a9be40a 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -786,12 +786,22 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, #ifdef CONFIG_DM_USB /* Set up TT fields to support FS/LS devices */ if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) { - dev = dev_get_parent_priv(udev->dev); - if (dev->speed == USB_SPEED_HIGH) { - hub = dev_get_uclass_priv(udev->dev); + struct udevice *parent = udev->dev; + + dev = udev; + do { + port_num = dev->portnr; + dev = dev_get_parent_priv(parent); + if (usb_hub_is_root_hub(dev->dev)) + break; + parent = dev->dev->parent; + } while (dev->speed != USB_SPEED_HIGH); + + if (!usb_hub_is_root_hub(dev->dev)) { + hub = dev_get_uclass_priv(dev->dev); if (hub->tt.multi) slot_ctx->dev_info |= cpu_to_le32(DEV_MTT); - slot_ctx->tt_info |= cpu_to_le32(TT_PORT(udev->portnr)); + slot_ctx->tt_info |= cpu_to_le32(TT_PORT(port_num)); slot_ctx->tt_info |= cpu_to_le32(TT_SLOT(dev->slot_id)); } } @@ -840,6 +850,12 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, trb_64 = (uintptr_t)virt_dev->eps[0].ring->first_seg->trbs; ep0_ctx->deq = cpu_to_le64(trb_64 | virt_dev->eps[0].ring->cycle_state); + /* + * xHCI spec 6.2.3: + * software shall set 'Average TRB Length' to 8 for control endpoints. + */ + ep0_ctx->tx_info = cpu_to_le32(EP_AVG_TRB_LENGTH(8)); + /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ xhci_flush_cache((uintptr_t)ep0_ctx, sizeof(struct xhci_ep_ctx)); diff --git a/drivers/usb/host/xhci-rockchip.c b/drivers/usb/host/xhci-rockchip.c index ec55f4e59f7..b1f98842739 100644 --- a/drivers/usb/host/xhci-rockchip.c +++ b/drivers/usb/host/xhci-rockchip.c @@ -6,8 +6,6 @@ */ #include <common.h> #include <dm.h> -#include <fdtdec.h> -#include <libfdt.h> #include <malloc.h> #include <usb.h> #include <watchdog.h> @@ -46,9 +44,9 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) /* * Get the base address for XHCI controller from the device node */ - plat->hcd_base = devfdt_get_addr(dev); + plat->hcd_base = dev_read_addr(dev); if (plat->hcd_base == FDT_ADDR_T_NONE) { - error("Can't get the XHCI register base address\n"); + pr_err("Can't get the XHCI register base address\n"); return -ENXIO; } @@ -62,7 +60,7 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) } if (plat->phy_base == FDT_ADDR_T_NONE) { - error("Can't get the usbphy register address\n"); + pr_err("Can't get the usbphy register address\n"); return -ENXIO; } @@ -119,7 +117,7 @@ static int rockchip_xhci_core_init(struct rockchip_xhci *rkxhci, ret = dwc3_core_init(rkxhci->dwc3_reg); if (ret) { - error("failed to initialize core\n"); + pr_err("failed to initialize core\n"); return ret; } @@ -151,14 +149,14 @@ static int xhci_usb_probe(struct udevice *dev) if (plat->vbus_supply) { ret = regulator_set_enable(plat->vbus_supply, true); if (ret) { - error("XHCI: failed to set VBus supply\n"); + pr_err("XHCI: failed to set VBus supply\n"); return ret; } } ret = rockchip_xhci_core_init(ctx, dev); if (ret) { - error("XHCI: failed to initialize controller\n"); + pr_err("XHCI: failed to initialize controller\n"); return ret; } @@ -181,7 +179,7 @@ static int xhci_usb_remove(struct udevice *dev) if (plat->vbus_supply) { ret = regulator_set_enable(plat->vbus_supply, false); if (ret) - error("XHCI: failed to set VBus supply\n"); + pr_err("XHCI: failed to set VBus supply\n"); } return ret; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9b82ee5c602..4673738d1e8 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -257,6 +257,188 @@ static unsigned int xhci_get_ep_index(struct usb_endpoint_descriptor *desc) return index; } +/* + * Convert bInterval expressed in microframes (in 1-255 range) to exponent of + * microframes, rounded down to nearest power of 2. + */ +static unsigned int xhci_microframes_to_exponent(unsigned int desc_interval, + unsigned int min_exponent, + unsigned int max_exponent) +{ + unsigned int interval; + + interval = fls(desc_interval) - 1; + interval = clamp_val(interval, min_exponent, max_exponent); + if ((1 << interval) != desc_interval) + debug("rounding interval to %d microframes, "\ + "ep desc says %d microframes\n", + 1 << interval, desc_interval); + + return interval; +} + +static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + if (endpt_desc->bInterval == 0) + return 0; + + return xhci_microframes_to_exponent(endpt_desc->bInterval, 0, 15); +} + +static unsigned int xhci_parse_frame_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + return xhci_microframes_to_exponent(endpt_desc->bInterval * 8, 3, 10); +} + +/* + * Convert interval expressed as 2^(bInterval - 1) == interval into + * straight exponent value 2^n == interval. + */ +static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + unsigned int interval; + + interval = clamp_val(endpt_desc->bInterval, 1, 16) - 1; + if (interval != endpt_desc->bInterval - 1) + debug("ep %#x - rounding interval to %d %sframes\n", + endpt_desc->bEndpointAddress, 1 << interval, + udev->speed == USB_SPEED_FULL ? "" : "micro"); + + if (udev->speed == USB_SPEED_FULL) { + /* + * Full speed isoc endpoints specify interval in frames, + * not microframes. We are using microframes everywhere, + * so adjust accordingly. + */ + interval += 3; /* 1 frame = 2^3 uframes */ + } + + return interval; +} + +/* + * Return the polling or NAK interval. + * + * The polling interval is expressed in "microframes". If xHCI's Interval field + * is set to N, it will service the endpoint every 2^(Interval)*125us. + * + * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval + * is set to 0. + */ +static unsigned int xhci_get_endpoint_interval(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc) +{ + unsigned int interval = 0; + + switch (udev->speed) { + case USB_SPEED_HIGH: + /* Max NAK rate */ + if (usb_endpoint_xfer_control(endpt_desc) || + usb_endpoint_xfer_bulk(endpt_desc)) { + interval = xhci_parse_microframe_interval(udev, + endpt_desc); + break; + } + /* Fall through - SS and HS isoc/int have same decoding */ + + case USB_SPEED_SUPER: + if (usb_endpoint_xfer_int(endpt_desc) || + usb_endpoint_xfer_isoc(endpt_desc)) { + interval = xhci_parse_exponent_interval(udev, + endpt_desc); + } + break; + + case USB_SPEED_FULL: + if (usb_endpoint_xfer_isoc(endpt_desc)) { + interval = xhci_parse_exponent_interval(udev, + endpt_desc); + break; + } + /* + * Fall through for interrupt endpoint interval decoding + * since it uses the same rules as low speed interrupt + * endpoints. + */ + + case USB_SPEED_LOW: + if (usb_endpoint_xfer_int(endpt_desc) || + usb_endpoint_xfer_isoc(endpt_desc)) { + interval = xhci_parse_frame_interval(udev, endpt_desc); + } + break; + + default: + BUG(); + } + + return interval; +} + +/* + * The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps. + * High speed endpoint descriptors can define "the number of additional + * transaction opportunities per microframe", but that goes in the Max Burst + * endpoint context field. + */ +static u32 xhci_get_endpoint_mult(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc, + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc) +{ + if (udev->speed < USB_SPEED_SUPER || + !usb_endpoint_xfer_isoc(endpt_desc)) + return 0; + + return ss_ep_comp_desc->bmAttributes; +} + +static u32 xhci_get_endpoint_max_burst(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc, + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc) +{ + /* Super speed and Plus have max burst in ep companion desc */ + if (udev->speed >= USB_SPEED_SUPER) + return ss_ep_comp_desc->bMaxBurst; + + if (udev->speed == USB_SPEED_HIGH && + (usb_endpoint_xfer_isoc(endpt_desc) || + usb_endpoint_xfer_int(endpt_desc))) + return usb_endpoint_maxp_mult(endpt_desc) - 1; + + return 0; +} + +/* + * Return the maximum endpoint service interval time (ESIT) payload. + * Basically, this is the maxpacket size, multiplied by the burst size + * and mult size. + */ +static u32 xhci_get_max_esit_payload(struct usb_device *udev, + struct usb_endpoint_descriptor *endpt_desc, + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc) +{ + int max_burst; + int max_packet; + + /* Only applies for interrupt or isochronous endpoints */ + if (usb_endpoint_xfer_control(endpt_desc) || + usb_endpoint_xfer_bulk(endpt_desc)) + return 0; + + /* SuperSpeed Isoc ep with less than 48k per esit */ + if (udev->speed >= USB_SPEED_SUPER) + return le16_to_cpu(ss_ep_comp_desc->wBytesPerInterval); + + max_packet = usb_endpoint_maxp(endpt_desc); + max_burst = usb_endpoint_maxp_mult(endpt_desc); + + /* A 0 in max burst means 1 transfer per ESIT */ + return max_packet * max_burst; +} + /** * Issue a configure endpoint command or evaluate context command * and wait for it to finish. @@ -324,6 +506,12 @@ static int xhci_set_configuration(struct usb_device *udev) int slot_id = udev->slot_id; struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; struct usb_interface *ifdesc; + u32 max_esit_payload; + unsigned int interval; + unsigned int mult; + unsigned int max_burst; + unsigned int avg_trb_len; + unsigned int err_count = 0; out_ctx = virt_dev->out_ctx; in_ctx = virt_dev->in_ctx; @@ -357,10 +545,28 @@ static int xhci_set_configuration(struct usb_device *udev) /* filling up ep contexts */ for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) { struct usb_endpoint_descriptor *endpt_desc = NULL; + struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc = NULL; endpt_desc = &ifdesc->ep_desc[cur_ep]; + ss_ep_comp_desc = &ifdesc->ss_ep_comp_desc[cur_ep]; trb_64 = 0; + /* + * Get values to fill the endpoint context, mostly from ep + * descriptor. The average TRB buffer lengt for bulk endpoints + * is unclear as we have no clue on scatter gather list entry + * size. For Isoc and Int, set it to max available. + * See xHCI 1.1 spec 4.14.1.1 for details. + */ + max_esit_payload = xhci_get_max_esit_payload(udev, endpt_desc, + ss_ep_comp_desc); + interval = xhci_get_endpoint_interval(udev, endpt_desc); + mult = xhci_get_endpoint_mult(udev, endpt_desc, + ss_ep_comp_desc); + max_burst = xhci_get_endpoint_max_burst(udev, endpt_desc, + ss_ep_comp_desc); + avg_trb_len = max_esit_payload; + ep_index = xhci_get_ep_index(endpt_desc); ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index); @@ -372,20 +578,38 @@ static int xhci_set_configuration(struct usb_device *udev) /*NOTE: ep_desc[0] actually represents EP1 and so on */ dir = (((endpt_desc->bEndpointAddress) & (0x80)) >> 7); ep_type = (((endpt_desc->bmAttributes) & (0x3)) | (dir << 2)); + + ep_ctx[ep_index]->ep_info = + cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) | + EP_INTERVAL(interval) | EP_MULT(mult)); + ep_ctx[ep_index]->ep_info2 = cpu_to_le32(ep_type << EP_TYPE_SHIFT); ep_ctx[ep_index]->ep_info2 |= cpu_to_le32(MAX_PACKET (get_unaligned(&endpt_desc->wMaxPacketSize))); + /* Allow 3 retries for everything but isoc, set CErr = 3 */ + if (!usb_endpoint_xfer_isoc(endpt_desc)) + err_count = 3; ep_ctx[ep_index]->ep_info2 |= - cpu_to_le32(((0 & MAX_BURST_MASK) << MAX_BURST_SHIFT) | - ((3 & ERROR_COUNT_MASK) << ERROR_COUNT_SHIFT)); + cpu_to_le32(MAX_BURST(max_burst) | + ERROR_COUNT(err_count)); trb_64 = (uintptr_t) virt_dev->eps[ep_index].ring->enqueue; ep_ctx[ep_index]->deq = cpu_to_le64(trb_64 | virt_dev->eps[ep_index].ring->cycle_state); + + /* + * xHCI spec 6.2.3: + * 'Average TRB Length' should be 8 for control endpoints. + */ + if (usb_endpoint_xfer_control(endpt_desc)) + avg_trb_len = 8; + ep_ctx[ep_index]->tx_info = + cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) | + EP_AVG_TRB_LENGTH(avg_trb_len)); } return xhci_configure_endpoints(udev, false); @@ -546,16 +770,13 @@ int xhci_check_maxpacket(struct usb_device *udev) int max_packet_size; int hw_max_packet_size; int ret = 0; - struct usb_interface *ifdesc; - - ifdesc = &udev->config.if_desc[0]; out_ctx = ctrl->devs[slot_id]->out_ctx; xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size); ep_ctx = xhci_get_ep_ctx(ctrl, out_ctx, ep_index); hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); - max_packet_size = usb_endpoint_maxp(&ifdesc->ep_desc[0]); + max_packet_size = udev->epmaxpacketin[0]; if (hw_max_packet_size != max_packet_size) { debug("Max Packet Size for ep 0 changed.\n"); debug("Max packet size in usb_device = %d\n", max_packet_size); @@ -567,7 +788,8 @@ int xhci_check_maxpacket(struct usb_device *udev) ctrl->devs[slot_id]->out_ctx, ep_index); in_ctx = ctrl->devs[slot_id]->in_ctx; ep_ctx = xhci_get_ep_ctx(ctrl, in_ctx, ep_index); - ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK); + ep_ctx->ep_info2 &= cpu_to_le32(~((0xffff & MAX_PACKET_MASK) + << MAX_PACKET_SHIFT)); ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size)); /* @@ -890,11 +1112,18 @@ unknown: static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe, void *buffer, int length, int interval) { + if (usb_pipetype(pipe) != PIPE_INTERRUPT) { + printf("non-interrupt pipe (type=%lu)", usb_pipetype(pipe)); + return -EINVAL; + } + /* - * TODO: Not addressing any interrupt type transfer requests - * Add support for it later. + * xHCI uses normal TRBs for both bulk and interrupt. When the + * interrupt endpoint is to be serviced, the xHC will consume + * (at most) one TD. A TD (comprised of sg list entries) can + * take several service intervals to transmit. */ - return -EINVAL; + return xhci_bulk_tx(udev, pipe, length, buffer); } /** @@ -1228,6 +1457,20 @@ static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev) return xhci_configure_endpoints(udev, false); } +static int xhci_get_max_xfer_size(struct udevice *dev, size_t *size) +{ + /* + * xHCD allocates one segment which includes 64 TRBs for each endpoint + * and the last TRB in this segment is configured as a link TRB to form + * a TRB ring. Each TRB can transfer up to 64K bytes, however data + * buffers referenced by transfer TRBs shall not span 64KB boundaries. + * Hence the maximum number of TRBs we can use in one transfer is 62. + */ + *size = (TRBS_PER_SEGMENT - 2) * TRB_MAX_BUFF_SIZE; + + return 0; +} + int xhci_register(struct udevice *dev, struct xhci_hccr *hccr, struct xhci_hcor *hcor) { @@ -1281,6 +1524,7 @@ struct dm_usb_ops xhci_usb_ops = { .interrupt = xhci_submit_int_msg, .alloc_device = xhci_alloc_device, .update_hub_device = xhci_update_hub_device, + .get_max_xfer_size = xhci_get_max_xfer_size, }; #endif diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a497d9d830f..ba5f650144f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -663,8 +663,9 @@ struct xhci_ep_ctx { #define GET_MAX_PACKET(p) ((p) & 0x7ff) /* tx_info bitmasks */ -#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff) -#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16) +#define EP_AVG_TRB_LENGTH(p) ((p) & 0xffff) +#define EP_MAX_ESIT_PAYLOAD_LO(p) (((p) & 0xffff) << 16) +#define EP_MAX_ESIT_PAYLOAD_HI(p) ((((p) >> 16) & 0xff) << 24) #define CTX_TO_MAX_ESIT_PAYLOAD(p) (((p) >> 16) & 0xffff) /* deq bitmasks */ @@ -1045,9 +1046,9 @@ struct xhci_scratchpad { * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, * meaning 64 ring segments. * Initial allocated size of the ERST, in number of entries */ -#define ERST_NUM_SEGS 3 +#define ERST_NUM_SEGS 1 /* Initial number of event segment rings allocated */ -#define ERST_ENTRIES 3 +#define ERST_ENTRIES 1 /* Initial allocated size of the ERST, in number of entries */ #define ERST_SIZE 64 /* Poll every 60 seconds */ diff --git a/drivers/usb/musb-new/linux-compat.h b/drivers/usb/musb-new/linux-compat.h index 4dae83ed685..7bb53d2b198 100644 --- a/drivers/usb/musb-new/linux-compat.h +++ b/drivers/usb/musb-new/linux-compat.h @@ -5,8 +5,6 @@ #include <linux/list.h> #include <linux/compat.h> -#define pr_debug(fmt, args...) debug(fmt, ##args) - #define WARN(condition, fmt, args...) ({ \ int ret_warn = !!condition; \ if (ret_warn) \ diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c index 5c1a902e42d..7ee44ea9190 100644 --- a/drivers/usb/musb-new/sunxi.c +++ b/drivers/usb/musb-new/sunxi.c @@ -308,9 +308,6 @@ static struct musb_hdrc_platform_data musb_plat = { .platform_ops = &sunxi_musb_ops, }; -#ifdef CONFIG_USB_MUSB_HOST -static int musb_usb_remove(struct udevice *dev); - static int musb_usb_probe(struct udevice *dev) { struct musb_host_data *host = dev_get_priv(dev); @@ -319,16 +316,20 @@ static int musb_usb_probe(struct udevice *dev) priv->desc_before_addr = true; +#ifdef CONFIG_USB_MUSB_HOST host->host = musb_init_controller(&musb_plat, NULL, (void *)SUNXI_USB0_BASE); if (!host->host) return -EIO; ret = musb_lowlevel_init(host); - if (ret == 0) - printf("MUSB OTG\n"); - else - musb_usb_remove(dev); + if (!ret) + printf("Allwinner mUSB OTG (Host)\n"); +#else + ret = musb_register(&musb_plat, NULL, (void *)SUNXI_USB0_BASE); + if (!ret) + printf("Allwinner mUSB OTG (Peripheral)\n"); +#endif return ret; } @@ -352,30 +353,27 @@ static int musb_usb_remove(struct udevice *dev) return 0; } -U_BOOT_DRIVER(usb_musb) = { - .name = "sunxi-musb", - .id = UCLASS_USB, - .probe = musb_usb_probe, - .remove = musb_usb_remove, - .ops = &musb_usb_ops, - .platdata_auto_alloc_size = sizeof(struct usb_platdata), - .priv_auto_alloc_size = sizeof(struct musb_host_data), +static const struct udevice_id sunxi_musb_ids[] = { + { .compatible = "allwinner,sun4i-a10-musb" }, + { .compatible = "allwinner,sun6i-a31-musb" }, + { .compatible = "allwinner,sun8i-a33-musb" }, + { .compatible = "allwinner,sun8i-h3-musb" }, + { } }; -#endif -void sunxi_musb_board_init(void) -{ +U_BOOT_DRIVER(usb_musb) = { + .name = "sunxi-musb", #ifdef CONFIG_USB_MUSB_HOST - struct udevice *dev; - - /* - * Bind the driver directly for now as musb linux kernel support is - * still pending upstream so our dts files do not have the necessary - * nodes yet. TODO: Remove this as soon as the dts nodes are in place - * and bind by compatible instead. - */ - device_bind_driver(dm_root(), "sunxi-musb", "sunxi-musb", &dev); + .id = UCLASS_USB, #else - musb_register(&musb_plat, NULL, (void *)SUNXI_USB0_BASE); + .id = UCLASS_USB_DEV_GENERIC, #endif -} + .of_match = sunxi_musb_ids, + .probe = musb_usb_probe, + .remove = musb_usb_remove, +#ifdef CONFIG_USB_MUSB_HOST + .ops = &musb_usb_ops, +#endif + .platdata_auto_alloc_size = sizeof(struct usb_platdata), + .priv_auto_alloc_size = sizeof(struct musb_host_data), +}; diff --git a/drivers/usb/musb-new/ti-musb.c b/drivers/usb/musb-new/ti-musb.c index de101319cda..233857ad7a1 100644 --- a/drivers/usb/musb-new/ti-musb.c +++ b/drivers/usb/musb-new/ti-musb.c @@ -106,7 +106,7 @@ static int ti_musb_ofdata_to_platdata(struct udevice *dev) "mentor,multipoint", -1); if (platdata->musb_config.multipoint < 0) { - error("MUSB multipoint DT entry missing\n"); + pr_err("MUSB multipoint DT entry missing\n"); return -ENOENT; } @@ -115,14 +115,14 @@ static int ti_musb_ofdata_to_platdata(struct udevice *dev) platdata->musb_config.num_eps = fdtdec_get_int(fdt, node, "mentor,num-eps", -1); if (platdata->musb_config.num_eps < 0) { - error("MUSB num-eps DT entry missing\n"); + pr_err("MUSB num-eps DT entry missing\n"); return -ENOENT; } platdata->musb_config.ram_bits = fdtdec_get_int(fdt, node, "mentor,ram-bits", -1); if (platdata->musb_config.ram_bits < 0) { - error("MUSB ram-bits DT entry missing\n"); + pr_err("MUSB ram-bits DT entry missing\n"); return -ENOENT; } @@ -132,7 +132,7 @@ static int ti_musb_ofdata_to_platdata(struct udevice *dev) platdata->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1); if (platdata->plat.power < 0) { - error("MUSB mentor,power DT entry missing\n"); + pr_err("MUSB mentor,power DT entry missing\n"); return -ENOENT; } @@ -183,7 +183,7 @@ static int ti_musb_host_ofdata_to_platdata(struct udevice *dev) ret = ti_musb_ofdata_to_platdata(dev); if (ret) { - error("platdata dt parse error\n"); + pr_err("platdata dt parse error\n"); return ret; } @@ -229,7 +229,7 @@ static int ti_musb_wrapper_bind(struct udevice *parent) ret = device_bind_driver_to_node(parent, "ti-musb-host", name, offset_to_ofnode(node), &dev); if (ret) { - error("musb - not able to bind usb host node\n"); + pr_err("musb - not able to bind usb host node\n"); return ret; } break; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 7ba7b580db1..e6b7f11dc9d 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -65,6 +65,14 @@ config VIDEO_BPP32 this option, such displays will not be supported and console output will be empty. +config VIDEO_ANSI + bool "Support ANSI escape sequences in video console" + depends on DM_VIDEO + default y if DM_VIDEO + help + Enable ANSI escape sequence decoding for a more fully functional + console. + config CONSOLE_NORMAL bool "Support a simple text console" depends on DM_VIDEO diff --git a/drivers/video/am335x-fb.c b/drivers/video/am335x-fb.c index bb5cc9788ab..a8b3e747a03 100644 --- a/drivers/video/am335x-fb.c +++ b/drivers/video/am335x-fb.c @@ -128,7 +128,7 @@ int am335xfb_init(struct am335x_lcdpanel *panel) raster_ctrl |= LCD_TFT_24BPP_MODE; break; default: - error("am335x-fb: invalid bpp value: %d\n", panel->bpp); + pr_err("am335x-fb: invalid bpp value: %d\n", panel->bpp); return -1; } diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index b5afd72227c..5f63c12d6c5 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -9,6 +9,7 @@ */ #include <common.h> +#include <linux/ctype.h> #include <dm.h> #include <video.h> #include <video_console.h> @@ -107,12 +108,213 @@ static void vidconsole_newline(struct udevice *dev) video_sync(dev->parent); } +static const struct { + unsigned r; + unsigned g; + unsigned b; +} colors[] = { + { 0x00, 0x00, 0x00 }, /* black */ + { 0xff, 0x00, 0x00 }, /* red */ + { 0x00, 0xff, 0x00 }, /* green */ + { 0xff, 0xff, 0x00 }, /* yellow */ + { 0x00, 0x00, 0xff }, /* blue */ + { 0xff, 0x00, 0xff }, /* magenta */ + { 0x00, 0xff, 0xff }, /* cyan */ + { 0xff, 0xff, 0xff }, /* white */ +}; + +static void set_color(struct video_priv *priv, unsigned idx, unsigned *c) +{ + switch (priv->bpix) { + case VIDEO_BPP16: + *c = ((colors[idx].r >> 3) << 0) | + ((colors[idx].g >> 2) << 5) | + ((colors[idx].b >> 3) << 11); + break; + case VIDEO_BPP32: + *c = 0xff000000 | + (colors[idx].r << 0) | + (colors[idx].g << 8) | + (colors[idx].b << 16); + break; + default: + /* unsupported, leave current color in place */ + break; + } +} + +static char *parsenum(char *s, int *num) +{ + char *end; + *num = simple_strtol(s, &end, 10); + return end; +} + +/* + * Process a character while accumulating an escape string. Chars are + * accumulated into escape_buf until the end of escape sequence is + * found, at which point the sequence is parsed and processed. + */ +static void vidconsole_escape_char(struct udevice *dev, char ch) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + + if (!IS_ENABLED(CONFIG_VIDEO_ANSI)) + goto error; + + /* Sanity checking for bogus ESC sequences: */ + if (priv->escape_len >= sizeof(priv->escape_buf)) + goto error; + if (priv->escape_len == 0 && ch != '[') + goto error; + + priv->escape_buf[priv->escape_len++] = ch; + + /* + * Escape sequences are terminated by a letter, so keep + * accumulating until we get one: + */ + if (!isalpha(ch)) + return; + + /* + * clear escape mode first, otherwise things will get highly + * surprising if you hit any debug prints that come back to + * this console. + */ + priv->escape = 0; + + switch (ch) { + case 'H': + case 'f': { + int row, col; + char *s = priv->escape_buf; + + /* + * Set cursor position: [%d;%df or [%d;%dH + */ + s++; /* [ */ + s = parsenum(s, &row); + s++; /* ; */ + s = parsenum(s, &col); + + priv->ycur = row * priv->y_charsize; + priv->xcur_frac = priv->xstart_frac + + VID_TO_POS(col * priv->x_charsize); + + break; + } + case 'J': { + int mode; + + /* + * Clear part/all screen: + * [J or [0J - clear screen from cursor down + * [1J - clear screen from cursor up + * [2J - clear entire screen + * + * TODO we really only handle entire-screen case, others + * probably require some additions to video-uclass (and + * are not really needed yet by efi_console) + */ + parsenum(priv->escape_buf + 1, &mode); + + if (mode == 2) { + video_clear(dev->parent); + video_sync(dev->parent); + priv->ycur = 0; + priv->xcur_frac = priv->xstart_frac; + } else { + debug("unsupported clear mode: %d\n", mode); + } + break; + } + case 'm': { + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + char *s = priv->escape_buf; + char *end = &priv->escape_buf[priv->escape_len]; + + /* + * Set graphics mode: [%d;...;%dm + * + * Currently only supports the color attributes: + * + * Foreground Colors: + * + * 30 Black + * 31 Red + * 32 Green + * 33 Yellow + * 34 Blue + * 35 Magenta + * 36 Cyan + * 37 White + * + * Background Colors: + * + * 40 Black + * 41 Red + * 42 Green + * 43 Yellow + * 44 Blue + * 45 Magenta + * 46 Cyan + * 47 White + */ + + s++; /* [ */ + while (s < end) { + int val; + + s = parsenum(s, &val); + s++; + + switch (val) { + case 30 ... 37: + /* fg color */ + set_color(vid_priv, val - 30, + (unsigned *)&vid_priv->colour_fg); + break; + case 40 ... 47: + /* bg color */ + set_color(vid_priv, val - 40, + (unsigned *)&vid_priv->colour_bg); + break; + default: + /* unknown/unsupported */ + break; + } + } + + break; + } + default: + debug("unrecognized escape sequence: %*s\n", + priv->escape_len, priv->escape_buf); + } + + return; + +error: + /* something went wrong, just revert to normal mode: */ + priv->escape = 0; +} + int vidconsole_put_char(struct udevice *dev, char ch) { struct vidconsole_priv *priv = dev_get_uclass_priv(dev); int ret; + if (priv->escape) { + vidconsole_escape_char(dev, ch); + return 0; + } + switch (ch) { + case '\x1b': + priv->escape_len = 0; + priv->escape = 1; + break; case '\a': /* beep */ break; @@ -163,6 +365,7 @@ static void vidconsole_putc(struct stdio_dev *sdev, const char ch) struct udevice *dev = sdev->priv; vidconsole_put_char(dev, ch); + video_sync(dev->parent); } static void vidconsole_puts(struct stdio_dev *sdev, const char *s) @@ -260,6 +463,8 @@ static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc, for (s = argv[1]; *s; s++) vidconsole_put_char(dev, *s); + video_sync(dev->parent); + return 0; } diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index dfa39b0d1b8..dcaceed42c4 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -87,7 +87,7 @@ int video_reserve(ulong *addrp) return 0; } -static int video_clear(struct udevice *dev) +void video_clear(struct udevice *dev) { struct video_priv *priv = dev_get_uclass_priv(dev); @@ -100,8 +100,6 @@ static int video_clear(struct udevice *dev) } else { memset(priv->fb, priv->colour_bg, priv->fb_size); } - - return 0; } /* Flush video activity to the caches */ |