Merge tag 'fbdev-updates-for-3.5' of git://github.com/schandinat/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Jun 2012 23:57:51 +0000 (16:57 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Jun 2012 23:57:51 +0000 (16:57 -0700)
Pull fbdev updates from Florian Tobias Schandinat:
 - driver for AUO-K1900 and AUO-K1901 epaper controller
 - large updates for OMAP (e.g. decouple HDMI audio and video)
 - some updates for Exynos and SH Mobile
 - various other small fixes and cleanups

* tag 'fbdev-updates-for-3.5' of git://github.com/schandinat/linux-2.6: (130 commits)
  video: bfin_adv7393fb: Fix cleanup code
  video: exynos_dp: reduce delay time when configuring video setting
  video: exynos_dp: move sw reset prioir to enabling sw defined function
  video: exynos_dp: use devm_ functions
  fb: handle NULL pointers in framebuffer release
  OMAPDSS: HDMI: OMAP4: Update IRQ flags for the HPD IRQ request
  OMAPDSS: Apply VENC timings even if panel is disabled
  OMAPDSS: VENC/DISPC: Delay dividing Y resolution for managers connected to VENC
  OMAPDSS: DISPC: Support rotation through TILER
  OMAPDSS: VRFB: remove compiler warnings when CONFIG_BUG=n
  OMAPFB: remove compiler warnings when CONFIG_BUG=n
  OMAPDSS: remove compiler warnings when CONFIG_BUG=n
  OMAPDSS: DISPC: fix usage of dispc_ovl_set_accu_uv
  OMAPDSS: use DSI_FIFO_BUG workaround only for manual update displays
  OMAPDSS: DSI: Support command mode interleaving during video mode blanking periods
  OMAPDSS: DISPC: Update Accumulator configuration for chroma plane
  drivers/video: fsl-diu-fb: don't initialize the THRESHOLDS registers
  video: exynos mipi dsi: support reverse panel type
  video: exynos mipi dsi: Properly interpret the interrupt source flags
  video: exynos mipi dsi: Avoid races in probe()
  ...

94 files changed:
Documentation/arm/OMAP/DSS
arch/arm/mach-exynos/mach-nuri.c
arch/arm/mach-exynos/mach-origen.c
arch/arm/mach-exynos/mach-smdkv310.c
arch/arm/mach-exynos/mach-universal_c210.c
arch/arm/mach-omap2/display.c
arch/arm/mach-s3c24xx/mach-smdk2416.c
arch/arm/mach-s3c64xx/mach-anw6410.c
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-s3c64xx/mach-hmt.c
arch/arm/mach-s3c64xx/mach-mini6410.c
arch/arm/mach-s3c64xx/mach-real6410.c
arch/arm/mach-s3c64xx/mach-smartq5.c
arch/arm/mach-s3c64xx/mach-smartq7.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-s5p64x0/mach-smdk6440.c
arch/arm/mach-s5p64x0/mach-smdk6450.c
arch/arm/mach-s5pc100/mach-smdkc100.c
arch/arm/mach-s5pv210/mach-aquila.c
arch/arm/mach-s5pv210/mach-goni.c
arch/arm/mach-s5pv210/mach-smdkv210.c
arch/arm/plat-samsung/include/plat/fb.h
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/auo_k1900fb.c [new file with mode: 0644]
drivers/video/auo_k1901fb.c [new file with mode: 0644]
drivers/video/auo_k190x.c [new file with mode: 0644]
drivers/video/auo_k190x.h [new file with mode: 0644]
drivers/video/bfin_adv7393fb.c
drivers/video/cobalt_lcdfb.c
drivers/video/ep93xx-fb.c
drivers/video/exynos/exynos_dp_core.c
drivers/video/exynos/exynos_dp_core.h
drivers/video/exynos/exynos_dp_reg.c
drivers/video/exynos/exynos_dp_reg.h
drivers/video/exynos/exynos_mipi_dsi.c
drivers/video/exynos/exynos_mipi_dsi_common.c
drivers/video/exynos/s6e8ax0.c
drivers/video/fb_defio.c
drivers/video/fbsysfs.c
drivers/video/fsl-diu-fb.c
drivers/video/intelfb/intelfbdrv.c
drivers/video/mb862xx/mb862xx-i2c.c
drivers/video/mb862xx/mb862xxfbdrv.c
drivers/video/mbx/mbxfb.c
drivers/video/mxsfb.c
drivers/video/omap/Kconfig
drivers/video/omap2/displays/panel-acx565akm.c
drivers/video/omap2/displays/panel-generic-dpi.c
drivers/video/omap2/displays/panel-n8x0.c
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/displays/panel-tfp410.c
drivers/video/omap2/displays/panel-tpo-td043mtea1.c
drivers/video/omap2/dss/Kconfig
drivers/video/omap2/dss/apply.c
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dispc.h
drivers/video/omap2/dss/display.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/hdmi_panel.c
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/ti_hdmi.h
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/omapfb-ioctl.c
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/omap2/omapfb/omapfb.h
drivers/video/omap2/vrfb.c
drivers/video/pxa3xx-gcu.c
drivers/video/s3c-fb.c
drivers/video/sh_mobile_hdmi.c
drivers/video/sis/init.h
drivers/video/sis/sis_main.c
drivers/video/skeletonfb.c
drivers/video/smscufx.c
drivers/video/udlfb.c
drivers/video/via/viafbdev.c
include/linux/fb.h
include/video/auo_k190xfb.h [new file with mode: 0644]
include/video/exynos_dp.h
include/video/exynos_mipi_dsim.h
include/video/omapdss.h
include/video/sh_mobile_hdmi.h

index 888ae7b..a564cee 100644 (file)
@@ -47,6 +47,51 @@ flexible way to enable non-common multi-display configuration. In addition to
 modelling the hardware overlays, omapdss supports virtual overlays and overlay
 managers. These can be used when updating a display with CPU or system DMA.
 
+omapdss driver support for audio
+--------------------------------
+There exist several display technologies and standards that support audio as
+well. Hence, it is relevant to update the DSS device driver to provide an audio
+interface that may be used by an audio driver or any other driver interested in
+the functionality.
+
+The audio_enable function is intended to prepare the relevant
+IP for playback (e.g., enabling an audio FIFO, taking in/out of reset
+some IP, enabling companion chips, etc). It is intended to be called before
+audio_start. The audio_disable function performs the reverse operation and is
+intended to be called after audio_stop.
+
+While a given DSS device driver may support audio, it is possible that for
+certain configurations audio is not supported (e.g., an HDMI display using a
+VESA video timing). The audio_supported function is intended to query whether
+the current configuration of the display supports audio.
+
+The audio_config function is intended to configure all the relevant audio
+parameters of the display. In order to make the function independent of any
+specific DSS device driver, a struct omap_dss_audio is defined. Its purpose
+is to contain all the required parameters for audio configuration. At the
+moment, such structure contains pointers to IEC-60958 channel status word
+and CEA-861 audio infoframe structures. This should be enough to support
+HDMI and DisplayPort, as both are based on CEA-861 and IEC-60958.
+
+The audio_enable/disable, audio_config and audio_supported functions could be
+implemented as functions that may sleep. Hence, they should not be called
+while holding a spinlock or a readlock.
+
+The audio_start/audio_stop function is intended to effectively start/stop audio
+playback after the configuration has taken place. These functions are designed
+to be used in an atomic context. Hence, audio_start should return quickly and be
+called only after all the needed resources for audio playback (audio FIFOs,
+DMA channels, companion chips, etc) have been enabled to begin data transfers.
+audio_stop is designed to only stop the audio transfers. The resources used
+for playback are released using audio_disable.
+
+The enum omap_dss_audio_state may be used to help the implementations of
+the interface to keep track of the audio state. The initial state is _DISABLED;
+then, the state transitions to _CONFIGURED, and then, when it is ready to
+play audio, to _ENABLED. The state _PLAYING is used when the audio is being
+rendered.
+
+
 Panel and controller drivers
 ----------------------------
 
@@ -156,6 +201,7 @@ timings             Display timings (pixclock,xres/hfp/hbp/hsw,yres/vfp/vbp/vsw)
                "pal" and "ntsc"
 panel_name
 tear_elim      Tearing elimination 0=off, 1=on
+output_type    Output type (video encoder only): "composite" or "svideo"
 
 There are also some debugfs files at <debugfs>/omapdss/ which show information
 about clocks and registers.
index 972983e..656f8fc 100644 (file)
@@ -237,25 +237,29 @@ static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
 #else
 /* Frame Buffer */
 static struct s3c_fb_pd_win nuri_fb_win0 = {
-       .win_mode = {
-               .left_margin    = 64,
-               .right_margin   = 16,
-               .upper_margin   = 64,
-               .lower_margin   = 1,
-               .hsync_len      = 48,
-               .vsync_len      = 3,
-               .xres           = 1024,
-               .yres           = 600,
-               .refresh        = 60,
-       },
        .max_bpp        = 24,
        .default_bpp    = 16,
+       .xres           = 1024,
+       .yres           = 600,
        .virtual_x      = 1024,
        .virtual_y      = 2 * 600,
 };
 
+static struct fb_videomode nuri_lcd_timing = {
+       .left_margin    = 64,
+       .right_margin   = 16,
+       .upper_margin   = 64,
+       .lower_margin   = 1,
+       .hsync_len      = 48,
+       .vsync_len      = 3,
+       .xres           = 1024,
+       .yres           = 600,
+       .refresh        = 60,
+};
+
 static struct s3c_fb_platdata nuri_fb_pdata __initdata = {
        .win[0]         = &nuri_fb_win0,
+       .vtiming        = &nuri_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
                          VIDCON0_CLKSEL_LCD,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
index a7f7fd5..f5572be 100644 (file)
@@ -604,24 +604,28 @@ static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
 };
 #else
 static struct s3c_fb_pd_win origen_fb_win0 = {
-       .win_mode = {
-               .left_margin    = 64,
-               .right_margin   = 16,
-               .upper_margin   = 64,
-               .lower_margin   = 16,
-               .hsync_len      = 48,
-               .vsync_len      = 3,
-               .xres           = 1024,
-               .yres           = 600,
-       },
+       .xres                   = 1024,
+       .yres                   = 600,
        .max_bpp                = 32,
        .default_bpp            = 24,
        .virtual_x              = 1024,
        .virtual_y              = 2 * 600,
 };
 
+static struct fb_videomode origen_lcd_timing = {
+       .left_margin    = 64,
+       .right_margin   = 16,
+       .upper_margin   = 64,
+       .lower_margin   = 16,
+       .hsync_len      = 48,
+       .vsync_len      = 3,
+       .xres           = 1024,
+       .yres           = 600,
+};
+
 static struct s3c_fb_platdata origen_lcd_pdata __initdata = {
        .win[0]         = &origen_fb_win0,
+       .vtiming        = &origen_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
                                VIDCON1_INV_VCLK,
index 70df1a0..262e9e4 100644 (file)
@@ -178,22 +178,26 @@ static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
 };
 #else
 static struct s3c_fb_pd_win smdkv310_fb_win0 = {
-       .win_mode = {
-               .left_margin    = 13,
-               .right_margin   = 8,
-               .upper_margin   = 7,
-               .lower_margin   = 5,
-               .hsync_len      = 3,
-               .vsync_len      = 1,
-               .xres           = 800,
-               .yres           = 480,
-       },
-       .max_bpp                = 32,
-       .default_bpp            = 24,
+       .max_bpp        = 32,
+       .default_bpp    = 24,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode smdkv310_lcd_timing = {
+       .left_margin    = 13,
+       .right_margin   = 8,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
 };
 
 static struct s3c_fb_platdata smdkv310_lcd0_pdata __initdata = {
        .win[0]         = &smdkv310_fb_win0,
+       .vtiming        = &smdkv310_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
        .setup_gpio     = exynos4_fimd0_gpio_setup_24bpp,
index 083b44d..cd92fa8 100644 (file)
@@ -843,25 +843,29 @@ static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
 #else
 /* Frame Buffer */
 static struct s3c_fb_pd_win universal_fb_win0 = {
-       .win_mode = {
-               .left_margin    = 16,
-               .right_margin   = 16,
-               .upper_margin   = 2,
-               .lower_margin   = 28,
-               .hsync_len      = 2,
-               .vsync_len      = 1,
-               .xres           = 480,
-               .yres           = 800,
-               .refresh        = 55,
-       },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .xres           = 480,
+       .yres           = 800,
        .virtual_x      = 480,
        .virtual_y      = 2 * 800,
 };
 
+static struct fb_videomode universal_lcd_timing = {
+       .left_margin    = 16,
+       .right_margin   = 16,
+       .upper_margin   = 2,
+       .lower_margin   = 28,
+       .hsync_len      = 2,
+       .vsync_len      = 1,
+       .xres           = 480,
+       .yres           = 800,
+       .refresh        = 55,
+};
+
 static struct s3c_fb_platdata universal_lcd_pdata __initdata = {
        .win[0]         = &universal_fb_win0,
+       .vtiming        = &universal_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
                          VIDCON0_CLKSEL_LCD,
        .vidcon1        = VIDCON1_INV_VCLK | VIDCON1_INV_VDEN
index db5a88a..54d49dd 100644 (file)
@@ -180,16 +180,133 @@ static void omap_dsi_disable_pads(int dsi_id, unsigned lane_mask)
                omap4_dsi_mux_pads(dsi_id, 0);
 }
 
+static int omap_dss_set_min_bus_tput(struct device *dev, unsigned long tput)
+{
+       return omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, tput);
+}
+
+static struct platform_device *create_dss_pdev(const char *pdev_name,
+               int pdev_id, const char *oh_name, void *pdata, int pdata_len,
+               struct platform_device *parent)
+{
+       struct platform_device *pdev;
+       struct omap_device *od;
+       struct omap_hwmod *ohs[1];
+       struct omap_hwmod *oh;
+       int r;
+
+       oh = omap_hwmod_lookup(oh_name);
+       if (!oh) {
+               pr_err("Could not look up %s\n", oh_name);
+               r = -ENODEV;
+               goto err;
+       }
+
+       pdev = platform_device_alloc(pdev_name, pdev_id);
+       if (!pdev) {
+               pr_err("Could not create pdev for %s\n", pdev_name);
+               r = -ENOMEM;
+               goto err;
+       }
+
+       if (parent != NULL)
+               pdev->dev.parent = &parent->dev;
+
+       if (pdev->id != -1)
+               dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
+       else
+               dev_set_name(&pdev->dev, "%s", pdev->name);
+
+       ohs[0] = oh;
+       od = omap_device_alloc(pdev, ohs, 1, NULL, 0);
+       if (!od) {
+               pr_err("Could not alloc omap_device for %s\n", pdev_name);
+               r = -ENOMEM;
+               goto err;
+       }
+
+       r = platform_device_add_data(pdev, pdata, pdata_len);
+       if (r) {
+               pr_err("Could not set pdata for %s\n", pdev_name);
+               goto err;
+       }
+
+       r = omap_device_register(pdev);
+       if (r) {
+               pr_err("Could not register omap_device for %s\n", pdev_name);
+               goto err;
+       }
+
+       return pdev;
+
+err:
+       return ERR_PTR(r);
+}
+
+static struct platform_device *create_simple_dss_pdev(const char *pdev_name,
+               int pdev_id, void *pdata, int pdata_len,
+               struct platform_device *parent)
+{
+       struct platform_device *pdev;
+       int r;
+
+       pdev = platform_device_alloc(pdev_name, pdev_id);
+       if (!pdev) {
+               pr_err("Could not create pdev for %s\n", pdev_name);
+               r = -ENOMEM;
+               goto err;
+       }
+
+       if (parent != NULL)
+               pdev->dev.parent = &parent->dev;
+
+       if (pdev->id != -1)
+               dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
+       else
+               dev_set_name(&pdev->dev, "%s", pdev->name);
+
+       r = platform_device_add_data(pdev, pdata, pdata_len);
+       if (r) {
+               pr_err("Could not set pdata for %s\n", pdev_name);
+               goto err;
+       }
+
+       r = omap_device_register(pdev);
+       if (r) {
+               pr_err("Could not register omap_device for %s\n", pdev_name);
+               goto err;
+       }
+
+       return pdev;
+
+err:
+       return ERR_PTR(r);
+}
+
 int __init omap_display_init(struct omap_dss_board_info *board_data)
 {
        int r = 0;
-       struct omap_hwmod *oh;
        struct platform_device *pdev;
        int i, oh_count;
-       struct omap_display_platform_data pdata;
        const struct omap_dss_hwmod_data *curr_dss_hwmod;
+       struct platform_device *dss_pdev;
+
+       /* create omapdss device */
+
+       board_data->dsi_enable_pads = omap_dsi_enable_pads;
+       board_data->dsi_disable_pads = omap_dsi_disable_pads;
+       board_data->get_context_loss_count = omap_pm_get_dev_context_loss_count;
+       board_data->set_min_bus_tput = omap_dss_set_min_bus_tput;
+
+       omap_display_device.dev.platform_data = board_data;
+
+       r = platform_device_register(&omap_display_device);
+       if (r < 0) {
+               pr_err("Unable to register omapdss device\n");
+               return r;
+       }
 
-       memset(&pdata, 0, sizeof(pdata));
+       /* create devices for dss hwmods */
 
        if (cpu_is_omap24xx()) {
                curr_dss_hwmod = omap2_dss_hwmod_data;
@@ -202,39 +319,58 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
                oh_count = ARRAY_SIZE(omap4_dss_hwmod_data);
        }
 
-       if (board_data->dsi_enable_pads == NULL)
-               board_data->dsi_enable_pads = omap_dsi_enable_pads;
-       if (board_data->dsi_disable_pads == NULL)
-               board_data->dsi_disable_pads = omap_dsi_disable_pads;
-
-       pdata.board_data = board_data;
-       pdata.board_data->get_context_loss_count =
-               omap_pm_get_dev_context_loss_count;
-
-       for (i = 0; i < oh_count; i++) {
-               oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
-               if (!oh) {
-                       pr_err("Could not look up %s\n",
-                               curr_dss_hwmod[i].oh_name);
-                       return -ENODEV;
+       /*
+        * First create the pdev for dss_core, which is used as a parent device
+        * by the other dss pdevs. Note: dss_core has to be the first item in
+        * the hwmod list.
+        */
+       dss_pdev = create_dss_pdev(curr_dss_hwmod[0].dev_name,
+                       curr_dss_hwmod[0].id,
+                       curr_dss_hwmod[0].oh_name,
+                       board_data, sizeof(*board_data),
+                       NULL);
+
+       if (IS_ERR(dss_pdev)) {
+               pr_err("Could not build omap_device for %s\n",
+                               curr_dss_hwmod[0].oh_name);
+
+               return PTR_ERR(dss_pdev);
+       }
+
+       for (i = 1; i < oh_count; i++) {
+               pdev = create_dss_pdev(curr_dss_hwmod[i].dev_name,
+                               curr_dss_hwmod[i].id,
+                               curr_dss_hwmod[i].oh_name,
+                               board_data, sizeof(*board_data),
+                               dss_pdev);
+
+               if (IS_ERR(pdev)) {
+                       pr_err("Could not build omap_device for %s\n",
+                                       curr_dss_hwmod[i].oh_name);
+
+                       return PTR_ERR(pdev);
                }
+       }
 
-               pdev = omap_device_build(curr_dss_hwmod[i].dev_name,
-                               curr_dss_hwmod[i].id, oh, &pdata,
-                               sizeof(struct omap_display_platform_data),
-                               NULL, 0, 0);
+       /* Create devices for DPI and SDI */
 
-               if (WARN((IS_ERR(pdev)), "Could not build omap_device for %s\n",
-                               curr_dss_hwmod[i].oh_name))
-                       return -ENODEV;
+       pdev = create_simple_dss_pdev("omapdss_dpi", -1,
+                       board_data, sizeof(*board_data), dss_pdev);
+       if (IS_ERR(pdev)) {
+               pr_err("Could not build platform_device for omapdss_dpi\n");
+               return PTR_ERR(pdev);
        }
-       omap_display_device.dev.platform_data = board_data;
 
-       r = platform_device_register(&omap_display_device);
-       if (r < 0)
-               printk(KERN_ERR "Unable to register OMAP-Display device\n");
+       if (cpu_is_omap34xx()) {
+               pdev = create_simple_dss_pdev("omapdss_sdi", -1,
+                               board_data, sizeof(*board_data), dss_pdev);
+               if (IS_ERR(pdev)) {
+                       pr_err("Could not build platform_device for omapdss_sdi\n");
+                       return PTR_ERR(pdev);
+               }
+       }
 
-       return r;
+       return 0;
 }
 
 static void dispc_disable_outputs(void)
index 30a44f8..c3100a0 100644 (file)
@@ -148,23 +148,25 @@ static struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
 
 static struct s3c_fb_pd_win smdk2416_fb_win[] = {
        [0] = {
-               /* think this is the same as the smdk6410 */
-               .win_mode       = {
-                       .pixclock       = 41094,
-                       .left_margin    = 8,
-                       .right_margin   = 13,
-                       .upper_margin   = 7,
-                       .lower_margin   = 5,
-                       .hsync_len      = 3,
-                       .vsync_len      = 1,
-                       .xres           = 800,
-                       .yres           = 480,
-               },
                .default_bpp    = 16,
                .max_bpp        = 32,
+               .xres           = 800,
+               .yres           = 480,
        },
 };
 
+static struct fb_videomode smdk2416_lcd_timing = {
+       .pixclock       = 41094,
+       .left_margin    = 8,
+       .right_margin   = 13,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
+};
+
 static void s3c2416_fb_gpio_setup_24bpp(void)
 {
        unsigned int gpio;
@@ -187,6 +189,7 @@ static void s3c2416_fb_gpio_setup_24bpp(void)
 
 static struct s3c_fb_platdata smdk2416_fb_platdata = {
        .win[0]         = &smdk2416_fb_win[0],
+       .vtiming        = &smdk2416_lcd_timing,
        .setup_gpio     = s3c2416_fb_gpio_setup_24bpp,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
index 314df05..ffa29dd 100644 (file)
@@ -134,24 +134,27 @@ static struct platform_device anw6410_lcd_powerdev = {
 };
 
 static struct s3c_fb_pd_win anw6410_fb_win0 = {
-       /* this is to ensure we use win0 */
-       .win_mode       = {
-               .left_margin    = 8,
-               .right_margin   = 13,
-               .upper_margin   = 7,
-               .lower_margin   = 5,
-               .hsync_len      = 3,
-               .vsync_len      = 1,
-               .xres           = 800,
-               .yres           = 480,
-       },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode anw6410_lcd_timing = {
+       .left_margin    = 8,
+       .right_margin   = 13,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
 };
 
 /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
 static struct s3c_fb_platdata anw6410_lcd_pdata __initdata = {
        .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .vtiming        = &anw6410_lcd_timing,
        .win[0]         = &anw6410_fb_win0,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
index 6b20a71..d0c352d 100644 (file)
@@ -151,26 +151,29 @@ static struct platform_device crag6410_lcd_powerdev = {
 
 /* 640x480 URT */
 static struct s3c_fb_pd_win crag6410_fb_win0 = {
-       /* this is to ensure we use win0 */
-       .win_mode       = {
-               .left_margin    = 150,
-               .right_margin   = 80,
-               .upper_margin   = 40,
-               .lower_margin   = 5,
-               .hsync_len      = 40,
-               .vsync_len      = 5,
-               .xres           = 640,
-               .yres           = 480,
-       },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .xres           = 640,
+       .yres           = 480,
        .virtual_y      = 480 * 2,
        .virtual_x      = 640,
 };
 
+static struct fb_videomode crag6410_lcd_timing = {
+       .left_margin    = 150,
+       .right_margin   = 80,
+       .upper_margin   = 40,
+       .lower_margin   = 5,
+       .hsync_len      = 40,
+       .vsync_len      = 5,
+       .xres           = 640,
+       .yres           = 480,
+};
+
 /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
 static struct s3c_fb_platdata crag6410_lcd_pdata __initdata = {
        .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .vtiming        = &crag6410_lcd_timing,
        .win[0]         = &crag6410_fb_win0,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
index 1bf6b9d..6890881 100644 (file)
@@ -129,23 +129,27 @@ static struct platform_device hmt_backlight_device = {
 };
 
 static struct s3c_fb_pd_win hmt_fb_win0 = {
-       .win_mode       = {
-               .left_margin    = 8,
-               .right_margin   = 13,
-               .upper_margin   = 7,
-               .lower_margin   = 5,
-               .hsync_len      = 3,
-               .vsync_len      = 1,
-               .xres           = 800,
-               .yres           = 480,
-       },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode hmt_lcd_timing = {
+       .left_margin    = 8,
+       .right_margin   = 13,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
 };
 
 /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
 static struct s3c_fb_platdata hmt_lcd_pdata __initdata = {
        .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .vtiming        = &hmt_lcd_timing,
        .win[0]         = &hmt_fb_win0,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
index f8ea61e..5539a25 100644 (file)
@@ -140,41 +140,59 @@ static struct s3c2410_platform_nand mini6410_nand_info = {
        .sets           = mini6410_nand_sets,
 };
 
-static struct s3c_fb_pd_win mini6410_fb_win[] = {
+static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
+       .max_bpp        = 32,
+       .default_bpp    = 16,
+       .xres           = 480,
+       .yres           = 272,
+};
+
+static struct fb_videomode mini6410_lcd_type0_timing = {
+       /* 4.3" 480x272 */
+       .left_margin    = 3,
+       .right_margin   = 2,
+       .upper_margin   = 1,
+       .lower_margin   = 1,
+       .hsync_len      = 40,
+       .vsync_len      = 1,
+       .xres           = 480,
+       .yres           = 272,
+};
+
+static struct s3c_fb_pd_win mini6410_lcd_type1_fb_win = {
+       .max_bpp        = 32,
+       .default_bpp    = 16,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode mini6410_lcd_type1_timing = {
+       /* 7.0" 800x480 */
+       .left_margin    = 8,
+       .right_margin   = 13,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct s3c_fb_platdata mini6410_lcd_pdata[] __initdata = {
        {
-               .win_mode       = {     /* 4.3" 480x272 */
-                       .left_margin    = 3,
-                       .right_margin   = 2,
-                       .upper_margin   = 1,
-                       .lower_margin   = 1,
-                       .hsync_len      = 40,
-                       .vsync_len      = 1,
-                       .xres           = 480,
-                       .yres           = 272,
-               },
-               .max_bpp        = 32,
-               .default_bpp    = 16,
+               .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+               .vtiming        = &mini6410_lcd_type0_timing,
+               .win[0]         = &mini6410_lcd_type0_fb_win,
+               .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+               .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
        }, {
-               .win_mode       = {     /* 7.0" 800x480 */
-                       .left_margin    = 8,
-                       .right_margin   = 13,
-                       .upper_margin   = 7,
-                       .lower_margin   = 5,
-                       .hsync_len      = 3,
-                       .vsync_len      = 1,
-                       .xres           = 800,
-                       .yres           = 480,
-               },
-               .max_bpp        = 32,
-               .default_bpp    = 16,
+               .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+               .vtiming        = &mini6410_lcd_type1_timing,
+               .win[0]         = &mini6410_lcd_type1_fb_win,
+               .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+               .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
        },
-};
-
-static struct s3c_fb_platdata mini6410_lcd_pdata __initdata = {
-       .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
-       .win[0]         = &mini6410_fb_win[0],
-       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
-       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+       { },
 };
 
 static void mini6410_lcd_power_set(struct plat_lcd_data *pd,
@@ -272,7 +290,7 @@ static void mini6410_parse_features(
                                        "screen type already set\n", f);
                        } else {
                                int li = f - '0';
-                               if (li >= ARRAY_SIZE(mini6410_fb_win))
+                               if (li >= ARRAY_SIZE(mini6410_lcd_pdata))
                                        printk(KERN_INFO "MINI6410: '%c' out "
                                                "of range LCD mode\n", f);
                                else {
@@ -296,14 +314,12 @@ static void __init mini6410_machine_init(void)
        /* Parse the feature string */
        mini6410_parse_features(&features, mini6410_features_str);
 
-       mini6410_lcd_pdata.win[0] = &mini6410_fb_win[features.lcd_index];
-
        printk(KERN_INFO "MINI6410: selected LCD display is %dx%d\n",
-               mini6410_lcd_pdata.win[0]->win_mode.xres,
-               mini6410_lcd_pdata.win[0]->win_mode.yres);
+               mini6410_lcd_pdata[features.lcd_index].win[0]->xres,
+               mini6410_lcd_pdata[features.lcd_index].win[0]->yres);
 
        s3c_nand_set_platdata(&mini6410_nand_info);
-       s3c_fb_set_platdata(&mini6410_lcd_pdata);
+       s3c_fb_set_platdata(&mini6410_lcd_pdata[features.lcd_index]);
        s3c24xx_ts_set_platdata(NULL);
 
        /* configure nCS1 width to 16 bits */
index b92d8e1..326b216 100644 (file)
@@ -106,41 +106,57 @@ static struct platform_device real6410_device_eth = {
        },
 };
 
-static struct s3c_fb_pd_win real6410_fb_win[] = {
+static struct s3c_fb_pd_win real6410_lcd_type0_fb_win = {
+       .max_bpp        = 32,
+       .default_bpp    = 16,
+       .xres           = 480,
+       .yres           = 272,
+};
+
+static struct fb_videomode real6410_lcd_type0_timing = {
+       /* 4.3" 480x272 */
+       .left_margin    = 3,
+       .right_margin   = 2,
+       .upper_margin   = 1,
+       .lower_margin   = 1,
+       .hsync_len      = 40,
+       .vsync_len      = 1,
+};
+
+static struct s3c_fb_pd_win real6410_lcd_type1_fb_win = {
+       .max_bpp        = 32,
+       .default_bpp    = 16,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode real6410_lcd_type1_timing = {
+       /* 7.0" 800x480 */
+       .left_margin    = 8,
+       .right_margin   = 13,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct s3c_fb_platdata real6410_lcd_pdata[] __initdata = {
        {
-               .win_mode       = {     /* 4.3" 480x272 */
-                       .left_margin    = 3,
-                       .right_margin   = 2,
-                       .upper_margin   = 1,
-                       .lower_margin   = 1,
-                       .hsync_len      = 40,
-                       .vsync_len      = 1,
-                       .xres           = 480,
-                       .yres           = 272,
-               },
-               .max_bpp        = 32,
-               .default_bpp    = 16,
+               .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+               .vtiming        = &real6410_lcd_type0_timing,
+               .win[0]         = &real6410_lcd_type0_fb_win,
+               .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+               .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
        }, {
-               .win_mode       = {     /* 7.0" 800x480 */
-                       .left_margin    = 8,
-                       .right_margin   = 13,
-                       .upper_margin   = 7,
-                       .lower_margin   = 5,
-                       .hsync_len      = 3,
-                       .vsync_len      = 1,
-                       .xres           = 800,
-                       .yres           = 480,
-               },
-               .max_bpp        = 32,
-               .default_bpp    = 16,
+               .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+               .vtiming        = &real6410_lcd_type1_timing,
+               .win[0]         = &real6410_lcd_type1_fb_win,
+               .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+               .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
        },
-};
-
-static struct s3c_fb_platdata real6410_lcd_pdata __initdata = {
-       .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
-       .win[0]         = &real6410_fb_win[0],
-       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
-       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+       { },
 };
 
 static struct mtd_partition real6410_nand_part[] = {
@@ -253,7 +269,7 @@ static void real6410_parse_features(
                                        "screen type already set\n", f);
                        } else {
                                int li = f - '0';
-                               if (li >= ARRAY_SIZE(real6410_fb_win))
+                               if (li >= ARRAY_SIZE(real6410_lcd_pdata))
                                        printk(KERN_INFO "REAL6410: '%c' out "
                                                "of range LCD mode\n", f);
                                else {
@@ -277,13 +293,11 @@ static void __init real6410_machine_init(void)
        /* Parse the feature string */
        real6410_parse_features(&features, real6410_features_str);
 
-       real6410_lcd_pdata.win[0] = &real6410_fb_win[features.lcd_index];
-
        printk(KERN_INFO "REAL6410: selected LCD display is %dx%d\n",
-               real6410_lcd_pdata.win[0]->win_mode.xres,
-               real6410_lcd_pdata.win[0]->win_mode.yres);
+               real6410_lcd_pdata[features.lcd_index].win[0]->xres,
+               real6410_lcd_pdata[features.lcd_index].win[0]->yres);
 
-       s3c_fb_set_platdata(&real6410_lcd_pdata);
+       s3c_fb_set_platdata(&real6410_lcd_pdata[features.lcd_index]);
        s3c_nand_set_platdata(&real6410_nand_info);
        s3c24xx_ts_set_platdata(NULL);
 
index c5021d0..d6266d8 100644 (file)
@@ -108,23 +108,27 @@ static struct platform_device smartq5_buttons_device  = {
 };
 
 static struct s3c_fb_pd_win smartq5_fb_win0 = {
-       .win_mode       = {
-               .left_margin    = 216,
-               .right_margin   = 40,
-               .upper_margin   = 35,
-               .lower_margin   = 10,
-               .hsync_len      = 1,
-               .vsync_len      = 1,
-               .xres           = 800,
-               .yres           = 480,
-               .refresh        = 80,
-       },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode smartq5_lcd_timing = {
+       .left_margin    = 216,
+       .right_margin   = 40,
+       .upper_margin   = 35,
+       .lower_margin   = 10,
+       .hsync_len      = 1,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
+       .refresh        = 80,
 };
 
 static struct s3c_fb_platdata smartq5_lcd_pdata __initdata = {
        .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .vtiming        = &smartq5_lcd_timing,
        .win[0]         = &smartq5_fb_win0,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
index aa9072a..0957d2a 100644 (file)
@@ -124,23 +124,27 @@ static struct platform_device smartq7_buttons_device  = {
 };
 
 static struct s3c_fb_pd_win smartq7_fb_win0 = {
-       .win_mode       = {
-               .left_margin    = 3,
-               .right_margin   = 5,
-               .upper_margin   = 1,
-               .lower_margin   = 20,
-               .hsync_len      = 10,
-               .vsync_len      = 3,
-               .xres           = 800,
-               .yres           = 480,
-               .refresh        = 80,
-       },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode smartq7_lcd_timing = {
+       .left_margin    = 3,
+       .right_margin   = 5,
+       .upper_margin   = 1,
+       .lower_margin   = 20,
+       .hsync_len      = 10,
+       .vsync_len      = 3,
+       .xres           = 800,
+       .yres           = 480,
+       .refresh        = 80,
 };
 
 static struct s3c_fb_platdata smartq7_lcd_pdata __initdata = {
        .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .vtiming        = &smartq7_lcd_timing,
        .win[0]         = &smartq7_fb_win0,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
index d44319b..df3103d 100644 (file)
@@ -146,26 +146,29 @@ static struct platform_device smdk6410_lcd_powerdev = {
 };
 
 static struct s3c_fb_pd_win smdk6410_fb_win0 = {
-       /* this is to ensure we use win0 */
-       .win_mode       = {
-               .left_margin    = 8,
-               .right_margin   = 13,
-               .upper_margin   = 7,
-               .lower_margin   = 5,
-               .hsync_len      = 3,
-               .vsync_len      = 1,
-               .xres           = 800,
-               .yres           = 480,
-       },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .xres           = 800,
+       .yres           = 480,
        .virtual_y      = 480 * 2,
        .virtual_x      = 800,
 };
 
+static struct fb_videomode smdk6410_lcd_timing = {
+       .left_margin    = 8,
+       .right_margin   = 13,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
+};
+
 /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
 static struct s3c_fb_platdata smdk6410_lcd_pdata __initdata = {
        .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .vtiming        = &smdk6410_lcd_timing,
        .win[0]         = &smdk6410_fb_win0,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
index a40e325..92fefad 100644 (file)
@@ -103,22 +103,26 @@ static struct s3c2410_uartcfg smdk6440_uartcfgs[] __initdata = {
 
 /* Frame Buffer */
 static struct s3c_fb_pd_win smdk6440_fb_win0 = {
-       .win_mode = {
-               .left_margin    = 8,
-               .right_margin   = 13,
-               .upper_margin   = 7,
-               .lower_margin   = 5,
-               .hsync_len      = 3,
-               .vsync_len      = 1,
-               .xres           = 800,
-               .yres           = 480,
-       },
        .max_bpp        = 32,
        .default_bpp    = 24,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode smdk6440_lcd_timing = {
+       .left_margin    = 8,
+       .right_margin   = 13,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
 };
 
 static struct s3c_fb_platdata smdk6440_lcd_pdata __initdata = {
        .win[0]         = &smdk6440_fb_win0,
+       .vtiming        = &smdk6440_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
        .setup_gpio     = s5p64x0_fb_gpio_setup_24bpp,
index efb69e2..e2335ec 100644 (file)
@@ -121,22 +121,26 @@ static struct s3c2410_uartcfg smdk6450_uartcfgs[] __initdata = {
 
 /* Frame Buffer */
 static struct s3c_fb_pd_win smdk6450_fb_win0 = {
-       .win_mode       = {
-               .left_margin    = 8,
-               .right_margin   = 13,
-               .upper_margin   = 7,
-               .lower_margin   = 5,
-               .hsync_len      = 3,
-               .vsync_len      = 1,
-               .xres           = 800,
-               .yres           = 480,
-       },
        .max_bpp        = 32,
        .default_bpp    = 24,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode smdk6450_lcd_timing = {
+       .left_margin    = 8,
+       .right_margin   = 13,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
 };
 
 static struct s3c_fb_platdata smdk6450_lcd_pdata __initdata = {
        .win[0]         = &smdk6450_fb_win0,
+       .vtiming        = &smdk6450_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
        .setup_gpio     = s5p64x0_fb_gpio_setup_24bpp,
index 674d229..0c3ae38 100644 (file)
@@ -136,24 +136,27 @@ static struct platform_device smdkc100_lcd_powerdev = {
 
 /* Frame Buffer */
 static struct s3c_fb_pd_win smdkc100_fb_win0 = {
-       /* this is to ensure we use win0 */
-       .win_mode       = {
-               .left_margin    = 8,
-               .right_margin   = 13,
-               .upper_margin   = 7,
-               .lower_margin   = 5,
-               .hsync_len      = 3,
-               .vsync_len      = 1,
-               .xres           = 800,
-               .yres           = 480,
-               .refresh        = 80,
-       },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode smdkc100_lcd_timing = {
+       .left_margin    = 8,
+       .right_margin   = 13,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
+       .refresh        = 80,
 };
 
 static struct s3c_fb_platdata smdkc100_lcd_pdata __initdata = {
        .win[0]         = &smdkc100_fb_win0,
+       .vtiming        = &smdkc100_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
        .setup_gpio     = s5pc100_fb_gpio_setup_24bpp,
index 48d018f..af528f9 100644 (file)
@@ -96,38 +96,34 @@ static struct s3c2410_uartcfg aquila_uartcfgs[] __initdata = {
 
 /* Frame Buffer */
 static struct s3c_fb_pd_win aquila_fb_win0 = {
-       .win_mode = {
-               .left_margin = 16,
-               .right_margin = 16,
-               .upper_margin = 3,
-               .lower_margin = 28,
-               .hsync_len = 2,
-               .vsync_len = 2,
-               .xres = 480,
-               .yres = 800,
-       },
        .max_bpp = 32,
        .default_bpp = 16,
+       .xres = 480,
+       .yres = 800,
 };
 
 static struct s3c_fb_pd_win aquila_fb_win1 = {
-       .win_mode = {
-               .left_margin = 16,
-               .right_margin = 16,
-               .upper_margin = 3,
-               .lower_margin = 28,
-               .hsync_len = 2,
-               .vsync_len = 2,
-               .xres = 480,
-               .yres = 800,
-       },
        .max_bpp = 32,
        .default_bpp = 16,
+       .xres = 480,
+       .yres = 800,
+};
+
+static struct fb_videomode aquila_lcd_timing = {
+       .left_margin = 16,
+       .right_margin = 16,
+       .upper_margin = 3,
+       .lower_margin = 28,
+       .hsync_len = 2,
+       .vsync_len = 2,
+       .xres = 480,
+       .yres = 800,
 };
 
 static struct s3c_fb_platdata aquila_lcd_pdata __initdata = {
        .win[0]         = &aquila_fb_win0,
        .win[1]         = &aquila_fb_win1,
+       .vtiming        = &aquila_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
                          VIDCON1_INV_VCLK | VIDCON1_INV_VDEN,
index f20a97c..bf5087c 100644 (file)
@@ -107,25 +107,29 @@ static struct s3c2410_uartcfg goni_uartcfgs[] __initdata = {
 
 /* Frame Buffer */
 static struct s3c_fb_pd_win goni_fb_win0 = {
-       .win_mode = {
-               .left_margin    = 16,
-               .right_margin   = 16,
-               .upper_margin   = 2,
-               .lower_margin   = 28,
-               .hsync_len      = 2,
-               .vsync_len      = 1,
-               .xres           = 480,
-               .yres           = 800,
-               .refresh        = 55,
-       },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .xres           = 480,
+       .yres           = 800,
        .virtual_x      = 480,
        .virtual_y      = 2 * 800,
 };
 
+static struct fb_videomode goni_lcd_timing = {
+       .left_margin    = 16,
+       .right_margin   = 16,
+       .upper_margin   = 2,
+       .lower_margin   = 28,
+       .hsync_len      = 2,
+       .vsync_len      = 1,
+       .xres           = 480,
+       .yres           = 800,
+       .refresh        = 55,
+};
+
 static struct s3c_fb_platdata goni_lcd_pdata __initdata = {
        .win[0]         = &goni_fb_win0,
+       .vtiming        = &goni_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
                          VIDCON0_CLKSEL_LCD,
        .vidcon1        = VIDCON1_INV_VCLK | VIDCON1_INV_VDEN
index fa1b612..0d7ddec 100644 (file)
@@ -178,22 +178,26 @@ static struct platform_device smdkv210_lcd_lte480wv = {
 };
 
 static struct s3c_fb_pd_win smdkv210_fb_win0 = {
-       .win_mode = {
-               .left_margin    = 13,
-               .right_margin   = 8,
-               .upper_margin   = 7,
-               .lower_margin   = 5,
-               .hsync_len      = 3,
-               .vsync_len      = 1,
-               .xres           = 800,
-               .yres           = 480,
-       },
        .max_bpp        = 32,
        .default_bpp    = 24,
+       .xres           = 800,
+       .yres           = 480,
+};
+
+static struct fb_videomode smdkv210_lcd_timing = {
+       .left_margin    = 13,
+       .right_margin   = 8,
+       .upper_margin   = 7,
+       .lower_margin   = 5,
+       .hsync_len      = 3,
+       .vsync_len      = 1,
+       .xres           = 800,
+       .yres           = 480,
 };
 
 static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {
        .win[0]         = &smdkv210_fb_win0,
+       .vtiming        = &smdkv210_lcd_timing,
        .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
        .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
        .setup_gpio     = s5pv210_fb_gpio_setup_24bpp,
index 0fedf47..536002f 100644 (file)
 
 /**
  * struct s3c_fb_pd_win - per window setup data
- * @win_mode: The display parameters to initialise (not for window 0)
+ * @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 {
-       struct fb_videomode     win_mode;
-
        unsigned short          default_bpp;
        unsigned short          max_bpp;
+       unsigned short          xres;
+       unsigned short          yres;
        unsigned short          virtual_x;
        unsigned short          virtual_y;
 };
@@ -45,6 +46,7 @@ struct s3c_fb_pd_win {
  * @default_win: default window layer number to be used for UI layer.
  * @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.
  *
@@ -58,8 +60,7 @@ struct s3c_fb_platdata {
        void    (*setup_gpio)(void);
 
        struct s3c_fb_pd_win    *win[S3C_FB_MAX_WIN];
-
-       u32                      default_win;
+       struct fb_videomode     *vtiming;
 
        u32                      vidcon0;
        u32                      vidcon1;
index a290be5..0217f74 100644 (file)
@@ -2210,7 +2210,7 @@ config FB_XILINX
 
 config FB_COBALT
        tristate "Cobalt server LCD frame buffer support"
-       depends on FB && MIPS_COBALT
+       depends on FB && (MIPS_COBALT || MIPS_SEAD3)
 
 config FB_SH7760
        bool "SH7760/SH7763/SH7720/SH7721 LCDC support"
@@ -2382,6 +2382,39 @@ config FB_BROADSHEET
          and could also have been called by other names when coupled with
          a bridge adapter.
 
+config FB_AUO_K190X
+       tristate "AUO-K190X EPD controller support"
+       depends on FB
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       select FB_SYS_FOPS
+       select FB_DEFERRED_IO
+       help
+         Provides support for epaper controllers from the K190X series
+         of AUO. These controllers can be used to drive epaper displays
+         from Sipix.
+
+         This option enables the common support, shared by the individual
+         controller drivers. You will also have to enable the driver
+         for the controller type used in your device.
+
+config FB_AUO_K1900
+       tristate "AUO-K1900 EPD controller support"
+       depends on FB && FB_AUO_K190X
+       help
+         This driver implements support for the AUO K1900 epd-controller.
+         This controller can drive Sipix epaper displays but can only do
+         serial updates, reducing the number of possible frames per second.
+
+config FB_AUO_K1901
+       tristate "AUO-K1901 EPD controller support"
+       depends on FB && FB_AUO_K190X
+       help
+         This driver implements support for the AUO K1901 epd-controller.
+         This controller can drive Sipix epaper displays and supports
+         concurrent updates, making higher frames per second possible.
+
 config FB_JZ4740
        tristate "JZ4740 LCD framebuffer support"
        depends on FB && MACH_JZ4740
index 9356add..ee8dafb 100644 (file)
@@ -118,6 +118,9 @@ obj-$(CONFIG_FB_PMAGB_B)      += pmagb-b-fb.o
 obj-$(CONFIG_FB_MAXINE)                  += maxinefb.o
 obj-$(CONFIG_FB_METRONOME)        += metronomefb.o
 obj-$(CONFIG_FB_BROADSHEET)       += broadsheetfb.o
+obj-$(CONFIG_FB_AUO_K190X)       += auo_k190x.o
+obj-$(CONFIG_FB_AUO_K1900)       += auo_k1900fb.o
+obj-$(CONFIG_FB_AUO_K1901)       += auo_k1901fb.o
 obj-$(CONFIG_FB_S1D13XXX)        += s1d13xxxfb.o
 obj-$(CONFIG_FB_SH7760)                  += sh7760fb.o
 obj-$(CONFIG_FB_IMX)              += imxfb.o
diff --git a/drivers/video/auo_k1900fb.c b/drivers/video/auo_k1900fb.c
new file mode 100644 (file)
index 0000000..c36cf96
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * auok190xfb.c -- FB driver for AUO-K1900 controllers
+ *
+ * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on broadsheetfb.c
+ *
+ * Copyright (C) 2008, Jaya Kumar
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ *
+ * This driver is written to be used with the AUO-K1900 display controller.
+ *
+ * It is intended to be architecture independent. A board specific driver
+ * must be used to perform all the physical IO interactions.
+ *
+ * The controller supports different update modes:
+ * mode0+1 16 step gray (4bit)
+ * mode2 4 step gray (2bit) - FIXME: add strange refresh
+ * mode3 2 step gray (1bit) - FIXME: add strange refresh
+ * mode4 handwriting mode (strange behaviour)
+ * mode5 automatic selection of update mode
+ */
+
+#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/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/pm_runtime.h>
+
+#include <video/auo_k190xfb.h>
+
+#include "auo_k190x.h"
+
+/*
+ * AUO-K1900 specific commands
+ */
+
+#define AUOK1900_CMD_PARTIALDISP       0x1001
+#define AUOK1900_CMD_ROTATION          0x1006
+#define AUOK1900_CMD_LUT_STOP          0x1009
+
+#define AUOK1900_INIT_TEMP_AVERAGE     (1 << 13)
+#define AUOK1900_INIT_ROTATE(_x)       ((_x & 0x3) << 10)
+#define AUOK1900_INIT_RESOLUTION(_res) ((_res & 0x7) << 2)
+
+static void auok1900_init(struct auok190xfb_par *par)
+{
+       struct auok190x_board *board = par->board;
+       u16 init_param = 0;
+
+       init_param |= AUOK1900_INIT_TEMP_AVERAGE;
+       init_param |= AUOK1900_INIT_ROTATE(par->rotation);
+       init_param |= AUOK190X_INIT_INVERSE_WHITE;
+       init_param |= AUOK190X_INIT_FORMAT0;
+       init_param |= AUOK1900_INIT_RESOLUTION(par->resolution);
+       init_param |= AUOK190X_INIT_SHIFT_RIGHT;
+
+       auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param);
+
+       /* let the controller finish */
+       board->wait_for_rdy(par);
+}
+
+static void auok1900_update_region(struct auok190xfb_par *par, int mode,
+                                               u16 y1, u16 y2)
+{
+       struct device *dev = par->info->device;
+       unsigned char *buf = (unsigned char *)par->info->screen_base;
+       int xres = par->info->var.xres;
+       u16 args[4];
+
+       pm_runtime_get_sync(dev);
+
+       mutex_lock(&(par->io_lock));
+
+       /* y1 and y2 must be a multiple of 2 so drop the lowest bit */
+       y1 &= 0xfffe;
+       y2 &= 0xfffe;
+
+       dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n",
+               1, y1+1, xres, y2-y1, mode);
+
+       /* to FIX handle different partial update modes */
+       args[0] = mode | 1;
+       args[1] = y1 + 1;
+       args[2] = xres;
+       args[3] = y2 - y1;
+       buf += y1 * xres;
+       auok190x_send_cmdargs_pixels(par, AUOK1900_CMD_PARTIALDISP, 4, args,
+                                    ((y2 - y1) * xres)/2, (u16 *) buf);
+       auok190x_send_command(par, AUOK190X_CMD_DATA_STOP);
+
+       par->update_cnt++;
+
+       mutex_unlock(&(par->io_lock));
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+}
+
+static void auok1900fb_dpy_update_pages(struct auok190xfb_par *par,
+                                               u16 y1, u16 y2)
+{
+       int mode;
+
+       if (par->update_mode < 0) {
+               mode = AUOK190X_UPDATE_MODE(1);
+               par->last_mode = -1;
+       } else {
+               mode = AUOK190X_UPDATE_MODE(par->update_mode);
+               par->last_mode = par->update_mode;
+       }
+
+       if (par->flash)
+               mode |= AUOK190X_UPDATE_NONFLASH;
+
+       auok1900_update_region(par, mode, y1, y2);
+}
+
+static void auok1900fb_dpy_update(struct auok190xfb_par *par)
+{
+       int mode;
+
+       if (par->update_mode < 0) {
+               mode = AUOK190X_UPDATE_MODE(0);
+               par->last_mode = -1;
+       } else {
+               mode = AUOK190X_UPDATE_MODE(par->update_mode);
+               par->last_mode = par->update_mode;
+       }
+
+       if (par->flash)
+               mode |= AUOK190X_UPDATE_NONFLASH;
+
+       auok1900_update_region(par, mode, 0, par->info->var.yres);
+       par->update_cnt = 0;
+}
+
+static bool auok1900fb_need_refresh(struct auok190xfb_par *par)
+{
+       return (par->update_cnt > 10);
+}
+
+static int __devinit auok1900fb_probe(struct platform_device *pdev)
+{
+       struct auok190x_init_data init;
+       struct auok190x_board *board;
+
+       /* pick up board specific routines */
+       board = pdev->dev.platform_data;
+       if (!board)
+               return -EINVAL;
+
+       /* fill temporary init struct for common init */
+       init.id = "auo_k1900fb";
+       init.board = board;
+       init.update_partial = auok1900fb_dpy_update_pages;
+       init.update_all = auok1900fb_dpy_update;
+       init.need_refresh = auok1900fb_need_refresh;
+       init.init = auok1900_init;
+
+       return auok190x_common_probe(pdev, &init);
+}
+
+static int __devexit auok1900fb_remove(struct platform_device *pdev)
+{
+       return auok190x_common_remove(pdev);
+}
+
+static struct platform_driver auok1900fb_driver = {
+       .probe  = auok1900fb_probe,
+       .remove = __devexit_p(auok1900fb_remove),
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "auo_k1900fb",
+               .pm = &auok190x_pm,
+       },
+};
+module_platform_driver(auok1900fb_driver);
+
+MODULE_DESCRIPTION("framebuffer driver for the AUO-K1900 EPD controller");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/auo_k1901fb.c b/drivers/video/auo_k1901fb.c
new file mode 100644 (file)
index 0000000..1c054c1
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * auok190xfb.c -- FB driver for AUO-K1901 controllers
+ *
+ * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on broadsheetfb.c
+ *
+ * Copyright (C) 2008, Jaya Kumar
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ *
+ * This driver is written to be used with the AUO-K1901 display controller.
+ *
+ * It is intended to be architecture independent. A board specific driver
+ * must be used to perform all the physical IO interactions.
+ *
+ * The controller supports different update modes:
+ * mode0+1 16 step gray (4bit)
+ * mode2+3 4 step gray (2bit)
+ * mode4+5 2 step gray (1bit)
+ * - mode4 is described as "without LUT"
+ * mode7 automatic selection of update mode
+ *
+ * The most interesting difference to the K1900 is the ability to do screen
+ * updates in an asynchronous fashion. Where the K1900 needs to wait for the
+ * current update to complete, the K1901 can process later updates already.
+ */
+
+#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/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/pm_runtime.h>
+
+#include <video/auo_k190xfb.h>
+
+#include "auo_k190x.h"
+
+/*
+ * AUO-K1901 specific commands
+ */
+
+#define AUOK1901_CMD_LUT_INTERFACE     0x0005
+#define AUOK1901_CMD_DMA_START         0x1001
+#define AUOK1901_CMD_CURSOR_START      0x1007
+#define AUOK1901_CMD_CURSOR_STOP       AUOK190X_CMD_DATA_STOP
+#define AUOK1901_CMD_DDMA_START                0x1009
+
+#define AUOK1901_INIT_GATE_PULSE_LOW   (0 << 14)
+#define AUOK1901_INIT_GATE_PULSE_HIGH  (1 << 14)
+#define AUOK1901_INIT_SINGLE_GATE      (0 << 13)
+#define AUOK1901_INIT_DOUBLE_GATE      (1 << 13)
+
+/* Bits to pixels
+ *   Mode      15-12   11-8    7-4     3-0
+ *   format2   2       T       1       T
+ *   format3   1       T       2       T
+ *   format4   T       2       T       1
+ *   format5   T       1       T       2
+ *
+ *   halftone modes:
+ *   format6   2       2       1       1
+ *   format7   1       1       2       2
+ */
+#define AUOK1901_INIT_FORMAT2          (1 << 7)
+#define AUOK1901_INIT_FORMAT3          ((1 << 7) | (1 << 6))
+#define AUOK1901_INIT_FORMAT4          (1 << 8)
+#define AUOK1901_INIT_FORMAT5          ((1 << 8) | (1 << 6))
+#define AUOK1901_INIT_FORMAT6          ((1 << 8) | (1 << 7))
+#define AUOK1901_INIT_FORMAT7          ((1 << 8) | (1 << 7) | (1 << 6))
+
+/* res[4] to bit 10
+ * res[3-0] to bits 5-2
+ */
+#define AUOK1901_INIT_RESOLUTION(_res) (((_res & (1 << 4)) << 6) \
+                                        | ((_res & 0xf) << 2))
+
+/*
+ * portrait / landscape orientation in AUOK1901_CMD_DMA_START
+ */
+#define AUOK1901_DMA_ROTATE90(_rot)            ((_rot & 1) << 13)
+
+/*
+ * equivalent to 1 << 11, needs the ~ to have same rotation like K1900
+ */
+#define AUOK1901_DDMA_ROTATE180(_rot)          ((~_rot & 2) << 10)
+
+static void auok1901_init(struct auok190xfb_par *par)
+{
+       struct auok190x_board *board = par->board;
+       u16 init_param = 0;
+
+       init_param |= AUOK190X_INIT_INVERSE_WHITE;
+       init_param |= AUOK190X_INIT_FORMAT0;
+       init_param |= AUOK1901_INIT_RESOLUTION(par->resolution);
+       init_param |= AUOK190X_INIT_SHIFT_LEFT;
+
+       auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param);
+
+       /* let the controller finish */
+       board->wait_for_rdy(par);
+}
+
+static void auok1901_update_region(struct auok190xfb_par *par, int mode,
+                                               u16 y1, u16 y2)
+{
+       struct device *dev = par->info->device;
+       unsigned char *buf = (unsigned char *)par->info->screen_base;
+       int xres = par->info->var.xres;
+       u16 args[5];
+
+       pm_runtime_get_sync(dev);
+
+       mutex_lock(&(par->io_lock));
+
+       /* y1 and y2 must be a multiple of 2 so drop the lowest bit */
+       y1 &= 0xfffe;
+       y2 &= 0xfffe;
+
+       dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n",
+               1, y1+1, xres, y2-y1, mode);
+
+       /* K1901: first transfer the region data */
+       args[0] = AUOK1901_DMA_ROTATE90(par->rotation) | 1;
+       args[1] = y1 + 1;
+       args[2] = xres;
+       args[3] = y2 - y1;
+       buf += y1 * xres;
+       auok190x_send_cmdargs_pixels_nowait(par, AUOK1901_CMD_DMA_START, 4,
+                                           args, ((y2 - y1) * xres)/2,
+                                           (u16 *) buf);
+       auok190x_send_command_nowait(par, AUOK190X_CMD_DATA_STOP);
+
+       /* K1901: second tell the controller to update the region with mode */
+       args[0] = mode | AUOK1901_DDMA_ROTATE180(par->rotation);
+       args[1] = 1;
+       args[2] = y1 + 1;
+       args[3] = xres;
+       args[4] = y2 - y1;
+       auok190x_send_cmdargs_nowait(par, AUOK1901_CMD_DDMA_START, 5, args);
+
+       par->update_cnt++;
+
+       mutex_unlock(&(par->io_lock));
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+}
+
+static void auok1901fb_dpy_update_pages(struct auok190xfb_par *par,
+                                               u16 y1, u16 y2)
+{
+       int mode;
+
+       if (par->update_mode < 0) {
+               mode = AUOK190X_UPDATE_MODE(1);
+               par->last_mode = -1;
+       } else {
+               mode = AUOK190X_UPDATE_MODE(par->update_mode);
+               par->last_mode = par->update_mode;
+       }
+
+       if (par->flash)
+               mode |= AUOK190X_UPDATE_NONFLASH;
+
+       auok1901_update_region(par, mode, y1, y2);
+}
+
+static void auok1901fb_dpy_update(struct auok190xfb_par *par)
+{
+       int mode;
+
+       /* When doing full updates, wait for the controller to be ready
+        * This will hopefully catch some hangs of the K1901
+        */
+       par->board->wait_for_rdy(par);
+
+       if (par->update_mode < 0) {
+               mode = AUOK190X_UPDATE_MODE(0);
+               par->last_mode = -1;
+       } else {
+               mode = AUOK190X_UPDATE_MODE(par->update_mode);
+               par->last_mode = par->update_mode;
+       }
+
+       if (par->flash)
+               mode |= AUOK190X_UPDATE_NONFLASH;
+
+       auok1901_update_region(par, mode, 0, par->info->var.yres);
+       par->update_cnt = 0;
+}
+
+static bool auok1901fb_need_refresh(struct auok190xfb_par *par)
+{
+       return (par->update_cnt > 10);
+}
+
+static int __devinit auok1901fb_probe(struct platform_device *pdev)
+{
+       struct auok190x_init_data init;
+       struct auok190x_board *board;
+
+       /* pick up board specific routines */
+       board = pdev->dev.platform_data;
+       if (!board)
+               return -EINVAL;
+
+       /* fill temporary init struct for common init */
+       init.id = "auo_k1901fb";
+       init.board = board;
+       init.update_partial = auok1901fb_dpy_update_pages;
+       init.update_all = auok1901fb_dpy_update;
+       init.need_refresh = auok1901fb_need_refresh;
+       init.init = auok1901_init;
+
+       return auok190x_common_probe(pdev, &init);
+}
+
+static int __devexit auok1901fb_remove(struct platform_device *pdev)
+{
+       return auok190x_common_remove(pdev);
+}
+
+static struct platform_driver auok1901fb_driver = {
+       .probe  = auok1901fb_probe,
+       .remove = __devexit_p(auok1901fb_remove),
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "auo_k1901fb",
+               .pm = &auok190x_pm,
+       },
+};
+module_platform_driver(auok1901fb_driver);
+
+MODULE_DESCRIPTION("framebuffer driver for the AUO-K1901 EPD controller");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/auo_k190x.c b/drivers/video/auo_k190x.c
new file mode 100644 (file)
index 0000000..77da6a2
--- /dev/null
@@ -0,0 +1,1046 @@
+/*
+ * Common code for AUO-K190X framebuffer drivers
+ *
+ * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/auo_k190xfb.h>
+
+#include "auo_k190x.h"
+
+struct panel_info {
+       int w;
+       int h;
+};
+
+/* table of panel specific parameters to be indexed into by the board drivers */
+static struct panel_info panel_table[] = {
+       /* standard 6" */
+       [AUOK190X_RESOLUTION_800_600] = {
+               .w = 800,
+               .h = 600,
+       },
+       /* standard 9" */
+       [AUOK190X_RESOLUTION_1024_768] = {
+               .w = 1024,
+               .h = 768,
+       },
+};
+
+/*
+ * private I80 interface to the board driver
+ */
+
+static void auok190x_issue_data(struct auok190xfb_par *par, u16 data)
+{
+       par->board->set_ctl(par, AUOK190X_I80_WR, 0);
+       par->board->set_hdb(par, data);
+       par->board->set_ctl(par, AUOK190X_I80_WR, 1);
+}
+
+static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data)
+{
+       par->board->set_ctl(par, AUOK190X_I80_DC, 0);
+       auok190x_issue_data(par, data);
+       par->board->set_ctl(par, AUOK190X_I80_DC, 1);
+}
+
+static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
+                                u16 *data)
+{
+       struct device *dev = par->info->device;
+       int i;
+       u16 tmp;
+
+       if (size & 3) {
+               dev_err(dev, "issue_pixels: size %d must be a multiple of 4\n",
+                       size);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < (size >> 1); i++) {
+               par->board->set_ctl(par, AUOK190X_I80_WR, 0);
+
+               /* simple reduction of 8bit staticgray to 4bit gray
+                * combines 4 * 4bit pixel values into a 16bit value
+                */
+               tmp  = (data[2*i] & 0xF0) >> 4;
+               tmp |= (data[2*i] & 0xF000) >> 8;
+               tmp |= (data[2*i+1] & 0xF0) << 4;
+               tmp |= (data[2*i+1] & 0xF000);
+
+               par->board->set_hdb(par, tmp);
+               par->board->set_ctl(par, AUOK190X_I80_WR, 1);
+       }
+
+       return 0;
+}
+
+static u16 auok190x_read_data(struct auok190xfb_par *par)
+{
+       u16 data;
+
+       par->board->set_ctl(par, AUOK190X_I80_OE, 0);
+       data = par->board->get_hdb(par);
+       par->board->set_ctl(par, AUOK190X_I80_OE, 1);
+
+       return data;
+}
+
+/*
+ * Command interface for the controller drivers
+ */
+
+void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data)
+{
+       par->board->set_ctl(par, AUOK190X_I80_CS, 0);
+       auok190x_issue_cmd(par, data);
+       par->board->set_ctl(par, AUOK190X_I80_CS, 1);
+}
+EXPORT_SYMBOL_GPL(auok190x_send_command_nowait);
+
+void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd,
+                                 int argc, u16 *argv)
+{
+       int i;
+
+       par->board->set_ctl(par, AUOK190X_I80_CS, 0);
+       auok190x_issue_cmd(par, cmd);
+
+       for (i = 0; i < argc; i++)
+               auok190x_issue_data(par, argv[i]);
+       par->board->set_ctl(par, AUOK190X_I80_CS, 1);
+}
+EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_nowait);
+
+int auok190x_send_command(struct auok190xfb_par *par, u16 data)
+{
+       int ret;
+
+       ret = par->board->wait_for_rdy(par);
+       if (ret)
+               return ret;
+
+       auok190x_send_command_nowait(par, data);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_send_command);
+
+int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd,
+                          int argc, u16 *argv)
+{
+       int ret;
+
+       ret = par->board->wait_for_rdy(par);
+       if (ret)
+               return ret;
+
+       auok190x_send_cmdargs_nowait(par, cmd, argc, argv);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_send_cmdargs);
+
+int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd,
+                          int argc, u16 *argv)
+{
+       int i, ret;
+
+       ret = par->board->wait_for_rdy(par);
+       if (ret)
+               return ret;
+
+       par->board->set_ctl(par, AUOK190X_I80_CS, 0);
+       auok190x_issue_cmd(par, cmd);
+
+       for (i = 0; i < argc; i++)
+               argv[i] = auok190x_read_data(par);
+       par->board->set_ctl(par, AUOK190X_I80_CS, 1);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_read_cmdargs);
+
+void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, u16 cmd,
+                                 int argc, u16 *argv, int size, u16 *data)
+{
+       int i;
+
+       par->board->set_ctl(par, AUOK190X_I80_CS, 0);
+
+       auok190x_issue_cmd(par, cmd);
+
+       for (i = 0; i < argc; i++)
+               auok190x_issue_data(par, argv[i]);
+
+       auok190x_issue_pixels(par, size, data);
+
+       par->board->set_ctl(par, AUOK190X_I80_CS, 1);
+}
+EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels_nowait);
+
+int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd,
+                                 int argc, u16 *argv, int size, u16 *data)
+{
+       int ret;
+
+       ret = par->board->wait_for_rdy(par);
+       if (ret)
+               return ret;
+
+       auok190x_send_cmdargs_pixels_nowait(par, cmd, argc, argv, size, data);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels);
+
+/*
+ * fbdefio callbacks - common on both controllers.
+ */
+
+static void auok190xfb_dpy_first_io(struct fb_info *info)
+{
+       /* tell runtime-pm that we wish to use the device in a short time */
+       pm_runtime_get(info->device);
+}
+
+/* this is called back from the deferred io workqueue */
+static void auok190xfb_dpy_deferred_io(struct fb_info *info,
+                               struct list_head *pagelist)
+{
+       struct fb_deferred_io *fbdefio = info->fbdefio;
+       struct auok190xfb_par *par = info->par;
+       u16 yres = info->var.yres;
+       u16 xres = info->var.xres;
+       u16 y1 = 0, h = 0;
+       int prev_index = -1;
+       struct page *cur;
+       int h_inc;
+       int threshold;
+
+       if (!list_empty(pagelist))
+               /* the device resume should've been requested through first_io,
+                * if the resume did not finish until now, wait for it.
+                */
+               pm_runtime_barrier(info->device);
+       else
+               /* We reached this via the fsync or some other way.
+                * In either case the first_io function did not run,
+                * so we runtime_resume the device here synchronously.
+                */
+               pm_runtime_get_sync(info->device);
+
+       /* Do a full screen update every n updates to prevent
+        * excessive darkening of the Sipix display.
+        * If we do this, there is no need to walk the pages.
+        */
+       if (par->need_refresh(par)) {
+               par->update_all(par);
+               goto out;
+       }
+
+       /* height increment is fixed per page */
+       h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
+
+       /* calculate number of pages from pixel height */
+       threshold = par->consecutive_threshold / h_inc;
+       if (threshold < 1)
+               threshold = 1;
+
+       /* walk the written page list and swizzle the data */
+       list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+               if (prev_index < 0) {
+                       /* just starting so assign first page */
+                       y1 = (cur->index << PAGE_SHIFT) / xres;
+                       h = h_inc;
+               } else if ((cur->index - prev_index) <= threshold) {
+                       /* page is within our threshold for single updates */
+                       h += h_inc * (cur->index - prev_index);
+               } else {
+                       /* page not consecutive, issue previous update first */
+                       par->update_partial(par, y1, y1 + h);
+
+                       /* start over with our non consecutive page */
+                       y1 = (cur->index << PAGE_SHIFT) / xres;
+                       h = h_inc;
+               }
+               prev_index = cur->index;
+       }
+
+       /* if we still have any pages to update we do so now */
+       if (h >= yres)
+               /* its a full screen update, just do it */
+               par->update_all(par);
+       else
+               par->update_partial(par, y1, min((u16) (y1 + h), yres));
+
+out:
+       pm_runtime_mark_last_busy(info->device);
+       pm_runtime_put_autosuspend(info->device);
+}
+
+/*
+ * framebuffer operations
+ */
+
+/*
+ * this is the slow path from userspace. they can seek and write to
+ * the fb. it's inefficient to do anything less than a full screen draw
+ */
+static ssize_t auok190xfb_write(struct fb_info *info, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       struct auok190xfb_par *par = info->par;
+       unsigned long p = *ppos;
+       void *dst;
+       int err = 0;
+       unsigned long total_size;
+
+       if (info->state != FBINFO_STATE_RUNNING)
+               return -EPERM;
+
+       total_size = info->fix.smem_len;
+
+       if (p > total_size)
+               return -EFBIG;
+
+       if (count > total_size) {
+               err = -EFBIG;
+               count = total_size;
+       }
+
+       if (count + p > total_size) {
+               if (!err)
+                       err = -ENOSPC;
+
+               count = total_size - p;
+       }
+
+       dst = (void *)(info->screen_base + p);
+
+       if (copy_from_user(dst, buf, count))
+               err = -EFAULT;
+
+       if  (!err)
+               *ppos += count;
+
+       par->update_all(par);
+
+       return (err) ? err : count;
+}
+
+static void auok190xfb_fillrect(struct fb_info *info,
+                                  const struct fb_fillrect *rect)
+{
+       struct auok190xfb_par *par = info->par;
+
+       sys_fillrect(info, rect);
+
+       par->update_all(par);
+}
+
+static void auok190xfb_copyarea(struct fb_info *info,
+                                  const struct fb_copyarea *area)
+{
+       struct auok190xfb_par *par = info->par;
+
+       sys_copyarea(info, area);
+
+       par->update_all(par);
+}
+
+static void auok190xfb_imageblit(struct fb_info *info,
+                               const struct fb_image *image)
+{
+       struct auok190xfb_par *par = info->par;
+
+       sys_imageblit(info, image);
+
+       par->update_all(par);
+}
+
+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);
+               return -EINVAL;
+       }
+
+       /*
+        *  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);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static struct fb_ops auok190xfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_read        = fb_sys_read,
+       .fb_write       = auok190xfb_write,
+       .fb_fillrect    = auok190xfb_fillrect,
+       .fb_copyarea    = auok190xfb_copyarea,
+       .fb_imageblit   = auok190xfb_imageblit,
+       .fb_check_var   = auok190xfb_check_var,
+};
+
+/*
+ * Controller-functions common to both K1900 and K1901
+ */
+
+static int auok190x_read_temperature(struct auok190xfb_par *par)
+{
+       struct device *dev = par->info->device;
+       u16 data[4];
+       int temp;
+
+       pm_runtime_get_sync(dev);
+
+       mutex_lock(&(par->io_lock));
+
+       auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
+
+       mutex_unlock(&(par->io_lock));
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
+       /* sanitize and split of half-degrees for now */
+       temp = ((data[0] & AUOK190X_VERSION_TEMP_MASK) >> 1);
+
+       /* handle positive and negative temperatures */
+       if (temp >= 201)
+               return (255 - temp + 1) * (-1);
+       else
+               return temp;
+}
+
+static void auok190x_identify(struct auok190xfb_par *par)
+{
+       struct device *dev = par->info->device;
+       u16 data[4];
+
+       pm_runtime_get_sync(dev);
+
+       mutex_lock(&(par->io_lock));
+
+       auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
+
+       mutex_unlock(&(par->io_lock));
+
+       par->epd_type = data[1] & AUOK190X_VERSION_TEMP_MASK;
+
+       par->panel_size_int = AUOK190X_VERSION_SIZE_INT(data[2]);
+       par->panel_size_float = AUOK190X_VERSION_SIZE_FLOAT(data[2]);
+       par->panel_model = AUOK190X_VERSION_MODEL(data[2]);
+
+       par->tcon_version = AUOK190X_VERSION_TCON(data[3]);
+       par->lut_version = AUOK190X_VERSION_LUT(data[3]);
+
+       dev_dbg(dev, "panel %d.%din, model 0x%x, EPD 0x%x TCON-rev 0x%x, LUT-rev 0x%x",
+               par->panel_size_int, par->panel_size_float, par->panel_model,
+               par->epd_type, par->tcon_version, par->lut_version);
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+}
+
+/*
+ * Sysfs functions
+ */
+
+static ssize_t update_mode_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct auok190xfb_par *par = info->par;
+
+       return sprintf(buf, "%d\n", par->update_mode);
+}
+
+static ssize_t update_mode_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct auok190xfb_par *par = info->par;
+       int mode, ret;
+
+       ret = kstrtoint(buf, 10, &mode);
+       if (ret)
+               return ret;
+
+       par->update_mode = mode;
+
+       /* if we enter a better mode, do a full update */
+       if (par->last_mode > 1 && mode < par->last_mode)
+               par->update_all(par);
+
+       return count;
+}
+
+static ssize_t flash_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct auok190xfb_par *par = info->par;
+
+       return sprintf(buf, "%d\n", par->flash);
+}
+
+static ssize_t flash_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct auok190xfb_par *par = info->par;
+       int flash, ret;
+
+       ret = kstrtoint(buf, 10, &flash);
+       if (ret)
+               return ret;
+
+       if (flash > 0)
+               par->flash = 1;
+       else
+               par->flash = 0;
+
+       return count;
+}
+
+static ssize_t temp_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct auok190xfb_par *par = info->par;
+       int temp;
+
+       temp = auok190x_read_temperature(par);
+       return sprintf(buf, "%d\n", temp);
+}
+
+static DEVICE_ATTR(update_mode, 0644, update_mode_show, update_mode_store);
+static DEVICE_ATTR(flash, 0644, flash_show, flash_store);
+static DEVICE_ATTR(temp, 0644, temp_show, NULL);
+
+static struct attribute *auok190x_attributes[] = {
+       &dev_attr_update_mode.attr,
+       &dev_attr_flash.attr,
+       &dev_attr_temp.attr,
+       NULL
+};
+
+static const struct attribute_group auok190x_attr_group = {
+       .attrs          = auok190x_attributes,
+};
+
+static int auok190x_power(struct auok190xfb_par *par, bool on)
+{
+       struct auok190x_board *board = par->board;
+       int ret;
+
+       if (on) {
+               /* We should maintain POWER up for at least 80ms before set
+                * RST_N and SLP_N to high (TCON spec 20100803_v35 p59)
+                */
+               ret = regulator_enable(par->regulator);
+               if (ret)
+                       return ret;
+
+               msleep(200);
+               gpio_set_value(board->gpio_nrst, 1);
+               gpio_set_value(board->gpio_nsleep, 1);
+               msleep(200);
+       } else {
+               regulator_disable(par->regulator);
+               gpio_set_value(board->gpio_nrst, 0);
+               gpio_set_value(board->gpio_nsleep, 0);
+       }
+
+       return 0;
+}
+
+/*
+ * Recovery - powercycle the controller
+ */
+
+static void auok190x_recover(struct auok190xfb_par *par)
+{
+       auok190x_power(par, 0);
+       msleep(100);
+       auok190x_power(par, 1);
+
+       par->init(par);
+
+       /* wait for init to complete */
+       par->board->wait_for_rdy(par);
+}
+
+/*
+ * Power-management
+ */
+
+#ifdef CONFIG_PM
+static int auok190x_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct fb_info *info = platform_get_drvdata(pdev);
+       struct auok190xfb_par *par = info->par;
+       struct auok190x_board *board = par->board;
+       u16 standby_param;
+
+       /* take and keep the lock until we are resumed, as the controller
+        * will never reach the non-busy state when in standby mode
+        */
+       mutex_lock(&(par->io_lock));
+
+       if (par->standby) {
+               dev_warn(dev, "already in standby, runtime-pm pairing mismatch\n");
+               mutex_unlock(&(par->io_lock));
+               return 0;
+       }
+
+       /* according to runtime_pm.txt runtime_suspend only means, that the
+        * device will not process data and will not communicate with the CPU
+        * As we hold the lock, this stays true even without standby
+        */
+       if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
+               dev_dbg(dev, "runtime suspend without standby\n");
+               goto finish;
+       } else if (board->quirks & AUOK190X_QUIRK_STANDBYPARAM) {
+               /* for some TCON versions STANDBY expects a parameter (0) but
+                * it seems the real tcon version has to be determined yet.
+                */
+               dev_dbg(dev, "runtime suspend with additional empty param\n");
+               standby_param = 0;
+               auok190x_send_cmdargs(par, AUOK190X_CMD_STANDBY, 1,
+                                     &standby_param);
+       } else {
+               dev_dbg(dev, "runtime suspend without param\n");
+               auok190x_send_command(par, AUOK190X_CMD_STANDBY);
+       }
+
+       msleep(64);
+
+finish:
+       par->standby = 1;
+
+       return 0;
+}
+
+static int auok190x_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct fb_info *info = platform_get_drvdata(pdev);
+       struct auok190xfb_par *par = info->par;
+       struct auok190x_board *board = par->board;
+
+       if (!par->standby) {
+               dev_warn(dev, "not in standby, runtime-pm pairing mismatch\n");
+               return 0;
+       }
+
+       if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
+               dev_dbg(dev, "runtime resume without standby\n");
+       } else {
+               /* when in standby, controller is always busy
+                * and only accepts the wakeup command
+                */
+               dev_dbg(dev, "runtime resume from standby\n");
+               auok190x_send_command_nowait(par, AUOK190X_CMD_WAKEUP);
+
+               msleep(160);
+
+               /* wait for the controller to be ready and release the lock */
+               board->wait_for_rdy(par);
+       }
+
+       par->standby = 0;
+
+       mutex_unlock(&(par->io_lock));
+
+       return 0;
+}
+
+static int auok190x_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct fb_info *info = platform_get_drvdata(pdev);
+       struct auok190xfb_par *par = info->par;
+       struct auok190x_board *board = par->board;
+       int ret;
+
+       dev_dbg(dev, "suspend\n");
+       if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
+               /* suspend via powering off the ic */
+               dev_dbg(dev, "suspend with broken standby\n");
+
+               auok190x_power(par, 0);
+       } else {
+               dev_dbg(dev, "suspend using sleep\n");
+
+               /* the sleep state can only be entered from the standby state.
+                * pm_runtime_get_noresume gets called before the suspend call.
+                * So the devices usage count is >0 but it is not necessarily
+                * active.
+                */
+               if (!pm_runtime_status_suspended(dev)) {
+                       ret = auok190x_runtime_suspend(dev);
+                       if (ret < 0) {
+                               dev_err(dev, "auok190x_runtime_suspend failed with %d\n",
+                                       ret);
+                               return ret;
+                       }
+                       par->manual_standby = 1;
+               }
+
+               gpio_direction_output(board->gpio_nsleep, 0);
+       }
+
+       msleep(100);
+
+       return 0;
+}
+
+static int auok190x_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct fb_info *info = platform_get_drvdata(pdev);
+       struct auok190xfb_par *par = info->par;
+       struct auok190x_board *board = par->board;
+
+       dev_dbg(dev, "resume\n");
+       if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
+               dev_dbg(dev, "resume with broken standby\n");
+
+               auok190x_power(par, 1);
+
+               par->init(par);
+       } else {
+               dev_dbg(dev, "resume from sleep\n");
+
+               /* device should be in runtime suspend when we were suspended
+                * and pm_runtime_put_sync gets called after this function.
+                * So there is no need to touch the standby mode here at all.
+                */
+               gpio_direction_output(board->gpio_nsleep, 1);
+               msleep(100);
+
+               /* an additional init call seems to be necessary after sleep */
+               auok190x_runtime_resume(dev);
+               par->init(par);
+
+               /* if we were runtime-suspended before, suspend again*/
+               if (!par->manual_standby)
+                       auok190x_runtime_suspend(dev);
+               else
+                       par->manual_standby = 0;
+       }
+
+       return 0;
+}
+#endif
+
+const struct dev_pm_ops auok190x_pm = {
+       SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume,
+                          NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(auok190x_suspend, auok190x_resume)
+};
+EXPORT_SYMBOL_GPL(auok190x_pm);
+
+/*
+ * Common probe and remove code
+ */
+
+int __devinit auok190x_common_probe(struct platform_device *pdev,
+                                   struct auok190x_init_data *init)
+{
+       struct auok190x_board *board = init->board;
+       struct auok190xfb_par *par;
+       struct fb_info *info;
+       struct panel_info *panel;
+       int videomemorysize, ret;
+       unsigned char *videomemory;
+
+       /* check board contents */
+       if (!board->init || !board->cleanup || !board->wait_for_rdy
+           || !board->set_ctl || !board->set_hdb || !board->get_hdb
+           || !board->setup_irq)
+               return -EINVAL;
+
+       info = framebuffer_alloc(sizeof(struct auok190xfb_par), &pdev->dev);
+       if (!info)
+               return -ENOMEM;
+
+       par = info->par;
+       par->info = info;
+       par->board = board;
+       par->recover = auok190x_recover;
+       par->update_partial = init->update_partial;
+       par->update_all = init->update_all;
+       par->need_refresh = init->need_refresh;
+       par->init = init->init;
+
+       /* init update modes */
+       par->update_cnt = 0;
+       par->update_mode = -1;
+       par->last_mode = -1;
+       par->flash = 0;
+
+       par->regulator = regulator_get(info->device, "vdd");
+       if (IS_ERR(par->regulator)) {
+               ret = PTR_ERR(par->regulator);
+               dev_err(info->device, "Failed to get regulator: %d\n", ret);
+               goto err_reg;
+       }
+
+       ret = board->init(par);
+       if (ret) {
+               dev_err(info->device, "board init failed, %d\n", ret);
+               goto err_board;
+       }
+
+       ret = gpio_request(board->gpio_nsleep, "AUOK190x sleep");
+       if (ret) {
+               dev_err(info->device, "could not request sleep gpio, %d\n",
+                       ret);
+               goto err_gpio1;
+       }
+
+       ret = gpio_direction_output(board->gpio_nsleep, 0);
+       if (ret) {
+               dev_err(info->device, "could not set sleep gpio, %d\n", ret);
+               goto err_gpio2;
+       }
+
+       ret = gpio_request(board->gpio_nrst, "AUOK190x reset");
+       if (ret) {
+               dev_err(info->device, "could not request reset gpio, %d\n",
+                       ret);
+               goto err_gpio2;
+       }
+
+       ret = gpio_direction_output(board->gpio_nrst, 0);
+       if (ret) {
+               dev_err(info->device, "could not set reset gpio, %d\n", ret);
+               goto err_gpio3;
+       }
+
+       ret = auok190x_power(par, 1);
+       if (ret) {
+               dev_err(info->device, "could not power on the device, %d\n",
+                       ret);
+               goto err_gpio3;
+       }
+
+       mutex_init(&par->io_lock);
+
+       init_waitqueue_head(&par->waitq);
+
+       ret = par->board->setup_irq(par->info);
+       if (ret) {
+               dev_err(info->device, "could not setup ready-irq, %d\n", ret);
+               goto err_irq;
+       }
+
+       /* wait for init to complete */
+       par->board->wait_for_rdy(par);
+
+       /*
+        * From here on the controller can talk to us
+        */
+
+       /* 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;
+
+       /* videomemory handling */
+
+       videomemorysize = roundup((panel->w * panel->h), PAGE_SIZE);
+       videomemory = vmalloc(videomemorysize);
+       if (!videomemory) {
+               ret = -ENOMEM;
+               goto err_irq;
+       }
+
+       memset(videomemory, 0, videomemorysize);
+       info->screen_base = (char *)videomemory;
+       info->fix.smem_len = videomemorysize;
+
+       info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
+       info->fbops = &auok190xfb_ops;
+
+       /* deferred io init */
+
+       info->fbdefio = devm_kzalloc(info->device,
+                                    sizeof(struct fb_deferred_io),
+                                    GFP_KERNEL);
+       if (!info->fbdefio) {
+               dev_err(info->device, "Failed to allocate memory\n");
+               ret = -ENOMEM;
+               goto err_defio;
+       }
+
+       dev_dbg(info->device, "targetting %d frames per second\n", board->fps);
+       info->fbdefio->delay = HZ / board->fps;
+       info->fbdefio->first_io = auok190xfb_dpy_first_io,
+       info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io,
+       fb_deferred_io_init(info);
+
+       /* color map */
+
+       ret = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (ret < 0) {
+               dev_err(info->device, "Failed to allocate colormap\n");
+               goto err_cmap;
+       }
+
+       /* controller init */
+
+       par->consecutive_threshold = 100;
+       par->init(par);
+       auok190x_identify(par);
+
+       platform_set_drvdata(pdev, info);
+
+       ret = register_framebuffer(info);
+       if (ret < 0)
+               goto err_regfb;
+
+       ret = sysfs_create_group(&info->device->kobj, &auok190x_attr_group);
+       if (ret)
+               goto err_sysfs;
+
+       dev_info(info->device, "fb%d: %dx%d using %dK of video memory\n",
+                info->node, info->var.xres, info->var.yres,
+                videomemorysize >> 10);
+
+       /* increase autosuspend_delay when we use alternative methods
+        * for runtime_pm
+        */
+       par->autosuspend_delay = (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN)
+                                       ? 1000 : 200;
+
+       pm_runtime_set_active(info->device);
+       pm_runtime_enable(info->device);
+       pm_runtime_set_autosuspend_delay(info->device, par->autosuspend_delay);
+       pm_runtime_use_autosuspend(info->device);
+
+       return 0;
+
+err_sysfs:
+       unregister_framebuffer(info);
+err_regfb:
+       fb_dealloc_cmap(&info->cmap);
+err_cmap:
+       fb_deferred_io_cleanup(info);
+       kfree(info->fbdefio);
+err_defio:
+       vfree((void *)info->screen_base);
+err_irq:
+       auok190x_power(par, 0);
+err_gpio3:
+       gpio_free(board->gpio_nrst);
+err_gpio2:
+       gpio_free(board->gpio_nsleep);
+err_gpio1:
+       board->cleanup(par);
+err_board:
+       regulator_put(par->regulator);
+err_reg:
+       framebuffer_release(info);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(auok190x_common_probe);
+
+int  __devexit auok190x_common_remove(struct platform_device *pdev)
+{
+       struct fb_info *info = platform_get_drvdata(pdev);
+       struct auok190xfb_par *par = info->par;
+       struct auok190x_board *board = par->board;
+
+       pm_runtime_disable(info->device);
+
+       sysfs_remove_group(&info->device->kobj, &auok190x_attr_group);
+
+       unregister_framebuffer(info);
+
+       fb_dealloc_cmap(&info->cmap);
+
+       fb_deferred_io_cleanup(info);
+       kfree(info->fbdefio);
+
+       vfree((void *)info->screen_base);
+
+       auok190x_power(par, 0);
+
+       gpio_free(board->gpio_nrst);
+       gpio_free(board->gpio_nsleep);
+
+       board->cleanup(par);
+
+       regulator_put(par->regulator);
+
+       framebuffer_release(info);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_common_remove);
+
+MODULE_DESCRIPTION("Common code for AUO-K190X controllers");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/auo_k190x.h b/drivers/video/auo_k190x.h
new file mode 100644 (file)
index 0000000..e35af1f
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Private common definitions for AUO-K190X framebuffer drivers
+ *
+ * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * I80 interface specific defines
+ */
+
+#define AUOK190X_I80_CS                        0x01
+#define AUOK190X_I80_DC                        0x02
+#define AUOK190X_I80_WR                        0x03
+#define AUOK190X_I80_OE                        0x04
+
+/*
+ * AUOK190x commands, common to both controllers
+ */
+
+#define AUOK190X_CMD_INIT              0x0000
+#define AUOK190X_CMD_STANDBY           0x0001
+#define AUOK190X_CMD_WAKEUP            0x0002
+#define AUOK190X_CMD_TCON_RESET                0x0003
+#define AUOK190X_CMD_DATA_STOP         0x1002
+#define AUOK190X_CMD_LUT_START         0x1003
+#define AUOK190X_CMD_DISP_REFRESH      0x1004
+#define AUOK190X_CMD_DISP_RESET                0x1005
+#define AUOK190X_CMD_PRE_DISPLAY_START 0x100D
+#define AUOK190X_CMD_PRE_DISPLAY_STOP  0x100F
+#define AUOK190X_CMD_FLASH_W           0x2000
+#define AUOK190X_CMD_FLASH_E           0x2001
+#define AUOK190X_CMD_FLASH_STS         0x2002
+#define AUOK190X_CMD_FRAMERATE         0x3000
+#define AUOK190X_CMD_READ_VERSION      0x4000
+#define AUOK190X_CMD_READ_STATUS       0x4001
+#define AUOK190X_CMD_READ_LUT          0x4003
+#define AUOK190X_CMD_DRIVERTIMING      0x5000
+#define AUOK190X_CMD_LBALANCE          0x5001
+#define AUOK190X_CMD_AGINGMODE         0x6000
+#define AUOK190X_CMD_AGINGEXIT         0x6001
+
+/*
+ * Common settings for AUOK190X_CMD_INIT
+ */
+
+#define AUOK190X_INIT_DATA_FILTER      (0 << 12)
+#define AUOK190X_INIT_DATA_BYPASS      (1 << 12)
+#define AUOK190X_INIT_INVERSE_WHITE    (0 << 9)
+#define AUOK190X_INIT_INVERSE_BLACK    (1 << 9)
+#define AUOK190X_INIT_SCAN_DOWN                (0 << 1)
+#define AUOK190X_INIT_SCAN_UP          (1 << 1)
+#define AUOK190X_INIT_SHIFT_LEFT       (0 << 0)
+#define AUOK190X_INIT_SHIFT_RIGHT      (1 << 0)
+
+/* Common bits to pixels
+ *   Mode      15-12   11-8    7-4     3-0
+ *   format0   4       3       2       1
+ *   format1   3       4       1       2
+ */
+
+#define AUOK190X_INIT_FORMAT0          0
+#define AUOK190X_INIT_FORMAT1          (1 << 6)
+
+/*
+ * settings for AUOK190X_CMD_RESET
+ */
+
+#define AUOK190X_RESET_TCON            (0 << 0)
+#define AUOK190X_RESET_NORMAL          (1 << 0)
+#define AUOK190X_RESET_PON             (1 << 1)
+
+/*
+ * AUOK190X_CMD_VERSION
+ */
+
+#define AUOK190X_VERSION_TEMP_MASK             (0x1ff)
+#define AUOK190X_VERSION_EPD_MASK              (0xff)
+#define AUOK190X_VERSION_SIZE_INT(_val)                ((_val & 0xfc00) >> 10)
+#define AUOK190X_VERSION_SIZE_FLOAT(_val)      ((_val & 0x3c0) >> 6)
+#define AUOK190X_VERSION_MODEL(_val)           (_val & 0x3f)
+#define AUOK190X_VERSION_LUT(_val)             (_val & 0xff)
+#define AUOK190X_VERSION_TCON(_val)            ((_val & 0xff00) >> 8)
+
+/*
+ * update modes for CMD_PARTIALDISP on K1900 and CMD_DDMA on K1901
+ */
+
+#define AUOK190X_UPDATE_MODE(_res)             ((_res & 0x7) << 12)
+#define AUOK190X_UPDATE_NONFLASH               (1 << 15)
+
+/*
+ * track panel specific parameters for common init
+ */
+
+struct auok190x_init_data {
+       char *id;
+       struct auok190x_board *board;
+
+       void (*update_partial)(struct auok190xfb_par *par, u16 y1, u16 y2);
+       void (*update_all)(struct auok190xfb_par *par);
+       bool (*need_refresh)(struct auok190xfb_par *par);
+       void (*init)(struct auok190xfb_par *par);
+};
+
+
+extern void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data);
+extern int auok190x_send_command(struct auok190xfb_par *par, u16 data);
+extern void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd,
+                                        int argc, u16 *argv);
+extern int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd,
+                                 int argc, u16 *argv);
+extern void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par,
+                                               u16 cmd, int argc, u16 *argv,
+                                               int size, u16 *data);
+extern int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd,
+                                       int argc, u16 *argv, int size,
+                                       u16 *data);
+extern int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd,
+                                 int argc, u16 *argv);
+
+extern int auok190x_common_probe(struct platform_device *pdev,
+                                struct auok190x_init_data *init);
+extern int auok190x_common_remove(struct platform_device *pdev);
+
+extern const struct dev_pm_ops auok190x_pm;
index 1a268a2..33ea874 100644 (file)
@@ -414,14 +414,14 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
                if (ret) {
                        dev_err(&client->dev, "PPI0_FS3 GPIO request failed\n");
                        ret = -EBUSY;
-                       goto out_8;
+                       goto free_fbdev;
                }
        }
 
        if (peripheral_request_list(ppi_pins, DRIVER_NAME)) {
                dev_err(&client->dev, "requesting PPI peripheral failed\n");
                ret = -EFAULT;
-               goto out_8;
+               goto free_gpio;
        }
 
        fbdev->fb_mem =
@@ -432,7 +432,7 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
                dev_err(&client->dev, "couldn't allocate dma buffer (%d bytes)\n",
                       (u32) fbdev->fb_len);
                ret = -ENOMEM;
-               goto out_7;
+               goto free_ppi_pins;
        }
 
        fbdev->info.screen_base = (void *)fbdev->fb_mem;
@@ -464,27 +464,27 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
        if (!fbdev->info.pseudo_palette) {
                dev_err(&client->dev, "failed to allocate pseudo_palette\n");
                ret = -ENOMEM;
-               goto out_6;
+               goto free_fb_mem;
        }
 
        if (fb_alloc_cmap(&fbdev->info.cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
                dev_err(&client->dev, "failed to allocate colormap (%d entries)\n",
                           BFIN_LCD_NBR_PALETTE_ENTRIES);
                ret = -EFAULT;
-               goto out_5;
+               goto free_palette;
        }
 
        if (request_dma(CH_PPI, "BF5xx_PPI_DMA") < 0) {
                dev_err(&client->dev, "unable to request PPI DMA\n");
                ret = -EFAULT;
-               goto out_4;
+               goto free_cmap;
        }
 
        if (request_irq(IRQ_PPI_ERROR, ppi_irq_error, 0,
                        "PPI ERROR", fbdev) < 0) {
                dev_err(&client->dev, "unable to request PPI ERROR IRQ\n");
                ret = -EFAULT;
-               goto out_3;
+               goto free_ch_ppi;
        }
 
        fbdev->open = 0;
@@ -494,14 +494,14 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
 
        if (ret) {
                dev_err(&client->dev, "i2c attach: init error\n");
-               goto out_1;
+               goto free_irq_ppi;
        }
 
 
        if (register_framebuffer(&fbdev->info) < 0) {
                dev_err(&client->dev, "unable to register framebuffer\n");
                ret = -EFAULT;
-               goto out_1;
+               goto free_irq_ppi;
        }
 
        dev_info(&client->dev, "fb%d: %s frame buffer device\n",
@@ -512,7 +512,7 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
        if (!entry) {
                dev_err(&client->dev, "unable to create /proc entry\n");
                ret = -EFAULT;
-               goto out_0;
+               goto free_fb;
        }
 
        entry->read_proc = adv7393_read_proc;
@@ -521,22 +521,25 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
 
        return 0;
 
- out_0:
+free_fb:
        unregister_framebuffer(&fbdev->info);
- out_1:
+free_irq_ppi:
        free_irq(IRQ_PPI_ERROR, fbdev);
- out_3:
+free_ch_ppi:
        free_dma(CH_PPI);
- out_4:
-       dma_free_coherent(NULL, fbdev->fb_len, fbdev->fb_mem,
-                         fbdev->dma_handle);
- out_5:
+free_cmap:
        fb_dealloc_cmap(&fbdev->info.cmap);
- out_6:
+free_palette:
        kfree(fbdev->info.pseudo_palette);
- out_7:
+free_fb_mem:
+       dma_free_coherent(NULL, fbdev->fb_len, fbdev->fb_mem,
+                         fbdev->dma_handle);
+free_ppi_pins:
        peripheral_free_list(ppi_pins);
- out_8:
+free_gpio:
+       if (ANOMALY_05000400)
+               gpio_free(P_IDENT(P_PPI0_FS3));
+free_fbdev:
        kfree(fbdev);
 
        return ret;
index f56699d..eae46f6 100644 (file)
@@ -1,7 +1,8 @@
 /*
- *  Cobalt server LCD frame buffer driver.
+ *  Cobalt/SEAD3 LCD frame buffer driver.
  *
  *  Copyright (C) 2008  Yoichi Yuasa <yuasa@linux-mips.org>
+ *  Copyright (C) 2012  MIPS Technologies, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -62,6 +63,7 @@
 #define LCD_CUR_POS(x)         ((x) & LCD_CUR_POS_MASK)
 #define LCD_TEXT_POS(x)                ((x) | LCD_TEXT_MODE)
 
+#ifdef CONFIG_MIPS_COBALT
 static inline void lcd_write_control(struct fb_info *info, u8 control)
 {
        writel((u32)control << 24, info->screen_base);
@@ -81,6 +83,47 @@ static inline u8 lcd_read_data(struct fb_info *info)
 {
        return readl(info->screen_base + LCD_DATA_REG_OFFSET) >> 24;
 }
+#else
+
+#define LCD_CTL                        0x00
+#define LCD_DATA               0x08
+#define CPLD_STATUS            0x10
+#define CPLD_DATA              0x18
+
+static inline void cpld_wait(struct fb_info *info)
+{
+       do {
+       } while (readl(info->screen_base + CPLD_STATUS) & 1);
+}
+
+static inline void lcd_write_control(struct fb_info *info, u8 control)
+{
+       cpld_wait(info);
+       writel(control, info->screen_base + LCD_CTL);
+}
+
+static inline u8 lcd_read_control(struct fb_info *info)
+{
+       cpld_wait(info);
+       readl(info->screen_base + LCD_CTL);
+       cpld_wait(info);
+       return readl(info->screen_base + CPLD_DATA) & 0xff;
+}
+
+static inline void lcd_write_data(struct fb_info *info, u8 data)
+{
+       cpld_wait(info);
+       writel(data, info->screen_base + LCD_DATA);
+}
+
+static inline u8 lcd_read_data(struct fb_info *info)
+{
+       cpld_wait(info);
+       readl(info->screen_base + LCD_DATA);
+       cpld_wait(info);
+       return readl(info->screen_base + CPLD_DATA) & 0xff;
+}
+#endif
 
 static int lcd_busy_wait(struct fb_info *info)
 {
index f8babbe..345d962 100644 (file)
@@ -507,16 +507,16 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
 
        err = fb_alloc_cmap(&info->cmap, 256, 0);
        if (err)
-               goto failed;
+               goto failed_cmap;
 
        err = ep93xxfb_alloc_videomem(info);
        if (err)
-               goto failed;
+               goto failed_videomem;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                err = -ENXIO;
-               goto failed;
+               goto failed_resource;
        }
 
        /*
@@ -532,7 +532,7 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
        fbi->mmio_base = ioremap(res->start, resource_size(res));
        if (!fbi->mmio_base) {
                err = -ENXIO;
-               goto failed;
+               goto failed_resource;
        }
 
        strcpy(info->fix.id, pdev->name);
@@ -553,24 +553,24 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
        if (err == 0) {
                dev_err(info->dev, "No suitable video mode found\n");
                err = -EINVAL;
-               goto failed;
+               goto failed_mode;
        }
 
        if (mach_info->setup) {
                err = mach_info->setup(pdev);
                if (err)
-                       return err;
+                       goto failed_mode;
        }
 
        err = ep93xxfb_check_var(&info->var, info);
        if (err)
-               goto failed;
+               goto failed_check;
 
        fbi->clk = clk_get(info->dev, NULL);
        if (IS_ERR(fbi->clk)) {
                err = PTR_ERR(fbi->clk);
                fbi->clk = NULL;
-               goto failed;
+               goto failed_check;
        }
 
        ep93xxfb_set_par(info);
@@ -585,15 +585,17 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
        return 0;
 
 failed:
-       if (fbi->clk)
-               clk_put(fbi->clk);
-       if (fbi->mmio_base)
-               iounmap(fbi->mmio_base);
-       ep93xxfb_dealloc_videomem(info);
-       if (&info->cmap)
-               fb_dealloc_cmap(&info->cmap);
+       clk_put(fbi->clk);
+failed_check:
        if (fbi->mach_info->teardown)
                fbi->mach_info->teardown(pdev);
+failed_mode:
+       iounmap(fbi->mmio_base);
+failed_resource:
+       ep93xxfb_dealloc_videomem(info);
+failed_videomem:
+       fb_dealloc_cmap(&info->cmap);
+failed_cmap:
        kfree(info);
        platform_set_drvdata(pdev, NULL);
 
index 2a4481c..a36b2d2 100644 (file)
 
 #include <video/exynos_dp.h>
 
-#include <plat/cpu.h>
-
 #include "exynos_dp_core.h"
 
 static int exynos_dp_init_dp(struct exynos_dp_device *dp)
 {
        exynos_dp_reset(dp);
 
+       exynos_dp_swreset(dp);
+
        /* SW defined function Normal operation */
        exynos_dp_enable_sw_function(dp);
 
@@ -478,7 +478,7 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
        int lane_count;
        u8 buf[5];
 
-       u8 *adjust_request;
+       u8 adjust_request[2];
        u8 voltage_swing;
        u8 pre_emphasis;
        u8 training_lane;
@@ -493,8 +493,8 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
                /* set training pattern 2 for EQ */
                exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
 
-               adjust_request = link_status + (DPCD_ADDR_ADJUST_REQUEST_LANE0_1
-                                               - DPCD_ADDR_LANE0_1_STATUS);
+               adjust_request[0] = link_status[4];
+               adjust_request[1] = link_status[5];
 
                exynos_dp_get_adjust_train(dp, adjust_request);
 
@@ -566,7 +566,7 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
        u8 buf[5];
        u32 reg;
 
-       u8 *adjust_request;
+       u8 adjust_request[2];
 
        udelay(400);
 
@@ -575,8 +575,8 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
        lane_count = dp->link_train.lane_count;
 
        if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
-               adjust_request = link_status + (DPCD_ADDR_ADJUST_REQUEST_LANE0_1
-                                               - DPCD_ADDR_LANE0_1_STATUS);
+               adjust_request[0] = link_status[4];
+               adjust_request[1] = link_status[5];
 
                if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) {
                        /* traing pattern Set to Normal */
@@ -770,7 +770,7 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp,
                        return -ETIMEDOUT;
                }
 
-               mdelay(100);
+               udelay(1);
        }
 
        /* Set to use the register calculated M/N video */
@@ -804,7 +804,7 @@ static int exynos_dp_config_video(struct exynos_dp_device *dp,
                        return -ETIMEDOUT;
                }
 
-               mdelay(100);
+               mdelay(1);
        }
 
        if (retval != 0)
@@ -860,7 +860,8 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       dp = kzalloc(sizeof(struct exynos_dp_device), GFP_KERNEL);
+       dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
+                               GFP_KERNEL);
        if (!dp) {
                dev_err(&pdev->dev, "no memory for device data\n");
                return -ENOMEM;
@@ -871,8 +872,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
        dp->clock = clk_get(&pdev->dev, "dp");
        if (IS_ERR(dp->clock)) {
                dev_err(&pdev->dev, "failed to get clock\n");
-               ret = PTR_ERR(dp->clock);
-               goto err_dp;
+               return PTR_ERR(dp->clock);
        }
 
        clk_enable(dp->clock);
@@ -884,35 +884,25 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
                goto err_clock;
        }
 
-       res = request_mem_region(res->start, resource_size(res),
-                               dev_name(&pdev->dev));
-       if (!res) {
-               dev_err(&pdev->dev, "failed to request registers region\n");
-               ret = -EINVAL;
-               goto err_clock;
-       }
-
-       dp->res = res;
-
-       dp->reg_base = ioremap(res->start, resource_size(res));
+       dp->reg_base = devm_request_and_ioremap(&pdev->dev, res);
        if (!dp->reg_base) {
                dev_err(&pdev->dev, "failed to ioremap\n");
                ret = -ENOMEM;
-               goto err_req_region;
+               goto err_clock;
        }
 
        dp->irq = platform_get_irq(pdev, 0);
        if (!dp->irq) {
                dev_err(&pdev->dev, "failed to get irq\n");
                ret = -ENODEV;
-               goto err_ioremap;
+               goto err_clock;
        }
 
-       ret = request_irq(dp->irq, exynos_dp_irq_handler, 0,
-                       "exynos-dp", dp);
+       ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
+                               "exynos-dp", dp);
        if (ret) {
                dev_err(&pdev->dev, "failed to request irq\n");
-               goto err_ioremap;
+               goto err_clock;
        }
 
        dp->video_info = pdata->video_info;
@@ -924,7 +914,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
        ret = exynos_dp_detect_hpd(dp);
        if (ret) {
                dev_err(&pdev->dev, "unable to detect hpd\n");
-               goto err_irq;
+               goto err_clock;
        }
 
        exynos_dp_handle_edid(dp);
@@ -933,7 +923,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
                                dp->video_info->link_rate);
        if (ret) {
                dev_err(&pdev->dev, "unable to do link train\n");
-               goto err_irq;
+               goto err_clock;
        }
 
        exynos_dp_enable_scramble(dp, 1);
@@ -947,23 +937,15 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
        ret = exynos_dp_config_video(dp, dp->video_info);
        if (ret) {
                dev_err(&pdev->dev, "unable to config video\n");
-               goto err_irq;
+               goto err_clock;
        }
 
        platform_set_drvdata(pdev, dp);
 
        return 0;
 
-err_irq:
-       free_irq(dp->irq, dp);
-err_ioremap:
-       iounmap(dp->reg_base);
-err_req_region:
-       release_mem_region(res->start, resource_size(res));
 err_clock:
        clk_put(dp->clock);
-err_dp:
-       kfree(dp);
 
        return ret;
 }
@@ -976,16 +958,9 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev)
        if (pdata && pdata->phy_exit)
                pdata->phy_exit();
 
-       free_irq(dp->irq, dp);
-       iounmap(dp->reg_base);
-
        clk_disable(dp->clock);
        clk_put(dp->clock);
 
-       release_mem_region(dp->res->start, resource_size(dp->res));
-
-       kfree(dp);
-
        return 0;
 }
 
index 90ceaca..1e0f998 100644 (file)
@@ -26,7 +26,6 @@ struct link_train {
 
 struct exynos_dp_device {
        struct device           *dev;
-       struct resource         *res;
        struct clk              *clock;
        unsigned int            irq;
        void __iomem            *reg_base;
@@ -39,8 +38,10 @@ struct exynos_dp_device {
 void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable);
 void exynos_dp_stop_video(struct exynos_dp_device *dp);
 void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_init_analog_param(struct exynos_dp_device *dp);
 void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
 void exynos_dp_reset(struct exynos_dp_device *dp);
+void exynos_dp_swreset(struct exynos_dp_device *dp);
 void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
 u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
 void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
index 6548afa..6ce76d5 100644 (file)
@@ -16,8 +16,6 @@
 
 #include <video/exynos_dp.h>
 
-#include <plat/cpu.h>
-
 #include "exynos_dp_core.h"
 #include "exynos_dp_reg.h"
 
@@ -65,6 +63,28 @@ void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable)
        writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP);
 }
 
+void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = TX_TERMINAL_CTRL_50_OHM;
+       writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1);
+
+       reg = SEL_24M | TX_DVDD_BIT_1_0625V;
+       writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2);
+
+       reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
+       writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
+
+       reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
+               TX_CUR1_2X | TX_CUR_8_MA;
+       writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
+
+       reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
+               CH1_AMP_400_MV | CH0_AMP_400_MV;
+       writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL);
+}
+
 void exynos_dp_init_interrupt(struct exynos_dp_device *dp)
 {
        /* Set interrupt pin assertion polarity as high */
@@ -89,8 +109,6 @@ void exynos_dp_reset(struct exynos_dp_device *dp)
 {
        u32 reg;
 
-       writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET);
-
        exynos_dp_stop_video(dp);
        exynos_dp_enable_video_mute(dp, 0);
 
@@ -131,9 +149,15 @@ void exynos_dp_reset(struct exynos_dp_device *dp)
 
        writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
 
+       exynos_dp_init_analog_param(dp);
        exynos_dp_init_interrupt(dp);
 }
 
+void exynos_dp_swreset(struct exynos_dp_device *dp)
+{
+       writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET);
+}
+
 void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
 {
        u32 reg;
@@ -271,6 +295,7 @@ void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
 void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
 {
        u32 reg;
+       int timeout_loop = 0;
 
        exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
 
@@ -282,9 +307,19 @@ void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
        writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL);
 
        /* Power up PLL */
-       if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED)
+       if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
                exynos_dp_set_pll_power_down(dp, 0);
 
+               while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+                       timeout_loop++;
+                       if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+                               dev_err(dp->dev, "failed to get pll lock status\n");
+                               return;
+                       }
+                       usleep_range(10, 20);
+               }
+       }
+
        /* Enable Serdes FIFO function and Link symbol clock domain module */
        reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
        reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
index 42f608e..125b27c 100644 (file)
 
 #define EXYNOS_DP_LANE_MAP                     0x35C
 
+#define EXYNOS_DP_ANALOG_CTL_1                 0x370
+#define EXYNOS_DP_ANALOG_CTL_2                 0x374
+#define EXYNOS_DP_ANALOG_CTL_3                 0x378
+#define EXYNOS_DP_PLL_FILTER_CTL_1             0x37C
+#define EXYNOS_DP_TX_AMP_TUNING_CTL            0x380
+
 #define EXYNOS_DP_AUX_HW_RETRY_CTL             0x390
 
 #define EXYNOS_DP_COMMON_INT_STA_1             0x3C4
 #define LANE0_MAP_LOGIC_LANE_2                 (0x2 << 0)
 #define LANE0_MAP_LOGIC_LANE_3                 (0x3 << 0)
 
+/* EXYNOS_DP_ANALOG_CTL_1 */
+#define TX_TERMINAL_CTRL_50_OHM                        (0x1 << 4)
+
+/* EXYNOS_DP_ANALOG_CTL_2 */
+#define SEL_24M                                        (0x1 << 3)
+#define TX_DVDD_BIT_1_0625V                    (0x4 << 0)
+
+/* EXYNOS_DP_ANALOG_CTL_3 */
+#define DRIVE_DVDD_BIT_1_0625V                 (0x4 << 5)
+#define VCO_BIT_600_MICRO                      (0x5 << 0)
+
+/* EXYNOS_DP_PLL_FILTER_CTL_1 */
+#define PD_RING_OSC                            (0x1 << 6)
+#define AUX_TERMINAL_CTRL_50_OHM               (0x2 << 4)
+#define TX_CUR1_2X                             (0x1 << 2)
+#define TX_CUR_8_MA                            (0x2 << 0)
+
+/* EXYNOS_DP_TX_AMP_TUNING_CTL */
+#define CH3_AMP_400_MV                         (0x0 << 24)
+#define CH2_AMP_400_MV                         (0x0 << 16)
+#define CH1_AMP_400_MV                         (0x0 << 8)
+#define CH0_AMP_400_MV                         (0x0 << 0)
+
 /* EXYNOS_DP_AUX_HW_RETRY_CTL */
 #define AUX_BIT_PERIOD_EXPECTED_DELAY(x)       (((x) & 0x7) << 8)
 #define AUX_HW_RETRY_INTERVAL_MASK             (0x3 << 3)
index 557091d..6c1f5c3 100644 (file)
@@ -58,7 +58,7 @@ static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device
 }
 
 static struct regulator_bulk_data supplies[] = {
-       { .supply = "vdd10", },
+       { .supply = "vdd11", },
        { .supply = "vdd18", },
 };
 
@@ -102,6 +102,8 @@ static void exynos_mipi_update_cfg(struct mipi_dsim_device *dsim)
        /* set display timing. */
        exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
 
+       exynos_mipi_dsi_init_interrupt(dsim);
+
        /*
         * data from Display controller(FIMD) is transferred in video mode
         * but in case of command mode, all settigs is updated to registers.
@@ -413,27 +415,30 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
                goto err_platform_get_irq;
        }
 
+       init_completion(&dsim_wr_comp);
+       init_completion(&dsim_rd_comp);
+       platform_set_drvdata(pdev, dsim);
+
        ret = request_irq(dsim->irq, exynos_mipi_dsi_interrupt_handler,
-                       IRQF_SHARED, pdev->name, dsim);
+                       IRQF_SHARED, dev_name(&pdev->dev), dsim);
        if (ret != 0) {
                dev_err(&pdev->dev, "failed to request dsim irq\n");
                ret = -EINVAL;
                goto err_bind;
        }
 
-       init_completion(&dsim_wr_comp);
-       init_completion(&dsim_rd_comp);
-
-       /* enable interrupt */
+       /* enable interrupts */
        exynos_mipi_dsi_init_interrupt(dsim);
 
        /* initialize mipi-dsi client(lcd panel). */
        if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
                dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
 
-       /* in case that mipi got enabled at bootloader. */
-       if (dsim_pd->enabled)
-               goto out;
+       /* in case mipi-dsi has been enabled by bootloader */
+       if (dsim_pd->enabled) {
+               exynos_mipi_regulator_enable(dsim);
+               goto done;
+       }
 
        /* lcd panel power on. */
        if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on)
@@ -453,12 +458,11 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 
        dsim->suspended = false;
 
-out:
+done:
        platform_set_drvdata(pdev, dsim);
 
-       dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n",
-               (dsim_config->e_interface == DSIM_COMMAND) ?
-                       "CPU" : "RGB");
+       dev_dbg(&pdev->dev, "%s() completed sucessfuly (%s mode)\n", __func__,
+               dsim_config->e_interface == DSIM_COMMAND ? "CPU" : "RGB");
 
        return 0;
 
@@ -515,10 +519,10 @@ static int __devexit exynos_mipi_dsi_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int exynos_mipi_dsi_suspend(struct platform_device *pdev,
-               pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int exynos_mipi_dsi_suspend(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
        struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
        struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
@@ -544,8 +548,9 @@ static int exynos_mipi_dsi_suspend(struct platform_device *pdev,
        return 0;
 }
 
-static int exynos_mipi_dsi_resume(struct platform_device *pdev)
+static int exynos_mipi_dsi_resume(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
        struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
        struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
@@ -577,19 +582,19 @@ static int exynos_mipi_dsi_resume(struct platform_device *pdev)
 
        return 0;
 }
-#else
-#define exynos_mipi_dsi_suspend NULL
-#define exynos_mipi_dsi_resume NULL
 #endif
 
+static const struct dev_pm_ops exynos_mipi_dsi_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(exynos_mipi_dsi_suspend, exynos_mipi_dsi_resume)
+};
+
 static struct platform_driver exynos_mipi_dsi_driver = {
        .probe = exynos_mipi_dsi_probe,
        .remove = __devexit_p(exynos_mipi_dsi_remove),
-       .suspend = exynos_mipi_dsi_suspend,
-       .resume = exynos_mipi_dsi_resume,
        .driver = {
                   .name = "exynos-mipi-dsim",
                   .owner = THIS_MODULE,
+                  .pm = &exynos_mipi_dsi_pm_ops,
        },
 };
 
index 14909c1..47b533a 100644 (file)
@@ -76,33 +76,25 @@ static unsigned int dpll_table[15] = {
 
 irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id)
 {
-       unsigned int intsrc = 0;
-       unsigned int intmsk = 0;
-       struct mipi_dsim_device *dsim = NULL;
-
-       dsim = dev_id;
-       if (!dsim) {
-               dev_dbg(dsim->dev, KERN_ERR "%s:error: wrong parameter\n",
-                                                       __func__);
-               return IRQ_HANDLED;
+       struct mipi_dsim_device *dsim = dev_id;
+       unsigned int intsrc, intmsk;
+
+       if (dsim == NULL) {
+               dev_err(dsim->dev, "%s: wrong parameter\n", __func__);
+               return IRQ_NONE;
        }
 
        intsrc = exynos_mipi_dsi_read_interrupt(dsim);
        intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim);
+       intmsk = ~intmsk & intsrc;
 
-       intmsk = ~(intmsk) & intsrc;
-
-       switch (intmsk) {
-       case INTMSK_RX_DONE:
+       if (intsrc & INTMSK_RX_DONE) {
                complete(&dsim_rd_comp);
                dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n");
-               break;
-       case INTMSK_FIFO_EMPTY:
+       }
+       if (intsrc & INTMSK_FIFO_EMPTY) {
                complete(&dsim_wr_comp);
                dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n");
-               break;
-       default:
-               break;
        }
 
        exynos_mipi_dsi_clear_interrupt(dsim, intmsk);
@@ -738,11 +730,11 @@ int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
                if (dsim_config->auto_vertical_cnt == 0) {
                        exynos_mipi_dsi_set_main_disp_vporch(dsim,
                                dsim_config->cmd_allow,
-                               timing->upper_margin,
-                               timing->lower_margin);
+                               timing->lower_margin,
+                               timing->upper_margin);
                        exynos_mipi_dsi_set_main_disp_hporch(dsim,
-                               timing->left_margin,
-                               timing->right_margin);
+                               timing->right_margin,
+                               timing->left_margin);
                        exynos_mipi_dsi_set_main_disp_sync_area(dsim,
                                timing->vsync_len,
                                timing->hsync_len);
index 4aa9ac6..05d080b 100644 (file)
@@ -293,9 +293,20 @@ static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd)
                0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
                0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8
        };
+       static const unsigned char data_to_send_panel_reverse[] = {
+               0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
+               0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
+               0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
+               0xc1, 0x01, 0x41, 0xc1, 0x00, 0xc1, 0xf6, 0xf6, 0xc1
+       };
 
-       ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
-               data_to_send, ARRAY_SIZE(data_to_send));
+       if (lcd->dsim_dev->panel_reverse)
+               ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+                               data_to_send_panel_reverse,
+                               ARRAY_SIZE(data_to_send_panel_reverse));
+       else
+               ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+                               data_to_send, ARRAY_SIZE(data_to_send));
 }
 
 static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
index c27e153..1ddeb11 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/rmap.h>
 #include <linux/pagemap.h>
 
-struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs)
+static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs)
 {
        void *screen_base = (void __force *) info->screen_base;
        struct page *page;
@@ -107,6 +107,10 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
        /* protect against the workqueue changing the page list */
        mutex_lock(&fbdefio->lock);
 
+       /* first write in this cycle, notify the driver */
+       if (fbdefio->first_io && list_empty(&fbdefio->pagelist))
+               fbdefio->first_io(info);
+
        /*
         * We want the page to remain locked from ->page_mkwrite until
         * the PTE is marked dirty to avoid page_mkclean() being called
index 67afa9c..a55e366 100644 (file)
@@ -80,6 +80,8 @@ EXPORT_SYMBOL(framebuffer_alloc);
  */
 void framebuffer_release(struct fb_info *info)
 {
+       if (!info)
+               return;
        kfree(info->apertures);
        kfree(info);
 }
index 6af3f16..458c006 100644 (file)
@@ -834,7 +834,6 @@ static void update_lcdc(struct fb_info *info)
        diu_ops.set_pixel_clock(var->pixclock);
 
        out_be32(&hw->syn_pol, 0);      /* SYNC SIGNALS POLARITY */
-       out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */
        out_be32(&hw->int_status, 0);   /* INTERRUPT STATUS */
        out_be32(&hw->plut, 0x01F5F666);
 
index 02fd226..bdcbfba 100644 (file)
@@ -680,6 +680,7 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev,
                 + dinfo->fb.size);
        if (!dinfo->aperture.virtual) {
                ERR_MSG("Cannot remap FB region.\n");
+               agp_backend_release(bridge);
                cleanup(dinfo);
                return -ENODEV;
        }
@@ -689,6 +690,7 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev,
                                              INTEL_REG_SIZE);
        if (!dinfo->mmio_base) {
                ERR_MSG("Cannot remap MMIO region.\n");
+               agp_backend_release(bridge);
                cleanup(dinfo);
                return -ENODEV;
        }
index 273769b..c87e17a 100644 (file)
@@ -68,7 +68,7 @@ static int mb862xx_i2c_read_byte(struct i2c_adapter *adap, u8 *byte, int last)
        return 1;
 }
 
-void mb862xx_i2c_stop(struct i2c_adapter *adap)
+static void mb862xx_i2c_stop(struct i2c_adapter *adap)
 {
        struct mb862xxfb_par *par = adap->algo_data;
 
index 11a7a33..00ce1f3 100644 (file)
@@ -579,7 +579,7 @@ static ssize_t mb862xxfb_show_dispregs(struct device *dev,
 
 static DEVICE_ATTR(dispregs, 0444, mb862xxfb_show_dispregs, NULL);
 
-irqreturn_t mb862xx_intr(int irq, void *dev_id)
+static irqreturn_t mb862xx_intr(int irq, void *dev_id)
 {
        struct mb862xxfb_par *par = (struct mb862xxfb_par *) dev_id;
        unsigned long reg_ist, mask;
index 55bf619..ab0a8e5 100644 (file)
@@ -950,7 +950,7 @@ static int __devinit mbxfb_probe(struct platform_device *dev)
 
        mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
                                             res_size(mfbi->fb_req));
-       if (!mfbi->reg_virt_addr) {
+       if (!mfbi->fb_virt_addr) {
                dev_err(&dev->dev, "failed to ioremap frame buffer\n");
                ret = -EINVAL;
                goto err4;
index 6c6bc57..abbe691 100644 (file)
@@ -889,6 +889,18 @@ static int __devexit mxsfb_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void mxsfb_shutdown(struct platform_device *pdev)
+{
+       struct fb_info *fb_info = platform_get_drvdata(pdev);
+       struct mxsfb_info *host = to_imxfb_host(fb_info);
+
+       /*
+        * Force stop the LCD controller as keeping it running during reboot
+        * might interfere with the BootROM's boot mode pads sampling.
+        */
+       writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR);
+}
+
 static struct platform_device_id mxsfb_devtype[] = {
        {
                .name = "imx23-fb",
@@ -905,6 +917,7 @@ MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
 static struct platform_driver mxsfb_driver = {
        .probe = mxsfb_probe,
        .remove = __devexit_p(mxsfb_remove),
+       .shutdown = mxsfb_shutdown,
        .id_table = mxsfb_devtype,
        .driver = {
                   .name = DRIVER_NAME,
index 1e7536d..b48f95f 100644 (file)
@@ -39,14 +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_BOOTLOADER_INIT
-       bool "Check bootloader initialization"
-       depends on FB_OMAP
-       help
-         Say Y here if you want to enable checking if the bootloader has
-         already initialized the display controller. In this case the
-         driver will skip the initialization.
-
 config FB_OMAP_CONSISTENT_DMA_SIZE
        int "Consistent DMA memory size (MB)"
        depends on FB_OMAP
index 74e7cf0..ad741c3 100644 (file)
@@ -739,12 +739,6 @@ static void acx_panel_set_timings(struct omap_dss_device *dssdev,
        }
 }
 
-static void acx_panel_get_timings(struct omap_dss_device *dssdev,
-               struct omap_video_timings *timings)
-{
-       *timings = dssdev->panel.timings;
-}
-
 static int acx_panel_check_timings(struct omap_dss_device *dssdev,
                struct omap_video_timings *timings)
 {
@@ -762,7 +756,6 @@ static struct omap_dss_driver acx_panel_driver = {
        .resume         = acx_panel_resume,
 
        .set_timings    = acx_panel_set_timings,
-       .get_timings    = acx_panel_get_timings,
        .check_timings  = acx_panel_check_timings,
 
        .get_recommended_bpp = acx_get_recommended_bpp,
index 30fe4df..e42f9dc 100644 (file)
@@ -386,6 +386,106 @@ static struct panel_config generic_dpi_panels[] = {
 
                .name                   = "innolux_at080tn52",
        },
+
+       /* Mitsubishi AA084SB01 */
+       {
+               {
+                       .x_res          = 800,
+                       .y_res          = 600,
+                       .pixel_clock    = 40000,
+
+                       .hsw            = 1,
+                       .hfp            = 254,
+                       .hbp            = 1,
+
+                       .vsw            = 1,
+                       .vfp            = 26,
+                       .vbp            = 1,
+               },
+               .config                 = OMAP_DSS_LCD_TFT,
+               .name                   = "mitsubishi_aa084sb01",
+       },
+       /* EDT ET0500G0DH6 */
+       {
+               {
+                       .x_res          = 800,
+                       .y_res          = 480,
+                       .pixel_clock    = 33260,
+
+                       .hsw            = 128,
+                       .hfp            = 216,
+                       .hbp            = 40,
+
+                       .vsw            = 2,
+                       .vfp            = 35,
+                       .vbp            = 10,
+               },
+               .config                 = OMAP_DSS_LCD_TFT,
+               .name                   = "edt_et0500g0dh6",
+       },
+
+       /* Prime-View PD050VL1 */
+       {
+               {
+                       .x_res          = 640,
+                       .y_res          = 480,
+
+                       .pixel_clock    = 25000,
+
+                       .hsw            = 96,
+                       .hfp            = 18,
+                       .hbp            = 46,
+
+                       .vsw            = 2,
+                       .vfp            = 10,
+                       .vbp            = 33,
+               },
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                         OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,
+               .name                   = "primeview_pd050vl1",
+       },
+
+       /* Prime-View PM070WL4 */
+       {
+               {
+                       .x_res          = 800,
+                       .y_res          = 480,
+
+                       .pixel_clock    = 32000,
+
+                       .hsw            = 128,
+                       .hfp            = 42,
+                       .hbp            = 86,
+
+                       .vsw            = 2,
+                       .vfp            = 10,
+                       .vbp            = 33,
+               },
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                         OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,
+               .name                   = "primeview_pm070wl4",
+       },
+
+       /* Prime-View PD104SLF */
+       {
+               {
+                       .x_res          = 800,
+                       .y_res          = 600,
+
+                       .pixel_clock    = 40000,
+
+                       .hsw            = 128,
+                       .hfp            = 42,
+                       .hbp            = 86,
+
+                       .vsw            = 4,
+                       .vfp            = 1,
+                       .vbp            = 23,
+               },
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                         OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,
+               .name                   = "primeview_pd104slf",
+       },
 };
 
 struct panel_drv_data {
@@ -549,12 +649,6 @@ static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
        dpi_set_timings(dssdev, timings);
 }
 
-static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
-               struct omap_video_timings *timings)
-{
-       *timings = dssdev->panel.timings;
-}
-
 static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
                struct omap_video_timings *timings)
 {
@@ -571,7 +665,6 @@ static struct omap_dss_driver dpi_driver = {
        .resume         = generic_dpi_panel_resume,
 
        .set_timings    = generic_dpi_panel_set_timings,
-       .get_timings    = generic_dpi_panel_get_timings,
        .check_timings  = generic_dpi_panel_check_timings,
 
        .driver         = {
index dc9408d..4a34cdc 100644 (file)
@@ -610,12 +610,6 @@ static int n8x0_panel_resume(struct omap_dss_device *dssdev)
        return 0;
 }
 
-static void n8x0_panel_get_timings(struct omap_dss_device *dssdev,
-               struct omap_video_timings *timings)
-{
-       *timings = dssdev->panel.timings;
-}
-
 static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev,
                u16 *xres, u16 *yres)
 {
@@ -678,8 +672,6 @@ static struct omap_dss_driver n8x0_panel_driver = {
        .get_resolution = n8x0_panel_get_resolution,
        .get_recommended_bpp = omapdss_default_get_recommended_bpp,
 
-       .get_timings    = n8x0_panel_get_timings,
-
        .driver         = {
                .name   = "n8x0_panel",
                .owner  = THIS_MODULE,
index b2dd88b..2ce9992 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/gpio.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
-#include <linux/regulator/consumer.h>
 #include <linux/mutex.h>
 
 #include <video/omapdss.h>
@@ -55,73 +54,6 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
 
 static int taal_panel_reset(struct omap_dss_device *dssdev);
 
-struct panel_regulator {
-       struct regulator *regulator;
-       const char *name;
-       int min_uV;
-       int max_uV;
-};
-
-static void free_regulators(struct panel_regulator *regulators, int n)
-{
-       int i;
-
-       for (i = 0; i < n; i++) {
-               /* disable/put in reverse order */
-               regulator_disable(regulators[n - i - 1].regulator);
-               regulator_put(regulators[n - i - 1].regulator);
-       }
-}
-
-static int init_regulators(struct omap_dss_device *dssdev,
-                       struct panel_regulator *regulators, int n)
-{
-       int r, i, v;
-
-       for (i = 0; i < n; i++) {
-               struct regulator *reg;
-
-               reg = regulator_get(&dssdev->dev, regulators[i].name);
-               if (IS_ERR(reg)) {
-                       dev_err(&dssdev->dev, "failed to get regulator %s\n",
-                               regulators[i].name);
-                       r = PTR_ERR(reg);
-                       goto err;
-               }
-
-               /* FIXME: better handling of fixed vs. variable regulators */
-               v = regulator_get_voltage(reg);
-               if (v < regulators[i].min_uV || v > regulators[i].max_uV) {
-                       r = regulator_set_voltage(reg, regulators[i].min_uV,
-                                               regulators[i].max_uV);
-                       if (r) {
-                               dev_err(&dssdev->dev,
-                                       "failed to set regulator %s voltage\n",
-                                       regulators[i].name);
-                               regulator_put(reg);
-                               goto err;
-                       }
-               }
-
-               r = regulator_enable(reg);
-               if (r) {
-                       dev_err(&dssdev->dev, "failed to enable regulator %s\n",
-                               regulators[i].name);
-                       regulator_put(reg);
-                       goto err;
-               }
-
-               regulators[i].regulator = reg;
-       }
-
-       return 0;
-
-err:
-       free_regulators(regulators, i);
-
-       return r;
-}
-
 /**
  * struct panel_config - panel configuration
  * @name: panel name
@@ -150,8 +82,6 @@ struct panel_config {
                unsigned int low;
        } reset_sequence;
 
-       struct panel_regulator *regulators;
-       int num_regulators;
 };
 
 enum {
@@ -577,12 +507,6 @@ static const struct backlight_ops taal_bl_ops = {
        .update_status  = taal_bl_update_status,
 };
 
-static void taal_get_timings(struct omap_dss_device *dssdev,
-                       struct omap_video_timings *timings)
-{
-       *timings = dssdev->panel.timings;
-}
-
 static void taal_get_resolution(struct omap_dss_device *dssdev,
                u16 *xres, u16 *yres)
 {
@@ -977,11 +901,6 @@ static int taal_probe(struct omap_dss_device *dssdev)
 
        atomic_set(&td->do_update, 0);
 
-       r = init_regulators(dssdev, panel_config->regulators,
-                       panel_config->num_regulators);
-       if (r)
-               goto err_reg;
-
        td->workqueue = create_singlethread_workqueue("taal_esd");
        if (td->workqueue == NULL) {
                dev_err(&dssdev->dev, "can't create ESD workqueue\n");
@@ -1087,8 +1006,6 @@ err_bl:
 err_rst_gpio:
        destroy_workqueue(td->workqueue);
 err_wq:
-       free_regulators(panel_config->regulators, panel_config->num_regulators);
-err_reg:
        kfree(td);
 err:
        return r;
@@ -1125,9 +1042,6 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
        /* reset, to be sure that the panel is in a valid state */
        taal_hw_reset(dssdev);
 
-       free_regulators(td->panel_config->regulators,
-                       td->panel_config->num_regulators);
-
        if (gpio_is_valid(panel_data->reset_gpio))
                gpio_free(panel_data->reset_gpio);
 
@@ -1909,8 +1823,6 @@ static struct omap_dss_driver taal_driver = {
        .run_test       = taal_run_test,
        .memory_read    = taal_memory_read,
 
-       .get_timings    = taal_get_timings,
-
        .driver         = {
                .name   = "taal",
                .owner  = THIS_MODULE,
index 52637fa..bff306e 100644 (file)
@@ -47,13 +47,9 @@ struct panel_drv_data {
        struct mutex lock;
 
        int pd_gpio;
-};
 
-static inline struct tfp410_platform_data
-*get_pdata(const struct omap_dss_device *dssdev)
-{
-       return dssdev->data;
-}
+       struct i2c_adapter *i2c_adapter;
+};
 
 static int tfp410_power_on(struct omap_dss_device *dssdev)
 {
@@ -68,7 +64,7 @@ static int tfp410_power_on(struct omap_dss_device *dssdev)
                goto err0;
 
        if (gpio_is_valid(ddata->pd_gpio))
-               gpio_set_value(ddata->pd_gpio, 1);
+               gpio_set_value_cansleep(ddata->pd_gpio, 1);
 
        return 0;
 err0:
@@ -83,18 +79,18 @@ static void tfp410_power_off(struct omap_dss_device *dssdev)
                return;
 
        if (gpio_is_valid(ddata->pd_gpio))
-               gpio_set_value(ddata->pd_gpio, 0);
+               gpio_set_value_cansleep(ddata->pd_gpio, 0);
 
        omapdss_dpi_display_disable(dssdev);
 }
 
 static int tfp410_probe(struct omap_dss_device *dssdev)
 {
-       struct tfp410_platform_data *pdata = get_pdata(dssdev);
        struct panel_drv_data *ddata;
        int r;
+       int i2c_bus_num;
 
-       ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
+       ddata = devm_kzalloc(&dssdev->dev, sizeof(*ddata), GFP_KERNEL);
        if (!ddata)
                return -ENOMEM;
 
@@ -104,10 +100,15 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
        ddata->dssdev = dssdev;
        mutex_init(&ddata->lock);
 
-       if (pdata)
+       if (dssdev->data) {
+               struct tfp410_platform_data *pdata = dssdev->data;
+
                ddata->pd_gpio = pdata->power_down_gpio;
-       else
+               i2c_bus_num = pdata->i2c_bus_num;
+       } else {
                ddata->pd_gpio = -1;
+               i2c_bus_num = -1;
+       }
 
        if (gpio_is_valid(ddata->pd_gpio)) {
                r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW,
@@ -115,13 +116,31 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
                if (r) {
                        dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n",
                                        ddata->pd_gpio);
-                       ddata->pd_gpio = -1;
+                       return r;
                }
        }
 
+       if (i2c_bus_num != -1) {
+               struct i2c_adapter *adapter;
+
+               adapter = i2c_get_adapter(i2c_bus_num);
+               if (!adapter) {
+                       dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
+                                       i2c_bus_num);
+                       r = -EINVAL;
+                       goto err_i2c;
+               }
+
+               ddata->i2c_adapter = adapter;
+       }
+
        dev_set_drvdata(&dssdev->dev, ddata);
 
        return 0;
+err_i2c:
+       if (gpio_is_valid(ddata->pd_gpio))
+               gpio_free(ddata->pd_gpio);
+       return r;
 }
 
 static void __exit tfp410_remove(struct omap_dss_device *dssdev)
@@ -130,14 +149,15 @@ static void __exit tfp410_remove(struct omap_dss_device *dssdev)
 
        mutex_lock(&ddata->lock);
 
+       if (ddata->i2c_adapter)
+               i2c_put_adapter(ddata->i2c_adapter);
+
        if (gpio_is_valid(ddata->pd_gpio))
                gpio_free(ddata->pd_gpio);
 
        dev_set_drvdata(&dssdev->dev, NULL);
 
        mutex_unlock(&ddata->lock);
-
-       kfree(ddata);
 }
 
 static int tfp410_enable(struct omap_dss_device *dssdev)
@@ -269,27 +289,17 @@ static int tfp410_read_edid(struct omap_dss_device *dssdev,
                u8 *edid, int len)
 {
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-       struct tfp410_platform_data *pdata = get_pdata(dssdev);
-       struct i2c_adapter *adapter;
        int r, l, bytes_read;
 
        mutex_lock(&ddata->lock);
 
-       if (pdata->i2c_bus_num == 0) {
+       if (!ddata->i2c_adapter) {
                r = -ENODEV;
                goto err;
        }
 
-       adapter = i2c_get_adapter(pdata->i2c_bus_num);
-       if (!adapter) {
-               dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
-                               pdata->i2c_bus_num);
-               r = -EINVAL;
-               goto err;
-       }
-
        l = min(EDID_LENGTH, len);
-       r = tfp410_ddc_read(adapter, edid, l, 0);
+       r = tfp410_ddc_read(ddata->i2c_adapter, edid, l, 0);
        if (r)
                goto err;
 
@@ -299,7 +309,7 @@ static int tfp410_read_edid(struct omap_dss_device *dssdev,
        if (len > EDID_LENGTH && edid[0x7e] > 0) {
                l = min(EDID_LENGTH, len - EDID_LENGTH);
 
-               r = tfp410_ddc_read(adapter, edid + EDID_LENGTH,
+               r = tfp410_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH,
                                l, EDID_LENGTH);
                if (r)
                        goto err;
@@ -319,21 +329,15 @@ err:
 static bool tfp410_detect(struct omap_dss_device *dssdev)
 {
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
-       struct tfp410_platform_data *pdata = get_pdata(dssdev);
-       struct i2c_adapter *adapter;
        unsigned char out;
        int r;
 
        mutex_lock(&ddata->lock);
 
-       if (pdata->i2c_bus_num == 0)
-               goto out;
-
-       adapter = i2c_get_adapter(pdata->i2c_bus_num);
-       if (!adapter)
+       if (!ddata->i2c_adapter)
                goto out;
 
-       r = tfp410_ddc_read(adapter, &out, 1, 0);
+       r = tfp410_ddc_read(ddata->i2c_adapter, &out, 1, 0);
 
        mutex_unlock(&ddata->lock);
 
index 32f3fcd..4b6448b 100644 (file)
@@ -272,13 +272,16 @@ static const struct omap_video_timings tpo_td043_timings = {
 static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043)
 {
        int nreset_gpio = tpo_td043->nreset_gpio;
+       int r;
 
        if (tpo_td043->powered_on)
                return 0;
 
-       regulator_enable(tpo_td043->vcc_reg);
+       r = regulator_enable(tpo_td043->vcc_reg);
+       if (r != 0)
+               return r;
 
-       /* wait for regulator to stabilize */
+       /* wait for panel to stabilize */
        msleep(160);
 
        if (gpio_is_valid(nreset_gpio))
@@ -470,6 +473,18 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev)
                gpio_free(nreset_gpio);
 }
 
+static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       dpi_set_timings(dssdev, timings);
+}
+
+static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       return dpi_check_timings(dssdev, timings);
+}
+
 static struct omap_dss_driver tpo_td043_driver = {
        .probe          = tpo_td043_probe,
        .remove         = tpo_td043_remove,
@@ -481,6 +496,9 @@ static struct omap_dss_driver tpo_td043_driver = {
        .set_mirror     = tpo_td043_set_hmirror,
        .get_mirror     = tpo_td043_get_hmirror,
 
+       .set_timings    = tpo_td043_set_timings,
+       .check_timings  = tpo_td043_check_timings,
+
        .driver         = {
                .name   = "tpo_td043mtea1_panel",
                .owner  = THIS_MODULE,
index 7be7c06..43324e5 100644 (file)
@@ -68,6 +68,10 @@ config OMAP4_DSS_HDMI
          HDMI Interface. This adds the High Definition Multimedia Interface.
          See http://www.hdmi.org/ for HDMI specification.
 
+config OMAP4_DSS_HDMI_AUDIO
+       bool
+       depends on OMAP4_DSS_HDMI
+
 config OMAP2_DSS_SDI
        bool "SDI support"
        depends on ARCH_OMAP3
@@ -90,15 +94,6 @@ config OMAP2_DSS_DSI
 
          See http://www.mipi.org/ for DSI spesifications.
 
-config OMAP2_DSS_FAKE_VSYNC
-       bool "Fake VSYNC irq from manual update displays"
-       default n
-       help
-         If this is selected, DSI will generate a fake DISPC VSYNC interrupt
-         when DSI has sent a frame. This is only needed with DSI or RFBI
-         displays using manual mode, and you want VSYNC to, for example,
-         time animation.
-
 config OMAP2_DSS_MIN_FCK_PER_PCK
        int "Minimum FCK/PCK ratio (for scaling)"
        range 0 32
index b10b3bc..ab22cc2 100644 (file)
@@ -99,6 +99,11 @@ struct mgr_priv_data {
 
        /* If true, a display is enabled using this manager */
        bool enabled;
+
+       bool extra_info_dirty;
+       bool shadow_extra_info_dirty;
+
+       struct omap_video_timings timings;
 };
 
 static struct {
@@ -176,7 +181,7 @@ static bool mgr_manual_update(struct omap_overlay_manager *mgr)
 }
 
 static int dss_check_settings_low(struct omap_overlay_manager *mgr,
-               struct omap_dss_device *dssdev, bool applying)
+               bool applying)
 {
        struct omap_overlay_info *oi;
        struct omap_overlay_manager_info *mi;
@@ -187,6 +192,9 @@ static int dss_check_settings_low(struct omap_overlay_manager *mgr,
 
        mp = get_mgr_priv(mgr);
 
+       if (!mp->enabled)
+               return 0;
+
        if (applying && mp->user_info_dirty)
                mi = &mp->user_info;
        else
@@ -206,26 +214,24 @@ static int dss_check_settings_low(struct omap_overlay_manager *mgr,
                ois[ovl->id] = oi;
        }
 
-       return dss_mgr_check(mgr, dssdev, mi, ois);
+       return dss_mgr_check(mgr, mi, &mp->timings, ois);
 }
 
 /*
  * check manager and overlay settings using overlay_info from data->info
  */
-static int dss_check_settings(struct omap_overlay_manager *mgr,
-               struct omap_dss_device *dssdev)
+static int dss_check_settings(struct omap_overlay_manager *mgr)
 {
-       return dss_check_settings_low(mgr, dssdev, false);
+       return dss_check_settings_low(mgr, false);
 }
 
 /*
  * check manager and overlay settings using overlay_info from ovl->info if
  * dirty and from data->info otherwise
  */
-static int dss_check_settings_apply(struct omap_overlay_manager *mgr,
-               struct omap_dss_device *dssdev)
+static int dss_check_settings_apply(struct omap_overlay_manager *mgr)
 {
-       return dss_check_settings_low(mgr, dssdev, true);
+       return dss_check_settings_low(mgr, true);
 }
 
 static bool need_isr(void)
@@ -261,6 +267,20 @@ static bool need_isr(void)
                        if (mp->shadow_info_dirty)
                                return true;
 
+                       /*
+                        * NOTE: we don't check extra_info flags for disabled
+                        * managers, once the manager is enabled, the extra_info
+                        * related manager changes will be taken in by HW.
+                        */
+
+                       /* to write new values to registers */
+                       if (mp->extra_info_dirty)
+                               return true;
+
+                       /* to set GO bit */
+                       if (mp->shadow_extra_info_dirty)
+                               return true;
+
                        list_for_each_entry(ovl, &mgr->overlays, list) {
                                struct ovl_priv_data *op;
 
@@ -305,7 +325,7 @@ static bool need_go(struct omap_overlay_manager *mgr)
 
        mp = get_mgr_priv(mgr);
 
-       if (mp->shadow_info_dirty)
+       if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)
                return true;
 
        list_for_each_entry(ovl, &mgr->overlays, list) {
@@ -320,20 +340,16 @@ static bool need_go(struct omap_overlay_manager *mgr)
 /* returns true if an extra_info field is currently being updated */
 static bool extra_info_update_ongoing(void)
 {
-       const int num_ovls = omap_dss_get_num_overlays();
-       struct ovl_priv_data *op;
-       struct omap_overlay *ovl;
-       struct mgr_priv_data *mp;
+       const int num_mgrs = dss_feat_get_num_mgrs();
        int i;
 
-       for (i = 0; i < num_ovls; ++i) {
-               ovl = omap_dss_get_overlay(i);
-               op = get_ovl_priv(ovl);
-
-               if (!ovl->manager)
-                       continue;
+       for (i = 0; i < num_mgrs; ++i) {
+               struct omap_overlay_manager *mgr;
+               struct omap_overlay *ovl;
+               struct mgr_priv_data *mp;
 
-               mp = get_mgr_priv(ovl->manager);
+               mgr = omap_dss_get_overlay_manager(i);
+               mp = get_mgr_priv(mgr);
 
                if (!mp->enabled)
                        continue;
@@ -341,8 +357,15 @@ static bool extra_info_update_ongoing(void)
                if (!mp->updating)
                        continue;
 
-               if (op->extra_info_dirty || op->shadow_extra_info_dirty)
+               if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)
                        return true;
+
+               list_for_each_entry(ovl, &mgr->overlays, list) {
+                       struct ovl_priv_data *op = get_ovl_priv(ovl);
+
+                       if (op->extra_info_dirty || op->shadow_extra_info_dirty)
+                               return true;
+               }
        }
 
        return false;
@@ -525,11 +548,13 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl)
 
        oi = &op->info;
 
+       mp = get_mgr_priv(ovl->manager);
+
        replication = dss_use_replication(ovl->manager->device, oi->color_mode);
 
        ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
 
-       r = dispc_ovl_setup(ovl->id, oi, ilace, replication);
+       r = dispc_ovl_setup(ovl->id, oi, ilace, replication, &mp->timings);
        if (r) {
                /*
                 * We can't do much here, as this function can be called from
@@ -543,8 +568,6 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl)
                return;
        }
 
-       mp = get_mgr_priv(ovl->manager);
-
        op->info_dirty = false;
        if (mp->updating)
                op->shadow_info_dirty = true;
@@ -601,6 +624,22 @@ static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
        }
 }
 
+static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
+{
+       struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+       DSSDBGF("%d", mgr->id);
+
+       if (!mp->extra_info_dirty)
+               return;
+
+       dispc_mgr_set_timings(mgr->id, &mp->timings);
+
+       mp->extra_info_dirty = false;
+       if (mp->updating)
+               mp->shadow_extra_info_dirty = true;
+}
+
 static void dss_write_regs_common(void)
 {
        const int num_mgrs = omap_dss_get_num_overlay_managers();
@@ -646,7 +685,7 @@ static void dss_write_regs(void)
                if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
                        continue;
 
-               r = dss_check_settings(mgr, mgr->device);
+               r = dss_check_settings(mgr);
                if (r) {
                        DSSERR("cannot write registers for manager %s: "
                                        "illegal configuration\n", mgr->name);
@@ -654,6 +693,7 @@ static void dss_write_regs(void)
                }
 
                dss_mgr_write_regs(mgr);
+               dss_mgr_write_regs_extra(mgr);
        }
 }
 
@@ -693,6 +733,7 @@ static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
 
        mp = get_mgr_priv(mgr);
        mp->shadow_info_dirty = false;
+       mp->shadow_extra_info_dirty = false;
 
        list_for_each_entry(ovl, &mgr->overlays, list) {
                op = get_ovl_priv(ovl);
@@ -711,7 +752,7 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr)
 
        WARN_ON(mp->updating);
 
-       r = dss_check_settings(mgr, mgr->device);
+       r = dss_check_settings(mgr);
        if (r) {
                DSSERR("cannot start manual update: illegal configuration\n");
                spin_unlock_irqrestore(&data_lock, flags);
@@ -719,6 +760,7 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr)
        }
 
        dss_mgr_write_regs(mgr);
+       dss_mgr_write_regs_extra(mgr);
 
        dss_write_regs_common();
 
@@ -857,7 +899,7 @@ int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
        spin_lock_irqsave(&data_lock, flags);
 
-       r = dss_check_settings_apply(mgr, mgr->device);
+       r = dss_check_settings_apply(mgr);
        if (r) {
                spin_unlock_irqrestore(&data_lock, flags);
                DSSERR("failed to apply settings: illegal configuration.\n");
@@ -918,16 +960,13 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
                bool use_fifo_merge)
 {
        struct ovl_priv_data *op = get_ovl_priv(ovl);
-       struct omap_dss_device *dssdev;
        u32 fifo_low, fifo_high;
 
        if (!op->enabled && !op->enabling)
                return;
 
-       dssdev = ovl->manager->device;
-
        dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
-                       use_fifo_merge);
+                       use_fifo_merge, ovl_manual_update(ovl));
 
        dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
 }
@@ -1050,7 +1089,7 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
 
        mp->enabled = true;
 
-       r = dss_check_settings(mgr, mgr->device);
+       r = dss_check_settings(mgr);
        if (r) {
                DSSERR("failed to enable manager %d: check_settings failed\n",
                                mgr->id);
@@ -1225,6 +1264,35 @@ err:
        return r;
 }
 
+static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
+               struct omap_video_timings *timings)
+{
+       struct mgr_priv_data *mp = get_mgr_priv(mgr);
+
+       mp->timings = *timings;
+       mp->extra_info_dirty = true;
+}
+
+void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
+               struct omap_video_timings *timings)
+{
+       unsigned long flags;
+
+       mutex_lock(&apply_lock);
+
+       spin_lock_irqsave(&data_lock, flags);
+
+       dss_apply_mgr_timings(mgr, timings);
+
+       dss_write_regs();
+       dss_set_go_bits();
+
+       spin_unlock_irqrestore(&data_lock, flags);
+
+       wait_pending_extra_info_updates();
+
+       mutex_unlock(&apply_lock);
+}
 
 int dss_ovl_set_info(struct omap_overlay *ovl,
                struct omap_overlay_info *info)
@@ -1393,7 +1461,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
 
        op->enabling = true;
 
-       r = dss_check_settings(ovl->manager, ovl->manager->device);
+       r = dss_check_settings(ovl->manager);
        if (r) {
                DSSERR("failed to enable overlay %d: check_settings failed\n",
                                ovl->id);
index e8a1207..72ded9c 100644 (file)
@@ -43,6 +43,8 @@ static struct {
 
        struct regulator *vdds_dsi_reg;
        struct regulator *vdds_sdi_reg;
+
+       const char *default_display_name;
 } core;
 
 static char *def_disp_name;
@@ -54,9 +56,6 @@ bool dss_debug;
 module_param_named(debug, dss_debug, bool, 0644);
 #endif
 
-static int omap_dss_register_device(struct omap_dss_device *);
-static void omap_dss_unregister_device(struct omap_dss_device *);
-
 /* REGULATORS */
 
 struct regulator *dss_get_vdds_dsi(void)
@@ -87,6 +86,51 @@ struct regulator *dss_get_vdds_sdi(void)
        return reg;
 }
 
+int dss_get_ctx_loss_count(struct device *dev)
+{
+       struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
+       int cnt;
+
+       if (!board_data->get_context_loss_count)
+               return -ENOENT;
+
+       cnt = board_data->get_context_loss_count(dev);
+
+       WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt);
+
+       return cnt;
+}
+
+int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask)
+{
+       struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
+
+       if (!board_data->dsi_enable_pads)
+               return -ENOENT;
+
+       return board_data->dsi_enable_pads(dsi_id, lane_mask);
+}
+
+void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask)
+{
+       struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
+
+       if (!board_data->dsi_enable_pads)
+               return;
+
+       return board_data->dsi_disable_pads(dsi_id, lane_mask);
+}
+
+int dss_set_min_bus_tput(struct device *dev, unsigned long tput)
+{
+       struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
+
+       if (pdata->set_min_bus_tput)
+               return pdata->set_min_bus_tput(dev, tput);
+       else
+               return 0;
+}
+
 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
 static int dss_debug_show(struct seq_file *s, void *unused)
 {
@@ -121,34 +165,6 @@ static int dss_initialize_debugfs(void)
        debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
                        &dss_debug_dump_clocks, &dss_debug_fops);
 
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-       debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir,
-                       &dispc_dump_irqs, &dss_debug_fops);
-#endif
-
-#if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS)
-       dsi_create_debugfs_files_irq(dss_debugfs_dir, &dss_debug_fops);
-#endif
-
-       debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
-                       &dss_dump_regs, &dss_debug_fops);
-       debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir,
-                       &dispc_dump_regs, &dss_debug_fops);
-#ifdef CONFIG_OMAP2_DSS_RFBI
-       debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir,
-                       &rfbi_dump_regs, &dss_debug_fops);
-#endif
-#ifdef CONFIG_OMAP2_DSS_DSI
-       dsi_create_debugfs_files_reg(dss_debugfs_dir, &dss_debug_fops);
-#endif
-#ifdef CONFIG_OMAP2_DSS_VENC
-       debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
-                       &venc_dump_regs, &dss_debug_fops);
-#endif
-#ifdef CONFIG_OMAP4_DSS_HDMI
-       debugfs_create_file("hdmi", S_IRUGO, dss_debugfs_dir,
-                       &hdmi_dump_regs, &dss_debug_fops);
-#endif
        return 0;
 }
 
@@ -157,6 +173,19 @@ static void dss_uninitialize_debugfs(void)
        if (dss_debugfs_dir)
                debugfs_remove_recursive(dss_debugfs_dir);
 }
+
+int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
+{
+       struct dentry *d;
+
+       d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
+                       write, &dss_debug_fops);
+
+       if (IS_ERR(d))
+               return PTR_ERR(d);
+
+       return 0;
+}
 #else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
 static inline int dss_initialize_debugfs(void)
 {
@@ -165,14 +194,18 @@ static inline int dss_initialize_debugfs(void)
 static inline void dss_uninitialize_debugfs(void)
 {
 }
+static inline int dss_debugfs_create_file(const char *name,
+               void (*write)(struct seq_file *))
+{
+       return 0;
+}
 #endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
 
 /* PLATFORM DEVICE */
-static int omap_dss_probe(struct platform_device *pdev)
+static int __init omap_dss_probe(struct platform_device *pdev)
 {
        struct omap_dss_board_info *pdata = pdev->dev.platform_data;
        int r;
-       int i;
 
        core.pdev = pdev;
 
@@ -187,28 +220,13 @@ static int omap_dss_probe(struct platform_device *pdev)
        if (r)
                goto err_debugfs;
 
-       for (i = 0; i < pdata->num_devices; ++i) {
-               struct omap_dss_device *dssdev = pdata->devices[i];
-
-               r = omap_dss_register_device(dssdev);
-               if (r) {
-                       DSSERR("device %d %s register failed %d\n", i,
-                               dssdev->name ?: "unnamed", r);
-
-                       while (--i >= 0)
-                               omap_dss_unregister_device(pdata->devices[i]);
-
-                       goto err_register;
-               }
-
-               if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
-                       pdata->default_device = dssdev;
-       }
+       if (def_disp_name)
+               core.default_display_name = def_disp_name;
+       else if (pdata->default_device)
+               core.default_display_name = pdata->default_device->name;
 
        return 0;
 
-err_register:
-       dss_uninitialize_debugfs();
 err_debugfs:
 
        return r;
@@ -216,17 +234,11 @@ err_debugfs:
 
 static int omap_dss_remove(struct platform_device *pdev)
 {
-       struct omap_dss_board_info *pdata = pdev->dev.platform_data;
-       int i;
-
        dss_uninitialize_debugfs();
 
        dss_uninit_overlays(pdev);
        dss_uninit_overlay_managers(pdev);
 
-       for (i = 0; i < pdata->num_devices; ++i)
-               omap_dss_unregister_device(pdata->devices[i]);
-
        return 0;
 }
 
@@ -251,7 +263,6 @@ static int omap_dss_resume(struct platform_device *pdev)
 }
 
 static struct platform_driver omap_dss_driver = {
-       .probe          = omap_dss_probe,
        .remove         = omap_dss_remove,
        .shutdown       = omap_dss_shutdown,
        .suspend        = omap_dss_suspend,
@@ -326,7 +337,6 @@ static int dss_driver_probe(struct device *dev)
        int r;
        struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
        bool force;
 
        DSSDBG("driver_probe: dev %s/%s, drv %s\n",
@@ -335,7 +345,8 @@ static int dss_driver_probe(struct device *dev)
 
        dss_init_device(core.pdev, dssdev);
 
-       force = pdata->default_device == dssdev;
+       force = core.default_display_name &&
+               strcmp(core.default_display_name, dssdev->name) == 0;
        dss_recheck_connections(dssdev, force);
 
        r = dssdrv->probe(dssdev);
@@ -381,6 +392,8 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
        if (dssdriver->get_recommended_bpp == NULL)
                dssdriver->get_recommended_bpp =
                        omapdss_default_get_recommended_bpp;
+       if (dssdriver->get_timings == NULL)
+               dssdriver->get_timings = omapdss_default_get_timings;
 
        return driver_register(&dssdriver->driver);
 }
@@ -427,27 +440,38 @@ static void omap_dss_dev_release(struct device *dev)
        reset_device(dev, 0);
 }
 
-static int omap_dss_register_device(struct omap_dss_device *dssdev)
+int omap_dss_register_device(struct omap_dss_device *dssdev,
+               struct device *parent, int disp_num)
 {
-       static int dev_num;
-
        WARN_ON(!dssdev->driver_name);
 
        reset_device(&dssdev->dev, 1);
        dssdev->dev.bus = &dss_bus_type;
-       dssdev->dev.parent = &dss_bus;
+       dssdev->dev.parent = parent;
        dssdev->dev.release = omap_dss_dev_release;
-       dev_set_name(&dssdev->dev, "display%d", dev_num++);
+       dev_set_name(&dssdev->dev, "display%d", disp_num);
        return device_register(&dssdev->dev);
 }
 
-static void omap_dss_unregister_device(struct omap_dss_device *dssdev)
+void omap_dss_unregister_device(struct omap_dss_device *dssdev)
 {
        device_unregister(&dssdev->dev);
 }
 
+static int dss_unregister_dss_dev(struct device *dev, void *data)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       omap_dss_unregister_device(dssdev);
+       return 0;
+}
+
+void omap_dss_unregister_child_devices(struct device *parent)
+{
+       device_for_each_child(parent, NULL, dss_unregister_dss_dev);
+}
+
 /* BUS */
-static int omap_dss_bus_register(void)
+static int __init omap_dss_bus_register(void)
 {
        int r;
 
@@ -469,12 +493,56 @@ static int omap_dss_bus_register(void)
 }
 
 /* INIT */
+static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
+#ifdef CONFIG_OMAP2_DSS_DPI
+       dpi_init_platform_driver,
+#endif
+#ifdef CONFIG_OMAP2_DSS_SDI
+       sdi_init_platform_driver,
+#endif
+#ifdef CONFIG_OMAP2_DSS_RFBI
+       rfbi_init_platform_driver,
+#endif
+#ifdef CONFIG_OMAP2_DSS_VENC
+       venc_init_platform_driver,
+#endif
+#ifdef CONFIG_OMAP2_DSS_DSI
+       dsi_init_platform_driver,
+#endif
+#ifdef CONFIG_OMAP4_DSS_HDMI
+       hdmi_init_platform_driver,
+#endif
+};
+
+static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
+#ifdef CONFIG_OMAP2_DSS_DPI
+       dpi_uninit_platform_driver,
+#endif
+#ifdef CONFIG_OMAP2_DSS_SDI
+       sdi_uninit_platform_driver,
+#endif
+#ifdef CONFIG_OMAP2_DSS_RFBI
+       rfbi_uninit_platform_driver,
+#endif
+#ifdef CONFIG_OMAP2_DSS_VENC
+       venc_uninit_platform_driver,
+#endif
+#ifdef CONFIG_OMAP2_DSS_DSI
+       dsi_uninit_platform_driver,
+#endif
+#ifdef CONFIG_OMAP4_DSS_HDMI
+       hdmi_uninit_platform_driver,
+#endif
+};
+
+static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)];
 
 static int __init omap_dss_register_drivers(void)
 {
        int r;
+       int i;
 
-       r = platform_driver_register(&omap_dss_driver);
+       r = platform_driver_probe(&omap_dss_driver, omap_dss_probe);
        if (r)
                return r;
 
@@ -490,40 +558,18 @@ static int __init omap_dss_register_drivers(void)
                goto err_dispc;
        }
 
-       r = rfbi_init_platform_driver();
-       if (r) {
-               DSSERR("Failed to initialize rfbi platform driver\n");
-               goto err_rfbi;
-       }
-
-       r = venc_init_platform_driver();
-       if (r) {
-               DSSERR("Failed to initialize venc platform driver\n");
-               goto err_venc;
-       }
-
-       r = dsi_init_platform_driver();
-       if (r) {
-               DSSERR("Failed to initialize DSI platform driver\n");
-               goto err_dsi;
-       }
-
-       r = hdmi_init_platform_driver();
-       if (r) {
-               DSSERR("Failed to initialize hdmi\n");
-               goto err_hdmi;
+       /*
+        * It's ok if the output-driver register fails. It happens, for example,
+        * when there is no output-device (e.g. SDI for OMAP4).
+        */
+       for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) {
+               r = dss_output_drv_reg_funcs[i]();
+               if (r == 0)
+                       dss_output_drv_loaded[i] = true;
        }
 
        return 0;
 
-err_hdmi:
-       dsi_uninit_platform_driver();
-err_dsi:
-       venc_uninit_platform_driver();
-err_venc:
-       rfbi_uninit_platform_driver();
-err_rfbi:
-       dispc_uninit_platform_driver();
 err_dispc:
        dss_uninit_platform_driver();
 err_dss:
@@ -534,10 +580,13 @@ err_dss:
 
 static void __exit omap_dss_unregister_drivers(void)
 {
-       hdmi_uninit_platform_driver();
-       dsi_uninit_platform_driver();
-       venc_uninit_platform_driver();
-       rfbi_uninit_platform_driver();
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) {
+               if (dss_output_drv_loaded[i])
+                       dss_output_drv_unreg_funcs[i]();
+       }
+
        dispc_uninit_platform_driver();
        dss_uninit_platform_driver();
 
index ee30937..4749ac3 100644 (file)
@@ -131,23 +131,6 @@ static inline u32 dispc_read_reg(const u16 idx)
        return __raw_readl(dispc.base + idx);
 }
 
-static int dispc_get_ctx_loss_count(void)
-{
-       struct device *dev = &dispc.pdev->dev;
-       struct omap_display_platform_data *pdata = dev->platform_data;
-       struct omap_dss_board_info *board_data = pdata->board_data;
-       int cnt;
-
-       if (!board_data->get_context_loss_count)
-               return -ENOENT;
-
-       cnt = board_data->get_context_loss_count(dev);
-
-       WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt);
-
-       return cnt;
-}
-
 #define SR(reg) \
        dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
 #define RR(reg) \
@@ -251,7 +234,7 @@ static void dispc_save_context(void)
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                SR(DIVISOR);
 
-       dispc.ctx_loss_cnt = dispc_get_ctx_loss_count();
+       dispc.ctx_loss_cnt = dss_get_ctx_loss_count(&dispc.pdev->dev);
        dispc.ctx_valid = true;
 
        DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt);
@@ -266,7 +249,7 @@ static void dispc_restore_context(void)
        if (!dispc.ctx_valid)
                return;
 
-       ctx = dispc_get_ctx_loss_count();
+       ctx = dss_get_ctx_loss_count(&dispc.pdev->dev);
 
        if (ctx >= 0 && ctx == dispc.ctx_loss_cnt)
                return;
@@ -413,14 +396,6 @@ static inline bool dispc_mgr_is_lcd(enum omap_channel channel)
                return false;
 }
 
-static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel)
-{
-       struct omap_overlay_manager *mgr =
-               omap_dss_get_overlay_manager(channel);
-
-       return mgr ? mgr->device : NULL;
-}
-
 u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
 {
        switch (channel) {
@@ -432,6 +407,7 @@ u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
                return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -446,6 +422,7 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
                return 0;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -764,7 +741,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane,
                case OMAP_DSS_COLOR_XRGB16_1555:
                        m = 0xf; break;
                default:
-                       BUG(); break;
+                       BUG(); return;
                }
        } else {
                switch (color_mode) {
@@ -801,13 +778,25 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane,
                case OMAP_DSS_COLOR_XRGB16_1555:
                        m = 0xf; break;
                default:
-                       BUG(); break;
+                       BUG(); return;
                }
        }
 
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
 }
 
+static void dispc_ovl_configure_burst_type(enum omap_plane plane,
+               enum omap_dss_rotation_type rotation_type)
+{
+       if (dss_has_feature(FEAT_BURST_2D) == 0)
+               return;
+
+       if (rotation_type == OMAP_DSS_ROT_TILER)
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
+       else
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
+}
+
 void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
 {
        int shift;
@@ -845,6 +834,7 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
                        break;
                default:
                        BUG();
+                       return;
                }
 
                val = FLD_MOD(val, chan, shift, shift);
@@ -872,6 +862,7 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
                break;
        default:
                BUG();
+               return 0;
        }
 
        val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
@@ -983,20 +974,13 @@ static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable)
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
 }
 
-void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
+static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
+               u16 height)
 {
        u32 val;
-       BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
-       val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       dispc_write_reg(DISPC_SIZE_MGR(channel), val);
-}
 
-void dispc_set_digit_size(u16 width, u16 height)
-{
-       u32 val;
-       BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val);
+       dispc_write_reg(DISPC_SIZE_MGR(channel), val);
 }
 
 static void dispc_read_plane_fifo_sizes(void)
@@ -1063,7 +1047,8 @@ void dispc_enable_fifomerge(bool enable)
 }
 
 void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
-               u32 *fifo_low, u32 *fifo_high, bool use_fifomerge)
+               u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
+               bool manual_update)
 {
        /*
         * All sizes are in bytes. Both the buffer and burst are made of
@@ -1091,7 +1076,7 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
         * combined fifo size
         */
 
-       if (dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
+       if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
                *fifo_low = ovl_fifo_size - burst_size * 2;
                *fifo_high = total_fifo_size - burst_size;
        } else {
@@ -1185,6 +1170,94 @@ static void dispc_ovl_set_scale_param(enum omap_plane plane,
        dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
 }
 
+static void dispc_ovl_set_accu_uv(enum omap_plane plane,
+               u16 orig_width, u16 orig_height, u16 out_width, u16 out_height,
+               bool ilace, enum omap_color_mode color_mode, u8 rotation)
+{
+       int h_accu2_0, h_accu2_1;
+       int v_accu2_0, v_accu2_1;
+       int chroma_hinc, chroma_vinc;
+       int idx;
+
+       struct accu {
+               s8 h0_m, h0_n;
+               s8 h1_m, h1_n;
+               s8 v0_m, v0_n;
+               s8 v1_m, v1_n;
+       };
+
+       const struct accu *accu_table;
+       const struct accu *accu_val;
+
+       static const struct accu accu_nv12[4] = {
+               {  0, 1,  0, 1 , -1, 2, 0, 1 },
+               {  1, 2, -3, 4 ,  0, 1, 0, 1 },
+               { -1, 1,  0, 1 , -1, 2, 0, 1 },
+               { -1, 2, -1, 2 , -1, 1, 0, 1 },
+       };
+
+       static const struct accu accu_nv12_ilace[4] = {
+               {  0, 1,  0, 1 , -3, 4, -1, 4 },
+               { -1, 4, -3, 4 ,  0, 1,  0, 1 },
+               { -1, 1,  0, 1 , -1, 4, -3, 4 },
+               { -3, 4, -3, 4 , -1, 1,  0, 1 },
+       };
+
+       static const struct accu accu_yuv[4] = {
+               {  0, 1, 0, 1,  0, 1, 0, 1 },
+               {  0, 1, 0, 1,  0, 1, 0, 1 },
+               { -1, 1, 0, 1,  0, 1, 0, 1 },
+               {  0, 1, 0, 1, -1, 1, 0, 1 },
+       };
+
+       switch (rotation) {
+       case OMAP_DSS_ROT_0:
+               idx = 0;
+               break;
+       case OMAP_DSS_ROT_90:
+               idx = 1;
+               break;
+       case OMAP_DSS_ROT_180:
+               idx = 2;
+               break;
+       case OMAP_DSS_ROT_270:
+               idx = 3;
+               break;
+       default:
+               BUG();
+               return;
+       }
+
+       switch (color_mode) {
+       case OMAP_DSS_COLOR_NV12:
+               if (ilace)
+                       accu_table = accu_nv12_ilace;
+               else
+                       accu_table = accu_nv12;
+               break;
+       case OMAP_DSS_COLOR_YUV2:
+       case OMAP_DSS_COLOR_UYVY:
+               accu_table = accu_yuv;
+               break;
+       default:
+               BUG();
+               return;
+       }
+
+       accu_val = &accu_table[idx];
+
+       chroma_hinc = 1024 * orig_width / out_width;
+       chroma_vinc = 1024 * orig_height / out_height;
+
+       h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
+       h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
+       v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
+       v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
+
+       dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0);
+       dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1);
+}
+
 static void dispc_ovl_set_scaling_common(enum omap_plane plane,
                u16 orig_width, u16 orig_height,
                u16 out_width, u16 out_height,
@@ -1258,6 +1331,10 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
                REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
                return;
        }
+
+       dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width,
+                       out_height, ilace, color_mode, rotation);
+
        switch (color_mode) {
        case OMAP_DSS_COLOR_NV12:
                /* UV is subsampled by 2 vertically*/
@@ -1280,6 +1357,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
                break;
        default:
                BUG();
+               return;
        }
 
        if (out_width != orig_width)
@@ -1297,9 +1375,6 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
        /* set V scaling */
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
-
-       dispc_ovl_set_vid_accu2_0(plane, 0x80, 0);
-       dispc_ovl_set_vid_accu2_1(plane, 0x80, 0);
 }
 
 static void dispc_ovl_set_scaling(enum omap_plane plane,
@@ -1410,6 +1485,7 @@ static int color_mode_to_bpp(enum omap_color_mode color_mode)
                return 32;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -1423,6 +1499,7 @@ static s32 pixinc(int pixels, u8 ps)
                return 1 - (-pixels + 1) * ps;
        else
                BUG();
+               return 0;
 }
 
 static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
@@ -1431,7 +1508,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
                enum omap_color_mode color_mode, bool fieldmode,
                unsigned int field_offset,
                unsigned *offset0, unsigned *offset1,
-               s32 *row_inc, s32 *pix_inc)
+               s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
 {
        u8 ps;
 
@@ -1477,10 +1554,10 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
                else
                        *offset0 = 0;
 
-               *row_inc = pixinc(1 + (screen_width - width) +
-                               (fieldmode ? screen_width : 0),
-                               ps);
-               *pix_inc = pixinc(1, ps);
+               *row_inc = pixinc(1 +
+                       (y_predecim * screen_width - x_predecim * width) +
+                       (fieldmode ? screen_width : 0), ps);
+               *pix_inc = pixinc(x_predecim, ps);
                break;
 
        case OMAP_DSS_ROT_0 + 4:
@@ -1498,14 +1575,15 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
                        *offset0 = field_offset * screen_width * ps;
                else
                        *offset0 = 0;
-               *row_inc = pixinc(1 - (screen_width + width) -
-                               (fieldmode ? screen_width : 0),
-                               ps);
-               *pix_inc = pixinc(1, ps);
+               *row_inc = pixinc(1 -
+                       (y_predecim * screen_width + x_predecim * width) -
+                       (fieldmode ? screen_width : 0), ps);
+               *pix_inc = pixinc(x_predecim, ps);
                break;
 
        default:
                BUG();
+               return;
        }
 }
 
@@ -1515,7 +1593,7 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                enum omap_color_mode color_mode, bool fieldmode,
                unsigned int field_offset,
                unsigned *offset0, unsigned *offset1,
-               s32 *row_inc, s32 *pix_inc)
+               s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
 {
        u8 ps;
        u16 fbw, fbh;
@@ -1557,10 +1635,14 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                        *offset0 = *offset1 + field_offset * screen_width * ps;
                else
                        *offset0 = *offset1;
-               *row_inc = pixinc(1 + (screen_width - fbw) +
-                               (fieldmode ? screen_width : 0),
-                               ps);
-               *pix_inc = pixinc(1, ps);
+               *row_inc = pixinc(1 +
+                       (y_predecim * screen_width - fbw * x_predecim) +
+                       (fieldmode ? screen_width : 0), ps);
+               if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+                       color_mode == OMAP_DSS_COLOR_UYVY)
+                       *pix_inc = pixinc(x_predecim, 2 * ps);
+               else
+                       *pix_inc = pixinc(x_predecim, ps);
                break;
        case OMAP_DSS_ROT_90:
                *offset1 = screen_width * (fbh - 1) * ps;
@@ -1568,9 +1650,9 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                        *offset0 = *offset1 + field_offset * ps;
                else
                        *offset0 = *offset1;
-               *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
-                               (fieldmode ? 1 : 0), ps);
-               *pix_inc = pixinc(-screen_width, ps);
+               *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) +
+                               y_predecim + (fieldmode ? 1 : 0), ps);
+               *pix_inc = pixinc(-x_predecim * screen_width, ps);
                break;
        case OMAP_DSS_ROT_180:
                *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
@@ -1579,10 +1661,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                else
                        *offset0 = *offset1;
                *row_inc = pixinc(-1 -
-                               (screen_width - fbw) -
-                               (fieldmode ? screen_width : 0),
-                               ps);
-               *pix_inc = pixinc(-1, ps);
+                       (y_predecim * screen_width - fbw * x_predecim) -
+                       (fieldmode ? screen_width : 0), ps);
+               if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+                       color_mode == OMAP_DSS_COLOR_UYVY)
+                       *pix_inc = pixinc(-x_predecim, 2 * ps);
+               else
+                       *pix_inc = pixinc(-x_predecim, ps);
                break;
        case OMAP_DSS_ROT_270:
                *offset1 = (fbw - 1) * ps;
@@ -1590,9 +1675,9 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                        *offset0 = *offset1 - field_offset * ps;
                else
                        *offset0 = *offset1;
-               *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
-                               (fieldmode ? 1 : 0), ps);
-               *pix_inc = pixinc(screen_width, ps);
+               *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) -
+                               y_predecim - (fieldmode ? 1 : 0), ps);
+               *pix_inc = pixinc(x_predecim * screen_width, ps);
                break;
 
        /* mirroring */
@@ -1602,10 +1687,14 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                        *offset0 = *offset1 + field_offset * screen_width * ps;
                else
                        *offset0 = *offset1;
-               *row_inc = pixinc(screen_width * 2 - 1 +
+               *row_inc = pixinc(y_predecim * screen_width * 2 - 1 +
                                (fieldmode ? screen_width : 0),
                                ps);
-               *pix_inc = pixinc(-1, ps);
+               if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+                       color_mode == OMAP_DSS_COLOR_UYVY)
+                       *pix_inc = pixinc(-x_predecim, 2 * ps);
+               else
+                       *pix_inc = pixinc(-x_predecim, ps);
                break;
 
        case OMAP_DSS_ROT_90 + 4:
@@ -1614,10 +1703,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                        *offset0 = *offset1 + field_offset * ps;
                else
                        *offset0 = *offset1;
-               *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
-                               (fieldmode ? 1 : 0),
+               *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) +
+                               y_predecim + (fieldmode ? 1 : 0),
                                ps);
-               *pix_inc = pixinc(screen_width, ps);
+               *pix_inc = pixinc(x_predecim * screen_width, ps);
                break;
 
        case OMAP_DSS_ROT_180 + 4:
@@ -1626,10 +1715,14 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                        *offset0 = *offset1 - field_offset * screen_width * ps;
                else
                        *offset0 = *offset1;
-               *row_inc = pixinc(1 - screen_width * 2 -
+               *row_inc = pixinc(1 - y_predecim * screen_width * 2 -
                                (fieldmode ? screen_width : 0),
                                ps);
-               *pix_inc = pixinc(1, ps);
+               if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+                       color_mode == OMAP_DSS_COLOR_UYVY)
+                       *pix_inc = pixinc(x_predecim, 2 * ps);
+               else
+                       *pix_inc = pixinc(x_predecim, ps);
                break;
 
        case OMAP_DSS_ROT_270 + 4:
@@ -1638,34 +1731,130 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
                        *offset0 = *offset1 - field_offset * ps;
                else
                        *offset0 = *offset1;
-               *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
-                               (fieldmode ? 1 : 0),
+               *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) -
+                               y_predecim - (fieldmode ? 1 : 0),
                                ps);
-               *pix_inc = pixinc(-screen_width, ps);
+               *pix_inc = pixinc(-x_predecim * screen_width, ps);
                break;
 
        default:
                BUG();
+               return;
+       }
+}
+
+static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
+               enum omap_color_mode color_mode, bool fieldmode,
+               unsigned int field_offset, unsigned *offset0, unsigned *offset1,
+               s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
+{
+       u8 ps;
+
+       switch (color_mode) {
+       case OMAP_DSS_COLOR_CLUT1:
+       case OMAP_DSS_COLOR_CLUT2:
+       case OMAP_DSS_COLOR_CLUT4:
+       case OMAP_DSS_COLOR_CLUT8:
+               BUG();
+               return;
+       default:
+               ps = color_mode_to_bpp(color_mode) / 8;
+               break;
        }
+
+       DSSDBG("scrw %d, width %d\n", screen_width, width);
+
+       /*
+        * field 0 = even field = bottom field
+        * field 1 = odd field = top field
+        */
+       *offset1 = 0;
+       if (field_offset)
+               *offset0 = *offset1 + field_offset * screen_width * ps;
+       else
+               *offset0 = *offset1;
+       *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
+                       (fieldmode ? screen_width : 0), ps);
+       if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+               color_mode == OMAP_DSS_COLOR_UYVY)
+               *pix_inc = pixinc(x_predecim, 2 * ps);
+       else
+               *pix_inc = pixinc(x_predecim, ps);
 }
 
-static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
+/*
+ * This function is used to avoid synclosts in OMAP3, because of some
+ * undocumented horizontal position and timing related limitations.
+ */
+static int check_horiz_timing_omap3(enum omap_channel channel,
+               const struct omap_video_timings *t, u16 pos_x,
+               u16 width, u16 height, u16 out_width, u16 out_height)
+{
+       int DS = DIV_ROUND_UP(height, out_height);
+       unsigned long nonactive, lclk, pclk;
+       static const u8 limits[3] = { 8, 10, 20 };
+       u64 val, blank;
+       int i;
+
+       nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;
+       pclk = dispc_mgr_pclk_rate(channel);
+       if (dispc_mgr_is_lcd(channel))
+               lclk = dispc_mgr_lclk_rate(channel);
+       else
+               lclk = dispc_fclk_rate();
+
+       i = 0;
+       if (out_height < height)
+               i++;
+       if (out_width < width)
+               i++;
+       blank = div_u64((u64)(t->hbp + t->hsw + t->hfp) * lclk, pclk);
+       DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
+       if (blank <= limits[i])
+               return -EINVAL;
+
+       /*
+        * Pixel data should be prepared before visible display point starts.
+        * So, atleast DS-2 lines must have already been fetched by DISPC
+        * during nonactive - pos_x period.
+        */
+       val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
+       DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
+               val, max(0, DS - 2) * width);
+       if (val < max(0, DS - 2) * width)
+               return -EINVAL;
+
+       /*
+        * All lines need to be refilled during the nonactive period of which
+        * only one line can be loaded during the active period. So, atleast
+        * DS - 1 lines should be loaded during nonactive period.
+        */
+       val =  div_u64((u64)nonactive * lclk, pclk);
+       DSSDBG("nonactive * pcd  = %llu, max(0, DS - 1) * width = %d\n",
+               val, max(0, DS - 1) * width);
+       if (val < max(0, DS - 1) * width)
+               return -EINVAL;
+
+       return 0;
+}
+
+static unsigned long calc_core_clk_five_taps(enum omap_channel channel,
+               const struct omap_video_timings *mgr_timings, u16 width,
                u16 height, u16 out_width, u16 out_height,
                enum omap_color_mode color_mode)
 {
-       u32 fclk = 0;
+       u32 core_clk = 0;
        u64 tmp, pclk = dispc_mgr_pclk_rate(channel);
 
        if (height <= out_height && width <= out_width)
                return (unsigned long) pclk;
 
        if (height > out_height) {
-               struct omap_dss_device *dssdev = dispc_mgr_get_device(channel);
-               unsigned int ppl = dssdev->panel.timings.x_res;
+               unsigned int ppl = mgr_timings->x_res;
 
                tmp = pclk * height * out_width;
                do_div(tmp, 2 * out_height * ppl);
-               fclk = tmp;
+               core_clk = tmp;
 
                if (height > 2 * out_height) {
                        if (ppl == out_width)
@@ -1673,23 +1862,23 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
 
                        tmp = pclk * (height - 2 * out_height) * out_width;
                        do_div(tmp, 2 * out_height * (ppl - out_width));
-                       fclk = max(fclk, (u32) tmp);
+                       core_clk = max_t(u32, core_clk, tmp);
                }
        }
 
        if (width > out_width) {
                tmp = pclk * width;
                do_div(tmp, out_width);
-               fclk = max(fclk, (u32) tmp);
+               core_clk = max_t(u32, core_clk, tmp);
 
                if (color_mode == OMAP_DSS_COLOR_RGB24U)
-                       fclk <<= 1;
+                       core_clk <<= 1;
        }
 
-       return fclk;
+       return core_clk;
 }
 
-static unsigned long calc_fclk(enum omap_channel channel, u16 width,
+static unsigned long calc_core_clk(enum omap_channel channel, u16 width,
                u16 height, u16 out_width, u16 out_height)
 {
        unsigned int hf, vf;
@@ -1730,15 +1919,20 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
 }
 
 static int dispc_ovl_calc_scaling(enum omap_plane plane,
-               enum omap_channel channel, u16 width, u16 height,
-               u16 out_width, u16 out_height,
-               enum omap_color_mode color_mode, bool *five_taps)
+               enum omap_channel channel,
+               const struct omap_video_timings *mgr_timings,
+               u16 width, u16 height, u16 out_width, u16 out_height,
+               enum omap_color_mode color_mode, bool *five_taps,
+               int *x_predecim, int *y_predecim, u16 pos_x)
 {
        struct omap_overlay *ovl = omap_dss_get_overlay(plane);
        const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
        const int maxsinglelinewidth =
                                dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
-       unsigned long fclk = 0;
+       const int max_decim_limit = 16;
+       unsigned long core_clk = 0;
+       int decim_x, decim_y, error, min_factor;
+       u16 in_width, in_height, in_width_max = 0;
 
        if (width == out_width && height == out_height)
                return 0;
@@ -1746,64 +1940,154 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
        if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
                return -EINVAL;
 
-       if (out_width < width / maxdownscale ||
-                       out_width > width * 8)
+       *x_predecim = max_decim_limit;
+       *y_predecim = max_decim_limit;
+
+       if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
+           color_mode == OMAP_DSS_COLOR_CLUT2 ||
+           color_mode == OMAP_DSS_COLOR_CLUT4 ||
+           color_mode == OMAP_DSS_COLOR_CLUT8) {
+               *x_predecim = 1;
+               *y_predecim = 1;
+               *five_taps = false;
+               return 0;
+       }
+
+       decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
+       decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
+
+       min_factor = min(decim_x, decim_y);
+
+       if (decim_x > *x_predecim || out_width > width * 8)
                return -EINVAL;
 
-       if (out_height < height / maxdownscale ||
-                       out_height > height * 8)
+       if (decim_y > *y_predecim || out_height > height * 8)
                return -EINVAL;
 
        if (cpu_is_omap24xx()) {
-               if (width > maxsinglelinewidth)
-                       DSSERR("Cannot scale max input width exceeded");
                *five_taps = false;
-               fclk = calc_fclk(channel, width, height, out_width,
-                                                               out_height);
+
+               do {
+                       in_height = DIV_ROUND_UP(height, decim_y);
+                       in_width = DIV_ROUND_UP(width, decim_x);
+                       core_clk = calc_core_clk(channel, in_width, in_height,
+                                       out_width, out_height);
+                       error = (in_width > maxsinglelinewidth || !core_clk ||
+                               core_clk > dispc_core_clk_rate());
+                       if (error) {
+                               if (decim_x == decim_y) {
+                                       decim_x = min_factor;
+                                       decim_y++;
+                               } else {
+                                       swap(decim_x, decim_y);
+                                       if (decim_x < decim_y)
+                                               decim_x++;
+                               }
+                       }
+               } while (decim_x <= *x_predecim && decim_y <= *y_predecim &&
+                               error);
+
+               if (in_width > maxsinglelinewidth) {
+                       DSSERR("Cannot scale max input width exceeded");
+                       return -EINVAL;
+               }
        } else if (cpu_is_omap34xx()) {
-               if (width > (maxsinglelinewidth * 2)) {
+
+               do {
+                       in_height = DIV_ROUND_UP(height, decim_y);
+                       in_width = DIV_ROUND_UP(width, decim_x);
+                       core_clk = calc_core_clk_five_taps(channel, mgr_timings,
+                               in_width, in_height, out_width, out_height,
+                               color_mode);
+
+                       error = check_horiz_timing_omap3(channel, mgr_timings,
+                               pos_x, in_width, in_height, out_width,
+                               out_height);
+
+                       if (in_width > maxsinglelinewidth)
+                               if (in_height > out_height &&
+                                       in_height < out_height * 2)
+                                       *five_taps = false;
+                       if (!*five_taps)
+                               core_clk = calc_core_clk(channel, in_width,
+                                       in_height, out_width, out_height);
+                       error = (error || in_width > maxsinglelinewidth * 2 ||
+                               (in_width > maxsinglelinewidth && *five_taps) ||
+                               !core_clk || core_clk > dispc_core_clk_rate());
+                       if (error) {
+                               if (decim_x == decim_y) {
+                                       decim_x = min_factor;
+                                       decim_y++;
+                               } else {
+                                       swap(decim_x, decim_y);
+                                       if (decim_x < decim_y)
+                                               decim_x++;
+                               }
+                       }
+               } while (decim_x <= *x_predecim && decim_y <= *y_predecim
+                       && error);
+
+               if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width,
+                       height, out_width, out_height)){
+                               DSSERR("horizontal timing too tight\n");
+                               return -EINVAL;
+               }
+
+               if (in_width > (maxsinglelinewidth * 2)) {
                        DSSERR("Cannot setup scaling");
                        DSSERR("width exceeds maximum width possible");
                        return -EINVAL;
                }
-               fclk = calc_fclk_five_taps(channel, width, height, out_width,
-                                               out_height, color_mode);
-               if (width > maxsinglelinewidth) {
-                       if (height > out_height && height < out_height * 2)
-                               *five_taps = false;
-                       else {
-                               DSSERR("cannot setup scaling with five taps");
-                               return -EINVAL;
-                       }
+
+               if (in_width > maxsinglelinewidth && *five_taps) {
+                       DSSERR("cannot setup scaling with five taps");
+                       return -EINVAL;
                }
-               if (!*five_taps)
-                       fclk = calc_fclk(channel, width, height, out_width,
-                                       out_height);
        } else {
-               if (width > maxsinglelinewidth) {
+               int decim_x_min = decim_x;
+               in_height = DIV_ROUND_UP(height, decim_y);
+               in_width_max = dispc_core_clk_rate() /
+                               DIV_ROUND_UP(dispc_mgr_pclk_rate(channel),
+                                               out_width);
+               decim_x = DIV_ROUND_UP(width, in_width_max);
+
+               decim_x = decim_x > decim_x_min ? decim_x : decim_x_min;
+               if (decim_x > *x_predecim)
+                       return -EINVAL;
+
+               do {
+                       in_width = DIV_ROUND_UP(width, decim_x);
+               } while (decim_x <= *x_predecim &&
+                               in_width > maxsinglelinewidth && decim_x++);
+
+               if (in_width > maxsinglelinewidth) {
                        DSSERR("Cannot scale width exceeds max line width");
                        return -EINVAL;
                }
-               fclk = calc_fclk(channel, width, height, out_width,
-                               out_height);
+
+               core_clk = calc_core_clk(channel, in_width, in_height,
+                               out_width, out_height);
        }
 
-       DSSDBG("required fclk rate = %lu Hz\n", fclk);
-       DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
+       DSSDBG("required core clk rate = %lu Hz\n", core_clk);
+       DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate());
 
-       if (!fclk || fclk > dispc_fclk_rate()) {
+       if (!core_clk || core_clk > dispc_core_clk_rate()) {
                DSSERR("failed to set up scaling, "
-                       "required fclk rate = %lu Hz, "
-                       "current fclk rate = %lu Hz\n",
-                       fclk, dispc_fclk_rate());
+                       "required core clk rate = %lu Hz, "
+                       "current core clk rate = %lu Hz\n",
+                       core_clk, dispc_core_clk_rate());
                return -EINVAL;
        }
 
+       *x_predecim = decim_x;
+       *y_predecim = decim_y;
        return 0;
 }
 
 int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
-               bool ilace, bool replication)
+               bool ilace, bool replication,
+               const struct omap_video_timings *mgr_timings)
 {
        struct omap_overlay *ovl = omap_dss_get_overlay(plane);
        bool five_taps = true;
@@ -1814,8 +2098,11 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
        s32 pix_inc;
        u16 frame_height = oi->height;
        unsigned int field_offset = 0;
-       u16 outw, outh;
+       u16 in_height = oi->height;
+       u16 in_width = oi->width;
+       u16 out_width, out_height;
        enum omap_channel channel;
+       int x_predecim = 1, y_predecim = 1;
 
        channel = dispc_ovl_get_channel_out(plane);
 
@@ -1829,32 +2116,35 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
        if (oi->paddr == 0)
                return -EINVAL;
 
-       outw = oi->out_width == 0 ? oi->width : oi->out_width;
-       outh = oi->out_height == 0 ? oi->height : oi->out_height;
+       out_width = oi->out_width == 0 ? oi->width : oi->out_width;
+       out_height = oi->out_height == 0 ? oi->height : oi->out_height;
 
-       if (ilace && oi->height == outh)
+       if (ilace && oi->height == out_height)
                fieldmode = 1;
 
        if (ilace) {
                if (fieldmode)
-                       oi->height /= 2;
+                       in_height /= 2;
                oi->pos_y /= 2;
-               outh /= 2;
+               out_height /= 2;
 
                DSSDBG("adjusting for ilace: height %d, pos_y %d, "
                                "out_height %d\n",
-                               oi->height, oi->pos_y, outh);
+                               in_height, oi->pos_y, out_height);
        }
 
        if (!dss_feat_color_mode_supported(plane, oi->color_mode))
                return -EINVAL;
 
-       r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height,
-                       outw, outh, oi->color_mode,
-                       &five_taps);
+       r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width,
+                       in_height, out_width, out_height, oi->color_mode,
+                       &five_taps, &x_predecim, &y_predecim, oi->pos_x);
        if (r)
                return r;
 
+       in_width = DIV_ROUND_UP(in_width, x_predecim);
+       in_height = DIV_ROUND_UP(in_height, y_predecim);
+
        if (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
                        oi->color_mode == OMAP_DSS_COLOR_UYVY ||
                        oi->color_mode == OMAP_DSS_COLOR_NV12)
@@ -1868,32 +2158,46 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
                 * so the integer part must be added to the base address of the
                 * bottom field.
                 */
-               if (!oi->height || oi->height == outh)
+               if (!in_height || in_height == out_height)
                        field_offset = 0;
                else
-                       field_offset = oi->height / outh / 2;
+                       field_offset = in_height / out_height / 2;
        }
 
        /* Fields are independent but interleaved in memory. */
        if (fieldmode)
                field_offset = 1;
 
-       if (oi->rotation_type == OMAP_DSS_ROT_DMA)
+       offset0 = 0;
+       offset1 = 0;
+       row_inc = 0;
+       pix_inc = 0;
+
+       if (oi->rotation_type == OMAP_DSS_ROT_TILER)
+               calc_tiler_rotation_offset(oi->screen_width, in_width,
+                               oi->color_mode, fieldmode, field_offset,
+                               &offset0, &offset1, &row_inc, &pix_inc,
+                               x_predecim, y_predecim);
+       else if (oi->rotation_type == OMAP_DSS_ROT_DMA)
                calc_dma_rotation_offset(oi->rotation, oi->mirror,
-                               oi->screen_width, oi->width, frame_height,
+                               oi->screen_width, in_width, frame_height,
                                oi->color_mode, fieldmode, field_offset,
-                               &offset0, &offset1, &row_inc, &pix_inc);
+                               &offset0, &offset1, &row_inc, &pix_inc,
+                               x_predecim, y_predecim);
        else
                calc_vrfb_rotation_offset(oi->rotation, oi->mirror,
-                               oi->screen_width, oi->width, frame_height,
+                               oi->screen_width, in_width, frame_height,
                                oi->color_mode, fieldmode, field_offset,
-                               &offset0, &offset1, &row_inc, &pix_inc);
+                               &offset0, &offset1, &row_inc, &pix_inc,
+                               x_predecim, y_predecim);
 
        DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
                        offset0, offset1, row_inc, pix_inc);
 
        dispc_ovl_set_color_mode(plane, oi->color_mode);
 
+       dispc_ovl_configure_burst_type(plane, oi->rotation_type);
+
        dispc_ovl_set_ba0(plane, oi->paddr + offset0);
        dispc_ovl_set_ba1(plane, oi->paddr + offset1);
 
@@ -1906,19 +2210,18 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
        dispc_ovl_set_row_inc(plane, row_inc);
        dispc_ovl_set_pix_inc(plane, pix_inc);
 
-       DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width,
-                       oi->height, outw, outh);
+       DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width,
+                       in_height, out_width, out_height);
 
        dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y);
 
-       dispc_ovl_set_pic_size(plane, oi->width, oi->height);
+       dispc_ovl_set_pic_size(plane, in_width, in_height);
 
        if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) {
-               dispc_ovl_set_scaling(plane, oi->width, oi->height,
-                                  outw, outh,
-                                  ilace, five_taps, fieldmode,
+               dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
+                                  out_height, ilace, five_taps, fieldmode,
                                   oi->color_mode, oi->rotation);
-               dispc_ovl_set_vid_size(plane, outw, outh);
+               dispc_ovl_set_vid_size(plane, out_width, out_height);
                dispc_ovl_set_vid_color_conv(plane, cconv);
        }
 
@@ -2087,8 +2390,10 @@ bool dispc_mgr_is_enabled(enum omap_channel channel)
                return !!REG_GET(DISPC_CONTROL, 1, 1);
        else if (channel == OMAP_DSS_CHANNEL_LCD2)
                return !!REG_GET(DISPC_CONTROL2, 0, 0);
-       else
+       else {
                BUG();
+               return false;
+       }
 }
 
 void dispc_mgr_enable(enum omap_channel channel, bool enable)
@@ -2285,6 +2590,12 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
                REG_FLD_MOD(DISPC_CONTROL, enable, 11, 11);
 }
 
+static bool _dispc_mgr_size_ok(u16 width, u16 height)
+{
+       return width <= dss_feat_get_param_max(FEAT_PARAM_MGR_WIDTH) &&
+               height <= dss_feat_get_param_max(FEAT_PARAM_MGR_HEIGHT);
+}
+
 static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
                int vsw, int vfp, int vbp)
 {
@@ -2309,11 +2620,20 @@ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
        return true;
 }
 
-bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
+bool dispc_mgr_timings_ok(enum omap_channel channel,
+               const struct omap_video_timings *timings)
 {
-       return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
-                       timings->hbp, timings->vsw,
-                       timings->vfp, timings->vbp);
+       bool timings_ok;
+
+       timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
+
+       if (dispc_mgr_is_lcd(channel))
+               timings_ok =  timings_ok && _dispc_lcd_timings_ok(timings->hsw,
+                                               timings->hfp, timings->hbp,
+                                               timings->vsw, timings->vfp,
+                                               timings->vbp);
+
+       return timings_ok;
 }
 
 static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
@@ -2340,37 +2660,45 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
 }
 
 /* change name to mode? */
-void dispc_mgr_set_lcd_timings(enum omap_channel channel,
+void dispc_mgr_set_timings(enum omap_channel channel,
                struct omap_video_timings *timings)
 {
        unsigned xtot, ytot;
        unsigned long ht, vt;
+       struct omap_video_timings t = *timings;
+
+       DSSDBG("channel %d xres %u yres %u\n", channel, t.x_res, t.y_res);
 
-       if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
-                               timings->hbp, timings->vsw,
-                               timings->vfp, timings->vbp))
+       if (!dispc_mgr_timings_ok(channel, &t)) {
                BUG();
+               return;
+       }
+
+       if (dispc_mgr_is_lcd(channel)) {
+               _dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw,
+                               t.vfp, t.vbp);
+
+               xtot = t.x_res + t.hfp + t.hsw + t.hbp;
+               ytot = t.y_res + t.vfp + t.vsw + t.vbp;
 
-       _dispc_mgr_set_lcd_timings(channel, timings->hsw, timings->hfp,
-                       timings->hbp, timings->vsw, timings->vfp,
-                       timings->vbp);
+               ht = (timings->pixel_clock * 1000) / xtot;
+               vt = (timings->pixel_clock * 1000) / xtot / ytot;
 
-       dispc_mgr_set_lcd_size(channel, timings->x_res, timings->y_res);
+               DSSDBG("pck %u\n", timings->pixel_clock);
+               DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
+                       t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp);
 
-       xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
-       ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
+               DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
+       } else {
+               enum dss_hdmi_venc_clk_source_select source;
 
-       ht = (timings->pixel_clock * 1000) / xtot;
-       vt = (timings->pixel_clock * 1000) / xtot / ytot;
+               source = dss_get_hdmi_venc_clk_source();
 
-       DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res,
-                       timings->y_res);
-       DSSDBG("pck %u\n", timings->pixel_clock);
-       DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
-                       timings->hsw, timings->hfp, timings->hbp,
-                       timings->vsw, timings->vfp, timings->vbp);
+               if (source == DSS_VENC_TV_CLK)
+                       t.y_res /= 2;
+       }
 
-       DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
+       dispc_mgr_set_size(channel, t.x_res, t.y_res);
 }
 
 static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
@@ -2411,6 +2739,7 @@ unsigned long dispc_fclk_rate(void)
                break;
        default:
                BUG();
+               return 0;
        }
 
        return r;
@@ -2441,6 +2770,7 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
                break;
        default:
                BUG();
+               return 0;
        }
 
        return r / lcd;
@@ -2462,20 +2792,35 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
 
                return r / pcd;
        } else {
-               struct omap_dss_device *dssdev =
-                       dispc_mgr_get_device(channel);
+               enum dss_hdmi_venc_clk_source_select source;
 
-               switch (dssdev->type) {
-               case OMAP_DISPLAY_TYPE_VENC:
+               source = dss_get_hdmi_venc_clk_source();
+
+               switch (source) {
+               case DSS_VENC_TV_CLK:
                        return venc_get_pixel_clock();
-               case OMAP_DISPLAY_TYPE_HDMI:
+               case DSS_HDMI_M_PCLK:
                        return hdmi_get_pixel_clock();
                default:
                        BUG();
+                       return 0;
                }
        }
 }
 
+unsigned long dispc_core_clk_rate(void)
+{
+       int lcd;
+       unsigned long fclk = dispc_fclk_rate();
+
+       if (dss_has_feature(FEAT_CORE_CLK_DIV))
+               lcd = REG_GET(DISPC_DIVISOR, 23, 16);
+       else
+               lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16);
+
+       return fclk / lcd;
+}
+
 void dispc_dump_clocks(struct seq_file *s)
 {
        int lcd, pcd;
@@ -2588,7 +2933,7 @@ void dispc_dump_irqs(struct seq_file *s)
 }
 #endif
 
-void dispc_dump_regs(struct seq_file *s)
+static void dispc_dump_regs(struct seq_file *s)
 {
        int i, j;
        const char *mgr_names[] = {
@@ -3247,27 +3592,6 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
        return 0;
 }
 
-#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
-void dispc_fake_vsync_irq(void)
-{
-       u32 irqstatus = DISPC_IRQ_VSYNC;
-       int i;
-
-       WARN_ON(!in_interrupt());
-
-       for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
-               struct omap_dispc_isr_data *isr_data;
-               isr_data = &dispc.registered_isr[i];
-
-               if (!isr_data->isr)
-                       continue;
-
-               if (isr_data->mask & irqstatus)
-                       isr_data->isr(isr_data->arg, irqstatus);
-       }
-}
-#endif
-
 static void _omap_dispc_initialize_irq(void)
 {
        unsigned long flags;
@@ -3330,7 +3654,7 @@ static void _omap_dispc_initial_config(void)
 }
 
 /* DISPC HW IP initialisation */
-static int omap_dispchw_probe(struct platform_device *pdev)
+static int __init omap_dispchw_probe(struct platform_device *pdev)
 {
        u32 rev;
        int r = 0;
@@ -3399,6 +3723,11 @@ static int omap_dispchw_probe(struct platform_device *pdev)
 
        dispc_runtime_put();
 
+       dss_debugfs_create_file("dispc", dispc_dump_regs);
+
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+       dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
+#endif
        return 0;
 
 err_runtime_get:
@@ -3407,7 +3736,7 @@ err_runtime_get:
        return r;
 }
 
-static int omap_dispchw_remove(struct platform_device *pdev)
+static int __exit omap_dispchw_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
 
@@ -3419,19 +3748,12 @@ static int omap_dispchw_remove(struct platform_device *pdev)
 static int dispc_runtime_suspend(struct device *dev)
 {
        dispc_save_context();
-       dss_runtime_put();
 
        return 0;
 }
 
 static int dispc_runtime_resume(struct device *dev)
 {
-       int r;
-
-       r = dss_runtime_get();
-       if (r < 0)
-               return r;
-
        dispc_restore_context();
 
        return 0;
@@ -3443,8 +3765,7 @@ static const struct dev_pm_ops dispc_pm_ops = {
 };
 
 static struct platform_driver omap_dispchw_driver = {
-       .probe          = omap_dispchw_probe,
-       .remove         = omap_dispchw_remove,
+       .remove         = __exit_p(omap_dispchw_remove),
        .driver         = {
                .name   = "omapdss_dispc",
                .owner  = THIS_MODULE,
@@ -3452,12 +3773,12 @@ static struct platform_driver omap_dispchw_driver = {
        },
 };
 
-int dispc_init_platform_driver(void)
+int __init dispc_init_platform_driver(void)
 {
-       return platform_driver_register(&omap_dispchw_driver);
+       return platform_driver_probe(&omap_dispchw_driver, omap_dispchw_probe);
 }
 
-void dispc_uninit_platform_driver(void)
+void __exit dispc_uninit_platform_driver(void)
 {
-       return platform_driver_unregister(&omap_dispchw_driver);
+       platform_driver_unregister(&omap_dispchw_driver);
 }
index 5836bd1..f278080 100644 (file)
@@ -120,6 +120,7 @@ static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
                return 0x03AC;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -134,6 +135,7 @@ static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel)
                return 0x03B0;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -144,10 +146,12 @@ static inline u16 DISPC_TIMING_H(enum omap_channel channel)
                return 0x0064;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x0400;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -158,10 +162,12 @@ static inline u16 DISPC_TIMING_V(enum omap_channel channel)
                return 0x0068;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x0404;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -172,10 +178,12 @@ static inline u16 DISPC_POL_FREQ(enum omap_channel channel)
                return 0x006C;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x0408;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -186,10 +194,12 @@ static inline u16 DISPC_DIVISORo(enum omap_channel channel)
                return 0x0070;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x040C;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -205,6 +215,7 @@ static inline u16 DISPC_SIZE_MGR(enum omap_channel channel)
                return 0x03CC;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -215,10 +226,12 @@ static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel)
                return 0x01D4;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x03C0;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -229,10 +242,12 @@ static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel)
                return 0x01D8;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x03C4;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -243,10 +258,12 @@ static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel)
                return 0x01DC;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x03C8;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -257,10 +274,12 @@ static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel)
                return 0x0220;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x03BC;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -271,10 +290,12 @@ static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel)
                return 0x0224;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x03B8;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -285,10 +306,12 @@ static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel)
                return 0x0228;
        case OMAP_DSS_CHANNEL_DIGIT:
                BUG();
+               return 0;
        case OMAP_DSS_CHANNEL_LCD2:
                return 0x03B4;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -306,6 +329,7 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
                return 0x0300;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -321,6 +345,7 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
                return 0x0008;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -335,6 +360,7 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
                return 0x000C;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -343,6 +369,7 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x0544;
        case OMAP_DSS_VIDEO2:
@@ -351,6 +378,7 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
                return 0x0310;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -359,6 +387,7 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x0548;
        case OMAP_DSS_VIDEO2:
@@ -367,6 +396,7 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
                return 0x0314;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -381,6 +411,7 @@ static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
                return 0x009C;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -395,6 +426,7 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
                return 0x00A8;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -410,6 +442,7 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
                return 0x0070;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -418,6 +451,7 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x0568;
        case OMAP_DSS_VIDEO2:
@@ -426,6 +460,7 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
                return 0x032C;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -441,6 +476,7 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
                return 0x008C;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -456,6 +492,7 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
                return 0x0088;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -471,6 +508,7 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
                return 0x00A4;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -486,6 +524,7 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
                return 0x0098;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -498,8 +537,10 @@ static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO2:
        case OMAP_DSS_VIDEO3:
                BUG();
+               return 0;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -512,8 +553,10 @@ static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
        case OMAP_DSS_VIDEO2:
        case OMAP_DSS_VIDEO3:
                BUG();
+               return 0;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -522,6 +565,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0024;
@@ -529,6 +573,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
                return 0x0090;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -537,6 +582,7 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x0580;
        case OMAP_DSS_VIDEO2:
@@ -545,6 +591,7 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
                return 0x0424;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -553,6 +600,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0028;
@@ -560,6 +608,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
                return 0x0094;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -569,6 +618,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x002C;
@@ -576,6 +626,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
                return 0x0000;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -584,6 +635,7 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x0584;
        case OMAP_DSS_VIDEO2:
@@ -592,6 +644,7 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
                return 0x0428;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -600,6 +653,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0030;
@@ -607,6 +661,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
                return 0x0004;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -615,6 +670,7 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x0588;
        case OMAP_DSS_VIDEO2:
@@ -623,6 +679,7 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
                return 0x042C;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -632,6 +689,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0034 + i * 0x8;
@@ -639,6 +697,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
                return 0x0010 + i * 0x8;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -648,6 +707,7 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x058C + i * 0x8;
        case OMAP_DSS_VIDEO2:
@@ -656,6 +716,7 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
                return 0x0430 + i * 0x8;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -665,6 +726,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
                return 0x0038 + i * 0x8;
@@ -672,6 +734,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
                return 0x0014 + i * 0x8;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -681,6 +744,7 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x0590 + i * 8;
        case OMAP_DSS_VIDEO2:
@@ -689,6 +753,7 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
                return 0x0434 + i * 0x8;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -698,12 +763,14 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
        case OMAP_DSS_VIDEO2:
        case OMAP_DSS_VIDEO3:
                return 0x0074 + i * 0x4;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -713,6 +780,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x0124 + i * 0x4;
        case OMAP_DSS_VIDEO2:
@@ -721,6 +789,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
                return 0x0050 + i * 0x4;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -730,6 +799,7 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
        switch (plane) {
        case OMAP_DSS_GFX:
                BUG();
+               return 0;
        case OMAP_DSS_VIDEO1:
                return 0x05CC + i * 0x4;
        case OMAP_DSS_VIDEO2:
@@ -738,6 +808,7 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
                return 0x0470 + i * 0x4;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -754,6 +825,7 @@ static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
                return 0x00A0;
        default:
                BUG();
+               return 0;
        }
 }
 #endif
index 4424c19..2490106 100644 (file)
@@ -304,10 +304,18 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
                return 24;
        default:
                BUG();
+               return 0;
        }
 }
 EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
 
+void omapdss_default_get_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings)
+{
+       *timings = dssdev->panel.timings;
+}
+EXPORT_SYMBOL(omapdss_default_get_timings);
+
 /* Checks if replication logic should be used. Only use for active matrix,
  * when overlay is in RGB12U or RGB16 mode, and LCD interface is
  * 18bpp or 24bpp */
@@ -340,6 +348,7 @@ bool dss_use_replication(struct omap_dss_device *dssdev,
                break;
        default:
                BUG();
+               return false;
        }
 
        return bpp > 16;
@@ -352,46 +361,6 @@ void dss_init_device(struct platform_device *pdev,
        int i;
        int r;
 
-       switch (dssdev->type) {
-#ifdef CONFIG_OMAP2_DSS_DPI
-       case OMAP_DISPLAY_TYPE_DPI:
-               r = dpi_init_display(dssdev);
-               break;
-#endif
-#ifdef CONFIG_OMAP2_DSS_RFBI
-       case OMAP_DISPLAY_TYPE_DBI:
-               r = rfbi_init_display(dssdev);
-               break;
-#endif
-#ifdef CONFIG_OMAP2_DSS_VENC
-       case OMAP_DISPLAY_TYPE_VENC:
-               r = venc_init_display(dssdev);
-               break;
-#endif
-#ifdef CONFIG_OMAP2_DSS_SDI
-       case OMAP_DISPLAY_TYPE_SDI:
-               r = sdi_init_display(dssdev);
-               break;
-#endif
-#ifdef CONFIG_OMAP2_DSS_DSI
-       case OMAP_DISPLAY_TYPE_DSI:
-               r = dsi_init_display(dssdev);
-               break;
-#endif
-       case OMAP_DISPLAY_TYPE_HDMI:
-               r = hdmi_init_display(dssdev);
-               break;
-       default:
-               DSSERR("Support for display '%s' not compiled in.\n",
-                               dssdev->name);
-               return;
-       }
-
-       if (r) {
-               DSSERR("failed to init display %s\n", dssdev->name);
-               return;
-       }
-
        /* create device sysfs files */
        i = 0;
        while ((attr = display_sysfs_attrs[i++]) != NULL) {
index faaf305..8c2056c 100644 (file)
@@ -156,7 +156,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
                t->pixel_clock = pck;
        }
 
-       dispc_mgr_set_lcd_timings(dssdev->manager->id, t);
+       dss_mgr_set_timings(dssdev->manager, t);
 
        return 0;
 }
@@ -202,10 +202,6 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
                        goto err_reg_enable;
        }
 
-       r = dss_runtime_get();
-       if (r)
-               goto err_get_dss;
-
        r = dispc_runtime_get();
        if (r)
                goto err_get_dispc;
@@ -244,8 +240,6 @@ err_dsi_pll_init:
 err_get_dsi:
        dispc_runtime_put();
 err_get_dispc:
-       dss_runtime_put();
-err_get_dss:
        if (cpu_is_omap34xx())
                regulator_disable(dpi.vdds_dsi_reg);
 err_reg_enable:
@@ -266,7 +260,6 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
        }
 
        dispc_runtime_put();
-       dss_runtime_put();
 
        if (cpu_is_omap34xx())
                regulator_disable(dpi.vdds_dsi_reg);
@@ -283,21 +276,15 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
        DSSDBG("dpi_set_timings\n");
        dssdev->panel.timings = *timings;
        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
-               r = dss_runtime_get();
-               if (r)
-                       return;
-
                r = dispc_runtime_get();
-               if (r) {
-                       dss_runtime_put();
+               if (r)
                        return;
-               }
 
                dpi_set_mode(dssdev);
-               dispc_mgr_go(dssdev->manager->id);
 
                dispc_runtime_put();
-               dss_runtime_put();
+       } else {
+               dss_mgr_set_timings(dssdev->manager, timings);
        }
 }
 EXPORT_SYMBOL(dpi_set_timings);
@@ -312,7 +299,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
        unsigned long pck;
        struct dispc_clock_info dispc_cinfo;
 
-       if (!dispc_lcd_timings_ok(timings))
+       if (dss_mgr_check_timings(dssdev->manager, timings))
                return -EINVAL;
 
        if (timings->pixel_clock == 0)
@@ -352,7 +339,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
 }
 EXPORT_SYMBOL(dpi_check_timings);
 
-int dpi_init_display(struct omap_dss_device *dssdev)
+static int __init dpi_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("init_display\n");
 
@@ -378,12 +365,58 @@ int dpi_init_display(struct omap_dss_device *dssdev)
        return 0;
 }
 
-int dpi_init(void)
+static void __init dpi_probe_pdata(struct platform_device *pdev)
 {
+       struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+       int i, r;
+
+       for (i = 0; i < pdata->num_devices; ++i) {
+               struct omap_dss_device *dssdev = pdata->devices[i];
+
+               if (dssdev->type != OMAP_DISPLAY_TYPE_DPI)
+                       continue;
+
+               r = dpi_init_display(dssdev);
+               if (r) {
+                       DSSERR("device %s init failed: %d\n", dssdev->name, r);
+                       continue;
+               }
+
+               r = omap_dss_register_device(dssdev, &pdev->dev, i);
+               if (r)
+                       DSSERR("device %s register failed: %d\n",
+                                       dssdev->name, r);
+       }
+}
+
+static int __init omap_dpi_probe(struct platform_device *pdev)
+{
+       dpi_probe_pdata(pdev);
+
+       return 0;
+}
+
+static int __exit omap_dpi_remove(struct platform_device *pdev)
+{
+       omap_dss_unregister_child_devices(&pdev->dev);
+
        return 0;
 }
 
-void dpi_exit(void)
+static struct platform_driver omap_dpi_driver = {
+       .remove         = __exit_p(omap_dpi_remove),
+       .driver         = {
+               .name   = "omapdss_dpi",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int __init dpi_init_platform_driver(void)
 {
+       return platform_driver_probe(&omap_dpi_driver, omap_dpi_probe);
 }
 
+void __exit dpi_uninit_platform_driver(void)
+{
+       platform_driver_unregister(&omap_dpi_driver);
+}
index 210a3c4..ec363d8 100644 (file)
@@ -256,14 +256,13 @@ struct dsi_data {
        struct platform_device *pdev;
        void __iomem    *base;
 
+       int module_id;
+
        int irq;
 
        struct clk *dss_clk;
        struct clk *sys_clk;
 
-       int (*enable_pads)(int dsi_id, unsigned lane_mask);
-       void (*disable_pads)(int dsi_id, unsigned lane_mask);
-
        struct dsi_clock_info current_cinfo;
 
        bool vdds_dsi_enabled;
@@ -361,11 +360,6 @@ struct platform_device *dsi_get_dsidev_from_id(int module)
        return dsi_pdev_map[module];
 }
 
-static inline int dsi_get_dsidev_id(struct platform_device *dsidev)
-{
-       return dsidev->id;
-}
-
 static inline void dsi_write_reg(struct platform_device *dsidev,
                const struct dsi_reg idx, u32 val)
 {
@@ -452,6 +446,7 @@ u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
                return 16;
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -1184,10 +1179,9 @@ static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
 static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
 {
        unsigned long r;
-       int dsi_module = dsi_get_dsidev_id(dsidev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
-       if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) {
+       if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) {
                /* DSI FCLK source is DSS_CLK_FCK */
                r = clk_get_rate(dsi->dss_clk);
        } else {
@@ -1279,10 +1273,9 @@ static int dsi_pll_power(struct platform_device *dsidev,
 }
 
 /* calculate clock rates using dividers in cinfo */
-static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
+static int dsi_calc_clock_rates(struct platform_device *dsidev,
                struct dsi_clock_info *cinfo)
 {
-       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max)
@@ -1297,21 +1290,8 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
        if (cinfo->regm_dsi > dsi->regm_dsi_max)
                return -EINVAL;
 
-       if (cinfo->use_sys_clk) {
-               cinfo->clkin = clk_get_rate(dsi->sys_clk);
-               /* XXX it is unclear if highfreq should be used
-                * with DSS_SYS_CLK source also */
-               cinfo->highfreq = 0;
-       } else {
-               cinfo->clkin = dispc_mgr_pclk_rate(dssdev->manager->id);
-
-               if (cinfo->clkin < 32000000)
-                       cinfo->highfreq = 0;
-               else
-                       cinfo->highfreq = 1;
-       }
-
-       cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
+       cinfo->clkin = clk_get_rate(dsi->sys_clk);
+       cinfo->fint = cinfo->clkin / cinfo->regn;
 
        if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min)
                return -EINVAL;
@@ -1378,27 +1358,21 @@ retry:
 
        memset(&cur, 0, sizeof(cur));
        cur.clkin = dss_sys_clk;
-       cur.use_sys_clk = 1;
-       cur.highfreq = 0;
 
-       /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
-       /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
+       /* 0.75MHz < Fint = clkin / regn < 2.1MHz */
        /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
        for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
-               if (cur.highfreq == 0)
-                       cur.fint = cur.clkin / cur.regn;
-               else
-                       cur.fint = cur.clkin / (2 * cur.regn);
+               cur.fint = cur.clkin / cur.regn;
 
                if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
                        continue;
 
-               /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
+               /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
                for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
                        unsigned long a, b;
 
                        a = 2 * cur.regm * (cur.clkin/1000);
-                       b = cur.regn * (cur.highfreq + 1);
+                       b = cur.regn;
                        cur.clkin4ddr = a / b * 1000;
 
                        if (cur.clkin4ddr > 1800 * 1000 * 1000)
@@ -1486,9 +1460,7 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,
 
        DSSDBGF();
 
-       dsi->current_cinfo.use_sys_clk = cinfo->use_sys_clk;
-       dsi->current_cinfo.highfreq = cinfo->highfreq;
-
+       dsi->current_cinfo.clkin = cinfo->clkin;
        dsi->current_cinfo.fint = cinfo->fint;
        dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
        dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk =
@@ -1503,17 +1475,13 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,
 
        DSSDBG("DSI Fint %ld\n", cinfo->fint);
 
-       DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
-                       cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree",
-                       cinfo->clkin,
-                       cinfo->highfreq);
+       DSSDBG("clkin rate %ld\n", cinfo->clkin);
 
        /* DSIPHY == CLKIN4DDR */
-       DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu / %d = %lu\n",
+       DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu = %lu\n",
                        cinfo->regm,
                        cinfo->regn,
                        cinfo->clkin,
-                       cinfo->highfreq + 1,
                        cinfo->clkin4ddr);
 
        DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
@@ -1568,10 +1536,6 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,
 
        if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
                l = FLD_MOD(l, f, 4, 1);        /* DSI_PLL_FREQSEL */
-       l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1,
-                       11, 11);                /* DSI_PLL_CLKSEL */
-       l = FLD_MOD(l, cinfo->highfreq,
-                       12, 12);                /* DSI_PLL_HIGHFREQ */
        l = FLD_MOD(l, 1, 13, 13);              /* DSI_PLL_REFEN */
        l = FLD_MOD(l, 0, 14, 14);              /* DSIPHY_CLKINEN */
        l = FLD_MOD(l, 1, 20, 20);              /* DSI_HSDIVBYPASS */
@@ -1716,7 +1680,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        struct dsi_clock_info *cinfo = &dsi->current_cinfo;
        enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
-       int dsi_module = dsi_get_dsidev_id(dsidev);
+       int dsi_module = dsi->module_id;
 
        dispc_clk_src = dss_get_dispc_clk_source();
        dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
@@ -1726,8 +1690,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
 
        seq_printf(s,   "- DSI%d PLL -\n", dsi_module + 1);
 
-       seq_printf(s,   "dsi pll source = %s\n",
-                       cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree");
+       seq_printf(s,   "dsi pll clkin\t%lu\n", cinfo->clkin);
 
        seq_printf(s,   "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
 
@@ -1789,7 +1752,6 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        struct dsi_irq_stats stats;
-       int dsi_module = dsi_get_dsidev_id(dsidev);
 
        spin_lock_irqsave(&dsi->irq_stats_lock, flags);
 
@@ -1806,7 +1768,7 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
 #define PIS(x) \
        seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
 
-       seq_printf(s, "-- DSI%d interrupts --\n", dsi_module + 1);
+       seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1);
        PIS(VC0);
        PIS(VC1);
        PIS(VC2);
@@ -1886,22 +1848,6 @@ static void dsi2_dump_irqs(struct seq_file *s)
 
        dsi_dump_dsidev_irqs(dsidev, s);
 }
-
-void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
-               const struct file_operations *debug_fops)
-{
-       struct platform_device *dsidev;
-
-       dsidev = dsi_get_dsidev_from_id(0);
-       if (dsidev)
-               debugfs_create_file("dsi1_irqs", S_IRUGO, debugfs_dir,
-                       &dsi1_dump_irqs, debug_fops);
-
-       dsidev = dsi_get_dsidev_from_id(1);
-       if (dsidev)
-               debugfs_create_file("dsi2_irqs", S_IRUGO, debugfs_dir,
-                       &dsi2_dump_irqs, debug_fops);
-}
 #endif
 
 static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
@@ -2002,21 +1948,6 @@ static void dsi2_dump_regs(struct seq_file *s)
        dsi_dump_dsidev_regs(dsidev, s);
 }
 
-void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
-               const struct file_operations *debug_fops)
-{
-       struct platform_device *dsidev;
-
-       dsidev = dsi_get_dsidev_from_id(0);
-       if (dsidev)
-               debugfs_create_file("dsi1_regs", S_IRUGO, debugfs_dir,
-                       &dsi1_dump_regs, debug_fops);
-
-       dsidev = dsi_get_dsidev_from_id(1);
-       if (dsidev)
-               debugfs_create_file("dsi2_regs", S_IRUGO, debugfs_dir,
-                       &dsi2_dump_regs, debug_fops);
-}
 enum dsi_cio_power_state {
        DSI_COMPLEXIO_POWER_OFF         = 0x0,
        DSI_COMPLEXIO_POWER_ON          = 0x1,
@@ -2073,6 +2004,7 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
                return 1365 * 3;        /* 1365x24 bits */
        default:
                BUG();
+               return 0;
        }
 }
 
@@ -2337,7 +2269,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
 
        DSSDBGF();
 
-       r = dsi->enable_pads(dsidev->id, dsi_get_lane_mask(dssdev));
+       r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
        if (r)
                return r;
 
@@ -2447,7 +2379,7 @@ err_cio_pwr:
                dsi_cio_disable_lane_override(dsidev);
 err_scp_clk_dom:
        dsi_disable_scp_clk(dsidev);
-       dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev));
+       dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
        return r;
 }
 
@@ -2461,7 +2393,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev)
 
        dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
        dsi_disable_scp_clk(dsidev);
-       dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev));
+       dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
 }
 
 static void dsi_config_tx_fifo(struct platform_device *dsidev,
@@ -2485,6 +2417,7 @@ static void dsi_config_tx_fifo(struct platform_device *dsidev,
                if (add + size > 4) {
                        DSSERR("Illegal FIFO configuration\n");
                        BUG();
+                       return;
                }
 
                v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
@@ -2517,6 +2450,7 @@ static void dsi_config_rx_fifo(struct platform_device *dsidev,
                if (add + size > 4) {
                        DSSERR("Illegal FIFO configuration\n");
                        BUG();
+                       return;
                }
 
                v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
@@ -2658,6 +2592,7 @@ static int dsi_sync_vc(struct platform_device *dsidev, int channel)
                return dsi_sync_vc_l4(dsidev, channel);
        default:
                BUG();
+               return -EINVAL;
        }
 }
 
@@ -3226,6 +3161,7 @@ static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev,
                data = reqdata[0] | (reqdata[1] << 8);
        } else {
                BUG();
+               return -EINVAL;
        }
 
        r = dsi_vc_send_short(dsidev, channel, data_type, data, 0);
@@ -3340,7 +3276,6 @@ static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel,
                goto err;
        }
 
-       BUG();
 err:
        DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel,
                type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS");
@@ -3735,6 +3670,186 @@ static void dsi_config_blanking_modes(struct omap_dss_device *dssdev)
        dsi_write_reg(dsidev, DSI_CTRL, r);
 }
 
+/*
+ * According to section 'HS Command Mode Interleaving' in OMAP TRM, Scenario 3
+ * results in maximum transition time for data and clock lanes to enter and
+ * exit HS mode. Hence, this is the scenario where the least amount of command
+ * mode data can be interleaved. We program the minimum amount of TXBYTECLKHS
+ * clock cycles that can be used to interleave command mode data in HS so that
+ * all scenarios are satisfied.
+ */
+static int dsi_compute_interleave_hs(int blank, bool ddr_alwon, int enter_hs,
+               int exit_hs, int exiths_clk, int ddr_pre, int ddr_post)
+{
+       int transition;
+
+       /*
+        * If DDR_CLK_ALWAYS_ON is set, we need to consider HS mode transition
+        * time of data lanes only, if it isn't set, we need to consider HS
+        * transition time of both data and clock lanes. HS transition time
+        * of Scenario 3 is considered.
+        */
+       if (ddr_alwon) {
+               transition = enter_hs + exit_hs + max(enter_hs, 2) + 1;
+       } else {
+               int trans1, trans2;
+               trans1 = ddr_pre + enter_hs + exit_hs + max(enter_hs, 2) + 1;
+               trans2 = ddr_pre + enter_hs + exiths_clk + ddr_post + ddr_pre +
+                               enter_hs + 1;
+               transition = max(trans1, trans2);
+       }
+
+       return blank > transition ? blank - transition : 0;
+}
+
+/*
+ * According to section 'LP Command Mode Interleaving' in OMAP TRM, Scenario 1
+ * results in maximum transition time for data lanes to enter and exit LP mode.
+ * Hence, this is the scenario where the least amount of command mode data can
+ * be interleaved. We program the minimum amount of bytes that can be
+ * interleaved in LP so that all scenarios are satisfied.
+ */
+static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
+               int lp_clk_div, int tdsi_fclk)
+{
+       int trans_lp;   /* time required for a LP transition, in TXBYTECLKHS */
+       int tlp_avail;  /* time left for interleaving commands, in CLKIN4DDR */
+       int ttxclkesc;  /* period of LP transmit escape clock, in CLKIN4DDR */
+       int thsbyte_clk = 16;   /* Period of TXBYTECLKHS clock, in CLKIN4DDR */
+       int lp_inter;   /* cmd mode data that can be interleaved, in bytes */
+
+       /* maximum LP transition time according to Scenario 1 */
+       trans_lp = exit_hs + max(enter_hs, 2) + 1;
+
+       /* CLKIN4DDR = 16 * TXBYTECLKHS */
+       tlp_avail = thsbyte_clk * (blank - trans_lp);
+
+       ttxclkesc = tdsi_fclk / lp_clk_div;
+
+       lp_inter = ((tlp_avail - 8 * thsbyte_clk - 5 * tdsi_fclk) / ttxclkesc -
+                       26) / 16;
+
+       return max(lp_inter, 0);
+}
+
+static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int blanking_mode;
+       int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode;
+       int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div;
+       int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
+       int tclk_trail, ths_exit, exiths_clk;
+       bool ddr_alwon;
+       struct omap_video_timings *timings = &dssdev->panel.timings;
+       int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+       int ndl = dsi->num_lanes_used - 1;
+       int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1;
+       int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
+       int hfp_interleave_hs = 0, hfp_interleave_lp = 0;
+       int hbp_interleave_hs = 0, hbp_interleave_lp = 0;
+       int bl_interleave_hs = 0, bl_interleave_lp = 0;
+       u32 r;
+
+       r = dsi_read_reg(dsidev, DSI_CTRL);
+       blanking_mode = FLD_GET(r, 20, 20);
+       hfp_blanking_mode = FLD_GET(r, 21, 21);
+       hbp_blanking_mode = FLD_GET(r, 22, 22);
+       hsa_blanking_mode = FLD_GET(r, 23, 23);
+
+       r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
+       hbp = FLD_GET(r, 11, 0);
+       hfp = FLD_GET(r, 23, 12);
+       hsa = FLD_GET(r, 31, 24);
+
+       r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
+       ddr_clk_post = FLD_GET(r, 7, 0);
+       ddr_clk_pre = FLD_GET(r, 15, 8);
+
+       r = dsi_read_reg(dsidev, DSI_VM_TIMING7);
+       exit_hs_mode_lat = FLD_GET(r, 15, 0);
+       enter_hs_mode_lat = FLD_GET(r, 31, 16);
+
+       r = dsi_read_reg(dsidev, DSI_CLK_CTRL);
+       lp_clk_div = FLD_GET(r, 12, 0);
+       ddr_alwon = FLD_GET(r, 13, 13);
+
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
+       ths_exit = FLD_GET(r, 7, 0);
+
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
+       tclk_trail = FLD_GET(r, 15, 8);
+
+       exiths_clk = ths_exit + tclk_trail;
+
+       width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
+       bllp = hbp + hfp + hsa + DIV_ROUND_UP(width_bytes + 6, ndl);
+
+       if (!hsa_blanking_mode) {
+               hsa_interleave_hs = dsi_compute_interleave_hs(hsa, ddr_alwon,
+                                       enter_hs_mode_lat, exit_hs_mode_lat,
+                                       exiths_clk, ddr_clk_pre, ddr_clk_post);
+               hsa_interleave_lp = dsi_compute_interleave_lp(hsa,
+                                       enter_hs_mode_lat, exit_hs_mode_lat,
+                                       lp_clk_div, dsi_fclk_hsdiv);
+       }
+
+       if (!hfp_blanking_mode) {
+               hfp_interleave_hs = dsi_compute_interleave_hs(hfp, ddr_alwon,
+                                       enter_hs_mode_lat, exit_hs_mode_lat,
+                                       exiths_clk, ddr_clk_pre, ddr_clk_post);
+               hfp_interleave_lp = dsi_compute_interleave_lp(hfp,
+                                       enter_hs_mode_lat, exit_hs_mode_lat,
+                                       lp_clk_div, dsi_fclk_hsdiv);
+       }
+
+       if (!hbp_blanking_mode) {
+               hbp_interleave_hs = dsi_compute_interleave_hs(hbp, ddr_alwon,
+                                       enter_hs_mode_lat, exit_hs_mode_lat,
+                                       exiths_clk, ddr_clk_pre, ddr_clk_post);
+
+               hbp_interleave_lp = dsi_compute_interleave_lp(hbp,
+                                       enter_hs_mode_lat, exit_hs_mode_lat,
+                                       lp_clk_div, dsi_fclk_hsdiv);
+       }
+
+       if (!blanking_mode) {
+               bl_interleave_hs = dsi_compute_interleave_hs(bllp, ddr_alwon,
+                                       enter_hs_mode_lat, exit_hs_mode_lat,
+                                       exiths_clk, ddr_clk_pre, ddr_clk_post);
+
+               bl_interleave_lp = dsi_compute_interleave_lp(bllp,
+                                       enter_hs_mode_lat, exit_hs_mode_lat,
+                                       lp_clk_div, dsi_fclk_hsdiv);
+       }
+
+       DSSDBG("DSI HS interleaving(TXBYTECLKHS) HSA %d, HFP %d, HBP %d, BLLP %d\n",
+               hsa_interleave_hs, hfp_interleave_hs, hbp_interleave_hs,
+               bl_interleave_hs);
+
+       DSSDBG("DSI LP interleaving(bytes) HSA %d, HFP %d, HBP %d, BLLP %d\n",
+               hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp,
+               bl_interleave_lp);
+
+       r = dsi_read_reg(dsidev, DSI_VM_TIMING4);
+       r = FLD_MOD(r, hsa_interleave_hs, 23, 16);
+       r = FLD_MOD(r, hfp_interleave_hs, 15, 8);
+       r = FLD_MOD(r, hbp_interleave_hs, 7, 0);
+       dsi_write_reg(dsidev, DSI_VM_TIMING4, r);
+
+       r = dsi_read_reg(dsidev, DSI_VM_TIMING5);
+       r = FLD_MOD(r, hsa_interleave_lp, 23, 16);
+       r = FLD_MOD(r, hfp_interleave_lp, 15, 8);
+       r = FLD_MOD(r, hbp_interleave_lp, 7, 0);
+       dsi_write_reg(dsidev, DSI_VM_TIMING5, r);
+
+       r = dsi_read_reg(dsidev, DSI_VM_TIMING6);
+       r = FLD_MOD(r, bl_interleave_hs, 31, 15);
+       r = FLD_MOD(r, bl_interleave_lp, 16, 0);
+       dsi_write_reg(dsidev, DSI_VM_TIMING6, r);
+}
+
 static int dsi_proto_config(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -3769,6 +3884,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
                break;
        default:
                BUG();
+               return -EINVAL;
        }
 
        r = dsi_read_reg(dsidev, DSI_CTRL);
@@ -3793,6 +3909,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
        if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
                dsi_config_vp_sync_events(dssdev);
                dsi_config_blanking_modes(dssdev);
+               dsi_config_cmd_mode_interleaving(dssdev);
        }
 
        dsi_vc_initial_config(dsidev, 0);
@@ -4008,6 +4125,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
                        break;
                default:
                        BUG();
+                       return -EINVAL;
                };
 
                dsi_if_enable(dsidev, false);
@@ -4192,10 +4310,6 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
        __cancel_delayed_work(&dsi->framedone_timeout_work);
 
        dsi_handle_framedone(dsidev, 0);
-
-#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
-       dispc_fake_vsync_irq();
-#endif
 }
 
 int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
@@ -4259,13 +4373,12 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
                dispc_mgr_enable_stallmode(dssdev->manager->id, true);
                dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 1);
 
-               dispc_mgr_set_lcd_timings(dssdev->manager->id, &timings);
+               dss_mgr_set_timings(dssdev->manager, &timings);
        } else {
                dispc_mgr_enable_stallmode(dssdev->manager->id, false);
                dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 0);
 
-               dispc_mgr_set_lcd_timings(dssdev->manager->id,
-                       &dssdev->panel.timings);
+               dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
        }
 
                dispc_mgr_set_lcd_display_type(dssdev->manager->id,
@@ -4294,13 +4407,11 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
        struct dsi_clock_info cinfo;
        int r;
 
-       /* we always use DSS_CLK_SYSCK as input clock */
-       cinfo.use_sys_clk = true;
        cinfo.regn  = dssdev->clocks.dsi.regn;
        cinfo.regm  = dssdev->clocks.dsi.regm;
        cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc;
        cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi;
-       r = dsi_calc_clock_rates(dssdev, &cinfo);
+       r = dsi_calc_clock_rates(dsidev, &cinfo);
        if (r) {
                DSSERR("Failed to calc dsi clocks\n");
                return r;
@@ -4345,7 +4456,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
 static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
-       int dsi_module = dsi_get_dsidev_id(dsidev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r;
 
        r = dsi_pll_init(dsidev, true, true);
@@ -4357,7 +4468,7 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
                goto err1;
 
        dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
-       dss_select_dsi_clk_source(dsi_module, dssdev->clocks.dsi.dsi_fclk_src);
+       dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
        dss_select_lcd_clk_source(dssdev->manager->id,
                        dssdev->clocks.dispc.channel.lcd_clk_src);
 
@@ -4396,7 +4507,7 @@ err3:
        dsi_cio_uninit(dssdev);
 err2:
        dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
-       dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
+       dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
        dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
 
 err1:
@@ -4410,7 +4521,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-       int dsi_module = dsi_get_dsidev_id(dsidev);
 
        if (enter_ulps && !dsi->ulps_enabled)
                dsi_enter_ulps(dsidev);
@@ -4423,7 +4533,7 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
        dsi_vc_enable(dsidev, 3, 0);
 
        dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
-       dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
+       dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
        dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
        dsi_cio_uninit(dssdev);
        dsi_pll_uninit(dsidev, disconnect_lanes);
@@ -4527,7 +4637,7 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 }
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
 
-int dsi_init_display(struct omap_dss_device *dssdev)
+static int __init dsi_init_display(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
@@ -4680,13 +4790,39 @@ static void dsi_put_clocks(struct platform_device *dsidev)
                clk_put(dsi->sys_clk);
 }
 
+static void __init dsi_probe_pdata(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct omap_dss_board_info *pdata = dsidev->dev.platform_data;
+       int i, r;
+
+       for (i = 0; i < pdata->num_devices; ++i) {
+               struct omap_dss_device *dssdev = pdata->devices[i];
+
+               if (dssdev->type != OMAP_DISPLAY_TYPE_DSI)
+                       continue;
+
+               if (dssdev->phy.dsi.module != dsi->module_id)
+                       continue;
+
+               r = dsi_init_display(dssdev);
+               if (r) {
+                       DSSERR("device %s init failed: %d\n", dssdev->name, r);
+                       continue;
+               }
+
+               r = omap_dss_register_device(dssdev, &dsidev->dev, i);
+               if (r)
+                       DSSERR("device %s register failed: %d\n",
+                                       dssdev->name, r);
+       }
+}
+
 /* DSI1 HW IP initialisation */
-static int omap_dsihw_probe(struct platform_device *dsidev)
+static int __init omap_dsihw_probe(struct platform_device *dsidev)
 {
-       struct omap_display_platform_data *dss_plat_data;
-       struct omap_dss_board_info *board_info;
        u32 rev;
-       int r, i, dsi_module = dsi_get_dsidev_id(dsidev);
+       int r, i;
        struct resource *dsi_mem;
        struct dsi_data *dsi;
 
@@ -4694,15 +4830,11 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
        if (!dsi)
                return -ENOMEM;
 
+       dsi->module_id = dsidev->id;
        dsi->pdev = dsidev;
-       dsi_pdev_map[dsi_module] = dsidev;
+       dsi_pdev_map[dsi->module_id] = dsidev;
        dev_set_drvdata(&dsidev->dev, dsi);
 
-       dss_plat_data = dsidev->dev.platform_data;
-       board_info = dss_plat_data->board_data;
-       dsi->enable_pads = board_info->dsi_enable_pads;
-       dsi->disable_pads = board_info->dsi_disable_pads;
-
        spin_lock_init(&dsi->irq_lock);
        spin_lock_init(&dsi->errors_lock);
        dsi->errors = 0;
@@ -4780,8 +4912,21 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
        else
                dsi->num_lanes_supported = 3;
 
+       dsi_probe_pdata(dsidev);
+
        dsi_runtime_put(dsidev);
 
+       if (dsi->module_id == 0)
+               dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs);
+       else if (dsi->module_id == 1)
+               dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs);
+
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+       if (dsi->module_id == 0)
+               dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs);
+       else if (dsi->module_id == 1)
+               dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs);
+#endif
        return 0;
 
 err_runtime_get:
@@ -4790,12 +4935,14 @@ err_runtime_get:
        return r;
 }
 
-static int omap_dsihw_remove(struct platform_device *dsidev)
+static int __exit omap_dsihw_remove(struct platform_device *dsidev)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        WARN_ON(dsi->scp_clk_refcount > 0);
 
+       omap_dss_unregister_child_devices(&dsidev->dev);
+
        pm_runtime_disable(&dsidev->dev);
 
        dsi_put_clocks(dsidev);
@@ -4816,7 +4963,6 @@ static int omap_dsihw_remove(struct platform_device *dsidev)
 static int dsi_runtime_suspend(struct device *dev)
 {
        dispc_runtime_put();
-       dss_runtime_put();
 
        return 0;
 }
@@ -4825,20 +4971,11 @@ static int dsi_runtime_resume(struct device *dev)
 {
        int r;
 
-       r = dss_runtime_get();
-       if (r)
-               goto err_get_dss;
-
        r = dispc_runtime_get();
        if (r)
-               goto err_get_dispc;
+               return r;
 
        return 0;
-
-err_get_dispc:
-       dss_runtime_put();
-err_get_dss:
-       return r;
 }
 
 static const struct dev_pm_ops dsi_pm_ops = {
@@ -4847,8 +4984,7 @@ static const struct dev_pm_ops dsi_pm_ops = {
 };
 
 static struct platform_driver omap_dsihw_driver = {
-       .probe          = omap_dsihw_probe,
-       .remove         = omap_dsihw_remove,
+       .remove         = __exit_p(omap_dsihw_remove),
        .driver         = {
                .name   = "omapdss_dsi",
                .owner  = THIS_MODULE,
@@ -4856,12 +4992,12 @@ static struct platform_driver omap_dsihw_driver = {
        },
 };
 
-int dsi_init_platform_driver(void)
+int __init dsi_init_platform_driver(void)
 {
-       return platform_driver_register(&omap_dsihw_driver);
+       return platform_driver_probe(&omap_dsihw_driver, omap_dsihw_probe);
 }
 
-void dsi_uninit_platform_driver(void)
+void __exit dsi_uninit_platform_driver(void)
 {
-       return platform_driver_unregister(&omap_dsihw_driver);
+       platform_driver_unregister(&omap_dsihw_driver);
 }
index bd2d5e1..6ea1ff1 100644 (file)
@@ -62,6 +62,9 @@ struct dss_reg {
 #define REG_FLD_MOD(idx, val, start, end) \
        dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
 
+static int dss_runtime_get(void);
+static void dss_runtime_put(void);
+
 static struct {
        struct platform_device *pdev;
        void __iomem    *base;
@@ -277,7 +280,7 @@ void dss_dump_clocks(struct seq_file *s)
        dss_runtime_put();
 }
 
-void dss_dump_regs(struct seq_file *s)
+static void dss_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
 
@@ -322,6 +325,7 @@ void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
                break;
        default:
                BUG();
+               return;
        }
 
        dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
@@ -335,7 +339,7 @@ void dss_select_dsi_clk_source(int dsi_module,
                enum omap_dss_clk_source clk_src)
 {
        struct platform_device *dsidev;
-       int b;
+       int b, pos;
 
        switch (clk_src) {
        case OMAP_DSS_CLK_SRC_FCK:
@@ -355,9 +359,11 @@ void dss_select_dsi_clk_source(int dsi_module,
                break;
        default:
                BUG();
+               return;
        }
 
-       REG_FLD_MOD(DSS_CONTROL, b, 1, 1);      /* DSI_CLK_SWITCH */
+       pos = dsi_module == 0 ? 1 : 10;
+       REG_FLD_MOD(DSS_CONTROL, b, pos, pos);  /* DSIx_CLK_SWITCH */
 
        dss.dsi_clk_source[dsi_module] = clk_src;
 }
@@ -389,6 +395,7 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
                break;
        default:
                BUG();
+               return;
        }
 
        pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12;
@@ -706,7 +713,7 @@ static void dss_put_clocks(void)
        clk_put(dss.dss_clk);
 }
 
-int dss_runtime_get(void)
+static int dss_runtime_get(void)
 {
        int r;
 
@@ -717,7 +724,7 @@ int dss_runtime_get(void)
        return r < 0 ? r : 0;
 }
 
-void dss_runtime_put(void)
+static void dss_runtime_put(void)
 {
        int r;
 
@@ -740,7 +747,7 @@ void dss_debug_dump_clocks(struct seq_file *s)
 #endif
 
 /* DSS HW IP initialisation */
-static int omap_dsshw_probe(struct platform_device *pdev)
+static int __init omap_dsshw_probe(struct platform_device *pdev)
 {
        struct resource *dss_mem;
        u32 rev;
@@ -785,40 +792,24 @@ static int omap_dsshw_probe(struct platform_device *pdev)
        dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
        dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
 
-       r = dpi_init();
-       if (r) {
-               DSSERR("Failed to initialize DPI\n");
-               goto err_dpi;
-       }
-
-       r = sdi_init();
-       if (r) {
-               DSSERR("Failed to initialize SDI\n");
-               goto err_sdi;
-       }
-
        rev = dss_read_reg(DSS_REVISION);
        printk(KERN_INFO "OMAP DSS rev %d.%d\n",
                        FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
        dss_runtime_put();
 
+       dss_debugfs_create_file("dss", dss_dump_regs);
+
        return 0;
-err_sdi:
-       dpi_exit();
-err_dpi:
-       dss_runtime_put();
+
 err_runtime_get:
        pm_runtime_disable(&pdev->dev);
        dss_put_clocks();
        return r;
 }
 
-static int omap_dsshw_remove(struct platform_device *pdev)
+static int __exit omap_dsshw_remove(struct platform_device *pdev)
 {
-       dpi_exit();
-       sdi_exit();
-
        pm_runtime_disable(&pdev->dev);
 
        dss_put_clocks();
@@ -829,11 +820,24 @@ static int omap_dsshw_remove(struct platform_device *pdev)
 static int dss_runtime_suspend(struct device *dev)
 {
        dss_save_context();
+       dss_set_min_bus_tput(dev, 0);
        return 0;
 }
 
 static int dss_runtime_resume(struct device *dev)
 {
+       int r;
+       /*
+        * Set an arbitrarily high tput request to ensure OPP100.
+        * What we should really do is to make a request to stay in OPP100,
+        * without any tput requirements, but that is not currently possible
+        * via the PM layer.
+        */
+
+       r = dss_set_min_bus_tput(dev, 1000000000);
+       if (r)
+               return r;
+
        dss_restore_context();
        return 0;
 }
@@ -844,8 +848,7 @@ static const struct dev_pm_ops dss_pm_ops = {
 };
 
 static struct platform_driver omap_dsshw_driver = {
-       .probe          = omap_dsshw_probe,
-       .remove         = omap_dsshw_remove,
+       .remove         = __exit_p(omap_dsshw_remove),
        .driver         = {
                .name   = "omapdss_dss",
                .owner  = THIS_MODULE,
@@ -853,12 +856,12 @@ static struct platform_driver omap_dsshw_driver = {
        },
 };
 
-int dss_init_platform_driver(void)
+int __init dss_init_platform_driver(void)
 {
-       return platform_driver_register(&omap_dsshw_driver);
+       return platform_driver_probe(&omap_dsshw_driver, omap_dsshw_probe);
 }
 
 void dss_uninit_platform_driver(void)
 {
-       return platform_driver_unregister(&omap_dsshw_driver);
+       platform_driver_unregister(&omap_dsshw_driver);
 }
index d4b3dff..dd1092c 100644 (file)
@@ -150,9 +150,6 @@ struct dsi_clock_info {
        u16 regm_dsi;   /* OMAP3: REGM4
                         * OMAP4: REGM5 */
        u16 lp_clk_div;
-
-       u8 highfreq;
-       bool use_sys_clk;
 };
 
 struct seq_file;
@@ -162,6 +159,16 @@ struct platform_device;
 struct bus_type *dss_get_bus(void);
 struct regulator *dss_get_vdds_dsi(void);
 struct regulator *dss_get_vdds_sdi(void);
+int dss_get_ctx_loss_count(struct device *dev);
+int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask);
+void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
+int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
+int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
+
+int omap_dss_register_device(struct omap_dss_device *dssdev,
+               struct device *parent, int disp_num);
+void omap_dss_unregister_device(struct omap_dss_device *dssdev);
+void omap_dss_unregister_child_devices(struct device *parent);
 
 /* apply */
 void dss_apply_init(void);
@@ -179,6 +186,9 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
 int dss_mgr_set_device(struct omap_overlay_manager *mgr,
                struct omap_dss_device *dssdev);
 int dss_mgr_unset_device(struct omap_overlay_manager *mgr);
+void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
+               struct omap_video_timings *timings);
+const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr);
 
 bool dss_ovl_is_enabled(struct omap_overlay *ovl);
 int dss_ovl_enable(struct omap_overlay *ovl);
@@ -208,9 +218,11 @@ int dss_init_overlay_managers(struct platform_device *pdev);
 void dss_uninit_overlay_managers(struct platform_device *pdev);
 int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
                const struct omap_overlay_manager_info *info);
+int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
+               const struct omap_video_timings *timings);
 int dss_mgr_check(struct omap_overlay_manager *mgr,
-               struct omap_dss_device *dssdev,
                struct omap_overlay_manager_info *info,
+               const struct omap_video_timings *mgr_timings,
                struct omap_overlay_info **overlay_infos);
 
 /* overlay */
@@ -220,22 +232,18 @@ void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
 void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
 int dss_ovl_simple_check(struct omap_overlay *ovl,
                const struct omap_overlay_info *info);
-int dss_ovl_check(struct omap_overlay *ovl,
-               struct omap_overlay_info *info, struct omap_dss_device *dssdev);
+int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
+               const struct omap_video_timings *mgr_timings);
 
 /* DSS */
-int dss_init_platform_driver(void);
+int dss_init_platform_driver(void) __init;
 void dss_uninit_platform_driver(void);
 
-int dss_runtime_get(void);
-void dss_runtime_put(void);
-
 void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
 enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
 const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
 void dss_dump_clocks(struct seq_file *s);
 
-void dss_dump_regs(struct seq_file *s);
 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
 void dss_debug_dump_clocks(struct seq_file *s);
 #endif
@@ -265,19 +273,8 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
                struct dispc_clock_info *dispc_cinfo);
 
 /* SDI */
-#ifdef CONFIG_OMAP2_DSS_SDI
-int sdi_init(void);
-void sdi_exit(void);
-int sdi_init_display(struct omap_dss_device *display);
-#else
-static inline int sdi_init(void)
-{
-       return 0;
-}
-static inline void sdi_exit(void)
-{
-}
-#endif
+int sdi_init_platform_driver(void) __init;
+void sdi_uninit_platform_driver(void) __exit;
 
 /* DSI */
 #ifdef CONFIG_OMAP2_DSS_DSI
@@ -285,19 +282,14 @@ static inline void sdi_exit(void)
 struct dentry;
 struct file_operations;
 
-int dsi_init_platform_driver(void);
-void dsi_uninit_platform_driver(void);
+int dsi_init_platform_driver(void) __init;
+void dsi_uninit_platform_driver(void) __exit;
 
 int dsi_runtime_get(struct platform_device *dsidev);
 void dsi_runtime_put(struct platform_device *dsidev);
 
 void dsi_dump_clocks(struct seq_file *s);
-void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
-               const struct file_operations *debug_fops);
-void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
-               const struct file_operations *debug_fops);
 
-int dsi_init_display(struct omap_dss_device *display);
 void dsi_irq_handler(void);
 u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
 
@@ -314,13 +306,6 @@ void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
 void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
 struct platform_device *dsi_get_dsidev_from_id(int module);
 #else
-static inline int dsi_init_platform_driver(void)
-{
-       return 0;
-}
-static inline void dsi_uninit_platform_driver(void)
-{
-}
 static inline int dsi_runtime_get(struct platform_device *dsidev)
 {
        return 0;
@@ -377,28 +362,14 @@ static inline struct platform_device *dsi_get_dsidev_from_id(int module)
 #endif
 
 /* DPI */
-#ifdef CONFIG_OMAP2_DSS_DPI
-int dpi_init(void);
-void dpi_exit(void);
-int dpi_init_display(struct omap_dss_device *dssdev);
-#else
-static inline int dpi_init(void)
-{
-       return 0;
-}
-static inline void dpi_exit(void)
-{
-}
-#endif
+int dpi_init_platform_driver(void) __init;
+void dpi_uninit_platform_driver(void) __exit;
 
 /* DISPC */
-int dispc_init_platform_driver(void);
-void dispc_uninit_platform_driver(void);
+int dispc_init_platform_driver(void) __init;
+void dispc_uninit_platform_driver(void) __exit;
 void dispc_dump_clocks(struct seq_file *s);
-void dispc_dump_irqs(struct seq_file *s);
-void dispc_dump_regs(struct seq_file *s);
 void dispc_irq_handler(void);
-void dispc_fake_vsync_irq(void);
 
 int dispc_runtime_get(void);
 void dispc_runtime_put(void);
@@ -409,12 +380,12 @@ void dispc_disable_sidle(void);
 void dispc_lcd_enable_signal_polarity(bool act_high);
 void dispc_lcd_enable_signal(bool enable);
 void dispc_pck_free_enable(bool enable);
-void dispc_set_digit_size(u16 width, u16 height);
 void dispc_enable_fifomerge(bool enable);
 void dispc_enable_gamma_table(bool enable);
 void dispc_set_loadmode(enum omap_dss_load_mode mode);
 
-bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
+bool dispc_mgr_timings_ok(enum omap_channel channel,
+               const struct omap_video_timings *timings);
 unsigned long dispc_fclk_rate(void);
 void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
                struct dispc_clock_info *cinfo);
@@ -424,15 +395,16 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
 
 void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
 void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
-               u32 *fifo_low, u32 *fifo_high, bool use_fifomerge);
+               u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
+               bool manual_update);
 int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
-               bool ilace, bool replication);
+               bool ilace, bool replication,
+               const struct omap_video_timings *mgr_timings);
 int dispc_ovl_enable(enum omap_plane plane, bool enable);
 void dispc_ovl_set_channel_out(enum omap_plane plane,
                enum omap_channel channel);
 
 void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable);
-void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
 u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
 u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
 bool dispc_mgr_go_busy(enum omap_channel channel);
@@ -445,12 +417,13 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable);
 void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines);
 void dispc_mgr_set_lcd_display_type(enum omap_channel channel,
                enum omap_lcd_display_type type);
-void dispc_mgr_set_lcd_timings(enum omap_channel channel,
+void dispc_mgr_set_timings(enum omap_channel channel,
                struct omap_video_timings *timings);
 void dispc_mgr_set_pol_freq(enum omap_channel channel,
                enum omap_panel_config config, u8 acbi, u8 acb);
 unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
 unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
+unsigned long dispc_core_clk_rate(void);
 int dispc_mgr_set_clock_div(enum omap_channel channel,
                struct dispc_clock_info *cinfo);
 int dispc_mgr_get_clock_div(enum omap_channel channel,
@@ -460,19 +433,10 @@ void dispc_mgr_setup(enum omap_channel channel,
 
 /* VENC */
 #ifdef CONFIG_OMAP2_DSS_VENC
-int venc_init_platform_driver(void);
-void venc_uninit_platform_driver(void);
-void venc_dump_regs(struct seq_file *s);
-int venc_init_display(struct omap_dss_device *display);
+int venc_init_platform_driver(void) __init;
+void venc_uninit_platform_driver(void) __exit;
 unsigned long venc_get_pixel_clock(void);
 #else
-static inline int venc_init_platform_driver(void)
-{
-       return 0;
-}
-static inline void venc_uninit_platform_driver(void)
-{
-}
 static inline unsigned long venc_get_pixel_clock(void)
 {
        WARN("%s: VENC not compiled in, returning pclk as 0\n", __func__);
@@ -482,23 +446,10 @@ static inline unsigned long venc_get_pixel_clock(void)
 
 /* HDMI */
 #ifdef CONFIG_OMAP4_DSS_HDMI
-int hdmi_init_platform_driver(void);
-void hdmi_uninit_platform_driver(void);
-int hdmi_init_display(struct omap_dss_device *dssdev);
+int hdmi_init_platform_driver(void) __init;
+void hdmi_uninit_platform_driver(void) __exit;
 unsigned long hdmi_get_pixel_clock(void);
-void hdmi_dump_regs(struct seq_file *s);
 #else
-static inline int hdmi_init_display(struct omap_dss_device *dssdev)
-{
-       return 0;
-}
-static inline int hdmi_init_platform_driver(void)
-{
-       return 0;
-}
-static inline void hdmi_uninit_platform_driver(void)
-{
-}
 static inline unsigned long hdmi_get_pixel_clock(void)
 {
        WARN("%s: HDMI not compiled in, returning pclk as 0\n", __func__);
@@ -514,22 +465,18 @@ int omapdss_hdmi_read_edid(u8 *buf, int len);
 bool omapdss_hdmi_detect(void);
 int hdmi_panel_init(void);
 void hdmi_panel_exit(void);
+#ifdef CONFIG_OMAP4_DSS_HDMI_AUDIO
+int hdmi_audio_enable(void);
+void hdmi_audio_disable(void);
+int hdmi_audio_start(void);
+void hdmi_audio_stop(void);
+bool hdmi_mode_has_audio(void);
+int hdmi_audio_config(struct omap_dss_audio *audio);
+#endif
 
 /* RFBI */
-#ifdef CONFIG_OMAP2_DSS_RFBI
-int rfbi_init_platform_driver(void);
-void rfbi_uninit_platform_driver(void);
-void rfbi_dump_regs(struct seq_file *s);
-int rfbi_init_display(struct omap_dss_device *display);
-#else
-static inline int rfbi_init_platform_driver(void)
-{
-       return 0;
-}
-static inline void rfbi_uninit_platform_driver(void)
-{
-}
-#endif
+int rfbi_init_platform_driver(void) __init;
+void rfbi_uninit_platform_driver(void) __exit;
 
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
index ce14aa6..9387097 100644 (file)
@@ -52,6 +52,8 @@ struct omap_dss_features {
        const char * const *clksrc_names;
        const struct dss_param_range *dss_params;
 
+       const enum omap_dss_rotation_type supported_rotation_types;
+
        const u32 buffer_size_unit;
        const u32 burst_size_unit;
 };
@@ -311,6 +313,8 @@ static const struct dss_param_range omap2_dss_param_range[] = {
         * scaler cannot scale a image with width more than 768.
         */
        [FEAT_PARAM_LINEWIDTH]                  = { 1, 768 },
+       [FEAT_PARAM_MGR_WIDTH]                  = { 1, 2048 },
+       [FEAT_PARAM_MGR_HEIGHT]                 = { 1, 2048 },
 };
 
 static const struct dss_param_range omap3_dss_param_range[] = {
@@ -324,6 +328,8 @@ static const struct dss_param_range omap3_dss_param_range[] = {
        [FEAT_PARAM_DSIPLL_LPDIV]               = { 1, (1 << 13) - 1},
        [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
        [FEAT_PARAM_LINEWIDTH]                  = { 1, 1024 },
+       [FEAT_PARAM_MGR_WIDTH]                  = { 1, 2048 },
+       [FEAT_PARAM_MGR_HEIGHT]                 = { 1, 2048 },
 };
 
 static const struct dss_param_range omap4_dss_param_range[] = {
@@ -337,6 +343,8 @@ static const struct dss_param_range omap4_dss_param_range[] = {
        [FEAT_PARAM_DSIPLL_LPDIV]               = { 0, (1 << 13) - 1 },
        [FEAT_PARAM_DOWNSCALE]                  = { 1, 4 },
        [FEAT_PARAM_LINEWIDTH]                  = { 1, 2048 },
+       [FEAT_PARAM_MGR_WIDTH]                  = { 1, 2048 },
+       [FEAT_PARAM_MGR_HEIGHT]                 = { 1, 2048 },
 };
 
 static const enum dss_feat_id omap2_dss_feat_list[] = {
@@ -399,6 +407,7 @@ static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = {
        FEAT_FIR_COEF_V,
        FEAT_ALPHA_FREE_ZORDER,
        FEAT_FIFO_MERGE,
+       FEAT_BURST_2D,
 };
 
 static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = {
@@ -416,6 +425,7 @@ static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = {
        FEAT_FIR_COEF_V,
        FEAT_ALPHA_FREE_ZORDER,
        FEAT_FIFO_MERGE,
+       FEAT_BURST_2D,
 };
 
 static const enum dss_feat_id omap4_dss_feat_list[] = {
@@ -434,6 +444,7 @@ static const enum dss_feat_id omap4_dss_feat_list[] = {
        FEAT_FIR_COEF_V,
        FEAT_ALPHA_FREE_ZORDER,
        FEAT_FIFO_MERGE,
+       FEAT_BURST_2D,
 };
 
 /* OMAP2 DSS Features */
@@ -451,6 +462,7 @@ static const struct omap_dss_features omap2_dss_features = {
        .overlay_caps = omap2_dss_overlay_caps,
        .clksrc_names = omap2_dss_clk_source_names,
        .dss_params = omap2_dss_param_range,
+       .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
        .buffer_size_unit = 1,
        .burst_size_unit = 8,
 };
@@ -470,6 +482,7 @@ static const struct omap_dss_features omap3430_dss_features = {
        .overlay_caps = omap3430_dss_overlay_caps,
        .clksrc_names = omap3_dss_clk_source_names,
        .dss_params = omap3_dss_param_range,
+       .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
        .buffer_size_unit = 1,
        .burst_size_unit = 8,
 };
@@ -488,6 +501,7 @@ static const struct omap_dss_features omap3630_dss_features = {
        .overlay_caps = omap3630_dss_overlay_caps,
        .clksrc_names = omap3_dss_clk_source_names,
        .dss_params = omap3_dss_param_range,
+       .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
        .buffer_size_unit = 1,
        .burst_size_unit = 8,
 };
@@ -508,6 +522,7 @@ static const struct omap_dss_features omap4430_es1_0_dss_features  = {
        .overlay_caps = omap4_dss_overlay_caps,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
+       .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
        .buffer_size_unit = 16,
        .burst_size_unit = 16,
 };
@@ -527,6 +542,7 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
        .overlay_caps = omap4_dss_overlay_caps,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
+       .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
        .buffer_size_unit = 16,
        .burst_size_unit = 16,
 };
@@ -546,6 +562,7 @@ static const struct omap_dss_features omap4_dss_features = {
        .overlay_caps = omap4_dss_overlay_caps,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
+       .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
        .buffer_size_unit = 16,
        .burst_size_unit = 16,
 };
@@ -562,13 +579,17 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
        .pll_enable             =       ti_hdmi_4xxx_pll_enable,
        .pll_disable            =       ti_hdmi_4xxx_pll_disable,
        .video_enable           =       ti_hdmi_4xxx_wp_video_start,
+       .video_disable          =       ti_hdmi_4xxx_wp_video_stop,
        .dump_wrapper           =       ti_hdmi_4xxx_wp_dump,
        .dump_core              =       ti_hdmi_4xxx_core_dump,
        .dump_pll               =       ti_hdmi_4xxx_pll_dump,
        .dump_phy               =       ti_hdmi_4xxx_phy_dump,
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
        .audio_enable           =       ti_hdmi_4xxx_wp_audio_enable,
+       .audio_disable          =       ti_hdmi_4xxx_wp_audio_disable,
+       .audio_start            =       ti_hdmi_4xxx_audio_start,
+       .audio_stop             =       ti_hdmi_4xxx_audio_stop,
+       .audio_config           =       ti_hdmi_4xxx_audio_config,
 #endif
 
 };
@@ -662,6 +683,11 @@ void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end)
        *end = omap_current_dss_features->reg_fields[id].end;
 }
 
+bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type)
+{
+       return omap_current_dss_features->supported_rotation_types & rot_type;
+}
+
 void dss_features_init(void)
 {
        if (cpu_is_omap24xx())
index c332e7d..bdf469f 100644 (file)
@@ -62,6 +62,7 @@ enum dss_feat_id {
        FEAT_FIFO_MERGE,
        /* An unknown HW bug causing the normal FIFO thresholds not to work */
        FEAT_OMAP3_DSI_FIFO_BUG,
+       FEAT_BURST_2D,
 };
 
 /* DSS register field id */
@@ -91,6 +92,8 @@ enum dss_range_param {
        FEAT_PARAM_DSIPLL_LPDIV,
        FEAT_PARAM_DOWNSCALE,
        FEAT_PARAM_LINEWIDTH,
+       FEAT_PARAM_MGR_WIDTH,
+       FEAT_PARAM_MGR_HEIGHT,
 };
 
 /* DSS Feature Functions */
@@ -108,6 +111,8 @@ const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
 u32 dss_feat_get_buffer_size_unit(void);       /* in bytes */
 u32 dss_feat_get_burst_size_unit(void);                /* in bytes */
 
+bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type);
+
 bool dss_has_feature(enum dss_feat_id id);
 void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
 void dss_features_init(void);
index c4b4f69..8195c71 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/clk.h>
 #include <video/omapdss.h>
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-#include "ti_hdmi_4xxx_ip.h"
-#endif
 
 #include "ti_hdmi.h"
 #include "dss.h"
@@ -63,7 +57,6 @@
 
 static struct {
        struct mutex lock;
-       struct omap_display_platform_data *pdata;
        struct platform_device *pdev;
        struct hdmi_ip_data ip_data;
 
@@ -130,25 +123,12 @@ static int hdmi_runtime_get(void)
 
        DSSDBG("hdmi_runtime_get\n");
 
-       /*
-        * HACK: Add dss_runtime_get() to ensure DSS clock domain is enabled.
-        * This should be removed later.
-        */
-       r = dss_runtime_get();
-       if (r < 0)
-               goto err_get_dss;
-
        r = pm_runtime_get_sync(&hdmi.pdev->dev);
        WARN_ON(r < 0);
        if (r < 0)
-               goto err_get_hdmi;
+               return r;
 
        return 0;
-
-err_get_hdmi:
-       dss_runtime_put();
-err_get_dss:
-       return r;
 }
 
 static void hdmi_runtime_put(void)
@@ -159,15 +139,9 @@ static void hdmi_runtime_put(void)
 
        r = pm_runtime_put_sync(&hdmi.pdev->dev);
        WARN_ON(r < 0);
-
-       /*
-        * HACK: This is added to complement the dss_runtime_get() call in
-        * hdmi_runtime_get(). This should be removed later.
-        */
-       dss_runtime_put();
 }
 
-int hdmi_init_display(struct omap_dss_device *dssdev)
+static int __init hdmi_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("init_display\n");
 
@@ -344,7 +318,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 
        hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
 
-       hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
+       hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
 
        /* config the PLL and PHY hdmi_set_pll_pwrfirst */
        r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
@@ -376,10 +350,11 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        dispc_enable_gamma_table(0);
 
        /* tv size */
-       dispc_set_digit_size(dssdev->panel.timings.x_res,
-                       dssdev->panel.timings.y_res);
+       dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
 
-       hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1);
+       r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
+       if (r)
+               goto err_vid_enable;
 
        r = dss_mgr_enable(dssdev->manager);
        if (r)
@@ -388,7 +363,8 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        return 0;
 
 err_mgr_enable:
-       hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
+       hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
+err_vid_enable:
        hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
        hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
 err:
@@ -400,7 +376,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
 {
        dss_mgr_disable(dssdev->manager);
 
-       hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0);
+       hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
        hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
        hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
        hdmi_runtime_put();
@@ -436,10 +412,12 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
                r = hdmi_power_on(dssdev);
                if (r)
                        DSSERR("failed to power on device\n");
+       } else {
+               dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
        }
 }
 
-void hdmi_dump_regs(struct seq_file *s)
+static void hdmi_dump_regs(struct seq_file *s)
 {
        mutex_lock(&hdmi.lock);
 
@@ -555,248 +533,201 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
        mutex_unlock(&hdmi.lock);
 }
 
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-
-static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai)
+static int hdmi_get_clocks(struct platform_device *pdev)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-       struct platform_device *pdev = to_platform_device(codec->dev);
-       struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec);
-       int err = 0;
+       struct clk *clk;
 
-       if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) {
-               dev_err(&pdev->dev, "Cannot enable/disable audio\n");
-               return -ENODEV;
+       clk = clk_get(&pdev->dev, "sys_clk");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get sys_clk\n");
+               return PTR_ERR(clk);
        }
 
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ip_data->ops->audio_enable(ip_data, true);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               ip_data->ops->audio_enable(ip_data, false);
-               break;
-       default:
-               err = -EINVAL;
-       }
-       return err;
-}
-
-static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
-                                   struct snd_pcm_hw_params *params,
-                                   struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-       struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec);
-       struct hdmi_audio_format audio_format;
-       struct hdmi_audio_dma audio_dma;
-       struct hdmi_core_audio_config core_cfg;
-       struct hdmi_core_infoframe_audio aud_if_cfg;
-       int err, n, cts;
-       enum hdmi_core_audio_sample_freq sample_freq;
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               core_cfg.i2s_cfg.word_max_length =
-                       HDMI_AUDIO_I2S_MAX_WORD_20BITS;
-               core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS;
-               core_cfg.i2s_cfg.in_length_bits =
-                       HDMI_AUDIO_I2S_INPUT_LENGTH_16;
-               core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
-               audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
-               audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
-               audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
-               audio_dma.transfer_size = 0x10;
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               core_cfg.i2s_cfg.word_max_length =
-                       HDMI_AUDIO_I2S_MAX_WORD_24BITS;
-               core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS;
-               core_cfg.i2s_cfg.in_length_bits =
-                       HDMI_AUDIO_I2S_INPUT_LENGTH_24;
-               audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
-               audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
-               audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
-               core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
-               audio_dma.transfer_size = 0x20;
-               break;
-       default:
+       hdmi.sys_clk = clk;
+
+       return 0;
+}
+
+static void hdmi_put_clocks(void)
+{
+       if (hdmi.sys_clk)
+               clk_put(hdmi.sys_clk);
+}
+
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
+{
+       u32 deep_color;
+       bool deep_color_correct = false;
+       u32 pclk = hdmi.ip_data.cfg.timings.pixel_clock;
+
+       if (n == NULL || cts == NULL)
                return -EINVAL;
-       }
 
-       switch (params_rate(params)) {
+       /* TODO: When implemented, query deep color mode here. */
+       deep_color = 100;
+
+       /*
+        * When using deep color, the default N value (as in the HDMI
+        * specification) yields to an non-integer CTS. Hence, we
+        * modify it while keeping the restrictions described in
+        * section 7.2.1 of the HDMI 1.4a specification.
+        */
+       switch (sample_freq) {
        case 32000:
-               sample_freq = HDMI_AUDIO_FS_32000;
+       case 48000:
+       case 96000:
+       case 192000:
+               if (deep_color == 125)
+                       if (pclk == 27027 || pclk == 74250)
+                               deep_color_correct = true;
+               if (deep_color == 150)
+                       if (pclk == 27027)
+                               deep_color_correct = true;
                break;
        case 44100:
-               sample_freq = HDMI_AUDIO_FS_44100;
-               break;
-       case 48000:
-               sample_freq = HDMI_AUDIO_FS_48000;
+       case 88200:
+       case 176400:
+               if (deep_color == 125)
+                       if (pclk == 27027)
+                               deep_color_correct = true;
                break;
        default:
                return -EINVAL;
        }
 
-       err = hdmi_config_audio_acr(ip_data, params_rate(params), &n, &cts);
-       if (err < 0)
-               return err;
-
-       /* Audio wrapper config */
-       audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
-       audio_format.active_chnnls_msk = 0x03;
-       audio_format.type = HDMI_AUDIO_TYPE_LPCM;
-       audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
-       /* Disable start/stop signals of IEC 60958 blocks */
-       audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF;
+       if (deep_color_correct) {
+               switch (sample_freq) {
+               case 32000:
+                       *n = 8192;
+                       break;
+               case 44100:
+                       *n = 12544;
+                       break;
+               case 48000:
+                       *n = 8192;
+                       break;
+               case 88200:
+                       *n = 25088;
+                       break;
+               case 96000:
+                       *n = 16384;
+                       break;
+               case 176400:
+                       *n = 50176;
+                       break;
+               case 192000:
+                       *n = 32768;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               switch (sample_freq) {
+               case 32000:
+                       *n = 4096;
+                       break;
+               case 44100:
+                       *n = 6272;
+                       break;
+               case 48000:
+                       *n = 6144;
+                       break;
+               case 88200:
+                       *n = 12544;
+                       break;
+               case 96000:
+                       *n = 12288;
+                       break;
+               case 176400:
+                       *n = 25088;
+                       break;
+               case 192000:
+                       *n = 24576;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
+       *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
 
-       audio_dma.block_size = 0xC0;
-       audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
-       audio_dma.fifo_threshold = 0x20; /* in number of samples */
+       return 0;
+}
 
-       hdmi_wp_audio_config_dma(ip_data, &audio_dma);
-       hdmi_wp_audio_config_format(ip_data, &audio_format);
+int hdmi_audio_enable(void)
+{
+       DSSDBG("audio_enable\n");
 
-       /*
-        * I2S config
-        */
-       core_cfg.i2s_cfg.en_high_bitrate_aud = false;
-       /* Only used with high bitrate audio */
-       core_cfg.i2s_cfg.cbit_order = false;
-       /* Serial data and word select should change on sck rising edge */
-       core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
-       core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
-       /* Set I2S word select polarity */
-       core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT;
-       core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
-       /* Set serial data to word select shift. See Phillips spec. */
-       core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
-       /* Enable one of the four available serial data channels */
-       core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
-
-       /* Core audio config */
-       core_cfg.freq_sample = sample_freq;
-       core_cfg.n = n;
-       core_cfg.cts = cts;
-       if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
-               core_cfg.aud_par_busclk = 0;
-               core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
-               core_cfg.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK);
-       } else {
-               core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8);
-               core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
-               core_cfg.use_mclk = true;
-       }
+       return hdmi.ip_data.ops->audio_enable(&hdmi.ip_data);
+}
 
-       if (core_cfg.use_mclk)
-               core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS;
-       core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
-       core_cfg.en_spdif = false;
-       /* Use sample frequency from channel status word */
-       core_cfg.fs_override = true;
-       /* Enable ACR packets */
-       core_cfg.en_acr_pkt = true;
-       /* Disable direct streaming digital audio */
-       core_cfg.en_dsd_audio = false;
-       /* Use parallel audio interface */
-       core_cfg.en_parallel_aud_input = true;
-
-       hdmi_core_audio_config(ip_data, &core_cfg);
+void hdmi_audio_disable(void)
+{
+       DSSDBG("audio_disable\n");
 
-       /*
-        * Configure packet
-        * info frame audio see doc CEA861-D page 74
-        */
-       aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM;
-       aud_if_cfg.db1_channel_count = 2;
-       aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM;
-       aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM;
-       aud_if_cfg.db4_channel_alloc = 0x00;
-       aud_if_cfg.db5_downmix_inh = false;
-       aud_if_cfg.db5_lsv = 0;
-
-       hdmi_core_audio_infoframe_config(ip_data, &aud_if_cfg);
-       return 0;
+       hdmi.ip_data.ops->audio_disable(&hdmi.ip_data);
 }
 
-static int hdmi_audio_startup(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
+int hdmi_audio_start(void)
 {
-       if (!hdmi.ip_data.cfg.cm.mode) {
-               pr_err("Current video settings do not support audio.\n");
-               return -EIO;
-       }
-       return 0;
+       DSSDBG("audio_start\n");
+
+       return hdmi.ip_data.ops->audio_start(&hdmi.ip_data);
 }
 
-static int hdmi_audio_codec_probe(struct snd_soc_codec *codec)
+void hdmi_audio_stop(void)
 {
-       struct hdmi_ip_data *priv = &hdmi.ip_data;
+       DSSDBG("audio_stop\n");
 
-       snd_soc_codec_set_drvdata(codec, priv);
-       return 0;
+       hdmi.ip_data.ops->audio_stop(&hdmi.ip_data);
 }
 
-static struct snd_soc_codec_driver hdmi_audio_codec_drv = {
-       .probe = hdmi_audio_codec_probe,
-};
+bool hdmi_mode_has_audio(void)
+{
+       if (hdmi.ip_data.cfg.cm.mode == HDMI_HDMI)
+               return true;
+       else
+               return false;
+}
 
-static struct snd_soc_dai_ops hdmi_audio_codec_ops = {
-       .hw_params = hdmi_audio_hw_params,
-       .trigger = hdmi_audio_trigger,
-       .startup = hdmi_audio_startup,
-};
+int hdmi_audio_config(struct omap_dss_audio *audio)
+{
+       return hdmi.ip_data.ops->audio_config(&hdmi.ip_data, audio);
+}
 
-static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
-               .name = "hdmi-audio-codec",
-               .playback = {
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_32000 |
-                               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
-                               SNDRV_PCM_FMTBIT_S24_LE,
-               },
-               .ops = &hdmi_audio_codec_ops,
-};
 #endif
 
-static int hdmi_get_clocks(struct platform_device *pdev)
+static void __init hdmi_probe_pdata(struct platform_device *pdev)
 {
-       struct clk *clk;
+       struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+       int r, i;
 
-       clk = clk_get(&pdev->dev, "sys_clk");
-       if (IS_ERR(clk)) {
-               DSSERR("can't get sys_clk\n");
-               return PTR_ERR(clk);
-       }
+       for (i = 0; i < pdata->num_devices; ++i) {
+               struct omap_dss_device *dssdev = pdata->devices[i];
 
-       hdmi.sys_clk = clk;
+               if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI)
+                       continue;
 
-       return 0;
-}
+               r = hdmi_init_display(dssdev);
+               if (r) {
+                       DSSERR("device %s init failed: %d\n", dssdev->name, r);
+                       continue;
+               }
 
-static void hdmi_put_clocks(void)
-{
-       if (hdmi.sys_clk)
-               clk_put(hdmi.sys_clk);
+               r = omap_dss_register_device(dssdev, &pdev->dev, i);
+               if (r)
+                       DSSERR("device %s register failed: %d\n",
+                                       dssdev->name, r);
+       }
 }
 
 /* HDMI HW IP initialisation */
-static int omapdss_hdmihw_probe(struct platform_device *pdev)
+static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
 {
        struct resource *hdmi_mem;
        int r;
 
-       hdmi.pdata = pdev->dev.platform_data;
        hdmi.pdev = pdev;
 
        mutex_init(&hdmi.lock);
@@ -830,28 +761,18 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 
        hdmi_panel_init();
 
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+       dss_debugfs_create_file("hdmi", hdmi_dump_regs);
+
+       hdmi_probe_pdata(pdev);
 
-       /* Register ASoC codec DAI */
-       r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
-                                       &hdmi_codec_dai_drv, 1);
-       if (r) {
-               DSSERR("can't register ASoC HDMI audio codec\n");
-               return r;
-       }
-#endif
        return 0;
 }
 
-static int omapdss_hdmihw_remove(struct platform_device *pdev)
+static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
 {
-       hdmi_panel_exit();
+       omap_dss_unregister_child_devices(&pdev->dev);
 
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-       snd_soc_unregister_codec(&pdev->dev);
-#endif
+       hdmi_panel_exit();
 
        pm_runtime_disable(&pdev->dev);
 
@@ -867,7 +788,6 @@ static int hdmi_runtime_suspend(struct device *dev)
        clk_disable(hdmi.sys_clk);
 
        dispc_runtime_put();
-       dss_runtime_put();
 
        return 0;
 }
@@ -876,23 +796,13 @@ static int hdmi_runtime_resume(struct device *dev)
 {
        int r;
 
-       r = dss_runtime_get();
-       if (r < 0)
-               goto err_get_dss;
-
        r = dispc_runtime_get();
        if (r < 0)
-               goto err_get_dispc;
-
+               return r;
 
        clk_enable(hdmi.sys_clk);
 
        return 0;
-
-err_get_dispc:
-       dss_runtime_put();
-err_get_dss:
-       return r;
 }
 
 static const struct dev_pm_ops hdmi_pm_ops = {
@@ -901,8 +811,7 @@ static const struct dev_pm_ops hdmi_pm_ops = {
 };
 
 static struct platform_driver omapdss_hdmihw_driver = {
-       .probe          = omapdss_hdmihw_probe,
-       .remove         = omapdss_hdmihw_remove,
+       .remove         = __exit_p(omapdss_hdmihw_remove),
        .driver         = {
                .name   = "omapdss_hdmi",
                .owner  = THIS_MODULE,
@@ -910,12 +819,12 @@ static struct platform_driver omapdss_hdmihw_driver = {
        },
 };
 
-int hdmi_init_platform_driver(void)
+int __init hdmi_init_platform_driver(void)
 {
-       return platform_driver_register(&omapdss_hdmihw_driver);
+       return platform_driver_probe(&omapdss_hdmihw_driver, omapdss_hdmihw_probe);
 }
 
-void hdmi_uninit_platform_driver(void)
+void __exit hdmi_uninit_platform_driver(void)
 {
-       return platform_driver_unregister(&omapdss_hdmihw_driver);
+       platform_driver_unregister(&omapdss_hdmihw_driver);
 }
index 533d5dc..1179e3c 100644 (file)
 #include "dss.h"
 
 static struct {
-       struct mutex hdmi_lock;
+       /* This protects the panel ops, mainly when accessing the HDMI IP. */
+       struct mutex lock;
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+       /* This protects the audio ops, specifically. */
+       spinlock_t audio_lock;
+#endif
 } hdmi;
 
 
@@ -54,12 +59,168 @@ static void hdmi_panel_remove(struct omap_dss_device *dssdev)
 
 }
 
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev)
+{
+       unsigned long flags;
+       int r;
+
+       mutex_lock(&hdmi.lock);
+       spin_lock_irqsave(&hdmi.audio_lock, flags);
+
+       /* enable audio only if the display is active and supports audio */
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
+           !hdmi_mode_has_audio()) {
+               DSSERR("audio not supported or display is off\n");
+               r = -EPERM;
+               goto err;
+       }
+
+       r = hdmi_audio_enable();
+
+       if (!r)
+               dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
+
+err:
+       spin_unlock_irqrestore(&hdmi.audio_lock, flags);
+       mutex_unlock(&hdmi.lock);
+       return r;
+}
+
+static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hdmi.audio_lock, flags);
+
+       hdmi_audio_disable();
+
+       dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
+
+       spin_unlock_irqrestore(&hdmi.audio_lock, flags);
+}
+
+static int hdmi_panel_audio_start(struct omap_dss_device *dssdev)
+{
+       unsigned long flags;
+       int r;
+
+       spin_lock_irqsave(&hdmi.audio_lock, flags);
+       /*
+        * No need to check the panel state. It was checked when trasitioning
+        * to AUDIO_ENABLED.
+        */
+       if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) {
+               DSSERR("audio start from invalid state\n");
+               r = -EPERM;
+               goto err;
+       }
+
+       r = hdmi_audio_start();
+
+       if (!r)
+               dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
+
+err:
+       spin_unlock_irqrestore(&hdmi.audio_lock, flags);
+       return r;
+}
+
+static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hdmi.audio_lock, flags);
+
+       hdmi_audio_stop();
+       dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
+
+       spin_unlock_irqrestore(&hdmi.audio_lock, flags);
+}
+
+static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev)
+{
+       bool r = false;
+
+       mutex_lock(&hdmi.lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               goto err;
+
+       if (!hdmi_mode_has_audio())
+               goto err;
+
+       r = true;
+err:
+       mutex_unlock(&hdmi.lock);
+       return r;
+}
+
+static int hdmi_panel_audio_config(struct omap_dss_device *dssdev,
+               struct omap_dss_audio *audio)
+{
+       unsigned long flags;
+       int r;
+
+       mutex_lock(&hdmi.lock);
+       spin_lock_irqsave(&hdmi.audio_lock, flags);
+
+       /* config audio only if the display is active and supports audio */
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE ||
+           !hdmi_mode_has_audio()) {
+               DSSERR("audio not supported or display is off\n");
+               r = -EPERM;
+               goto err;
+       }
+
+       r = hdmi_audio_config(audio);
+
+       if (!r)
+               dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
+
+err:
+       spin_unlock_irqrestore(&hdmi.audio_lock, flags);
+       mutex_unlock(&hdmi.lock);
+       return r;
+}
+
+#else
+static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev)
+{
+       return -EPERM;
+}
+
+static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev)
+{
+}
+
+static int hdmi_panel_audio_start(struct omap_dss_device *dssdev)
+{
+       return -EPERM;
+}
+
+static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev)
+{
+}
+
+static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev)
+{
+       return false;
+}
+
+static int hdmi_panel_audio_config(struct omap_dss_device *dssdev,
+               struct omap_dss_audio *audio)
+{
+       return -EPERM;
+}
+#endif
+
 static int hdmi_panel_enable(struct omap_dss_device *dssdev)
 {
        int r = 0;
        DSSDBG("ENTER hdmi_panel_enable\n");
 
-       mutex_lock(&hdmi.hdmi_lock);
+       mutex_lock(&hdmi.lock);
 
        if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
                r = -EINVAL;
@@ -75,40 +236,52 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev)
        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
 err:
-       mutex_unlock(&hdmi.hdmi_lock);
+       mutex_unlock(&hdmi.lock);
 
        return r;
 }
 
 static void hdmi_panel_disable(struct omap_dss_device *dssdev)
 {
-       mutex_lock(&hdmi.hdmi_lock);
-
-       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+       mutex_lock(&hdmi.lock);
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+               /*
+                * TODO: notify audio users that the display was disabled. For
+                * now, disable audio locally to not break our audio state
+                * machine.
+                */
+               hdmi_panel_audio_disable(dssdev);
                omapdss_hdmi_display_disable(dssdev);
+       }
 
        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 
-       mutex_unlock(&hdmi.hdmi_lock);
+       mutex_unlock(&hdmi.lock);
 }
 
 static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
 {
        int r = 0;
 
-       mutex_lock(&hdmi.hdmi_lock);
+       mutex_lock(&hdmi.lock);
 
        if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
                r = -EINVAL;
                goto err;
        }
 
-       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+       /*
+        * TODO: notify audio users that the display was suspended. For now,
+        * disable audio locally to not break our audio state machine.
+        */
+       hdmi_panel_audio_disable(dssdev);
 
+       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
        omapdss_hdmi_display_disable(dssdev);
 
 err:
-       mutex_unlock(&hdmi.hdmi_lock);
+       mutex_unlock(&hdmi.lock);
 
        return r;
 }
@@ -117,7 +290,7 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev)
 {
        int r = 0;
 
-       mutex_lock(&hdmi.hdmi_lock);
+       mutex_lock(&hdmi.lock);
 
        if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
                r = -EINVAL;
@@ -129,11 +302,12 @@ static int hdmi_panel_resume(struct omap_dss_device *dssdev)
                DSSERR("failed to power on\n");
                goto err;
        }
+       /* TODO: notify audio users that the panel resumed. */
 
        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
 err:
-       mutex_unlock(&hdmi.hdmi_lock);
+       mutex_unlock(&hdmi.lock);
 
        return r;
 }
@@ -141,11 +315,11 @@ err:
 static void hdmi_get_timings(struct omap_dss_device *dssdev,
                        struct omap_video_timings *timings)
 {
-       mutex_lock(&hdmi.hdmi_lock);
+       mutex_lock(&hdmi.lock);
 
        *timings = dssdev->panel.timings;
 
-       mutex_unlock(&hdmi.hdmi_lock);
+       mutex_unlock(&hdmi.lock);
 }
 
 static void hdmi_set_timings(struct omap_dss_device *dssdev,
@@ -153,12 +327,18 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev,
 {
        DSSDBG("hdmi_set_timings\n");
 
-       mutex_lock(&hdmi.hdmi_lock);
+       mutex_lock(&hdmi.lock);
+
+       /*
+        * TODO: notify audio users that there was a timings change. For
+        * now, disable audio locally to not break our audio state machine.
+        */
+       hdmi_panel_audio_disable(dssdev);
 
        dssdev->panel.timings = *timings;
        omapdss_hdmi_display_set_timing(dssdev);
 
-       mutex_unlock(&hdmi.hdmi_lock);
+       mutex_unlock(&hdmi.lock);
 }
 
 static int hdmi_check_timings(struct omap_dss_device *dssdev,
@@ -168,11 +348,11 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev,
 
        DSSDBG("hdmi_check_timings\n");
 
-       mutex_lock(&hdmi.hdmi_lock);
+       mutex_lock(&hdmi.lock);
 
        r = omapdss_hdmi_display_check_timing(dssdev, timings);
 
-       mutex_unlock(&hdmi.hdmi_lock);
+       mutex_unlock(&hdmi.lock);
        return r;
 }
 
@@ -180,7 +360,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
 {
        int r;
 
-       mutex_lock(&hdmi.hdmi_lock);
+       mutex_lock(&hdmi.lock);
 
        if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
                r = omapdss_hdmi_display_enable(dssdev);
@@ -194,7 +374,7 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len)
                        dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
                omapdss_hdmi_display_disable(dssdev);
 err:
-       mutex_unlock(&hdmi.hdmi_lock);
+       mutex_unlock(&hdmi.lock);
 
        return r;
 }
@@ -203,7 +383,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev)
 {
        int r;
 
-       mutex_lock(&hdmi.hdmi_lock);
+       mutex_lock(&hdmi.lock);
 
        if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
                r = omapdss_hdmi_display_enable(dssdev);
@@ -217,7 +397,7 @@ static bool hdmi_detect(struct omap_dss_device *dssdev)
                        dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
                omapdss_hdmi_display_disable(dssdev);
 err:
-       mutex_unlock(&hdmi.hdmi_lock);
+       mutex_unlock(&hdmi.lock);
 
        return r;
 }
@@ -234,6 +414,12 @@ static struct omap_dss_driver hdmi_driver = {
        .check_timings  = hdmi_check_timings,
        .read_edid      = hdmi_read_edid,
        .detect         = hdmi_detect,
+       .audio_enable   = hdmi_panel_audio_enable,
+       .audio_disable  = hdmi_panel_audio_disable,
+       .audio_start    = hdmi_panel_audio_start,
+       .audio_stop     = hdmi_panel_audio_stop,
+       .audio_supported        = hdmi_panel_audio_supported,
+       .audio_config   = hdmi_panel_audio_config,
        .driver                 = {
                .name   = "hdmi_panel",
                .owner  = THIS_MODULE,
@@ -242,7 +428,11 @@ static struct omap_dss_driver hdmi_driver = {
 
 int hdmi_panel_init(void)
 {
-       mutex_init(&hdmi.hdmi_lock);
+       mutex_init(&hdmi.lock);
+
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+       spin_lock_init(&hdmi.audio_lock);
+#endif
 
        omap_dss_register_driver(&hdmi_driver);
 
index e736460..0cbcde4 100644 (file)
@@ -654,9 +654,20 @@ static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
        return 0;
 }
 
+int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
+               const struct omap_video_timings *timings)
+{
+       if (!dispc_mgr_timings_ok(mgr->id, timings)) {
+               DSSERR("check_manager: invalid timings\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 int dss_mgr_check(struct omap_overlay_manager *mgr,
-               struct omap_dss_device *dssdev,
                struct omap_overlay_manager_info *info,
+               const struct omap_video_timings *mgr_timings,
                struct omap_overlay_info **overlay_infos)
 {
        struct omap_overlay *ovl;
@@ -668,6 +679,10 @@ int dss_mgr_check(struct omap_overlay_manager *mgr,
                        return r;
        }
 
+       r = dss_mgr_check_timings(mgr, mgr_timings);
+       if (r)
+               return r;
+
        list_for_each_entry(ovl, &mgr->overlays, list) {
                struct omap_overlay_info *oi;
                int r;
@@ -677,7 +692,7 @@ int dss_mgr_check(struct omap_overlay_manager *mgr,
                if (oi == NULL)
                        continue;
 
-               r = dss_ovl_check(ovl, oi, dssdev);
+               r = dss_ovl_check(ovl, oi, mgr_timings);
                if (r)
                        return r;
        }
index 6e82181..b0ba60f 100644 (file)
@@ -628,19 +628,23 @@ int dss_ovl_simple_check(struct omap_overlay *ovl,
                return -EINVAL;
        }
 
+       if (dss_feat_rotation_type_supported(info->rotation_type) == 0) {
+               DSSERR("check_overlay: rotation type %d not supported\n",
+                               info->rotation_type);
+               return -EINVAL;
+       }
+
        return 0;
 }
 
-int dss_ovl_check(struct omap_overlay *ovl,
-               struct omap_overlay_info *info, struct omap_dss_device *dssdev)
+int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
+               const struct omap_video_timings *mgr_timings)
 {
        u16 outw, outh;
        u16 dw, dh;
 
-       if (dssdev == NULL)
-               return 0;
-
-       dssdev->driver->get_resolution(dssdev, &dw, &dh);
+       dw = mgr_timings->x_res;
+       dh = mgr_timings->y_res;
 
        if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
                outw = info->width;
index 788a0ef..3d8c206 100644 (file)
@@ -304,13 +304,23 @@ static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
                u16 height, void (*callback)(void *data), void *data)
 {
        u32 l;
+       struct omap_video_timings timings = {
+               .hsw            = 1,
+               .hfp            = 1,
+               .hbp            = 1,
+               .vsw            = 1,
+               .vfp            = 0,
+               .vbp            = 0,
+               .x_res          = width,
+               .y_res          = height,
+       };
 
        /*BUG_ON(callback == 0);*/
        BUG_ON(rfbi.framedone_callback != NULL);
 
        DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
 
-       dispc_mgr_set_lcd_size(dssdev->manager->id, width, height);
+       dss_mgr_set_timings(dssdev->manager, &timings);
 
        dispc_mgr_enable(dssdev->manager->id, true);
 
@@ -766,6 +776,16 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
                u16 *x, u16 *y, u16 *w, u16 *h)
 {
        u16 dw, dh;
+       struct omap_video_timings timings = {
+               .hsw            = 1,
+               .hfp            = 1,
+               .hbp            = 1,
+               .vsw            = 1,
+               .vfp            = 0,
+               .vbp            = 0,
+               .x_res          = *w,
+               .y_res          = *h,
+       };
 
        dssdev->driver->get_resolution(dssdev, &dw, &dh);
 
@@ -784,7 +804,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
        if (*w == 0 || *h == 0)
                return -EINVAL;
 
-       dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h);
+       dss_mgr_set_timings(dssdev->manager, &timings);
 
        return 0;
 }
@@ -799,7 +819,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev,
 }
 EXPORT_SYMBOL(omap_rfbi_update);
 
-void rfbi_dump_regs(struct seq_file *s)
+static void rfbi_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
 
@@ -900,15 +920,39 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_disable);
 
-int rfbi_init_display(struct omap_dss_device *dssdev)
+static int __init rfbi_init_display(struct omap_dss_device *dssdev)
 {
        rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
        dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
        return 0;
 }
 
+static void __init rfbi_probe_pdata(struct platform_device *pdev)
+{
+       struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+       int i, r;
+
+       for (i = 0; i < pdata->num_devices; ++i) {
+               struct omap_dss_device *dssdev = pdata->devices[i];
+
+               if (dssdev->type != OMAP_DISPLAY_TYPE_DBI)
+                       continue;
+
+               r = rfbi_init_display(dssdev);
+               if (r) {
+                       DSSERR("device %s init failed: %d\n", dssdev->name, r);
+                       continue;
+               }
+
+               r = omap_dss_register_device(dssdev, &pdev->dev, i);
+               if (r)
+                       DSSERR("device %s register failed: %d\n",
+                               dssdev->name, r);
+       }
+}
+
 /* RFBI HW IP initialisation */
-static int omap_rfbihw_probe(struct platform_device *pdev)
+static int __init omap_rfbihw_probe(struct platform_device *pdev)
 {
        u32 rev;
        struct resource *rfbi_mem;
@@ -956,6 +1000,10 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
 
        rfbi_runtime_put();
 
+       dss_debugfs_create_file("rfbi", rfbi_dump_regs);
+
+       rfbi_probe_pdata(pdev);
+
        return 0;
 
 err_runtime_get:
@@ -963,8 +1011,9 @@ err_runtime_get:
        return r;
 }
 
-static int omap_rfbihw_remove(struct platform_device *pdev)
+static int __exit omap_rfbihw_remove(struct platform_device *pdev)
 {
+       omap_dss_unregister_child_devices(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return 0;
 }
@@ -972,7 +1021,6 @@ static int omap_rfbihw_remove(struct platform_device *pdev)
 static int rfbi_runtime_suspend(struct device *dev)
 {
        dispc_runtime_put();
-       dss_runtime_put();
 
        return 0;
 }
@@ -981,20 +1029,11 @@ static int rfbi_runtime_resume(struct device *dev)
 {
        int r;
 
-       r = dss_runtime_get();
-       if (r < 0)
-               goto err_get_dss;
-
        r = dispc_runtime_get();
        if (r < 0)
-               goto err_get_dispc;
+               return r;
 
        return 0;
-
-err_get_dispc:
-       dss_runtime_put();
-err_get_dss:
-       return r;
 }
 
 static const struct dev_pm_ops rfbi_pm_ops = {
@@ -1003,8 +1042,7 @@ static const struct dev_pm_ops rfbi_pm_ops = {
 };
 
 static struct platform_driver omap_rfbihw_driver = {
-       .probe          = omap_rfbihw_probe,
-       .remove         = omap_rfbihw_remove,
+       .remove         = __exit_p(omap_rfbihw_remove),
        .driver         = {
                .name   = "omapdss_rfbi",
                .owner  = THIS_MODULE,
@@ -1012,12 +1050,12 @@ static struct platform_driver omap_rfbihw_driver = {
        },
 };
 
-int rfbi_init_platform_driver(void)
+int __init rfbi_init_platform_driver(void)
 {
-       return platform_driver_register(&omap_rfbihw_driver);
+       return platform_driver_probe(&omap_rfbihw_driver, omap_rfbihw_probe);
 }
 
-void rfbi_uninit_platform_driver(void)
+void __exit rfbi_uninit_platform_driver(void)
 {
-       return platform_driver_unregister(&omap_rfbihw_driver);
+       platform_driver_unregister(&omap_rfbihw_driver);
 }
index 8266ca0..3a43dc2 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/err.h>
 #include <linux/regulator/consumer.h>
 #include <linux/export.h>
+#include <linux/platform_device.h>
 
 #include <video/omapdss.h>
 #include "dss.h"
@@ -71,10 +72,6 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        if (r)
                goto err_reg_enable;
 
-       r = dss_runtime_get();
-       if (r)
-               goto err_get_dss;
-
        r = dispc_runtime_get();
        if (r)
                goto err_get_dispc;
@@ -107,7 +104,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        }
 
 
-       dispc_mgr_set_lcd_timings(dssdev->manager->id, t);
+       dss_mgr_set_timings(dssdev->manager, t);
 
        r = dss_set_clock_div(&dss_cinfo);
        if (r)
@@ -137,8 +134,6 @@ err_set_dss_clock_div:
 err_calc_clock_div:
        dispc_runtime_put();
 err_get_dispc:
-       dss_runtime_put();
-err_get_dss:
        regulator_disable(sdi.vdds_sdi_reg);
 err_reg_enable:
        omap_dss_stop_device(dssdev);
@@ -154,7 +149,6 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
        dss_sdi_disable();
 
        dispc_runtime_put();
-       dss_runtime_put();
 
        regulator_disable(sdi.vdds_sdi_reg);
 
@@ -162,7 +156,7 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
 }
 EXPORT_SYMBOL(omapdss_sdi_display_disable);
 
-int sdi_init_display(struct omap_dss_device *dssdev)
+static int __init sdi_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("SDI init\n");
 
@@ -182,11 +176,58 @@ int sdi_init_display(struct omap_dss_device *dssdev)
        return 0;
 }
 
-int sdi_init(void)
+static void __init sdi_probe_pdata(struct platform_device *pdev)
+{
+       struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+       int i, r;
+
+       for (i = 0; i < pdata->num_devices; ++i) {
+               struct omap_dss_device *dssdev = pdata->devices[i];
+
+               if (dssdev->type != OMAP_DISPLAY_TYPE_SDI)
+                       continue;
+
+               r = sdi_init_display(dssdev);
+               if (r) {
+                       DSSERR("device %s init failed: %d\n", dssdev->name, r);
+                       continue;
+               }
+
+               r = omap_dss_register_device(dssdev, &pdev->dev, i);
+               if (r)
+                       DSSERR("device %s register failed: %d\n",
+                                       dssdev->name, r);
+       }
+}
+
+static int __init omap_sdi_probe(struct platform_device *pdev)
 {
+       sdi_probe_pdata(pdev);
+
+       return 0;
+}
+
+static int __exit omap_sdi_remove(struct platform_device *pdev)
+{
+       omap_dss_unregister_child_devices(&pdev->dev);
+
        return 0;
 }
 
-void sdi_exit(void)
+static struct platform_driver omap_sdi_driver = {
+       .remove         = __exit_p(omap_sdi_remove),
+       .driver         = {
+               .name   = "omapdss_sdi",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int __init sdi_init_platform_driver(void)
+{
+       return platform_driver_probe(&omap_sdi_driver, omap_sdi_probe);
+}
+
+void __exit sdi_uninit_platform_driver(void)
 {
+       platform_driver_unregister(&omap_sdi_driver);
 }
index 1f58b84..e734cb4 100644 (file)
@@ -96,7 +96,9 @@ struct ti_hdmi_ip_ops {
 
        void (*pll_disable)(struct hdmi_ip_data *ip_data);
 
-       void (*video_enable)(struct hdmi_ip_data *ip_data, bool start);
+       int (*video_enable)(struct hdmi_ip_data *ip_data);
+
+       void (*video_disable)(struct hdmi_ip_data *ip_data);
 
        void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s);
 
@@ -106,9 +108,17 @@ struct ti_hdmi_ip_ops {
 
        void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s);
 
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-       void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start);
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+       int (*audio_enable)(struct hdmi_ip_data *ip_data);
+
+       void (*audio_disable)(struct hdmi_ip_data *ip_data);
+
+       int (*audio_start)(struct hdmi_ip_data *ip_data);
+
+       void (*audio_stop)(struct hdmi_ip_data *ip_data);
+
+       int (*audio_config)(struct hdmi_ip_data *ip_data,
+               struct omap_dss_audio *audio);
 #endif
 
 };
@@ -173,7 +183,8 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data);
 void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data);
 int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len);
 bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data);
-void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start);
+int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data);
+void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data);
 int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data);
 void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data);
 void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data);
@@ -181,8 +192,13 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
 void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
 void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
 void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s);
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable);
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts);
+int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data);
+void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data);
+int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data);
+void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data);
+int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data,
+               struct omap_dss_audio *audio);
 #endif
 #endif
index bfe6fe6..4dae1b2 100644 (file)
 #include <linux/string.h>
 #include <linux/seq_file.h>
 #include <linux/gpio.h>
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+#include <sound/asound.h>
+#include <sound/asoundef.h>
+#endif
 
 #include "ti_hdmi_4xxx_ip.h"
 #include "dss.h"
+#include "dss_features.h"
 
 static inline void hdmi_write_reg(void __iomem *base_addr,
                                const u16 idx, u32 val)
@@ -298,9 +303,9 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
        REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
 
        r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio),
-                       NULL, hpd_irq_handler,
-                       IRQF_DISABLED | IRQF_TRIGGER_RISING |
-                       IRQF_TRIGGER_FALLING, "hpd", ip_data);
+                                NULL, hpd_irq_handler,
+                                IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+                                IRQF_ONESHOT, "hpd", ip_data);
        if (r) {
                DSSERR("HPD IRQ request failed\n");
                hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
@@ -699,9 +704,15 @@ static void hdmi_wp_init(struct omap_video_timings *timings,
 
 }
 
-void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start)
+int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data)
+{
+       REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, true, 31, 31);
+       return 0;
+}
+
+void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data)
 {
-       REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, start, 31, 31);
+       REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, false, 31, 31);
 }
 
 static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt,
@@ -886,10 +897,12 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
 
 #define CORE_REG(i, name) name(i)
 #define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\
-               hdmi_read_reg(hdmi_pll_base(ip_data), r))
-#define DUMPCOREAV(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \
+               hdmi_read_reg(hdmi_core_sys_base(ip_data), r))
+#define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\
+               hdmi_read_reg(hdmi_av_base(ip_data), r))
+#define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \
                (i < 10) ? 32 - strlen(#r) : 31 - strlen(#r), " ", \
-               hdmi_read_reg(hdmi_pll_base(ip_data), CORE_REG(i, r)))
+               hdmi_read_reg(hdmi_av_base(ip_data), CORE_REG(i, r)))
 
        DUMPCORE(HDMI_CORE_SYS_VND_IDL);
        DUMPCORE(HDMI_CORE_SYS_DEV_IDL);
@@ -898,6 +911,13 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
        DUMPCORE(HDMI_CORE_SYS_SRST);
        DUMPCORE(HDMI_CORE_CTRL1);
        DUMPCORE(HDMI_CORE_SYS_SYS_STAT);
+       DUMPCORE(HDMI_CORE_SYS_DE_DLY);
+       DUMPCORE(HDMI_CORE_SYS_DE_CTRL);
+       DUMPCORE(HDMI_CORE_SYS_DE_TOP);
+       DUMPCORE(HDMI_CORE_SYS_DE_CNTL);
+       DUMPCORE(HDMI_CORE_SYS_DE_CNTH);
+       DUMPCORE(HDMI_CORE_SYS_DE_LINL);
+       DUMPCORE(HDMI_CORE_SYS_DE_LINH_1);
        DUMPCORE(HDMI_CORE_SYS_VID_ACEN);
        DUMPCORE(HDMI_CORE_SYS_VID_MODE);
        DUMPCORE(HDMI_CORE_SYS_INTR_STATE);
@@ -907,102 +927,91 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
        DUMPCORE(HDMI_CORE_SYS_INTR4);
        DUMPCORE(HDMI_CORE_SYS_UMASK1);
        DUMPCORE(HDMI_CORE_SYS_TMDS_CTRL);
-       DUMPCORE(HDMI_CORE_SYS_DE_DLY);
-       DUMPCORE(HDMI_CORE_SYS_DE_CTRL);
-       DUMPCORE(HDMI_CORE_SYS_DE_TOP);
-       DUMPCORE(HDMI_CORE_SYS_DE_CNTL);
-       DUMPCORE(HDMI_CORE_SYS_DE_CNTH);
-       DUMPCORE(HDMI_CORE_SYS_DE_LINL);
-       DUMPCORE(HDMI_CORE_SYS_DE_LINH_1);
 
-       DUMPCORE(HDMI_CORE_DDC_CMD);
-       DUMPCORE(HDMI_CORE_DDC_STATUS);
        DUMPCORE(HDMI_CORE_DDC_ADDR);
+       DUMPCORE(HDMI_CORE_DDC_SEGM);
        DUMPCORE(HDMI_CORE_DDC_OFFSET);
        DUMPCORE(HDMI_CORE_DDC_COUNT1);
        DUMPCORE(HDMI_CORE_DDC_COUNT2);
+       DUMPCORE(HDMI_CORE_DDC_STATUS);
+       DUMPCORE(HDMI_CORE_DDC_CMD);
        DUMPCORE(HDMI_CORE_DDC_DATA);
-       DUMPCORE(HDMI_CORE_DDC_SEGM);
 
-       DUMPCORE(HDMI_CORE_AV_HDMI_CTRL);
-       DUMPCORE(HDMI_CORE_AV_DPD);
-       DUMPCORE(HDMI_CORE_AV_PB_CTRL1);
-       DUMPCORE(HDMI_CORE_AV_PB_CTRL2);
-       DUMPCORE(HDMI_CORE_AV_AVI_TYPE);
-       DUMPCORE(HDMI_CORE_AV_AVI_VERS);
-       DUMPCORE(HDMI_CORE_AV_AVI_LEN);
-       DUMPCORE(HDMI_CORE_AV_AVI_CHSUM);
+       DUMPCOREAV(HDMI_CORE_AV_ACR_CTRL);
+       DUMPCOREAV(HDMI_CORE_AV_FREQ_SVAL);
+       DUMPCOREAV(HDMI_CORE_AV_N_SVAL1);
+       DUMPCOREAV(HDMI_CORE_AV_N_SVAL2);
+       DUMPCOREAV(HDMI_CORE_AV_N_SVAL3);
+       DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL1);
+       DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL2);
+       DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL3);
+       DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL1);
+       DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL2);
+       DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL3);
+       DUMPCOREAV(HDMI_CORE_AV_AUD_MODE);
+       DUMPCOREAV(HDMI_CORE_AV_SPDIF_CTRL);
+       DUMPCOREAV(HDMI_CORE_AV_HW_SPDIF_FS);
+       DUMPCOREAV(HDMI_CORE_AV_SWAP_I2S);
+       DUMPCOREAV(HDMI_CORE_AV_SPDIF_ERTH);
+       DUMPCOREAV(HDMI_CORE_AV_I2S_IN_MAP);
+       DUMPCOREAV(HDMI_CORE_AV_I2S_IN_CTRL);
+       DUMPCOREAV(HDMI_CORE_AV_I2S_CHST0);
+       DUMPCOREAV(HDMI_CORE_AV_I2S_CHST1);
+       DUMPCOREAV(HDMI_CORE_AV_I2S_CHST2);
+       DUMPCOREAV(HDMI_CORE_AV_I2S_CHST4);
+       DUMPCOREAV(HDMI_CORE_AV_I2S_CHST5);
+       DUMPCOREAV(HDMI_CORE_AV_ASRC);
+       DUMPCOREAV(HDMI_CORE_AV_I2S_IN_LEN);
+       DUMPCOREAV(HDMI_CORE_AV_HDMI_CTRL);
+       DUMPCOREAV(HDMI_CORE_AV_AUDO_TXSTAT);
+       DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_1);
+       DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_2);
+       DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_3);
+       DUMPCOREAV(HDMI_CORE_AV_TEST_TXCTRL);
+       DUMPCOREAV(HDMI_CORE_AV_DPD);
+       DUMPCOREAV(HDMI_CORE_AV_PB_CTRL1);
+       DUMPCOREAV(HDMI_CORE_AV_PB_CTRL2);
+       DUMPCOREAV(HDMI_CORE_AV_AVI_TYPE);
+       DUMPCOREAV(HDMI_CORE_AV_AVI_VERS);
+       DUMPCOREAV(HDMI_CORE_AV_AVI_LEN);
+       DUMPCOREAV(HDMI_CORE_AV_AVI_CHSUM);
 
        for (i = 0; i < HDMI_CORE_AV_AVI_DBYTE_NELEMS; i++)
-               DUMPCOREAV(i, HDMI_CORE_AV_AVI_DBYTE);
+               DUMPCOREAV2(i, HDMI_CORE_AV_AVI_DBYTE);
+
+       DUMPCOREAV(HDMI_CORE_AV_SPD_TYPE);
+       DUMPCOREAV(HDMI_CORE_AV_SPD_VERS);
+       DUMPCOREAV(HDMI_CORE_AV_SPD_LEN);
+       DUMPCOREAV(HDMI_CORE_AV_SPD_CHSUM);
 
        for (i = 0; i < HDMI_CORE_AV_SPD_DBYTE_NELEMS; i++)
-               DUMPCOREAV(i, HDMI_CORE_AV_SPD_DBYTE);
+               DUMPCOREAV2(i, HDMI_CORE_AV_SPD_DBYTE);
+
+       DUMPCOREAV(HDMI_CORE_AV_AUDIO_TYPE);
+       DUMPCOREAV(HDMI_CORE_AV_AUDIO_VERS);
+       DUMPCOREAV(HDMI_CORE_AV_AUDIO_LEN);
+       DUMPCOREAV(HDMI_CORE_AV_AUDIO_CHSUM);
 
        for (i = 0; i < HDMI_CORE_AV_AUD_DBYTE_NELEMS; i++)
-               DUMPCOREAV(i, HDMI_CORE_AV_AUD_DBYTE);
+               DUMPCOREAV2(i, HDMI_CORE_AV_AUD_DBYTE);
+
+       DUMPCOREAV(HDMI_CORE_AV_MPEG_TYPE);
+       DUMPCOREAV(HDMI_CORE_AV_MPEG_VERS);
+       DUMPCOREAV(HDMI_CORE_AV_MPEG_LEN);
+       DUMPCOREAV(HDMI_CORE_AV_MPEG_CHSUM);
 
        for (i = 0; i < HDMI_CORE_AV_MPEG_DBYTE_NELEMS; i++)
-               DUMPCOREAV(i, HDMI_CORE_AV_MPEG_DBYTE);
+               DUMPCOREAV2(i, HDMI_CORE_AV_MPEG_DBYTE);
 
        for (i = 0; i < HDMI_CORE_AV_GEN_DBYTE_NELEMS; i++)
-               DUMPCOREAV(i, HDMI_CORE_AV_GEN_DBYTE);
+               DUMPCOREAV2(i, HDMI_CORE_AV_GEN_DBYTE);
+
+       DUMPCOREAV(HDMI_CORE_AV_CP_BYTE1);
 
        for (i = 0; i < HDMI_CORE_AV_GEN2_DBYTE_NELEMS; i++)
-               DUMPCOREAV(i, HDMI_CORE_AV_GEN2_DBYTE);
-
-       DUMPCORE(HDMI_CORE_AV_ACR_CTRL);
-       DUMPCORE(HDMI_CORE_AV_FREQ_SVAL);
-       DUMPCORE(HDMI_CORE_AV_N_SVAL1);
-       DUMPCORE(HDMI_CORE_AV_N_SVAL2);
-       DUMPCORE(HDMI_CORE_AV_N_SVAL3);
-       DUMPCORE(HDMI_CORE_AV_CTS_SVAL1);
-       DUMPCORE(HDMI_CORE_AV_CTS_SVAL2);
-       DUMPCORE(HDMI_CORE_AV_CTS_SVAL3);
-       DUMPCORE(HDMI_CORE_AV_CTS_HVAL1);
-       DUMPCORE(HDMI_CORE_AV_CTS_HVAL2);
-       DUMPCORE(HDMI_CORE_AV_CTS_HVAL3);
-       DUMPCORE(HDMI_CORE_AV_AUD_MODE);
-       DUMPCORE(HDMI_CORE_AV_SPDIF_CTRL);
-       DUMPCORE(HDMI_CORE_AV_HW_SPDIF_FS);
-       DUMPCORE(HDMI_CORE_AV_SWAP_I2S);
-       DUMPCORE(HDMI_CORE_AV_SPDIF_ERTH);
-       DUMPCORE(HDMI_CORE_AV_I2S_IN_MAP);
-       DUMPCORE(HDMI_CORE_AV_I2S_IN_CTRL);
-       DUMPCORE(HDMI_CORE_AV_I2S_CHST0);
-       DUMPCORE(HDMI_CORE_AV_I2S_CHST1);
-       DUMPCORE(HDMI_CORE_AV_I2S_CHST2);
-       DUMPCORE(HDMI_CORE_AV_I2S_CHST4);
-       DUMPCORE(HDMI_CORE_AV_I2S_CHST5);
-       DUMPCORE(HDMI_CORE_AV_ASRC);
-       DUMPCORE(HDMI_CORE_AV_I2S_IN_LEN);
-       DUMPCORE(HDMI_CORE_AV_HDMI_CTRL);
-       DUMPCORE(HDMI_CORE_AV_AUDO_TXSTAT);
-       DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_1);
-       DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_2);
-       DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_3);
-       DUMPCORE(HDMI_CORE_AV_TEST_TXCTRL);
-       DUMPCORE(HDMI_CORE_AV_DPD);
-       DUMPCORE(HDMI_CORE_AV_PB_CTRL1);
-       DUMPCORE(HDMI_CORE_AV_PB_CTRL2);
-       DUMPCORE(HDMI_CORE_AV_AVI_TYPE);
-       DUMPCORE(HDMI_CORE_AV_AVI_VERS);
-       DUMPCORE(HDMI_CORE_AV_AVI_LEN);
-       DUMPCORE(HDMI_CORE_AV_AVI_CHSUM);
-       DUMPCORE(HDMI_CORE_AV_SPD_TYPE);
-       DUMPCORE(HDMI_CORE_AV_SPD_VERS);
-       DUMPCORE(HDMI_CORE_AV_SPD_LEN);
-       DUMPCORE(HDMI_CORE_AV_SPD_CHSUM);
-       DUMPCORE(HDMI_CORE_AV_AUDIO_TYPE);
-       DUMPCORE(HDMI_CORE_AV_AUDIO_VERS);
-       DUMPCORE(HDMI_CORE_AV_AUDIO_LEN);
-       DUMPCORE(HDMI_CORE_AV_AUDIO_CHSUM);
-       DUMPCORE(HDMI_CORE_AV_MPEG_TYPE);
-       DUMPCORE(HDMI_CORE_AV_MPEG_VERS);
-       DUMPCORE(HDMI_CORE_AV_MPEG_LEN);
-       DUMPCORE(HDMI_CORE_AV_MPEG_CHSUM);
-       DUMPCORE(HDMI_CORE_AV_CP_BYTE1);
-       DUMPCORE(HDMI_CORE_AV_CEC_ADDR_ID);
+               DUMPCOREAV2(i, HDMI_CORE_AV_GEN2_DBYTE);
+
+       DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID);
 }
 
 void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
@@ -1016,9 +1025,8 @@ void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
        DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
 }
 
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data,
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+static void ti_hdmi_4xxx_wp_audio_config_format(struct hdmi_ip_data *ip_data,
                                        struct hdmi_audio_format *aud_fmt)
 {
        u32 r;
@@ -1037,7 +1045,7 @@ void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data,
        hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r);
 }
 
-void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
+static void ti_hdmi_4xxx_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
                                        struct hdmi_audio_dma *aud_dma)
 {
        u32 r;
@@ -1055,7 +1063,7 @@ void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
        hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r);
 }
 
-void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
+static void ti_hdmi_4xxx_core_audio_config(struct hdmi_ip_data *ip_data,
                                        struct hdmi_core_audio_config *cfg)
 {
        u32 r;
@@ -1106,27 +1114,33 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
        REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL,
                                                cfg->fs_override, 1, 1);
 
-       /* I2S parameters */
-       REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_CHST4,
-                                               cfg->freq_sample, 3, 0);
-
+       /*
+        * Set IEC-60958-3 channel status word. It is passed to the IP
+        * just as it is received. The user of the driver is responsible
+        * for its contents.
+        */
+       hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST0,
+                      cfg->iec60958_cfg->status[0]);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST1,
+                      cfg->iec60958_cfg->status[1]);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST2,
+                      cfg->iec60958_cfg->status[2]);
+       /* yes, this is correct: status[3] goes to CHST4 register */
+       hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST4,
+                      cfg->iec60958_cfg->status[3]);
+       /* yes, this is correct: status[4] goes to CHST5 register */
+       hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5,
+                      cfg->iec60958_cfg->status[4]);
+
+       /* set I2S parameters */
        r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL);
-       r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7);
        r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
-       r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5);
        r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
-       r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3);
        r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
        r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
        r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
        hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r);
 
-       r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_CHST5);
-       r = FLD_MOD(r, cfg->freq_sample, 7, 4);
-       r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1);
-       r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0);
-       hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5, r);
-
        REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN,
                        cfg->i2s_cfg.in_length_bits, 3, 0);
 
@@ -1138,12 +1152,19 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
        r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
        r = FLD_MOD(r, cfg->en_spdif, 1, 1);
        hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r);
+
+       /* Audio channel mappings */
+       /* TODO: Make channel mapping dynamic. For now, map channels
+        * in the ALSA order: FL/FR/RL/RR/C/LFE/SL/SR. Remapping is needed as
+        * HDMI speaker order is different. See CEA-861 Section 6.6.2.
+        */
+       hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_MAP, 0x78);
+       REG_FLD_MOD(av_base, HDMI_CORE_AV_SWAP_I2S, 1, 5, 5);
 }
 
-void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
-               struct hdmi_core_infoframe_audio *info_aud)
+static void ti_hdmi_4xxx_core_audio_infoframe_cfg(struct hdmi_ip_data *ip_data,
+               struct snd_cea_861_aud_if *info_aud)
 {
-       u8 val;
        u8 sum = 0, checksum = 0;
        void __iomem *av_base = hdmi_av_base(ip_data);
 
@@ -1157,24 +1178,23 @@ void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
        hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a);
        sum += 0x84 + 0x001 + 0x00a;
 
-       val = (info_aud->db1_coding_type << 4)
-                       | (info_aud->db1_channel_count - 1);
-       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0), val);
-       sum += val;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0),
+                      info_aud->db1_ct_cc);
+       sum += info_aud->db1_ct_cc;
 
-       val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size;
-       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1), val);
-       sum += val;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1),
+                      info_aud->db2_sf_ss);
+       sum += info_aud->db2_sf_ss;
 
-       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), 0x00);
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud->db3);
+       sum += info_aud->db3;
 
-       val = info_aud->db4_channel_alloc;
-       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), val);
-       sum += val;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud->db4_ca);
+       sum += info_aud->db4_ca;
 
-       val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3);
-       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4), val);
-       sum += val;
+       hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4),
+                      info_aud->db5_dminh_lsv);
+       sum += info_aud->db5_dminh_lsv;
 
        hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
        hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
@@ -1192,70 +1212,212 @@ void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
         */
 }
 
-int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
-                               u32 sample_freq, u32 *n, u32 *cts)
+int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data,
+               struct omap_dss_audio *audio)
 {
-       u32 r;
-       u32 deep_color = 0;
-       u32 pclk = ip_data->cfg.timings.pixel_clock;
-
-       if (n == NULL || cts == NULL)
+       struct hdmi_audio_format audio_format;
+       struct hdmi_audio_dma audio_dma;
+       struct hdmi_core_audio_config core;
+       int err, n, cts, channel_count;
+       unsigned int fs_nr;
+       bool word_length_16b = false;
+
+       if (!audio || !audio->iec || !audio->cea || !ip_data)
                return -EINVAL;
+
+       core.iec60958_cfg = audio->iec;
        /*
-        * Obtain current deep color configuration. This needed
-        * to calculate the TMDS clock based on the pixel clock.
+        * In the IEC-60958 status word, check if the audio sample word length
+        * is 16-bit as several optimizations can be performed in such case.
         */
-       r = REG_GET(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, 1, 0);
-       switch (r) {
-       case 1: /* No deep color selected */
-               deep_color = 100;
+       if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24))
+               if (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16)
+                       word_length_16b = true;
+
+       /* I2S configuration. See Phillips' specification */
+       if (word_length_16b)
+               core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+       else
+               core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+       /*
+        * The I2S input word length is twice the lenght given in the IEC-60958
+        * status word. If the word size is greater than
+        * 20 bits, increment by one.
+        */
+       core.i2s_cfg.in_length_bits = audio->iec->status[4]
+               & IEC958_AES4_CON_WORDLEN;
+       if (audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24)
+               core.i2s_cfg.in_length_bits++;
+       core.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
+       core.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
+       core.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
+       core.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
+
+       /* convert sample frequency to a number */
+       switch (audio->iec->status[3] & IEC958_AES3_CON_FS) {
+       case IEC958_AES3_CON_FS_32000:
+               fs_nr = 32000;
+               break;
+       case IEC958_AES3_CON_FS_44100:
+               fs_nr = 44100;
+               break;
+       case IEC958_AES3_CON_FS_48000:
+               fs_nr = 48000;
                break;
-       case 2: /* 10-bit deep color selected */
-               deep_color = 125;
+       case IEC958_AES3_CON_FS_88200:
+               fs_nr = 88200;
                break;
-       case 3: /* 12-bit deep color selected */
-               deep_color = 150;
+       case IEC958_AES3_CON_FS_96000:
+               fs_nr = 96000;
+               break;
+       case IEC958_AES3_CON_FS_176400:
+               fs_nr = 176400;
+               break;
+       case IEC958_AES3_CON_FS_192000:
+               fs_nr = 192000;
                break;
        default:
                return -EINVAL;
        }
 
-       switch (sample_freq) {
-       case 32000:
-               if ((deep_color == 125) && ((pclk == 54054)
-                               || (pclk == 74250)))
-                       *n = 8192;
-               else
-                       *n = 4096;
+       err = hdmi_compute_acr(fs_nr, &n, &cts);
+
+       /* Audio clock regeneration settings */
+       core.n = n;
+       core.cts = cts;
+       if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
+               core.aud_par_busclk = 0;
+               core.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
+               core.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK);
+       } else {
+               core.aud_par_busclk = (((128 * 31) - 1) << 8);
+               core.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
+               core.use_mclk = true;
+       }
+
+       if (core.use_mclk)
+               core.mclk_mode = HDMI_AUDIO_MCLK_128FS;
+
+       /* Audio channels settings */
+       channel_count = (audio->cea->db1_ct_cc &
+                        CEA861_AUDIO_INFOFRAME_DB1CC) + 1;
+
+       switch (channel_count) {
+       case 2:
+               audio_format.active_chnnls_msk = 0x03;
+               break;
+       case 3:
+               audio_format.active_chnnls_msk = 0x07;
+               break;
+       case 4:
+               audio_format.active_chnnls_msk = 0x0f;
+               break;
+       case 5:
+               audio_format.active_chnnls_msk = 0x1f;
                break;
-       case 44100:
-               *n = 6272;
+       case 6:
+               audio_format.active_chnnls_msk = 0x3f;
                break;
-       case 48000:
-               if ((deep_color == 125) && ((pclk == 54054)
-                               || (pclk == 74250)))
-                       *n = 8192;
-               else
-                       *n = 6144;
+       case 7:
+               audio_format.active_chnnls_msk = 0x7f;
+               break;
+       case 8:
+               audio_format.active_chnnls_msk = 0xff;
                break;
        default:
-               *n = 0;
                return -EINVAL;
        }
 
-       /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
-       *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
+       /*
+        * the HDMI IP needs to enable four stereo channels when transmitting
+        * more than 2 audio channels
+        */
+       if (channel_count == 2) {
+               audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
+               core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
+               core.layout = HDMI_AUDIO_LAYOUT_2CH;
+       } else {
+               audio_format.stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS;
+               core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN |
+                               HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN |
+                               HDMI_AUDIO_I2S_SD3_EN;
+               core.layout = HDMI_AUDIO_LAYOUT_8CH;
+       }
+
+       core.en_spdif = false;
+       /* use sample frequency from channel status word */
+       core.fs_override = true;
+       /* enable ACR packets */
+       core.en_acr_pkt = true;
+       /* disable direct streaming digital audio */
+       core.en_dsd_audio = false;
+       /* use parallel audio interface */
+       core.en_parallel_aud_input = true;
+
+       /* DMA settings */
+       if (word_length_16b)
+               audio_dma.transfer_size = 0x10;
+       else
+               audio_dma.transfer_size = 0x20;
+       audio_dma.block_size = 0xC0;
+       audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
+       audio_dma.fifo_threshold = 0x20; /* in number of samples */
+
+       /* audio FIFO format settings */
+       if (word_length_16b) {
+               audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
+               audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
+               audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+       } else {
+               audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
+               audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
+               audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+       }
+       audio_format.type = HDMI_AUDIO_TYPE_LPCM;
+       audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+       /* disable start/stop signals of IEC 60958 blocks */
+       audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
+
+       /* configure DMA and audio FIFO format*/
+       ti_hdmi_4xxx_wp_audio_config_dma(ip_data, &audio_dma);
+       ti_hdmi_4xxx_wp_audio_config_format(ip_data, &audio_format);
+
+       /* configure the core*/
+       ti_hdmi_4xxx_core_audio_config(ip_data, &core);
+
+       /* configure CEA 861 audio infoframe*/
+       ti_hdmi_4xxx_core_audio_infoframe_cfg(ip_data, audio->cea);
 
        return 0;
 }
 
-void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable)
+int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data)
+{
+       REG_FLD_MOD(hdmi_wp_base(ip_data),
+                   HDMI_WP_AUDIO_CTRL, true, 31, 31);
+       return 0;
+}
+
+void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data)
+{
+       REG_FLD_MOD(hdmi_wp_base(ip_data),
+                   HDMI_WP_AUDIO_CTRL, false, 31, 31);
+}
+
+int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data)
 {
        REG_FLD_MOD(hdmi_av_base(ip_data),
-                               HDMI_CORE_AV_AUD_MODE, enable, 0, 0);
+                   HDMI_CORE_AV_AUD_MODE, true, 0, 0);
        REG_FLD_MOD(hdmi_wp_base(ip_data),
-                               HDMI_WP_AUDIO_CTRL, enable, 31, 31);
+                   HDMI_WP_AUDIO_CTRL, true, 30, 30);
+       return 0;
+}
+
+void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data)
+{
+       REG_FLD_MOD(hdmi_av_base(ip_data),
+                   HDMI_CORE_AV_AUD_MODE, false, 0, 0);
        REG_FLD_MOD(hdmi_wp_base(ip_data),
-                               HDMI_WP_AUDIO_CTRL, enable, 30, 30);
+                   HDMI_WP_AUDIO_CTRL, false, 30, 30);
 }
 #endif
index a14d1a0..8366ae1 100644 (file)
 #include <linux/string.h>
 #include <video/omapdss.h>
 #include "ti_hdmi.h"
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-#endif
 
 /* HDMI Wrapper */
 
 #define HDMI_CORE_SYS_SRST                     0x14
 #define HDMI_CORE_CTRL1                                0x20
 #define HDMI_CORE_SYS_SYS_STAT                 0x24
+#define HDMI_CORE_SYS_DE_DLY                   0xC8
+#define HDMI_CORE_SYS_DE_CTRL                  0xCC
+#define HDMI_CORE_SYS_DE_TOP                   0xD0
+#define HDMI_CORE_SYS_DE_CNTL                  0xD8
+#define HDMI_CORE_SYS_DE_CNTH                  0xDC
+#define HDMI_CORE_SYS_DE_LINL                  0xE0
+#define HDMI_CORE_SYS_DE_LINH_1                        0xE4
 #define HDMI_CORE_SYS_VID_ACEN                 0x124
 #define HDMI_CORE_SYS_VID_MODE                 0x128
 #define HDMI_CORE_SYS_INTR_STATE               0x1C0
 #define HDMI_CORE_SYS_INTR4                    0x1D0
 #define HDMI_CORE_SYS_UMASK1                   0x1D4
 #define HDMI_CORE_SYS_TMDS_CTRL                        0x208
-#define HDMI_CORE_SYS_DE_DLY                   0xC8
-#define HDMI_CORE_SYS_DE_CTRL                  0xCC
-#define HDMI_CORE_SYS_DE_TOP                   0xD0
-#define HDMI_CORE_SYS_DE_CNTL                  0xD8
-#define HDMI_CORE_SYS_DE_CNTH                  0xDC
-#define HDMI_CORE_SYS_DE_LINL                  0xE0
-#define HDMI_CORE_SYS_DE_LINH_1                        0xE4
+
 #define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC        0x1
 #define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC        0x1
-#define HDMI_CORE_CTRL1_BSEL_24BITBUS          0x1
+#define HDMI_CORE_CTRL1_BSEL_24BITBUS  0x1
 #define HDMI_CORE_CTRL1_EDGE_RISINGEDGE        0x1
 
 /* HDMI DDC E-DID */
-#define HDMI_CORE_DDC_CMD                      0x3CC
-#define HDMI_CORE_DDC_STATUS                   0x3C8
 #define HDMI_CORE_DDC_ADDR                     0x3B4
+#define HDMI_CORE_DDC_SEGM                     0x3B8
 #define HDMI_CORE_DDC_OFFSET                   0x3BC
 #define HDMI_CORE_DDC_COUNT1                   0x3C0
 #define HDMI_CORE_DDC_COUNT2                   0x3C4
+#define HDMI_CORE_DDC_STATUS                   0x3C8
+#define HDMI_CORE_DDC_CMD                      0x3CC
 #define HDMI_CORE_DDC_DATA                     0x3D0
-#define HDMI_CORE_DDC_SEGM                     0x3B8
 
 /* HDMI IP Core Audio Video */
 
-#define HDMI_CORE_AV_HDMI_CTRL                 0xBC
-#define HDMI_CORE_AV_DPD                       0xF4
-#define HDMI_CORE_AV_PB_CTRL1                  0xF8
-#define HDMI_CORE_AV_PB_CTRL2                  0xFC
-#define HDMI_CORE_AV_AVI_TYPE                  0x100
-#define HDMI_CORE_AV_AVI_VERS                  0x104
-#define HDMI_CORE_AV_AVI_LEN                   0x108
-#define HDMI_CORE_AV_AVI_CHSUM                 0x10C
-#define HDMI_CORE_AV_AVI_DBYTE(n)              (n * 4 + 0x110)
-#define HDMI_CORE_AV_AVI_DBYTE_NELEMS          15
-#define HDMI_CORE_AV_SPD_DBYTE(n)              (n * 4 + 0x190)
-#define HDMI_CORE_AV_SPD_DBYTE_NELEMS          27
-#define HDMI_CORE_AV_AUD_DBYTE(n)              (n * 4 + 0x210)
-#define HDMI_CORE_AV_AUD_DBYTE_NELEMS          10
-#define HDMI_CORE_AV_MPEG_DBYTE(n)             (n * 4 + 0x290)
-#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS         27
-#define HDMI_CORE_AV_GEN_DBYTE(n)              (n * 4 + 0x300)
-#define HDMI_CORE_AV_GEN_DBYTE_NELEMS          31
-#define HDMI_CORE_AV_GEN2_DBYTE(n)             (n * 4 + 0x380)
-#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS         31
 #define HDMI_CORE_AV_ACR_CTRL                  0x4
 #define HDMI_CORE_AV_FREQ_SVAL                 0x8
 #define HDMI_CORE_AV_N_SVAL1                   0xC
 #define HDMI_CORE_AV_AVI_VERS                  0x104
 #define HDMI_CORE_AV_AVI_LEN                   0x108
 #define HDMI_CORE_AV_AVI_CHSUM                 0x10C
+#define HDMI_CORE_AV_AVI_DBYTE(n)              (n * 4 + 0x110)
 #define HDMI_CORE_AV_SPD_TYPE                  0x180
 #define HDMI_CORE_AV_SPD_VERS                  0x184
 #define HDMI_CORE_AV_SPD_LEN                   0x188
 #define HDMI_CORE_AV_SPD_CHSUM                 0x18C
+#define HDMI_CORE_AV_SPD_DBYTE(n)              (n * 4 + 0x190)
 #define HDMI_CORE_AV_AUDIO_TYPE                        0x200
 #define HDMI_CORE_AV_AUDIO_VERS                        0x204
 #define HDMI_CORE_AV_AUDIO_LEN                 0x208
 #define HDMI_CORE_AV_AUDIO_CHSUM               0x20C
+#define HDMI_CORE_AV_AUD_DBYTE(n)              (n * 4 + 0x210)
 #define HDMI_CORE_AV_MPEG_TYPE                 0x280
 #define HDMI_CORE_AV_MPEG_VERS                 0x284
 #define HDMI_CORE_AV_MPEG_LEN                  0x288
 #define HDMI_CORE_AV_MPEG_CHSUM                        0x28C
+#define HDMI_CORE_AV_MPEG_DBYTE(n)             (n * 4 + 0x290)
+#define HDMI_CORE_AV_GEN_DBYTE(n)              (n * 4 + 0x300)
 #define HDMI_CORE_AV_CP_BYTE1                  0x37C
+#define HDMI_CORE_AV_GEN2_DBYTE(n)             (n * 4 + 0x380)
 #define HDMI_CORE_AV_CEC_ADDR_ID               0x3FC
+
 #define HDMI_CORE_AV_SPD_DBYTE_ELSIZE          0x4
 #define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE         0x4
 #define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE         0x4
 #define HDMI_CORE_AV_GEN_DBYTE_ELSIZE          0x4
 
+#define HDMI_CORE_AV_AVI_DBYTE_NELEMS          15
+#define HDMI_CORE_AV_SPD_DBYTE_NELEMS          27
+#define HDMI_CORE_AV_AUD_DBYTE_NELEMS          10
+#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS         27
+#define HDMI_CORE_AV_GEN_DBYTE_NELEMS          31
+#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS         31
+
 /* PLL */
 
 #define PLLCTRL_PLL_CONTROL                    0x0
@@ -284,35 +274,6 @@ enum hdmi_core_infoframe {
        HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
        HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
        HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
-       HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0,
-       HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1,
-       HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2,
-       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3,
-       HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4,
-       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5,
-       HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6,
-       HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7,
-       HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8,
-       HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9,
-       HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10,
-       HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11,
-       HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12,
-       HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13,
-       HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14,
-       HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0,
-       HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1,
-       HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2,
-       HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3,
-       HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4,
-       HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5,
-       HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6,
-       HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7,
-       HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0,
-       HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1,
-       HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2,
-       HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3,
-       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0,
-       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1
 };
 
 enum hdmi_packing_mode {
@@ -322,17 +283,6 @@ enum hdmi_packing_mode {
        HDMI_PACK_ALREADYPACKED = 7
 };
 
-enum hdmi_core_audio_sample_freq {
-       HDMI_AUDIO_FS_32000 = 0x3,
-       HDMI_AUDIO_FS_44100 = 0x0,
-       HDMI_AUDIO_FS_48000 = 0x2,
-       HDMI_AUDIO_FS_88200 = 0x8,
-       HDMI_AUDIO_FS_96000 = 0xA,
-       HDMI_AUDIO_FS_176400 = 0xC,
-       HDMI_AUDIO_FS_192000 = 0xE,
-       HDMI_AUDIO_FS_NOT_INDICATED = 0x1
-};
-
 enum hdmi_core_audio_layout {
        HDMI_AUDIO_LAYOUT_2CH = 0,
        HDMI_AUDIO_LAYOUT_8CH = 1
@@ -387,37 +337,12 @@ enum hdmi_audio_blk_strt_end_sig {
 };
 
 enum hdmi_audio_i2s_config {
-       HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0,
-       HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1,
        HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
        HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
-       HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0,
-       HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1,
-       HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0,
-       HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1,
-       HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6,
-       HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2,
-       HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4,
-       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5,
-       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1,
-       HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6,
-       HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2,
-       HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4,
-       HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5,
        HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
        HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
        HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
        HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9,
-       HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11,
        HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
        HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
        HDMI_AUDIO_I2S_SD0_EN = 1,
@@ -446,20 +371,6 @@ struct hdmi_core_video_config {
        enum hdmi_core_tclkselclkmult   tclk_sel_clkmult;
 };
 
-/*
- * Refer to section 8.2 in HDMI 1.3 specification for
- * details about infoframe databytes
- */
-struct hdmi_core_infoframe_audio {
-       u8 db1_coding_type;
-       u8 db1_channel_count;
-       u8 db2_sample_freq;
-       u8 db2_sample_size;
-       u8 db4_channel_alloc;
-       bool db5_downmix_inh;
-       u8 db5_lsv;     /* Level shift values for downmix */
-};
-
 struct hdmi_core_packet_enable_repeat {
        u32     audio_pkt;
        u32     audio_pkt_repeat;
@@ -496,15 +407,10 @@ struct hdmi_audio_dma {
 };
 
 struct hdmi_core_audio_i2s_config {
-       u8 word_max_length;
-       u8 word_length;
        u8 in_length_bits;
        u8 justification;
-       u8 en_high_bitrate_aud;
        u8 sck_edge_mode;
-       u8 cbit_order;
        u8 vbit;
-       u8 ws_polarity;
        u8 direction;
        u8 shift;
        u8 active_sds;
@@ -512,7 +418,7 @@ struct hdmi_core_audio_i2s_config {
 
 struct hdmi_core_audio_config {
        struct hdmi_core_audio_i2s_config       i2s_cfg;
-       enum hdmi_core_audio_sample_freq        freq_sample;
+       struct snd_aes_iec958                   *iec60958_cfg;
        bool                                    fs_override;
        u32                                     n;
        u32                                     cts;
@@ -527,17 +433,4 @@ struct hdmi_core_audio_config {
        bool                                    en_spdif;
 };
 
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data,
-                               u32 sample_freq, u32 *n, u32 *cts);
-void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
-               struct hdmi_core_infoframe_audio *info_aud);
-void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
-                                       struct hdmi_core_audio_config *cfg);
-void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
-                                       struct hdmi_audio_dma *aud_dma);
-void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data,
-                                       struct hdmi_audio_format *aud_fmt);
-#endif
 #endif
index 9c3daf7..2b89739 100644 (file)
@@ -415,6 +415,7 @@ static const struct venc_config *venc_timings_to_config(
                return &venc_config_ntsc_trm;
 
        BUG();
+       return NULL;
 }
 
 static int venc_power_on(struct omap_dss_device *dssdev)
@@ -440,10 +441,11 @@ static int venc_power_on(struct omap_dss_device *dssdev)
 
        venc_write_reg(VENC_OUTPUT_CONTROL, l);
 
-       dispc_set_digit_size(dssdev->panel.timings.x_res,
-                       dssdev->panel.timings.y_res/2);
+       dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
 
-       regulator_enable(venc.vdda_dac_reg);
+       r = regulator_enable(venc.vdda_dac_reg);
+       if (r)
+               goto err;
 
        if (dssdev->platform_enable)
                dssdev->platform_enable(dssdev);
@@ -485,16 +487,68 @@ unsigned long venc_get_pixel_clock(void)
        return 13500000;
 }
 
+static ssize_t display_output_type_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       const char *ret;
+
+       switch (dssdev->phy.venc.type) {
+       case OMAP_DSS_VENC_TYPE_COMPOSITE:
+               ret = "composite";
+               break;
+       case OMAP_DSS_VENC_TYPE_SVIDEO:
+               ret = "svideo";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", ret);
+}
+
+static ssize_t display_output_type_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       enum omap_dss_venc_type new_type;
+
+       if (sysfs_streq("composite", buf))
+               new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
+       else if (sysfs_streq("svideo", buf))
+               new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
+       else
+               return -EINVAL;
+
+       mutex_lock(&venc.venc_lock);
+
+       if (dssdev->phy.venc.type != new_type) {
+               dssdev->phy.venc.type = new_type;
+               if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+                       venc_power_off(dssdev);
+                       venc_power_on(dssdev);
+               }
+       }
+
+       mutex_unlock(&venc.venc_lock);
+
+       return size;
+}
+
+static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
+               display_output_type_show, display_output_type_store);
+
 /* driver */
 static int venc_panel_probe(struct omap_dss_device *dssdev)
 {
        dssdev->panel.timings = omap_dss_pal_timings;
 
-       return 0;
+       return device_create_file(&dssdev->dev, &dev_attr_output_type);
 }
 
 static void venc_panel_remove(struct omap_dss_device *dssdev)
 {
+       device_remove_file(&dssdev->dev, &dev_attr_output_type);
 }
 
 static int venc_panel_enable(struct omap_dss_device *dssdev)
@@ -577,12 +631,6 @@ static int venc_panel_resume(struct omap_dss_device *dssdev)
        return venc_panel_enable(dssdev);
 }
 
-static void venc_get_timings(struct omap_dss_device *dssdev,
-                       struct omap_video_timings *timings)
-{
-       *timings = dssdev->panel.timings;
-}
-
 static void venc_set_timings(struct omap_dss_device *dssdev,
                        struct omap_video_timings *timings)
 {
@@ -597,6 +645,8 @@ static void venc_set_timings(struct omap_dss_device *dssdev,
                /* turn the venc off and on to get new timings to use */
                venc_panel_disable(dssdev);
                venc_panel_enable(dssdev);
+       } else {
+               dss_mgr_set_timings(dssdev->manager, timings);
        }
 }
 
@@ -661,7 +711,6 @@ static struct omap_dss_driver venc_driver = {
        .get_resolution = omapdss_default_get_resolution,
        .get_recommended_bpp = omapdss_default_get_recommended_bpp,
 
-       .get_timings    = venc_get_timings,
        .set_timings    = venc_set_timings,
        .check_timings  = venc_check_timings,
 
@@ -675,7 +724,7 @@ static struct omap_dss_driver venc_driver = {
 };
 /* driver end */
 
-int venc_init_display(struct omap_dss_device *dssdev)
+static int __init venc_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("init_display\n");
 
@@ -695,7 +744,7 @@ int venc_init_display(struct omap_dss_device *dssdev)
        return 0;
 }
 
-void venc_dump_regs(struct seq_file *s)
+static void venc_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
 
@@ -779,8 +828,32 @@ static void venc_put_clocks(void)
                clk_put(venc.tv_dac_clk);
 }
 
+static void __init venc_probe_pdata(struct platform_device *pdev)
+{
+       struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+       int r, i;
+
+       for (i = 0; i < pdata->num_devices; ++i) {
+               struct omap_dss_device *dssdev = pdata->devices[i];
+
+               if (dssdev->type != OMAP_DISPLAY_TYPE_VENC)
+                       continue;
+
+               r = venc_init_display(dssdev);
+               if (r) {
+                       DSSERR("device %s init failed: %d\n", dssdev->name, r);
+                       continue;
+               }
+
+               r = omap_dss_register_device(dssdev, &pdev->dev, i);
+               if (r)
+                       DSSERR("device %s register failed: %d\n",
+                                       dssdev->name, r);
+       }
+}
+
 /* VENC HW IP initialisation */
-static int omap_venchw_probe(struct platform_device *pdev)
+static int __init omap_venchw_probe(struct platform_device *pdev)
 {
        u8 rev_id;
        struct resource *venc_mem;
@@ -824,6 +897,10 @@ static int omap_venchw_probe(struct platform_device *pdev)
        if (r)
                goto err_reg_panel_driver;
 
+       dss_debugfs_create_file("venc", venc_dump_regs);
+
+       venc_probe_pdata(pdev);
+
        return 0;
 
 err_reg_panel_driver:
@@ -833,12 +910,15 @@ err_runtime_get:
        return r;
 }
 
-static int omap_venchw_remove(struct platform_device *pdev)
+static int __exit omap_venchw_remove(struct platform_device *pdev)
 {
+       omap_dss_unregister_child_devices(&pdev->dev);
+
        if (venc.vdda_dac_reg != NULL) {
                regulator_put(venc.vdda_dac_reg);
                venc.vdda_dac_reg = NULL;
        }
+
        omap_dss_unregister_driver(&venc_driver);
 
        pm_runtime_disable(&pdev->dev);
@@ -853,7 +933,6 @@ static int venc_runtime_suspend(struct device *dev)
                clk_disable(venc.tv_dac_clk);
 
        dispc_runtime_put();
-       dss_runtime_put();
 
        return 0;
 }
@@ -862,23 +941,14 @@ static int venc_runtime_resume(struct device *dev)
 {
        int r;
 
-       r = dss_runtime_get();
-       if (r < 0)
-               goto err_get_dss;
-
        r = dispc_runtime_get();
        if (r < 0)
-               goto err_get_dispc;
+               return r;
 
        if (venc.tv_dac_clk)
                clk_enable(venc.tv_dac_clk);
 
        return 0;
-
-err_get_dispc:
-       dss_runtime_put();
-err_get_dss:
-       return r;
 }
 
 static const struct dev_pm_ops venc_pm_ops = {
@@ -887,8 +957,7 @@ static const struct dev_pm_ops venc_pm_ops = {
 };
 
 static struct platform_driver omap_venchw_driver = {
-       .probe          = omap_venchw_probe,
-       .remove         = omap_venchw_remove,
+       .remove         = __exit_p(omap_venchw_remove),
        .driver         = {
                .name   = "omapdss_venc",
                .owner  = THIS_MODULE,
@@ -896,18 +965,18 @@ static struct platform_driver omap_venchw_driver = {
        },
 };
 
-int venc_init_platform_driver(void)
+int __init venc_init_platform_driver(void)
 {
        if (cpu_is_omap44xx())
                return 0;
 
-       return platform_driver_register(&omap_venchw_driver);
+       return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe);
 }
 
-void venc_uninit_platform_driver(void)
+void __exit venc_uninit_platform_driver(void)
 {
        if (cpu_is_omap44xx())
                return;
 
-       return platform_driver_unregister(&omap_venchw_driver);
+       platform_driver_unregister(&omap_venchw_driver);
 }
index 6a09ef8..c6cf372 100644 (file)
@@ -70,7 +70,7 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
 
        DBG("omapfb_setup_plane\n");
 
-       if (ofbi->num_overlays != 1) {
+       if (ofbi->num_overlays == 0) {
                r = -EINVAL;
                goto out;
        }
@@ -185,7 +185,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
 {
        struct omapfb_info *ofbi = FB2OFB(fbi);
 
-       if (ofbi->num_overlays != 1) {
+       if (ofbi->num_overlays == 0) {
                memset(pi, 0, sizeof(*pi));
        } else {
                struct omap_overlay *ovl;
@@ -225,6 +225,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
        down_write_nested(&rg->lock, rg->id);
        atomic_inc(&rg->lock_count);
 
+       if (rg->size == size && rg->type == mi->type)
+               goto out;
+
        if (atomic_read(&rg->map_count)) {
                r = -EBUSY;
                goto out;
@@ -247,12 +250,10 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
                }
        }
 
-       if (rg->size != size || rg->type != mi->type) {
-               r = omapfb_realloc_fbmem(fbi, size, mi->type);
-               if (r) {
-                       dev_err(fbdev->dev, "realloc fbmem failed\n");
-                       goto out;
-               }
+       r = omapfb_realloc_fbmem(fbi, size, mi->type);
+       if (r) {
+               dev_err(fbdev->dev, "realloc fbmem failed\n");
+               goto out;
        }
 
  out:
index b00db40..3450ea0 100644 (file)
@@ -179,6 +179,7 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
                break;
        default:
                BUG();
+               return 0;
        }
 
        offset *= vrfb->bytespp;
@@ -1502,7 +1503,7 @@ static int omapfb_parse_vram_param(const char *param, int max_entries,
 
                fbnum = simple_strtoul(p, &p, 10);
 
-               if (p == param)
+               if (p == start)
                        return -EINVAL;
 
                if (*p != ':')
@@ -2307,7 +2308,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
        return 0;
 }
 
-static int omapfb_probe(struct platform_device *pdev)
+static int __init omapfb_probe(struct platform_device *pdev)
 {
        struct omapfb2_device *fbdev = NULL;
        int r = 0;
@@ -2448,7 +2449,7 @@ err0:
        return r;
 }
 
-static int omapfb_remove(struct platform_device *pdev)
+static int __exit omapfb_remove(struct platform_device *pdev)
 {
        struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
 
@@ -2462,8 +2463,7 @@ static int omapfb_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver omapfb_driver = {
-       .probe          = omapfb_probe,
-       .remove         = omapfb_remove,
+       .remove         = __exit_p(omapfb_remove),
        .driver         = {
                .name   = "omapfb",
                .owner  = THIS_MODULE,
@@ -2474,7 +2474,7 @@ static int __init omapfb_init(void)
 {
        DBG("omapfb_init\n");
 
-       if (platform_driver_register(&omapfb_driver)) {
+       if (platform_driver_probe(&omapfb_driver, omapfb_probe)) {
                printk(KERN_ERR "failed to register omapfb driver\n");
                return -ENODEV;
        }
index c0bdc9b..30361a0 100644 (file)
@@ -166,6 +166,7 @@ static inline struct omapfb_display_data *get_display_data(
 
        /* This should never happen */
        BUG();
+       return NULL;
 }
 
 static inline void omapfb_lock(struct omapfb2_device *fbdev)
index 4e5b960..7e99022 100644 (file)
@@ -179,8 +179,10 @@ void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
                pixel_size_exp = 2;
        else if (bytespp == 2)
                pixel_size_exp = 1;
-       else
+       else {
                BUG();
+               return;
+       }
 
        vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
        vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT);
index 1d71c08..0b4ae0c 100644 (file)
@@ -316,12 +316,9 @@ pxa3xx_gcu_wait_idle(struct pxa3xx_gcu_priv *priv)
                ret = wait_event_interruptible_timeout(priv->wait_idle,
                                        !priv->shared->hw_running, HZ*4);
 
-               if (ret < 0)
+               if (ret != 0)
                        break;
 
-               if (ret > 0)
-                       continue;
-
                if (gc_readl(priv, REG_GCRBEXHR) == rbexhr &&
                    priv->shared->num_interrupts == num) {
                        QERROR("TIMEOUT");
index f310516..5f9d8e6 100644 (file)
@@ -47,7 +47,7 @@
 #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
 #undef writel
 #define writel(v, r) do { \
-       printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \
+       pr_debug("%s: %08x => %p\n", __func__, (unsigned int)v, r); \
        __raw_writel(v, r); \
 } while (0)
 #endif /* FB_S3C_DEBUG_REGWRITE */
@@ -495,7 +495,6 @@ static int s3c_fb_set_par(struct fb_info *info)
        u32 alpha = 0;
        u32 data;
        u32 pagewidth;
-       int clkdiv;
 
        dev_dbg(sfb->dev, "setting framebuffer parameters\n");
 
@@ -532,48 +531,9 @@ static int s3c_fb_set_par(struct fb_info *info)
        /* disable the window whilst we update it */
        writel(0, regs + WINCON(win_no));
 
-       /* use platform specified window as the basis for the lcd timings */
-
-       if (win_no == sfb->pdata->default_win) {
-               clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
-
-               data = sfb->pdata->vidcon0;
-               data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
-
-               if (clkdiv > 1)
-                       data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
-               else
-                       data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
-
-               /* write the timing data to the panel */
-
-               if (sfb->variant.is_2443)
-                       data |= (1 << 5);
-
-               writel(data, regs + VIDCON0);
-
+       if (!sfb->output_on)
                s3c_fb_enable(sfb, 1);
 
-               data = VIDTCON0_VBPD(var->upper_margin - 1) |
-                      VIDTCON0_VFPD(var->lower_margin - 1) |
-                      VIDTCON0_VSPW(var->vsync_len - 1);
-
-               writel(data, regs + sfb->variant.vidtcon);
-
-               data = VIDTCON1_HBPD(var->left_margin - 1) |
-                      VIDTCON1_HFPD(var->right_margin - 1) |
-                      VIDTCON1_HSPW(var->hsync_len - 1);
-
-               /* VIDTCON1 */
-               writel(data, regs + sfb->variant.vidtcon + 4);
-
-               data = VIDTCON2_LINEVAL(var->yres - 1) |
-                      VIDTCON2_HOZVAL(var->xres - 1) |
-                      VIDTCON2_LINEVAL_E(var->yres - 1) |
-                      VIDTCON2_HOZVAL_E(var->xres - 1);
-               writel(data, regs + sfb->variant.vidtcon + 8);
-       }
-
        /* write the buffer address */
 
        /* start and end registers stride is 8 */
@@ -839,6 +799,7 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
        struct s3c_fb *sfb = win->parent;
        unsigned int index = win->index;
        u32 wincon;
+       u32 output_on = sfb->output_on;
 
        dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
 
@@ -877,34 +838,18 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
 
        shadow_protect_win(win, 1);
        writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
-       shadow_protect_win(win, 0);
 
        /* Check the enabled state to see if we need to be running the
         * main LCD interface, as if there are no active windows then
         * it is highly likely that we also do not need to output
         * anything.
         */
-
-       /* We could do something like the following code, but the current
-        * system of using framebuffer events means that we cannot make
-        * the distinction between just window 0 being inactive and all
-        * the windows being down.
-        *
-        * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
-       */
-
-       /* we're stuck with this until we can do something about overriding
-        * the power control using the blanking event for a single fb.
-        */
-       if (index == sfb->pdata->default_win) {
-               shadow_protect_win(win, 1);
-               s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
-               shadow_protect_win(win, 0);
-       }
+       s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
+       shadow_protect_win(win, 0);
 
        pm_runtime_put_sync(sfb->dev);
 
-       return 0;
+       return output_on == sfb->output_on;
 }
 
 /**
@@ -1111,7 +1056,7 @@ static struct fb_ops s3c_fb_ops = {
  *
  * Calculate the pixel clock when none has been given through platform data.
  */
-static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode)
+static void s3c_fb_missing_pixclock(struct fb_videomode *mode)
 {
        u64 pixclk = 1000000000000ULL;
        u32 div;
@@ -1144,11 +1089,11 @@ static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
 
        dev_dbg(sfb->dev, "allocating memory for display\n");
 
-       real_size = windata->win_mode.xres * windata->win_mode.yres;
+       real_size = windata->xres * windata->yres;
        virt_size = windata->virtual_x * windata->virtual_y;
 
        dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
-               real_size, windata->win_mode.xres, windata->win_mode.yres,
+               real_size, windata->xres, windata->yres,
                virt_size, windata->virtual_x, windata->virtual_y);
 
        size = (real_size > virt_size) ? real_size : virt_size;
@@ -1230,7 +1175,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
                                      struct s3c_fb_win **res)
 {
        struct fb_var_screeninfo *var;
-       struct fb_videomode *initmode;
+       struct fb_videomode initmode;
        struct s3c_fb_pd_win *windata;
        struct s3c_fb_win *win;
        struct fb_info *fbinfo;
@@ -1251,11 +1196,11 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        }
 
        windata = sfb->pdata->win[win_no];
-       initmode = &windata->win_mode;
+       initmode = *sfb->pdata->vtiming;
 
        WARN_ON(windata->max_bpp == 0);
-       WARN_ON(windata->win_mode.xres == 0);
-       WARN_ON(windata->win_mode.yres == 0);
+       WARN_ON(windata->xres == 0);
+       WARN_ON(windata->yres == 0);
 
        win = fbinfo->par;
        *res = win;
@@ -1294,7 +1239,9 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        }
 
        /* setup the initial video mode from the window */
-       fb_videomode_to_var(&fbinfo->var, initmode);
+       initmode.xres = windata->xres;
+       initmode.yres = windata->yres;
+       fb_videomode_to_var(&fbinfo->var, &initmode);
 
        fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
        fbinfo->fix.accel       = FB_ACCEL_NONE;
@@ -1338,6 +1285,53 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        return 0;
 }
 
+/**
+ * s3c_fb_set_rgb_timing() - set video timing for rgb interface.
+ * @sfb: The base resources for the hardware.
+ *
+ * Set horizontal and vertical lcd rgb interface timing.
+ */
+static void s3c_fb_set_rgb_timing(struct s3c_fb *sfb)
+{
+       struct fb_videomode *vmode = sfb->pdata->vtiming;
+       void __iomem *regs = sfb->regs;
+       int clkdiv;
+       u32 data;
+
+       if (!vmode->pixclock)
+               s3c_fb_missing_pixclock(vmode);
+
+       clkdiv = s3c_fb_calc_pixclk(sfb, vmode->pixclock);
+
+       data = sfb->pdata->vidcon0;
+       data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
+
+       if (clkdiv > 1)
+               data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
+       else
+               data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
+
+       if (sfb->variant.is_2443)
+               data |= (1 << 5);
+       writel(data, regs + VIDCON0);
+
+       data = VIDTCON0_VBPD(vmode->upper_margin - 1) |
+              VIDTCON0_VFPD(vmode->lower_margin - 1) |
+              VIDTCON0_VSPW(vmode->vsync_len - 1);
+       writel(data, regs + sfb->variant.vidtcon);
+
+       data = VIDTCON1_HBPD(vmode->left_margin - 1) |
+              VIDTCON1_HFPD(vmode->right_margin - 1) |
+              VIDTCON1_HSPW(vmode->hsync_len - 1);
+       writel(data, regs + sfb->variant.vidtcon + 4);
+
+       data = VIDTCON2_LINEVAL(vmode->yres - 1) |
+              VIDTCON2_HOZVAL(vmode->xres - 1) |
+              VIDTCON2_LINEVAL_E(vmode->yres - 1) |
+              VIDTCON2_HOZVAL_E(vmode->xres - 1);
+       writel(data, regs + sfb->variant.vidtcon + 8);
+}
+
 /**
  * s3c_fb_clear_win() - clear hardware window registers.
  * @sfb: The base resources for the hardware.
@@ -1481,15 +1475,14 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
                writel(0xffffff, regs + WKEYCON1);
        }
 
+       s3c_fb_set_rgb_timing(sfb);
+
        /* we have the register setup, start allocating framebuffers */
 
        for (win = 0; win < fbdrv->variant.nr_windows; win++) {
                if (!pd->win[win])
                        continue;
 
-               if (!pd->win[win]->win_mode.pixclock)
-                       s3c_fb_missing_pixclock(&pd->win[win]->win_mode);
-
                ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
                                       &sfb->windows[win]);
                if (ret < 0) {
@@ -1564,6 +1557,8 @@ static int s3c_fb_suspend(struct device *dev)
        struct s3c_fb_win *win;
        int win_no;
 
+       pm_runtime_get_sync(sfb->dev);
+
        for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
                win = sfb->windows[win_no];
                if (!win)
@@ -1577,6 +1572,9 @@ static int s3c_fb_suspend(struct device *dev)
                clk_disable(sfb->lcd_clk);
 
        clk_disable(sfb->bus_clk);
+
+       pm_runtime_put_sync(sfb->dev);
+
        return 0;
 }
 
@@ -1589,6 +1587,8 @@ static int s3c_fb_resume(struct device *dev)
        int win_no;
        u32 reg;
 
+       pm_runtime_get_sync(sfb->dev);
+
        clk_enable(sfb->bus_clk);
 
        if (!sfb->variant.has_clksel)
@@ -1623,6 +1623,8 @@ static int s3c_fb_resume(struct device *dev)
                shadow_protect_win(win, 0);
        }
 
+       s3c_fb_set_rgb_timing(sfb);
+
        /* restore framebuffers */
        for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
                win = sfb->windows[win_no];
@@ -1633,6 +1635,8 @@ static int s3c_fb_resume(struct device *dev)
                s3c_fb_set_par(win->fbinfo);
        }
 
+       pm_runtime_put_sync(sfb->dev);
+
        return 0;
 }
 #endif
index eafb19d..930e550 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "sh_mobile_lcdcfb.h"
 
+/* HDMI Core Control Register (HTOP0) */
 #define HDMI_SYSTEM_CTRL                       0x00 /* System control */
 #define HDMI_L_R_DATA_SWAP_CTRL_RPKT           0x01 /* L/R data swap control,
                                                        bits 19..16 of 20-bit N for Audio Clock Regeneration packet */
 #define HDMI_REVISION_ID                       0xF1 /* Revision ID */
 #define HDMI_TEST_MODE                         0xFE /* Test mode */
 
+/* HDMI Control Register (HTOP1) */
+#define HDMI_HTOP1_TEST_MODE                   0x0000 /* Test mode */
+#define HDMI_HTOP1_VIDEO_INPUT                 0x0008 /* VideoInput */
+#define HDMI_HTOP1_CORE_RSTN                   0x000C /* CoreResetn */
+#define HDMI_HTOP1_PLLBW                       0x0018 /* PLLBW */
+#define HDMI_HTOP1_CLK_TO_PHY                  0x001C /* Clk to Phy */
+#define HDMI_HTOP1_VIDEO_INPUT2                        0x0020 /* VideoInput2 */
+#define HDMI_HTOP1_TISEMP0_1                   0x0024 /* tisemp0-1 */
+#define HDMI_HTOP1_TISEMP2_C                   0x0028 /* tisemp2-c */
+#define HDMI_HTOP1_TISIDRV                     0x002C /* tisidrv */
+#define HDMI_HTOP1_TISEN                       0x0034 /* tisen */
+#define HDMI_HTOP1_TISDREN                     0x0038 /* tisdren  */
+#define HDMI_HTOP1_CISRANGE                    0x003C /* cisrange  */
+#define HDMI_HTOP1_ENABLE_SELECTOR             0x0040 /* Enable Selector */
+#define HDMI_HTOP1_MACRO_RESET                 0x0044 /* Macro reset */
+#define HDMI_HTOP1_PLL_CALIBRATION             0x0048 /* PLL calibration */
+#define HDMI_HTOP1_RE_CALIBRATION              0x004C /* Re-calibration */
+#define HDMI_HTOP1_CURRENT                     0x0050 /* Current */
+#define HDMI_HTOP1_PLL_LOCK_DETECT             0x0054 /* PLL lock detect */
+#define HDMI_HTOP1_PHY_TEST_MODE               0x0058 /* PHY Test Mode */
+#define HDMI_HTOP1_CLK_SET                     0x0080 /* Clock Set */
+#define HDMI_HTOP1_DDC_FAIL_SAFE               0x0084 /* DDC fail safe */
+#define HDMI_HTOP1_PRBS                                0x0088 /* PRBS */
+#define HDMI_HTOP1_EDID_AINC_CONTROL           0x008C /* EDID ainc Control */
+#define HDMI_HTOP1_HTOP_DCL_MODE               0x00FC /* Deep Coloer Mode */
+#define HDMI_HTOP1_HTOP_DCL_FRC_COEF0          0x0100 /* Deep Color:FRC COEF0 */
+#define HDMI_HTOP1_HTOP_DCL_FRC_COEF1          0x0104 /* Deep Color:FRC COEF1 */
+#define HDMI_HTOP1_HTOP_DCL_FRC_COEF2          0x0108 /* Deep Color:FRC COEF2 */
+#define HDMI_HTOP1_HTOP_DCL_FRC_COEF3          0x010C /* Deep Color:FRC COEF3 */
+#define HDMI_HTOP1_HTOP_DCL_FRC_COEF0_C                0x0110 /* Deep Color:FRC COEF0C */
+#define HDMI_HTOP1_HTOP_DCL_FRC_COEF1_C                0x0114 /* Deep Color:FRC COEF1C */
+#define HDMI_HTOP1_HTOP_DCL_FRC_COEF2_C                0x0118 /* Deep Color:FRC COEF2C */
+#define HDMI_HTOP1_HTOP_DCL_FRC_COEF3_C                0x011C /* Deep Color:FRC COEF3C */
+#define HDMI_HTOP1_HTOP_DCL_FRC_MODE           0x0120 /* Deep Color:FRC Mode */
+#define HDMI_HTOP1_HTOP_DCL_RECT_START1                0x0124 /* Deep Color:Rect Start1 */
+#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE1         0x0128 /* Deep Color:Rect Size1 */
+#define HDMI_HTOP1_HTOP_DCL_RECT_START2                0x012C /* Deep Color:Rect Start2 */
+#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE2         0x0130 /* Deep Color:Rect Size2 */
+#define HDMI_HTOP1_HTOP_DCL_RECT_START3                0x0134 /* Deep Color:Rect Start3 */
+#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE3         0x0138 /* Deep Color:Rect Size3 */
+#define HDMI_HTOP1_HTOP_DCL_RECT_START4                0x013C /* Deep Color:Rect Start4 */
+#define HDMI_HTOP1_HTOP_DCL_RECT_SIZE4         0x0140 /* Deep Color:Rect Size4 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_1      0x0144 /* Deep Color:Fil Para Y1_1 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_2      0x0148 /* Deep Color:Fil Para Y1_2 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_1     0x014C /* Deep Color:Fil Para CB1_1 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_2     0x0150 /* Deep Color:Fil Para CB1_2 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_1     0x0154 /* Deep Color:Fil Para CR1_1 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_2     0x0158 /* Deep Color:Fil Para CR1_2 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_1      0x015C /* Deep Color:Fil Para Y2_1 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_2      0x0160 /* Deep Color:Fil Para Y2_2 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_1     0x0164 /* Deep Color:Fil Para CB2_1 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_2     0x0168 /* Deep Color:Fil Para CB2_2 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_1     0x016C /* Deep Color:Fil Para CR2_1 */
+#define HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_2     0x0170 /* Deep Color:Fil Para CR2_2 */
+#define HDMI_HTOP1_HTOP_DCL_COR_PARA_Y1                0x0174 /* Deep Color:Cor Para Y1 */
+#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CB1       0x0178 /* Deep Color:Cor Para CB1 */
+#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CR1       0x017C /* Deep Color:Cor Para CR1 */
+#define HDMI_HTOP1_HTOP_DCL_COR_PARA_Y2                0x0180 /* Deep Color:Cor Para Y2 */
+#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CB2       0x0184 /* Deep Color:Cor Para CB2 */
+#define HDMI_HTOP1_HTOP_DCL_COR_PARA_CR2       0x0188 /* Deep Color:Cor Para CR2 */
+#define HDMI_HTOP1_EDID_DATA_READ              0x0200 /* EDID Data Read 128Byte:0x03FC */
+
 enum hotplug_state {
        HDMI_HOTPLUG_DISCONNECTED,
        HDMI_HOTPLUG_CONNECTED,
@@ -211,6 +274,7 @@ struct sh_hdmi {
        struct sh_mobile_lcdc_entity entity;
 
        void __iomem *base;
+       void __iomem *htop1;
        enum hotplug_state hp_state;    /* hot-plug status */
        u8 preprogrammed_vic;           /* use a pre-programmed VIC or
                                           the external mode */
@@ -222,20 +286,66 @@ struct sh_hdmi {
        struct delayed_work edid_work;
        struct fb_videomode mode;
        struct fb_monspecs monspec;
+
+       /* register access functions */
+       void (*write)(struct sh_hdmi *hdmi, u8 data, u8 reg);
+       u8 (*read)(struct sh_hdmi *hdmi, u8 reg);
 };
 
 #define entity_to_sh_hdmi(e)   container_of(e, struct sh_hdmi, entity)
 
-static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
+static void __hdmi_write8(struct sh_hdmi *hdmi, u8 data, u8 reg)
 {
        iowrite8(data, hdmi->base + reg);
 }
 
-static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg)
+static u8 __hdmi_read8(struct sh_hdmi *hdmi, u8 reg)
 {
        return ioread8(hdmi->base + reg);
 }
 
+static void __hdmi_write32(struct sh_hdmi *hdmi, u8 data, u8 reg)
+{
+       iowrite32((u32)data, hdmi->base + (reg * 4));
+       udelay(100);
+}
+
+static u8 __hdmi_read32(struct sh_hdmi *hdmi, u8 reg)
+{
+       return (u8)ioread32(hdmi->base + (reg * 4));
+}
+
+static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
+{
+       hdmi->write(hdmi, data, reg);
+}
+
+static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg)
+{
+       return hdmi->read(hdmi, reg);
+}
+
+static void hdmi_bit_set(struct sh_hdmi *hdmi, u8 mask, u8 data, u8 reg)
+{
+       u8 val = hdmi_read(hdmi, reg);
+
+       val &= ~mask;
+       val |= (data & mask);
+
+       hdmi_write(hdmi, val, reg);
+}
+
+static void hdmi_htop1_write(struct sh_hdmi *hdmi, u32 data, u32 reg)
+{
+       iowrite32(data, hdmi->htop1 + reg);
+       udelay(100);
+}
+
+static u32 hdmi_htop1_read(struct sh_hdmi *hdmi, u32 reg)
+{
+       return ioread32(hdmi->htop1 + reg);
+}
+
 /*
  *     HDMI sound
  */
@@ -693,11 +803,11 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi)
        msleep(10);
 
        /* PS mode b->d, reset PLLA and PLLB */
-       hdmi_write(hdmi, 0x4C, HDMI_SYSTEM_CTRL);
+       hdmi_bit_set(hdmi, 0xFC, 0x4C, HDMI_SYSTEM_CTRL);
 
        udelay(10);
 
-       hdmi_write(hdmi, 0x40, HDMI_SYSTEM_CTRL);
+       hdmi_bit_set(hdmi, 0xFC, 0x40, HDMI_SYSTEM_CTRL);
 }
 
 static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
@@ -746,7 +856,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
        /* Read EDID */
        dev_dbg(hdmi->dev, "Read back EDID code:");
        for (i = 0; i < 128; i++) {
-               edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW);
+               edid[i] = (hdmi->htop1) ?
+                       (u8)hdmi_htop1_read(hdmi, HDMI_HTOP1_EDID_DATA_READ + (i * 4)) :
+                       hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW);
 #ifdef DEBUG
                if ((i % 16) == 0) {
                        printk(KERN_CONT "\n");
@@ -917,13 +1029,13 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id)
        u8 status1, status2, mask1, mask2;
 
        /* mode_b and PLLA and PLLB reset */
-       hdmi_write(hdmi, 0x2C, HDMI_SYSTEM_CTRL);
+       hdmi_bit_set(hdmi, 0xFC, 0x2C, HDMI_SYSTEM_CTRL);
 
        /* How long shall reset be held? */
        udelay(10);
 
        /* mode_b and PLLA and PLLB reset release */
-       hdmi_write(hdmi, 0x20, HDMI_SYSTEM_CTRL);
+       hdmi_bit_set(hdmi, 0xFC, 0x20, HDMI_SYSTEM_CTRL);
 
        status1 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_1);
        status2 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_2);
@@ -1001,7 +1113,7 @@ static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity)
         */
        if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) {
                /* PS mode d->e. All functions are active */
-               hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL);
+               hdmi_bit_set(hdmi, 0xFC, 0x80, HDMI_SYSTEM_CTRL);
                dev_dbg(hdmi->dev, "HDMI running\n");
        }
 
@@ -1016,7 +1128,7 @@ static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity)
 
        dev_dbg(hdmi->dev, "%s(%p)\n", __func__, hdmi);
        /* PS mode e->a */
-       hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL);
+       hdmi_bit_set(hdmi, 0xFC, 0x10, HDMI_SYSTEM_CTRL);
 }
 
 static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = {
@@ -1110,10 +1222,58 @@ out:
        dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi);
 }
 
+static void sh_hdmi_htop1_init(struct sh_hdmi *hdmi)
+{
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_MODE);
+       hdmi_htop1_write(hdmi, 0x0000000b, 0x0010);
+       hdmi_htop1_write(hdmi, 0x00006710, HDMI_HTOP1_HTOP_DCL_FRC_MODE);
+       hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_1);
+       hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y1_2);
+       hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_1);
+       hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB1_2);
+       hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_1);
+       hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR1_2);
+       hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_1);
+       hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_Y2_2);
+       hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_1);
+       hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CB2_2);
+       hdmi_htop1_write(hdmi, 0x01020406, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_1);
+       hdmi_htop1_write(hdmi, 0x07080806, HDMI_HTOP1_HTOP_DCL_FIL_PARA_CR2_2);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_Y1);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CB1);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CR1);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_Y2);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CB2);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_HTOP_DCL_COR_PARA_CR2);
+       hdmi_htop1_write(hdmi, 0x00000008, HDMI_HTOP1_CURRENT);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_TISEMP0_1);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_TISEMP2_C);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_PHY_TEST_MODE);
+       hdmi_htop1_write(hdmi, 0x00000081, HDMI_HTOP1_TISIDRV);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_PLLBW);
+       hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISEN);
+       hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISDREN);
+       hdmi_htop1_write(hdmi, 0x00000003, HDMI_HTOP1_ENABLE_SELECTOR);
+       hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_MACRO_RESET);
+       hdmi_htop1_write(hdmi, 0x00000016, HDMI_HTOP1_CISRANGE);
+       msleep(100);
+       hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_ENABLE_SELECTOR);
+       msleep(100);
+       hdmi_htop1_write(hdmi, 0x00000003, HDMI_HTOP1_ENABLE_SELECTOR);
+       hdmi_htop1_write(hdmi, 0x00000001, HDMI_HTOP1_MACRO_RESET);
+       hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISEN);
+       hdmi_htop1_write(hdmi, 0x0000000f, HDMI_HTOP1_TISDREN);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_VIDEO_INPUT);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_CLK_TO_PHY);
+       hdmi_htop1_write(hdmi, 0x00000000, HDMI_HTOP1_VIDEO_INPUT2);
+       hdmi_htop1_write(hdmi, 0x0000000a, HDMI_HTOP1_CLK_SET);
+}
+
 static int __init sh_hdmi_probe(struct platform_device *pdev)
 {
        struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data;
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct resource *htop1_res;
        int irq = platform_get_irq(pdev, 0), ret;
        struct sh_hdmi *hdmi;
        long rate;
@@ -1121,6 +1281,15 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
        if (!res || !pdata || irq < 0)
                return -ENODEV;
 
+       htop1_res = NULL;
+       if (pdata->flags & HDMI_HAS_HTOP1) {
+               htop1_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               if (!htop1_res) {
+                       dev_err(&pdev->dev, "htop1 needs register base\n");
+                       return -EINVAL;
+               }
+       }
+
        hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
        if (!hdmi) {
                dev_err(&pdev->dev, "Cannot allocate device data\n");
@@ -1138,6 +1307,15 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
                goto egetclk;
        }
 
+       /* select register access functions */
+       if (pdata->flags & HDMI_32BIT_REG) {
+               hdmi->write     = __hdmi_write32;
+               hdmi->read      = __hdmi_read32;
+       } else {
+               hdmi->write     = __hdmi_write8;
+               hdmi->read      = __hdmi_read8;
+       }
+
        /* An arbitrary relaxed pixclock just to get things started: from standard 480p */
        rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037));
        if (rate > 0)
@@ -1176,6 +1354,24 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
 
+       /* init interrupt polarity */
+       if (pdata->flags & HDMI_OUTPUT_PUSH_PULL)
+               hdmi_bit_set(hdmi, 0x02, 0x02, HDMI_SYSTEM_CTRL);
+
+       if (pdata->flags & HDMI_OUTPUT_POLARITY_HI)
+               hdmi_bit_set(hdmi, 0x01, 0x01, HDMI_SYSTEM_CTRL);
+
+       /* enable htop1 register if needed */
+       if (htop1_res) {
+               hdmi->htop1 = ioremap(htop1_res->start, resource_size(htop1_res));
+               if (!hdmi->htop1) {
+                       dev_err(&pdev->dev, "control register region already claimed\n");
+                       ret = -ENOMEM;
+                       goto emap_htop1;
+               }
+               sh_hdmi_htop1_init(hdmi);
+       }
+
        /* Product and revision IDs are 0 in sh-mobile version */
        dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n",
                 hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID));
@@ -1199,6 +1395,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 ecodec:
        free_irq(irq, hdmi);
 ereqirq:
+       if (hdmi->htop1)
+               iounmap(hdmi->htop1);
+emap_htop1:
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        iounmap(hdmi->base);
@@ -1230,6 +1429,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
        clk_disable(hdmi->hdmi_clk);
        clk_put(hdmi->hdmi_clk);
+       if (hdmi->htop1)
+               iounmap(hdmi->htop1);
        iounmap(hdmi->base);
        release_mem_region(res->start, resource_size(res));
        kfree(hdmi);
index aff7384..85d6738 100644 (file)
@@ -105,51 +105,6 @@ static const unsigned short ModeIndex_1920x1440[]    = {0x68, 0x69, 0x00, 0x6b};
 static const unsigned short ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00};
 static const unsigned short ModeIndex_310_2048x1536[]= {0x6c, 0x6d, 0x00, 0x6e};
 
-static const unsigned short SiS_DRAMType[17][5]={
-       {0x0C,0x0A,0x02,0x40,0x39},
-       {0x0D,0x0A,0x01,0x40,0x48},
-       {0x0C,0x09,0x02,0x20,0x35},
-       {0x0D,0x09,0x01,0x20,0x44},
-       {0x0C,0x08,0x02,0x10,0x31},
-       {0x0D,0x08,0x01,0x10,0x40},
-       {0x0C,0x0A,0x01,0x20,0x34},
-       {0x0C,0x09,0x01,0x08,0x32},
-       {0x0B,0x08,0x02,0x08,0x21},
-       {0x0C,0x08,0x01,0x08,0x30},
-       {0x0A,0x08,0x02,0x04,0x11},
-       {0x0B,0x0A,0x01,0x10,0x28},
-       {0x09,0x08,0x02,0x02,0x01},
-       {0x0B,0x09,0x01,0x08,0x24},
-       {0x0B,0x08,0x01,0x04,0x20},
-       {0x0A,0x08,0x01,0x02,0x10},
-       {0x09,0x08,0x01,0x01,0x00}
-};
-
-static const unsigned short SiS_SDRDRAM_TYPE[13][5] =
-{
-       { 2,12, 9,64,0x35},
-       { 1,13, 9,64,0x44},
-       { 2,12, 8,32,0x31},
-       { 2,11, 9,32,0x25},
-       { 1,12, 9,32,0x34},
-       { 1,13, 8,32,0x40},
-       { 2,11, 8,16,0x21},
-       { 1,12, 8,16,0x30},
-       { 1,11, 9,16,0x24},
-       { 1,11, 8, 8,0x20},
-       { 2, 9, 8, 4,0x01},
-       { 1,10, 8, 4,0x10},
-       { 1, 9, 8, 2,0x00}
-};
-
-static const unsigned short SiS_DDRDRAM_TYPE[4][5] =
-{
-       { 2,12, 9,64,0x35},
-       { 2,12, 8,32,0x31},
-       { 2,11, 8,16,0x21},
-       { 2, 9, 8, 4,0x01}
-};
-
 static const unsigned char SiS_MDA_DAC[] =
 {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
index 078ca21..a7a48db 100644 (file)
@@ -4222,6 +4222,26 @@ sisfb_post_300_buswidth(struct sis_video_info *ivideo)
        return 1;                       /* 32bit */
 }
 
+static const unsigned short __devinitconst SiS_DRAMType[17][5] = {
+       {0x0C,0x0A,0x02,0x40,0x39},
+       {0x0D,0x0A,0x01,0x40,0x48},
+       {0x0C,0x09,0x02,0x20,0x35},
+       {0x0D,0x09,0x01,0x20,0x44},
+       {0x0C,0x08,0x02,0x10,0x31},
+       {0x0D,0x08,0x01,0x10,0x40},
+       {0x0C,0x0A,0x01,0x20,0x34},
+       {0x0C,0x09,0x01,0x08,0x32},
+       {0x0B,0x08,0x02,0x08,0x21},
+       {0x0C,0x08,0x01,0x08,0x30},
+       {0x0A,0x08,0x02,0x04,0x11},
+       {0x0B,0x0A,0x01,0x10,0x28},
+       {0x09,0x08,0x02,0x02,0x01},
+       {0x0B,0x09,0x01,0x08,0x24},
+       {0x0B,0x08,0x01,0x04,0x20},
+       {0x0A,0x08,0x01,0x02,0x10},
+       {0x09,0x08,0x01,0x01,0x00}
+};
+
 static int __devinit
 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
                        int PseudoRankCapacity, int PseudoAdrPinCount,
@@ -4231,27 +4251,8 @@ sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth
        unsigned short sr14;
        unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
        unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
-       static const unsigned short SiS_DRAMType[17][5] = {
-               {0x0C,0x0A,0x02,0x40,0x39},
-               {0x0D,0x0A,0x01,0x40,0x48},
-               {0x0C,0x09,0x02,0x20,0x35},
-               {0x0D,0x09,0x01,0x20,0x44},
-               {0x0C,0x08,0x02,0x10,0x31},
-               {0x0D,0x08,0x01,0x10,0x40},
-               {0x0C,0x0A,0x01,0x20,0x34},
-               {0x0C,0x09,0x01,0x08,0x32},
-               {0x0B,0x08,0x02,0x08,0x21},
-               {0x0C,0x08,0x01,0x08,0x30},
-               {0x0A,0x08,0x02,0x04,0x11},
-               {0x0B,0x0A,0x01,0x10,0x28},
-               {0x09,0x08,0x02,0x02,0x01},
-               {0x0B,0x09,0x01,0x08,0x24},
-               {0x0B,0x08,0x01,0x04,0x20},
-               {0x0A,0x08,0x01,0x02,0x10},
-               {0x09,0x08,0x01,0x01,0x00}
-       };
 
-        for(k = 0; k <= 16; k++) {
+        for(k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) {
 
                RankCapacity = buswidth * SiS_DRAMType[k][3];
 
index 30f7a81..5b6abc6 100644 (file)
@@ -1036,6 +1036,6 @@ static void __exit xxxfb_exit(void)
      */
 
 module_init(xxxfb_init);
-module_exit(xxxfb_remove);
+module_exit(xxxfb_exit);
 
 MODULE_LICENSE("GPL");
index ccbfef5..af3ef27 100644 (file)
@@ -846,7 +846,7 @@ static void ufx_raw_rect(struct ufx_data *dev, u16 *cmd, int x, int y,
        }
 }
 
-int ufx_handle_damage(struct ufx_data *dev, int x, int y,
+static int ufx_handle_damage(struct ufx_data *dev, int x, int y,
        int width, int height)
 {
        size_t packed_line_len = ALIGN((width * 2), 4);
@@ -1083,7 +1083,7 @@ static int ufx_ops_open(struct fb_info *info, int user)
 
                struct fb_deferred_io *fbdefio;
 
-               fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+               fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
 
                if (fbdefio) {
                        fbdefio->delay = UFX_DEFIO_WRITE_DELAY;
index 7af1e81..8af6414 100644 (file)
@@ -893,7 +893,7 @@ static int dlfb_ops_open(struct fb_info *info, int user)
 
                struct fb_deferred_io *fbdefio;
 
-               fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+               fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
 
                if (fbdefio) {
                        fbdefio->delay = DL_DEFIO_WRITE_DELAY;
index 0c88375..c80e770 100644 (file)
@@ -1276,17 +1276,12 @@ static int viafb_dfph_proc_open(struct inode *inode, struct file *file)
 static ssize_t viafb_dfph_proc_write(struct file *file,
        const char __user *buffer, size_t count, loff_t *pos)
 {
-       char buf[20];
-       u8 reg_val = 0;
-       unsigned long length;
-       if (count < 1)
-               return -EINVAL;
-       length = count > 20 ? 20 : count;
-       if (copy_from_user(&buf[0], buffer, length))
-               return -EFAULT;
-       buf[length - 1] = '\0'; /*Ensure end string */
-       if (kstrtou8(buf, 0, &reg_val) < 0)
-               return -EINVAL;
+       int err;
+       u8 reg_val;
+       err = kstrtou8_from_user(buffer, count, 0, &reg_val);
+       if (err)
+               return err;
+
        viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f);
        return count;
 }
@@ -1316,17 +1311,12 @@ static int viafb_dfpl_proc_open(struct inode *inode, struct file *file)
 static ssize_t viafb_dfpl_proc_write(struct file *file,
        const char __user *buffer, size_t count, loff_t *pos)
 {
-       char buf[20];
-       u8 reg_val = 0;
-       unsigned long length;
-       if (count < 1)
-               return -EINVAL;
-       length = count > 20 ? 20 : count;
-       if (copy_from_user(&buf[0], buffer, length))
-               return -EFAULT;
-       buf[length - 1] = '\0'; /*Ensure end string */
-       if (kstrtou8(buf, 0, &reg_val) < 0)
-               return -EINVAL;
+       int err;
+       u8 reg_val;
+       err = kstrtou8_from_user(buffer, count, 0, &reg_val);
+       if (err)
+               return err;
+
        viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f);
        return count;
 }
index a3229d7..ac3f1c6 100644 (file)
@@ -611,6 +611,7 @@ struct fb_deferred_io {
        struct mutex lock; /* mutex that protects the page list */
        struct list_head pagelist; /* list of touched pages */
        /* callback */
+       void (*first_io)(struct fb_info *info);
        void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
 };
 #endif
diff --git a/include/video/auo_k190xfb.h b/include/video/auo_k190xfb.h
new file mode 100644 (file)
index 0000000..609efe8
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Definitions for AUO-K190X framebuffer drivers
+ *
+ * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_VIDEO_AUO_K190XFB_H_
+#define _LINUX_VIDEO_AUO_K190XFB_H_
+
+/* Controller standby command needs a param */
+#define AUOK190X_QUIRK_STANDBYPARAM    (1 << 0)
+
+/* Controller standby is completely broken */
+#define AUOK190X_QUIRK_STANDBYBROKEN   (1 << 1)
+
+/*
+ * Resolutions for the displays
+ */
+#define AUOK190X_RESOLUTION_800_600            0
+#define AUOK190X_RESOLUTION_1024_768           1
+
+/*
+ * struct used by auok190x. board specific stuff comes from *board
+ */
+struct auok190xfb_par {
+       struct fb_info *info;
+       struct auok190x_board *board;
+
+       struct regulator *regulator;
+
+       struct mutex io_lock;
+       struct delayed_work work;
+       wait_queue_head_t waitq;
+       int resolution;
+       int rotation;
+       int consecutive_threshold;
+       int update_cnt;
+
+       /* panel and controller informations */
+       int epd_type;
+       int panel_size_int;
+       int panel_size_float;
+       int panel_model;
+       int tcon_version;
+       int lut_version;
+
+       /* individual controller callbacks */
+       void (*update_partial)(struct auok190xfb_par *par, u16 y1, u16 y2);
+       void (*update_all)(struct auok190xfb_par *par);
+       bool (*need_refresh)(struct auok190xfb_par *par);
+       void (*init)(struct auok190xfb_par *par);
+       void (*recover)(struct auok190xfb_par *par);
+
+       int update_mode; /* mode to use for updates */
+       int last_mode; /* update mode last used */
+       int flash;
+
+       /* power management */
+       int autosuspend_delay;
+       bool standby;
+       bool manual_standby;
+};
+
+/**
+ * Board specific platform-data
+ * @init:              initialize the controller interface
+ * @cleanup:           cleanup the controller interface
+ * @wait_for_rdy:      wait until the controller is not busy anymore
+ * @set_ctl:           change an interface control
+ * @set_hdb:           write a value to the data register
+ * @get_hdb:           read a value from the data register
+ * @setup_irq:         method to setup the irq handling on the busy gpio
+ * @gpio_nsleep:       sleep gpio
+ * @gpio_nrst:         reset gpio
+ * @gpio_nbusy:                busy gpio
+ * @resolution:                one of the AUOK190X_RESOLUTION constants
+ * @rotation:          rotation of the framebuffer
+ * @quirks:            controller quirks to honor
+ * @fps:               frames per second for defio
+ */
+struct auok190x_board {
+       int (*init)(struct auok190xfb_par *);
+       void (*cleanup)(struct auok190xfb_par *);
+       int (*wait_for_rdy)(struct auok190xfb_par *);
+
+       void (*set_ctl)(struct auok190xfb_par *, unsigned char, u8);
+       void (*set_hdb)(struct auok190xfb_par *, u16);
+       u16 (*get_hdb)(struct auok190xfb_par *);
+
+       int (*setup_irq)(struct fb_info *);
+
+       int gpio_nsleep;
+       int gpio_nrst;
+       int gpio_nbusy;
+
+       int resolution;
+       int rotation;
+       int quirks;
+       int fps;
+};
+
+#endif
index 8847a9d..bd8cabd 100644 (file)
@@ -14,7 +14,7 @@
 
 #define DP_TIMEOUT_LOOP_COUNT 100
 #define MAX_CR_LOOP 5
-#define MAX_EQ_LOOP 4
+#define MAX_EQ_LOOP 5
 
 enum link_rate_type {
        LINK_RATE_1_62GBPS = 0x06,
index 772c770..83ce5e6 100644 (file)
@@ -315,6 +315,7 @@ struct mipi_dsim_lcd_device {
        int                     id;
        int                     bus_id;
        int                     irq;
+       int                     panel_reverse;
 
        struct mipi_dsim_device *master;
        void                    *platform_data;
index 1c46a14..c8e59b4 100644 (file)
@@ -51,6 +51,8 @@
 
 struct omap_dss_device;
 struct omap_overlay_manager;
+struct snd_aes_iec958;
+struct snd_cea_861_aud_if;
 
 enum omap_display_type {
        OMAP_DISPLAY_TYPE_NONE          = 0,
@@ -158,6 +160,13 @@ enum omap_dss_display_state {
        OMAP_DSS_DISPLAY_SUSPENDED,
 };
 
+enum omap_dss_audio_state {
+       OMAP_DSS_AUDIO_DISABLED = 0,
+       OMAP_DSS_AUDIO_ENABLED,
+       OMAP_DSS_AUDIO_CONFIGURED,
+       OMAP_DSS_AUDIO_PLAYING,
+};
+
 /* XXX perhaps this should be removed */
 enum omap_dss_overlay_managers {
        OMAP_DSS_OVL_MGR_LCD,
@@ -166,8 +175,9 @@ enum omap_dss_overlay_managers {
 };
 
 enum omap_dss_rotation_type {
-       OMAP_DSS_ROT_DMA = 0,
-       OMAP_DSS_ROT_VRFB = 1,
+       OMAP_DSS_ROT_DMA        = 1 << 0,
+       OMAP_DSS_ROT_VRFB       = 1 << 1,
+       OMAP_DSS_ROT_TILER      = 1 << 2,
 };
 
 /* clockwise rotation angle */
@@ -309,6 +319,7 @@ struct omap_dss_board_info {
        struct omap_dss_device *default_device;
        int (*dsi_enable_pads)(int dsi_id, unsigned lane_mask);
        void (*dsi_disable_pads)(int dsi_id, unsigned lane_mask);
+       int (*set_min_bus_tput)(struct device *dev, unsigned long r);
 };
 
 /* Init with the board info */
@@ -316,11 +327,6 @@ extern int omap_display_init(struct omap_dss_board_info *board_data);
 /* HDMI mux init*/
 extern int omap_hdmi_init(enum omap_hdmi_flags flags);
 
-struct omap_display_platform_data {
-       struct omap_dss_board_info *board_data;
-       /* TODO: Additional members to be added when PM is considered */
-};
-
 struct omap_video_timings {
        /* Unit: pixels */
        u16 x_res;
@@ -587,6 +593,8 @@ struct omap_dss_device {
 
        enum omap_dss_display_state state;
 
+       enum omap_dss_audio_state audio_state;
+
        /* platform specific  */
        int (*platform_enable)(struct omap_dss_device *dssdev);
        void (*platform_disable)(struct omap_dss_device *dssdev);
@@ -599,6 +607,11 @@ struct omap_dss_hdmi_data
        int hpd_gpio;
 };
 
+struct omap_dss_audio {
+       struct snd_aes_iec958 *iec;
+       struct snd_cea_861_aud_if *cea;
+};
+
 struct omap_dss_driver {
        struct device_driver driver;
 
@@ -646,6 +659,24 @@ struct omap_dss_driver {
 
        int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
        bool (*detect)(struct omap_dss_device *dssdev);
+
+       /*
+        * For display drivers that support audio. This encompasses
+        * HDMI and DisplayPort at the moment.
+        */
+       /*
+        * Note: These functions might sleep. Do not call while
+        * holding a spinlock/readlock.
+        */
+       int (*audio_enable)(struct omap_dss_device *dssdev);
+       void (*audio_disable)(struct omap_dss_device *dssdev);
+       bool (*audio_supported)(struct omap_dss_device *dssdev);
+       int (*audio_config)(struct omap_dss_device *dssdev,
+               struct omap_dss_audio *audio);
+       /* Note: These functions may not sleep */
+       int (*audio_start)(struct omap_dss_device *dssdev);
+       void (*audio_stop)(struct omap_dss_device *dssdev);
+
 };
 
 int omap_dss_register_driver(struct omap_dss_driver *);
@@ -670,6 +701,8 @@ struct omap_overlay *omap_dss_get_overlay(int num);
 void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
                u16 *xres, u16 *yres);
 int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev);
+void omapdss_default_get_timings(struct omap_dss_device *dssdev,
+               struct omap_video_timings *timings);
 
 typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
index 728f9de..63d20ef 100644 (file)
@@ -18,9 +18,11 @@ struct clk;
 /*
  * flags format
  *
- * 0x0000000A
+ * 0x00000CBA
  *
  * A: Audio source select
+ * B: Int output option
+ * C: Chip specific option
  */
 
 /* Audio source select */
@@ -30,6 +32,14 @@ struct clk;
 #define HDMI_SND_SRC_DSD       (2 << 0)
 #define HDMI_SND_SRC_HBR       (3 << 0)
 
+/* Int output option */
+#define HDMI_OUTPUT_PUSH_PULL  (1 << 4) /* System control : output mode */
+#define HDMI_OUTPUT_POLARITY_HI        (1 << 5) /* System control : output polarity */
+
+/* Chip specific option */
+#define HDMI_32BIT_REG         (1 << 8)
+#define HDMI_HAS_HTOP1         (1 << 9)
+
 struct sh_mobile_hdmi_info {
        unsigned int                     flags;
        long (*clk_optimize_parent)(unsigned long target, unsigned long *best_freq,