armada_510.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2012 Russell King
  4. *
  5. * Armada 510 (aka Dove) variant support
  6. */
  7. #include <linux/clk.h>
  8. #include <linux/io.h>
  9. #include <linux/of.h>
  10. #include <drm/drm_probe_helper.h>
  11. #include "armada_crtc.h"
  12. #include "armada_drm.h"
  13. #include "armada_hw.h"
  14. struct armada510_variant_data {
  15. struct clk *clks[4];
  16. struct clk *sel_clk;
  17. };
  18. static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
  19. {
  20. struct armada510_variant_data *v;
  21. struct clk *clk;
  22. int idx;
  23. v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL);
  24. if (!v)
  25. return -ENOMEM;
  26. dcrtc->variant_data = v;
  27. if (dev->of_node) {
  28. struct property *prop;
  29. const char *s;
  30. of_property_for_each_string(dev->of_node, "clock-names", prop,
  31. s) {
  32. if (!strcmp(s, "ext_ref_clk0"))
  33. idx = 0;
  34. else if (!strcmp(s, "ext_ref_clk1"))
  35. idx = 1;
  36. else if (!strcmp(s, "plldivider"))
  37. idx = 2;
  38. else if (!strcmp(s, "axibus"))
  39. idx = 3;
  40. else
  41. continue;
  42. clk = devm_clk_get(dev, s);
  43. if (IS_ERR(clk))
  44. return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
  45. PTR_ERR(clk);
  46. v->clks[idx] = clk;
  47. }
  48. } else {
  49. clk = devm_clk_get(dev, "ext_ref_clk1");
  50. if (IS_ERR(clk))
  51. return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER :
  52. PTR_ERR(clk);
  53. v->clks[1] = clk;
  54. }
  55. /*
  56. * Lower the watermark so to eliminate jitter at higher bandwidths.
  57. * Disable SRAM read wait state to avoid system hang with external
  58. * clock.
  59. */
  60. armada_updatel(CFG_DMA_WM(0x20), CFG_SRAM_WAIT | CFG_DMA_WM_MASK,
  61. dcrtc->base + LCD_CFG_RDREG4F);
  62. /* Initialise SPU register */
  63. writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
  64. dcrtc->base + LCD_SPU_ADV_REG);
  65. return 0;
  66. }
  67. static const u32 armada510_clk_sels[] = {
  68. SCLK_510_EXTCLK0,
  69. SCLK_510_EXTCLK1,
  70. SCLK_510_PLL,
  71. SCLK_510_AXI,
  72. };
  73. static const struct armada_clocking_params armada510_clocking = {
  74. /* HDMI requires -0.6%..+0.5% */
  75. .permillage_min = 994,
  76. .permillage_max = 1005,
  77. .settable = BIT(0) | BIT(1),
  78. .div_max = SCLK_510_INT_DIV_MASK,
  79. };
  80. /*
  81. * Armada510 specific SCLK register selection.
  82. * This gets called with sclk = NULL to test whether the mode is
  83. * supportable, and again with sclk != NULL to set the clocks up for
  84. * that. The former can return an error, but the latter is expected
  85. * not to.
  86. */
  87. static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
  88. const struct drm_display_mode *mode, uint32_t *sclk)
  89. {
  90. struct armada510_variant_data *v = dcrtc->variant_data;
  91. unsigned long desired_khz = mode->crtc_clock;
  92. struct armada_clk_result res;
  93. int ret, idx;
  94. idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking,
  95. v->clks, ARRAY_SIZE(v->clks),
  96. desired_khz);
  97. if (idx < 0)
  98. return idx;
  99. ret = clk_prepare_enable(res.clk);
  100. if (ret)
  101. return ret;
  102. if (sclk) {
  103. clk_set_rate(res.clk, res.desired_clk_hz);
  104. *sclk = res.div | armada510_clk_sels[idx];
  105. /* We are now using this clock */
  106. v->sel_clk = res.clk;
  107. swap(dcrtc->clk, res.clk);
  108. }
  109. clk_disable_unprepare(res.clk);
  110. return 0;
  111. }
  112. static void armada510_crtc_disable(struct armada_crtc *dcrtc)
  113. {
  114. if (dcrtc->clk) {
  115. clk_disable_unprepare(dcrtc->clk);
  116. dcrtc->clk = NULL;
  117. }
  118. }
  119. static void armada510_crtc_enable(struct armada_crtc *dcrtc,
  120. const struct drm_display_mode *mode)
  121. {
  122. struct armada510_variant_data *v = dcrtc->variant_data;
  123. if (!dcrtc->clk && v->sel_clk) {
  124. if (!WARN_ON(clk_prepare_enable(v->sel_clk)))
  125. dcrtc->clk = v->sel_clk;
  126. }
  127. }
  128. const struct armada_variant armada510_ops = {
  129. .has_spu_adv_reg = true,
  130. .init = armada510_crtc_init,
  131. .compute_clock = armada510_crtc_compute_clock,
  132. .disable = armada510_crtc_disable,
  133. .enable = armada510_crtc_enable,
  134. };