diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/imx/Kconfig | 16 | ||||
-rw-r--r-- | drivers/clk/imx/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imx8qxp.c | 12 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imxrt1050.c | 292 | ||||
-rw-r--r-- | drivers/clk/imx/clk-pfd.c | 22 | ||||
-rw-r--r-- | drivers/clk/imx/clk-pllv3.c | 218 | ||||
-rw-r--r-- | drivers/gpio/mxc_gpio.c | 7 | ||||
-rw-r--r-- | drivers/mmc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc_imx.c | 49 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/Kconfig | 14 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imxrt.c | 40 | ||||
-rw-r--r-- | drivers/ram/Kconfig | 8 | ||||
-rw-r--r-- | drivers/ram/Makefile | 2 | ||||
-rw-r--r-- | drivers/ram/imxrt_sdram.c | 439 | ||||
-rw-r--r-- | drivers/serial/serial_lpuart.c | 31 |
16 files changed, 1122 insertions, 33 deletions
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 2f149ff6f8..059bc2fbb9 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -68,3 +68,19 @@ config CLK_IMX8MP select CLK_CCF help This enables support clock driver for i.MX8MP platforms. + +config SPL_CLK_IMXRT1050 + bool "SPL clock support for i.MXRT1050" + depends on ARCH_IMXRT && SPL + select SPL_CLK + select SPL_CLK_CCF + help + This enables SPL DM/DTS support for clock driver in i.MXRT1050 + +config CLK_IMXRT1050 + bool "Clock support for i.MXRT1050" + depends on ARCH_IMXRT + select CLK + select CLK_CCF + help + This enables support clock driver for i.MXRT1050 platforms. diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 255a87b18e..1e8a49d0f3 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -16,3 +16,5 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ clk-composite-8m.o obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \ clk-composite-8m.o + +obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index 1fca36ac91..0db4539a1f 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -56,18 +56,22 @@ ulong imx8_clk_get_rate(struct clk *clk) pm_clk = SC_PM_CLK_CPU; break; case IMX8QXP_I2C0_CLK: + case IMX8QXP_I2C0_IPG_CLK: resource = SC_R_I2C_0; pm_clk = SC_PM_CLK_PER; break; case IMX8QXP_I2C1_CLK: + case IMX8QXP_I2C1_IPG_CLK: resource = SC_R_I2C_1; pm_clk = SC_PM_CLK_PER; break; case IMX8QXP_I2C2_CLK: + case IMX8QXP_I2C2_IPG_CLK: resource = SC_R_I2C_2; pm_clk = SC_PM_CLK_PER; break; case IMX8QXP_I2C3_CLK: + case IMX8QXP_I2C3_IPG_CLK: resource = SC_R_I2C_3; pm_clk = SC_PM_CLK_PER; break; @@ -145,18 +149,22 @@ ulong imx8_clk_set_rate(struct clk *clk, unsigned long rate) switch (clk->id) { case IMX8QXP_I2C0_CLK: + case IMX8QXP_I2C0_IPG_CLK: resource = SC_R_I2C_0; pm_clk = SC_PM_CLK_PER; break; case IMX8QXP_I2C1_CLK: + case IMX8QXP_I2C1_IPG_CLK: resource = SC_R_I2C_1; pm_clk = SC_PM_CLK_PER; break; case IMX8QXP_I2C2_CLK: + case IMX8QXP_I2C2_IPG_CLK: resource = SC_R_I2C_2; pm_clk = SC_PM_CLK_PER; break; case IMX8QXP_I2C3_CLK: + case IMX8QXP_I2C3_IPG_CLK: resource = SC_R_I2C_3; pm_clk = SC_PM_CLK_PER; break; @@ -234,18 +242,22 @@ int __imx8_clk_enable(struct clk *clk, bool enable) switch (clk->id) { case IMX8QXP_I2C0_CLK: + case IMX8QXP_I2C0_IPG_CLK: resource = SC_R_I2C_0; pm_clk = SC_PM_CLK_PER; break; case IMX8QXP_I2C1_CLK: + case IMX8QXP_I2C1_IPG_CLK: resource = SC_R_I2C_1; pm_clk = SC_PM_CLK_PER; break; case IMX8QXP_I2C2_CLK: + case IMX8QXP_I2C2_IPG_CLK: resource = SC_R_I2C_2; pm_clk = SC_PM_CLK_PER; break; case IMX8QXP_I2C3_CLK: + case IMX8QXP_I2C3_IPG_CLK: resource = SC_R_I2C_3; pm_clk = SC_PM_CLK_PER; break; diff --git a/drivers/clk/imx/clk-imxrt1050.c b/drivers/clk/imx/clk-imxrt1050.c new file mode 100644 index 0000000000..44ca52c013 --- /dev/null +++ b/drivers/clk/imx/clk-imxrt1050.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright(C) 2019 + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.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/imxrt1050-clock.h> + +#include "clk.h" + +static ulong imxrt1050_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 imxrt1050_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 __imxrt1050_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 imxrt1050_clk_disable(struct clk *clk) +{ + return __imxrt1050_clk_enable(clk, 0); +} + +static int imxrt1050_clk_enable(struct clk *clk) +{ + return __imxrt1050_clk_enable(clk, 1); +} + +static struct clk_ops imxrt1050_clk_ops = { + .set_rate = imxrt1050_clk_set_rate, + .get_rate = imxrt1050_clk_get_rate, + .enable = imxrt1050_clk_enable, + .disable = imxrt1050_clk_disable, +}; + +static const char * const pll_ref_sels[] = {"osc", "dummy", }; +static const char * const pll1_bypass_sels[] = {"pll1_arm", "pll1_arm_ref_sel", }; +static const char * const pll2_bypass_sels[] = {"pll2_sys", "pll2_sys_ref_sel", }; +static const char * const pll3_bypass_sels[] = {"pll3_usb_otg", "pll3_usb_otg_ref_sel", }; +static const char * const pll5_bypass_sels[] = {"pll5_video", "pll5_video_ref_sel", }; + +static const char *const pre_periph_sels[] = { "pll2_sys", "pll2_pfd2_396m", "pll2_pfd0_352m", "arm_podf", }; +static const char *const periph_sels[] = { "pre_periph_sel", "todo", }; +static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *const lpuart_sels[] = { "pll3_80m", "osc", }; +static const char *const semc_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_664_62m", }; +static const char *const semc_sels[] = { "periph_sel", "semc_alt_sel", }; +static const char *const lcdif_sels[] = { "pll2_sys", "pll3_pfd3_454_74m", "pll5_video:", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_664_62m"}; + +static int imxrt1050_clk_probe(struct udevice *dev) +{ + void *base; + + /* Anatop clocks */ + base = (void *)ANATOP_BASE_ADDR; + + clk_dm(IMXRT1050_CLK_PLL1_REF_SEL, + imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMXRT1050_CLK_PLL2_REF_SEL, + imx_clk_mux("pll2_sys_ref_sel", base + 0x30, 14, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMXRT1050_CLK_PLL3_REF_SEL, + imx_clk_mux("pll3_usb_otg_ref_sel", base + 0x10, 14, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMXRT1050_CLK_PLL5_REF_SEL, + imx_clk_mux("pll5_video_ref_sel", base + 0xa0, 14, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + + clk_dm(IMXRT1050_CLK_PLL1_ARM, + imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_arm", "pll1_arm_ref_sel", + base + 0x0, 0x7f)); + clk_dm(IMXRT1050_CLK_PLL2_SYS, + imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", "pll2_sys_ref_sel", + base + 0x30, 0x1)); + clk_dm(IMXRT1050_CLK_PLL3_USB_OTG, + imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", + "pll3_usb_otg_ref_sel", + base + 0x10, 0x1)); + clk_dm(IMXRT1050_CLK_PLL5_VIDEO, + imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "pll5_video_ref_sel", + base + 0xa0, 0x7f)); + + /* PLL bypass out */ + clk_dm(IMXRT1050_CLK_PLL1_BYPASS, + imx_clk_mux_flags("pll1_bypass", base + 0x0, 16, 1, + pll1_bypass_sels, + ARRAY_SIZE(pll1_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMXRT1050_CLK_PLL2_BYPASS, + imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, + pll2_bypass_sels, + ARRAY_SIZE(pll2_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMXRT1050_CLK_PLL3_BYPASS, + imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, + pll3_bypass_sels, + ARRAY_SIZE(pll3_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMXRT1050_CLK_PLL5_BYPASS, + imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, + pll5_bypass_sels, + ARRAY_SIZE(pll5_bypass_sels), + CLK_SET_RATE_PARENT)); + + clk_dm(IMXRT1050_CLK_VIDEO_POST_DIV_SEL, + imx_clk_divider("video_post_div_sel", "pll5_video", + base + 0xa0, 19, 2)); + clk_dm(IMXRT1050_CLK_VIDEO_DIV, + imx_clk_divider("video_div", "video_post_div_sel", + base + 0x170, 30, 2)); + + clk_dm(IMXRT1050_CLK_PLL3_80M, + imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6)); + + clk_dm(IMXRT1050_CLK_PLL2_PFD0_352M, + imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + 0x100, 0)); + clk_dm(IMXRT1050_CLK_PLL2_PFD1_594M, + imx_clk_pfd("pll2_pfd1_594m", "pll2_sys", base + 0x100, 1)); + clk_dm(IMXRT1050_CLK_PLL2_PFD2_396M, + imx_clk_pfd("pll2_pfd2_396m", "pll2_sys", base + 0x100, 2)); + clk_dm(IMXRT1050_CLK_PLL3_PFD1_664_62M, + imx_clk_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", base + 0xf0, + 1)); + clk_dm(IMXRT1050_CLK_PLL3_PFD3_454_74M, + imx_clk_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", base + 0xf0, + 3)); + + /* CCM clocks */ + base = dev_read_addr_ptr(dev); + if (base == (void *)FDT_ADDR_T_NONE) + return -EINVAL; + + clk_dm(IMXRT1050_CLK_ARM_PODF, + imx_clk_divider("arm_podf", "pll1_arm", + base + 0x10, 0, 3)); + + clk_dm(IMXRT1050_CLK_PRE_PERIPH_SEL, + imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, + pre_periph_sels, ARRAY_SIZE(pre_periph_sels))); + clk_dm(IMXRT1050_CLK_PERIPH_SEL, + imx_clk_mux("periph_sel", base + 0x14, 25, 1, + periph_sels, ARRAY_SIZE(periph_sels))); + clk_dm(IMXRT1050_CLK_USDHC1_SEL, + imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, + usdhc_sels, ARRAY_SIZE(usdhc_sels))); + clk_dm(IMXRT1050_CLK_USDHC2_SEL, + imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, + usdhc_sels, ARRAY_SIZE(usdhc_sels))); + clk_dm(IMXRT1050_CLK_LPUART_SEL, + imx_clk_mux("lpuart_sel", base + 0x24, 6, 1, + lpuart_sels, ARRAY_SIZE(lpuart_sels))); + clk_dm(IMXRT1050_CLK_SEMC_ALT_SEL, + imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1, + semc_alt_sels, ARRAY_SIZE(semc_alt_sels))); + clk_dm(IMXRT1050_CLK_SEMC_SEL, + imx_clk_mux("semc_sel", base + 0x14, 6, 1, + semc_sels, ARRAY_SIZE(semc_sels))); + clk_dm(IMXRT1050_CLK_LCDIF_SEL, + imx_clk_mux("lcdif_sel", base + 0x38, 15, 3, + lcdif_sels, ARRAY_SIZE(lcdif_sels))); + + clk_dm(IMXRT1050_CLK_AHB_PODF, + imx_clk_divider("ahb_podf", "periph_sel", + base + 0x14, 10, 3)); + clk_dm(IMXRT1050_CLK_USDHC1_PODF, + imx_clk_divider("usdhc1_podf", "usdhc1_sel", + base + 0x24, 11, 3)); + clk_dm(IMXRT1050_CLK_USDHC2_PODF, + imx_clk_divider("usdhc2_podf", "usdhc2_sel", + base + 0x24, 16, 3)); + clk_dm(IMXRT1050_CLK_LPUART_PODF, + imx_clk_divider("lpuart_podf", "lpuart_sel", + base + 0x24, 0, 6)); + clk_dm(IMXRT1050_CLK_SEMC_PODF, + imx_clk_divider("semc_podf", "semc_sel", + base + 0x14, 16, 3)); + clk_dm(IMXRT1050_CLK_LCDIF_PRED, + imx_clk_divider("lcdif_pred", "lcdif_sel", + base + 0x38, 12, 3)); + clk_dm(IMXRT1050_CLK_LCDIF_PODF, + imx_clk_divider("lcdif_podf", "lcdif_pred", + base + 0x18, 23, 3)); + + clk_dm(IMXRT1050_CLK_USDHC1, + imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2)); + clk_dm(IMXRT1050_CLK_USDHC2, + imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4)); + clk_dm(IMXRT1050_CLK_LPUART1, + imx_clk_gate2("lpuart1", "lpuart_podf", base + 0x7c, 24)); + clk_dm(IMXRT1050_CLK_SEMC, + imx_clk_gate2("semc", "semc_podf", base + 0x74, 4)); + clk_dm(IMXRT1050_CLK_LCDIF, + imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, 28)); + +#ifdef CONFIG_SPL_BUILD + struct clk *clk, *clk1; + + /* bypass pll1 before setting its rate */ + clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk); + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); + clk_set_parent(clk1, clk); + + clk_get_by_id(IMXRT1050_CLK_PLL1_ARM, &clk); + clk_enable(clk); + clk_set_rate(clk, 1056000000UL); + + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); + clk_set_parent(clk1, clk); + + clk_get_by_id(IMXRT1050_CLK_SEMC_SEL, &clk1); + clk_get_by_id(IMXRT1050_CLK_SEMC_ALT_SEL, &clk); + clk_set_parent(clk1, clk); + + clk_get_by_id(IMXRT1050_CLK_PLL2_SYS, &clk); + clk_enable(clk); + clk_set_rate(clk, 528000000UL); + + clk_get_by_id(IMXRT1050_CLK_PLL2_BYPASS, &clk1); + clk_set_parent(clk1, clk); + + /* Configure PLL3_USB_OTG to 480MHz */ + clk_get_by_id(IMXRT1050_CLK_PLL3_USB_OTG, &clk); + clk_enable(clk); + clk_set_rate(clk, 480000000UL); + + clk_get_by_id(IMXRT1050_CLK_PLL3_BYPASS, &clk1); + clk_set_parent(clk1, clk); + +#endif + + return 0; +} + +static const struct udevice_id imxrt1050_clk_ids[] = { + { .compatible = "fsl,imxrt1050-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imxrt1050_clk) = { + .name = "clk_imxrt1050", + .id = UCLASS_CLK, + .of_match = imxrt1050_clk_ids, + .ops = &imxrt1050_clk_ops, + .probe = imxrt1050_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c index 188b2b3b90..4ae55f5a07 100644 --- a/drivers/clk/imx/clk-pfd.c +++ b/drivers/clk/imx/clk-pfd.c @@ -52,8 +52,30 @@ static unsigned long clk_pfd_recalc_rate(struct clk *clk) return tmp; } +static unsigned long clk_pfd_set_rate(struct clk *clk, unsigned long rate) +{ + struct clk_pfd *pfd = to_clk_pfd(clk); + unsigned long parent_rate = clk_get_parent_rate(clk); + u64 tmp = parent_rate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + writel(0x3f << (pfd->idx * 8), pfd->reg + CLR); + writel(frac << (pfd->idx * 8), pfd->reg + SET); + + return 0; +} + static const struct clk_ops clk_pfd_ops = { .get_rate = clk_pfd_recalc_rate, + .set_rate = clk_pfd_set_rate, }; struct clk *imx_clk_pfd(const char *name, const char *parent_name, diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index fbb7b24d5e..fc16416d5f 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -6,6 +6,7 @@ #include <common.h> #include <asm/io.h> +#include <div64.h> #include <malloc.h> #include <clk-uclass.h> #include <dm/device.h> @@ -13,18 +14,29 @@ #include <clk.h> #include "clk.h" -#define UBOOT_DM_CLK_IMX_PLLV3 "imx_clk_pllv3" +#define UBOOT_DM_CLK_IMX_PLLV3_GENERIC "imx_clk_pllv3_generic" +#define UBOOT_DM_CLK_IMX_PLLV3_SYS "imx_clk_pllv3_sys" +#define UBOOT_DM_CLK_IMX_PLLV3_USB "imx_clk_pllv3_usb" +#define UBOOT_DM_CLK_IMX_PLLV3_AV "imx_clk_pllv3_av" + +#define PLL_NUM_OFFSET 0x10 +#define PLL_DENOM_OFFSET 0x20 + +#define BM_PLL_POWER (0x1 << 12) +#define BM_PLL_LOCK (0x1 << 31) struct clk_pllv3 { struct clk clk; void __iomem *base; + u32 power_bit; + bool powerup_set; u32 div_mask; u32 div_shift; }; #define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk) -static ulong clk_pllv3_get_rate(struct clk *clk) +static ulong clk_pllv3_generic_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); @@ -34,8 +46,165 @@ static ulong clk_pllv3_get_rate(struct clk *clk) return (div == 1) ? parent_rate * 22 : parent_rate * 20; } +static ulong clk_pllv3_generic_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 val, div; + + if (rate == parent_rate * 22) + div = 1; + else if (rate == parent_rate * 20) + div = 0; + else + return -EINVAL; + + val = readl(pll->base); + val &= ~(pll->div_mask << pll->div_shift); + val |= (div << pll->div_shift); + writel(val, pll->base); + + /* Wait for PLL to lock */ + while (!(readl(pll->base) & BM_PLL_LOCK)) + ; + + return 0; +} + +static int clk_pllv3_generic_enable(struct clk *clk) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + u32 val; + + val = readl(pll->base); + if (pll->powerup_set) + val |= pll->power_bit; + else + val &= ~pll->power_bit; + writel(val, pll->base); + + return 0; +} + +static int clk_pllv3_generic_disable(struct clk *clk) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + u32 val; + + val = readl(pll->base); + if (pll->powerup_set) + val &= ~pll->power_bit; + else + val |= pll->power_bit; + writel(val, pll->base); + + return 0; +} + static const struct clk_ops clk_pllv3_generic_ops = { - .get_rate = clk_pllv3_get_rate, + .get_rate = clk_pllv3_generic_get_rate, + .enable = clk_pllv3_generic_enable, + .disable = clk_pllv3_generic_disable, + .set_rate = clk_pllv3_generic_set_rate, +}; + +static ulong clk_pllv3_sys_get_rate(struct clk *clk) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + unsigned long parent_rate = clk_get_parent_rate(clk); + u32 div = readl(pll->base) & pll->div_mask; + + return parent_rate * div / 2; +} + +static ulong clk_pllv3_sys_set_rate(struct clk *clk, ulong rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + unsigned long parent_rate = clk_get_parent_rate(clk); + unsigned long min_rate = parent_rate * 54 / 2; + unsigned long max_rate = parent_rate * 108 / 2; + u32 val, div; + + if (rate < min_rate || rate > max_rate) + return -EINVAL; + + div = rate * 2 / parent_rate; + val = readl(pll->base); + val &= ~pll->div_mask; + val |= div; + writel(val, pll->base); + + /* Wait for PLL to lock */ + while (!(readl(pll->base) & BM_PLL_LOCK)) + ; + + return 0; +} + +static const struct clk_ops clk_pllv3_sys_ops = { + .enable = clk_pllv3_generic_enable, + .disable = clk_pllv3_generic_disable, + .get_rate = clk_pllv3_sys_get_rate, + .set_rate = clk_pllv3_sys_set_rate, +}; + +static ulong clk_pllv3_av_get_rate(struct clk *clk) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + unsigned long parent_rate = clk_get_parent_rate(clk); + u32 mfn = readl(pll->base + PLL_NUM_OFFSET); + u32 mfd = readl(pll->base + PLL_DENOM_OFFSET); + u32 div = readl(pll->base) & pll->div_mask; + u64 temp64 = (u64)parent_rate; + + temp64 *= mfn; + do_div(temp64, mfd); + + return parent_rate * div + (unsigned long)temp64; +} + +static ulong clk_pllv3_av_set_rate(struct clk *clk, ulong rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + unsigned long parent_rate = clk_get_parent_rate(clk); + unsigned long min_rate = parent_rate * 27; + unsigned long max_rate = parent_rate * 54; + u32 val, div; + u32 mfn, mfd = 1000000; + u32 max_mfd = 0x3FFFFFFF; + u64 temp64; + + if (rate < min_rate || rate > max_rate) + return -EINVAL; + + if (parent_rate <= max_mfd) + mfd = parent_rate; + + div = rate / parent_rate; + temp64 = (u64)(rate - div * parent_rate); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + val = readl(pll->base); + val &= ~pll->div_mask; + val |= div; + writel(val, pll->base); + writel(mfn, pll->base + PLL_NUM_OFFSET); + writel(mfd, pll->base + PLL_DENOM_OFFSET); + + /* Wait for PLL to lock */ + while (!(readl(pll->base) & BM_PLL_LOCK)) + ; + + return 0; +} + +static const struct clk_ops clk_pllv3_av_ops = { + .enable = clk_pllv3_generic_enable, + .disable = clk_pllv3_generic_disable, + .get_rate = clk_pllv3_av_get_rate, + .set_rate = clk_pllv3_av_set_rate, }; struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, @@ -51,10 +220,28 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, if (!pll) return ERR_PTR(-ENOMEM); + pll->power_bit = BM_PLL_POWER; + switch (type) { case IMX_PLLV3_GENERIC: + drv_name = UBOOT_DM_CLK_IMX_PLLV3_GENERIC; + 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; + pll->powerup_set = false; + break; case IMX_PLLV3_USB: - drv_name = UBOOT_DM_CLK_IMX_PLLV3; + drv_name = UBOOT_DM_CLK_IMX_PLLV3_USB; + pll->div_shift = 1; + pll->powerup_set = true; + break; + case IMX_PLLV3_AV: + drv_name = UBOOT_DM_CLK_IMX_PLLV3_AV; + pll->div_shift = 0; + pll->powerup_set = false; break; default: kfree(pll); @@ -75,8 +262,29 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, } U_BOOT_DRIVER(clk_pllv3_generic) = { - .name = UBOOT_DM_CLK_IMX_PLLV3, + .name = UBOOT_DM_CLK_IMX_PLLV3_GENERIC, .id = UCLASS_CLK, .ops = &clk_pllv3_generic_ops, .flags = DM_FLAG_PRE_RELOC, }; + +U_BOOT_DRIVER(clk_pllv3_sys) = { + .name = UBOOT_DM_CLK_IMX_PLLV3_SYS, + .id = UCLASS_CLK, + .ops = &clk_pllv3_sys_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(clk_pllv3_usb) = { + .name = UBOOT_DM_CLK_IMX_PLLV3_USB, + .id = UCLASS_CLK, + .ops = &clk_pllv3_generic_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(clk_pllv3_av) = { + .name = UBOOT_DM_CLK_IMX_PLLV3_AV, + .id = UCLASS_CLK, + .ops = &clk_pllv3_av_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c index 6592d141d3..c924e52f07 100644 --- a/drivers/gpio/mxc_gpio.c +++ b/drivers/gpio/mxc_gpio.c @@ -41,14 +41,15 @@ static unsigned long gpio_ports[] = { #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \ - defined(CONFIG_ARCH_IMX8) + defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050) [3] = GPIO4_BASE_ADDR, #endif #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || \ - defined(CONFIG_ARCH_IMX8) + defined(CONFIG_ARCH_IMX8) || defined(CONFIG_IMXRT1050) [4] = GPIO5_BASE_ADDR, -#if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) || defined(CONFIG_IMX8M)) +#if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) || \ + defined(CONFIG_IMX8M) || defined(CONFIG_IMXRT1050)) [5] = GPIO6_BASE_ADDR, #endif #endif diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 85fd1906bd..2bc19dd56b 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -732,7 +732,7 @@ config FSL_ESDHC_IMX config FSL_USDHC bool "Freescale/NXP i.MX uSDHC controller support" - depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || TARGET_S32V234EVB + depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || IMXRT || TARGET_S32V234EVB select FSL_ESDHC_IMX help This enables the Ultra Secured Digital Host Controller enhancements diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index f7b754bd9d..96fe01e26d 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -78,7 +78,7 @@ struct fsl_esdhc { uint vendorspec; uint mmcboot; uint vendorspec2; - uint tuning_ctrl; /* on i.MX6/7/8 */ + uint tuning_ctrl; /* on i.MX6/7/8/RT */ char reserved5[44]; uint hostver; /* Host controller version register */ char reserved6[4]; /* reserved */ @@ -115,6 +115,7 @@ struct esdhc_soc_data { * Following is used when Driver Model is enabled for MMC * @dev: pointer for the device * @non_removable: 0: removable; 1: non-removable + * @broken_cd: 0: use GPIO for card detect; 1: Do not use GPIO for card detect * @wp_enable: 1: enable checking wp; 0: no check * @vs18_enable: 1: use 1.8V voltage; 0: use 3.3V * @flags: ESDHC_FLAG_xx in include/fsl_esdhc_imx.h @@ -138,6 +139,7 @@ struct fsl_esdhc_priv { #endif struct udevice *dev; int non_removable; + int broken_cd; int wp_enable; int vs18_enable; u32 flags; @@ -1093,6 +1095,9 @@ static int esdhc_getcd_common(struct fsl_esdhc_priv *priv) #if CONFIG_IS_ENABLED(DM_MMC) if (priv->non_removable) return 1; + + if (priv->broken_cd) + return 1; #if CONFIG_IS_ENABLED(DM_GPIO) if (dm_gpio_is_valid(&priv->cd_gpio)) return dm_gpio_get_value(&priv->cd_gpio); @@ -1451,6 +1456,9 @@ static int fsl_esdhc_probe(struct udevice *dev) ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT); priv->strobe_dll_delay_target = val; + if (dev_read_bool(dev, "broken-cd")) + priv->broken_cd = 1; + if (dev_read_bool(dev, "non-removable")) { priv->non_removable = 1; } else { @@ -1515,27 +1523,27 @@ static int fsl_esdhc_probe(struct udevice *dev) init_clk_usdhc(dev->seq); - if (CONFIG_IS_ENABLED(CLK)) { - /* Assigned clock already set clock */ - ret = clk_get_by_name(dev, "per", &priv->per_clk); - if (ret) { - printf("Failed to get per_clk\n"); - return ret; - } - ret = clk_enable(&priv->per_clk); - if (ret) { - printf("Failed to enable per_clk\n"); - return ret; - } +#if CONFIG_IS_ENABLED(CLK) + /* Assigned clock already set clock */ + ret = clk_get_by_name(dev, "per", &priv->per_clk); + if (ret) { + printf("Failed to get per_clk\n"); + return ret; + } + ret = clk_enable(&priv->per_clk); + if (ret) { + printf("Failed to enable per_clk\n"); + return ret; + } - priv->sdhc_clk = clk_get_rate(&priv->per_clk); - } else { - priv->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK + dev->seq); - if (priv->sdhc_clk <= 0) { - dev_err(dev, "Unable to get clk for %s\n", dev->name); - return -EINVAL; - } + priv->sdhc_clk = clk_get_rate(&priv->per_clk); +#else + priv->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK + dev->seq); + if (priv->sdhc_clk <= 0) { + dev_err(dev, "Unable to get clk for %s\n", dev->name); + return -EINVAL; } +#endif ret = fsl_esdhc_init(priv, plat); if (ret) { @@ -1652,6 +1660,7 @@ static const struct udevice_id fsl_esdhc_ids[] = { { .compatible = "fsl,imx8mm-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,imx8mn-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,imx8mq-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, + { .compatible = "fsl,imxrt-usdhc", }, { .compatible = "fsl,esdhc", }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig index f2e67ca231..ec55351e61 100644 --- a/drivers/pinctrl/nxp/Kconfig +++ b/drivers/pinctrl/nxp/Kconfig @@ -99,6 +99,20 @@ config PINCTRL_MXS familiy, e.g. i.MX28. This feature depends on device tree configuration. +config PINCTRL_IMXRT + bool "IMXRT pinctrl driver" + depends on ARCH_IMXRT && PINCTRL_FULL + select DEVRES + select PINCTRL_IMX + help + Say Y here to enable the imxrt pinctrl driver + + This provides a simple pinctrl driver for i.MXRT SoC familiy. + This feature depends on device tree configuration. This driver + is different from the linux one, this is a simple implementation, + only parses the 'fsl,pins' property and configure related + registers. + config PINCTRL_VYBRID bool "Vybrid (vf610) pinctrl driver" depends on ARCH_VF610 && PINCTRL_FULL diff --git a/drivers/pinctrl/nxp/Makefile b/drivers/pinctrl/nxp/Makefile index b86448aac9..066ca75b65 100644 --- a/drivers/pinctrl/nxp/Makefile +++ b/drivers/pinctrl/nxp/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_PINCTRL_IMX8) += pinctrl-imx8.o obj-$(CONFIG_PINCTRL_IMX8M) += pinctrl-imx8m.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o obj-$(CONFIG_PINCTRL_VYBRID) += pinctrl-vf610.o +obj-$(CONFIG_PINCTRL_IMXRT) += pinctrl-imxrt.o diff --git a/drivers/pinctrl/nxp/pinctrl-imxrt.c b/drivers/pinctrl/nxp/pinctrl-imxrt.c new file mode 100644 index 0000000000..4a93941927 --- /dev/null +++ b/drivers/pinctrl/nxp/pinctrl-imxrt.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> + */ + +#include <common.h> +#include <dm.h> +#include <dm/pinctrl.h> + +#include "pinctrl-imx.h" + +static struct imx_pinctrl_soc_info imxrt_pinctrl_soc_info = { + .flags = ZERO_OFFSET_VALID, +}; + +static int imxrt_pinctrl_probe(struct udevice *dev) +{ + struct imx_pinctrl_soc_info *info = + (struct imx_pinctrl_soc_info *)dev_get_driver_data(dev); + + return imx_pinctrl_probe(dev, info); +} + +static const struct udevice_id imxrt_pinctrl_match[] = { + { .compatible = "fsl,imxrt-iomuxc", + .data = (ulong)&imxrt_pinctrl_soc_info }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(imxrt_pinctrl) = { + .name = "imxrt-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(imxrt_pinctrl_match), + .probe = imxrt_pinctrl_probe, + .remove = imx_pinctrl_remove, + .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv), + .ops = &imx_pinctrl_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index b454ceb599..56fea7c94c 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -65,5 +65,13 @@ config K3_J721E_DDRSS Enabling this config adds support for the DDR memory controller on J721E family of SoCs. +config IMXRT_SDRAM + bool "Enable i.MXRT SDRAM support" + depends on RAM + help + i.MXRT family devices support smart external memory controller(SEMC) + to support external memories like sdram, psram & nand. + This driver is for the sdram memory interface with the SEMC. + source "drivers/ram/rockchip/Kconfig" source "drivers/ram/stm32mp1/Kconfig" diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile index 4b77969b39..5c897410c6 100644 --- a/drivers/ram/Makefile +++ b/drivers/ram/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_K3_AM654_DDRSS) += k3-am654-ddrss.o obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_K3_J721E_DDRSS) += k3-j721e/ + +obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o diff --git a/drivers/ram/imxrt_sdram.c b/drivers/ram/imxrt_sdram.c new file mode 100644 index 0000000000..af7400be82 --- /dev/null +++ b/drivers/ram/imxrt_sdram.c @@ -0,0 +1,439 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <ram.h> +#include <asm/io.h> + +/* SDRAM Command Code */ +#define SD_CC_ARD 0x0 /* Master Bus (AXI) command - Read */ +#define SD_CC_AWR 0x1 /* Master Bus (AXI) command - Write */ +#define SD_CC_IRD 0x8 /* IP command - Read */ +#define SD_CC_IWR 0x9 /* IP command - Write */ +#define SD_CC_IMS 0xA /* IP command - Set Mode Register */ +#define SD_CC_IACT 0xB /* IP command - ACTIVE */ +#define SD_CC_IAF 0xC /* IP command - Auto Refresh */ +#define SD_CC_ISF 0xD /* IP Command - Self Refresh */ +#define SD_CC_IPRE 0xE /* IP command - Precharge */ +#define SD_CC_IPREA 0xF /* IP command - Precharge ALL */ + +#define SEMC_MCR_MDIS BIT(1) +#define SEMC_MCR_DQSMD BIT(2) + +#define SEMC_INTR_IPCMDERR BIT(1) +#define SEMC_INTR_IPCMDDONE BIT(0) + +#define SEMC_IPCMD_KEY 0xA55A0000 + +struct imxrt_semc_regs { + /* 0x0 */ + u32 mcr; + u32 iocr; + u32 bmcr0; + u32 bmcr1; + u32 br[9]; + + /* 0x34 */ + u32 res1; + u32 inten; + u32 intr; + /* 0x40 */ + u32 sdramcr0; + u32 sdramcr1; + u32 sdramcr2; + u32 sdramcr3; + /* 0x50 */ + u32 nandcr0; + u32 nandcr1; + u32 nandcr2; + u32 nandcr3; + /* 0x60 */ + u32 norcr0; + u32 norcr1; + u32 norcr2; + u32 norcr3; + /* 0x70 */ + u32 sramcr0; + u32 sramcr1; + u32 sramcr2; + u32 sramcr3; + /* 0x80 */ + u32 dbicr0; + u32 dbicr1; + u32 res2[2]; + /* 0x90 */ + u32 ipcr0; + u32 ipcr1; + u32 ipcr2; + u32 ipcmd; + /* 0xA0 */ + u32 iptxdat; + u32 res3[3]; + /* 0xB0 */ + u32 iprxdat; + u32 res4[3]; + /* 0xC0 */ + u32 sts[16]; +}; + +#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 + +struct imxrt_sdram_mux { + u8 a8; + u8 csx0; + u8 csx1; + u8 csx2; + u8 csx3; + u8 rdy; +}; + +#define SEMC_SDRAMCR0_PS_SHIFT 0 +#define SEMC_SDRAMCR0_BL_SHIFT 4 +#define SEMC_SDRAMCR0_COL_SHIFT 8 +#define SEMC_SDRAMCR0_CL_SHIFT 10 + +struct imxrt_sdram_control { + u8 memory_width; + u8 burst_len; + u8 no_columns; + u8 cas_latency; +}; + +#define SEMC_SDRAMCR1_PRE2ACT_SHIFT 0 +#define SEMC_SDRAMCR1_ACT2RW_SHIFT 4 +#define SEMC_SDRAMCR1_RFRC_SHIFT 8 +#define SEMC_SDRAMCR1_WRC_SHIFT 13 +#define SEMC_SDRAMCR1_CKEOFF_SHIFT 16 +#define SEMC_SDRAMCR1_ACT2PRE_SHIFT 20 + +#define SEMC_SDRAMCR2_SRRC_SHIFT 0 +#define SEMC_SDRAMCR2_REF2REF_SHIFT 8 +#define SEMC_SDRAMCR2_ACT2ACT_SHIFT 16 +#define SEMC_SDRAMCR2_ITO_SHIFT 24 + +#define SEMC_SDRAMCR3_REN BIT(0) +#define SEMC_SDRAMCR3_REBL_SHIFT 1 +#define SEMC_SDRAMCR3_PRESCALE_SHIFT 8 +#define SEMC_SDRAMCR3_RT_SHIFT 16 +#define SEMC_SDRAMCR3_UT_SHIFT 24 + +struct imxrt_sdram_timing { + u8 pre2act; + u8 act2rw; + u8 rfrc; + u8 wrc; + u8 ckeoff; + u8 act2pre; + + u8 srrc; + u8 ref2ref; + u8 act2act; + u8 ito; + + u8 rebl; + u8 prescale; + u8 rt; + u8 ut; +}; + +enum imxrt_semc_bank { + SDRAM_BANK1, + SDRAM_BANK2, + SDRAM_BANK3, + SDRAM_BANK4, + MAX_SDRAM_BANK, +}; + +#define SEMC_BR_VLD_MASK 1 +#define SEMC_BR_MS_SHIFT 1 + +struct bank_params { + enum imxrt_semc_bank target_bank; + u32 base_address; + u32 memory_size; +}; + +struct imxrt_sdram_params { + struct imxrt_semc_regs *base; + + struct imxrt_sdram_mux *sdram_mux; + struct imxrt_sdram_control *sdram_control; + struct imxrt_sdram_timing *sdram_timing; + + struct bank_params bank_params[MAX_SDRAM_BANK]; + u8 no_sdram_banks; +}; + +static int imxrt_sdram_wait_ipcmd_done(struct imxrt_semc_regs *regs) +{ + do { + readl(®s->intr); + + if (regs->intr & SEMC_INTR_IPCMDDONE) + return 0; + if (regs->intr & SEMC_INTR_IPCMDERR) + return -EIO; + + mdelay(50); + } while (1); +} + +static int imxrt_sdram_ipcmd(struct imxrt_semc_regs *regs, u32 mem_addr, + u32 ipcmd, u32 wd, u32 *rd) +{ + int ret; + + if (ipcmd == SD_CC_IWR || ipcmd == SD_CC_IMS) + writel(wd, ®s->iptxdat); + + /* set slave address for every command as specified on RM */ + writel(mem_addr, ®s->ipcr0); + + /* execute command */ + writel(SEMC_IPCMD_KEY | ipcmd, ®s->ipcmd); + + ret = imxrt_sdram_wait_ipcmd_done(regs); + if (ret < 0) + return ret; + + if (ipcmd == SD_CC_IRD) { + if (!rd) + return -EINVAL; + + *rd = readl(®s->iprxdat); + } + + return 0; +} + +int imxrt_sdram_init(struct udevice *dev) +{ + struct imxrt_sdram_params *params = dev_get_platdata(dev); + struct imxrt_sdram_mux *mux = params->sdram_mux; + struct imxrt_sdram_control *ctrl = params->sdram_control; + struct imxrt_sdram_timing *time = params->sdram_timing; + struct imxrt_semc_regs *regs = params->base; + struct bank_params *bank_params; + u32 rd; + int i; + + /* enable the SEMC controller */ + clrbits_le32(®s->mcr, SEMC_MCR_MDIS); + /* set DQS mode from DQS pad */ + setbits_le32(®s->mcr, SEMC_MCR_DQSMD); + + for (i = 0, bank_params = params->bank_params; + i < params->no_sdram_banks; bank_params++, + i++) + writel((bank_params->base_address & 0xfffff000) + | bank_params->memory_size << SEMC_BR_MS_SHIFT + | SEMC_BR_VLD_MASK, + ®s->br[bank_params->target_bank]); + + writel(mux->a8 << SEMC_IOCR_MUX_A8_SHIFT + | mux->csx0 << SEMC_IOCR_MUX_CSX0_SHIFT + | mux->csx1 << SEMC_IOCR_MUX_CSX1_SHIFT + | mux->csx2 << SEMC_IOCR_MUX_CSX2_SHIFT + | mux->csx3 << SEMC_IOCR_MUX_CSX3_SHIFT + | mux->rdy << SEMC_IOCR_MUX_RDY_SHIFT, + ®s->iocr); + + writel(ctrl->memory_width << SEMC_SDRAMCR0_PS_SHIFT + | ctrl->burst_len << SEMC_SDRAMCR0_BL_SHIFT + | ctrl->no_columns << SEMC_SDRAMCR0_COL_SHIFT + | ctrl->cas_latency << SEMC_SDRAMCR0_CL_SHIFT, + ®s->sdramcr0); + + writel(time->pre2act << SEMC_SDRAMCR1_PRE2ACT_SHIFT + | time->act2rw << SEMC_SDRAMCR1_ACT2RW_SHIFT + | time->rfrc << SEMC_SDRAMCR1_RFRC_SHIFT + | time->wrc << SEMC_SDRAMCR1_WRC_SHIFT + | time->ckeoff << SEMC_SDRAMCR1_CKEOFF_SHIFT + | time->act2pre << SEMC_SDRAMCR1_ACT2PRE_SHIFT, + ®s->sdramcr1); + + writel(time->srrc << SEMC_SDRAMCR2_SRRC_SHIFT + | time->ref2ref << SEMC_SDRAMCR2_REF2REF_SHIFT + | time->act2act << SEMC_SDRAMCR2_ACT2ACT_SHIFT + | time->ito << SEMC_SDRAMCR2_ITO_SHIFT, + ®s->sdramcr2); + + writel(time->rebl << SEMC_SDRAMCR3_REBL_SHIFT + | time->prescale << SEMC_SDRAMCR3_PRESCALE_SHIFT + | time->rt << SEMC_SDRAMCR3_RT_SHIFT + | time->ut << SEMC_SDRAMCR3_UT_SHIFT + | SEMC_SDRAMCR3_REN, + ®s->sdramcr3); + + writel(2, ®s->ipcr1); + + for (i = 0, bank_params = params->bank_params; + i < params->no_sdram_banks; bank_params++, + i++) { + mdelay(250); + imxrt_sdram_ipcmd(regs, bank_params->base_address, SD_CC_IPREA, + 0, &rd); + imxrt_sdram_ipcmd(regs, bank_params->base_address, SD_CC_IAF, + 0, &rd); + imxrt_sdram_ipcmd(regs, bank_params->base_address, SD_CC_IAF, + 0, &rd); + imxrt_sdram_ipcmd(regs, bank_params->base_address, SD_CC_IMS, + ctrl->burst_len | (ctrl->cas_latency << 4), + &rd); + mdelay(250); + } + + return 0; +} + +static int imxrt_semc_ofdata_to_platdata(struct udevice *dev) +{ + struct imxrt_sdram_params *params = dev_get_platdata(dev); + ofnode bank_node; + u8 bank = 0; + + params->sdram_mux = + (struct imxrt_sdram_mux *) + dev_read_u8_array_ptr(dev, + "fsl,sdram-mux", + sizeof(struct imxrt_sdram_mux)); + if (!params->sdram_mux) { + pr_err("fsl,sdram-mux not found"); + return -EINVAL; + } + + params->sdram_control = + (struct imxrt_sdram_control *) + dev_read_u8_array_ptr(dev, + "fsl,sdram-control", + sizeof(struct imxrt_sdram_control)); + if (!params->sdram_control) { + pr_err("fsl,sdram-control not found"); + return -EINVAL; + } + + params->sdram_timing = + (struct imxrt_sdram_timing *) + dev_read_u8_array_ptr(dev, + "fsl,sdram-timing", + sizeof(struct imxrt_sdram_timing)); + if (!params->sdram_timing) { + pr_err("fsl,sdram-timing not found"); + return -EINVAL; + } + + dev_for_each_subnode(bank_node, dev) { + struct bank_params *bank_params; + char *bank_name; + int ret; + + /* extract the bank index from DT */ + bank_name = (char *)ofnode_get_name(bank_node); + strsep(&bank_name, "@"); + if (!bank_name) { + pr_err("missing sdram bank index"); + return -EINVAL; + } + + bank_params = ¶ms->bank_params[bank]; + strict_strtoul(bank_name, 10, + (unsigned long *)&bank_params->target_bank); + if (bank_params->target_bank >= MAX_SDRAM_BANK) { + pr_err("Found bank %d , but only bank 0,1,2,3 are supported", + bank_params->target_bank); + return -EINVAL; + } + + ret = ofnode_read_u32(bank_node, + "fsl,memory-size", + &bank_params->memory_size); + if (ret < 0) { + pr_err("fsl,memory-size not found"); + return -EINVAL; + } + + ret = ofnode_read_u32(bank_node, + "fsl,base-address", + &bank_params->base_address); + if (ret < 0) { + pr_err("fsl,base-address not found"); + return -EINVAL; + } + + debug("Found bank %s %u\n", bank_name, + bank_params->target_bank); + bank++; + } + + params->no_sdram_banks = bank; + debug("%s, no of banks = %d\n", __func__, params->no_sdram_banks); + + return 0; +} + +static int imxrt_semc_probe(struct udevice *dev) +{ + struct imxrt_sdram_params *params = dev_get_platdata(dev); + int ret; + fdt_addr_t addr; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + params->base = (struct imxrt_semc_regs *)addr; + +#ifdef CONFIG_CLK + struct clk clk; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } +#endif + ret = imxrt_sdram_init(dev); + if (ret) + return ret; + + return 0; +} + +static int imxrt_semc_get_info(struct udevice *dev, struct ram_info *info) +{ + return 0; +} + +static struct ram_ops imxrt_semc_ops = { + .get_info = imxrt_semc_get_info, +}; + +static const struct udevice_id imxrt_semc_ids[] = { + { .compatible = "fsl,imxrt-semc", .data = 0 }, + { } +}; + +U_BOOT_DRIVER(imxrt_semc) = { + .name = "imxrt_semc", + .id = UCLASS_RAM, + .of_match = imxrt_semc_ids, + .ops = &imxrt_semc_ops, + .ofdata_to_platdata = imxrt_semc_ofdata_to_platdata, + .probe = imxrt_semc_probe, + .platdata_auto_alloc_size = sizeof(struct imxrt_sdram_params), +}; diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c index 4b0a964d1b..ccb3ce6701 100644 --- a/drivers/serial/serial_lpuart.c +++ b/drivers/serial/serial_lpuart.c @@ -49,7 +49,7 @@ #define FIFO_RXSIZE_MASK 0x7 #define FIFO_RXSIZE_OFF 0 #define FIFO_TXFE 0x80 -#ifdef CONFIG_ARCH_IMX8 +#if defined(CONFIG_ARCH_IMX8) || defined(CONFIG_ARCH_IMXRT) #define FIFO_RXFE 0x08 #else #define FIFO_RXFE 0x40 @@ -67,7 +67,8 @@ enum lpuart_devtype { DEV_VF610 = 1, DEV_LS1021A, DEV_MX7ULP, - DEV_IMX8 + DEV_IMX8, + DEV_IMXRT, }; struct lpuart_serial_platdata { @@ -409,7 +410,8 @@ static int _lpuart32_serial_init(struct udevice *dev) lpuart_write32(plat->flags, &base->match, 0); - if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8) { + if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8 || + plat->devtype == DEV_IMXRT) { _lpuart32_serial_setbrg_7ulp(dev, gd->baudrate); } else { /* provide data bits, parity, stop bit, etc */ @@ -426,7 +428,8 @@ static int lpuart_serial_setbrg(struct udevice *dev, int baudrate) struct lpuart_serial_platdata *plat = dev_get_platdata(dev); if (is_lpuart32(dev)) { - if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8) + if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8 || + plat->devtype == DEV_IMXRT) _lpuart32_serial_setbrg_7ulp(dev, baudrate); else _lpuart32_serial_setbrg(dev, baudrate); @@ -483,6 +486,22 @@ static int lpuart_serial_pending(struct udevice *dev, bool input) static int lpuart_serial_probe(struct udevice *dev) { +#if CONFIG_IS_ENABLED(CLK) + struct clk per_clk; + int ret; + + ret = clk_get_by_name(dev, "per", &per_clk); + if (!ret) { + ret = clk_enable(&per_clk); + if (ret) { + dev_err(dev, "Failed to get per clk: %d\n", ret); + return ret; + } + } else { + dev_warn(dev, "Failed to get per clk: %d\n", ret); + } +#endif + if (is_lpuart32(dev)) return _lpuart32_serial_init(dev); else @@ -514,6 +533,8 @@ static int lpuart_serial_ofdata_to_platdata(struct udevice *dev) plat->devtype = DEV_VF610; else if (!fdt_node_check_compatible(blob, node, "fsl,imx8qm-lpuart")) plat->devtype = DEV_IMX8; + else if (!fdt_node_check_compatible(blob, node, "fsl,imxrt-lpuart")) + plat->devtype = DEV_IMXRT; return 0; } @@ -533,6 +554,8 @@ static const struct udevice_id lpuart_serial_ids[] = { { .compatible = "fsl,vf610-lpuart"}, { .compatible = "fsl,imx8qm-lpuart", .data = LPUART_FLAG_REGMAP_32BIT_REG }, + { .compatible = "fsl,imxrt-lpuart", + .data = LPUART_FLAG_REGMAP_32BIT_REG }, { } }; |