1*08a7aa1eSSimon Glass /* 2*08a7aa1eSSimon Glass * Copyright (C) 2012 Samsung Electronics 3*08a7aa1eSSimon Glass * 4*08a7aa1eSSimon Glass * Author: InKi Dae <inki.dae@samsung.com> 5*08a7aa1eSSimon Glass * Author: Donghwa Lee <dh09.lee@samsung.com> 6*08a7aa1eSSimon Glass * 7*08a7aa1eSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 8*08a7aa1eSSimon Glass */ 9*08a7aa1eSSimon Glass 10*08a7aa1eSSimon Glass #include <config.h> 11*08a7aa1eSSimon Glass #include <common.h> 12*08a7aa1eSSimon Glass #include <lcd.h> 13*08a7aa1eSSimon Glass #include <fdtdec.h> 14*08a7aa1eSSimon Glass #include <libfdt.h> 15*08a7aa1eSSimon Glass #include <asm/io.h> 16*08a7aa1eSSimon Glass #include <asm/arch/cpu.h> 17*08a7aa1eSSimon Glass #include <asm/arch/clock.h> 18*08a7aa1eSSimon Glass #include <asm/arch/clk.h> 19*08a7aa1eSSimon Glass #include <asm/arch/mipi_dsim.h> 20*08a7aa1eSSimon Glass #include <asm/arch/dp_info.h> 21*08a7aa1eSSimon Glass #include <asm/arch/system.h> 22*08a7aa1eSSimon Glass #include <asm/gpio.h> 23*08a7aa1eSSimon Glass #include <asm-generic/errno.h> 24*08a7aa1eSSimon Glass 25*08a7aa1eSSimon Glass #include "exynos_fb.h" 26*08a7aa1eSSimon Glass 27*08a7aa1eSSimon Glass DECLARE_GLOBAL_DATA_PTR; 28*08a7aa1eSSimon Glass 29*08a7aa1eSSimon Glass static unsigned int panel_width, panel_height; 30*08a7aa1eSSimon Glass 31*08a7aa1eSSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL) 32*08a7aa1eSSimon Glass vidinfo_t panel_info = { 33*08a7aa1eSSimon Glass /* 34*08a7aa1eSSimon Glass * Insert a value here so that we don't end up in the BSS 35*08a7aa1eSSimon Glass * Reference: drivers/video/tegra.c 36*08a7aa1eSSimon Glass */ 37*08a7aa1eSSimon Glass .vl_col = -1, 38*08a7aa1eSSimon Glass }; 39*08a7aa1eSSimon Glass #endif 40*08a7aa1eSSimon Glass 41*08a7aa1eSSimon Glass ushort *configuration_get_cmap(void) 42*08a7aa1eSSimon Glass { 43*08a7aa1eSSimon Glass #if defined(CONFIG_LCD_LOGO) 44*08a7aa1eSSimon Glass return bmp_logo_palette; 45*08a7aa1eSSimon Glass #else 46*08a7aa1eSSimon Glass return NULL; 47*08a7aa1eSSimon Glass #endif 48*08a7aa1eSSimon Glass } 49*08a7aa1eSSimon Glass 50*08a7aa1eSSimon Glass static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid) 51*08a7aa1eSSimon Glass { 52*08a7aa1eSSimon Glass unsigned long palette_size; 53*08a7aa1eSSimon Glass unsigned int fb_size; 54*08a7aa1eSSimon Glass 55*08a7aa1eSSimon Glass fb_size = vid->vl_row * vid->vl_col * (NBITS(vid->vl_bpix) >> 3); 56*08a7aa1eSSimon Glass 57*08a7aa1eSSimon Glass palette_size = NBITS(vid->vl_bpix) == 8 ? 256 : 16; 58*08a7aa1eSSimon Glass 59*08a7aa1eSSimon Glass exynos_fimd_lcd_init_mem((unsigned long)lcdbase, 60*08a7aa1eSSimon Glass (unsigned long)fb_size, palette_size); 61*08a7aa1eSSimon Glass } 62*08a7aa1eSSimon Glass 63*08a7aa1eSSimon Glass static void exynos_lcd_init(vidinfo_t *vid) 64*08a7aa1eSSimon Glass { 65*08a7aa1eSSimon Glass exynos_fimd_lcd_init(vid); 66*08a7aa1eSSimon Glass 67*08a7aa1eSSimon Glass /* Enable flushing after LCD writes if requested */ 68*08a7aa1eSSimon Glass lcd_set_flush_dcache(1); 69*08a7aa1eSSimon Glass } 70*08a7aa1eSSimon Glass 71*08a7aa1eSSimon Glass __weak void exynos_cfg_lcd_gpio(void) 72*08a7aa1eSSimon Glass { 73*08a7aa1eSSimon Glass } 74*08a7aa1eSSimon Glass 75*08a7aa1eSSimon Glass __weak void exynos_backlight_on(unsigned int onoff) 76*08a7aa1eSSimon Glass { 77*08a7aa1eSSimon Glass } 78*08a7aa1eSSimon Glass 79*08a7aa1eSSimon Glass __weak void exynos_reset_lcd(void) 80*08a7aa1eSSimon Glass { 81*08a7aa1eSSimon Glass } 82*08a7aa1eSSimon Glass 83*08a7aa1eSSimon Glass __weak void exynos_lcd_power_on(void) 84*08a7aa1eSSimon Glass { 85*08a7aa1eSSimon Glass } 86*08a7aa1eSSimon Glass 87*08a7aa1eSSimon Glass __weak void exynos_cfg_ldo(void) 88*08a7aa1eSSimon Glass { 89*08a7aa1eSSimon Glass } 90*08a7aa1eSSimon Glass 91*08a7aa1eSSimon Glass __weak void exynos_enable_ldo(unsigned int onoff) 92*08a7aa1eSSimon Glass { 93*08a7aa1eSSimon Glass } 94*08a7aa1eSSimon Glass 95*08a7aa1eSSimon Glass __weak void exynos_backlight_reset(void) 96*08a7aa1eSSimon Glass { 97*08a7aa1eSSimon Glass } 98*08a7aa1eSSimon Glass 99*08a7aa1eSSimon Glass __weak int exynos_lcd_misc_init(vidinfo_t *vid) 100*08a7aa1eSSimon Glass { 101*08a7aa1eSSimon Glass return 0; 102*08a7aa1eSSimon Glass } 103*08a7aa1eSSimon Glass 104*08a7aa1eSSimon Glass static void lcd_panel_on(vidinfo_t *vid) 105*08a7aa1eSSimon Glass { 106*08a7aa1eSSimon Glass struct gpio_desc pwm_out_gpio; 107*08a7aa1eSSimon Glass struct gpio_desc bl_en_gpio; 108*08a7aa1eSSimon Glass unsigned int node; 109*08a7aa1eSSimon Glass 110*08a7aa1eSSimon Glass udelay(vid->init_delay); 111*08a7aa1eSSimon Glass 112*08a7aa1eSSimon Glass exynos_backlight_reset(); 113*08a7aa1eSSimon Glass 114*08a7aa1eSSimon Glass exynos_cfg_lcd_gpio(); 115*08a7aa1eSSimon Glass 116*08a7aa1eSSimon Glass exynos_lcd_power_on(); 117*08a7aa1eSSimon Glass 118*08a7aa1eSSimon Glass udelay(vid->power_on_delay); 119*08a7aa1eSSimon Glass 120*08a7aa1eSSimon Glass if (vid->dp_enabled) 121*08a7aa1eSSimon Glass exynos_init_dp(); 122*08a7aa1eSSimon Glass 123*08a7aa1eSSimon Glass exynos_reset_lcd(); 124*08a7aa1eSSimon Glass 125*08a7aa1eSSimon Glass udelay(vid->reset_delay); 126*08a7aa1eSSimon Glass 127*08a7aa1eSSimon Glass exynos_backlight_on(1); 128*08a7aa1eSSimon Glass 129*08a7aa1eSSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL) 130*08a7aa1eSSimon Glass node = fdtdec_next_compatible(gd->fdt_blob, 0, 131*08a7aa1eSSimon Glass COMPAT_SAMSUNG_EXYNOS_FIMD); 132*08a7aa1eSSimon Glass if (node <= 0) { 133*08a7aa1eSSimon Glass debug("FIMD: Can't get device node for FIMD\n"); 134*08a7aa1eSSimon Glass return; 135*08a7aa1eSSimon Glass } 136*08a7aa1eSSimon Glass gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,pwm-out-gpio", 137*08a7aa1eSSimon Glass 0, &pwm_out_gpio, 138*08a7aa1eSSimon Glass GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); 139*08a7aa1eSSimon Glass 140*08a7aa1eSSimon Glass gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,bl-en-gpio", 0, 141*08a7aa1eSSimon Glass &bl_en_gpio, 142*08a7aa1eSSimon Glass GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); 143*08a7aa1eSSimon Glass 144*08a7aa1eSSimon Glass #endif 145*08a7aa1eSSimon Glass exynos_cfg_ldo(); 146*08a7aa1eSSimon Glass 147*08a7aa1eSSimon Glass exynos_enable_ldo(1); 148*08a7aa1eSSimon Glass 149*08a7aa1eSSimon Glass if (vid->mipi_enabled) 150*08a7aa1eSSimon Glass exynos_mipi_dsi_init(); 151*08a7aa1eSSimon Glass } 152*08a7aa1eSSimon Glass 153*08a7aa1eSSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL) 154*08a7aa1eSSimon Glass int exynos_lcd_early_init(const void *blob) 155*08a7aa1eSSimon Glass { 156*08a7aa1eSSimon Glass unsigned int node; 157*08a7aa1eSSimon Glass node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_FIMD); 158*08a7aa1eSSimon Glass if (node <= 0) { 159*08a7aa1eSSimon Glass debug("exynos_fb: Can't get device node for fimd\n"); 160*08a7aa1eSSimon Glass return -ENODEV; 161*08a7aa1eSSimon Glass } 162*08a7aa1eSSimon Glass 163*08a7aa1eSSimon Glass panel_info.vl_col = fdtdec_get_int(blob, node, "samsung,vl-col", 0); 164*08a7aa1eSSimon Glass if (panel_info.vl_col == 0) { 165*08a7aa1eSSimon Glass debug("Can't get XRES\n"); 166*08a7aa1eSSimon Glass return -ENXIO; 167*08a7aa1eSSimon Glass } 168*08a7aa1eSSimon Glass 169*08a7aa1eSSimon Glass panel_info.vl_row = fdtdec_get_int(blob, node, "samsung,vl-row", 0); 170*08a7aa1eSSimon Glass if (panel_info.vl_row == 0) { 171*08a7aa1eSSimon Glass debug("Can't get YRES\n"); 172*08a7aa1eSSimon Glass return -ENXIO; 173*08a7aa1eSSimon Glass } 174*08a7aa1eSSimon Glass 175*08a7aa1eSSimon Glass panel_info.vl_width = fdtdec_get_int(blob, node, 176*08a7aa1eSSimon Glass "samsung,vl-width", 0); 177*08a7aa1eSSimon Glass 178*08a7aa1eSSimon Glass panel_info.vl_height = fdtdec_get_int(blob, node, 179*08a7aa1eSSimon Glass "samsung,vl-height", 0); 180*08a7aa1eSSimon Glass 181*08a7aa1eSSimon Glass panel_info.vl_freq = fdtdec_get_int(blob, node, "samsung,vl-freq", 0); 182*08a7aa1eSSimon Glass if (panel_info.vl_freq == 0) { 183*08a7aa1eSSimon Glass debug("Can't get refresh rate\n"); 184*08a7aa1eSSimon Glass return -ENXIO; 185*08a7aa1eSSimon Glass } 186*08a7aa1eSSimon Glass 187*08a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-clkp")) 188*08a7aa1eSSimon Glass panel_info.vl_clkp = CONFIG_SYS_LOW; 189*08a7aa1eSSimon Glass 190*08a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-oep")) 191*08a7aa1eSSimon Glass panel_info.vl_oep = CONFIG_SYS_LOW; 192*08a7aa1eSSimon Glass 193*08a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-hsp")) 194*08a7aa1eSSimon Glass panel_info.vl_hsp = CONFIG_SYS_LOW; 195*08a7aa1eSSimon Glass 196*08a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-vsp")) 197*08a7aa1eSSimon Glass panel_info.vl_vsp = CONFIG_SYS_LOW; 198*08a7aa1eSSimon Glass 199*08a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-dp")) 200*08a7aa1eSSimon Glass panel_info.vl_dp = CONFIG_SYS_LOW; 201*08a7aa1eSSimon Glass 202*08a7aa1eSSimon Glass panel_info.vl_bpix = fdtdec_get_int(blob, node, "samsung,vl-bpix", 0); 203*08a7aa1eSSimon Glass if (panel_info.vl_bpix == 0) { 204*08a7aa1eSSimon Glass debug("Can't get bits per pixel\n"); 205*08a7aa1eSSimon Glass return -ENXIO; 206*08a7aa1eSSimon Glass } 207*08a7aa1eSSimon Glass 208*08a7aa1eSSimon Glass panel_info.vl_hspw = fdtdec_get_int(blob, node, "samsung,vl-hspw", 0); 209*08a7aa1eSSimon Glass if (panel_info.vl_hspw == 0) { 210*08a7aa1eSSimon Glass debug("Can't get hsync width\n"); 211*08a7aa1eSSimon Glass return -ENXIO; 212*08a7aa1eSSimon Glass } 213*08a7aa1eSSimon Glass 214*08a7aa1eSSimon Glass panel_info.vl_hfpd = fdtdec_get_int(blob, node, "samsung,vl-hfpd", 0); 215*08a7aa1eSSimon Glass if (panel_info.vl_hfpd == 0) { 216*08a7aa1eSSimon Glass debug("Can't get right margin\n"); 217*08a7aa1eSSimon Glass return -ENXIO; 218*08a7aa1eSSimon Glass } 219*08a7aa1eSSimon Glass 220*08a7aa1eSSimon Glass panel_info.vl_hbpd = (u_char)fdtdec_get_int(blob, node, 221*08a7aa1eSSimon Glass "samsung,vl-hbpd", 0); 222*08a7aa1eSSimon Glass if (panel_info.vl_hbpd == 0) { 223*08a7aa1eSSimon Glass debug("Can't get left margin\n"); 224*08a7aa1eSSimon Glass return -ENXIO; 225*08a7aa1eSSimon Glass } 226*08a7aa1eSSimon Glass 227*08a7aa1eSSimon Glass panel_info.vl_vspw = (u_char)fdtdec_get_int(blob, node, 228*08a7aa1eSSimon Glass "samsung,vl-vspw", 0); 229*08a7aa1eSSimon Glass if (panel_info.vl_vspw == 0) { 230*08a7aa1eSSimon Glass debug("Can't get vsync width\n"); 231*08a7aa1eSSimon Glass return -ENXIO; 232*08a7aa1eSSimon Glass } 233*08a7aa1eSSimon Glass 234*08a7aa1eSSimon Glass panel_info.vl_vfpd = fdtdec_get_int(blob, node, 235*08a7aa1eSSimon Glass "samsung,vl-vfpd", 0); 236*08a7aa1eSSimon Glass if (panel_info.vl_vfpd == 0) { 237*08a7aa1eSSimon Glass debug("Can't get lower margin\n"); 238*08a7aa1eSSimon Glass return -ENXIO; 239*08a7aa1eSSimon Glass } 240*08a7aa1eSSimon Glass 241*08a7aa1eSSimon Glass panel_info.vl_vbpd = fdtdec_get_int(blob, node, "samsung,vl-vbpd", 0); 242*08a7aa1eSSimon Glass if (panel_info.vl_vbpd == 0) { 243*08a7aa1eSSimon Glass debug("Can't get upper margin\n"); 244*08a7aa1eSSimon Glass return -ENXIO; 245*08a7aa1eSSimon Glass } 246*08a7aa1eSSimon Glass 247*08a7aa1eSSimon Glass panel_info.vl_cmd_allow_len = fdtdec_get_int(blob, node, 248*08a7aa1eSSimon Glass "samsung,vl-cmd-allow-len", 0); 249*08a7aa1eSSimon Glass 250*08a7aa1eSSimon Glass panel_info.win_id = fdtdec_get_int(blob, node, "samsung,winid", 0); 251*08a7aa1eSSimon Glass panel_info.init_delay = fdtdec_get_int(blob, node, 252*08a7aa1eSSimon Glass "samsung,init-delay", 0); 253*08a7aa1eSSimon Glass panel_info.power_on_delay = fdtdec_get_int(blob, node, 254*08a7aa1eSSimon Glass "samsung,power-on-delay", 0); 255*08a7aa1eSSimon Glass panel_info.reset_delay = fdtdec_get_int(blob, node, 256*08a7aa1eSSimon Glass "samsung,reset-delay", 0); 257*08a7aa1eSSimon Glass panel_info.interface_mode = fdtdec_get_int(blob, node, 258*08a7aa1eSSimon Glass "samsung,interface-mode", 0); 259*08a7aa1eSSimon Glass panel_info.mipi_enabled = fdtdec_get_int(blob, node, 260*08a7aa1eSSimon Glass "samsung,mipi-enabled", 0); 261*08a7aa1eSSimon Glass panel_info.dp_enabled = fdtdec_get_int(blob, node, 262*08a7aa1eSSimon Glass "samsung,dp-enabled", 0); 263*08a7aa1eSSimon Glass panel_info.cs_setup = fdtdec_get_int(blob, node, 264*08a7aa1eSSimon Glass "samsung,cs-setup", 0); 265*08a7aa1eSSimon Glass panel_info.wr_setup = fdtdec_get_int(blob, node, 266*08a7aa1eSSimon Glass "samsung,wr-setup", 0); 267*08a7aa1eSSimon Glass panel_info.wr_act = fdtdec_get_int(blob, node, "samsung,wr-act", 0); 268*08a7aa1eSSimon Glass panel_info.wr_hold = fdtdec_get_int(blob, node, "samsung,wr-hold", 0); 269*08a7aa1eSSimon Glass 270*08a7aa1eSSimon Glass panel_info.logo_on = fdtdec_get_int(blob, node, "samsung,logo-on", 0); 271*08a7aa1eSSimon Glass if (panel_info.logo_on) { 272*08a7aa1eSSimon Glass panel_info.logo_width = fdtdec_get_int(blob, node, 273*08a7aa1eSSimon Glass "samsung,logo-width", 0); 274*08a7aa1eSSimon Glass panel_info.logo_height = fdtdec_get_int(blob, node, 275*08a7aa1eSSimon Glass "samsung,logo-height", 0); 276*08a7aa1eSSimon Glass panel_info.logo_addr = fdtdec_get_int(blob, node, 277*08a7aa1eSSimon Glass "samsung,logo-addr", 0); 278*08a7aa1eSSimon Glass } 279*08a7aa1eSSimon Glass 280*08a7aa1eSSimon Glass panel_info.rgb_mode = fdtdec_get_int(blob, node, 281*08a7aa1eSSimon Glass "samsung,rgb-mode", 0); 282*08a7aa1eSSimon Glass panel_info.pclk_name = fdtdec_get_int(blob, node, 283*08a7aa1eSSimon Glass "samsung,pclk-name", 0); 284*08a7aa1eSSimon Glass panel_info.sclk_div = fdtdec_get_int(blob, node, 285*08a7aa1eSSimon Glass "samsung,sclk-div", 0); 286*08a7aa1eSSimon Glass panel_info.dual_lcd_enabled = fdtdec_get_int(blob, node, 287*08a7aa1eSSimon Glass "samsung,dual-lcd-enabled", 0); 288*08a7aa1eSSimon Glass 289*08a7aa1eSSimon Glass return 0; 290*08a7aa1eSSimon Glass } 291*08a7aa1eSSimon Glass #endif 292*08a7aa1eSSimon Glass 293*08a7aa1eSSimon Glass void lcd_ctrl_init(void *lcdbase) 294*08a7aa1eSSimon Glass { 295*08a7aa1eSSimon Glass set_system_display_ctrl(); 296*08a7aa1eSSimon Glass set_lcd_clk(); 297*08a7aa1eSSimon Glass 298*08a7aa1eSSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL) 299*08a7aa1eSSimon Glass #ifdef CONFIG_EXYNOS_MIPI_DSIM 300*08a7aa1eSSimon Glass exynos_init_dsim_platform_data(&panel_info); 301*08a7aa1eSSimon Glass #endif 302*08a7aa1eSSimon Glass exynos_lcd_misc_init(&panel_info); 303*08a7aa1eSSimon Glass #else 304*08a7aa1eSSimon Glass /* initialize parameters which is specific to panel. */ 305*08a7aa1eSSimon Glass init_panel_info(&panel_info); 306*08a7aa1eSSimon Glass #endif 307*08a7aa1eSSimon Glass 308*08a7aa1eSSimon Glass panel_width = panel_info.vl_width; 309*08a7aa1eSSimon Glass panel_height = panel_info.vl_height; 310*08a7aa1eSSimon Glass 311*08a7aa1eSSimon Glass exynos_lcd_init_mem(lcdbase, &panel_info); 312*08a7aa1eSSimon Glass 313*08a7aa1eSSimon Glass exynos_lcd_init(&panel_info); 314*08a7aa1eSSimon Glass } 315*08a7aa1eSSimon Glass 316*08a7aa1eSSimon Glass void lcd_enable(void) 317*08a7aa1eSSimon Glass { 318*08a7aa1eSSimon Glass if (panel_info.logo_on) { 319*08a7aa1eSSimon Glass memset((void *) gd->fb_base, 0, panel_width * panel_height * 320*08a7aa1eSSimon Glass (NBITS(panel_info.vl_bpix) >> 3)); 321*08a7aa1eSSimon Glass } 322*08a7aa1eSSimon Glass 323*08a7aa1eSSimon Glass lcd_panel_on(&panel_info); 324*08a7aa1eSSimon Glass } 325*08a7aa1eSSimon Glass 326*08a7aa1eSSimon Glass /* dummy function */ 327*08a7aa1eSSimon Glass void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) 328*08a7aa1eSSimon Glass { 329*08a7aa1eSSimon Glass return; 330*08a7aa1eSSimon Glass } 331