把代码粘上来,肯定能用,照着裸机改的,我刚刚试过的
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
#include <asm/mach/map.h>
#include <plat/fb.h>
static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *info);
static struct fb_ops s3c_lcdfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = s3c_lcdfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static struct fb_info *s3c_lcd;
struct clk *lcd_clk;
static u32 pseudo_palette[16];
/*mini210 lcd regs*/
static volatile unsigned long *gPF0CON;
static volatile unsigned long *gPF1CON;
static volatile unsigned long *gPF2CON;
static volatile unsigned long *gPF3CON;
static volatile unsigned long *gPD0CON;
static volatile unsigned long *gPD0DAT;
static volatile unsigned long *cLK_SRC1;
static volatile unsigned long *cLK_DIV1;
static volatile unsigned long *dISPLAY_CONTROL;
static volatile unsigned long *vIDCON0;
static volatile unsigned long *vIDCON1;
static volatile unsigned long *vIDTCON2;
static volatile unsigned long *wINCON0;
static volatile unsigned long *wINCON2;
static volatile unsigned long *sHADOWCON;
static volatile unsigned long *vIDOSD0A;
static volatile unsigned long *vIDOSD0B;
static volatile unsigned long *vIDOSD0C;
static volatile unsigned long *vIDW00ADD0B0;
static volatile unsigned long *vIDW00ADD1B0;
static volatile unsigned long *vIDTCON0;
static volatile unsigned long *vIDTCON1;
static volatile unsigned long *clk_gate_block;
#define HSPW (0)
#define HBPD (40 - 1)
#define HFPD (5 - 1)
#define VSPW (0)
#define VBPD (8 - 1)
#define VFPD (8 - 1)
// FB地址
//#define FB_ADDR (0x23000000)
#define ROW (272)
#define COL (480)
#define HOZVAL (COL-1)
#define LINEVAL (ROW-1)
#define LeftTopX 0
#define LeftTopY 0
#define RightBotX 479
#define RightBotY 271
/* from pxafb.c */
static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
chan &= 0xffff;
chan >>= 16 - bf->length;
return chan << bf->offset;
}
static void regs_remap(void)
{
gPF0CON= ioremap(0xE0200120, 4);
gPF1CON= ioremap(0xE0200140, 4);
gPF2CON= ioremap(0xE0200160, 4);
gPF3CON= ioremap(0xE0200180, 4);
gPD0CON= ioremap(0xE02000A0, 4);
gPD0DAT= ioremap(0xE02000A4, 4);
cLK_SRC1= ioremap(0xe0100204, 4);
cLK_DIV1= ioremap(0xe0100304, 4);
dISPLAY_CONTROL= ioremap(0xe0107008, 4);
vIDCON0= ioremap(0xF8000000, 4);
vIDCON1= ioremap(0xF8000004, 4);
vIDTCON2= ioremap(0xF8000018, 4);
wINCON0= ioremap(0xF8000020, 4);
wINCON2= ioremap(0xF8000028, 4);
sHADOWCON= ioremap(0xF8000034, 4);
vIDOSD0A= ioremap(0xF8000040, 4);
vIDOSD0B= ioremap(0xF8000044, 4);
vIDOSD0C= ioremap(0xF8000048, 4);
vIDW00ADD0B0= ioremap(0xF80000A0, 4);
vIDW00ADD1B0= ioremap(0xF80000D0, 4);
vIDTCON0= ioremap(0xF8000010, 4);
vIDTCON1= ioremap(0xF8000014, 4);
//clk_gate_block= ioremap(0xE0100480, 4);
}
static void regs_unremap(void)
{
//iounmap(clk_gate_block);
iounmap(gPF0CON);
iounmap(gPF1CON);
iounmap(gPF2CON);
iounmap(gPF3CON);
iounmap(gPD0CON);
iounmap(gPD0DAT);
iounmap(cLK_SRC1);
iounmap(cLK_DIV1);
iounmap(dISPLAY_CONTROL);
iounmap(vIDCON0);
iounmap(vIDCON1);
iounmap(vIDTCON2);
iounmap(wINCON0);
iounmap(wINCON2);
iounmap(sHADOWCON);
iounmap(vIDOSD0A);
iounmap(vIDOSD0B);
iounmap(vIDOSD0C);
iounmap(vIDW00ADD0B0 );
iounmap(vIDW00ADD1B0);
iounmap(vIDTCON0);
iounmap(vIDTCON1);
}
static void lcd_hadinit(void)
{
// 配置引脚用于LCD功能
*gPF0CON = 0x22222222;
*gPF1CON = 0x22222222;
*gPF2CON = 0x22222222;
*gPF3CON = 0x22222222;
// 打开背光
*gPD0CON &= ~(0xf<<4);
*gPD0CON |= (1<<4);
printk("close backlight\n");
*gPD0DAT |= (1<<1);
// 10: RGB=FIMD I80=FIMD ITU=FIMD
*dISPLAY_CONTROL = 2<<0;
// bit[26~28]:使用RGB接口
// bit[18]:RGB 并行
// bit[2]:选择时钟源为HCLK_DSYS=166MHz
*vIDCON0 &= ~( (3<<26)|(1<<18)|(1<<2) );
// bit[1]:使能lcd控制器
// bit[0]:当前帧结束后使能lcd控制器
*vIDCON0 |= ( (1<<0)|(1<<1) );
// bit[6]:选择需要分频
// bit[6~13]:分频系数为15,即VCLK = 166M/(14+1) = 11M
*vIDCON0 |= 14<<6 | 1<<4;
// H43-HSD043I9W1.pdf(p13) 时序图:VSYNC和HSYNC都是低脉冲
// s5pv210芯片手册(p1207) 时序图:VSYNC和HSYNC都是高脉冲有效,所以需要反转
*vIDCON1 |= 1<<5 | 1<<6;
// 设置时序
*vIDTCON0 = VBPD<<16 | VFPD<<8 | VSPW<<0;
*vIDTCON1 = HBPD<<16 | HFPD<<8 | HSPW<<0;
// 设置长宽
*vIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);
// 设置windows1 // bit[0]:使能
// bit[2~5]:24bpp
// 设置windows1的上下左右
*vIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);
*vIDOSD0B = (RightBotX<<11) | (RightBotY << 0);
*vIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);
}
static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red,
unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *info)
{
unsigned int val;
if (regno > 16)
return 1;
/* 用red,green,blue三原色构造出val */
val = chan_to_field(red, &info->var.red);
val |= chan_to_field(green, &info->var.green);
val |= chan_to_field(blue, &info->var.blue);
//((u32 *)(info->pseudo_palette))[regno] = val;
pseudo_palette[regno] = val;
return 0;
}
static int lcd_init(void)
{
printk("mini210000000 lcd init \n");
/* 1. 分配一个fb_info */
s3c_lcd = framebuffer_alloc(0, NULL);
/* 2. 设置 */
/* 2.1 设置固定的参数 */
strcpy(s3c_lcd->fix.id, "mylcd");
s3c_lcd->fix.smem_len = 480*272*32/8; /* TQ2440的LCD位宽是24,但是2440里会分配4字节即32位(浪费1字节) */
s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS;
s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR; /* TFT */
s3c_lcd->fix.line_length = 480*4;
/* 2.2 设置可变的参数 */
s3c_lcd->var.xres = 480;
s3c_lcd->var.yres = 272;
s3c_lcd->var.xres_virtual = 480;
s3c_lcd->var.yres_virtual = 272;
s3c_lcd->var.bits_per_pixel = 32;
/* RGB:565 */
s3c_lcd->var.red.offset = 16;
s3c_lcd->var.red.length = 8;
s3c_lcd->var.green.offset = 8;
s3c_lcd->var.green.length = 8;
s3c_lcd->var.blue.offset = 0;
s3c_lcd->var.blue.length = 8;
s3c_lcd->var.activate = FB_ACTIVATE_NOW;
/* 2.3 设置操作函数 */
s3c_lcd->fbops = &s3c_lcdfb_ops;
/* 2.4 其他的设置 */
s3c_lcd->pseudo_palette = pseudo_palette;
//s3c_lcd->screen_base = ; /* 显存的虚拟地址 */
s3c_lcd->screen_size = 480*272*32/8;
/* 3. 硬件相关的操作 */
/* 3.1 配置GPIO用于LCD */
regs_remap();
// 配置引脚用于LCD功能
*gPF0CON = 0x22222222;
*gPF1CON = 0x22222222;
*gPF2CON = 0x22222222;
*gPF3CON = 0x22222222;
// 打开背光
*gPD0CON &= ~(0xf<<4);
*gPD0CON |= (1<<4);
printk("close backlight\n");
*gPD0DAT |= (1<<1);
// 10: RGB=FIMD I80=FIMD ITU=FIMD
*dISPLAY_CONTROL = 2<<0;
// *clk_gate_block&=~((1<<3)|(1<<2));
lcd_clk = clk_get(NULL,"lcd");
if(!lcd_clk||IS_ERR(lcd_clk)){
printk(KERN_INFO"FAILED to get lcd clock source\n");
}
clk_enable(lcd_clk);
// bit[26~28]:使用RGB接口
// bit[18]:RGB 并行
// bit[2]:选择时钟源为HCLK_DSYS=166MHz
*vIDCON0 &= ~( (3<<26)|(1<<18)|(1<<2) );
// bit[1]:使能lcd控制器
// bit[0]:当前帧结束后使能lcd控制器
*vIDCON0 |= ( (1<<0)|(1<<1) );
// bit[6]:选择需要分频
// bit[6~13]:分频系数为15,即VCLK = 166M/(14+1) = 11M
*vIDCON0 |= 14<<6 | 1<<4;
// H43-HSD043I9W1.pdf(p13) 时序图:VSYNC和HSYNC都是低脉冲
// s5pv210芯片手册(p1207) 时序图:VSYNC和HSYNC都是高脉冲有效,所以需要反转
*vIDCON1 |= 1<<5 | 1<<6;
// 设置时序
*vIDTCON0 = VBPD<<16 | VFPD<<8 | VSPW<<0;
*vIDTCON1 = HBPD<<16 | HFPD<<8 | HSPW<<0;
// 设置长宽
*vIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);
*wINCON0 |= 1<<0;
*wINCON0 &= ~(0xf << 2);
*wINCON0 |= (0xB<<2) | (1<<15);
// 设置windows1的上下左右
*vIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);
*vIDOSD0B = (RightBotX<<11) | (RightBotY << 0);
*vIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);
/* 3.3 分配显存(framebuffer), 并把地址告诉LCD控制器 */
s3c_lcd->screen_base = dma_alloc_writecombine(NULL, s3c_lcd->fix.smem_len, (dma_addr_t *)&(s3c_lcd->fix.smem_start), GFP_KERNEL);
// 设置fb的地址
*vIDW00ADD0B0 = s3c_lcd->fix.smem_start;
*vIDW00ADD1B0 = s3c_lcd->fix.smem_start+s3c_lcd->fix.smem_len;
// 使能channel 0传输数据
*sHADOWCON = 0x1;
//s3c_lcd->fix.smem_start = xxx; /* 显存的物理地址 */
/* 启动LCD */
/* 4. 注册 */
register_framebuffer(s3c_lcd);
return 0;
}
static void lcd_exit(void)
{
unregister_framebuffer(s3c_lcd);
*vIDCON0&=~(1<<1);
*wINCON0 &= ~(1<<0);
// lcd_regs->lcdcon1 &= ~(1<<0); /* 关闭LCD控制器 */
// lcd_regs->lcdcon1 &= ~(1<<3); /* 关闭LCD本身 */
// *gpbdat &= ~1; /* 关闭背光 */
printk("lcd exit");
dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start);
regs_unremap();
framebuffer_release(s3c_lcd);
}
module_init(lcd_init);
module_exit(lcd_exit);
MODULE_LICENSE("GPL");