#include <linux/types.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 <asm/arch/regs-fb.h>
-#include <asm/arch/hardware.h>
#include <asm/arch/gpio.h>
#include "s5p-fb.h"
-/* DISPLAY CONTROL REGISTER */
-#define DCR 0xE0107008
-
-/* CLOCK DIVIDER 0 */
-#define CLK_DIV0 0xE0100300
-#define CLK_DIV1 0xE0100304
-
/* LCD CONTROLLER REGISTER BASE */
#define S5PC100_LCRB 0xEE000000
#define S5PC110_LCRB 0xF8000000
#define MPLL 1
-#define S5P_VFRAME_FREQ 60
-
static unsigned int ctrl_base;
static unsigned long *lcd_base_addr;
static vidinfo_t *pvid = NULL;
-extern unsigned long get_pll_clk(int pllreg);
-
void s5pc_fimd_lcd_init_mem(u_long screen_base, u_long fb_size, u_long palette_size)
{
lcd_base_addr = (unsigned long *)screen_base;
return;
}
-void s5pc_c100_gpio_setup(void)
+static void s5pc_fimd_set_dualrgb(unsigned int enabled)
{
- /* set GPF0[0:7] for RGB Interface and Data lines */
- writel(0x22222222, S5PC100_GPIO_BASE(S5PC100_GPIO_F0_OFFSET));
-
- /* set Data lines */
- writel(0x22222222, S5PC100_GPIO_BASE(S5PC100_GPIO_F1_OFFSET));
- writel(0x22222222, S5PC100_GPIO_BASE(S5PC100_GPIO_F2_OFFSET));
- writel(0x2222, S5PC100_GPIO_BASE(S5PC100_GPIO_F3_OFFSET));
+ unsigned int cfg = 0;
- /* set gpio configuration pin for MLCD_RST */
- writel(0x10000000, S5PC100_GPIO_BASE(S5PC100_GPIO_H1_OFFSET));
+ if (enabled) {
+ cfg = S5P_DUALRGB_BYPASS_DUAL | S5P_DUALRGB_LINESPLIT |
+ S5P_DUALRGB_VDEN_EN_ENABLE;
- /* set gpio configuration pin for MLCD_ON */
- writel(0x1000, S5PC100_GPIO_BASE(S5PC100_GPIO_J1_OFFSET));
- writel(readl(S5PC100_GPIO_BASE(S5PC100_GPIO_J1_OFFSET+S5PC1XX_GPIO_DAT_OFFSET)) & 0xf7,
- S5PC100_GPIO_BASE(S5PC100_GPIO_J1_OFFSET+S5PC1XX_GPIO_DAT_OFFSET));
+ /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */
+ cfg |= S5P_DUALRGB_SUB_CNT(pvid->vl_col/2) | S5P_DUALRGB_MAIN_CNT(0);
+ } else
+ cfg = 0;
- /* set gpio configuration pin for DISPLAY_CS, DISPLAY_CLK and DISPLSY_SI */
- writel(0x11100000, S5PC100_GPIO_BASE(S5PC100_GPIO_K3_OFFSET));
-}
-
-void s5pc_c110_gpio_setup(void)
-{
- /* set GPF0[0:7] for RGB Interface and Data lines (32bit) */
- writel(0x22222222, S5PC110_GPIO_BASE(S5PC110_GPIO_F0_OFFSET));
- /* pull-up/down disable */
- writel(0x0, S5PC110_GPIO_BASE(S5PC110_GPIO_F0_OFFSET+S5PC1XX_GPIO_PULL_OFFSET));
- /* drive strength to max (24bit) */
- writel(0xffffff, S5PC110_GPIO_BASE(S5PC110_GPIO_F0_OFFSET+S5PC1XX_GPIO_DRV_OFFSET));
-
- /* set Data lines (32bit) */
- writel(0x22222222, S5PC110_GPIO_BASE(S5PC110_GPIO_F1_OFFSET));
- writel(0x22222222, S5PC110_GPIO_BASE(S5PC110_GPIO_F2_OFFSET));
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_F3_OFFSET)) & 0xFF0000,
- S5PC110_GPIO_BASE(S5PC110_GPIO_F3_OFFSET));
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_F3_OFFSET)) | 0x002222,
- S5PC110_GPIO_BASE(S5PC110_GPIO_F3_OFFSET));
-
- /* drive strength to max (24bit) */
- writel(0xffffff, S5PC110_GPIO_BASE(S5PC110_GPIO_F1_OFFSET+S5PC1XX_GPIO_DRV_OFFSET));
- writel(0xffffff, S5PC110_GPIO_BASE(S5PC110_GPIO_F2_OFFSET+S5PC1XX_GPIO_DRV_OFFSET));
- /* [11:0](drive stength level), [15:12](none), [21:16](Slew Rate) */
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_F3_OFFSET+S5PC1XX_GPIO_DRV_OFFSET)) & 0x3FFF00,
- S5PC110_GPIO_BASE(S5PC110_GPIO_F3_OFFSET+S5PC1XX_GPIO_DRV_OFFSET));
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_F3_OFFSET+S5PC1XX_GPIO_DRV_OFFSET)) | 0x0000FF,
- S5PC110_GPIO_BASE(S5PC110_GPIO_F3_OFFSET+S5PC1XX_GPIO_DRV_OFFSET));
-
- /* pull-up/down disable */
- writel(0x0, S5PC110_GPIO_BASE(S5PC110_GPIO_F1_OFFSET+S5PC1XX_GPIO_PULL_OFFSET));
- writel(0x0, S5PC110_GPIO_BASE(S5PC110_GPIO_F2_OFFSET+S5PC1XX_GPIO_PULL_OFFSET));
- writel(0x0, S5PC110_GPIO_BASE(S5PC110_GPIO_F3_OFFSET+S5PC1XX_GPIO_PULL_OFFSET));
-
- /* display output path selection (only [1:0] valid) */
- writel(0x2, DCR);
-
- /* set gpio configuration pin for MLCD_RST */
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_H1_OFFSET)) & 0x0fffffff,
- S5PC110_GPIO_BASE(S5PC110_GPIO_H1_OFFSET));
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_H1_OFFSET)) | 0x10000000,
- S5PC110_GPIO_BASE(S5PC110_GPIO_H1_OFFSET));
-
- /* set gpio configuration pin for MLCD_ON and then to LOW */
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_J1_OFFSET)) & 0xFFFF0FFF,
- S5PC110_GPIO_BASE(S5PC110_GPIO_J1_OFFSET));
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_J1_OFFSET)) | 0x00001000,
- S5PC110_GPIO_BASE(S5PC110_GPIO_J1_OFFSET));
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_J1_OFFSET+4)) & 0xf7,
- S5PC110_GPIO_BASE(S5PC110_GPIO_J1_OFFSET+S5PC1XX_GPIO_DAT_OFFSET));
-
- /* set gpio configuration pin for DISPLAY_CS, DISPLAY_CLK, DISPLSY_SI and LCD_ID */
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_MP0_1_OFFSET)) & 0xFFFFFF0F,
- S5PC110_GPIO_BASE(S5PC110_GPIO_MP0_1_OFFSET));
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_MP0_1_OFFSET)) | 0x00000010,
- S5PC110_GPIO_BASE(S5PC110_GPIO_MP0_1_OFFSET));
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_MP0_4_OFFSET)) & 0xFFFF000F,
- S5PC110_GPIO_BASE(S5PC110_GPIO_MP0_4_OFFSET));
- writel(readl(S5PC110_GPIO_BASE(S5PC110_GPIO_MP0_4_OFFSET)) | 0x00001110,
- S5PC110_GPIO_BASE(S5PC110_GPIO_MP0_4_OFFSET));
- return;
+ writel(cfg, ctrl_base + S5P_DUALRGB);
}
static void s5pc_fimd_set_par(unsigned int win_id)
static void s5pc_fimd_set_clock(void)
{
- unsigned int cfg = 0, div = 0, mpll_ratio = 0;
+ unsigned int cfg = 0, div = 0, fimd_ratio = 0, temp = 0,
+ remainder, remainder_div;
unsigned long pixel_clock, src_clock, max_clock;
+ struct s5pc110_clock *clk = (struct s5pc110_clock *)S5PC1XX_CLOCK_BASE;
+ u64 div64;
- max_clock = 66 * 1000000;
+ s5pc1xx_clock_init();
+
+ max_clock = 86 * 1000000;
+
+ 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
+ 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);
- pixel_clock = S5P_VFRAME_FREQ * (pvid->vl_hpw + pvid->vl_blw +
- pvid->vl_elw + pvid->vl_width) * (pvid->vl_vpw +
- pvid->vl_bfw + pvid->vl_efw + pvid->vl_height);
+ if (get_pll_clk == NULL) {
+ printf("get_pll_clk is null.\n");
+ return;
+ }
src_clock = get_pll_clk(MPLL);
cfg = readl(ctrl_base + S5P_VIDCON0);
cfg &= ~(S5P_VIDCON0_CLKSEL_MASK | S5P_VIDCON0_CLKVALUP_MASK | \
S5P_VIDCON0_VCLKEN_MASK | S5P_VIDCON0_CLKDIR_MASK);
- cfg |= (S5P_VIDCON0_CLKSEL_HCLK | S5P_VIDCON0_CLKVALUP_ALWAYS | \
+ cfg |= (S5P_VIDCON0_CLKSEL_SCLK | S5P_VIDCON0_CLKVALUP_ALWAYS | \
S5P_VIDCON0_VCLKEN_NORMAL | S5P_VIDCON0_CLKDIR_DIVIDED);
if (pixel_clock > max_clock)
pixel_clock = max_clock;
+ /* set source clock to SCLKMPLL. */
+ temp = readl(&clk->src1);
+ writel((temp & ~0xf00000) | 0x600000, &clk->src1);
+ temp = 0;
+
+ /* set fimd ratio to 3. */
+ temp = readl(&clk->div1);
+ writel((temp & ~0xf00000) | 0x200000, &clk->div1);
+ temp = 0;
+
/* get mpll ratio */
- if (cpu_is_s5pc110())
- mpll_ratio = (readl(CLK_DIV0) & 0xf0000) >> 16;
- else
- mpll_ratio = (readl(CLK_DIV1) & 0xf0) >> 4;
-
- /*
- * It can get source clock speed as (mpll / mpll_ratio)
- * because lcd controller uses hclk_dsys.
- * mpll is a parent of hclk_dsys.
- */
- div = (unsigned int)((src_clock / (mpll_ratio + 1)) / pixel_clock);
+ temp = readl(&clk->div1);
+ fimd_ratio = (temp & 0xf00000) >> 20;
+ temp = 0;
+
+ div64 = ((u64)src_clock) / (fimd_ratio + 1);
+
+ /* get quotient and remainder. */
+ remainder = do_div(div64, pixel_clock);
+ div = (u32) div64;
+
+ 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 |= S5P_VIDCON0_CLKVAL_F(div - 1);
writel(cfg, ctrl_base + S5P_VIDCON0);
- udebug("mpll_ratio = %d, src_clock = %d, pixel_clock = %d, div = %d\n",
- mpll_ratio, src_clock, pixel_clock, div);
+ udebug("fimd_ratio = %d, src_clock = %d, pixel_clock = %d, div = %d\n",
+ fimd_ratio, src_clock / (fimd_ratio + 1), pixel_clock, div);
return;
}
-static s5pc_fimd_lcd_on(unsigned int win_id)
+static void s5pc_fimd_lcd_on(unsigned int win_id)
{
- int cfg = 0;
+ unsigned int cfg = 0;
/* display on */
cfg = readl(ctrl_base + S5P_VIDCON0);
cfg |= (S5P_VIDCON0_ENVID_ENABLE | S5P_VIDCON0_ENVID_F_ENABLE);
writel(cfg, ctrl_base + S5P_VIDCON0);
udebug("vidcon0 = %x\n", cfg);
+}
+
+static void s5pc_fimd_window_on(unsigned int win_id)
+{
+ unsigned int cfg = 0;
/* enable window */
cfg = readl(ctrl_base + S5P_WINCON(win_id));
cfg |= S5P_WINCON_ENWIN_ENABLE;
writel(cfg, ctrl_base + S5P_WINCON(win_id));
udebug("wincon%d=%x\n", win_id, cfg);
+
+ /* evt1 */
+ cfg = readl(ctrl_base + S5P_WINSHMAP);
+ cfg |= S5P_WINSHMAP_CH_ENABLE(win_id);
+ writel(cfg, ctrl_base + S5P_WINSHMAP);
+}
+
+void s5pc_fimd_lcd_off(unsigned int win_id)
+{
+ unsigned int cfg = 0;
+
+ cfg = readl(ctrl_base + S5P_VIDCON0);
+ cfg &= (S5P_VIDCON0_ENVID_DISABLE | S5P_VIDCON0_ENVID_F_DISABLE);
+ writel(cfg, ctrl_base + S5P_VIDCON0);
+}
+
+void s5pc_fimd_window_off(unsigned int win_id)
+{
+ unsigned int cfg = 0;
+
+ cfg = readl(ctrl_base + S5P_WINCON(win_id));
+ cfg &= S5P_WINCON_ENWIN_DISABLE;
+ writel(cfg, ctrl_base + S5P_WINCON(win_id));
+
+ /* evt1 */
+ cfg = readl(ctrl_base + S5P_WINSHMAP);
+ cfg &= ~S5P_WINSHMAP_CH_DISABLE(win_id);
+ writel(cfg, ctrl_base + S5P_WINSHMAP);
}
void s5pc_fimd_lcd_init(vidinfo_t *vid)
{
- unsigned int cfg = 0, rgb_mode, win_id = 0;
+ unsigned int cfg = 0, rgb_mode, win_id = 3;
/* store panel info to global variable */
pvid = vid;
/* set output to RGB */
rgb_mode = MODE_RGB_P;
- cfg = readl(ctrl_base + S5P_VIDCON0);
+ cfg = readl(ctrl_base + S5P_VIDCON0);
cfg &= ~S5P_VIDCON0_VIDOUT_MASK;
/* clock source is HCLK */
/* set polarity */
cfg = 0;
- cfg |= S5P_VIDCON1_IVDEN_INVERT | S5P_VIDCON1_IVCLK_RISING_EDGE;
+ if (!pvid->vl_clkp)
+ cfg |= S5P_VIDCON1_IVCLK_RISING_EDGE;
+ if (!pvid->vl_hsp)
+ cfg |= S5P_VIDCON1_IHSYNC_INVERT;
+ if (!pvid->vl_vsp)
+ cfg |= S5P_VIDCON1_IVSYNC_INVERT;
+ if (!pvid->vl_dp)
+ cfg |= S5P_VIDCON1_IVDEN_INVERT;
+
writel(cfg, ctrl_base + S5P_VIDCON1);
/* set timing */
cfg = 0;
- cfg |= S5P_VIDTCON0_VBPD(pvid->vl_bfw - 1);
- cfg |= S5P_VIDTCON0_VFPD(pvid->vl_efw - 1);
- cfg |= S5P_VIDTCON0_VSPW(pvid->vl_vpw - 1);
+ cfg |= S5P_VIDTCON0_VFPD(pvid->vl_vfpd - 1);
+ cfg |= S5P_VIDTCON0_VBPD(pvid->vl_vbpd - 1);
+ cfg |= S5P_VIDTCON0_VSPW(pvid->vl_vspw - 1);
writel(cfg, ctrl_base + S5P_VIDTCON0);
udebug("vidtcon0 = %x\n", cfg);
cfg = 0;
- cfg |= S5P_VIDTCON1_HBPD(pvid->vl_blw - 1);
- cfg |= S5P_VIDTCON1_HFPD(pvid->vl_elw - 1);
- cfg |= S5P_VIDTCON1_HSPW(pvid->vl_hpw - 1);
+ cfg |= S5P_VIDTCON1_HFPD(pvid->vl_hfpd - 1);
+ cfg |= S5P_VIDTCON1_HBPD(pvid->vl_hbpd - 1);
+ cfg |= S5P_VIDTCON1_HSPW(pvid->vl_hspw - 1);
writel(cfg, ctrl_base + S5P_VIDTCON1);
udebug("vidtcon1 = %x\n", cfg);
cfg = 0;
cfg |= S5P_VIDTCON2_HOZVAL(pvid->vl_col - 1);
cfg |= S5P_VIDTCON2_LINEVAL(pvid->vl_row - 1);
-
+
writel(cfg, ctrl_base + S5P_VIDTCON2);
udebug("vidtcon2 = %x\n", cfg);
/* set clock */
s5pc_fimd_set_clock();
+ /* set rgb mode to dual lcd. */
+ if (pvid->dual_lcd_enabled)
+ s5pc_fimd_set_dualrgb(1);
+ else
+ s5pc_fimd_set_dualrgb(0);
+
/* display on */
s5pc_fimd_lcd_on(win_id);
+ /* window on */
+ s5pc_fimd_window_on(win_id);
+
udebug("lcd controller init completed.\n");
return;