tegra.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * Copyright (c) 2011 The Chromium OS Authors.
  3. * See file CREDITS for list of people who contributed to this
  4. * project.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  19. * MA 02111-1307 USA
  20. */
  21. #include <common.h>
  22. #include <fdtdec.h>
  23. #include <lcd.h>
  24. #include <asm/system.h>
  25. #include <asm/gpio.h>
  26. #include <asm/arch/clock.h>
  27. #include <asm/arch/funcmux.h>
  28. #include <asm/arch/pinmux.h>
  29. #include <asm/arch/pwm.h>
  30. #include <asm/arch/display.h>
  31. #include <asm/arch-tegra/timer.h>
  32. DECLARE_GLOBAL_DATA_PTR;
  33. /* These are the stages we go throuh in enabling the LCD */
  34. enum stage_t {
  35. STAGE_START,
  36. STAGE_PANEL_VDD,
  37. STAGE_LVDS,
  38. STAGE_BACKLIGHT_VDD,
  39. STAGE_PWM,
  40. STAGE_BACKLIGHT_EN,
  41. STAGE_DONE,
  42. };
  43. static enum stage_t stage; /* Current stage we are at */
  44. static unsigned long timer_next; /* Time we can move onto next stage */
  45. /* Our LCD config, set up in handle_stage() */
  46. static struct fdt_panel_config config;
  47. struct fdt_disp_config *disp_config; /* Display controller config */
  48. enum {
  49. /* Maximum LCD size we support */
  50. LCD_MAX_WIDTH = 1366,
  51. LCD_MAX_HEIGHT = 768,
  52. LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */
  53. };
  54. vidinfo_t panel_info = {
  55. /* Insert a value here so that we don't end up in the BSS */
  56. .vl_col = -1,
  57. };
  58. #ifndef CONFIG_OF_CONTROL
  59. #error "You must enable CONFIG_OF_CONTROL to get Tegra LCD support"
  60. #endif
  61. static void update_panel_size(struct fdt_disp_config *config)
  62. {
  63. panel_info.vl_col = config->width;
  64. panel_info.vl_row = config->height;
  65. panel_info.vl_bpix = config->log2_bpp;
  66. }
  67. /*
  68. * Main init function called by lcd driver.
  69. * Inits and then prints test pattern if required.
  70. */
  71. void lcd_ctrl_init(void *lcdbase)
  72. {
  73. int type = DCACHE_OFF;
  74. int size;
  75. assert(disp_config);
  76. /* Make sure that we can acommodate the selected LCD */
  77. assert(disp_config->width <= LCD_MAX_WIDTH);
  78. assert(disp_config->height <= LCD_MAX_HEIGHT);
  79. assert(disp_config->log2_bpp <= LCD_MAX_LOG2_BPP);
  80. if (disp_config->width <= LCD_MAX_WIDTH
  81. && disp_config->height <= LCD_MAX_HEIGHT
  82. && disp_config->log2_bpp <= LCD_MAX_LOG2_BPP)
  83. update_panel_size(disp_config);
  84. size = lcd_get_size(&lcd_line_length);
  85. /* Set up the LCD caching as requested */
  86. if (config.cache_type & FDT_LCD_CACHE_WRITE_THROUGH)
  87. type = DCACHE_WRITETHROUGH;
  88. else if (config.cache_type & FDT_LCD_CACHE_WRITE_BACK)
  89. type = DCACHE_WRITEBACK;
  90. mmu_set_region_dcache_behaviour(disp_config->frame_buffer, size, type);
  91. /* Enable flushing after LCD writes if requested */
  92. lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH);
  93. debug("LCD frame buffer at %08X\n", disp_config->frame_buffer);
  94. }
  95. ulong calc_fbsize(void)
  96. {
  97. return (panel_info.vl_col * panel_info.vl_row *
  98. NBITS(panel_info.vl_bpix)) / 8;
  99. }
  100. void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
  101. {
  102. }
  103. void tegra_lcd_early_init(const void *blob)
  104. {
  105. /*
  106. * Go with the maximum size for now. We will fix this up after
  107. * relocation. These values are only used for memory alocation.
  108. */
  109. panel_info.vl_col = LCD_MAX_WIDTH;
  110. panel_info.vl_row = LCD_MAX_HEIGHT;
  111. panel_info.vl_bpix = LCD_MAX_LOG2_BPP;
  112. }
  113. /**
  114. * Decode the panel information from the fdt.
  115. *
  116. * @param blob fdt blob
  117. * @param config structure to store fdt config into
  118. * @return 0 if ok, -ve on error
  119. */
  120. static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config)
  121. {
  122. int display_node;
  123. disp_config = tegra_display_get_config();
  124. if (!disp_config) {
  125. debug("%s: Display controller is not configured\n", __func__);
  126. return -1;
  127. }
  128. display_node = disp_config->panel_node;
  129. if (display_node < 0) {
  130. debug("%s: No panel configuration available\n", __func__);
  131. return -1;
  132. }
  133. config->pwm_channel = pwm_request(blob, display_node, "nvidia,pwm");
  134. if (config->pwm_channel < 0) {
  135. debug("%s: Unable to request PWM channel\n", __func__);
  136. return -1;
  137. }
  138. config->cache_type = fdtdec_get_int(blob, display_node,
  139. "nvidia,cache-type",
  140. FDT_LCD_CACHE_WRITE_BACK_FLUSH);
  141. /* These GPIOs are all optional */
  142. fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-enable-gpios",
  143. &config->backlight_en);
  144. fdtdec_decode_gpio(blob, display_node, "nvidia,lvds-shutdown-gpios",
  145. &config->lvds_shutdown);
  146. fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-vdd-gpios",
  147. &config->backlight_vdd);
  148. fdtdec_decode_gpio(blob, display_node, "nvidia,panel-vdd-gpios",
  149. &config->panel_vdd);
  150. return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings",
  151. config->panel_timings, FDT_LCD_TIMINGS);
  152. }
  153. /**
  154. * Handle the next stage of device init
  155. */
  156. static int handle_stage(const void *blob)
  157. {
  158. debug("%s: stage %d\n", __func__, stage);
  159. /* do the things for this stage */
  160. switch (stage) {
  161. case STAGE_START:
  162. /* Initialize the Tegra display controller */
  163. if (tegra_display_probe(gd->fdt_blob, (void *)gd->fb_base)) {
  164. printf("%s: Failed to probe display driver\n",
  165. __func__);
  166. return -1;
  167. }
  168. /* get panel details */
  169. if (fdt_decode_lcd(blob, &config)) {
  170. printf("No valid LCD information in device tree\n");
  171. return -1;
  172. }
  173. /*
  174. * It is possible that the FDT has requested that the LCD be
  175. * disabled. We currently don't support this. It would require
  176. * changes to U-Boot LCD subsystem to have LCD support
  177. * compiled in but not used. An easier option might be to
  178. * still have a frame buffer, but leave the backlight off and
  179. * remove all mention of lcd in the stdout environment
  180. * variable.
  181. */
  182. funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
  183. fdtdec_setup_gpio(&config.panel_vdd);
  184. fdtdec_setup_gpio(&config.lvds_shutdown);
  185. fdtdec_setup_gpio(&config.backlight_vdd);
  186. fdtdec_setup_gpio(&config.backlight_en);
  187. /*
  188. * TODO: If fdt includes output flag we can omit this code
  189. * since fdtdec_setup_gpio will do it for us.
  190. */
  191. if (fdt_gpio_isvalid(&config.panel_vdd))
  192. gpio_direction_output(config.panel_vdd.gpio, 0);
  193. if (fdt_gpio_isvalid(&config.lvds_shutdown))
  194. gpio_direction_output(config.lvds_shutdown.gpio, 0);
  195. if (fdt_gpio_isvalid(&config.backlight_vdd))
  196. gpio_direction_output(config.backlight_vdd.gpio, 0);
  197. if (fdt_gpio_isvalid(&config.backlight_en))
  198. gpio_direction_output(config.backlight_en.gpio, 0);
  199. break;
  200. case STAGE_PANEL_VDD:
  201. if (fdt_gpio_isvalid(&config.panel_vdd))
  202. gpio_direction_output(config.panel_vdd.gpio, 1);
  203. break;
  204. case STAGE_LVDS:
  205. if (fdt_gpio_isvalid(&config.lvds_shutdown))
  206. gpio_set_value(config.lvds_shutdown.gpio, 1);
  207. break;
  208. case STAGE_BACKLIGHT_VDD:
  209. if (fdt_gpio_isvalid(&config.backlight_vdd))
  210. gpio_set_value(config.backlight_vdd.gpio, 1);
  211. break;
  212. case STAGE_PWM:
  213. /* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
  214. pinmux_set_func(PINGRP_GPU, PMUX_FUNC_PWM);
  215. pinmux_tristate_disable(PINGRP_GPU);
  216. pwm_enable(config.pwm_channel, 32768, 0xdf, 1);
  217. break;
  218. case STAGE_BACKLIGHT_EN:
  219. if (fdt_gpio_isvalid(&config.backlight_en))
  220. gpio_set_value(config.backlight_en.gpio, 1);
  221. break;
  222. case STAGE_DONE:
  223. break;
  224. }
  225. /* set up timer for next stage */
  226. timer_next = timer_get_us();
  227. if (stage < FDT_LCD_TIMINGS)
  228. timer_next += config.panel_timings[stage] * 1000;
  229. /* move to next stage */
  230. stage++;
  231. return 0;
  232. }
  233. int tegra_lcd_check_next_stage(const void *blob, int wait)
  234. {
  235. if (stage == STAGE_DONE)
  236. return 0;
  237. do {
  238. /* wait if we need to */
  239. debug("%s: stage %d\n", __func__, stage);
  240. if (stage != STAGE_START) {
  241. int delay = timer_next - timer_get_us();
  242. if (delay > 0) {
  243. if (wait)
  244. udelay(delay);
  245. else
  246. return 0;
  247. }
  248. }
  249. if (handle_stage(blob))
  250. return -1;
  251. } while (wait && stage != STAGE_DONE);
  252. if (stage == STAGE_DONE)
  253. debug("%s: LCD init complete\n", __func__);
  254. return 0;
  255. }
  256. void lcd_enable(void)
  257. {
  258. /*
  259. * Backlight and power init will be done separately in
  260. * tegra_lcd_check_next_stage(), which should be called in
  261. * board_late_init().
  262. *
  263. * U-Boot code supports only colour depth, selected at compile time.
  264. * The device tree setting should match this. Otherwise the display
  265. * will not look right, and U-Boot may crash.
  266. */
  267. if (disp_config->log2_bpp != LCD_BPP) {
  268. printf("%s: Error: LCD depth configured in FDT (%d = %dbpp)"
  269. " must match setting of LCD_BPP (%d)\n", __func__,
  270. disp_config->log2_bpp, disp_config->bpp, LCD_BPP);
  271. }
  272. }