rgb.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Copyright (C) 2012 Avionic Design GmbH
  3. * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. */
  9. #include <linux/clk.h>
  10. #include "drm.h"
  11. #include "dc.h"
  12. struct tegra_rgb {
  13. struct tegra_output output;
  14. struct clk *clk_parent;
  15. struct clk *clk;
  16. };
  17. static inline struct tegra_rgb *to_rgb(struct tegra_output *output)
  18. {
  19. return container_of(output, struct tegra_rgb, output);
  20. }
  21. struct reg_entry {
  22. unsigned long offset;
  23. unsigned long value;
  24. };
  25. static const struct reg_entry rgb_enable[] = {
  26. { DC_COM_PIN_OUTPUT_ENABLE(0), 0x00000000 },
  27. { DC_COM_PIN_OUTPUT_ENABLE(1), 0x00000000 },
  28. { DC_COM_PIN_OUTPUT_ENABLE(2), 0x00000000 },
  29. { DC_COM_PIN_OUTPUT_ENABLE(3), 0x00000000 },
  30. { DC_COM_PIN_OUTPUT_POLARITY(0), 0x00000000 },
  31. { DC_COM_PIN_OUTPUT_POLARITY(1), 0x01000000 },
  32. { DC_COM_PIN_OUTPUT_POLARITY(2), 0x00000000 },
  33. { DC_COM_PIN_OUTPUT_POLARITY(3), 0x00000000 },
  34. { DC_COM_PIN_OUTPUT_DATA(0), 0x00000000 },
  35. { DC_COM_PIN_OUTPUT_DATA(1), 0x00000000 },
  36. { DC_COM_PIN_OUTPUT_DATA(2), 0x00000000 },
  37. { DC_COM_PIN_OUTPUT_DATA(3), 0x00000000 },
  38. { DC_COM_PIN_OUTPUT_SELECT(0), 0x00000000 },
  39. { DC_COM_PIN_OUTPUT_SELECT(1), 0x00000000 },
  40. { DC_COM_PIN_OUTPUT_SELECT(2), 0x00000000 },
  41. { DC_COM_PIN_OUTPUT_SELECT(3), 0x00000000 },
  42. { DC_COM_PIN_OUTPUT_SELECT(4), 0x00210222 },
  43. { DC_COM_PIN_OUTPUT_SELECT(5), 0x00002200 },
  44. { DC_COM_PIN_OUTPUT_SELECT(6), 0x00020000 },
  45. };
  46. static const struct reg_entry rgb_disable[] = {
  47. { DC_COM_PIN_OUTPUT_SELECT(6), 0x00000000 },
  48. { DC_COM_PIN_OUTPUT_SELECT(5), 0x00000000 },
  49. { DC_COM_PIN_OUTPUT_SELECT(4), 0x00000000 },
  50. { DC_COM_PIN_OUTPUT_SELECT(3), 0x00000000 },
  51. { DC_COM_PIN_OUTPUT_SELECT(2), 0x00000000 },
  52. { DC_COM_PIN_OUTPUT_SELECT(1), 0x00000000 },
  53. { DC_COM_PIN_OUTPUT_SELECT(0), 0x00000000 },
  54. { DC_COM_PIN_OUTPUT_DATA(3), 0xaaaaaaaa },
  55. { DC_COM_PIN_OUTPUT_DATA(2), 0xaaaaaaaa },
  56. { DC_COM_PIN_OUTPUT_DATA(1), 0xaaaaaaaa },
  57. { DC_COM_PIN_OUTPUT_DATA(0), 0xaaaaaaaa },
  58. { DC_COM_PIN_OUTPUT_POLARITY(3), 0x00000000 },
  59. { DC_COM_PIN_OUTPUT_POLARITY(2), 0x00000000 },
  60. { DC_COM_PIN_OUTPUT_POLARITY(1), 0x00000000 },
  61. { DC_COM_PIN_OUTPUT_POLARITY(0), 0x00000000 },
  62. { DC_COM_PIN_OUTPUT_ENABLE(3), 0x55555555 },
  63. { DC_COM_PIN_OUTPUT_ENABLE(2), 0x55555555 },
  64. { DC_COM_PIN_OUTPUT_ENABLE(1), 0x55150005 },
  65. { DC_COM_PIN_OUTPUT_ENABLE(0), 0x55555555 },
  66. };
  67. static void tegra_dc_write_regs(struct tegra_dc *dc,
  68. const struct reg_entry *table,
  69. unsigned int num)
  70. {
  71. unsigned int i;
  72. for (i = 0; i < num; i++)
  73. tegra_dc_writel(dc, table[i].value, table[i].offset);
  74. }
  75. static int tegra_output_rgb_enable(struct tegra_output *output)
  76. {
  77. struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
  78. tegra_dc_write_regs(dc, rgb_enable, ARRAY_SIZE(rgb_enable));
  79. return 0;
  80. }
  81. static int tegra_output_rgb_disable(struct tegra_output *output)
  82. {
  83. struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
  84. tegra_dc_write_regs(dc, rgb_disable, ARRAY_SIZE(rgb_disable));
  85. return 0;
  86. }
  87. static int tegra_output_rgb_setup_clock(struct tegra_output *output,
  88. struct clk *clk, unsigned long pclk)
  89. {
  90. struct tegra_rgb *rgb = to_rgb(output);
  91. return clk_set_parent(clk, rgb->clk_parent);
  92. }
  93. static int tegra_output_rgb_check_mode(struct tegra_output *output,
  94. struct drm_display_mode *mode,
  95. enum drm_mode_status *status)
  96. {
  97. /*
  98. * FIXME: For now, always assume that the mode is okay. There are
  99. * unresolved issues with clk_round_rate(), which doesn't always
  100. * reliably report whether a frequency can be set or not.
  101. */
  102. *status = MODE_OK;
  103. return 0;
  104. }
  105. static const struct tegra_output_ops rgb_ops = {
  106. .enable = tegra_output_rgb_enable,
  107. .disable = tegra_output_rgb_disable,
  108. .setup_clock = tegra_output_rgb_setup_clock,
  109. .check_mode = tegra_output_rgb_check_mode,
  110. };
  111. int tegra_dc_rgb_probe(struct tegra_dc *dc)
  112. {
  113. struct device_node *np;
  114. struct tegra_rgb *rgb;
  115. int err;
  116. np = of_get_child_by_name(dc->dev->of_node, "rgb");
  117. if (!np || !of_device_is_available(np))
  118. return -ENODEV;
  119. rgb = devm_kzalloc(dc->dev, sizeof(*rgb), GFP_KERNEL);
  120. if (!rgb)
  121. return -ENOMEM;
  122. rgb->output.dev = dc->dev;
  123. rgb->output.of_node = np;
  124. err = tegra_output_probe(&rgb->output);
  125. if (err < 0)
  126. return err;
  127. rgb->clk = devm_clk_get(dc->dev, NULL);
  128. if (IS_ERR(rgb->clk)) {
  129. dev_err(dc->dev, "failed to get clock\n");
  130. return PTR_ERR(rgb->clk);
  131. }
  132. rgb->clk_parent = devm_clk_get(dc->dev, "parent");
  133. if (IS_ERR(rgb->clk_parent)) {
  134. dev_err(dc->dev, "failed to get parent clock\n");
  135. return PTR_ERR(rgb->clk_parent);
  136. }
  137. err = clk_set_parent(rgb->clk, rgb->clk_parent);
  138. if (err < 0) {
  139. dev_err(dc->dev, "failed to set parent clock: %d\n", err);
  140. return err;
  141. }
  142. dc->rgb = &rgb->output;
  143. return 0;
  144. }
  145. int tegra_dc_rgb_remove(struct tegra_dc *dc)
  146. {
  147. int err;
  148. if (!dc->rgb)
  149. return 0;
  150. err = tegra_output_remove(dc->rgb);
  151. if (err < 0)
  152. return err;
  153. return 0;
  154. }
  155. int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc)
  156. {
  157. struct tegra_rgb *rgb = to_rgb(dc->rgb);
  158. int err;
  159. if (!dc->rgb)
  160. return -ENODEV;
  161. rgb->output.type = TEGRA_OUTPUT_RGB;
  162. rgb->output.ops = &rgb_ops;
  163. err = tegra_output_init(dc->base.dev, &rgb->output);
  164. if (err < 0) {
  165. dev_err(dc->dev, "output setup failed: %d\n", err);
  166. return err;
  167. }
  168. /*
  169. * By default, outputs can be associated with each display controller.
  170. * RGB outputs are an exception, so we make sure they can be attached
  171. * to only their parent display controller.
  172. */
  173. rgb->output.encoder.possible_crtcs = 1 << dc->pipe;
  174. return 0;
  175. }
  176. int tegra_dc_rgb_exit(struct tegra_dc *dc)
  177. {
  178. if (dc->rgb) {
  179. int err;
  180. err = tegra_output_disable(dc->rgb);
  181. if (err < 0) {
  182. dev_err(dc->dev, "output failed to disable: %d\n", err);
  183. return err;
  184. }
  185. err = tegra_output_exit(dc->rgb);
  186. if (err < 0) {
  187. dev_err(dc->dev, "output cleanup failed: %d\n", err);
  188. return err;
  189. }
  190. dc->rgb = NULL;
  191. }
  192. return 0;
  193. }