/**
 * Power off sequence for video mode MIPI panel.
 * NOTE: do NOT modify this function
 */
static int __dpi_panel_power_off(struct mdfld_dsi_config *dsi_config,
		struct panel_funcs *p_funcs)
{
	u32 val = 0;
	u32 tmp = 0;
	struct mdfld_dsi_hw_registers *regs;
	struct mdfld_dsi_hw_context *ctx;
	struct drm_device *dev;
	struct drm_psb_private *dev_priv;
	int retry;
	int i;
	int err = 0;
	u32 guit_val = 0;
	u32 power_island = 0;
	int offset = 0;

	PSB_DEBUG_ENTRY("\n");

	if (!dsi_config)
		return -EINVAL;

	regs = &dsi_config->regs;
	ctx = &dsi_config->dsi_hw_context;
	dev = dsi_config->dev;
	dev_priv = dev->dev_private;

	/* Don't reset brightness to 0.*/
	ctx->lastbrightnesslevel = psb_brightness;

	tmp = REG_READ(regs->pipeconf_reg);

	/*save color_coef (chrome) */
	for (i = 0; i < 6; i++)
		ctx->color_coef[i] = REG_READ(regs->color_coef_reg + (i<<2));

	/* save palette (gamma) */
	for (i = 0; i < 256; i++)
		ctx->palette[i] = REG_READ(regs->palette_reg + (i<<2));

	/*
	 * Couldn't disable the pipe until DRM_WAIT_ON signaled by last
	 * vblank event when playing video, otherwise the last vblank event
	 * will lost when pipe disabled before vblank interrupt coming
	 * sometimes.
	 */

	/*Disable panel*/
	val = ctx->dspcntr;
	REG_WRITE(regs->dspcntr_reg, (val & ~BIT31));
	/*Disable overlay & cursor panel assigned to this pipe*/
	REG_WRITE(regs->pipeconf_reg, (tmp | (0x000c0000)));

	/*Disable pipe*/
	val = REG_READ(regs->pipeconf_reg);
	ctx->pipeconf = val;
	REG_WRITE(regs->pipeconf_reg, (val & ~BIT31));

	/*wait for pipe disabling,
	  pipe synchronization plus , only avaiable when
	  timer generator is working*/
	if (REG_READ(regs->mipi_reg) & BIT31) {
		retry = 100000;
		while (--retry && (REG_READ(regs->pipeconf_reg) & BIT30))
			udelay(5);

		if (!retry) {
			DRM_ERROR("Failed to disable pipe\n");
			err = -EAGAIN;
			goto power_off_err;
		}
	}

	/**
	 * Different panel may have different ways to have
	 * panel turned off. Support it!
	 */
	if (p_funcs && p_funcs->power_off) {
		if (p_funcs->power_off(dsi_config)) {
			DRM_ERROR("Failed to power off panel\n");
			err = -EAGAIN;
			goto power_off_err;
		}
	}

	/*Disable MIPI port*/
	REG_WRITE(regs->mipi_reg, (REG_READ(regs->mipi_reg) & ~BIT31));

	/*clear Low power output hold*/
	REG_WRITE(regs->mipi_reg, (REG_READ(regs->mipi_reg) & ~BIT16));

	/*Disable DSI controller*/
	REG_WRITE(regs->device_ready_reg, (ctx->device_ready & ~BIT0));

	/*enter ULPS*/
	__dpi_enter_ulps_locked(dsi_config, offset);

	if (is_dual_dsi(dev)) {
		offset = 0x1000;
		/*Disable MIPI port*/
		REG_WRITE(regs->mipi_reg, (REG_READ(regs->mipi_reg) & ~BIT31));

		/*clear Low power output hold*/
		REG_WRITE(regs->mipi_reg, (REG_READ(regs->mipi_reg) & ~BIT16));
		offset = 0x800;
		/*Disable DSI controller*/
		REG_WRITE(regs->device_ready_reg, (ctx->device_ready & ~BIT0));

		/*enter ULPS*/
		__dpi_enter_ulps_locked(dsi_config, offset);
		offset = 0x0;
	}

	/* Disable DSI PLL */
	intel_mid_msgbus_write32(CCK_PORT, DSI_PLL_DIV_REG, 0);
	guit_val = intel_mid_msgbus_read32(CCK_PORT, DSI_PLL_CTRL_REG);
	intel_mid_msgbus_write32(CCK_PORT, DSI_PLL_CTRL_REG, _DSI_LDO_EN);

power_off_err:
	power_island = pipe_to_island(dsi_config->pipe);

	if (power_island & (OSPM_DISPLAY_A | OSPM_DISPLAY_C))
		power_island |= OSPM_DISPLAY_MIO;

	if (is_dual_dsi(dev))
		power_island |= OSPM_DISPLAY_C;

	if (!power_island_put(power_island))
		return -EINVAL;

	return err;
}
/**
 * Power off sequence for video mode MIPI panel.
 * NOTE: do NOT modify this function
 */
static int __dpi_panel_power_off(struct mdfld_dsi_config *dsi_config,
                                 struct panel_funcs *p_funcs)
{
    u32 val = 0;
    u32 tmp = 0;
    struct mdfld_dsi_hw_registers *regs;
    struct mdfld_dsi_hw_context *ctx;
    struct drm_device *dev;
    struct drm_psb_private *dev_priv;
    int retry;
    int i;
    int pipe0_enabled;
    int pipe2_enabled;
    int err = 0;
    if (!dsi_config)
        return -EINVAL;

    regs = &dsi_config->regs;
    ctx = &dsi_config->dsi_hw_context;
    dev = dsi_config->dev;
    dev_priv = dev->dev_private;

    if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND,
                                   OSPM_UHB_FORCE_POWER_ON))
        return -EAGAIN;

    ctx->lastbrightnesslevel = psb_brightness;
    if (p_funcs && p_funcs->set_brightness)
        if (p_funcs->set_brightness(dsi_config, 0))
            DRM_ERROR("Failed to set panel brightness\n");

    /*Notify PVR module that screen is off*/
    if (dev_priv->pvr_screen_event_handler)
        dev_priv->pvr_screen_event_handler(dev, 0);

    /*save the plane informaton, for it will updated*/
    ctx->dspsurf = REG_READ(regs->dspsurf_reg);
    ctx->dsplinoff = REG_READ(regs->dsplinoff_reg);
    ctx->dspsize = REG_READ(regs->dspsize_reg);
    ctx->pipestat = REG_READ(regs->pipestat_reg);
    ctx->dspcntr = REG_READ(regs->dspcntr_reg);
    ctx->dspstride= REG_READ(regs->dspstride_reg);

    tmp = REG_READ(regs->pipeconf_reg);

    /*save color_coef (chrome) */
    for (i = 0; i < 6; i++) {
        ctx->color_coef[i] = REG_READ(regs->color_coef_reg + (i<<2));
    }

    /* save palette (gamma) */
    for (i = 0; i < 256; i++)
        ctx->palette[i] = REG_READ(regs->palette_reg + (i<<2));

    /* restore gamma correction max (RGB) */
    REG_WRITE(regs->gamma_red_max_reg, ctx->gamma_red_max);
    REG_WRITE(regs->gamma_green_max_reg, ctx->gamma_green_max);
    REG_WRITE(regs->gamma_blue_max_reg, ctx->gamma_blue_max);

    /*
     * Couldn't disable the pipe until DRM_WAIT_ON signaled by last
     * vblank event when playing video, otherwise the last vblank event
     * will lost when pipe disabled before vblank interrupt coming sometimes.
     */

    /*Disable panel*/
    val = ctx->dspcntr;
    val &= ~(PIPEACONF_COLOR_MATRIX_ENABLE | PIPEACONF_GAMMA);
    REG_WRITE(regs->dspcntr_reg, (val & ~BIT31));
    /*Disable overlay & cursor panel assigned to this pipe*/
    REG_WRITE(regs->pipeconf_reg, (tmp | (0x000c0000)));

    /*Disable pipe*/
    val = REG_READ(regs->pipeconf_reg);
    ctx->pipeconf = val;
    REG_WRITE(regs->pipeconf_reg, (val & ~BIT31));

    /*wait for pipe disabling,
    pipe synchronization plus , only avaiable when
    timer generator is working*/
    if (REG_READ(regs->mipi_reg) & BIT31) {
        retry = 100000;
        while (--retry && (REG_READ(regs->pipeconf_reg) & BIT30))
            udelay(5);

        if (!retry) {
            DRM_ERROR("Failed to disable pipe\n");
            err = -EAGAIN;
            goto power_off_err;
        }
    }
    /*Disable MIPI port*/
    REG_WRITE(regs->mipi_reg, (REG_READ(regs->mipi_reg) & ~BIT31));

    /**
     * Different panel may have different ways to have
     * panel turned off. Support it!
     */
    if (p_funcs && p_funcs->power_off) {
        if (p_funcs->power_off(dsi_config)) {
            DRM_ERROR("Failed to power off panel\n");
            err = -EAGAIN;
            goto power_off_err;
        }
    }

    /* check latch out, expected to be lp00 */
    intel_dc_dsi_check_latch_out(dsi_config);

    /*Set clock stopping*/
    REG_WRITE(regs->eot_disable_reg, (REG_READ(regs->eot_disable_reg) | BIT1));

    /* clear device ready and reset device ready
     * to make clock stopping setting take effects.
     */
    REG_WRITE(regs->device_ready_reg, (REG_READ(regs->device_ready_reg) & ~BIT0));
    REG_WRITE(regs->device_ready_reg, (REG_READ(regs->device_ready_reg) | BIT0));

    /* check latch out, expected to be lp11 */
    intel_dc_dsi_check_latch_out(dsi_config);

    if (__dpi_enter_ulps_locked(dsi_config)) {
        DRM_ERROR("Faild to enter ULPS\n");
        goto power_off_err;
    }

    /*Disable DSI PLL*/
    pipe0_enabled = (REG_READ(PIPEACONF) & BIT31) ? 1 : 0;
    pipe2_enabled = (REG_READ(PIPECCONF) & BIT31) ? 1 : 0;

    if (!pipe0_enabled && !pipe2_enabled) {
        REG_WRITE(regs->dpll_reg , 0x0);
        /*power gate pll*/
        REG_WRITE(regs->dpll_reg, BIT30);
    }

power_off_err:
    ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
    return err;
}