diff options
Diffstat (limited to 'drivers')
48 files changed, 1692 insertions, 333 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e3135bb75f..9a08575053 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1167,6 +1167,14 @@ int ahci_probe_scsi(struct udevice *ahci_dev, ulong base) if (ret) return ret; + /* + * scsi_scan_dev() scans devices up-to the number of max_id. + * Update max_id if the number of detected ports exceeds max_id. + * This allows SCSI to scan all detected ports. + */ + uc_plat->max_id = max_t(unsigned long, uc_priv->n_ports, + uc_plat->max_id); + return 0; } diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index c23b6682a6..baaf431e5e 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -208,11 +208,7 @@ int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) if (ret) return ret; - ret = blk_select_hwpart(dev, hwpart); - if (!ret) - blkcache_invalidate(if_type, devnum); - - return ret; + return blk_select_hwpart(dev, hwpart); } int blk_list_part(enum if_type if_type) @@ -352,13 +348,7 @@ int blk_select_hwpart(struct udevice *dev, int hwpart) int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) { - int ret; - - ret = blk_select_hwpart(desc->bdev, hwpart); - if (!ret) - blkcache_invalidate(desc->if_type, desc->devnum); - - return ret; + return blk_select_hwpart(desc->bdev, hwpart); } int blk_first_device(int if_type, struct udevice **devp) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index a3f0171b45..95fe0aea2c 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -48,7 +48,7 @@ config CLK_BOSTON config SPL_CLK_CCF bool "SPL Common Clock Framework [CCF] support " - depends on SPL_CLK_IMX6Q + depends on SPL help Enable this option if you want to (re-)use the Linux kernel's Common Clock Framework [CCF] code in U-Boot's SPL. @@ -62,7 +62,6 @@ config SPL_CLK_COMPOSITE_CCF config CLK_CCF bool "Common Clock Framework [CCF] support " - depends on CLK_IMX6Q || SANDBOX_CLK_CCF help Enable this option if you want to (re-)use the Linux kernel's Common Clock Framework [CCF] code in U-Boot's clock driver. diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index c66b6f3c4e..64c181f4ad 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -449,13 +449,45 @@ int clk_set_parent(struct clk *clk, struct clk *parent) int clk_enable(struct clk *clk) { const struct clk_ops *ops = clk_dev_ops(clk->dev); + struct clk *clkp = NULL; + int ret; debug("%s(clk=%p)\n", __func__, clk); - if (!ops->enable) - return -ENOSYS; + if (CONFIG_IS_ENABLED(CLK_CCF)) { + /* Take id 0 as a non-valid clk, such as dummy */ + if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + if (clkp->enable_count) { + clkp->enable_count++; + return 0; + } + if (clkp->dev->parent && + device_get_uclass_id(clkp->dev) == UCLASS_CLK) { + ret = clk_enable(dev_get_clk_ptr(clkp->dev->parent)); + if (ret) { + printf("Enable %s failed\n", + clkp->dev->parent->name); + return ret; + } + } + } - return ops->enable(clk); + if (ops->enable) { + ret = ops->enable(clk); + if (ret) { + printf("Enable %s failed\n", clk->dev->name); + return ret; + } + } + if (clkp) + clkp->enable_count++; + } else { + if (!ops->enable) + return -ENOSYS; + return ops->enable(clk); + } + + return 0; } int clk_enable_bulk(struct clk_bulk *bulk) @@ -474,13 +506,46 @@ int clk_enable_bulk(struct clk_bulk *bulk) int clk_disable(struct clk *clk) { const struct clk_ops *ops = clk_dev_ops(clk->dev); + struct clk *clkp = NULL; + int ret; debug("%s(clk=%p)\n", __func__, clk); - if (!ops->disable) - return -ENOSYS; + if (CONFIG_IS_ENABLED(CLK_CCF)) { + if (clk->id && !clk_get_by_id(clk->id, &clkp)) { + if (clkp->enable_count == 0) { + printf("clk %s already disabled\n", + clkp->dev->name); + return 0; + } - return ops->disable(clk); + if (--clkp->enable_count > 0) + return 0; + } + + if (ops->disable) { + ret = ops->disable(clk); + if (ret) + return ret; + } + + if (clkp && clkp->dev->parent && + device_get_uclass_id(clkp->dev) == UCLASS_CLK) { + ret = clk_disable(dev_get_clk_ptr(clkp->dev->parent)); + if (ret) { + printf("Disable %s failed\n", + clkp->dev->parent->name); + return ret; + } + } + } else { + if (!ops->disable) + return -ENOSYS; + + return ops->disable(clk); + } + + return 0; } int clk_disable_bulk(struct clk_bulk *bulk) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 39b3087067..1cf9987f6c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -40,6 +40,7 @@ int clk_register(struct clk *clk, const char *drv_name, return ret; } + clk->enable_count = 0; /* Store back pointer to clk from udevice */ clk->dev->uclass_priv = clk; diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index 08cce0d79b..f51126793e 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -27,6 +27,7 @@ static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev) /* Make fixed rate clock accessible from higher level struct clk */ dev->uclass_priv = clk; clk->dev = dev; + clk->enable_count = 0; return 0; } diff --git a/drivers/clk/clk_sandbox_ccf.c b/drivers/clk/clk_sandbox_ccf.c index e126f18d8e..9fa27229e1 100644 --- a/drivers/clk/clk_sandbox_ccf.c +++ b/drivers/clk/clk_sandbox_ccf.c @@ -25,6 +25,18 @@ struct clk_pllv3 { u32 div_shift; }; +int sandbox_clk_enable_count(struct clk *clk) +{ + struct clk *clkp = NULL; + int ret; + + ret = clk_get_by_id(clk->id, &clkp); + if (ret) + return 0; + + return clkp->enable_count; +} + static ulong clk_pllv3_get_rate(struct clk *clk) { unsigned long parent_rate = clk_get_parent_rate(clk); @@ -254,6 +266,9 @@ static int sandbox_clk_ccf_probe(struct udevice *dev) sandbox_clk_composite("i2c", i2c_sels, ARRAY_SIZE(i2c_sels), ®, 0)); + clk_dm(SANDBOX_CLK_I2C_ROOT, + sandbox_clk_gate2("i2c_root", "i2c", base + 0x7c, 0)); + return 0; } diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 5806d48696..e87307fa60 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -15,6 +15,8 @@ #include <dt-bindings/clock/stm32mp1-clks.h> #include <dt-bindings/clock/stm32mp1-clksrc.h> +DECLARE_GLOBAL_DATA_PTR; + #ifndef CONFIG_STM32MP1_TRUSTED #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) /* activate clock tree initialization in the driver */ @@ -759,9 +761,6 @@ static ulong stm32mp1_clk_get_fixed(struct stm32mp1_clk_priv *priv, int idx) return 0; } - debug("%s: clk id %d = %x : %ld kHz\n", __func__, idx, - (u32)priv->osc[idx], priv->osc[idx] / 1000); - return priv->osc[idx]; } @@ -863,8 +862,6 @@ static ulong pll_get_fref_ck(struct stm32mp1_clk_priv *priv, src = selr & RCC_SELR_SRC_MASK; refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]); - debug("PLL%d : selr=%x refclk = %d kHz\n", - pll_id, selr, (u32)(refclk / 1000)); return refclk; } @@ -889,9 +886,6 @@ static ulong pll_get_fvco(struct stm32mp1_clk_priv *priv, divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; - debug("PLL%d : cfgr1=%x fracr=%x DIVN=%d DIVM=%d\n", - pll_id, cfgr1, fracr, divn, divm); - refclk = pll_get_fref_ck(priv, pll_id); /* with FRACV : @@ -908,7 +902,6 @@ static ulong pll_get_fvco(struct stm32mp1_clk_priv *priv, } else { fvco = (ulong)(refclk * (divn + 1) / (divm + 1)); } - debug("PLL%d : %s = %ld\n", pll_id, __func__, fvco); return fvco; } @@ -921,17 +914,13 @@ static ulong stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv, ulong dfout; u32 cfgr2; - debug("%s(%d, %d)\n", __func__, pll_id, div_id); if (div_id >= _DIV_NB) return 0; cfgr2 = readl(priv->base + pll[pll_id].pllxcfgr2); divy = (cfgr2 >> RCC_PLLNCFGR2_SHIFT(div_id)) & RCC_PLLNCFGR2_DIVX_MASK; - debug("PLL%d : cfgr2=%x DIVY=%d\n", pll_id, cfgr2, divy); - dfout = pll_get_fvco(priv, pll_id) / (divy + 1); - debug(" => dfout = %d kHz\n", (u32)(dfout / 1000)); return dfout; } @@ -1574,9 +1563,6 @@ static void stgen_config(struct stm32mp1_clk_priv *priv) /* need to update gd->arch.timer_rate_hz with new frequency */ timer_init(); - pr_debug("gd->arch.timer_rate_hz = %x\n", - (u32)gd->arch.timer_rate_hz); - pr_debug("Tick = %x\n", (u32)(get_ticks())); } } @@ -1882,7 +1868,6 @@ static int pll_set_output_rate(struct udevice *dev, if (div > 128) div = 128; - debug("fvco = %ld, clk_rate = %ld, div=%d\n", fvco, clk_rate, div); /* stop the requested output */ clrbits_le32(pllxcr, 0x1 << div_id << RCC_PLLNCR_DIVEN_SHIFT); /* change divider */ @@ -1915,6 +1900,9 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate) } p = stm32mp1_clk_get_parent(priv, clk->id); +#ifdef DEBUG + debug("%s: parent = %d:%s\n", __func__, p, stm32mp1_clk_parent_name[p]); +#endif if (p < 0) return -EINVAL; @@ -1932,6 +1920,7 @@ static ulong stm32mp1_clk_set_rate(struct clk *clk, unsigned long clk_rate) return result; } #endif + case _PLL4_Q: /* for LTDC_PX and DSI_PX case */ return pll_set_output_rate(clk->dev, _PLL4, _DIV_Q, clk_rate); @@ -2055,22 +2044,22 @@ static int stm32mp1_clk_probe(struct udevice *dev) stm32mp1_clk_dump(priv); #endif + gd->cpu_clk = stm32mp1_clk_get(priv, _CK_MPU); + gd->bus_clk = stm32mp1_clk_get(priv, _ACLK); + /* DDRPHYC father */ + gd->mem_clk = stm32mp1_clk_get(priv, _PLL2_R); #if defined(CONFIG_DISPLAY_CPUINFO) if (gd->flags & GD_FLG_RELOC) { char buf[32]; printf("Clocks:\n"); - printf("- MPU : %s MHz\n", - strmhz(buf, stm32mp1_clk_get(priv, _CK_MPU))); + printf("- MPU : %s MHz\n", strmhz(buf, gd->cpu_clk)); printf("- MCU : %s MHz\n", strmhz(buf, stm32mp1_clk_get(priv, _CK_MCU))); - printf("- AXI : %s MHz\n", - strmhz(buf, stm32mp1_clk_get(priv, _ACLK))); + printf("- AXI : %s MHz\n", strmhz(buf, gd->bus_clk)); printf("- PER : %s MHz\n", strmhz(buf, stm32mp1_clk_get(priv, _CK_PER))); - /* DDRPHYC father */ - printf("- DDR : %s MHz\n", - strmhz(buf, stm32mp1_clk_get(priv, _PLL2_R))); + printf("- DDR : %s MHz\n", strmhz(buf, gd->mem_clk)); } #endif /* CONFIG_DISPLAY_CPUINFO */ #endif diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 3e6a980c8c..aae69cf9b0 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -20,3 +20,19 @@ config CLK_IMX8 select CLK help This enables support clock driver for i.MX8 platforms. + +config SPL_CLK_IMX8MM + bool "SPL clock support for i.MX8MM" + depends on ARCH_IMX8M && SPL + select SPL_CLK + select SPL_CLK_CCF + help + This enables SPL DM/DTS support for clock driver in i.MX8MM + +config CLK_IMX8MM + bool "Clock support for i.MX8MM" + depends on ARCH_IMX8M + select CLK + select CLK_CCF + help + This enables support clock driver for i.MX8MM platforms. diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 105a58ca90..5ad7967fe9 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -10,3 +10,5 @@ ifdef CONFIG_CLK_IMX8 obj-$(CONFIG_IMX8QXP) += clk-imx8qxp.o obj-$(CONFIG_IMX8QM) += clk-imx8qm.o endif +obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += clk-imx8mm.o clk-pll14xx.o \ + clk-composite-8m.o diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c new file mode 100644 index 0000000000..95120d6559 --- /dev/null +++ b/drivers/clk/imx/clk-composite-8m.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP + */ + +#include <common.h> +#include <asm/io.h> +#include <malloc.h> +#include <clk-uclass.h> +#include <dm/device.h> +#include <linux/clk-provider.h> +#include <clk.h> +#include "clk.h" + +#define UBOOT_DM_CLK_IMX_COMPOSITE "imx_clk_composite" + +#define PCG_PREDIV_SHIFT 16 +#define PCG_PREDIV_WIDTH 3 +#define PCG_PREDIV_MAX 8 + +#define PCG_DIV_SHIFT 0 +#define PCG_DIV_WIDTH 6 +#define PCG_DIV_MAX 64 + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 + +#define PCG_CGC_SHIFT 28 + +static unsigned long imx8m_clk_composite_divider_recalc_rate(struct clk *clk) +{ + struct clk_divider *divider = (struct clk_divider *)to_clk_divider(clk); + struct clk_composite *composite = (struct clk_composite *)clk->data; + ulong parent_rate = clk_get_parent_rate(&composite->clk); + unsigned long prediv_rate; + unsigned int prediv_value; + unsigned int div_value; + + debug("%s: name %s prate: %lu reg: %p\n", __func__, + (&composite->clk)->dev->name, parent_rate, divider->reg); + prediv_value = readl(divider->reg) >> divider->shift; + prediv_value &= clk_div_mask(divider->width); + + prediv_rate = divider_recalc_rate(clk, parent_rate, prediv_value, + NULL, divider->flags, + divider->width); + + div_value = readl(divider->reg) >> PCG_DIV_SHIFT; + div_value &= clk_div_mask(PCG_DIV_WIDTH); + + return divider_recalc_rate(clk, prediv_rate, div_value, NULL, + divider->flags, PCG_DIV_WIDTH); +} + +static int imx8m_clk_composite_compute_dividers(unsigned long rate, + unsigned long parent_rate, + int *prediv, int *postdiv) +{ + int div1, div2; + int error = INT_MAX; + int ret = -EINVAL; + + *prediv = 1; + *postdiv = 1; + + for (div1 = 1; div1 <= PCG_PREDIV_MAX; div1++) { + for (div2 = 1; div2 <= PCG_DIV_MAX; div2++) { + int new_error = ((parent_rate / div1) / div2) - rate; + + if (abs(new_error) < abs(error)) { + *prediv = div1; + *postdiv = div2; + error = new_error; + ret = 0; + } + } + } + return ret; +} + +/* + * The clk are bound to a dev, because it is part of composite clk + * use composite clk to get dev + */ +static ulong imx8m_clk_composite_divider_set_rate(struct clk *clk, + unsigned long rate) +{ + struct clk_divider *divider = (struct clk_divider *)to_clk_divider(clk); + struct clk_composite *composite = (struct clk_composite *)clk->data; + ulong parent_rate = clk_get_parent_rate(&composite->clk); + int prediv_value; + int div_value; + int ret; + u32 val; + + ret = imx8m_clk_composite_compute_dividers(rate, parent_rate, + &prediv_value, &div_value); + if (ret) + return ret; + + val = readl(divider->reg); + val &= ~((clk_div_mask(divider->width) << divider->shift) | + (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); + + val |= (u32)(prediv_value - 1) << divider->shift; + val |= (u32)(div_value - 1) << PCG_DIV_SHIFT; + writel(val, divider->reg); + + return clk_get_rate(&composite->clk); +} + +static const struct clk_ops imx8m_clk_composite_divider_ops = { + .get_rate = imx8m_clk_composite_divider_recalc_rate, + .set_rate = imx8m_clk_composite_divider_set_rate, +}; + +struct clk *imx8m_clk_composite_flags(const char *name, + const char * const *parent_names, + int num_parents, void __iomem *reg, + unsigned long flags) +{ + struct clk *clk = ERR_PTR(-ENOMEM); + struct clk_divider *div = NULL; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + goto fail; + + mux->reg = reg; + mux->shift = PCG_PCS_SHIFT; + mux->mask = PCG_PCS_MASK; + mux->num_parents = num_parents; + mux->flags = flags; + mux->parent_names = parent_names; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + goto fail; + + div->reg = reg; + div->shift = PCG_PREDIV_SHIFT; + div->width = PCG_PREDIV_WIDTH; + div->flags = CLK_DIVIDER_ROUND_CLOSEST | flags; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + goto fail; + + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + gate->flags = flags; + + clk = clk_register_composite(NULL, name, + parent_names, num_parents, + &mux->clk, &clk_mux_ops, &div->clk, + &imx8m_clk_composite_divider_ops, + &gate->clk, &clk_gate_ops, flags); + if (IS_ERR(clk)) + goto fail; + + return clk; + +fail: + kfree(gate); + kfree(div); + kfree(mux); + return ERR_CAST(clk); +} diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c new file mode 100644 index 0000000000..f4913e70ab --- /dev/null +++ b/drivers/clk/imx/clk-imx8mm.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP + * Peng Fan <peng.fan@nxp.com> + */ + +#include <common.h> +#include <clk.h> +#include <clk-uclass.h> +#include <dm.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <dt-bindings/clock/imx8mm-clock.h> + +#include "clk.h" + +#define PLL_1416X_RATE(_rate, _m, _p, _s) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + .kdiv = (_k), \ + } + +static const struct imx_pll14xx_rate_table imx8mm_pll1416x_tbl[] = { + PLL_1416X_RATE(1800000000U, 225, 3, 0), + PLL_1416X_RATE(1600000000U, 200, 3, 0), + PLL_1416X_RATE(1200000000U, 300, 3, 1), + PLL_1416X_RATE(1000000000U, 250, 3, 1), + PLL_1416X_RATE(800000000U, 200, 3, 1), + PLL_1416X_RATE(750000000U, 250, 2, 2), + PLL_1416X_RATE(700000000U, 350, 3, 2), + PLL_1416X_RATE(600000000U, 300, 3, 2), +}; + +static const struct imx_pll14xx_rate_table imx8mm_drampll_tbl[] = { + PLL_1443X_RATE(650000000U, 325, 3, 2, 0), +}; + +static struct imx_pll14xx_clk imx8mm_dram_pll __initdata = { + .type = PLL_1443X, + .rate_table = imx8mm_drampll_tbl, + .rate_count = ARRAY_SIZE(imx8mm_drampll_tbl), +}; + +static struct imx_pll14xx_clk imx8mm_arm_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mm_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl), +}; + +static struct imx_pll14xx_clk imx8mm_sys_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mm_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl), +}; + +static const char *pll_ref_sels[] = { "clock-osc-24m", "dummy", "dummy", "dummy", }; +static const char *dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", }; +static const char *sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", }; +static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", }; + +static const char *imx8mm_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m", + "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", }; + +static const char *imx8mm_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m", "sys_pll1_400m", + "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", }; + +static const char *imx8mm_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_250m", + "sys_pll2_200m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", }; + +static const char *imx8mm_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m", + "sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", }; + +static const char *imx8mm_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", + "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", }; + +static const char *imx8mm_usdhc2_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", + "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", }; + +static const char *imx8mm_i2c1_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mm_i2c2_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mm_i2c3_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mm_i2c4_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mm_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_160m", "vpu_pll_out", + "sys_pll2_125m", "sys_pll3_out", "sys_pll1_80m", "sys_pll2_166m", }; + +static const char *imx8mm_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m", + "sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", }; + +static ulong imx8mm_clk_get_rate(struct clk *clk) +{ + struct clk *c; + int ret; + + debug("%s(#%lu)\n", __func__, clk->id); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_get_rate(c); +} + +static ulong imx8mm_clk_set_rate(struct clk *clk, unsigned long rate) +{ + struct clk *c; + int ret; + + debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_set_rate(c, rate); +} + +static int __imx8mm_clk_enable(struct clk *clk, bool enable) +{ + struct clk *c; + int ret; + + debug("%s(#%lu) en: %d\n", __func__, clk->id, enable); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + if (enable) + ret = clk_enable(c); + else + ret = clk_disable(c); + + return ret; +} + +static int imx8mm_clk_disable(struct clk *clk) +{ + return __imx8mm_clk_enable(clk, 0); +} + +static int imx8mm_clk_enable(struct clk *clk) +{ + return __imx8mm_clk_enable(clk, 1); +} + +static struct clk_ops imx8mm_clk_ops = { + .set_rate = imx8mm_clk_set_rate, + .get_rate = imx8mm_clk_get_rate, + .enable = imx8mm_clk_enable, + .disable = imx8mm_clk_disable, +}; + +static int imx8mm_clk_probe(struct udevice *dev) +{ + void __iomem *base; + + base = (void *)ANATOP_BASE_ADDR; + + clk_dm(IMX8MM_DRAM_PLL_REF_SEL, + imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MM_ARM_PLL_REF_SEL, + imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MM_SYS_PLL1_REF_SEL, + imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MM_SYS_PLL2_REF_SEL, + imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MM_SYS_PLL3_REF_SEL, + imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + + clk_dm(IMX8MM_DRAM_PLL, + imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", + base + 0x50, &imx8mm_dram_pll)); + clk_dm(IMX8MM_ARM_PLL, + imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", + base + 0x84, &imx8mm_arm_pll)); + clk_dm(IMX8MM_SYS_PLL1, + imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", + base + 0x94, &imx8mm_sys_pll)); + clk_dm(IMX8MM_SYS_PLL2, + imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", + base + 0x104, &imx8mm_sys_pll)); + clk_dm(IMX8MM_SYS_PLL3, + imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", + base + 0x114, &imx8mm_sys_pll)); + + /* PLL bypass out */ + clk_dm(IMX8MM_DRAM_PLL_BYPASS, + imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1, + dram_pll_bypass_sels, + ARRAY_SIZE(dram_pll_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MM_ARM_PLL_BYPASS, + imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1, + arm_pll_bypass_sels, + ARRAY_SIZE(arm_pll_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MM_SYS_PLL1_BYPASS, + imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1, + sys_pll1_bypass_sels, + ARRAY_SIZE(sys_pll1_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MM_SYS_PLL2_BYPASS, + imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1, + sys_pll2_bypass_sels, + ARRAY_SIZE(sys_pll2_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MM_SYS_PLL3_BYPASS, + imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1, + sys_pll3_bypass_sels, + ARRAY_SIZE(sys_pll3_bypass_sels), + CLK_SET_RATE_PARENT)); + + /* PLL out gate */ + clk_dm(IMX8MM_DRAM_PLL_OUT, + imx_clk_gate("dram_pll_out", "dram_pll_bypass", + base + 0x50, 13)); + clk_dm(IMX8MM_ARM_PLL_OUT, + imx_clk_gate("arm_pll_out", "arm_pll_bypass", + base + 0x84, 11)); + clk_dm(IMX8MM_SYS_PLL1_OUT, + imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", + base + 0x94, 11)); + clk_dm(IMX8MM_SYS_PLL2_OUT, + imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", + base + 0x104, 11)); + clk_dm(IMX8MM_SYS_PLL3_OUT, + imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", + base + 0x114, 11)); + + /* SYS PLL fixed output */ + clk_dm(IMX8MM_SYS_PLL1_40M, + imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20)); + clk_dm(IMX8MM_SYS_PLL1_80M, + imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10)); + clk_dm(IMX8MM_SYS_PLL1_100M, + imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8)); + clk_dm(IMX8MM_SYS_PLL1_133M, + imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6)); + clk_dm(IMX8MM_SYS_PLL1_160M, + imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5)); + clk_dm(IMX8MM_SYS_PLL1_200M, + imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4)); + clk_dm(IMX8MM_SYS_PLL1_266M, + imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3)); + clk_dm(IMX8MM_SYS_PLL1_400M, + imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2)); + clk_dm(IMX8MM_SYS_PLL1_800M, + imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1)); + + clk_dm(IMX8MM_SYS_PLL2_50M, + imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20)); + clk_dm(IMX8MM_SYS_PLL2_100M, + imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10)); + clk_dm(IMX8MM_SYS_PLL2_125M, + imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8)); + clk_dm(IMX8MM_SYS_PLL2_166M, + imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6)); + clk_dm(IMX8MM_SYS_PLL2_200M, + imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5)); + clk_dm(IMX8MM_SYS_PLL2_250M, + imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4)); + clk_dm(IMX8MM_SYS_PLL2_333M, + imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3)); + clk_dm(IMX8MM_SYS_PLL2_500M, + imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2)); + clk_dm(IMX8MM_SYS_PLL2_1000M, + imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1)); + + base = dev_read_addr_ptr(dev); + if (base == (void *)FDT_ADDR_T_NONE) + return -EINVAL; + + clk_dm(IMX8MM_CLK_A53_SRC, + imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, + imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels))); + clk_dm(IMX8MM_CLK_A53_CG, + imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28)); + clk_dm(IMX8MM_CLK_A53_DIV, + imx_clk_divider2("arm_a53_div", "arm_a53_cg", + base + 0x8000, 0, 3)); + + clk_dm(IMX8MM_CLK_AHB, + imx8m_clk_composite_critical("ahb", imx8mm_ahb_sels, + base + 0x9000)); + clk_dm(IMX8MM_CLK_IPG_ROOT, + imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1)); + + clk_dm(IMX8MM_CLK_ENET_AXI, + imx8m_clk_composite("enet_axi", imx8mm_enet_axi_sels, + base + 0x8880)); + clk_dm(IMX8MM_CLK_NAND_USDHC_BUS, + imx8m_clk_composite_critical("nand_usdhc_bus", + imx8mm_nand_usdhc_sels, + base + 0x8900)); + + /* IP */ + clk_dm(IMX8MM_CLK_USDHC1, + imx8m_clk_composite("usdhc1", imx8mm_usdhc1_sels, + base + 0xac00)); + clk_dm(IMX8MM_CLK_USDHC2, + imx8m_clk_composite("usdhc2", imx8mm_usdhc2_sels, + base + 0xac80)); + clk_dm(IMX8MM_CLK_I2C1, + imx8m_clk_composite("i2c1", imx8mm_i2c1_sels, base + 0xad00)); + clk_dm(IMX8MM_CLK_I2C2, + imx8m_clk_composite("i2c2", imx8mm_i2c2_sels, base + 0xad80)); + clk_dm(IMX8MM_CLK_I2C3, + imx8m_clk_composite("i2c3", imx8mm_i2c3_sels, base + 0xae00)); + clk_dm(IMX8MM_CLK_I2C4, + imx8m_clk_composite("i2c4", imx8mm_i2c4_sels, base + 0xae80)); + clk_dm(IMX8MM_CLK_WDOG, + imx8m_clk_composite("wdog", imx8mm_wdog_sels, base + 0xb900)); + clk_dm(IMX8MM_CLK_USDHC3, + imx8m_clk_composite("usdhc3", imx8mm_usdhc3_sels, + base + 0xbc80)); + + clk_dm(IMX8MM_CLK_I2C1_ROOT, + imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0)); + clk_dm(IMX8MM_CLK_I2C2_ROOT, + imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0)); + clk_dm(IMX8MM_CLK_I2C3_ROOT, + imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0)); + clk_dm(IMX8MM_CLK_I2C4_ROOT, + imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0)); + clk_dm(IMX8MM_CLK_OCOTP_ROOT, + imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0)); + clk_dm(IMX8MM_CLK_USDHC1_ROOT, + imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0)); + clk_dm(IMX8MM_CLK_USDHC2_ROOT, + imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0)); + clk_dm(IMX8MM_CLK_WDOG1_ROOT, + imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0)); + clk_dm(IMX8MM_CLK_WDOG2_ROOT, + imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0)); + clk_dm(IMX8MM_CLK_WDOG3_ROOT, + imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0)); + clk_dm(IMX8MM_CLK_USDHC3_ROOT, + imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0)); + +#ifdef CONFIG_SPL_BUILD + struct clk *clkp, *clkp1; + + clk_get_by_id(IMX8MM_CLK_WDOG1_ROOT, &clkp); + clk_enable(clkp); + clk_get_by_id(IMX8MM_CLK_WDOG2_ROOT, &clkp); + clk_enable(clkp); + clk_get_by_id(IMX8MM_CLK_WDOG3_ROOT, &clkp); + clk_enable(clkp); + + /* Configure SYS_PLL3 to 750MHz */ + clk_get_by_id(IMX8MM_SYS_PLL3, &clkp); + clk_set_rate(clkp, 750000000UL); + clk_enable(clkp); + + /* Configure ARM to sys_pll2_500m */ + clk_get_by_id(IMX8MM_CLK_A53_SRC, &clkp); + clk_get_by_id(IMX8MM_SYS_PLL2_OUT, &clkp1); + clk_enable(clkp1); + clk_get_by_id(IMX8MM_SYS_PLL2_500M, &clkp1); + clk_set_parent(clkp, clkp1); + + /* Configure ARM PLL to 1.2GHz */ + clk_get_by_id(IMX8MM_ARM_PLL, &clkp1); + clk_set_rate(clkp1, 1200000000UL); + clk_get_by_id(IMX8MM_ARM_PLL_OUT, &clkp1); + clk_enable(clkp1); + clk_set_parent(clkp, clkp1); + + /* Configure DIV to 1.2GHz */ + clk_get_by_id(IMX8MM_CLK_A53_DIV, &clkp1); + clk_set_rate(clkp1, 1200000000UL); +#endif + + return 0; +} + +static const struct udevice_id imx8mm_clk_ids[] = { + { .compatible = "fsl,imx8mm-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imx8mm_clk) = { + .name = "clk_imx8mm", + .id = UCLASS_CLK, + .of_match = imx8mm_clk_ids, + .ops = &imx8mm_clk_ops, + .probe = imx8mm_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c new file mode 100644 index 0000000000..2246beb21b --- /dev/null +++ b/drivers/clk/imx/clk-pll14xx.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2017-2019 NXP. + * + * Peng Fan <peng.fan@nxp.com> + */ + +#include <common.h> +#include <asm/io.h> +#include <malloc.h> +#include <clk-uclass.h> +#include <dm/device.h> +#include <linux/clk-provider.h> +#include <linux/iopoll.h> +#include <clk.h> +#include <div64.h> + +#include "clk.h" + +#define UBOOT_DM_CLK_IMX_PLL1443X "imx_clk_pll1443x" +#define UBOOT_DM_CLK_IMX_PLL1416X "imx_clk_pll1416x" + +#define GNRL_CTL 0x0 +#define DIV_CTL 0x4 +#define LOCK_STATUS BIT(31) +#define LOCK_SEL_MASK BIT(29) +#define CLKE_MASK BIT(11) +#define RST_MASK BIT(9) +#define BYPASS_MASK BIT(4) +#define MDIV_SHIFT 12 +#define MDIV_MASK GENMASK(21, 12) +#define PDIV_SHIFT 4 +#define PDIV_MASK GENMASK(9, 4) +#define SDIV_SHIFT 0 +#define SDIV_MASK GENMASK(2, 0) +#define KDIV_SHIFT 0 +#define KDIV_MASK GENMASK(15, 0) + +#define LOCK_TIMEOUT_US 10000 + +struct clk_pll14xx { + struct clk clk; + void __iomem *base; + enum imx_pll14xx_type type; + const struct imx_pll14xx_rate_table *rate_table; + int rate_count; +}; + +#define to_clk_pll14xx(_clk) container_of(_clk, struct clk_pll14xx, clk) + +static const struct imx_pll14xx_rate_table *imx_get_pll_settings( + struct clk_pll14xx *pll, unsigned long rate) +{ + const struct imx_pll14xx_rate_table *rate_table = pll->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) + if (rate == rate_table[i].rate) + return &rate_table[i]; + + return NULL; +} + +static unsigned long clk_pll1416x_recalc_rate(struct clk *clk) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev)); + u64 fvco = clk_get_parent_rate(clk); + u32 mdiv, pdiv, sdiv, pll_div; + + pll_div = readl(pll->base + 4); + mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT; + pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT; + sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT; + + fvco *= mdiv; + do_div(fvco, pdiv << sdiv); + + return fvco; +} + +static unsigned long clk_pll1443x_recalc_rate(struct clk *clk) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev)); + u64 fvco = clk_get_parent_rate(clk); + u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1; + short int kdiv; + + pll_div_ctl0 = readl(pll->base + 4); + pll_div_ctl1 = readl(pll->base + 8); + mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT; + pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT; + sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT; + kdiv = pll_div_ctl1 & KDIV_MASK; + + /* fvco = (m * 65536 + k) * Fin / (p * 65536) */ + fvco *= (mdiv * 65536 + kdiv); + pdiv *= 65536; + + do_div(fvco, pdiv << sdiv); + + return fvco; +} + +static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate, + u32 pll_div) +{ + u32 old_mdiv, old_pdiv; + + old_mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT; + old_pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT; + + return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv; +} + +static inline bool clk_pll1443x_mpk_change(const struct imx_pll14xx_rate_table *rate, + u32 pll_div_ctl0, u32 pll_div_ctl1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT; + old_pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT; + old_kdiv = (pll_div_ctl1 & KDIV_MASK) >> KDIV_SHIFT; + + return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv || + rate->kdiv != old_kdiv; +} + +static inline bool clk_pll1443x_mp_change(const struct imx_pll14xx_rate_table *rate, + u32 pll_div_ctl0, u32 pll_div_ctl1) +{ + u32 old_mdiv, old_pdiv, old_kdiv; + + old_mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT; + old_pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT; + old_kdiv = (pll_div_ctl1 & KDIV_MASK) >> KDIV_SHIFT; + + return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv || + rate->kdiv != old_kdiv; +} + +static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & LOCK_TIMEOUT_US, + LOCK_TIMEOUT_US); +} + +static ulong clk_pll1416x_set_rate(struct clk *clk, unsigned long drate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev)); + const struct imx_pll14xx_rate_table *rate; + u32 tmp, div_val; + int ret; + + rate = imx_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, "xxxx"); + return -EINVAL; + } + + tmp = readl(pll->base + 4); + + if (!clk_pll1416x_mp_change(rate, tmp)) { + tmp &= ~(SDIV_MASK) << SDIV_SHIFT; + tmp |= rate->sdiv << SDIV_SHIFT; + writel(tmp, pll->base + 4); + + return clk_pll1416x_recalc_rate(clk); + } + + /* Bypass clock and set lock to pll output lock */ + tmp = readl(pll->base); + tmp |= LOCK_SEL_MASK; + writel(tmp, pll->base); + + /* Enable RST */ + tmp &= ~RST_MASK; + writel(tmp, pll->base); + + /* Enable BYPASS */ + tmp |= BYPASS_MASK; + writel(tmp, pll->base); + + + div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) | + (rate->sdiv << SDIV_SHIFT); + writel(div_val, pll->base + 0x4); + + /* + * According to SPEC, t3 - t2 need to be greater than + * 1us and 1/FREF, respectively. + * FREF is FIN / Prediv, the prediv is [1, 63], so choose + * 3us. + */ + udelay(3); + + /* Disable RST */ + tmp |= RST_MASK; + writel(tmp, pll->base); + + /* Wait Lock */ + ret = clk_pll14xx_wait_lock(pll); + if (ret) + return ret; + + /* Bypass */ + tmp &= ~BYPASS_MASK; + writel(tmp, pll->base); + + return clk_pll1416x_recalc_rate(clk); +} + +static ulong clk_pll1443x_set_rate(struct clk *clk, unsigned long drate) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev)); + const struct imx_pll14xx_rate_table *rate; + u32 tmp, div_val; + int ret; + + rate = imx_get_pll_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, "==="); + return -EINVAL; + } + + tmp = readl(pll->base + 4); + div_val = readl(pll->base + 8); + + if (!clk_pll1443x_mpk_change(rate, tmp, div_val)) { + tmp &= ~(SDIV_MASK) << SDIV_SHIFT; + tmp |= rate->sdiv << SDIV_SHIFT; + writel(tmp, pll->base + 4); + + return clk_pll1443x_recalc_rate(clk); + } + + tmp = readl(pll->base); + + /* Enable RST */ + tmp &= ~RST_MASK; + writel(tmp, pll->base); + + /* Enable BYPASS */ + tmp |= BYPASS_MASK; + writel(tmp, pll->base); + + div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) | + (rate->sdiv << SDIV_SHIFT); + writel(div_val, pll->base + 0x4); + writel(rate->kdiv << KDIV_SHIFT, pll->base + 0x8); + + /* + * According to SPEC, t3 - t2 need to be greater than + * 1us and 1/FREF, respectively. + * FREF is FIN / Prediv, the prediv is [1, 63], so choose + * 3us. + */ + udelay(3); + + /* Disable RST */ + tmp |= RST_MASK; + writel(tmp, pll->base); + + /* Wait Lock*/ + ret = clk_pll14xx_wait_lock(pll); + if (ret) + return ret; + + /* Bypass */ + tmp &= ~BYPASS_MASK; + writel(tmp, pll->base); + + return clk_pll1443x_recalc_rate(clk); +} + +static int clk_pll14xx_prepare(struct clk *clk) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev)); + u32 val; + + /* + * RESETB = 1 from 0, PLL starts its normal + * operation after lock time + */ + val = readl(pll->base + GNRL_CTL); + val |= RST_MASK; + writel(val, pll->base + GNRL_CTL); + + return clk_pll14xx_wait_lock(pll); +} + +static int clk_pll14xx_unprepare(struct clk *clk) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev)); + u32 val; + + /* + * Set RST to 0, power down mode is enabled and + * every digital block is reset + */ + val = readl(pll->base + GNRL_CTL); + val &= ~RST_MASK; + writel(val, pll->base + GNRL_CTL); + + return 0; +} + +static const struct clk_ops clk_pll1416x_ops = { + .enable = clk_pll14xx_prepare, + .disable = clk_pll14xx_unprepare, + .set_rate = clk_pll1416x_set_rate, + .get_rate = clk_pll1416x_recalc_rate, +}; + +static const struct clk_ops clk_pll1443x_ops = { + .enable = clk_pll14xx_prepare, + .disable = clk_pll14xx_unprepare, + .set_rate = clk_pll1443x_set_rate, + .get_rate = clk_pll1443x_recalc_rate, +}; + +struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_pll14xx_clk *pll_clk) +{ + struct clk_pll14xx *pll; + struct clk *clk; + char *type_name; + int ret; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + switch (pll_clk->type) { + case PLL_1416X: + type_name = UBOOT_DM_CLK_IMX_PLL1416X; + break; + case PLL_1443X: + type_name = UBOOT_DM_CLK_IMX_PLL1443X; + break; + default: + pr_err("%s: Unknown pll type for pll clk %s\n", + __func__, name); + return ERR_PTR(-EINVAL); + }; + + pll->base = base; + pll->type = pll_clk->type; + pll->rate_table = pll_clk->rate_table; + pll->rate_count = pll_clk->rate_count; + + clk = &pll->clk; + + ret = clk_register(clk, type_name, name, parent_name); + if (ret) { + pr_err("%s: failed to register pll %s %d\n", + __func__, name, ret); + kfree(pll); + return ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(clk_pll1443x) = { + .name = UBOOT_DM_CLK_IMX_PLL1443X, + .id = UCLASS_CLK, + .ops = &clk_pll1443x_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(clk_pll1416x) = { + .name = UBOOT_DM_CLK_IMX_PLL1416X, + .id = UCLASS_CLK, + .ops = &clk_pll1416x_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 1d480d8722..4956e04a92 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -20,6 +20,31 @@ enum imx_pllv3_type { IMX_PLLV3_DDR_IMX7, }; +enum imx_pll14xx_type { + PLL_1416X, + PLL_1443X, +}; + +/* NOTE: Rate table should be kept sorted in descending order. */ +struct imx_pll14xx_rate_table { + unsigned int rate; + unsigned int pdiv; + unsigned int mdiv; + unsigned int sdiv; + unsigned int kdiv; +}; + +struct imx_pll14xx_clk { + enum imx_pll14xx_type type; + const struct imx_pll14xx_rate_table *rate_table; + int rate_count; + int flags; +}; + +struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_pll14xx_clk *pll_clk); + struct clk *clk_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, u8 cgr_val, diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 112326e553..43dac1aa37 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -405,6 +405,7 @@ static struct clk_ops meson_clk_ops = { static const struct udevice_id meson_clk_ids[] = { { .compatible = "amlogic,g12a-clkc" }, + { .compatible = "amlogic,g12b-clkc" }, { } }; diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c index a89e2ecc4a..5957a00402 100644 --- a/drivers/clk/rockchip/clk_rk3328.c +++ b/drivers/clk/rockchip/clk_rk3328.c @@ -745,10 +745,22 @@ static int rk3328_clk_set_parent(struct clk *clk, struct clk *parent) return -ENOENT; } +static int rk3328_clk_enable(struct clk *clk) +{ + switch (clk->id) { + case HCLK_HOST0: + /* Required to successfully probe the ehci generic driver */ + return 0; + } + + return -ENOENT; +} + static struct clk_ops rk3328_clk_ops = { .get_rate = rk3328_clk_get_rate, .set_rate = rk3328_clk_set_rate, .set_parent = rk3328_clk_set_parent, + .enable = rk3328_clk_enable, }; static int rk3328_clk_probe(struct udevice *dev) diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 2d195ae35e..3b95b5387b 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -92,7 +92,7 @@ config DM_SEQ_ALIAS config SPL_DM_SEQ_ALIAS bool "Support numbered aliases in device tree in SPL" - depends on DM + depends on SPL_DM default n help Most boards will have a '/aliases' node containing the path to diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c index e1f69a1d25..0aa6aedae7 100644 --- a/drivers/ddr/fsl/main.c +++ b/drivers/ddr/fsl/main.c @@ -10,6 +10,7 @@ */ #include <common.h> +#include <dm.h> #include <i2c.h> #include <fsl_ddr_sdram.h> #include <fsl_ddr.h> @@ -82,17 +83,82 @@ u8 spd_i2c_addr[CONFIG_SYS_NUM_DDR_CTLRS][CONFIG_DIMM_SLOTS_PER_CTLR] = { #endif +#if defined(CONFIG_DM_I2C) +#define DEV_TYPE struct udevice +#else +/* Local udevice */ +struct ludevice { + u8 chip; +}; + +#define DEV_TYPE struct ludevice + +#endif + #define SPD_SPA0_ADDRESS 0x36 #define SPD_SPA1_ADDRESS 0x37 -static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address) +static int ddr_i2c_read(DEV_TYPE *dev, unsigned int addr, + int alen, uint8_t *buf, int len) { int ret; + +#ifdef CONFIG_DM_I2C + ret = dm_i2c_read(dev, 0, buf, len); +#else + ret = i2c_read(dev->chip, addr, alen, buf, len); +#endif + + return ret; +} + #ifdef CONFIG_SYS_FSL_DDR4 - uint8_t dummy = 0; +static int ddr_i2c_dummy_write(unsigned int chip_addr) +{ + uint8_t buf = 0; + +#ifdef CONFIG_DM_I2C + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(CONFIG_SYS_SPD_BUS_NUM, chip_addr, + 1, &dev); + if (ret) { + printf("%s: Cannot find udev for a bus %d\n", __func__, + CONFIG_SYS_SPD_BUS_NUM); + return ret; + } + + return dm_i2c_write(dev, 0, &buf, 1); +#else + return i2c_write(chip_addr, 0, 1, &buf, 1); #endif + return 0; +} +#endif + +static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address) +{ + int ret; + DEV_TYPE *dev; + +#if defined(CONFIG_DM_I2C) + ret = i2c_get_chip_for_busnum(CONFIG_SYS_SPD_BUS_NUM, i2c_address, + 1, &dev); + if (ret) { + printf("%s: Cannot find udev for a bus %d\n", __func__, + CONFIG_SYS_SPD_BUS_NUM); + return; + } +#else /* Non DM I2C support - will be removed */ + struct ludevice ldev = { + .chip = i2c_address, + }; + dev = &ldev; + i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM); +#endif #ifdef CONFIG_SYS_FSL_DDR4 /* @@ -101,18 +167,19 @@ static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address) * To access the upper 256 bytes, we need to set EE page address to 1 * See Jedec standar No. 21-C for detail */ - i2c_write(SPD_SPA0_ADDRESS, 0, 1, &dummy, 1); - ret = i2c_read(i2c_address, 0, 1, (uchar *)spd, 256); + ddr_i2c_dummy_write(SPD_SPA0_ADDRESS); + ret = ddr_i2c_read(dev, 0, 1, (uchar *)spd, 256); if (!ret) { - i2c_write(SPD_SPA1_ADDRESS, 0, 1, &dummy, 1); - ret = i2c_read(i2c_address, 0, 1, - (uchar *)((ulong)spd + 256), - min(256, - (int)sizeof(generic_spd_eeprom_t) - 256)); + ddr_i2c_dummy_write(SPD_SPA1_ADDRESS); + ret = ddr_i2c_read(dev, 0, 1, (uchar *)((ulong)spd + 256), + min(256, + (int)sizeof(generic_spd_eeprom_t) + - 256)); } + #else - ret = i2c_read(i2c_address, 0, 1, (uchar *)spd, - sizeof(generic_spd_eeprom_t)); + ret = ddr_i2c_read(dev, 0, 1, (uchar *)spd, + sizeof(generic_spd_eeprom_t)); #endif if (ret) { diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7d9c97f537..f2dabb554f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -139,6 +139,11 @@ config MXC_GPIO help Support GPIO controllers on various i.MX platforms +config MXS_GPIO + bool "Freescale/NXP MXS GPIO driver" + help + Support GPIO controllers on i.MX23 and i.MX28 platforms + config OMAP_GPIO bool "TI OMAP GPIO driver" depends on ARCH_OMAP2PLUS diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 28f640042f..e8b124f4f5 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -106,7 +106,7 @@ static int i2c_mux_gpio_probe(struct udevice *dev) } ret = gpio_request_list_by_name(dev, "mux-gpios", gpios, mux->n_gpios, - GPIOD_IS_OUT_ACTIVE); + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); if (ret <= 0) { dev_err(dev, "Failed to request mux-gpios\n"); return ret; diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 23119cce65..20f6dc4ecb 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -558,6 +558,14 @@ static int i2c_read_data(struct mxc_i2c_bus *i2c_bus, uchar chip, uchar *buf, return 0; } +int __enable_i2c_clk(unsigned char enable, unsigned int i2c_num) +{ + return 1; +} + +int enable_i2c_clk(unsigned char enable, unsigned int i2c_num) + __attribute__((weak, alias("__enable_i2c_clk"))); + #ifndef CONFIG_DM_I2C /* * Read data from I2C device @@ -723,13 +731,6 @@ static int mxc_i2c_probe(struct i2c_adapter *adap, uint8_t chip) return bus_i2c_write(i2c_get_base(adap), chip, 0, 0, NULL, 0); } -int __enable_i2c_clk(unsigned char enable, unsigned i2c_num) -{ - return 1; -} -int enable_i2c_clk(unsigned char enable, unsigned i2c_num) - __attribute__((weak, alias("__enable_i2c_clk"))); - void bus_i2c_init(int index, int speed, int unused, int (*idle_bus_fn)(void *p), void *idle_bus_data) { @@ -916,13 +917,6 @@ static int mxc_i2c_probe(struct udevice *bus) } } - ret = i2c_idle_bus(i2c_bus); - if (ret < 0) { - /* Disable clk */ - enable_i2c_clk(0, bus->seq); - return ret; - } - /* * Pinmux settings are in board file now, until pinmux is supported, * we can set pinmux here in probe function. diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index cb8b5c04db..8037b6ee2d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -88,6 +88,7 @@ config CROS_EC config SPL_CROS_EC bool "Enable Chrome OS EC in SPL" + depends on SPL help Enable access to the Chrome OS EC in SPL. This is a separate microcontroller typically available on a SPI bus on Chromebooks. It @@ -97,6 +98,7 @@ config SPL_CROS_EC config TPL_CROS_EC bool "Enable Chrome OS EC in TPL" + depends on TPL help Enable access to the Chrome OS EC in TPL. This is a separate microcontroller typically available on a SPI bus on Chromebooks. It diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c index f25d054007..8f2349ad5a 100644 --- a/drivers/misc/i2c_eeprom.c +++ b/drivers/misc/i2c_eeprom.c @@ -84,6 +84,14 @@ static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev) static int i2c_eeprom_std_probe(struct udevice *dev) { + u8 test_byte; + int ret; + + /* Verify that the chip is functional */ + ret = i2c_eeprom_read(dev, 0, &test_byte, 1); + if (ret) + return -ENODEV; + return 0; } diff --git a/drivers/misc/stm32_rcc.c b/drivers/misc/stm32_rcc.c index 13d70696f6..e7efcdeafa 100644 --- a/drivers/misc/stm32_rcc.c +++ b/drivers/misc/stm32_rcc.c @@ -68,8 +68,6 @@ static int stm32_rcc_bind(struct udevice *dev) dev_ofnode(dev), &child); } -static const struct misc_ops stm32_rcc_ops = { -}; static const struct udevice_id stm32_rcc_ids[] = { {.compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32_rcc_clk_f42x }, @@ -82,8 +80,7 @@ static const struct udevice_id stm32_rcc_ids[] = { U_BOOT_DRIVER(stm32_rcc) = { .name = "stm32-rcc", - .id = UCLASS_MISC, + .id = UCLASS_NOP, .of_match = stm32_rcc_ids, .bind = stm32_rcc_bind, - .ops = &stm32_rcc_ops, }; diff --git a/drivers/misc/stm32mp_fuse.c b/drivers/misc/stm32mp_fuse.c index 801d946b77..0eed345973 100644 --- a/drivers/misc/stm32mp_fuse.c +++ b/drivers/misc/stm32mp_fuse.c @@ -20,7 +20,7 @@ */ int fuse_read(u32 bank, u32 word, u32 *val) { - int ret = 0; + int ret; struct udevice *dev; switch (bank) { @@ -32,15 +32,25 @@ int fuse_read(u32 bank, u32 word, u32 *val) return ret; ret = misc_read(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET, val, 4); - if (ret < 0) - return ret; - ret = 0; + if (ret != 4) + ret = -EINVAL; + else + ret = 0; break; #ifdef CONFIG_PMIC_STPMIC1 case STM32MP_NVM_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stpmic1_nvm), + &dev); + if (ret) + return ret; *val = 0; - ret = stpmic1_shadow_read_byte(word, (u8 *)val); + ret = misc_read(dev, -word, val, 1); + if (ret != 1) + ret = -EINVAL; + else + ret = 0; break; #endif /* CONFIG_PMIC_STPMIC1 */ @@ -67,14 +77,24 @@ int fuse_prog(u32 bank, u32 word, u32 val) return ret; ret = misc_write(dev, word * 4 + STM32_BSEC_OTP_OFFSET, &val, 4); - if (ret < 0) - return ret; - ret = 0; + if (ret != 4) + ret = -EINVAL; + else + ret = 0; break; #ifdef CONFIG_PMIC_STPMIC1 case STM32MP_NVM_BANK: - ret = stpmic1_nvm_write_byte(word, (u8 *)&val); + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stpmic1_nvm), + &dev); + if (ret) + return ret; + ret = misc_write(dev, word, &val, 1); + if (ret != 1) + ret = -EINVAL; + else + ret = 0; break; #endif /* CONFIG_PMIC_STPMIC1 */ @@ -100,15 +120,25 @@ int fuse_sense(u32 bank, u32 word, u32 *val) if (ret) return ret; ret = misc_read(dev, word * 4 + STM32_BSEC_OTP_OFFSET, val, 4); - if (ret < 0) - return ret; - ret = 0; + if (ret != 4) + ret = -EINVAL; + else + ret = 0; break; #ifdef CONFIG_PMIC_STPMIC1 case STM32MP_NVM_BANK: + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stpmic1_nvm), + &dev); + if (ret) + return ret; *val = 0; - ret = stpmic1_nvm_read_byte(word, (u8 *)val); + ret = misc_read(dev, word, val, 1); + if (ret != 1) + ret = -EINVAL; + else + ret = 0; break; #endif /* CONFIG_PMIC_STPMIC1 */ @@ -135,14 +165,24 @@ int fuse_override(u32 bank, u32 word, u32 val) return ret; ret = misc_write(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET, &val, 4); - if (ret < 0) - return ret; - ret = 0; + if (ret != 4) + ret = -EINVAL; + else + ret = 0; break; #ifdef CONFIG_PMIC_STPMIC1 case STM32MP_NVM_BANK: - ret = stpmic1_shadow_write_byte(word, (u8 *)&val); + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_GET_DRIVER(stpmic1_nvm), + &dev); + if (ret) + return ret; + ret = misc_write(dev, -word, &val, 1); + if (ret != 1) + ret = -EINVAL; + else + ret = 0; break; #endif /* CONFIG_PMIC_STPMIC1 */ diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index c6812f6517..0ccb1ea701 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -694,6 +694,13 @@ config FSL_ESDHC_IMX This selects support for the i.MX eSDHC (Enhanced Secure Digital Host Controller) found on numerous Freescale/NXP SoCs. +config FSL_USDHC + bool "Freescale/NXP i.MX uSDHC controller support" + depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || TARGET_S32V234EVB + select FSL_ESDHC_IMX + help + This enables the Ultra Secured Digital Host Controller enhancements + endmenu config SYS_FSL_ERRATUM_ESDHC111 diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 551007905c..2b146ea43c 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -360,6 +360,7 @@ static int mmc_select_hwpart(struct udevice *bdev, int hwpart) struct udevice *mmc_dev = dev_get_parent(bdev); struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); struct blk_desc *desc = dev_get_uclass_platdata(bdev); + int ret; if (desc->hwpart == hwpart) return 0; @@ -367,7 +368,11 @@ static int mmc_select_hwpart(struct udevice *bdev, int hwpart) if (mmc->part_config == MMCPART_NOAVAILABLE) return -EMEDIUMTYPE; - return mmc_switch_part(mmc, hwpart); + ret = mmc_switch_part(mmc, hwpart); + if (!ret) + blkcache_invalidate(desc->if_type, desc->devnum); + + return ret; } static int mmc_blk_probe(struct udevice *dev) diff --git a/drivers/mmc/sti_sdhci.c b/drivers/mmc/sti_sdhci.c index 8ed47e113d..d6c75ea601 100644 --- a/drivers/mmc/sti_sdhci.c +++ b/drivers/mmc/sti_sdhci.c @@ -97,14 +97,14 @@ static int sti_sdhci_probe(struct udevice *dev) SDHCI_QUIRK_NO_HISPD_BIT; host->host_caps = MMC_MODE_DDR_52MHz; + host->mmc = &plat->mmc; + host->mmc->dev = dev; + host->mmc->priv = host; ret = sdhci_setup_cfg(&plat->cfg, host, 50000000, 400000); if (ret) return ret; - host->mmc = &plat->mmc; - host->mmc->priv = host; - host->mmc->dev = dev; upriv->mmc = host->mmc; return sdhci_probe(dev); diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index 867ed569eb..32434a4762 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -14,6 +14,7 @@ #include <asm/io.h> #include <asm/gpio.h> #include <linux/iopoll.h> +#include <watchdog.h> struct stm32_sdmmc2_plat { struct mmc_config cfg; @@ -190,7 +191,7 @@ struct stm32_sdmmc2_ctx { #define SDMMC_IDMACTRL_IDMAEN BIT(0) #define SDMMC_CMD_TIMEOUT 0xFFFFFFFF -#define SDMMC_BUSYD0END_TIMEOUT_US 1000000 +#define SDMMC_BUSYD0END_TIMEOUT_US 2000000 static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv, struct mmc_data *data, @@ -432,6 +433,8 @@ static int stm32_sdmmc2_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, u32 cmdat = data ? SDMMC_CMD_CMDTRANS : 0; int ret, retry = 3; + WATCHDOG_RESET(); + retry_cmd: ctx.data_length = 0; ctx.dpsm_abort = false; diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index f86035bcce..a129f44869 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -15,6 +15,11 @@ config SYS_NAND_DRIVER_ECC_LAYOUT Omit standard ECC layouts to safe space. Select this if your driver is known to provide its own ECC layout. +config SYS_NAND_USE_FLASH_BBT + bool "Enable BBT (Bad Block Table) support" + help + Enable the BBT (Bad Block Table) usage. + config NAND_ATMEL bool "Support Atmel NAND controller" imply SYS_NAND_USE_FLASH_BBT diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index 1d96e4bdc2..c980ba4edb 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -282,6 +282,16 @@ static int mc_fixup_dpl_mac_addr(void *blob, int dpmac_id, MC_FIXUP_DPL); } +void fdt_fixup_mc_ddr(u64 *base, u64 *size) +{ + u64 mc_size = mc_get_dram_block_size(); + + if (mc_size < MC_DRAM_BLOCK_DEFAULT_SIZE) { + *base = mc_get_dram_addr() + mc_size; + *size = MC_DRAM_BLOCK_DEFAULT_SIZE - mc_size; + } +} + void fdt_fsl_mc_fixup_iommu_map_entry(void *blob) { u32 *prop; diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index d4965e2ef6..47f101e280 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -73,6 +73,9 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2, u64 *prp_pool; int length = total_len; int i, nprps; + u32 prps_per_page = (page_size >> 3) - 1; + u32 num_pages; + length -= (page_size - offset); if (length <= 0) { @@ -89,15 +92,20 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2, } nprps = DIV_ROUND_UP(length, page_size); + num_pages = DIV_ROUND_UP(nprps, prps_per_page); if (nprps > dev->prp_entry_num) { free(dev->prp_pool); - dev->prp_pool = malloc(nprps << 3); + /* + * Always increase in increments of pages. It doesn't waste + * much memory and reduces the number of allocations. + */ + dev->prp_pool = memalign(page_size, num_pages * page_size); if (!dev->prp_pool) { printf("Error: malloc prp_pool fail\n"); return -ENOMEM; } - dev->prp_entry_num = nprps; + dev->prp_entry_num = prps_per_page * num_pages; } prp_pool = dev->prp_pool; @@ -788,14 +796,6 @@ static int nvme_probe(struct udevice *udev) } memset(ndev->queues, 0, NVME_Q_NUM * sizeof(struct nvme_queue *)); - ndev->prp_pool = malloc(MAX_PRP_POOL); - if (!ndev->prp_pool) { - ret = -ENOMEM; - printf("Error: %s: Out of memory!\n", udev->name); - goto free_nvme; - } - ndev->prp_entry_num = MAX_PRP_POOL >> 3; - ndev->cap = nvme_readq(&ndev->bar->cap); ndev->q_depth = min_t(int, NVME_CAP_MQES(ndev->cap) + 1, NVME_Q_DEPTH); ndev->db_stride = 1 << NVME_CAP_STRIDE(ndev->cap); @@ -805,6 +805,15 @@ static int nvme_probe(struct udevice *udev) if (ret) goto free_queue; + /* Allocate after the page size is known */ + ndev->prp_pool = memalign(ndev->page_size, MAX_PRP_POOL); + if (!ndev->prp_pool) { + ret = -ENOMEM; + printf("Error: %s: Out of memory!\n", udev->name); + goto free_nvme; + } + ndev->prp_entry_num = MAX_PRP_POOL >> 3; + ret = nvme_setup_io_queues(ndev); if (ret) goto free_queue; diff --git a/drivers/pci/pcie_fsl.c b/drivers/pci/pcie_fsl.c index 4d61a46cef..ab25aeee73 100644 --- a/drivers/pci/pcie_fsl.c +++ b/drivers/pci/pcie_fsl.c @@ -299,8 +299,9 @@ static int fsl_pcie_setup_inbound_win(struct fsl_pcie *pcie, int idx, out_be32(&pi->piwbear, 0); #endif - if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A005434)) - flag = 0; +#ifdef CONFIG_SYS_FSL_ERRATUM_A005434 + flag = 0; +#endif flag |= PIWAR_EN | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; if (pf) @@ -401,47 +402,47 @@ static int fsl_pcie_init_port(struct fsl_pcie *pcie) fsl_pcie_init_atmu(pcie); - if (IS_ENABLED(CONFIG_FSL_PCIE_DISABLE_ASPM)) { - val_32 = 0; - fsl_pcie_hose_read_config_dword(pcie, PCI_LCR, &val_32); - val_32 &= ~0x03; - fsl_pcie_hose_write_config_dword(pcie, PCI_LCR, val_32); - udelay(1); - } +#ifdef CONFIG_FSL_PCIE_DISABLE_ASPM + val_32 = 0; + fsl_pcie_hose_read_config_dword(pcie, PCI_LCR, &val_32); + val_32 &= ~0x03; + fsl_pcie_hose_write_config_dword(pcie, PCI_LCR, val_32); + udelay(1); +#endif - if (IS_ENABLED(CONFIG_FSL_PCIE_RESET)) { - u16 ltssm; - int i; +#ifdef CONFIG_FSL_PCIE_RESET + u16 ltssm; + int i; - if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) { + if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) { + /* assert PCIe reset */ + setbits_be32(®s->pdb_stat, 0x08000000); + (void)in_be32(®s->pdb_stat); + udelay(1000); + /* clear PCIe reset */ + clrbits_be32(®s->pdb_stat, 0x08000000); + asm("sync;isync"); + for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++) + udelay(1000); + } else { + fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, <ssm); + if (ltssm == 1) { /* assert PCIe reset */ setbits_be32(®s->pdb_stat, 0x08000000); (void)in_be32(®s->pdb_stat); - udelay(1000); + udelay(100); /* clear PCIe reset */ clrbits_be32(®s->pdb_stat, 0x08000000); asm("sync;isync"); - for (i = 0; i < 100 && !fsl_pcie_link_up(pcie); i++) + for (i = 0; i < 100 && + !fsl_pcie_link_up(pcie); i++) udelay(1000); - } else { - fsl_pcie_hose_read_config_word(pcie, PCI_LTSSM, <ssm); - if (ltssm == 1) { - /* assert PCIe reset */ - setbits_be32(®s->pdb_stat, 0x08000000); - (void)in_be32(®s->pdb_stat); - udelay(100); - /* clear PCIe reset */ - clrbits_be32(®s->pdb_stat, 0x08000000); - asm("sync;isync"); - for (i = 0; i < 100 && - !fsl_pcie_link_up(pcie); i++) - udelay(1000); - } } } +#endif - if (IS_ENABLED(CONFIG_SYS_P4080_ERRATUM_PCIE_A003) && - !fsl_pcie_link_up(pcie)) { +#ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003 + if (!fsl_pcie_link_up(pcie)) { serdes_corenet_t *srds_regs; srds_regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR; @@ -460,13 +461,15 @@ static int fsl_pcie_init_port(struct fsl_pcie *pcie) udelay(1000); } } +#endif /* * The Read-Only Write Enable bit defaults to 1 instead of 0. * Set to 0 to protect the read-only registers. */ - if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A007815)) - clrbits_be32(®s->dbi_ro_wr_en, 0x01); +#ifdef CONFIG_SYS_FSL_ERRATUM_A007815 + clrbits_be32(®s->dbi_ro_wr_en, 0x01); +#endif /* * Enable All Error Interrupts except @@ -500,14 +503,23 @@ static int fsl_pcie_init_port(struct fsl_pcie *pcie) static int fsl_pcie_fixup_classcode(struct fsl_pcie *pcie) { ccsr_fsl_pci_t *regs = pcie->regs; + u32 classcode_reg; u32 val; - setbits_be32(®s->dbi_ro_wr_en, 0x01); - fsl_pcie_hose_read_config_dword(pcie, PCI_CLASS_REVISION, &val); + if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) { + classcode_reg = PCI_CLASS_REVISION; + setbits_be32(®s->dbi_ro_wr_en, 0x01); + } else { + classcode_reg = CSR_CLASSCODE; + } + + fsl_pcie_hose_read_config_dword(pcie, classcode_reg, &val); val &= 0xff; val |= PCI_CLASS_BRIDGE_PCI << 16; - fsl_pcie_hose_write_config_dword(pcie, PCI_CLASS_REVISION, val); - clrbits_be32(®s->dbi_ro_wr_en, 0x01); + fsl_pcie_hose_write_config_dword(pcie, classcode_reg, val); + + if (pcie->block_rev >= PEX_IP_BLK_REV_3_0) + clrbits_be32(®s->dbi_ro_wr_en, 0x01); return 0; } @@ -570,6 +582,7 @@ static int fsl_pcie_probe(struct udevice *dev) static int fsl_pcie_ofdata_to_platdata(struct udevice *dev) { struct fsl_pcie *pcie = dev_get_priv(dev); + struct fsl_pcie_data *info; int ret; pcie->regs = dev_remap_addr(dev); @@ -584,7 +597,10 @@ static int fsl_pcie_ofdata_to_platdata(struct udevice *dev) return ret; } - pcie->idx = (dev_read_addr(dev) - 0xffe240000) / 0x10000; + info = (struct fsl_pcie_data *)dev_get_driver_data(dev); + pcie->info = info; + pcie->idx = abs((u32)(dev_read_addr(dev) & info->block_offset_mask) - + info->block_offset) / info->stride; return 0; } @@ -594,8 +610,35 @@ static const struct dm_pci_ops fsl_pcie_ops = { .write_config = fsl_pcie_write_config, }; +static struct fsl_pcie_data p1_p2_data = { + .block_offset = 0xa000, + .block_offset_mask = 0xffff, + .stride = 0x1000, +}; + +static struct fsl_pcie_data p2041_data = { + .block_offset = 0x200000, + .block_offset_mask = 0x3fffff, + .stride = 0x1000, +}; + +static struct fsl_pcie_data t2080_data = { + .block_offset = 0x240000, + .block_offset_mask = 0x3fffff, + .stride = 0x10000, +}; + static const struct udevice_id fsl_pcie_ids[] = { - { .compatible = "fsl,pcie-t2080" }, + { .compatible = "fsl,pcie-mpc8548", .data = (ulong)&p1_p2_data }, + { .compatible = "fsl,pcie-p1_p2", .data = (ulong)&p1_p2_data }, + { .compatible = "fsl,pcie-p2041", .data = (ulong)&p2041_data }, + { .compatible = "fsl,pcie-p3041", .data = (ulong)&p2041_data }, + { .compatible = "fsl,pcie-p4080", .data = (ulong)&p2041_data }, + { .compatible = "fsl,pcie-p5040", .data = (ulong)&p2041_data }, + { .compatible = "fsl,pcie-t102x", .data = (ulong)&t2080_data }, + { .compatible = "fsl,pcie-t104x", .data = (ulong)&t2080_data }, + { .compatible = "fsl,pcie-t2080", .data = (ulong)&t2080_data }, + { .compatible = "fsl,pcie-t4240", .data = (ulong)&t2080_data }, { } }; diff --git a/drivers/pci/pcie_fsl.h b/drivers/pci/pcie_fsl.h index 5eefc31fa9..dc8368d559 100644 --- a/drivers/pci/pcie_fsl.h +++ b/drivers/pci/pcie_fsl.h @@ -9,6 +9,9 @@ #ifndef _PCIE_FSL_H_ #define _PCIE_FSL_H_ +/* GPEX CSR */ +#define CSR_CLASSCODE 0x474 + #ifdef CONFIG_SYS_FSL_PCI_VER_3_X #define FSL_PCIE_CAP_ID 0x70 #else @@ -40,6 +43,12 @@ #define LTSSM_L0_REV3 0x11 #define LTSSM_L0 0x16 +struct fsl_pcie_data { + u32 block_offset; /* Offset from CCSR of 1st controller */ + u32 block_offset_mask; /* Mask out the CCSR base */ + u32 stride; /* Offset stride between controllers */ +}; + struct fsl_pcie { int idx; struct udevice *bus; @@ -49,6 +58,7 @@ struct fsl_pcie { bool mode; /* RC&EP mode flag */ bool enabled; /* Enable status */ struct list_head list; + struct fsl_pcie_data *info; }; extern struct list_head fsl_pcie_list; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 3942f035eb..02312273e2 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -19,7 +19,7 @@ config PHY config SPL_PHY bool "PHY Core in SPL" - depends on DM + depends on DM && SPL help PHY support in SPL. diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index 5431df9813..0b5a0433cd 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -231,23 +231,23 @@ static int stmfx_pinctrl_conf_set(struct udevice *dev, unsigned int pin, switch (param) { case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_DRIVE_PUSH_PULL: + ret = stmfx_pinctrl_set_type(dev, pin, 0); + break; case PIN_CONFIG_BIAS_PULL_DOWN: + ret = stmfx_pinctrl_set_type(dev, pin, 1); + if (ret) + return ret; ret = stmfx_pinctrl_set_pupd(dev, pin, 0); break; case PIN_CONFIG_BIAS_PULL_UP: + ret = stmfx_pinctrl_set_type(dev, pin, 1); + if (ret) + return ret; ret = stmfx_pinctrl_set_pupd(dev, pin, 1); break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: - if (dir == GPIOF_OUTPUT) - ret = stmfx_pinctrl_set_type(dev, pin, 1); - else - ret = stmfx_pinctrl_set_type(dev, pin, 0); - break; - case PIN_CONFIG_DRIVE_PUSH_PULL: - if (dir == GPIOF_OUTPUT) - ret = stmfx_pinctrl_set_type(dev, pin, 0); - else - ret = stmfx_pinctrl_set_type(dev, pin, 1); + ret = stmfx_pinctrl_set_type(dev, pin, 1); break; case PIN_CONFIG_OUTPUT: ret = stmfx_gpio_direction_output(plat->gpio, pin, arg); diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index cdbe463cff..3a235ae5a7 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -1,11 +1,11 @@ #include <common.h> #include <dm.h> -#include <dm/lists.h> -#include <dm/pinctrl.h> #include <hwspinlock.h> #include <asm/arch/gpio.h> #include <asm/gpio.h> #include <asm/io.h> +#include <dm/lists.h> +#include <dm/pinctrl.h> DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/power/pmic/stpmic1.c b/drivers/power/pmic/stpmic1.c index c3381489dd..de31934f41 100644 --- a/drivers/power/pmic/stpmic1.c +++ b/drivers/power/pmic/stpmic1.c @@ -7,6 +7,7 @@ #include <dm.h> #include <errno.h> #include <i2c.h> +#include <misc.h> #include <sysreset.h> #include <dm/device.h> #include <dm/lists.h> @@ -69,6 +70,7 @@ static int stpmic1_read(struct udevice *dev, uint reg, uint8_t *buff, int len) static int stpmic1_bind(struct udevice *dev) { + int ret; #if CONFIG_IS_ENABLED(DM_REGULATOR) ofnode regulators_node; int children; @@ -86,6 +88,13 @@ static int stpmic1_bind(struct udevice *dev) dev_dbg(dev, "no child found\n"); #endif /* DM_REGULATOR */ + if (!IS_ENABLED(CONFIG_SPL_BUILD)) { + ret = device_bind_driver(dev, "stpmic1-nvm", + "stpmic1-nvm", NULL); + if (ret) + return ret; + } + if (CONFIG_IS_ENABLED(SYSRESET)) return device_bind_driver(dev, "stpmic1-sysreset", "stpmic1-sysreset", NULL); @@ -113,32 +122,38 @@ U_BOOT_DRIVER(pmic_stpmic1) = { }; #ifndef CONFIG_SPL_BUILD -static int stpmic1_nvm_rw(u8 addr, u8 *buf, int buf_len, enum pmic_nvm_op op) +static int stpmic1_nvm_rw(struct udevice *dev, u8 addr, u8 *buf, int buf_len, + enum pmic_nvm_op op) { - struct udevice *dev; unsigned long timeout; u8 cmd = STPMIC1_NVM_CMD_READ; - int ret; - - ret = uclass_get_device_by_driver(UCLASS_PMIC, - DM_GET_DRIVER(pmic_stpmic1), &dev); - if (ret) - /* No PMIC on power discrete board */ - return -EOPNOTSUPP; + int ret, len = buf_len; if (addr < STPMIC1_NVM_START_ADDRESS) return -EACCES; + if (addr + buf_len > STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE) + len = STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE - addr; - if (op == SHADOW_READ) - return pmic_read(dev, addr, buf, buf_len); + if (op == SHADOW_READ) { + ret = pmic_read(dev, addr, buf, len); + if (ret < 0) + return ret; + else + return len; + } - if (op == SHADOW_WRITE) - return pmic_write(dev, addr, buf, buf_len); + if (op == SHADOW_WRITE) { + ret = pmic_write(dev, addr, buf, len); + if (ret < 0) + return ret; + else + return len; + } if (op == NVM_WRITE) { cmd = STPMIC1_NVM_CMD_PROGRAM; - ret = pmic_write(dev, addr, buf, buf_len); + ret = pmic_write(dev, addr, buf, len); if (ret < 0) return ret; } @@ -168,69 +183,61 @@ static int stpmic1_nvm_rw(u8 addr, u8 *buf, int buf_len, enum pmic_nvm_op op) return -ETIMEDOUT; if (op == NVM_READ) { - ret = pmic_read(dev, addr, buf, buf_len); + ret = pmic_read(dev, addr, buf, len); if (ret < 0) return ret; } - return 0; + return len; } -int stpmic1_shadow_read_byte(u8 addr, u8 *buf) +static int stpmic1_nvm_read(struct udevice *dev, int offset, + void *buf, int size) { - return stpmic1_nvm_rw(addr, buf, 1, SHADOW_READ); -} + enum pmic_nvm_op op = NVM_READ; -int stpmic1_shadow_write_byte(u8 addr, u8 *buf) -{ - return stpmic1_nvm_rw(addr, buf, 1, SHADOW_WRITE); -} + if (offset < 0) { + op = SHADOW_READ; + offset = -offset; + } -int stpmic1_nvm_read_byte(u8 addr, u8 *buf) -{ - return stpmic1_nvm_rw(addr, buf, 1, NVM_READ); + return stpmic1_nvm_rw(dev->parent, offset, buf, size, op); } -int stpmic1_nvm_write_byte(u8 addr, u8 *buf) +static int stpmic1_nvm_write(struct udevice *dev, int offset, + const void *buf, int size) { - return stpmic1_nvm_rw(addr, buf, 1, NVM_WRITE); -} + enum pmic_nvm_op op = NVM_WRITE; -int stpmic1_nvm_read_all(u8 *buf, int buf_len) -{ - if (buf_len != STPMIC1_NVM_SIZE) - return -EINVAL; + if (offset < 0) { + op = SHADOW_WRITE; + offset = -offset; + } - return stpmic1_nvm_rw(STPMIC1_NVM_START_ADDRESS, - buf, buf_len, NVM_READ); + return stpmic1_nvm_rw(dev->parent, offset, (void *)buf, size, op); } -int stpmic1_nvm_write_all(u8 *buf, int buf_len) -{ - if (buf_len != STPMIC1_NVM_SIZE) - return -EINVAL; +static const struct misc_ops stpmic1_nvm_ops = { + .read = stpmic1_nvm_read, + .write = stpmic1_nvm_write, +}; - return stpmic1_nvm_rw(STPMIC1_NVM_START_ADDRESS, - buf, buf_len, NVM_WRITE); -} +U_BOOT_DRIVER(stpmic1_nvm) = { + .name = "stpmic1-nvm", + .id = UCLASS_MISC, + .ops = &stpmic1_nvm_ops, +}; #endif /* CONFIG_SPL_BUILD */ #ifdef CONFIG_SYSRESET static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type) { - struct udevice *pmic_dev; + struct udevice *pmic_dev = dev->parent; int ret; if (type != SYSRESET_POWER && type != SYSRESET_POWER_OFF) return -EPROTONOSUPPORT; - ret = uclass_get_device_by_driver(UCLASS_PMIC, - DM_GET_DRIVER(pmic_stpmic1), - &pmic_dev); - - if (ret) - return -EOPNOTSUPP; - ret = pmic_reg_read(pmic_dev, STPMIC1_MAIN_CR); if (ret < 0) return ret; diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 81fc71c051..ed70137ce7 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1488,6 +1488,84 @@ static void dram_all_config(struct dram_info *dram, clrsetbits_le32(&dram->cru->glb_rst_con, 0x3, 0x3); } +static void set_cap_relate_config(const struct chan_info *chan, + struct rk3399_sdram_params *params, + unsigned int channel) +{ + u32 *denali_ctl = chan->pctl->denali_ctl; + u32 tmp; + struct rk3399_msch_timings *noc_timing; + + if (params->base.dramtype == LPDDR3) { + tmp = (8 << params->ch[channel].cap_info.bw) / + (8 << params->ch[channel].cap_info.dbw); + + /** + * memdata_ratio + * 1 -> 0, 2 -> 1, 4 -> 2 + */ + clrsetbits_le32(&denali_ctl[197], 0x7, + (tmp >> 1)); + clrsetbits_le32(&denali_ctl[198], 0x7 << 8, + (tmp >> 1) << 8); + } + + noc_timing = ¶ms->ch[channel].noc_timings; + + /* + * noc timing bw relate timing is 32 bit, and real bw is 16bit + * actually noc reg is setting at function dram_all_config + */ + if (params->ch[channel].cap_info.bw == 16 && + noc_timing->ddrmode.b.mwrsize == 2) { + if (noc_timing->ddrmode.b.burstsize) + noc_timing->ddrmode.b.burstsize -= 1; + noc_timing->ddrmode.b.mwrsize -= 1; + noc_timing->ddrtimingc0.b.burstpenalty *= 2; + noc_timing->ddrtimingc0.b.wrtomwr *= 2; + } +} + +static u32 calculate_ddrconfig(struct rk3399_sdram_params *params, u32 channel) +{ + unsigned int cs0_row = params->ch[channel].cap_info.cs0_row; + unsigned int col = params->ch[channel].cap_info.col; + unsigned int bw = params->ch[channel].cap_info.bw; + u16 ddr_cfg_2_rbc[] = { + /* + * [6] highest bit col + * [5:3] max row(14+n) + * [2] insertion row + * [1:0] col(9+n),col, data bus 32bit + * + * highbitcol, max_row, insertion_row, col + */ + ((0 << 6) | (2 << 3) | (0 << 2) | 0), /* 0 */ + ((0 << 6) | (2 << 3) | (0 << 2) | 1), /* 1 */ + ((0 << 6) | (1 << 3) | (0 << 2) | 2), /* 2 */ + ((0 << 6) | (0 << 3) | (0 << 2) | 3), /* 3 */ + ((0 << 6) | (2 << 3) | (1 << 2) | 1), /* 4 */ + ((0 << 6) | (1 << 3) | (1 << 2) | 2), /* 5 */ + ((1 << 6) | (0 << 3) | (0 << 2) | 2), /* 6 */ + ((1 << 6) | (1 << 3) | (0 << 2) | 2), /* 7 */ + }; + u32 i; + + col -= (bw == 2) ? 0 : 1; + col -= 9; + + for (i = 0; i < 4; i++) { + if ((col == (ddr_cfg_2_rbc[i] & 0x3)) && + (cs0_row <= (((ddr_cfg_2_rbc[i] >> 3) & 0x7) + 14))) + break; + } + + if (i >= 4) + i = -EINVAL; + + return i; +} + #if !defined(CONFIG_RAM_RK3399_LPDDR4) static int default_data_training(struct dram_info *dram, u32 channel, u8 rank, struct rk3399_sdram_params *params) @@ -1588,84 +1666,6 @@ static void set_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf, u32 stride) rk_clrsetreg(&pmusgrf->soc_con4, 0x1f << 10, stride << 10); } -static void set_cap_relate_config(const struct chan_info *chan, - struct rk3399_sdram_params *params, - unsigned int channel) -{ - u32 *denali_ctl = chan->pctl->denali_ctl; - u32 tmp; - struct rk3399_msch_timings *noc_timing; - - if (params->base.dramtype == LPDDR3) { - tmp = (8 << params->ch[channel].cap_info.bw) / - (8 << params->ch[channel].cap_info.dbw); - - /** - * memdata_ratio - * 1 -> 0, 2 -> 1, 4 -> 2 - */ - clrsetbits_le32(&denali_ctl[197], 0x7, - (tmp >> 1)); - clrsetbits_le32(&denali_ctl[198], 0x7 << 8, - (tmp >> 1) << 8); - } - - noc_timing = ¶ms->ch[channel].noc_timings; - - /* - * noc timing bw relate timing is 32 bit, and real bw is 16bit - * actually noc reg is setting at function dram_all_config - */ - if (params->ch[channel].cap_info.bw == 16 && - noc_timing->ddrmode.b.mwrsize == 2) { - if (noc_timing->ddrmode.b.burstsize) - noc_timing->ddrmode.b.burstsize -= 1; - noc_timing->ddrmode.b.mwrsize -= 1; - noc_timing->ddrtimingc0.b.burstpenalty *= 2; - noc_timing->ddrtimingc0.b.wrtomwr *= 2; - } -} - -static u32 calculate_ddrconfig(struct rk3399_sdram_params *params, u32 channel) -{ - unsigned int cs0_row = params->ch[channel].cap_info.cs0_row; - unsigned int col = params->ch[channel].cap_info.col; - unsigned int bw = params->ch[channel].cap_info.bw; - u16 ddr_cfg_2_rbc[] = { - /* - * [6] highest bit col - * [5:3] max row(14+n) - * [2] insertion row - * [1:0] col(9+n),col, data bus 32bit - * - * highbitcol, max_row, insertion_row, col - */ - ((0 << 6) | (2 << 3) | (0 << 2) | 0), /* 0 */ - ((0 << 6) | (2 << 3) | (0 << 2) | 1), /* 1 */ - ((0 << 6) | (1 << 3) | (0 << 2) | 2), /* 2 */ - ((0 << 6) | (0 << 3) | (0 << 2) | 3), /* 3 */ - ((0 << 6) | (2 << 3) | (1 << 2) | 1), /* 4 */ - ((0 << 6) | (1 << 3) | (1 << 2) | 2), /* 5 */ - ((1 << 6) | (0 << 3) | (0 << 2) | 2), /* 6 */ - ((1 << 6) | (1 << 3) | (0 << 2) | 2), /* 7 */ - }; - u32 i; - - col -= (bw == 2) ? 0 : 1; - col -= 9; - - for (i = 0; i < 4; i++) { - if ((col == (ddr_cfg_2_rbc[i] & 0x3)) && - (cs0_row <= (((ddr_cfg_2_rbc[i] >> 3) & 0x7) + 14))) - break; - } - - if (i >= 4) - i = -EINVAL; - - return i; -} - /** * read mr_num mode register * rank = 1: cs0 @@ -2592,8 +2592,11 @@ static int sdram_init(struct dram_info *dram, } sdram_print_ddr_info(cap_info, ¶ms->base); + set_memory_map(chan, channel, params); + cap_info->ddrconfig = calculate_ddrconfig(params, channel); set_ddrconfig(chan, params, channel, cap_info->ddrconfig); + set_cap_relate_config(chan, params, channel); } if (params->base.num_channels == 0) { diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h index a8eed89e3c..52b748f3ca 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h @@ -197,10 +197,6 @@ void stm32mp1_edit_param(const struct stm32mp1_ddr_config *config, char *name, char *string); -void stm32mp1_dump_info( - const struct ddr_info *priv, - const struct stm32mp1_ddr_config *config); - bool stm32mp1_ddr_interactive( void *priv, enum stm32mp1_ddr_interact_step step, diff --git a/drivers/ram/stm32mp1/stm32mp1_tests.c b/drivers/ram/stm32mp1/stm32mp1_tests.c index b6fb2a9c58..581ee4897f 100644 --- a/drivers/ram/stm32mp1/stm32mp1_tests.c +++ b/drivers/ram/stm32mp1/stm32mp1_tests.c @@ -4,6 +4,7 @@ */ #include <common.h> #include <console.h> +#include <watchdog.h> #include <asm/io.h> #include <linux/log2.h> #include "stm32mp1_tests.h" @@ -154,6 +155,8 @@ static int test_loop_end(u32 *loop, u32 nb_loop, u32 progress) return 1; } printf("loop #%d\n", *loop); + WATCHDOG_RESET(); + return 0; } @@ -578,27 +581,29 @@ static enum test_result test_random(struct stm32mp1_ddrctl *ctl, u32 error = 0; unsigned int seed; - if (get_bufsize(string, argc, argv, 0, &bufsize, 4 * 1024)) + if (get_bufsize(string, argc, argv, 0, &bufsize, 8 * 1024)) return TEST_ERROR; if (get_nb_loop(string, argc, argv, 1, &nb_loop, 1)) return TEST_ERROR; if (get_addr(string, argc, argv, 2, &addr)) return TEST_ERROR; - printf("running %d loops at 0x%x\n", nb_loop, addr); + bufsize /= 2; + printf("running %d loops copy from 0x%x to 0x%x (buffer size=0x%x)\n", + nb_loop, addr, addr + bufsize, bufsize); while (!error) { seed = rand(); - for (offset = addr; offset < addr + bufsize; offset += 4) - writel(rand(), offset); + for (offset = 0; offset < bufsize; offset += 4) + writel(rand(), addr + offset); memcpy((void *)addr + bufsize, (void *)addr, bufsize); srand(seed); - for (offset = addr; offset < addr + 2 * bufsize; offset += 4) { - if (offset == (addr + bufsize)) + for (offset = 0; offset < 2 * bufsize; offset += 4) { + if (offset == bufsize) srand(seed); value = rand(); - error = check_addr(offset, value); + error = check_addr(addr + offset, value); if (error) break; if (progress(offset)) @@ -607,6 +612,7 @@ static enum test_result test_random(struct stm32mp1_ddrctl *ctl, if (test_loop_end(&loop, nb_loop, 100)) break; } + putc('\n'); if (error) { sprintf(string, @@ -791,9 +797,9 @@ static enum test_result test_loop(const u32 *pattern, u32 *address, int i; int j; enum test_result res = TEST_PASSED; - u32 *offset, testsize, remaining; + u32 offset, testsize, remaining; - offset = address; + offset = (u32)address; remaining = bufsize; while (remaining) { testsize = bufsize > 0x1000000 ? 0x1000000 : bufsize; @@ -809,7 +815,7 @@ static enum test_result test_loop(const u32 *pattern, u32 *address, __asm__("stmia r1!, {R3-R10}"); __asm__("stmia r1!, {R3-R10}"); __asm__("stmia r1!, {R3-R10}"); - __asm__("subs r2, r2, #8"); + __asm__("subs r2, r2, #128"); __asm__("bge loop2"); __asm__("pop {R0-R10}"); @@ -1238,27 +1244,38 @@ static enum test_result test_read(struct stm32mp1_ddrctl *ctl, u32 *addr; u32 data; u32 loop = 0; + int i, size = 1024 * 1024; bool random = false; if (get_addr(string, argc, argv, 0, (u32 *)&addr)) return TEST_ERROR; + if (get_pattern(string, argc, argv, 1, &data, 0xA5A5AA55)) + return TEST_ERROR; + if ((u32)addr == ADDR_INVALID) { - printf("random "); + printf("running random\n"); random = true; + } else { + printf("running at 0x%08x with pattern=0x%08x\n", + (u32)addr, data); + writel(data, addr); } - printf("running at 0x%08x\n", (u32)addr); - while (1) { - if (random) - addr = (u32 *)(STM32_DDR_BASE + - (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); - data = readl(addr); - if (test_loop_end(&loop, 0, 1000)) + for (i = 0; i < size; i++) { + if (random) + addr = (u32 *)(STM32_DDR_BASE + + (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); + data = readl(addr); + } + if (test_loop_end(&loop, 0, 1)) break; } - sprintf(string, "0x%x: %x", (u32)addr, data); + if (random) + sprintf(string, "%d loops random", loop); + else + sprintf(string, "%d loops at 0x%x: %x", loop, (u32)addr, data); return TEST_PASSED; } @@ -1275,31 +1292,41 @@ static enum test_result test_write(struct stm32mp1_ddrctl *ctl, char *string, int argc, char *argv[]) { u32 *addr; - u32 data = 0xA5A5AA55; + u32 data; u32 loop = 0; + int i, size = 1024 * 1024; bool random = false; if (get_addr(string, argc, argv, 0, (u32 *)&addr)) return TEST_ERROR; + if (get_pattern(string, argc, argv, 1, &data, 0xA5A5AA55)) + return TEST_ERROR; + if ((u32)addr == ADDR_INVALID) { - printf("random "); + printf("running random\n"); random = true; + } else { + printf("running at 0x%08x with pattern 0x%08x\n", + (u32)addr, data); } - printf("running at 0x%08x\n", (u32)addr); - while (1) { - if (random) { - addr = (u32 *)(STM32_DDR_BASE + - (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); - data = rand(); + for (i = 0; i < size; i++) { + if (random) { + addr = (u32 *)(STM32_DDR_BASE + + (rand() & (STM32_DDR_SIZE - 1) & ~0x3)); + data = rand(); + } + writel(data, addr); } - writel(data, addr); - if (test_loop_end(&loop, 0, 1000)) + if (test_loop_end(&loop, 0, 1)) break; } - sprintf(string, "0x%x: %x", (u32)addr, data); + if (random) + sprintf(string, "%d loops random", loop); + else + sprintf(string, "%d loops at 0x%x: %x", loop, (u32)addr, data); return TEST_PASSED; } @@ -1388,7 +1415,7 @@ const struct test_desc test[] = { "Verifies r/w and memcopy(burst for pseudo random value.", 3 }, - {test_freq_pattern, "FrequencySelectivePattern ", "[size]", + {test_freq_pattern, "FrequencySelectivePattern", "[size]", "write & test patterns: Mostly Zero, Mostly One and F/n", 1 }, @@ -1417,10 +1444,10 @@ const struct test_desc test[] = { 3 }, /* need to the the 2 last one (infinite) : skipped for test all */ - {test_read, "infinite read", "[addr]", - "basic test : infinite read access", 1}, - {test_write, "infinite write", "[addr]", - "basic test : infinite write access", 1}, + {test_read, "infinite read", "[addr] [pattern]", + "basic test : infinite read access (random: addr=0xFFFFFFFF)", 2}, + {test_write, "infinite write", "[addr] [pattern]", + "basic test : infinite write access (random: addr=0xFFFFFFFF)", 2}, }; const int test_nb = ARRAY_SIZE(test); diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c index de3b9729f3..ad941f67e8 100644 --- a/drivers/remoteproc/stm32_copro.c +++ b/drivers/remoteproc/stm32_copro.c @@ -243,7 +243,7 @@ static const struct dm_rproc_ops stm32_copro_ops = { }; static const struct udevice_id stm32_copro_ids[] = { - {.compatible = "st,stm32mp1-rproc"}, + {.compatible = "st,stm32mp1-m4"}, {} }; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 860b73d369..8778cc7b26 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -31,6 +31,12 @@ config TPL_DM_RTC drivers to perform the actual functions. See rtc.h for a description of the API. +config RTC_ENABLE_32KHZ_OUTPUT + bool "Enable RTC 32Khz output" + help + Some real-time clocks support the output of 32kHz square waves (such as ds3231), + the config symbol choose Real Time Clock device 32Khz output feature. + config RTC_PCF2127 bool "Enable PCF2127 driver" depends on DM_RTC diff --git a/drivers/rtc/ds3231.c b/drivers/rtc/ds3231.c index 79b026af4b..fde4d860ec 100644 --- a/drivers/rtc/ds3231.c +++ b/drivers/rtc/ds3231.c @@ -148,11 +148,13 @@ void rtc_reset (void) /* * Enable 32KHz output */ +#ifdef CONFIG_RTC_ENABLE_32KHZ_OUTPUT void rtc_enable_32khz_output(void) { rtc_write(RTC_STAT_REG_ADDR, RTC_STAT_BIT_BB32KHZ | RTC_STAT_BIT_EN32KHZ); } +#endif /* * Helper functions @@ -251,6 +253,21 @@ static int ds3231_probe(struct udevice *dev) return 0; } +#ifdef CONFIG_RTC_ENABLE_32KHZ_OUTPUT +int rtc_enable_32khz_output(int busnum, int chip_addr) +{ + int ret; + struct udevice *dev; + + ret = i2c_get_chip_for_busnum(busnum, chip_addr, 1, &dev); + if (!ret) + ret = dm_i2c_reg_write(dev, RTC_STAT_REG_ADDR, + RTC_STAT_BIT_BB32KHZ | + RTC_STAT_BIT_EN32KHZ); + return ret; +} +#endif + static const struct rtc_ops ds3231_rtc_ops = { .get = ds3231_rtc_get, .set = ds3231_rtc_set, diff --git a/drivers/rtc/stm32_rtc.c b/drivers/rtc/stm32_rtc.c index abd339076a..2674714442 100644 --- a/drivers/rtc/stm32_rtc.c +++ b/drivers/rtc/stm32_rtc.c @@ -72,7 +72,8 @@ static int stm32_rtc_get(struct udevice *dev, struct rtc_time *tm) tm->tm_mday = bcd2bin((dr & STM32_RTC_DATE) >> STM32_RTC_DATE_SHIFT); tm->tm_mon = bcd2bin((dr & STM32_RTC_MONTH) >> STM32_RTC_MONTH_SHIFT); - tm->tm_year = bcd2bin((dr & STM32_RTC_YEAR) >> STM32_RTC_YEAR_SHIFT); + tm->tm_year = 2000 + + bcd2bin((dr & STM32_RTC_YEAR) >> STM32_RTC_YEAR_SHIFT); tm->tm_wday = bcd2bin((dr & STM32_RTC_WDAY) >> STM32_RTC_WDAY_SHIFT); tm->tm_yday = 0; tm->tm_isdst = 0; @@ -174,6 +175,9 @@ static int stm32_rtc_set(struct udevice *dev, const struct rtc_time *tm) tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); + if (tm->tm_year < 2000 || tm->tm_year > 2099) + return -EINVAL; + /* Time in BCD format */ t = (bin2bcd(tm->tm_sec) << STM32_RTC_SEC_SHIFT) & STM32_RTC_SEC; t |= (bin2bcd(tm->tm_min) << STM32_RTC_MIN_SHIFT) & STM32_RTC_MIN; @@ -182,7 +186,8 @@ static int stm32_rtc_set(struct udevice *dev, const struct rtc_time *tm) /* Date in BCD format */ d = (bin2bcd(tm->tm_mday) << STM32_RTC_DATE_SHIFT) & STM32_RTC_DATE; d |= (bin2bcd(tm->tm_mon) << STM32_RTC_MONTH_SHIFT) & STM32_RTC_MONTH; - d |= (bin2bcd(tm->tm_year) << STM32_RTC_YEAR_SHIFT) & STM32_RTC_YEAR; + d |= (bin2bcd(tm->tm_year - 2000) << STM32_RTC_YEAR_SHIFT) & + STM32_RTC_YEAR; d |= (bin2bcd(tm->tm_wday) << STM32_RTC_WDAY_SHIFT) & STM32_RTC_WDAY; return stm32_rtc_set_time(dev, t, d); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 8a447fd6e3..ae2d819ba9 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -45,7 +45,7 @@ config SERIAL_PRESENT config SPL_SERIAL_PRESENT bool "Provide a serial driver in SPL" - depends on DM_SERIAL + depends on DM_SERIAL && SPL default y help In very space-constrained devices even the full UART driver is too @@ -55,7 +55,7 @@ config SPL_SERIAL_PRESENT config TPL_SERIAL_PRESENT bool "Provide a serial driver in TPL" - depends on DM_SERIAL + depends on DM_SERIAL && TPL default y help In very space-constrained devices even the full UART driver is too diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index 3ab536a52a..00a8e7249b 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -106,10 +106,11 @@ static int stm32_serial_getc(struct udevice *dev) if ((isr & USART_ISR_RXNE) == 0) return -EAGAIN; - if (isr & (USART_ISR_PE | USART_ISR_ORE)) { + if (isr & (USART_ISR_PE | USART_ISR_ORE | USART_ISR_FE)) { if (!stm32f4) setbits_le32(base + ICR_OFFSET, - USART_ICR_PCECF | USART_ICR_ORECF); + USART_ICR_PCECF | USART_ICR_ORECF | + USART_ICR_FECF); else readl(base + RDR_OFFSET(stm32f4)); return -EIO; diff --git a/drivers/serial/serial_stm32.h b/drivers/serial/serial_stm32.h index 5549f8c536..7b0c53145e 100644 --- a/drivers/serial/serial_stm32.h +++ b/drivers/serial/serial_stm32.h @@ -67,6 +67,7 @@ struct stm32x7_serial_platdata { #define USART_ISR_TXE BIT(7) #define USART_ISR_RXNE BIT(5) #define USART_ISR_ORE BIT(3) +#define USART_ISR_FE BIT(1) #define USART_ISR_PE BIT(0) #define USART_BRR_F_MASK GENMASK(7, 0) @@ -74,6 +75,7 @@ struct stm32x7_serial_platdata { #define USART_BRR_M_MASK GENMASK(15, 4) #define USART_ICR_ORECF BIT(3) +#define USART_ICR_FECF BIT(1) #define USART_ICR_PCECF BIT(0) #endif |