现在的位置: 首页 > 综合 > 正文

TFT LCD在S5PV210平台调试记录

2013年11月01日 ⁄ 综合 ⁄ 共 10850字 ⁄ 字号 评论关闭

首先弄清楚linux内核中LCD驱动相关文件包含内容,在驱动任务承担啥角色,然后对照《S5PV210_UM_REV1.1.pdf》和自己的LCD user manual修改参数。

我就是以前没有动过这部分调试,狠狠的看了三星samsung的芯片手册和液晶屏的Driver IC。A8核比2440和6410的LCD控制器要复杂、强大。

下面开始 ==>>

linux2.6.32内核中,关于lcd的驱动主要的文件为:

/drivers/video/sumsung/s3cfb.c 、s3cfb_fimd6x.c 等


一、LCD初始化入口

    @s3cfb.c  lines1306

static int s3cfb_probe(struct platform_device *pdev)
{
	struct s3c_platform_fb *pdata;
	struct resource *res;
	int ret = 0;
printk("# s3cfb_probe() for V-PDA LCD:\n");
#if 0
	/* ldo6 regulator on */
	printk("\t %s \n", __func__);
	lcd_regulator = regulator_get(NULL, "vddlcd");
	if (IS_ERR(lcd_regulator)) {
		printk(KERN_ERR "failed to get resource %s\n", "vddlcd");
		return PTR_ERR(lcd_regulator);
	}
	regulator_enable(lcd_regulator);
#endif
	/* initialzing global structure */
	fbdev = kzalloc(sizeof(struct s3cfb_global), GFP_KERNEL);
	if (!fbdev) {
		dev_err(fbdev->dev, "failed to allocate for "
			"global fb structure\n");
		goto err_global;
	}

	fbdev->dev = &pdev->dev;
	s3cfb_set_lcd_info(fbdev);//added in ili9341

	/* gpio */
	pdata = to_fb_plat(&pdev->dev);
	if (pdata->cfg_gpio)
		pdata->cfg_gpio(pdev);

	if (pdata->clk_on)
		pdata->clk_on(pdev, &fbdev->clock);

	/* io memory */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(fbdev->dev, "failed to get io memory region\n");
		ret = -EINVAL;
		goto err_io;
	}

	/* request mem region */
	res = request_mem_region(res->start,
				 res->end - res->start + 1, pdev->name);
	if (!res) {
		dev_err(fbdev->dev, "failed to request io memory region\n");
		ret = -EINVAL;
		goto err_io;
	}

	/* ioremap for register block */
	fbdev->regs = ioremap(res->start, res->end - res->start + 1);
	if (!fbdev->regs) {
		dev_err(fbdev->dev, "failed to remap io region\n");
		ret = -EINVAL;
		goto err_io;
	}

	/* irq */
	fbdev->irq = platform_get_irq(pdev, 0);
	if (request_irq(fbdev->irq, s3cfb_irq_frame, IRQF_SHARED,
			pdev->name, fbdev)) {
		dev_err(fbdev->dev, "request_irq failed\n");
		ret = -EINVAL;
		goto err_irq;
	}

	/*set gamma LUT*/ //SSCR xuhui 110130
	s3cfb_set_gamma(fbdev);

#if 1
	// added by jamie (2009.08.18)
	// enable VSYNC
	s3cfb_set_vsync_interrupt(fbdev, 1);  //开启场同步信号
	s3cfb_set_global_interrupt(fbdev, 1);  //设置全局中断变量
#endif

#ifdef CONFIG_FB_S3C_TRACE_UNDERRUN
	if (request_irq(platform_get_irq(pdev, 1), s3cfb_irq_fifo,
			IRQF_DISABLED, pdev->name, fbdev)) {
		dev_err(fbdev->dev, "request_irq failed\n");
		ret = -EINVAL;
		goto err_irq;
	}

	s3cfb_set_fifo_interrupt(fbdev, 1);
	dev_info(fbdev->dev, "fifo underrun trace\n");
#endif

	/* init global */
	s3cfb_init_global();

	/* prepare memory */
	if (s3cfb_alloc_framebuffer())
		goto err_alloc;

	if (s3cfb_register_framebuffer())
		goto err_alloc;

	s3cfb_set_clock(fbdev);
	s3cfb_enable_window(pdata->default_win);
	s3cfb_update_power_state(pdata->default_win, FB_BLANK_UNBLANK);

	s3cfb_display_on(fbdev);

#ifdef CONFIG_FB_S3C_LCD_INIT
	/* panel control */

#if defined(CONFIG_FB_S3C_TL2796)
	if (pdata->backlight_on)
		pdata->backlight_on(pdev);
#elif defined(CONFIG_FB_S3C_LTE480WV)
	if (pdata->backlight_on)
		pdata->backlight_on(pdev);
#elif defined(CONFIG_FB_S3C_ILI9341) /*Added by gezhenglai@v-simtone*/
	if (pdata->backlight_on)
		pdata->backlight_on(pdev);
#endif

	if (pdata->lcd_on)
		pdata->lcd_on(pdev);
#endif

#ifdef CONFIG_HAS_WAKELOCK
#ifdef CONFIG_HAS_EARLYSUSPEND
	fbdev->early_suspend.suspend = s3cfb_early_suspend;
	fbdev->early_suspend.resume = s3cfb_late_resume;
	fbdev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
	//if, is in USER_SLEEP status and no active auto expiring wake lock
	//if (has_wake_lock(WAKE_LOCK_SUSPEND) == 0 && get_suspend_state() == PM_SUSPEND_ON)
	register_early_suspend(&fbdev->early_suspend);
#endif
#endif

	ret = device_create_file(&(pdev->dev), &dev_attr_win_power);
	if (ret < 0)
		dev_err(fbdev->dev, "failed to add sysfs entries\n");

	dev_info(fbdev->dev, "registered successfully\n");

#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
	if (fb_prepare_logo( fbdev->fb[pdata->default_win], FB_ROTATE_UR)) {
		printk("Start display and show logo\n");
		/* Start display and show logo on boot */
		fb_set_cmap(&fbdev->fb[pdata->default_win]->cmap, fbdev->fb[pdata->default_win]);
		fb_show_logo(fbdev->fb[pdata->default_win], FB_ROTATE_UR);
	}
#endif
	return 0;

err_alloc:
	free_irq(fbdev->irq, fbdev);

err_irq:
	iounmap(fbdev->regs);

err_io:
	if (pdata->clk_off)
		pdata->clk_off(pdev, &fbdev->clock);

err_global:
	return ret;
}


二、lcd控制器初始化实例

2.1.看一下三星210手册中给的初始化流程的简要概述,一路设置下来:

Use the following registers to configure display controller:
1. VIDCON0: Configures video output format and displays enable/disable.
2. VIDCON1: Specifies RGB I/F control signal.
3. VIDCON2: Specifies output data format control.
4. VIDCON3: Specifies image enhancement control.
5. I80IFCONx: Specifies CPU interface control signal.
6. VIDTCONx: Configures video output timing and determines the size of display.
7. WINCONx: Specifies each window feature setting.
8. VIDOSDxA, VIDOSDxB: Specifies window position setting.
9. VIDOSDxC,D: Specifies OSD size setting.
10. VIDWxALPHA0/1: Specifies alpha value setting.
11. BLENDEQx: Specifies blending equation setting.
12. VIDWxxADDx: Specifies source image address setting.
13. WxKEYCONx: Specifies color key setting register.
14. WxKEYALPHA: Specifies color key alpha value setting.
15. WINxMAP: Specifies window color control.
16. GAMMALUT_xx: Specifies gamma value setting.
17. COLORGAINCON: Specifies color gain value setting.
18. HUExxx: Specifies Hue coefficient and offset value setting.
19. WPALCON: Specifies palette control register.
20. WxRTQOSCON: Specifies RTQoS control register.
21. WxPDATAxx: Specifies Window Palette Data of each Index.
22. SHDOWCON: Specifies Shadow control register.
23. WxRTQOSCON: Specifies QoS control register.

2.2. 在函数s3cfb_fimd6x.c

int s3cfb_set_clock(struct s3cfb_global *ctrl)
{
	struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev);
	u32 cfg, maxclk, src_clk, vclk, div;

	maxclk = 86 * 1000000;
	/* fixed clock source: hclk */
	cfg = readl(ctrl->regs + S3C_VIDCON0);
	cfg &= ~(S3C_VIDCON0_CLKSEL_MASK | S3C_VIDCON0_CLKDIR_MASK | S3C_VIDCON0_VCLKEN_MASK | S3C_VIDCON0_CLKVALUP_MASK);
	cfg |= (S3C_VIDCON0_CLKDIR_DIVIDED | S3C_VIDCON0_VCLKEN_NORMAL | S3C_VIDCON0_CLKVALUP_ALWAYS);
	//cfg |= (S3C_VIDCON0_VCLKEN_FREERUN | S3C_VIDCON0_CLKVALUP_ALWAYS);

	if (strcmp(pdata->clk_name, "sclk_fimd") == 0) {
		cfg |= S3C_VIDCON0_CLKSEL_SCLK;
		src_clk = clk_get_rate(ctrl->clock);
		printk(KERN_INFO "FIMD src sclk = %d\n", src_clk);
	} else {
		cfg |= S3C_VIDCON0_CLKSEL_HCLK;
		src_clk = ctrl->clock->parent->rate;
		printk(KERN_INFO "FIMD src hclk = %d\n", src_clk);

	}

	//vclk = PICOS2KHZ(ctrl->fb[pdata->default_win]->var.pixclock) * 1000;//normal foc ,but our lcd IC Fin div 10 internal
	vclk = PICOS2KHZ(ctrl->fb[pdata->default_win]->var.pixclock) * 100; //so we should div CLKOUT_vclk by 10

	if (vclk > maxclk) {
		dev_info(ctrl->dev, "vclk(%d) should be smaller than %d\n",
			vclk, maxclk);
		/* vclk = maxclk; */
	}

	div = src_clk / vclk;
	if (src_clk % vclk)
		div++;

	if ((src_clk/div) > maxclk)
		dev_info(ctrl->dev, "vclk(%d) should be smaller than %d Hz\n",
			src_clk/div, maxclk);

	cfg |= S3C_VIDCON0_CLKVAL_F(div - 1);  //
	writel(cfg, ctrl->regs + S3C_VIDCON0);

	dev_dbg(ctrl->dev, "parent clock: %d, vclk: %d, vclk div: %d\n",
			src_clk, vclk, div);

	return 0;
}

有vclk时钟输出而且是符合需要的频率。

int s3cfb_set_global_interrupt(struct s3cfb_global *ctrl, int enable)
{
	u32 cfg = 0;

	cfg = readl(ctrl->regs + S3C_VIDINTCON0);
	cfg &= ~(S3C_VIDINTCON0_INTFRMEN_ENABLE | S3C_VIDINTCON0_INT_ENABLE);

	if (enable) {
		dev_dbg(ctrl->dev, "video interrupt is on\n");
		cfg |= (S3C_VIDINTCON0_INTFRMEN_ENABLE | S3C_VIDINTCON0_INT_ENABLE);
	} else {
		dev_dbg(ctrl->dev, "video interrupt is off\n");
		cfg |= (S3C_VIDINTCON0_INTFRMEN_DISABLE | S3C_VIDINTCON0_INT_DISABLE);
	}

	writel(cfg, ctrl->regs + S3C_VIDINTCON0);

	return 0;
}

int s3cfb_set_vsync_interrupt(struct s3cfb_global *ctrl, int enable)
{
	u32 cfg = 0;

	cfg = readl(ctrl->regs + S3C_VIDINTCON0);
	cfg &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;

	if (enable) {
		dev_dbg(ctrl->dev, "vsync interrupt is on\n");
		cfg |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
	} else {
		dev_dbg(ctrl->dev, "vsync interrupt is off\n");
		cfg &= ~S3C_VIDINTCON0_FRAMESEL0_VSYNC;
	}

	writel(cfg, ctrl->regs + S3C_VIDINTCON0);

	/*enable VSYNC Signal Output added by gezhenglai*/
	cfg = readl(ctrl->regs + S3C_VIDTCON3);
	cfg &= ~(1 << 30);
	cfg |= (1 << 31); //|(1 << 29) |(2 << 0)|(4 << 8)
	writel(cfg, ctrl->regs + S3C_VIDTCON3);

	return 0;
}

这里设置了VYNC信号输出,但是示波器无法看到这个波形。纠结。。。

继续看源码,看看是何原因。

到这里突然看到关于VTIME这个始终控制的模块说明,S5PV210处理器的原文说明如下:

1.3.8.1 RGB Interface Controller
VTIME generates control signals such as RGB_VSYNC, RGB_HSYNC, RGB_VDEN, and RGB_VCLK signal for the RGB interface. These control signals are used while configuring theVIDTCON0/
1/ 2
registers in the VSFR register.
Based on the programmable configurations of display control registers in the VSFR, the VTIME module generates programmable control signals that support different types of display devices.
The RGB_VSYNC signal causes the LCD line pointer to begin at the top of display. The configuration of both HOZVAL field and LINEVAL registers control pulse generation of RGB_VSYNC and RGB_HSYNC. Based on the following equations, the size of the LCD panel determines
HOZVAL and LINEVAL:
• HOZVAL = (Horizontal display size) -1
• LINEVAL = (Vertical display size) -1
The CLKVAL field in VIDCON0 register controls the rate of RGB_VCLK signal. Table 1-5 defines the relationship of RGB_VCLK and CLKVAL. The minimum value of CLKVAL is 1.

− RGB_VCLK (Hz) =HCLK/ (CLKVAL+1), where CLKVAL >= 1
VSYNC, VBPD, VFPD, HSYNC, HBPD, HFPD, HOZVAL, and LINEVAL configure RGB_HSYNC and RGB_VSYNC signal. The frame rate is RGB_VSYNC signal frequency. The frame rate is related to the field of VSYNC, VBPD, VFPD, LINEVAL, HSYNC, HBPD, HFPD, HOZVAL, and CLKVAL registers.
Most LCD drivers need their own adequate frame rate.
To calculate frame rate, use the following equation:
• (1 / Frame Rate) =  { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1) }

                                    x {(HSPW+1) + (HBPD +1)  + (HFPD+1) + (HOZVAL + 1) }

                                    x { ( CLKVAL+1 ) / ( Frequency of Clock source ) }

说明VSYNC、HSYNC、VDEN和VCLK的时序都是由三个寄存器VIDTCON0/1/2控制的,在user manual中有关水平和垂直的HOZVAL、LINEVAL以及其他的VBPD等等计算得到frame rate,即像素时钟频率。

奇怪,我在代码中已经初始化这些寄存器了呀。如:

/*VIDTCON 0*/
//cfg |= S3C_VIDTCON0_VBPDE(time->v_bpe - 1);
cfg |= S3C_VIDTCON0_VBPD(time->v_bp - 1);
cfg |= S3C_VIDTCON0_VFPD(time->v_fp - 1);
cfg |= S3C_VIDTCON0_VSPW(time->v_sw - 1);
writel(cfg, ctrl->regs + S3C_VIDTCON0);

/*VIDTCON 1*/

cfg = 0;//cfg |= S3C_VIDTCON1_VFPDE(time->v_fpe - 1);cfg |= S3C_VIDTCON1_HBPD(time->h_bp - 1);cfg |= S3C_VIDTCON1_HFPD(time->h_fp - 1);cfg |= S3C_VIDTCON1_HSPW(time->h_sw - 1);writel(cfg, ctrl->regs + S3C_VIDTCON1);

/*VIDTCON 2*/
cfg |= S3C_VIDTCON2_HOZVAL(ctrl->lcd->width - 1);
cfg |= S3C_VIDTCON2_LINEVAL(ctrl->lcd->height - 1);
writel(cfg, ctrl->regs + S3C_VIDTCON2);

另外,还有VIDTCON3:
VIDTCON3        Bit                Description
VSYNCEN       [31]             Enables VSYNC Signal Output. (使能VSYNC输出)
                                              0 = Disables   1 = Enables
                                              VBPD(VFPD, VSPW) + 1 < LINEVAL (when VSYNCEN =1)(当此位使能是,lineval)
Reserved        [30]              Reserved
FRMEN           [29]              Enables the FRM signal output.
                                              0 = Disables  1 = Enables
INVFRM          [28]              Controls the polarity of FRM pulse.
                                              0 = Active HIGH  1 = Active LOW
FRMVRATE   [27:24]         Controls the FRM issue rate (Maximum rate up to 1:16)
Reserved       [23:16]         Reserved
FRMVFPD     [15:8]            Specifies the number of line between data active and FRM signal.
FRMVSPW    [7:0]              Specifies the number of line of FRM signal width.
                                              (FRMVFPD + 1) + (FRMVSPW + 1) < LINEVAL + 1 (in RGB)

对VIDCON0寄存器的配置错误时会造成无视频控制信号(vysnc\hysnc\vden)的输出

cfg |= (S3C_VIDCON0_CLKVALUP_ALWAYS | S3C_VIDCON0_VCLKEN_NORMAL | S3C_VIDCON0_CLKDIR_DIVIDED);

vidcon0的bit5为vclk运行模式控制

Controls VCLK Free Run (Only valid at RGB IF mode).
0 = Normal mode (controls using ENVID)
1 = Free-run mode

VIDOUT  bit28:26,设置为RGB interface

至于L0/L1_DATA16设置无关紧要

待续

部分参考链接

http://hi.baidu.com/prorgramstudio/item/fbf1bd824e07c3dd5f0ec1e1

抱歉!评论已关闭.