347 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.4 */5 6#include <linux/clk-provider.h>7#include <linux/module.h>8#include <linux/platform_device.h>9#include <linux/regmap.h>10 11#include <dt-bindings/clock/qcom,videocc-sdm845.h>12 13#include "common.h"14#include "clk-alpha-pll.h"15#include "clk-branch.h"16#include "clk-rcg.h"17#include "clk-regmap.h"18#include "clk-pll.h"19#include "gdsc.h"20 21enum {22 P_BI_TCXO,23 P_VIDEO_PLL0_OUT_MAIN,24 /* P_VIDEO_PLL0_OUT_EVEN, */25 /* P_VIDEO_PLL0_OUT_ODD, */26};27 28static const struct alpha_pll_config video_pll0_config = {29 .l = 0x10,30 .alpha = 0xaaab,31};32 33static struct clk_alpha_pll video_pll0 = {34 .offset = 0x42c,35 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],36 .clkr = {37 .hw.init = &(struct clk_init_data){38 .name = "video_pll0",39 .parent_data = &(const struct clk_parent_data){40 .fw_name = "bi_tcxo", .name = "bi_tcxo",41 },42 .num_parents = 1,43 .ops = &clk_alpha_pll_fabia_ops,44 },45 },46};47 48static const struct parent_map video_cc_parent_map_0[] = {49 { P_BI_TCXO, 0 },50 { P_VIDEO_PLL0_OUT_MAIN, 1 },51 /* { P_VIDEO_PLL0_OUT_EVEN, 2 }, */52 /* { P_VIDEO_PLL0_OUT_ODD, 3 }, */53};54 55static const struct clk_parent_data video_cc_parent_data_0[] = {56 { .fw_name = "bi_tcxo", .name = "bi_tcxo" },57 { .hw = &video_pll0.clkr.hw },58 /* { .name = "video_pll0_out_even" }, */59 /* { .name = "video_pll0_out_odd" }, */60};61 62static const struct freq_tbl ftbl_video_cc_venus_clk_src[] = {63 F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0),64 F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0),65 F(330000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),66 F(404000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),67 F(444000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),68 F(533000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),69 { }70};71 72static struct clk_rcg2 video_cc_venus_clk_src = {73 .cmd_rcgr = 0x7f0,74 .mnd_width = 0,75 .hid_width = 5,76 .parent_map = video_cc_parent_map_0,77 .freq_tbl = ftbl_video_cc_venus_clk_src,78 .clkr.hw.init = &(struct clk_init_data){79 .name = "video_cc_venus_clk_src",80 .parent_data = video_cc_parent_data_0,81 .num_parents = ARRAY_SIZE(video_cc_parent_data_0),82 .flags = CLK_SET_RATE_PARENT,83 .ops = &clk_rcg2_shared_ops,84 },85};86 87static struct clk_branch video_cc_apb_clk = {88 .halt_reg = 0x990,89 .halt_check = BRANCH_HALT,90 .clkr = {91 .enable_reg = 0x990,92 .enable_mask = BIT(0),93 .hw.init = &(struct clk_init_data){94 .name = "video_cc_apb_clk",95 .ops = &clk_branch2_ops,96 },97 },98};99 100static struct clk_branch video_cc_at_clk = {101 .halt_reg = 0x9f0,102 .halt_check = BRANCH_HALT,103 .clkr = {104 .enable_reg = 0x9f0,105 .enable_mask = BIT(0),106 .hw.init = &(struct clk_init_data){107 .name = "video_cc_at_clk",108 .ops = &clk_branch2_ops,109 },110 },111};112 113static struct clk_branch video_cc_qdss_trig_clk = {114 .halt_reg = 0x970,115 .halt_check = BRANCH_HALT,116 .clkr = {117 .enable_reg = 0x970,118 .enable_mask = BIT(0),119 .hw.init = &(struct clk_init_data){120 .name = "video_cc_qdss_trig_clk",121 .ops = &clk_branch2_ops,122 },123 },124};125 126static struct clk_branch video_cc_qdss_tsctr_div8_clk = {127 .halt_reg = 0x9d0,128 .halt_check = BRANCH_HALT,129 .clkr = {130 .enable_reg = 0x9d0,131 .enable_mask = BIT(0),132 .hw.init = &(struct clk_init_data){133 .name = "video_cc_qdss_tsctr_div8_clk",134 .ops = &clk_branch2_ops,135 },136 },137};138 139static struct clk_branch video_cc_vcodec0_axi_clk = {140 .halt_reg = 0x930,141 .halt_check = BRANCH_HALT,142 .clkr = {143 .enable_reg = 0x930,144 .enable_mask = BIT(0),145 .hw.init = &(struct clk_init_data){146 .name = "video_cc_vcodec0_axi_clk",147 .ops = &clk_branch2_ops,148 },149 },150};151 152static struct clk_branch video_cc_vcodec0_core_clk = {153 .halt_reg = 0x890,154 .halt_check = BRANCH_VOTED,155 .clkr = {156 .enable_reg = 0x890,157 .enable_mask = BIT(0),158 .hw.init = &(struct clk_init_data){159 .name = "video_cc_vcodec0_core_clk",160 .parent_hws = (const struct clk_hw*[]){161 &video_cc_venus_clk_src.clkr.hw,162 },163 .num_parents = 1,164 .flags = CLK_SET_RATE_PARENT,165 .ops = &clk_branch2_ops,166 },167 },168};169 170static struct clk_branch video_cc_vcodec1_axi_clk = {171 .halt_reg = 0x950,172 .halt_check = BRANCH_HALT,173 .clkr = {174 .enable_reg = 0x950,175 .enable_mask = BIT(0),176 .hw.init = &(struct clk_init_data){177 .name = "video_cc_vcodec1_axi_clk",178 .ops = &clk_branch2_ops,179 },180 },181};182 183static struct clk_branch video_cc_vcodec1_core_clk = {184 .halt_reg = 0x8d0,185 .halt_check = BRANCH_VOTED,186 .clkr = {187 .enable_reg = 0x8d0,188 .enable_mask = BIT(0),189 .hw.init = &(struct clk_init_data){190 .name = "video_cc_vcodec1_core_clk",191 .parent_hws = (const struct clk_hw*[]){192 &video_cc_venus_clk_src.clkr.hw,193 },194 .num_parents = 1,195 .flags = CLK_SET_RATE_PARENT,196 .ops = &clk_branch2_ops,197 },198 },199};200 201static struct clk_branch video_cc_venus_ahb_clk = {202 .halt_reg = 0x9b0,203 .halt_check = BRANCH_HALT,204 .clkr = {205 .enable_reg = 0x9b0,206 .enable_mask = BIT(0),207 .hw.init = &(struct clk_init_data){208 .name = "video_cc_venus_ahb_clk",209 .ops = &clk_branch2_ops,210 },211 },212};213 214static struct clk_branch video_cc_venus_ctl_axi_clk = {215 .halt_reg = 0x910,216 .halt_check = BRANCH_HALT,217 .clkr = {218 .enable_reg = 0x910,219 .enable_mask = BIT(0),220 .hw.init = &(struct clk_init_data){221 .name = "video_cc_venus_ctl_axi_clk",222 .ops = &clk_branch2_ops,223 },224 },225};226 227static struct clk_branch video_cc_venus_ctl_core_clk = {228 .halt_reg = 0x850,229 .halt_check = BRANCH_HALT,230 .clkr = {231 .enable_reg = 0x850,232 .enable_mask = BIT(0),233 .hw.init = &(struct clk_init_data){234 .name = "video_cc_venus_ctl_core_clk",235 .parent_hws = (const struct clk_hw*[]){236 &video_cc_venus_clk_src.clkr.hw,237 },238 .num_parents = 1,239 .flags = CLK_SET_RATE_PARENT,240 .ops = &clk_branch2_ops,241 },242 },243};244 245static struct gdsc venus_gdsc = {246 .gdscr = 0x814,247 .pd = {248 .name = "venus_gdsc",249 },250 .cxcs = (unsigned int []){ 0x850, 0x910 },251 .cxc_count = 2,252 .pwrsts = PWRSTS_OFF_ON,253 .flags = POLL_CFG_GDSCR,254};255 256static struct gdsc vcodec0_gdsc = {257 .gdscr = 0x874,258 .pd = {259 .name = "vcodec0_gdsc",260 },261 .cxcs = (unsigned int []){ 0x890, 0x930 },262 .cxc_count = 2,263 .flags = HW_CTRL | POLL_CFG_GDSCR,264 .pwrsts = PWRSTS_OFF_ON,265};266 267static struct gdsc vcodec1_gdsc = {268 .gdscr = 0x8b4,269 .pd = {270 .name = "vcodec1_gdsc",271 },272 .cxcs = (unsigned int []){ 0x8d0, 0x950 },273 .cxc_count = 2,274 .flags = HW_CTRL | POLL_CFG_GDSCR,275 .pwrsts = PWRSTS_OFF_ON,276};277 278static struct clk_regmap *video_cc_sdm845_clocks[] = {279 [VIDEO_CC_APB_CLK] = &video_cc_apb_clk.clkr,280 [VIDEO_CC_AT_CLK] = &video_cc_at_clk.clkr,281 [VIDEO_CC_QDSS_TRIG_CLK] = &video_cc_qdss_trig_clk.clkr,282 [VIDEO_CC_QDSS_TSCTR_DIV8_CLK] = &video_cc_qdss_tsctr_div8_clk.clkr,283 [VIDEO_CC_VCODEC0_AXI_CLK] = &video_cc_vcodec0_axi_clk.clkr,284 [VIDEO_CC_VCODEC0_CORE_CLK] = &video_cc_vcodec0_core_clk.clkr,285 [VIDEO_CC_VCODEC1_AXI_CLK] = &video_cc_vcodec1_axi_clk.clkr,286 [VIDEO_CC_VCODEC1_CORE_CLK] = &video_cc_vcodec1_core_clk.clkr,287 [VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr,288 [VIDEO_CC_VENUS_CLK_SRC] = &video_cc_venus_clk_src.clkr,289 [VIDEO_CC_VENUS_CTL_AXI_CLK] = &video_cc_venus_ctl_axi_clk.clkr,290 [VIDEO_CC_VENUS_CTL_CORE_CLK] = &video_cc_venus_ctl_core_clk.clkr,291 [VIDEO_PLL0] = &video_pll0.clkr,292};293 294static struct gdsc *video_cc_sdm845_gdscs[] = {295 [VENUS_GDSC] = &venus_gdsc,296 [VCODEC0_GDSC] = &vcodec0_gdsc,297 [VCODEC1_GDSC] = &vcodec1_gdsc,298};299 300static const struct regmap_config video_cc_sdm845_regmap_config = {301 .reg_bits = 32,302 .reg_stride = 4,303 .val_bits = 32,304 .max_register = 0xb90,305 .fast_io = true,306};307 308static const struct qcom_cc_desc video_cc_sdm845_desc = {309 .config = &video_cc_sdm845_regmap_config,310 .clks = video_cc_sdm845_clocks,311 .num_clks = ARRAY_SIZE(video_cc_sdm845_clocks),312 .gdscs = video_cc_sdm845_gdscs,313 .num_gdscs = ARRAY_SIZE(video_cc_sdm845_gdscs),314};315 316static const struct of_device_id video_cc_sdm845_match_table[] = {317 { .compatible = "qcom,sdm845-videocc" },318 { }319};320MODULE_DEVICE_TABLE(of, video_cc_sdm845_match_table);321 322static int video_cc_sdm845_probe(struct platform_device *pdev)323{324 struct regmap *regmap;325 326 regmap = qcom_cc_map(pdev, &video_cc_sdm845_desc);327 if (IS_ERR(regmap))328 return PTR_ERR(regmap);329 330 clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config);331 332 return qcom_cc_really_probe(&pdev->dev, &video_cc_sdm845_desc, regmap);333}334 335static struct platform_driver video_cc_sdm845_driver = {336 .probe = video_cc_sdm845_probe,337 .driver = {338 .name = "sdm845-videocc",339 .of_match_table = video_cc_sdm845_match_table,340 },341};342 343module_platform_driver(video_cc_sdm845_driver);344 345MODULE_LICENSE("GPL v2");346MODULE_DESCRIPTION("QTI SDM845 VIDEOCC Driver");347