xref: /rk3399_rockchip-uboot/drivers/video/tegra.c (revision 04072cba1983fd8b3140b1b97e3d544359d178a0)
10be8f203SSimon Glass /*
20be8f203SSimon Glass  * Copyright (c) 2011 The Chromium OS Authors.
31a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
40be8f203SSimon Glass  */
50be8f203SSimon Glass 
60be8f203SSimon Glass #include <common.h>
70be8f203SSimon Glass #include <fdtdec.h>
80be8f203SSimon Glass #include <lcd.h>
90be8f203SSimon Glass 
100be8f203SSimon Glass #include <asm/system.h>
110be8f203SSimon Glass #include <asm/gpio.h>
120be8f203SSimon Glass 
130be8f203SSimon Glass #include <asm/arch/clock.h>
140be8f203SSimon Glass #include <asm/arch/funcmux.h>
150be8f203SSimon Glass #include <asm/arch/pinmux.h>
160be8f203SSimon Glass #include <asm/arch/pwm.h>
170be8f203SSimon Glass #include <asm/arch/display.h>
180be8f203SSimon Glass #include <asm/arch-tegra/timer.h>
190be8f203SSimon Glass 
200be8f203SSimon Glass DECLARE_GLOBAL_DATA_PTR;
210be8f203SSimon Glass 
220be8f203SSimon Glass /* These are the stages we go throuh in enabling the LCD */
230be8f203SSimon Glass enum stage_t {
240be8f203SSimon Glass 	STAGE_START,
250be8f203SSimon Glass 	STAGE_PANEL_VDD,
260be8f203SSimon Glass 	STAGE_LVDS,
270be8f203SSimon Glass 	STAGE_BACKLIGHT_VDD,
280be8f203SSimon Glass 	STAGE_PWM,
290be8f203SSimon Glass 	STAGE_BACKLIGHT_EN,
300be8f203SSimon Glass 	STAGE_DONE,
310be8f203SSimon Glass };
320be8f203SSimon Glass 
330be8f203SSimon Glass static enum stage_t stage;	/* Current stage we are at */
340be8f203SSimon Glass static unsigned long timer_next; /* Time we can move onto next stage */
350be8f203SSimon Glass 
360be8f203SSimon Glass /* Our LCD config, set up in handle_stage() */
370be8f203SSimon Glass static struct fdt_panel_config config;
380be8f203SSimon Glass struct fdt_disp_config *disp_config;	/* Display controller config */
390be8f203SSimon Glass 
400be8f203SSimon Glass enum {
410be8f203SSimon Glass 	/* Maximum LCD size we support */
420be8f203SSimon Glass 	LCD_MAX_WIDTH		= 1366,
430be8f203SSimon Glass 	LCD_MAX_HEIGHT		= 768,
440be8f203SSimon Glass 	LCD_MAX_LOG2_BPP	= 4,		/* 2^4 = 16 bpp */
450be8f203SSimon Glass };
460be8f203SSimon Glass 
470be8f203SSimon Glass vidinfo_t panel_info = {
480be8f203SSimon Glass 	/* Insert a value here so that we don't end up in the BSS */
490be8f203SSimon Glass 	.vl_col = -1,
500be8f203SSimon Glass };
510be8f203SSimon Glass 
520be8f203SSimon Glass #ifndef CONFIG_OF_CONTROL
530be8f203SSimon Glass #error "You must enable CONFIG_OF_CONTROL to get Tegra LCD support"
540be8f203SSimon Glass #endif
550be8f203SSimon Glass 
560be8f203SSimon Glass static void update_panel_size(struct fdt_disp_config *config)
570be8f203SSimon Glass {
580be8f203SSimon Glass 	panel_info.vl_col = config->width;
590be8f203SSimon Glass 	panel_info.vl_row = config->height;
600be8f203SSimon Glass 	panel_info.vl_bpix = config->log2_bpp;
610be8f203SSimon Glass }
620be8f203SSimon Glass 
630be8f203SSimon Glass /*
640be8f203SSimon Glass  *  Main init function called by lcd driver.
650be8f203SSimon Glass  *  Inits and then prints test pattern if required.
660be8f203SSimon Glass  */
670be8f203SSimon Glass 
680be8f203SSimon Glass void lcd_ctrl_init(void *lcdbase)
690be8f203SSimon Glass {
7044706a87SSimon Glass 	int type = DCACHE_OFF;
710c558754SThierry Reding 	int size;
720be8f203SSimon Glass 
730be8f203SSimon Glass 	assert(disp_config);
740be8f203SSimon Glass 
750be8f203SSimon Glass 	/* Make sure that we can acommodate the selected LCD */
760be8f203SSimon Glass 	assert(disp_config->width <= LCD_MAX_WIDTH);
770be8f203SSimon Glass 	assert(disp_config->height <= LCD_MAX_HEIGHT);
780be8f203SSimon Glass 	assert(disp_config->log2_bpp <= LCD_MAX_LOG2_BPP);
790be8f203SSimon Glass 	if (disp_config->width <= LCD_MAX_WIDTH
800be8f203SSimon Glass 			&& disp_config->height <= LCD_MAX_HEIGHT
810be8f203SSimon Glass 			&& disp_config->log2_bpp <= LCD_MAX_LOG2_BPP)
820be8f203SSimon Glass 		update_panel_size(disp_config);
830c558754SThierry Reding 	size = lcd_get_size(&lcd_line_length);
840be8f203SSimon Glass 
8544706a87SSimon Glass 	/* Set up the LCD caching as requested */
8644706a87SSimon Glass 	if (config.cache_type & FDT_LCD_CACHE_WRITE_THROUGH)
8744706a87SSimon Glass 		type = DCACHE_WRITETHROUGH;
8844706a87SSimon Glass 	else if (config.cache_type & FDT_LCD_CACHE_WRITE_BACK)
8944706a87SSimon Glass 		type = DCACHE_WRITEBACK;
9044706a87SSimon Glass 	mmu_set_region_dcache_behaviour(disp_config->frame_buffer, size, type);
9144706a87SSimon Glass 
9244706a87SSimon Glass 	/* Enable flushing after LCD writes if requested */
9344706a87SSimon Glass 	lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH);
9444706a87SSimon Glass 
9500a0ca59SJeroen Hofstee 	debug("LCD frame buffer at %08X\n", disp_config->frame_buffer);
960be8f203SSimon Glass }
970be8f203SSimon Glass 
980be8f203SSimon Glass ulong calc_fbsize(void)
990be8f203SSimon Glass {
1000be8f203SSimon Glass 	return (panel_info.vl_col * panel_info.vl_row *
1010be8f203SSimon Glass 		NBITS(panel_info.vl_bpix)) / 8;
1020be8f203SSimon Glass }
1030be8f203SSimon Glass 
1040be8f203SSimon Glass void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
1050be8f203SSimon Glass {
1060be8f203SSimon Glass }
1070be8f203SSimon Glass 
1080be8f203SSimon Glass void tegra_lcd_early_init(const void *blob)
1090be8f203SSimon Glass {
1100be8f203SSimon Glass 	/*
1110be8f203SSimon Glass 	 * Go with the maximum size for now. We will fix this up after
1120be8f203SSimon Glass 	 * relocation. These values are only used for memory alocation.
1130be8f203SSimon Glass 	 */
1140be8f203SSimon Glass 	panel_info.vl_col = LCD_MAX_WIDTH;
1150be8f203SSimon Glass 	panel_info.vl_row = LCD_MAX_HEIGHT;
1160be8f203SSimon Glass 	panel_info.vl_bpix = LCD_MAX_LOG2_BPP;
1170be8f203SSimon Glass }
1180be8f203SSimon Glass 
1190be8f203SSimon Glass /**
1200be8f203SSimon Glass  * Decode the panel information from the fdt.
1210be8f203SSimon Glass  *
1220be8f203SSimon Glass  * @param blob		fdt blob
1230be8f203SSimon Glass  * @param config	structure to store fdt config into
1240be8f203SSimon Glass  * @return 0 if ok, -ve on error
1250be8f203SSimon Glass  */
1260be8f203SSimon Glass static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config)
1270be8f203SSimon Glass {
1280be8f203SSimon Glass 	int display_node;
1290be8f203SSimon Glass 
1300be8f203SSimon Glass 	disp_config = tegra_display_get_config();
1310be8f203SSimon Glass 	if (!disp_config) {
1320be8f203SSimon Glass 		debug("%s: Display controller is not configured\n", __func__);
1330be8f203SSimon Glass 		return -1;
1340be8f203SSimon Glass 	}
1350be8f203SSimon Glass 	display_node = disp_config->panel_node;
1360be8f203SSimon Glass 	if (display_node < 0) {
1370be8f203SSimon Glass 		debug("%s: No panel configuration available\n", __func__);
1380be8f203SSimon Glass 		return -1;
1390be8f203SSimon Glass 	}
1400be8f203SSimon Glass 
1410be8f203SSimon Glass 	config->pwm_channel = pwm_request(blob, display_node, "nvidia,pwm");
1420be8f203SSimon Glass 	if (config->pwm_channel < 0) {
1430be8f203SSimon Glass 		debug("%s: Unable to request PWM channel\n", __func__);
1440be8f203SSimon Glass 		return -1;
1450be8f203SSimon Glass 	}
1460be8f203SSimon Glass 
1470be8f203SSimon Glass 	config->cache_type = fdtdec_get_int(blob, display_node,
1480be8f203SSimon Glass 					    "nvidia,cache-type",
1490be8f203SSimon Glass 					    FDT_LCD_CACHE_WRITE_BACK_FLUSH);
1500be8f203SSimon Glass 
1510be8f203SSimon Glass 	/* These GPIOs are all optional */
152*04072cbaSSimon Glass 	gpio_request_by_name_nodev(blob, display_node,
153*04072cbaSSimon Glass 				   "nvidia,backlight-enable-gpios", 0,
154*04072cbaSSimon Glass 				   &config->backlight_en, GPIOD_IS_OUT);
155*04072cbaSSimon Glass 	gpio_request_by_name_nodev(blob, display_node,
156*04072cbaSSimon Glass 				   "nvidia,lvds-shutdown-gpios", 0,
157*04072cbaSSimon Glass 				   &config->lvds_shutdown, GPIOD_IS_OUT);
158*04072cbaSSimon Glass 	gpio_request_by_name_nodev(blob, display_node,
159*04072cbaSSimon Glass 				   "nvidia,backlight-vdd-gpios", 0,
160*04072cbaSSimon Glass 				   &config->backlight_vdd, GPIOD_IS_OUT);
161*04072cbaSSimon Glass 	gpio_request_by_name_nodev(blob, display_node,
162*04072cbaSSimon Glass 				   "nvidia,panel-vdd-gpios", 0,
163*04072cbaSSimon Glass 				   &config->panel_vdd, GPIOD_IS_OUT);
1640be8f203SSimon Glass 
1650be8f203SSimon Glass 	return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings",
1660be8f203SSimon Glass 			config->panel_timings, FDT_LCD_TIMINGS);
1670be8f203SSimon Glass }
1680be8f203SSimon Glass 
1690be8f203SSimon Glass /**
1700be8f203SSimon Glass  * Handle the next stage of device init
1710be8f203SSimon Glass  */
1720be8f203SSimon Glass static int handle_stage(const void *blob)
1730be8f203SSimon Glass {
1740be8f203SSimon Glass 	debug("%s: stage %d\n", __func__, stage);
1750be8f203SSimon Glass 
1760be8f203SSimon Glass 	/* do the things for this stage */
1770be8f203SSimon Glass 	switch (stage) {
1780be8f203SSimon Glass 	case STAGE_START:
1790be8f203SSimon Glass 		/* Initialize the Tegra display controller */
1800be8f203SSimon Glass 		if (tegra_display_probe(gd->fdt_blob, (void *)gd->fb_base)) {
1810be8f203SSimon Glass 			printf("%s: Failed to probe display driver\n",
1820be8f203SSimon Glass 			__func__);
1830be8f203SSimon Glass 			return -1;
1840be8f203SSimon Glass 		}
1850be8f203SSimon Glass 
1860be8f203SSimon Glass 		/* get panel details */
1870be8f203SSimon Glass 		if (fdt_decode_lcd(blob, &config)) {
1880be8f203SSimon Glass 			printf("No valid LCD information in device tree\n");
1890be8f203SSimon Glass 			return -1;
1900be8f203SSimon Glass 		}
1910be8f203SSimon Glass 
1920be8f203SSimon Glass 		/*
1930be8f203SSimon Glass 		 * It is possible that the FDT has requested that the LCD be
1940be8f203SSimon Glass 		 * disabled. We currently don't support this. It would require
1950be8f203SSimon Glass 		 * changes to U-Boot LCD subsystem to have LCD support
1960be8f203SSimon Glass 		 * compiled in but not used. An easier option might be to
1970be8f203SSimon Glass 		 * still have a frame buffer, but leave the backlight off and
1980be8f203SSimon Glass 		 * remove all mention of lcd in the stdout environment
1990be8f203SSimon Glass 		 * variable.
2000be8f203SSimon Glass 		 */
2010be8f203SSimon Glass 
2020be8f203SSimon Glass 		funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
2030be8f203SSimon Glass 		break;
2040be8f203SSimon Glass 	case STAGE_PANEL_VDD:
205*04072cbaSSimon Glass 		if (dm_gpio_is_valid(&config.panel_vdd))
206*04072cbaSSimon Glass 			dm_gpio_set_value(&config.panel_vdd, 1);
2070be8f203SSimon Glass 		break;
2080be8f203SSimon Glass 	case STAGE_LVDS:
209*04072cbaSSimon Glass 		if (dm_gpio_is_valid(&config.lvds_shutdown))
210*04072cbaSSimon Glass 			dm_gpio_set_value(&config.lvds_shutdown, 1);
2110be8f203SSimon Glass 		break;
2120be8f203SSimon Glass 	case STAGE_BACKLIGHT_VDD:
213*04072cbaSSimon Glass 		if (dm_gpio_is_valid(&config.backlight_vdd))
214*04072cbaSSimon Glass 			dm_gpio_set_value(&config.backlight_vdd, 1);
2150be8f203SSimon Glass 		break;
2160be8f203SSimon Glass 	case STAGE_PWM:
2170be8f203SSimon Glass 		/* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
21870ad375eSStephen Warren 		pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_PWM);
21970ad375eSStephen Warren 		pinmux_tristate_disable(PMUX_PINGRP_GPU);
2200be8f203SSimon Glass 
2210be8f203SSimon Glass 		pwm_enable(config.pwm_channel, 32768, 0xdf, 1);
2220be8f203SSimon Glass 		break;
2230be8f203SSimon Glass 	case STAGE_BACKLIGHT_EN:
224*04072cbaSSimon Glass 		if (dm_gpio_is_valid(&config.backlight_en))
225*04072cbaSSimon Glass 			dm_gpio_set_value(&config.backlight_en, 1);
2260be8f203SSimon Glass 		break;
2270be8f203SSimon Glass 	case STAGE_DONE:
2280be8f203SSimon Glass 		break;
2290be8f203SSimon Glass 	}
2300be8f203SSimon Glass 
2310be8f203SSimon Glass 	/* set up timer for next stage */
2320be8f203SSimon Glass 	timer_next = timer_get_us();
2330be8f203SSimon Glass 	if (stage < FDT_LCD_TIMINGS)
2340be8f203SSimon Glass 		timer_next += config.panel_timings[stage] * 1000;
2350be8f203SSimon Glass 
2360be8f203SSimon Glass 	/* move to next stage */
2370be8f203SSimon Glass 	stage++;
2380be8f203SSimon Glass 	return 0;
2390be8f203SSimon Glass }
2400be8f203SSimon Glass 
2410be8f203SSimon Glass int tegra_lcd_check_next_stage(const void *blob, int wait)
2420be8f203SSimon Glass {
2430be8f203SSimon Glass 	if (stage == STAGE_DONE)
2440be8f203SSimon Glass 		return 0;
2450be8f203SSimon Glass 
2460be8f203SSimon Glass 	do {
2470be8f203SSimon Glass 		/* wait if we need to */
2480be8f203SSimon Glass 		debug("%s: stage %d\n", __func__, stage);
2490be8f203SSimon Glass 		if (stage != STAGE_START) {
2500be8f203SSimon Glass 			int delay = timer_next - timer_get_us();
2510be8f203SSimon Glass 
2520be8f203SSimon Glass 			if (delay > 0) {
2530be8f203SSimon Glass 				if (wait)
2540be8f203SSimon Glass 					udelay(delay);
2550be8f203SSimon Glass 				else
2560be8f203SSimon Glass 					return 0;
2570be8f203SSimon Glass 			}
2580be8f203SSimon Glass 		}
2590be8f203SSimon Glass 
2600be8f203SSimon Glass 		if (handle_stage(blob))
2610be8f203SSimon Glass 			return -1;
2620be8f203SSimon Glass 	} while (wait && stage != STAGE_DONE);
2630be8f203SSimon Glass 	if (stage == STAGE_DONE)
2640be8f203SSimon Glass 		debug("%s: LCD init complete\n", __func__);
2650be8f203SSimon Glass 
2660be8f203SSimon Glass 	return 0;
2670be8f203SSimon Glass }
2680be8f203SSimon Glass 
2690be8f203SSimon Glass void lcd_enable(void)
2700be8f203SSimon Glass {
2710be8f203SSimon Glass 	/*
2720be8f203SSimon Glass 	 * Backlight and power init will be done separately in
2730be8f203SSimon Glass 	 * tegra_lcd_check_next_stage(), which should be called in
2740be8f203SSimon Glass 	 * board_late_init().
2750be8f203SSimon Glass 	 *
2760be8f203SSimon Glass 	 * U-Boot code supports only colour depth, selected at compile time.
2770be8f203SSimon Glass 	 * The device tree setting should match this. Otherwise the display
2780be8f203SSimon Glass 	 * will not look right, and U-Boot may crash.
2790be8f203SSimon Glass 	 */
2800be8f203SSimon Glass 	if (disp_config->log2_bpp != LCD_BPP) {
2810be8f203SSimon Glass 		printf("%s: Error: LCD depth configured in FDT (%d = %dbpp)"
2820be8f203SSimon Glass 			" must match setting of LCD_BPP (%d)\n", __func__,
2830be8f203SSimon Glass 		       disp_config->log2_bpp, disp_config->bpp, LCD_BPP);
2840be8f203SSimon Glass 	}
2850be8f203SSimon Glass }
286