概述
static struct fb_ops my2440fb_ops =
{
.owner = THIS_MODULE,
.fb_check_var = my2440fb_check_var,
.fb_set_par = my2440fb_set_par,
.fb_blank = my2440fb_blank,
.fb_setcolreg = my2440fb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static int my2440fb_set_par(struct fb_info *fbinfo)
{
struct fb_var_screeninfo *var = &fbinfo->var;
switch (var->bits_per_pixel)
{
case 32:
case 16:
case 12:
fbinfo->fix.visual = FB_VISUAL_TRUECOLOR;
break;
case 1:
fbinfo->fix.visual = FB_VISUAL_MONO01;
break;
default:
fbinfo->fix.visual = FB_VISUAL_PSEUDOCOLOR;
break;
}
fbinfo->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
my2440fb_activate_var(fbinfo);
return 0;
}
static void my2440fb_activate_var(struct fb_info *fbinfo)
{
struct my2440fb_var *fbvar = fbinfo->par;
void __iomem *regs = fbvar->lcd_base;
struct fb_var_screeninfo *var = &fbinfo->var;
int clkdiv = my2440fb_calc_pixclk(fbvar, var->pixclock) / 2;
int type = fbvar->regs.lcdcon1 & S3C2410_LCDCON1_TFT;
if (type == S3C2410_LCDCON1_TFT)
{
my2440fb_config_tft_lcd_regs(fbinfo, &fbvar->regs);
--clkdiv;
if (clkdiv < 0)
{
clkdiv = 0;
}
}
else
{
my2440fb_config_stn_lcd_regs(fbinfo, &fbvar->regs);
if (clkdiv < 2)
{
clkdiv = 2;
}
}
fbvar->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);
writel(fbvar->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, regs + S3C2410_LCDCON1);
writel(fbvar->regs.lcdcon2, regs + S3C2410_LCDCON2);
writel(fbvar->regs.lcdcon3, regs + S3C2410_LCDCON3);
writel(fbvar->regs.lcdcon4, regs + S3C2410_LCDCON4);
writel(fbvar->regs.lcdcon5, regs + S3C2410_LCDCON5);
my2440fb_set_lcdaddr(fbinfo);
fbvar->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID,
writel(fbvar->regs.lcdcon1, regs + S3C2410_LCDCON1);
}
static unsigned int my2440fb_calc_pixclk(struct my2440fb_var *fbvar, unsigned longpixclk)
{
unsigned long clk = clk_get_rate(fbvar->lcd_clock);
unsigned long long div = (unsigned long long)clk * pixclk;
div >>= 12;
do_div(div, 625 * 625UL * 625);
return div;
}
static void my2440fb_config_tft_lcd_regs(const struct fb_info *fbinfo, structs3c2410fb_hw *regs)
{
const struct my2440fb_var *fbvar = fbinfo->par;
const struct fb_var_screeninfo *var = &fbinfo->var;
switch (var->bits_per_pixel)
{
case 1:
regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
break;
case 2:
regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
break;
case 4:
regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
break;
case 8:
regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
regs->lcdcon5 |= S3C2410_LCDCON5_BSWP | S3C2410_LCDCON5_FRM565;
regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP;
break;
case 16:
regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP;
regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP;
break;
case 32:
regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP;
regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP | S3C2410_LCDCON5_HWSWP |S3C2410_LCDCON5_BPP24BL);
break;
default:
dev_err(fbvar->dev, "invalid bpp %dn", var->bits_per_pixel);
}
regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) |
S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |
S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |
S3C2410_LCDCON2_VSPW(var->vsync_len - 1);
regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) |
S3C2410_LCDCON3_HFPD(var->left_margin - 1) |
S3C2410_LCDCON3_HOZVAL(var->xres - 1);
regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1);
}
static void my2440fb_config_stn_lcd_regs(const struct fb_info *fbinfo, structs3c2410fb_hw *regs)
{
const struct my2440fb_var *fbvar = fbinfo->par;
const struct fb_var_screeninfo *var = &fbinfo->var;
int type = regs->lcdcon1 & ~S3C2410_LCDCON1_TFT;
int hs = var->xres >> 2;
unsigned wdly = (var->left_margin >> 4) - 1;
unsigned wlh = (var->hsync_len >> 4) - 1;
if (type != S3C2410_LCDCON1_STN4)
{
hs >>= 1;
}
switch (var->bits_per_pixel)
{
case 1:
regs->lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
break;
case 2:
regs->lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
break;
case 4:
regs->lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
break;
case 8:
regs->lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
hs *= 3;
break;
case 12:
regs->lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
hs *= 3;
break;
default:
dev_err(fbvar->dev, "invalid bpp %dn", var->bits_per_pixel);
}
if (wdly > 3) wdly = 3;
if (wlh > 3) wlh = 3;
regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1);
regs->lcdcon3 = S3C2410_LCDCON3_WDLY(wdly) |
S3C2410_LCDCON3_LINEBLANK(var->right_margin / 8) |
S3C2410_LCDCON3_HOZVAL(hs - 1);
regs->lcdcon4 = S3C2410_LCDCON4_WLH(wlh);
}
static void my2440fb_set_lcdaddr(struct fb_info *fbinfo)
{
unsigned long saddr1, saddr2, saddr3;
struct my2440fb_var *fbvar = fbinfo->par;
void __iomem *regs = fbvar->lcd_base;
saddr1 = fbinfo->fix.smem_start >> 1;
saddr2 = fbinfo->fix.smem_start;
saddr2 += fbinfo->fix.line_length * fbinfo->var.yres;
saddr2 >>= 1;
saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((fbinfo->fix.line_length / 2) &0x3ff);
writel(saddr1, regs + S3C2410_LCDSADDR1);
writel(saddr2, regs + S3C2410_LCDSADDR2);
writel(saddr3, regs + S3C2410_LCDSADDR3);
}
static int my2440fb_blank(int blank_mode, struct fb_info *fbinfo)
{
struct my2440fb_var *fbvar = fbinfo->par;
void __iomem *regs = fbvar->lcd_base;
if (blank_mode == FB_BLANK_POWERDOWN)
{
my2440fb_lcd_enable(fbvar, 0);
}
else
{
my2440fb_lcd_enable(fbvar, 1);
}
if (blank_mode == FB_BLANK_UNBLANK)
{
writel(0x0, regs + S3C2410_TPAL);
}
else
{
writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL);
}
return 0;
}
static int my2440fb_setcolreg(unsigned regno,unsigned red,unsigned green,unsignedblue,unsigned transp,struct fb_info *fbinfo)
{
unsigned int val;
struct my2440fb_var *fbvar = fbinfo->par;
void __iomem *regs = fbvar->lcd_base;
switch (fbinfo->fix.visual)
{
case FB_VISUAL_TRUECOLOR:
if (regno < 16)
{
u32 *pal = fbinfo->pseudo_palette;
val = chan_to_field(red, &fbinfo->var.red);
val |= chan_to_field(green, &fbinfo->var.green);
val |= chan_to_field(blue, &fbinfo->var.blue);
pal[regno] = val;
}
break;
case FB_VISUAL_PSEUDOCOLOR:
if (regno < 256)
{
val = (red >> 0) & 0xf800;
val |= (green >> 5) & 0x07e0;
val |= (blue >> 11) & 0x001f;
writel(val, regs + S3C2410_TFTPAL(regno));
schedule_palette_update(fbvar, regno, val);
}
break;
default:
return 1;
}
return 0;
}
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 schedule_palette_update(struct my2440fb_var *fbvar, unsigned int regno,unsigned int val)
{
unsigned long flags;
unsigned long irqen;
void __iomem *lcd_irq_base = fbvar->lcd_base + S3C2410_LCDINTBASE;
local_irq_save(flags);
fbvar->palette_buffer[regno] = val;
if (!fbvar->palette_ready)
{
fbvar->palette_ready = 1;
irqen = readl(lcd_irq_base + S3C24XX_LCDINTMSK);
irqen &= ~S3C2410_LCDINT_FRSYNC;
writel(irqen, lcd_irq_base + S3C24XX_LCDINTMSK);
}
local_irq_restore(flags);
}
最后
以上就是怕孤单冬天为你收集整理的嵌入式linux mono,嵌入式Linux之我行——S3C2440上LCD驱动(FrameBuffer)实例开发讲解的全部内容,希望文章能够帮你解决嵌入式linux mono,嵌入式Linux之我行——S3C2440上LCD驱动(FrameBuffer)实例开发讲解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复