The clk support for K3 SoCs is implemented on the Cortex-R5 boot processor by the ti-dm firmware binary. The A53 cores access the clks via mailboxes. However, during early boot we are running barebox on the Cortex-R5 processor and the ti-dm firmware is not yet running, so we must implement our own clk driver. Code is based on U-Boot-2025.01-rc1. Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- drivers/clk/Makefile | 1 + drivers/clk/k3/Makefile | 2 + drivers/clk/k3/am625.c | 475 +++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/k3/pll.c | 375 +++++++++++++++++++++++++++++++++++ drivers/clk/k3/ti-k3-clk.h | 8 + include/soc/k3/clk.h | 7 + 6 files changed, 868 insertions(+) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 764539e91e..8c3544c750 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -31,3 +31,4 @@ obj-y += bcm/ obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o obj-$(CONFIG_COMMON_CLK_GPIO) += clk-gpio.o obj-$(CONFIG_TI_SCI_CLK) += ti-sci-clk.o +obj-$(CONFIG_ARCH_K3) += k3/ diff --git a/drivers/clk/k3/Makefile b/drivers/clk/k3/Makefile new file mode 100644 index 0000000000..8d96373ab6 --- /dev/null +++ b/drivers/clk/k3/Makefile @@ -0,0 +1,2 @@ +obj-y += am625.o +obj-pbl-y += pll.o diff --git a/drivers/clk/k3/am625.c b/drivers/clk/k3/am625.c new file mode 100644 index 0000000000..c7e28658d1 --- /dev/null +++ b/drivers/clk/k3/am625.c @@ -0,0 +1,475 @@ +#define pr_fmt(fmt) "ti-k3-clk: " fmt + +#include <linux/clk.h> +#include <of.h> +#include <driver.h> +#include "ti-k3-clk.h" + +static const char * const gluelogic_hfosc0_clkout_parents[] = { + NULL, + NULL, + "osc_24_mhz", + "osc_25_mhz", + "osc_26_mhz", + NULL, +}; + +static const char * const main_emmcsd0_io_clklb_sel_out0_parents[] = { + "board_0_mmc0_clklb_out", + "board_0_mmc0_clk_out", +}; + +static const char * const main_emmcsd1_io_clklb_sel_out0_parents[] = { + "board_0_mmc1_clklb_out", + "board_0_mmc1_clk_out", +}; + +static const char * const main_ospi_loopback_clk_sel_out0_parents[] = { + "board_0_ospi0_dqs_out", + "board_0_ospi0_lbclko_out", +}; + +static const char * const main_usb0_refclk_sel_out0_parents[] = { + "gluelogic_hfosc0_clkout", + "postdiv4_16ff_main_0_hsdivout8_clk", +}; + +static const char * const main_usb1_refclk_sel_out0_parents[] = { + "gluelogic_hfosc0_clkout", + "postdiv4_16ff_main_0_hsdivout8_clk", +}; + +static const char * const sam62_pll_ctrl_wrap_main_0_sysclkout_clk_parents[] = { + "gluelogic_hfosc0_clkout", + "hsdiv4_16fft_main_0_hsdivout0_clk", +}; + +static const char * const sam62_pll_ctrl_wrap_mcu_0_sysclkout_clk_parents[] = { + "gluelogic_hfosc0_clkout", + "hsdiv4_16fft_mcu_0_hsdivout0_clk", +}; + +static const char * const clkout0_ctrl_out0_parents[] = { + "hsdiv4_16fft_main_2_hsdivout1_clk", + "hsdiv4_16fft_main_2_hsdivout1_clk10", +}; + +static const char * const clk_32k_rc_sel_out0_parents[] = { + "gluelogic_rcosc_clk_1p0v_97p65k", + "hsdiv0_16fft_mcu_32khz_gen_0_hsdivout0_clk", + "clk_32k_rc_sel_div_clkout", + "gluelogic_lfosc0_clkout", +}; + +static const char * const main_cp_gemac_cpts_clk_sel_out0_parents[] = { + "postdiv4_16ff_main_2_hsdivout5_clk", + "postdiv4_16ff_main_0_hsdivout6_clk", + "board_0_cp_gemac_cpts0_rft_clk_out", + NULL, + "board_0_mcu_ext_refclk0_out", + "board_0_ext_refclk1_out", + "sam62_pll_ctrl_wrap_mcu_0_chip_div1_clk_clk", + "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk", +}; + +static const char * const main_emmcsd0_refclk_sel_out0_parents[] = { + "postdiv4_16ff_main_0_hsdivout5_clk", + "hsdiv4_16fft_main_2_hsdivout2_clk", +}; + +static const char * const main_emmcsd1_refclk_sel_out0_parents[] = { + "postdiv4_16ff_main_0_hsdivout5_clk", + "hsdiv4_16fft_main_2_hsdivout2_clk", +}; + +static const char * const main_gtcclk_sel_out0_parents[] = { + "postdiv4_16ff_main_2_hsdivout5_clk", + "postdiv4_16ff_main_0_hsdivout6_clk", + "board_0_cp_gemac_cpts0_rft_clk_out", + NULL, + "board_0_mcu_ext_refclk0_out", + "board_0_ext_refclk1_out", + "sam62_pll_ctrl_wrap_mcu_0_chip_div1_clk_clk", + "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk", +}; + +static const char * const main_ospi_ref_clk_sel_out0_parents[] = { + "hsdiv4_16fft_main_0_hsdivout1_clk", + "postdiv1_16fft_main_1_hsdivout5_clk", +}; + +static const char * const wkup_clkout_sel_out0_parents[] = { + "gluelogic_hfosc0_clkout", + "gluelogic_lfosc0_clkout", + "hsdiv4_16fft_main_0_hsdivout2_clk", + "hsdiv4_16fft_main_1_hsdivout2_clk", + "postdiv4_16ff_main_2_hsdivout9_clk", + "clk_32k_rc_sel_out0", + "gluelogic_rcosc_clkout", + "gluelogic_hfosc0_clkout", +}; + +static const char * const wkup_clksel_out0_parents[] = { + "hsdiv1_16fft_main_15_hsdivout0_clk", + "hsdiv4_16fft_mcu_0_hsdivout0_clk", +}; + +static const char * const main_usart0_fclk_sel_out0_parents[] = { + "usart_programmable_clock_divider_out0", + "hsdiv4_16fft_main_1_hsdivout1_clk", +}; + +static inline struct clk *k3_clk_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width, u32 flags, u32 div_flags) +{ + return clk_divider(name, parent, CLK_SET_RATE_PARENT, reg, shift, width, 0); +} + +static inline struct clk *k3_clk_pll(const char *name, const char *parent, + void __iomem *reg, u32 flags) +{ + return clk_register_ti_k3_pll(name, parent, reg); +} + +static inline struct clk *k3_clk_mux(const char *name, const char * const *parents, + int num_parents, void __iomem *reg, u8 shift, + u8 width, u32 flags) +{ + return clk_mux(name, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | flags, reg, + shift, width, parents, num_parents, 0); +} + +static inline struct clk *k3_clk_div_devfreq(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width, u32 flags, u32 div_flags, u32 freq) +{ + return NULL; +} + +static inline struct clk *k3_clk_mux_pllctrl(const char *name, const char * const *parents, + int num_parents, void __iomem *reg, u32 freq) +{ + return NULL; +} + +struct clk_lookup_data { + unsigned int dev_id; + unsigned int clk_id; + const char *clk_name; +}; + +#define DEV_CLK(_dev_id, _clk_id, _clk_name) { .dev_id = _dev_id, \ + .clk_id = _clk_id, .clk_name = _clk_name, } + +static struct clk_lookup_data am625_lookup[] = { + DEV_CLK(13, 0, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(13, 3, "main_cp_gemac_cpts_clk_sel_out0"), + DEV_CLK(13, 4, "postdiv4_16ff_main_2_hsdivout5_clk"), + DEV_CLK(13, 5, "postdiv4_16ff_main_0_hsdivout6_clk"), + DEV_CLK(13, 6, "board_0_cp_gemac_cpts0_rft_clk_out"), + DEV_CLK(13, 8, "board_0_mcu_ext_refclk0_out"), + DEV_CLK(13, 9, "board_0_ext_refclk1_out"), + DEV_CLK(13, 10, "sam62_pll_ctrl_wrap_mcu_0_chip_div1_clk_clk"), + DEV_CLK(13, 11, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(13, 13, "hsdiv4_16fft_main_2_hsdivout1_clk"), + DEV_CLK(13, 14, "hsdiv4_16fft_main_2_hsdivout1_clk"), + DEV_CLK(13, 15, "hsdiv4_16fft_main_2_hsdivout1_clk"), + DEV_CLK(13, 16, "hsdiv4_16fft_main_2_hsdivout1_clk"), + DEV_CLK(13, 17, "hsdiv4_16fft_main_2_hsdivout1_clk"), + DEV_CLK(13, 19, "board_0_rgmii1_rxc_out"), + DEV_CLK(13, 20, "board_0_rgmii1_txc_out"), + DEV_CLK(13, 22, "board_0_rgmii2_rxc_out"), + DEV_CLK(13, 23, "board_0_rgmii2_txc_out"), + DEV_CLK(13, 25, "hsdiv4_16fft_main_2_hsdivout1_clk"), + DEV_CLK(13, 26, "hsdiv4_16fft_main_2_hsdivout1_clk"), + DEV_CLK(13, 27, "hsdiv4_16fft_main_2_hsdivout1_clk"), + DEV_CLK(13, 28, "board_0_rmii1_ref_clk_out"), + DEV_CLK(13, 29, "board_0_rmii2_ref_clk_out"), + DEV_CLK(16, 0, "hsdiv4_16fft_main_0_hsdivout1_clk"), + DEV_CLK(16, 1, "hsdiv4_16fft_main_0_hsdivout2_clk"), + DEV_CLK(16, 2, "hsdiv4_16fft_main_0_hsdivout3_clk"), + DEV_CLK(16, 3, "hsdiv4_16fft_main_0_hsdivout4_clk"), + DEV_CLK(16, 4, "gluelogic_hfosc0_clkout"), + DEV_CLK(16, 5, "board_0_ext_refclk1_out"), + DEV_CLK(16, 6, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(16, 7, "postdiv4_16ff_main_2_hsdivout8_clk"), + DEV_CLK(16, 8, "gluelogic_hfosc0_clkout"), + DEV_CLK(16, 9, "board_0_ext_refclk1_out"), + DEV_CLK(16, 10, "gluelogic_rcosc_clkout"), + DEV_CLK(16, 11, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(16, 12, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(57, 0, "main_emmcsd0_io_clklb_sel_out0"), + DEV_CLK(57, 1, "board_0_mmc0_clklb_out"), + DEV_CLK(57, 2, "board_0_mmc0_clk_out"), + DEV_CLK(57, 5, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(57, 6, "main_emmcsd0_refclk_sel_out0"), + DEV_CLK(57, 7, "postdiv4_16ff_main_0_hsdivout5_clk"), + DEV_CLK(57, 8, "hsdiv4_16fft_main_2_hsdivout2_clk"), + DEV_CLK(58, 0, "main_emmcsd1_io_clklb_sel_out0"), + DEV_CLK(58, 1, "board_0_mmc1_clklb_out"), + DEV_CLK(58, 2, "board_0_mmc1_clk_out"), + DEV_CLK(58, 5, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(58, 6, "main_emmcsd1_refclk_sel_out0"), + DEV_CLK(58, 7, "postdiv4_16ff_main_0_hsdivout5_clk"), + DEV_CLK(58, 8, "hsdiv4_16fft_main_2_hsdivout2_clk"), + DEV_CLK(61, 0, "main_gtcclk_sel_out0"), + DEV_CLK(61, 1, "postdiv4_16ff_main_2_hsdivout5_clk"), + DEV_CLK(61, 2, "postdiv4_16ff_main_0_hsdivout6_clk"), + DEV_CLK(61, 3, "board_0_cp_gemac_cpts0_rft_clk_out"), + DEV_CLK(61, 5, "board_0_mcu_ext_refclk0_out"), + DEV_CLK(61, 6, "board_0_ext_refclk1_out"), + DEV_CLK(61, 7, "sam62_pll_ctrl_wrap_mcu_0_chip_div1_clk_clk"), + DEV_CLK(61, 8, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(61, 9, "wkup_clksel_out0"), + DEV_CLK(61, 10, "hsdiv1_16fft_main_15_hsdivout0_clk"), + DEV_CLK(61, 11, "hsdiv4_16fft_mcu_0_hsdivout0_clk"), + DEV_CLK(75, 0, "board_0_ospi0_dqs_out"), + DEV_CLK(75, 1, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(75, 2, "main_ospi_loopback_clk_sel_out0"), + DEV_CLK(75, 3, "board_0_ospi0_dqs_out"), + DEV_CLK(75, 4, "board_0_ospi0_lbclko_out"), + DEV_CLK(75, 6, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(75, 7, "main_ospi_ref_clk_sel_out0"), + DEV_CLK(75, 8, "hsdiv4_16fft_main_0_hsdivout1_clk"), + DEV_CLK(75, 9, "postdiv1_16fft_main_1_hsdivout5_clk"), + DEV_CLK(77, 0, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(95, 0, "gluelogic_rcosc_clkout"), + DEV_CLK(95, 1, "gluelogic_hfosc0_clkout"), + DEV_CLK(95, 2, "wkup_clksel_out0"), + DEV_CLK(95, 3, "hsdiv1_16fft_main_15_hsdivout0_clk"), + DEV_CLK(95, 4, "hsdiv4_16fft_mcu_0_hsdivout0_clk"), + DEV_CLK(102, 0, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(102, 1, "board_0_i2c0_scl_out"), + DEV_CLK(102, 2, "hsdiv4_16fft_main_1_hsdivout0_clk"), + DEV_CLK(107, 0, "wkup_clksel_out0"), + DEV_CLK(107, 1, "hsdiv1_16fft_main_15_hsdivout0_clk"), + DEV_CLK(107, 2, "hsdiv4_16fft_mcu_0_hsdivout0_clk"), + DEV_CLK(107, 3, "mshsi2c_wkup_0_porscl"), + DEV_CLK(107, 4, "hsdiv4_16fft_mcu_0_hsdivout1_clk"), + DEV_CLK(135, 0, "hsdiv0_16fft_main_8_hsdivout0_clk"), + DEV_CLK(136, 0, "hsdiv0_16fft_main_8_hsdivout0_clk"), + DEV_CLK(140, 0, "sam62_pll_ctrl_wrap_mcu_0_chip_div1_clk_clk"), + DEV_CLK(140, 1, "sam62_pll_ctrl_wrap_mcu_0_chip_div1_clk_clk"), + DEV_CLK(146, 0, "main_usart0_fclk_sel_out0"), + DEV_CLK(146, 1, "usart_programmable_clock_divider_out0"), + DEV_CLK(146, 2, "hsdiv4_16fft_main_1_hsdivout1_clk"), + DEV_CLK(146, 5, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(157, 20, "clkout0_ctrl_out0"), + DEV_CLK(157, 21, "hsdiv4_16fft_main_2_hsdivout1_clk"), + DEV_CLK(157, 22, "hsdiv4_16fft_main_2_hsdivout1_clk10"), + DEV_CLK(157, 24, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(157, 25, "board_0_ddr0_ck0_out"), + DEV_CLK(157, 40, "mshsi2c_main_0_porscl"), + DEV_CLK(157, 77, "sam62_pll_ctrl_wrap_mcu_0_sysclkout_clk"), + DEV_CLK(157, 82, "cpsw_3guss_main_0_mdio_mdclk_o"), + DEV_CLK(157, 83, "emmcsd8ss_main_0_emmcsdss_io_clk_o"), + DEV_CLK(157, 87, "emmcsd4ss_main_0_emmcsdss_io_clk_o"), + DEV_CLK(157, 89, "emmcsd4ss_main_0_emmcsdss_io_clk_o"), + DEV_CLK(157, 129, "fss_ul_main_0_ospi_0_ospi_oclk_clk"), + DEV_CLK(157, 132, "cpsw_3guss_main_0_rgmii1_txc_o"), + DEV_CLK(157, 135, "cpsw_3guss_main_0_rgmii2_txc_o"), + DEV_CLK(157, 145, "sam62_pll_ctrl_wrap_main_0_sysclkout_clk"), + DEV_CLK(157, 158, "wkup_clkout_sel_out0"), + DEV_CLK(157, 159, "gluelogic_hfosc0_clkout"), + DEV_CLK(157, 160, "gluelogic_lfosc0_clkout"), + DEV_CLK(157, 161, "hsdiv4_16fft_main_0_hsdivout2_clk"), + DEV_CLK(157, 162, "hsdiv4_16fft_main_1_hsdivout2_clk"), + DEV_CLK(157, 163, "postdiv4_16ff_main_2_hsdivout9_clk"), + DEV_CLK(157, 164, "clk_32k_rc_sel_out0"), + DEV_CLK(157, 165, "gluelogic_rcosc_clkout"), + DEV_CLK(157, 166, "gluelogic_hfosc0_clkout"), + DEV_CLK(161, 0, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(161, 1, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(161, 2, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(161, 3, "main_usb0_refclk_sel_out0"), + DEV_CLK(161, 4, "gluelogic_hfosc0_clkout"), + DEV_CLK(161, 5, "postdiv4_16ff_main_0_hsdivout8_clk"), + DEV_CLK(161, 10, "board_0_tck_out"), + DEV_CLK(162, 0, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(162, 1, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(162, 2, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(162, 3, "main_usb1_refclk_sel_out0"), + DEV_CLK(162, 4, "gluelogic_hfosc0_clkout"), + DEV_CLK(162, 5, "postdiv4_16ff_main_0_hsdivout8_clk"), + DEV_CLK(162, 10, "board_0_tck_out"), + DEV_CLK(166, 3, "hsdiv0_16fft_main_8_hsdivout0_clk"), + DEV_CLK(166, 5, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(169, 0, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(169, 1, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(170, 0, "hsdiv0_16fft_main_12_hsdivout0_clk"), + DEV_CLK(170, 1, "board_0_tck_out"), + DEV_CLK(170, 2, "sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + + /* + * Timer clocks. There is a mux between the timer and the clock core + * which we haven't modeled here. The values reflect the reset default + * of the mux + */ + DEV_CLK(35, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(36, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(37, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(38, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(39, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(40, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(41, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(42, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(43, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(48, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(49, 2, "gluelogic_hfosc0_clkout"), + DEV_CLK(50, 2, "gluelogic_hfosc0_clkout"), + + DEV_CLK(0, 0, NULL), +}; + +static struct clk *of_clk_ti_k3_get(struct of_phandle_args *clkspec, void *data) +{ + struct clk_lookup_data *clk_data = data; + struct clk *clk; + unsigned int dev_id = clkspec->args[0]; + unsigned int clk_id = clkspec->args[1]; + + while (1) { + if (!clk_data->clk_name) { + pr_err("clk %d/%d not found\n", dev_id, clk_id); + return ERR_PTR(-ENOENT); + } + + if (clk_data->dev_id == dev_id && clk_data->clk_id == clk_id) + goto found; + + clk_data++; + } +found: + clk = clk_lookup(clk_data->clk_name); + if (IS_ERR(clk)) + pr_err("clk %s not found\n", clk_data->clk_name); + + return clk; +} + +static int am625_clk_init(struct device *dev) +{ + int ret; + + clk_fixed("osc_26_mhz", 26000000); + clk_fixed("osc_25_mhz", 25000000); + clk_fixed("osc_24_mhz", 24000000); + k3_clk_mux("gluelogic_hfosc0_clkout", + gluelogic_hfosc0_clkout_parents, 6, (void *)0x43000030, 0, 3, 0), + clk_fixed("gluelogic_rcosc_clkout", 12500000); + clk_fixed("gluelogic_rcosc_clk_1p0v_97p65k", 97656); + clk_fixed("board_0_cp_gemac_cpts0_rft_clk_out", 0); + clk_fixed("board_0_ddr0_ck0_out", 0); + clk_fixed("board_0_ext_refclk1_out", 0); + clk_fixed("board_0_i2c0_scl_out", 0); + clk_fixed("board_0_mcu_ext_refclk0_out", 0); + clk_fixed("board_0_mmc0_clklb_out", 0); + clk_fixed("board_0_mmc0_clk_out", 0); + clk_fixed("board_0_mmc1_clklb_out", 0); + clk_fixed("board_0_mmc1_clk_out", 0); + clk_fixed("board_0_ospi0_dqs_out", 0); + clk_fixed("board_0_ospi0_lbclko_out", 0); + clk_fixed("board_0_rgmii1_rxc_out", 0); + clk_fixed("board_0_rgmii1_txc_out", 0); + clk_fixed("board_0_rgmii2_rxc_out", 0); + clk_fixed("board_0_rgmii2_txc_out", 0); + clk_fixed("board_0_rmii1_ref_clk_out", 0); + clk_fixed("board_0_rmii2_ref_clk_out", 0); + clk_fixed("board_0_tck_out", 0); + clk_fixed("cpsw_3guss_main_0_mdio_mdclk_o", 0); + clk_fixed("cpsw_3guss_main_0_rgmii1_txc_o", 0); + clk_fixed("cpsw_3guss_main_0_rgmii2_txc_o", 0); + clk_fixed("emmcsd4ss_main_0_emmcsdss_io_clk_o", 0); + clk_fixed("emmcsd8ss_main_0_emmcsdss_io_clk_o", 0); + clk_fixed("fss_ul_main_0_ospi_0_ospi_oclk_clk", 0); + k3_clk_divider("hsdiv0_16fft_mcu_32khz_gen_0_hsdivout0_clk", "gluelogic_hfosc0_clkout", (void *)0x4508030, 0, 7, 0, 0); + clk_fixed("mshsi2c_main_0_porscl", 0); + k3_clk_pll("pllfracf_ssmod_16fft_main_0_foutvcop_clk", "gluelogic_hfosc0_clkout", (void *)0x680000, 0); + k3_clk_divider("pllfracf_ssmod_16fft_main_0_foutpostdiv_clk_subdiv", "pllfracf_ssmod_16fft_main_0_foutvcop_clk", (void *)0x680038, 16, 3, 0, CLK_DIVIDER_ONE_BASED); + k3_clk_divider("pllfracf_ssmod_16fft_main_0_foutpostdiv_clk", "pllfracf_ssmod_16fft_main_0_foutpostdiv_clk_subdiv", (void *)0x680038, 24, 3, 0, CLK_DIVIDER_ONE_BASED); + k3_clk_pll("pllfracf_ssmod_16fft_main_1_foutvcop_clk", "gluelogic_hfosc0_clkout", (void *)0x681000, 0); + k3_clk_divider("pllfracf_ssmod_16fft_main_1_foutpostdiv_clk_subdiv", "pllfracf_ssmod_16fft_main_1_foutvcop_clk", (void *)0x681038, 16, 3, 0, CLK_DIVIDER_ONE_BASED); + k3_clk_divider("pllfracf_ssmod_16fft_main_1_foutpostdiv_clk", "pllfracf_ssmod_16fft_main_1_foutpostdiv_clk_subdiv", (void *)0x681038, 24, 3, 0, CLK_DIVIDER_ONE_BASED); + k3_clk_pll("pllfracf_ssmod_16fft_main_12_foutvcop_clk", "gluelogic_hfosc0_clkout", (void *)0x68c000, 0); + k3_clk_pll("pllfracf_ssmod_16fft_main_15_foutvcop_clk", "gluelogic_hfosc0_clkout", (void *)0x68f000, 0); + k3_clk_pll("pllfracf_ssmod_16fft_main_2_foutvcop_clk", "gluelogic_hfosc0_clkout", (void *)0x682000, 0); + k3_clk_divider("pllfracf_ssmod_16fft_main_2_foutpostdiv_clk_subdiv", "pllfracf_ssmod_16fft_main_2_foutvcop_clk", (void *)0x682038, 16, 3, 0, CLK_DIVIDER_ONE_BASED); + k3_clk_divider("pllfracf_ssmod_16fft_main_2_foutpostdiv_clk", "pllfracf_ssmod_16fft_main_2_foutpostdiv_clk_subdiv", (void *)0x682038, 24, 3, 0, CLK_DIVIDER_ONE_BASED); + k3_clk_pll("pllfracf_ssmod_16fft_main_8_foutvcop_clk", "gluelogic_hfosc0_clkout", (void *)0x688000, 0); + k3_clk_pll("pllfracf_ssmod_16fft_mcu_0_foutvcop_clk", "gluelogic_hfosc0_clkout", (void *)0x4040000, 0); + k3_clk_divider("postdiv1_16fft_main_1_hsdivout5_clk", "pllfracf_ssmod_16fft_main_1_foutpostdiv_clk", (void *)0x681094, 0, 7, 0, 0); + k3_clk_divider("postdiv4_16ff_main_0_hsdivout5_clk", "pllfracf_ssmod_16fft_main_0_foutpostdiv_clk", (void *)0x680094, 0, 7, 0, 0); + k3_clk_divider("postdiv4_16ff_main_0_hsdivout6_clk", "pllfracf_ssmod_16fft_main_0_foutpostdiv_clk", (void *)0x680098, 0, 7, 0, 0); + k3_clk_divider("postdiv4_16ff_main_0_hsdivout8_clk", "pllfracf_ssmod_16fft_main_0_foutpostdiv_clk", (void *)0x6800a0, 0, 7, 0, 0); + k3_clk_divider("postdiv4_16ff_main_2_hsdivout5_clk", "pllfracf_ssmod_16fft_main_2_foutpostdiv_clk", (void *)0x682094, 0, 7, 0, 0); + k3_clk_divider("postdiv4_16ff_main_2_hsdivout8_clk", "pllfracf_ssmod_16fft_main_2_foutpostdiv_clk", (void *)0x6820a0, 0, 7, 0, 0); + k3_clk_divider("postdiv4_16ff_main_2_hsdivout9_clk", "pllfracf_ssmod_16fft_main_2_foutpostdiv_clk", (void *)0x6820a4, 0, 7, 0, 0); + k3_clk_mux("main_emmcsd0_io_clklb_sel_out0", main_emmcsd0_io_clklb_sel_out0_parents, 2, (void *)0x108160, 16, 1, 0); + k3_clk_mux("main_emmcsd1_io_clklb_sel_out0", main_emmcsd1_io_clklb_sel_out0_parents, 2, (void *)0x108168, 16, 1, 0); + k3_clk_mux("main_ospi_loopback_clk_sel_out0", main_ospi_loopback_clk_sel_out0_parents, 2, (void *)0x108500, 4, 1, 0); + k3_clk_mux("main_usb0_refclk_sel_out0", main_usb0_refclk_sel_out0_parents, 2, (void *)0x43008190, 0, 1, 0); + k3_clk_mux("main_usb1_refclk_sel_out0", main_usb1_refclk_sel_out0_parents, 2, (void *)0x43008194, 0, 1, 0); + k3_clk_divider("hsdiv0_16fft_main_12_hsdivout0_clk", "pllfracf_ssmod_16fft_main_12_foutvcop_clk", (void *)0x68c080, 0, 7, 0, 0); + k3_clk_divider("hsdiv0_16fft_main_8_hsdivout0_clk", "pllfracf_ssmod_16fft_main_8_foutvcop_clk", (void *)0x688080, 0, 7, 0, 0); + k3_clk_divider("hsdiv1_16fft_main_15_hsdivout0_clk", "pllfracf_ssmod_16fft_main_15_foutvcop_clk", (void *)0x68f080, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_main_0_hsdivout0_clk", "pllfracf_ssmod_16fft_main_0_foutvcop_clk", (void *)0x680080, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_main_0_hsdivout1_clk", "pllfracf_ssmod_16fft_main_0_foutvcop_clk", (void *)0x680084, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_main_0_hsdivout2_clk", "pllfracf_ssmod_16fft_main_0_foutvcop_clk", (void *)0x680088, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_main_0_hsdivout3_clk", "pllfracf_ssmod_16fft_main_0_foutvcop_clk", (void *)0x68008c, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_main_0_hsdivout4_clk", "pllfracf_ssmod_16fft_main_0_foutvcop_clk", (void *)0x680090, 0, 7, 0, 0); + k3_clk_div_devfreq("hsdiv4_16fft_main_1_hsdivout0_clk", "pllfracf_ssmod_16fft_main_1_foutvcop_clk", (void *)0x681080, 0, 7, 0, 0, 192000000); + k3_clk_divider("hsdiv4_16fft_main_1_hsdivout1_clk", "pllfracf_ssmod_16fft_main_1_foutvcop_clk", (void *)0x681084, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_main_1_hsdivout2_clk", "pllfracf_ssmod_16fft_main_1_foutvcop_clk", (void *)0x681088, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_main_2_hsdivout1_clk", "pllfracf_ssmod_16fft_main_2_foutvcop_clk", (void *)0x682084, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_main_2_hsdivout1_clk10", "pllfracf_ssmod_16fft_main_2_foutvcop_clk", (void *)0x682084, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_main_2_hsdivout2_clk", "pllfracf_ssmod_16fft_main_2_foutvcop_clk", (void *)0x682088, 0, 7, 0, 0); + k3_clk_divider("hsdiv4_16fft_mcu_0_hsdivout0_clk", "pllfracf_ssmod_16fft_mcu_0_foutvcop_clk", (void *)0x4040080, 0, 7, 0, 0); + k3_clk_mux_pllctrl("sam62_pll_ctrl_wrap_main_0_sysclkout_clk", sam62_pll_ctrl_wrap_main_0_sysclkout_clk_parents, 2, (void *)0x410000, 0); + k3_clk_divider("sam62_pll_ctrl_wrap_main_0_chip_div1_clk_clk", "sam62_pll_ctrl_wrap_main_0_sysclkout_clk", (void *)0x410118, 0, 5, 0, 0); + k3_clk_mux_pllctrl("sam62_pll_ctrl_wrap_mcu_0_sysclkout_clk", sam62_pll_ctrl_wrap_mcu_0_sysclkout_clk_parents, 2, (void *)0x4020000, 0); + k3_clk_divider("sam62_pll_ctrl_wrap_mcu_0_chip_div1_clk_clk", "sam62_pll_ctrl_wrap_mcu_0_sysclkout_clk", (void *)0x4020118, 0, 5, 0, 0); + k3_clk_mux("clkout0_ctrl_out0", clkout0_ctrl_out0_parents, 2, (void *)0x108010, 0, 1, 0); + k3_clk_mux("clk_32k_rc_sel_out0", clk_32k_rc_sel_out0_parents, 4, (void *)0x4508058, 0, 2, 0); + k3_clk_mux("main_cp_gemac_cpts_clk_sel_out0", main_cp_gemac_cpts_clk_sel_out0_parents, 8, (void *)0x108140, 0, 3, 0); + k3_clk_mux("main_emmcsd0_refclk_sel_out0", main_emmcsd0_refclk_sel_out0_parents, 2, (void *)0x108160, 0, 1, 0); + k3_clk_mux("main_emmcsd1_refclk_sel_out0", main_emmcsd1_refclk_sel_out0_parents, 2, (void *)0x108168, 0, 1, 0); + k3_clk_mux("main_gtcclk_sel_out0", main_gtcclk_sel_out0_parents, 8, (void *)0x43008030, 0, 3, 0); + k3_clk_mux("main_ospi_ref_clk_sel_out0", main_ospi_ref_clk_sel_out0_parents, 2, (void *)0x108500, 0, 1, 0); + k3_clk_div_devfreq("usart_programmable_clock_divider_out0", "hsdiv4_16fft_main_1_hsdivout0_clk", (void *)0x108240, 0, 2, 0, 0, 48000000); + k3_clk_mux("wkup_clkout_sel_out0", wkup_clkout_sel_out0_parents, 8, (void *)0x43008020, 0, 3, 0); + k3_clk_mux("wkup_clksel_out0", wkup_clksel_out0_parents, 2, (void *)0x43008010, 0, 1, 0); + k3_clk_mux("main_usart0_fclk_sel_out0", main_usart0_fclk_sel_out0_parents, 2, (void *)0x108280, 0, 1, 0); + k3_clk_divider("hsdiv4_16fft_mcu_0_hsdivout1_clk", "pllfracf_ssmod_16fft_mcu_0_foutvcop_clk", (void *)0x4040084, 0, 7, 0, 0); + clk_fixed("mshsi2c_wkup_0_porscl", 0); + k3_clk_divider("sam62_pll_ctrl_wrap_main_0_chip_div24_clk_clk", "sam62_pll_ctrl_wrap_main_0_sysclkout_clk", (void *)0x41011c, 0, 5, 0, 0); + k3_clk_divider("sam62_pll_ctrl_wrap_mcu_0_chip_div24_clk_clk", "sam62_pll_ctrl_wrap_mcu_0_sysclkout_clk", (void *)0x402011c, 0, 5, 0, 0); + + ret = of_clk_add_provider(dev->of_node, of_clk_ti_k3_get, &am625_lookup); + if (ret < 0) + pr_err("failed to register clks for i.MX8MM\n"); + + return 0; +}; + +static int ti_k3_clk_probe(struct device *dev) +{ + if (of_machine_is_compatible("ti,am625")) + return am625_clk_init(dev); + + return dev_err_probe(dev, -EINVAL, "Unknown SoC\n"); +} + +static __maybe_unused struct of_device_id ti_k3_clk_dt_ids[] = { + { + .compatible = "ti,k2g-sci-clk", + }, { + /* sentinel */ + } +}; + +static struct driver ti_k3_clk_driver = { + .probe = ti_k3_clk_probe, + .name = "ti-k3-clk", + .of_compatible = ti_k3_clk_dt_ids, +}; + +core_platform_driver(ti_k3_clk_driver); diff --git a/drivers/clk/k3/pll.c b/drivers/clk/k3/pll.c new file mode 100644 index 0000000000..c76a91b1d0 --- /dev/null +++ b/drivers/clk/k3/pll.c @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Texas Instruments K3 SoC PLL clock driver + * + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/ + * Tero Kristo <t-kristo@xxxxxx> + */ + +#include <io.h> +#include <errno.h> +#include <linux/clk-provider.h> +#include <linux/rational.h> +#include <linux/slab.h> +#include <linux/bitmap.h> +#include <linux/printk.h> +#include <soc/k3/clk.h> + +#include "ti-k3-clk.h" + +/* 16FFT register offsets */ +#define PLL_16FFT_CFG 0x08 +#define PLL_KICK0 0x10 +#define PLL_KICK1 0x14 +#define PLL_16FFT_CTRL 0x20 +#define PLL_16FFT_STAT 0x24 +#define PLL_16FFT_FREQ_CTRL0 0x30 +#define PLL_16FFT_FREQ_CTRL1 0x34 +#define PLL_16FFT_DIV_CTRL 0x38 +#define PLL_16FFT_CAL_CTRL 0x60 +#define PLL_16FFT_CAL_STAT 0x64 + +/* CAL STAT register bits */ +#define PLL_16FFT_CAL_STAT_CAL_LOCK BIT(31) + +/* CFG register bits */ +#define PLL_16FFT_CFG_PLL_TYPE_SHIFT (0) +#define PLL_16FFT_CFG_PLL_TYPE_MASK (0x3 << 0) +#define PLL_16FFT_CFG_PLL_TYPE_FRACF 1 + +/* CAL CTRL register bits */ +#define PLL_16FFT_CAL_CTRL_CAL_EN BIT(31) +#define PLL_16FFT_CAL_CTRL_FAST_CAL BIT(20) +#define PLL_16FFT_CAL_CTRL_CAL_BYP BIT(15) +#define PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT 16 +#define PLL_16FFT_CAL_CTRL_CAL_CNT_MASK (0x7 << 16) + +/* CTRL register bits */ +#define PLL_16FFT_CTRL_BYPASS_EN BIT(31) +#define PLL_16FFT_CTRL_PLL_EN BIT(15) +#define PLL_16FFT_CTRL_DSM_EN BIT(1) + +/* STAT register bits */ +#define PLL_16FFT_STAT_LOCK BIT(0) + +/* FREQ_CTRL0 bits */ +#define PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK 0xfff + +/* DIV CTRL register bits */ +#define PLL_16FFT_DIV_CTRL_REF_DIV_MASK 0x3f + +/* HSDIV register bits*/ +#define PLL_16FFT_HSDIV_CTRL_CLKOUT_EN BIT(15) + +/* FREQ_CTRL1 bits */ +#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS 24 +#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK 0xffffff +#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_SHIFT 0 + +/* KICK register magic values */ +#define PLL_KICK0_VALUE 0x68ef3490 +#define PLL_KICK1_VALUE 0xd172bc5a + +/** + * struct ti_pll_clk - TI PLL clock data info structure + * @clk: core clock structure + * @reg: memory address of the PLL controller + */ +struct ti_pll_clk { + struct clk_hw hw; + void __iomem *reg; + const char *parent; +}; + +static inline struct ti_pll_clk *to_pll(struct clk_hw *hw) +{ + return container_of(hw, struct ti_pll_clk, hw); +} + +static int ti_pll_wait_for_lock(struct ti_pll_clk *pll) +{ + u32 stat; + u32 cfg; + u32 cal; + u32 freq_ctrl1; + int i; + u32 pllfm; + u32 pll_type; + int success; + + for (i = 0; i < 100000; i++) { + stat = readl(pll->reg + PLL_16FFT_STAT); + if (stat & PLL_16FFT_STAT_LOCK) { + success = 1; + break; + } + } + + /* Enable calibration if not in fractional mode of the FRACF PLL */ + freq_ctrl1 = readl(pll->reg + PLL_16FFT_FREQ_CTRL1); + pllfm = freq_ctrl1 & PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK; + pllfm >>= PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_SHIFT; + cfg = readl(pll->reg + PLL_16FFT_CFG); + pll_type = (cfg & PLL_16FFT_CFG_PLL_TYPE_MASK) >> PLL_16FFT_CFG_PLL_TYPE_SHIFT; + + if (success && pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF && pllfm == 0) { + cal = readl(pll->reg + PLL_16FFT_CAL_CTRL); + + /* Enable calibration for FRACF */ + cal |= PLL_16FFT_CAL_CTRL_CAL_EN; + + /* Enable fast cal mode */ + cal |= PLL_16FFT_CAL_CTRL_FAST_CAL; + + /* Disable calibration bypass */ + cal &= ~PLL_16FFT_CAL_CTRL_CAL_BYP; + + /* Set CALCNT to 2 */ + cal &= ~PLL_16FFT_CAL_CTRL_CAL_CNT_MASK; + cal |= 2 << PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT; + + /* Note this register does not readback the written value. */ + writel(cal, pll->reg + PLL_16FFT_CAL_CTRL); + + success = 0; + for (i = 0; i < 100000; i++) { + stat = readl(pll->reg + PLL_16FFT_CAL_STAT); + if (stat & PLL_16FFT_CAL_STAT_CAL_LOCK) { + success = 1; + break; + } + } + } + + if (success == 0) { + pr_err("%s: pll (%s) failed to lock\n", __func__, + pll->hw.clk.name); + return -EBUSY; + } else { + return 0; + } +} + +static unsigned long ti_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct ti_pll_clk *pll = to_pll(hw); + u64 current_freq; + u64 parent_freq = parent_rate; + u32 pllm; + u32 plld; + u32 pllfm; + u32 ctrl; + + /* Check if we are in bypass */ + ctrl = readl(pll->reg + PLL_16FFT_CTRL); + if (ctrl & PLL_16FFT_CTRL_BYPASS_EN) + return parent_freq; + + pllm = readl(pll->reg + PLL_16FFT_FREQ_CTRL0); + pllfm = readl(pll->reg + PLL_16FFT_FREQ_CTRL1); + + plld = readl(pll->reg + PLL_16FFT_DIV_CTRL) & + PLL_16FFT_DIV_CTRL_REF_DIV_MASK; + + current_freq = parent_freq * pllm; + + do_div(current_freq, plld); + + if (pllfm) { + u64 tmp; + + tmp = parent_freq * pllfm; + do_div(tmp, plld); + tmp >>= PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS; + current_freq += tmp; + } + + return current_freq; +} + +static int ti_pll_clk_set_rate(struct ti_pll_clk *pll, unsigned long rate, + unsigned long parent_rate) +{ + u64 parent_freq = parent_rate; + int ret; + u32 ctrl; + unsigned long pllm; + u32 pllfm = 0; + unsigned long plld; + u32 div_ctrl; + u32 rem; + int shift; + + if (rate != parent_freq) + /* + * Attempt with higher max multiplier value first to give + * some space for fractional divider to kick in. + */ + for (shift = 8; shift >= 0; shift -= 8) { + rational_best_approximation(rate, parent_freq, + ((PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK + 1) << shift) - 1, + PLL_16FFT_DIV_CTRL_REF_DIV_MASK, &pllm, &plld); + if (pllm / plld <= PLL_16FFT_FREQ_CTRL0_FB_DIV_INT_MASK) + break; + } + + /* Put PLL to bypass mode */ + ctrl = readl(pll->reg + PLL_16FFT_CTRL); + ctrl |= PLL_16FFT_CTRL_BYPASS_EN; + writel(ctrl, pll->reg + PLL_16FFT_CTRL); + + if (rate == parent_freq) + return 0; + + pr_debug("%s: pre-frac-calc: rate=%u, parent_freq=%u, plld=%u, pllm=%u\n", + __func__, (u32)rate, (u32)parent_freq, (u32)plld, (u32)pllm); + + /* Check if we need fractional config */ + if (plld > 1) { + pllfm = pllm % plld; + pllfm <<= PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS; + rem = pllfm % plld; + pllfm /= plld; + if (rem) + pllfm++; + pllm /= plld; + plld = 1; + } + + if (pllfm) + ctrl |= PLL_16FFT_CTRL_DSM_EN; + else + ctrl &= ~PLL_16FFT_CTRL_DSM_EN; + + writel(pllm, pll->reg + PLL_16FFT_FREQ_CTRL0); + writel(pllfm, pll->reg + PLL_16FFT_FREQ_CTRL1); + + /* + * div_ctrl register contains other divider values, so rmw + * only plld and leave existing values alone + */ + div_ctrl = readl(pll->reg + PLL_16FFT_DIV_CTRL); + div_ctrl &= ~PLL_16FFT_DIV_CTRL_REF_DIV_MASK; + div_ctrl |= plld; + writel(div_ctrl, pll->reg + PLL_16FFT_DIV_CTRL); + + ctrl &= ~PLL_16FFT_CTRL_BYPASS_EN; + ctrl |= PLL_16FFT_CTRL_PLL_EN; + writel(ctrl, pll->reg + PLL_16FFT_CTRL); + + ret = ti_pll_wait_for_lock(pll); + if (ret) + return ret; + + pr_debug("%s: pllm=%u, plld=%u, pllfm=%u, parent_freq=%u\n", + __func__, (u32)pllm, (u32)plld, (u32)pllfm, (u32)parent_freq); + + return 0; +} + +static int __ti_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ti_pll_clk *pll = to_pll(hw); + + return ti_pll_clk_set_rate(pll, rate, parent_rate); +} + +static long ti_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return rate; /* FIXME */ +} + +static int ti_pll_clk_enable(struct clk_hw *hw) +{ + struct ti_pll_clk *pll = to_pll(hw); + u32 ctrl; + + ctrl = readl(pll->reg + PLL_16FFT_CTRL); + ctrl &= ~PLL_16FFT_CTRL_BYPASS_EN; + ctrl |= PLL_16FFT_CTRL_PLL_EN; + writel(ctrl, pll->reg + PLL_16FFT_CTRL); + + return ti_pll_wait_for_lock(pll); +} + +static void ti_pll_clk_disable(struct clk_hw *hw) +{ + struct ti_pll_clk *pll = to_pll(hw); + u32 ctrl; + + ctrl = readl(pll->reg + PLL_16FFT_CTRL); + ctrl |= PLL_16FFT_CTRL_BYPASS_EN; + writel(ctrl, pll->reg + PLL_16FFT_CTRL); +} + +static const struct clk_ops ti_pll_clk_ops = { + .recalc_rate = ti_pll_clk_recalc_rate, + .round_rate = ti_pll_clk_round_rate, + .set_rate = __ti_pll_clk_set_rate, + .enable = ti_pll_clk_enable, + .disable = ti_pll_clk_disable, +}; + +void ti_k3_pll_init(void __iomem *reg) +{ + u32 cfg, ctrl, hsdiv_presence_bit, hsdiv_ctrl_offs; + int i; + + /* Unlock the PLL registers */ + writel(PLL_KICK0_VALUE, reg + PLL_KICK0); + writel(PLL_KICK1_VALUE, reg + PLL_KICK1); + + /* Enable all HSDIV outputs */ + cfg = readl(reg + PLL_16FFT_CFG); + for (i = 0; i < 16; i++) { + hsdiv_presence_bit = BIT(16 + i); + hsdiv_ctrl_offs = 0x80 + (i * 4); + /* Enable HSDIV output if present */ + if ((hsdiv_presence_bit & cfg) != 0UL) { + ctrl = readl(reg + hsdiv_ctrl_offs); + ctrl |= PLL_16FFT_HSDIV_CTRL_CLKOUT_EN; + writel(ctrl, reg + hsdiv_ctrl_offs); + } + } +} + +int ti_k3_pll_set_rate(void __iomem *reg, unsigned long rate, unsigned long parent_rate) +{ + struct ti_pll_clk pll = { + .reg = reg, + .hw.clk.name = "PBL", + }; + + return ti_pll_clk_set_rate(&pll, rate, parent_rate); +} + +struct clk *clk_register_ti_k3_pll(const char *name, const char *parent_name, + void __iomem *reg) +{ + struct ti_pll_clk *pll; + int ret; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->reg = reg; + + pll->parent = parent_name; + pll->hw.clk.ops = &ti_pll_clk_ops; + pll->hw.clk.name = name; + pll->hw.clk.parent_names = &pll->parent; + pll->hw.clk.num_parents = 1; + + ti_k3_pll_init(pll->reg); + + ret = bclk_register(&pll->hw.clk); + if (ret) { + kfree(pll); + return ERR_PTR(ret); + } + + return &pll->hw.clk; +} diff --git a/drivers/clk/k3/ti-k3-clk.h b/drivers/clk/k3/ti-k3-clk.h new file mode 100644 index 0000000000..88980412bf --- /dev/null +++ b/drivers/clk/k3/ti-k3-clk.h @@ -0,0 +1,8 @@ +#ifndef __TI_K3_CLK_H +#define __TI_K3_CLK_H + +struct clk *clk_register_ti_k3_pll(const char *name, const char *parent_name, + void __iomem *reg); + +#endif + diff --git a/include/soc/k3/clk.h b/include/soc/k3/clk.h new file mode 100644 index 0000000000..a9921f5a9c --- /dev/null +++ b/include/soc/k3/clk.h @@ -0,0 +1,7 @@ +#ifndef __SOC_K3_CLK_H +#define __SOC_K3_CLK_H + +void ti_k3_pll_init(void __iomem *reg); +int ti_k3_pll_set_rate(void __iomem *reg, unsigned long rate, unsigned long parent_rate); + +#endif /* __SOC_K3_CLK_H */ -- 2.39.5