TFT LCD在S5PV210平臺調試記錄

首先弄清楚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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章