tegra.c 9.7 KB

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