From 2242ac5d800916058bd9f4e4380ceeac40025305 Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Tue, 26 Jul 2022 01:43:42 -0400 Subject: clk: imx: Add i.MXRT11xx pllv3 variant The i.MXRT11 series has two new pll types but are variants of existing. This patch adds the ability to read one of the pll types' frequency as it can't be changed unlike the generic pll it also has the division factors swapped. Signed-off-by: Jesse Taube --- drivers/clk/imx/clk-pllv3.c | 56 ++++++++++++++++++++++++++++++++++++++++++--- drivers/clk/imx/clk.h | 1 + 2 files changed, 54 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index 077757efcb8..fad306aeed2 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -21,19 +21,23 @@ #define UBOOT_DM_CLK_IMX_PLLV3_USB "imx_clk_pllv3_usb" #define UBOOT_DM_CLK_IMX_PLLV3_AV "imx_clk_pllv3_av" #define UBOOT_DM_CLK_IMX_PLLV3_ENET "imx_clk_pllv3_enet" +#define UBOOT_DM_CLK_IMX_PLLV3_GENV2 "imx_clk_pllv3_genericv2" #define PLL_NUM_OFFSET 0x10 #define PLL_DENOM_OFFSET 0x20 #define BM_PLL_POWER (0x1 << 12) +#define BM_PLL_POWER_V2 (0x1 << 21) #define BM_PLL_ENABLE (0x1 << 13) #define BM_PLL_LOCK (0x1 << 31) +#define BM_PLL_LOCK_V2 (0x1 << 29) struct clk_pllv3 { struct clk clk; void __iomem *base; u32 power_bit; bool powerup_set; + u32 lock_bit; u32 enable_bit; u32 div_mask; u32 div_shift; @@ -42,6 +46,30 @@ struct clk_pllv3 { #define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk) +static ulong clk_pllv3_genericv2_get_rate(struct clk *clk) +{ + struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev)); + unsigned long parent_rate = clk_get_parent_rate(clk); + + u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask; + + return (div == 0) ? parent_rate * 22 : parent_rate * 20; +} + +static ulong clk_pllv3_genericv2_set_rate(struct clk *clk, ulong rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + unsigned long parent_rate = clk_get_parent_rate(clk); + + u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask; + u32 val = (div == 0) ? parent_rate * 22 : parent_rate * 20; + + if (rate == val) + return 0; + + return -EINVAL; +} + static ulong clk_pllv3_generic_get_rate(struct clk *clk) { struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev)); @@ -71,7 +99,7 @@ static ulong clk_pllv3_generic_set_rate(struct clk *clk, ulong rate) writel(val, pll->base); /* Wait for PLL to lock */ - while (!(readl(pll->base) & BM_PLL_LOCK)) + while (!(readl(pll->base) & pll->lock_bit)) ; return 0; @@ -120,6 +148,13 @@ static const struct clk_ops clk_pllv3_generic_ops = { .set_rate = clk_pllv3_generic_set_rate, }; +static const struct clk_ops clk_pllv3_genericv2_ops = { + .get_rate = clk_pllv3_genericv2_get_rate, + .enable = clk_pllv3_generic_enable, + .disable = clk_pllv3_generic_disable, + .set_rate = clk_pllv3_genericv2_set_rate, +}; + static ulong clk_pllv3_sys_get_rate(struct clk *clk) { struct clk_pllv3 *pll = to_clk_pllv3(clk); @@ -153,7 +188,7 @@ static ulong clk_pllv3_sys_set_rate(struct clk *clk, ulong rate) writel(val, pll->base); /* Wait for PLL to lock */ - while (!(readl(pll->base) & BM_PLL_LOCK)) + while (!(readl(pll->base) & pll->lock_bit)) ; return 0; @@ -221,7 +256,7 @@ static ulong clk_pllv3_av_set_rate(struct clk *clk, ulong rate) writel(mfd, pll->base + PLL_DENOM_OFFSET); /* Wait for PLL to lock */ - while (!(readl(pll->base) & BM_PLL_LOCK)) + while (!(readl(pll->base) & pll->lock_bit)) ; return 0; @@ -262,6 +297,7 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, pll->power_bit = BM_PLL_POWER; pll->enable_bit = BM_PLL_ENABLE; + pll->lock_bit = BM_PLL_LOCK; switch (type) { case IMX_PLLV3_GENERIC: @@ -269,6 +305,13 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, pll->div_shift = 0; pll->powerup_set = false; break; + case IMX_PLLV3_GENERICV2: + pll->power_bit = BM_PLL_POWER_V2; + pll->lock_bit = BM_PLL_LOCK_V2; + drv_name = UBOOT_DM_CLK_IMX_PLLV3_GENV2; + pll->div_shift = 0; + pll->powerup_set = false; + break; case IMX_PLLV3_SYS: drv_name = UBOOT_DM_CLK_IMX_PLLV3_SYS; pll->div_shift = 0; @@ -313,6 +356,13 @@ U_BOOT_DRIVER(clk_pllv3_generic) = { .flags = DM_FLAG_PRE_RELOC, }; +U_BOOT_DRIVER(clk_pllv3_genericv2) = { + .name = UBOOT_DM_CLK_IMX_PLLV3_GENV2, + .id = UCLASS_CLK, + .ops = &clk_pllv3_genericv2_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + U_BOOT_DRIVER(clk_pllv3_sys) = { .name = UBOOT_DM_CLK_IMX_PLLV3_SYS, .id = UCLASS_CLK, diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 0e1eaf03d41..46dee35a673 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -10,6 +10,7 @@ enum imx_pllv3_type { IMX_PLLV3_GENERIC, + IMX_PLLV3_GENERICV2, IMX_PLLV3_SYS, IMX_PLLV3_USB, IMX_PLLV3_USB_VF610, -- cgit v1.3.1 From 79f7632e80e35461812015582e38ea2ff8fe2b8a Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Tue, 26 Jul 2022 01:43:43 -0400 Subject: clk: imx: Add initial support for i.MXRT1170 clock driver Add clock driver support for i.MXRT1170. Signed-off-by: Jesse Taube --- drivers/clk/imx/Kconfig | 16 +++ drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imxrt1170.c | 221 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 drivers/clk/imx/clk-imxrt1170.c (limited to 'drivers') diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 04d252a1e03..abcb19ce6d5 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -124,3 +124,19 @@ config CLK_IMXRT1050 select CLK_COMPOSITE_CCF help This enables support clock driver for i.MXRT1050 platforms. + +config SPL_CLK_IMXRT1170 + bool "SPL clock support for i.MXRT1170" + depends on ARCH_IMXRT && SPL + select SPL_CLK + select SPL_CLK_CCF + help + This enables SPL DM/DTS support for clock driver in i.MXRT1170. + +config CLK_IMXRT1170 + bool "Clock support for i.MXRT1170" + depends on ARCH_IMXRT + select CLK + select CLK_CCF + help + This enables support clock driver for i.MXRT1170 platforms. diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index c5766901f2b..b9c197f952e 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MQ) += clk-imx8mq.o clk-pll14xx.o \ obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1020) += clk-imxrt1020.o obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o +obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1170) += clk-imxrt1170.o diff --git a/drivers/clk/imx/clk-imxrt1170.c b/drivers/clk/imx/clk-imxrt1170.c new file mode 100644 index 00000000000..077dd1bf02d --- /dev/null +++ b/drivers/clk/imx/clk-imxrt1170.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022 + * Author(s): Jesse Taube + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static ulong imxrt1170_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 imxrt1170_clk_set_rate(struct clk *clk, ulong 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 __imxrt1170_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 imxrt1170_clk_disable(struct clk *clk) +{ + return __imxrt1170_clk_enable(clk, 0); +} + +static int imxrt1170_clk_enable(struct clk *clk) +{ + return __imxrt1170_clk_enable(clk, 1); +} + +static int imxrt1170_clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk *c, *cp; + int ret; + + debug("%s(#%lu), parent: %lu\n", __func__, clk->id, parent->id); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + ret = clk_get_by_id(parent->id, &cp); + if (ret) + return ret; + + return clk_set_parent(c, cp); +} + +static struct clk_ops imxrt1170_clk_ops = { + .set_rate = imxrt1170_clk_set_rate, + .get_rate = imxrt1170_clk_get_rate, + .enable = imxrt1170_clk_enable, + .disable = imxrt1170_clk_disable, + .set_parent = imxrt1170_clk_set_parent, +}; + +static const char * const lpuart1_sels[] = {"rcosc48M_div2", "osc", "rcosc400M", "rcosc16M", +"pll3_div2", "pll1_div5", "pll2_sys", "pll2_pfd3"}; +static const char * const gpt1_sels[] = {"rcosc48M_div2", "osc", "rcosc400M", "rcosc16M", +"pll3_div2", "pll1_div5", "pll3_pfd2", "pll3_pfd3"}; +static const char * const usdhc1_sels[] = {"rcosc48M_div2", "osc", "rcosc400M", "rcosc16M", +"pll2_pfd2", "pll2_pfd0", "pll1_div5", "pll_arm"}; +static const char * const semc_sels[] = {"rcosc48M_div2", "osc", "rcosc400M", "rcosc16M", +"pll1_div5", "pll2_sys", "pll2_pfd2", "pll3_pfd0"}; + +static int imxrt1170_clk_probe(struct udevice *dev) +{ + void *base; + + /* Anatop clocks */ + base = (void *)ofnode_get_addr(ofnode_by_compatible(ofnode_null(), "fsl,imxrt-anatop")); + + + + clk_dm(IMXRT1170_CLK_RCOSC_48M, + imx_clk_fixed_factor("rcosc48M", "rcosc16M", 3, 1)); + clk_dm(IMXRT1170_CLK_RCOSC_400M, + imx_clk_fixed_factor("rcosc400M", "rcosc16M", 25, 1)); + clk_dm(IMXRT1170_CLK_RCOSC_48M_DIV2, + imx_clk_fixed_factor("rcosc48M_div2", "rcosc48M", 1, 2)); + + + clk_dm(IMXRT1170_CLK_PLL_ARM, + imx_clk_pllv3(IMX_PLLV3_SYS, "pll_arm", "osc", + base + 0x200, 0xff)); + clk_dm(IMXRT1170_CLK_PLL3, + imx_clk_pllv3(IMX_PLLV3_GENERICV2, "pll3_sys", "osc", + base + 0x210, 1)); + clk_dm(IMXRT1170_CLK_PLL2, + imx_clk_pllv3(IMX_PLLV3_GENERICV2, "pll2_sys", "osc", + base + 0x240, 1)); + + clk_dm(IMXRT1170_CLK_PLL3_PFD0, + imx_clk_pfd("pll3_pfd0", "pll3_sys", base + 0x230, 0)); + clk_dm(IMXRT1170_CLK_PLL3_PFD1, + imx_clk_pfd("pll3_pfd1", "pll3_sys", base + 0x230, 1)); + clk_dm(IMXRT1170_CLK_PLL3_PFD2, + imx_clk_pfd("pll3_pfd2", "pll3_sys", base + 0x230, 2)); + clk_dm(IMXRT1170_CLK_PLL3_PFD3, + imx_clk_pfd("pll3_pfd3", "pll3_sys", base + 0x230, 3)); + + clk_dm(IMXRT1170_CLK_PLL2_PFD0, + imx_clk_pfd("pll2_pfd0", "pll2_sys", base + 0x270, 0)); + clk_dm(IMXRT1170_CLK_PLL2_PFD1, + imx_clk_pfd("pll2_pfd1", "pll2_sys", base + 0x270, 1)); + clk_dm(IMXRT1170_CLK_PLL2_PFD2, + imx_clk_pfd("pll2_pfd2", "pll2_sys", base + 0x270, 2)); + clk_dm(IMXRT1170_CLK_PLL2_PFD3, + imx_clk_pfd("pll2_pfd3", "pll2_sys", base + 0x270, 3)); + + clk_dm(IMXRT1170_CLK_PLL3_DIV2, + imx_clk_fixed_factor("pll3_div2", "pll3_sys", 1, 2)); + + /* CCM clocks */ + base = dev_read_addr_ptr(dev); + if (base == (void *)FDT_ADDR_T_NONE) + return -EINVAL; + + clk_dm(IMXRT1170_CLK_LPUART1_SEL, + imx_clk_mux("lpuart1_sel", base + (25 * 0x80), 8, 3, + lpuart1_sels, ARRAY_SIZE(lpuart1_sels))); + clk_dm(IMXRT1170_CLK_LPUART1, + imx_clk_divider("lpuart1", "lpuart1_sel", + base + (25 * 0x80), 0, 8)); + + clk_dm(IMXRT1170_CLK_USDHC1_SEL, + imx_clk_mux("usdhc1_sel", base + (58 * 0x80), 8, 3, + usdhc1_sels, ARRAY_SIZE(usdhc1_sels))); + clk_dm(IMXRT1170_CLK_USDHC1, + imx_clk_divider("usdhc1", "usdhc1_sel", + base + (58 * 0x80), 0, 8)); + + clk_dm(IMXRT1170_CLK_GPT1_SEL, + imx_clk_mux("gpt1_sel", base + (14 * 0x80), 8, 3, + gpt1_sels, ARRAY_SIZE(gpt1_sels))); + clk_dm(IMXRT1170_CLK_GPT1, + imx_clk_divider("gpt1", "gpt1_sel", + base + (14 * 0x80), 0, 8)); + + clk_dm(IMXRT1170_CLK_SEMC_SEL, + imx_clk_mux("semc_sel", base + (4 * 0x80), 8, 3, + semc_sels, ARRAY_SIZE(semc_sels))); + clk_dm(IMXRT1170_CLK_SEMC, + imx_clk_divider("semc", "semc_sel", + base + (4 * 0x80), 0, 8)); + struct clk *clk, *clk1; + + clk_get_by_id(IMXRT1170_CLK_PLL2_PFD2, &clk); + + clk_get_by_id(IMXRT1170_CLK_SEMC_SEL, &clk1); + clk_enable(clk1); + clk_set_parent(clk1, clk); + + clk_get_by_id(IMXRT1170_CLK_SEMC, &clk); + clk_enable(clk); + clk_set_rate(clk, 132000000UL); + + clk_get_by_id(IMXRT1170_CLK_GPT1, &clk); + clk_enable(clk); + clk_set_rate(clk, 32000000UL); + + return 0; +} + +static const struct udevice_id imxrt1170_clk_ids[] = { + { .compatible = "fsl,imxrt1170-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imxrt1170_clk) = { + .name = "clk_imxrt1170", + .id = UCLASS_CLK, + .of_match = imxrt1170_clk_ids, + .ops = &imxrt1170_clk_ops, + .probe = imxrt1170_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; -- cgit v1.3.1 From 7d9c6f1781be08512703aa1aa2f6bb9b17b7150f Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Tue, 26 Jul 2022 01:43:44 -0400 Subject: RAM: Add changes for i.MXRT11xx series The i.MXRT11 series has different offsets for IOCR_MUX, it also can address 64MiB of SDRAM so add a macro for that. Signed-off-by: Jesse Taube --- drivers/ram/imxrt_sdram.c | 9 +++++++++ include/dt-bindings/memory/imxrt-sdram.h | 1 + 2 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/ram/imxrt_sdram.c b/drivers/ram/imxrt_sdram.c index ca2eec767d7..d0a88845cf9 100644 --- a/drivers/ram/imxrt_sdram.c +++ b/drivers/ram/imxrt_sdram.c @@ -87,12 +87,21 @@ struct imxrt_semc_regs { u32 sts[16]; }; +#if !defined(TARGET_IMXRT1170_EVK) #define SEMC_IOCR_MUX_A8_SHIFT 0 #define SEMC_IOCR_MUX_CSX0_SHIFT 3 #define SEMC_IOCR_MUX_CSX1_SHIFT 6 #define SEMC_IOCR_MUX_CSX2_SHIFT 9 #define SEMC_IOCR_MUX_CSX3_SHIFT 12 #define SEMC_IOCR_MUX_RDY_SHIFT 15 +#else +#define SEMC_IOCR_MUX_A8_SHIFT 0 +#define SEMC_IOCR_MUX_CSX0_SHIFT 4 +#define SEMC_IOCR_MUX_CSX1_SHIFT 8 +#define SEMC_IOCR_MUX_CSX2_SHIFT 12 +#define SEMC_IOCR_MUX_CSX3_SHIFT 16 +#define SEMC_IOCR_MUX_RDY_SHIFT 20 +#endif struct imxrt_sdram_mux { u8 a8; diff --git a/include/dt-bindings/memory/imxrt-sdram.h b/include/dt-bindings/memory/imxrt-sdram.h index acb35bce277..4b3b0c2f504 100644 --- a/include/dt-bindings/memory/imxrt-sdram.h +++ b/include/dt-bindings/memory/imxrt-sdram.h @@ -82,6 +82,7 @@ #define MEM_WIDTH_8BITS 0x0 #define MEM_WIDTH_16BITS 0x1 +#define MEM_WIDTH_32BITS 0x2 #define BL_1 0x0 #define BL_2 0x1 -- cgit v1.3.1 From 41460786884691a804091c4b1f125be68e4a0820 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Fri, 29 Jul 2022 15:32:23 +0530 Subject: crypto/fsl: fsl_hash: Fix crash in flush dcache wrong end address passed to flush_dcache_range. modified the flush_dache logic for scatter list elements. Fixes: 1919f58a8f (crypto/fsl: fsl_hash: Fix dcache issue in caam_hash_finish) Signed-off-by: Gaurav Jain --- drivers/crypto/fsl/fsl_hash.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/fsl/fsl_hash.c b/drivers/crypto/fsl/fsl_hash.c index 575196778cc..f22f24b6077 100644 --- a/drivers/crypto/fsl/fsl_hash.c +++ b/drivers/crypto/fsl/fsl_hash.c @@ -131,25 +131,35 @@ static int caam_hash_update(void *hash_ctx, const void *buf, static int caam_hash_finish(void *hash_ctx, void *dest_buf, int size, enum caam_hash_algos caam_algo) { - uint32_t len = 0; + uint32_t len = 0, sg_entry_len; struct sha_ctx *ctx = hash_ctx; int i = 0, ret = 0; + caam_dma_addr_t addr; if (size < driver_hash[caam_algo].digestsize) { return -EINVAL; } - for (i = 0; i < ctx->sg_num; i++) - len += (sec_in32(&ctx->sg_tbl[i].len_flag) & - SG_ENTRY_LENGTH_MASK); - + flush_dcache_range((ulong)ctx->sg_tbl, + (ulong)(ctx->sg_tbl) + (ctx->sg_num * sizeof(struct sg_entry))); + for (i = 0; i < ctx->sg_num; i++) { + sg_entry_len = (sec_in32(&ctx->sg_tbl[i].len_flag) & + SG_ENTRY_LENGTH_MASK); + len += sg_entry_len; +#ifdef CONFIG_CAAM_64BIT + addr = sec_in32(&ctx->sg_tbl[i].addr_hi); + addr = (addr << 32) | sec_in32(&ctx->sg_tbl[i].addr_lo); +#else + addr = sec_in32(&ctx->sg_tbl[i].addr_lo); +#endif + flush_dcache_range(addr, addr + sg_entry_len); + } inline_cnstr_jobdesc_hash(ctx->sha_desc, (uint8_t *)ctx->sg_tbl, len, ctx->hash, driver_hash[caam_algo].alg_type, driver_hash[caam_algo].digestsize, 1); - flush_dcache_range((ulong)ctx->sg_tbl, (ulong)(ctx->sg_tbl) + len); flush_dcache_range((ulong)ctx->sha_desc, (ulong)(ctx->sha_desc) + (sizeof(uint32_t) * MAX_CAAM_DESCSIZE)); flush_dcache_range((ulong)ctx->hash, -- cgit v1.3.1 From 7e9bd84883aeb1e241c21ee267db623aee881c05 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 19 Aug 2022 13:02:23 +0200 Subject: imx8m: ddrphy_utils: Remove unused file The ddrphy_utils.c is now deduplicated in drivers/ddr/imx/phy/ddrphy_utils.c , this drivers/ddr/imx/imx8m/ddrphy_utils.c is a remnant from when the deduplication was implemented and was not removed. Remove it as it is unused. Signed-off-by: Marek Vasut Cc: Fabio Estevam Cc: Peng Fan Cc: Stefano Babic Cc: Ye Li Cc: uboot-imx Reviewed-by: Fabio Estevam Reviewed-by: Peng Fan --- drivers/ddr/imx/imx8m/ddrphy_utils.c | 369 ----------------------------------- 1 file changed, 369 deletions(-) delete mode 100644 drivers/ddr/imx/imx8m/ddrphy_utils.c (limited to 'drivers') diff --git a/drivers/ddr/imx/imx8m/ddrphy_utils.c b/drivers/ddr/imx/imx8m/ddrphy_utils.c deleted file mode 100644 index 975d553674a..00000000000 --- a/drivers/ddr/imx/imx8m/ddrphy_utils.c +++ /dev/null @@ -1,369 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2018 NXP - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned int g_cdd_rr_max[4]; -static unsigned int g_cdd_rw_max[4]; -static unsigned int g_cdd_wr_max[4]; -static unsigned int g_cdd_ww_max[4]; - -static inline void poll_pmu_message_ready(void) -{ - unsigned int reg; - - do { - reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0004); - } while (reg & 0x1); -} - -static inline void ack_pmu_message_receive(void) -{ - unsigned int reg; - - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0031, 0x0); - - do { - reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0004); - } while (!(reg & 0x1)); - - reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0031, 0x1); -} - -static inline unsigned int get_mail(void) -{ - unsigned int reg; - - poll_pmu_message_ready(); - - reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0032); - - ack_pmu_message_receive(); - - return reg; -} - -static inline unsigned int get_stream_message(void) -{ - unsigned int reg, reg2; - - poll_pmu_message_ready(); - - reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0032); - - reg2 = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * 0xd0034); - - reg2 = (reg2 << 16) | reg; - - ack_pmu_message_receive(); - - return reg2; -} - -static inline void decode_major_message(unsigned int mail) -{ - debug("[PMU Major message = 0x%08x]\n", mail); -} - -static inline void decode_streaming_message(void) -{ - unsigned int string_index, arg __maybe_unused; - int i = 0; - - string_index = get_stream_message(); - debug("PMU String index = 0x%08x\n", string_index); - while (i < (string_index & 0xffff)) { - arg = get_stream_message(); - debug("arg[%d] = 0x%08x\n", i, arg); - i++; - } - - debug("\n"); -} - -int wait_ddrphy_training_complete(void) -{ - unsigned int mail; - - while (1) { - mail = get_mail(); - decode_major_message(mail); - if (mail == 0x08) { - decode_streaming_message(); - } else if (mail == 0x07) { - debug("Training PASS\n"); - return 0; - } else if (mail == 0xff) { - debug("Training FAILED\n"); - return -1; - } - } -} - -void ddrphy_init_set_dfi_clk(unsigned int drate) -{ - switch (drate) { - case 4000: - dram_pll_init(MHZ(1000)); - dram_disable_bypass(); - break; - case 3732: - dram_pll_init(MHZ(933)); - dram_disable_bypass(); - break; - case 3200: - dram_pll_init(MHZ(800)); - dram_disable_bypass(); - break; - case 3000: - dram_pll_init(MHZ(750)); - dram_disable_bypass(); - break; - case 2400: - dram_pll_init(MHZ(600)); - dram_disable_bypass(); - break; - case 1600: - dram_pll_init(MHZ(400)); - dram_disable_bypass(); - break; - case 1066: - dram_pll_init(MHZ(266)); - dram_disable_bypass(); - break; - case 667: - dram_pll_init(MHZ(167)); - dram_disable_bypass(); - break; - case 400: - dram_enable_bypass(MHZ(400)); - break; - case 100: - dram_enable_bypass(MHZ(100)); - break; - default: - return; - } -} - -void ddrphy_init_read_msg_block(enum fw_type type) -{ -} - -void lpddr4_mr_write(unsigned int mr_rank, unsigned int mr_addr, - unsigned int mr_data) -{ - unsigned int tmp; - /* - * 1. Poll MRSTAT.mr_wr_busy until it is 0. - * This checks that there is no outstanding MR transaction. - * No writes should be performed to MRCTRL0 and MRCTRL1 if - * MRSTAT.mr_wr_busy = 1. - */ - do { - tmp = reg32_read(DDRC_MRSTAT(0)); - } while (tmp & 0x1); - /* - * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank and - * (for MRWs) MRCTRL1.mr_data to define the MR transaction. - */ - reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4)); - reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8) | mr_data); - reg32setbit(DDRC_MRCTRL0(0), 31); -} - -unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr) -{ - unsigned int tmp; - - reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x1); - do { - tmp = reg32_read(DDRC_MRSTAT(0)); - } while (tmp & 0x1); - - reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4) | 0x1); - reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8)); - reg32setbit(DDRC_MRCTRL0(0), 31); - do { - tmp = reg32_read(DRC_PERF_MON_MRR0_DAT(0)); - } while ((tmp & 0x8) == 0); - tmp = reg32_read(DRC_PERF_MON_MRR1_DAT(0)); - reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x4); - while (tmp) { //try to find a significant byte in the word - if (tmp & 0xff) { - tmp &= 0xff; - break; - } - tmp >>= 8; - } - return tmp; -} - -unsigned int look_for_max(unsigned int data[], - unsigned int addr_start, unsigned int addr_end) -{ - unsigned int i, imax = 0; - - for (i = addr_start; i <= addr_end; i++) { - if (((data[i] >> 7) == 0) && (data[i] > imax)) - imax = data[i]; - } - - return imax; -} - -void get_trained_CDD(u32 fsp) -{ - unsigned int i, ddr_type, tmp; - unsigned int cdd_cha[12], cdd_chb[12]; - unsigned int cdd_cha_rr_max, cdd_cha_rw_max, cdd_cha_wr_max, cdd_cha_ww_max; - unsigned int cdd_chb_rr_max, cdd_chb_rw_max, cdd_chb_wr_max, cdd_chb_ww_max; - - ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f; - if (ddr_type == 0x20) { - for (i = 0; i < 6; i++) { - tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54013 + i) * 4); - cdd_cha[i * 2] = tmp & 0xff; - cdd_cha[i * 2 + 1] = (tmp >> 8) & 0xff; - } - - for (i = 0; i < 7; i++) { - tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x5402c + i) * 4); - if (i == 0) { - cdd_cha[0] = (tmp >> 8) & 0xff; - } else if (i == 6) { - cdd_cha[11] = tmp & 0xff; - } else { - cdd_chb[i * 2 - 1] = tmp & 0xff; - cdd_chb[i * 2] = (tmp >> 8) & 0xff; - } - } - - cdd_cha_rr_max = look_for_max(cdd_cha, 0, 1); - cdd_cha_rw_max = look_for_max(cdd_cha, 2, 5); - cdd_cha_wr_max = look_for_max(cdd_cha, 6, 9); - cdd_cha_ww_max = look_for_max(cdd_cha, 10, 11); - cdd_chb_rr_max = look_for_max(cdd_chb, 0, 1); - cdd_chb_rw_max = look_for_max(cdd_chb, 2, 5); - cdd_chb_wr_max = look_for_max(cdd_chb, 6, 9); - cdd_chb_ww_max = look_for_max(cdd_chb, 10, 11); - g_cdd_rr_max[fsp] = cdd_cha_rr_max > cdd_chb_rr_max ? cdd_cha_rr_max : cdd_chb_rr_max; - g_cdd_rw_max[fsp] = cdd_cha_rw_max > cdd_chb_rw_max ? cdd_cha_rw_max : cdd_chb_rw_max; - g_cdd_wr_max[fsp] = cdd_cha_wr_max > cdd_chb_wr_max ? cdd_cha_wr_max : cdd_chb_wr_max; - g_cdd_ww_max[fsp] = cdd_cha_ww_max > cdd_chb_ww_max ? cdd_cha_ww_max : cdd_chb_ww_max; - } else { - unsigned int ddr4_cdd[64]; - - for (i = 0; i < 29; i++) { - tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54012 + i) * 4); - ddr4_cdd[i * 2] = tmp & 0xff; - ddr4_cdd[i * 2 + 1] = (tmp >> 8) & 0xff; - } - - g_cdd_rr_max[fsp] = look_for_max(ddr4_cdd, 1, 12); - g_cdd_ww_max[fsp] = look_for_max(ddr4_cdd, 13, 24); - g_cdd_rw_max[fsp] = look_for_max(ddr4_cdd, 25, 40); - g_cdd_wr_max[fsp] = look_for_max(ddr4_cdd, 41, 56); - } -} - -void update_umctl2_rank_space_setting(unsigned int pstat_num) -{ - unsigned int i, ddr_type; - unsigned int addr_slot, rdata, tmp, tmp_t; - unsigned int ddrc_w2r, ddrc_r2w, ddrc_wr_gap, ddrc_rd_gap; - - ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f; - for (i = 0; i < pstat_num; i++) { - addr_slot = i ? (i + 1) * 0x1000 : 0; - if (ddr_type == 0x20) { - /* update r2w:[13:8], w2r:[5:0] */ - rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot); - ddrc_w2r = rdata & 0x3f; - if (is_imx8mp()) - tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1); - else - tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1; - ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp; - - ddrc_r2w = (rdata >> 8) & 0x3f; - if (is_imx8mp()) - tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1); - else - tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1; - ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp; - - tmp_t = (rdata & 0xffffc0c0) | (ddrc_r2w << 8) | ddrc_w2r; - reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t); - } else { - /* update w2r:[5:0] */ - rdata = reg32_read(DDRC_DRAMTMG9(0) + addr_slot); - ddrc_w2r = rdata & 0x3f; - if (is_imx8mp()) - tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1); - else - tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1; - ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp; - tmp_t = (rdata & 0xffffffc0) | ddrc_w2r; - reg32_write((DDRC_DRAMTMG9(0) + addr_slot), tmp_t); - - /* update r2w:[13:8] */ - rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot); - ddrc_r2w = (rdata >> 8) & 0x3f; - if (is_imx8mp()) - tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1); - else - tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1; - ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp; - - tmp_t = (rdata & 0xffffc0ff) | (ddrc_r2w << 8); - reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t); - } - - if (!is_imx8mq()) { - /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */ - rdata = reg32_read(DDRC_RANKCTL(0) + addr_slot); - ddrc_wr_gap = (rdata >> 8) & 0xf; - if (is_imx8mp()) - tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1); - else - tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1) + 1; - ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp; - - ddrc_rd_gap = (rdata >> 4) & 0xf; - if (is_imx8mp()) - tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1); - else - tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1) + 1; - ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp; - - tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4); - reg32_write((DDRC_RANKCTL(0) + addr_slot), tmp_t); - } - } - - if (is_imx8mq()) { - /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */ - rdata = reg32_read(DDRC_RANKCTL(0)); - ddrc_wr_gap = (rdata >> 8) & 0xf; - tmp = ddrc_wr_gap + (g_cdd_ww_max[0] >> 1) + 1; - ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp; - - ddrc_rd_gap = (rdata >> 4) & 0xf; - tmp = ddrc_rd_gap + (g_cdd_rr_max[0] >> 1) + 1; - ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp; - - tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4); - reg32_write(DDRC_RANKCTL(0), tmp_t); - } -} -- cgit v1.3.1 From 25b7ce32871f94b96385b31e4bd6b1fd830cccd7 Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Tue, 6 Sep 2022 14:15:03 +0200 Subject: serial: mxc: enable the RX pipeline on imx8(mm) the RXDMUXSEL needs to be set for data going over the wire (as observable on a connected 'scope) to actually make it into the RXFIFO the reference manual is not overly clear about this, and only mentiones that "UCR3_RXDMUXSEL should always be set." - and since the CR3 register reverts to its reset values after setting the baudrate, setting this bit is done during '_mxc_serial_setbgr' Signed-off-by: Johannes Schneider Reviewed-by: Peng Fan Reviewed-by: Fabio Estevam --- drivers/serial/serial_mxc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index 70a0e5e9197..ee17a960d47 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -61,6 +61,11 @@ #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ #define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */ #define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */ + +/* imx8 names these bitsfields instead: */ +#define UCR3_DTRDEN BIT(3) /* bit not used in this chip */ +#define UCR3_RXDMUXSEL BIT(2) /* RXD muxed input selected; 'should always be set' */ + #define UCR3_INVT (1<<1) /* Inverted Infrared transmission */ #define UCR3_BPEN (1<<0) /* Preset registers enable */ #define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */ @@ -176,6 +181,14 @@ static void _mxc_serial_setbrg(struct mxc_uart *base, unsigned long clk, writel(UCR2_WS | UCR2_IRTS | UCR2_RXEN | UCR2_TXEN | UCR2_SRST, &base->cr2); + + /* + * setting the baudrate triggers a reset, returning cr3 to its + * reset value but UCR3_RXDMUXSEL "should always be set." + * according to the imx8 reference-manual + */ + writel(readl(&base->cr3) | UCR3_RXDMUXSEL, &base->cr3); + writel(UCR1_UARTEN, &base->cr1); } -- cgit v1.3.1 From c7878a0483c59c48a730123bc0f4659fd40921bf Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Tue, 6 Sep 2022 14:15:04 +0200 Subject: serial: mxc: have putc use the TXFIFO only waiting for TXEMPTY leads to corrupted messages going over the wire - which is fixed by making use of the FIFO this change is following the linux kernel uart driver (drivers/tty/serial/imx.c), which also checks UTS_TXFULL instead of UTS_TXEMPTY Signed-off-by: Johannes Schneider Reviewed-by: Peng Fan Reviewed-by: Fabio Estevam --- drivers/serial/serial_mxc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index ee17a960d47..af1fd1ea9bc 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -311,7 +311,7 @@ static int mxc_serial_putc(struct udevice *dev, const char ch) struct mxc_serial_plat *plat = dev_get_plat(dev); struct mxc_uart *const uart = plat->reg; - if (!(readl(&uart->ts) & UTS_TXEMPTY)) + if (readl(&uart->ts) & UTS_TXFULL) return -EAGAIN; writel(ch, &uart->txd); -- cgit v1.3.1