diff options
Diffstat (limited to 'arch/arm/mach-imx')
-rw-r--r-- | arch/arm/mach-imx/cache.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-imx/cmd_nandbcb.c | 42 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8m/Kconfig | 25 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8m/clock_imx8mm.c | 24 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8m/clock_imx8mq.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8m/soc.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8ulp/cgc.c | 325 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8ulp/clock.c | 156 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8ulp/pcc.c | 158 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8ulp/soc.c | 117 | ||||
-rw-r--r-- | arch/arm/mach-imx/mx6/soc.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-imx/mx7/soc.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-imx/mx7ulp/Kconfig | 15 | ||||
-rw-r--r-- | arch/arm/mach-imx/mx7ulp/soc.c | 2 |
14 files changed, 819 insertions, 118 deletions
diff --git a/arch/arm/mach-imx/cache.c b/arch/arm/mach-imx/cache.c index 4e3b49a3fd..ab9b621a2a 100644 --- a/arch/arm/mach-imx/cache.c +++ b/arch/arm/mach-imx/cache.c @@ -11,7 +11,7 @@ #include <asm/io.h> #include <asm/mach-imx/sys_proto.h> -static void enable_ca7_smp(void) +void enable_ca7_smp(void) { u32 val; diff --git a/arch/arm/mach-imx/cmd_nandbcb.c b/arch/arm/mach-imx/cmd_nandbcb.c index 09622c13c9..f119e9f88d 100644 --- a/arch/arm/mach-imx/cmd_nandbcb.c +++ b/arch/arm/mach-imx/cmd_nandbcb.c @@ -132,6 +132,7 @@ static struct platform_config imx8q_plat_config = { /* boot search related variables and definitions */ static int g_boot_search_count = 4; +static int g_boot_secondary_offset; static int g_boot_search_stride; static int g_pages_per_stride; @@ -275,9 +276,9 @@ static int nandbcb_set_boot_config(int argc, char * const argv[], boot_stream2_address = ((maxsize - boot_stream1_address) / 2 + boot_stream1_address); - if (boot_cfg->secondary_boot_stream_off_in_MB) + if (g_boot_secondary_offset) boot_stream2_address = - (loff_t)boot_cfg->secondary_boot_stream_off_in_MB * 1024 * 1024; + (loff_t)g_boot_secondary_offset * 1024 * 1024; max_boot_stream_size = boot_stream2_address - boot_stream1_address; @@ -650,7 +651,7 @@ static int write_fcb(struct boot_config *boot_cfg, struct fcb_block *fcb) }; ret = mtd_write_oob(mtd, off, &ops); - printf("NAND FCB write to 0x%llxx offset 0x%zx written: %s\n", off, ops.len, ret ? "ERROR" : "OK"); + printf("NAND FCB write to 0x%llx offset 0x%zx written: %s\n", off, ops.len, ret ? "ERROR" : "OK"); } if (ret) @@ -1269,6 +1270,36 @@ static bool check_fingerprint(void *data, int fingerprint) return (*(int *)(data + off) == fingerprint); } +static int fuse_secondary_boot(u32 bank, u32 word, u32 mask, u32 off) +{ + int err; + u32 val; + int ret; + + err = fuse_read(bank, word, &val); + if (err) + return 0; + + val = (val & mask) >> off; + + if (val > 10) + return 0; + + switch (val) { + case 0: + ret = 4; + break; + case 1: + ret = 1; + break; + default: + ret = 2 << val; + break; + } + + return ret; +}; + static int fuse_to_search_count(u32 bank, u32 word, u32 mask, u32 off) { int err; @@ -1506,6 +1537,11 @@ static int do_nandbcb(struct cmd_tbl *cmdtp, int flag, int argc, g_boot_search_count); } + if (plat_config.misc_flags & FIRMWARE_SECONDARY_FIXED_ADDR) { + if (is_imx8mn()) + g_boot_secondary_offset = fuse_secondary_boot(2, 1, 0xff0000, 16); + } + cmd = argv[1]; --argc; ++argv; diff --git a/arch/arm/mach-imx/imx8m/Kconfig b/arch/arm/mach-imx/imx8m/Kconfig index d6a869068a..73bc9b34f3 100644 --- a/arch/arm/mach-imx/imx8m/Kconfig +++ b/arch/arm/mach-imx/imx8m/Kconfig @@ -112,6 +112,19 @@ config TARGET_PICO_IMX8MQ select IMX8MQ select IMX8M_LPDDR4 +config TARGET_IMX8MN_VAR_SOM + bool "imx8mn_var_som" + select BINMAN + select IMX8MN + select SUPPORT_SPL + select IMX8M_DDR4 + +config TARGET_KONTRON_PITX_IMX8M + bool "Support Kontron pITX-imx8m" + select BINMAN + select IMX8MQ + select IMX8M_LPDDR4 + config TARGET_VERDIN_IMX8MM bool "Support Toradex Verdin iMX8M Mini module" select BINMAN @@ -119,6 +132,13 @@ config TARGET_VERDIN_IMX8MM select SUPPORT_SPL select IMX8M_LPDDR4 +config TARGET_VERDIN_IMX8MP + bool "Support Toradex Verdin iMX8M Plus module" + select BINMAN + select IMX8MP + select SUPPORT_SPL + select IMX8M_LPDDR4 + config TARGET_IMX8MM_BEACON bool "imx8mm Beacon Embedded devkit" select BINMAN @@ -153,6 +173,7 @@ config TARGET_IMX8MM_CL_IOT_GATE select IMX8MM select SUPPORT_SPL select IMX8M_LPDDR4 + select SUPPORT_EXTENSION_SCAN config TARGET_IMX8MM_CL_IOT_GATE_OPTEE bool "CompuLab iot-gate-imx8 with optee support" @@ -160,6 +181,7 @@ config TARGET_IMX8MM_CL_IOT_GATE_OPTEE select IMX8MM select SUPPORT_SPL select IMX8M_LPDDR4 + select SUPPORT_EXTENSION_SCAN endchoice source "board/beacon/imx8mm/Kconfig" @@ -172,11 +194,14 @@ source "board/freescale/imx8mn_evk/Kconfig" source "board/freescale/imx8mp_evk/Kconfig" source "board/gateworks/venice/Kconfig" source "board/google/imx8mq_phanbell/Kconfig" +source "board/kontron/pitx_imx8m/Kconfig" source "board/kontron/sl-mx8mm/Kconfig" source "board/phytec/phycore_imx8mm/Kconfig" source "board/phytec/phycore_imx8mp/Kconfig" source "board/ronetix/imx8mq-cm/Kconfig" source "board/technexion/pico-imx8mq/Kconfig" +source "board/variscite/imx8mn_var_som/Kconfig" source "board/toradex/verdin-imx8mm/Kconfig" +source "board/toradex/verdin-imx8mp/Kconfig" endif diff --git a/arch/arm/mach-imx/imx8m/clock_imx8mm.c b/arch/arm/mach-imx/imx8m/clock_imx8mm.c index f8e4ec0d90..76132defc2 100644 --- a/arch/arm/mach-imx/imx8m/clock_imx8mm.c +++ b/arch/arm/mach-imx/imx8m/clock_imx8mm.c @@ -244,9 +244,29 @@ int intpll_configure(enum pll_clocks pll, ulong freq) INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1); break; case MHZ(1200): - /* 24 * 0xc8 / 2 / 2 ^ 1 */ + /* 24 * 0x12c / 3 / 2 ^ 1 */ + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x12c) | + INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1); + break; + case MHZ(1400): + /* 24 * 0x15e / 3 / 2 ^ 1 */ + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x15e) | + INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1); + break; + case MHZ(1500): + /* 24 * 0x177 / 3 / 2 ^ 1 */ + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x177) | + INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1); + break; + case MHZ(1600): + /* 24 * 0xc8 / 3 / 2 ^ 0 */ pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xc8) | - INTPLL_PRE_DIV_VAL(2) | INTPLL_POST_DIV_VAL(1); + INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(0); + break; + case MHZ(1800): + /* 24 * 0xe1 / 3 / 2 ^ 0 */ + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xe1) | + INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(0); break; case MHZ(2000): /* 24 * 0xfa / 3 / 2 ^ 0 */ diff --git a/arch/arm/mach-imx/imx8m/clock_imx8mq.c b/arch/arm/mach-imx/imx8m/clock_imx8mq.c index 60e2218a3c..9db62b944e 100644 --- a/arch/arm/mach-imx/imx8m/clock_imx8mq.c +++ b/arch/arm/mach-imx/imx8m/clock_imx8mq.c @@ -359,10 +359,18 @@ unsigned int mxc_get_clock(enum mxc_clock clk) clock_get_target_val(IPG_CLK_ROOT, &val); val = val & 0x3; return get_root_clk(AHB_CLK_ROOT) / (val + 1); + case MXC_CSPI_CLK: + return get_root_clk(ECSPI1_CLK_ROOT); case MXC_ESDHC_CLK: return get_root_clk(USDHC1_CLK_ROOT); case MXC_ESDHC2_CLK: return get_root_clk(USDHC2_CLK_ROOT); + case MXC_I2C_CLK: + return get_root_clk(I2C1_CLK_ROOT); + case MXC_UART_CLK: + return get_root_clk(UART1_CLK_ROOT); + case MXC_QSPI_CLK: + return get_root_clk(QSPI_CLK_ROOT); default: return get_root_clk(clk); } diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c index 863508776d..da106769b1 100644 --- a/arch/arm/mach-imx/imx8m/soc.c +++ b/arch/arm/mach-imx/imx8m/soc.c @@ -66,8 +66,21 @@ void enable_tzc380(void) /* Enable TZASC and lock setting */ setbits_le32(&gpr->gpr[10], GPR_TZASC_EN); setbits_le32(&gpr->gpr[10], GPR_TZASC_EN_LOCK); + + /* + * According to TRM, TZASC_ID_SWAP_BYPASS should be set in + * order to avoid AXI Bus errors when GPU is in use + */ if (is_imx8mm() || is_imx8mn() || is_imx8mp()) - setbits_le32(&gpr->gpr[10], BIT(1)); + setbits_le32(&gpr->gpr[10], GPR_TZASC_ID_SWAP_BYPASS); + + /* + * imx8mn and imx8mp implements the lock bit for + * TZASC_ID_SWAP_BYPASS, enable it to lock settings + */ + if (is_imx8mn() || is_imx8mp()) + setbits_le32(&gpr->gpr[10], GPR_TZASC_ID_SWAP_BYPASS_LOCK); + /* * set Region 0 attribute to allow secure and non-secure * read/write permission. Found some masters like usb dwc3 @@ -1316,40 +1329,35 @@ void do_error(struct pt_regs *pt_regs, unsigned int esr) enum env_location env_get_location(enum env_operation op, int prio) { enum boot_device dev = get_boot_device(); - enum env_location env_loc = ENVL_UNKNOWN; if (prio) - return env_loc; + return ENVL_UNKNOWN; switch (dev) { -#ifdef CONFIG_ENV_IS_IN_SPI_FLASH case QSPI_BOOT: - env_loc = ENVL_SPI_FLASH; - break; -#endif -#ifdef CONFIG_ENV_IS_IN_NAND + if (IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH)) + return ENVL_SPI_FLASH; + return ENVL_NOWHERE; case NAND_BOOT: - env_loc = ENVL_NAND; - break; -#endif -#ifdef CONFIG_ENV_IS_IN_MMC + if (IS_ENABLED(CONFIG_ENV_IS_IN_NAND)) + return ENVL_NAND; + return ENVL_NOWHERE; case SD1_BOOT: case SD2_BOOT: case SD3_BOOT: case MMC1_BOOT: case MMC2_BOOT: case MMC3_BOOT: - env_loc = ENVL_MMC; - break; -#endif + if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC)) + return ENVL_MMC; + else if (IS_ENABLED(CONFIG_ENV_IS_IN_EXT4)) + return ENVL_EXT4; + else if (IS_ENABLED(CONFIG_ENV_IS_IN_FAT)) + return ENVL_FAT; + return ENVL_NOWHERE; default: -#if defined(CONFIG_ENV_IS_NOWHERE) - env_loc = ENVL_NOWHERE; -#endif - break; + return ENVL_NOWHERE; } - - return env_loc; } #ifndef ENV_IS_EMBEDDED diff --git a/arch/arm/mach-imx/imx8ulp/cgc.c b/arch/arm/mach-imx/imx8ulp/cgc.c index 7bfc3862cd..38bcbb91e6 100644 --- a/arch/arm/mach-imx/imx8ulp/cgc.c +++ b/arch/arm/mach-imx/imx8ulp/cgc.c @@ -189,8 +189,8 @@ void cgc2_pll4_init(void) ; /* Enable all 4 PFDs */ - setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 0); /* 316.8Mhz for NIC_LPAV */ - setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 8); + setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 0); + setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 8); /* 316.8Mhz for NIC_LPAV */ setbits_le32(&cgc2_regs->pll4pfdcfg, 12 << 16); setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 24); @@ -205,15 +205,144 @@ void cgc2_pll4_init(void) clrbits_le32(&cgc2_regs->pll4div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31)); } +void cgc2_pll4_pfd_config(enum cgc_clk pllpfd, u32 pfd) +{ + void __iomem *reg = &cgc2_regs->pll4div_pfd0; + u32 halt_mask = BIT(7) | BIT(15); + u32 pfd_shift = (pllpfd - PLL4_PFD0) * 8; + u32 val; + + if (pllpfd < PLL4_PFD0 || pllpfd > PLL4_PFD3) + return; + + if ((pllpfd - PLL4_PFD0) >> 1) + reg = &cgc2_regs->pll4div_pfd1; + + halt_mask = halt_mask << (((pllpfd - PLL4_PFD0) & 0x1) * 16); + + /* halt pfd div */ + setbits_le32(reg, halt_mask); + + /* gate pfd */ + setbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) << pfd_shift); + + val = readl(&cgc2_regs->pll4pfdcfg); + val &= ~(0x3f << pfd_shift); + val |= (pfd << pfd_shift); + writel(val, &cgc2_regs->pll4pfdcfg); + + /* ungate */ + clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) << pfd_shift); + + /* Wait stable */ + while ((readl(&cgc2_regs->pll4pfdcfg) & (BIT(6) << pfd_shift)) + != (BIT(6) << pfd_shift)) + ; + + /* enable pfd div */ + clrbits_le32(reg, halt_mask); +} + +void cgc2_pll4_pfddiv_config(enum cgc_clk pllpfddiv, u32 div) +{ + void __iomem *reg = &cgc2_regs->pll4div_pfd0; + u32 shift = ((pllpfddiv - PLL4_PFD0_DIV1) & 0x3) * 8; + + if (pllpfddiv < PLL4_PFD0_DIV1 || pllpfddiv > PLL4_PFD3_DIV2) + return; + + if ((pllpfddiv - PLL4_PFD0_DIV1) >> 2) + reg = &cgc2_regs->pll4div_pfd1; + + /* Halt pfd div */ + setbits_le32(reg, BIT(7) << shift); + + /* Clear div */ + clrbits_le32(reg, 0x3f << shift); + + /* Set div*/ + setbits_le32(reg, div << shift); + + /* Enable pfd div */ + clrbits_le32(reg, BIT(7) << shift); +} + void cgc2_ddrclk_config(u32 src, u32 div) { + /* If reg lock is set, wait until unlock by HW */ + /* This lock is triggered by div updating and ddrclk halt status change, */ + while ((readl(&cgc2_regs->ddrclk) & BIT(31))) + ; + writel((src << 28) | (div << 21), &cgc2_regs->ddrclk); /* wait for DDRCLK switching done */ while (!(readl(&cgc2_regs->ddrclk) & BIT(27))) ; } -u32 decode_pll(enum cgc1_clk pll) +void cgc2_ddrclk_wait_unlock(void) +{ + while ((readl(&cgc2_regs->ddrclk) & BIT(31))) + ; +} + +void cgc2_lpav_init(enum cgc_clk clk) +{ + u32 i, scs, reg; + const enum cgc_clk src[] = {FRO, PLL4_PFD1, SOSC, LVDS}; + + reg = readl(&cgc2_regs->niclpavclk); + scs = (reg >> 28) & 0x3; + + for (i = 0; i < 4; i++) { + if (clk == src[i]) { + if (scs == i) + return; + + reg &= ~(0x3 << 28); + reg |= (i << 28); + + writel(reg, &cgc2_regs->niclpavclk); + break; + } + } + + if (i == 4) + printf("Invalid clock source [%u] for LPAV\n", clk); +} + +u32 cgc2_nic_get_rate(enum cgc_clk clk) +{ + u32 reg, rate; + u32 scs, lpav_axi_clk, lpav_ahb_clk, lpav_bus_clk; + const enum cgc_clk src[] = {FRO, PLL4_PFD1, SOSC, LVDS}; + + reg = readl(&cgc2_regs->niclpavclk); + scs = (reg >> 28) & 0x3; + lpav_axi_clk = ((reg >> 21) & 0x3f) + 1; + lpav_ahb_clk = ((reg >> 14) & 0x3f) + 1; + lpav_bus_clk = ((reg >> 7) & 0x3f) + 1; + + rate = cgc_clk_get_rate(src[scs]); + + switch (clk) { + case LPAV_AXICLK: + rate = rate / lpav_axi_clk; + break; + case LPAV_AHBCLK: + rate = rate / (lpav_axi_clk * lpav_ahb_clk); + break; + case LPAV_BUSCLK: + rate = rate / (lpav_axi_clk * lpav_bus_clk); + break; + default: + return 0; + } + + return rate; +} + +u32 decode_pll(enum cgc_clk pll) { u32 reg, infreq, mult; u32 num, denom; @@ -247,6 +376,17 @@ u32 decode_pll(enum cgc1_clk pll) num = readl(&cgc1_regs->pll3num) & 0x3FFFFFFF; return (u64)infreq * mult + (u64)infreq * num / denom; + case PLL4: + reg = readl(&cgc2_regs->pll4csr); + if (!(reg & BIT(24))) + return 0; + + reg = readl(&cgc2_regs->pll4cfg); + mult = (reg >> 16) & 0x7F; + denom = readl(&cgc2_regs->pll4denom) & 0x3FFFFFFF; + num = readl(&cgc2_regs->pll4num) & 0x3FFFFFFF; + + return (u64)infreq * mult + (u64)infreq * num / denom; default: printf("Unsupported pll clocks %d\n", pll); break; @@ -255,93 +395,117 @@ u32 decode_pll(enum cgc1_clk pll) return 0; } -u32 cgc1_pll3_vcodiv_rate(void) +u32 cgc_pll_vcodiv_rate(enum cgc_clk clk) { u32 reg, gate, div; + void __iomem *plldiv_vco; + enum cgc_clk pll; + + if (clk == PLL3_VCODIV) { + plldiv_vco = &cgc1_regs->pll3div_vco; + pll = PLL3; + } else { + plldiv_vco = &cgc2_regs->pll4div_vco; + pll = PLL4; + } - reg = readl(&cgc1_regs->pll3div_vco); + reg = readl(plldiv_vco); gate = BIT(7) & reg; div = reg & 0x3F; - return gate ? 0 : decode_pll(PLL3) / (div + 1); + return gate ? 0 : decode_pll(pll) / (div + 1); } -u32 cgc1_pll3_pfd_rate(enum cgc1_clk clk) +u32 cgc_pll_pfd_rate(enum cgc_clk clk) { u32 index, gate, vld, reg; + void __iomem *pllpfdcfg; + enum cgc_clk pll; switch (clk) { case PLL3_PFD0: - index = 0; - break; case PLL3_PFD1: - index = 1; - break; case PLL3_PFD2: - index = 2; - break; case PLL3_PFD3: - index = 3; + index = clk - PLL3_PFD0; + pllpfdcfg = &cgc1_regs->pll3pfdcfg; + pll = PLL3; + break; + case PLL4_PFD0: + case PLL4_PFD1: + case PLL4_PFD2: + case PLL4_PFD3: + index = clk - PLL4_PFD0; + pllpfdcfg = &cgc2_regs->pll4pfdcfg; + pll = PLL4; break; default: return 0; } - reg = readl(&cgc1_regs->pll3pfdcfg); + reg = readl(pllpfdcfg); gate = reg & (BIT(7) << (index * 8)); vld = reg & (BIT(6) << (index * 8)); if (gate || !vld) return 0; - return (u64)decode_pll(PLL3) * 18 / ((reg >> (index * 8)) & 0x3F); + return (u64)decode_pll(pll) * 18 / ((reg >> (index * 8)) & 0x3F); } -u32 cgc1_pll3_pfd_div(enum cgc1_clk clk) +u32 cgc_pll_pfd_div(enum cgc_clk clk) { void __iomem *base; u32 pfd, index, gate, reg; switch (clk) { case PLL3_PFD0_DIV1: - base = &cgc1_regs->pll3div_pfd0; - pfd = PLL3_PFD0; - index = 0; - break; case PLL3_PFD0_DIV2: base = &cgc1_regs->pll3div_pfd0; pfd = PLL3_PFD0; - index = 1; + index = clk - PLL3_PFD0_DIV1; break; case PLL3_PFD1_DIV1: - base = &cgc1_regs->pll3div_pfd0; - pfd = PLL3_PFD1; - index = 2; - break; case PLL3_PFD1_DIV2: base = &cgc1_regs->pll3div_pfd0; pfd = PLL3_PFD1; - index = 3; + index = clk - PLL3_PFD0_DIV1; break; case PLL3_PFD2_DIV1: - base = &cgc1_regs->pll3div_pfd1; - pfd = PLL3_PFD2; - index = 0; - break; case PLL3_PFD2_DIV2: base = &cgc1_regs->pll3div_pfd1; pfd = PLL3_PFD2; - index = 1; + index = clk - PLL3_PFD2_DIV1; break; case PLL3_PFD3_DIV1: - base = &cgc1_regs->pll3div_pfd1; - pfd = PLL3_PFD3; - index = 2; - break; case PLL3_PFD3_DIV2: base = &cgc1_regs->pll3div_pfd1; pfd = PLL3_PFD3; - index = 3; + index = clk - PLL3_PFD2_DIV1; + break; + case PLL4_PFD0_DIV1: + case PLL4_PFD0_DIV2: + base = &cgc2_regs->pll4div_pfd0; + pfd = PLL4_PFD0; + index = clk - PLL4_PFD0_DIV1; + break; + case PLL4_PFD1_DIV1: + case PLL4_PFD1_DIV2: + base = &cgc2_regs->pll4div_pfd0; + pfd = PLL4_PFD1; + index = clk - PLL4_PFD0_DIV1; + break; + case PLL4_PFD2_DIV1: + case PLL4_PFD2_DIV2: + base = &cgc2_regs->pll4div_pfd1; + pfd = PLL4_PFD2; + index = clk - PLL4_PFD2_DIV1; + break; + case PLL4_PFD3_DIV1: + case PLL4_PFD3_DIV2: + base = &cgc2_regs->pll4div_pfd1; + pfd = PLL4_PFD3; + index = clk - PLL4_PFD2_DIV1; break; default: return 0; @@ -353,10 +517,52 @@ u32 cgc1_pll3_pfd_div(enum cgc1_clk clk) if (gate) return 0; - return cgc1_pll3_pfd_rate(pfd) / (((reg >> (index * 8)) & 0x3F) + 1); + return cgc_pll_pfd_rate(pfd) / (((reg >> (index * 8)) & 0x3F) + 1); +} + +u32 cgc1_nic_get_rate(enum cgc_clk clk) +{ + u32 reg, rate; + u32 scs, nic_ad_divplat, nic_per_divplat; + u32 xbar_ad_divplat, xbar_divbus, ad_slow; + const enum cgc_clk src[] = {FRO, PLL3_PFD0, SOSC, LVDS}; + + reg = readl(&cgc1_regs->nicclk); + scs = (reg >> 28) & 0x3; + nic_ad_divplat = ((reg >> 21) & 0x3f) + 1; + nic_per_divplat = ((reg >> 14) & 0x3f) + 1; + + reg = readl(&cgc1_regs->xbarclk); + xbar_ad_divplat = ((reg >> 14) & 0x3f) + 1; + xbar_divbus = ((reg >> 7) & 0x3f) + 1; + ad_slow = (reg & 0x3f) + 1; + + rate = cgc_clk_get_rate(src[scs]); + + switch (clk) { + case NIC_APCLK: + rate = rate / nic_ad_divplat; + break; + case NIC_PERCLK: + rate = rate / (nic_ad_divplat * nic_per_divplat); + break; + case XBAR_APCLK: + rate = rate / (nic_ad_divplat * xbar_ad_divplat); + break; + case XBAR_BUSCLK: + rate = rate / (nic_ad_divplat * xbar_ad_divplat * xbar_divbus); + break; + case AD_SLOWCLK: + rate = rate / (nic_ad_divplat * xbar_ad_divplat * ad_slow); + break; + default: + return 0; + } + + return rate; } -u32 cgc1_sosc_div(enum cgc1_clk clk) +u32 cgc1_sosc_div(enum cgc_clk clk) { u32 reg, gate, index; @@ -385,7 +591,7 @@ u32 cgc1_sosc_div(enum cgc1_clk clk) return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1); } -u32 cgc1_fro_div(enum cgc1_clk clk) +u32 cgc1_fro_div(enum cgc_clk clk) { u32 reg, gate, vld, index; @@ -415,9 +621,11 @@ u32 cgc1_fro_div(enum cgc1_clk clk) return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1); } -u32 cgc1_clk_get_rate(enum cgc1_clk clk) +u32 cgc_clk_get_rate(enum cgc_clk clk) { switch (clk) { + case LVDS: + return 0; /* No external LVDS clock used */ case SOSC: case SOSC_DIV1: case SOSC_DIV2: @@ -429,16 +637,21 @@ u32 cgc1_clk_get_rate(enum cgc1_clk clk) case FRO_DIV3: return cgc1_fro_div(clk); case PLL2: - return decode_pll(PLL2); case PLL3: - return decode_pll(PLL3); + case PLL4: + return decode_pll(clk); case PLL3_VCODIV: - return cgc1_pll3_vcodiv_rate(); + case PLL4_VCODIV: + return cgc_pll_vcodiv_rate(clk); case PLL3_PFD0: case PLL3_PFD1: case PLL3_PFD2: case PLL3_PFD3: - return cgc1_pll3_pfd_rate(clk); + case PLL4_PFD0: + case PLL4_PFD1: + case PLL4_PFD2: + case PLL4_PFD3: + return cgc_pll_pfd_rate(clk); case PLL3_PFD0_DIV1: case PLL3_PFD0_DIV2: case PLL3_PFD1_DIV1: @@ -447,9 +660,27 @@ u32 cgc1_clk_get_rate(enum cgc1_clk clk) case PLL3_PFD2_DIV2: case PLL3_PFD3_DIV1: case PLL3_PFD3_DIV2: - return cgc1_pll3_pfd_div(clk); + case PLL4_PFD0_DIV1: + case PLL4_PFD0_DIV2: + case PLL4_PFD1_DIV1: + case PLL4_PFD1_DIV2: + case PLL4_PFD2_DIV1: + case PLL4_PFD2_DIV2: + case PLL4_PFD3_DIV1: + case PLL4_PFD3_DIV2: + return cgc_pll_pfd_div(clk); + case NIC_APCLK: + case NIC_PERCLK: + case XBAR_APCLK: + case XBAR_BUSCLK: + case AD_SLOWCLK: + return cgc1_nic_get_rate(clk); + case LPAV_AXICLK: + case LPAV_AHBCLK: + case LPAV_BUSCLK: + return cgc2_nic_get_rate(clk); default: - printf("Unsupported cgc1 clock: %d\n", clk); + printf("Unsupported cgc clock: %d\n", clk); return 0; } } diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c index ebbaad4106..91580b2c29 100644 --- a/arch/arm/mach-imx/imx8ulp/clock.c +++ b/arch/arm/mach-imx/imx8ulp/clock.c @@ -27,7 +27,7 @@ DECLARE_GLOBAL_DATA_PTR; #define PLL_USB_LOCK_MASK (0x01 << 31) #define PCC5_LPDDR4_ADDR 0x2da70108 -static void lpuart_set_clk(u32 index, enum cgc1_clk clk) +static void lpuart_set_clk(u32 index, enum cgc_clk clk) { const u32 lpuart_pcc_slots[] = { LPUART4_PCC3_SLOT, @@ -97,6 +97,9 @@ void ddrphy_pll_lock(void) void init_clk_ddr(void) { + /* disable the ddr pcc */ + writel(0xc0000000, PCC5_LPDDR4_ADDR); + /* enable pll4 and ddrclk*/ cgc2_pll4_init(); cgc2_ddrclk_config(1, 1); @@ -104,6 +107,9 @@ void init_clk_ddr(void) /* enable ddr pcc */ writel(0xd0000000, PCC5_LPDDR4_ADDR); + /* Wait until ddrclk reg lock bit is cleared, so that the div update is finished */ + cgc2_ddrclk_wait_unlock(); + /* for debug */ /* setclkout_ddr(); */ } @@ -141,6 +147,9 @@ int set_ddr_clk(u32 phy_freq_mhz) return -EINVAL; } + /* Wait until ddrclk reg lock bit is cleared, so that the div update is finished */ + cgc2_ddrclk_wait_unlock(); + return 0; } @@ -186,6 +195,9 @@ int enable_i2c_clk(unsigned char enable, u32 i2c_num) LPI2C7_PCC4_SLOT << 8 | 4, }; + if (i2c_num == 0) + return 0; + if (i2c_num < 4 || i2c_num > 7) return -EINVAL; @@ -214,6 +226,9 @@ u32 imx_get_i2cclk(u32 i2c_num) LPI2C7_PCC4_SLOT << 8 | 4, }; + if (i2c_num == 0) + return 24000000; + if (i2c_num < 4 || i2c_num > 7) return 0; @@ -317,6 +332,99 @@ int enable_usb_pll(ulong usb_phy_base) return 0; } +void enable_mipi_dsi_clk(unsigned char enable) +{ + if (enable) { + pcc_clock_enable(5, DSI_PCC5_SLOT, false); + pcc_reset_peripheral(5, DSI_PCC5_SLOT, true); + pcc_clock_sel(5, DSI_PCC5_SLOT, PLL4_PFD3_DIV2); + pcc_clock_div_config(5, DSI_PCC5_SLOT, 0, 6); + pcc_clock_enable(5, DSI_PCC5_SLOT, true); + pcc_reset_peripheral(5, DSI_PCC5_SLOT, false); + } else { + pcc_clock_enable(5, DSI_PCC5_SLOT, false); + pcc_reset_peripheral(5, DSI_PCC5_SLOT, true); + } +} + +void enable_adc1_clk(bool enable) +{ + if (enable) { + pcc_clock_enable(1, ADC1_PCC1_SLOT, false); + pcc_clock_sel(1, ADC1_PCC1_SLOT, CM33_BUSCLK); + pcc_clock_enable(1, ADC1_PCC1_SLOT, true); + pcc_reset_peripheral(1, ADC1_PCC1_SLOT, false); + } else { + pcc_clock_enable(1, ADC1_PCC1_SLOT, false); + } +} + +void reset_lcdclk(void) +{ + /* Disable clock and reset dcnano*/ + pcc_clock_enable(5, DCNANO_PCC5_SLOT, false); + pcc_reset_peripheral(5, DCNANO_PCC5_SLOT, true); +} + +void mxs_set_lcdclk(u32 base_addr, u32 freq_in_khz) +{ + u8 pcd, best_pcd = 0; + u32 frac, rate, parent_rate, pfd, div; + u32 best_pfd = 0, best_frac = 0, best = 0, best_div = 0; + u32 pll4_rate; + + pcc_clock_enable(5, DCNANO_PCC5_SLOT, false); + + pll4_rate = cgc_clk_get_rate(PLL4); + pll4_rate = pll4_rate / 1000; /* Change to khz*/ + + debug("PLL4 rate %ukhz\n", pll4_rate); + + for (pfd = 12; pfd <= 35; pfd++) { + parent_rate = pll4_rate; + parent_rate = parent_rate * 18 / pfd; + + for (div = 1; div <= 64; div++) { + parent_rate = parent_rate / div; + + for (pcd = 0; pcd < 8; pcd++) { + for (frac = 0; frac < 2; frac++) { + if (pcd == 0 && frac == 1) + continue; + + rate = parent_rate * (frac + 1) / (pcd + 1); + if (rate > freq_in_khz) + continue; + + if (best == 0 || rate > best) { + best = rate; + best_pfd = pfd; + best_frac = frac; + best_pcd = pcd; + best_div = div; + } + } + } + } + } + + if (best == 0) { + printf("Can't find parent clock for LCDIF, target freq: %u\n", freq_in_khz); + return; + } + + debug("LCD target rate %ukhz, best rate %ukhz, frac %u, pcd %u, best_pfd %u, best_div %u\n", + freq_in_khz, best, best_frac, best_pcd, best_pfd, best_div); + + cgc2_pll4_pfd_config(PLL4_PFD0, best_pfd); + cgc2_pll4_pfddiv_config(PLL4_PFD0_DIV1, best_div - 1); + + pcc_clock_sel(5, DCNANO_PCC5_SLOT, PLL4_PFD0_DIV1); + pcc_clock_div_config(5, DCNANO_PCC5_SLOT, best_frac, best_pcd + 1); + pcc_clock_enable(5, DCNANO_PCC5_SLOT, true); + pcc_reset_peripheral(5, DCNANO_PCC5_SLOT, false); +} + u32 mxc_get_clock(enum mxc_clock clk) { switch (clk) { @@ -327,7 +435,7 @@ u32 mxc_get_clock(enum mxc_clock clk) case MXC_ESDHC3_CLK: return pcc_clock_get_rate(4, SDHC2_PCC4_SLOT); case MXC_ARM_CLK: - return cgc1_clk_get_rate(PLL2); + return cgc_clk_get_rate(PLL2); default: return 0; } @@ -376,16 +484,40 @@ int do_mx8ulp_showclocks(struct cmd_tbl *cmdtp, int flag, int argc, char * const printf("SDHC1 %8d MHz\n", pcc_clock_get_rate(4, SDHC1_PCC4_SLOT) / 1000000); printf("SDHC2 %8d MHz\n", pcc_clock_get_rate(4, SDHC2_PCC4_SLOT) / 1000000); - printf("SOSC %8d MHz\n", cgc1_clk_get_rate(SOSC) / 1000000); - printf("FRO %8d MHz\n", cgc1_clk_get_rate(FRO) / 1000000); - printf("PLL2 %8d MHz\n", cgc1_clk_get_rate(PLL2) / 1000000); - printf("PLL3 %8d MHz\n", cgc1_clk_get_rate(PLL3) / 1000000); - printf("PLL3_VCODIV %8d MHz\n", cgc1_clk_get_rate(PLL3_VCODIV) / 1000000); - printf("PLL3_PFD0 %8d MHz\n", cgc1_clk_get_rate(PLL3_PFD0) / 1000000); - printf("PLL3_PFD1 %8d MHz\n", cgc1_clk_get_rate(PLL3_PFD1) / 1000000); - printf("PLL3_PFD2 %8d MHz\n", cgc1_clk_get_rate(PLL3_PFD2) / 1000000); - printf("PLL3_PFD3 %8d MHz\n", cgc1_clk_get_rate(PLL3_PFD3) / 1000000); - + printf("SOSC %8d MHz\n", cgc_clk_get_rate(SOSC) / 1000000); + printf("FRO %8d MHz\n", cgc_clk_get_rate(FRO) / 1000000); + printf("PLL2 %8d MHz\n", cgc_clk_get_rate(PLL2) / 1000000); + printf("PLL3 %8d MHz\n", cgc_clk_get_rate(PLL3) / 1000000); + printf("PLL3_VCODIV %8d MHz\n", cgc_clk_get_rate(PLL3_VCODIV) / 1000000); + printf("PLL3_PFD0 %8d MHz\n", cgc_clk_get_rate(PLL3_PFD0) / 1000000); + printf("PLL3_PFD1 %8d MHz\n", cgc_clk_get_rate(PLL3_PFD1) / 1000000); + printf("PLL3_PFD2 %8d MHz\n", cgc_clk_get_rate(PLL3_PFD2) / 1000000); + printf("PLL3_PFD3 %8d MHz\n", cgc_clk_get_rate(PLL3_PFD3) / 1000000); + + printf("PLL4_PFD0 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD0) / 1000000); + printf("PLL4_PFD1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD1) / 1000000); + printf("PLL4_PFD2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD2) / 1000000); + printf("PLL4_PFD3 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD3) / 1000000); + + printf("PLL4_PFD0_DIV1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD0_DIV1) / 1000000); + printf("PLL4_PFD0_DIV2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD0_DIV2) / 1000000); + printf("PLL4_PFD1_DIV1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD1_DIV1) / 1000000); + printf("PLL4_PFD1_DIV2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD1_DIV2) / 1000000); + + printf("PLL4_PFD2_DIV1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD2_DIV1) / 1000000); + printf("PLL4_PFD2_DIV2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD2_DIV2) / 1000000); + printf("PLL4_PFD3_DIV1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD3_DIV1) / 1000000); + printf("PLL4_PFD3_DIV2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD3_DIV2) / 1000000); + + printf("LPAV_AXICLK %8d MHz\n", cgc_clk_get_rate(LPAV_AXICLK) / 1000000); + printf("LPAV_AHBCLK %8d MHz\n", cgc_clk_get_rate(LPAV_AHBCLK) / 1000000); + printf("LPAV_BUSCLK %8d MHz\n", cgc_clk_get_rate(LPAV_BUSCLK) / 1000000); + printf("NIC_APCLK %8d MHz\n", cgc_clk_get_rate(NIC_APCLK) / 1000000); + + printf("NIC_PERCLK %8d MHz\n", cgc_clk_get_rate(NIC_PERCLK) / 1000000); + printf("XBAR_APCLK %8d MHz\n", cgc_clk_get_rate(XBAR_APCLK) / 1000000); + printf("XBAR_BUSCLK %8d MHz\n", cgc_clk_get_rate(XBAR_BUSCLK) / 1000000); + printf("AD_SLOWCLK %8d MHz\n", cgc_clk_get_rate(AD_SLOWCLK) / 1000000); return 0; } diff --git a/arch/arm/mach-imx/imx8ulp/pcc.c b/arch/arm/mach-imx/imx8ulp/pcc.c index 711b685cd7..7909d770af 100644 --- a/arch/arm/mach-imx/imx8ulp/pcc.c +++ b/arch/arm/mach-imx/imx8ulp/pcc.c @@ -12,10 +12,25 @@ #include <asm/arch/cgc.h> #include <asm/arch/sys_proto.h> -#define cgc1_clk_TYPES 2 -#define cgc1_clk_NUM 8 +#define cgc_clk_TYPES 2 +#define cgc_clk_NUM 8 -static enum cgc1_clk pcc3_clksrc[][8] = { +static enum cgc_clk pcc1_clksrc[][8] = { + { + }, + { + DUMMY0_CLK, + LPOSC, + SOSC_DIV2, + FRO_DIV2, + CM33_BUSCLK, + PLL1_VCO_DIV, + PLL0_PFD2_DIV, + PLL0_PFD1_DIV, + } +}; + +static enum cgc_clk pcc3_clksrc[][8] = { { }, { DUMMY0_CLK, @@ -29,7 +44,7 @@ static enum cgc1_clk pcc3_clksrc[][8] = { } }; -static enum cgc1_clk pcc4_clksrc[][8] = { +static enum cgc_clk pcc4_clksrc[][8] = { { DUMMY0_CLK, SOSC_DIV1, @@ -52,6 +67,34 @@ static enum cgc1_clk pcc4_clksrc[][8] = { } }; +static enum cgc_clk pcc5_clksrc[][8] = { + { + DUMMY0_CLK, + PLL4_PFD3_DIV2, + PLL4_PFD2_DIV2, + PLL4_PFD2_DIV1, + PLL4_PFD1_DIV2, + PLL4_PFD1_DIV1, + PLL4_PFD0_DIV2, + PLL4_PFD0_DIV1 + }, + { + DUMMY0_CLK, + DUMMY1_CLK, + LPOSC, + SOSC_DIV2, + FRO_DIV2, + LPAV_BUSCLK, + PLL4_VCODIV, + PLL4_PFD3_DIV1 + } +}; + +static struct pcc_entry pcc1_arrays[] = { + {PCC1_RBASE, ADC1_PCC1_SLOT, CLKSRC_PER_BUS, PCC_NO_DIV, PCC_HAS_RST_B}, + {} +}; + static struct pcc_entry pcc3_arrays[] = { {PCC3_RBASE, DMA1_MP_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, {PCC3_RBASE, DMA1_CH0_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, @@ -136,12 +179,79 @@ static struct pcc_entry pcc4_arrays[] = { {} }; +static struct pcc_entry pcc5_arrays[] = { + {PCC5_RBASE, DMA2_MP_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH0_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH1_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH2_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH3_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH4_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH5_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH6_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH7_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH8_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH9_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH10_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH11_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH12_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH13_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH14_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH15_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH16_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH17_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH18_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH19_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH20_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH21_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH22_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH23_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH24_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH25_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH26_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH27_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH28_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH29_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH30_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, DMA2_CH31_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, MU2_B_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, MU3_B_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, SEMA42_2_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, CMC2_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, AVD_SIM_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, LPAV_CGC_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, PCC5_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, TPM8_PCC5_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, SAI6_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, SAI7_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, SPDIF_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, ISI_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, CSI_REGS_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, CSI_PCC5_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, DSI_PCC5_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, WDOG5_PCC5_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, EPDC_PCC5_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, PXP_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, SFA2_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, GPU2D_PCC5_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, GPU3D_PCC5_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, DCNANO_PCC5_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, LPDDR4_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC5_RBASE, CSI_CLK_UI_PCC5_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, CSI_CLK_ESC_PCC5_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_NO_RST_B }, + {PCC5_RBASE, RGPIOD_PCC5_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {} +}; + static int find_pcc_entry(int pcc_controller, int pcc_clk_slot, struct pcc_entry **out) { struct pcc_entry *pcc_array; int index = 0; switch (pcc_controller) { + case 1: + pcc_array = pcc1_arrays; + *out = &pcc1_arrays[0]; + break; case 3: pcc_array = pcc3_arrays; *out = &pcc3_arrays[0]; @@ -150,6 +260,10 @@ static int find_pcc_entry(int pcc_controller, int pcc_clk_slot, struct pcc_entry pcc_array = pcc4_arrays; *out = &pcc4_arrays[0]; break; + case 5: + pcc_array = pcc5_arrays; + *out = &pcc5_arrays[0]; + break; default: printf("Not supported pcc_controller: %d\n", pcc_controller); return -EINVAL; @@ -199,12 +313,12 @@ int pcc_clock_enable(int pcc_controller, int pcc_clk_slot, bool enable) } /* The clock source select needs clock is disabled */ -int pcc_clock_sel(int pcc_controller, int pcc_clk_slot, enum cgc1_clk src) +int pcc_clock_sel(int pcc_controller, int pcc_clk_slot, enum cgc_clk src) { u32 val, i, clksrc_type; void __iomem *reg; struct pcc_entry *pcc_array; - enum cgc1_clk *cgc1_clk_array; + enum cgc_clk *cgc_clk_array; int clk; clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array); @@ -220,19 +334,23 @@ int pcc_clock_sel(int pcc_controller, int pcc_clk_slot, enum cgc1_clk src) return -EPERM; } - if (pcc_controller == 3) - cgc1_clk_array = pcc3_clksrc[clksrc_type]; + if (pcc_controller == 1) + cgc_clk_array = pcc1_clksrc[clksrc_type]; + else if (pcc_controller == 3) + cgc_clk_array = pcc3_clksrc[clksrc_type]; + else if (pcc_controller == 4) + cgc_clk_array = pcc4_clksrc[clksrc_type]; else - cgc1_clk_array = pcc4_clksrc[clksrc_type]; + cgc_clk_array = pcc5_clksrc[clksrc_type]; - for (i = 0; i < cgc1_clk_NUM; i++) { - if (cgc1_clk_array[i] == src) { + for (i = 0; i < cgc_clk_NUM; i++) { + if (cgc_clk_array[i] == src) { /* Find the clock src, then set it to PCS */ break; } } - if (i == cgc1_clk_NUM) { + if (i == cgc_clk_NUM) { printf("No parent in PCS of PCC %d, invalid scg_clk %d\n", clk, src); return -EINVAL; } @@ -320,13 +438,13 @@ bool pcc_clock_is_enable(int pcc_controller, int pcc_clk_slot) return false; } -int pcc_clock_get_clksrc(int pcc_controller, int pcc_clk_slot, enum cgc1_clk *src) +int pcc_clock_get_clksrc(int pcc_controller, int pcc_clk_slot, enum cgc_clk *src) { u32 val, clksrc_type; void __iomem *reg; struct pcc_entry *pcc_array; int clk; - enum cgc1_clk *cgc1_clk_array; + enum cgc_clk *cgc_clk_array; clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array); if (clk < 0) @@ -360,11 +478,13 @@ int pcc_clock_get_clksrc(int pcc_controller, int pcc_clk_slot, enum cgc1_clk *sr } if (pcc_controller == 3) - cgc1_clk_array = pcc3_clksrc[clksrc_type]; + cgc_clk_array = pcc3_clksrc[clksrc_type]; + else if (pcc_controller == 4) + cgc_clk_array = pcc4_clksrc[clksrc_type]; else - cgc1_clk_array = pcc4_clksrc[clksrc_type]; + cgc_clk_array = pcc5_clksrc[clksrc_type]; - *src = cgc1_clk_array[val]; + *src = cgc_clk_array[val]; debug("%s: parent cgc1 clk %d\n", __func__, *src); @@ -412,7 +532,7 @@ u32 pcc_clock_get_rate(int pcc_controller, int pcc_clk_slot) { u32 val, rate, frac, div; void __iomem *reg; - enum cgc1_clk parent; + enum cgc_clk parent; int ret; int clk; struct pcc_entry *pcc_array; @@ -425,7 +545,7 @@ u32 pcc_clock_get_rate(int pcc_controller, int pcc_clk_slot) if (ret) return 0; - rate = cgc1_clk_get_rate(parent); + rate = cgc_clk_get_rate(parent); debug("%s: parent rate %u\n", __func__, rate); diff --git a/arch/arm/mach-imx/imx8ulp/soc.c b/arch/arm/mach-imx/imx8ulp/soc.c index bba6323f96..934b0ef038 100644 --- a/arch/arm/mach-imx/imx8ulp/soc.c +++ b/arch/arm/mach-imx/imx8ulp/soc.c @@ -23,6 +23,8 @@ #include <dm/uclass.h> #include <dm/device.h> #include <dm/uclass-internal.h> +#include <fuse.h> +#include <thermal.h> DECLARE_GLOBAL_DATA_PTR; @@ -210,11 +212,27 @@ int print_cpuinfo(void) cpurev = get_cpu_rev(); - printf("CPU: Freescale i.MX%s rev%d.%d at %d MHz\n", + printf("CPU: i.MX%s rev%d.%d at %d MHz\n", get_imx_type((cpurev & 0xFF000) >> 12), (cpurev & 0x000F0) >> 4, (cpurev & 0x0000F) >> 0, mxc_get_clock(MXC_ARM_CLK) / 1000000); +#if defined(CONFIG_IMX_PMC_TEMPERATURE) + struct udevice *udev; + int ret, temp; + + ret = uclass_get_device(UCLASS_THERMAL, 0, &udev); + if (!ret) { + ret = thermal_get_temp(udev, &temp); + if (!ret) + printf("CPU current temperature: %d\n", temp); + else + debug(" - failed to get CPU current temperature\n"); + } else { + debug(" - failed to get CPU current temperature\n"); + } +#endif + printf("Reset cause: %s\n", get_reset_cause(cause)); printf("Boot mode: "); @@ -462,28 +480,84 @@ static int trdc_set_access(void) /* Iomuxc0: : PBridge1 slot 33 */ trdc_mbc_set_access(2, 7, 1, 33, false); + /* flexspi0 */ + trdc_mrc_region_set_access(0, 7, 0x04000000, 0x0c000000, false); + + /* tpm0: PBridge1 slot 21 */ + trdc_mbc_set_access(2, 7, 1, 21, false); + /* lpi2c0: PBridge1 slot 24 */ + trdc_mbc_set_access(2, 7, 1, 24, false); return 0; } +void lpav_configure(void) +{ + /* LPAV to APD */ + setbits_le32(SIM_SEC_BASE_ADDR + 0x44, BIT(7)); + + /* PXP/GPU 2D/3D/DCNANO/MIPI_DSI/EPDC/HIFI4 to APD */ + setbits_le32(SIM_SEC_BASE_ADDR + 0x4c, 0x7F); + + /* LPAV slave/dma2 ch allocation and request allocation to APD */ + writel(0x1f, SIM_SEC_BASE_ADDR + 0x50); + writel(0xffffffff, SIM_SEC_BASE_ADDR + 0x54); + writel(0x003fffff, SIM_SEC_BASE_ADDR + 0x58); +} + +void load_lposc_fuse(void) +{ + int ret; + u32 val = 0, val2 = 0, reg; + + ret = fuse_read(25, 0, &val); + if (ret) + return; /* failed */ + + ret = fuse_read(25, 1, &val2); + if (ret) + return; /* failed */ + + /* LPOSCCTRL */ + reg = readl(0x2802f304); + reg &= ~0xff; + reg |= (val & 0xff); + writel(reg, 0x2802f304); +} + +void set_lpav_qos(void) +{ + /* Set read QoS of dcnano on LPAV NIC */ + writel(0xf, 0x2e447100); +} + int arch_cpu_init(void) { if (IS_ENABLED(CONFIG_SPL_BUILD)) { + u32 val = 0; + int ret; + bool rdc_en = true; /* Default assume DBD_EN is set */ + /* Disable wdog */ init_wdog(); + /* Read DBD_EN fuse */ + ret = fuse_read(8, 1, &val); + if (!ret) + rdc_en = !!(val & 0x4000); + if (get_boot_mode() == SINGLE_BOOT) { - release_rdc(RDC_TRDC); + if (rdc_en) + release_rdc(RDC_TRDC); + trdc_set_access(); - /* LPAV to APD */ - setbits_le32(0x2802B044, BIT(7)); - /* GPU 2D/3D to APD */ - setbits_le32(0x2802B04C, BIT(1) | BIT(2)); - /* DCNANO and MIPI_DSI to APD */ - setbits_le32(0x2802B04C, BIT(1) | BIT(2) | BIT(3) | BIT(4)); + + lpav_configure(); } - /* release xrdc, then allow A35 to write SRAM2 */ - release_rdc(RDC_XRDC); + /* Release xrdc, then allow A35 to write SRAM2 */ + if (rdc_en) + release_rdc(RDC_XRDC); + xrdc_mrc_region_set_access(2, CONFIG_SPL_TEXT_BASE, 0xE00); clock_init(); @@ -531,7 +605,30 @@ __weak void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) { + u32 val[2] = {}; + int ret; + + ret = fuse_read(5, 3, &val[0]); + if (ret) + goto err; + + ret = fuse_read(5, 4, &val[1]); + if (ret) + goto err; + + mac[0] = val[0]; + mac[1] = val[0] >> 8; + mac[2] = val[0] >> 16; + mac[3] = val[0] >> 24; + mac[4] = val[1]; + mac[5] = val[1] >> 8; + + debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n", + __func__, dev_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return; +err: memset(mac, 0, 6); + printf("%s: fuse read err: %d\n", __func__, ret); } int (*card_emmc_is_boot_part_en)(void) = (void *)0x67cc; diff --git a/arch/arm/mach-imx/mx6/soc.c b/arch/arm/mach-imx/mx6/soc.c index aacfc854a2..03d6b8c1ce 100644 --- a/arch/arm/mach-imx/mx6/soc.c +++ b/arch/arm/mach-imx/mx6/soc.c @@ -366,11 +366,13 @@ static void init_bandgap(void) * 111 - set REFTOP_VBGADJ[2:0] to 3b'111, */ if (is_mx6ull()) { + static const u32 map[] = {6, 1, 2, 3, 4, 5, 0, 7}; + val = readl(&fuse->mem0); val >>= OCOTP_MEM0_REFTOP_TRIM_SHIFT; val &= 0x7; - writel(val << BM_ANADIG_ANA_MISC0_REFTOP_VBGADJ_SHIFT, + writel(map[val] << BM_ANADIG_ANA_MISC0_REFTOP_VBGADJ_SHIFT, &anatop->ana_misc0_set); } } @@ -487,6 +489,9 @@ int arch_cpu_init(void) if (is_mx6dqp()) noc_setup(); #endif + + enable_ca7_smp(); + return 0; } @@ -498,8 +503,7 @@ __weak int board_mmc_get_env_dev(int devno) static int mmc_get_boot_dev(void) { - struct src *src_regs = (struct src *)SRC_BASE_ADDR; - u32 soc_sbmr = readl(&src_regs->sbmr1); + u32 soc_sbmr = imx6_src_get_boot_mode(); u32 bootsel; int devno; diff --git a/arch/arm/mach-imx/mx7/soc.c b/arch/arm/mach-imx/mx7/soc.c index 21690072e1..f6aec5a3aa 100644 --- a/arch/arm/mach-imx/mx7/soc.c +++ b/arch/arm/mach-imx/mx7/soc.c @@ -14,6 +14,7 @@ #include <asm/mach-imx/rdc-sema.h> #include <asm/arch/imx-rdc.h> #include <asm/mach-imx/boot_mode.h> +#include <asm/mach-imx/sys_proto.h> #include <asm/arch/crm_regs.h> #include <asm/bootm.h> #include <dm.h> @@ -323,6 +324,8 @@ int arch_cpu_init(void) imx_gpcv2_init(); + enable_ca7_smp(); + return 0; } #else diff --git a/arch/arm/mach-imx/mx7ulp/Kconfig b/arch/arm/mach-imx/mx7ulp/Kconfig index 2ffac9cf7c..15c3ab6dae 100644 --- a/arch/arm/mach-imx/mx7ulp/Kconfig +++ b/arch/arm/mach-imx/mx7ulp/Kconfig @@ -9,6 +9,9 @@ config LDO_ENABLED_MODE Select this option to enable the PMC1 LDO. config MX7ULP + select ARCH_SUPPORT_PSCI + select CPU_V7_HAS_NONSEC + select CPU_V7_HAS_VIRT select HAS_CAAM bool @@ -20,6 +23,18 @@ config TARGET_MX7ULP_COM bool "Support MX7ULP COM board" select MX7ULP select SYS_ARCH_TIMER + select SPL_DM if SPL + select SPL_GPIO_SUPPORT if SPL + select SPL_LIBCOMMON_SUPPORT if SPL + select SPL_LIBDISK_SUPPORT if SPL + select SPL_LIBGENERIC_SUPPORT if SPL + select SPL_MMC_SUPPORT if SPL + select SPL_OF_CONTROL if SPL + select SPL_OF_LIBFDT if SPL + select SPL_PINCTRL if SPL + select SPL_SEPARATE_BSS if SPL + select SPL_SERIAL_SUPPORT if SPL + select SUPPORT_SPL config TARGET_MX7ULP_EVK bool "Support mx7ulp EVK board" diff --git a/arch/arm/mach-imx/mx7ulp/soc.c b/arch/arm/mach-imx/mx7ulp/soc.c index c90ce22404..bc41cbc687 100644 --- a/arch/arm/mach-imx/mx7ulp/soc.c +++ b/arch/arm/mach-imx/mx7ulp/soc.c @@ -13,6 +13,7 @@ #include <asm/arch/sys_proto.h> #include <asm/mach-imx/boot_mode.h> #include <asm/mach-imx/hab.h> +#include <asm/mach-imx/sys_proto.h> #include <asm/setup.h> #include <linux/bitops.h> @@ -77,6 +78,7 @@ enum bt_mode get_boot_mode(void) int arch_cpu_init(void) { + enable_ca7_smp(); return 0; } |