diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 09:35:27 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 09:35:27 -0700 |
commit | 8127b39e700f965a60fca443d23f3e171bf7c3a9 (patch) | |
tree | 435e3e4b640cb6e0c2428d2d84bfde39304be5ed /drivers/video | |
parent | 96a3e8af5a54c324535472ca946215d5bafe6539 (diff) | |
parent | 9bf9d47a29afbf7a43eae74a988a4aefe88ccbfd (diff) |
Merge tag 'fbdev-for-3.10' of git://gitorious.org/linux-omap-dss2/linux
Pull fbdev updates from Tomi Valkeinen:
- use vm_iomap_memory() in various fb drivers to map the fb memory to
userspace
- Cleanups for the videomode and display_timing features
- Updates to vt8500, wm8505 and auo-k190x fb drivers
* tag 'fbdev-for-3.10' of git://gitorious.org/linux-omap-dss2/linux: (36 commits)
fbdev: fix check for fb_mmap's mmio availability
fbdev: improve fb_mmap bounds checks
fbdev/ps3fb: use vm_iomap_memory()
fbdev/sgivwfb: use vm_iomap_memory()
fbdev/vermillion: use vm_iomap_memory()
fbdev/sa1100fb: use vm_iomap_memory()
fbdev/fb-puv3: use vm_iomap_memory()
fbdev/controlfb: use vm_iomap_memory()
fbdev/omapfb: use vm_iomap_memory()
video: vt8500: fix Kconfig for videomode
video/s3c: move platform_data out of arch/arm
video/exynos: remove unnecessary header inclusions
drivers/video: fsl-diu-fb: add hardware cursor support
drivers: video: use module_platform_driver_probe()
ARM: OMAP: remove "config FB_OMAP_CONSISTENT_DMA_SIZE"
video: wm8505fb: Convert to devm_ioremap_resource()
AUO-K190x: Add resolutions for portrait displays
AUO-K190x: add framebuffer rotation support
AUO-K190x: add a 16bit truecolor mode
AUO-K190x: make color handling more flexible
...
Diffstat (limited to 'drivers/video')
35 files changed, 598 insertions, 451 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 09394657926e..981c1c08c727 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -31,26 +31,8 @@ config VIDEO_OUTPUT_CONTROL This framework adds support for low-level control of the video output switch. -config DISPLAY_TIMING - bool - -config VIDEOMODE - bool - -config OF_DISPLAY_TIMING - bool "Enable device tree display timing support" - depends on OF - select DISPLAY_TIMING - help - helper to parse display timings from the devicetree - -config OF_VIDEOMODE - bool "Enable device tree videomode support" - depends on OF - select VIDEOMODE - select OF_DISPLAY_TIMING - help - helper to get videomodes from the devicetree +config VIDEOMODE_HELPERS + bool config HDMI bool @@ -212,14 +194,6 @@ config FB_SYS_FOPS depends on FB default n -config FB_WMT_GE_ROPS - tristate - depends on FB - default n - ---help--- - Include functions for accelerated rectangle filling and area - copying using WonderMedia Graphics Engine operations. - config FB_DEFERRED_IO bool depends on FB @@ -1797,22 +1771,37 @@ config FB_AU1200 option au1200fb:panel=<name>. config FB_VT8500 - bool "VT8500 LCD Driver" + bool "VIA VT8500 framebuffer support" depends on (FB = y) && ARM && ARCH_VT8500 - select FB_WMT_GE_ROPS + select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) + select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) select FB_SYS_IMAGEBLIT + select FB_MODE_HELPERS + select VIDEOMODE_HELPERS help This is the framebuffer driver for VIA VT8500 integrated LCD controller. config FB_WM8505 - bool "WM8505 frame buffer support" + bool "Wondermedia WM8xxx-series frame buffer support" depends on (FB = y) && ARM && ARCH_VT8500 - select FB_WMT_GE_ROPS + select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) + select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) select FB_SYS_IMAGEBLIT + select FB_MODE_HELPERS + select VIDEOMODE_HELPERS + help + This is the framebuffer driver for WonderMedia WM8xxx-series + integrated LCD controller. This driver covers the WM8505, WM8650 + and WM8850 SoCs. + +config FB_WMT_GE_ROPS + bool "VT8500/WM8xxx accelerated raster ops support" + depends on (FB = y) && (FB_VT8500 || FB_WM8505) + default n help - This is the framebuffer driver for WonderMedia WM8505/WM8650 - integrated LCD controller. + This adds support for accelerated raster operations on the + VIA VT8500 and Wondermedia 85xx series SoCs. source "drivers/video/geode/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 9df387334cb7..e414378d6a51 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -171,7 +171,7 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o #video output switch sysfs driver obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o -obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o -obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o -obj-$(CONFIG_VIDEOMODE) += videomode.o -obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o +obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o +ifeq ($(CONFIG_OF),y) +obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o +endif diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 7fa1bf823729..77cb4ffa1fe4 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -3788,19 +3788,7 @@ static struct platform_driver amifb_driver = { }, }; -static int __init amifb_init(void) -{ - return platform_driver_probe(&amifb_driver, amifb_probe); -} - -module_init(amifb_init); - -static void __exit amifb_exit(void) -{ - platform_driver_unregister(&amifb_driver); -} - -module_exit(amifb_exit); +module_platform_driver_probe(amifb_driver, amifb_probe); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:amiga-video"); diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 025428e04c33..98348ec0b3ce 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -1158,18 +1158,7 @@ static struct platform_driver atmel_lcdfb_driver = { }, }; -static int __init atmel_lcdfb_init(void) -{ - return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe); -} - -static void __exit atmel_lcdfb_exit(void) -{ - platform_driver_unregister(&atmel_lcdfb_driver); -} - -module_init(atmel_lcdfb_init); -module_exit(atmel_lcdfb_exit); +module_platform_driver_probe(atmel_lcdfb_driver, atmel_lcdfb_probe); MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver"); MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>"); diff --git a/drivers/video/auo_k1900fb.c b/drivers/video/auo_k1900fb.c index 1a9ac6e1f4b3..f5b668e77af3 100644 --- a/drivers/video/auo_k1900fb.c +++ b/drivers/video/auo_k1900fb.c @@ -60,9 +60,12 @@ static void auok1900_init(struct auok190xfb_par *par) { + struct device *dev = par->info->device; struct auok190x_board *board = par->board; u16 init_param = 0; + pm_runtime_get_sync(dev); + init_param |= AUOK1900_INIT_TEMP_AVERAGE; init_param |= AUOK1900_INIT_ROTATE(par->rotation); init_param |= AUOK190X_INIT_INVERSE_WHITE; @@ -74,6 +77,9 @@ static void auok1900_init(struct auok190xfb_par *par) /* let the controller finish */ board->wait_for_rdy(par); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); } static void auok1900_update_region(struct auok190xfb_par *par, int mode, @@ -82,6 +88,7 @@ static void auok1900_update_region(struct auok190xfb_par *par, int mode, struct device *dev = par->info->device; unsigned char *buf = (unsigned char *)par->info->screen_base; int xres = par->info->var.xres; + int line_length = par->info->fix.line_length; u16 args[4]; pm_runtime_get_sync(dev); @@ -100,9 +107,9 @@ static void auok1900_update_region(struct auok190xfb_par *par, int mode, args[1] = y1 + 1; args[2] = xres; args[3] = y2 - y1; - buf += y1 * xres; + buf += y1 * line_length; auok190x_send_cmdargs_pixels(par, AUOK1900_CMD_PARTIALDISP, 4, args, - ((y2 - y1) * xres)/2, (u16 *) buf); + ((y2 - y1) * line_length)/2, (u16 *) buf); auok190x_send_command(par, AUOK190X_CMD_DATA_STOP); par->update_cnt++; diff --git a/drivers/video/auo_k1901fb.c b/drivers/video/auo_k1901fb.c index d1db1653cd88..12b9adcb75c5 100644 --- a/drivers/video/auo_k1901fb.c +++ b/drivers/video/auo_k1901fb.c @@ -101,9 +101,12 @@ static void auok1901_init(struct auok190xfb_par *par) { + struct device *dev = par->info->device; struct auok190x_board *board = par->board; u16 init_param = 0; + pm_runtime_get_sync(dev); + init_param |= AUOK190X_INIT_INVERSE_WHITE; init_param |= AUOK190X_INIT_FORMAT0; init_param |= AUOK1901_INIT_RESOLUTION(par->resolution); @@ -113,6 +116,9 @@ static void auok1901_init(struct auok190xfb_par *par) /* let the controller finish */ board->wait_for_rdy(par); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); } static void auok1901_update_region(struct auok190xfb_par *par, int mode, @@ -121,6 +127,7 @@ static void auok1901_update_region(struct auok190xfb_par *par, int mode, struct device *dev = par->info->device; unsigned char *buf = (unsigned char *)par->info->screen_base; int xres = par->info->var.xres; + int line_length = par->info->fix.line_length; u16 args[5]; pm_runtime_get_sync(dev); @@ -139,9 +146,9 @@ static void auok1901_update_region(struct auok190xfb_par *par, int mode, args[1] = y1 + 1; args[2] = xres; args[3] = y2 - y1; - buf += y1 * xres; + buf += y1 * line_length; auok190x_send_cmdargs_pixels_nowait(par, AUOK1901_CMD_DMA_START, 4, - args, ((y2 - y1) * xres)/2, + args, ((y2 - y1) * line_length)/2, (u16 *) buf); auok190x_send_command_nowait(par, AUOK190X_CMD_DATA_STOP); diff --git a/drivers/video/auo_k190x.c b/drivers/video/auo_k190x.c index 53846cb534d4..b1f19b266da7 100644 --- a/drivers/video/auo_k190x.c +++ b/drivers/video/auo_k190x.c @@ -40,6 +40,14 @@ static struct panel_info panel_table[] = { .w = 1024, .h = 768, }, + [AUOK190X_RESOLUTION_600_800] = { + .w = 600, + .h = 800, + }, + [AUOK190X_RESOLUTION_768_1024] = { + .w = 768, + .h = 1024, + }, }; /* @@ -60,8 +68,48 @@ static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data) par->board->set_ctl(par, AUOK190X_I80_DC, 1); } -static int auok190x_issue_pixels(struct auok190xfb_par *par, int size, - u16 *data) +/** + * Conversion of 16bit color to 4bit grayscale + * does roughly (0.3 * R + 0.6 G + 0.1 B) / 2 + */ +static inline int rgb565_to_gray4(u16 data, struct fb_var_screeninfo *var) +{ + return ((((data & 0xF800) >> var->red.offset) * 77 + + ((data & 0x07E0) >> (var->green.offset + 1)) * 151 + + ((data & 0x1F) >> var->blue.offset) * 28) >> 8 >> 1); +} + +static int auok190x_issue_pixels_rgb565(struct auok190xfb_par *par, int size, + u16 *data) +{ + struct fb_var_screeninfo *var = &par->info->var; + struct device *dev = par->info->device; + int i; + u16 tmp; + + if (size & 7) { + dev_err(dev, "issue_pixels: size %d must be a multiple of 8\n", + size); + return -EINVAL; + } + + for (i = 0; i < (size >> 2); i++) { + par->board->set_ctl(par, AUOK190X_I80_WR, 0); + + tmp = (rgb565_to_gray4(data[4*i], var) & 0x000F); + tmp |= (rgb565_to_gray4(data[4*i+1], var) << 4) & 0x00F0; + tmp |= (rgb565_to_gray4(data[4*i+2], var) << 8) & 0x0F00; + tmp |= (rgb565_to_gray4(data[4*i+3], var) << 12) & 0xF000; + + par->board->set_hdb(par, tmp); + par->board->set_ctl(par, AUOK190X_I80_WR, 1); + } + + return 0; +} + +static int auok190x_issue_pixels_gray8(struct auok190xfb_par *par, int size, + u16 *data) { struct device *dev = par->info->device; int i; @@ -91,6 +139,23 @@ static int auok190x_issue_pixels(struct auok190xfb_par *par, int size, return 0; } +static int auok190x_issue_pixels(struct auok190xfb_par *par, int size, + u16 *data) +{ + struct fb_info *info = par->info; + struct device *dev = par->info->device; + + if (info->var.bits_per_pixel == 8 && info->var.grayscale) + auok190x_issue_pixels_gray8(par, size, data); + else if (info->var.bits_per_pixel == 16) + auok190x_issue_pixels_rgb565(par, size, data); + else + dev_err(dev, "unsupported color mode (bits: %d, gray: %d)\n", + info->var.bits_per_pixel, info->var.grayscale); + + return 0; +} + static u16 auok190x_read_data(struct auok190xfb_par *par) { u16 data; @@ -224,8 +289,8 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info, { struct fb_deferred_io *fbdefio = info->fbdefio; struct auok190xfb_par *par = info->par; + u16 line_length = info->fix.line_length; u16 yres = info->var.yres; - u16 xres = info->var.xres; u16 y1 = 0, h = 0; int prev_index = -1; struct page *cur; @@ -254,7 +319,7 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info, } /* height increment is fixed per page */ - h_inc = DIV_ROUND_UP(PAGE_SIZE , xres); + h_inc = DIV_ROUND_UP(PAGE_SIZE , line_length); /* calculate number of pages from pixel height */ threshold = par->consecutive_threshold / h_inc; @@ -265,7 +330,7 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info, list_for_each_entry(cur, &fbdefio->pagelist, lru) { if (prev_index < 0) { /* just starting so assign first page */ - y1 = (cur->index << PAGE_SHIFT) / xres; + y1 = (cur->index << PAGE_SHIFT) / line_length; h = h_inc; } else if ((cur->index - prev_index) <= threshold) { /* page is within our threshold for single updates */ @@ -275,7 +340,7 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info, par->update_partial(par, y1, y1 + h); /* start over with our non consecutive page */ - y1 = (cur->index << PAGE_SHIFT) / xres; + y1 = (cur->index << PAGE_SHIFT) / line_length; h = h_inc; } prev_index = cur->index; @@ -376,27 +441,127 @@ static void auok190xfb_imageblit(struct fb_info *info, static int auok190xfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - if (info->var.xres != var->xres || info->var.yres != var->yres || - info->var.xres_virtual != var->xres_virtual || - info->var.yres_virtual != var->yres_virtual) { - pr_info("%s: Resolution not supported: X%u x Y%u\n", - __func__, var->xres, var->yres); + struct device *dev = info->device; + struct auok190xfb_par *par = info->par; + struct panel_info *panel = &panel_table[par->resolution]; + int size; + + /* + * Color depth + */ + + if (var->bits_per_pixel == 8 && var->grayscale == 1) { + /* + * For 8-bit grayscale, R, G, and B offset are equal. + */ + var->red.length = 8; + var->red.offset = 0; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 0; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + } else if (var->bits_per_pixel == 16) { + var->red.length = 5; + var->red.offset = 11; + var->red.msb_right = 0; + + var->green.length = 6; + var->green.offset = 5; + var->green.msb_right = 0; + + var->blue.length = 5; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + } else { + dev_warn(dev, "unsupported color mode (bits: %d, grayscale: %d)\n", + info->var.bits_per_pixel, info->var.grayscale); return -EINVAL; } /* + * Dimensions + */ + + switch (var->rotate) { + case FB_ROTATE_UR: + case FB_ROTATE_UD: + var->xres = panel->w; + var->yres = panel->h; + break; + case FB_ROTATE_CW: + case FB_ROTATE_CCW: + var->xres = panel->h; + var->yres = panel->w; + break; + default: + dev_dbg(dev, "Invalid rotation request\n"); + return -EINVAL; + } + + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + + /* * Memory limit */ - if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { - pr_info("%s: Memory Limit requested yres_virtual = %u\n", - __func__, var->yres_virtual); + size = var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8; + if (size > info->fix.smem_len) { + dev_err(dev, "Memory limit exceeded, requested %dK\n", + size >> 10); return -ENOMEM; } return 0; } +static int auok190xfb_set_fix(struct fb_info *info) +{ + struct fb_fix_screeninfo *fix = &info->fix; + struct fb_var_screeninfo *var = &info->var; + + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->accel = FB_ACCEL_NONE; + fix->visual = (var->grayscale) ? FB_VISUAL_STATIC_PSEUDOCOLOR + : FB_VISUAL_TRUECOLOR; + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + + return 0; +} + +static int auok190xfb_set_par(struct fb_info *info) +{ + struct auok190xfb_par *par = info->par; + + par->rotation = info->var.rotate; + auok190xfb_set_fix(info); + + /* reinit the controller to honor the rotation */ + par->init(par); + + /* wait for init to complete */ + par->board->wait_for_rdy(par); + + return 0; +} + static struct fb_ops auok190xfb_ops = { .owner = THIS_MODULE, .fb_read = fb_sys_read, @@ -405,6 +570,7 @@ static struct fb_ops auok190xfb_ops = { .fb_copyarea = auok190xfb_copyarea, .fb_imageblit = auok190xfb_imageblit, .fb_check_var = auok190xfb_check_var, + .fb_set_par = auok190xfb_set_par, }; /* @@ -588,10 +754,16 @@ static int auok190x_power(struct auok190xfb_par *par, bool on) static void auok190x_recover(struct auok190xfb_par *par) { + struct device *dev = par->info->device; + auok190x_power(par, 0); msleep(100); auok190x_power(par, 1); + /* after powercycling the device, it's always active */ + pm_runtime_set_active(dev); + par->standby = 0; + par->init(par); /* wait for init to complete */ @@ -875,42 +1047,17 @@ int auok190x_common_probe(struct platform_device *pdev, /* initialise fix, var, resolution and rotation */ strlcpy(info->fix.id, init->id, 16); - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; - info->fix.xpanstep = 0; - info->fix.ypanstep = 0; - info->fix.ywrapstep = 0; - info->fix.accel = FB_ACCEL_NONE; - info->var.bits_per_pixel = 8; info->var.grayscale = 1; - info->var.red.length = 8; - info->var.green.length = 8; - info->var.blue.length = 8; panel = &panel_table[board->resolution]; - /* if 90 degree rotation, switch width and height */ - if (board->rotation & 1) { - info->var.xres = panel->h; - info->var.yres = panel->w; - info->var.xres_virtual = panel->h; - info->var.yres_virtual = panel->w; - info->fix.line_length = panel->h; - } else { - info->var.xres = panel->w; - info->var.yres = panel->h; - info->var.xres_virtual = panel->w; - info->var.yres_virtual = panel->h; - info->fix.line_length = panel->w; - } - par->resolution = board->resolution; - par->rotation = board->rotation; + par->rotation = 0; /* videomemory handling */ - videomemorysize = roundup((panel->w * panel->h), PAGE_SIZE); + videomemorysize = roundup((panel->w * panel->h) * 2, PAGE_SIZE); videomemory = vmalloc(videomemorysize); if (!videomemory) { ret = -ENOMEM; @@ -924,6 +1071,12 @@ int auok190x_common_probe(struct platform_device *pdev, info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; info->fbops = &auok190xfb_ops; + ret = auok190xfb_check_var(&info->var, info); + if (ret) + goto err_defio; + + auok190xfb_set_fix(info); + /* deferred io init */ info->fbdefio = devm_kzalloc(info->device, diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 0c189b32a4c5..67b77b40aa7f 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -285,36 +285,26 @@ static int controlfb_pan_display(struct fb_var_screeninfo *var, static int controlfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - unsigned long off, start; - u32 len; - - off = vma->vm_pgoff << PAGE_SHIFT; - - /* frame buffer memory */ - start = info->fix.smem_start; - len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.smem_len); - if (off >= len) { - /* memory mapped io */ - off -= len; - if (info->var.accel_flags) - return -EINVAL; - start = info->fix.mmio_start; - len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.mmio_len); - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - } else { - /* framebuffer */ - vma->vm_page_prot = pgprot_cached_wthru(vma->vm_page_prot); - } - start &= PAGE_MASK; - if ((vma->vm_end - vma->vm_start + off) > len) - return -EINVAL; - off += start; - vma->vm_pgoff = off >> PAGE_SHIFT; - if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot)) - return -EAGAIN; - - return 0; + unsigned long mmio_pgoff; + unsigned long start; + u32 len; + + start = info->fix.smem_start; + len = info->fix.smem_len; + mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT; + if (vma->vm_pgoff >= mmio_pgoff) { + if (info->var.accel_flags) + return -EINVAL; + vma->vm_pgoff -= mmio_pgoff; + start = info->fix.mmio_start; + len = info->fix.mmio_len; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + } else { + /* framebuffer */ + vma->vm_page_prot = pgprot_cached_wthru(vma->vm_page_prot); + } + + return vm_iomap_memory(vma, start, len); } static int controlfb_blank(int blank_mode, struct fb_info *info) diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index fac7df6d1aba..3dd43ca2b95f 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -35,8 +35,6 @@ #include <video/exynos_mipi_dsim.h> -#include <plat/fb.h> - #include "exynos_mipi_dsi_common.h" #include "exynos_mipi_dsi_lowlevel.h" diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c index c70cb8926df6..520fc9bd887b 100644 --- a/drivers/video/exynos/exynos_mipi_dsi_common.c +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c @@ -31,8 +31,6 @@ #include <video/mipi_display.h> #include <video/exynos_mipi_dsim.h> -#include <mach/map.h> - #include "exynos_mipi_dsi_regs.h" #include "exynos_mipi_dsi_lowlevel.h" #include "exynos_mipi_dsi_common.h" diff --git a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c index 95cb99a1fe2d..15c5abd408dc 100644 --- a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c +++ b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c @@ -26,8 +26,6 @@ #include <video/exynos_mipi_dsim.h> -#include <mach/map.h> - #include "exynos_mipi_dsi_regs.h" void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim) diff --git a/drivers/video/fb-puv3.c b/drivers/video/fb-puv3.c index 7d106f1f4906..27fc956166fa 100644 --- a/drivers/video/fb-puv3.c +++ b/drivers/video/fb-puv3.c @@ -640,21 +640,9 @@ static int unifb_pan_display(struct fb_var_screeninfo *var, int unifb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long pos = info->fix.smem_start + offset; - - if (offset + size > info->fix.smem_len) - return -EINVAL; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (io_remap_pfn_range(vma, vma->vm_start, pos >> PAGE_SHIFT, size, - vma->vm_page_prot)) - return -EAGAIN; - - /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ - return 0; + return vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len); } static struct fb_ops unifb_ops = { diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 86291dcd964a..dcb669eb4532 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1398,6 +1398,11 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) len = info->fix.smem_len; mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT; if (vma->vm_pgoff >= mmio_pgoff) { + if (info->var.accel_flags) { + mutex_unlock(&info->mm_lock); + return -EINVAL; + } + vma->vm_pgoff -= mmio_pgoff; start = info->fix.mmio_start; len = info->fix.mmio_len; diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 7f6709991a5c..6103fa6fb54f 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -1376,7 +1376,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf return err; } -#if IS_ENABLED(CONFIG_VIDEOMODE) +#ifdef CONFIG_VIDEOMODE_HELPERS int fb_videomode_from_videomode(const struct videomode *vm, struct fb_videomode *fbmode) { @@ -1398,13 +1398,13 @@ int fb_videomode_from_videomode(const struct videomode *vm, fbmode->sync = 0; fbmode->vmode = 0; - if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH) + if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH) fbmode->sync |= FB_SYNC_HOR_HIGH_ACT; - if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH) + if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH) fbmode->sync |= FB_SYNC_VERT_HIGH_ACT; - if (vm->data_flags & DISPLAY_FLAGS_INTERLACED) + if (vm->flags & DISPLAY_FLAGS_INTERLACED) fbmode->vmode |= FB_VMODE_INTERLACED; - if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN) + if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN) fbmode->vmode |= FB_VMODE_DOUBLE; fbmode->flag = 0; @@ -1424,9 +1424,8 @@ int fb_videomode_from_videomode(const struct videomode *vm, return 0; } EXPORT_SYMBOL_GPL(fb_videomode_from_videomode); -#endif -#if IS_ENABLED(CONFIG_OF_VIDEOMODE) +#ifdef CONFIG_OF static inline void dump_fb_videomode(const struct fb_videomode *m) { pr_debug("fb_videomode = %ux%u@%uHz (%ukHz) %u %u %u %u %u %u %u %u %u\n", @@ -1465,7 +1464,8 @@ int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb, return 0; } EXPORT_SYMBOL_GPL(of_get_fb_videomode); -#endif +#endif /* CONFIG_OF */ +#endif /* CONFIG_VIDEOMODE_HELPERS */ #else int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 41fbd9453c5f..6c278056fc60 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -375,7 +375,10 @@ struct fsl_diu_data { struct diu_ad dummy_ad __aligned(8); struct diu_ad ad[NUM_AOIS] __aligned(8); u8 gamma[256 * 3] __aligned(32); - u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32); + /* It's easier to parse the cursor data as little-endian */ + __le16 cursor[MAX_CURS * MAX_CURS] __aligned(32); + /* Blank cursor data -- used to hide the cursor */ + __le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32); uint8_t edid_data[EDID_LENGTH]; bool has_edid; } __aligned(32); @@ -824,7 +827,6 @@ static void update_lcdc(struct fb_info *info) /* Program DIU registers */ out_be32(&hw->gamma, DMA_ADDR(data, gamma)); - out_be32(&hw->cursor, DMA_ADDR(data, cursor)); out_be32(&hw->bgnd, 0x007F7F7F); /* Set background to grey */ out_be32(&hw->disp_size, (var->yres << 16) | var->xres); @@ -968,6 +970,156 @@ static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel) } /* + * Copies a cursor image from user space to the proper place in driver + * memory so that the hardware can display the cursor image. + * + * Cursor data is represented as a sequence of 'width' bits packed into bytes. + * That is, the first 8 bits are in the first byte, the second 8 bits in the + * second byte, and so on. Therefore, the each row of the cursor is (width + + * 7) / 8 bytes of 'data' + * + * The DIU only supports cursors up to 32x32 (MAX_CURS). We reject cursors + * larger than this, so we already know that 'width' <= 32. Therefore, we can + * simplify our code by using a 32-bit big-endian integer ("line") to read in + * a single line of pixels, and only look at the top 'width' bits of that + * integer. + * + * This could result in an unaligned 32-bit read. For example, if the cursor + * is 24x24, then the first three bytes of 'image' contain the pixel data for + * the top line of the cursor. We do a 32-bit read of 'image', but we look + * only at the top 24 bits. Then we increment 'image' by 3 bytes. The next + * read is unaligned. The only problem is that we might read past the end of + * 'image' by 1-3 bytes, but that should not cause any problems. + */ +static void fsl_diu_load_cursor_image(struct fb_info *info, + const void *image, uint16_t bg, uint16_t fg, + unsigned int width, unsigned int height) +{ + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *data = mfbi->parent; + __le16 *cursor = data->cursor; + __le16 _fg = cpu_to_le16(fg); + __le16 _bg = cpu_to_le16(bg); + unsigned int h, w; + + for (h = 0; h < height; h++) { + uint32_t mask = 1 << 31; + uint32_t line = be32_to_cpup(image); + + for (w = 0; w < width; w++) { + cursor[w] = (line & mask) ? _fg : _bg; + mask >>= 1; + } + + cursor += MAX_CURS; + image += DIV_ROUND_UP(width, 8); + } +} + +/* + * Set a hardware cursor. The image data for the cursor is passed via the + * fb_cursor object. + */ +static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct mfb_info *mfbi = info->par; + struct fsl_diu_data *data = mfbi->parent; + struct diu __iomem *hw = data->diu_reg; + + if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) + return -EINVAL; + + /* The cursor size has changed */ + if (cursor->set & FB_CUR_SETSIZE) { + /* + * The DIU cursor is a fixed size, so when we get this + * message, instead of resizing the cursor, we just clear + * all the image data, in expectation of new data. However, + * in tests this control does not appear to be normally + * called. + */ + memset(data->cursor, 0, sizeof(data->cursor)); + } + + /* The cursor position has changed (cursor->image.dx|dy) */ + if (cursor->set & FB_CUR_SETPOS) { + uint32_t xx, yy; + + yy = (cursor->image.dy - info->var.yoffset) & 0x7ff; + xx = (cursor->image.dx - info->var.xoffset) & 0x7ff; + + out_be32(&hw->curs_pos, yy << 16 | xx); + } + + /* + * FB_CUR_SETIMAGE - the cursor image has changed + * FB_CUR_SETCMAP - the cursor colors has changed + * FB_CUR_SETSHAPE - the cursor bitmask has changed + */ + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) { + unsigned int image_size = + DIV_ROUND_UP(cursor->image.width, 8) * cursor->image.height; + unsigned int image_words = + DIV_ROUND_UP(image_size, sizeof(uint32_t)); + unsigned int bg_idx = cursor->image.bg_color; + unsigned int fg_idx = cursor->image.fg_color; + uint8_t buffer[image_size]; + uint32_t *image, *source, *mask; + uint16_t fg, bg; + unsigned int i; + + if (info->state != FBINFO_STATE_RUNNING) + return 0; + + /* + * Determine the size of the cursor image data. Normally, + * it's 8x16. + */ + image_size = DIV_ROUND_UP(cursor->image.width, 8) * + cursor->image.height; + + bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) | + ((info->cmap.green[bg_idx] & 0xf8) << 2) | + ((info->cmap.blue[bg_idx] & 0xf8) >> 3) | + 1 << 15; + + fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) | + ((info->cmap.green[fg_idx] & 0xf8) << 2) | + ((info->cmap.blue[fg_idx] & 0xf8) >> 3) | + 1 << 15; + + /* Use 32-bit operations on the data to improve performance */ + image = (uint32_t *)buffer; + source = (uint32_t *)cursor->image.data; + mask = (uint32_t *)cursor->mask; + + if (cursor->rop == ROP_XOR) + for (i = 0; i < image_words; i++) + image[i] = source[i] ^ mask[i]; + else + for (i = 0; i < image_words; i++) + image[i] = source[i] & mask[i]; + + fsl_diu_load_cursor_image(info, image, bg, fg, + cursor->image.width, cursor->image.height); + }; + + /* + * Show or hide the cursor. The cursor data is always stored in the + * 'cursor' memory block, and the actual cursor position is always in + * the DIU's CURS_POS register. To hide the cursor, we redirect the + * CURSOR register to a blank cursor. The show the cursor, we + * redirect the CURSOR register to the real cursor data. + */ + if (cursor->enable) + out_be32(&hw->cursor, DMA_ADDR(data, cursor)); + else + out_be32(&hw->cursor, DMA_ADDR(data, blank_cursor)); + + return 0; +} + +/* * Using the fb_var_screeninfo in fb_info we set the resolution of this * particular framebuffer. This function alters the fb_fix_screeninfo stored * in fb_info. It does not alter var in fb_info since we are using that @@ -1312,6 +1464,7 @@ static struct fb_ops fsl_diu_ops = { .fb_ioctl = fsl_diu_ioctl, .fb_open = fsl_diu_open, .fb_release = fsl_diu_release, + .fb_cursor = fsl_diu_cursor, }; static int install_fb(struct fb_info *info) diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index bda5e3941510..ceab37020fff 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -1016,7 +1016,9 @@ static int gbefb_mmap(struct fb_info *info, /* check range */ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; - if (offset + size > gbe_mem_size) + if (size > gbe_mem_size) + return -EINVAL; + if (offset > gbe_mem_size - size) return -EINVAL; /* remap using the fastest write-through mode on architecture */ diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c index 13ecd9897010..56009bc02b02 100644 --- a/drivers/video/of_display_timing.c +++ b/drivers/video/of_display_timing.c @@ -79,25 +79,24 @@ static struct display_timing *of_get_display_timing(struct device_node *np) ret |= parse_timing_property(np, "vsync-len", &dt->vsync_len); ret |= parse_timing_property(np, "clock-frequency", &dt->pixelclock); - dt->dmt_flags = 0; - dt->data_flags = 0; + dt->flags = 0; if (!of_property_read_u32(np, "vsync-active", &val)) - dt->dmt_flags |= val ? VESA_DMT_VSYNC_HIGH : - VESA_DMT_VSYNC_LOW; + dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH : + DISPLAY_FLAGS_VSYNC_LOW; if (!of_property_read_u32(np, "hsync-active", &val)) - dt->dmt_flags |= val ? VESA_DMT_HSYNC_HIGH : - VESA_DMT_HSYNC_LOW; + dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH : + DISPLAY_FLAGS_HSYNC_LOW; if (!of_property_read_u32(np, "de-active", &val)) - dt->data_flags |= val ? DISPLAY_FLAGS_DE_HIGH : + dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH : DISPLAY_FLAGS_DE_LOW; if (!of_property_read_u32(np, "pixelclk-active", &val)) - dt->data_flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE : + dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE : DISPLAY_FLAGS_PIXDATA_NEGEDGE; if (of_property_read_bool(np, "interlaced")) - dt->data_flags |= DISPLAY_FLAGS_INTERLACED; + dt->flags |= DISPLAY_FLAGS_INTERLACED; if (of_property_read_bool(np, "doublescan")) - dt->data_flags |= DISPLAY_FLAGS_DOUBLESCAN; + dt->flags |= DISPLAY_FLAGS_DOUBLESCAN; if (ret) { pr_err("%s: error reading timing properties\n", diff --git a/drivers/video/of_videomode.c b/drivers/video/of_videomode.c index 5b8066cd397f..111c2d1911d3 100644 --- a/drivers/video/of_videomode.c +++ b/drivers/video/of_videomode.c @@ -43,7 +43,7 @@ int of_get_videomode(struct device_node *np, struct videomode *vm, if (index == OF_USE_NATIVE_MODE) index = disp->native_mode; - ret = videomode_from_timing(disp, vm, index); + ret = videomode_from_timings(disp, vm, index); if (ret) return ret; diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig index e512581300fc..0bc3a936ce2b 100644 --- a/drivers/video/omap/Kconfig +++ b/drivers/video/omap/Kconfig @@ -39,17 +39,6 @@ config FB_OMAP_LCD_MIPID the Mobile Industry Processor Interface DBI-C/DCS specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3) -config FB_OMAP_CONSISTENT_DMA_SIZE - int "Consistent DMA memory size (MB)" - depends on FB_OMAP - range 1 14 - default 2 - help - Increase the DMA consistent memory size according to your video - memory needs, for example if you want to use multiple planes. - The size must be 2MB aligned. - If unsure say 1. - config FB_OMAP_DMA_TUNE bool "Set DMA SDRAM access priority high" depends on FB_OMAP diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index ca585ef37f25..717f13a93351 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1101,41 +1101,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) struct omapfb_info *ofbi = FB2OFB(fbi); struct fb_fix_screeninfo *fix = &fbi->fix; struct omapfb2_mem_region *rg; - unsigned long off; unsigned long start; u32 len; - int r = -EINVAL; - - if (vma->vm_end - vma->vm_start == 0) - return 0; - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) - return -EINVAL; - off = vma->vm_pgoff << PAGE_SHIFT; + int r; rg = omapfb_get_mem_region(ofbi->region); start = omapfb_get_region_paddr(ofbi); len = fix->smem_len; - if (off >= len) - goto error; - if ((vma->vm_end - vma->vm_start + off) > len) - goto error; - - off += start; - DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off); + DBG("user mmap region start %lx, len %d, off %lx\n", start, len, + vma->vm_pgoff << PAGE_SHIFT); - vma->vm_pgoff = off >> PAGE_SHIFT; - /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); vma->vm_ops = &mmap_user_ops; vma->vm_private_data = rg; - if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) { - r = -EAGAIN; + + r = vm_iomap_memory(vma, start, len); + if (r) goto error; - } /* vm_ops.open won't be called for mmap itself. */ atomic_inc(&rg->map_count); @@ -1144,7 +1128,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) return 0; - error: +error: omapfb_put_mem_region(ofbi->region); return r; diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c index 10560efeb35a..5261229c79af 100644 --- a/drivers/video/omap2/vrfb.c +++ b/drivers/video/omap2/vrfb.c @@ -397,18 +397,7 @@ static struct platform_driver vrfb_driver = { .remove = __exit_p(vrfb_remove), }; -static int __init vrfb_init(void) -{ - return platform_driver_probe(&vrfb_driver, &vrfb_probe); -} - -static void __exit vrfb_exit(void) -{ - platform_driver_unregister(&vrfb_driver); -} - -module_init(vrfb_init); -module_exit(vrfb_exit); +module_platform_driver_probe(vrfb_driver, vrfb_probe); MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); MODULE_DESCRIPTION("OMAP VRFB"); diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 920c27bf3947..d9f08c653d62 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -705,21 +705,15 @@ static int ps3fb_pan_display(struct fb_var_screeninfo *var, static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - unsigned long size, offset; + int r; - size = vma->vm_end - vma->vm_start; - offset = vma->vm_pgoff << PAGE_SHIFT; - if (offset + size > info->fix.smem_len) - return -EINVAL; - - offset += info->fix.smem_start; - if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, - size, vma->vm_page_prot)) - return -EAGAIN; + r = vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len); dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", - offset, vma->vm_start); - return 0; + info->fix.smem_start + vma->vm_pgoff << PAGE_SHIFT, + vma->vm_start); + + return r; } /* diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 968a62571df7..2e7991c7ca08 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -24,10 +24,9 @@ #include <linux/uaccess.h> #include <linux/interrupt.h> #include <linux/pm_runtime.h> +#include <linux/platform_data/video_s3c.h> #include <video/samsung_fimd.h> -#include <mach/map.h> -#include <plat/fb.h> /* This driver will export a number of framebuffer interfaces depending * on the configuration passed in via the platform data. Each fb instance diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index cfbde5e85cbf..f34c858642e8 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -556,7 +556,7 @@ static int sa1100fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; - unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT; + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; if (off < info->fix.smem_len) { vma->vm_pgoff += 1; /* skip over the palette */ @@ -564,19 +564,9 @@ static int sa1100fb_mmap(struct fb_info *info, fbi->map_dma, fbi->map_size); } - start = info->fix.mmio_start; - len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); - - if ((vma->vm_end - vma->vm_start + off) > len) - return -EINVAL; - - off += start & PAGE_MASK; - vma->vm_pgoff = off >> PAGE_SHIFT; - vma->vm_flags |= VM_IO; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); + + return vm_iomap_memory(vma, info->fix.mmio_start, info->fix.mmio_len); } static struct fb_ops sa1100fb_ops = { diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index 2331fadc272b..b2a8912f6435 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c @@ -705,23 +705,17 @@ static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, static int sgivwfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + int r; - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) - return -EINVAL; - if (offset + size > sgivwfb_mem_size) - return -EINVAL; - offset += sgivwfb_mem_phys; pgprot_val(vma->vm_page_prot) = - pgprot_val(vma->vm_page_prot) | _PAGE_PCD; - vma->vm_flags |= VM_IO; - if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, - size, vma->vm_page_prot)) - return -EAGAIN; + pgprot_val(vma->vm_page_prot) | _PAGE_PCD; + + r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size); + printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", offset, vma->vm_start); - return 0; + + return r; } int __init sgivwfb_setup(char *options) diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 701b461cf8a9..6cad53075e99 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -581,17 +581,7 @@ static struct platform_driver sh_mipi_driver = { }, }; -static int __init sh_mipi_init(void) -{ - return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe); -} -module_init(sh_mipi_init); - -static void __exit sh_mipi_exit(void) -{ - platform_driver_unregister(&sh_mipi_driver); -} -module_exit(sh_mipi_exit); +module_platform_driver_probe(sh_mipi_driver, sh_mipi_probe); MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver"); diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 930e550e752a..bfe4728480fd 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -1445,17 +1445,7 @@ static struct platform_driver sh_hdmi_driver = { }, }; -static int __init sh_hdmi_init(void) -{ - return platform_driver_probe(&sh_hdmi_driver, sh_hdmi_probe); -} -module_init(sh_hdmi_init); - -static void __exit sh_hdmi_exit(void) -{ - platform_driver_unregister(&sh_hdmi_driver); -} -module_exit(sh_hdmi_exit); +module_platform_driver_probe(sh_hdmi_driver, sh_hdmi_probe); MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); MODULE_DESCRIPTION("SuperH / ARM-shmobile HDMI driver"); diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c index 97bd6620c364..b2b33fc1ac3f 100644 --- a/drivers/video/smscufx.c +++ b/drivers/video/smscufx.c @@ -782,7 +782,11 @@ static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long page, pos; - if (offset + size > info->fix.smem_len) + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + if (size > info->fix.smem_len) + return -EINVAL; + if (offset > info->fix.smem_len - size) return -EINVAL; pos = (unsigned long)info->fix.smem_start + offset; diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 86d449ea3169..ec03e726c940 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -324,7 +324,11 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long page, pos; - if (offset + size > info->fix.smem_len) + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + if (size > info->fix.smem_len) + return -EINVAL; + if (offset > info->fix.smem_len - size) return -EINVAL; pos = (unsigned long)info->fix.smem_start + offset; diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 0aa516fc59cd..09a136633f35 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -1003,24 +1003,18 @@ static int vmlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct vml_info *vinfo = container_of(info, struct vml_info, info); - unsigned long size = vma->vm_end - vma->vm_start; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; int ret; - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) - return -EINVAL; - if (offset + size > vinfo->vram_contig_size) - return -EINVAL; ret = vmlfb_vram_offset(vinfo, offset); if (ret) return -EINVAL; - offset += vinfo->vram_start; + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; - if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, - size, vma->vm_page_prot)) - return -EAGAIN; - return 0; + + return vm_iomap_memory(vma, vinfo->vram_start, + vinfo->vram_contig_size); } static int vmlfb_sync(struct fb_info *info) diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 8bc1f9398945..ee5985efa15c 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -420,9 +420,12 @@ static int vfb_mmap(struct fb_info *info, unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long page, pos; - if (offset + size > info->fix.smem_len) { + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + if (size > info->fix.smem_len) + return -EINVAL; + if (offset > info->fix.smem_len - size) return -EINVAL; - } pos = (unsigned long)info->fix.smem_start + offset; diff --git a/drivers/video/videomode.c b/drivers/video/videomode.c index 21c47a202afa..df375c96c5d3 100644 --- a/drivers/video/videomode.c +++ b/drivers/video/videomode.c @@ -11,7 +11,25 @@ #include <video/display_timing.h> #include <video/videomode.h> -int videomode_from_timing(const struct display_timings *disp, +void videomode_from_timing(const struct display_timing *dt, + struct videomode *vm) +{ + vm->pixelclock = dt->pixelclock.typ; + vm->hactive = dt->hactive.typ; + vm->hfront_porch = dt->hfront_porch.typ; + vm->hback_porch = dt->hback_porch.typ; + vm->hsync_len = dt->hsync_len.typ; + + vm->vactive = dt->vactive.typ; + vm->vfront_porch = dt->vfront_porch.typ; + vm->vback_porch = dt->vback_porch.typ; + vm->vsync_len = dt->vsync_len.typ; + + vm->flags = dt->flags; +} +EXPORT_SYMBOL_GPL(videomode_from_timing); + +int videomode_from_timings(const struct display_timings *disp, struct videomode *vm, unsigned int index) { struct display_timing *dt; @@ -20,20 +38,8 @@ int videomode_from_timing(const struct display_timings *disp, if (!dt) return -EINVAL; - vm->pixelclock = display_timing_get_value(&dt->pixelclock, TE_TYP); - vm->hactive = display_timing_get_value(&dt->hactive, TE_TYP); - vm->hfront_porch = display_timing_get_value(&dt->hfront_porch, TE_TYP); - vm->hback_porch = display_timing_get_value(&dt->hback_porch, TE_TYP); - vm->hsync_len = display_timing_get_value(&dt->hsync_len, TE_TYP); - - vm->vactive = display_timing_get_value(&dt->vactive, TE_TYP); - vm->vfront_porch = display_timing_get_value(&dt->vfront_porch, TE_TYP); - vm->vback_porch = display_timing_get_value(&dt->vback_porch, TE_TYP); - vm->vsync_len = display_timing_get_value(&dt->vsync_len, TE_TYP); - - vm->dmt_flags = dt->dmt_flags; - vm->data_flags = dt->data_flags; + videomode_from_timing(dt, vm); return 0; } -EXPORT_SYMBOL_GPL(videomode_from_timing); +EXPORT_SYMBOL_GPL(videomode_from_timings); diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index aa2579c2364a..9547e1831e03 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c @@ -15,22 +15,21 @@ * GNU General Public License for more details. */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/slab.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> #include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/string.h> #include <linux/wait.h> - -#include <linux/platform_data/video-vt8500lcdfb.h> +#include <video/of_display_timing.h> #include "vt8500lcdfb.h" #include "wmt_ge_rops.h" @@ -277,11 +276,11 @@ static int vt8500lcd_probe(struct platform_device *pdev) { struct vt8500lcd_info *fbi; struct resource *res; + struct display_timings *disp_timing; void *addr; int irq, ret; struct fb_videomode of_mode; - struct device_node *np; u32 bpp; dma_addr_t fb_mem_phys; unsigned long fb_mem_len; @@ -346,32 +345,18 @@ static int vt8500lcd_probe(struct platform_device *pdev) goto failed_free_res; } - np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0); - if (!np) { - pr_err("%s: No display description in Device Tree\n", __func__); - ret = -EINVAL; - goto failed_free_res; - } + disp_timing = of_get_display_timings(pdev->dev.of_node); + if (!disp_timing) + return -EINVAL; - /* - * This code is copied from Sascha Hauer's of_videomode helper - * and can be replaced with a call to the helper once mainlined - */ - ret = 0; - ret |= of_property_read_u32(np, "hactive", &of_mode.xres); - ret |= of_property_read_u32(np, "vactive", &of_mode.yres); - ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin); - ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin); - ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len); - ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin); - ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin); - ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len); - ret |= of_property_read_u32(np, "bpp", &bpp); - if (ret) { - pr_err("%s: Unable to read display properties\n", __func__); - goto failed_free_res; - } - of_mode.vmode = FB_VMODE_NONINTERLACED; + ret = of_get_fb_videomode(pdev->dev.of_node, &of_mode, + OF_USE_NATIVE_MODE); + if (ret) + return ret; + + ret = of_property_read_u32(pdev->dev.of_node, "bits-per-pixel", &bpp); + if (ret) + return ret; /* try allocating the framebuffer */ fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8); diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c index 4dd0580f96fd..01f9ace068e2 100644 --- a/drivers/video/wm8505fb.c +++ b/drivers/video/wm8505fb.c @@ -14,25 +14,25 @@ * GNU General Public License for more details. */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/slab.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/fb.h> +#include <linux/errno.h> +#include <linux/err.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/dma-mapping.h> -#include <linux/platform_device.h> -#include <linux/wait.h> +#include <linux/kernel.h> +#include <linux/memblock.h> +#include <linux/mm.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/of_fdt.h> -#include <linux/memblock.h> - -#include <linux/platform_data/video-vt8500lcdfb.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/wait.h> +#include <video/of_display_timing.h> #include "wm8505fb_regs.h" #include "wmt_ge_rops.h" @@ -263,26 +263,22 @@ static struct fb_ops wm8505fb_ops = { static int wm8505fb_probe(struct platform_device *pdev) { struct wm8505fb_info *fbi; - struct resource *res; + struct resource *res; + struct display_timings *disp_timing; void *addr; int ret; - struct fb_videomode of_mode; - struct device_node *np; + struct fb_videomode mode; u32 bpp; dma_addr_t fb_mem_phys; unsigned long fb_mem_len; void *fb_mem_virt; - ret = -ENOMEM; - fbi = NULL; - fbi = devm_kzalloc(&pdev->dev, sizeof(struct wm8505fb_info) + sizeof(u32) * 16, GFP_KERNEL); if (!fbi) { dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); - ret = -ENOMEM; - goto failed; + return -ENOMEM; } strcpy(fbi->fb.fix.id, DRIVER_NAME); @@ -308,54 +304,23 @@ static int wm8505fb_probe(struct platform_device *pdev) fbi->fb.pseudo_palette = addr; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no I/O memory resource defined\n"); - ret = -ENODEV; - goto failed_fbi; - } + fbi->regbase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fbi->regbase)) + return PTR_ERR(fbi->regbase); - res = request_mem_region(res->start, resource_size(res), DRIVER_NAME); - if (res == NULL) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - ret = -EBUSY; - goto failed_fbi; - } - - fbi->regbase = ioremap(res->start, resource_size(res)); - if (fbi->regbase == NULL) { - dev_err(&pdev->dev, "failed to map I/O memory\n"); - ret = -EBUSY; - goto failed_free_res; - } + disp_timing = of_get_display_timings(pdev->dev.of_node); + if (!disp_timing) + return -EINVAL; - np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0); - if (!np) { - pr_err("%s: No display description in Device Tree\n", __func__); - ret = -EINVAL; - goto failed_free_res; - } + ret = of_get_fb_videomode(pdev->dev.of_node, &mode, OF_USE_NATIVE_MODE); + if (ret) + return ret; - /* - * This code is copied from Sascha Hauer's of_videomode helper - * and can be replaced with a call to the helper once mainlined - */ - ret = 0; - ret |= of_property_read_u32(np, "hactive", &of_mode.xres); - ret |= of_property_read_u32(np, "vactive", &of_mode.yres); - ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin); - ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin); - ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len); - ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin); - ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin); - ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len); - ret |= of_property_read_u32(np, "bpp", &bpp); - if (ret) { - pr_err("%s: Unable to read display properties\n", __func__); - goto failed_free_res; - } + ret = of_property_read_u32(pdev->dev.of_node, "bits-per-pixel", &bpp); + if (ret) + return ret; - of_mode.vmode = FB_VMODE_NONINTERLACED; - fb_videomode_to_var(&fbi->fb.var, &of_mode); + fb_videomode_to_var(&fbi->fb.var, &mode); fbi->fb.var.nonstd = 0; fbi->fb.var.activate = FB_ACTIVATE_NOW; @@ -364,16 +329,16 @@ static int wm8505fb_probe(struct platform_device *pdev) fbi->fb.var.width = -1; /* try allocating the framebuffer */ - fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8); - fb_mem_virt = dma_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys, + fb_mem_len = mode.xres * mode.yres * 2 * (bpp / 8); + fb_mem_virt = dmam_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys, GFP_KERNEL); if (!fb_mem_virt) { pr_err("%s: Failed to allocate framebuffer\n", __func__); return -ENOMEM; - }; + } - fbi->fb.var.xres_virtual = of_mode.xres; - fbi->fb.var.yres_virtual = of_mode.yres * 2; + fbi->fb.var.xres_virtual = mode.xres; + fbi->fb.var.yres_virtual = mode.yres * 2; fbi->fb.var.bits_per_pixel = bpp; fbi->fb.fix.smem_start = fb_mem_phys; @@ -381,28 +346,29 @@ static int wm8505fb_probe(struct platform_device *pdev) fbi->fb.screen_base = fb_mem_virt; fbi->fb.screen_size = fb_mem_len; + fbi->contrast = 0x10; + ret = wm8505fb_set_par(&fbi->fb); + if (ret) { + dev_err(&pdev->dev, "Failed to set parameters\n"); + return ret; + } + if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { dev_err(&pdev->dev, "Failed to allocate color map\n"); - ret = -ENOMEM; - goto failed_free_io; + return -ENOMEM; } wm8505fb_init_hw(&fbi->fb); - fbi->contrast = 0x80; - ret = wm8505fb_set_par(&fbi->fb); - if (ret) { - dev_err(&pdev->dev, "Failed to set parameters\n"); - goto failed_free_cmap; - } - platform_set_drvdata(pdev, fbi); ret = register_framebuffer(&fbi->fb); if (ret < 0) { dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n", ret); - goto failed_free_cmap; + if (fbi->fb.cmap.len) + fb_dealloc_cmap(&fbi->fb.cmap); + return ret; } ret = device_create_file(&pdev->dev, &dev_attr_contrast); @@ -416,25 +382,11 @@ static int wm8505fb_probe(struct platform_device *pdev) fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1); return 0; - -failed_free_cmap: - if (fbi->fb.cmap.len) - fb_dealloc_cmap(&fbi->fb.cmap); -failed_free_io: - iounmap(fbi->regbase); -failed_free_res: - release_mem_region(res->start, resource_size(res)); -failed_fbi: - platform_set_drvdata(pdev, NULL); - kfree(fbi); -failed: - return ret; } static int wm8505fb_remove(struct platform_device *pdev) { struct wm8505fb_info *fbi = platform_get_drvdata(pdev); - struct resource *res; device_remove_file(&pdev->dev, &dev_attr_contrast); @@ -445,13 +397,6 @@ static int wm8505fb_remove(struct platform_device *pdev) if (fbi->fb.cmap.len) fb_dealloc_cmap(&fbi->fb.cmap); - iounmap(fbi->regbase); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - kfree(fbi); - return 0; } diff --git a/drivers/video/wmt_ge_rops.h b/drivers/video/wmt_ge_rops.h index 87380751a443..f73ec6377a46 100644 --- a/drivers/video/wmt_ge_rops.h +++ b/drivers/video/wmt_ge_rops.h @@ -1,5 +1,28 @@ +#ifdef CONFIG_FB_WMT_GE_ROPS + extern void wmt_ge_fillrect(struct fb_info *info, const struct fb_fillrect *rect); extern void wmt_ge_copyarea(struct fb_info *info, const struct fb_copyarea *area); extern int wmt_ge_sync(struct fb_info *info); + +#else + +static inline int wmt_ge_sync(struct fb_info *p) +{ + return 0; +} + +static inline void wmt_ge_fillrect(struct fb_info *p, + const struct fb_fillrect *rect) +{ + sys_fillrect(p, rect); +} + +static inline void wmt_ge_copyarea(struct fb_info *p, + const struct fb_copyarea *area) +{ + sys_copyarea(p, area); +} + +#endif |