TI中文支持网
TI专业的中文技术问题搜集分享网站

AM335x u-boot中添加LCD驱动,不能操作LCD控制器,怎么解决?

AM335x u-boot中添加LCD驱动,不能操作LCD控制器,怎么解决?

LCD控制是通过lcd_ctrl_init来完成的,具体的lcd_ctrl_init代码如下~~

/*
 * Copyright (C) 2013 Hannes Schmelzer <oe5hpm@oevsv.at>
 * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
 *
 * minimal framebuffer driver for TI's AM335x SoC to be compatible with
 * Wolfgang Denk's LCD-Framework (CONFIG_LCD, common/lcd.c)
 *
 * - supporting only 24bit RGB/TFT raster Mode (not using palette)
 * - sets up LCD controller as in 'am335x_lcdpanel' struct given
 * - starts output DMA from gd->fb_base buffer
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */
#include <common.h>
#include <version.h>
#include <asm/arch/hardware.h>
#include <lcd.h>
#include "am3354-lcd.h"
#include <asm/io.h>
#include <asm/arch/gpio.h>
#include <asm/gpio.h>

#define LCD_CNTL_BASE 0x4830E000
#if !defined(LCD_CNTL_BASE)
#error "hw-base address of LCD-Controller (LCD_CNTL_BASE) not defined!"
#endif


/* LCD Control Register */
#define LCD_CLK_DIVISOR(x)			((x) << 8)
#define LCD_RASTER_MODE				0x01
/* LCD Clock Enable Register */
#define LCD_CORECLKEN				(0x01 << 0)
#define LCD_LIDDCLKEN				(0x01 << 1)
#define LCD_DMACLKEN				(0x01 << 2)
/* LCD DMA Control Register */
#define LCD_DMA_BURST_SIZE(x)			((x) << 4)
#define LCD_DMA_BURST_1				0x0
#define LCD_DMA_BURST_2				0x1
#define LCD_DMA_BURST_4				0x2
#define LCD_DMA_BURST_8				0x3
#define LCD_DMA_BURST_16			0x4
/* LCD Timing_0 Register */
#define LCD_HBPLSB(x)				((((x)-1) & 0xFF) << 24)
#define LCD_HFPLSB(x)				((((x)-1) & 0xFF) << 16)
#define LCD_HSWLSB(x)				((((x)-1) & 0x3F) << 10)
#define LCD_HORLSB(x)				(((((x) >> 4)-1) & 0x3F) << 4)
#define LCD_HORMSB(x)				(((((x) >> 4)-1) & 0x40) >> 4)
/* LCD Timing_1 Register */
#define LCD_VBP(x)				((x) << 24)
#define LCD_VFP(x)				((x) << 16)
#define LCD_VSW(x)				(((x)-1) << 10)
#define LCD_VERLSB(x)				(((x)-1) & 0x3FF)
/* LCD Timing_2 Register */
#define LCD_HSWMSB(x)				((((x)-1) & 0x3C0) << 21)
#define LCD_VERMSB(x)				((((x)-1) & 0x400) << 16)
#define LCD_HBPMSB(x)				((((x)-1) & 0x300) >> 4)
#define LCD_HFPMSB(x)				((((x)-1) & 0x300) >> 8)
#define LCD_INVMASK(x)				((x) & 0x3F00000)
/* LCD Raster Ctrl Register */
#define LCD_TFT_24BPP_MODE			(1 << 25)
#define LCD_TFT_24BPP_UNPACK			(1 << 26)
#define LCD_PALMODE_RAWDATA			(0x10 << 20)
#define LCD_TFT_MODE				(0x01 << 7)
#define LCD_RASTER_ENABLE			(0x01 << 0)
#define LCD_RASTER_DISABLE(0x00 << 0)


/* Macro definitions */
#define FBSIZE(x)	((x->hactive * x->vactive * x->bpp) >> 3)

struct am335x_lcdhw {
	unsigned int		pid;			/* 0x00 */
	unsigned int		ctrl;			/* 0x04 */
	unsigned int		gap0;			/* 0x08 */
	unsigned int		lidd_ctrl;		/* 0x0C */
	unsigned int		lidd_cs0_conf;		/* 0x10 */
	unsigned int		lidd_cs0_addr;		/* 0x14 */
	unsigned int		lidd_cs0_data;		/* 0x18 */
	unsigned int		lidd_cs1_conf;		/* 0x1C */
	unsigned int		lidd_cs1_addr;		/* 0x20 */
	unsigned int		lidd_cs1_data;		/* 0x24 */
	unsigned int		raster_ctrl;		/* 0x28 */
	unsigned int		raster_timing0;		/* 0x2C */
	unsigned int		raster_timing1;		/* 0x30 */
	unsigned int		raster_timing2;		/* 0x34 */
	unsigned int		raster_subpanel;	/* 0x38 */
	unsigned int		raster_subpanel2;	/* 0x3C */
	unsigned int		lcddma_ctrl;		/* 0x40 */
	unsigned int		lcddma_fb0_base;	/* 0x44 */
	unsigned int		lcddma_fb0_ceiling;	/* 0x48 */
	unsigned int		lcddma_fb1_base;	/* 0x4C */
	unsigned int		lcddma_fb1_ceiling;	/* 0x50 */
	unsigned int		sysconfig;		/* 0x54 */
	unsigned int		irqstatus_raw;		/* 0x58 */
	unsigned int		irqstatus;		/* 0x5C */
	unsigned int		irqenable_set;		/* 0x60 */
	unsigned int		irqenable_clear;	/* 0x64 */
	unsigned int		gap1;			/* 0x68 */
	unsigned int		clkc_enable;		/* 0x6C */
	unsigned int		clkc_reset;		/* 0x70 */
};

static struct am335x_lcdhw *lcdhw = (void *)LCD_CNTL_BASE;
DECLARE_GLOBAL_DATA_PTR;


struct am335x_lcdpanel lcd_panelq = {
		.hactive=480,	/* Horizontal active area */
		.vactive=272,	/* Vertical active area */
		.bpp=24,		/* bits per pixel */
		.hfp=2,		/* Horizontal front porch */
		.hbp=2,		/* Horizontal back porch */
		.hsw=41,		/* Horizontal Sync Pulse Width */
		.vfp=2,		/* Vertical front porch */
		.vbp=2,		/* Vertical back porch */
		.vsw=10,		/* Vertical Sync Pulse Width */
		.pxl_clk_div=5,	/* Pixel clock divider*/
		.pol=0x3F000000,		/* polarity of sync, clock signals */
		.pup_delay=50,	/** time in ms after power on to* initialization of lcd-controller* (VCC ramp up time)*/
		.pon_delay=50,	/** time in ms after initialization of* lcd-controller (pic stabilization)*/
	//void (*panel_power_ctrl)(int);	/* fp for power on/off display */
};

vidinfo_t panel_info = {
	.vl_col = 480,
	.vl_row = 272,
	.vl_bpix = 5
};

int load_lcdtiming(struct am335x_lcdpanel *panel)
{
	struct am335x_lcdpanel pnltmp;

	pnltmp.hactive = 480;
	pnltmp.vactive = 272;
	pnltmp.bpp = 32;
	pnltmp.hfp = 2;
	pnltmp.hbp = 2;
	pnltmp.hsw = 41;
	pnltmp.vfp = 2;
	pnltmp.vbp = 2;
	pnltmp.vsw = 10;
	pnltmp.pxl_clk_div = 5;
	pnltmp.pol = 0x3F000000;
	pnltmp.pup_delay = 50;
	pnltmp.pon_delay = 50;
	//panel_info.vl_rot = getenv_ulong("ds1_rotation", 10, 0);

	if (~0UL == (pnltmp.hactive) ||~0UL == (pnltmp.vactive) ||~0UL == (pnltmp.bpp) ||~0UL == (pnltmp.hfp) ||~0UL == (pnltmp.hbp) ||~0UL == (pnltmp.hsw) ||~0UL == (pnltmp.vfp) ||~0UL == (pnltmp.vbp) ||~0UL == (pnltmp.vsw) ||~0UL == (pnltmp.pxl_clk_div) ||~0UL == (pnltmp.pol) ||~0UL == (pnltmp.pup_delay) ||~0UL == (pnltmp.pon_delay)) {
		puts("lcd-settings in env/dtb incomplete!\n");
		printf("display-timings:\n"
			"================\n"
			"hactive: %d\n"
			"vactive: %d\n"
			"bpp: %d\n"
			"hfp: %d\n"
			"hbp: %d\n"
			"hsw: %d\n"
			"vfp: %d\n"
			"vbp: %d\n"
			"vsw: %d\n"
			"pxlclk : %d\n"
			"pol: 0x%08x\n"
			"pondly : %d\n",
			pnltmp.hactive, pnltmp.vactive, pnltmp.bpp,
			pnltmp.hfp, pnltmp.hbp, pnltmp.hsw,
			pnltmp.vfp, pnltmp.vbp, pnltmp.vsw,
			pnltmp.pxl_clk_div, pnltmp.pol, pnltmp.pon_delay);

		return -1;
	}
	debug("lcd-settings in env complete, taking over.\n");
	memcpy((void *)panel,(void *)&pnltmp,sizeof(struct am335x_lcdpanel));

	return 0;
}

void lcdbacklight(int on)
{
	gpio_request( (3*32+17), "led_light" );
	gpio_direction_output( (3*32+17), 0 );
}

void br_summaryscreen(void)
{

	br_summaryscreen_printenv(" - B&R -", "br_orderno", 0, "-\n");
	br_summaryscreen_printenv(" Serial/Rev :", "br_serial", 0, "\n");
	br_summaryscreen_printenv(" MAC (IF1)  :", "br_mac1", "ethaddr", "\n");
	br_summaryscreen_printenv(" MAC (IF2)  :", "br_mac2", 0, "\n");
	lcd_puts(" Bootloader : " PLAIN_VERSION "\n");
	lcd_puts("\n");

}

static void br_summaryscreen_printenv(char *prefix,char *name, char *altname,char *suffix)
{
	char *envval = getenv(name);
	if (0 != envval) {
		lcd_printf("%s %s %s", prefix, envval, suffix);
	} else if (0 != altname) {
		envval = getenv(altname);
		if (0 != envval)
			lcd_printf("%s %s %s", prefix, envval, suffix);
	} else {
		lcd_printf("\n");
	}
}

int lcd_get_size(int *line_length)
{
	*line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
	return *line_length * panel_info.vl_row + 0x20;
}

void lcd_ctrl_init(void *lcdbase)
{
	printf("lcd_ctrl_init\n");
	
	struct am335x_lcdpanel lcd_panel;
	memset(&lcd_panel, 0, sizeof(struct am335x_lcdpanel));
	
	if (load_lcdtiming(&lcd_panel) != 0)
		return;
		
	//lcd_panel.panel_power_ctrl = &lcdpower;
	if (0 != am335xfb_init(&lcd_panel))
		printf("ERROR: failed to initialize video!\n");
		
	panel_info.vl_col = lcd_panel.hactive;
	panel_info.vl_row = lcd_panel.vactive;
	lcd_set_flush_dcache(1);
	
}

void lcd_enable(void)
{
	br_summaryscreen();
	lcdbacklight(1);  
}

int am335xfb_init(struct am335x_lcdpanel *panel)
{
	if (0 == gd->fb_base) {
		printf("ERROR: no valid fb_base stored in GLOBAL_DATA_PTR!\n");
		return -1;
	}
	if (0 == panel) {
		printf("ERROR: missing ptr to am335x_lcdpanel!\n");
		return -1;
	}

	debug("setting up LCD-Controller for %dx%dx%d (hfp=%d,hbp=%d,hsw=%d / ",panel->hactive, panel->vactive, panel->bpp,panel->hfp, panel->hbp, panel->hsw);
	debug("vfp=%d,vbp=%d,vsw=%d / clk-div=%d)\n",panel->vfp, panel->vfp, panel->vsw, panel->pxl_clk_div);
	debug("using frambuffer at 0x%08x with size %d.\n",(unsigned int)gd->fb_base, FBSIZE(panel));
	printf("using frambuffer at0x%x with size %x\n",
		(unsigned int)gd->fb_base, FBSIZE(panel));

	/* palette default entry */
	memset((void *)gd->fb_base, 0, 0x20);
	*(unsigned int *)gd->fb_base = 0x4000;

	printf("printf address of lcdhw->clk_enable2 %x\n",*(unsigned int *)gd->fb_base);
	/* turn ON display through powercontrol function if accessible */
	/*
	if (0 != panel->panel_power_ctrl)
		panel->panel_power_ctrl(1);
	*/
	
	debug("am335x-fb: wait for stable power ...\n");
	mdelay(panel->pup_delay);
	writel( LCD_CORECLKEN | LCD_LIDDCLKEN | LCD_DMACLKEN, (LCD_CNTL_BASE+lcdhw->clkc_enable) );
	
	printf("printf address of lcdhw->clk_enable2 %x\n",lcdhw->clkc_enable);
	lcdhw->clkc_enable = LCD_CORECLKEN | LCD_LIDDCLKEN | LCD_DMACLKEN;
	
	lcdhw->raster_ctrl = 0;
	lcdhw->ctrl = LCD_CLK_DIVISOR(panel->pxl_clk_div) | LCD_RASTER_MODE;
	lcdhw->lcddma_fb0_base = gd->fb_base;
	lcdhw->lcddma_fb0_ceiling = gd->fb_base + FBSIZE(panel) + 0x20;
	lcdhw->lcddma_fb1_base = gd->fb_base;
	lcdhw->lcddma_fb1_ceiling = gd->fb_base + FBSIZE(panel) + 0x20;
	lcdhw->lcddma_ctrl = LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);

	lcdhw->raster_timing0 = LCD_HORLSB(panel->hactive) |
				LCD_HORMSB(panel->hactive) |
				LCD_HFPLSB(panel->hfp) |
				LCD_HBPLSB(panel->hbp) |
				LCD_HSWLSB(panel->hsw);
	lcdhw->raster_timing1 = LCD_VBP(panel->vbp) |
				LCD_VFP(panel->vfp) |
				LCD_VSW(panel->vsw) |
				LCD_VERLSB(panel->vactive);
	lcdhw->raster_timing2 = LCD_HSWMSB(panel->hsw) |
				LCD_VERMSB(panel->vactive) |
				LCD_INVMASK(panel->pol) |
				LCD_HBPMSB(panel->hbp) |
				LCD_HFPMSB(panel->hfp) |
				0x0000FF00;	/* clk cycles for ac-bias */
	lcdhw->raster_ctrl =	LCD_TFT_24BPP_MODE |
				LCD_TFT_24BPP_UNPACK |
				LCD_PALMODE_RAWDATA |
				LCD_TFT_MODE |
				LCD_RASTER_ENABLE;

	gd->fb_base += 0x20;	/* point fb behind palette */

	debug("am335x-fb: waiting picture to be stable.\n.");
	mdelay(panel->pon_delay);

	return 0;
}

编译能通过,但是CPU运行的

writel( LCD_CORECLKEN | LCD_LIDDCLKEN | LCD_DMACLKEN, (LCD_CNTL_BASE+lcdhw->clkc_enable) );
这里就死掉了,过会就自动复位了,串口显示如下:

U-Boot 2016.03 (May 09 2017 – 18:25:01 +0800)

U-Boot code: 80800000 -> 8085FBE4 BSS_END: -> 808AC4BC
Watchdog enabled
I2C: ready
DRAM: 256 MiB
lcd_init
[LCD] Initializing LCD frambuffer at 8ff70000
lcd_ctrl_init
using frambuffer at0x8ff70000 with size 7f800
printf address of lcdhw->clk_enable2 4000
CCCCCCCCCCCCCCCCCCCCCCCC

Denny%20Yang99373:

可以通过CCS仿真器 手动修改这些寄存器看看

user4985813:

回复 Denny%20Yang99373:

我手上没有CCS仿真器,我用的是AM335x Starter Kit的开发板。会不会CPU运行内存地址有问题?

int am335xfb_init(struct am335x_lcdpanel *panel)
{if (0 == gd->fb_base) {printf("ERROR: no valid fb_base stored in GLOBAL_DATA_PTR!\n");return -1;}if (0 == panel) {printf("ERROR: missing ptr to am335x_lcdpanel!\n");return -1;}debug("setting up LCD-Controller for %dx%dx%d (hfp=%d,hbp=%d,hsw=%d / ",panel->hactive, panel->vactive, panel->bpp,panel->hfp, panel->hbp, panel->hsw);debug("vfp=%d,vbp=%d,vsw=%d / clk-div=%d)\n",panel->vfp, panel->vfp, panel->vsw, panel->pxl_clk_div);debug("using frambuffer at 0x%08x with size %d.\n",(unsigned int)gd->fb_base, FBSIZE(panel));printf("using frambuffer at0x%x with size %x\n",(unsigned int)gd->fb_base, FBSIZE(panel));/* palette default entry */memset((void *)gd->fb_base, 0, 0x20);*(unsigned int *)gd->fb_base = 0x4000;printf("printf address of lcdhw->clk_enable2 %x\n",*(unsigned int *)gd->fb_base);/* turn ON display through powercontrol function if accessible *//*if (0 != panel->panel_power_ctrl)panel->panel_power_ctrl(1);*/debug("am335x-fb: wait for stable power ...\n");mdelay(panel->pup_delay);
/*writel( LCD_CORECLKEN | LCD_LIDDCLKEN | LCD_DMACLKEN, (LCD_CNTL_BASE+lcdhw->clkc_enable) );printf("printf address of lcdhw->clk_enable2 %x\n",lcdhw->clkc_enable);lcdhw->clkc_enable = LCD_CORECLKEN | LCD_LIDDCLKEN | LCD_DMACLKEN;lcdhw->raster_ctrl = 0;lcdhw->ctrl = LCD_CLK_DIVISOR(panel->pxl_clk_div) | LCD_RASTER_MODE;lcdhw->lcddma_fb0_base = gd->fb_base;lcdhw->lcddma_fb0_ceiling = gd->fb_base + FBSIZE(panel) + 0x20;lcdhw->lcddma_fb1_base = gd->fb_base;lcdhw->lcddma_fb1_ceiling = gd->fb_base + FBSIZE(panel) + 0x20;lcdhw->lcddma_ctrl = LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);lcdhw->raster_timing0 = LCD_HORLSB(panel->hactive) |LCD_HORMSB(panel->hactive) |LCD_HFPLSB(panel->hfp) |LCD_HBPLSB(panel->hbp) |LCD_HSWLSB(panel->hsw);lcdhw->raster_timing1 = LCD_VBP(panel->vbp) |LCD_VFP(panel->vfp) |LCD_VSW(panel->vsw) |LCD_VERLSB(panel->vactive);lcdhw->raster_timing2 = LCD_HSWMSB(panel->hsw) |LCD_VERMSB(panel->vactive) |LCD_INVMASK(panel->pol) |LCD_HBPMSB(panel->hbp) |LCD_HFPMSB(panel->hfp) |0x0000FF00;	/* clk cycles for ac-bias */lcdhw->raster_ctrl =	LCD_TFT_24BPP_MODE |LCD_TFT_24BPP_UNPACK |LCD_PALMODE_RAWDATA |LCD_TFT_MODE |LCD_RASTER_ENABLE;gd->fb_base += 0x20;debug("am335x-fb: waiting picture to be stable.\n.");mdelay(panel->pon_delay);
*/return 0;
}

我如果把此函数

int am335xfb_init(struct am335x_lcdpanel *panel)

内读写LCD控制器的相关代码给注释掉,u-boot就可以跑完了,除了用CCS仿真器意外,还有什么解决方案吗?还是在读写LCD控制器之前要初始化其他什么东东

Eggsy Pang:

你是对lcd的clk的寄存器写失败,很大可能你还没有使能display 的PLL

user4985813:

回复 Eggsy Pang:

根据资料我在SPL启动期间对LCD的时钟进行了这样的配置:

在相应的文件代码里加入:

1、

const struct dpll_regs dpll_disp_regs = { .cm_clkmode_dpll = CM_WKUP + 0x98, .cm_idlest_dpll = CM_WKUP + 0x48, .cm_clksel_dpll = CM_WKUP + 0x54, .cm_div_m2_dpll = CM_WKUP + 0xA4,};

2、

const struct dpll_params dpll_disp = { 100, OSC-1, 1, -1, -1, -1, -1};

3、

const struct dpll_params *get_dpll_disp_params(void){ return &dpll_disp;}

4、

enable_basic_clocks

    clk_domains[]

     + —>&cmper->lcdcclkstctrl,

    clk_modules_explicit_en[]

     + —>&cmper->lcdclkctrl,

原文件中有对应的l3clkstctrl,l3sclkstctrl,l4lsclkstctrl时钟唤醒与时钟使能(l3clkctrl,l4lsclkctrl)

5、

setup_dplls

writel(0x300, &cmwkup->clkdcoldodpllper);

   +   —->writel(0x0, &cmdpll->clklcdcpixelclk);//根据ti_manual Figure 8-13选择CLKOUT作为LCD_CLK—-LCD_CLK=CLKIN*100/((24-1)+1)*1

   +          params = get_dpll_disp_params();

   +           do_setup_dpll(&dpll_disp_regs, params);

params = get_dpll_ddr_params();

编译下载,现象并没有改善,我以为这样至少能访问LCD控制器了,但是还是不能,在u-boot中不可以这样使能LCD时钟?

Eggsy Pang:

回复 user4985813:

参考我之前发过的帖子,里面有时钟见解和LCD配置

http://www.deyisupport.com/question_answer/dsp_arm/sitara_arm/f/25/t/122028.aspx

user4985813:

回复 Eggsy Pang:

我写之前没有看到您的帖子,后来浏览论坛看到了您的帖子,之前不知道l3'l4ls这些寄存器的作用,看到之后知道了,后来我又根据你的帖子对照了一些自己的程序感觉是没有错误的。我在想是不是真的lcd时钟配置多样性,不能在uboot自带的时钟配置程序中添加,需要另外写一个时钟配置函数?

不过非常感谢您的回复!!!!

Eggsy Pang:

回复 user4985813:

是的,对于LCD需要enable lcd的时钟,我的link里面有相关文件

user4985813:

回复 Eggsy Pang:

参考您给的问题处理方案,Uboot中已成功添加LCD的驱动,除了你提到的修改的地方,还要注意,Drivers文件下的Makefile的修改(添加obj-y += lcd/),以及./a.out 480 272 ./图片名称.bmp ./image.h 24 RGB 生成image.h时用RGB不是BGR。

user4985813:

回复 Eggsy Pang:

根据你给的问题解决方案:uboot中已成功添加LCD驱动,除了你提到的修改的地方,还需要注意生成image.h时,最后用RGB而不是BGR(./a.out 480 272 ./图片名称.bmp ./image.h 24 BGR),还要注意drivers目录下的Makefile文件的修改(添加obj-y += lcd/)。

Eggsy Pang:

回复 user4985813:

对的,你说的没错,当时我可能只是为了测试,文章写漏了,

所以你还有其他问题吗?

赞(0)
未经允许不得转载:TI中文支持网 » AM335x u-boot中添加LCD驱动,不能操作LCD控制器,怎么解决?
分享到: 更多 (0)