/* drivers/video/s1d13xxxfb.c * * (c) 2004 Simtec Electronics * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org> * (c) 2009 Kristoffer Ericson <kristoffer.ericson@gmail.com> * * Driver for Epson S1D13xxx series framebuffer chips * * Adapted from * linux/drivers/video/skeletonfb.c * linux/drivers/video/epson1355fb.c * linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson) * * TODO: - handle dual screen display (CRT and LCD at the same time). * - check_var(), mode change, etc. * - probably not SMP safe :) * - support all bitblt operations on all cards * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details.
*/
/* * set this to enable debugging on general functions
*/ #if 0 #define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0) #else #define dbg(fmt, args...) do { no_printk(KERN_INFO fmt, ## args); } while (0) #endif
/* * set this to enable debugging on 2D acceleration
*/ #if 0 #define dbg_blit(fmt, args...) do { printk(KERN_INFO BLIT fmt, ## args); } while (0) #else #define dbg_blit(fmt, args...) do { } while (0) #endif
/* * we make sure only one bitblt operation is running
*/ static DEFINE_SPINLOCK(s1d13xxxfb_bitblt_lock);
/* * list of card production ids
*/ staticconstint s1d13xxxfb_prod_ids[] = {
S1D13505_PROD_ID,
S1D13506_PROD_ID,
S1D13806_PROD_ID,
};
/* * List of card strings
*/ staticconstchar *s1d13xxxfb_prod_names[] = { "S1D13505", "S1D13506", "S1D13806",
};
/** * s1d13xxxfb_set_par - Alters the hardware state. * @info: frame buffer structure * * Using the fb_var_screeninfo in fb_info we set the depth of the * framebuffer. This function alters the par AND the * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in * fb_info since we are using that data. This means we depend on the * data in var inside fb_info to be supported by the hardware. * xxxfb_check_var is always called before xxxfb_set_par to ensure this. * * XXX TODO: write proper s1d13xxxfb_check_var(), without which that * function is quite useless.
*/ staticint
s1d13xxxfb_set_par(struct fb_info *info)
{ struct s1d13xxxfb_par *s1dfb = info->par; unsignedint val;
dbg("setting line_length to %d\n", info->fix.line_length);
dbg("done setup\n");
return 0;
}
/** * s1d13xxxfb_setcolreg - sets a color register. * @regno: Which register in the CLUT we are programming * @red: The red value which can be up to 16 bits wide * @green: The green value which can be up to 16 bits wide * @blue: The blue value which can be up to 16 bits wide. * @transp: If supported the alpha value which can be up to 16 bits wide. * @info: frame buffer info structure * * Returns negative errno on error, or zero on success.
*/ staticint
s1d13xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{ struct s1d13xxxfb_par *s1dfb = info->par; unsignedint pseudo_val;
/** * s1d13xxxfb_blank - blanks the display. * @blank_mode: the blank mode we want. * @info: frame buffer structure that represents a single frame buffer * * Blank the screen if blank_mode != 0, else unblank. Return 0 if * blanking succeeded, != 0 if un-/blanking failed due to e.g. a * video mode which doesn't support it. Implements VESA suspend * and powerdown modes on hardware that supports disabling hsync/vsync: * blank_mode == 2: suspend vsync * blank_mode == 3: suspend hsync * blank_mode == 4: powerdown * * Returns negative errno on error, or zero on success.
*/ staticint
s1d13xxxfb_blank(int blank_mode, struct fb_info *info)
{ struct s1d13xxxfb_par *par = info->par;
switch (blank_mode) { case FB_BLANK_UNBLANK: case FB_BLANK_NORMAL: if ((par->display & 0x01) != 0)
lcd_enable(par, 1); if ((par->display & 0x02) != 0)
crt_enable(par, 1); break; case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: break; case FB_BLANK_POWERDOWN:
lcd_enable(par, 0);
crt_enable(par, 0); break; default: return -EINVAL;
}
/* let fbcon do a soft blank for us */ return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
}
/** * s1d13xxxfb_pan_display - Pans the display. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer * * Pan (or wrap, depending on the `vmode' field) the display using the * `yoffset' field of the `var' structure (`xoffset' not yet supported). * If the values don't fit, return -EINVAL. * * Returns negative errno on error, or zero on success.
*/ staticint
s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{ struct s1d13xxxfb_par *par = info->par;
u32 start;
if (var->xoffset != 0) /* not yet ... */ return -EINVAL;
if (var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL;
/************************************************************ functions to handle bitblt acceleration
************************************************************/
/** * bltbit_wait_bitclear - waits for change in register value * @info : frambuffer structure * @bit : value currently in register * @timeout : ... * * waits until value changes FROM bit *
*/ static u8
bltbit_wait_bitclear(struct fb_info *info, u8 bit, int timeout)
{ while (s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit) {
udelay(10); if (!--timeout) {
dbg_blit("wait_bitclear timeout\n"); break;
}
}
/* set foreground color */
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC0, (fg & 0xff));
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC1, (fg >> 8) & 0xff);
/* set rectangual region of memory (rectangle and not linear) */
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0);
/* set operation mode SOLID_FILL */
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, BBLT_SOLID_FILL);
/* set bits per pixel (1 = 16bpp, 0 = 8bpp) */
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (info->var.bits_per_pixel >> 4));
/* set the memory offset for the bblt in word sizes */
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (screen_stride >> 1) & 0x00ff);
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (screen_stride >> 9));
/* and away we go.... */
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80);
/* wait until its done */
bltbit_wait_bitclear(info, 0x80, 8000);
/* let others play */
spin_unlock(&s1d13xxxfb_bitblt_lock);
}
/** * s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to * hardware setup. * @info: frame buffer structure * * We setup the framebuffer structures according to the current * hardware setup. On some machines, the BIOS will have filled * the chip registers with such info, on others, these values will * have been written in some init procedure. In any case, the * software values needs to match the hardware ones. This is what * this function ensures. * * Note: some of the hardcoded values here might need some love to * work on various chips, and might need to no longer be hardcoded.
*/ staticvoid s1d13xxxfb_fetch_hw_state(struct fb_info *info)
{ struct fb_var_screeninfo *var = &info->var; struct fb_fix_screeninfo *fix = &info->fix; struct s1d13xxxfb_par *par = info->par;
u8 panel, display;
u16 offset;
u32 xres, yres;
u32 xres_virtual, yres_virtual; int bpp, lcd_bpp; int is_color, is_dual, is_tft; int lcd_enabled, crt_enabled;
if (!info->screen_base) {
printk(KERN_ERR PFX "unable to map framebuffer\n");
ret = -ENOMEM; goto bail;
}
/* production id is top 6 bits */
prod_id = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2; /* revision id is lower 2 bits */
revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) & 0x3;
ret = -ENODEV;
for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_prod_ids); i++) { if (prod_id == s1d13xxxfb_prod_ids[i]) { /* looks like we got it in our list */
default_par->prod_id = prod_id;
default_par->revision = revision;
ret = 0; break;
}
}
if (!ret) {
printk(KERN_INFO PFX "chip production id %i = %s\n",
prod_id, s1d13xxxfb_prod_names[i]);
printk(KERN_INFO PFX "chip revision %i\n", revision);
} else {
printk(KERN_INFO PFX "unknown chip production id %i, revision %i\n",
prod_id, revision);
printk(KERN_INFO PFX "please contact maintainer\n"); goto bail;
}
/* awaken the chip */
s1d13xxxfb_writereg(s1dfb, S1DREG_PS_CNF, 0x10);
/* do not let go until SDRAM "wakes up" */ while ((s1d13xxxfb_readreg(s1dfb, S1DREG_PS_STATUS) & 0x01))
udelay(10);
if (dev_get_platdata(&dev->dev))
pdata = dev_get_platdata(&dev->dev);
if (s1dfb->regs_save) { /* will write RO regs, *should* get away with it :) */
memcpy_toio(s1dfb->regs, s1dfb->regs_save, info->fix.mmio_len);
kfree(s1dfb->regs_save);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.