diff options
| -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; | ||
| 270 | 402 | ||
| 271 | rpmh_clk = to_clk_rpmh(hw_clks[i]); | 403 | rpmh_clk = to_clk_rpmh(hw_clks[i]); |
| 272 | res_addr = cmd_db_read_addr(rpmh_clk->res_name); | 404 | res_addr = cmd_db_read_addr(rpmh_clk->res_name); |
| @@ -275,6 +407,20 @@ static int clk_rpmh_probe(struct platform_device *pdev) | |||
| 275 | rpmh_clk->res_name); | 407 | rpmh_clk->res_name); |
| 276 | return -ENODEV; | 408 | return -ENODEV; |
| 277 | } | 409 | } |
| 410 | |||
| 411 | data = cmd_db_read_aux_data(rpmh_clk->res_name, &aux_data_len); | ||
| 412 | if (IS_ERR(data)) { | ||
| 413 | ret = PTR_ERR(data); | ||
| 414 | dev_err(&pdev->dev, | ||
| 415 | "error reading RPMh aux data for %s (%d)\n", | ||
| 416 | rpmh_clk->res_name, ret); | ||
| 417 | return ret; | ||
| 418 | } | ||
| 419 | |||
| 420 | /* Convert unit from Khz to Hz */ | ||
| 421 | if (aux_data_len == sizeof(*data)) | ||
| 422 | rpmh_clk->unit = le32_to_cpu(data->unit) * 1000ULL; | ||
| 423 | |||
| 278 | rpmh_clk->res_addr += res_addr; | 424 | rpmh_clk->res_addr += res_addr; |
| 279 | rpmh_clk->dev = &pdev->dev; | 425 | rpmh_clk->dev = &pdev->dev; |
| 280 | 426 | ||
diff --git a/include/dt-bindings/clock/qcom,rpmh.h b/include/dt-bindings/clock/qcom,rpmh.h index f48fbd6f2095..edcab3f7b7d3 100644 --- a/include/dt-bindings/clock/qcom,rpmh.h +++ b/include/dt-bindings/clock/qcom,rpmh.h | |||
| @@ -18,5 +18,6 @@ | |||
| 18 | #define RPMH_RF_CLK2_A 9 | 18 | #define RPMH_RF_CLK2_A 9 |
| 19 | #define RPMH_RF_CLK3 10 | 19 | #define RPMH_RF_CLK3 10 |
| 20 | #define RPMH_RF_CLK3_A 11 | 20 | #define RPMH_RF_CLK3_A 11 |
| 21 | #define RPMH_IPA_CLK 12 | ||
| 21 | 22 | ||
| 22 | #endif | 23 | #endif |
