diff options
| author | David Dai <daidavid1@codeaurora.org> | 2019-01-24 19:47:00 -0500 |
|---|---|---|
| committer | Stephen Boyd <sboyd@kernel.org> | 2019-02-21 16:57:55 -0500 |
| commit | 04053f4d23a41b9383dcea4da302fd43f673afb3 (patch) | |
| tree | 15c0ce6a2700c97e3860929a5e797f5fcb6aca58 | |
| parent | bfeffd155283772bbe78c6a05dec7c0128ee500c (diff) | |
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>
| -rw-r--r-- | drivers/clk/qcom/clk-rpmh.c | 146 | ||||
| -rw-r--r-- | include/dt-bindings/clock/qcom,rpmh.h | 1 |
2 files changed, 147 insertions, 0 deletions
diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 9f4fc7773fb2..c3fd632af119 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c | |||
| @@ -18,6 +18,31 @@ | |||
| 18 | #define CLK_RPMH_ARC_EN_OFFSET 0 | 18 | #define CLK_RPMH_ARC_EN_OFFSET 0 |
| 19 | #define CLK_RPMH_VRM_EN_OFFSET 4 | 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 | * struct clk_rpmh - individual rpmh clock data structure | 47 | * struct clk_rpmh - individual rpmh clock data structure |
| 23 | * @hw: handle between common and hardware-specific interfaces | 48 | * @hw: handle between common and hardware-specific interfaces |
| @@ -29,6 +54,7 @@ | |||
| 29 | * @aggr_state: rpmh clock aggregated state | 54 | * @aggr_state: rpmh clock aggregated state |
| 30 | * @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh | 55 | * @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh |
| 31 | * @valid_state_mask: mask to determine the state of the rpmh clock | 56 | * @valid_state_mask: mask to determine the state of the rpmh clock |
| 57 | * @unit: divisor to convert rate to rpmh msg in magnitudes of Khz | ||
| 32 | * @dev: device to which it is attached | 58 | * @dev: device to which it is attached |
| 33 | * @peer: pointer to the clock rpmh sibling | 59 | * @peer: pointer to the clock rpmh sibling |
| 34 | */ | 60 | */ |
| @@ -42,6 +68,7 @@ struct clk_rpmh { | |||
| 42 | u32 aggr_state; | 68 | u32 aggr_state; |
| 43 | u32 last_sent_aggr_state; | 69 | u32 last_sent_aggr_state; |
| 44 | u32 valid_state_mask; | 70 | u32 valid_state_mask; |
| 71 | u32 unit; | ||
| 45 | struct device *dev; | 72 | struct device *dev; |
| 46 | struct clk_rpmh *peer; | 73 | struct clk_rpmh *peer; |
| 47 | }; | 74 | }; |
| @@ -98,6 +125,17 @@ static DEFINE_MUTEX(rpmh_clk_lock); | |||
| 98 | __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \ | 125 | __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \ |
| 99 | CLK_RPMH_VRM_EN_OFFSET, 1, _div) | 126 | CLK_RPMH_VRM_EN_OFFSET, 1, _div) |
| 100 | 127 | ||
| 128 | #define DEFINE_CLK_RPMH_BCM(_platform, _name, _res_name) \ | ||
| 129 | static struct clk_rpmh _platform##_##_name = { \ | ||
| 130 | .res_name = _res_name, \ | ||
| 131 | .valid_state_mask = BIT(RPMH_ACTIVE_ONLY_STATE), \ | ||
| 132 | .div = 1, \ | ||
| 133 | .hw.init = &(struct clk_init_data){ \ | ||
| 134 | .ops = &clk_rpmh_bcm_ops, \ | ||
| 135 | .name = #_name, \ | ||
| 136 | }, \ | ||
| 137 | } | ||
| 138 | |||
| 101 | static inline struct clk_rpmh *to_clk_rpmh(struct clk_hw *_hw) | 139 | static inline struct clk_rpmh *to_clk_rpmh(struct clk_hw *_hw) |
| 102 | { | 140 | { |
| 103 | return container_of(_hw, struct clk_rpmh, hw); | 141 | return container_of(_hw, struct clk_rpmh, hw); |
| @@ -210,6 +248,96 @@ static const struct clk_ops clk_rpmh_ops = { | |||
| 210 | .recalc_rate = clk_rpmh_recalc_rate, | 248 | .recalc_rate = clk_rpmh_recalc_rate, |
| 211 | }; | 249 | }; |
| 212 | 250 | ||
| 251 | static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable) | ||
| 252 | { | ||
| 253 | struct tcs_cmd cmd = { 0 }; | ||
| 254 | u32 cmd_state; | ||
| 255 | int ret; | ||
| 256 | |||
| 257 | mutex_lock(&rpmh_clk_lock); | ||
| 258 | |||
| 259 | cmd_state = 0; | ||
| 260 | if (enable) { | ||
| 261 | cmd_state = 1; | ||
| 262 | if (c->aggr_state) | ||
| 263 | cmd_state = c->aggr_state; | ||
| 264 | } | ||
| 265 | |||
| 266 | if (c->last_sent_aggr_state == cmd_state) { | ||
| 267 | mutex_unlock(&rpmh_clk_lock); | ||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | cmd.addr = c->res_addr; | ||
| 272 | cmd.data = BCM_TCS_CMD(enable, cmd_state); | ||
| 273 | |||
| 274 | ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1); | ||
| 275 | if (ret) { | ||
| 276 | dev_err(c->dev, "set active state of %s failed: (%d)\n", | ||
| 277 | c->res_name, ret); | ||
| 278 | mutex_unlock(&rpmh_clk_lock); | ||
| 279 | return ret; | ||
| 280 | } | ||
| 281 | |||
| 282 | c->last_sent_aggr_state = cmd_state; | ||
| 283 | |||
| 284 | mutex_unlock(&rpmh_clk_lock); | ||
| 285 | |||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static int clk_rpmh_bcm_prepare(struct clk_hw *hw) | ||
| 290 | { | ||
| 291 | struct clk_rpmh *c = to_clk_rpmh(hw); | ||
| 292 | |||
| 293 | return clk_rpmh_bcm_send_cmd(c, true); | ||
| 294 | }; | ||
| 295 | |||
| 296 | static void clk_rpmh_bcm_unprepare(struct clk_hw *hw) | ||
| 297 | { | ||
| 298 | struct clk_rpmh *c = to_clk_rpmh(hw); | ||
| 299 | |||
| 300 | clk_rpmh_bcm_send_cmd(c, false); | ||
| 301 | }; | ||
| 302 | |||
| 303 | static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 304 | unsigned long parent_rate) | ||
| 305 | { | ||
| 306 | struct clk_rpmh *c = to_clk_rpmh(hw); | ||
| 307 | |||
| 308 | c->aggr_state = rate / c->unit; | ||
| 309 | /* | ||
| 310 | * Since any non-zero value sent to hw would result in enabling the | ||
| 311 | * clock, only send the value if the clock has already been prepared. | ||
| 312 | */ | ||
| 313 | if (clk_hw_is_prepared(hw)) | ||
| 314 | clk_rpmh_bcm_send_cmd(c, true); | ||
| 315 | |||
| 316 | return 0; | ||
| 317 | }; | ||
| 318 | |||
| 319 | static long clk_rpmh_round_rate(struct clk_hw *hw, unsigned long rate, | ||
| 320 | unsigned long *parent_rate) | ||
| 321 | { | ||
| 322 | return rate; | ||
| 323 | } | ||
| 324 | |||
| 325 | static unsigned long clk_rpmh_bcm_recalc_rate(struct clk_hw *hw, | ||
| 326 | unsigned long prate) | ||
| 327 | { | ||
| 328 | struct clk_rpmh *c = to_clk_rpmh(hw); | ||
| 329 | |||
| 330 | return c->aggr_state * c->unit; | ||
| 331 | } | ||
| 332 | |||
| 333 | static const struct clk_ops clk_rpmh_bcm_ops = { | ||
| 334 | .prepare = clk_rpmh_bcm_prepare, | ||
| 335 | .unprepare = clk_rpmh_bcm_unprepare, | ||
| 336 | .set_rate = clk_rpmh_bcm_set_rate, | ||
| 337 | .round_rate = clk_rpmh_round_rate, | ||
| 338 | .recalc_rate = clk_rpmh_bcm_recalc_rate, | ||
| 339 | }; | ||
| 340 | |||
| 213 | /* Resource name must match resource id present in cmd-db. */ | 341 | /* Resource name must match resource id present in cmd-db. */ |
| 214 | DEFINE_CLK_RPMH_ARC(sdm845, bi_tcxo, bi_tcxo_ao, "xo.lvl", 0x3, 2); | 342 | DEFINE_CLK_RPMH_ARC(sdm845, bi_tcxo, bi_tcxo_ao, "xo.lvl", 0x3, 2); |
| 215 | DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk2, ln_bb_clk2_ao, "lnbclka2", 2); | 343 | DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk2, ln_bb_clk2_ao, "lnbclka2", 2); |
| @@ -217,6 +345,7 @@ DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk3, ln_bb_clk3_ao, "lnbclka3", 2); | |||
| 217 | DEFINE_CLK_RPMH_VRM(sdm845, rf_clk1, rf_clk1_ao, "rfclka1", 1); | 345 | DEFINE_CLK_RPMH_VRM(sdm845, rf_clk1, rf_clk1_ao, "rfclka1", 1); |
| 218 | DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1); | 346 | DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1); |
| 219 | DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1); | 347 | DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1); |
| 348 | DEFINE_CLK_RPMH_BCM(sdm845, ipa, "IP0"); | ||
| 220 | 349 | ||
| 221 | static struct clk_hw *sdm845_rpmh_clocks[] = { | 350 | static struct clk_hw *sdm845_rpmh_clocks[] = { |
| 222 | [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, | 351 | [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, |
| @@ -231,6 +360,7 @@ static struct clk_hw *sdm845_rpmh_clocks[] = { | |||
| 231 | [RPMH_RF_CLK2_A] = &sdm845_rf_clk2_ao.hw, | 360 | [RPMH_RF_CLK2_A] = &sdm845_rf_clk2_ao.hw, |
| 232 | [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw, | 361 | [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw, |
| 233 | [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw, | 362 | [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw, |
| 363 | [RPMH_IPA_CLK] = &sdm845_ipa.hw, | ||
| 234 | }; | 364 | }; |
| 235 | 365 | ||
| 236 | static const struct clk_rpmh_desc clk_rpmh_sdm845 = { | 366 | static const struct clk_rpmh_desc clk_rpmh_sdm845 = { |
| @@ -267,6 +397,8 @@ static int clk_rpmh_probe(struct platform_device *pdev) | |||
| 267 | 397 | ||
| 268 | for (i = 0; i < desc->num_clks; i++) { | 398 | for (i = 0; i < desc->num_clks; i++) { |
| 269 | u32 res_addr; | 399 | u32 res_addr; |
| 400 | size_t aux_data_len; | ||
| 401 | const struct bcm_db *data; | ||
