/drivers/video/tegra/dc/mode.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t · C · 318 lines · 217 code · 57 blank · 44 comment · 38 complexity · 18f7472e71468303ee73fdf8e041c38f MD5 · raw file

  1. /*
  2. * drivers/video/tegra/dc/mode.c
  3. *
  4. * Copyright (C) 2010 Google, Inc.
  5. *
  6. * Copyright (c) 2010-2012, NVIDIA CORPORATION, All rights reserved.
  7. *
  8. * This software is licensed under the terms of the GNU General Public
  9. * License version 2, as published by the Free Software Foundation, and
  10. * may be copied, distributed, and modified under those terms.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. */
  18. #include <linux/err.h>
  19. #include <linux/types.h>
  20. #include <linux/clk.h>
  21. #include <mach/clk.h>
  22. #include <mach/dc.h>
  23. #include "dc_reg.h"
  24. #include "dc_priv.h"
  25. /* return non-zero if constraint is violated */
  26. static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href)
  27. {
  28. long a, b;
  29. /* Constraint 5: H_REF_TO_SYNC >= 0 */
  30. a = 0;
  31. /* Constraint 6: H_FRONT_PORT >= (H_REF_TO_SYNC + 1) */
  32. b = mode->h_front_porch - 1;
  33. /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11 */
  34. if (a + mode->h_sync_width + mode->h_back_porch <= 11)
  35. a = 1 + 11 - mode->h_sync_width - mode->h_back_porch;
  36. /* check Constraint 1 and 6 */
  37. if (a > b)
  38. return 1;
  39. /* Constraint 4: H_SYNC_WIDTH >= 1 */
  40. if (mode->h_sync_width < 1)
  41. return 4;
  42. /* Constraint 7: H_DISP_ACTIVE >= 16 */
  43. if (mode->h_active < 16)
  44. return 7;
  45. if (href) {
  46. if (b > a && a % 2)
  47. *href = a + 1; /* use smallest even value */
  48. else
  49. *href = a; /* even or only possible value */
  50. }
  51. return 0;
  52. }
  53. static int calc_v_ref_to_sync(const struct tegra_dc_mode *mode, int *vref)
  54. {
  55. long a;
  56. a = 1; /* Constraint 5: V_REF_TO_SYNC >= 1 */
  57. /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1 */
  58. if (a + mode->v_sync_width + mode->v_back_porch <= 1)
  59. a = 1 + 1 - mode->v_sync_width - mode->v_back_porch;
  60. /* Constraint 6 */
  61. if (mode->v_front_porch < a + 1)
  62. a = mode->v_front_porch - 1;
  63. /* Constraint 4: V_SYNC_WIDTH >= 1 */
  64. if (mode->v_sync_width < 1)
  65. return 4;
  66. /* Constraint 7: V_DISP_ACTIVE >= 16 */
  67. if (mode->v_active < 16)
  68. return 7;
  69. if (vref)
  70. *vref = a;
  71. return 0;
  72. }
  73. static int calc_ref_to_sync(struct tegra_dc_mode *mode)
  74. {
  75. int ret;
  76. ret = calc_h_ref_to_sync(mode, &mode->h_ref_to_sync);
  77. if (ret)
  78. return ret;
  79. ret = calc_v_ref_to_sync(mode, &mode->v_ref_to_sync);
  80. if (ret)
  81. return ret;
  82. return 0;
  83. }
  84. static bool check_ref_to_sync(struct tegra_dc_mode *mode)
  85. {
  86. /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11. */
  87. if (mode->h_ref_to_sync + mode->h_sync_width + mode->h_back_porch <= 11)
  88. return false;
  89. /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1. */
  90. if (mode->v_ref_to_sync + mode->v_sync_width + mode->v_back_porch <= 1)
  91. return false;
  92. /* Constraint 3: V_FRONT_PORCH + V_SYNC_WIDTH + V_BACK_PORCH > 1
  93. * (vertical blank). */
  94. if (mode->v_front_porch + mode->v_sync_width + mode->v_back_porch <= 1)
  95. return false;
  96. /* Constraint 4: V_SYNC_WIDTH >= 1; H_SYNC_WIDTH >= 1. */
  97. if (mode->v_sync_width < 1 || mode->h_sync_width < 1)
  98. return false;
  99. /* Constraint 5: V_REF_TO_SYNC >= 1; H_REF_TO_SYNC >= 0. */
  100. if (mode->v_ref_to_sync < 1 || mode->h_ref_to_sync < 0)
  101. return false;
  102. /* Constraint 6: V_FRONT_PORT >= (V_REF_TO_SYNC + 1);
  103. * H_FRONT_PORT >= (H_REF_TO_SYNC + 1). */
  104. if (mode->v_front_porch < mode->v_ref_to_sync + 1 ||
  105. mode->h_front_porch < mode->h_ref_to_sync + 1)
  106. return false;
  107. /* Constraint 7: H_DISP_ACTIVE >= 16; V_DISP_ACTIVE >= 16. */
  108. if (mode->h_active < 16 || mode->v_active < 16)
  109. return false;
  110. return true;
  111. }
  112. /* return in 1000ths of a Hertz */
  113. int tegra_dc_calc_refresh(const struct tegra_dc_mode *m)
  114. {
  115. long h_total, v_total, refresh;
  116. h_total = m->h_active + m->h_front_porch + m->h_back_porch +
  117. m->h_sync_width;
  118. v_total = m->v_active + m->v_front_porch + m->v_back_porch +
  119. m->v_sync_width;
  120. refresh = m->pclk / h_total;
  121. refresh *= 1000;
  122. refresh /= v_total;
  123. return refresh;
  124. }
  125. #ifdef DEBUG
  126. static void print_mode(struct tegra_dc *dc,
  127. const struct tegra_dc_mode *mode, const char *note)
  128. {
  129. if (mode) {
  130. int refresh = tegra_dc_calc_refresh(mode);
  131. dev_info(&dc->ndev->dev, "%s():MODE:%dx%d@%d.%03uHz pclk=%d\n",
  132. note ? note : "",
  133. mode->h_active, mode->v_active,
  134. refresh / 1000, refresh % 1000,
  135. mode->pclk);
  136. }
  137. }
  138. #else /* !DEBUG */
  139. static inline void print_mode(struct tegra_dc *dc,
  140. const struct tegra_dc_mode *mode, const char *note) { }
  141. #endif /* DEBUG */
  142. int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode)
  143. {
  144. unsigned long val;
  145. unsigned long rate;
  146. unsigned long div;
  147. unsigned long pclk;
  148. print_mode(dc, mode, __func__);
  149. /* use default EMC rate when switching modes */
  150. dc->new_emc_clk_rate = tegra_dc_get_default_emc_clk_rate(dc);
  151. tegra_dc_program_bandwidth(dc, true);
  152. tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
  153. tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16),
  154. DC_DISP_REF_TO_SYNC);
  155. tegra_dc_writel(dc, mode->h_sync_width | (mode->v_sync_width << 16),
  156. DC_DISP_SYNC_WIDTH);
  157. tegra_dc_writel(dc, mode->h_back_porch | (mode->v_back_porch << 16),
  158. DC_DISP_BACK_PORCH);
  159. tegra_dc_writel(dc, mode->h_active | (mode->v_active << 16),
  160. DC_DISP_DISP_ACTIVE);
  161. tegra_dc_writel(dc, mode->h_front_porch | (mode->v_front_porch << 16),
  162. DC_DISP_FRONT_PORCH);
  163. tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL,
  164. DC_DISP_DATA_ENABLE_OPTIONS);
  165. /* TODO: MIPI/CRT/HDMI clock cals */
  166. val = DISP_DATA_FORMAT_DF1P1C;
  167. if (dc->out->align == TEGRA_DC_ALIGN_MSB)
  168. val |= DISP_DATA_ALIGNMENT_MSB;
  169. else
  170. val |= DISP_DATA_ALIGNMENT_LSB;
  171. if (dc->out->order == TEGRA_DC_ORDER_RED_BLUE)
  172. val |= DISP_DATA_ORDER_RED_BLUE;
  173. else
  174. val |= DISP_DATA_ORDER_BLUE_RED;
  175. tegra_dc_writel(dc, val, DC_DISP_DISP_INTERFACE_CONTROL);
  176. rate = tegra_dc_clk_get_rate(dc);
  177. pclk = tegra_dc_pclk_round_rate(dc, mode->pclk);
  178. trace_printk("%s:pclk=%ld\n", dc->ndev->name, pclk);
  179. if (pclk < (mode->pclk / 100 * 99) ||
  180. pclk > (mode->pclk / 100 * 109)) {
  181. dev_err(&dc->ndev->dev,
  182. "can't divide %ld clock to %d -1/+9%% %ld %d %d\n",
  183. rate, mode->pclk,
  184. pclk, (mode->pclk / 100 * 99),
  185. (mode->pclk / 100 * 109));
  186. return -EINVAL;
  187. }
  188. div = (rate * 2 / pclk) - 2;
  189. trace_printk("%s:div=%ld\n", dc->ndev->name, div);
  190. tegra_dc_writel(dc, 0x00010001,
  191. DC_DISP_SHIFT_CLOCK_OPTIONS);
  192. tegra_dc_writel(dc, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(div),
  193. DC_DISP_DISP_CLOCK_CONTROL);
  194. #ifdef CONFIG_SWITCH
  195. switch_set_state(&dc->modeset_switch,
  196. (mode->h_active << 16) | mode->v_active);
  197. #endif
  198. tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
  199. tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
  200. print_mode_info(dc, dc->mode);
  201. return 0;
  202. }
  203. int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
  204. {
  205. memcpy(&dc->mode, mode, sizeof(dc->mode));
  206. print_mode(dc, mode, __func__);
  207. return 0;
  208. }
  209. EXPORT_SYMBOL(tegra_dc_set_mode);
  210. int tegra_dc_set_fb_mode(struct tegra_dc *dc,
  211. const struct fb_videomode *fbmode, bool stereo_mode)
  212. {
  213. struct tegra_dc_mode mode;
  214. if (!fbmode->pixclock)
  215. return -EINVAL;
  216. mode.pclk = PICOS2KHZ(fbmode->pixclock) * 1000;
  217. mode.h_sync_width = fbmode->hsync_len;
  218. mode.v_sync_width = fbmode->vsync_len;
  219. mode.h_back_porch = fbmode->left_margin;
  220. mode.v_back_porch = fbmode->upper_margin;
  221. mode.h_active = fbmode->xres;
  222. mode.v_active = fbmode->yres;
  223. mode.h_front_porch = fbmode->right_margin;
  224. mode.v_front_porch = fbmode->lower_margin;
  225. mode.stereo_mode = stereo_mode;
  226. if (dc->out->type == TEGRA_DC_OUT_HDMI) {
  227. /* HDMI controller requires h_ref=1, v_ref=1 */
  228. mode.h_ref_to_sync = 1;
  229. mode.v_ref_to_sync = 1;
  230. } else {
  231. calc_ref_to_sync(&mode);
  232. }
  233. if (!check_ref_to_sync(&mode)) {
  234. dev_err(&dc->ndev->dev,
  235. "Display timing doesn't meet restrictions.\n");
  236. return -EINVAL;
  237. }
  238. dev_info(&dc->ndev->dev, "Using mode %dx%d pclk=%d href=%d vref=%d\n",
  239. mode.h_active, mode.v_active, mode.pclk,
  240. mode.h_ref_to_sync, mode.v_ref_to_sync
  241. );
  242. #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
  243. /* Double the pixel clock and update v_active only for
  244. * frame packed mode */
  245. if (mode.stereo_mode) {
  246. mode.pclk *= 2;
  247. /* total v_active = yres*2 + activespace */
  248. mode.v_active = fbmode->yres * 2 +
  249. fbmode->vsync_len +
  250. fbmode->upper_margin +
  251. fbmode->lower_margin;
  252. }
  253. #endif
  254. mode.flags = 0;
  255. if (!(fbmode->sync & FB_SYNC_HOR_HIGH_ACT))
  256. mode.flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
  257. if (!(fbmode->sync & FB_SYNC_VERT_HIGH_ACT))
  258. mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
  259. return tegra_dc_set_mode(dc, &mode);
  260. }
  261. EXPORT_SYMBOL(tegra_dc_set_fb_mode);