/** * 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 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; ctx->dsparb = REG_READ(DSPARB); ctx->dsparb2 = REG_READ(DSPARB2); /* Don't reset brightness to 0.*/ ctx->lastbrightnesslevel = psb_brightness; tmp = REG_READ(regs->pipeconf_reg); ctx->dspcntr = REG_READ(regs->dspcntr_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"); if (IS_MOFD(dev)) { /* * FIXME: turn off the power island directly * although failed to disable pipe. */ err = 0; } else 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; } 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; }
void psb_RecalcAlternativeOutput(object_context_p obj_context) { psb_driver_data_p driver_data = obj_context->driver_data; object_surface_p obj_surface = obj_context->current_render_target; int angle, new_rotate, i; int old_rotate = driver_data->msvdx_rotate_want; int mode = INIT_VALUE; #ifdef TARGET_HAS_MULTIPLE_DISPLAY mode = psb_android_get_mds_mode((void*)driver_data->ws_priv); #endif if (mode != INIT_VALUE) { // clear device rotation info if (driver_data->mipi0_rotation != VA_ROTATION_NONE) { driver_data->mipi0_rotation = VA_ROTATION_NONE; driver_data->hdmi_rotation = VA_ROTATION_NONE; } // Disable msvdx rotation if // WIDI video is play and meta data rotation angle is 0 if (mode == WIDI_VIDEO_ISPLAYING) { if (driver_data->va_rotate == VA_ROTATION_NONE) driver_data->disable_msvdx_rotate = 1; else { driver_data->mipi0_rotation = 0; driver_data->hdmi_rotation = 0; driver_data->disable_msvdx_rotate = 0; } } else { if (IS_MOFD(driver_data)) driver_data->disable_msvdx_rotate = 1; else driver_data->disable_msvdx_rotate = driver_data->disable_msvdx_rotate_backup; } } else if (IS_MOFD(driver_data)) { /* Moorefield has overlay rotaion, so decoder doesn't generate rotation * output according to windows manager. It is controlled by payload info * in which HWC signal decoder to generate rotation output */ long long hwc_timestamp = 0; int index = -1; for (i = 0; i < obj_context->num_render_targets; i++) { object_surface_p obj_surface = SURFACE(obj_context->render_targets[i]); /* traverse all surfaces' share info to find out the latest transform info */ if (obj_surface && obj_surface->share_info) { if (obj_surface->share_info->hwc_timestamp > hwc_timestamp) { hwc_timestamp = obj_surface->share_info->hwc_timestamp; index = i; } } } if (index >= 0) { object_surface_p obj_surface = SURFACE(obj_context->render_targets[index]); if (obj_surface && obj_surface->share_info) { int transform = obj_surface->share_info->layer_transform; driver_data->mipi0_rotation = HAL2VAROTATION(transform); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Signal from HWC to rotate %d\n", driver_data->mipi0_rotation); } } } else if (driver_data->native_window) { int display_rotate = 0; psb_android_surfaceflinger_rotate(driver_data->native_window, &display_rotate); drv_debug_msg(VIDEO_DEBUG_GENERAL, "NativeWindow(0x%x), get surface flinger rotate %d\n", driver_data->native_window, display_rotate); if (driver_data->mipi0_rotation != display_rotate) { driver_data->mipi0_rotation = display_rotate; } } else { long long hwc_timestamp = 0; int index = -1; for (i = 0; i < obj_context->num_render_targets; i++) { object_surface_p obj_surface = SURFACE(obj_context->render_targets[i]); /* traverse all surfaces' share info to find out the latest transform info */ if (obj_surface && obj_surface->share_info) { if (obj_surface->share_info->hwc_timestamp > hwc_timestamp) { hwc_timestamp = obj_surface->share_info->hwc_timestamp; index = i; } } } if (index >= 0) { object_surface_p obj_surface = SURFACE(obj_context->render_targets[index]); if (obj_surface && obj_surface->share_info) { int transform = obj_surface->share_info->layer_transform; driver_data->mipi0_rotation = HAL2VAROTATION(transform); } } } #ifdef PSBVIDEO_MRFL if ((mode == HDMI_VIDEO_ISPLAYING) && driver_data->native_window) { int display_rotate = 0; psb_android_surfaceflinger_rotate(driver_data->native_window, &display_rotate); drv_debug_msg(VIDEO_DEBUG_GENERAL, "NativeWindow(0x%x), get surface flinger rotate %d\n", driver_data->native_window, display_rotate); if (driver_data->mipi0_rotation != display_rotate && !IS_MOFD(driver_data)) { driver_data->mipi0_rotation = display_rotate; } } #endif /* calc VA rotation and WM rotation, and assign to the final rotation degree */ angle = Rotation2Angle(driver_data->va_rotate) + Rotation2Angle(driver_data->mipi0_rotation); driver_data->local_rotation = Angle2Rotation(angle); angle = Rotation2Angle(driver_data->va_rotate) + Rotation2Angle(driver_data->hdmi_rotation); driver_data->extend_rotation = Angle2Rotation(angle); /* On MOFD, no need to use meta rotation, just use rotation angle signal from HWC */ if (IS_MOFD(driver_data)) { driver_data->local_rotation = driver_data->mipi0_rotation; driver_data->extend_rotation = Rotation2Angle(driver_data->hdmi_rotation); } /* for any case that local and extened rotation are not same, fallback to GPU */ if ((driver_data->mipi1_rotation != VA_ROTATION_NONE) || ((driver_data->local_rotation != VA_ROTATION_NONE) && (driver_data->extend_rotation != VA_ROTATION_NONE) && (driver_data->local_rotation != driver_data->extend_rotation))) { new_rotate = ROTATE_VA2MSVDX(driver_data->local_rotation); if (driver_data->is_android == 0) /*fallback to texblit path*/ driver_data->output_method = PSB_PUTSURFACE_CTEXTURE; } else { if (driver_data->local_rotation == VA_ROTATION_NONE) new_rotate = driver_data->extend_rotation; else new_rotate = driver_data->local_rotation; if (driver_data->is_android == 0) { if (driver_data->output_method != PSB_PUTSURFACE_FORCE_CTEXTURE) driver_data->output_method = PSB_PUTSURFACE_COVERLAY; } } if (old_rotate != new_rotate) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSVDX: new rotation %d desired\n", new_rotate); driver_data->msvdx_rotate_want = new_rotate; } #ifdef TARGET_HAS_MULTIPLE_DISPLAY int scaling_buffer_width = 1920, scaling_buffer_height = 1080 ; int scaling_width = 0, scaling_height = 0; int scaling_offset_x = 0, scaling_offset_y = 0; int old_bufw = 0, old_bufh = 0, old_x = 0, old_y = 0, old_w = 0, old_h = 0; int bScaleChanged = 0, size = 0; unsigned char * surface_data; int ret = psb_android_get_mds_decoder_output_resolution( (void*)driver_data->ws_priv, &scaling_width, &scaling_height, &scaling_offset_x, &scaling_offset_y, &scaling_buffer_width, &scaling_buffer_height); if ((old_bufw != scaling_buffer_width) || (old_bufh != scaling_buffer_height) || (old_x != scaling_offset_x) || (old_y != scaling_offset_y) || (old_w != scaling_width) || (old_h != scaling_height)) { bScaleChanged = 1; } old_x = scaling_offset_x; old_y = scaling_offset_y; old_w = scaling_width; old_h = scaling_height; old_bufw = scaling_buffer_width; old_bufh = scaling_buffer_height; /* turn off ved downscaling if width and height are 0. * Besides, scaling_width and scaling_height must be a multiple of 2. */ if (!ret || (!scaling_width || !scaling_height) || (scaling_width & 1) || (scaling_height & 1)) { obj_context->msvdx_scaling = 0; obj_context->scaling_width = 0; obj_context->scaling_height = 0; obj_context->scaling_offset_x= 0; obj_context->scaling_offset_y = 0; obj_context->scaling_buffer_width = 0; obj_context->scaling_buffer_height = 0; } else { obj_context->msvdx_scaling = 1; obj_context->scaling_width = scaling_width; obj_context->scaling_height = scaling_height; obj_context->scaling_offset_x= scaling_offset_x; obj_context->scaling_offset_y = scaling_offset_y; obj_context->scaling_buffer_width = scaling_buffer_width; obj_context->scaling_buffer_height = scaling_buffer_height; } if (bScaleChanged) { if ((obj_surface != NULL) && (obj_surface->out_loop_surface != NULL)) { if (psb_buffer_map(&obj_surface->out_loop_surface->buf, &surface_data)) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to map rotation buffer before clear it"); } else { size = obj_surface->out_loop_surface->chroma_offset; memset(surface_data, 0, size); memset(surface_data + size, 0x80, obj_surface->out_loop_surface->size - size); psb_buffer_unmap(&obj_context->current_render_target->out_loop_surface->buf); } } } #endif }
/** * Power off sequence for DBI interface */ int __dbi_power_off(struct mdfld_dsi_config *dsi_config) { struct mdfld_dsi_hw_registers *regs; struct mdfld_dsi_hw_context *ctx; struct drm_device *dev; struct drm_psb_private *dev_priv; int err = 0; u32 power_island = 0; int retry,i; int offset = 0; u32 val; if (!dsi_config) return -EINVAL; PSB_DEBUG_ENTRY("\n"); regs = &dsi_config->regs; ctx = &dsi_config->dsi_hw_context; dev = dsi_config->dev; dev_priv = dev->dev_private; ctx->dspcntr = REG_READ(regs->dspcntr_reg); ctx->pipeconf = REG_READ(regs->pipeconf_reg); ctx->dsparb = REG_READ(DSPARB); ctx->dsparb2 = REG_READ(DSPARB2); /*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)); /*Disable plane*/ val = ctx->dspcntr; REG_WRITE(regs->dspcntr_reg, (val & ~BIT31)); /*Disable pipe*/ /* Don't disable DSR mode. */ REG_WRITE(regs->pipeconf_reg, (REG_READ(regs->pipeconf_reg) & ~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"); if (IS_MOFD(dev)) { /* * FIXME: turn off the power island directly * although failed to disable pipe. */ err = 0; } else err = -EAGAIN; goto power_off_err; } } if (!is_dual_dsi(dev)) { /*enter ULPS*/ __dbi_enter_ulps_locked(dsi_config, offset); } else { /*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*/ __dbi_enter_ulps_locked(dsi_config, offset); offset = 0x1000; /*Disable MIPI port*/ REG_WRITE(regs->mipi_reg +offset, (REG_READ(regs->mipi_reg + offset) & ~BIT31)); /*clear Low power output hold*/ REG_WRITE(regs->mipi_reg + offset, (REG_READ(regs->mipi_reg + offset) & ~BIT16)); offset = 0x800; /*Disable DSI controller*/ REG_WRITE(regs->device_ready_reg + offset, (ctx->device_ready & ~BIT0)); /*enter ULPS*/ __dbi_enter_ulps_locked(dsi_config, offset); offset = 0x0; } 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; }