Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[pandora-kernel.git] / drivers / staging / gma500 / psb_intel_display.c
index 09e378d..4afa671 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright Â© 2006-2007 Intel Corporation
+ * Copyright Â© 2006-2011 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
 #include <linux/pm_runtime.h>
 
 #include <drm/drmP.h>
-#include "psb_fb.h"
+#include "framebuffer.h"
 #include "psb_drv.h"
 #include "psb_intel_drv.h"
 #include "psb_intel_reg.h"
 #include "psb_intel_display.h"
-#include "psb_powermgmt.h"
+#include "power.h"
 
+#include "mdfld_output.h"
 
 struct psb_intel_clock_t {
        /* given values */
@@ -350,17 +351,15 @@ int psb_intel_pipe_set_base(struct drm_crtc *crtc,
        u32 dspcntr;
        int ret = 0;
 
-       PSB_DEBUG_ENTRY("\n");
+       if (!gma_power_begin(dev, true))
+               return 0;
 
        /* no fb bound */
        if (!crtc->fb) {
-               DRM_DEBUG("No FB bound\n");
-               return 0;
+               dev_dbg(dev->dev, "No FB bound\n");
+               goto psb_intel_pipe_cleaner;
        }
 
-       if (!gma_power_begin(dev, true))
-               return 0;
-
        /* We are displaying this buffer, make sure it is actually loaded
           into the GTT */
        ret = psb_gtt_pin(psbfb->gtt);
@@ -390,7 +389,7 @@ int psb_intel_pipe_set_base(struct drm_crtc *crtc,
                dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
                break;
        default:
-               DRM_ERROR("Unknown color depth\n");
+               dev_err(dev->dev, "Unknown color depth\n");
                ret = -EINVAL;
                psb_gtt_unpin(psbfb->gtt);
                goto psb_intel_pipe_set_base_exit;
@@ -398,7 +397,6 @@ int psb_intel_pipe_set_base(struct drm_crtc *crtc,
        REG_WRITE(dspcntr_reg, dspcntr);
 
 
-       DRM_DEBUG("Writing base %08lX %08lX %d %d\n", start, offset, x, y);
        if (0 /* FIXMEAC - check what PSB needs */) {
                REG_WRITE(dspbase, offset);
                REG_READ(dspbase);
@@ -409,6 +407,7 @@ int psb_intel_pipe_set_base(struct drm_crtc *crtc,
                REG_READ(dspbase);
        }
 
+psb_intel_pipe_cleaner:
        /* If there was a previous display we can now unpin it */
        if (old_fb)
                psb_gtt_unpin(to_psb_fb(old_fb)->gtt);
@@ -588,6 +587,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        int pipe = psb_intel_crtc->pipe;
        int fp_reg = (pipe == 0) ? FPA0 : FPB0;
        int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
@@ -610,6 +610,12 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct drm_connector *connector;
 
+       /* No scan out no play */
+       if (crtc->fb == NULL) {
+               crtc_funcs->mode_set_base(crtc, x, y, old_fb);
+               return 0;
+       }
+
        list_for_each_entry(connector, &mode_config->connector_list, head) {
                struct psb_intel_output *psb_intel_output =
                    to_psb_intel_output(connector);
@@ -642,7 +648,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
        ok = psb_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk,
                                 &clock);
        if (!ok) {
-               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               dev_err(dev->dev, "Couldn't find PLL settings for mode!\n");
                return 0;
        }
 
@@ -706,7 +712,6 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
        if (psb_intel_panel_fitter_pipe(dev) == pipe)
                REG_WRITE(PFIT_CONTROL, 0);
 
-       DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
        drm_mode_debug_printmodeline(mode);
 
        if (dpll & DPLL_VCO_ENABLE) {
@@ -723,17 +728,18 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
        if (is_lvds) {
                u32 lvds = REG_READ(LVDS);
 
-               lvds |=
-                   LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP |
-                   LVDS_PIPEB_SELECT;
+               lvds &= ~LVDS_PIPEB_SELECT;
+               if (pipe == 1)
+                       lvds |= LVDS_PIPEB_SELECT;
+
+               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
                /* Set the B0-B3 data pairs corresponding to
                 * whether we're going to
                 * set the DPLLs for dual-channel mode or not.
                 */
+               lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
                if (clock.p2 == 7)
                        lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
-               else
-                       lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
 
                /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
                 * appropriately here, but we need to look more
@@ -785,11 +791,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
        REG_WRITE(dspcntr_reg, dspcntr);
 
        /* Flush the plane changes */
-       {
-               struct drm_crtc_helper_funcs *crtc_funcs =
-                   crtc->helper_private;
-               crtc_funcs->mode_set_base(crtc, x, y, old_fb);
-       }
+       crtc_funcs->mode_set_base(crtc, x, y, old_fb);
 
        psb_intel_wait_for_vblank(dev);
 
@@ -820,7 +822,7 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
                palreg = PALETTE_C;
                break;
        default:
-               DRM_ERROR("Illegal Pipe Number.\n");
+               dev_err(dev->dev, "Illegal Pipe Number.\n");
                return;
        }
 
@@ -863,10 +865,8 @@ static void psb_intel_crtc_save(struct drm_crtc *crtc)
        uint32_t paletteReg;
        int i;
 
-       DRM_DEBUG("\n");
-
        if (!crtc_state) {
-               DRM_DEBUG("No CRTC state found\n");
+               dev_err(dev->dev, "No CRTC state found\n");
                return;
        }
 
@@ -890,25 +890,6 @@ static void psb_intel_crtc_save(struct drm_crtc *crtc)
 
        crtc_state->saveDSPBASE = REG_READ(pipeA ? DSPABASE : DSPBBASE);
 
-       DRM_DEBUG("(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n",
-                       crtc_state->saveDSPCNTR,
-                       crtc_state->savePIPECONF,
-                       crtc_state->savePIPESRC,
-                       crtc_state->saveFP0,
-                       crtc_state->saveFP1,
-                       crtc_state->saveDPLL,
-                       crtc_state->saveHTOTAL,
-                       crtc_state->saveHBLANK,
-                       crtc_state->saveHSYNC,
-                       crtc_state->saveVTOTAL,
-                       crtc_state->saveVBLANK,
-                       crtc_state->saveVSYNC,
-                       crtc_state->saveDSPSTRIDE,
-                       crtc_state->saveDSPSIZE,
-                       crtc_state->saveDSPPOS,
-                       crtc_state->saveDSPBASE
-               );
-
        paletteReg = pipeA ? PALETTE_A : PALETTE_B;
        for (i = 0; i < 256; ++i)
                crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2));
@@ -929,60 +910,15 @@ static void psb_intel_crtc_restore(struct drm_crtc *crtc)
        uint32_t paletteReg;
        int i;
 
-       DRM_DEBUG("\n");
-
        if (!crtc_state) {
-               DRM_DEBUG("No crtc state\n");
+               dev_err(dev->dev, "No crtc state\n");
                return;
        }
 
-       DRM_DEBUG(
-               "current:(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n",
-               REG_READ(pipeA ? DSPACNTR : DSPBCNTR),
-               REG_READ(pipeA ? PIPEACONF : PIPEBCONF),
-               REG_READ(pipeA ? PIPEASRC : PIPEBSRC),
-               REG_READ(pipeA ? FPA0 : FPB0),
-               REG_READ(pipeA ? FPA1 : FPB1),
-               REG_READ(pipeA ? DPLL_A : DPLL_B),
-               REG_READ(pipeA ? HTOTAL_A : HTOTAL_B),
-               REG_READ(pipeA ? HBLANK_A : HBLANK_B),
-               REG_READ(pipeA ? HSYNC_A : HSYNC_B),
-               REG_READ(pipeA ? VTOTAL_A : VTOTAL_B),
-               REG_READ(pipeA ? VBLANK_A : VBLANK_B),
-               REG_READ(pipeA ? VSYNC_A : VSYNC_B),
-               REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE),
-               REG_READ(pipeA ? DSPASIZE : DSPBSIZE),
-               REG_READ(pipeA ? DSPAPOS : DSPBPOS),
-               REG_READ(pipeA ? DSPABASE : DSPBBASE)
-               );
-
-       DRM_DEBUG(
-               "saved: (%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n",
-               crtc_state->saveDSPCNTR,
-               crtc_state->savePIPECONF,
-               crtc_state->savePIPESRC,
-               crtc_state->saveFP0,
-               crtc_state->saveFP1,
-               crtc_state->saveDPLL,
-               crtc_state->saveHTOTAL,
-               crtc_state->saveHBLANK,
-               crtc_state->saveHSYNC,
-               crtc_state->saveVTOTAL,
-               crtc_state->saveVBLANK,
-               crtc_state->saveVSYNC,
-               crtc_state->saveDSPSTRIDE,
-               crtc_state->saveDSPSIZE,
-               crtc_state->saveDSPPOS,
-               crtc_state->saveDSPBASE
-               );
-
-
        if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) {
                REG_WRITE(pipeA ? DPLL_A : DPLL_B,
                        crtc_state->saveDPLL & ~DPLL_VCO_ENABLE);
                REG_READ(pipeA ? DPLL_A : DPLL_B);
-               DRM_DEBUG("write dpll: %x\n",
-                               REG_READ(pipeA ? DPLL_A : DPLL_B));
                udelay(150);
        }
 
@@ -1039,11 +975,8 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
        struct drm_gem_object *obj;
        int ret;
 
-       DRM_DEBUG("\n");
-
        /* if we want to turn of the cursor ignore width and height */
        if (!handle) {
-               DRM_DEBUG("cursor off\n");
                /* turn off the cursor */
                temp = CURSOR_MODE_DISABLE;
 
@@ -1067,7 +1000,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
 
        /* Currently we only support 64x64 cursors */
        if (width != 64 || height != 64) {
-               DRM_ERROR("we currently only support 64x64 cursors\n");
+               dev_dbg(dev->dev, "we currently only support 64x64 cursors\n");
                return -EINVAL;
        }
 
@@ -1076,7 +1009,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
                return -ENOENT;
 
        if (obj->size < width * height * 4) {
-               DRM_ERROR("buffer is to small\n");
+               dev_dbg(dev->dev, "buffer is to small\n");
                return -ENOMEM;
        }
 
@@ -1085,7 +1018,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
        /* Pin the memory into the GTT */
        ret = psb_gtt_pin(gt);
        if (ret) {
-               DRM_ERROR("Can not pin down handle 0x%x\n", handle);
+               dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle);
                return ret;
        }
 
@@ -1106,14 +1039,13 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
        }
 
        /* unpin the old bo */
-       if (psb_intel_crtc->cursor_obj && psb_intel_crtc->cursor_obj != obj) {
+       if (psb_intel_crtc->cursor_obj) {
                gt = container_of(psb_intel_crtc->cursor_obj,
                                                        struct gtt_range, gem);
                psb_gtt_unpin(gt);
                drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
                psb_intel_crtc->cursor_obj = obj;
        }
-
        return 0;
 }
 
@@ -1148,7 +1080,7 @@ static int psb_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        return 0;
 }
 
-static void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
+void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
                         u16 *green, u16 *blue, uint32_t type, uint32_t size)
 {
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
@@ -1309,7 +1241,7 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
        return mode;
 }
 
-static void psb_intel_crtc_destroy(struct drm_crtc *crtc)
+void psb_intel_crtc_destroy(struct drm_crtc *crtc)
 {
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
        struct gtt_range *gt;
@@ -1327,7 +1259,7 @@ static void psb_intel_crtc_destroy(struct drm_crtc *crtc)
        kfree(psb_intel_crtc);
 }
 
-static const struct drm_crtc_helper_funcs psb_intel_helper_funcs = {
+const struct drm_crtc_helper_funcs psb_intel_helper_funcs = {
        .dpms = psb_intel_crtc_dpms,
        .mode_fixup = psb_intel_crtc_mode_fixup,
        .mode_set = psb_intel_crtc_mode_set,
@@ -1346,6 +1278,19 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = {
        .destroy = psb_intel_crtc_destroy,
 };
 
+/*
+ * Set the default value of cursor control and base register
+ * to zero. This is a workaround for h/w defect on Oaktrail
+ */
+static void psb_intel_cursor_init(struct drm_device *dev, int pipe)
+{
+       u32 control[3] = { CURACNTR, CURBCNTR, CURCCNTR };
+       u32 base[3] = { CURABASE, CURBBASE, CURCBASE };
+
+       REG_WRITE(control[pipe], 0);
+       REG_WRITE(base[pipe], 0);
+}
+
 void psb_intel_crtc_init(struct drm_device *dev, int pipe,
                     struct psb_intel_mode_device *mode_dev)
 {
@@ -1354,8 +1299,6 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
        int i;
        uint16_t *r_base, *g_base, *b_base;
 
-       PSB_DEBUG_ENTRY("\n");
-
        /* We allocate a extra array of drm_connector pointers
         * for fbdev after the crtc */
        psb_intel_crtc =
@@ -1368,12 +1311,13 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
        psb_intel_crtc->crtc_state =
                kzalloc(sizeof(struct psb_intel_crtc_state), GFP_KERNEL);
        if (!psb_intel_crtc->crtc_state) {
-               DRM_INFO("Crtc state error: No memory\n");
+               dev_err(dev->dev, "Crtc state error: No memory\n");
                kfree(psb_intel_crtc);
                return;
        }
 
-       drm_crtc_init(dev, &psb_intel_crtc->base, &psb_intel_crtc_funcs);
+       /* Set the CRTC operations from the chip specific data */
+       drm_crtc_init(dev, &psb_intel_crtc->base, dev_priv->ops->crtc_funcs);
 
        drm_mode_crtc_set_gamma_size(&psb_intel_crtc->base, 256);
        psb_intel_crtc->pipe = pipe;
@@ -1396,12 +1340,8 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
        psb_intel_crtc->mode_dev = mode_dev;
        psb_intel_crtc->cursor_addr = 0;
 
-       if (IS_MRST(dev))
-               drm_crtc_helper_add(&psb_intel_crtc->base,
-                                   &mrst_helper_funcs);
-       else
-               drm_crtc_helper_add(&psb_intel_crtc->base,
-                                   &psb_intel_helper_funcs);
+       drm_crtc_helper_add(&psb_intel_crtc->base,
+                                               dev_priv->ops->crtc_helper);
 
        /* Setup the array of drm_connector pointer array */
        psb_intel_crtc->mode_set.crtc = &psb_intel_crtc->base;
@@ -1414,6 +1354,7 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
        psb_intel_crtc->mode_set.connectors =
            (struct drm_connector **) (psb_intel_crtc + 1);
        psb_intel_crtc->mode_set.num_connectors = 0;
+       psb_intel_cursor_init(dev, pipe);
 }
 
 int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
@@ -1425,7 +1366,7 @@ int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
        struct psb_intel_crtc *crtc;
 
        if (!dev_priv) {
-               DRM_ERROR("called with no initialization\n");
+               dev_err(dev->dev, "called with no initialization\n");
                return -EINVAL;
        }
 
@@ -1433,7 +1374,7 @@ int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
                        DRM_MODE_OBJECT_CRTC);
 
        if (!drmmode_obj) {
-               DRM_ERROR("no such CRTC id\n");
+               dev_err(dev->dev, "no such CRTC id\n");
                return -EINVAL;
        }