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:
对的,你说的没错,当时我可能只是为了测试,文章写漏了,
所以你还有其他问题吗?
TI中文支持网