rgb.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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 tegra_dc *dc;
  15. bool enabled;
  16. struct clk *clk_parent;
  17. struct clk *clk;
  18. };
  19. static inline struct tegra_rgb *to_rgb(struct tegra_output *output)
  20. {
  21. return container_of(output, struct tegra_rgb, output);
  22. }
  23. struct reg_entry {
  24. unsigned long offset;
  25. unsigned long value;
  26. };
  27. static const struct reg_entry rgb_enable[] = {
  28. { DC_COM_PIN_OUTPUT_ENABLE(0), 0x00000000 },
  29. { DC_COM_PIN_OUTPUT_ENABLE(1), 0x00000000 },
  30. { DC_COM_PIN_OUTPUT_ENABLE(2), 0x00000000 },
  31. { DC_COM_PIN_OUTPUT_ENABLE(3), 0x00000000 },
  32. { DC_COM_PIN_OUTPUT_POLARITY(0), 0x00000000 },
  33. { DC_COM_PIN_OUTPUT_POLARITY(1), 0x01000000 },
  34. { DC_COM_PIN_OUTPUT_POLARITY(2), 0x00000000 },
  35. { DC_COM_PIN_OUTPUT_POLARITY(3), 0x00000000 },
  36. { DC_COM_PIN_OUTPUT_DATA(0), 0x00000000 },
  37. { DC_COM_PIN_OUTPUT_DATA(1), 0x00000000 },
  38. { DC_COM_PIN_OUTPUT_DATA(2), 0x00000000 },
  39. { DC_COM_PIN_OUTPUT_DATA(3), 0x00000000 },
  40. { DC_COM_PIN_OUTPUT_SELECT(0), 0x00000000 },
  41. { DC_COM_PIN_OUTPUT_SELECT(1), 0x00000000 },
  42. { DC_COM_PIN_OUTPUT_SELECT(2), 0x00000000 },
  43. { DC_COM_PIN_OUTPUT_SELECT(3), 0x00000000 },
  44. { DC_COM_PIN_OUTPUT_SELECT(4), 0x00210222 },
  45. { DC_COM_PIN_OUTPUT_SELECT(5), 0x00002200 },
  46. { DC_COM_PIN_OUTPUT_SELECT(6), 0x00020000 },
  47. };
  48. static const struct reg_entry rgb_disable[] = {
  49. { DC_COM_PIN_OUTPUT_SELECT(6), 0x00000000 },
  50. { DC_COM_PIN_OUTPUT_SELECT(5), 0x00000000 },
  51. { DC_COM_PIN_OUTPUT_SELECT(4), 0x00000000 },
  52. { DC_COM_PIN_OUTPUT_SELECT(3), 0x00000000 },
  53. { DC_COM_PIN_OUTPUT_SELECT(2), 0x00000000 },
  54. { DC_COM_PIN_OUTPUT_SELECT(1), 0x00000000 },
  55. { DC_COM_PIN_OUTPUT_SELECT(0), 0x00000000 },
  56. { DC_COM_PIN_OUTPUT_DATA(3), 0xaaaaaaaa },
  57. { DC_COM_PIN_OUTPUT_DATA(2), 0xaaaaaaaa },
  58. { DC_COM_PIN_OUTPUT_DATA(1), 0xaaaaaaaa },
  59. { DC_COM_PIN_OUTPUT_DATA(0), 0xaaaaaaaa },
  60. { DC_COM_PIN_OUTPUT_POLARITY(3), 0x00000000 },
  61. { DC_COM_PIN_OUTPUT_POLARITY(2), 0x00000000 },
  62. { DC_COM_PIN_OUTPUT_POLARITY(1), 0x00000000 },
  63. { DC_COM_PIN_OUTPUT_POLARITY(0), 0x00000000 },
  64. { DC_COM_PIN_OUTPUT_ENABLE(3), 0x55555555 },
  65. { DC_COM_PIN_OUTPUT_ENABLE(2), 0x55555555 },
  66. { DC_COM_PIN_OUTPUT_ENABLE(1), 0x55150005 },
  67. { DC_COM_PIN_OUTPUT_ENABLE(0), 0x55555555 },
  68. };
  69. static void tegra_dc_write_regs(struct tegra_dc *dc,
  70. const struct reg_entry *table,
  71. unsigned int num)
  72. {
  73. unsigned int i;
  74. for (i = 0; i < num; i++)
  75. tegra_dc_writel(dc, table[i].value, table[i].offset);
  76. }
  77. static int tegra_output_rgb_enable(struct tegra_output *output)
  78. {
  79. struct tegra_rgb *rgb = to_rgb(output);
  80. unsigned long value;
  81. if (rgb->enabled)
  82. return 0;
  83. tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
  84. value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
  85. tegra_dc_writel(rgb->dc, value, DC_DISP_DATA_ENABLE_OPTIONS);
  86. /* XXX: parameterize? */
  87. value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(1));
  88. value &= ~LVS_OUTPUT_POLARITY_LOW;
  89. value &= ~LHS_OUTPUT_POLARITY_LOW;
  90. tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(1));
  91. /* XXX: parameterize? */
  92. value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB |
  93. DISP_ORDER_RED_BLUE;
  94. tegra_dc_writel(rgb->dc, value, DC_DISP_DISP_INTERFACE_CONTROL);
  95. /* XXX: parameterize? */
  96. value = SC0_H_QUALIFIER_NONE | SC1_H_QUALIFIER_NONE;
  97. tegra_dc_writel(rgb->dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);
  98. value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND);
  99. value &= ~DISP_CTRL_MODE_MASK;
  100. value |= DISP_CTRL_MODE_C_DISPLAY;
  101. tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND);
  102. value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
  103. value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
  104. PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
  105. tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
  106. tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
  107. tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
  108. rgb->enabled = true;
  109. return 0;
  110. }
  111. static int tegra_output_rgb_disable(struct tegra_output *output)
  112. {
  113. struct tegra_rgb *rgb = to_rgb(output);
  114. unsigned long value;
  115. if (!rgb->enabled)
  116. return 0;
  117. value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
  118. value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
  119. PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
  120. tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
  121. value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND);
  122. value &= ~DISP_CTRL_MODE_MASK;
  123. tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND);
  124. tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
  125. tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
  126. tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
  127. rgb->enabled = false;
  128. return 0;
  129. }
  130. static int tegra_output_rgb_setup_clock(struct tegra_output *output,
  131. struct clk *clk, unsigned long pclk)
  132. {
  133. struct tegra_rgb *rgb = to_rgb(output);
  134. return clk_set_parent(clk, rgb->clk_parent);
  135. }
  136. static int tegra_output_rgb_check_mode(struct tegra_output *output,
  137. struct drm_display_mode *mode,
  138. enum drm_mode_status *status)
  139. {
  140. /*
  141. * FIXME: For now, always assume that the mode is okay. There are
  142. * unresolved issues with clk_round_rate(), which doesn't always
  143. * reliably report whether a frequency can be set or not.
  144. */
  145. *status = MODE_OK;
  146. return 0;
  147. }
  148. static const struct tegra_output_ops rgb_ops = {
  149. .enable = tegra_output_rgb_enable,
  150. .disable = tegra_output_rgb_disable,
  151. .setup_clock = tegra_output_rgb_setup_clock,
  152. .check_mode = tegra_output_rgb_check_mode,
  153. };
  154. int tegra_dc_rgb_probe(struct tegra_dc *dc)
  155. {
  156. struct device_node *np;
  157. struct tegra_rgb *rgb;
  158. int err;
  159. np = of_get_child_by_name(dc->dev->of_node, "rgb");
  160. if (!np || !of_device_is_available(np))
  161. return -ENODEV;
  162. rgb = devm_kzalloc(dc->dev, sizeof(*rgb), GFP_KERNEL);
  163. if (!rgb)
  164. return -ENOMEM;
  165. rgb->output.dev = dc->dev;
  166. rgb->output.of_node = np;
  167. rgb->dc = dc;
  168. err = tegra_output_probe(&rgb->output);
  169. if (err < 0)
  170. return err;
  171. rgb->clk = devm_clk_get(dc->dev, NULL);
  172. if (IS_ERR(rgb->clk)) {
  173. dev_err(dc->dev, "failed to get clock\n");
  174. return PTR_ERR(rgb->clk);
  175. }
  176. rgb->clk_parent = devm_clk_get(dc->dev, "parent");
  177. if (IS_ERR(rgb->clk_parent)) {
  178. dev_err(dc->dev, "failed to get parent clock\n");
  179. return PTR_ERR(rgb->clk_parent);
  180. }
  181. err = clk_set_parent(rgb->clk, rgb->clk_parent);
  182. if (err < 0) {
  183. dev_err(dc->dev, "failed to set parent clock: %d\n", err);
  184. return err;
  185. }
  186. dc->rgb = &rgb->output;
  187. return 0;
  188. }
  189. int tegra_dc_rgb_remove(struct tegra_dc *dc)
  190. {
  191. int err;
  192. if (!dc->rgb)
  193. return 0;
  194. err = tegra_output_remove(dc->rgb);
  195. if (err < 0)
  196. return err;
  197. return 0;
  198. }
  199. int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc)
  200. {
  201. struct tegra_rgb *rgb = to_rgb(dc->rgb);
  202. int err;
  203. if (!dc->rgb)
  204. return -ENODEV;
  205. rgb->output.type = TEGRA_OUTPUT_RGB;
  206. rgb->output.ops = &rgb_ops;
  207. err = tegra_output_init(dc->base.dev, &rgb->output);
  208. if (err < 0) {
  209. dev_err(dc->dev, "output setup failed: %d\n", err);
  210. return err;
  211. }
  212. /*
  213. * By default, outputs can be associated with each display controller.
  214. * RGB outputs are an exception, so we make sure they can be attached
  215. * to only their parent display controller.
  216. */
  217. rgb->output.encoder.possible_crtcs = drm_crtc_mask(&dc->base);
  218. return 0;
  219. }
  220. int tegra_dc_rgb_exit(struct tegra_dc *dc)
  221. {
  222. if (dc->rgb) {
  223. int err;
  224. err = tegra_output_disable(dc->rgb);
  225. if (err < 0) {
  226. dev_err(dc->dev, "output failed to disable: %d\n", err);
  227. return err;
  228. }
  229. err = tegra_output_exit(dc->rgb);
  230. if (err < 0) {
  231. dev_err(dc->dev, "output cleanup failed: %d\n", err);
  232. return err;
  233. }
  234. dc->rgb = NULL;
  235. }
  236. return 0;
  237. }