]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/gma500/psb_intel_display.c
gma500: handle poulsbo cursor restriction
[karo-tx-linux.git] / drivers / gpu / drm / gma500 / psb_intel_display.c
index 2616558457c8e1beccf5818d3fc21d9e50ee151c..36c3c99612f6e04715e249ecfb33c11ee62998bb 100644 (file)
@@ -337,15 +337,12 @@ static int psb_intel_pipe_set_base(struct drm_crtc *crtc,
                            int x, int y, struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
-       /* struct drm_i915_master_private *master_priv; */
+       struct drm_psb_private *dev_priv = dev->dev_private;
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
        struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
        int pipe = psb_intel_crtc->pipe;
+       const struct psb_offset *map = &dev_priv->regmap[pipe];
        unsigned long start, offset;
-       int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE);
-       int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
-       int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
-       int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
        u32 dspcntr;
        int ret = 0;
 
@@ -367,9 +364,9 @@ static int psb_intel_pipe_set_base(struct drm_crtc *crtc,
 
        offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
 
-       REG_WRITE(dspstride, crtc->fb->pitches[0]);
+       REG_WRITE(map->stride, crtc->fb->pitches[0]);
 
-       dspcntr = REG_READ(dspcntr_reg);
+       dspcntr = REG_READ(map->cntr);
        dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 
        switch (crtc->fb->bits_per_pixel) {
@@ -392,18 +389,10 @@ static int psb_intel_pipe_set_base(struct drm_crtc *crtc,
                psb_gtt_unpin(psbfb->gtt);
                goto psb_intel_pipe_set_base_exit;
        }
-       REG_WRITE(dspcntr_reg, dspcntr);
-
+       REG_WRITE(map->cntr, dspcntr);
 
-       if (0 /* FIXMEAC - check what PSB needs */) {
-               REG_WRITE(dspbase, offset);
-               REG_READ(dspbase);
-               REG_WRITE(dspsurf, start);
-               REG_READ(dspsurf);
-       } else {
-               REG_WRITE(dspbase, start + offset);
-               REG_READ(dspbase);
-       }
+       REG_WRITE(map->base, start + offset);
+       REG_READ(map->base);
 
 psb_intel_pipe_cleaner:
        /* If there was a previous display we can now unpin it */
@@ -424,14 +413,10 @@ psb_intel_pipe_set_base_exit:
 static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct drm_device *dev = crtc->dev;
-       /* struct drm_i915_master_private *master_priv; */
-       /* struct drm_i915_private *dev_priv = dev->dev_private; */
+       struct drm_psb_private *dev_priv = dev->dev_private;
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
        int pipe = psb_intel_crtc->pipe;
-       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-       int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
-       int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+       const struct psb_offset *map = &dev_priv->regmap[pipe];
        u32 temp;
 
        /* XXX: When our outputs are all unaware of DPMS modes other than off
@@ -442,34 +427,34 @@ static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
                /* Enable the DPLL */
-               temp = REG_READ(dpll_reg);
+               temp = REG_READ(map->dpll);
                if ((temp & DPLL_VCO_ENABLE) == 0) {
-                       REG_WRITE(dpll_reg, temp);
-                       REG_READ(dpll_reg);
+                       REG_WRITE(map->dpll, temp);
+                       REG_READ(map->dpll);
                        /* Wait for the clocks to stabilize. */
                        udelay(150);
-                       REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-                       REG_READ(dpll_reg);
+                       REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
+                       REG_READ(map->dpll);
                        /* Wait for the clocks to stabilize. */
                        udelay(150);
-                       REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-                       REG_READ(dpll_reg);
+                       REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
+                       REG_READ(map->dpll);
                        /* Wait for the clocks to stabilize. */
                        udelay(150);
                }
 
                /* Enable the pipe */
-               temp = REG_READ(pipeconf_reg);
+               temp = REG_READ(map->conf);
                if ((temp & PIPEACONF_ENABLE) == 0)
-                       REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
+                       REG_WRITE(map->conf, temp | PIPEACONF_ENABLE);
 
                /* Enable the plane */
-               temp = REG_READ(dspcntr_reg);
+               temp = REG_READ(map->cntr);
                if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-                       REG_WRITE(dspcntr_reg,
+                       REG_WRITE(map->cntr,
                                  temp | DISPLAY_PLANE_ENABLE);
                        /* Flush the plane changes */
-                       REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+                       REG_WRITE(map->base, REG_READ(map->base));
                }
 
                psb_intel_crtc_load_lut(crtc);
@@ -487,29 +472,29 @@ static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
                REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
 
                /* Disable display plane */
-               temp = REG_READ(dspcntr_reg);
+               temp = REG_READ(map->cntr);
                if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-                       REG_WRITE(dspcntr_reg,
+                       REG_WRITE(map->cntr,
                                  temp & ~DISPLAY_PLANE_ENABLE);
                        /* Flush the plane changes */
-                       REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
-                       REG_READ(dspbase_reg);
+                       REG_WRITE(map->base, REG_READ(map->base));
+                       REG_READ(map->base);
                }
 
                /* Next, disable display pipes */
-               temp = REG_READ(pipeconf_reg);
+               temp = REG_READ(map->conf);
                if ((temp & PIPEACONF_ENABLE) != 0) {
-                       REG_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
-                       REG_READ(pipeconf_reg);
+                       REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE);
+                       REG_READ(map->conf);
                }
 
                /* Wait for vblank for the disable to take effect. */
                psb_intel_wait_for_vblank(dev);
 
-               temp = REG_READ(dpll_reg);
+               temp = REG_READ(map->dpll);
                if ((temp & DPLL_VCO_ENABLE) != 0) {
-                       REG_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
-                       REG_READ(dpll_reg);
+                       REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE);
+                       REG_READ(map->dpll);
                }
 
                /* Wait for the clocks to turn off. */
@@ -589,22 +574,11 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
                               struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
        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;
-       int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
-       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-       int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-       int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-       int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-       int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-       int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-       int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-       int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
-       int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
-       int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+       const struct psb_offset *map = &dev_priv->regmap[pipe];
        int refclk;
        struct psb_intel_clock_t clock;
        u32 dpll = 0, fp = 0, dspcntr, pipeconf;
@@ -690,7 +664,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
        dpll |= PLL_REF_INPUT_DREFCLK;
 
        /* setup pipeconf */
-       pipeconf = REG_READ(pipeconf_reg);
+       pipeconf = REG_READ(map->conf);
 
        /* Set up the display plane register */
        dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -712,9 +686,9 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
        drm_mode_debug_printmodeline(mode);
 
        if (dpll & DPLL_VCO_ENABLE) {
-               REG_WRITE(fp_reg, fp);
-               REG_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
-               REG_READ(dpll_reg);
+               REG_WRITE(map->fp0, fp);
+               REG_WRITE(map->dpll, dpll & ~DPLL_VCO_ENABLE);
+               REG_READ(map->dpll);
                udelay(150);
        }
 
@@ -747,45 +721,45 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
                REG_READ(LVDS);
        }
 
-       REG_WRITE(fp_reg, fp);
-       REG_WRITE(dpll_reg, dpll);
-       REG_READ(dpll_reg);
+       REG_WRITE(map->fp0, fp);
+       REG_WRITE(map->dpll, dpll);
+       REG_READ(map->dpll);
        /* Wait for the clocks to stabilize. */
        udelay(150);
 
        /* write it again -- the BIOS does, after all */
-       REG_WRITE(dpll_reg, dpll);
+       REG_WRITE(map->dpll, dpll);
 
-       REG_READ(dpll_reg);
+       REG_READ(map->dpll);
        /* Wait for the clocks to stabilize. */
        udelay(150);
 
-       REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+       REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) |
                  ((adjusted_mode->crtc_htotal - 1) << 16));
-       REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+       REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) |
                  ((adjusted_mode->crtc_hblank_end - 1) << 16));
-       REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+       REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) |
                  ((adjusted_mode->crtc_hsync_end - 1) << 16));
-       REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+       REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) |
                  ((adjusted_mode->crtc_vtotal - 1) << 16));
-       REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+       REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) |
                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
-       REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+       REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) |
                  ((adjusted_mode->crtc_vsync_end - 1) << 16));
        /* pipesrc and dspsize control the size that is scaled from,
         * which should always be the user's requested size.
         */
-       REG_WRITE(dspsize_reg,
+       REG_WRITE(map->size,
                  ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
-       REG_WRITE(dsppos_reg, 0);
-       REG_WRITE(pipesrc_reg,
+       REG_WRITE(map->pos, 0);
+       REG_WRITE(map->src,
                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
-       REG_WRITE(pipeconf_reg, pipeconf);
-       REG_READ(pipeconf_reg);
+       REG_WRITE(map->conf, pipeconf);
+       REG_READ(map->conf);
 
        psb_intel_wait_for_vblank(dev);
 
-       REG_WRITE(dspcntr_reg, dspcntr);
+       REG_WRITE(map->cntr, dspcntr);
 
        /* Flush the plane changes */
        crtc_funcs->mode_set_base(crtc, x, y, old_fb);
@@ -799,10 +773,10 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
 void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_psb_private *dev_priv =
-                               (struct drm_psb_private *)dev->dev_private;
+       struct drm_psb_private *dev_priv = dev->dev_private;
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
-       int palreg = PALETTE_A;
+       const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe];
+       int palreg = map->palette;
        int i;
 
        /* The clocks have to be on to load the palette. */
@@ -811,12 +785,7 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
 
        switch (psb_intel_crtc->pipe) {
        case 0:
-               break;
        case 1:
-               palreg = PALETTE_B;
-               break;
-       case 2:
-               palreg = PALETTE_C;
                break;
        default:
                dev_err(dev->dev, "Illegal Pipe Number.\n");
@@ -836,7 +805,7 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
                gma_power_end(dev);
        } else {
                for (i = 0; i < 256; i++) {
-                       dev_priv->regs.psb.save_palette_a[i] =
+                       dev_priv->regs.pipe[0].palette[i] =
                                  ((psb_intel_crtc->lut_r[i] +
                                  psb_intel_crtc->lut_adj[i]) << 16) |
                                  ((psb_intel_crtc->lut_g[i] +
@@ -854,11 +823,10 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
 static void psb_intel_crtc_save(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       /* struct drm_psb_private *dev_priv =
-                       (struct drm_psb_private *)dev->dev_private; */
+       struct drm_psb_private *dev_priv = dev->dev_private;
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
        struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state;
-       int pipeA = (psb_intel_crtc->pipe == 0);
+       const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe];
        uint32_t paletteReg;
        int i;
 
@@ -867,27 +835,27 @@ static void psb_intel_crtc_save(struct drm_crtc *crtc)
                return;
        }
 
-       crtc_state->saveDSPCNTR = REG_READ(pipeA ? DSPACNTR : DSPBCNTR);
-       crtc_state->savePIPECONF = REG_READ(pipeA ? PIPEACONF : PIPEBCONF);
-       crtc_state->savePIPESRC = REG_READ(pipeA ? PIPEASRC : PIPEBSRC);
-       crtc_state->saveFP0 = REG_READ(pipeA ? FPA0 : FPB0);
-       crtc_state->saveFP1 = REG_READ(pipeA ? FPA1 : FPB1);
-       crtc_state->saveDPLL = REG_READ(pipeA ? DPLL_A : DPLL_B);
-       crtc_state->saveHTOTAL = REG_READ(pipeA ? HTOTAL_A : HTOTAL_B);
-       crtc_state->saveHBLANK = REG_READ(pipeA ? HBLANK_A : HBLANK_B);
-       crtc_state->saveHSYNC = REG_READ(pipeA ? HSYNC_A : HSYNC_B);
-       crtc_state->saveVTOTAL = REG_READ(pipeA ? VTOTAL_A : VTOTAL_B);
-       crtc_state->saveVBLANK = REG_READ(pipeA ? VBLANK_A : VBLANK_B);
-       crtc_state->saveVSYNC = REG_READ(pipeA ? VSYNC_A : VSYNC_B);
-       crtc_state->saveDSPSTRIDE = REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE);
+       crtc_state->saveDSPCNTR = REG_READ(map->cntr);
+       crtc_state->savePIPECONF = REG_READ(map->conf);
+       crtc_state->savePIPESRC = REG_READ(map->src);
+       crtc_state->saveFP0 = REG_READ(map->fp0);
+       crtc_state->saveFP1 = REG_READ(map->fp1);
+       crtc_state->saveDPLL = REG_READ(map->dpll);
+       crtc_state->saveHTOTAL = REG_READ(map->htotal);
+       crtc_state->saveHBLANK = REG_READ(map->hblank);
+       crtc_state->saveHSYNC = REG_READ(map->hsync);
+       crtc_state->saveVTOTAL = REG_READ(map->vtotal);
+       crtc_state->saveVBLANK = REG_READ(map->vblank);
+       crtc_state->saveVSYNC = REG_READ(map->vsync);
+       crtc_state->saveDSPSTRIDE = REG_READ(map->stride);
 
        /*NOTE: DSPSIZE DSPPOS only for psb*/
-       crtc_state->saveDSPSIZE = REG_READ(pipeA ? DSPASIZE : DSPBSIZE);
-       crtc_state->saveDSPPOS = REG_READ(pipeA ? DSPAPOS : DSPBPOS);
+       crtc_state->saveDSPSIZE = REG_READ(map->size);
+       crtc_state->saveDSPPOS = REG_READ(map->pos);
 
-       crtc_state->saveDSPBASE = REG_READ(pipeA ? DSPABASE : DSPBBASE);
+       crtc_state->saveDSPBASE = REG_READ(map->base);
 
-       paletteReg = pipeA ? PALETTE_A : PALETTE_B;
+       paletteReg = map->palette;
        for (i = 0; i < 256; ++i)
                crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2));
 }
@@ -898,12 +866,10 @@ static void psb_intel_crtc_save(struct drm_crtc *crtc)
 static void psb_intel_crtc_restore(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       /* struct drm_psb_private * dev_priv =
-                               (struct drm_psb_private *)dev->dev_private; */
+       struct drm_psb_private *dev_priv = dev->dev_private;
        struct psb_intel_crtc *psb_intel_crtc =  to_psb_intel_crtc(crtc);
        struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state;
-       /* struct drm_crtc_helper_funcs * crtc_funcs = crtc->helper_private; */
-       int pipeA = (psb_intel_crtc->pipe == 0);
+       const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe];
        uint32_t paletteReg;
        int i;
 
@@ -913,45 +879,45 @@ static void psb_intel_crtc_restore(struct drm_crtc *crtc)
        }
 
        if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) {
-               REG_WRITE(pipeA ? DPLL_A : DPLL_B,
+               REG_WRITE(map->dpll,
                        crtc_state->saveDPLL & ~DPLL_VCO_ENABLE);
-               REG_READ(pipeA ? DPLL_A : DPLL_B);
+               REG_READ(map->dpll);
                udelay(150);
        }
 
-       REG_WRITE(pipeA ? FPA0 : FPB0, crtc_state->saveFP0);
-       REG_READ(pipeA ? FPA0 : FPB0);
+       REG_WRITE(map->fp0, crtc_state->saveFP0);
+       REG_READ(map->fp0);
 
-       REG_WRITE(pipeA ? FPA1 : FPB1, crtc_state->saveFP1);
-       REG_READ(pipeA ? FPA1 : FPB1);
+       REG_WRITE(map->fp1, crtc_state->saveFP1);
+       REG_READ(map->fp1);
 
-       REG_WRITE(pipeA ? DPLL_A : DPLL_B, crtc_state->saveDPLL);
-       REG_READ(pipeA ? DPLL_A : DPLL_B);
+       REG_WRITE(map->dpll, crtc_state->saveDPLL);
+       REG_READ(map->dpll);
        udelay(150);
 
-       REG_WRITE(pipeA ? HTOTAL_A : HTOTAL_B, crtc_state->saveHTOTAL);
-       REG_WRITE(pipeA ? HBLANK_A : HBLANK_B, crtc_state->saveHBLANK);
-       REG_WRITE(pipeA ? HSYNC_A : HSYNC_B, crtc_state->saveHSYNC);
-       REG_WRITE(pipeA ? VTOTAL_A : VTOTAL_B, crtc_state->saveVTOTAL);
-       REG_WRITE(pipeA ? VBLANK_A : VBLANK_B, crtc_state->saveVBLANK);
-       REG_WRITE(pipeA ? VSYNC_A : VSYNC_B, crtc_state->saveVSYNC);
-       REG_WRITE(pipeA ? DSPASTRIDE : DSPBSTRIDE, crtc_state->saveDSPSTRIDE);
+       REG_WRITE(map->htotal, crtc_state->saveHTOTAL);
+       REG_WRITE(map->hblank, crtc_state->saveHBLANK);
+       REG_WRITE(map->hsync, crtc_state->saveHSYNC);
+       REG_WRITE(map->vtotal, crtc_state->saveVTOTAL);
+       REG_WRITE(map->vblank, crtc_state->saveVBLANK);
+       REG_WRITE(map->vsync, crtc_state->saveVSYNC);
+       REG_WRITE(map->stride, crtc_state->saveDSPSTRIDE);
 
-       REG_WRITE(pipeA ? DSPASIZE : DSPBSIZE, crtc_state->saveDSPSIZE);
-       REG_WRITE(pipeA ? DSPAPOS : DSPBPOS, crtc_state->saveDSPPOS);
+       REG_WRITE(map->size, crtc_state->saveDSPSIZE);
+       REG_WRITE(map->pos, crtc_state->saveDSPPOS);
 
-       REG_WRITE(pipeA ? PIPEASRC : PIPEBSRC, crtc_state->savePIPESRC);
-       REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE);
-       REG_WRITE(pipeA ? PIPEACONF : PIPEBCONF, crtc_state->savePIPECONF);
+       REG_WRITE(map->src, crtc_state->savePIPESRC);
+       REG_WRITE(map->base, crtc_state->saveDSPBASE);
+       REG_WRITE(map->conf, crtc_state->savePIPECONF);
 
        psb_intel_wait_for_vblank(dev);
 
-       REG_WRITE(pipeA ? DSPACNTR : DSPBCNTR, crtc_state->saveDSPCNTR);
-       REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE);
+       REG_WRITE(map->cntr, crtc_state->saveDSPCNTR);
+       REG_WRITE(map->base, crtc_state->saveDSPBASE);
 
        psb_intel_wait_for_vblank(dev);
 
-       paletteReg = pipeA ? PALETTE_A : PALETTE_B;
+       paletteReg = map->palette;
        for (i = 0; i < 256; ++i)
                REG_WRITE(paletteReg + (i << 2), crtc_state->savePalette[i]);
 }
@@ -962,6 +928,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
                                 uint32_t width, uint32_t height)
 {
        struct drm_device *dev = crtc->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
        int pipe = psb_intel_crtc->pipe;
        uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
@@ -969,8 +936,10 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
        uint32_t temp;
        size_t addr = 0;
        struct gtt_range *gt;
+       struct gtt_range *cursor_gt = psb_intel_crtc->cursor_gt;
        struct drm_gem_object *obj;
-       int ret;
+       void *tmp_dst, *tmp_src;
+       int ret, i, cursor_pages;
 
        /* if we want to turn of the cursor ignore width and height */
        if (!handle) {
@@ -1019,10 +988,32 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
                return ret;
        }
 
+       if (dev_priv->ops->cursor_needs_phys) {
+               if (cursor_gt == NULL) {
+                       dev_err(dev->dev, "No hardware cursor mem available");
+                       return -ENOMEM;
+               }
 
-       addr = gt->offset;      /* Or resource.start ??? */
+               /* Prevent overflow */
+               if (gt->npage > 4)
+                       cursor_pages = 4;
+               else
+                       cursor_pages = gt->npage;
+
+               /* Copy the cursor to cursor mem */
+               tmp_dst = dev_priv->vram_addr + cursor_gt->offset;
+               for (i = 0; i < cursor_pages; i++) {
+                       tmp_src = kmap(gt->pages[i]);
+                       memcpy(tmp_dst, tmp_src, PAGE_SIZE);
+                       kunmap(gt->pages[i]);
+                       tmp_dst += PAGE_SIZE;
+               }
 
-       psb_intel_crtc->cursor_addr = addr;
+               addr = psb_intel_crtc->cursor_addr;
+       } else {
+               addr = gt->offset;      /* Or resource.start ??? */
+               psb_intel_crtc->cursor_addr = addr;
+       }
 
        temp = 0;
        /* set the pipe for the cursor */
@@ -1115,34 +1106,30 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev,
                                struct drm_crtc *crtc)
 {
        struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+       struct drm_psb_private *dev_priv = dev->dev_private;
        int pipe = psb_intel_crtc->pipe;
+       const struct psb_offset *map = &dev_priv->regmap[pipe];
        u32 dpll;
        u32 fp;
        struct psb_intel_clock_t clock;
        bool is_lvds;
-       struct drm_psb_private *dev_priv = dev->dev_private;
+       struct psb_pipe *p = &dev_priv->regs.pipe[pipe];
 
        if (gma_power_begin(dev, false)) {
-               dpll = REG_READ((pipe == 0) ? DPLL_A : DPLL_B);
+               dpll = REG_READ(map->dpll);
                if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
-                       fp = REG_READ((pipe == 0) ? FPA0 : FPB0);
+                       fp = REG_READ(map->fp0);
                else
-                       fp = REG_READ((pipe == 0) ? FPA1 : FPB1);
+                       fp = REG_READ(map->fp1);
                is_lvds = (pipe == 1) && (REG_READ(LVDS) & LVDS_PORT_EN);
                gma_power_end(dev);
        } else {
-               dpll = (pipe == 0) ?
-                       dev_priv->regs.psb.saveDPLL_A :
-                       dev_priv->regs.psb.saveDPLL_B;
+               dpll = p->dpll;
 
                if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
-                       fp = (pipe == 0) ?
-                               dev_priv->regs.psb.saveFPA0 :
-                               dev_priv->regs.psb.saveFPB0;
+                       fp = p->fp0;
                else
-                       fp = (pipe == 0) ?
-                               dev_priv->regs.psb.saveFPA1 :
-                               dev_priv->regs.psb.saveFPB1;
+                       fp = p->fp1;
 
                is_lvds = (pipe == 1) && (dev_priv->regs.psb.saveLVDS &
                                                                LVDS_PORT_EN);
@@ -1202,26 +1189,20 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
        int vtot;
        int vsync;
        struct drm_psb_private *dev_priv = dev->dev_private;
+       struct psb_pipe *p = &dev_priv->regs.pipe[pipe];
+       const struct psb_offset *map = &dev_priv->regmap[pipe];
 
        if (gma_power_begin(dev, false)) {
-               htot = REG_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B);
-               hsync = REG_READ((pipe == 0) ? HSYNC_A : HSYNC_B);
-               vtot = REG_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B);
-               vsync = REG_READ((pipe == 0) ? VSYNC_A : VSYNC_B);
+               htot = REG_READ(map->htotal);
+               hsync = REG_READ(map->hsync);
+               vtot = REG_READ(map->vtotal);
+               vsync = REG_READ(map->vsync);
                gma_power_end(dev);
        } else {
-               htot = (pipe == 0) ?
-                       dev_priv->regs.psb.saveHTOTAL_A :
-                       dev_priv->regs.psb.saveHTOTAL_B;
-               hsync = (pipe == 0) ?
-                       dev_priv->regs.psb.saveHSYNC_A :
-                       dev_priv->regs.psb.saveHSYNC_B;
-               vtot = (pipe == 0) ?
-                       dev_priv->regs.psb.saveVTOTAL_A :
-                       dev_priv->regs.psb.saveVTOTAL_B;
-               vsync = (pipe == 0) ?
-                       dev_priv->regs.psb.saveVSYNC_A :
-                       dev_priv->regs.psb.saveVSYNC_B;
+               htot = p->htotal;
+               hsync = p->hsync;
+               vtot = p->vtotal;
+               vsync = p->vsync;
        }
 
        mode = kzalloc(sizeof(*mode), GFP_KERNEL);
@@ -1257,6 +1238,9 @@ void psb_intel_crtc_destroy(struct drm_crtc *crtc)
                drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
                psb_intel_crtc->cursor_obj = NULL;
        }
+
+       if (psb_intel_crtc->cursor_gt != NULL)
+               psb_gtt_free_range(crtc->dev, psb_intel_crtc->cursor_gt);
        kfree(psb_intel_crtc->crtc_state);
        drm_crtc_cleanup(crtc);
        kfree(psb_intel_crtc);
@@ -1285,13 +1269,33 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = {
  * 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)
+static void psb_intel_cursor_init(struct drm_device *dev,
+                                 struct psb_intel_crtc *psb_intel_crtc)
 {
+       struct drm_psb_private *dev_priv = dev->dev_private;
        u32 control[3] = { CURACNTR, CURBCNTR, CURCCNTR };
        u32 base[3] = { CURABASE, CURBBASE, CURCBASE };
+       struct gtt_range *cursor_gt;
+
+       if (dev_priv->ops->cursor_needs_phys) {
+               /* Allocate 4 pages of stolen mem for a hardware cursor. That
+                * is enough for the 64 x 64 ARGB cursors we support.
+                */
+               cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1);
+               if (!cursor_gt) {
+                       psb_intel_crtc->cursor_gt = NULL;
+                       goto out;
+               }
+               psb_intel_crtc->cursor_gt = cursor_gt;
+               psb_intel_crtc->cursor_addr = dev_priv->stolen_base +
+                                                       cursor_gt->offset;
+       } else {
+               psb_intel_crtc->cursor_gt = NULL;
+       }
 
-       REG_WRITE(control[pipe], 0);
-       REG_WRITE(base[pipe], 0);
+out:
+       REG_WRITE(control[psb_intel_crtc->pipe], 0);
+       REG_WRITE(base[psb_intel_crtc->pipe], 0);
 }
 
 void psb_intel_crtc_init(struct drm_device *dev, int pipe,
@@ -1357,7 +1361,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);
+       psb_intel_cursor_init(dev, psb_intel_crtc);
 }
 
 int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,