diff options
| author | Donghwa Lee <dh09.lee@samsung.com> | 2012-04-05 19:36:17 +0000 | 
|---|---|---|
| committer | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2012-05-15 08:31:29 +0200 | 
| commit | 6d4339f622ef378d903a0c35484581533a242d2b (patch) | |
| tree | fcab4c664749c44817c0b22e27ab25cef1be37a8 /drivers | |
| parent | 559a05cc32a0162d4d2aebe6d3410e91f883a04d (diff) | |
| download | olio-uboot-2014.01-6d4339f622ef378d903a0c35484581533a242d2b.tar.xz olio-uboot-2014.01-6d4339f622ef378d903a0c35484581533a242d2b.zip | |
EXYNOS: support EXYNOS framebuffer and FIMD display drivers.
This patch support EXYNOS FB and FIMD display drivers.
Signed-off-by: Donghwa Lee <dh09.lee@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Acked-by: Anatolij Gustschin <agust@denx.de>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/video/Makefile | 1 | ||||
| -rw-r--r-- | drivers/video/exynos_fb.c | 128 | ||||
| -rw-r--r-- | drivers/video/exynos_fb.h | 61 | ||||
| -rw-r--r-- | drivers/video/exynos_fimd.c | 354 | 
4 files changed, 544 insertions, 0 deletions
| diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 6252f6a25..8896abe51 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -28,6 +28,7 @@ LIB	:= $(obj)libvideo.o  COBJS-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o  COBJS-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o  COBJS-$(CONFIG_CFB_CONSOLE) += cfb_console.o +COBJS-$(CONFIG_EXYNOS_FB) += exynos_fb.o exynos_fimd.o  COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o  COBJS-$(CONFIG_S6E63D6) += s6e63d6.o  COBJS-$(CONFIG_SED156X) += sed156x.o diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c new file mode 100644 index 000000000..0eb7f5868 --- /dev/null +++ b/drivers/video/exynos_fb.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae <inki.dae@samsung.com> + * Author: Donghwa Lee <dh09.lee@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> +#include <common.h> +#include <lcd.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clock.h> +#include <asm/arch/clk.h> +#include <asm/arch/mipi_dsim.h> +#include <asm/arch/system.h> + +#include "exynos_fb.h" + +int lcd_line_length; +int lcd_color_fg; +int lcd_color_bg; + +void *lcd_base; +void *lcd_console_address; + +short console_col; +short console_row; + +static unsigned int panel_width, panel_height; + +/* LCD Panel data */ +vidinfo_t panel_info; + +static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid) +{ +	unsigned long palette_size; +	unsigned int fb_size; + +	fb_size = vid->vl_row * vid->vl_col * (vid->vl_bpix >> 3); + +	lcd_base = lcdbase; + +	palette_size = NBITS(vid->vl_bpix) == 8 ? 256 : 16; + +	exynos_fimd_lcd_init_mem((unsigned long)lcd_base, +			(unsigned long)fb_size, palette_size); +} + +static void exynos_lcd_init(vidinfo_t *vid) +{ +	exynos_fimd_lcd_init(vid); +} + +static void lcd_panel_on(vidinfo_t *vid) +{ +	udelay(vid->init_delay); + +	if (vid->backlight_reset) +		vid->backlight_reset(); + +	if (vid->cfg_gpio) +		vid->cfg_gpio(); + +	if (vid->lcd_power_on) +		vid->lcd_power_on(); + +	udelay(vid->power_on_delay); + +	if (vid->reset_lcd) { +		vid->reset_lcd(); +		udelay(vid->reset_delay); +	} + +	if (vid->backlight_on) +		vid->backlight_on(1); + +	if (vid->cfg_ldo) +		vid->cfg_ldo(); + +	if (vid->enable_ldo) +		vid->enable_ldo(1); + +	if (vid->mipi_enabled) +		exynos_mipi_dsi_init(); +} + +void lcd_ctrl_init(void *lcdbase) +{ +	set_system_display_ctrl(); +	set_lcd_clk(); + +	/* initialize parameters which is specific to panel. */ +	init_panel_info(&panel_info); + +	panel_width = panel_info.vl_width; +	panel_height = panel_info.vl_height; + +	exynos_lcd_init_mem(lcdbase, &panel_info); + +	exynos_lcd_init(&panel_info); +} + +void lcd_enable(void) +{ +	lcd_panel_on(&panel_info); +} + +/* dummy function */ +void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) +{ +	return; +} diff --git a/drivers/video/exynos_fb.h b/drivers/video/exynos_fb.h new file mode 100644 index 000000000..66f5da6d4 --- /dev/null +++ b/drivers/video/exynos_fb.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae <inki.dae@samsung.com> + * Author: Donghwa Lee <dh09.lee@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _EXYNOS_FB_H_ +#define _EXYNOS_FB_H_ + +#include <asm/arch/fb.h> + +#define MAX_CLOCK	(86 * 1000000) + +enum exynos_fb_rgb_mode_t { +	MODE_RGB_P = 0, +	MODE_BGR_P = 1, +	MODE_RGB_S = 2, +	MODE_BGR_S = 3, +}; + +enum exynos_cpu_auto_cmd_rate { +	DISABLE_AUTO_FRM, +	PER_TWO_FRM, +	PER_FOUR_FRM, +	PER_SIX_FRM, +	PER_EIGHT_FRM, +	PER_TEN_FRM, +	PER_TWELVE_FRM, +	PER_FOURTEEN_FRM, +	PER_SIXTEEN_FRM, +	PER_EIGHTEEN_FRM, +	PER_TWENTY_FRM, +	PER_TWENTY_TWO_FRM, +	PER_TWENTY_FOUR_FRM, +	PER_TWENTY_SIX_FRM, +	PER_TWENTY_EIGHT_FRM, +	PER_THIRTY_FRM, +}; + +void exynos_fimd_lcd_init_mem(unsigned long screen_base, unsigned long fb_size, +	unsigned long palette_size); +void exynos_fimd_lcd_init(vidinfo_t *vid); +unsigned long exynos_fimd_calc_fbsize(void); + +#endif diff --git a/drivers/video/exynos_fimd.c b/drivers/video/exynos_fimd.c new file mode 100644 index 000000000..2a60fcfba --- /dev/null +++ b/drivers/video/exynos_fimd.c @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae <inki.dae@samsung.com> + * Author: Donghwa Lee <dh09.lee@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> +#include <common.h> +#include <asm/io.h> +#include <lcd.h> +#include <div64.h> +#include <asm/arch/clk.h> +#include <asm/arch/clock.h> +#include <asm/arch/cpu.h> +#include "exynos_fb.h" + +static unsigned long *lcd_base_addr; +static vidinfo_t *pvid; + +void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size, +		u_long palette_size) +{ +	lcd_base_addr = (unsigned long *)screen_base; +} + +static void exynos_fimd_set_dualrgb(unsigned int enabled) +{ +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); +	unsigned int cfg = 0; + +	if (enabled) { +		cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT | +			EXYNOS_DUALRGB_VDEN_EN_ENABLE; + +		/* in case of Line Split mode, MAIN_CNT doesn't neet to set. */ +		cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) | +			EXYNOS_DUALRGB_MAIN_CNT(0); +	} + +	writel(cfg, &fimd_ctrl->dualrgb); +} + +static void exynos_fimd_set_par(unsigned int win_id) +{ +	unsigned int cfg = 0; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	/* set window control */ +	cfg = readl((unsigned int)&fimd_ctrl->wincon0 + +			EXYNOS_WINCON(win_id)); + +	cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE | +		EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE | +		EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK | +		EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK); + +	/* DATAPATH is DMA */ +	cfg |= EXYNOS_WINCON_DATAPATH_DMA; + +	/* bpp is 32 */ +	cfg |= EXYNOS_WINCON_WSWP_ENABLE; + +	/* dma burst is 16 */ +	cfg |= EXYNOS_WINCON_BURSTLEN_16WORD; + +	/* pixel format is unpacked RGB888 */ +	cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888; + +	writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + +			EXYNOS_WINCON(win_id)); + +	/* set window position to x=0, y=0*/ +	cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0); +	writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a + +			EXYNOS_VIDOSD(win_id)); + +	cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) | +		EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1); +	writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b + +			EXYNOS_VIDOSD(win_id)); + +	/* set window size for window0*/ +	cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row); +	writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c + +			EXYNOS_VIDOSD(win_id)); +} + +static void exynos_fimd_set_buffer_address(unsigned int win_id) +{ +	unsigned long start_addr, end_addr; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	start_addr = (unsigned long)lcd_base_addr; +	end_addr = start_addr + ((pvid->vl_col * (pvid->vl_bpix / 8)) * +				pvid->vl_row); + +	writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 + +			EXYNOS_BUFFER_OFFSET(win_id)); +	writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 + +			EXYNOS_BUFFER_OFFSET(win_id)); +} + +static void exynos_fimd_set_clock(vidinfo_t *pvid) +{ +	unsigned int cfg = 0, div = 0, remainder, remainder_div; +	unsigned long pixel_clock; +	unsigned long long src_clock; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	if (pvid->dual_lcd_enabled) { +		pixel_clock = pvid->vl_freq * +				(pvid->vl_hspw + pvid->vl_hfpd + +				 pvid->vl_hbpd + pvid->vl_col / 2) * +				(pvid->vl_vspw + pvid->vl_vfpd + +				 pvid->vl_vbpd + pvid->vl_row); +	} else if (pvid->interface_mode == FIMD_CPU_INTERFACE) { +		pixel_clock = pvid->vl_freq * +				pvid->vl_width * pvid->vl_height * +				(pvid->cs_setup + pvid->wr_setup + +				 pvid->wr_act + pvid->wr_hold + 1); +	} else { +		pixel_clock = pvid->vl_freq * +				(pvid->vl_hspw + pvid->vl_hfpd + +				 pvid->vl_hbpd + pvid->vl_col) * +				(pvid->vl_vspw + pvid->vl_vfpd + +				 pvid->vl_vbpd + pvid->vl_row); +	} + +	cfg = readl(&fimd_ctrl->vidcon0); +	cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK | +		EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK | +		EXYNOS_VIDCON0_CLKDIR_MASK); +	cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS | +		EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED); + +	if (pixel_clock > MAX_CLOCK) +		pixel_clock = MAX_CLOCK; + +	src_clock = (unsigned long long) get_lcd_clk(); + +	/* get quotient and remainder. */ +	remainder = do_div(src_clock, pixel_clock); +	div = src_clock; + +	remainder *= 10; +	remainder_div = remainder / pixel_clock; + +	/* round about one places of decimals. */ +	if (remainder_div >= 5) +		div++; + +	/* in case of dual lcd mode. */ +	if (pvid->dual_lcd_enabled) +		div--; + +	cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1); +	writel(cfg, &fimd_ctrl->vidcon0); +} + +void exynos_set_trigger(void) +{ +	unsigned int cfg = 0; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	cfg = readl(&fimd_ctrl->trigcon); + +	cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG); + +	writel(cfg, &fimd_ctrl->trigcon); +} + +int exynos_is_i80_frame_done(void) +{ +	unsigned int cfg = 0; +	int status; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	cfg = readl(&fimd_ctrl->trigcon); + +	/* frame done func is valid only when TRIMODE[0] is set to 1. */ +	status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) == +			EXYNOS_I80STATUS_TRIG_DONE; + +	return status; +} + +static void exynos_fimd_lcd_on(void) +{ +	unsigned int cfg = 0; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	/* display on */ +	cfg = readl(&fimd_ctrl->vidcon0); +	cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE); +	writel(cfg, &fimd_ctrl->vidcon0); +} + +static void exynos_fimd_window_on(unsigned int win_id) +{ +	unsigned int cfg = 0; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	/* enable window */ +	cfg = readl((unsigned int)&fimd_ctrl->wincon0 + +			EXYNOS_WINCON(win_id)); +	cfg |= EXYNOS_WINCON_ENWIN_ENABLE; +	writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + +			EXYNOS_WINCON(win_id)); + +	cfg = readl(&fimd_ctrl->winshmap); +	cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id); +	writel(cfg, &fimd_ctrl->winshmap); +} + +void exynos_fimd_lcd_off(void) +{ +	unsigned int cfg = 0; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	cfg = readl(&fimd_ctrl->vidcon0); +	cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE); +	writel(cfg, &fimd_ctrl->vidcon0); +} + +void exynos_fimd_window_off(unsigned int win_id) +{ +	unsigned int cfg = 0; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	cfg = readl((unsigned int)&fimd_ctrl->wincon0 + +			EXYNOS_WINCON(win_id)); +	cfg &= EXYNOS_WINCON_ENWIN_DISABLE; +	writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + +			EXYNOS_WINCON(win_id)); + +	cfg = readl(&fimd_ctrl->winshmap); +	cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id); +	writel(cfg, &fimd_ctrl->winshmap); +} + +void exynos_fimd_lcd_init(vidinfo_t *vid) +{ +	unsigned int cfg = 0, rgb_mode; +	struct exynos4_fb *fimd_ctrl = +		(struct exynos4_fb *)samsung_get_base_fimd(); + +	/* store panel info to global variable */ +	pvid = vid; + +	rgb_mode = MODE_RGB_P; + +	if (vid->interface_mode == FIMD_RGB_INTERFACE) { +		cfg |= EXYNOS_VIDCON0_VIDOUT_RGB; +		writel(cfg, &fimd_ctrl->vidcon0); + +		cfg = readl(&fimd_ctrl->vidcon2); +		cfg &= ~(EXYNOS_VIDCON2_WB_MASK | +			EXYNOS_VIDCON2_TVFORMATSEL_MASK | +			EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK); +		cfg |= EXYNOS_VIDCON2_WB_DISABLE; +		writel(cfg, &fimd_ctrl->vidcon2); + +		/* set polarity */ +		cfg = 0; +		if (!pvid->vl_clkp) +			cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE; +		if (!pvid->vl_hsp) +			cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT; +		if (!pvid->vl_vsp) +			cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT; +		if (!pvid->vl_dp) +			cfg |= EXYNOS_VIDCON1_IVDEN_INVERT; + +		writel(cfg, &fimd_ctrl->vidcon1); + +		/* set timing */ +		cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1); +		cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1); +		cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1); +		writel(cfg, &fimd_ctrl->vidtcon0); + +		cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1); +		cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1); +		cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1); + +		writel(cfg, &fimd_ctrl->vidtcon1); + +		/* set lcd size */ +		cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1); +		cfg |= EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1); + +		writel(cfg, &fimd_ctrl->vidtcon2); +	} + +	/* set display mode */ +	cfg = readl(&fimd_ctrl->vidcon0); +	cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK; +	cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT); +	writel(cfg, &fimd_ctrl->vidcon0); + +	/* set par */ +	exynos_fimd_set_par(pvid->win_id); + +	/* set memory address */ +	exynos_fimd_set_buffer_address(pvid->win_id); + +	/* set buffer size */ +	cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * pvid->vl_bpix / 8); +	writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 + +					EXYNOS_BUFFER_SIZE(pvid->win_id)); + +	/* set clock */ +	exynos_fimd_set_clock(pvid); + +	/* set rgb mode to dual lcd. */ +	exynos_fimd_set_dualrgb(pvid->dual_lcd_enabled); + +	/* display on */ +	exynos_fimd_lcd_on(); + +	/* window on */ +	exynos_fimd_window_on(pvid->win_id); +} + +unsigned long exynos_fimd_calc_fbsize(void) +{ +	return pvid->vl_col * pvid->vl_row * (pvid->vl_bpix / 8); +} |