1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2018, The Linux Foundation. All rights reserved. 4 * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. 5 */ 6 7 #include <linux/clk.h> 8 #include <linux/clk-provider.h> 9 #include <linux/err.h> 10 #include <linux/interconnect-provider.h> 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/platform_device.h> 14 #include <linux/regmap.h> 15 16 #include <dt-bindings/arm/qcom,ids.h> 17 #include <dt-bindings/clock/qcom,apss-ipq.h> 18 #include <dt-bindings/interconnect/qcom,ipq5424.h> 19 20 #include "clk-alpha-pll.h" 21 #include "clk-branch.h" 22 #include "clk-rcg.h" 23 #include "clk-regmap.h" 24 #include "common.h" 25 26 enum { 27 DT_XO, 28 DT_CLK_REF, 29 }; 30 31 enum { 32 P_XO, 33 P_GPLL0, 34 P_APSS_PLL_EARLY, 35 P_L3_PLL, 36 }; 37 38 static const struct alpha_pll_config apss_pll_config = { 39 .l = 0x3b, 40 .config_ctl_val = 0x08200920, 41 .config_ctl_hi_val = 0x05008001, 42 .config_ctl_hi1_val = 0x04000000, 43 .user_ctl_val = 0xf, 44 }; 45 46 static struct clk_alpha_pll ipq5424_apss_pll = { 47 .offset = 0x0, 48 .config = &apss_pll_config, 49 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_HUAYRA_2290], 50 .flags = SUPPORTS_DYNAMIC_UPDATE, 51 .clkr = { 52 .enable_reg = 0x0, 53 .enable_mask = BIT(0), 54 .hw.init = &(struct clk_init_data){ 55 .name = "apss_pll", 56 .parent_data = &(const struct clk_parent_data) { 57 .index = DT_XO, 58 }, 59 .num_parents = 1, 60 .ops = &clk_alpha_pll_huayra_ops, 61 }, 62 }, 63 }; 64 65 static const struct clk_parent_data parents_apss_silver_clk_src[] = { 66 { .index = DT_XO }, 67 { .index = DT_CLK_REF }, 68 { .hw = &ipq5424_apss_pll.clkr.hw }, 69 }; 70 71 static const struct parent_map parents_apss_silver_clk_src_map[] = { 72 { P_XO, 0 }, 73 { P_GPLL0, 4 }, 74 { P_APSS_PLL_EARLY, 5 }, 75 }; 76 77 static const struct freq_tbl ftbl_apss_clk_src[] = { 78 F(816000000, P_APSS_PLL_EARLY, 1, 0, 0), 79 F(1416000000, P_APSS_PLL_EARLY, 1, 0, 0), 80 F(1800000000, P_APSS_PLL_EARLY, 1, 0, 0), 81 { } 82 }; 83 84 static struct clk_rcg2 apss_silver_clk_src = { 85 .cmd_rcgr = 0x0080, 86 .freq_tbl = ftbl_apss_clk_src, 87 .hid_width = 5, 88 .parent_map = parents_apss_silver_clk_src_map, 89 .clkr.hw.init = &(struct clk_init_data) { 90 .name = "apss_silver_clk_src", 91 .parent_data = parents_apss_silver_clk_src, 92 .num_parents = ARRAY_SIZE(parents_apss_silver_clk_src), 93 .ops = &clk_rcg2_ops, 94 .flags = CLK_SET_RATE_PARENT, 95 }, 96 }; 97 98 static struct clk_branch apss_silver_core_clk = { 99 .halt_reg = 0x008c, 100 .clkr = { 101 .enable_reg = 0x008c, 102 .enable_mask = BIT(0), 103 .hw.init = &(struct clk_init_data) { 104 .name = "apss_silver_core_clk", 105 .parent_hws = (const struct clk_hw *[]) { 106 &apss_silver_clk_src.clkr.hw 107 }, 108 .num_parents = 1, 109 .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 110 .ops = &clk_branch2_ops, 111 }, 112 }, 113 }; 114 115 static const struct alpha_pll_config l3_pll_config = { 116 .l = 0x29, 117 .config_ctl_val = 0x08200920, 118 .config_ctl_hi_val = 0x05008001, 119 .config_ctl_hi1_val = 0x04000000, 120 .user_ctl_val = 0xf, 121 }; 122 123 static struct clk_alpha_pll ipq5424_l3_pll = { 124 .offset = 0x10000, 125 .config = &l3_pll_config, 126 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_HUAYRA_2290], 127 .flags = SUPPORTS_DYNAMIC_UPDATE, 128 .clkr = { 129 .enable_reg = 0x0, 130 .enable_mask = BIT(0), 131 .hw.init = &(struct clk_init_data) { 132 .name = "l3_pll", 133 .parent_data = &(const struct clk_parent_data) { 134 .index = DT_XO, 135 }, 136 .num_parents = 1, 137 .ops = &clk_alpha_pll_huayra_ops, 138 }, 139 }, 140 }; 141 142 static const struct clk_parent_data parents_l3_clk_src[] = { 143 { .index = DT_XO }, 144 { .index = DT_CLK_REF }, 145 { .hw = &ipq5424_l3_pll.clkr.hw }, 146 }; 147 148 static const struct parent_map parents_l3_clk_src_map[] = { 149 { P_XO, 0 }, 150 { P_GPLL0, 4 }, 151 { P_L3_PLL, 5 }, 152 }; 153 154 static const struct freq_tbl ftbl_l3_clk_src[] = { 155 F(816000000, P_L3_PLL, 1, 0, 0), 156 F(984000000, P_L3_PLL, 1, 0, 0), 157 F(1272000000, P_L3_PLL, 1, 0, 0), 158 { } 159 }; 160 161 static struct clk_rcg2 l3_clk_src = { 162 .cmd_rcgr = 0x10080, 163 .freq_tbl = ftbl_l3_clk_src, 164 .hid_width = 5, 165 .parent_map = parents_l3_clk_src_map, 166 .clkr.hw.init = &(struct clk_init_data) { 167 .name = "l3_clk_src", 168 .parent_data = parents_l3_clk_src, 169 .num_parents = ARRAY_SIZE(parents_l3_clk_src), 170 .ops = &clk_rcg2_ops, 171 .flags = CLK_SET_RATE_PARENT, 172 }, 173 }; 174 175 static struct clk_branch l3_core_clk = { 176 .halt_reg = 0x1008c, 177 .clkr = { 178 .enable_reg = 0x1008c, 179 .enable_mask = BIT(0), 180 .hw.init = &(struct clk_init_data) { 181 .name = "l3_clk", 182 .parent_hws = (const struct clk_hw *[]) { 183 &l3_clk_src.clkr.hw 184 }, 185 .num_parents = 1, 186 .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 187 .ops = &clk_branch2_ops, 188 }, 189 }, 190 }; 191 192 static const struct regmap_config apss_ipq5424_regmap_config = { 193 .reg_bits = 32, 194 .reg_stride = 4, 195 .val_bits = 32, 196 .max_register = 0x20000, 197 .fast_io = true, 198 }; 199 200 static struct clk_regmap *apss_ipq5424_clks[] = { 201 [APSS_PLL_EARLY] = &ipq5424_apss_pll.clkr, 202 [APSS_SILVER_CLK_SRC] = &apss_silver_clk_src.clkr, 203 [APSS_SILVER_CORE_CLK] = &apss_silver_core_clk.clkr, 204 [L3_PLL] = &ipq5424_l3_pll.clkr, 205 [L3_CLK_SRC] = &l3_clk_src.clkr, 206 [L3_CORE_CLK] = &l3_core_clk.clkr, 207 }; 208 209 static struct clk_alpha_pll *ipa5424_apss_plls[] = { 210 &ipq5424_l3_pll, 211 &ipq5424_apss_pll, 212 }; 213 214 static struct qcom_cc_driver_data ipa5424_apss_driver_data = { 215 .alpha_plls = ipa5424_apss_plls, 216 .num_alpha_plls = ARRAY_SIZE(ipa5424_apss_plls), 217 }; 218 219 #define IPQ_APPS_PLL_ID (5424 * 3) /* some unique value */ 220 221 static const struct qcom_icc_hws_data icc_ipq5424_cpu_l3[] = { 222 { MASTER_CPU, SLAVE_L3, L3_CORE_CLK }, 223 }; 224 225 static const struct qcom_cc_desc apss_ipq5424_desc = { 226 .config = &apss_ipq5424_regmap_config, 227 .clks = apss_ipq5424_clks, 228 .num_clks = ARRAY_SIZE(apss_ipq5424_clks), 229 .icc_hws = icc_ipq5424_cpu_l3, 230 .num_icc_hws = ARRAY_SIZE(icc_ipq5424_cpu_l3), 231 .icc_first_node_id = IPQ_APPS_PLL_ID, 232 .driver_data = &ipa5424_apss_driver_data, 233 }; 234 235 static int apss_ipq5424_probe(struct platform_device *pdev) 236 { 237 return qcom_cc_probe(pdev, &apss_ipq5424_desc); 238 } 239 240 static const struct of_device_id apss_ipq5424_match_table[] = { 241 { .compatible = "qcom,ipq5424-apss-clk" }, 242 { } 243 }; 244 MODULE_DEVICE_TABLE(of, apss_ipq5424_match_table); 245 246 static struct platform_driver apss_ipq5424_driver = { 247 .probe = apss_ipq5424_probe, 248 .driver = { 249 .name = "apss-ipq5424-clk", 250 .of_match_table = apss_ipq5424_match_table, 251 .sync_state = icc_sync_state, 252 }, 253 }; 254 255 module_platform_driver(apss_ipq5424_driver); 256 257 MODULE_DESCRIPTION("QCOM APSS IPQ5424 CLK Driver"); 258 MODULE_LICENSE("GPL"); 259