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> 120c84358cSSimon Glass #include <div64.h> 1308a7aa1eSSimon Glass #include <lcd.h> 1408a7aa1eSSimon Glass #include <fdtdec.h> 1508a7aa1eSSimon Glass #include <libfdt.h> 1608a7aa1eSSimon Glass #include <asm/io.h> 1708a7aa1eSSimon Glass #include <asm/arch/cpu.h> 1808a7aa1eSSimon Glass #include <asm/arch/clock.h> 1908a7aa1eSSimon Glass #include <asm/arch/clk.h> 2008a7aa1eSSimon Glass #include <asm/arch/mipi_dsim.h> 2108a7aa1eSSimon Glass #include <asm/arch/dp_info.h> 2208a7aa1eSSimon Glass #include <asm/arch/system.h> 2308a7aa1eSSimon Glass #include <asm/gpio.h> 2408a7aa1eSSimon Glass #include <asm-generic/errno.h> 2508a7aa1eSSimon Glass 2608a7aa1eSSimon Glass #include "exynos_fb.h" 2708a7aa1eSSimon Glass 2808a7aa1eSSimon Glass DECLARE_GLOBAL_DATA_PTR; 2908a7aa1eSSimon Glass 30aaca5b19SSimon Glass struct vidinfo panel_info = { 3108a7aa1eSSimon Glass /* 3208a7aa1eSSimon Glass * Insert a value here so that we don't end up in the BSS 3308a7aa1eSSimon Glass * Reference: drivers/video/tegra.c 3408a7aa1eSSimon Glass */ 3508a7aa1eSSimon Glass .vl_col = -1, 3608a7aa1eSSimon Glass }; 3708a7aa1eSSimon Glass 38*8b449a66SSimon Glass static void exynos_fimd_set_dualrgb(struct vidinfo *priv, unsigned int enabled) 390c84358cSSimon Glass { 40*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 410c84358cSSimon Glass unsigned int cfg = 0; 420c84358cSSimon Glass 430c84358cSSimon Glass if (enabled) { 440c84358cSSimon Glass cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT | 450c84358cSSimon Glass EXYNOS_DUALRGB_VDEN_EN_ENABLE; 460c84358cSSimon Glass 470c84358cSSimon Glass /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */ 48*8b449a66SSimon Glass cfg |= EXYNOS_DUALRGB_SUB_CNT(priv->vl_col / 2) | 490c84358cSSimon Glass EXYNOS_DUALRGB_MAIN_CNT(0); 500c84358cSSimon Glass } 510c84358cSSimon Glass 52*8b449a66SSimon Glass writel(cfg, ®->dualrgb); 530c84358cSSimon Glass } 540c84358cSSimon Glass 55*8b449a66SSimon Glass static void exynos_fimd_set_dp_clkcon(struct vidinfo *priv, 560c84358cSSimon Glass unsigned int enabled) 570c84358cSSimon Glass { 58*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 590c84358cSSimon Glass unsigned int cfg = 0; 600c84358cSSimon Glass 610c84358cSSimon Glass if (enabled) 620c84358cSSimon Glass cfg = EXYNOS_DP_CLK_ENABLE; 630c84358cSSimon Glass 64*8b449a66SSimon Glass writel(cfg, ®->dp_mie_clkcon); 650c84358cSSimon Glass } 660c84358cSSimon Glass 67*8b449a66SSimon Glass static void exynos_fimd_set_par(struct vidinfo *priv, unsigned int win_id) 680c84358cSSimon Glass { 69*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 700c84358cSSimon Glass unsigned int cfg = 0; 710c84358cSSimon Glass 720c84358cSSimon Glass /* set window control */ 73*8b449a66SSimon Glass cfg = readl((unsigned int)®->wincon0 + 740c84358cSSimon Glass EXYNOS_WINCON(win_id)); 750c84358cSSimon Glass 760c84358cSSimon Glass cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE | 770c84358cSSimon Glass EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE | 780c84358cSSimon Glass EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK | 790c84358cSSimon Glass EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK); 800c84358cSSimon Glass 810c84358cSSimon Glass /* DATAPATH is DMA */ 820c84358cSSimon Glass cfg |= EXYNOS_WINCON_DATAPATH_DMA; 830c84358cSSimon Glass 840c84358cSSimon Glass cfg |= EXYNOS_WINCON_HAWSWP_ENABLE; 850c84358cSSimon Glass 860c84358cSSimon Glass /* dma burst is 16 */ 870c84358cSSimon Glass cfg |= EXYNOS_WINCON_BURSTLEN_16WORD; 880c84358cSSimon Glass 89*8b449a66SSimon Glass switch (priv->vl_bpix) { 900c84358cSSimon Glass case 4: 910c84358cSSimon Glass cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565; 920c84358cSSimon Glass break; 930c84358cSSimon Glass default: 940c84358cSSimon Glass cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888; 950c84358cSSimon Glass break; 960c84358cSSimon Glass } 970c84358cSSimon Glass 98*8b449a66SSimon Glass writel(cfg, (unsigned int)®->wincon0 + 990c84358cSSimon Glass EXYNOS_WINCON(win_id)); 1000c84358cSSimon Glass 1010c84358cSSimon Glass /* set window position to x=0, y=0*/ 1020c84358cSSimon Glass cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0); 103*8b449a66SSimon Glass writel(cfg, (unsigned int)®->vidosd0a + 1040c84358cSSimon Glass EXYNOS_VIDOSD(win_id)); 1050c84358cSSimon Glass 106*8b449a66SSimon Glass cfg = EXYNOS_VIDOSD_RIGHT_X(priv->vl_col - 1) | 107*8b449a66SSimon Glass EXYNOS_VIDOSD_BOTTOM_Y(priv->vl_row - 1) | 1080c84358cSSimon Glass EXYNOS_VIDOSD_RIGHT_X_E(1) | 1090c84358cSSimon Glass EXYNOS_VIDOSD_BOTTOM_Y_E(0); 1100c84358cSSimon Glass 111*8b449a66SSimon Glass writel(cfg, (unsigned int)®->vidosd0b + 1120c84358cSSimon Glass EXYNOS_VIDOSD(win_id)); 1130c84358cSSimon Glass 1140c84358cSSimon Glass /* set window size for window0*/ 115*8b449a66SSimon Glass cfg = EXYNOS_VIDOSD_SIZE(priv->vl_col * priv->vl_row); 116*8b449a66SSimon Glass writel(cfg, (unsigned int)®->vidosd0c + 1170c84358cSSimon Glass EXYNOS_VIDOSD(win_id)); 1180c84358cSSimon Glass } 1190c84358cSSimon Glass 120*8b449a66SSimon Glass static void exynos_fimd_set_buffer_address(struct vidinfo *priv, 1210c84358cSSimon Glass unsigned int win_id, 1220c84358cSSimon Glass ulong lcd_base_addr) 1230c84358cSSimon Glass { 124*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 1250c84358cSSimon Glass unsigned long start_addr, end_addr; 1260c84358cSSimon Glass 1270c84358cSSimon Glass start_addr = lcd_base_addr; 128*8b449a66SSimon Glass end_addr = start_addr + ((priv->vl_col * (NBITS(priv->vl_bpix) / 8)) * 129*8b449a66SSimon Glass priv->vl_row); 1300c84358cSSimon Glass 131*8b449a66SSimon Glass writel(start_addr, (unsigned int)®->vidw00add0b0 + 1320c84358cSSimon Glass EXYNOS_BUFFER_OFFSET(win_id)); 133*8b449a66SSimon Glass writel(end_addr, (unsigned int)®->vidw00add1b0 + 1340c84358cSSimon Glass EXYNOS_BUFFER_OFFSET(win_id)); 1350c84358cSSimon Glass } 1360c84358cSSimon Glass 137*8b449a66SSimon Glass static void exynos_fimd_set_clock(struct vidinfo *priv) 1380c84358cSSimon Glass { 139*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 1400c84358cSSimon Glass unsigned int cfg = 0, div = 0, remainder, remainder_div; 1410c84358cSSimon Glass unsigned long pixel_clock; 1420c84358cSSimon Glass unsigned long long src_clock; 1430c84358cSSimon Glass 144*8b449a66SSimon Glass if (priv->dual_lcd_enabled) { 145*8b449a66SSimon Glass pixel_clock = priv->vl_freq * 146*8b449a66SSimon Glass (priv->vl_hspw + priv->vl_hfpd + 147*8b449a66SSimon Glass priv->vl_hbpd + priv->vl_col / 2) * 148*8b449a66SSimon Glass (priv->vl_vspw + priv->vl_vfpd + 149*8b449a66SSimon Glass priv->vl_vbpd + priv->vl_row); 150*8b449a66SSimon Glass } else if (priv->interface_mode == FIMD_CPU_INTERFACE) { 151*8b449a66SSimon Glass pixel_clock = priv->vl_freq * 152*8b449a66SSimon Glass priv->vl_width * priv->vl_height * 153*8b449a66SSimon Glass (priv->cs_setup + priv->wr_setup + 154*8b449a66SSimon Glass priv->wr_act + priv->wr_hold + 1); 1550c84358cSSimon Glass } else { 156*8b449a66SSimon Glass pixel_clock = priv->vl_freq * 157*8b449a66SSimon Glass (priv->vl_hspw + priv->vl_hfpd + 158*8b449a66SSimon Glass priv->vl_hbpd + priv->vl_col) * 159*8b449a66SSimon Glass (priv->vl_vspw + priv->vl_vfpd + 160*8b449a66SSimon Glass priv->vl_vbpd + priv->vl_row); 1610c84358cSSimon Glass } 1620c84358cSSimon Glass 163*8b449a66SSimon Glass cfg = readl(®->vidcon0); 1640c84358cSSimon Glass cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK | 1650c84358cSSimon Glass EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK | 1660c84358cSSimon Glass EXYNOS_VIDCON0_CLKDIR_MASK); 1670c84358cSSimon Glass cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS | 1680c84358cSSimon Glass EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED); 1690c84358cSSimon Glass 1700c84358cSSimon Glass src_clock = (unsigned long long) get_lcd_clk(); 1710c84358cSSimon Glass 1720c84358cSSimon Glass /* get quotient and remainder. */ 1730c84358cSSimon Glass remainder = do_div(src_clock, pixel_clock); 1740c84358cSSimon Glass div = src_clock; 1750c84358cSSimon Glass 1760c84358cSSimon Glass remainder *= 10; 1770c84358cSSimon Glass remainder_div = remainder / pixel_clock; 1780c84358cSSimon Glass 1790c84358cSSimon Glass /* round about one places of decimals. */ 1800c84358cSSimon Glass if (remainder_div >= 5) 1810c84358cSSimon Glass div++; 1820c84358cSSimon Glass 1830c84358cSSimon Glass /* in case of dual lcd mode. */ 184*8b449a66SSimon Glass if (priv->dual_lcd_enabled) 1850c84358cSSimon Glass div--; 1860c84358cSSimon Glass 1870c84358cSSimon Glass cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1); 188*8b449a66SSimon Glass writel(cfg, ®->vidcon0); 1890c84358cSSimon Glass } 1900c84358cSSimon Glass 191*8b449a66SSimon Glass void exynos_set_trigger(struct vidinfo *priv) 1920c84358cSSimon Glass { 193*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 1940c84358cSSimon Glass unsigned int cfg = 0; 1950c84358cSSimon Glass 196*8b449a66SSimon Glass cfg = readl(®->trigcon); 1970c84358cSSimon Glass 1980c84358cSSimon Glass cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG); 1990c84358cSSimon Glass 200*8b449a66SSimon Glass writel(cfg, ®->trigcon); 2010c84358cSSimon Glass } 2020c84358cSSimon Glass 203*8b449a66SSimon Glass int exynos_is_i80_frame_done(struct vidinfo *priv) 2040c84358cSSimon Glass { 205*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 2060c84358cSSimon Glass unsigned int cfg = 0; 2070c84358cSSimon Glass int status; 2080c84358cSSimon Glass 209*8b449a66SSimon Glass cfg = readl(®->trigcon); 2100c84358cSSimon Glass 2110c84358cSSimon Glass /* frame done func is valid only when TRIMODE[0] is set to 1. */ 2120c84358cSSimon Glass status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) == 2130c84358cSSimon Glass EXYNOS_I80STATUS_TRIG_DONE; 2140c84358cSSimon Glass 2150c84358cSSimon Glass return status; 2160c84358cSSimon Glass } 2170c84358cSSimon Glass 218*8b449a66SSimon Glass static void exynos_fimd_lcd_on(struct vidinfo *priv) 2190c84358cSSimon Glass { 220*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 2210c84358cSSimon Glass unsigned int cfg = 0; 2220c84358cSSimon Glass 2230c84358cSSimon Glass /* display on */ 224*8b449a66SSimon Glass cfg = readl(®->vidcon0); 2250c84358cSSimon Glass cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE); 226*8b449a66SSimon Glass writel(cfg, ®->vidcon0); 2270c84358cSSimon Glass } 2280c84358cSSimon Glass 229*8b449a66SSimon Glass static void exynos_fimd_window_on(struct vidinfo *priv, unsigned int win_id) 2300c84358cSSimon Glass { 231*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 2320c84358cSSimon Glass unsigned int cfg = 0; 2330c84358cSSimon Glass 2340c84358cSSimon Glass /* enable window */ 235*8b449a66SSimon Glass cfg = readl((unsigned int)®->wincon0 + 2360c84358cSSimon Glass EXYNOS_WINCON(win_id)); 2370c84358cSSimon Glass cfg |= EXYNOS_WINCON_ENWIN_ENABLE; 238*8b449a66SSimon Glass writel(cfg, (unsigned int)®->wincon0 + 2390c84358cSSimon Glass EXYNOS_WINCON(win_id)); 2400c84358cSSimon Glass 241*8b449a66SSimon Glass cfg = readl(®->winshmap); 2420c84358cSSimon Glass cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id); 243*8b449a66SSimon Glass writel(cfg, ®->winshmap); 2440c84358cSSimon Glass } 2450c84358cSSimon Glass 246*8b449a66SSimon Glass void exynos_fimd_lcd_off(struct vidinfo *priv) 2470c84358cSSimon Glass { 248*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 2490c84358cSSimon Glass unsigned int cfg = 0; 2500c84358cSSimon Glass 251*8b449a66SSimon Glass cfg = readl(®->vidcon0); 2520c84358cSSimon Glass cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE); 253*8b449a66SSimon Glass writel(cfg, ®->vidcon0); 2540c84358cSSimon Glass } 2550c84358cSSimon Glass 256*8b449a66SSimon Glass void exynos_fimd_window_off(struct vidinfo *priv, unsigned int win_id) 2570c84358cSSimon Glass { 258*8b449a66SSimon Glass struct exynos_fb *reg = priv->reg; 2590c84358cSSimon Glass unsigned int cfg = 0; 2600c84358cSSimon Glass 261*8b449a66SSimon Glass cfg = readl((unsigned int)®->wincon0 + 2620c84358cSSimon Glass EXYNOS_WINCON(win_id)); 2630c84358cSSimon Glass cfg &= EXYNOS_WINCON_ENWIN_DISABLE; 264*8b449a66SSimon Glass writel(cfg, (unsigned int)®->wincon0 + 2650c84358cSSimon Glass EXYNOS_WINCON(win_id)); 2660c84358cSSimon Glass 267*8b449a66SSimon Glass cfg = readl(®->winshmap); 2680c84358cSSimon Glass cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id); 269*8b449a66SSimon Glass writel(cfg, ®->winshmap); 2700c84358cSSimon Glass } 2710c84358cSSimon Glass 2720c84358cSSimon Glass /* 2730c84358cSSimon Glass * The reset value for FIMD SYSMMU register MMU_CTRL is 3 2740c84358cSSimon Glass * on Exynos5420 and newer versions. 2750c84358cSSimon Glass * This means FIMD SYSMMU is on by default on Exynos5420 2760c84358cSSimon Glass * and newer versions. 2770c84358cSSimon Glass * Since in u-boot we don't use SYSMMU, we should disable 2780c84358cSSimon Glass * those FIMD SYSMMU. 2790c84358cSSimon Glass * Note that there are 2 SYSMMU for FIMD: m0 and m1. 2800c84358cSSimon Glass * m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3. 2810c84358cSSimon Glass * We disable both of them here. 2820c84358cSSimon Glass */ 2830c84358cSSimon Glass void exynos_fimd_disable_sysmmu(void) 2840c84358cSSimon Glass { 2850c84358cSSimon Glass u32 *sysmmufimd; 2860c84358cSSimon Glass unsigned int node; 2870c84358cSSimon Glass int node_list[2]; 2880c84358cSSimon Glass int count; 2890c84358cSSimon Glass int i; 2900c84358cSSimon Glass 2910c84358cSSimon Glass count = fdtdec_find_aliases_for_id(gd->fdt_blob, "fimd", 2920c84358cSSimon Glass COMPAT_SAMSUNG_EXYNOS_SYSMMU, node_list, 2); 2930c84358cSSimon Glass for (i = 0; i < count; i++) { 2940c84358cSSimon Glass node = node_list[i]; 2950c84358cSSimon Glass if (node <= 0) { 2960c84358cSSimon Glass debug("Can't get device node for fimd sysmmu\n"); 2970c84358cSSimon Glass return; 2980c84358cSSimon Glass } 2990c84358cSSimon Glass 3000c84358cSSimon Glass sysmmufimd = (u32 *)fdtdec_get_addr(gd->fdt_blob, node, "reg"); 3010c84358cSSimon Glass if (!sysmmufimd) { 3020c84358cSSimon Glass debug("Can't get base address for sysmmu fimdm0"); 3030c84358cSSimon Glass return; 3040c84358cSSimon Glass } 3050c84358cSSimon Glass 3060c84358cSSimon Glass writel(0x0, sysmmufimd); 3070c84358cSSimon Glass } 3080c84358cSSimon Glass } 3090c84358cSSimon Glass 310*8b449a66SSimon Glass void exynos_fimd_lcd_init(struct vidinfo *priv, ulong lcd_base_address) 3110c84358cSSimon Glass { 312*8b449a66SSimon Glass struct exynos_fb *reg; 3130c84358cSSimon Glass unsigned int cfg = 0, rgb_mode; 3140c84358cSSimon Glass unsigned int offset; 3150c84358cSSimon Glass unsigned int node; 3160c84358cSSimon Glass 3170c84358cSSimon Glass node = fdtdec_next_compatible(gd->fdt_blob, 3180c84358cSSimon Glass 0, COMPAT_SAMSUNG_EXYNOS_FIMD); 3190c84358cSSimon Glass if (node <= 0) 3200c84358cSSimon Glass debug("exynos_fb: Can't get device node for fimd\n"); 3210c84358cSSimon Glass 322*8b449a66SSimon Glass reg = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, node, 3230c84358cSSimon Glass "reg"); 324*8b449a66SSimon Glass if (reg == NULL) 3250c84358cSSimon Glass debug("Can't get the FIMD base address\n"); 326*8b449a66SSimon Glass priv->reg = reg; 3270c84358cSSimon Glass 3280c84358cSSimon Glass if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu")) 3290c84358cSSimon Glass exynos_fimd_disable_sysmmu(); 3300c84358cSSimon Glass 3310c84358cSSimon Glass offset = exynos_fimd_get_base_offset(); 3320c84358cSSimon Glass 333*8b449a66SSimon Glass rgb_mode = priv->rgb_mode; 3340c84358cSSimon Glass 335*8b449a66SSimon Glass if (priv->interface_mode == FIMD_RGB_INTERFACE) { 3360c84358cSSimon Glass cfg |= EXYNOS_VIDCON0_VIDOUT_RGB; 337*8b449a66SSimon Glass writel(cfg, ®->vidcon0); 3380c84358cSSimon Glass 339*8b449a66SSimon Glass cfg = readl(®->vidcon2); 3400c84358cSSimon Glass cfg &= ~(EXYNOS_VIDCON2_WB_MASK | 3410c84358cSSimon Glass EXYNOS_VIDCON2_TVFORMATSEL_MASK | 3420c84358cSSimon Glass EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK); 3430c84358cSSimon Glass cfg |= EXYNOS_VIDCON2_WB_DISABLE; 344*8b449a66SSimon Glass writel(cfg, ®->vidcon2); 3450c84358cSSimon Glass 3460c84358cSSimon Glass /* set polarity */ 3470c84358cSSimon Glass cfg = 0; 348*8b449a66SSimon Glass if (!priv->vl_clkp) 3490c84358cSSimon Glass cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE; 350*8b449a66SSimon Glass if (!priv->vl_hsp) 3510c84358cSSimon Glass cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT; 352*8b449a66SSimon Glass if (!priv->vl_vsp) 3530c84358cSSimon Glass cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT; 354*8b449a66SSimon Glass if (!priv->vl_dp) 3550c84358cSSimon Glass cfg |= EXYNOS_VIDCON1_IVDEN_INVERT; 3560c84358cSSimon Glass 357*8b449a66SSimon Glass writel(cfg, (unsigned int)®->vidcon1 + offset); 3580c84358cSSimon Glass 3590c84358cSSimon Glass /* set timing */ 360*8b449a66SSimon Glass cfg = EXYNOS_VIDTCON0_VFPD(priv->vl_vfpd - 1); 361*8b449a66SSimon Glass cfg |= EXYNOS_VIDTCON0_VBPD(priv->vl_vbpd - 1); 362*8b449a66SSimon Glass cfg |= EXYNOS_VIDTCON0_VSPW(priv->vl_vspw - 1); 363*8b449a66SSimon Glass writel(cfg, (unsigned int)®->vidtcon0 + offset); 3640c84358cSSimon Glass 365*8b449a66SSimon Glass cfg = EXYNOS_VIDTCON1_HFPD(priv->vl_hfpd - 1); 366*8b449a66SSimon Glass cfg |= EXYNOS_VIDTCON1_HBPD(priv->vl_hbpd - 1); 367*8b449a66SSimon Glass cfg |= EXYNOS_VIDTCON1_HSPW(priv->vl_hspw - 1); 3680c84358cSSimon Glass 369*8b449a66SSimon Glass writel(cfg, (unsigned int)®->vidtcon1 + offset); 3700c84358cSSimon Glass 3710c84358cSSimon Glass /* set lcd size */ 372*8b449a66SSimon Glass cfg = EXYNOS_VIDTCON2_HOZVAL(priv->vl_col - 1) | 373*8b449a66SSimon Glass EXYNOS_VIDTCON2_LINEVAL(priv->vl_row - 1) | 374*8b449a66SSimon Glass EXYNOS_VIDTCON2_HOZVAL_E(priv->vl_col - 1) | 375*8b449a66SSimon Glass EXYNOS_VIDTCON2_LINEVAL_E(priv->vl_row - 1); 3760c84358cSSimon Glass 377*8b449a66SSimon Glass writel(cfg, (unsigned int)®->vidtcon2 + offset); 3780c84358cSSimon Glass } 3790c84358cSSimon Glass 3800c84358cSSimon Glass /* set display mode */ 381*8b449a66SSimon Glass cfg = readl(®->vidcon0); 3820c84358cSSimon Glass cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK; 3830c84358cSSimon Glass cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT); 384*8b449a66SSimon Glass writel(cfg, ®->vidcon0); 3850c84358cSSimon Glass 3860c84358cSSimon Glass /* set par */ 387*8b449a66SSimon Glass exynos_fimd_set_par(priv, priv->win_id); 3880c84358cSSimon Glass 3890c84358cSSimon Glass /* set memory address */ 390*8b449a66SSimon Glass exynos_fimd_set_buffer_address(priv, priv->win_id, lcd_base_address); 3910c84358cSSimon Glass 3920c84358cSSimon Glass /* set buffer size */ 393*8b449a66SSimon Glass cfg = EXYNOS_VIDADDR_PAGEWIDTH(priv->vl_col * 394*8b449a66SSimon Glass NBITS(priv->vl_bpix) / 8) | 395*8b449a66SSimon Glass EXYNOS_VIDADDR_PAGEWIDTH_E(priv->vl_col * 396*8b449a66SSimon Glass NBITS(priv->vl_bpix) / 8) | 3970c84358cSSimon Glass EXYNOS_VIDADDR_OFFSIZE(0) | 3980c84358cSSimon Glass EXYNOS_VIDADDR_OFFSIZE_E(0); 3990c84358cSSimon Glass 400*8b449a66SSimon Glass writel(cfg, (unsigned int)®->vidw00add2 + 401*8b449a66SSimon Glass EXYNOS_BUFFER_SIZE(priv->win_id)); 4020c84358cSSimon Glass 4030c84358cSSimon Glass /* set clock */ 404*8b449a66SSimon Glass exynos_fimd_set_clock(priv); 4050c84358cSSimon Glass 4060c84358cSSimon Glass /* set rgb mode to dual lcd. */ 407*8b449a66SSimon Glass exynos_fimd_set_dualrgb(priv, priv->dual_lcd_enabled); 4080c84358cSSimon Glass 4090c84358cSSimon Glass /* display on */ 410*8b449a66SSimon Glass exynos_fimd_lcd_on(priv); 4110c84358cSSimon Glass 4120c84358cSSimon Glass /* window on */ 413*8b449a66SSimon Glass exynos_fimd_window_on(priv, priv->win_id); 4140c84358cSSimon Glass 415*8b449a66SSimon Glass exynos_fimd_set_dp_clkcon(priv, priv->dp_enabled); 4160c84358cSSimon Glass } 4170c84358cSSimon Glass 418*8b449a66SSimon Glass unsigned long exynos_fimd_calc_fbsize(struct vidinfo *priv) 4190c84358cSSimon Glass { 420*8b449a66SSimon Glass return priv->vl_col * priv->vl_row * (NBITS(priv->vl_bpix) / 8); 4210c84358cSSimon Glass } 4220c84358cSSimon Glass 42308a7aa1eSSimon Glass ushort *configuration_get_cmap(void) 42408a7aa1eSSimon Glass { 42508a7aa1eSSimon Glass #if defined(CONFIG_LCD_LOGO) 42608a7aa1eSSimon Glass return bmp_logo_palette; 42708a7aa1eSSimon Glass #else 42808a7aa1eSSimon Glass return NULL; 42908a7aa1eSSimon Glass #endif 43008a7aa1eSSimon Glass } 43108a7aa1eSSimon Glass 43240d50021SSimon Glass static void exynos_lcd_init(struct vidinfo *vid, ulong lcd_base) 43308a7aa1eSSimon Glass { 43440d50021SSimon Glass exynos_fimd_lcd_init(vid, lcd_base); 43508a7aa1eSSimon Glass 43608a7aa1eSSimon Glass /* Enable flushing after LCD writes if requested */ 43708a7aa1eSSimon Glass lcd_set_flush_dcache(1); 43808a7aa1eSSimon Glass } 43908a7aa1eSSimon Glass 44008a7aa1eSSimon Glass __weak void exynos_cfg_lcd_gpio(void) 44108a7aa1eSSimon Glass { 44208a7aa1eSSimon Glass } 44308a7aa1eSSimon Glass 44408a7aa1eSSimon Glass __weak void exynos_backlight_on(unsigned int onoff) 44508a7aa1eSSimon Glass { 44608a7aa1eSSimon Glass } 44708a7aa1eSSimon Glass 44808a7aa1eSSimon Glass __weak void exynos_reset_lcd(void) 44908a7aa1eSSimon Glass { 45008a7aa1eSSimon Glass } 45108a7aa1eSSimon Glass 45208a7aa1eSSimon Glass __weak void exynos_lcd_power_on(void) 45308a7aa1eSSimon Glass { 45408a7aa1eSSimon Glass } 45508a7aa1eSSimon Glass 45608a7aa1eSSimon Glass __weak void exynos_cfg_ldo(void) 45708a7aa1eSSimon Glass { 45808a7aa1eSSimon Glass } 45908a7aa1eSSimon Glass 46008a7aa1eSSimon Glass __weak void exynos_enable_ldo(unsigned int onoff) 46108a7aa1eSSimon Glass { 46208a7aa1eSSimon Glass } 46308a7aa1eSSimon Glass 46408a7aa1eSSimon Glass __weak void exynos_backlight_reset(void) 46508a7aa1eSSimon Glass { 46608a7aa1eSSimon Glass } 46708a7aa1eSSimon Glass 468aaca5b19SSimon Glass __weak int exynos_lcd_misc_init(struct vidinfo *vid) 46908a7aa1eSSimon Glass { 47008a7aa1eSSimon Glass return 0; 47108a7aa1eSSimon Glass } 47208a7aa1eSSimon Glass 473aaca5b19SSimon Glass static void lcd_panel_on(struct vidinfo *vid) 47408a7aa1eSSimon Glass { 47508a7aa1eSSimon Glass struct gpio_desc pwm_out_gpio; 47608a7aa1eSSimon Glass struct gpio_desc bl_en_gpio; 47708a7aa1eSSimon Glass unsigned int node; 47808a7aa1eSSimon Glass 47908a7aa1eSSimon Glass udelay(vid->init_delay); 48008a7aa1eSSimon Glass 48108a7aa1eSSimon Glass exynos_backlight_reset(); 48208a7aa1eSSimon Glass 48308a7aa1eSSimon Glass exynos_cfg_lcd_gpio(); 48408a7aa1eSSimon Glass 48508a7aa1eSSimon Glass exynos_lcd_power_on(); 48608a7aa1eSSimon Glass 48708a7aa1eSSimon Glass udelay(vid->power_on_delay); 48808a7aa1eSSimon Glass 48908a7aa1eSSimon Glass if (vid->dp_enabled) 49008a7aa1eSSimon Glass exynos_init_dp(); 49108a7aa1eSSimon Glass 49208a7aa1eSSimon Glass exynos_reset_lcd(); 49308a7aa1eSSimon Glass 49408a7aa1eSSimon Glass udelay(vid->reset_delay); 49508a7aa1eSSimon Glass 49608a7aa1eSSimon Glass exynos_backlight_on(1); 49708a7aa1eSSimon Glass 49808a7aa1eSSimon Glass node = fdtdec_next_compatible(gd->fdt_blob, 0, 49908a7aa1eSSimon Glass COMPAT_SAMSUNG_EXYNOS_FIMD); 50008a7aa1eSSimon Glass if (node <= 0) { 50108a7aa1eSSimon Glass debug("FIMD: Can't get device node for FIMD\n"); 50208a7aa1eSSimon Glass return; 50308a7aa1eSSimon Glass } 50408a7aa1eSSimon Glass gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,pwm-out-gpio", 50508a7aa1eSSimon Glass 0, &pwm_out_gpio, 50608a7aa1eSSimon Glass GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); 50708a7aa1eSSimon Glass 50808a7aa1eSSimon Glass gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,bl-en-gpio", 0, 50908a7aa1eSSimon Glass &bl_en_gpio, 51008a7aa1eSSimon Glass GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); 51108a7aa1eSSimon Glass 51208a7aa1eSSimon Glass exynos_cfg_ldo(); 51308a7aa1eSSimon Glass 51408a7aa1eSSimon Glass exynos_enable_ldo(1); 51508a7aa1eSSimon Glass 51608a7aa1eSSimon Glass if (vid->mipi_enabled) 517652d15c0SSimon Glass exynos_mipi_dsi_init(panel_info.dsim_platform_data_dt); 51808a7aa1eSSimon Glass } 51908a7aa1eSSimon Glass 52008a7aa1eSSimon Glass int exynos_lcd_early_init(const void *blob) 52108a7aa1eSSimon Glass { 52208a7aa1eSSimon Glass unsigned int node; 52308a7aa1eSSimon Glass node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_FIMD); 52408a7aa1eSSimon Glass if (node <= 0) { 52508a7aa1eSSimon Glass debug("exynos_fb: Can't get device node for fimd\n"); 52608a7aa1eSSimon Glass return -ENODEV; 52708a7aa1eSSimon Glass } 52808a7aa1eSSimon Glass 52908a7aa1eSSimon Glass panel_info.vl_col = fdtdec_get_int(blob, node, "samsung,vl-col", 0); 53008a7aa1eSSimon Glass if (panel_info.vl_col == 0) { 53108a7aa1eSSimon Glass debug("Can't get XRES\n"); 53208a7aa1eSSimon Glass return -ENXIO; 53308a7aa1eSSimon Glass } 53408a7aa1eSSimon Glass 53508a7aa1eSSimon Glass panel_info.vl_row = fdtdec_get_int(blob, node, "samsung,vl-row", 0); 53608a7aa1eSSimon Glass if (panel_info.vl_row == 0) { 53708a7aa1eSSimon Glass debug("Can't get YRES\n"); 53808a7aa1eSSimon Glass return -ENXIO; 53908a7aa1eSSimon Glass } 54008a7aa1eSSimon Glass 54108a7aa1eSSimon Glass panel_info.vl_width = fdtdec_get_int(blob, node, 54208a7aa1eSSimon Glass "samsung,vl-width", 0); 54308a7aa1eSSimon Glass 54408a7aa1eSSimon Glass panel_info.vl_height = fdtdec_get_int(blob, node, 54508a7aa1eSSimon Glass "samsung,vl-height", 0); 54608a7aa1eSSimon Glass 54708a7aa1eSSimon Glass panel_info.vl_freq = fdtdec_get_int(blob, node, "samsung,vl-freq", 0); 54808a7aa1eSSimon Glass if (panel_info.vl_freq == 0) { 54908a7aa1eSSimon Glass debug("Can't get refresh rate\n"); 55008a7aa1eSSimon Glass return -ENXIO; 55108a7aa1eSSimon Glass } 55208a7aa1eSSimon Glass 55308a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-clkp")) 55408a7aa1eSSimon Glass panel_info.vl_clkp = CONFIG_SYS_LOW; 55508a7aa1eSSimon Glass 55608a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-oep")) 55708a7aa1eSSimon Glass panel_info.vl_oep = CONFIG_SYS_LOW; 55808a7aa1eSSimon Glass 55908a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-hsp")) 56008a7aa1eSSimon Glass panel_info.vl_hsp = CONFIG_SYS_LOW; 56108a7aa1eSSimon Glass 56208a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-vsp")) 56308a7aa1eSSimon Glass panel_info.vl_vsp = CONFIG_SYS_LOW; 56408a7aa1eSSimon Glass 56508a7aa1eSSimon Glass if (fdtdec_get_bool(blob, node, "samsung,vl-dp")) 56608a7aa1eSSimon Glass panel_info.vl_dp = CONFIG_SYS_LOW; 56708a7aa1eSSimon Glass 56808a7aa1eSSimon Glass panel_info.vl_bpix = fdtdec_get_int(blob, node, "samsung,vl-bpix", 0); 56908a7aa1eSSimon Glass if (panel_info.vl_bpix == 0) { 57008a7aa1eSSimon Glass debug("Can't get bits per pixel\n"); 57108a7aa1eSSimon Glass return -ENXIO; 57208a7aa1eSSimon Glass } 57308a7aa1eSSimon Glass 57408a7aa1eSSimon Glass panel_info.vl_hspw = fdtdec_get_int(blob, node, "samsung,vl-hspw", 0); 57508a7aa1eSSimon Glass if (panel_info.vl_hspw == 0) { 57608a7aa1eSSimon Glass debug("Can't get hsync width\n"); 57708a7aa1eSSimon Glass return -ENXIO; 57808a7aa1eSSimon Glass } 57908a7aa1eSSimon Glass 58008a7aa1eSSimon Glass panel_info.vl_hfpd = fdtdec_get_int(blob, node, "samsung,vl-hfpd", 0); 58108a7aa1eSSimon Glass if (panel_info.vl_hfpd == 0) { 58208a7aa1eSSimon Glass debug("Can't get right margin\n"); 58308a7aa1eSSimon Glass return -ENXIO; 58408a7aa1eSSimon Glass } 58508a7aa1eSSimon Glass 58608a7aa1eSSimon Glass panel_info.vl_hbpd = (u_char)fdtdec_get_int(blob, node, 58708a7aa1eSSimon Glass "samsung,vl-hbpd", 0); 58808a7aa1eSSimon Glass if (panel_info.vl_hbpd == 0) { 58908a7aa1eSSimon Glass debug("Can't get left margin\n"); 59008a7aa1eSSimon Glass return -ENXIO; 59108a7aa1eSSimon Glass } 59208a7aa1eSSimon Glass 59308a7aa1eSSimon Glass panel_info.vl_vspw = (u_char)fdtdec_get_int(blob, node, 59408a7aa1eSSimon Glass "samsung,vl-vspw", 0); 59508a7aa1eSSimon Glass if (panel_info.vl_vspw == 0) { 59608a7aa1eSSimon Glass debug("Can't get vsync width\n"); 59708a7aa1eSSimon Glass return -ENXIO; 59808a7aa1eSSimon Glass } 59908a7aa1eSSimon Glass 60008a7aa1eSSimon Glass panel_info.vl_vfpd = fdtdec_get_int(blob, node, 60108a7aa1eSSimon Glass "samsung,vl-vfpd", 0); 60208a7aa1eSSimon Glass if (panel_info.vl_vfpd == 0) { 60308a7aa1eSSimon Glass debug("Can't get lower margin\n"); 60408a7aa1eSSimon Glass return -ENXIO; 60508a7aa1eSSimon Glass } 60608a7aa1eSSimon Glass 60708a7aa1eSSimon Glass panel_info.vl_vbpd = fdtdec_get_int(blob, node, "samsung,vl-vbpd", 0); 60808a7aa1eSSimon Glass if (panel_info.vl_vbpd == 0) { 60908a7aa1eSSimon Glass debug("Can't get upper margin\n"); 61008a7aa1eSSimon Glass return -ENXIO; 61108a7aa1eSSimon Glass } 61208a7aa1eSSimon Glass 61308a7aa1eSSimon Glass panel_info.vl_cmd_allow_len = fdtdec_get_int(blob, node, 61408a7aa1eSSimon Glass "samsung,vl-cmd-allow-len", 0); 61508a7aa1eSSimon Glass 61608a7aa1eSSimon Glass panel_info.win_id = fdtdec_get_int(blob, node, "samsung,winid", 0); 61708a7aa1eSSimon Glass panel_info.init_delay = fdtdec_get_int(blob, node, 61808a7aa1eSSimon Glass "samsung,init-delay", 0); 61908a7aa1eSSimon Glass panel_info.power_on_delay = fdtdec_get_int(blob, node, 62008a7aa1eSSimon Glass "samsung,power-on-delay", 0); 62108a7aa1eSSimon Glass panel_info.reset_delay = fdtdec_get_int(blob, node, 62208a7aa1eSSimon Glass "samsung,reset-delay", 0); 62308a7aa1eSSimon Glass panel_info.interface_mode = fdtdec_get_int(blob, node, 62408a7aa1eSSimon Glass "samsung,interface-mode", 0); 62508a7aa1eSSimon Glass panel_info.mipi_enabled = fdtdec_get_int(blob, node, 62608a7aa1eSSimon Glass "samsung,mipi-enabled", 0); 62708a7aa1eSSimon Glass panel_info.dp_enabled = fdtdec_get_int(blob, node, 62808a7aa1eSSimon Glass "samsung,dp-enabled", 0); 62908a7aa1eSSimon Glass panel_info.cs_setup = fdtdec_get_int(blob, node, 63008a7aa1eSSimon Glass "samsung,cs-setup", 0); 63108a7aa1eSSimon Glass panel_info.wr_setup = fdtdec_get_int(blob, node, 63208a7aa1eSSimon Glass "samsung,wr-setup", 0); 63308a7aa1eSSimon Glass panel_info.wr_act = fdtdec_get_int(blob, node, "samsung,wr-act", 0); 63408a7aa1eSSimon Glass panel_info.wr_hold = fdtdec_get_int(blob, node, "samsung,wr-hold", 0); 63508a7aa1eSSimon Glass 63608a7aa1eSSimon Glass panel_info.logo_on = fdtdec_get_int(blob, node, "samsung,logo-on", 0); 63708a7aa1eSSimon Glass if (panel_info.logo_on) { 63808a7aa1eSSimon Glass panel_info.logo_width = fdtdec_get_int(blob, node, 63908a7aa1eSSimon Glass "samsung,logo-width", 0); 64008a7aa1eSSimon Glass panel_info.logo_height = fdtdec_get_int(blob, node, 64108a7aa1eSSimon Glass "samsung,logo-height", 0); 64208a7aa1eSSimon Glass panel_info.logo_addr = fdtdec_get_int(blob, node, 64308a7aa1eSSimon Glass "samsung,logo-addr", 0); 64408a7aa1eSSimon Glass } 64508a7aa1eSSimon Glass 64608a7aa1eSSimon Glass panel_info.rgb_mode = fdtdec_get_int(blob, node, 64708a7aa1eSSimon Glass "samsung,rgb-mode", 0); 64808a7aa1eSSimon Glass panel_info.pclk_name = fdtdec_get_int(blob, node, 64908a7aa1eSSimon Glass "samsung,pclk-name", 0); 65008a7aa1eSSimon Glass panel_info.sclk_div = fdtdec_get_int(blob, node, 65108a7aa1eSSimon Glass "samsung,sclk-div", 0); 65208a7aa1eSSimon Glass panel_info.dual_lcd_enabled = fdtdec_get_int(blob, node, 65308a7aa1eSSimon Glass "samsung,dual-lcd-enabled", 0); 65408a7aa1eSSimon Glass 65508a7aa1eSSimon Glass return 0; 65608a7aa1eSSimon Glass } 65708a7aa1eSSimon Glass 65808a7aa1eSSimon Glass void lcd_ctrl_init(void *lcdbase) 65908a7aa1eSSimon Glass { 66008a7aa1eSSimon Glass set_system_display_ctrl(); 66108a7aa1eSSimon Glass set_lcd_clk(); 66208a7aa1eSSimon Glass 66308a7aa1eSSimon Glass #ifdef CONFIG_EXYNOS_MIPI_DSIM 66408a7aa1eSSimon Glass exynos_init_dsim_platform_data(&panel_info); 66508a7aa1eSSimon Glass #endif 66608a7aa1eSSimon Glass exynos_lcd_misc_init(&panel_info); 66708a7aa1eSSimon Glass 66840d50021SSimon Glass exynos_lcd_init(&panel_info, (ulong)lcdbase); 66908a7aa1eSSimon Glass } 67008a7aa1eSSimon Glass 67108a7aa1eSSimon Glass void lcd_enable(void) 67208a7aa1eSSimon Glass { 67308a7aa1eSSimon Glass if (panel_info.logo_on) { 6749c4d440eSSimon Glass memset((void *)gd->fb_base, 0, 6759c4d440eSSimon Glass panel_info.vl_width * panel_info.vl_height * 67608a7aa1eSSimon Glass (NBITS(panel_info.vl_bpix) >> 3)); 67708a7aa1eSSimon Glass } 67808a7aa1eSSimon Glass 67908a7aa1eSSimon Glass lcd_panel_on(&panel_info); 68008a7aa1eSSimon Glass } 68108a7aa1eSSimon Glass 68208a7aa1eSSimon Glass /* dummy function */ 68308a7aa1eSSimon Glass void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) 68408a7aa1eSSimon Glass { 68508a7aa1eSSimon Glass return; 68608a7aa1eSSimon Glass } 687