xref: /rk3399_rockchip-uboot/drivers/video/tegra.c (revision 00a0ca5986c13d24ebbc5000cc1b7a1cdac0ba4b)
10be8f203SSimon Glass /*
20be8f203SSimon Glass  * Copyright (c) 2011 The Chromium OS Authors.
30be8f203SSimon Glass  * See file CREDITS for list of people who contributed to this
40be8f203SSimon Glass  * project.
50be8f203SSimon Glass  *
60be8f203SSimon Glass  * This program is free software; you can redistribute it and/or
70be8f203SSimon Glass  * modify it under the terms of the GNU General Public License as
80be8f203SSimon Glass  * published by the Free Software Foundation; either version 2 of
90be8f203SSimon Glass  * the License, or (at your option) any later version.
100be8f203SSimon Glass  *
110be8f203SSimon Glass  * This program is distributed in the hope that it will be useful,
120be8f203SSimon Glass  * but WITHOUT ANY WARRANTY; without even the implied warranty of
130be8f203SSimon Glass  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
140be8f203SSimon Glass  * GNU General Public License for more details.
150be8f203SSimon Glass  *
160be8f203SSimon Glass  * You should have received a copy of the GNU General Public License
170be8f203SSimon Glass  * along with this program; if not, write to the Free Software
180be8f203SSimon Glass  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
190be8f203SSimon Glass  * MA 02111-1307 USA
200be8f203SSimon Glass  */
210be8f203SSimon Glass 
220be8f203SSimon Glass #include <common.h>
230be8f203SSimon Glass #include <fdtdec.h>
240be8f203SSimon Glass #include <lcd.h>
250be8f203SSimon Glass 
260be8f203SSimon Glass #include <asm/system.h>
270be8f203SSimon Glass #include <asm/gpio.h>
280be8f203SSimon Glass 
290be8f203SSimon Glass #include <asm/arch/clock.h>
300be8f203SSimon Glass #include <asm/arch/funcmux.h>
310be8f203SSimon Glass #include <asm/arch/pinmux.h>
320be8f203SSimon Glass #include <asm/arch/pwm.h>
330be8f203SSimon Glass #include <asm/arch/display.h>
340be8f203SSimon Glass #include <asm/arch-tegra/timer.h>
350be8f203SSimon Glass 
360be8f203SSimon Glass DECLARE_GLOBAL_DATA_PTR;
370be8f203SSimon Glass 
380be8f203SSimon Glass /* These are the stages we go throuh in enabling the LCD */
390be8f203SSimon Glass enum stage_t {
400be8f203SSimon Glass 	STAGE_START,
410be8f203SSimon Glass 	STAGE_PANEL_VDD,
420be8f203SSimon Glass 	STAGE_LVDS,
430be8f203SSimon Glass 	STAGE_BACKLIGHT_VDD,
440be8f203SSimon Glass 	STAGE_PWM,
450be8f203SSimon Glass 	STAGE_BACKLIGHT_EN,
460be8f203SSimon Glass 	STAGE_DONE,
470be8f203SSimon Glass };
480be8f203SSimon Glass 
490be8f203SSimon Glass static enum stage_t stage;	/* Current stage we are at */
500be8f203SSimon Glass static unsigned long timer_next; /* Time we can move onto next stage */
510be8f203SSimon Glass 
520be8f203SSimon Glass /* Our LCD config, set up in handle_stage() */
530be8f203SSimon Glass static struct fdt_panel_config config;
540be8f203SSimon Glass struct fdt_disp_config *disp_config;	/* Display controller config */
550be8f203SSimon Glass 
560be8f203SSimon Glass enum {
570be8f203SSimon Glass 	/* Maximum LCD size we support */
580be8f203SSimon Glass 	LCD_MAX_WIDTH		= 1366,
590be8f203SSimon Glass 	LCD_MAX_HEIGHT		= 768,
600be8f203SSimon Glass 	LCD_MAX_LOG2_BPP	= 4,		/* 2^4 = 16 bpp */
610be8f203SSimon Glass };
620be8f203SSimon Glass 
630be8f203SSimon Glass vidinfo_t panel_info = {
640be8f203SSimon Glass 	/* Insert a value here so that we don't end up in the BSS */
650be8f203SSimon Glass 	.vl_col = -1,
660be8f203SSimon Glass };
670be8f203SSimon Glass 
680be8f203SSimon Glass #ifndef CONFIG_OF_CONTROL
690be8f203SSimon Glass #error "You must enable CONFIG_OF_CONTROL to get Tegra LCD support"
700be8f203SSimon Glass #endif
710be8f203SSimon Glass 
720be8f203SSimon Glass static void update_panel_size(struct fdt_disp_config *config)
730be8f203SSimon Glass {
740be8f203SSimon Glass 	panel_info.vl_col = config->width;
750be8f203SSimon Glass 	panel_info.vl_row = config->height;
760be8f203SSimon Glass 	panel_info.vl_bpix = config->log2_bpp;
770be8f203SSimon Glass }
780be8f203SSimon Glass 
790be8f203SSimon Glass /*
800be8f203SSimon Glass  *  Main init function called by lcd driver.
810be8f203SSimon Glass  *  Inits and then prints test pattern if required.
820be8f203SSimon Glass  */
830be8f203SSimon Glass 
840be8f203SSimon Glass void lcd_ctrl_init(void *lcdbase)
850be8f203SSimon Glass {
8644706a87SSimon Glass 	int type = DCACHE_OFF;
870c558754SThierry Reding 	int size;
880be8f203SSimon Glass 
890be8f203SSimon Glass 	assert(disp_config);
900be8f203SSimon Glass 
910be8f203SSimon Glass 	/* Make sure that we can acommodate the selected LCD */
920be8f203SSimon Glass 	assert(disp_config->width <= LCD_MAX_WIDTH);
930be8f203SSimon Glass 	assert(disp_config->height <= LCD_MAX_HEIGHT);
940be8f203SSimon Glass 	assert(disp_config->log2_bpp <= LCD_MAX_LOG2_BPP);
950be8f203SSimon Glass 	if (disp_config->width <= LCD_MAX_WIDTH
960be8f203SSimon Glass 			&& disp_config->height <= LCD_MAX_HEIGHT
970be8f203SSimon Glass 			&& disp_config->log2_bpp <= LCD_MAX_LOG2_BPP)
980be8f203SSimon Glass 		update_panel_size(disp_config);
990c558754SThierry Reding 	size = lcd_get_size(&lcd_line_length);
1000be8f203SSimon Glass 
10144706a87SSimon Glass 	/* Set up the LCD caching as requested */
10244706a87SSimon Glass 	if (config.cache_type & FDT_LCD_CACHE_WRITE_THROUGH)
10344706a87SSimon Glass 		type = DCACHE_WRITETHROUGH;
10444706a87SSimon Glass 	else if (config.cache_type & FDT_LCD_CACHE_WRITE_BACK)
10544706a87SSimon Glass 		type = DCACHE_WRITEBACK;
10644706a87SSimon Glass 	mmu_set_region_dcache_behaviour(disp_config->frame_buffer, size, type);
10744706a87SSimon Glass 
10844706a87SSimon Glass 	/* Enable flushing after LCD writes if requested */
10944706a87SSimon Glass 	lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH);
11044706a87SSimon Glass 
111*00a0ca59SJeroen Hofstee 	debug("LCD frame buffer at %08X\n", disp_config->frame_buffer);
1120be8f203SSimon Glass }
1130be8f203SSimon Glass 
1140be8f203SSimon Glass ulong calc_fbsize(void)
1150be8f203SSimon Glass {
1160be8f203SSimon Glass 	return (panel_info.vl_col * panel_info.vl_row *
1170be8f203SSimon Glass 		NBITS(panel_info.vl_bpix)) / 8;
1180be8f203SSimon Glass }
1190be8f203SSimon Glass 
1200be8f203SSimon Glass void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
1210be8f203SSimon Glass {
1220be8f203SSimon Glass }
1230be8f203SSimon Glass 
1240be8f203SSimon Glass void tegra_lcd_early_init(const void *blob)
1250be8f203SSimon Glass {
1260be8f203SSimon Glass 	/*
1270be8f203SSimon Glass 	 * Go with the maximum size for now. We will fix this up after
1280be8f203SSimon Glass 	 * relocation. These values are only used for memory alocation.
1290be8f203SSimon Glass 	 */
1300be8f203SSimon Glass 	panel_info.vl_col = LCD_MAX_WIDTH;
1310be8f203SSimon Glass 	panel_info.vl_row = LCD_MAX_HEIGHT;
1320be8f203SSimon Glass 	panel_info.vl_bpix = LCD_MAX_LOG2_BPP;
1330be8f203SSimon Glass }
1340be8f203SSimon Glass 
1350be8f203SSimon Glass /**
1360be8f203SSimon Glass  * Decode the panel information from the fdt.
1370be8f203SSimon Glass  *
1380be8f203SSimon Glass  * @param blob		fdt blob
1390be8f203SSimon Glass  * @param config	structure to store fdt config into
1400be8f203SSimon Glass  * @return 0 if ok, -ve on error
1410be8f203SSimon Glass  */
1420be8f203SSimon Glass static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config)
1430be8f203SSimon Glass {
1440be8f203SSimon Glass 	int display_node;
1450be8f203SSimon Glass 
1460be8f203SSimon Glass 	disp_config = tegra_display_get_config();
1470be8f203SSimon Glass 	if (!disp_config) {
1480be8f203SSimon Glass 		debug("%s: Display controller is not configured\n", __func__);
1490be8f203SSimon Glass 		return -1;
1500be8f203SSimon Glass 	}
1510be8f203SSimon Glass 	display_node = disp_config->panel_node;
1520be8f203SSimon Glass 	if (display_node < 0) {
1530be8f203SSimon Glass 		debug("%s: No panel configuration available\n", __func__);
1540be8f203SSimon Glass 		return -1;
1550be8f203SSimon Glass 	}
1560be8f203SSimon Glass 
1570be8f203SSimon Glass 	config->pwm_channel = pwm_request(blob, display_node, "nvidia,pwm");
1580be8f203SSimon Glass 	if (config->pwm_channel < 0) {
1590be8f203SSimon Glass 		debug("%s: Unable to request PWM channel\n", __func__);
1600be8f203SSimon Glass 		return -1;
1610be8f203SSimon Glass 	}
1620be8f203SSimon Glass 
1630be8f203SSimon Glass 	config->cache_type = fdtdec_get_int(blob, display_node,
1640be8f203SSimon Glass 					    "nvidia,cache-type",
1650be8f203SSimon Glass 					    FDT_LCD_CACHE_WRITE_BACK_FLUSH);
1660be8f203SSimon Glass 
1670be8f203SSimon Glass 	/* These GPIOs are all optional */
1680be8f203SSimon Glass 	fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-enable-gpios",
1690be8f203SSimon Glass 			    &config->backlight_en);
1700be8f203SSimon Glass 	fdtdec_decode_gpio(blob, display_node, "nvidia,lvds-shutdown-gpios",
1710be8f203SSimon Glass 			   &config->lvds_shutdown);
1720be8f203SSimon Glass 	fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-vdd-gpios",
1730be8f203SSimon Glass 			   &config->backlight_vdd);
1740be8f203SSimon Glass 	fdtdec_decode_gpio(blob, display_node, "nvidia,panel-vdd-gpios",
1750be8f203SSimon Glass 			   &config->panel_vdd);
1760be8f203SSimon Glass 
1770be8f203SSimon Glass 	return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings",
1780be8f203SSimon Glass 			config->panel_timings, FDT_LCD_TIMINGS);
1790be8f203SSimon Glass }
1800be8f203SSimon Glass 
1810be8f203SSimon Glass /**
1820be8f203SSimon Glass  * Handle the next stage of device init
1830be8f203SSimon Glass  */
1840be8f203SSimon Glass static int handle_stage(const void *blob)
1850be8f203SSimon Glass {
1860be8f203SSimon Glass 	debug("%s: stage %d\n", __func__, stage);
1870be8f203SSimon Glass 
1880be8f203SSimon Glass 	/* do the things for this stage */
1890be8f203SSimon Glass 	switch (stage) {
1900be8f203SSimon Glass 	case STAGE_START:
1910be8f203SSimon Glass 		/* Initialize the Tegra display controller */
1920be8f203SSimon Glass 		if (tegra_display_probe(gd->fdt_blob, (void *)gd->fb_base)) {
1930be8f203SSimon Glass 			printf("%s: Failed to probe display driver\n",
1940be8f203SSimon Glass 			__func__);
1950be8f203SSimon Glass 			return -1;
1960be8f203SSimon Glass 		}
1970be8f203SSimon Glass 
1980be8f203SSimon Glass 		/* get panel details */
1990be8f203SSimon Glass 		if (fdt_decode_lcd(blob, &config)) {
2000be8f203SSimon Glass 			printf("No valid LCD information in device tree\n");
2010be8f203SSimon Glass 			return -1;
2020be8f203SSimon Glass 		}
2030be8f203SSimon Glass 
2040be8f203SSimon Glass 		/*
2050be8f203SSimon Glass 		 * It is possible that the FDT has requested that the LCD be
2060be8f203SSimon Glass 		 * disabled. We currently don't support this. It would require
2070be8f203SSimon Glass 		 * changes to U-Boot LCD subsystem to have LCD support
2080be8f203SSimon Glass 		 * compiled in but not used. An easier option might be to
2090be8f203SSimon Glass 		 * still have a frame buffer, but leave the backlight off and
2100be8f203SSimon Glass 		 * remove all mention of lcd in the stdout environment
2110be8f203SSimon Glass 		 * variable.
2120be8f203SSimon Glass 		 */
2130be8f203SSimon Glass 
2140be8f203SSimon Glass 		funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
2150be8f203SSimon Glass 
2160be8f203SSimon Glass 		fdtdec_setup_gpio(&config.panel_vdd);
2170be8f203SSimon Glass 		fdtdec_setup_gpio(&config.lvds_shutdown);
2180be8f203SSimon Glass 		fdtdec_setup_gpio(&config.backlight_vdd);
2190be8f203SSimon Glass 		fdtdec_setup_gpio(&config.backlight_en);
2200be8f203SSimon Glass 
2210be8f203SSimon Glass 		/*
2220be8f203SSimon Glass 		 * TODO: If fdt includes output flag we can omit this code
2230be8f203SSimon Glass 		 * since fdtdec_setup_gpio will do it for us.
2240be8f203SSimon Glass 		 */
2250be8f203SSimon Glass 		if (fdt_gpio_isvalid(&config.panel_vdd))
2260be8f203SSimon Glass 			gpio_direction_output(config.panel_vdd.gpio, 0);
2270be8f203SSimon Glass 		if (fdt_gpio_isvalid(&config.lvds_shutdown))
2280be8f203SSimon Glass 			gpio_direction_output(config.lvds_shutdown.gpio, 0);
2290be8f203SSimon Glass 		if (fdt_gpio_isvalid(&config.backlight_vdd))
2300be8f203SSimon Glass 			gpio_direction_output(config.backlight_vdd.gpio, 0);
2310be8f203SSimon Glass 		if (fdt_gpio_isvalid(&config.backlight_en))
2320be8f203SSimon Glass 			gpio_direction_output(config.backlight_en.gpio, 0);
2330be8f203SSimon Glass 		break;
2340be8f203SSimon Glass 	case STAGE_PANEL_VDD:
2350be8f203SSimon Glass 		if (fdt_gpio_isvalid(&config.panel_vdd))
2360be8f203SSimon Glass 			gpio_direction_output(config.panel_vdd.gpio, 1);
2370be8f203SSimon Glass 		break;
2380be8f203SSimon Glass 	case STAGE_LVDS:
2390be8f203SSimon Glass 		if (fdt_gpio_isvalid(&config.lvds_shutdown))
2400be8f203SSimon Glass 			gpio_set_value(config.lvds_shutdown.gpio, 1);
2410be8f203SSimon Glass 		break;
2420be8f203SSimon Glass 	case STAGE_BACKLIGHT_VDD:
2430be8f203SSimon Glass 		if (fdt_gpio_isvalid(&config.backlight_vdd))
2440be8f203SSimon Glass 			gpio_set_value(config.backlight_vdd.gpio, 1);
2450be8f203SSimon Glass 		break;
2460be8f203SSimon Glass 	case STAGE_PWM:
2470be8f203SSimon Glass 		/* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
2480be8f203SSimon Glass 		pinmux_set_func(PINGRP_GPU, PMUX_FUNC_PWM);
2490be8f203SSimon Glass 		pinmux_tristate_disable(PINGRP_GPU);
2500be8f203SSimon Glass 
2510be8f203SSimon Glass 		pwm_enable(config.pwm_channel, 32768, 0xdf, 1);
2520be8f203SSimon Glass 		break;
2530be8f203SSimon Glass 	case STAGE_BACKLIGHT_EN:
2540be8f203SSimon Glass 		if (fdt_gpio_isvalid(&config.backlight_en))
2550be8f203SSimon Glass 			gpio_set_value(config.backlight_en.gpio, 1);
2560be8f203SSimon Glass 		break;
2570be8f203SSimon Glass 	case STAGE_DONE:
2580be8f203SSimon Glass 		break;
2590be8f203SSimon Glass 	}
2600be8f203SSimon Glass 
2610be8f203SSimon Glass 	/* set up timer for next stage */
2620be8f203SSimon Glass 	timer_next = timer_get_us();
2630be8f203SSimon Glass 	if (stage < FDT_LCD_TIMINGS)
2640be8f203SSimon Glass 		timer_next += config.panel_timings[stage] * 1000;
2650be8f203SSimon Glass 
2660be8f203SSimon Glass 	/* move to next stage */
2670be8f203SSimon Glass 	stage++;
2680be8f203SSimon Glass 	return 0;
2690be8f203SSimon Glass }
2700be8f203SSimon Glass 
2710be8f203SSimon Glass int tegra_lcd_check_next_stage(const void *blob, int wait)
2720be8f203SSimon Glass {
2730be8f203SSimon Glass 	if (stage == STAGE_DONE)
2740be8f203SSimon Glass 		return 0;
2750be8f203SSimon Glass 
2760be8f203SSimon Glass 	do {
2770be8f203SSimon Glass 		/* wait if we need to */
2780be8f203SSimon Glass 		debug("%s: stage %d\n", __func__, stage);
2790be8f203SSimon Glass 		if (stage != STAGE_START) {
2800be8f203SSimon Glass 			int delay = timer_next - timer_get_us();
2810be8f203SSimon Glass 
2820be8f203SSimon Glass 			if (delay > 0) {
2830be8f203SSimon Glass 				if (wait)
2840be8f203SSimon Glass 					udelay(delay);
2850be8f203SSimon Glass 				else
2860be8f203SSimon Glass 					return 0;
2870be8f203SSimon Glass 			}
2880be8f203SSimon Glass 		}
2890be8f203SSimon Glass 
2900be8f203SSimon Glass 		if (handle_stage(blob))
2910be8f203SSimon Glass 			return -1;
2920be8f203SSimon Glass 	} while (wait && stage != STAGE_DONE);
2930be8f203SSimon Glass 	if (stage == STAGE_DONE)
2940be8f203SSimon Glass 		debug("%s: LCD init complete\n", __func__);
2950be8f203SSimon Glass 
2960be8f203SSimon Glass 	return 0;
2970be8f203SSimon Glass }
2980be8f203SSimon Glass 
2990be8f203SSimon Glass void lcd_enable(void)
3000be8f203SSimon Glass {
3010be8f203SSimon Glass 	/*
3020be8f203SSimon Glass 	 * Backlight and power init will be done separately in
3030be8f203SSimon Glass 	 * tegra_lcd_check_next_stage(), which should be called in
3040be8f203SSimon Glass 	 * board_late_init().
3050be8f203SSimon Glass 	 *
3060be8f203SSimon Glass 	 * U-Boot code supports only colour depth, selected at compile time.
3070be8f203SSimon Glass 	 * The device tree setting should match this. Otherwise the display
3080be8f203SSimon Glass 	 * will not look right, and U-Boot may crash.
3090be8f203SSimon Glass 	 */
3100be8f203SSimon Glass 	if (disp_config->log2_bpp != LCD_BPP) {
3110be8f203SSimon Glass 		printf("%s: Error: LCD depth configured in FDT (%d = %dbpp)"
3120be8f203SSimon Glass 			" must match setting of LCD_BPP (%d)\n", __func__,
3130be8f203SSimon Glass 		       disp_config->log2_bpp, disp_config->bpp, LCD_BPP);
3140be8f203SSimon Glass 	}
3150be8f203SSimon Glass }
316