From ca5b345d5056d9e849de66539c30a552c2f6bfb5 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Wed, 17 Jun 2026 16:37:54 +0530 Subject: [PATCH] clk: qcom: Add EVA clock controller driver for Glymur SoC Add the Enhanced Video Analytics (EVA) clock controller driver for the Glymur SoC. The EVACC manages the PLL, RCGs, branch clocks, GDSCs and resets for the EVA subsystem which handles vision processing workloads. Signed-off-by: Taniya Das Reviewed-by: Konrad Dybcio Link: https://patch.msgid.link/20260617-evacc_glymur-v2-3-905108dacaaa@oss.qualcomm.com Signed-off-by: Abel Vesa --- drivers/clk/qcom/Kconfig | 11 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/evacc-glymur.c | 455 ++++++++++++++++++++++++++++++++ 3 files changed, 467 insertions(+) create mode 100644 drivers/clk/qcom/evacc-glymur.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 5d46158bc023..8a6f3505886d 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -66,6 +66,17 @@ config CLK_GLYMUR_DISPCC Say Y if you want to support display devices and functionality such as splash screen. +config CLK_GLYMUR_EVACC + tristate "Glymur EVA Clock Controller" + depends on ARM64 || COMPILE_TEST + default m if ARCH_QCOM + select CLK_GLYMUR_GCC + help + Support for the Enhanced Video Analytics (EVA) clock controller on + Qualcomm Technologies, Inc. Glymur devices. + Say Y if you want to support EVA devices and functionality such as + vision processing. + config CLK_GLYMUR_GCC tristate "Glymur Global Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 8180ee4c0089..6622c00f5aaa 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_CLK_ELIZA_TCSRCC) += tcsrcc-eliza.o obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o obj-$(CONFIG_CLK_GLYMUR_CAMCC) += camcc-glymur.o obj-$(CONFIG_CLK_GLYMUR_DISPCC) += dispcc-glymur.o +obj-$(CONFIG_CLK_GLYMUR_EVACC) += evacc-glymur.o obj-$(CONFIG_CLK_GLYMUR_GCC) += gcc-glymur.o obj-$(CONFIG_CLK_GLYMUR_GPUCC) += gpucc-glymur.o gxclkctl-kaanapali.o obj-$(CONFIG_CLK_GLYMUR_TCSRCC) += tcsrcc-glymur.o diff --git a/drivers/clk/qcom/evacc-glymur.c b/drivers/clk/qcom/evacc-glymur.c new file mode 100644 index 000000000000..ba124cfc1a4d --- /dev/null +++ b/drivers/clk/qcom/evacc-glymur.c @@ -0,0 +1,455 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_AHB_CLK, + DT_BI_TCXO, + DT_SLEEP_CLK, +}; + +enum { + P_BI_TCXO, + P_EVA_CC_PLL0_OUT_MAIN, + P_SLEEP_CLK, +}; + +static const struct pll_vco taycan_eko_t_vco[] = { + { 249600000, 2500000000, 0 }, +}; + +/* 840.0 MHz Configuration */ +static const struct alpha_pll_config eva_cc_pll0_config = { + .l = 0x2b, + .alpha = 0xc000, + .config_ctl_val = 0x25c400e7, + .config_ctl_hi_val = 0x0a8060e0, + .config_ctl_hi1_val = 0xf51dea20, + .user_ctl_val = 0x00000008, + .user_ctl_hi_val = 0x00000002, +}; + +static struct clk_alpha_pll eva_cc_pll0 = { + .offset = 0x0, + .config = &eva_cc_pll0_config, + .vco_table = taycan_eko_t_vco, + .num_vco = ARRAY_SIZE(taycan_eko_t_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_taycan_eko_t_ops, + }, + }, +}; + +static const struct parent_map eva_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data eva_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map eva_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_EVA_CC_PLL0_OUT_MAIN, 1 }, +}; + +static const struct clk_parent_data eva_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &eva_cc_pll0.clkr.hw }, +}; + +static const struct parent_map eva_cc_parent_map_2[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data eva_cc_parent_data_2[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct freq_tbl ftbl_eva_cc_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 eva_cc_ahb_clk_src = { + .cmd_rcgr = 0x8018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = eva_cc_parent_map_0, + .freq_tbl = ftbl_eva_cc_ahb_clk_src, + .hw_clk_ctrl = true, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_ahb_clk_src", + .parent_data = eva_cc_parent_data_0, + .num_parents = ARRAY_SIZE(eva_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_eva_cc_mvs0_clk_src[] = { + F(840000000, P_EVA_CC_PLL0_OUT_MAIN, 1, 0, 0), + F(1050000000, P_EVA_CC_PLL0_OUT_MAIN, 1, 0, 0), + F(1350000000, P_EVA_CC_PLL0_OUT_MAIN, 1, 0, 0), + F(1500000000, P_EVA_CC_PLL0_OUT_MAIN, 1, 0, 0), + F(1650000000, P_EVA_CC_PLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 eva_cc_mvs0_clk_src = { + .cmd_rcgr = 0x8000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = eva_cc_parent_map_1, + .freq_tbl = ftbl_eva_cc_mvs0_clk_src, + .hw_clk_ctrl = true, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_mvs0_clk_src", + .parent_data = eva_cc_parent_data_1, + .num_parents = ARRAY_SIZE(eva_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_eva_cc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 eva_cc_sleep_clk_src = { + .cmd_rcgr = 0x80e0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = eva_cc_parent_map_2, + .freq_tbl = ftbl_eva_cc_sleep_clk_src, + .hw_clk_ctrl = true, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_sleep_clk_src", + .parent_data = eva_cc_parent_data_2, + .num_parents = ARRAY_SIZE(eva_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, + }, +}; + +static struct clk_rcg2 eva_cc_xo_clk_src = { + .cmd_rcgr = 0x80bc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = eva_cc_parent_map_0, + .freq_tbl = ftbl_eva_cc_ahb_clk_src, + .hw_clk_ctrl = true, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_xo_clk_src", + .parent_data = eva_cc_parent_data_0, + .num_parents = ARRAY_SIZE(eva_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, + }, +}; + +static struct clk_regmap_div eva_cc_mvs0_div_clk_src = { + .reg = 0x809c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "eva_cc_mvs0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &eva_cc_mvs0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div eva_cc_mvs0c_div2_div_clk_src = { + .reg = 0x8060, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "eva_cc_mvs0c_div2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &eva_cc_mvs0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch eva_cc_mvs0_clk = { + .halt_reg = 0x807c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x807c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x807c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_mvs0_clk", + .parent_hws = (const struct clk_hw*[]) { + &eva_cc_mvs0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch eva_cc_mvs0_freerun_clk = { + .halt_reg = 0x808c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x808c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_mvs0_freerun_clk", + .parent_hws = (const struct clk_hw*[]) { + &eva_cc_mvs0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch eva_cc_mvs0_shift_clk = { + .halt_reg = 0x80d8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x80d8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x80d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_mvs0_shift_clk", + .parent_hws = (const struct clk_hw*[]) { + &eva_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch eva_cc_mvs0c_clk = { + .halt_reg = 0x804c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x804c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_mvs0c_clk", + .parent_hws = (const struct clk_hw*[]) { + &eva_cc_mvs0c_div2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch eva_cc_mvs0c_freerun_clk = { + .halt_reg = 0x805c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x805c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_mvs0c_freerun_clk", + .parent_hws = (const struct clk_hw*[]) { + &eva_cc_mvs0c_div2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch eva_cc_mvs0c_shift_clk = { + .halt_reg = 0x80dc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x80dc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x80dc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "eva_cc_mvs0c_shift_clk", + .parent_hws = (const struct clk_hw*[]) { + &eva_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc eva_cc_mvs0c_gdsc = { + .gdscr = 0x8034, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x6, + .pd = { + .name = "eva_cc_mvs0c_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc eva_cc_mvs0_gdsc = { + .gdscr = 0x8068, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x6, + .pd = { + .name = "eva_cc_mvs0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, + .parent = &eva_cc_mvs0c_gdsc.pd, +}; + +static struct clk_regmap *eva_cc_glymur_clocks[] = { + [EVA_CC_AHB_CLK_SRC] = &eva_cc_ahb_clk_src.clkr, + [EVA_CC_MVS0_CLK] = &eva_cc_mvs0_clk.clkr, + [EVA_CC_MVS0_CLK_SRC] = &eva_cc_mvs0_clk_src.clkr, + [EVA_CC_MVS0_DIV_CLK_SRC] = &eva_cc_mvs0_div_clk_src.clkr, + [EVA_CC_MVS0_FREERUN_CLK] = &eva_cc_mvs0_freerun_clk.clkr, + [EVA_CC_MVS0_SHIFT_CLK] = &eva_cc_mvs0_shift_clk.clkr, + [EVA_CC_MVS0C_CLK] = &eva_cc_mvs0c_clk.clkr, + [EVA_CC_MVS0C_DIV2_DIV_CLK_SRC] = &eva_cc_mvs0c_div2_div_clk_src.clkr, + [EVA_CC_MVS0C_FREERUN_CLK] = &eva_cc_mvs0c_freerun_clk.clkr, + [EVA_CC_MVS0C_SHIFT_CLK] = &eva_cc_mvs0c_shift_clk.clkr, + [EVA_CC_PLL0] = &eva_cc_pll0.clkr, + [EVA_CC_SLEEP_CLK_SRC] = &eva_cc_sleep_clk_src.clkr, + [EVA_CC_XO_CLK_SRC] = &eva_cc_xo_clk_src.clkr, +}; + +static struct gdsc *eva_cc_glymur_gdscs[] = { + [EVA_CC_MVS0_GDSC] = &eva_cc_mvs0_gdsc, + [EVA_CC_MVS0C_GDSC] = &eva_cc_mvs0c_gdsc, +}; + +static const struct qcom_reset_map eva_cc_glymur_resets[] = { + [EVA_CC_INTERFACE_BCR] = { 0x80a0 }, + [EVA_CC_MVS0_BCR] = { 0x8064 }, + [EVA_CC_MVS0C_CLK_ARES] = { 0x804c, 2 }, + [EVA_CC_MVS0C_BCR] = { 0x8030 }, + [EVA_CC_MVS0C_FREERUN_CLK_ARES] = { 0x805c, 2 }, +}; + +static struct clk_alpha_pll *eva_cc_glymur_plls[] = { + &eva_cc_pll0, +}; + +static const u32 eva_cc_glymur_critical_cbcrs[] = { + 0x80a4, /* EVA_CC_AHB_CLK */ + 0x80f8, /* EVA_CC_SLEEP_CLK */ + 0x80d4, /* EVA_CC_XO_CLK */ +}; + +static const struct regmap_config eva_cc_glymur_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9f50, + .fast_io = true, +}; + +static void clk_glymur_regs_configure(struct device *dev, struct regmap *regmap) +{ + /* + * Update CTRL_IN register as per HW recommendation to ensure clocks + * stay cycle‑aligned when the EVA core is ON. + */ + regmap_set_bits(regmap, 0x9f24, BIT(0)); +} + +static const struct qcom_cc_driver_data eva_cc_glymur_driver_data = { + .alpha_plls = eva_cc_glymur_plls, + .num_alpha_plls = ARRAY_SIZE(eva_cc_glymur_plls), + .clk_cbcrs = eva_cc_glymur_critical_cbcrs, + .num_clk_cbcrs = ARRAY_SIZE(eva_cc_glymur_critical_cbcrs), + .clk_regs_configure = clk_glymur_regs_configure, +}; + +static const struct qcom_cc_desc eva_cc_glymur_desc = { + .config = &eva_cc_glymur_regmap_config, + .clks = eva_cc_glymur_clocks, + .num_clks = ARRAY_SIZE(eva_cc_glymur_clocks), + .resets = eva_cc_glymur_resets, + .num_resets = ARRAY_SIZE(eva_cc_glymur_resets), + .gdscs = eva_cc_glymur_gdscs, + .num_gdscs = ARRAY_SIZE(eva_cc_glymur_gdscs), + .use_rpm = true, + .driver_data = &eva_cc_glymur_driver_data, +}; + +static const struct of_device_id eva_cc_glymur_match_table[] = { + { .compatible = "qcom,glymur-evacc" }, + { } +}; +MODULE_DEVICE_TABLE(of, eva_cc_glymur_match_table); + +static int eva_cc_glymur_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &eva_cc_glymur_desc); +} + +static struct platform_driver eva_cc_glymur_driver = { + .probe = eva_cc_glymur_probe, + .driver = { + .name = "evacc-glymur", + .of_match_table = eva_cc_glymur_match_table, + }, +}; + +module_platform_driver(eva_cc_glymur_driver); + +MODULE_DESCRIPTION("QTI EVACC Glymur Driver"); +MODULE_LICENSE("GPL");