dp_pll.c 3.7 KB

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