diff options
54 files changed, 799 insertions, 728 deletions
diff --git a/Documentation/devicetree/bindings/video/via,vt8500-fb.txt b/Documentation/devicetree/bindings/video/via,vt8500-fb.txt index c870b64..2871e21 100644 --- a/Documentation/devicetree/bindings/video/via,vt8500-fb.txt +++ b/Documentation/devicetree/bindings/video/via,vt8500-fb.txt @@ -5,58 +5,32 @@ Required properties: - compatible : "via,vt8500-fb" - reg : Should contain 1 register ranges(address and length) - interrupts : framebuffer controller interrupt -- display: a phandle pointing to the display node +- bits-per-pixel : bit depth of framebuffer (16 or 32) -Required nodes: -- display: a display node is required to initialize the lcd panel - This should be in the board dts. -- default-mode: a videomode within the display with timing parameters - as specified below. +Required subnodes: +- display-timings: see display-timing.txt for information Example: - fb@d800e400 { + fb@d8050800 { compatible = "via,vt8500-fb"; reg = <0xd800e400 0x400>; interrupts = <12>; - display = <&display>; - default-mode = <&mode0>; - }; - -VIA VT8500 Display ------------------------------------------------------ -Required properties (as per of_videomode_helper): - - - hactive, vactive: Display resolution - - hfront-porch, hback-porch, hsync-len: Horizontal Display timing parameters - in pixels - vfront-porch, vback-porch, vsync-len: Vertical display timing parameters in - lines - - clock: displayclock in Hz - - bpp: lcd panel bit-depth. - <16> for RGB565, <32> for RGB888 - -Optional properties (as per of_videomode_helper): - - width-mm, height-mm: Display dimensions in mm - - hsync-active-high (bool): Hsync pulse is active high - - vsync-active-high (bool): Vsync pulse is active high - - interlaced (bool): This is an interlaced mode - - doublescan (bool): This is a doublescan mode + bits-per-pixel = <16>; -Example: - display: display@0 { - modes { - mode0: mode@0 { + display-timings { + native-mode = <&timing0>; + timing0: 800x480 { + clock-frequency = <0>; /* unused but required */ hactive = <800>; vactive = <480>; - hback-porch = <88>; hfront-porch = <40>; + hback-porch = <88>; hsync-len = <0>; vback-porch = <32>; vfront-porch = <11>; vsync-len = <1>; - clock = <0>; /* unused but required */ - bpp = <16>; /* non-standard but required */ }; }; }; + diff --git a/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt b/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt index 3d325e1..0bcadb2 100644 --- a/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt +++ b/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt @@ -4,20 +4,30 @@ Wondermedia WM8505 Framebuffer Required properties: - compatible : "wm,wm8505-fb" - reg : Should contain 1 register ranges(address and length) -- via,display: a phandle pointing to the display node +- bits-per-pixel : bit depth of framebuffer (16 or 32) -Required nodes: -- display: a display node is required to initialize the lcd panel - This should be in the board dts. See definition in - Documentation/devicetree/bindings/video/via,vt8500-fb.txt -- default-mode: a videomode node as specified in - Documentation/devicetree/bindings/video/via,vt8500-fb.txt +Required subnodes: +- display-timings: see display-timing.txt for information Example: - fb@d8050800 { + fb@d8051700 { compatible = "wm,wm8505-fb"; - reg = <0xd8050800 0x200>; - display = <&display>; - default-mode = <&mode0>; + reg = <0xd8051700 0x200>; + bits-per-pixel = <16>; + + display-timings { + native-mode = <&timing0>; + timing0: 800x480 { + clock-frequency = <0>; /* unused but required */ + hactive = <800>; + vactive = <480>; + hfront-porch = <40>; + hback-porch = <88>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; + }; + }; }; diff --git a/arch/arm/boot/dts/vt8500-bv07.dts b/arch/arm/boot/dts/vt8500-bv07.dts index 567cf4e..877b33a 100644 --- a/arch/arm/boot/dts/vt8500-bv07.dts +++ b/arch/arm/boot/dts/vt8500-bv07.dts @@ -11,26 +11,22 @@ / { model = "Benign BV07 Netbook"; +}; - /* - * Display node is based on Sascha Hauer's patch on dri-devel. - * Added a bpp property to calculate the size of the framebuffer - * until the binding is formalized. - */ - display: display@0 { - modes { - mode0: mode@0 { - hactive = <800>; - vactive = <480>; - hback-porch = <88>; - hfront-porch = <40>; - hsync-len = <0>; - vback-porch = <32>; - vfront-porch = <11>; - vsync-len = <1>; - clock = <0>; /* unused but required */ - bpp = <16>; /* non-standard but required */ - }; +&fb { + bits-per-pixel = <16>; + display-timings { + native-mode = <&timing0>; + timing0: 800x480 { + clock-frequency = <0>; /* unused but required */ + hactive = <800>; + vactive = <480>; + hfront-porch = <40>; + hback-porch = <88>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; }; }; }; diff --git a/arch/arm/boot/dts/vt8500.dtsi b/arch/arm/boot/dts/vt8500.dtsi index cf31ced..68c8dc6 100644 --- a/arch/arm/boot/dts/vt8500.dtsi +++ b/arch/arm/boot/dts/vt8500.dtsi @@ -98,12 +98,10 @@ interrupts = <43>; }; - fb@d800e400 { + fb: fb@d8050800 { compatible = "via,vt8500-fb"; reg = <0xd800e400 0x400>; interrupts = <12>; - display = <&display>; - default-mode = <&mode0>; }; ge_rops@d8050400 { diff --git a/arch/arm/boot/dts/wm8505-ref.dts b/arch/arm/boot/dts/wm8505-ref.dts index fd4e248..edd2cec 100644 --- a/arch/arm/boot/dts/wm8505-ref.dts +++ b/arch/arm/boot/dts/wm8505-ref.dts @@ -11,26 +11,22 @@ / { model = "Wondermedia WM8505 Netbook"; +}; - /* - * Display node is based on Sascha Hauer's patch on dri-devel. - * Added a bpp property to calculate the size of the framebuffer - * until the binding is formalized. - */ - display: display@0 { - modes { - mode0: mode@0 { - hactive = <800>; - vactive = <480>; - hback-porch = <88>; - hfront-porch = <40>; - hsync-len = <0>; - vback-porch = <32>; - vfront-porch = <11>; - vsync-len = <1>; - clock = <0>; /* unused but required */ - bpp = <32>; /* non-standard but required */ - }; +&fb { + bits-per-pixel = <32>; + display-timings { + native-mode = <&timing0>; + timing0: 800x480 { + clock-frequency = <0>; /* unused but required */ + hactive = <800>; + vactive = <480>; + hfront-porch = <40>; + hback-porch = <88>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; }; }; }; diff --git a/arch/arm/boot/dts/wm8505.dtsi b/arch/arm/boot/dts/wm8505.dtsi index e74a1c0..bcf668d 100644 --- a/arch/arm/boot/dts/wm8505.dtsi +++ b/arch/arm/boot/dts/wm8505.dtsi @@ -128,11 +128,9 @@ interrupts = <0>; }; - fb@d8050800 { + fb: fb@d8050800 { compatible = "wm,wm8505-fb"; reg = <0xd8050800 0x200>; - display = <&display>; - default-mode = <&mode0>; }; ge_rops@d8050400 { diff --git a/arch/arm/boot/dts/wm8650-mid.dts b/arch/arm/boot/dts/wm8650-mid.dts index cefd938..61671a0 100644 --- a/arch/arm/boot/dts/wm8650-mid.dts +++ b/arch/arm/boot/dts/wm8650-mid.dts @@ -11,26 +11,24 @@ / { model = "Wondermedia WM8650-MID Tablet"; +}; + +&fb { + bits-per-pixel = <16>; - /* - * Display node is based on Sascha Hauer's patch on dri-devel. - * Added a bpp property to calculate the size of the framebuffer - * until the binding is formalized. - */ - display: display@0 { - modes { - mode0: mode@0 { - hactive = <800>; - vactive = <480>; - hback-porch = <88>; - hfront-porch = <40>; - hsync-len = <0>; - vback-porch = <32>; - vfront-porch = <11>; - vsync-len = <1>; - clock = <0>; /* unused but required */ - bpp = <16>; /* non-standard but required */ - }; + display-timings { + native-mode = <&timing0>; + timing0: 800x480 { + clock-frequency = <0>; /* unused but required */ + hactive = <800>; + vactive = <480>; + hfront-porch = <40>; + hback-porch = <88>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; }; }; }; + diff --git a/arch/arm/boot/dts/wm8650.dtsi b/arch/arm/boot/dts/wm8650.dtsi index db3c0a1..9313407 100644 --- a/arch/arm/boot/dts/wm8650.dtsi +++ b/arch/arm/boot/dts/wm8650.dtsi @@ -128,11 +128,9 @@ interrupts = <43>; }; - fb@d8050800 { + fb: fb@d8050800 { compatible = "wm,wm8505-fb"; reg = <0xd8050800 0x200>; - display = <&display>; - default-mode = <&mode0>; }; ge_rops@d8050400 { diff --git a/arch/arm/boot/dts/wm8850-w70v2.dts b/arch/arm/boot/dts/wm8850-w70v2.dts index fcc660c..32d2253 100644 --- a/arch/arm/boot/dts/wm8850-w70v2.dts +++ b/arch/arm/boot/dts/wm8850-w70v2.dts @@ -15,28 +15,6 @@ / { model = "Wondermedia WM8850-W70v2 Tablet"; - /* - * Display node is based on Sascha Hauer's patch on dri-devel. - * Added a bpp property to calculate the size of the framebuffer - * until the binding is formalized. - */ - display: display@0 { - modes { - mode0: mode@0 { - hactive = <800>; - vactive = <480>; - hback-porch = <88>; - hfront-porch = <40>; - hsync-len = <0>; - vback-porch = <32>; - vfront-porch = <11>; - vsync-len = <1>; - clock = <0>; /* unused but required */ - bpp = <16>; /* non-standard but required */ - }; - }; - }; - backlight { compatible = "pwm-backlight"; pwms = <&pwm 0 50000 1>; /* duty inverted */ @@ -45,3 +23,21 @@ default-brightness-level = <5>; }; }; + +&fb { + bits-per-pixel = <16>; + display-timings { + native-mode = <&timing0>; + timing0: 800x480 { + clock-frequency = <0>; /* unused but required */ + hactive = <800>; + vactive = <480>; + hfront-porch = <40>; + hback-porch = <88>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; + }; + }; +}; diff --git a/arch/arm/boot/dts/wm8850.dtsi b/arch/arm/boot/dts/wm8850.dtsi index e8cbfdc..7149cd1 100644 --- a/arch/arm/boot/dts/wm8850.dtsi +++ b/arch/arm/boot/dts/wm8850.dtsi @@ -135,11 +135,9 @@ }; }; - fb@d8051700 { + fb: fb@d8051700 { compatible = "wm,wm8505-fb"; reg = <0xd8051700 0x200>; - display = <&display>; - default-mode = <&mode0>; }; ge_rops@d8050400 { diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-samsung/include/plat/fb.h index b885322..9ae5072 100644 --- a/arch/arm/plat-samsung/include/plat/fb.h +++ b/arch/arm/plat-samsung/include/plat/fb.h @@ -15,55 +15,7 @@ #ifndef __PLAT_S3C_FB_H #define __PLAT_S3C_FB_H __FILE__ -/* S3C_FB_MAX_WIN - * Set to the maximum number of windows that any of the supported hardware - * can use. Since the platform data uses this for an array size, having it - * set to the maximum of any version of the hardware can do is safe. - */ -#define S3C_FB_MAX_WIN (5) - -/** - * struct s3c_fb_pd_win - per window setup data - * @xres : The window X size. - * @yres : The window Y size. - * @virtual_x: The virtual X size. - * @virtual_y: The virtual Y size. - */ -struct s3c_fb_pd_win { - unsigned short default_bpp; - unsigned short max_bpp; - unsigned short xres; - unsigned short yres; - unsigned short virtual_x; - unsigned short virtual_y; -}; - -/** - * struct s3c_fb_platdata - S3C driver platform specific information - * @setup_gpio: Setup the external GPIO pins to the right state to transfer - * the data from the display system to the connected display - * device. - * @vidcon0: The base vidcon0 values to control the panel data format. - * @vidcon1: The base vidcon1 values to control the panel data output. - * @vtiming: Video timing when connected to a RGB type panel. - * @win: The setup data for each hardware window, or NULL for unused. - * @display_mode: The LCD output display mode. - * - * The platform data supplies the video driver with all the information - * it requires to work with the display(s) attached to the machine. It - * controls the initial mode, the number of display windows (0 is always - * the base framebuffer) that are initialised etc. - * - */ -struct s3c_fb_platdata { - void (*setup_gpio)(void); - - struct s3c_fb_pd_win *win[S3C_FB_MAX_WIN]; - struct fb_videomode *vtiming; - - u32 vidcon0; - u32 vidcon1; -}; +#include <linux/platform_data/video_s3c.h> /** * s3c_fb_set_platdata() - Setup the FB device with platform data. diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 04fa6f1..f83f071 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -506,7 +506,7 @@ drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, } EXPORT_SYMBOL(drm_gtf_mode); -#if IS_ENABLED(CONFIG_VIDEOMODE) +#ifdef CONFIG_VIDEOMODE_HELPERS int drm_display_mode_from_videomode(const struct videomode *vm, struct drm_display_mode *dmode) { @@ -523,26 +523,25 @@ int drm_display_mode_from_videomode(const struct videomode *vm, dmode->clock = vm->pixelclock / 1000; dmode->flags = 0; - if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH) + if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH) dmode->flags |= DRM_MODE_FLAG_PHSYNC; - else if (vm->dmt_flags & VESA_DMT_HSYNC_LOW) + else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW) dmode->flags |= DRM_MODE_FLAG_NHSYNC; - if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH) + if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH) dmode->flags |= DRM_MODE_FLAG_PVSYNC; - else if (vm->dmt_flags & VESA_DMT_VSYNC_LOW) + else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW) dmode->flags |= DRM_MODE_FLAG_NVSYNC; - if (vm->data_flags & DISPLAY_FLAGS_INTERLACED) + if (vm->flags & DISPLAY_FLAGS_INTERLACED) dmode->flags |= DRM_MODE_FLAG_INTERLACE; - if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN) + if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN) dmode->flags |= DRM_MODE_FLAG_DBLSCAN; drm_mode_set_name(dmode); return 0; } EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode); -#endif -#if IS_ENABLED(CONFIG_OF_VIDEOMODE) +#ifdef CONFIG_OF /** * of_get_drm_display_mode - get a drm_display_mode from devicetree * @np: device_node with the timing specification @@ -572,7 +571,8 @@ int of_get_drm_display_mode(struct device_node *np, return 0; } EXPORT_SYMBOL_GPL(of_get_drm_display_mode); -#endif +#endif /* CONFIG_OF */ +#endif /* CONFIG_VIDEOMODE_HELPERS */ /** * drm_mode_set_name - set the name on a mode diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig index d24d040..e461e99 100644 --- a/drivers/gpu/drm/tilcdc/Kconfig +++ b/drivers/gpu/drm/tilcdc/Kconfig @@ -4,8 +4,7 @@ config DRM_TILCDC select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER select DRM_GEM_CMA_HELPER - select OF_VIDEOMODE - select OF_DISPLAY_TIMING + select VIDEOMODE_HELPERS select BACKLIGHT_CLASS_DEVICE help Choose this option if you have an TI SoC with LCDC display diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 580b74e..90ee497 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -173,7 +173,7 @@ static int panel_connector_get_modes(struct drm_connector *connector) struct drm_display_mode *mode = drm_mode_create(dev); struct videomode vm; - if (videomode_from_timing(timings, &vm, i)) + if (videomode_from_timings(timings, &vm, i)) break; drm_display_mode_from_videomode(&vm, mode); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0939465..981c1c0 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 9df3873..e414378 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 7fa1bf8..77cb4ff 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 025428e..98348ec 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 1a9ac6e..f5b668e 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 d1db165..12b9adc 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 53846cb..b1f19b2 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 0c189b3..67b77b4 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 fac7df6..3dd43ca 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 c70cb89..520fc9b 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 95cb99a..15c5abd 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 7d106f1f..27fc956 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 86291dc..dcb669e 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 7f67099..6103fa6 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 41fbd94..6c27805 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 bda5e39..ceab370 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 13ecd98..56009bc 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 5b8066c..111c2d1 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 e512581..0bc3a93 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 ca585ef..717f13a 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 10560ef..5261229 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 920c27b..d9f08c6 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 968a625..2e7991c 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 cfbde5e..f34c8586 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 2331fad..b2a8912 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 701b461..6cad530 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 930e550..bfe4728 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 97bd662..b2b33fc 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 86d449e..ec03e72 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 0aa516f..09a1366 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 8bc1f93..ee5985e 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 21c47a2..df375c9 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 aa2579c..9547e18 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 4dd0580..01f9ace 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 8738075..f73ec63 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 diff --git a/include/linux/platform_data/video-vt8500lcdfb.h b/include/linux/platform_data/video-vt8500lcdfb.h deleted file mode 100644 index 7f399c3..0000000 --- a/include/linux/platform_data/video-vt8500lcdfb.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * VT8500/WM8505 Frame Buffer platform data definitions - * - * Copyright (C) 2010 Ed Spiridonov <edo.rus@gmail.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _VT8500FB_H -#define _VT8500FB_H - -#include <linux/fb.h> - -struct vt8500fb_platform_data { - struct fb_videomode mode; - u32 xres_virtual; - u32 yres_virtual; - u32 bpp; - unsigned long video_mem_phys; - void *video_mem_virt; - unsigned long video_mem_len; -}; - -#endif /* _VT8500FB_H */ diff --git a/include/linux/platform_data/video_s3c.h b/include/linux/platform_data/video_s3c.h new file mode 100644 index 0000000..4888399 --- /dev/null +++ b/include/linux/platform_data/video_s3c.h @@ -0,0 +1,54 @@ +#ifndef __PLATFORM_DATA_VIDEO_S3C +#define __PLATFORM_DATA_VIDEO_S3C + +/* S3C_FB_MAX_WIN + * Set to the maximum number of windows that any of the supported hardware + * can use. Since the platform data uses this for an array size, having it + * set to the maximum of any version of the hardware can do is safe. + */ +#define S3C_FB_MAX_WIN (5) + +/** + * struct s3c_fb_pd_win - per window setup data + * @xres : The window X size. + * @yres : The window Y size. + * @virtual_x: The virtual X size. + * @virtual_y: The virtual Y size. + */ +struct s3c_fb_pd_win { + unsigned short default_bpp; + unsigned short max_bpp; + unsigned short xres; + unsigned short yres; + unsigned short virtual_x; + unsigned short virtual_y; +}; + +/** + * struct s3c_fb_platdata - S3C driver platform specific information + * @setup_gpio: Setup the external GPIO pins to the right state to transfer + * the data from the display system to the connected display + * device. + * @vidcon0: The base vidcon0 values to control the panel data format. + * @vidcon1: The base vidcon1 values to control the panel data output. + * @vtiming: Video timing when connected to a RGB type panel. + * @win: The setup data for each hardware window, or NULL for unused. + * @display_mode: The LCD output display mode. + * + * The platform data supplies the video driver with all the information + * it requires to work with the display(s) attached to the machine. It + * controls the initial mode, the number of display windows (0 is always + * the base framebuffer) that are initialised etc. + * + */ +struct s3c_fb_platdata { + void (*setup_gpio)(void); + + struct s3c_fb_pd_win *win[S3C_FB_MAX_WIN]; + struct fb_videomode *vtiming; + + u32 vidcon0; + u32 vidcon1; +}; + +#endif diff --git a/include/video/auo_k190xfb.h b/include/video/auo_k190xfb.h index 609efe8..ac329ee 100644 --- a/include/video/auo_k190xfb.h +++ b/include/video/auo_k190xfb.h @@ -22,6 +22,8 @@ */ #define AUOK190X_RESOLUTION_800_600 0 #define AUOK190X_RESOLUTION_1024_768 1 +#define AUOK190X_RESOLUTION_600_800 4 +#define AUOK190X_RESOLUTION_768_1024 5 /* * struct used by auok190x. board specific stuff comes from *board @@ -98,7 +100,6 @@ struct auok190x_board { int gpio_nbusy; int resolution; - int rotation; int quirks; int fps; }; diff --git a/include/video/display_timing.h b/include/video/display_timing.h index 71e9a38..5d0259b 100644 --- a/include/video/display_timing.h +++ b/include/video/display_timing.h @@ -12,19 +12,22 @@ #include <linux/bitops.h> #include <linux/types.h> -/* VESA display monitor timing parameters */ -#define VESA_DMT_HSYNC_LOW BIT(0) -#define VESA_DMT_HSYNC_HIGH BIT(1) -#define VESA_DMT_VSYNC_LOW BIT(2) -#define VESA_DMT_VSYNC_HIGH BIT(3) - -/* display specific flags */ -#define DISPLAY_FLAGS_DE_LOW BIT(0) /* data enable flag */ -#define DISPLAY_FLAGS_DE_HIGH BIT(1) -#define DISPLAY_FLAGS_PIXDATA_POSEDGE BIT(2) /* drive data on pos. edge */ -#define DISPLAY_FLAGS_PIXDATA_NEGEDGE BIT(3) /* drive data on neg. edge */ -#define DISPLAY_FLAGS_INTERLACED BIT(4) -#define DISPLAY_FLAGS_DOUBLESCAN BIT(5) +enum display_flags { + DISPLAY_FLAGS_HSYNC_LOW = BIT(0), + DISPLAY_FLAGS_HSYNC_HIGH = BIT(1), + DISPLAY_FLAGS_VSYNC_LOW = BIT(2), + DISPLAY_FLAGS_VSYNC_HIGH = BIT(3), + + /* data enable flag */ + DISPLAY_FLAGS_DE_LOW = BIT(4), + DISPLAY_FLAGS_DE_HIGH = BIT(5), + /* drive data on pos. edge */ + DISPLAY_FLAGS_PIXDATA_POSEDGE = BIT(6), + /* drive data on neg. edge */ + DISPLAY_FLAGS_PIXDATA_NEGEDGE = BIT(7), + DISPLAY_FLAGS_INTERLACED = BIT(8), + DISPLAY_FLAGS_DOUBLESCAN = BIT(9), +}; /* * A single signal can be specified via a range of minimal and maximal values @@ -36,12 +39,6 @@ struct timing_entry { u32 max; }; -enum timing_entry_index { - TE_MIN = 0, - TE_TYP = 1, - TE_MAX = 2, -}; - /* * Single "mode" entry. This describes one set of signal timings a display can * have in one setting. This struct can later be converted to struct videomode @@ -72,8 +69,7 @@ struct display_timing { struct timing_entry vback_porch; /* ver. back porch */ struct timing_entry vsync_len; /* ver. sync len */ - unsigned int dmt_flags; /* VESA DMT flags */ - unsigned int data_flags; /* video data flags */ + enum display_flags flags; /* display flags */ }; /* @@ -89,25 +85,6 @@ struct display_timings { struct display_timing **timings; }; -/* get value specified by index from struct timing_entry */ -static inline u32 display_timing_get_value(const struct timing_entry *te, - enum timing_entry_index index) -{ - switch (index) { - case TE_MIN: - return te->min; - break; - case TE_TYP: - return te->typ; - break; - case TE_MAX: - return te->max; - break; - default: - return te->typ; - } -} - /* get one entry from struct display_timings */ static inline struct display_timing *display_timings_get(const struct display_timings *disp, diff --git a/include/video/videomode.h b/include/video/videomode.h index a421562..3f1049d 100644 --- a/include/video/videomode.h +++ b/include/video/videomode.h @@ -29,20 +29,30 @@ struct videomode { u32 vback_porch; u32 vsync_len; - unsigned int dmt_flags; /* VESA DMT flags */ - unsigned int data_flags; /* video data flags */ + enum display_flags flags; /* display flags */ }; /** * videomode_from_timing - convert display timing to videomode + * @dt: display_timing structure + * @vm: return value + * + * DESCRIPTION: + * This function converts a struct display_timing to a struct videomode. + */ +void videomode_from_timing(const struct display_timing *dt, + struct videomode *vm); + +/** + * videomode_from_timings - convert one display timings entry to videomode * @disp: structure with all possible timing entries * @vm: return value * @index: index into the list of display timings in devicetree * * DESCRIPTION: - * This function converts a struct display_timing to a struct videomode. + * This function converts one struct display_timing entry to a struct videomode. */ -int videomode_from_timing(const struct display_timings *disp, +int videomode_from_timings(const struct display_timings *disp, struct videomode *vm, unsigned int index); #endif |