diff options
author | Andy Gross <andy.gross@linaro.org> | 2018-09-30 13:44:18 -0400 |
---|---|---|
committer | Andy Gross <andy.gross@linaro.org> | 2018-09-30 13:44:18 -0400 |
commit | bbd4b28bb8f65fc7347202f32ac82901201ac02f (patch) | |
tree | c962261e4e443b776653771b5e34405c5d6073c7 | |
parent | 5b394b2ddf0347bef56e50c69a58773c94343ff3 (diff) | |
parent | 969fc78c37c3fb1363b4669a7d4df9c3804591e7 (diff) |
Merge tag 'qcom-geni-immutable-for-mark-brown' into drivers-for-4.20-final
Immutable branch for QCOM Geni patches
-rw-r--r-- | drivers/soc/qcom/qcom-geni-se.c | 41 | ||||
-rw-r--r-- | include/linux/qcom-geni-se.h | 13 |
2 files changed, 28 insertions, 26 deletions
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index feed3db21c10..ee89ffb6dde8 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c | |||
@@ -513,7 +513,7 @@ EXPORT_SYMBOL(geni_se_resources_on); | |||
513 | */ | 513 | */ |
514 | int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) | 514 | int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) |
515 | { | 515 | { |
516 | unsigned long freq = 0; | 516 | long freq = 0; |
517 | int i; | 517 | int i; |
518 | 518 | ||
519 | if (se->clk_perf_tbl) { | 519 | if (se->clk_perf_tbl) { |
@@ -529,7 +529,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) | |||
529 | 529 | ||
530 | for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { | 530 | for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { |
531 | freq = clk_round_rate(se->clk, freq + 1); | 531 | freq = clk_round_rate(se->clk, freq + 1); |
532 | if (!freq || freq == se->clk_perf_tbl[i - 1]) | 532 | if (freq <= 0 || freq == se->clk_perf_tbl[i - 1]) |
533 | break; | 533 | break; |
534 | se->clk_perf_tbl[i] = freq; | 534 | se->clk_perf_tbl[i] = freq; |
535 | } | 535 | } |
@@ -544,16 +544,17 @@ EXPORT_SYMBOL(geni_se_clk_tbl_get); | |||
544 | * @se: Pointer to the concerned serial engine. | 544 | * @se: Pointer to the concerned serial engine. |
545 | * @req_freq: Requested clock frequency. | 545 | * @req_freq: Requested clock frequency. |
546 | * @index: Index of the resultant frequency in the table. | 546 | * @index: Index of the resultant frequency in the table. |
547 | * @res_freq: Resultant frequency which matches or is closer to the | 547 | * @res_freq: Resultant frequency of the source clock. |
548 | * requested frequency. | ||
549 | * @exact: Flag to indicate exact multiple requirement of the requested | 548 | * @exact: Flag to indicate exact multiple requirement of the requested |
550 | * frequency. | 549 | * frequency. |
551 | * | 550 | * |
552 | * This function is called by the protocol drivers to determine the matching | 551 | * This function is called by the protocol drivers to determine the best match |
553 | * or exact multiple of the requested frequency, as provided by the serial | 552 | * of the requested frequency as provided by the serial engine clock in order |
554 | * engine clock in order to meet the performance requirements. If there is | 553 | * to meet the performance requirements. |
555 | * no matching or exact multiple of the requested frequency found, then it | 554 | * |
556 | * selects the closest floor frequency, if exact flag is not set. | 555 | * If we return success: |
556 | * - if @exact is true then @res_freq / <an_integer> == @req_freq | ||
557 | * - if @exact is false then @res_freq / <an_integer> <= @req_freq | ||
557 | * | 558 | * |
558 | * Return: 0 on success, standard Linux error codes on failure. | 559 | * Return: 0 on success, standard Linux error codes on failure. |
559 | */ | 560 | */ |
@@ -564,6 +565,9 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, | |||
564 | unsigned long *tbl; | 565 | unsigned long *tbl; |
565 | int num_clk_levels; | 566 | int num_clk_levels; |
566 | int i; | 567 | int i; |
568 | unsigned long best_delta; | ||
569 | unsigned long new_delta; | ||
570 | unsigned int divider; | ||
567 | 571 | ||
568 | num_clk_levels = geni_se_clk_tbl_get(se, &tbl); | 572 | num_clk_levels = geni_se_clk_tbl_get(se, &tbl); |
569 | if (num_clk_levels < 0) | 573 | if (num_clk_levels < 0) |
@@ -572,18 +576,21 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, | |||
572 | if (num_clk_levels == 0) | 576 | if (num_clk_levels == 0) |
573 | return -EINVAL; | 577 | return -EINVAL; |
574 | 578 | ||
575 | *res_freq = 0; | 579 | best_delta = ULONG_MAX; |
576 | for (i = 0; i < num_clk_levels; i++) { | 580 | for (i = 0; i < num_clk_levels; i++) { |
577 | if (!(tbl[i] % req_freq)) { | 581 | divider = DIV_ROUND_UP(tbl[i], req_freq); |
582 | new_delta = req_freq - tbl[i] / divider; | ||
583 | if (new_delta < best_delta) { | ||
584 | /* We have a new best! */ | ||
578 | *index = i; | 585 | *index = i; |
579 | *res_freq = tbl[i]; | 586 | *res_freq = tbl[i]; |
580 | return 0; | ||
581 | } | ||
582 | 587 | ||
583 | if (!(*res_freq) || ((tbl[i] > *res_freq) && | 588 | /* If the new best is exact then we're done */ |
584 | (tbl[i] < req_freq))) { | 589 | if (new_delta == 0) |
585 | *index = i; | 590 | return 0; |
586 | *res_freq = tbl[i]; | 591 | |
592 | /* Record how close we got */ | ||
593 | best_delta = new_delta; | ||
587 | } | 594 | } |
588 | } | 595 | } |
589 | 596 | ||
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h index 5d6144977828..3bcd67fd5548 100644 --- a/include/linux/qcom-geni-se.h +++ b/include/linux/qcom-geni-se.h | |||
@@ -225,19 +225,14 @@ struct geni_se { | |||
225 | #define HW_VER_MINOR_SHFT 16 | 225 | #define HW_VER_MINOR_SHFT 16 |
226 | #define HW_VER_STEP_MASK GENMASK(15, 0) | 226 | #define HW_VER_STEP_MASK GENMASK(15, 0) |
227 | 227 | ||
228 | #define GENI_SE_VERSION_MAJOR(ver) ((ver & HW_VER_MAJOR_MASK) >> HW_VER_MAJOR_SHFT) | ||
229 | #define GENI_SE_VERSION_MINOR(ver) ((ver & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT) | ||
230 | #define GENI_SE_VERSION_STEP(ver) (ver & HW_VER_STEP_MASK) | ||
231 | |||
228 | #if IS_ENABLED(CONFIG_QCOM_GENI_SE) | 232 | #if IS_ENABLED(CONFIG_QCOM_GENI_SE) |
229 | 233 | ||
230 | u32 geni_se_get_qup_hw_version(struct geni_se *se); | 234 | u32 geni_se_get_qup_hw_version(struct geni_se *se); |
231 | 235 | ||
232 | #define geni_se_get_wrapper_version(se, major, minor, step) do { \ | ||
233 | u32 ver; \ | ||
234 | \ | ||
235 | ver = geni_se_get_qup_hw_version(se); \ | ||
236 | major = (ver & HW_VER_MAJOR_MASK) >> HW_VER_MAJOR_SHFT; \ | ||
237 | minor = (ver & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT; \ | ||
238 | step = version & HW_VER_STEP_MASK; \ | ||
239 | } while (0) | ||
240 | |||
241 | /** | 236 | /** |
242 | * geni_se_read_proto() - Read the protocol configured for a serial engine | 237 | * geni_se_read_proto() - Read the protocol configured for a serial engine |
243 | * @se: Pointer to the concerned serial engine. | 238 | * @se: Pointer to the concerned serial engine. |