summaryrefslogtreecommitdiff
path: root/drivers/staging/gma500/mdfld_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/gma500/mdfld_device.c')
-rw-r--r--drivers/staging/gma500/mdfld_device.c714
1 files changed, 714 insertions, 0 deletions
diff --git a/drivers/staging/gma500/mdfld_device.c b/drivers/staging/gma500/mdfld_device.c
new file mode 100644
index 000000000000..f47aeb7a2039
--- /dev/null
+++ b/drivers/staging/gma500/mdfld_device.c
@@ -0,0 +1,714 @@
+/**************************************************************************
+ * Copyright (c) 2011, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ **************************************************************************/
+
+#include <linux/backlight.h>
+#include <drm/drmP.h>
+#include <drm/drm.h>
+#include "psb_reg.h"
+#include "psb_intel_reg.h"
+#include "psb_drm.h"
+#include "psb_drv.h"
+#include "mdfld_output.h"
+#include "mdfld_dsi_output.h"
+#include "mid_bios.h"
+
+/*
+ * Provide the Medfield specific backlight management
+ */
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+
+static int mdfld_brightness;
+struct backlight_device *mdfld_backlight_device;
+
+static int mfld_set_brightness(struct backlight_device *bd)
+{
+ struct drm_device *dev = bl_get_data(mdfld_backlight_device);
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ int level = bd->props.brightness;
+
+ /* Percentage 1-100% being valid */
+ if (level < 1)
+ level = 1;
+
+ if (gma_power_begin(dev, 0)) {
+ /* Calculate and set the brightness value */
+ u32 adjusted_level;
+
+ /* Adjust the backlight level with the percent in
+ * dev_priv->blc_adj2;
+ */
+ adjusted_level = level * dev_priv->blc_adj2;
+ adjusted_level = adjusted_level / 100;
+#if 0
+#ifndef CONFIG_MDFLD_DSI_DPU
+ if(!(dev_priv->dsr_fb_update & MDFLD_DSR_MIPI_CONTROL) &&
+ (dev_priv->dbi_panel_on || dev_priv->dbi_panel_on2)){
+ mdfld_dsi_dbi_exit_dsr(dev,MDFLD_DSR_MIPI_CONTROL, 0, 0);
+ dev_dbg(dev->dev, "Out of DSR before set brightness to %d.\n",adjusted_level);
+ }
+#endif
+ mdfld_dsi_brightness_control(dev, 0, adjusted_level);
+
+ if ((dev_priv->dbi_panel_on2) || (dev_priv->dpi_panel_on2))
+ mdfld_dsi_brightness_control(dev, 2, adjusted_level);
+#endif
+ gma_power_end(dev);
+ }
+ mdfld_brightness = level;
+ return 0;
+}
+
+int psb_get_brightness(struct backlight_device *bd)
+{
+ /* return locally cached var instead of HW read (due to DPST etc.) */
+ /* FIXME: ideally return actual value in case firmware fiddled with
+ it */
+ return mdfld_brightness;
+}
+
+static const struct backlight_ops mfld_ops = {
+ .get_brightness = psb_get_brightness,
+ .update_status = mfld_set_brightness,
+};
+
+static int mdfld_backlight_init(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct backlight_properties props;
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = 100;
+ props.type = BACKLIGHT_PLATFORM;
+
+ mdfld_backlight_device = backlight_device_register("mfld-bl",
+ NULL, (void *)dev, &mfld_ops, &props);
+
+ if (IS_ERR(mdfld_backlight_device))
+ return PTR_ERR(mdfld_backlight_device);
+
+ dev_priv->blc_adj1 = 100;
+ dev_priv->blc_adj2 = 100;
+ mdfld_backlight_device->props.brightness = 100;
+ mdfld_backlight_device->props.max_brightness = 100;
+ backlight_update_status(mdfld_backlight_device);
+ dev_priv->backlight_device = mdfld_backlight_device;
+ return 0;
+}
+
+#endif
+
+/*
+ * Provide the Medfield specific chip logic and low level methods for
+ * power management.
+ */
+
+static void mdfld_init_pm(struct drm_device *dev)
+{
+ /* No work needed here yet */
+}
+
+/**
+ * mdfld_save_display_registers - save registers for pipe
+ * @dev: our device
+ * @pipe: pipe to save
+ *
+ * Save the pipe state of the device before we power it off. Keep everything
+ * we need to put it back again
+ */
+static int mdfld_save_display_registers(struct drm_device *dev, int pipe)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ int i;
+
+ /* register */
+ u32 dpll_reg = MRST_DPLL_A;
+ u32 fp_reg = MRST_FPA0;
+ u32 pipeconf_reg = PIPEACONF;
+ u32 htot_reg = HTOTAL_A;
+ u32 hblank_reg = HBLANK_A;
+ u32 hsync_reg = HSYNC_A;
+ u32 vtot_reg = VTOTAL_A;
+ u32 vblank_reg = VBLANK_A;
+ u32 vsync_reg = VSYNC_A;
+ u32 pipesrc_reg = PIPEASRC;
+ u32 dspstride_reg = DSPASTRIDE;
+ u32 dsplinoff_reg = DSPALINOFF;
+ u32 dsptileoff_reg = DSPATILEOFF;
+ u32 dspsize_reg = DSPASIZE;
+ u32 dsppos_reg = DSPAPOS;
+ u32 dspsurf_reg = DSPASURF;
+ u32 mipi_reg = MIPI;
+ u32 dspcntr_reg = DSPACNTR;
+ u32 dspstatus_reg = PIPEASTAT;
+ u32 palette_reg = PALETTE_A;
+
+ /* pointer to values */
+ u32 *dpll_val = &dev_priv->saveDPLL_A;
+ u32 *fp_val = &dev_priv->saveFPA0;
+ u32 *pipeconf_val = &dev_priv->savePIPEACONF;
+ u32 *htot_val = &dev_priv->saveHTOTAL_A;
+ u32 *hblank_val = &dev_priv->saveHBLANK_A;
+ u32 *hsync_val = &dev_priv->saveHSYNC_A;
+ u32 *vtot_val = &dev_priv->saveVTOTAL_A;
+ u32 *vblank_val = &dev_priv->saveVBLANK_A;
+ u32 *vsync_val = &dev_priv->saveVSYNC_A;
+ u32 *pipesrc_val = &dev_priv->savePIPEASRC;
+ u32 *dspstride_val = &dev_priv->saveDSPASTRIDE;
+ u32 *dsplinoff_val = &dev_priv->saveDSPALINOFF;
+ u32 *dsptileoff_val = &dev_priv->saveDSPATILEOFF;
+ u32 *dspsize_val = &dev_priv->saveDSPASIZE;
+ u32 *dsppos_val = &dev_priv->saveDSPAPOS;
+ u32 *dspsurf_val = &dev_priv->saveDSPASURF;
+ u32 *mipi_val = &dev_priv->saveMIPI;
+ u32 *dspcntr_val = &dev_priv->saveDSPACNTR;
+ u32 *dspstatus_val = &dev_priv->saveDSPASTATUS;
+ u32 *palette_val = dev_priv->save_palette_a;
+
+ switch (pipe) {
+ case 0:
+ break;
+ case 1:
+ /* register */
+ dpll_reg = MDFLD_DPLL_B;
+ fp_reg = MDFLD_DPLL_DIV0;
+ pipeconf_reg = PIPEBCONF;
+ htot_reg = HTOTAL_B;
+ hblank_reg = HBLANK_B;
+ hsync_reg = HSYNC_B;
+ vtot_reg = VTOTAL_B;
+ vblank_reg = VBLANK_B;
+ vsync_reg = VSYNC_B;
+ pipesrc_reg = PIPEBSRC;
+ dspstride_reg = DSPBSTRIDE;
+ dsplinoff_reg = DSPBLINOFF;
+ dsptileoff_reg = DSPBTILEOFF;
+ dspsize_reg = DSPBSIZE;
+ dsppos_reg = DSPBPOS;
+ dspsurf_reg = DSPBSURF;
+ dspcntr_reg = DSPBCNTR;
+ dspstatus_reg = PIPEBSTAT;
+ palette_reg = PALETTE_B;
+
+ /* values */
+ dpll_val = &dev_priv->saveDPLL_B;
+ fp_val = &dev_priv->saveFPB0;
+ pipeconf_val = &dev_priv->savePIPEBCONF;
+ htot_val = &dev_priv->saveHTOTAL_B;
+ hblank_val = &dev_priv->saveHBLANK_B;
+ hsync_val = &dev_priv->saveHSYNC_B;
+ vtot_val = &dev_priv->saveVTOTAL_B;
+ vblank_val = &dev_priv->saveVBLANK_B;
+ vsync_val = &dev_priv->saveVSYNC_B;
+ pipesrc_val = &dev_priv->savePIPEBSRC;
+ dspstride_val = &dev_priv->saveDSPBSTRIDE;
+ dsplinoff_val = &dev_priv->saveDSPBLINOFF;
+ dsptileoff_val = &dev_priv->saveDSPBTILEOFF;
+ dspsize_val = &dev_priv->saveDSPBSIZE;
+ dsppos_val = &dev_priv->saveDSPBPOS;
+ dspsurf_val = &dev_priv->saveDSPBSURF;
+ dspcntr_val = &dev_priv->saveDSPBCNTR;
+ dspstatus_val = &dev_priv->saveDSPBSTATUS;
+ palette_val = dev_priv->save_palette_b;
+ break;
+ case 2:
+ /* register */
+ pipeconf_reg = PIPECCONF;
+ htot_reg = HTOTAL_C;
+ hblank_reg = HBLANK_C;
+ hsync_reg = HSYNC_C;
+ vtot_reg = VTOTAL_C;
+ vblank_reg = VBLANK_C;
+ vsync_reg = VSYNC_C;
+ pipesrc_reg = PIPECSRC;
+ dspstride_reg = DSPCSTRIDE;
+ dsplinoff_reg = DSPCLINOFF;
+ dsptileoff_reg = DSPCTILEOFF;
+ dspsize_reg = DSPCSIZE;
+ dsppos_reg = DSPCPOS;
+ dspsurf_reg = DSPCSURF;
+ mipi_reg = MIPI_C;
+ dspcntr_reg = DSPCCNTR;
+ dspstatus_reg = PIPECSTAT;
+ palette_reg = PALETTE_C;
+
+ /* pointer to values */
+ pipeconf_val = &dev_priv->savePIPECCONF;
+ htot_val = &dev_priv->saveHTOTAL_C;
+ hblank_val = &dev_priv->saveHBLANK_C;
+ hsync_val = &dev_priv->saveHSYNC_C;
+ vtot_val = &dev_priv->saveVTOTAL_C;
+ vblank_val = &dev_priv->saveVBLANK_C;
+ vsync_val = &dev_priv->saveVSYNC_C;
+ pipesrc_val = &dev_priv->savePIPECSRC;
+ dspstride_val = &dev_priv->saveDSPCSTRIDE;
+ dsplinoff_val = &dev_priv->saveDSPCLINOFF;
+ dsptileoff_val = &dev_priv->saveDSPCTILEOFF;
+ dspsize_val = &dev_priv->saveDSPCSIZE;
+ dsppos_val = &dev_priv->saveDSPCPOS;
+ dspsurf_val = &dev_priv->saveDSPCSURF;
+ mipi_val = &dev_priv->saveMIPI_C;
+ dspcntr_val = &dev_priv->saveDSPCCNTR;
+ dspstatus_val = &dev_priv->saveDSPCSTATUS;
+ palette_val = dev_priv->save_palette_c;
+ break;
+ default:
+ DRM_ERROR("%s, invalid pipe number.\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Pipe & plane A info */
+ *dpll_val = PSB_RVDC32(dpll_reg);
+ *fp_val = PSB_RVDC32(fp_reg);
+ *pipeconf_val = PSB_RVDC32(pipeconf_reg);
+ *htot_val = PSB_RVDC32(htot_reg);
+ *hblank_val = PSB_RVDC32(hblank_reg);
+ *hsync_val = PSB_RVDC32(hsync_reg);
+ *vtot_val = PSB_RVDC32(vtot_reg);
+ *vblank_val = PSB_RVDC32(vblank_reg);
+ *vsync_val = PSB_RVDC32(vsync_reg);
+ *pipesrc_val = PSB_RVDC32(pipesrc_reg);
+ *dspstride_val = PSB_RVDC32(dspstride_reg);
+ *dsplinoff_val = PSB_RVDC32(dsplinoff_reg);
+ *dsptileoff_val = PSB_RVDC32(dsptileoff_reg);
+ *dspsize_val = PSB_RVDC32(dspsize_reg);
+ *dsppos_val = PSB_RVDC32(dsppos_reg);
+ *dspsurf_val = PSB_RVDC32(dspsurf_reg);
+ *dspcntr_val = PSB_RVDC32(dspcntr_reg);
+ *dspstatus_val = PSB_RVDC32(dspstatus_reg);
+
+ /*save palette (gamma) */
+ for (i = 0; i < 256; i++)
+ palette_val[i] = PSB_RVDC32(palette_reg + (i<<2));
+
+ if (pipe == 1) {
+ dev_priv->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
+ dev_priv->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
+ dev_priv->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
+ dev_priv->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
+ return 0;
+ }
+ *mipi_val = PSB_RVDC32(mipi_reg);
+ return 0;
+}
+
+/**
+ * mdfld_save_cursor_overlay_registers - save cursor overlay info
+ * @dev: our device
+ *
+ * Save the cursor and overlay register state
+ */
+static int mdfld_save_cursor_overlay_registers(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+
+ /* Save cursor regs */
+ dev_priv->saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR);
+ dev_priv->saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE);
+ dev_priv->saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS);
+
+ dev_priv->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR);
+ dev_priv->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE);
+ dev_priv->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS);
+
+ dev_priv->saveDSPCCURSOR_CTRL = PSB_RVDC32(CURCCNTR);
+ dev_priv->saveDSPCCURSOR_BASE = PSB_RVDC32(CURCBASE);
+ dev_priv->saveDSPCCURSOR_POS = PSB_RVDC32(CURCPOS);
+
+ /* HW overlay */
+ dev_priv->saveOV_OVADD = PSB_RVDC32(OV_OVADD);
+ dev_priv->saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0);
+ dev_priv->saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1);
+ dev_priv->saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2);
+ dev_priv->saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3);
+ dev_priv->saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4);
+ dev_priv->saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5);
+
+ dev_priv->saveOV_OVADD_C = PSB_RVDC32(OV_OVADD + OV_C_OFFSET);
+ dev_priv->saveOV_OGAMC0_C = PSB_RVDC32(OV_OGAMC0 + OV_C_OFFSET);
+ dev_priv->saveOV_OGAMC1_C = PSB_RVDC32(OV_OGAMC1 + OV_C_OFFSET);
+ dev_priv->saveOV_OGAMC2_C = PSB_RVDC32(OV_OGAMC2 + OV_C_OFFSET);
+ dev_priv->saveOV_OGAMC3_C = PSB_RVDC32(OV_OGAMC3 + OV_C_OFFSET);
+ dev_priv->saveOV_OGAMC4_C = PSB_RVDC32(OV_OGAMC4 + OV_C_OFFSET);
+ dev_priv->saveOV_OGAMC5_C = PSB_RVDC32(OV_OGAMC5 + OV_C_OFFSET);
+
+ return 0;
+}
+/*
+ * mdfld_restore_display_registers - restore the state of a pipe
+ * @dev: our device
+ * @pipe: the pipe to restore
+ *
+ * Restore the state of a pipe to that which was saved by the register save
+ * functions.
+ */
+static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
+{
+ /* To get panel out of ULPS mode */
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct mdfld_dsi_config *dsi_config = NULL;
+ u32 i = 0;
+ u32 dpll = 0;
+ u32 timeout = 0;
+ u32 reg_offset = 0;
+
+ /* register */
+ u32 dpll_reg = MRST_DPLL_A;
+ u32 fp_reg = MRST_FPA0;
+ u32 pipeconf_reg = PIPEACONF;
+ u32 htot_reg = HTOTAL_A;
+ u32 hblank_reg = HBLANK_A;
+ u32 hsync_reg = HSYNC_A;
+ u32 vtot_reg = VTOTAL_A;
+ u32 vblank_reg = VBLANK_A;
+ u32 vsync_reg = VSYNC_A;
+ u32 pipesrc_reg = PIPEASRC;
+ u32 dspstride_reg = DSPASTRIDE;
+ u32 dsplinoff_reg = DSPALINOFF;
+ u32 dsptileoff_reg = DSPATILEOFF;
+ u32 dspsize_reg = DSPASIZE;
+ u32 dsppos_reg = DSPAPOS;
+ u32 dspsurf_reg = DSPASURF;
+ u32 dspstatus_reg = PIPEASTAT;
+ u32 mipi_reg = MIPI;
+ u32 dspcntr_reg = DSPACNTR;
+ u32 palette_reg = PALETTE_A;
+
+ /* values */
+ u32 dpll_val = dev_priv->saveDPLL_A & ~DPLL_VCO_ENABLE;
+ u32 fp_val = dev_priv->saveFPA0;
+ u32 pipeconf_val = dev_priv->savePIPEACONF;
+ u32 htot_val = dev_priv->saveHTOTAL_A;
+ u32 hblank_val = dev_priv->saveHBLANK_A;
+ u32 hsync_val = dev_priv->saveHSYNC_A;
+ u32 vtot_val = dev_priv->saveVTOTAL_A;
+ u32 vblank_val = dev_priv->saveVBLANK_A;
+ u32 vsync_val = dev_priv->saveVSYNC_A;
+ u32 pipesrc_val = dev_priv->savePIPEASRC;
+ u32 dspstride_val = dev_priv->saveDSPASTRIDE;
+ u32 dsplinoff_val = dev_priv->saveDSPALINOFF;
+ u32 dsptileoff_val = dev_priv->saveDSPATILEOFF;
+ u32 dspsize_val = dev_priv->saveDSPASIZE;
+ u32 dsppos_val = dev_priv->saveDSPAPOS;
+ u32 dspsurf_val = dev_priv->saveDSPASURF;
+ u32 dspstatus_val = dev_priv->saveDSPASTATUS;
+ u32 mipi_val = dev_priv->saveMIPI;
+ u32 dspcntr_val = dev_priv->saveDSPACNTR;
+ u32 *palette_val = dev_priv->save_palette_a;
+
+ switch (pipe) {
+ case 0:
+ dsi_config = dev_priv->dsi_configs[0];
+ break;
+ case 1:
+ /* register */
+ dpll_reg = MDFLD_DPLL_B;
+ fp_reg = MDFLD_DPLL_DIV0;
+ pipeconf_reg = PIPEBCONF;
+ htot_reg = HTOTAL_B;
+ hblank_reg = HBLANK_B;
+ hsync_reg = HSYNC_B;
+ vtot_reg = VTOTAL_B;
+ vblank_reg = VBLANK_B;
+ vsync_reg = VSYNC_B;
+ pipesrc_reg = PIPEBSRC;
+ dspstride_reg = DSPBSTRIDE;
+ dsplinoff_reg = DSPBLINOFF;
+ dsptileoff_reg = DSPBTILEOFF;
+ dspsize_reg = DSPBSIZE;
+ dsppos_reg = DSPBPOS;
+ dspsurf_reg = DSPBSURF;
+ dspcntr_reg = DSPBCNTR;
+ palette_reg = PALETTE_B;
+ dspstatus_reg = PIPEBSTAT;
+
+ /* values */
+ dpll_val = dev_priv->saveDPLL_B & ~DPLL_VCO_ENABLE;
+ fp_val = dev_priv->saveFPB0;
+ pipeconf_val = dev_priv->savePIPEBCONF;
+ htot_val = dev_priv->saveHTOTAL_B;
+ hblank_val = dev_priv->saveHBLANK_B;
+ hsync_val = dev_priv->saveHSYNC_B;
+ vtot_val = dev_priv->saveVTOTAL_B;
+ vblank_val = dev_priv->saveVBLANK_B;
+ vsync_val = dev_priv->saveVSYNC_B;
+ pipesrc_val = dev_priv->savePIPEBSRC;
+ dspstride_val = dev_priv->saveDSPBSTRIDE;
+ dsplinoff_val = dev_priv->saveDSPBLINOFF;
+ dsptileoff_val = dev_priv->saveDSPBTILEOFF;
+ dspsize_val = dev_priv->saveDSPBSIZE;
+ dsppos_val = dev_priv->saveDSPBPOS;
+ dspsurf_val = dev_priv->saveDSPBSURF;
+ dspcntr_val = dev_priv->saveDSPBCNTR;
+ dspstatus_val = dev_priv->saveDSPBSTATUS;
+ palette_val = dev_priv->save_palette_b;
+ break;
+ case 2:
+ reg_offset = MIPIC_REG_OFFSET;
+
+ /* register */
+ pipeconf_reg = PIPECCONF;
+ htot_reg = HTOTAL_C;
+ hblank_reg = HBLANK_C;
+ hsync_reg = HSYNC_C;
+ vtot_reg = VTOTAL_C;
+ vblank_reg = VBLANK_C;
+ vsync_reg = VSYNC_C;
+ pipesrc_reg = PIPECSRC;
+ dspstride_reg = DSPCSTRIDE;
+ dsplinoff_reg = DSPCLINOFF;
+ dsptileoff_reg = DSPCTILEOFF;
+ dspsize_reg = DSPCSIZE;
+ dsppos_reg = DSPCPOS;
+ dspsurf_reg = DSPCSURF;
+ mipi_reg = MIPI_C;
+ dspcntr_reg = DSPCCNTR;
+ palette_reg = PALETTE_C;
+ dspstatus_reg = PIPECSTAT;
+
+ /* values */
+ pipeconf_val = dev_priv->savePIPECCONF;
+ htot_val = dev_priv->saveHTOTAL_C;
+ hblank_val = dev_priv->saveHBLANK_C;
+ hsync_val = dev_priv->saveHSYNC_C;
+ vtot_val = dev_priv->saveVTOTAL_C;
+ vblank_val = dev_priv->saveVBLANK_C;
+ vsync_val = dev_priv->saveVSYNC_C;
+ pipesrc_val = dev_priv->savePIPECSRC;
+ dspstride_val = dev_priv->saveDSPCSTRIDE;
+ dsplinoff_val = dev_priv->saveDSPCLINOFF;
+ dsptileoff_val = dev_priv->saveDSPCTILEOFF;
+ dspsize_val = dev_priv->saveDSPCSIZE;
+ dsppos_val = dev_priv->saveDSPCPOS;
+ dspsurf_val = dev_priv->saveDSPCSURF;
+ dspstatus_val = dev_priv->saveDSPCSTATUS;
+ mipi_val = dev_priv->saveMIPI_C;
+ dspcntr_val = dev_priv->saveDSPCCNTR;
+ palette_val = dev_priv->save_palette_c;
+
+ dsi_config = dev_priv->dsi_configs[1];
+ break;
+ default:
+ DRM_ERROR("%s, invalid pipe number.\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Make sure VGA plane is off. it initializes to on after reset!*/
+ PSB_WVDC32(0x80000000, VGACNTRL);
+ if (pipe == 1) {
+ PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, dpll_reg);
+ PSB_RVDC32(dpll_reg);
+
+ PSB_WVDC32(fp_val, fp_reg);
+ } else {
+ dpll = PSB_RVDC32(dpll_reg);
+
+ if (!(dpll & DPLL_VCO_ENABLE)) {
+
+ /* When ungating power of DPLL, needs to wait 0.5us before enable the VCO */
+ if (dpll & MDFLD_PWR_GATE_EN) {
+ dpll &= ~MDFLD_PWR_GATE_EN;
+ PSB_WVDC32(dpll, dpll_reg);
+ udelay(500); /* FIXME: 1 ? */
+ }
+
+ PSB_WVDC32(fp_val, fp_reg);
+ PSB_WVDC32(dpll_val, dpll_reg);
+ /* FIXME_MDFLD PO - change 500 to 1 after PO */
+ udelay(500);
+
+ dpll_val |= DPLL_VCO_ENABLE;
+ PSB_WVDC32(dpll_val, dpll_reg);
+ PSB_RVDC32(dpll_reg);
+
+ /* wait for DSI PLL to lock */
+ while ((timeout < 20000) && !(PSB_RVDC32(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+ udelay(150);
+ timeout++;
+ }
+
+ if (timeout == 20000) {
+ DRM_ERROR("%s, can't lock DSIPLL.\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+ }
+ /* Restore mode */
+ PSB_WVDC32(htot_val, htot_reg);
+ PSB_WVDC32(hblank_val, hblank_reg);
+ PSB_WVDC32(hsync_val, hsync_reg);
+ PSB_WVDC32(vtot_val, vtot_reg);
+ PSB_WVDC32(vblank_val, vblank_reg);
+ PSB_WVDC32(vsync_val, vsync_reg);
+ PSB_WVDC32(pipesrc_val, pipesrc_reg);
+ PSB_WVDC32(dspstatus_val, dspstatus_reg);
+
+ /* Set up the plane */
+ PSB_WVDC32(dspstride_val, dspstride_reg);
+ PSB_WVDC32(dsplinoff_val, dsplinoff_reg);
+ PSB_WVDC32(dsptileoff_val, dsptileoff_reg);
+ PSB_WVDC32(dspsize_val, dspsize_reg);
+ PSB_WVDC32(dsppos_val, dsppos_reg);
+ PSB_WVDC32(dspsurf_val, dspsurf_reg);
+
+ if (pipe == 1) {
+ PSB_WVDC32(dev_priv->savePFIT_CONTROL, PFIT_CONTROL);
+ PSB_WVDC32(dev_priv->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
+ PSB_WVDC32(dev_priv->saveHDMIPHYMISCCTL, HDMIPHYMISCCTL);
+ PSB_WVDC32(dev_priv->saveHDMIB_CONTROL, HDMIB_CONTROL);
+
+ } else {
+ /* Set up pipe related registers */
+ PSB_WVDC32(mipi_val, mipi_reg);
+ /* Setup MIPI adapter + MIPI IP registers */
+ mdfld_dsi_controller_init(dsi_config, pipe);
+ msleep(20);
+ }
+ /* Enable the plane */
+ PSB_WVDC32(dspcntr_val, dspcntr_reg);
+ msleep(20);
+ /* Enable the pipe */
+ PSB_WVDC32(pipeconf_val, pipeconf_reg);
+
+ for (i = 0; i < 256; i++)
+ PSB_WVDC32(palette_val[i], palette_reg + (i<<2));
+ if (pipe == 1)
+ return 0;
+ if (!mdfld_panel_dpi(dev))
+ mdfld_enable_te(dev, pipe);
+ return 0;
+}
+
+/**
+ * mdfld_restore_cursor_overlay_registers - restore cursor
+ * @dev: our device
+ *
+ * Restore the cursor and overlay state that was saved earlier
+ */
+static int mdfld_restore_cursor_overlay_registers(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+
+ /* Enable Cursor A */
+ PSB_WVDC32(dev_priv->saveDSPACURSOR_CTRL, CURACNTR);
+ PSB_WVDC32(dev_priv->saveDSPACURSOR_POS, CURAPOS);
+ PSB_WVDC32(dev_priv->saveDSPACURSOR_BASE, CURABASE);
+
+ PSB_WVDC32(dev_priv->saveDSPBCURSOR_CTRL, CURBCNTR);
+ PSB_WVDC32(dev_priv->saveDSPBCURSOR_POS, CURBPOS);
+ PSB_WVDC32(dev_priv->saveDSPBCURSOR_BASE, CURBBASE);
+
+ PSB_WVDC32(dev_priv->saveDSPCCURSOR_CTRL, CURCCNTR);
+ PSB_WVDC32(dev_priv->saveDSPCCURSOR_POS, CURCPOS);
+ PSB_WVDC32(dev_priv->saveDSPCCURSOR_BASE, CURCBASE);
+
+ /* Restore HW overlay */
+ PSB_WVDC32(dev_priv->saveOV_OVADD, OV_OVADD);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC0, OV_OGAMC0);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC1, OV_OGAMC1);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC2, OV_OGAMC2);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC3, OV_OGAMC3);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC4, OV_OGAMC4);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC5, OV_OGAMC5);
+
+ PSB_WVDC32(dev_priv->saveOV_OVADD_C, OV_OVADD + OV_C_OFFSET);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC0_C, OV_OGAMC0 + OV_C_OFFSET);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC1_C, OV_OGAMC1 + OV_C_OFFSET);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC2_C, OV_OGAMC2 + OV_C_OFFSET);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC3_C, OV_OGAMC3 + OV_C_OFFSET);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC4_C, OV_OGAMC4 + OV_C_OFFSET);
+ PSB_WVDC32(dev_priv->saveOV_OGAMC5_C, OV_OGAMC5 + OV_C_OFFSET);
+
+ return 0;
+}
+
+/**
+ * mdfld_save_display_registers - save registers lost on suspend
+ * @dev: our DRM device
+ *
+ * Save the state we need in order to be able to restore the interface
+ * upon resume from suspend
+ */
+static int mdfld_save_registers(struct drm_device *dev)
+{
+ /* FIXME: We need to shut down panels here if using them
+ and once the right bits are merged */
+ mdfld_save_cursor_overlay_registers(dev);
+ mdfld_save_display_registers(dev, 0);
+ mdfld_save_display_registers(dev, 0);
+ mdfld_save_display_registers(dev, 2);
+ mdfld_save_display_registers(dev, 1);
+ mdfld_disable_crtc(dev, 0);
+ mdfld_disable_crtc(dev, 2);
+ mdfld_disable_crtc(dev, 1);
+ return 0;
+}
+
+/**
+ * mdfld_restore_display_registers - restore lost register state
+ * @dev: our DRM device
+ *
+ * Restore register state that was lost during suspend and resume.
+ */
+static int mdfld_restore_registers(struct drm_device *dev)
+{
+ mdfld_restore_display_registers(dev, 1);
+ mdfld_restore_display_registers(dev, 0);
+ mdfld_restore_display_registers(dev, 2);
+ mdfld_restore_cursor_overlay_registers(dev);
+ return 0;
+}
+
+static int mdfld_power_down(struct drm_device *dev)
+{
+ /* FIXME */
+ return 0;
+}
+
+static int mdfld_power_up(struct drm_device *dev)
+{
+ /* FIXME */
+ return 0;
+}
+
+const struct psb_ops mdfld_chip_ops = {
+ .name = "Medfield",
+ .accel_2d = 0,
+ .pipes = 3,
+ .crtcs = 2,
+ .sgx_offset = MRST_SGX_OFFSET,
+
+ .chip_setup = mid_chip_setup,
+
+ .crtc_helper = &mdfld_helper_funcs,
+ .crtc_funcs = &mdfld_intel_crtc_funcs,
+
+ .output_init = mdfld_output_init,
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+ .backlight_init = mdfld_backlight_init,
+#endif
+
+ .init_pm = mdfld_init_pm,
+ .save_regs = mdfld_save_registers,
+ .restore_regs = mdfld_restore_registers,
+ .power_down = mdfld_power_down,
+ .power_up = mdfld_power_up,
+};
+