From cd54b2bcf65508cde41adae071fcd22615ea076b Mon Sep 17 00:00:00 2001 From: Ye Li Date: Tue, 9 Apr 2019 21:06:02 -0700 Subject: [PATCH] MLK-21837-2 imx8: clock: Update non-DM clock functions Signed-off-by: Ye Li (cherry picked from commit e1b5acafb549eb8c09379e466151ddd358b48ad7) (cherry picked from commit d7e21ae132cecb7fee8fa0d30e92024a0d10241c) --- arch/arm/include/asm/arch-imx8/clock.h | 8 + arch/arm/mach-imx/imx8/Makefile | 2 +- arch/arm/mach-imx/imx8/clock.c | 317 ++++++++++++++++++++++++- 3 files changed, 322 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/arch-imx8/clock.h b/arch/arm/include/asm/arch-imx8/clock.h index bea157171f..4435259d61 100644 --- a/arch/arm/include/asm/arch-imx8/clock.h +++ b/arch/arm/include/asm/arch-imx8/clock.h @@ -23,5 +23,13 @@ enum mxc_clock { }; u32 mxc_get_clock(enum mxc_clock clk); +u32 get_lpuart_clk(void); +int enable_i2c_clk(unsigned char enable, unsigned i2c_num); +u32 imx_get_i2cclk(unsigned i2c_num); +void enable_usboh3_clk(unsigned char enable); +u32 imx_get_fecclk(void); +void init_clk_usdhc(u32 index); +void init_clk_gpmi_nand(void); +void init_clk_usb3(int index); #endif /* __ASM_ARCH_IMX8_CLOCK_H__ */ diff --git a/arch/arm/mach-imx/imx8/Makefile b/arch/arm/mach-imx/imx8/Makefile index 9305c7dc6c..fc2973e125 100644 --- a/arch/arm/mach-imx/imx8/Makefile +++ b/arch/arm/mach-imx/imx8/Makefile @@ -4,7 +4,7 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += cpu.o iomux.o misc.o lowlevel_init.o lpcg.o +obj-y += cpu.o iomux.o misc.o lowlevel_init.o lpcg.o clock.o obj-$(CONFIG_OF_SYSTEM_SETUP) += fdt.o obj-$(CONFIG_AHAB_BOOT) += ahab.o diff --git a/arch/arm/mach-imx/imx8/clock.c b/arch/arm/mach-imx/imx8/clock.c index f1c2b6ac08..cb9ec2090f 100644 --- a/arch/arm/mach-imx/imx8/clock.c +++ b/arch/arm/mach-imx/imx8/clock.c @@ -1,18 +1,78 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2018 NXP + * Copyright 2018-2019 NXP */ #include #include #include #include +#include +#include +#include +#include DECLARE_GLOBAL_DATA_PTR; +u32 get_lpuart_clk(void) +{ + return mxc_get_clock(MXC_UART_CLK); +} + u32 mxc_get_clock(enum mxc_clock clk) { + sc_err_t err; + sc_pm_clock_rate_t clkrate; + switch (clk) { + case MXC_UART_CLK: + err = sc_pm_get_clock_rate(-1, + SC_R_UART_0, 2, &clkrate); + if (err != SC_ERR_NONE) { + printf("sc get UART clk failed! err=%d\n", err); + return 0; + } + return clkrate; + case MXC_ESDHC_CLK: + err = sc_pm_get_clock_rate(-1, + SC_R_SDHC_0, 2, &clkrate); + if (err != SC_ERR_NONE) { + printf("sc get uSDHC1 clk failed! err=%d\n", err); + return 0; + } + return clkrate; + case MXC_ESDHC2_CLK: + err = sc_pm_get_clock_rate(-1, + SC_R_SDHC_1, 2, &clkrate); + if (err != SC_ERR_NONE) { + printf("sc get uSDHC2 clk failed! err=%d\n", err); + return 0; + } + return clkrate; + case MXC_ESDHC3_CLK: + err = sc_pm_get_clock_rate(-1, + SC_R_SDHC_2, 2, &clkrate); + if (err != SC_ERR_NONE) { + printf("sc get uSDHC3 clk failed! err=%d\n", err); + return 0; + } + return clkrate; + case MXC_FEC_CLK: + err = sc_pm_get_clock_rate(-1, + SC_R_ENET_0, 2, &clkrate); + if (err != SC_ERR_NONE) { + printf("sc get ENET clk failed! err=%d\n", err); + return 0; + } + return clkrate; + case MXC_DDR_CLK: + err = sc_pm_get_clock_rate(-1, + SC_R_DRC_0, 0, &clkrate); + if (err != SC_ERR_NONE) { + printf("sc get DRC0 clk failed! err=%d\n", err); + return 0; + } + return clkrate; default: printf("Unsupported mxc_clock %d\n", clk); break; @@ -21,9 +81,140 @@ u32 mxc_get_clock(enum mxc_clock clk) return 0; } +u32 imx_get_fecclk(void) +{ + return mxc_get_clock(MXC_FEC_CLK); +} + +static struct imx_i2c_map *get_i2c_desc(unsigned i2c_num) +{ + int i; + for (i = 0; i < ARRAY_SIZE(imx_i2c_desc); i++) { + if (imx_i2c_desc[i].index == i2c_num) + return &imx_i2c_desc[i]; + } + return NULL; +} + +int enable_i2c_clk(unsigned char enable, unsigned i2c_num) +{ + sc_err_t err; + struct imx_i2c_map *desc; + int i; + + desc = get_i2c_desc(i2c_num); + if (!desc) + return -EINVAL; + + + if (enable) + err = sc_pm_clock_enable(-1, + desc->rsrc, 2, true, false); + else + err = sc_pm_clock_enable(-1, + desc->rsrc, 2, false, false); + + if (err != SC_ERR_NONE) { + printf("i2c clock error %d\n", err); + return -EPERM; + } + + for (i = 0; i < 4; i++) { + if (desc->lpcg[i] == 0) + break; + lpcg_all_clock_on(desc->lpcg[i]); + } + + return 0; +} + +u32 imx_get_i2cclk(unsigned i2c_num) +{ + sc_err_t err; + u32 clock_rate; + struct imx_i2c_map *desc; + + desc = get_i2c_desc(i2c_num); + if (!desc) + return -EINVAL; + + err = sc_pm_get_clock_rate(-1, desc->rsrc, 2, + &clock_rate); + if (err != SC_ERR_NONE) + return 0; + + return clock_rate; +} + +void init_clk_fspi(int index) +{ + sc_err_t sciErr = 0; + sc_pm_clock_rate_t rate; + + /* Set FSPI0 clock root to 29 MHz */ + rate = 29000000; + sciErr = sc_pm_set_clock_rate(-1, SC_R_FSPI_0, SC_PM_CLK_PER, &rate); + if (sciErr != SC_ERR_NONE) { + puts("FSPI0 setrate failed\n"); + return; + } + + /* Enable FSPI0 clock root */ + sciErr = sc_pm_clock_enable(-1, SC_R_FSPI_0, SC_PM_CLK_PER, true, false); + if (sciErr != SC_ERR_NONE) { + puts("FSPI0 enable clock failed\n"); + return; + } + + lpcg_all_clock_on(FSPI_0_LPCG); + + return; +} + +void init_clk_gpmi_nand(void) +{ + sc_err_t sciErr = 0; + sc_pm_clock_rate_t rate; + + /* Set NAND BCH clock root to 50 MHz */ + rate = 50000000; + sciErr = sc_pm_set_clock_rate(-1, SC_R_NAND, SC_PM_CLK_PER, &rate); + if (sciErr != SC_ERR_NONE) { + puts("NAND BCH set rate failed\n"); + return; + } + + /* Enable NAND BCH clock root */ + sciErr = sc_pm_clock_enable(-1, SC_R_NAND, SC_PM_CLK_PER, true, false); + if (sciErr != SC_ERR_NONE) { + puts("NAND BCH enable clock failed\n"); + return; + } + + /* Set NAND GPMI clock root to 50 MHz */ + rate = 50000000; + sciErr = sc_pm_set_clock_rate(-1, SC_R_NAND, SC_PM_CLK_MST_BUS, &rate); + if (sciErr != SC_ERR_NONE) { + puts("NAND GPMI set rate failed\n"); + return; + } + + /* Enable NAND GPMI clock root */ + sciErr = sc_pm_clock_enable(-1, SC_R_NAND, SC_PM_CLK_MST_BUS, true, false); + if (sciErr != SC_ERR_NONE) { + puts("NAND GPMI enable clock failed\n"); + return; + } + + lpcg_all_clock_on(NAND_LPCG); + lpcg_all_clock_on(NAND_LPCG + 0x4); + + return; +} + void enable_usboh3_clk(unsigned char enable) { - LPCG_AllClockOn(USB_2_LPCG); + lpcg_all_clock_on(USB_2_LPCG); return; } @@ -46,7 +237,7 @@ void init_clk_usb3(int index) printf("USB3 set clock failed!, line=%d (error = %d)\n", __LINE__, err); - LPCG_AllClockOn(USB_3_LPCG); + lpcg_all_clock_on(USB_3_LPCG); return; } @@ -60,7 +251,7 @@ int cdns3_disable_clks(int index) { sc_err_t err; - LPCG_AllClockOff(USB_3_LPCG); + lpcg_all_clock_off(USB_3_LPCG); err = sc_pm_clock_enable(-1, SC_R_USB_2, SC_PM_CLK_MISC, false, false); if (err != SC_ERR_NONE) @@ -79,3 +270,121 @@ int cdns3_disable_clks(int index) return 0; } + +void init_clk_usdhc(u32 index) +{ +#ifdef CONFIG_IMX8QM + sc_rsrc_t usdhcs[] = {SC_R_SDHC_0, SC_R_SDHC_1, SC_R_SDHC_2}; + u32 instances = 3; +#else + sc_rsrc_t usdhcs[] = {SC_R_SDHC_0, SC_R_SDHC_1}; + u32 instances = 2; +#endif + + sc_err_t err; + sc_pm_clock_rate_t actual = 400000000; + + if (index >= instances) + return; + + /* Must disable the clock before set clock parent */ + err = sc_pm_clock_enable(-1, usdhcs[index], SC_PM_CLK_PER, false, false); + if (err != SC_ERR_NONE) { + printf("SDHC_%d per clk enable failed!\n", index); + return; + } + + /* + * IMX8QXP USDHC_CLK_ROOT default source from DPLL, but this DPLL + * do not stable, will cause usdhc data transfer crc error. So here + * is a workaround, let USDHC_CLK_ROOT source from AVPLL. Due to + * AVPLL is fixed to 1000MHz, so here config USDHC1_CLK_ROOT to 333MHz, + * USDHC2_CLK_ROOT to 200MHz, make eMMC HS400ES work at 166MHz, and SD + * SDR104 work at 200MHz. + */ + if (is_imx8qxp()) { + err = sc_pm_set_clock_parent(-1, usdhcs[index], 2, SC_PM_PARENT_PLL1); + if (err != SC_ERR_NONE) + printf("SDHC_%d set clock parent failed!(error = %d)\n", index, err); + + if (index == 1) + actual = 200000000; + } + + err = sc_pm_set_clock_rate(-1, usdhcs[index], 2, &actual); + if (err != SC_ERR_NONE) { + printf("SDHC_%d set clock failed! (error = %d)\n", index, err); + return; + } + + if (actual != 400000000) + debug("Actual rate for SDHC_%d is %d\n", index, actual); + + err = sc_pm_clock_enable(-1, usdhcs[index], SC_PM_CLK_PER, true, false); + if (err != SC_ERR_NONE) { + printf("SDHC_%d per clk enable failed!\n", index); + return; + } + + lpcg_all_clock_on(USDHC_0_LPCG + index * 0x10000); +} + +void init_clk_fec(int index) +{ + sc_err_t err; + sc_pm_clock_rate_t rate = 24000000; + sc_rsrc_t enet[2] = {SC_R_ENET_0, SC_R_ENET_1}; + + if (index > 1) + return; + + if (index == -1) + index = 0; + + /* Disable SC_R_ENET_0 clock root */ + err = sc_pm_clock_enable(-1, enet[index], 0, false, false); + err |= sc_pm_clock_enable(-1, enet[index], 2, false, false); + err |= sc_pm_clock_enable(-1, enet[index], 4, false, false); + if (err != SC_ERR_NONE) { + printf("\nSC_R_ENET_0 set clock disable failed! (error = %d)\n", err); + return; + } + + /* Set SC_R_ENET_0 clock root to 250 MHz, the clkdiv is set to div 2 + * so finally RGMII TX clk is 125Mhz + */ + rate = 250000000; + + /* div = 8 clk_source = PLL_1 ss_slice #7 in verfication codes */ + err = sc_pm_set_clock_rate(-1, enet[index], 2, &rate); + if (err != SC_ERR_NONE) { + printf("\nSC_R_ENET_0 set clock ref clock 125M failed! (error = %d)\n", err); + return; + } + + /* Enable SC_R_ENET_0 clock root */ + err = sc_pm_clock_enable(-1, enet[index], 0, true, true); + err |= sc_pm_clock_enable(-1, enet[index], 2, true, true); + err |= sc_pm_clock_enable(-1, enet[index], 4, true, true); + if (err != SC_ERR_NONE) { + printf("\nSC_R_ENET_0 set clock enable failed! (error = %d)\n", err); + return; + } + + /* Configure GPR regisers */ + if (sc_misc_set_control(-1, enet[index], SC_C_TXCLK, 0) != SC_ERR_NONE) + printf("\nConfigure GPR registers operation(%d) failed!\n", SC_C_TXCLK); + /* Enable divclk */ + if (sc_misc_set_control(-1, enet[index], SC_C_CLKDIV, 1) != SC_ERR_NONE) + printf("\nConfigure GPR registers operation(%d) failed!\n", SC_C_CLKDIV); + if (sc_misc_set_control(-1, enet[index], SC_C_DISABLE_50, 1) != SC_ERR_NONE) + printf("\nConfigure GPR registers operation(%d) failed!\n", SC_C_DISABLE_50); + if (sc_misc_set_control(-1, enet[index], SC_C_DISABLE_125, 1) != SC_ERR_NONE) + printf("\nConfigure GPR registers operation(%d) failed!\n", SC_C_DISABLE_125); + if (sc_misc_set_control(-1, enet[index], SC_C_SEL_125, 0) != SC_ERR_NONE) + printf("\nConfigure GPR registers operation(%d) failed!\n", SC_C_SEL_125); + if (sc_misc_set_control(-1, enet[index], SC_C_IPG_STOP, 0) != SC_ERR_NONE) + printf("\nConfigure GPR registers operation(%d) failed!\n", SC_C_IPG_STOP); + + lpcg_all_clock_on(ENET_0_LPCG + index * 0x10000); +} -- 2.17.1