tegra.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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. int lcd_line_length;
  55. void *lcd_base; /* Start of framebuffer memory */
  56. void *lcd_console_address; /* Start of console buffer */
  57. short console_col;
  58. short console_row;
  59. vidinfo_t panel_info = {
  60. /* Insert a value here so that we don't end up in the BSS */
  61. .vl_col = -1,
  62. };
  63. #ifndef CONFIG_OF_CONTROL
  64. #error "You must enable CONFIG_OF_CONTROL to get Tegra LCD support"
  65. #endif
  66. static void update_panel_size(struct fdt_disp_config *config)
  67. {
  68. panel_info.vl_col = config->width;
  69. panel_info.vl_row = config->height;
  70. panel_info.vl_bpix = config->log2_bpp;
  71. }
  72. /*
  73. * Main init function called by lcd driver.
  74. * Inits and then prints test pattern if required.
  75. */
  76. void lcd_ctrl_init(void *lcdbase)
  77. {
  78. int type = DCACHE_OFF;
  79. int size;
  80. assert(disp_config);
  81. lcd_base = (void *)disp_config->frame_buffer;
  82. /* Make sure that we can acommodate the selected LCD */
  83. assert(disp_config->width <= LCD_MAX_WIDTH);
  84. assert(disp_config->height <= LCD_MAX_HEIGHT);
  85. assert(disp_config->log2_bpp <= LCD_MAX_LOG2_BPP);
  86. if (disp_config->width <= LCD_MAX_WIDTH
  87. && disp_config->height <= LCD_MAX_HEIGHT
  88. && disp_config->log2_bpp <= LCD_MAX_LOG2_BPP)
  89. update_panel_size(disp_config);
  90. size = lcd_get_size(&lcd_line_length);
  91. /* Set up the LCD caching as requested */
  92. if (config.cache_type & FDT_LCD_CACHE_WRITE_THROUGH)
  93. type = DCACHE_WRITETHROUGH;
  94. else if (config.cache_type & FDT_LCD_CACHE_WRITE_BACK)
  95. type = DCACHE_WRITEBACK;
  96. mmu_set_region_dcache_behaviour(disp_config->frame_buffer, size, type);
  97. /* Enable flushing after LCD writes if requested */
  98. lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH);
  99. debug("LCD frame buffer at %p\n", lcd_base);
  100. }
  101. ulong calc_fbsize(void)
  102. {
  103. return (panel_info.vl_col * panel_info.vl_row *
  104. NBITS(panel_info.vl_bpix)) / 8;
  105. }
  106. void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
  107. {
  108. }
  109. void tegra_lcd_early_init(const void *blob)
  110. {
  111. /*
  112. * Go with the maximum size for now. We will fix this up after
  113. * relocation. These values are only used for memory alocation.
  114. */
  115. panel_info.vl_col = LCD_MAX_WIDTH;
  116. panel_info.vl_row = LCD_MAX_HEIGHT;
  117. panel_info.vl_bpix = LCD_MAX_LOG2_BPP;
  118. }
  119. /**
  120. * Decode the panel information from the fdt.
  121. *
  122. * @param blob fdt blob
  123. * @param config structure to store fdt config into
  124. * @return 0 if ok, -ve on error
  125. */
  126. static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config)
  127. {
  128. int display_node;
  129. disp_config = tegra_display_get_config();
  130. if (!disp_config) {
  131. debug("%s: Display controller is not configured\n", __func__);
  132. return -1;
  133. }
  134. display_node = disp_config->panel_node;
  135. if (display_node < 0) {
  136. debug("%s: No panel configuration available\n", __func__);
  137. return -1;
  138. }
  139. config->pwm_channel = pwm_request(blob, display_node, "nvidia,pwm");
  140. if (config->pwm_channel < 0) {
  141. debug("%s: Unable to request PWM channel\n", __func__);
  142. return -1;
  143. }
  144. config->cache_type = fdtdec_get_int(blob, display_node,
  145. "nvidia,cache-type",
  146. FDT_LCD_CACHE_WRITE_BACK_FLUSH);
  147. /* These GPIOs are all optional */
  148. fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-enable-gpios",
  149. &config->backlight_en);
  150. fdtdec_decode_gpio(blob, display_node, "nvidia,lvds-shutdown-gpios",
  151. &config->lvds_shutdown);
  152. fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-vdd-gpios",
  153. &config->backlight_vdd);
  154. fdtdec_decode_gpio(blob, display_node, "nvidia,panel-vdd-gpios",
  155. &config->panel_vdd);
  156. return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings",
  157. config->panel_timings, FDT_LCD_TIMINGS);
  158. }
  159. /**
  160. * Handle the next stage of device init
  161. */
  162. static int handle_stage(const void *blob)
  163. {
  164. debug("%s: stage %d\n", __func__, stage);
  165. /* do the things for this stage */
  166. switch (stage) {
  167. case STAGE_START:
  168. /* Initialize the Tegra display controller */
  169. if (tegra_display_probe(gd->fdt_blob, (void *)gd->fb_base)) {
  170. printf("%s: Failed to probe display driver\n",
  171. __func__);
  172. return -1;
  173. }
  174. /* get panel details */
  175. if (fdt_decode_lcd(blob, &config)) {
  176. printf("No valid LCD information in device tree\n");
  177. return -1;
  178. }
  179. /*
  180. * It is possible that the FDT has requested that the LCD be
  181. * disabled. We currently don't support this. It would require
  182. * changes to U-Boot LCD subsystem to have LCD support
  183. * compiled in but not used. An easier option might be to
  184. * still have a frame buffer, but leave the backlight off and
  185. * remove all mention of lcd in the stdout environment
  186. * variable.
  187. */
  188. funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
  189. fdtdec_setup_gpio(&config.panel_vdd);
  190. fdtdec_setup_gpio(&config.lvds_shutdown);
  191. fdtdec_setup_gpio(&config.backlight_vdd);
  192. fdtdec_setup_gpio(&config.backlight_en);
  193. /*
  194. * TODO: If fdt includes output flag we can omit this code
  195. * since fdtdec_setup_gpio will do it for us.
  196. */
  197. if (fdt_gpio_isvalid(&config.panel_vdd))
  198. gpio_direction_output(config.panel_vdd.gpio, 0);
  199. if (fdt_gpio_isvalid(&config.lvds_shutdown))
  200. gpio_direction_output(config.lvds_shutdown.gpio, 0);
  201. if (fdt_gpio_isvalid(&config.backlight_vdd))
  202. gpio_direction_output(config.backlight_vdd.gpio, 0);
  203. if (fdt_gpio_isvalid(&config.backlight_en))
  204. gpio_direction_output(config.backlight_en.gpio, 0);
  205. break;
  206. case STAGE_PANEL_VDD:
  207. if (fdt_gpio_isvalid(&config.panel_vdd))
  208. gpio_direction_output(config.panel_vdd.gpio, 1);
  209. break;
  210. case STAGE_LVDS:
  211. if (fdt_gpio_isvalid(&config.lvds_shutdown))
  212. gpio_set_value(config.lvds_shutdown.gpio, 1);
  213. break;
  214. case STAGE_BACKLIGHT_VDD:
  215. if (fdt_gpio_isvalid(&config.backlight_vdd))
  216. gpio_set_value(config.backlight_vdd.gpio, 1);
  217. break;
  218. case STAGE_PWM:
  219. /* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
  220. pinmux_set_func(PINGRP_GPU, PMUX_FUNC_PWM);
  221. pinmux_tristate_disable(PINGRP_GPU);
  222. pwm_enable(config.pwm_channel, 32768, 0xdf, 1);
  223. break;
  224. case STAGE_BACKLIGHT_EN:
  225. if (fdt_gpio_isvalid(&config.backlight_en))
  226. gpio_set_value(config.backlight_en.gpio, 1);
  227. break;
  228. case STAGE_DONE:
  229. break;
  230. }
  231. /* set up timer for next stage */
  232. timer_next = timer_get_us();
  233. if (stage < FDT_LCD_TIMINGS)
  234. timer_next += config.panel_timings[stage] * 1000;
  235. /* move to next stage */
  236. stage++;
  237. return 0;
  238. }
  239. int tegra_lcd_check_next_stage(const void *blob, int wait)
  240. {
  241. if (stage == STAGE_DONE)
  242. return 0;
  243. do {
  244. /* wait if we need to */
  245. debug("%s: stage %d\n", __func__, stage);
  246. if (stage != STAGE_START) {
  247. int delay = timer_next - timer_get_us();
  248. if (delay > 0) {
  249. if (wait)
  250. udelay(delay);
  251. else
  252. return 0;
  253. }
  254. }
  255. if (handle_stage(blob))
  256. return -1;
  257. } while (wait && stage != STAGE_DONE);
  258. if (stage == STAGE_DONE)
  259. debug("%s: LCD init complete\n", __func__);
  260. return 0;
  261. }
  262. void lcd_enable(void)
  263. {
  264. /*
  265. * Backlight and power init will be done separately in
  266. * tegra_lcd_check_next_stage(), which should be called in
  267. * board_late_init().
  268. *
  269. * U-Boot code supports only colour depth, selected at compile time.
  270. * The device tree setting should match this. Otherwise the display
  271. * will not look right, and U-Boot may crash.
  272. */
  273. if (disp_config->log2_bpp != LCD_BPP) {
  274. printf("%s: Error: LCD depth configured in FDT (%d = %dbpp)"
  275. " must match setting of LCD_BPP (%d)\n", __func__,
  276. disp_config->log2_bpp, disp_config->bpp, LCD_BPP);
  277. }
  278. }