/** * 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; }