diff options
Diffstat (limited to 'drivers/video')
33 files changed, 705 insertions, 393 deletions
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index f8e711147501..fc65c02306dd 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -16,6 +16,7 @@ #include <linux/fb.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/backlight.h> #include <asm/arch/board.h> #include <asm/arch/cpu.h> @@ -69,6 +70,107 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, } #endif +static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 + | ATMEL_LCDC_POL_POSITIVE + | ATMEL_LCDC_ENA_PWMENABLE; + +#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC + +/* some bl->props field just changed */ +static int atmel_bl_update_status(struct backlight_device *bl) +{ + struct atmel_lcdfb_info *sinfo = bl_get_data(bl); + int power = sinfo->bl_power; + int brightness = bl->props.brightness; + + /* REVISIT there may be a meaningful difference between + * fb_blank and power ... there seem to be some cases + * this doesn't handle correctly. + */ + if (bl->props.fb_blank != sinfo->bl_power) + power = bl->props.fb_blank; + else if (bl->props.power != sinfo->bl_power) + power = bl->props.power; + + if (brightness < 0 && power == FB_BLANK_UNBLANK) + brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); + else if (power != FB_BLANK_UNBLANK) + brightness = 0; + + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, + brightness ? contrast_ctr : 0); + + bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; + + return 0; +} + +static int atmel_bl_get_brightness(struct backlight_device *bl) +{ + struct atmel_lcdfb_info *sinfo = bl_get_data(bl); + + return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); +} + +static struct backlight_ops atmel_lcdc_bl_ops = { + .update_status = atmel_bl_update_status, + .get_brightness = atmel_bl_get_brightness, +}; + +static void init_backlight(struct atmel_lcdfb_info *sinfo) +{ + struct backlight_device *bl; + + sinfo->bl_power = FB_BLANK_UNBLANK; + + if (sinfo->backlight) + return; + + bl = backlight_device_register("backlight", &sinfo->pdev->dev, + sinfo, &atmel_lcdc_bl_ops); + if (IS_ERR(sinfo->backlight)) { + dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n", + PTR_ERR(bl)); + return; + } + sinfo->backlight = bl; + + bl->props.power = FB_BLANK_UNBLANK; + bl->props.fb_blank = FB_BLANK_UNBLANK; + bl->props.max_brightness = 0xff; + bl->props.brightness = atmel_bl_get_brightness(bl); +} + +static void exit_backlight(struct atmel_lcdfb_info *sinfo) +{ + if (sinfo->backlight) + backlight_device_unregister(sinfo->backlight); +} + +#else + +static void init_backlight(struct atmel_lcdfb_info *sinfo) +{ + dev_warn(&sinfo->pdev->dev, "backlight control is not available\n"); +} + +static void exit_backlight(struct atmel_lcdfb_info *sinfo) +{ +} + +#endif + +static void init_contrast(struct atmel_lcdfb_info *sinfo) +{ + /* have some default contrast/backlight settings */ + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); + + if (sinfo->lcdcon_is_backlight) + init_backlight(sinfo); +} + static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { .type = FB_TYPE_PACKED_PIXELS, @@ -203,6 +305,26 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, var->transp.offset = var->transp.length = 0; var->xoffset = var->yoffset = 0; + /* Saturate vertical and horizontal timings at maximum values */ + var->vsync_len = min_t(u32, var->vsync_len, + (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); + var->upper_margin = min_t(u32, var->upper_margin, + ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET); + var->lower_margin = min_t(u32, var->lower_margin, + ATMEL_LCDC_VFP); + var->right_margin = min_t(u32, var->right_margin, + (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1); + var->hsync_len = min_t(u32, var->hsync_len, + (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1); + var->left_margin = min_t(u32, var->left_margin, + ATMEL_LCDC_HBP + 1); + + /* Some parameters can't be zero */ + var->vsync_len = max_t(u32, var->vsync_len, 1); + var->right_margin = max_t(u32, var->right_margin, 1); + var->hsync_len = max_t(u32, var->hsync_len, 1); + var->left_margin = max_t(u32, var->left_margin, 1); + switch (var->bits_per_pixel) { case 1: case 2: @@ -370,10 +492,6 @@ static int atmel_lcdfb_set_par(struct fb_info *info) /* Disable all interrupts */ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); - /* Set contrast */ - value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE; - lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value); - lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); /* ...wait for DMA engine to become idle... */ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) msleep(10); @@ -577,6 +695,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) sinfo->default_monspecs = pdata_sinfo->default_monspecs; sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; sinfo->guard_time = pdata_sinfo->guard_time; + sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; } else { dev_err(dev, "cannot get default configuration\n"); goto free_info; @@ -670,6 +789,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) goto release_mem; } + /* Initialize PWM for contrast or backlight ("off") */ + init_contrast(sinfo); + /* interrupt */ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); if (ret) { @@ -721,6 +843,7 @@ free_cmap: unregister_irqs: free_irq(sinfo->irq_base, info); unmap_mmio: + exit_backlight(sinfo); iounmap(sinfo->mmio); release_mem: release_mem_region(info->fix.mmio_start, info->fix.mmio_len); @@ -755,6 +878,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) if (!sinfo) return 0; + exit_backlight(sinfo); if (sinfo->atmel_lcdfb_power_control) sinfo->atmel_lcdfb_power_control(0); unregister_framebuffer(info); @@ -781,6 +905,9 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) static struct platform_driver atmel_lcdfb_driver = { .remove = __exit_p(atmel_lcdfb_remove), + +// FIXME need suspend, resume + .driver = { .name = "atmel_lcdfb", .owner = THIS_MODULE, diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 9609a6c676be..924e2551044a 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -50,6 +50,19 @@ config BACKLIGHT_CLASS_DEVICE To have support for your specific LCD panel you will have to select the proper drivers which depend on this option. +config BACKLIGHT_ATMEL_LCDC + bool "Atmel LCDC Contrast-as-Backlight control" + depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL + default y if MACH_SAM9261EK || MACH_SAM9263EK + help + This provides a backlight control internal to the Atmel LCDC + driver. If the LCD "contrast control" on your board is wired + so it controls the backlight brightness, select this option to + export this as a PWM-based backlight control. + + If in doubt, it's safe to enable this option; it doesn't kick + in unless the board's description says it's wired that way. + config BACKLIGHT_CORGI tristate "Generic (aka Sharp Corgi) Backlight Driver" depends on BACKLIGHT_CLASS_DEVICE diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index c8e7427a0bc8..0ce791e6f79c 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -498,8 +498,7 @@ static struct lcd_device *lcd_dev; static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) { - - /*struct bfin_bf54xfb_info *info = (struct bfin_bf54xfb_info *)dev_id;*/ + /*struct bfin_bf54xfb_info *info = dev_id;*/ u16 status = bfin_read_EPPI0_STATUS(); diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 308850df16fe..69864b1b3f9e 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -63,7 +63,7 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; struct fb_fillrect region; - region.color = attr_bgcol_ec(bgshift, vc); + region.color = attr_bgcol_ec(bgshift, vc, info); region.dx = sx * vc->vc_font.width; region.dy = sy * vc->vc_font.height; region.width = width * vc->vc_font.width; @@ -213,7 +213,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, unsigned int bs = info->var.yres - bh; struct fb_fillrect region; - region.color = attr_bgcol_ec(bgshift, vc); + region.color = attr_bgcol_ec(bgshift, vc, info); region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 0f32f4a00b2d..022282494d3f 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -84,7 +84,7 @@ #ifdef CONFIG_MAC #include <asm/macints.h> #endif -#if defined(__mc68000__) || defined(CONFIG_APUS) +#if defined(__mc68000__) #include <asm/machdep.h> #include <asm/setup.h> #endif @@ -147,7 +147,7 @@ static char fontname[40]; static int info_idx = -1; /* console rotation */ -static int rotate; +static int initial_rotation; static int fbcon_has_sysfs; static const struct consw fb_con; @@ -334,10 +334,7 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info, switch (depth) { case 1: { - int col = ~(0xfff << (max(info->var.green.length, - max(info->var.red.length, - info->var.blue.length)))) & 0xff; - + int col = mono_col(info); /* 0 or 1 */ int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0; int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col; @@ -537,9 +534,9 @@ static int __init fb_console_setup(char *this_opt) if (!strncmp(options, "rotate:", 7)) { options += 7; if (*options) - rotate = simple_strtoul(options, &options, 0); - if (rotate > 3) - rotate = 0; + initial_rotation = simple_strtoul(options, &options, 0); + if (initial_rotation > 3) + initial_rotation = 0; } } return 1; @@ -989,7 +986,7 @@ static const char *fbcon_startup(void) ops->graphics = 1; ops->cur_rotate = -1; info->fbcon_par = ops; - p->con_rotate = rotate; + p->con_rotate = initial_rotation; set_blitting_type(vc, info); if (info->fix.type != FB_TYPE_TEXT) { @@ -1176,7 +1173,7 @@ static void fbcon_init(struct vc_data *vc, int init) con_copy_unimap(vc, svc); ops = info->fbcon_par; - p->con_rotate = rotate; + p->con_rotate = initial_rotation; set_blitting_type(vc, info); cols = vc->vc_cols; @@ -2795,7 +2792,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) { struct fb_info *info = registered_fb[con2fb_map[fg_console]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[fg_console]; + struct display *disp = &fb_display[fg_console]; int offset, limit, scrollback_old; if (softback_top) { @@ -2833,7 +2830,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) logo_shown = FBCON_LOGO_CANSHOW; } fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); - fbcon_redraw_softback(vc, p, lines); + fbcon_redraw_softback(vc, disp, lines); fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); return 0; } @@ -2855,9 +2852,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) fbcon_cursor(vc, CM_ERASE); - offset = p->yscroll - scrollback_current; - limit = p->vrows; - switch (p->scrollmode) { + offset = disp->yscroll - scrollback_current; + limit = disp->vrows; + switch (disp->scrollmode) { case SCROLL_WRAP_MOVE: info->var.vmode |= FB_VMODE_YWRAP; break; diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 8e6ef4bc7a5c..3706307e70ed 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -93,10 +93,6 @@ struct fbcon_ops { (((s) >> (fgshift)) & 0x0f) #define attr_bgcol(bgshift,s) \ (((s) >> (bgshift)) & 0x0f) -#define attr_bgcol_ec(bgshift,vc) \ - ((vc) ? (((vc)->vc_video_erase_char >> (bgshift)) & 0x0f) : 0) -#define attr_fgcol_ec(fgshift,vc) \ - ((vc) ? (((vc)->vc_video_erase_char >> (fgshift)) & 0x0f) : 0) /* Monochrome */ #define attr_bold(s) \ @@ -108,6 +104,49 @@ struct fbcon_ops { #define attr_blink(s) \ ((s) & 0x8000) +#define mono_col(info) \ + (~(0xfff << (max((info)->var.green.length, \ + max((info)->var.red.length, \ + (info)->var.blue.length)))) & 0xff) + +static inline int attr_col_ec(int shift, struct vc_data *vc, + struct fb_info *info, int is_fg) +{ + int is_mono01; + int col; + int fg; + int bg; + + if (!vc) + return 0; + + if (vc->vc_can_do_color) + return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char) + : attr_bgcol(shift,vc->vc_video_erase_char); + + if (!info) + return 0; + + col = mono_col(info); + is_mono01 = info->fix.visual == FB_VISUAL_MONO01; + + if (attr_reverse(vc->vc_video_erase_char)) { + fg = is_mono01 ? col : 0; + bg = is_mono01 ? 0 : col; + } + else { + fg = is_mono01 ? 0 : col; + bg = is_mono01 ? col : 0; + } + + return is_fg ? fg : bg; +} + +#define attr_bgcol_ec(bgshift,vc,info) \ + attr_col_ec(bgshift,vc,info,0); +#define attr_fgcol_ec(fgshift,vc,info) \ + attr_col_ec(fgshift,vc,info,1); + /* Font */ #define REFCOUNT(fd) (((int *)(fd))[-1]) #define FNTSIZE(fd) (((int *)(fd))[-2]) diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c index 825e6d6972a7..bdf913ecf001 100644 --- a/drivers/video/console/fbcon_ccw.c +++ b/drivers/video/console/fbcon_ccw.c @@ -84,7 +84,7 @@ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; u32 vyres = GETVYRES(ops->p->scrollmode, info); - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.dx = sy * vc->vc_font.height; region.dy = vyres - ((sx + width) * vc->vc_font.width); region.height = width * vc->vc_font.width; @@ -198,7 +198,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, struct fb_fillrect region; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c index c637e6318803..a6819b9d1770 100644 --- a/drivers/video/console/fbcon_cw.c +++ b/drivers/video/console/fbcon_cw.c @@ -70,7 +70,7 @@ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; u32 vxres = GETVXRES(ops->p->scrollmode, info); - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.dx = vxres - ((sy + height) * vc->vc_font.height); region.dy = sx * vc->vc_font.width; region.height = width * vc->vc_font.width; @@ -182,7 +182,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, struct fb_fillrect region; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c index 1473506df5d0..d9b5d6eb68a7 100644 --- a/drivers/video/console/fbcon_ud.c +++ b/drivers/video/console/fbcon_ud.c @@ -71,7 +71,7 @@ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, u32 vyres = GETVYRES(ops->p->scrollmode, info); u32 vxres = GETVXRES(ops->p->scrollmode, info); - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.dy = vyres - ((sy + height) * vc->vc_font.height); region.dx = vxres - ((sx + width) * vc->vc_font.width); region.width = width * vc->vc_font.width; @@ -228,7 +228,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, struct fb_fillrect region; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c index 96979c377518..d0c03fd70871 100644 --- a/drivers/video/console/fonts.c +++ b/drivers/video/console/fonts.c @@ -15,7 +15,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> -#if defined(__mc68000__) || defined(CONFIG_APUS) +#if defined(__mc68000__) #include <asm/setup.h> #endif #include <linux/font.h> @@ -120,7 +120,7 @@ const struct font_desc *get_default_font(int xres, int yres, u32 font_w, for(i=0; i<num_fonts; i++) { f = fonts[i]; c = f->pref; -#if defined(__mc68000__) || defined(CONFIG_APUS) +#if defined(__mc68000__) #ifdef CONFIG_FONT_PEARL_8x8 if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX) c = 100; diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c index d981fe4d86c6..0056a41e5c35 100644 --- a/drivers/video/console/tileblit.c +++ b/drivers/video/console/tileblit.c @@ -40,8 +40,8 @@ static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy, rect.index = vc->vc_video_erase_char & ((vc->vc_hi_font_mask) ? 0x1ff : 0xff); - rect.fg = attr_fgcol_ec(fgshift, vc); - rect.bg = attr_bgcol_ec(bgshift, vc); + rect.fg = attr_fgcol_ec(fgshift, vc, info); + rect.bg = attr_bgcol_ec(bgshift, vc, info); rect.sx = sx; rect.sy = sy; rect.width = width; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f65bcd314d54..6df29a62d720 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1153,8 +1153,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) /* if 512 char mode is already enabled don't re-enable it. */ if ((set) && (ch512 != vga_512_chars)) { - int i; - /* attribute controller */ for (i = 0; i < MAX_NR_CONSOLES; i++) { struct vc_data *c = vc_cons[i].d; diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index a0c5d9d90d74..0f8cfb988c90 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -25,8 +25,8 @@ #include <linux/pagemap.h> /* this is to find and return the vmalloc-ed fb pages */ -static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma, - unsigned long vaddr, int *type) +static int fb_deferred_io_fault(struct vm_area_struct *vma, + struct vm_fault *vmf) { unsigned long offset; struct page *page; @@ -34,18 +34,17 @@ static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma, /* info->screen_base is in System RAM */ void *screen_base = (void __force *) info->screen_base; - offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + offset = vmf->pgoff << PAGE_SHIFT; if (offset >= info->fix.smem_len) - return NOPAGE_SIGBUS; + return VM_FAULT_SIGBUS; page = vmalloc_to_page(screen_base + offset); if (!page) - return NOPAGE_OOM; + return VM_FAULT_SIGBUS; get_page(page); - if (type) - *type = VM_FAULT_MINOR; - return page; + vmf->page = page; + return 0; } int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync) @@ -84,7 +83,7 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma, } static struct vm_operations_struct fb_deferred_io_vm_ops = { - .nopage = fb_deferred_io_nopage, + .fault = fb_deferred_io_fault, .page_mkwrite = fb_deferred_io_mkwrite, }; diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index cdafbe14ef1f..a2a0618d86a5 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h @@ -91,6 +91,7 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, val = comp(val >> 2, val << 2, REV_PIXELS_MASK2); if (bswapmask & 3) val = comp(val >> 4, val << 4, REV_PIXELS_MASK4); + return val; } static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 4ba9c0894416..052e18058498 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -4,7 +4,7 @@ * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net> * * Credits: - * + * * The EDID Parser is a conglomeration from the following sources: * * 1. SciTech SNAP Graphics Architecture @@ -12,13 +12,13 @@ * * 2. XFree86 4.3.0, interpret_edid.c * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> - * - * 3. John Fremlin <vii@users.sourceforge.net> and + * + * 3. John Fremlin <vii@users.sourceforge.net> and * Ani Joshi <ajoshi@unixbox.com> - * + * * Generalized Timing Formula is derived from: * - * GTF Spreadsheet by Andy Morrish (1/5/97) + * GTF Spreadsheet by Andy Morrish (1/5/97) * available at http://www.vesa.org * * This file is subject to the terms and conditions of the GNU General Public @@ -36,7 +36,7 @@ #endif #include "edid.h" -/* +/* * EDID parser */ @@ -160,8 +160,8 @@ static int check_edid(unsigned char *edid) for (i = 0; i < ARRAY_SIZE(brokendb); i++) { if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) && brokendb[i].model == model) { - fix = brokendb[i].fix; - break; + fix = brokendb[i].fix; + break; } } @@ -323,7 +323,7 @@ static void get_dpms_capabilities(unsigned char flags, (flags & DPMS_SUSPEND) ? "yes" : "no", (flags & DPMS_STANDBY) ? "yes" : "no"); } - + static void get_chroma(unsigned char *block, struct fb_monspecs *specs) { int tmp; @@ -365,7 +365,7 @@ static void get_chroma(unsigned char *block, struct fb_monspecs *specs) tmp += 512; specs->chroma.bluey = tmp/1024; DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey); - + tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2); tmp *= 1000; tmp += 512; @@ -383,7 +383,7 @@ static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode) { struct fb_var_screeninfo *var; - + var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL); if (var) { @@ -451,11 +451,11 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode) c = block[1]; if (c&0x80) { - mode[num++] = vesa_modes[9]; + mode[num++] = vesa_modes[9]; DPRINTK(" 800x600@72Hz\n"); } if (c&0x40) { - mode[num++] = vesa_modes[10]; + mode[num++] = vesa_modes[10]; DPRINTK(" 800x600@75Hz\n"); } if (c&0x20) { @@ -495,7 +495,7 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode) static int get_std_timing(unsigned char *block, struct fb_videomode *mode) { int xres, yres = 0, refresh, ratio, i; - + xres = (block[0] + 31) * 8; if (xres <= 256) return 0; @@ -519,7 +519,7 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode) DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); for (i = 0; i < VESA_MODEDB_SIZE; i++) { - if (vesa_modes[i].xres == xres && + if (vesa_modes[i].xres == xres && vesa_modes[i].yres == yres && vesa_modes[i].refresh == refresh) { *mode = vesa_modes[i]; @@ -536,13 +536,13 @@ static int get_dst_timing(unsigned char *block, { int j, num = 0; - for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE) + for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE) num += get_std_timing(block, &mode[num]); return num; } -static void get_detailed_timing(unsigned char *block, +static void get_detailed_timing(unsigned char *block, struct fb_videomode *mode) { mode->xres = H_ACTIVE; @@ -553,7 +553,7 @@ static void get_detailed_timing(unsigned char *block, mode->right_margin = H_SYNC_OFFSET; mode->left_margin = (H_ACTIVE + H_BLANKING) - (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); - mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - + mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - V_SYNC_WIDTH; mode->lower_margin = V_SYNC_OFFSET; mode->hsync_len = H_SYNC_WIDTH; @@ -597,7 +597,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) if (mode == NULL) return NULL; - if (edid == NULL || !edid_checksum(edid) || + if (edid == NULL || !edid_checksum(edid) || !edid_check_header(edid)) { kfree(mode); return NULL; @@ -632,7 +632,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) num += get_dst_timing(block + 5, &mode[num]); } - + /* Yikes, EDID data is totally useless */ if (!num) { kfree(mode); @@ -686,7 +686,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) /* estimate monitor limits based on modes supported */ if (retval) { struct fb_videomode *modes, *mode; - int num_modes, i, hz, hscan, pixclock; + int num_modes, hz, hscan, pixclock; int vtotal, htotal; modes = fb_create_modedb(edid, &num_modes); @@ -713,7 +713,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) hscan = (pixclock + htotal / 2) / htotal; hscan = (hscan + 500) / 1000 * 1000; hz = (hscan + vtotal / 2) / vtotal; - + if (specs->dclkmax == 0 || specs->dclkmax < pixclock) specs->dclkmax = pixclock; @@ -966,8 +966,8 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) DPRINTK("========================================\n"); } -/* - * VESA Generalized Timing Formula (GTF) +/* + * VESA Generalized Timing Formula (GTF) */ #define FLYBACK 550 @@ -996,7 +996,7 @@ struct __fb_timings { * @hfreq: horizontal freq * * DESCRIPTION: - * vblank = right_margin + vsync_len + left_margin + * vblank = right_margin + vsync_len + left_margin * * given: right_margin = 1 (V_FRONTPORCH) * vsync_len = 3 @@ -1010,12 +1010,12 @@ static u32 fb_get_vblank(u32 hfreq) { u32 vblank; - vblank = (hfreq * FLYBACK)/1000; + vblank = (hfreq * FLYBACK)/1000; vblank = (vblank + 500)/1000; return (vblank + V_FRONTPORCH); } -/** +/** * fb_get_hblank_by_freq - get horizontal blank time given hfreq * @hfreq: horizontal freq * @xres: horizontal resolution in pixels @@ -1031,7 +1031,7 @@ static u32 fb_get_vblank(u32 hfreq) * * where: C = ((offset - scale factor) * blank_scale) * -------------------------------------- + scale factor - * 256 + * 256 * M = blank_scale * gradient * */ @@ -1039,7 +1039,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) { u32 c_val, m_val, duty_cycle, hblank; - c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + + c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + H_SCALEFACTOR) * 1000; m_val = (H_BLANKSCALE * H_GRADIENT)/256; m_val = (m_val * 1000000)/hfreq; @@ -1048,7 +1048,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) return (hblank); } -/** +/** * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock * @dclk: pixelclock in Hz * @xres: horizontal resolution in pixels @@ -1061,7 +1061,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) * * duty cycle = percent of htotal assigned to inactive display * duty cycle = C - (M * h_period) - * + * * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100 * ----------------------------------------------- * 2 * M @@ -1077,11 +1077,11 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) h_period = 100 - C_VAL; h_period *= h_period; h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk); - h_period *=10000; + h_period *= 10000; h_period = int_sqrt(h_period); h_period -= (100 - C_VAL) * 100; - h_period *= 1000; + h_period *= 1000; h_period /= 2 * M_VAL; duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100; @@ -1089,7 +1089,7 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) hblank &= ~15; return (hblank); } - + /** * fb_get_hfreq - estimate hsync * @vfreq: vertical refresh rate @@ -1100,13 +1100,13 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) * (yres + front_port) * vfreq * 1000000 * hfreq = ------------------------------------- * (1000000 - (vfreq * FLYBACK) - * + * */ static u32 fb_get_hfreq(u32 vfreq, u32 yres) { u32 divisor, hfreq; - + divisor = (1000000 - (vfreq * FLYBACK))/1000; hfreq = (yres + V_FRONTPORCH) * vfreq * 1000; return (hfreq/divisor); @@ -1117,7 +1117,7 @@ static void fb_timings_vfreq(struct __fb_timings *timings) timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive); timings->vblank = fb_get_vblank(timings->hfreq); timings->vtotal = timings->vactive + timings->vblank; - timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, + timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, timings->hactive); timings->htotal = timings->hactive + timings->hblank; timings->dclk = timings->htotal * timings->hfreq; @@ -1128,7 +1128,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings) timings->vblank = fb_get_vblank(timings->hfreq); timings->vtotal = timings->vactive + timings->vblank; timings->vfreq = timings->hfreq/timings->vtotal; - timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, + timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, timings->hactive); timings->htotal = timings->hactive + timings->hblank; timings->dclk = timings->htotal * timings->hfreq; @@ -1136,7 +1136,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings) static void fb_timings_dclk(struct __fb_timings *timings) { - timings->hblank = fb_get_hblank_by_dclk(timings->dclk, + timings->hblank = fb_get_hblank_by_dclk(timings->dclk, timings->hactive); timings->htotal = timings->hactive + timings->hblank; timings->hfreq = timings->dclk/timings->htotal; @@ -1156,29 +1156,29 @@ static void fb_timings_dclk(struct __fb_timings *timings) * @info: pointer to fb_info * * DESCRIPTION: - * Calculates video mode based on monitor specs using VESA GTF. - * The GTF is best for VESA GTF compliant monitors but is + * Calculates video mode based on monitor specs using VESA GTF. + * The GTF is best for VESA GTF compliant monitors but is * specifically formulated to work for older monitors as well. * - * If @flag==0, the function will attempt to maximize the + * If @flag==0, the function will attempt to maximize the * refresh rate. Otherwise, it will calculate timings based on - * the flag and accompanying value. + * the flag and accompanying value. * - * If FB_IGNOREMON bit is set in @flags, monitor specs will be + * If FB_IGNOREMON bit is set in @flags, monitor specs will be * ignored and @var will be filled with the calculated timings. * * All calculations are based on the VESA GTF Spreadsheet * available at VESA's public ftp (http://www.vesa.org). - * + * * NOTES: * The timings generated by the GTF will be different from VESA * DMT. It might be a good idea to keep a table of standard * VESA modes as well. The GTF may also not work for some displays, * such as, and especially, analog TV. - * + * * REQUIRES: * A valid info->monspecs, otherwise 'safe numbers' will be used. - */ + */ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info) { struct __fb_timings *timings; @@ -1191,7 +1191,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf if (!timings) return -ENOMEM; - /* + /* * If monspecs are invalid, use values that are enough * for 640x480@60 */ @@ -1214,7 +1214,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf timings->hactive = var->xres; timings->vactive = var->yres; - if (var->vmode & FB_VMODE_INTERLACED) { + if (var->vmode & FB_VMODE_INTERLACED) { timings->vactive /= 2; interlace = 2; } @@ -1250,9 +1250,9 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf break; default: err = -EINVAL; - - } - + + } + if (err || (!(flags & FB_IGNOREMON) && (timings->vfreq < vfmin || timings->vfreq > vfmax || timings->hfreq < hfmin || timings->hfreq > hfmax || @@ -1269,7 +1269,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf var->upper_margin = (timings->vblank * interlace)/dscan - (var->vsync_len + var->lower_margin); } - + kfree(timings); return err; } @@ -1291,7 +1291,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, return -EINVAL; } #endif /* CONFIG_FB_MODE_HELPERS */ - + /* * fb_validate_mode - validates var against monitor capabilities * @var: pointer to fb_var_screeninfo @@ -1309,7 +1309,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) u32 hfreq, vfreq, htotal, vtotal, pixclock; u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax; - /* + /* * If monspecs are invalid, use values that are enough * for 640x480@60 */ @@ -1333,10 +1333,10 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) if (!var->pixclock) return -EINVAL; pixclock = PICOS2KHZ(var->pixclock) * 1000; - - htotal = var->xres + var->right_margin + var->hsync_len + + + htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin; - vtotal = var->yres + var->lower_margin + var->vsync_len + + vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin; if (var->vmode & FB_VMODE_INTERLACED) @@ -1349,7 +1349,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) vfreq = hfreq/vtotal; - return (vfreq < vfmin || vfreq > vfmax || + return (vfreq < vfmin || vfreq > vfmax || hfreq < hfmin || hfreq > hfmax || pixclock < dclkmin || pixclock > dclkmax) ? -EINVAL : 0; diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index 583185fd7c94..eb6b88171538 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c @@ -34,7 +34,7 @@ static int fbsize; * we try to make it something sane - 640x480-60 is sane */ -const struct fb_videomode geode_modedb[] __initdata = { +static const struct fb_videomode geode_modedb[] __initdata = { /* 640x480-60 */ { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index b18486ad8e17..2eb4fb159084 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -207,7 +207,8 @@ static struct fb_ops hpfb_ops = { #define HPFB_FBOMSB 0x5d /* Frame buffer offset */ #define HPFB_FBOLSB 0x5f -static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base) +static int __devinit hpfb_init_one(unsigned long phys_base, + unsigned long virt_base) { unsigned long fboff, fb_width, fb_height, fb_start; diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 1a7d7789d877..1d13dd099af8 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1476,7 +1476,7 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor) struct i810fb_par *par = info->par; u8 __iomem *mmio = par->mmio_start_virtual; - if (!par->dev_flags & LOCKUP) + if (!(par->dev_flags & LOCKUP)) return -ENXIO; if (cursor->image.width > 64 || cursor->image.height > 64) diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index b87ea21d3d78..3a81060137a2 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -400,6 +400,7 @@ int __init igafb_init(void) info = kzalloc(size, GFP_ATOMIC); if (!info) { printk("igafb_init: can't alloc fb_info\n"); + pci_dev_put(pdev); return -ENOMEM; } @@ -409,12 +410,14 @@ int __init igafb_init(void) if ((addr = pdev->resource[0].start) == 0) { printk("igafb_init: no memory start\n"); kfree(info); + pci_dev_put(pdev); return -ENXIO; } if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) { printk("igafb_init: can't remap %lx[2M]\n", addr); kfree(info); + pci_dev_put(pdev); return -ENXIO; } @@ -449,6 +452,7 @@ int __init igafb_init(void) printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start); iounmap((void *)info->screen_base); kfree(info); + pci_dev_put(pdev); return -ENXIO; } @@ -466,6 +470,7 @@ int __init igafb_init(void) iounmap((void *)par->io_base); iounmap(info->screen_base); kfree(info); + pci_dev_put(pdev); return -ENOMEM; } diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 5f6fb7d2c408..fa1fff553565 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -1971,7 +1971,7 @@ void intelfbhw_cursor_reset(struct intelfb_info *dinfo) static irqreturn_t intelfbhw_irq(int irq, void *dev_id) { u16 tmp; - struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; + struct intelfb_info *dinfo = dev_id; spin_lock(&dinfo->int_lock); diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 4b6a99b5be0d..5246b0402d76 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -2066,40 +2066,49 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2070: - sprintf(info->fix.id, "MagicGraph 128"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128"); break; case FB_ACCEL_NEOMAGIC_NM2090: - sprintf(info->fix.id, "MagicGraph 128V"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128V"); break; case FB_ACCEL_NEOMAGIC_NM2093: - sprintf(info->fix.id, "MagicGraph 128ZV"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128ZV"); break; case FB_ACCEL_NEOMAGIC_NM2097: - sprintf(info->fix.id, "MagicGraph 128ZV+"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128ZV+"); break; case FB_ACCEL_NEOMAGIC_NM2160: - sprintf(info->fix.id, "MagicGraph 128XD"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128XD"); break; case FB_ACCEL_NEOMAGIC_NM2200: - sprintf(info->fix.id, "MagicGraph 256AV"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 256AV"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; case FB_ACCEL_NEOMAGIC_NM2230: - sprintf(info->fix.id, "MagicGraph 256AV+"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 256AV+"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; case FB_ACCEL_NEOMAGIC_NM2360: - sprintf(info->fix.id, "MagicGraph 256ZX"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 256ZX"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; case FB_ACCEL_NEOMAGIC_NM2380: - sprintf(info->fix.id, "MagicGraph 256XL+"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 256XL+"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 30e14eb1f51e..74517b1b26a6 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -849,9 +849,27 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var, if (!mode_valid && info->monspecs.modedb_len) return -EINVAL; + /* + * If we're on a flat panel, check if the mode is outside of the + * panel dimensions. If so, cap it and try for the next best mode + * before bailing out. + */ if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres || - par->fpHeight < var->yres)) - return -EINVAL; + par->fpHeight < var->yres)) { + const struct fb_videomode *mode; + + var->xres = par->fpWidth; + var->yres = par->fpHeight; + + mode = fb_find_best_mode(var, &info->modelist); + if (!mode) { + printk(KERN_ERR PFX "mode out of range of flat " + "panel dimensions\n"); + return -EINVAL; + } + + fb_videomode_to_var(var, mode); + } if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 5591dfb22b18..30181b593829 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -1159,6 +1159,11 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) u32 fgx, bgx; const u32 *src = (const u32 *)image->data; u32 xres = (info->var.xres + 31) & ~31; + int raster_mode = 1; /* invert bits */ + +#ifdef __LITTLE_ENDIAN + raster_mode |= 3 << 7; /* reverse byte order */ +#endif if (info->state != FBINFO_STATE_RUNNING) return; @@ -1208,9 +1213,8 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | PM2F_INCREASE_X | PM2F_INCREASE_Y); - /* BitMapPackEachScanline & invert bits and byte order*/ - /* force background */ - pm2_WR(par, PM2R_RASTERIZER_MODE, (1 << 9) | 1 | (3 << 7)); + /* BitMapPackEachScanline */ + pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9)); pm2_WR(par, PM2R_CONSTANT_COLOR, fgx); pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | @@ -1224,8 +1228,7 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL | PM2F_INCREASE_X | PM2F_INCREASE_Y); - /* invert bits and byte order*/ - pm2_WR(par, PM2R_RASTERIZER_MODE, 1 | (3 << 7)); + pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode); pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx); pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 070659992c18..5dba8cdd0517 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -1227,7 +1227,7 @@ static struct fb_ops pm3fb_ops = { /* mmio register are already mapped when this function is called */ /* the pm3fb_fix.smem_start is also set */ -static unsigned long pm3fb_size_memory(struct pm3_par *par) +static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par) { unsigned long memsize = 0; unsigned long tempBypass, i, temp1, temp2; diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c index a864438b6008..6515ec11c16b 100644 --- a/drivers/video/pmag-aa-fb.c +++ b/drivers/video/pmag-aa-fb.c @@ -150,7 +150,7 @@ static int aafbcon_set_font(struct display *disp, int width, int height) { struct aafb_info *info = (struct aafb_info *)disp->fb_info; struct aafb_cursor *c = &info->cursor; - u8 fgc = ~attr_bgcol_ec(disp, disp->conp); + u8 fgc = ~attr_bgcol_ec(disp, disp->conp, &info->info); if (width > 64 || height > 64 || width < 0 || height < 0) return -EINVAL; diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 044a423a72cb..dc3af1c78c56 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -57,8 +57,6 @@ #define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64) #define GPU_MAX_LINE_LENGTH (65536 - 64) -#define PS3FB_FULL_MODE_BIT 0x80 - #define GPU_INTR_STATUS_VSYNC_0 0 /* vsync on head A */ #define GPU_INTR_STATUS_VSYNC_1 1 /* vsync on head B */ #define GPU_INTR_STATUS_FLIP_0 3 /* flip head A */ @@ -118,8 +116,6 @@ struct ps3fb_priv { unsigned int irq_no; u64 context_handle, memory_handle; - void *xdr_ea; - size_t xdr_size; struct gpu_driver_info *dinfo; u64 vblank_count; /* frame count */ @@ -136,42 +132,19 @@ static struct ps3fb_priv ps3fb; struct ps3fb_par { u32 pseudo_palette[16]; int mode_id, new_mode_id; - int res_index; unsigned int num_frames; /* num of frame buffers */ unsigned int width; unsigned int height; - unsigned long full_offset; /* start of fullscreen DDR fb */ - unsigned long fb_offset; /* start of actual DDR fb */ - unsigned long pan_offset; + unsigned int ddr_line_length; + unsigned int ddr_frame_size; + unsigned int xdr_frame_size; + unsigned int full_offset; /* start of fullscreen DDR fb */ + unsigned int fb_offset; /* start of actual DDR fb */ + unsigned int pan_offset; }; -struct ps3fb_res_table { - u32 xres; - u32 yres; - u32 xoff; - u32 yoff; - u32 type; -}; -#define PS3FB_RES_FULL 1 -static const struct ps3fb_res_table ps3fb_res[] = { - /* res_x,y margin_x,y full */ - { 720, 480, 72, 48 , 0}, - { 720, 576, 72, 58 , 0}, - { 1280, 720, 78, 38 , 0}, - { 1920, 1080, 116, 58 , 0}, - /* full mode */ - { 720, 480, 0, 0 , PS3FB_RES_FULL}, - { 720, 576, 0, 0 , PS3FB_RES_FULL}, - { 1280, 720, 0, 0 , PS3FB_RES_FULL}, - { 1920, 1080, 0, 0 , PS3FB_RES_FULL}, - /* vesa: normally full mode */ - { 1280, 768, 0, 0 , 0}, - { 1280, 1024, 0, 0 , 0}, - { 1920, 1200, 0, 0 , 0}, - { 0, 0, 0, 0 , 0} }; - -/* default resolution */ -#define GPU_RES_INDEX 0 /* 720 x 480 */ + +#define FIRST_NATIVE_MODE_INDEX 10 static const struct fb_videomode ps3fb_modedb[] = { /* 60 Hz broadcast modes (modes "1" to "5") */ @@ -211,7 +184,7 @@ static const struct fb_videomode ps3fb_modedb[] = { "720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { - /* 1080 */ + /* 1080i */ "1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { @@ -220,24 +193,7 @@ static const struct fb_videomode ps3fb_modedb[] = { FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, - /* VESA modes (modes "11" to "13") */ - { - /* WXGA */ - "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6, - 0, FB_VMODE_NONINTERLACED, - FB_MODE_IS_VESA - }, { - /* SXGA */ - "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, - FB_MODE_IS_VESA - }, { - /* WUXGA */ - "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6, - FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, - FB_MODE_IS_VESA - }, - + [FIRST_NATIVE_MODE_INDEX] = /* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */ { /* 480if */ @@ -276,12 +232,30 @@ static const struct fb_videomode ps3fb_modedb[] = { FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 1080if */ - "1080f", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5, + "1080if", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 1080pf */ "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED + }, + + /* VESA modes (modes "11" to "13") */ + { + /* WXGA */ + "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED, + FB_MODE_IS_VESA + }, { + /* SXGA */ + "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, + FB_MODE_IS_VESA + }, { + /* WUXGA */ + "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6, + FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, + FB_MODE_IS_VESA } }; @@ -289,110 +263,188 @@ static const struct fb_videomode ps3fb_modedb[] = { #define HEAD_A #define HEAD_B -#define X_OFF(i) (ps3fb_res[i].xoff) /* left/right margin (pixel) */ -#define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */ -#define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */ -#define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */ #define BPP 4 /* number of bytes per pixel */ -/* Start of the virtual frame buffer (relative to fullscreen ) */ -#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP) - static int ps3fb_mode; module_param(ps3fb_mode, int, 0); static char *mode_option __devinitdata; -static int ps3fb_get_res_table(u32 xres, u32 yres, int mode) +static int ps3fb_cmp_mode(const struct fb_videomode *vmode, + const struct fb_var_screeninfo *var) { - int full_mode; - unsigned int i; - u32 x, y, f; - - full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0; - for (i = 0;; i++) { - x = ps3fb_res[i].xres; - y = ps3fb_res[i].yres; - f = ps3fb_res[i].type; - - if (!x) { - pr_debug("ERROR: ps3fb_get_res_table()\n"); - return -1; - } + long xres, yres, left_margin, right_margin, upper_margin, lower_margin; + long dx, dy; + + /* maximum values */ + if (var->xres > vmode->xres || var->yres > vmode->yres || + var->pixclock > vmode->pixclock || + var->hsync_len > vmode->hsync_len || + var->vsync_len > vmode->vsync_len) + return -1; - if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL) - continue; + /* progressive/interlaced must match */ + if ((var->vmode & FB_VMODE_MASK) != vmode->vmode) + return -1; - if (x == xres && (yres == 0 || y == yres)) - break; + /* minimum resolution */ + xres = max(var->xres, 1U); + yres = max(var->yres, 1U); + + /* minimum margins */ + left_margin = max(var->left_margin, vmode->left_margin); + right_margin = max(var->right_margin, vmode->right_margin); + upper_margin = max(var->upper_margin, vmode->upper_margin); + lower_margin = max(var->lower_margin, vmode->lower_margin); + + /* resolution + margins may not exceed native parameters */ + dx = ((long)vmode->left_margin + (long)vmode->xres + + (long)vmode->right_margin) - + (left_margin + xres + right_margin); + if (dx < 0) + return -1; - x = x - 2 * ps3fb_res[i].xoff; - y = y - 2 * ps3fb_res[i].yoff; - if (x == xres && (yres == 0 || y == yres)) - break; + dy = ((long)vmode->upper_margin + (long)vmode->yres + + (long)vmode->lower_margin) - + (upper_margin + yres + lower_margin); + if (dy < 0) + return -1; + + /* exact match */ + if (!dx && !dy) + return 0; + + /* resolution difference */ + return (vmode->xres - xres) * (vmode->yres - yres); +} + +static const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id) +{ + return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1]; +} + +static const struct fb_videomode *ps3fb_vmode(int id) +{ + u32 mode = id & PS3AV_MODE_MASK; + + if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA) + return NULL; + + if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) { + /* Non-fullscreen broadcast mode */ + return &ps3fb_modedb[mode - 1]; } - return i; + + return ps3fb_native_vmode(mode); } -static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, +static unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var, u32 *ddr_line_length, u32 *xdr_line_length) { - unsigned int i, mode; - - for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++) - if (var->xres == ps3fb_modedb[i].xres && - var->yres == ps3fb_modedb[i].yres && - var->pixclock == ps3fb_modedb[i].pixclock && - var->hsync_len == ps3fb_modedb[i].hsync_len && - var->vsync_len == ps3fb_modedb[i].vsync_len && - var->left_margin == ps3fb_modedb[i].left_margin && - var->right_margin == ps3fb_modedb[i].right_margin && - var->upper_margin == ps3fb_modedb[i].upper_margin && - var->lower_margin == ps3fb_modedb[i].lower_margin && - var->sync == ps3fb_modedb[i].sync && - (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode) - goto found; - - pr_debug("ps3fb_find_mode: mode not found\n"); - return 0; + unsigned int id, best_id; + int diff, best_diff; + const struct fb_videomode *vmode; + long gap; + + best_id = 0; + best_diff = INT_MAX; + pr_debug("%s: wanted %u [%u] %u x %u [%u] %u\n", __func__, + var->left_margin, var->xres, var->right_margin, + var->upper_margin, var->yres, var->lower_margin); + for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) { + vmode = ps3fb_native_vmode(id); + diff = ps3fb_cmp_mode(vmode, var); + pr_debug("%s: mode %u: %u [%u] %u x %u [%u] %u: diff = %d\n", + __func__, id, vmode->left_margin, vmode->xres, + vmode->right_margin, vmode->upper_margin, + vmode->yres, vmode->lower_margin, diff); + if (diff < 0) + continue; + if (diff < best_diff) { + best_id = id; + if (!diff) + break; + best_diff = diff; + } + } -found: - /* Cropped broadcast modes use the full line length */ - *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP; + if (!best_id) { + pr_debug("%s: no suitable mode found\n", __func__); + return 0; + } - if (ps3_compare_firmware_version(1, 9, 0) >= 0) { - *xdr_line_length = GPU_ALIGN_UP(max(var->xres, - var->xres_virtual) * BPP); - if (*xdr_line_length > GPU_MAX_LINE_LENGTH) - *xdr_line_length = GPU_MAX_LINE_LENGTH; - } else - *xdr_line_length = *ddr_line_length; + id = best_id; + vmode = ps3fb_native_vmode(id); - /* Full broadcast modes have the full mode bit set */ - mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1; + *ddr_line_length = vmode->xres * BPP; - pr_debug("ps3fb_find_mode: mode %u\n", mode); + /* minimum resolution */ + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; - return mode; -} + /* minimum virtual resolution */ + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; -static const struct fb_videomode *ps3fb_default_mode(int id) -{ - u32 mode = id & PS3AV_MODE_MASK; - u32 flags; + /* minimum margins */ + if (var->left_margin < vmode->left_margin) + var->left_margin = vmode->left_margin; + if (var->right_margin < vmode->right_margin) + var->right_margin = vmode->right_margin; + if (var->upper_margin < vmode->upper_margin) + var->upper_margin = vmode->upper_margin; + if (var->lower_margin < vmode->lower_margin) + var->lower_margin = vmode->lower_margin; + + /* extra margins */ + gap = ((long)vmode->left_margin + (long)vmode->xres + + (long)vmode->right_margin) - + ((long)var->left_margin + (long)var->xres + + (long)var->right_margin); + if (gap > 0) { + var->left_margin += gap/2; + var->right_margin += (gap+1)/2; + pr_debug("%s: rounded up H to %u [%u] %u\n", __func__, + var->left_margin, var->xres, var->right_margin); + } - if (mode < 1 || mode > 13) - return NULL; + gap = ((long)vmode->upper_margin + (long)vmode->yres + + (long)vmode->lower_margin) - + ((long)var->upper_margin + (long)var->yres + + (long)var->lower_margin); + if (gap > 0) { + var->upper_margin += gap/2; + var->lower_margin += (gap+1)/2; + pr_debug("%s: rounded up V to %u [%u] %u\n", __func__, + var->upper_margin, var->yres, var->lower_margin); + } + + /* fixed fields */ + var->pixclock = vmode->pixclock; + var->hsync_len = vmode->hsync_len; + var->vsync_len = vmode->vsync_len; + var->sync = vmode->sync; - flags = id & ~PS3AV_MODE_MASK; + if (ps3_compare_firmware_version(1, 9, 0) >= 0) { + *xdr_line_length = GPU_ALIGN_UP(var->xres_virtual * BPP); + if (*xdr_line_length > GPU_MAX_LINE_LENGTH) + *xdr_line_length = GPU_MAX_LINE_LENGTH; + } else + *xdr_line_length = *ddr_line_length; - if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) { - /* Full broadcast mode */ - return &ps3fb_modedb[mode + 12]; + if (vmode->sync & FB_SYNC_BROADCAST) { + /* Full broadcast modes have the full mode bit set */ + if (vmode->xres == var->xres && vmode->yres == var->yres) + id |= PS3AV_MODE_FULL; } - return &ps3fb_modedb[mode - 1]; + pr_debug("%s: mode %u\n", __func__, id); + return id; } static void ps3fb_sync_image(struct device *dev, u64 frame_offset, @@ -439,8 +491,7 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset, static int ps3fb_sync(struct fb_info *info, u32 frame) { struct ps3fb_par *par = info->par; - int i, error = 0; - u32 ddr_line_length, xdr_line_length; + int error = 0; u64 ddr_base, xdr_base; if (frame > par->num_frames - 1) { @@ -450,16 +501,13 @@ static int ps3fb_sync(struct fb_info *info, u32 frame) goto out; } - i = par->res_index; - xdr_line_length = info->fix.line_length; - ddr_line_length = ps3fb_res[i].xres * BPP; - xdr_base = frame * info->var.yres_virtual * xdr_line_length; - ddr_base = frame * ps3fb_res[i].yres * ddr_line_length; + xdr_base = frame * par->xdr_frame_size; + ddr_base = frame * par->ddr_frame_size; ps3fb_sync_image(info->device, ddr_base + par->full_offset, ddr_base + par->fb_offset, xdr_base + par->pan_offset, - par->width, par->height, ddr_line_length, - xdr_line_length); + par->width, par->height, par->ddr_line_length, + info->fix.line_length); out: return error; @@ -498,22 +546,11 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) u32 xdr_line_length, ddr_line_length; int mode; - dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres, - info->var.xres); - dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres, - info->var.yres); - - /* FIXME For now we do exact matches only */ mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length); if (!mode) return -EINVAL; /* Virtual screen */ - if (var->xres_virtual < var->xres) - var->xres_virtual = var->xres; - if (var->yres_virtual < var->yres) - var->yres_virtual = var->yres; - if (var->xres_virtual > xdr_line_length / BPP) { dev_dbg(info->device, "Horizontal virtual screen size too large\n"); @@ -559,7 +596,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } /* Memory limit */ - if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) { + if (var->yres_virtual * xdr_line_length > info->fix.smem_len) { dev_dbg(info->device, "Not enough memory\n"); return -ENOMEM; } @@ -578,39 +615,38 @@ static int ps3fb_set_par(struct fb_info *info) { struct ps3fb_par *par = info->par; unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines; - int i; - unsigned long offset; + unsigned int ddr_xoff, ddr_yoff, offset; + const struct fb_videomode *vmode; u64 dst; - dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n", - info->var.xres, info->var.xres_virtual, - info->var.yres, info->var.yres_virtual, info->var.pixclock); - mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length); if (!mode) return -EINVAL; - i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode); - par->res_index = i; + vmode = ps3fb_native_vmode(mode & PS3AV_MODE_MASK); - info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); - info->fix.smem_len = ps3fb.xdr_size; info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; info->fix.line_length = xdr_line_length; - info->screen_base = (char __iomem *)ps3fb.xdr_ea; + par->ddr_line_length = ddr_line_length; + par->ddr_frame_size = vmode->yres * ddr_line_length; + par->xdr_frame_size = info->var.yres_virtual * xdr_line_length; - par->num_frames = ps3fb.xdr_size / - max(ps3fb_res[i].yres * ddr_line_length, - info->var.yres_virtual * xdr_line_length); + par->num_frames = info->fix.smem_len / + max(par->ddr_frame_size, par->xdr_frame_size); /* Keep the special bits we cannot set using fb_var_screeninfo */ par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode; par->width = info->var.xres; par->height = info->var.yres; - offset = VP_OFF(i); + + /* Start of the virtual frame buffer (relative to fullscreen) */ + ddr_xoff = info->var.left_margin - vmode->left_margin; + ddr_yoff = info->var.upper_margin - vmode->upper_margin; + offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP; + par->fb_offset = GPU_ALIGN_UP(offset); par->full_offset = par->fb_offset - offset; par->pan_offset = info->var.yoffset * xdr_line_length + @@ -625,16 +661,16 @@ static int ps3fb_set_par(struct fb_info *info) } /* Clear XDR frame buffer memory */ - memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size); + memset((void __force *)info->screen_base, 0, info->fix.smem_len); /* Clear DDR frame buffer memory */ - lines = ps3fb_res[i].yres * par->num_frames; + lines = vmode->yres * par->num_frames; if (par->full_offset) lines++; - maxlines = ps3fb.xdr_size / ddr_line_length; + maxlines = info->fix.smem_len / ddr_line_length; for (dst = 0; lines; dst += maxlines * ddr_line_length) { unsigned int l = min(lines, maxlines); - ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l, + ps3fb_sync_image(info->device, 0, dst, 0, vmode->xres, l, ddr_line_length, ddr_line_length); lines -= l; } @@ -797,7 +833,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, case PS3FB_IOCTL_SETMODE: { struct ps3fb_par *par = info->par; - const struct fb_videomode *mode; + const struct fb_videomode *vmode; struct fb_var_screeninfo var; if (copy_from_user(&val, argp, sizeof(val))) @@ -810,10 +846,10 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, } dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val); retval = -EINVAL; - mode = ps3fb_default_mode(val); - if (mode) { + vmode = ps3fb_vmode(val); + if (vmode) { var = info->var; - fb_videomode_to_var(&var, mode); + fb_videomode_to_var(&var, vmode); acquire_console_sem(); info->flags |= FBINFO_MISC_USEREVENT; /* Force, in case only special bits changed */ @@ -975,10 +1011,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev) __func__, status); return -ENXIO; } - dev_dbg(dev, - "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", - ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar, - virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size); + dev_dbg(dev, "video:%p ioif:%lx lpar:%lx size:%lx\n", + ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size); status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, @@ -1055,14 +1090,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) struct fb_info *info; struct ps3fb_par *par; int retval = -ENOMEM; - u32 xres, yres; u64 ddr_lpar = 0; u64 lpar_dma_control = 0; u64 lpar_driver_info = 0; u64 lpar_reports = 0; u64 lpar_reports_size = 0; u64 xdr_lpar; - int status, res_index; + void *fb_start; + int status; struct task_struct *task; unsigned long max_ps3fb_size; @@ -1080,14 +1115,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (!ps3fb_mode) ps3fb_mode = ps3av_get_mode(); - dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode); - - if (ps3fb_mode > 0 && - !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { - res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode); - dev_dbg(&dev->core, "res_index:%d\n", res_index); - } else - res_index = GPU_RES_INDEX; + dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode); atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ @@ -1124,7 +1152,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) } /* vsync interrupt */ - ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024); + ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); if (!ps3fb.dinfo) { dev_err(&dev->core, "%s: ioremap failed\n", __func__); goto err_gpu_context_free; @@ -1134,22 +1162,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (retval) goto err_iounmap_dinfo; - /* XDR frame buffer */ - ps3fb.xdr_ea = ps3fb_videomemory.address; - xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea)); - /* Clear memory to prevent kernel info leakage into userspace */ - memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); - - /* - * The GPU command buffer is at the start of video memory - * As we don't use the full command buffer, we can put the actual - * frame buffer at offset GPU_FB_START and save some precious XDR - * memory - */ - ps3fb.xdr_ea += GPU_FB_START; - ps3fb.xdr_size = ps3fb_videomemory.size - GPU_FB_START; + memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size); + xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); if (retval) goto err_free_irq; @@ -1161,15 +1177,22 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ par->new_mode_id = ps3fb_mode; - par->res_index = res_index; par->num_frames = 1; - info->screen_base = (char __iomem *)ps3fb.xdr_ea; info->fbops = &ps3fb_ops; - info->fix = ps3fb_fix; - info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); - info->fix.smem_len = ps3fb.xdr_size; + + /* + * The GPU command buffer is at the start of video memory + * As we don't use the full command buffer, we can put the actual + * frame buffer at offset GPU_FB_START and save some precious XDR + * memory + */ + fb_start = ps3fb_videomemory.address + GPU_FB_START; + info->screen_base = (char __force __iomem *)fb_start; + info->fix.smem_start = virt_to_abs(fb_start); + info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START; + info->pseudo_palette = par->pseudo_palette; info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; @@ -1180,7 +1203,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb, ARRAY_SIZE(ps3fb_modedb), - ps3fb_default_mode(par->new_mode_id), 32)) { + ps3fb_vmode(par->new_mode_id), 32)) { retval = -EINVAL; goto err_fb_dealloc; } @@ -1194,9 +1217,9 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) dev->core.driver_data = info; - dev_info(info->device, "%s %s, using %lu KiB of video memory\n", + dev_info(info->device, "%s %s, using %u KiB of video memory\n", dev_driver_string(info->dev), info->dev->bus_id, - ps3fb.xdr_size >> 10); + info->fix.smem_len >> 10); task = kthread_run(ps3fbd, info, DEVICE_NAME); if (IS_ERR(task)) { @@ -1219,7 +1242,7 @@ err_free_irq: free_irq(ps3fb.irq_no, &dev->core); ps3_irq_plug_destroy(ps3fb.irq_no); err_iounmap_dinfo: - iounmap((u8 __iomem *)ps3fb.dinfo); + iounmap((u8 __force __iomem *)ps3fb.dinfo); err_gpu_context_free: lv1_gpu_context_free(ps3fb.context_handle); err_gpu_memory_free: @@ -1254,7 +1277,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) framebuffer_release(info); info = dev->core.driver_data = NULL; } - iounmap((u8 __iomem *)ps3fb.dinfo); + iounmap((u8 __force __iomem *)ps3fb.dinfo); status = lv1_gpu_context_free(ps3fb.context_handle); if (status) diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index b3c31d9dc591..71fa6edb5c47 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -110,6 +110,11 @@ static int debug = 0; /* useful functions */ +static int is_s3c2412(struct s3c2410fb_info *fbi) +{ + return (fbi->drv_type == DRV_S3C2412); +} + /* s3c2410fb_set_lcdaddr * * initialise lcd controller address pointers @@ -501,7 +506,7 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi, { unsigned long flags; unsigned long irqen; - void __iomem *regs = fbi->io; + void __iomem *irq_base = fbi->irq_base; local_irq_save(flags); @@ -511,9 +516,9 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi, fbi->palette_ready = 1; /* enable IRQ */ - irqen = readl(regs + S3C2410_LCDINTMSK); + irqen = readl(irq_base + S3C24XX_LCDINTMSK); irqen &= ~S3C2410_LCDINT_FRSYNC; - writel(irqen, regs + S3C2410_LCDINTMSK); + writel(irqen, irq_base + S3C24XX_LCDINTMSK); } local_irq_restore(flags); @@ -594,15 +599,17 @@ static int s3c2410fb_setcolreg(unsigned regno, static int s3c2410fb_blank(int blank_mode, struct fb_info *info) { struct s3c2410fb_info *fbi = info->par; - void __iomem *regs = fbi->io; + void __iomem *tpal_reg = fbi->io; dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); + tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL; + if (blank_mode == FB_BLANK_UNBLANK) - writel(0x0, regs + S3C2410_TPAL); + writel(0x0, tpal_reg); else { dprintk("setting TPAL to output 0x000000\n"); - writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL); + writel(S3C2410_TPAL_EN, tpal_reg); } return 0; @@ -663,7 +670,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info) dma_addr_t map_dma; unsigned map_size = PAGE_ALIGN(info->fix.smem_len); - dprintk("map_video_memory(fbi=%p)\n", fbi); + dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size); info->screen_base = dma_alloc_writecombine(fbi->dev, map_size, &map_dma, GFP_KERNEL); @@ -672,7 +679,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info) /* prevent initial garbage on screen */ dprintk("map_video_memory: clear %p:%08x\n", info->screen_base, map_size); - memset(info->screen_base, 0xf0, map_size); + memset(info->screen_base, 0x00, map_size); info->fix.smem_start = map_dma; @@ -709,6 +716,16 @@ static int s3c2410fb_init_registers(struct fb_info *info) struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data; unsigned long flags; void __iomem *regs = fbi->io; + void __iomem *tpal; + void __iomem *lpcsel; + + if (is_s3c2412(fbi)) { + tpal = regs + S3C2412_TPAL; + lpcsel = regs + S3C2412_TCONSEL; + } else { + tpal = regs + S3C2410_TPAL; + lpcsel = regs + S3C2410_LPCSEL; + } /* Initialise LCD with values from haret */ @@ -724,12 +741,12 @@ static int s3c2410fb_init_registers(struct fb_info *info) local_irq_restore(flags); dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel); - writel(mach_info->lpcsel, regs + S3C2410_LPCSEL); + writel(mach_info->lpcsel, lpcsel); - dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL)); + dprintk("replacing TPAL %08x\n", readl(tpal)); /* ensure temporary palette disabled */ - writel(0x00, regs + S3C2410_TPAL); + writel(0x00, tpal); return 0; } @@ -763,15 +780,15 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi) static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) { struct s3c2410fb_info *fbi = dev_id; - void __iomem *regs = fbi->io; - unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND); + void __iomem *irq_base = fbi->irq_base; + unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND); if (lcdirq & S3C2410_LCDINT_FRSYNC) { if (fbi->palette_ready) s3c2410fb_write_palette(fbi); - writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND); - writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND); + writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND); + writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND); } return IRQ_HANDLED; @@ -779,7 +796,8 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) static char driver_name[] = "s3c2410fb"; -static int __init s3c2410fb_probe(struct platform_device *pdev) +static int __init s3c24xxfb_probe(struct platform_device *pdev, + enum s3c_drv_type drv_type) { struct s3c2410fb_info *info; struct s3c2410fb_display *display; @@ -799,6 +817,12 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) return -EINVAL; } + if (mach_info->default_display >= mach_info->num_displays) { + dev_err(&pdev->dev, "default is %d but only %d displays\n", + mach_info->default_display, mach_info->num_displays); + return -EINVAL; + } + display = mach_info->displays + mach_info->default_display; irq = platform_get_irq(pdev, 0); @@ -815,6 +839,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) info = fbinfo->par; info->dev = &pdev->dev; + info->drv_type = drv_type; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { @@ -838,6 +863,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) goto release_mem; } + info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE); + dprintk("devinit\n"); strcpy(fbinfo->fix.id, driver_name); @@ -946,6 +973,16 @@ dealloc_fb: return ret; } +static int __init s3c2410fb_probe(struct platform_device *pdev) +{ + return s3c24xxfb_probe(pdev, DRV_S3C2410); +} + +static int __init s3c2412fb_probe(struct platform_device *pdev) +{ + return s3c24xxfb_probe(pdev, DRV_S3C2412); +} + /* s3c2410fb_stop_lcd * * shutdown the lcd controller @@ -1047,14 +1084,31 @@ static struct platform_driver s3c2410fb_driver = { }, }; +static struct platform_driver s3c2412fb_driver = { + .probe = s3c2412fb_probe, + .remove = s3c2410fb_remove, + .suspend = s3c2410fb_suspend, + .resume = s3c2410fb_resume, + .driver = { + .name = "s3c2412-lcd", + .owner = THIS_MODULE, + }, +}; + int __init s3c2410fb_init(void) { - return platform_driver_register(&s3c2410fb_driver); + int ret = platform_driver_register(&s3c2410fb_driver); + + if (ret == 0) + ret = platform_driver_register(&s3c2412fb_driver);; + + return ret; } static void __exit s3c2410fb_cleanup(void) { platform_driver_unregister(&s3c2410fb_driver); + platform_driver_unregister(&s3c2412fb_driver); } module_init(s3c2410fb_init); diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h index 6ce5dc26c5f7..dbb73b95e2ef 100644 --- a/drivers/video/s3c2410fb.h +++ b/drivers/video/s3c2410fb.h @@ -25,13 +25,20 @@ #ifndef __S3C2410FB_H #define __S3C2410FB_H +enum s3c_drv_type { + DRV_S3C2410, + DRV_S3C2412, +}; + struct s3c2410fb_info { struct device *dev; struct clk *clk; struct resource *mem; void __iomem *io; + void __iomem *irq_base; + enum s3c_drv_type drv_type; struct s3c2410fb_hw regs; unsigned int palette_ready; diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 93ae747440cb..73803624c131 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -427,7 +427,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) monitor->feature = buffer[0x18]; - if(!buffer[0x14] & 0x80) { + if(!(buffer[0x14] & 0x80)) { if(!(buffer[0x14] & 0x08)) { printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n"); @@ -4621,9 +4621,9 @@ sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev, while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) { temp = pdev->vendor; - pci_dev_put(pdev); if(temp == pcivendor) { ret = 1; + pci_dev_put(pdev); break; } } diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 58f200c69be3..e83dfba7e636 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -641,6 +641,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) { unsigned long control; void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL; + struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl; control = readl(ctrl_reg); @@ -657,26 +658,34 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) sm501fb_sync_regs(fbi); mdelay(10); - control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */ - writel(control, ctrl_reg); - sm501fb_sync_regs(fbi); - mdelay(10); - - control |= SM501_DC_PANEL_CONTROL_FPEN; - writel(control, ctrl_reg); + if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) { + control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */ + writel(control, ctrl_reg); + sm501fb_sync_regs(fbi); + mdelay(10); + } + if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) { + control |= SM501_DC_PANEL_CONTROL_FPEN; + writel(control, ctrl_reg); + sm501fb_sync_regs(fbi); + mdelay(10); + } } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) { /* disable panel power */ + if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) { + control &= ~SM501_DC_PANEL_CONTROL_FPEN; + writel(control, ctrl_reg); + sm501fb_sync_regs(fbi); + mdelay(10); + } - control &= ~SM501_DC_PANEL_CONTROL_FPEN; - writel(control, ctrl_reg); - sm501fb_sync_regs(fbi); - mdelay(10); - - control &= ~SM501_DC_PANEL_CONTROL_BIAS; - writel(control, ctrl_reg); - sm501fb_sync_regs(fbi); - mdelay(10); + if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) { + control &= ~SM501_DC_PANEL_CONTROL_BIAS; + writel(control, ctrl_reg); + sm501fb_sync_regs(fbi); + mdelay(10); + } control &= ~SM501_DC_PANEL_CONTROL_DATA; writel(control, ctrl_reg); @@ -1267,6 +1276,7 @@ static int sm501fb_start(struct sm501fb_info *info, { struct resource *res; struct device *dev; + int k; int ret; info->dev = dev = &pdev->dev; @@ -1328,6 +1338,13 @@ static int sm501fb_start(struct sm501fb_info *info, info->fbmem_len = (res->end - res->start)+1; + /* clear framebuffer memory - avoids garbage data on unused fb */ + memset(info->fbmem, 0, info->fbmem_len); + + /* clear palette ram - undefined at power on */ + for (k = 0; k < (256 * 3); k++) + writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4)); + /* enable display controller */ sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); @@ -1681,6 +1698,15 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info, if (par->screen.size == 0) return 0; + /* blank the relevant interface to ensure unit power minimised */ + (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi); + + /* tell console/fb driver we are suspending */ + + acquire_console_sem(); + fb_set_suspend(fbi, 1); + release_console_sem(); + /* backup copies in case chip is powered down over suspend */ par->store_fb = vmalloc(par->screen.size); @@ -1700,12 +1726,6 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info, memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size); memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size); - /* blank the relevant interface to ensure unit power minimised */ - (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi); - - acquire_console_sem(); - fb_set_suspend(fbi, 1); - release_console_sem(); return 0; diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 057bdd593800..71e179ea5f95 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1342,7 +1342,7 @@ out_err: } #ifndef MODULE -static void tdfxfb_setup(char *options) +static void __init tdfxfb_setup(char *options) { char *this_opt; diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index a14ef894d571..be27b9c1ed72 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -2003,12 +2003,12 @@ static void __devexit uvesafb_exit(void) module_exit(uvesafb_exit); -static inline int param_get_scroll(char *buffer, struct kernel_param *kp) +static int param_get_scroll(char *buffer, struct kernel_param *kp) { return 0; } -static inline int param_set_scroll(const char *val, struct kernel_param *kp) +static int param_set_scroll(const char *val, struct kernel_param *kp) { ypan = 0; @@ -2022,11 +2022,11 @@ static inline int param_set_scroll(const char *val, struct kernel_param *kp) return 0; } -#define param_check_scroll(name, p) __param_check(name, p, void); +#define param_check_scroll(name, p) __param_check(name, p, void) module_param_named(scroll, ypan, scroll, 0); MODULE_PARM_DESC(scroll, - "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'"); + "Scrolling mode, set to 'redraw', 'ypan', or 'ywrap'"); module_param_named(vgapal, pmi_setpal, invbool, 0); MODULE_PARM_DESC(vgapal, "Set palette using VGA registers"); module_param_named(pmipal, pmi_setpal, bool, 0); diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 1c656667b937..2aa71eb67c2b 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -651,7 +651,7 @@ static int vmlfb_check_var_locked(struct fb_var_screeninfo *var, return -EINVAL; } - pitch = __ALIGN_MASK((var->xres * var->bits_per_pixel) >> 3, 0x3F); + pitch = ALIGN((var->xres * var->bits_per_pixel) >> 3, 0x40); mem = pitch * var->yres_virtual; if (mem > vinfo->vram_contig_size) { return -ENOMEM; @@ -785,8 +785,7 @@ static int vmlfb_set_par_locked(struct vml_info *vinfo) int clock; vinfo->bytes_per_pixel = var->bits_per_pixel >> 3; - vinfo->stride = - __ALIGN_MASK(var->xres_virtual * vinfo->bytes_per_pixel, 0x3F); + vinfo->stride = ALIGN(var->xres_virtual * vinfo->bytes_per_pixel, 0x40); info->fix.line_length = vinfo->stride; if (!subsys) |