Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: qcom: clk-rpmh: Add IPA clock support

The clk-rpmh driver only supports on and off RPMh clock resources. Let's
extend the driver by adding support for clocks that are managed by a
different type of RPMh resource known as Bus Clock Manager(BCM). The BCM
is a configurable shared resource aggregator that scales performance
based on a set of frequency points. The Qualcomm IP Accelerator (IPA)
clock is an example of a resource that is managed by the BCM and this a
requirement from the IPA driver in order to scale its core clock.

Signed-off-by: David Dai <daidavid1@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

David Dai and committed by
Stephen Boyd
04053f4d bfeffd15

+147
+146
drivers/clk/qcom/clk-rpmh.c
··· 18 18 #define CLK_RPMH_ARC_EN_OFFSET 0 19 19 #define CLK_RPMH_VRM_EN_OFFSET 4 20 20 21 + #define BCM_TCS_CMD_COMMIT_MASK 0x40000000 22 + #define BCM_TCS_CMD_VALID_SHIFT 29 23 + #define BCM_TCS_CMD_VOTE_MASK 0x3fff 24 + #define BCM_TCS_CMD_VOTE_SHIFT 0 25 + 26 + #define BCM_TCS_CMD(valid, vote) \ 27 + (BCM_TCS_CMD_COMMIT_MASK | \ 28 + ((valid) << BCM_TCS_CMD_VALID_SHIFT) | \ 29 + ((vote & BCM_TCS_CMD_VOTE_MASK) \ 30 + << BCM_TCS_CMD_VOTE_SHIFT)) 31 + 32 + /** 33 + * struct bcm_db - Auxiliary data pertaining to each Bus Clock Manager(BCM) 34 + * @unit: divisor used to convert Hz value to an RPMh msg 35 + * @width: multiplier used to convert Hz value to an RPMh msg 36 + * @vcd: virtual clock domain that this bcm belongs to 37 + * @reserved: reserved to pad the struct 38 + */ 39 + struct bcm_db { 40 + __le32 unit; 41 + __le16 width; 42 + u8 vcd; 43 + u8 reserved; 44 + }; 45 + 21 46 /** 22 47 * struct clk_rpmh - individual rpmh clock data structure 23 48 * @hw: handle between common and hardware-specific interfaces ··· 54 29 * @aggr_state: rpmh clock aggregated state 55 30 * @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh 56 31 * @valid_state_mask: mask to determine the state of the rpmh clock 32 + * @unit: divisor to convert rate to rpmh msg in magnitudes of Khz 57 33 * @dev: device to which it is attached 58 34 * @peer: pointer to the clock rpmh sibling 59 35 */ ··· 68 42 u32 aggr_state; 69 43 u32 last_sent_aggr_state; 70 44 u32 valid_state_mask; 45 + u32 unit; 71 46 struct device *dev; 72 47 struct clk_rpmh *peer; 73 48 }; ··· 124 97 _div) \ 125 98 __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \ 126 99 CLK_RPMH_VRM_EN_OFFSET, 1, _div) 100 + 101 + #define DEFINE_CLK_RPMH_BCM(_platform, _name, _res_name) \ 102 + static struct clk_rpmh _platform##_##_name = { \ 103 + .res_name = _res_name, \ 104 + .valid_state_mask = BIT(RPMH_ACTIVE_ONLY_STATE), \ 105 + .div = 1, \ 106 + .hw.init = &(struct clk_init_data){ \ 107 + .ops = &clk_rpmh_bcm_ops, \ 108 + .name = #_name, \ 109 + }, \ 110 + } 127 111 128 112 static inline struct clk_rpmh *to_clk_rpmh(struct clk_hw *_hw) 129 113 { ··· 248 210 .recalc_rate = clk_rpmh_recalc_rate, 249 211 }; 250 212 213 + static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable) 214 + { 215 + struct tcs_cmd cmd = { 0 }; 216 + u32 cmd_state; 217 + int ret; 218 + 219 + mutex_lock(&rpmh_clk_lock); 220 + 221 + cmd_state = 0; 222 + if (enable) { 223 + cmd_state = 1; 224 + if (c->aggr_state) 225 + cmd_state = c->aggr_state; 226 + } 227 + 228 + if (c->last_sent_aggr_state == cmd_state) { 229 + mutex_unlock(&rpmh_clk_lock); 230 + return 0; 231 + } 232 + 233 + cmd.addr = c->res_addr; 234 + cmd.data = BCM_TCS_CMD(enable, cmd_state); 235 + 236 + ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1); 237 + if (ret) { 238 + dev_err(c->dev, "set active state of %s failed: (%d)\n", 239 + c->res_name, ret); 240 + mutex_unlock(&rpmh_clk_lock); 241 + return ret; 242 + } 243 + 244 + c->last_sent_aggr_state = cmd_state; 245 + 246 + mutex_unlock(&rpmh_clk_lock); 247 + 248 + return 0; 249 + } 250 + 251 + static int clk_rpmh_bcm_prepare(struct clk_hw *hw) 252 + { 253 + struct clk_rpmh *c = to_clk_rpmh(hw); 254 + 255 + return clk_rpmh_bcm_send_cmd(c, true); 256 + }; 257 + 258 + static void clk_rpmh_bcm_unprepare(struct clk_hw *hw) 259 + { 260 + struct clk_rpmh *c = to_clk_rpmh(hw); 261 + 262 + clk_rpmh_bcm_send_cmd(c, false); 263 + }; 264 + 265 + static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate, 266 + unsigned long parent_rate) 267 + { 268 + struct clk_rpmh *c = to_clk_rpmh(hw); 269 + 270 + c->aggr_state = rate / c->unit; 271 + /* 272 + * Since any non-zero value sent to hw would result in enabling the 273 + * clock, only send the value if the clock has already been prepared. 274 + */ 275 + if (clk_hw_is_prepared(hw)) 276 + clk_rpmh_bcm_send_cmd(c, true); 277 + 278 + return 0; 279 + }; 280 + 281 + static long clk_rpmh_round_rate(struct clk_hw *hw, unsigned long rate, 282 + unsigned long *parent_rate) 283 + { 284 + return rate; 285 + } 286 + 287 + static unsigned long clk_rpmh_bcm_recalc_rate(struct clk_hw *hw, 288 + unsigned long prate) 289 + { 290 + struct clk_rpmh *c = to_clk_rpmh(hw); 291 + 292 + return c->aggr_state * c->unit; 293 + } 294 + 295 + static const struct clk_ops clk_rpmh_bcm_ops = { 296 + .prepare = clk_rpmh_bcm_prepare, 297 + .unprepare = clk_rpmh_bcm_unprepare, 298 + .set_rate = clk_rpmh_bcm_set_rate, 299 + .round_rate = clk_rpmh_round_rate, 300 + .recalc_rate = clk_rpmh_bcm_recalc_rate, 301 + }; 302 + 251 303 /* Resource name must match resource id present in cmd-db. */ 252 304 DEFINE_CLK_RPMH_ARC(sdm845, bi_tcxo, bi_tcxo_ao, "xo.lvl", 0x3, 2); 253 305 DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk2, ln_bb_clk2_ao, "lnbclka2", 2); ··· 345 217 DEFINE_CLK_RPMH_VRM(sdm845, rf_clk1, rf_clk1_ao, "rfclka1", 1); 346 218 DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1); 347 219 DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1); 220 + DEFINE_CLK_RPMH_BCM(sdm845, ipa, "IP0"); 348 221 349 222 static struct clk_hw *sdm845_rpmh_clocks[] = { 350 223 [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, ··· 360 231 [RPMH_RF_CLK2_A] = &sdm845_rf_clk2_ao.hw, 361 232 [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw, 362 233 [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw, 234 + [RPMH_IPA_CLK] = &sdm845_ipa.hw, 363 235 }; 364 236 365 237 static const struct clk_rpmh_desc clk_rpmh_sdm845 = { ··· 397 267 398 268 for (i = 0; i < desc->num_clks; i++) { 399 269 u32 res_addr; 270 + size_t aux_data_len; 271 + const struct bcm_db *data; 400 272 401 273 rpmh_clk = to_clk_rpmh(hw_clks[i]); 402 274 res_addr = cmd_db_read_addr(rpmh_clk->res_name); ··· 407 275 rpmh_clk->res_name); 408 276 return -ENODEV; 409 277 } 278 + 279 + data = cmd_db_read_aux_data(rpmh_clk->res_name, &aux_data_len); 280 + if (IS_ERR(data)) { 281 + ret = PTR_ERR(data); 282 + dev_err(&pdev->dev, 283 + "error reading RPMh aux data for %s (%d)\n", 284 + rpmh_clk->res_name, ret); 285 + return ret; 286 + } 287 + 288 + /* Convert unit from Khz to Hz */ 289 + if (aux_data_len == sizeof(*data)) 290 + rpmh_clk->unit = le32_to_cpu(data->unit) * 1000ULL; 291 + 410 292 rpmh_clk->res_addr += res_addr; 411 293 rpmh_clk->dev = &pdev->dev; 412 294
+1
include/dt-bindings/clock/qcom,rpmh.h
··· 18 18 #define RPMH_RF_CLK2_A 9 19 19 #define RPMH_RF_CLK3 10 20 20 #define RPMH_RF_CLK3_A 11 21 + #define RPMH_IPA_CLK 12 21 22 22 23 #endif