Merge tag 'fbdev-v4.19' of https://github.com/bzolnier/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Aug 2018 22:44:58 +0000 (15:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Aug 2018 22:44:58 +0000 (15:44 -0700)
Pull fbdev updates from Bartlomiej Zolnierkiewicz:
 "Mostly small fixes and cleanups for fb drivers (the biggest updates
  are for udlfb and pxafb drivers). This also adds deferred console
  takeover support to the console code and efifb driver.

  Summary:

   - add support for deferred console takeover, when enabled defers
     fbcon taking over the console from the dummy console until the
     first text is displayed on the console - together with the "quiet"
     kernel commandline option this allows fbcon to still be used
     together with a smooth graphical bootup (Hans de Goede)

   - improve console locking debugging code (Thomas Zimmermann)

   - copy the ACPI BGRT boot graphics to the framebuffer when deferred
     console takeover support is used in efifb driver (Hans de Goede)

   - update udlfb driver - fix lost console when the user unplugs a USB
     adapter, fix the screen corruption issue, fix locking and add some
     performance optimizations (Mikulas Patocka)

   - update pxafb driver - fix using uninitialized memory, switch to
     devm_* API, handle initialization errors and add support for
     lcd-supply regulator (Daniel Mack)

   - add support for boards booted with a DeviceTree in pxa3xx_gcu
     driver (Daniel Mack)

   - rename omap2 module to omap2fb.ko to avoid conflicts with omap1
     driver (Arnd Bergmann)

   - enable ACPI-based enumeration for goldfishfb driver (Yu Ning)

   - fix goldfishfb driver to make user space Android code use 60 fps
     (Christoffer Dall)

   - print big fat warning when nomodeset kernel parameter is used in
     vgacon driver (Lyude Paul)

   - remove VLA usage from fsl-diu-fb driver (Kees Cook)

   - misc fixes (Julia Lawall, Geert Uytterhoeven, Fredrik Noring,
     Yisheng Xie, Dan Carpenter, Daniel Vetter, Anton Vasilyev, Randy
     Dunlap, Gustavo A. R. Silva, Colin Ian King, Fengguang Wu)

   - misc cleanups (Roman Kiryanov, Yisheng Xie, Colin Ian King)"

* tag 'fbdev-v4.19' of https://github.com/bzolnier/linux: (54 commits)
  Documentation/fb: corrections for fbcon.txt
  fbcon: Do not takeover the console from atomic context
  dummycon: Stop exporting dummycon_[un]register_output_notifier
  fbcon: Only defer console takeover if the current console driver is the dummycon
  fbcon: Only allow FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER if fbdev is builtin
  fbdev: omap2: omapfb: fix ifnullfree.cocci warnings
  fbdev: omap2: omapfb: fix bugon.cocci warnings
  fbdev: omap2: omapfb: fix boolreturn.cocci warnings
  fb: amifb: fix build warnings when not builtin
  fbdev/core: Disable console-lock warnings when fb.lockless_register_fb is set
  console: Replace #if 0 with atomic var 'ignore_console_lock_warning'
  udlfb: use spin_lock_irq instead of spin_lock_irqsave
  udlfb: avoid prefetch
  udlfb: optimization - test the backing buffer
  udlfb: allow reallocating the framebuffer
  udlfb: set line_length in dlfb_ops_set_par
  udlfb: handle allocation failure
  udlfb: set optimal write delay
  udlfb: make a local copy of fb_ops
  udlfb: don't switch if we are switching to the same videomode
  ...

35 files changed:
Documentation/devicetree/bindings/display/marvell,pxa2xx-lcdc.txt
Documentation/devicetree/bindings/display/marvell,pxa300-gcu.txt [new file with mode: 0644]
Documentation/fb/fbcon.txt
drivers/firmware/efi/efi-bgrt.c
drivers/video/console/Kconfig
drivers/video/console/dummycon.c
drivers/video/console/vgacon.c
drivers/video/fbdev/amifb.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/core/modedb.c
drivers/video/fbdev/efifb.c
drivers/video/fbdev/fsl-diu-fb.c
drivers/video/fbdev/goldfishfb.c
drivers/video/fbdev/i740fb.c
drivers/video/fbdev/metronomefb.c
drivers/video/fbdev/omap/omapfb_main.c
drivers/video/fbdev/omap2/omapfb/Makefile
drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c
drivers/video/fbdev/omap2/omapfb/dss/dispc.c
drivers/video/fbdev/omap2/omapfb/omapfb-main.c
drivers/video/fbdev/pm2fb.c
drivers/video/fbdev/pxa3xx-gcu.c
drivers/video/fbdev/pxafb.c
drivers/video/fbdev/pxafb.h
drivers/video/fbdev/simplefb.c
drivers/video/fbdev/tdfxfb.c
drivers/video/fbdev/tridentfb.c
drivers/video/fbdev/udlfb.c
drivers/video/fbdev/via/lcd.c
drivers/video/fbdev/via/viafbdev.c
include/linux/console.h
include/linux/fb.h
include/video/udlfb.h
kernel/printk/printk.c

index f79641bd5f18e013a69ff939aa81a3f8cb02de5f..45ffd6c417487692df9ff8507e2fd62ced32846b 100644 (file)
@@ -10,6 +10,9 @@ Required properties:
  - interrupts : framebuffer controller interrupt.
  - clocks: phandle to input clocks
 
+Optional properties:
+ - lcd-supply: A phandle to a power regulator that controls the LCD voltage.
+
 Required nodes:
  - port: connection to the LCD panel (see video-interfaces.txt)
         This node must have its properties bus-width and remote-endpoint set.
diff --git a/Documentation/devicetree/bindings/display/marvell,pxa300-gcu.txt b/Documentation/devicetree/bindings/display/marvell,pxa300-gcu.txt
new file mode 100644 (file)
index 0000000..9cfae5c
--- /dev/null
@@ -0,0 +1,17 @@
+PXA3xx GCU Controller
+---------------------
+
+Required properties:
+ - compatible : "marvell,pxa300-gcu"
+ - reg : should contain the register range (address and length).
+ - interrupts : Controller interrupt.
+ - clocks: phandle to the PXA specific input clock.
+
+Example for PXA300:
+
+       display-controller@54000000 {
+               compatible = "marvell,pxa300-gcu";
+               reg = <0x54000000 0x1000>;
+               interrupts = <39>;
+               clocks = <&clks CLK_PXA300_GCU>;
+       };
index d4d642e1ce9ce4597e9d93759748a6ef8c9302b1..62af30511a95247549b7334093122e35884cbab8 100644 (file)
@@ -18,9 +18,10 @@ made available by the underlying graphics card are also possible.
 A. Configuration
 
        The framebuffer console can be enabled by using your favorite kernel
-configuration tool.  It is under Device Drivers->Graphics Support->Support for
-framebuffer devices->Framebuffer Console Support. Select 'y' to compile
-support statically, or 'm' for module support.  The module will be fbcon.
+configuration tool.  It is under Device Drivers->Graphics Support->Frame
+buffer Devices->Console display driver support->Framebuffer Console Support.
+Select 'y' to compile support statically or 'm' for module support.  The
+module will be fbcon.
 
        In order for fbcon to activate, at least one framebuffer driver is
 required, so choose from any of the numerous drivers available. For x86
@@ -29,10 +30,10 @@ always be available. However, using a chipset-specific driver will give you
 more speed and features, such as the ability to change the video mode
 dynamically.
 
-       To display the penguin logo, choose any logo available in Logo
-Configuration->Boot up logo.
+       To display the penguin logo, choose any logo available in Graphics
+support->Bootup logo.
 
-       Also, you will need to select at least one compiled-in fonts, but if
+       Also, you will need to select at least one compiled-in font, but if
 you don't do anything, the kernel configuration tool will select one for you,
 usually an 8x16 font.
 
@@ -135,16 +136,16 @@ C. Boot options
 
        The angle can be changed anytime afterwards by 'echoing' the same
        numbers to any one of the 2 attributes found in
-        /sys/class/graphics/fbcon
+       /sys/class/graphics/fbcon:
 
                rotate     - rotate the display of the active console
                rotate_all - rotate the display of all consoles
 
-       Console rotation will only become available if Console Rotation
-       Support is compiled in your kernel.
+       Console rotation will only become available if Framebuffer Console
+       Rotation support is compiled in your kernel.
 
        NOTE: This is purely console rotation.  Any other applications that
-       use the framebuffer will remain at their 'normal'orientation.
+       use the framebuffer will remain at their 'normal' orientation.
        Actually, the underlying fb driver is totally ignorant of console
        rotation.
 
@@ -164,7 +165,7 @@ C. Boot options
 
 C. Attaching, Detaching and Unloading
 
-Before going on how to attach, detach and unload the framebuffer console, an
+Before going on to how to attach, detach and unload the framebuffer console, an
 illustration of the dependencies may help.
 
 The console layer, as with most subsystems, needs a driver that interfaces with
@@ -182,7 +183,7 @@ because fbcon is an intermediate layer between the console and the drivers:
 
 console ---> fbcon ---> fbdev drivers ---> hardware
 
-The fbdev drivers cannot be unloaded if it's bound to fbcon, and fbcon cannot
+The fbdev drivers cannot be unloaded if bound to fbcon, and fbcon cannot
 be unloaded if it's bound to the console layer.
 
 So to unload the fbdev drivers, one must first unbind fbcon from the console,
@@ -232,7 +233,7 @@ restored properly. The following is one of the several methods that you can do:
        echo 0 > /sys/class/vtconsole/vtcon1/bind
 
 6. That's it, you're back to VGA mode. And if you compiled fbcon as a module,
-   you can unload it by 'rmmod fbcon'
+   you can unload it by 'rmmod fbcon'.
 
 7. To reattach fbcon:
 
@@ -290,7 +291,7 @@ Samples:
 ========
 
 Here are 2 sample bash scripts that you can use to bind or unbind the
-framebuffer console driver if you are in an X86 box:
+framebuffer console driver if you are on an X86 box:
 
 ---------------------------------------------------------------------------
 #!/bin/bash
index 50793fda78191da4d4889dcabf12744f71411254..b22ccfb0c991bde8c6d222d0a44ce527e304c7ae 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/efi-bgrt.h>
 
 struct acpi_table_bgrt bgrt_tab;
-size_t __initdata bgrt_image_size;
+size_t bgrt_image_size;
 
 struct bmp_header {
        u16 id;
index e91edef98633e9d624ca50f171c13d0978510eca..787792c3d08d66b93012c27deed878e820c06e12 100644 (file)
@@ -152,7 +152,7 @@ config FRAMEBUFFER_CONSOLE_ROTATION
 
 config FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
        bool "Framebuffer Console Deferred Takeover"
-       depends on FRAMEBUFFER_CONSOLE=y && DUMMY_CONSOLE=y
+       depends on FB=y && FRAMEBUFFER_CONSOLE && DUMMY_CONSOLE
        help
          If enabled this defers the framebuffer console taking over the
          console from the dummy console until the first text is displayed on
index 0254251fdd79a745e77a46793915e55425b4770f..45ad925ad5f8fbb203a137c0ab114f4fb71d62f2 100644 (file)
@@ -38,13 +38,11 @@ void dummycon_register_output_notifier(struct notifier_block *nb)
        if (dummycon_putc_called)
                nb->notifier_call(nb, 0, NULL);
 }
-EXPORT_SYMBOL_GPL(dummycon_register_output_notifier);
 
 void dummycon_unregister_output_notifier(struct notifier_block *nb)
 {
        raw_notifier_chain_unregister(&dummycon_output_nh, nb);
 }
-EXPORT_SYMBOL_GPL(dummycon_unregister_output_notifier);
 
 static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos)
 {
index f09e17b60e45ef611f51e2e21528432731fac8f0..09731b2f6815f98651acba84cf9cc8d679f34f7a 100644 (file)
@@ -112,6 +112,11 @@ EXPORT_SYMBOL(vgacon_text_force);
 static int __init text_mode(char *str)
 {
        vgacon_text_mode_force = true;
+
+       pr_warning("You have booted with nomodeset. This means your GPU drivers are DISABLED\n");
+       pr_warning("Any video related functionality will be severely degraded, and you may not even be able to suspend the system properly\n");
+       pr_warning("Unless you actually understand what nomodeset does, you should reboot without enabling it\n");
+
        return 1;
 }
 
index cc11c60612980208d8bb26bd4c92b8892d792bfe..0777aff211e5cddad3c216e0f58f6c9576e9ac7f 100644 (file)
@@ -2303,7 +2303,7 @@ static void ami_build_copper(struct fb_info *info)
        ami_rebuild_copper(info->par);
 }
 
-
+#ifndef MODULE
 static void __init amifb_setup_mcap(char *spec)
 {
        char *p;
@@ -2368,7 +2368,7 @@ static int __init amifb_setup(char *options)
 
        return 0;
 }
-
+#endif
 
 static int amifb_check_var(struct fb_var_screeninfo *var,
                           struct fb_info *info)
index 5fb156bdcf4e5450f0d8e0348010dadee09bd05f..75ebbbf0a1fbb5b4e3d633ced517967d94d02e6b 100644 (file)
@@ -2234,8 +2234,8 @@ static int fbcon_switch(struct vc_data *vc)
         *
         * info->currcon = vc->vc_num;
         */
-       for (i = 0; i < FB_MAX; i++) {
-               if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) {
+       for_each_registered_fb(i) {
+               if (registered_fb[i]->fbcon_par) {
                        struct fbcon_ops *o = registered_fb[i]->fbcon_par;
 
                        o->currcon = vc->vc_num;
@@ -3124,11 +3124,9 @@ static int fbcon_fb_unregistered(struct fb_info *info)
        if (idx == info_idx) {
                info_idx = -1;
 
-               for (i = 0; i < FB_MAX; i++) {
-                       if (registered_fb[i] != NULL) {
-                               info_idx = i;
-                               break;
-                       }
+               for_each_registered_fb(i) {
+                       info_idx = i;
+                       break;
                }
        }
 
@@ -3594,13 +3592,24 @@ static int fbcon_init_device(void)
 }
 
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
+static void fbcon_register_existing_fbs(struct work_struct *work)
+{
+       int i;
+
+       console_lock();
+
+       for_each_registered_fb(i)
+               fbcon_fb_registered(registered_fb[i]);
+
+       console_unlock();
+}
+
 static struct notifier_block fbcon_output_nb;
+static DECLARE_WORK(fbcon_deferred_takeover_work, fbcon_register_existing_fbs);
 
 static int fbcon_output_notifier(struct notifier_block *nb,
                                 unsigned long action, void *data)
 {
-       int i;
-
        WARN_CONSOLE_UNLOCKED();
 
        pr_info("fbcon: Taking over console\n");
@@ -3609,45 +3618,37 @@ static int fbcon_output_notifier(struct notifier_block *nb,
        deferred_takeover = false;
        logo_shown = FBCON_LOGO_DONTSHOW;
 
-       for (i = 0; i < FB_MAX; i++) {
-               if (registered_fb[i])
-                       fbcon_fb_registered(registered_fb[i]);
-       }
+       /* We may get called in atomic context */
+       schedule_work(&fbcon_deferred_takeover_work);
 
        return NOTIFY_OK;
 }
-
-static void fbcon_register_output_notifier(void)
-{
-       fbcon_output_nb.notifier_call = fbcon_output_notifier;
-       dummycon_register_output_notifier(&fbcon_output_nb);
-}
-#else
-static inline void fbcon_register_output_notifier(void) {}
 #endif
 
 static void fbcon_start(void)
 {
+       WARN_CONSOLE_UNLOCKED();
+
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
+       if (conswitchp != &dummy_con)
+               deferred_takeover = false;
+
        if (deferred_takeover) {
-               fbcon_register_output_notifier();
+               fbcon_output_nb.notifier_call = fbcon_output_notifier;
+               dummycon_register_output_notifier(&fbcon_output_nb);
                return;
        }
+#endif
 
        if (num_registered_fb) {
                int i;
 
-               console_lock();
-
-               for (i = 0; i < FB_MAX; i++) {
-                       if (registered_fb[i] != NULL) {
-                               info_idx = i;
-                               break;
-                       }
+               for_each_registered_fb(i) {
+                       info_idx = i;
+                       break;
                }
 
                do_fbcon_takeover(0);
-               console_unlock();
-
        }
 }
 
@@ -3669,15 +3670,12 @@ static void fbcon_exit(void)
        kfree((void *)softback_buf);
        softback_buf = 0UL;
 
-       for (i = 0; i < FB_MAX; i++) {
+       for_each_registered_fb(i) {
                int pending = 0;
 
                mapped = 0;
                info = registered_fb[i];
 
-               if (info == NULL)
-                       continue;
-
                if (info->queue.func)
                        pending = cancel_work_sync(&info->queue);
                DPRINTK("fbcon: %s pending work\n", (pending ? "canceled" :
@@ -3733,8 +3731,8 @@ void __init fb_console_init(void)
        for (i = 0; i < MAX_NR_CONSOLES; i++)
                con2fb_map[i] = -1;
 
-       console_unlock();
        fbcon_start();
+       console_unlock();
 }
 
 #ifdef MODULE
index 609438d2465b288f831eb086b9d0ef982bb5ddef..20405421a5ed07c398036fbf3110eea18f61e2e6 100644 (file)
@@ -1347,6 +1347,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
        case FBIOGET_CON2FBMAP:
        case FBIOPUT_CON2FBMAP:
                arg = (unsigned long) compat_ptr(arg);
+               /* fall through */
        case FBIOBLANK:
                ret = do_fb_ioctl(info, cmd, arg);
                break;
@@ -1593,10 +1594,8 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
        int i, ret;
 
        /* check all firmware fbs and kick off if the base addr overlaps */
-       for (i = 0 ; i < FB_MAX; i++) {
+       for_each_registered_fb(i) {
                struct apertures_struct *gen_aper;
-               if (!registered_fb[i])
-                       continue;
 
                if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
                        continue;
@@ -1691,25 +1690,30 @@ static int do_register_framebuffer(struct fb_info *fb_info)
        event.info = fb_info;
        if (!lockless_register_fb)
                console_lock();
+       else
+               atomic_inc(&ignore_console_lock_warning);
        if (!lock_fb_info(fb_info)) {
-               if (!lockless_register_fb)
-                       console_unlock();
-               return -ENODEV;
+               ret = -ENODEV;
+               goto unlock_console;
        }
+       ret = 0;
 
        fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
        unlock_fb_info(fb_info);
+unlock_console:
        if (!lockless_register_fb)
                console_unlock();
-       return 0;
+       else
+               atomic_dec(&ignore_console_lock_warning);
+       return ret;
 }
 
-static int do_unregister_framebuffer(struct fb_info *fb_info)
+static int unbind_console(struct fb_info *fb_info)
 {
        struct fb_event event;
-       int i, ret = 0;
+       int ret;
+       int i = fb_info->node;
 
-       i = fb_info->node;
        if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
                return -EINVAL;
 
@@ -1724,17 +1728,29 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
        unlock_fb_info(fb_info);
        console_unlock();
 
+       return ret;
+}
+
+static int __unlink_framebuffer(struct fb_info *fb_info);
+
+static int do_unregister_framebuffer(struct fb_info *fb_info)
+{
+       struct fb_event event;
+       int ret;
+
+       ret = unbind_console(fb_info);
+
        if (ret)
                return -EINVAL;
 
        pm_vt_switch_unregister(fb_info->dev);
 
-       unlink_framebuffer(fb_info);
+       __unlink_framebuffer(fb_info);
        if (fb_info->pixmap.addr &&
            (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
                kfree(fb_info->pixmap.addr);
        fb_destroy_modelist(&fb_info->modelist);
-       registered_fb[i] = NULL;
+       registered_fb[fb_info->node] = NULL;
        num_registered_fb--;
        fb_cleanup_device(fb_info);
        event.info = fb_info;
@@ -1747,7 +1763,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
        return 0;
 }
 
-int unlink_framebuffer(struct fb_info *fb_info)
+static int __unlink_framebuffer(struct fb_info *fb_info)
 {
        int i;
 
@@ -1759,6 +1775,20 @@ int unlink_framebuffer(struct fb_info *fb_info)
                device_destroy(fb_class, MKDEV(FB_MAJOR, i));
                fb_info->dev = NULL;
        }
+
+       return 0;
+}
+
+int unlink_framebuffer(struct fb_info *fb_info)
+{
+       int ret;
+
+       ret = __unlink_framebuffer(fb_info);
+       if (ret)
+               return ret;
+
+       unbind_console(fb_info);
+
        return 0;
 }
 EXPORT_SYMBOL(unlink_framebuffer);
index 2510fa728d77160326781219ec554ae50c99be4a..283d9307df21c2d9b46d609080f078e591943b65 100644 (file)
@@ -628,45 +628,47 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
 }
 
 /**
- *     fb_find_mode - finds a valid video mode
- *     @var: frame buffer user defined part of display
- *     @info: frame buffer info structure
- *     @mode_option: string video mode to find
- *     @db: video mode database
- *     @dbsize: size of @db
- *     @default_mode: default video mode to fall back to
- *     @default_bpp: default color depth in bits per pixel
+ * fb_find_mode - finds a valid video mode
+ * @var: frame buffer user defined part of display
+ * @info: frame buffer info structure
+ * @mode_option: string video mode to find
+ * @db: video mode database
+ * @dbsize: size of @db
+ * @default_mode: default video mode to fall back to
+ * @default_bpp: default color depth in bits per pixel
  *
- *     Finds a suitable video mode, starting with the specified mode
- *     in @mode_option with fallback to @default_mode.  If
- *     @default_mode fails, all modes in the video mode database will
- *     be tried.
+ * Finds a suitable video mode, starting with the specified mode
+ * in @mode_option with fallback to @default_mode.  If
+ * @default_mode fails, all modes in the video mode database will
+ * be tried.
  *
- *     Valid mode specifiers for @mode_option:
+ * Valid mode specifiers for @mode_option::
  *
- *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
- *     <name>[-<bpp>][@<refresh>]
+ *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][p][m]
+ *
+ * or ::
  *
- *     with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
- *     <name> a string.
+ *     <name>[-<bpp>][@<refresh>]
  *
- *      If 'M' is present after yres (and before refresh/bpp if present),
- *      the function will compute the timings using VESA(tm) Coordinated
- *      Video Timings (CVT).  If 'R' is present after 'M', will compute with
- *      reduced blanking (for flatpanels).  If 'i' is present, compute
- *      interlaced mode.  If 'm' is present, add margins equal to 1.8%
- *      of xres rounded down to 8 pixels, and 1.8% of yres. The char
- *      'i' and 'm' must be after 'M' and 'R'. Example:
+ * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
+ * <name> a string.
  *
- *      1024x768MR-8@60m - Reduced blank with margins at 60Hz.
+ * If 'M' is present after yres (and before refresh/bpp if present),
+ * the function will compute the timings using VESA(tm) Coordinated
+ * Video Timings (CVT).  If 'R' is present after 'M', will compute with
+ * reduced blanking (for flatpanels).  If 'i' or 'p' are present, compute
+ * interlaced or progressive mode.  If 'm' is present, add margins equal
+ * to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The char
+ * 'i', 'p' and 'm' must be after 'M' and 'R'. Example::
  *
- *     NOTE: The passed struct @var is _not_ cleared!  This allows you
- *     to supply values for e.g. the grayscale and accel_flags fields.
+ *     1024x768MR-8@60m - Reduced blank with margins at 60Hz.
  *
- *     Returns zero for failure, 1 if using specified @mode_option,
- *     2 if using specified @mode_option with an ignored refresh rate,
- *     3 if default mode is used, 4 if fall back to any valid mode.
+ * NOTE: The passed struct @var is _not_ cleared!  This allows you
+ * to supply values for e.g. the grayscale and accel_flags fields.
  *
+ * Returns zero for failure, 1 if using specified @mode_option,
+ * 2 if using specified @mode_option with an ignored refresh rate,
+ * 3 if default mode is used, 4 if fall back to any valid mode.
  */
 
 int fb_find_mode(struct fb_var_screeninfo *var,
@@ -697,7 +699,8 @@ int fb_find_mode(struct fb_var_screeninfo *var,
                unsigned int namelen = strlen(name);
                int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
                unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
-               int yres_specified = 0, cvt = 0, rb = 0, interlace = 0;
+               int yres_specified = 0, cvt = 0, rb = 0;
+               int interlace_specified = 0, interlace = 0;
                int margins = 0;
                u32 best, diff, tdiff;
 
@@ -748,9 +751,17 @@ int fb_find_mode(struct fb_var_screeninfo *var,
                                if (!cvt)
                                        margins = 1;
                                break;
+                       case 'p':
+                               if (!cvt) {
+                                       interlace = 0;
+                                       interlace_specified = 1;
+                               }
+                               break;
                        case 'i':
-                               if (!cvt)
+                               if (!cvt) {
                                        interlace = 1;
+                                       interlace_specified = 1;
+                               }
                                break;
                        default:
                                goto done;
@@ -819,11 +830,21 @@ done:
                        if ((name_matches(db[i], name, namelen) ||
                             (res_specified && res_matches(db[i], xres, yres))) &&
                            !fb_try_mode(var, info, &db[i], bpp)) {
-                               if (refresh_specified && db[i].refresh == refresh)
-                                       return 1;
+                               const int db_interlace = (db[i].vmode &
+                                       FB_VMODE_INTERLACED ? 1 : 0);
+                               int score = abs(db[i].refresh - refresh);
+
+                               if (interlace_specified)
+                                       score += abs(db_interlace - interlace);
+
+                               if (!interlace_specified ||
+                                   db_interlace == interlace)
+                                       if (refresh_specified &&
+                                           db[i].refresh == refresh)
+                                               return 1;
 
-                               if (abs(db[i].refresh - refresh) < diff) {
-                                       diff = abs(db[i].refresh - refresh);
+                               if (score < diff) {
+                                       diff = score;
                                        best = i;
                                }
                        }
index c6f78d27947b9dae5f00b148c325198956910095..3946649b85c8908f4e9874b837ccdad274af8499 100644 (file)
@@ -9,16 +9,39 @@
 
 #include <linux/kernel.h>
 #include <linux/efi.h>
+#include <linux/efi-bgrt.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/printk.h>
 #include <linux/screen_info.h>
 #include <video/vga.h>
 #include <asm/efi.h>
 #include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */
 #include <drm/drm_connector.h>  /* For DRM_MODE_PANEL_ORIENTATION_* */
 
+struct bmp_file_header {
+       u16 id;
+       u32 file_size;
+       u32 reserved;
+       u32 bitmap_offset;
+} __packed;
+
+struct bmp_dib_header {
+       u32 dib_header_size;
+       s32 width;
+       s32 height;
+       u16 planes;
+       u16 bpp;
+       u32 compression;
+       u32 bitmap_size;
+       u32 horz_resolution;
+       u32 vert_resolution;
+       u32 colors_used;
+       u32 colors_important;
+} __packed;
+
 static bool request_mem_succeeded = false;
 static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
 
@@ -66,6 +89,164 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
        return 0;
 }
 
+/*
+ * If fbcon deffered console takeover is configured, the intent is for the
+ * framebuffer to show the boot graphics (e.g. vendor logo) until there is some
+ * (error) message to display. But the boot graphics may have been destroyed by
+ * e.g. option ROM output, detect this and restore the boot graphics.
+ */
+#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \
+    defined CONFIG_ACPI_BGRT
+static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
+{
+       u8 r, g, b;
+
+       while (width--) {
+               b = *src++;
+               g = *src++;
+               r = *src++;
+               *dst++ = (r << si->red_pos)   |
+                        (g << si->green_pos) |
+                        (b << si->blue_pos);
+       }
+}
+
+#ifdef CONFIG_X86
+/*
+ * On x86 some firmwares use a low non native resolution for the display when
+ * they have shown some text messages. While keeping the bgrt filled with info
+ * for the native resolution. If the bgrt image intended for the native
+ * resolution still fits, it will be displayed very close to the right edge of
+ * the display looking quite bad. This function checks for this.
+ */
+static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
+{
+       static const int default_resolutions[][2] = {
+               {  800,  600 },
+               { 1024,  768 },
+               { 1280, 1024 },
+       };
+       u32 i, right_margin;
+
+       for (i = 0; i < ARRAY_SIZE(default_resolutions); i++) {
+               if (default_resolutions[i][0] == si->lfb_width &&
+                   default_resolutions[i][1] == si->lfb_height)
+                       break;
+       }
+       /* If not a default resolution used for textmode, this should be fine */
+       if (i >= ARRAY_SIZE(default_resolutions))
+               return true;
+
+       /* If the right margin is 5 times smaller then the left one, reject */
+       right_margin = si->lfb_width - (bgrt_tab.image_offset_x + bmp_width);
+       if (right_margin < (bgrt_tab.image_offset_x / 5))
+               return false;
+
+       return true;
+}
+#else
+static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
+{
+       return true;
+}
+#endif
+
+static void efifb_show_boot_graphics(struct fb_info *info)
+{
+       u32 bmp_width, bmp_height, bmp_pitch, screen_pitch, dst_x, y, src_y;
+       struct screen_info *si = &screen_info;
+       struct bmp_file_header *file_header;
+       struct bmp_dib_header *dib_header;
+       void *bgrt_image = NULL;
+       u8 *dst = info->screen_base;
+
+       if (!bgrt_tab.image_address) {
+               pr_info("efifb: No BGRT, not showing boot graphics\n");
+               return;
+       }
+
+       /* Avoid flashing the logo if we're going to print std probe messages */
+       if (console_loglevel > CONSOLE_LOGLEVEL_QUIET)
+               return;
+
+       /* bgrt_tab.status is unreliable, so we don't check it */
+
+       if (si->lfb_depth != 32) {
+               pr_info("efifb: not 32 bits, not showing boot graphics\n");
+               return;
+       }
+
+       bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size,
+                             MEMREMAP_WB);
+       if (!bgrt_image) {
+               pr_warn("efifb: Ignoring BGRT: failed to map image memory\n");
+               return;
+       }
+
+       if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header)))
+               goto error;
+
+       file_header = bgrt_image;
+       if (file_header->id != 0x4d42 || file_header->reserved != 0)
+               goto error;
+
+       dib_header = bgrt_image + sizeof(*file_header);
+       if (dib_header->dib_header_size != 40 || dib_header->width < 0 ||
+           dib_header->planes != 1 || dib_header->bpp != 24 ||
+           dib_header->compression != 0)
+               goto error;
+
+       bmp_width = dib_header->width;
+       bmp_height = abs(dib_header->height);
+       bmp_pitch = round_up(3 * bmp_width, 4);
+       screen_pitch = si->lfb_linelength;
+
+       if ((file_header->bitmap_offset + bmp_pitch * bmp_height) >
+                               bgrt_image_size)
+               goto error;
+
+       if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width ||
+           (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height)
+               goto error;
+
+       if (!efifb_bgrt_sanity_check(si, bmp_width))
+               goto error;
+
+       pr_info("efifb: showing boot graphics\n");
+
+       for (y = 0; y < si->lfb_height; y++, dst += si->lfb_linelength) {
+               /* Only background? */
+               if (y < bgrt_tab.image_offset_y ||
+                   y >= (bgrt_tab.image_offset_y + bmp_height)) {
+                       memset(dst, 0, 4 * si->lfb_width);
+                       continue;
+               }
+
+               src_y = y - bgrt_tab.image_offset_y;
+               /* Positive header height means upside down row order */
+               if (dib_header->height > 0)
+                       src_y = (bmp_height - 1) - src_y;
+
+               memset(dst, 0, bgrt_tab.image_offset_x * 4);
+               dst_x = bgrt_tab.image_offset_x;
+               efifb_copy_bmp(bgrt_image + file_header->bitmap_offset +
+                                           src_y * bmp_pitch,
+                              (u32 *)dst + dst_x, bmp_width, si);
+               dst_x += bmp_width;
+               memset((u32 *)dst + dst_x, 0, (si->lfb_width - dst_x) * 4);
+       }
+
+       memunmap(bgrt_image);
+       return;
+
+error:
+       memunmap(bgrt_image);
+       pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n");
+}
+#else
+static inline void efifb_show_boot_graphics(struct fb_info *info) {}
+#endif
+
 static void efifb_destroy(struct fb_info *info)
 {
        if (info->screen_base) {
@@ -311,6 +492,8 @@ static int efifb_probe(struct platform_device *dev)
                goto err_release_fb;
        }
 
+       efifb_show_boot_graphics(info);
+
        pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n",
               efifb_fix.smem_start, size_remap/1024, size_total/1024);
        pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
index 1bfd13cbd4e3e0ef40a23a5f03404c3e54e7f08a..bc9eb8afc3137dbea13728a9d1bff9fc03bff016 100644 (file)
@@ -360,6 +360,10 @@ struct mfb_info {
  * @ad[]: Area Descriptors for each real AOI
  * @gamma: gamma color table
  * @cursor: hardware cursor data
+ * @blank_cursor: blank cursor for hiding cursor
+ * @next_cursor: scratch space to build load cursor
+ * @edid_data: EDID information buffer
+ * @has_edid: whether or not the EDID buffer is valid
  *
  * This data structure must be allocated with 32-byte alignment, so that the
  * internal fields can be aligned properly.
@@ -381,6 +385,8 @@ struct fsl_diu_data {
        __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);
+       /* Scratch cursor data -- used to build new cursor */
+       __le16 next_cursor[MAX_CURS * MAX_CURS] __aligned(32);
        uint8_t edid_data[EDID_LENGTH];
        bool has_edid;
 } __aligned(32);
@@ -1056,13 +1062,17 @@ static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
         * FB_CUR_SETSHAPE - the cursor bitmask has changed
         */
        if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
+               /*
+                * Determine the size of the cursor image data.  Normally,
+                * it's 8x16.
+                */
                unsigned int image_size =
-                       DIV_ROUND_UP(cursor->image.width, 8) * cursor->image.height;
+                       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;
@@ -1070,13 +1080,6 @@ static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
                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) |
@@ -1088,7 +1091,7 @@ static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
                     1 << 15;
 
                /* Use 32-bit operations on the data to improve performance */
-               image = (uint32_t *)buffer;
+               image = (uint32_t *)data->next_cursor;
                source = (uint32_t *)cursor->image.data;
                mask = (uint32_t *)cursor->mask;
 
index 3b70044773b67566b6c7ebf516bc23dde166f95b..4377e344263878e0c907e89f8d70d43e23796744 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
+#include <linux/acpi.h>
 
 enum {
        FB_GET_WIDTH        = 0x00,
@@ -124,6 +125,7 @@ static int goldfish_fb_check_var(struct fb_var_screeninfo *var,
 static int goldfish_fb_set_par(struct fb_info *info)
 {
        struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb);
+
        if (fb->rotation != fb->fb.var.rotate) {
                info->fix.line_length = info->var.xres * 2;
                fb->rotation = fb->fb.var.rotate;
@@ -148,13 +150,14 @@ static int goldfish_fb_pan_display(struct fb_var_screeninfo *var,
        wait_event_timeout(fb->wait,
                        fb->base_update_count != base_update_count, HZ / 15);
        if (fb->base_update_count == base_update_count)
-               pr_err("goldfish_fb_pan_display: timeout waiting for base update\n");
+               pr_err("%s: timeout waiting for base update\n", __func__);
        return 0;
 }
 
 static int goldfish_fb_blank(int blank, struct fb_info *info)
 {
        struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb);
+
        switch (blank) {
        case FB_BLANK_NORMAL:
                writel(1, fb->reg_base + FB_SET_BLANK);
@@ -234,7 +237,7 @@ static int goldfish_fb_probe(struct platform_device *pdev)
        fb->fb.var.activate     = FB_ACTIVATE_NOW;
        fb->fb.var.height       = readl(fb->reg_base + FB_GET_PHYS_HEIGHT);
        fb->fb.var.width        = readl(fb->reg_base + FB_GET_PHYS_WIDTH);
-       fb->fb.var.pixclock     = 10000;
+       fb->fb.var.pixclock     = 0;
 
        fb->fb.var.red.offset = 11;
        fb->fb.var.red.length = 5;
@@ -301,6 +304,7 @@ static int goldfish_fb_remove(struct platform_device *pdev)
        dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base,
                                                fb->fb.fix.smem_start);
        iounmap(fb->reg_base);
+       kfree(fb);
        return 0;
 }
 
@@ -310,12 +314,19 @@ static const struct of_device_id goldfish_fb_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, goldfish_fb_of_match);
 
+static const struct acpi_device_id goldfish_fb_acpi_match[] = {
+       { "GFSH0004", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, goldfish_fb_acpi_match);
+
 static struct platform_driver goldfish_fb_driver = {
        .probe          = goldfish_fb_probe,
        .remove         = goldfish_fb_remove,
        .driver = {
                .name = "goldfish_fb",
                .of_match_table = goldfish_fb_of_match,
+               .acpi_match_table = ACPI_PTR(goldfish_fb_acpi_match),
        }
 };
 
index 7bc5f6056c77df7cd2293ffd5f4514080a6019b7..f6d7b04d6dffaf222c21277c7e0ecdcca5a2de35 100644 (file)
@@ -429,6 +429,7 @@ static int i740fb_decode_var(const struct fb_var_screeninfo *var,
                break;
        case 9 ... 15:
                bpp = 15;
+               /* fall through */
        case 16:
                if ((1000000 / var->pixclock) > DACSPEED16) {
                        dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n",
index 9085e9525341e8c811e6e1432d4138d5194776a3..bb4fee52e501722c7353d2f81c364bdbc9fb84e3 100644 (file)
@@ -233,7 +233,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t,
 
        /* check temperature range table checksum */
        cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1;
-       if (cksum_idx > size)
+       if (cksum_idx >= size)
                return -EINVAL;
        cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem);
        if (cksum != mem[cksum_idx]) {
@@ -245,7 +245,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t,
        /* check waveform mode table address checksum */
        wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF;
        cksum_idx = wmta + m*4 + 3;
-       if (cksum_idx > size)
+       if (cksum_idx >= size)
                return -EINVAL;
        cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
        if (cksum != mem[cksum_idx]) {
@@ -257,7 +257,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t,
        /* check waveform temperature table address checksum */
        tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF;
        cksum_idx = tta + trn*4 + 3;
-       if (cksum_idx > size)
+       if (cksum_idx >= size)
                return -EINVAL;
        cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
        if (cksum != mem[cksum_idx]) {
@@ -270,7 +270,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t,
        metromem buffer. this does runlength decoding of the waveform */
        wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF;
        owfm_idx = wfm_idx;
-       if (wfm_idx > size)
+       if (wfm_idx >= size)
                return -EINVAL;
        while (wfm_idx < size) {
                unsigned char rl;
@@ -292,7 +292,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t,
        }
 
        cksum_idx = wfm_idx;
-       if (cksum_idx > size)
+       if (cksum_idx >= size)
                return -EINVAL;
        cksum = calc_cksum(owfm_idx, cksum_idx, mem);
        if (cksum != mem[cksum_idx]) {
index 585f39efcff674715575221ce6a3a6ab43c214eb..1c75f4806ed3bda367b1666e98558d9f6d679f00 100644 (file)
@@ -958,7 +958,7 @@ int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
 {
        int r;
 
-       if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM)
+       if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM)
                return -EINVAL;
 
        if (!notifier_inited) {
index 602edfed09dfd85ab6de06a8d5d1214226b98bea..f54c3f56b64137039f8c60d91b1f0ec8036cbda4 100644 (file)
@@ -2,5 +2,5 @@
 obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
 obj-y += dss/
 obj-y += displays/
-obj-$(CONFIG_FB_OMAP2) += omapfb.o
-omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
+obj-$(CONFIG_FB_OMAP2) += omap2fb.o
+omap2fb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
index 3079a3df8c3756a46d528dc8a147508356aae8b0..47f0459e3551b3a493bd94e7ebb26e8ab6cfc622 100644 (file)
@@ -219,7 +219,7 @@ static int tpd_probe_of(struct platform_device *pdev)
 
 static int tpd_probe(struct platform_device *pdev)
 {
-       struct omap_dss_device *in, *dssdev;
+       struct omap_dss_device *dssdev;
        struct panel_drv_data *ddata;
        int r;
        struct gpio_desc *gpio;
@@ -238,25 +238,30 @@ static int tpd_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-
        gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
                GPIOD_OUT_LOW);
-       if (IS_ERR(gpio))
+       if (IS_ERR(gpio)) {
+               r = PTR_ERR(gpio);
                goto err_gpio;
+       }
 
        ddata->ct_cp_hpd_gpio = gpio;
 
        gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
                GPIOD_OUT_LOW);
-       if (IS_ERR(gpio))
+       if (IS_ERR(gpio)) {
+               r = PTR_ERR(gpio);
                goto err_gpio;
+       }
 
        ddata->ls_oe_gpio = gpio;
 
        gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2,
                GPIOD_IN);
-       if (IS_ERR(gpio))
+       if (IS_ERR(gpio)) {
+               r = PTR_ERR(gpio);
                goto err_gpio;
+       }
 
        ddata->hpd_gpio = gpio;
 
@@ -268,8 +273,6 @@ static int tpd_probe(struct platform_device *pdev)
        dssdev->owner = THIS_MODULE;
        dssdev->port_num = 1;
 
-       in = ddata->in;
-
        r = omapdss_register_output(dssdev);
        if (r) {
                dev_err(&pdev->dev, "Failed to register output\n");
index fb605aefd9b1e5359d24e0e607911babe57ff831..a06d9c25765c544bc7efa8da382edecf5943a8e1 100644 (file)
@@ -1858,7 +1858,7 @@ static s32 pixinc(int pixels, u8 ps)
                return 1 - (-pixels + 1) * ps;
        else
                BUG();
-               return 0;
+       return 0;
 }
 
 static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
@@ -1905,6 +1905,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
                if (color_mode == OMAP_DSS_COLOR_YUV2 ||
                        color_mode == OMAP_DSS_COLOR_UYVY)
                        width = width >> 1;
+               /* fall through */
        case OMAP_DSS_ROT_90:
        case OMAP_DSS_ROT_270:
                *offset1 = 0;
@@ -1927,6 +1928,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
                if (color_mode == OMAP_DSS_COLOR_YUV2 ||
                        color_mode == OMAP_DSS_COLOR_UYVY)
                        width = width >> 1;
+               /* fall through */
        case OMAP_DSS_ROT_90 + 4:
        case OMAP_DSS_ROT_270 + 4:
                *offset1 = 0;
index 3e7887c53d7c2bdb0a34123d4c81319f3ff1893d..b8b5b4ac0e09cf2195212cda09e4b0f24f27cb5c 100644 (file)
@@ -893,6 +893,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
                                / (var->bits_per_pixel >> 2);
                        break;
                }
+               /* fall through */
        default:
                screen_width = fix->line_length / (var->bits_per_pixel >> 3);
                break;
index bd6c2f5f6095d585b486399dcb19da50fd3c0c7b..1dcf02e12af4f3ee676bd7be8e4f59b71f864c21 100644 (file)
@@ -233,8 +233,10 @@ static u32 to3264(u32 timing, int bpp, int is64)
        switch (bpp) {
        case 24:
                timing *= 3;
+               /* fall through */
        case 8:
                timing >>= 1;
+               /* fall through */
        case 16:
                timing >>= 1;
        case 32:
index 0955622a12270266fd7c82ee1b0ff3d5bf015f43..69cfb337c8577ac1ca8f3eede0eeba7e1ec10087 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/clk.h>
 #include <linux/fs.h>
 #include <linux/io.h>
+#include <linux/of.h>
 
 #include "pxa3xx-gcu.h"
 
@@ -703,11 +704,20 @@ static int pxa3xx_gcu_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id pxa3xx_gcu_of_match[] = {
+       { .compatible = "marvell,pxa300-gcu", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pxa3xx_gcu_of_match);
+#endif
+
 static struct platform_driver pxa3xx_gcu_driver = {
        .probe    = pxa3xx_gcu_probe,
        .remove  = pxa3xx_gcu_remove,
        .driver  = {
                .name   = DRV_NAME,
+               .of_match_table = of_match_ptr(pxa3xx_gcu_of_match),
        },
 };
 
index 76722a59f55e34c83ec948d77c2c0df5c936fa16..bbed039617a4259b0517cb09e1f88676158ad8eb 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/freezer.h>
 #include <linux/console.h>
 #include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
 #include <video/of_display_timing.h>
 #include <video/videomode.h>
 
@@ -1423,6 +1424,21 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
 
        if (fbi->lcd_power)
                fbi->lcd_power(on, &fbi->fb.var);
+
+       if (fbi->lcd_supply && fbi->lcd_supply_enabled != on) {
+               int ret;
+
+               if (on)
+                       ret = regulator_enable(fbi->lcd_supply);
+               else
+                       ret = regulator_disable(fbi->lcd_supply);
+
+               if (ret < 0)
+                       pr_warn("Unable to %s LCD supply regulator: %d\n",
+                               on ? "enable" : "disable", ret);
+               else
+                       fbi->lcd_supply_enabled = on;
+       }
 }
 
 static void pxafb_enable_controller(struct pxafb_info *fbi)
@@ -1799,19 +1815,17 @@ static struct pxafb_info *pxafb_init_fbinfo(struct device *dev,
        void *addr;
 
        /* Alloc the pxafb_info and pseudo_palette in one step */
-       fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
+       fbi = devm_kzalloc(dev, sizeof(struct pxafb_info) + sizeof(u32) * 16,
+                          GFP_KERNEL);
        if (!fbi)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
-       memset(fbi, 0, sizeof(struct pxafb_info));
        fbi->dev = dev;
        fbi->inf = inf;
 
-       fbi->clk = clk_get(dev, NULL);
-       if (IS_ERR(fbi->clk)) {
-               kfree(fbi);
-               return NULL;
-       }
+       fbi->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(fbi->clk))
+               return ERR_CAST(fbi->clk);
 
        strcpy(fbi->fb.fix.id, PXA_NAME);
 
@@ -2128,8 +2142,9 @@ static int of_get_pxafb_display(struct device *dev, struct device_node *disp,
                return -EINVAL;
 
        ret = -ENOMEM;
-       info->modes = kmalloc_array(timings->num_timings,
-                                   sizeof(info->modes[0]), GFP_KERNEL);
+       info->modes = devm_kcalloc(dev, timings->num_timings,
+                                  sizeof(info->modes[0]),
+                                  GFP_KERNEL);
        if (!info->modes)
                goto out;
        info->num_modes = timings->num_timings;
@@ -2288,10 +2303,9 @@ static int pxafb_probe(struct platform_device *dev)
        }
 
        fbi = pxafb_init_fbinfo(&dev->dev, inf);
-       if (!fbi) {
-               /* only reason for pxafb_init_fbinfo to fail is kmalloc */
+       if (IS_ERR(fbi)) {
                dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(fbi);
                goto failed;
        }
 
@@ -2301,25 +2315,26 @@ static int pxafb_probe(struct platform_device *dev)
        fbi->backlight_power = inf->pxafb_backlight_power;
        fbi->lcd_power = inf->pxafb_lcd_power;
 
+       fbi->lcd_supply = devm_regulator_get_optional(&dev->dev, "lcd");
+       if (IS_ERR(fbi->lcd_supply)) {
+               if (PTR_ERR(fbi->lcd_supply) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               fbi->lcd_supply = NULL;
+       }
+
        r = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (r == NULL) {
                dev_err(&dev->dev, "no I/O memory resource defined\n");
                ret = -ENODEV;
-               goto failed_fbi;
-       }
-
-       r = request_mem_region(r->start, resource_size(r), dev->name);
-       if (r == NULL) {
-               dev_err(&dev->dev, "failed to request I/O memory\n");
-               ret = -EBUSY;
-               goto failed_fbi;
+               goto failed;
        }
 
-       fbi->mmio_base = ioremap(r->start, resource_size(r));
-       if (fbi->mmio_base == NULL) {
-               dev_err(&dev->dev, "failed to map I/O memory\n");
+       fbi->mmio_base = devm_ioremap_resource(&dev->dev, r);
+       if (IS_ERR(fbi->mmio_base)) {
+               dev_err(&dev->dev, "failed to get I/O memory\n");
                ret = -EBUSY;
-               goto failed_free_res;
+               goto failed;
        }
 
        fbi->dma_buff_size = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
@@ -2328,7 +2343,7 @@ static int pxafb_probe(struct platform_device *dev)
        if (fbi->dma_buff == NULL) {
                dev_err(&dev->dev, "failed to allocate memory for DMA\n");
                ret = -ENOMEM;
-               goto failed_free_io;
+               goto failed;
        }
 
        ret = pxafb_init_video_memory(fbi);
@@ -2345,7 +2360,7 @@ static int pxafb_probe(struct platform_device *dev)
                goto failed_free_mem;
        }
 
-       ret = request_irq(irq, pxafb_handle_irq, 0, "LCD", fbi);
+       ret = devm_request_irq(&dev->dev, irq, pxafb_handle_irq, 0, "LCD", fbi);
        if (ret) {
                dev_err(&dev->dev, "request_irq failed: %d\n", ret);
                ret = -EBUSY;
@@ -2355,7 +2370,7 @@ static int pxafb_probe(struct platform_device *dev)
        ret = pxafb_smart_init(fbi);
        if (ret) {
                dev_err(&dev->dev, "failed to initialize smartpanel\n");
-               goto failed_free_irq;
+               goto failed_free_mem;
        }
 
        /*
@@ -2365,13 +2380,13 @@ static int pxafb_probe(struct platform_device *dev)
        ret = pxafb_check_var(&fbi->fb.var, &fbi->fb);
        if (ret) {
                dev_err(&dev->dev, "failed to get suitable mode\n");
-               goto failed_free_irq;
+               goto failed_free_mem;
        }
 
        ret = pxafb_set_par(&fbi->fb);
        if (ret) {
                dev_err(&dev->dev, "Failed to set parameters\n");
-               goto failed_free_irq;
+               goto failed_free_mem;
        }
 
        platform_set_drvdata(dev, fbi);
@@ -2404,20 +2419,11 @@ static int pxafb_probe(struct platform_device *dev)
 failed_free_cmap:
        if (fbi->fb.cmap.len)
                fb_dealloc_cmap(&fbi->fb.cmap);
-failed_free_irq:
-       free_irq(irq, fbi);
 failed_free_mem:
        free_pages_exact(fbi->video_mem, fbi->video_mem_size);
 failed_free_dma:
        dma_free_coherent(&dev->dev, fbi->dma_buff_size,
                        fbi->dma_buff, fbi->dma_buff_phys);
-failed_free_io:
-       iounmap(fbi->mmio_base);
-failed_free_res:
-       release_mem_region(r->start, resource_size(r));
-failed_fbi:
-       clk_put(fbi->clk);
-       kfree(fbi);
 failed:
        return ret;
 }
@@ -2425,8 +2431,6 @@ failed:
 static int pxafb_remove(struct platform_device *dev)
 {
        struct pxafb_info *fbi = platform_get_drvdata(dev);
-       struct resource *r;
-       int irq;
        struct fb_info *info;
 
        if (!fbi)
@@ -2442,22 +2446,11 @@ static int pxafb_remove(struct platform_device *dev)
        if (fbi->fb.cmap.len)
                fb_dealloc_cmap(&fbi->fb.cmap);
 
-       irq = platform_get_irq(dev, 0);
-       free_irq(irq, fbi);
-
        free_pages_exact(fbi->video_mem, fbi->video_mem_size);
 
        dma_free_wc(&dev->dev, fbi->dma_buff_size, fbi->dma_buff,
                    fbi->dma_buff_phys);
 
-       iounmap(fbi->mmio_base);
-
-       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       release_mem_region(r->start, resource_size(r));
-
-       clk_put(fbi->clk);
-       kfree(fbi);
-
        return 0;
 }
 
index 5dc414e26fc84b2e02ba490b911a215c4f2c3694..b641289c8a99133e13bff44be0a540f6261339fc 100644 (file)
@@ -165,6 +165,9 @@ struct pxafb_info {
        struct notifier_block   freq_policy;
 #endif
 
+       struct regulator *lcd_supply;
+       bool lcd_supply_enabled;
+
        void (*lcd_power)(int, struct fb_var_screeninfo *);
        void (*backlight_power)(int);
 
index a3c44ecf4523e8edb6d64c45a89f574924453d7f..9a9d748b07f2777da666a2ecfc8fcd35738f1505 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
-#include <linux/clk-provider.h>
 #include <linux/of.h>
+#include <linux/of_clk.h>
 #include <linux/of_platform.h>
 #include <linux/parser.h>
 #include <linux/regulator/consumer.h>
index dec1fed9880eaa75b6d3dcf3bb6bbb24bed454f4..fbbf26b170f7857b7b3772346b5255c192c5558c 100644 (file)
@@ -522,6 +522,7 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        case 32:
                var->transp.offset = 24;
                var->transp.length = 8;
+               /* fall through */
        case 24:
                var->red.offset = 16;
                var->green.offset = 8;
index 284706184b1b67bdd28395fc97213baf844b58c2..f4b74559060087e3e6a1fdf4af88dbcd5e6adaed 100644 (file)
@@ -777,9 +777,6 @@ static int get_nativex(struct tridentfb_par *par)
        case 3:
                x = 800; y = 600;
                break;
-       case 4:
-               x = 1400; y = 1050;
-               break;
        case 1:
        default:
                x = 640;  y = 480;
index f365d4862015321e9ad8f2efdc072877e505a409..afbd6101c78eb4c0b87a4c6a8a4cce47cf474176 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/fb.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
-#include <linux/prefetch.h>
 #include <linux/delay.h>
+#include <asm/unaligned.h>
 #include <video/udlfb.h>
 #include "edid.h"
 
@@ -72,6 +72,13 @@ static bool fb_defio = 1;  /* Detect mmap writes using page faults */
 static bool shadow = 1; /* Optionally disable shadow framebuffer */
 static int pixel_limit; /* Optionally force a pixel resolution limit */
 
+struct dlfb_deferred_free {
+       struct list_head list;
+       void *mem;
+};
+
+static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info, u32 new_len);
+
 /* dlfb keeps a list of urbs for efficient bulk transfers */
 static void dlfb_urb_completion(struct urb *urb);
 static struct urb *dlfb_get_urb(struct dlfb_data *dlfb);
@@ -367,9 +374,6 @@ static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
        int start = width;
        int end = width;
 
-       prefetch((void *) front);
-       prefetch((void *) back);
-
        for (j = 0; j < width; j++) {
                if (back[j] != front[j]) {
                        start = j;
@@ -423,7 +427,9 @@ static void dlfb_compress_hline(
        const uint16_t *const pixel_end,
        uint32_t *device_address_ptr,
        uint8_t **command_buffer_ptr,
-       const uint8_t *const cmd_buffer_end)
+       const uint8_t *const cmd_buffer_end,
+       unsigned long back_buffer_offset,
+       int *ident_ptr)
 {
        const uint16_t *pixel = *pixel_start_ptr;
        uint32_t dev_addr  = *device_address_ptr;
@@ -436,7 +442,13 @@ static void dlfb_compress_hline(
                const uint16_t *raw_pixel_start = NULL;
                const uint16_t *cmd_pixel_start, *cmd_pixel_end = NULL;
 
-               prefetchw((void *) cmd); /* pull in one cache line at least */
+               if (back_buffer_offset &&
+                   *pixel == *(u16 *)((u8 *)pixel + back_buffer_offset)) {
+                       pixel++;
+                       dev_addr += BPP;
+                       (*ident_ptr)++;
+                       continue;
+               }
 
                *cmd++ = 0xAF;
                *cmd++ = 0x6B;
@@ -450,29 +462,39 @@ static void dlfb_compress_hline(
                raw_pixels_count_byte = cmd++; /*  we'll know this later */
                raw_pixel_start = pixel;
 
-               cmd_pixel_end = pixel + min(MAX_CMD_PIXELS + 1,
-                       min((int)(pixel_end - pixel),
-                           (int)(cmd_buffer_end - cmd) / BPP));
+               cmd_pixel_end = pixel + min3(MAX_CMD_PIXELS + 1UL,
+                                       (unsigned long)(pixel_end - pixel),
+                                       (unsigned long)(cmd_buffer_end - 1 - cmd) / BPP);
 
-               prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * BPP);
+               if (back_buffer_offset) {
+                       /* note: the framebuffer may change under us, so we must test for underflow */
+                       while (cmd_pixel_end - 1 > pixel &&
+                              *(cmd_pixel_end - 1) == *(u16 *)((u8 *)(cmd_pixel_end - 1) + back_buffer_offset))
+                               cmd_pixel_end--;
+               }
 
                while (pixel < cmd_pixel_end) {
                        const uint16_t * const repeating_pixel = pixel;
+                       u16 pixel_value = *pixel;
 
-                       *cmd++ = *pixel >> 8;
-                       *cmd++ = *pixel;
+                       put_unaligned_be16(pixel_value, cmd);
+                       if (back_buffer_offset)
+                               *(u16 *)((u8 *)pixel + back_buffer_offset) = pixel_value;
+                       cmd += 2;
                        pixel++;
 
                        if (unlikely((pixel < cmd_pixel_end) &&
-                                    (*pixel == *repeating_pixel))) {
+                                    (*pixel == pixel_value))) {
                                /* go back and fill in raw pixel count */
                                *raw_pixels_count_byte = ((repeating_pixel -
                                                raw_pixel_start) + 1) & 0xFF;
 
-                               while ((pixel < cmd_pixel_end)
-                                      && (*pixel == *repeating_pixel)) {
+                               do {
+                                       if (back_buffer_offset)
+                                               *(u16 *)((u8 *)pixel + back_buffer_offset) = pixel_value;
                                        pixel++;
-                               }
+                               } while ((pixel < cmd_pixel_end) &&
+                                        (*pixel == pixel_value));
 
                                /* immediately after raw data is repeat byte */
                                *cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF;
@@ -486,13 +508,16 @@ static void dlfb_compress_hline(
                if (pixel > raw_pixel_start) {
                        /* finalize last RAW span */
                        *raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF;
+               } else {
+                       /* undo unused byte */
+                       cmd--;
                }
 
                *cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF;
-               dev_addr += (pixel - cmd_pixel_start) * BPP;
+               dev_addr += (u8 *)pixel - (u8 *)cmd_pixel_start;
        }
 
-       if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
+       if (cmd_buffer_end - MIN_RLX_CMD_BYTES <= cmd) {
                /* Fill leftover bytes with no-ops */
                if (cmd_buffer_end > cmd)
                        memset(cmd, 0xAF, cmd_buffer_end - cmd);
@@ -520,6 +545,7 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr,
        struct urb *urb = *urb_ptr;
        u8 *cmd = *urb_buf_ptr;
        u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
+       unsigned long back_buffer_offset = 0;
 
        line_start = (u8 *) (front + byte_offset);
        next_pixel = line_start;
@@ -530,6 +556,8 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr,
                const u8 *back_start = (u8 *) (dlfb->backing_buffer
                                                + byte_offset);
 
+               back_buffer_offset = (unsigned long)back_start - (unsigned long)line_start;
+
                *ident_ptr += dlfb_trim_hline(back_start, &next_pixel,
                        &byte_width);
 
@@ -538,16 +566,14 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr,
                dev_addr += offset;
                back_start += offset;
                line_start += offset;
-
-               memcpy((char *)back_start, (char *) line_start,
-                      byte_width);
        }
 
        while (next_pixel < line_end) {
 
                dlfb_compress_hline((const uint16_t **) &next_pixel,
                             (const uint16_t *) line_end, &dev_addr,
-                       (u8 **) &cmd, (u8 *) cmd_end);
+                       (u8 **) &cmd, (u8 *) cmd_end, back_buffer_offset,
+                       ident_ptr);
 
                if (cmd >= cmd_end) {
                        int len = cmd - (u8 *) urb->transfer_buffer;
@@ -610,8 +636,11 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y,
        }
 
        if (cmd > (char *) urb->transfer_buffer) {
+               int len;
+               if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length)
+                       *cmd++ = 0xAF;
                /* Send partial buffer remaining before exiting */
-               int len = cmd - (char *) urb->transfer_buffer;
+               len = cmd - (char *) urb->transfer_buffer;
                ret = dlfb_submit_urb(dlfb, urb, len);
                bytes_sent += len;
        } else
@@ -735,8 +764,11 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
        }
 
        if (cmd > (char *) urb->transfer_buffer) {
+               int len;
+               if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length)
+                       *cmd++ = 0xAF;
                /* Send partial buffer remaining before exiting */
-               int len = cmd - (char *) urb->transfer_buffer;
+               len = cmd - (char *) urb->transfer_buffer;
                dlfb_submit_urb(dlfb, urb, len);
                bytes_sent += len;
        } else
@@ -917,19 +949,17 @@ static void dlfb_free(struct kref *kref)
 {
        struct dlfb_data *dlfb = container_of(kref, struct dlfb_data, kref);
 
+       while (!list_empty(&dlfb->deferred_free)) {
+               struct dlfb_deferred_free *d = list_entry(dlfb->deferred_free.next, struct dlfb_deferred_free, list);
+               list_del(&d->list);
+               vfree(d->mem);
+               kfree(d);
+       }
        vfree(dlfb->backing_buffer);
        kfree(dlfb->edid);
        kfree(dlfb);
 }
 
-static void dlfb_release_urb_work(struct work_struct *work)
-{
-       struct urb_node *unode = container_of(work, struct urb_node,
-                                             release_urb_work.work);
-
-       up(&unode->dlfb->urbs.limit_sem);
-}
-
 static void dlfb_free_framebuffer(struct dlfb_data *dlfb)
 {
        struct fb_info *info = dlfb->info;
@@ -1018,10 +1048,6 @@ static int dlfb_ops_check_var(struct fb_var_screeninfo *var,
        struct fb_videomode mode;
        struct dlfb_data *dlfb = info->par;
 
-       /* TODO: support dynamically changing framebuffer size */
-       if ((var->xres * var->yres * 2) > info->fix.smem_len)
-               return -EINVAL;
-
        /* set device-specific elements of var unrelated to mode */
        dlfb_var_color_format(var);
 
@@ -1039,22 +1065,42 @@ static int dlfb_ops_set_par(struct fb_info *info)
        int result;
        u16 *pix_framebuffer;
        int i;
+       struct fb_var_screeninfo fvs;
+       u32 line_length = info->var.xres * (info->var.bits_per_pixel / 8);
+
+       /* clear the activate field because it causes spurious miscompares */
+       fvs = info->var;
+       fvs.activate = 0;
+       fvs.vmode &= ~FB_VMODE_SMOOTH_XPAN;
+
+       if (!memcmp(&dlfb->current_mode, &fvs, sizeof(struct fb_var_screeninfo)))
+               return 0;
+
+       result = dlfb_realloc_framebuffer(dlfb, info, info->var.yres * line_length);
+       if (result)
+               return result;
 
        result = dlfb_set_video_mode(dlfb, &info->var);
 
-       if ((result == 0) && (dlfb->fb_count == 0)) {
+       if (result)
+               return result;
+
+       dlfb->current_mode = fvs;
+       info->fix.line_length = line_length;
+
+       if (dlfb->fb_count == 0) {
 
                /* paint greenscreen */
 
                pix_framebuffer = (u16 *) info->screen_base;
                for (i = 0; i < info->fix.smem_len / 2; i++)
                        pix_framebuffer[i] = 0x37e6;
-
-               dlfb_handle_damage(dlfb, 0, 0, info->var.xres, info->var.yres,
-                                  info->screen_base);
        }
 
-       return result;
+       dlfb_handle_damage(dlfb, 0, 0, info->var.xres, info->var.yres,
+                          info->screen_base);
+
+       return 0;
 }
 
 /* To fonzi the jukebox (e.g. make blanking changes take effect) */
@@ -1129,21 +1175,29 @@ static struct fb_ops dlfb_ops = {
 };
 
 
+static void dlfb_deferred_vfree(struct dlfb_data *dlfb, void *mem)
+{
+       struct dlfb_deferred_free *d = kmalloc(sizeof(struct dlfb_deferred_free), GFP_KERNEL);
+       if (!d)
+               return;
+       d->mem = mem;
+       list_add(&d->list, &dlfb->deferred_free);
+}
+
 /*
  * Assumes &info->lock held by caller
  * Assumes no active clients have framebuffer open
  */
-static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info)
+static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info, u32 new_len)
 {
-       int old_len = info->fix.smem_len;
-       int new_len;
-       unsigned char *old_fb = info->screen_base;
+       u32 old_len = info->fix.smem_len;
+       const void *old_fb = (const void __force *)info->screen_base;
        unsigned char *new_fb;
        unsigned char *new_back = NULL;
 
-       new_len = info->fix.line_length * info->var.yres;
+       new_len = PAGE_ALIGN(new_len);
 
-       if (PAGE_ALIGN(new_len) > old_len) {
+       if (new_len > old_len) {
                /*
                 * Alloc system memory for virtual framebuffer
                 */
@@ -1152,14 +1206,15 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info
                        dev_err(info->dev, "Virtual framebuffer alloc failed\n");
                        return -ENOMEM;
                }
+               memset(new_fb, 0xff, new_len);
 
                if (info->screen_base) {
                        memcpy(new_fb, old_fb, old_len);
-                       vfree(info->screen_base);
+                       dlfb_deferred_vfree(dlfb, (void __force *)info->screen_base);
                }
 
-               info->screen_base = new_fb;
-               info->fix.smem_len = PAGE_ALIGN(new_len);
+               info->screen_base = (char __iomem *)new_fb;
+               info->fix.smem_len = new_len;
                info->fix.smem_start = (unsigned long) new_fb;
                info->flags = udlfb_info_flags;
 
@@ -1175,7 +1230,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info
                        dev_info(info->dev,
                                 "No shadow/backing buffer allocated\n");
                else {
-                       vfree(dlfb->backing_buffer);
+                       dlfb_deferred_vfree(dlfb, dlfb->backing_buffer);
                        dlfb->backing_buffer = new_back;
                }
        }
@@ -1327,11 +1382,6 @@ static int dlfb_setup_modes(struct dlfb_data *dlfb,
                 * with mode size info, we can now alloc our framebuffer.
                 */
                memcpy(&info->fix, &dlfb_fix, sizeof(dlfb_fix));
-               info->fix.line_length = info->var.xres *
-                       (info->var.bits_per_pixel / 8);
-
-               result = dlfb_realloc_framebuffer(dlfb, info);
-
        } else
                result = -EINVAL;
 
@@ -1419,7 +1469,10 @@ static ssize_t edid_store(
        if (!dlfb->edid || memcmp(src, dlfb->edid, src_size))
                return -EINVAL;
 
-       dlfb_ops_set_par(fb_info);
+       ret = dlfb_ops_set_par(fb_info);
+       if (ret)
+               return ret;
+
        return src_size;
 }
 
@@ -1579,6 +1632,7 @@ static int dlfb_usb_probe(struct usb_interface *intf,
        }
 
        kref_init(&dlfb->kref); /* matching kref_put in usb .disconnect fn */
+       INIT_LIST_HEAD(&dlfb->deferred_free);
 
        dlfb->udev = usbdev;
        usb_set_intfdata(intf, dlfb);
@@ -1649,7 +1703,8 @@ static void dlfb_init_framebuffer_work(struct work_struct *work)
        dlfb->info = info;
        info->par = dlfb;
        info->pseudo_palette = dlfb->pseudo_palette;
-       info->fbops = &dlfb_ops;
+       dlfb->ops = dlfb_ops;
+       info->fbops = &dlfb->ops;
 
        retval = fb_alloc_cmap(&info->cmap, 256, 0);
        if (retval < 0) {
@@ -1675,7 +1730,9 @@ static void dlfb_init_framebuffer_work(struct work_struct *work)
        dlfb_select_std_channel(dlfb);
 
        dlfb_ops_check_var(&info->var, info);
-       dlfb_ops_set_par(info);
+       retval = dlfb_ops_set_par(info);
+       if (retval)
+               goto error;
 
        retval = register_framebuffer(info);
        if (retval < 0) {
@@ -1789,14 +1846,7 @@ static void dlfb_urb_completion(struct urb *urb)
        dlfb->urbs.available++;
        spin_unlock_irqrestore(&dlfb->urbs.lock, flags);
 
-       /*
-        * When using fb_defio, we deadlock if up() is called
-        * while another is waiting. So queue to another process.
-        */
-       if (fb_defio)
-               schedule_delayed_work(&unode->release_urb_work, 0);
-       else
-               up(&dlfb->urbs.limit_sem);
+       up(&dlfb->urbs.limit_sem);
 }
 
 static void dlfb_free_urb_list(struct dlfb_data *dlfb)
@@ -1805,23 +1855,17 @@ static void dlfb_free_urb_list(struct dlfb_data *dlfb)
        struct list_head *node;
        struct urb_node *unode;
        struct urb *urb;
-       int ret;
-       unsigned long flags;
 
        /* keep waiting and freeing, until we've got 'em all */
        while (count--) {
+               down(&dlfb->urbs.limit_sem);
 
-               /* Getting interrupted means a leak, but ok at disconnect */
-               ret = down_interruptible(&dlfb->urbs.limit_sem);
-               if (ret)
-                       break;
-
-               spin_lock_irqsave(&dlfb->urbs.lock, flags);
+               spin_lock_irq(&dlfb->urbs.lock);
 
                node = dlfb->urbs.list.next; /* have reserved one with sem */
                list_del_init(node);
 
-               spin_unlock_irqrestore(&dlfb->urbs.lock, flags);
+               spin_unlock_irq(&dlfb->urbs.lock);
 
                unode = list_entry(node, struct urb_node, entry);
                urb = unode->urb;
@@ -1838,25 +1882,27 @@ static void dlfb_free_urb_list(struct dlfb_data *dlfb)
 
 static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size)
 {
-       int i = 0;
        struct urb *urb;
        struct urb_node *unode;
        char *buf;
+       size_t wanted_size = count * size;
 
        spin_lock_init(&dlfb->urbs.lock);
 
+retry:
        dlfb->urbs.size = size;
        INIT_LIST_HEAD(&dlfb->urbs.list);
 
-       while (i < count) {
+       sema_init(&dlfb->urbs.limit_sem, 0);
+       dlfb->urbs.count = 0;
+       dlfb->urbs.available = 0;
+
+       while (dlfb->urbs.count * size < wanted_size) {
                unode = kzalloc(sizeof(*unode), GFP_KERNEL);
                if (!unode)
                        break;
                unode->dlfb = dlfb;
 
-               INIT_DELAYED_WORK(&unode->release_urb_work,
-                         dlfb_release_urb_work);
-
                urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!urb) {
                        kfree(unode);
@@ -1864,11 +1910,16 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size)
                }
                unode->urb = urb;
 
-               buf = usb_alloc_coherent(dlfb->udev, MAX_TRANSFER, GFP_KERNEL,
+               buf = usb_alloc_coherent(dlfb->udev, size, GFP_KERNEL,
                                         &urb->transfer_dma);
                if (!buf) {
                        kfree(unode);
                        usb_free_urb(urb);
+                       if (size > PAGE_SIZE) {
+                               size /= 2;
+                               dlfb_free_urb_list(dlfb);
+                               goto retry;
+                       }
                        break;
                }
 
@@ -1879,14 +1930,12 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size)
 
                list_add_tail(&unode->entry, &dlfb->urbs.list);
 
-               i++;
+               up(&dlfb->urbs.limit_sem);
+               dlfb->urbs.count++;
+               dlfb->urbs.available++;
        }
 
-       sema_init(&dlfb->urbs.limit_sem, i);
-       dlfb->urbs.count = i;
-       dlfb->urbs.available = i;
-
-       return i;
+       return dlfb->urbs.count;
 }
 
 static struct urb *dlfb_get_urb(struct dlfb_data *dlfb)
@@ -1894,7 +1943,6 @@ static struct urb *dlfb_get_urb(struct dlfb_data *dlfb)
        int ret;
        struct list_head *entry;
        struct urb_node *unode;
-       unsigned long flags;
 
        /* Wait for an in-flight buffer to complete and get re-queued */
        ret = down_timeout(&dlfb->urbs.limit_sem, GET_URB_TIMEOUT);
@@ -1906,14 +1954,14 @@ static struct urb *dlfb_get_urb(struct dlfb_data *dlfb)
                return NULL;
        }
 
-       spin_lock_irqsave(&dlfb->urbs.lock, flags);
+       spin_lock_irq(&dlfb->urbs.lock);
 
        BUG_ON(list_empty(&dlfb->urbs.list)); /* reserved one with limit_sem */
        entry = dlfb->urbs.list.next;
        list_del_init(entry);
        dlfb->urbs.available--;
 
-       spin_unlock_irqrestore(&dlfb->urbs.lock, flags);
+       spin_unlock_irq(&dlfb->urbs.lock);
 
        unode = list_entry(entry, struct urb_node, entry);
        return unode->urb;
index 5d21ff436ec80a313dc9133a22b1db08ab7006ae..b9305d73a1e5ada2d74d4dda8cde74b6c25a46e6 100644 (file)
@@ -758,6 +758,7 @@ static void set_lcd_output_path(int set_iga, int output_interface)
                    viaparinfo->chip_info->gfx_chip_name))
                        viafb_write_reg_mask(CR97, VIACR, 0x84,
                                       BIT7 + BIT2 + BIT1 + BIT0);
+               /* fall through */
        case INTERFACE_DVP0:
        case INTERFACE_DVP1:
        case INTERFACE_DFP_HIGH:
index d2f785068ef4bb97fbc7228a684eae00d0688280..7bb7e90b8f006f28548da5ed6b4944ee0f9131e6 100644 (file)
@@ -19,6 +19,7 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
@@ -1468,7 +1469,7 @@ static const struct file_operations viafb_vt1636_proc_fops = {
 
 #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
 
-static int viafb_sup_odev_proc_show(struct seq_file *m, void *v)
+static int __maybe_unused viafb_sup_odev_proc_show(struct seq_file *m, void *v)
 {
        via_odev_to_seq(m, supported_odev_map[
                viaparinfo->shared->chip_info.gfx_chip_name]);
index f59f3dbca65cb02d257ca0f1cf69f508200d508e..ec9bdb3d7bab6368a1ef7fb6598d70e0a5720a6d 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef _LINUX_CONSOLE_H_
 #define _LINUX_CONSOLE_H_ 1
 
+#include <linux/atomic.h>
 #include <linux/types.h>
 
 struct vc_data;
@@ -201,11 +202,14 @@ void vcs_make_sysfs(int index);
 void vcs_remove_sysfs(int index);
 
 /* Some debug stub to catch some of the obvious races in the VT code */
-#if 1
-#define WARN_CONSOLE_UNLOCKED()        WARN_ON(!is_console_locked() && !oops_in_progress)
-#else
-#define WARN_CONSOLE_UNLOCKED()
-#endif
+#define WARN_CONSOLE_UNLOCKED()                                                \
+       WARN_ON(!atomic_read(&ignore_console_lock_warning) &&           \
+               !is_console_locked() && !oops_in_progress)
+/*
+ * Increment ignore_console_lock_warning if you need to quiet
+ * WARN_CONSOLE_UNLOCKED() for debugging purposes.
+ */
+extern atomic_t ignore_console_lock_warning;
 
 /* VESA Blanking Levels */
 #define VESA_NO_BLANKING        0
index aa74a228bb92ec90885ce57f0957b1d8f58903e4..3e7e75383d327d2dbd2e81410033cd26c193e003 100644 (file)
@@ -126,7 +126,7 @@ struct fb_cursor_user {
 
 /*     The resolution of the passed in fb_info about to change */ 
 #define FB_EVENT_MODE_CHANGE           0x01
-/*     The display on this fb_info is beeing suspended, no access to the
+/*     The display on this fb_info is being suspended, no access to the
  *     framebuffer is allowed any more after that call returns
  */
 #define FB_EVENT_SUSPEND               0x02
@@ -159,9 +159,9 @@ struct fb_cursor_user {
 #define FB_EVENT_FB_UNBIND              0x0E
 /*      CONSOLE-SPECIFIC: remap all consoles to new fb - for vga_switcheroo */
 #define FB_EVENT_REMAP_ALL_CONSOLE      0x0F
-/*      A hardware display blank early change occured */
+/*      A hardware display blank early change occurred */
 #define FB_EARLY_EVENT_BLANK           0x10
-/*      A hardware display blank revert early change occured */
+/*      A hardware display blank revert early change occurred */
 #define FB_R_EARLY_EVENT_BLANK         0x11
 
 struct fb_event {
@@ -650,6 +650,10 @@ extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
 extern struct class *fb_class;
 
+#define for_each_registered_fb(i)              \
+       for (i = 0; i < FB_MAX; i++)            \
+               if (!registered_fb[i]) {} else
+
 extern int lock_fb_info(struct fb_info *info);
 
 static inline void unlock_fb_info(struct fb_info *info)
index 0cabe6b090954bd18ea2f246201a393f4a12a9f5..3abd327bada64c0fd089131192edcb88da26e916 100644 (file)
@@ -20,7 +20,6 @@ struct dloarea {
 struct urb_node {
        struct list_head entry;
        struct dlfb_data *dlfb;
-       struct delayed_work release_urb_work;
        struct urb *urb;
 };
 
@@ -52,11 +51,14 @@ struct dlfb_data {
        int base8;
        u32 pseudo_palette[256];
        int blank_mode; /*one of FB_BLANK_ */
+       struct fb_ops ops;
        /* blit-only rendering path metrics, exposed through sysfs */
        atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
        atomic_t bytes_identical; /* saved effort with backbuffer comparison */
        atomic_t bytes_sent; /* to usb, after compression including overhead */
        atomic_t cpu_kcycles_used; /* transpired during pixel processing */
+       struct fb_var_screeninfo current_mode;
+       struct list_head deferred_free;
 };
 
 #define NR_USB_REQUEST_I2C_SUB_IO 0x02
@@ -87,7 +89,7 @@ struct dlfb_data {
 #define MIN_RAW_PIX_BYTES      2
 #define MIN_RAW_CMD_BYTES      (RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
 
-#define DL_DEFIO_WRITE_DELAY    5 /* fb_deferred_io.delay in jiffies */
+#define DL_DEFIO_WRITE_DELAY    msecs_to_jiffies(HZ <= 300 ? 4 : 10) /* optimal value for 720p video */
 #define DL_DEFIO_WRITE_DISABLE  (HZ*60) /* "disable" with long delay */
 
 /* remove these once align.h patch is taken into kernel */
index 918f386b2f6ea7619878c927272a6d3920631a4e..924e37fb1620b5440e3265b4cc3465dad50475c1 100644 (file)
@@ -66,6 +66,9 @@ int console_printk[4] = {
        CONSOLE_LOGLEVEL_DEFAULT,       /* default_console_loglevel */
 };
 
+atomic_t ignore_console_lock_warning __read_mostly = ATOMIC_INIT(0);
+EXPORT_SYMBOL(ignore_console_lock_warning);
+
 /*
  * Low level drivers may need that to know if they can schedule in
  * their unblank() callback or not. So let's export it.