358 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.4 * Copyright (c) 2024, Danila Tikhonov <danila@jiaxyga.com>5 */6 7#include <linux/clk-provider.h>8#include <linux/mod_devicetable.h>9#include <linux/module.h>10#include <linux/platform_device.h>11#include <linux/regmap.h>12 13#include <dt-bindings/clock/qcom,sm7150-videocc.h>14 15#include "common.h"16#include "clk-alpha-pll.h"17#include "clk-branch.h"18#include "clk-rcg.h"19#include "clk-regmap.h"20#include "clk-pll.h"21#include "gdsc.h"22 23enum {24 DT_BI_TCXO,25 DT_BI_TCXO_AO,26};27 28enum {29 P_BI_TCXO,30 P_VIDEOCC_PLL0_OUT_EVEN,31 P_VIDEOCC_PLL0_OUT_MAIN,32 P_VIDEOCC_PLL0_OUT_ODD,33};34 35static const struct pll_vco fabia_vco[] = {36 { 249600000, 2000000000, 0 },37 { 125000000, 1000000000, 1 },38};39 40static struct alpha_pll_config videocc_pll0_config = {41 .l = 0x19,42 .alpha = 0x0,43 .config_ctl_val = 0x20485699,44 .config_ctl_hi_val = 0x00002067,45 .user_ctl_val = 0x00000001,46 .user_ctl_hi_val = 0x00004805,47 .test_ctl_hi_val = 0x40000000,48};49 50static struct clk_alpha_pll videocc_pll0 = {51 .offset = 0x42c,52 .vco_table = fabia_vco,53 .num_vco = ARRAY_SIZE(fabia_vco),54 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],55 .clkr = {56 .hw.init = &(const struct clk_init_data) {57 .name = "videocc_pll0",58 .parent_data = &(const struct clk_parent_data) {59 .index = DT_BI_TCXO,60 },61 .num_parents = 1,62 .ops = &clk_alpha_pll_fabia_ops,63 },64 },65};66 67static const struct parent_map videocc_parent_map_0[] = {68 { P_BI_TCXO, 0 },69 { P_VIDEOCC_PLL0_OUT_MAIN, 1 },70 { P_VIDEOCC_PLL0_OUT_EVEN, 2 },71 { P_VIDEOCC_PLL0_OUT_ODD, 3 },72};73 74static const struct clk_parent_data videocc_parent_data_0[] = {75 { .index = DT_BI_TCXO },76 { .hw = &videocc_pll0.clkr.hw },77 { .hw = &videocc_pll0.clkr.hw },78 { .hw = &videocc_pll0.clkr.hw },79};80 81static const struct parent_map videocc_parent_map_1[] = {82 { P_BI_TCXO, 0 },83};84 85static const struct clk_parent_data videocc_parent_data_1[] = {86 { .index = DT_BI_TCXO_AO },87};88 89static const struct freq_tbl ftbl_videocc_iris_clk_src[] = {90 F(240000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),91 F(338000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),92 F(365000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),93 F(444000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),94 F(533000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),95 { }96};97 98static struct clk_rcg2 videocc_iris_clk_src = {99 .cmd_rcgr = 0x7f0,100 .mnd_width = 0,101 .hid_width = 5,102 .parent_map = videocc_parent_map_0,103 .freq_tbl = ftbl_videocc_iris_clk_src,104 .clkr.hw.init = &(const struct clk_init_data) {105 .name = "videocc_iris_clk_src",106 .parent_data = videocc_parent_data_0,107 .num_parents = ARRAY_SIZE(videocc_parent_data_0),108 .flags = CLK_SET_RATE_PARENT,109 .ops = &clk_rcg2_shared_ops,110 },111};112 113static const struct freq_tbl ftbl_videocc_xo_clk_src[] = {114 F(19200000, P_BI_TCXO, 1, 0, 0),115 { }116};117 118static struct clk_rcg2 videocc_xo_clk_src = {119 .cmd_rcgr = 0xa98,120 .mnd_width = 0,121 .hid_width = 5,122 .parent_map = videocc_parent_map_1,123 .freq_tbl = ftbl_videocc_xo_clk_src,124 .clkr.hw.init = &(const struct clk_init_data) {125 .name = "videocc_xo_clk_src",126 .parent_data = videocc_parent_data_1,127 .num_parents = ARRAY_SIZE(videocc_parent_data_1),128 .ops = &clk_rcg2_ops,129 },130};131 132static struct clk_branch videocc_iris_ahb_clk = {133 .halt_reg = 0x8f4,134 .halt_check = BRANCH_VOTED,135 .clkr = {136 .enable_reg = 0x8f4,137 .enable_mask = BIT(0),138 .hw.init = &(const struct clk_init_data) {139 .name = "videocc_iris_ahb_clk",140 .parent_data = &(const struct clk_parent_data) {141 .hw = &videocc_iris_clk_src.clkr.hw,142 },143 .num_parents = 1,144 .flags = CLK_SET_RATE_PARENT,145 .ops = &clk_branch2_ops,146 },147 },148};149 150static struct clk_branch videocc_mvs0_axi_clk = {151 .halt_reg = 0x9ec,152 .halt_check = BRANCH_HALT,153 .clkr = {154 .enable_reg = 0x9ec,155 .enable_mask = BIT(0),156 .hw.init = &(const struct clk_init_data) {157 .name = "videocc_mvs0_axi_clk",158 .ops = &clk_branch2_ops,159 },160 },161};162 163static struct clk_branch videocc_mvs0_core_clk = {164 .halt_reg = 0x890,165 .halt_check = BRANCH_VOTED,166 .clkr = {167 .enable_reg = 0x890,168 .enable_mask = BIT(0),169 .hw.init = &(const struct clk_init_data) {170 .name = "videocc_mvs0_core_clk",171 .parent_data = &(const struct clk_parent_data) {172 .hw = &videocc_iris_clk_src.clkr.hw,173 },174 .num_parents = 1,175 .flags = CLK_SET_RATE_PARENT,176 .ops = &clk_branch2_ops,177 },178 },179};180 181static struct clk_branch videocc_mvs1_axi_clk = {182 .halt_reg = 0xa0c,183 .halt_check = BRANCH_HALT,184 .clkr = {185 .enable_reg = 0xa0c,186 .enable_mask = BIT(0),187 .hw.init = &(const struct clk_init_data) {188 .name = "videocc_mvs1_axi_clk",189 .ops = &clk_branch2_ops,190 },191 },192};193 194static struct clk_branch videocc_mvs1_core_clk = {195 .halt_reg = 0x8d0,196 .halt_check = BRANCH_VOTED,197 .clkr = {198 .enable_reg = 0x8d0,199 .enable_mask = BIT(0),200 .hw.init = &(const struct clk_init_data) {201 .name = "videocc_mvs1_core_clk",202 .parent_data = &(const struct clk_parent_data) {203 .hw = &videocc_iris_clk_src.clkr.hw,204 },205 .num_parents = 1,206 .flags = CLK_SET_RATE_PARENT,207 .ops = &clk_branch2_ops,208 },209 },210};211 212static struct clk_branch videocc_mvsc_core_clk = {213 .halt_reg = 0x850,214 .halt_check = BRANCH_HALT,215 .clkr = {216 .enable_reg = 0x850,217 .enable_mask = BIT(0),218 .hw.init = &(const struct clk_init_data) {219 .name = "videocc_mvsc_core_clk",220 .parent_data = &(const struct clk_parent_data) {221 .hw = &videocc_iris_clk_src.clkr.hw,222 },223 .num_parents = 1,224 .flags = CLK_SET_RATE_PARENT,225 .ops = &clk_branch2_ops,226 },227 },228};229 230static struct clk_branch videocc_mvsc_ctl_axi_clk = {231 .halt_reg = 0x9cc,232 .halt_check = BRANCH_HALT,233 .clkr = {234 .enable_reg = 0x9cc,235 .enable_mask = BIT(0),236 .hw.init = &(const struct clk_init_data) {237 .name = "videocc_mvsc_ctl_axi_clk",238 .ops = &clk_branch2_ops,239 },240 },241};242 243static struct clk_branch videocc_venus_ahb_clk = {244 .halt_reg = 0xa6c,245 .halt_check = BRANCH_HALT,246 .clkr = {247 .enable_reg = 0xa6c,248 .enable_mask = BIT(0),249 .hw.init = &(const struct clk_init_data) {250 .name = "videocc_venus_ahb_clk",251 .ops = &clk_branch2_ops,252 },253 },254};255 256static struct gdsc venus_gdsc = {257 .gdscr = 0x814,258 .pd = {259 .name = "venus_gdsc",260 },261 .cxcs = (unsigned int []){ 0x850, 0x9cc },262 .cxc_count = 2,263 .pwrsts = PWRSTS_OFF_ON,264 .flags = POLL_CFG_GDSCR,265};266 267static struct gdsc vcodec0_gdsc = {268 .gdscr = 0x874,269 .pd = {270 .name = "vcodec0_gdsc",271 },272 .cxcs = (unsigned int []){ 0x890, 0x9ec },273 .cxc_count = 2,274 .flags = HW_CTRL | POLL_CFG_GDSCR,275 .pwrsts = PWRSTS_OFF_ON,276};277 278static struct gdsc vcodec1_gdsc = {279 .gdscr = 0x8b4,280 .pd = {281 .name = "vcodec1_gdsc",282 },283 .cxcs = (unsigned int []){ 0x8d0, 0xa0c },284 .cxc_count = 2,285 .flags = HW_CTRL | POLL_CFG_GDSCR,286 .pwrsts = PWRSTS_OFF_ON,287};288 289static struct clk_regmap *videocc_sm7150_clocks[] = {290 [VIDEOCC_PLL0] = &videocc_pll0.clkr,291 [VIDEOCC_IRIS_AHB_CLK] = &videocc_iris_ahb_clk.clkr,292 [VIDEOCC_IRIS_CLK_SRC] = &videocc_iris_clk_src.clkr,293 [VIDEOCC_MVS0_AXI_CLK] = &videocc_mvs0_axi_clk.clkr,294 [VIDEOCC_MVS0_CORE_CLK] = &videocc_mvs0_core_clk.clkr,295 [VIDEOCC_MVS1_AXI_CLK] = &videocc_mvs1_axi_clk.clkr,296 [VIDEOCC_MVS1_CORE_CLK] = &videocc_mvs1_core_clk.clkr,297 [VIDEOCC_MVSC_CORE_CLK] = &videocc_mvsc_core_clk.clkr,298 [VIDEOCC_MVSC_CTL_AXI_CLK] = &videocc_mvsc_ctl_axi_clk.clkr,299 [VIDEOCC_VENUS_AHB_CLK] = &videocc_venus_ahb_clk.clkr,300 [VIDEOCC_XO_CLK_SRC] = &videocc_xo_clk_src.clkr,301};302 303static struct gdsc *videocc_sm7150_gdscs[] = {304 [VENUS_GDSC] = &venus_gdsc,305 [VCODEC0_GDSC] = &vcodec0_gdsc,306 [VCODEC1_GDSC] = &vcodec1_gdsc,307};308 309static const struct regmap_config videocc_sm7150_regmap_config = {310 .reg_bits = 32,311 .reg_stride = 4,312 .val_bits = 32,313 .max_register = 0xb94,314 .fast_io = true,315};316 317static const struct qcom_cc_desc videocc_sm7150_desc = {318 .config = &videocc_sm7150_regmap_config,319 .clks = videocc_sm7150_clocks,320 .num_clks = ARRAY_SIZE(videocc_sm7150_clocks),321 .gdscs = videocc_sm7150_gdscs,322 .num_gdscs = ARRAY_SIZE(videocc_sm7150_gdscs),323};324 325static const struct of_device_id videocc_sm7150_match_table[] = {326 { .compatible = "qcom,sm7150-videocc" },327 { }328};329MODULE_DEVICE_TABLE(of, videocc_sm7150_match_table);330 331static int videocc_sm7150_probe(struct platform_device *pdev)332{333 struct regmap *regmap;334 335 regmap = qcom_cc_map(pdev, &videocc_sm7150_desc);336 if (IS_ERR(regmap))337 return PTR_ERR(regmap);338 339 clk_fabia_pll_configure(&videocc_pll0, regmap, &videocc_pll0_config);340 341 /* Keep some clocks always-on */342 qcom_branch_set_clk_en(regmap, 0x984); /* VIDEOCC_XO_CLK */343 344 return qcom_cc_really_probe(&pdev->dev, &videocc_sm7150_desc, regmap);345}346 347static struct platform_driver videocc_sm7150_driver = {348 .probe = videocc_sm7150_probe,349 .driver = {350 .name = "videocc-sm7150",351 .of_match_table = videocc_sm7150_match_table,352 },353};354module_platform_driver(videocc_sm7150_driver);355 356MODULE_DESCRIPTION("Qualcomm SM7150 Video Clock Controller");357MODULE_LICENSE("GPL");358