dp_pll.c 3.9 KB

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