blob: f47aeb7a203942a3097868ccf65b52cda572c29e [file] [log] [blame]
/**************************************************************************
* 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,
};