[PATCH 08/20] clk: add K3 clk driver
Sascha Hauer
s.hauer at pengutronix.de
Fri Nov 29 03:44:23 PST 2024
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 at pengutronix.de>
---
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 at ti.com>
+ */
+
+#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
More information about the barebox
mailing list