108a7aa1eSSimon Glass /*
208a7aa1eSSimon Glass  * Copyright (C) 2012 Samsung Electronics
308a7aa1eSSimon Glass  *
408a7aa1eSSimon Glass  * Author: InKi Dae <inki.dae@samsung.com>
508a7aa1eSSimon Glass  * Author: Donghwa Lee <dh09.lee@samsung.com>
608a7aa1eSSimon Glass  *
708a7aa1eSSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
808a7aa1eSSimon Glass  */
908a7aa1eSSimon Glass 
1008a7aa1eSSimon Glass #include <config.h>
1108a7aa1eSSimon Glass #include <common.h>
1208a7aa1eSSimon Glass #include <lcd.h>
1308a7aa1eSSimon Glass #include <fdtdec.h>
1408a7aa1eSSimon Glass #include <libfdt.h>
1508a7aa1eSSimon Glass #include <asm/io.h>
1608a7aa1eSSimon Glass #include <asm/arch/cpu.h>
1708a7aa1eSSimon Glass #include <asm/arch/clock.h>
1808a7aa1eSSimon Glass #include <asm/arch/clk.h>
1908a7aa1eSSimon Glass #include <asm/arch/mipi_dsim.h>
2008a7aa1eSSimon Glass #include <asm/arch/dp_info.h>
2108a7aa1eSSimon Glass #include <asm/arch/system.h>
2208a7aa1eSSimon Glass #include <asm/gpio.h>
2308a7aa1eSSimon Glass #include <asm-generic/errno.h>
2408a7aa1eSSimon Glass 
2508a7aa1eSSimon Glass #include "exynos_fb.h"
2608a7aa1eSSimon Glass 
2708a7aa1eSSimon Glass DECLARE_GLOBAL_DATA_PTR;
2808a7aa1eSSimon Glass 
2908a7aa1eSSimon Glass static unsigned int panel_width, panel_height;
3008a7aa1eSSimon Glass 
31*aaca5b19SSimon Glass struct vidinfo panel_info  = {
3208a7aa1eSSimon Glass 	/*
3308a7aa1eSSimon Glass 	 * Insert a value here so that we don't end up in the BSS
3408a7aa1eSSimon Glass 	 * Reference: drivers/video/tegra.c
3508a7aa1eSSimon Glass 	 */
3608a7aa1eSSimon Glass 	.vl_col = -1,
3708a7aa1eSSimon Glass };
3808a7aa1eSSimon Glass 
3908a7aa1eSSimon Glass ushort *configuration_get_cmap(void)
4008a7aa1eSSimon Glass {
4108a7aa1eSSimon Glass #if defined(CONFIG_LCD_LOGO)
4208a7aa1eSSimon Glass 	return bmp_logo_palette;
4308a7aa1eSSimon Glass #else
4408a7aa1eSSimon Glass 	return NULL;
4508a7aa1eSSimon Glass #endif
4608a7aa1eSSimon Glass }
4708a7aa1eSSimon Glass 
48*aaca5b19SSimon Glass static void exynos_lcd_init_mem(void *lcdbase, struct vidinfo *vid)
4908a7aa1eSSimon Glass {
5008a7aa1eSSimon Glass 	unsigned long palette_size;
5108a7aa1eSSimon Glass 	unsigned int fb_size;
5208a7aa1eSSimon Glass 
5308a7aa1eSSimon Glass 	fb_size = vid->vl_row * vid->vl_col * (NBITS(vid->vl_bpix) >> 3);
5408a7aa1eSSimon Glass 
5508a7aa1eSSimon Glass 	palette_size = NBITS(vid->vl_bpix) == 8 ? 256 : 16;
5608a7aa1eSSimon Glass 
5708a7aa1eSSimon Glass 	exynos_fimd_lcd_init_mem((unsigned long)lcdbase,
5808a7aa1eSSimon Glass 			(unsigned long)fb_size, palette_size);
5908a7aa1eSSimon Glass }
6008a7aa1eSSimon Glass 
61*aaca5b19SSimon Glass static void exynos_lcd_init(struct vidinfo *vid)
6208a7aa1eSSimon Glass {
6308a7aa1eSSimon Glass 	exynos_fimd_lcd_init(vid);
6408a7aa1eSSimon Glass 
6508a7aa1eSSimon Glass 	/* Enable flushing after LCD writes if requested */
6608a7aa1eSSimon Glass 	lcd_set_flush_dcache(1);
6708a7aa1eSSimon Glass }
6808a7aa1eSSimon Glass 
6908a7aa1eSSimon Glass __weak void exynos_cfg_lcd_gpio(void)
7008a7aa1eSSimon Glass {
7108a7aa1eSSimon Glass }
7208a7aa1eSSimon Glass 
7308a7aa1eSSimon Glass __weak void exynos_backlight_on(unsigned int onoff)
7408a7aa1eSSimon Glass {
7508a7aa1eSSimon Glass }
7608a7aa1eSSimon Glass 
7708a7aa1eSSimon Glass __weak void exynos_reset_lcd(void)
7808a7aa1eSSimon Glass {
7908a7aa1eSSimon Glass }
8008a7aa1eSSimon Glass 
8108a7aa1eSSimon Glass __weak void exynos_lcd_power_on(void)
8208a7aa1eSSimon Glass {
8308a7aa1eSSimon Glass }
8408a7aa1eSSimon Glass 
8508a7aa1eSSimon Glass __weak void exynos_cfg_ldo(void)
8608a7aa1eSSimon Glass {
8708a7aa1eSSimon Glass }
8808a7aa1eSSimon Glass 
8908a7aa1eSSimon Glass __weak void exynos_enable_ldo(unsigned int onoff)
9008a7aa1eSSimon Glass {
9108a7aa1eSSimon Glass }
9208a7aa1eSSimon Glass 
9308a7aa1eSSimon Glass __weak void exynos_backlight_reset(void)
9408a7aa1eSSimon Glass {
9508a7aa1eSSimon Glass }
9608a7aa1eSSimon Glass 
97*aaca5b19SSimon Glass __weak int exynos_lcd_misc_init(struct vidinfo *vid)
9808a7aa1eSSimon Glass {
9908a7aa1eSSimon Glass 	return 0;
10008a7aa1eSSimon Glass }
10108a7aa1eSSimon Glass 
102*aaca5b19SSimon Glass static void lcd_panel_on(struct vidinfo *vid)
10308a7aa1eSSimon Glass {
10408a7aa1eSSimon Glass 	struct gpio_desc pwm_out_gpio;
10508a7aa1eSSimon Glass 	struct gpio_desc bl_en_gpio;
10608a7aa1eSSimon Glass 	unsigned int node;
10708a7aa1eSSimon Glass 
10808a7aa1eSSimon Glass 	udelay(vid->init_delay);
10908a7aa1eSSimon Glass 
11008a7aa1eSSimon Glass 	exynos_backlight_reset();
11108a7aa1eSSimon Glass 
11208a7aa1eSSimon Glass 	exynos_cfg_lcd_gpio();
11308a7aa1eSSimon Glass 
11408a7aa1eSSimon Glass 	exynos_lcd_power_on();
11508a7aa1eSSimon Glass 
11608a7aa1eSSimon Glass 	udelay(vid->power_on_delay);
11708a7aa1eSSimon Glass 
11808a7aa1eSSimon Glass 	if (vid->dp_enabled)
11908a7aa1eSSimon Glass 		exynos_init_dp();
12008a7aa1eSSimon Glass 
12108a7aa1eSSimon Glass 	exynos_reset_lcd();
12208a7aa1eSSimon Glass 
12308a7aa1eSSimon Glass 	udelay(vid->reset_delay);
12408a7aa1eSSimon Glass 
12508a7aa1eSSimon Glass 	exynos_backlight_on(1);
12608a7aa1eSSimon Glass 
12708a7aa1eSSimon Glass 	node = fdtdec_next_compatible(gd->fdt_blob, 0,
12808a7aa1eSSimon Glass 						COMPAT_SAMSUNG_EXYNOS_FIMD);
12908a7aa1eSSimon Glass 	if (node <= 0) {
13008a7aa1eSSimon Glass 		debug("FIMD: Can't get device node for FIMD\n");
13108a7aa1eSSimon Glass 		return;
13208a7aa1eSSimon Glass 	}
13308a7aa1eSSimon Glass 	gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,pwm-out-gpio",
13408a7aa1eSSimon Glass 				   0, &pwm_out_gpio,
13508a7aa1eSSimon Glass 				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
13608a7aa1eSSimon Glass 
13708a7aa1eSSimon Glass 	gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,bl-en-gpio", 0,
13808a7aa1eSSimon Glass 				   &bl_en_gpio,
13908a7aa1eSSimon Glass 				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
14008a7aa1eSSimon Glass 
14108a7aa1eSSimon Glass 	exynos_cfg_ldo();
14208a7aa1eSSimon Glass 
14308a7aa1eSSimon Glass 	exynos_enable_ldo(1);
14408a7aa1eSSimon Glass 
14508a7aa1eSSimon Glass 	if (vid->mipi_enabled)
14608a7aa1eSSimon Glass 		exynos_mipi_dsi_init();
14708a7aa1eSSimon Glass }
14808a7aa1eSSimon Glass 
14908a7aa1eSSimon Glass int exynos_lcd_early_init(const void *blob)
15008a7aa1eSSimon Glass {
15108a7aa1eSSimon Glass 	unsigned int node;
15208a7aa1eSSimon Glass 	node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_FIMD);
15308a7aa1eSSimon Glass 	if (node <= 0) {
15408a7aa1eSSimon Glass 		debug("exynos_fb: Can't get device node for fimd\n");
15508a7aa1eSSimon Glass 		return -ENODEV;
15608a7aa1eSSimon Glass 	}
15708a7aa1eSSimon Glass 
15808a7aa1eSSimon Glass 	panel_info.vl_col = fdtdec_get_int(blob, node, "samsung,vl-col", 0);
15908a7aa1eSSimon Glass 	if (panel_info.vl_col == 0) {
16008a7aa1eSSimon Glass 		debug("Can't get XRES\n");
16108a7aa1eSSimon Glass 		return -ENXIO;
16208a7aa1eSSimon Glass 	}
16308a7aa1eSSimon Glass 
16408a7aa1eSSimon Glass 	panel_info.vl_row = fdtdec_get_int(blob, node, "samsung,vl-row", 0);
16508a7aa1eSSimon Glass 	if (panel_info.vl_row == 0) {
16608a7aa1eSSimon Glass 		debug("Can't get YRES\n");
16708a7aa1eSSimon Glass 		return -ENXIO;
16808a7aa1eSSimon Glass 	}
16908a7aa1eSSimon Glass 
17008a7aa1eSSimon Glass 	panel_info.vl_width = fdtdec_get_int(blob, node,
17108a7aa1eSSimon Glass 						"samsung,vl-width", 0);
17208a7aa1eSSimon Glass 
17308a7aa1eSSimon Glass 	panel_info.vl_height = fdtdec_get_int(blob, node,
17408a7aa1eSSimon Glass 						"samsung,vl-height", 0);
17508a7aa1eSSimon Glass 
17608a7aa1eSSimon Glass 	panel_info.vl_freq = fdtdec_get_int(blob, node, "samsung,vl-freq", 0);
17708a7aa1eSSimon Glass 	if (panel_info.vl_freq == 0) {
17808a7aa1eSSimon Glass 		debug("Can't get refresh rate\n");
17908a7aa1eSSimon Glass 		return -ENXIO;
18008a7aa1eSSimon Glass 	}
18108a7aa1eSSimon Glass 
18208a7aa1eSSimon Glass 	if (fdtdec_get_bool(blob, node, "samsung,vl-clkp"))
18308a7aa1eSSimon Glass 		panel_info.vl_clkp = CONFIG_SYS_LOW;
18408a7aa1eSSimon Glass 
18508a7aa1eSSimon Glass 	if (fdtdec_get_bool(blob, node, "samsung,vl-oep"))
18608a7aa1eSSimon Glass 		panel_info.vl_oep = CONFIG_SYS_LOW;
18708a7aa1eSSimon Glass 
18808a7aa1eSSimon Glass 	if (fdtdec_get_bool(blob, node, "samsung,vl-hsp"))
18908a7aa1eSSimon Glass 		panel_info.vl_hsp = CONFIG_SYS_LOW;
19008a7aa1eSSimon Glass 
19108a7aa1eSSimon Glass 	if (fdtdec_get_bool(blob, node, "samsung,vl-vsp"))
19208a7aa1eSSimon Glass 		panel_info.vl_vsp = CONFIG_SYS_LOW;
19308a7aa1eSSimon Glass 
19408a7aa1eSSimon Glass 	if (fdtdec_get_bool(blob, node, "samsung,vl-dp"))
19508a7aa1eSSimon Glass 		panel_info.vl_dp = CONFIG_SYS_LOW;
19608a7aa1eSSimon Glass 
19708a7aa1eSSimon Glass 	panel_info.vl_bpix = fdtdec_get_int(blob, node, "samsung,vl-bpix", 0);
19808a7aa1eSSimon Glass 	if (panel_info.vl_bpix == 0) {
19908a7aa1eSSimon Glass 		debug("Can't get bits per pixel\n");
20008a7aa1eSSimon Glass 		return -ENXIO;
20108a7aa1eSSimon Glass 	}
20208a7aa1eSSimon Glass 
20308a7aa1eSSimon Glass 	panel_info.vl_hspw = fdtdec_get_int(blob, node, "samsung,vl-hspw", 0);
20408a7aa1eSSimon Glass 	if (panel_info.vl_hspw == 0) {
20508a7aa1eSSimon Glass 		debug("Can't get hsync width\n");
20608a7aa1eSSimon Glass 		return -ENXIO;
20708a7aa1eSSimon Glass 	}
20808a7aa1eSSimon Glass 
20908a7aa1eSSimon Glass 	panel_info.vl_hfpd = fdtdec_get_int(blob, node, "samsung,vl-hfpd", 0);
21008a7aa1eSSimon Glass 	if (panel_info.vl_hfpd == 0) {
21108a7aa1eSSimon Glass 		debug("Can't get right margin\n");
21208a7aa1eSSimon Glass 		return -ENXIO;
21308a7aa1eSSimon Glass 	}
21408a7aa1eSSimon Glass 
21508a7aa1eSSimon Glass 	panel_info.vl_hbpd = (u_char)fdtdec_get_int(blob, node,
21608a7aa1eSSimon Glass 							"samsung,vl-hbpd", 0);
21708a7aa1eSSimon Glass 	if (panel_info.vl_hbpd == 0) {
21808a7aa1eSSimon Glass 		debug("Can't get left margin\n");
21908a7aa1eSSimon Glass 		return -ENXIO;
22008a7aa1eSSimon Glass 	}
22108a7aa1eSSimon Glass 
22208a7aa1eSSimon Glass 	panel_info.vl_vspw = (u_char)fdtdec_get_int(blob, node,
22308a7aa1eSSimon Glass 							"samsung,vl-vspw", 0);
22408a7aa1eSSimon Glass 	if (panel_info.vl_vspw == 0) {
22508a7aa1eSSimon Glass 		debug("Can't get vsync width\n");
22608a7aa1eSSimon Glass 		return -ENXIO;
22708a7aa1eSSimon Glass 	}
22808a7aa1eSSimon Glass 
22908a7aa1eSSimon Glass 	panel_info.vl_vfpd = fdtdec_get_int(blob, node,
23008a7aa1eSSimon Glass 							"samsung,vl-vfpd", 0);
23108a7aa1eSSimon Glass 	if (panel_info.vl_vfpd == 0) {
23208a7aa1eSSimon Glass 		debug("Can't get lower margin\n");
23308a7aa1eSSimon Glass 		return -ENXIO;
23408a7aa1eSSimon Glass 	}
23508a7aa1eSSimon Glass 
23608a7aa1eSSimon Glass 	panel_info.vl_vbpd = fdtdec_get_int(blob, node, "samsung,vl-vbpd", 0);
23708a7aa1eSSimon Glass 	if (panel_info.vl_vbpd == 0) {
23808a7aa1eSSimon Glass 		debug("Can't get upper margin\n");
23908a7aa1eSSimon Glass 		return -ENXIO;
24008a7aa1eSSimon Glass 	}
24108a7aa1eSSimon Glass 
24208a7aa1eSSimon Glass 	panel_info.vl_cmd_allow_len = fdtdec_get_int(blob, node,
24308a7aa1eSSimon Glass 						"samsung,vl-cmd-allow-len", 0);
24408a7aa1eSSimon Glass 
24508a7aa1eSSimon Glass 	panel_info.win_id = fdtdec_get_int(blob, node, "samsung,winid", 0);
24608a7aa1eSSimon Glass 	panel_info.init_delay = fdtdec_get_int(blob, node,
24708a7aa1eSSimon Glass 						"samsung,init-delay", 0);
24808a7aa1eSSimon Glass 	panel_info.power_on_delay = fdtdec_get_int(blob, node,
24908a7aa1eSSimon Glass 						"samsung,power-on-delay", 0);
25008a7aa1eSSimon Glass 	panel_info.reset_delay = fdtdec_get_int(blob, node,
25108a7aa1eSSimon Glass 						"samsung,reset-delay", 0);
25208a7aa1eSSimon Glass 	panel_info.interface_mode = fdtdec_get_int(blob, node,
25308a7aa1eSSimon Glass 						"samsung,interface-mode", 0);
25408a7aa1eSSimon Glass 	panel_info.mipi_enabled = fdtdec_get_int(blob, node,
25508a7aa1eSSimon Glass 						"samsung,mipi-enabled", 0);
25608a7aa1eSSimon Glass 	panel_info.dp_enabled = fdtdec_get_int(blob, node,
25708a7aa1eSSimon Glass 						"samsung,dp-enabled", 0);
25808a7aa1eSSimon Glass 	panel_info.cs_setup = fdtdec_get_int(blob, node,
25908a7aa1eSSimon Glass 						"samsung,cs-setup", 0);
26008a7aa1eSSimon Glass 	panel_info.wr_setup = fdtdec_get_int(blob, node,
26108a7aa1eSSimon Glass 						"samsung,wr-setup", 0);
26208a7aa1eSSimon Glass 	panel_info.wr_act = fdtdec_get_int(blob, node, "samsung,wr-act", 0);
26308a7aa1eSSimon Glass 	panel_info.wr_hold = fdtdec_get_int(blob, node, "samsung,wr-hold", 0);
26408a7aa1eSSimon Glass 
26508a7aa1eSSimon Glass 	panel_info.logo_on = fdtdec_get_int(blob, node, "samsung,logo-on", 0);
26608a7aa1eSSimon Glass 	if (panel_info.logo_on) {
26708a7aa1eSSimon Glass 		panel_info.logo_width = fdtdec_get_int(blob, node,
26808a7aa1eSSimon Glass 						"samsung,logo-width", 0);
26908a7aa1eSSimon Glass 		panel_info.logo_height = fdtdec_get_int(blob, node,
27008a7aa1eSSimon Glass 						"samsung,logo-height", 0);
27108a7aa1eSSimon Glass 		panel_info.logo_addr = fdtdec_get_int(blob, node,
27208a7aa1eSSimon Glass 						"samsung,logo-addr", 0);
27308a7aa1eSSimon Glass 	}
27408a7aa1eSSimon Glass 
27508a7aa1eSSimon Glass 	panel_info.rgb_mode = fdtdec_get_int(blob, node,
27608a7aa1eSSimon Glass 						"samsung,rgb-mode", 0);
27708a7aa1eSSimon Glass 	panel_info.pclk_name = fdtdec_get_int(blob, node,
27808a7aa1eSSimon Glass 						"samsung,pclk-name", 0);
27908a7aa1eSSimon Glass 	panel_info.sclk_div = fdtdec_get_int(blob, node,
28008a7aa1eSSimon Glass 						"samsung,sclk-div", 0);
28108a7aa1eSSimon Glass 	panel_info.dual_lcd_enabled = fdtdec_get_int(blob, node,
28208a7aa1eSSimon Glass 						"samsung,dual-lcd-enabled", 0);
28308a7aa1eSSimon Glass 
28408a7aa1eSSimon Glass 	return 0;
28508a7aa1eSSimon Glass }
28608a7aa1eSSimon Glass 
28708a7aa1eSSimon Glass void lcd_ctrl_init(void *lcdbase)
28808a7aa1eSSimon Glass {
28908a7aa1eSSimon Glass 	set_system_display_ctrl();
29008a7aa1eSSimon Glass 	set_lcd_clk();
29108a7aa1eSSimon Glass 
29208a7aa1eSSimon Glass #ifdef CONFIG_EXYNOS_MIPI_DSIM
29308a7aa1eSSimon Glass 	exynos_init_dsim_platform_data(&panel_info);
29408a7aa1eSSimon Glass #endif
29508a7aa1eSSimon Glass 	exynos_lcd_misc_init(&panel_info);
29608a7aa1eSSimon Glass 
29708a7aa1eSSimon Glass 	panel_width = panel_info.vl_width;
29808a7aa1eSSimon Glass 	panel_height = panel_info.vl_height;
29908a7aa1eSSimon Glass 
30008a7aa1eSSimon Glass 	exynos_lcd_init_mem(lcdbase, &panel_info);
30108a7aa1eSSimon Glass 
30208a7aa1eSSimon Glass 	exynos_lcd_init(&panel_info);
30308a7aa1eSSimon Glass }
30408a7aa1eSSimon Glass 
30508a7aa1eSSimon Glass void lcd_enable(void)
30608a7aa1eSSimon Glass {
30708a7aa1eSSimon Glass 	if (panel_info.logo_on) {
30808a7aa1eSSimon Glass 		memset((void *) gd->fb_base, 0, panel_width * panel_height *
30908a7aa1eSSimon Glass 				(NBITS(panel_info.vl_bpix) >> 3));
31008a7aa1eSSimon Glass 	}
31108a7aa1eSSimon Glass 
31208a7aa1eSSimon Glass 	lcd_panel_on(&panel_info);
31308a7aa1eSSimon Glass }
31408a7aa1eSSimon Glass 
31508a7aa1eSSimon Glass /* dummy function */
31608a7aa1eSSimon Glass void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
31708a7aa1eSSimon Glass {
31808a7aa1eSSimon Glass 	return;
31908a7aa1eSSimon Glass }
320