dp_pll.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/err.h>
  7. #include <linux/of_device.h>
  8. #include "dp_debug.h"
  9. #include "dp_pll.h"
  10. static int dp_pll_fill_io(struct dp_pll *pll)
  11. {
  12. struct dp_parser *parser = pll->parser;
  13. pll->io.dp_phy = parser->get_io(parser, "dp_phy");
  14. if (!pll->io.dp_phy) {
  15. DP_ERR("Invalid dp_phy resource\n");
  16. return -ENOMEM;
  17. }
  18. pll->io.dp_pll = parser->get_io(parser, "dp_pll");
  19. if (!pll->io.dp_pll) {
  20. DP_ERR("Invalid dp_pll resource\n");
  21. return -ENOMEM;
  22. }
  23. pll->io.dp_ln_tx0 = parser->get_io(parser, "dp_ln_tx0");
  24. if (!pll->io.dp_ln_tx0) {
  25. DP_ERR("Invalid dp_ln_tx1 resource\n");
  26. return -ENOMEM;
  27. }
  28. pll->io.dp_ln_tx1 = parser->get_io(parser, "dp_ln_tx1");
  29. if (!pll->io.dp_ln_tx1) {
  30. DP_ERR("Invalid dp_ln_tx1 resource\n");
  31. return -ENOMEM;
  32. }
  33. pll->io.gdsc = parser->get_io(parser, "gdsc");
  34. if (!pll->io.gdsc) {
  35. DP_ERR("Invalid gdsc resource\n");
  36. return -ENOMEM;
  37. }
  38. return 0;
  39. }
  40. static int dp_pll_clock_register(struct dp_pll *pll)
  41. {
  42. int rc;
  43. switch (pll->revision) {
  44. case DP_PLL_5NM_V1:
  45. case DP_PLL_5NM_V2:
  46. rc = dp_pll_clock_register_5nm(pll);
  47. break;
  48. case DP_PLL_4NM_V1:
  49. case DP_PLL_4NM_V1_1:
  50. rc = dp_pll_clock_register_4nm(pll);
  51. break;
  52. default:
  53. rc = -ENOTSUPP;
  54. break;
  55. }
  56. return rc;
  57. }
  58. static void dp_pll_clock_unregister(struct dp_pll *pll)
  59. {
  60. switch (pll->revision) {
  61. case DP_PLL_5NM_V1:
  62. case DP_PLL_5NM_V2:
  63. dp_pll_clock_unregister_5nm(pll);
  64. break;
  65. case DP_PLL_4NM_V1:
  66. case DP_PLL_4NM_V1_1:
  67. dp_pll_clock_unregister_4nm(pll);
  68. break;
  69. default:
  70. break;
  71. }
  72. }
  73. int dp_pll_clock_register_helper(struct dp_pll *pll, struct dp_pll_vco_clk *clks, int num_clks)
  74. {
  75. int rc = 0, i = 0;
  76. struct platform_device *pdev;
  77. struct clk *clk;
  78. if (!pll || !clks) {
  79. DP_ERR("input not initialized\n");
  80. return -EINVAL;
  81. }
  82. pdev = pll->pdev;
  83. for (i = 0; i < num_clks; i++) {
  84. clks[i].priv = pll;
  85. clk = clk_register(&pdev->dev, &clks[i].hw);
  86. if (IS_ERR(clk)) {
  87. DP_ERR("%s registration failed for DP: %d\n",
  88. clk_hw_get_name(&clks[i].hw), pll->index);
  89. return -EINVAL;
  90. }
  91. pll->clk_data->clks[i] = clk;
  92. }
  93. return rc;
  94. }
  95. struct dp_pll *dp_pll_get(struct dp_pll_in *in)
  96. {
  97. int rc = 0;
  98. struct dp_pll *pll;
  99. struct dp_parser *parser;
  100. const char *label = NULL;
  101. struct platform_device *pdev;
  102. if (!in || !in->pdev || !in->pdev->dev.of_node || !in->parser) {
  103. DP_ERR("Invalid resource pointers\n");
  104. return ERR_PTR(-EINVAL);
  105. }
  106. pll = kzalloc(sizeof(*pll), GFP_KERNEL);
  107. if (!pll)
  108. return ERR_PTR(-ENOMEM);
  109. pll->pdev = in->pdev;
  110. pll->parser = in->parser;
  111. pll->aux = in->aux;
  112. pll->dp_core_revision = in->dp_core_revision;
  113. parser = pll->parser;
  114. pdev = pll->pdev;
  115. label = of_get_property(pdev->dev.of_node, "qcom,pll-revision", NULL);
  116. if (label) {
  117. if (!strcmp(label, "5nm-v1")) {
  118. pll->revision = DP_PLL_5NM_V1;
  119. } else if (!strcmp(label, "5nm-v2")) {
  120. pll->revision = DP_PLL_5NM_V2;
  121. } else if (!strcmp(label, "4nm-v1")) {
  122. pll->revision = DP_PLL_4NM_V1;
  123. } else if (!strcmp(label, "4nm-v1.1")) {
  124. pll->revision = DP_PLL_4NM_V1_1;
  125. } else {
  126. DP_ERR("Unsupported pll revision\n");
  127. rc = -ENOTSUPP;
  128. goto error;
  129. }
  130. } else {
  131. DP_ERR("pll revision not specified\n");
  132. rc = -EINVAL;
  133. goto error;
  134. }
  135. pll->ssc_en = of_property_read_bool(pdev->dev.of_node,
  136. "qcom,ssc-feature-enable");
  137. pll->bonding_en = of_property_read_bool(pdev->dev.of_node,
  138. "qcom,bonding-feature-enable");
  139. rc = dp_pll_fill_io(pll);
  140. if (rc)
  141. goto error;
  142. rc = dp_pll_clock_register(pll);
  143. if (rc)
  144. goto error;
  145. DP_INFO("revision=%s, ssc_en=%d, bonding_en=%d\n",
  146. dp_pll_get_revision(pll->revision), pll->ssc_en,
  147. pll->bonding_en);
  148. return pll;
  149. error:
  150. kfree(pll);
  151. return ERR_PTR(rc);
  152. }
  153. void dp_pll_put(struct dp_pll *pll)
  154. {
  155. dp_pll_clock_unregister(pll);
  156. kfree(pll);
  157. }