From 5ff18da34f915df28f2d20e1d72583d35947e858 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Fri, 29 Oct 2021 09:46:18 +0800 Subject: imx8ulp: clock: Support LPAV clocks in cgc and pcc Add the PCC5 clocks support and more LPAV clocks and PLL4 PFD in CGC. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/mach-imx/imx8ulp/clock.c | 48 +++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 12 deletions(-) (limited to 'arch/arm/mach-imx/imx8ulp/clock.c') diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c index ebbaad4106..2beacbceb0 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, @@ -327,7 +327,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 +376,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; } -- cgit v1.2.3 From 829e06bf41757980a67e6f9bdd1b70189c0c8537 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Fri, 29 Oct 2021 09:46:19 +0800 Subject: imx8ulp: clock: Add MIPI DSI clock and DCNano clock Add the DSI clock enable and disable with PCC reset used. Add the LCD pixel clock calculation and configuration for DCNano Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/include/asm/arch-imx8ulp/clock.h | 2 + arch/arm/mach-imx/imx8ulp/clock.c | 73 +++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) (limited to 'arch/arm/mach-imx/imx8ulp/clock.c') diff --git a/arch/arm/include/asm/arch-imx8ulp/clock.h b/arch/arm/include/asm/arch-imx8ulp/clock.h index 58e3356e32..24322f3ab2 100644 --- a/arch/arm/include/asm/arch-imx8ulp/clock.h +++ b/arch/arm/include/asm/arch-imx8ulp/clock.h @@ -38,4 +38,6 @@ void init_clk_ddr(void); int set_ddr_clk(u32 phy_freq_mhz); void clock_init(void); void cgc1_enet_stamp_sel(u32 clk_src); +void mxs_set_lcdclk(u32 base_addr, u32 freq_in_khz); +void enable_mipi_dsi_clk(unsigned char enable); #endif diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c index 2beacbceb0..02e90f7856 100644 --- a/arch/arm/mach-imx/imx8ulp/clock.c +++ b/arch/arm/mach-imx/imx8ulp/clock.c @@ -317,6 +317,79 @@ 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_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 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) { -- cgit v1.2.3 From 9dde390be69bfc80708458796c2554713c66cea4 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Fri, 29 Oct 2021 09:46:21 +0800 Subject: imx8ulp_evk: Control LPI2C0 PCA6416 and TPM0 for display The board use IO9 of PCA6416 on LPI2C0 and TPM0 for MIPI DSI MUX and backlight. However the LPI2C0 and TPM0 are M33 resources, in this patch we simply access them, but this is a temporary solution. We will modify it when M33 FW changes to set MIPI DSI panel as default path and enable backlight after reset. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/include/asm/arch-imx8ulp/imx8ulp-pins.h | 4 ++ arch/arm/mach-imx/imx8ulp/clock.c | 6 +++ arch/arm/mach-imx/imx8ulp/soc.c | 5 +++ board/freescale/imx8ulp_evk/imx8ulp_evk.c | 56 ++++++++++++++++++++++++ 4 files changed, 71 insertions(+) (limited to 'arch/arm/mach-imx/imx8ulp/clock.c') diff --git a/arch/arm/include/asm/arch-imx8ulp/imx8ulp-pins.h b/arch/arm/include/asm/arch-imx8ulp/imx8ulp-pins.h index d7c07f41b3..d0eefcbc92 100644 --- a/arch/arm/include/asm/arch-imx8ulp/imx8ulp-pins.h +++ b/arch/arm/include/asm/arch-imx8ulp/imx8ulp-pins.h @@ -9,6 +9,10 @@ #include enum { + IMX8ULP_PAD_PTA3__TPM0_CH2 = IOMUX_PAD(0x000c, 0x000c, IOMUX_CONFIG_MPORTS | 0x6, 0x0948, 0x1, 0), + IMX8ULP_PAD_PTA8__LPI2C0_SCL = IOMUX_PAD(0x0020, 0x0020, IOMUX_CONFIG_MPORTS | 0x5, 0x097c, 0x2, 0), + IMX8ULP_PAD_PTA9__LPI2C0_SDA = IOMUX_PAD(0x0024, 0x0024, IOMUX_CONFIG_MPORTS | 0x5, 0x0980, 0x2, 0), + IMX8ULP_PAD_PTB7__PMIC0_MODE2 = IOMUX_PAD(0x009C, 0x009C, IOMUX_CONFIG_MPORTS | 0xA, 0x0000, 0x0, 0), IMX8ULP_PAD_PTB8__PMIC0_MODE1 = IOMUX_PAD(0x00A0, 0x00A0, IOMUX_CONFIG_MPORTS | 0xA, 0x0000, 0x0, 0), IMX8ULP_PAD_PTB9__PMIC0_MODE0 = IOMUX_PAD(0x00A4, 0x00A4, IOMUX_CONFIG_MPORTS | 0xA, 0x0000, 0x0, 0), diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c index 02e90f7856..e599e6c4c6 100644 --- a/arch/arm/mach-imx/imx8ulp/clock.c +++ b/arch/arm/mach-imx/imx8ulp/clock.c @@ -186,6 +186,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 +217,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; diff --git a/arch/arm/mach-imx/imx8ulp/soc.c b/arch/arm/mach-imx/imx8ulp/soc.c index f64a8fb9fc..427b5e4117 100644 --- a/arch/arm/mach-imx/imx8ulp/soc.c +++ b/arch/arm/mach-imx/imx8ulp/soc.c @@ -465,6 +465,11 @@ static int trdc_set_access(void) /* 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; } diff --git a/board/freescale/imx8ulp_evk/imx8ulp_evk.c b/board/freescale/imx8ulp_evk/imx8ulp_evk.c index 3ff4d43c99..1502e4dbb6 100644 --- a/board/freescale/imx8ulp_evk/imx8ulp_evk.c +++ b/board/freescale/imx8ulp_evk/imx8ulp_evk.c @@ -12,6 +12,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -48,11 +49,66 @@ int board_phy_config(struct phy_device *phydev) } #endif +#define I2C_PAD_CTRL (PAD_CTL_ODE) +static const iomux_cfg_t lpi2c0_pads[] = { + IMX8ULP_PAD_PTA8__LPI2C0_SCL | MUX_PAD_CTRL(I2C_PAD_CTRL), + IMX8ULP_PAD_PTA9__LPI2C0_SDA | MUX_PAD_CTRL(I2C_PAD_CTRL), +}; + +#define TPM_PAD_CTRL (PAD_CTL_DSE) +static const iomux_cfg_t tpm0_pads[] = { + IMX8ULP_PAD_PTA3__TPM0_CH2 | MUX_PAD_CTRL(TPM_PAD_CTRL), +}; + +void mipi_dsi_mux_panel(void) +{ + int ret; + struct gpio_desc desc; + + /* It is temp solution to directly access i2c, need change to rpmsg later */ + + /* enable lpi2c0 clock and iomux */ + imx8ulp_iomux_setup_multiple_pads(lpi2c0_pads, ARRAY_SIZE(lpi2c0_pads)); + writel(0xD2000000, 0x28091060); + + ret = dm_gpio_lookup_name("gpio@20_9", &desc); + if (ret) { + printf("%s lookup gpio@20_9 failed ret = %d\n", __func__, ret); + return; + } + + ret = dm_gpio_request(&desc, "dsi_mux"); + if (ret) { + printf("%s request dsi_mux failed ret = %d\n", __func__, ret); + return; + } + + dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); +} + +void mipi_dsi_panel_backlight(void) +{ + /* It is temp solution to directly access pwm, need change to rpmsg later */ + imx8ulp_iomux_setup_multiple_pads(tpm0_pads, ARRAY_SIZE(tpm0_pads)); + writel(0xD4000001, 0x28091054); + + /* Use center-aligned PWM mode, CPWMS=1, MSnB:MSnA = 10, ELSnB:ELSnA = 00 */ + writel(1000, 0x28095018); + writel(1000, 0x28095034); /* MOD = CV, full duty */ + writel(0x28, 0x28095010); + writel(0x20, 0x28095030); +} + int board_init(void) { if (IS_ENABLED(CONFIG_FEC_MXC)) setup_fec(); + if (IS_ENABLED(CONFIG_DM_VIDEO)) { + mipi_dsi_mux_panel(); + mipi_dsi_panel_backlight(); + } + return 0; } -- cgit v1.2.3 From 55a7e7882da16d0a3e15a6dedf8fdb509b6fdf74 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Fri, 29 Oct 2021 09:46:26 +0800 Subject: imx8ulp: clock: Reset DDR controller before clock enable The LPAV is not allocated to APD when dual boot, so LPAV won't reset when APD is reset. We have to explicitly reset the DDR, otherwise its initialization will fail. Reviewed-by: Peng Fan Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/mach-imx/imx8ulp/clock.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/arm/mach-imx/imx8ulp/clock.c') diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c index e599e6c4c6..f54fc25763 100644 --- a/arch/arm/mach-imx/imx8ulp/clock.c +++ b/arch/arm/mach-imx/imx8ulp/clock.c @@ -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); -- cgit v1.2.3 From 3b320106917313a450f5a6a9ab3eb9aaf533bacf Mon Sep 17 00:00:00 2001 From: Ye Li Date: Fri, 29 Oct 2021 09:46:27 +0800 Subject: imx8ulp: clock: Support to reset DCNano and MIPI DSI When LPAV is allocated to RTD, the LPAV won't be reset. So we have to reset DCNano and MIPI DSI in u-boot before enabling the drivers Reviewed-by: Peng Fan Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/include/asm/arch-imx8ulp/clock.h | 1 + arch/arm/mach-imx/imx8ulp/clock.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'arch/arm/mach-imx/imx8ulp/clock.c') diff --git a/arch/arm/include/asm/arch-imx8ulp/clock.h b/arch/arm/include/asm/arch-imx8ulp/clock.h index 24322f3ab2..cc70284f55 100644 --- a/arch/arm/include/asm/arch-imx8ulp/clock.h +++ b/arch/arm/include/asm/arch-imx8ulp/clock.h @@ -39,5 +39,6 @@ int set_ddr_clk(u32 phy_freq_mhz); void clock_init(void); void cgc1_enet_stamp_sel(u32 clk_src); void mxs_set_lcdclk(u32 base_addr, u32 freq_in_khz); +void reset_lcdclk(void); void enable_mipi_dsi_clk(unsigned char enable); #endif diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c index f54fc25763..d03269ac04 100644 --- a/arch/arm/mach-imx/imx8ulp/clock.c +++ b/arch/arm/mach-imx/imx8ulp/clock.c @@ -330,6 +330,7 @@ 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); @@ -340,6 +341,13 @@ void enable_mipi_dsi_clk(unsigned char enable) } } +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; -- cgit v1.2.3 From 0f9b10aaba20696886477f29813d85f39ed32f3e Mon Sep 17 00:00:00 2001 From: Alice Guo Date: Fri, 29 Oct 2021 09:46:29 +0800 Subject: imx8ulp: clock: Support to enable/disable the ADC1 clock This patch implements enable_adc1_clk() to enable or disable the ADC1 clock on i.MX8ULP. Reviewed-by: Ye Li Signed-off-by: Alice Guo Signed-off-by: Peng Fan --- arch/arm/include/asm/arch-imx8ulp/cgc.h | 4 ++++ arch/arm/include/asm/arch-imx8ulp/clock.h | 1 + arch/arm/include/asm/arch-imx8ulp/imx-regs.h | 1 + arch/arm/include/asm/arch-imx8ulp/pcc.h | 4 ++++ arch/arm/mach-imx/imx8ulp/clock.c | 12 ++++++++++++ arch/arm/mach-imx/imx8ulp/pcc.c | 28 +++++++++++++++++++++++++++- 6 files changed, 49 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-imx/imx8ulp/clock.c') diff --git a/arch/arm/include/asm/arch-imx8ulp/cgc.h b/arch/arm/include/asm/arch-imx8ulp/cgc.h index 745fd7f5e8..e15ef1d6c1 100644 --- a/arch/arm/include/asm/arch-imx8ulp/cgc.h +++ b/arch/arm/include/asm/arch-imx8ulp/cgc.h @@ -56,6 +56,10 @@ enum cgc_clk { PLL4_PFD2_DIV2, PLL4_PFD3_DIV1, PLL4_PFD3_DIV2, + CM33_BUSCLK, + PLL1_VCO_DIV, + PLL0_PFD2_DIV, + PLL0_PFD1_DIV, }; struct cgc1_regs { diff --git a/arch/arm/include/asm/arch-imx8ulp/clock.h b/arch/arm/include/asm/arch-imx8ulp/clock.h index cc70284f55..c0f32cc087 100644 --- a/arch/arm/include/asm/arch-imx8ulp/clock.h +++ b/arch/arm/include/asm/arch-imx8ulp/clock.h @@ -41,4 +41,5 @@ void cgc1_enet_stamp_sel(u32 clk_src); void mxs_set_lcdclk(u32 base_addr, u32 freq_in_khz); void reset_lcdclk(void); void enable_mipi_dsi_clk(unsigned char enable); +void enable_adc1_clk(bool enable); #endif diff --git a/arch/arm/include/asm/arch-imx8ulp/imx-regs.h b/arch/arm/include/asm/arch-imx8ulp/imx-regs.h index af6845cbff..91adc85525 100644 --- a/arch/arm/include/asm/arch-imx8ulp/imx-regs.h +++ b/arch/arm/include/asm/arch-imx8ulp/imx-regs.h @@ -30,6 +30,7 @@ #define PCC_XRDC_MGR_ADDR 0x292d00bc +#define PCC1_RBASE 0x28091000 #define PCC3_RBASE 0x292d0000 #define PCC4_RBASE 0x29800000 #define PCC5_RBASE 0x2da70000 diff --git a/arch/arm/include/asm/arch-imx8ulp/pcc.h b/arch/arm/include/asm/arch-imx8ulp/pcc.h index 468015482b..46386f1aba 100644 --- a/arch/arm/include/asm/arch-imx8ulp/pcc.h +++ b/arch/arm/include/asm/arch-imx8ulp/pcc.h @@ -8,6 +8,10 @@ #include +enum pcc1_entry { + ADC1_PCC1_SLOT = 34, +}; + enum pcc3_entry { DMA1_MP_PCC3_SLOT = 1, DMA1_CH0_PCC3_SLOT = 2, diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c index d03269ac04..961702310c 100644 --- a/arch/arm/mach-imx/imx8ulp/clock.c +++ b/arch/arm/mach-imx/imx8ulp/clock.c @@ -341,6 +341,18 @@ void enable_mipi_dsi_clk(unsigned char enable) } } +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*/ diff --git a/arch/arm/mach-imx/imx8ulp/pcc.c b/arch/arm/mach-imx/imx8ulp/pcc.c index 6145b3ea6a..7909d770af 100644 --- a/arch/arm/mach-imx/imx8ulp/pcc.c +++ b/arch/arm/mach-imx/imx8ulp/pcc.c @@ -15,6 +15,21 @@ #define cgc_clk_TYPES 2 #define cgc_clk_NUM 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] = { { }, @@ -75,6 +90,11 @@ static enum cgc_clk pcc5_clksrc[][8] = { } }; +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}, @@ -228,6 +248,10 @@ static int find_pcc_entry(int pcc_controller, int pcc_clk_slot, struct pcc_entry 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]; @@ -310,7 +334,9 @@ int pcc_clock_sel(int pcc_controller, int pcc_clk_slot, enum cgc_clk src) return -EPERM; } - if (pcc_controller == 3) + 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]; -- cgit v1.2.3 From dc77d0f9fc0f31b591a7643b77b6162cb075a98d Mon Sep 17 00:00:00 2001 From: Ye Li Date: Fri, 29 Oct 2021 09:46:30 +0800 Subject: imx8ulp: clock: Handle the DDRLOCKED when setting DDR clock The DDRLOCKED bit in CGC2 DDRCLK will auto lock up and down by HW according to DDR DIV updating or DDR CLK halt status change. So DDR PCC disable/enable will trigger the lock up/down flow. We need wait until unlock to ensure clock is ready. And before configuring the DDRCLK DIV, we need polling the DDRLOCKED until it is unlocked. Otherwise writing ti DIV bits will not set. Reviewed-by: Peng Fan Signed-off-by: Ye Li Signed-off-by: Peng Fan --- arch/arm/include/asm/arch-imx8ulp/cgc.h | 1 + arch/arm/mach-imx/imx8ulp/cgc.c | 11 +++++++++++ arch/arm/mach-imx/imx8ulp/clock.c | 6 ++++++ 3 files changed, 18 insertions(+) (limited to 'arch/arm/mach-imx/imx8ulp/clock.c') diff --git a/arch/arm/include/asm/arch-imx8ulp/cgc.h b/arch/arm/include/asm/arch-imx8ulp/cgc.h index e15ef1d6c1..ad3edc85ad 100644 --- a/arch/arm/include/asm/arch-imx8ulp/cgc.h +++ b/arch/arm/include/asm/arch-imx8ulp/cgc.h @@ -152,6 +152,7 @@ void cgc1_soscdiv_init(void); void cgc1_init_core_clk(void); void cgc2_pll4_init(void); void cgc2_ddrclk_config(u32 src, u32 div); +void cgc2_ddrclk_wait_unlock(void); u32 cgc1_sosc_div(enum cgc_clk clk); void cgc1_enet_stamp_sel(u32 clk_src); void cgc2_pll4_pfd_config(enum cgc_clk pllpfd, u32 pfd); diff --git a/arch/arm/mach-imx/imx8ulp/cgc.c b/arch/arm/mach-imx/imx8ulp/cgc.c index fc84f3f293..38bcbb91e6 100644 --- a/arch/arm/mach-imx/imx8ulp/cgc.c +++ b/arch/arm/mach-imx/imx8ulp/cgc.c @@ -269,12 +269,23 @@ void cgc2_pll4_pfddiv_config(enum cgc_clk pllpfddiv, u32 div) 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))) ; } +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; diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c index 961702310c..91580b2c29 100644 --- a/arch/arm/mach-imx/imx8ulp/clock.c +++ b/arch/arm/mach-imx/imx8ulp/clock.c @@ -107,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(); */ } @@ -144,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; } -- cgit v1.2.3