Loading drivers/gpu/drm/msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,7 @@ enum msm_mdp_plane_property { PLANE_PROP_BLEND_OP, PLANE_PROP_SRC_CONFIG, PLANE_PROP_FB_TRANSLATION_MODE, PLANE_PROP_MULTIRECT_MODE, /* total # of properties */ PLANE_PROP_COUNT Loading drivers/gpu/drm/msm/sde/sde_plane.c +108 −41 Original line number Diff line number Diff line Loading @@ -58,6 +58,9 @@ #define SDE_PLANE_COLOR_FILL_FLAG BIT(31) #define TIME_MULTIPLEX_RECT(r0, r1, buffer_lines) \ ((r0).y >= ((r1).y + (r1).h + buffer_lines)) /* multirect rect index */ enum { R0, Loading Loading @@ -2787,6 +2790,12 @@ void sde_plane_clear_multirect(const struct drm_plane_state *drm_state) pstate->multirect_mode = SDE_SSPP_MULTIRECT_NONE; } /** * multi_rect validate API allows to validate only R0 and R1 RECT * passing for each plane. Client of this API must not pass multiple * plane which are not sharing same XIN client. Such calls will fail * even though kernel client is passing valid multirect configuration. */ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane) { struct sde_plane_state *pstate[R_MAX]; Loading @@ -2794,37 +2803,44 @@ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane) struct sde_rect src[R_MAX], dst[R_MAX]; struct sde_plane *sde_plane[R_MAX]; const struct sde_format *fmt[R_MAX]; int xin_id[R_MAX]; bool q16_data = true; int i, buffer_lines; int i, j, buffer_lines, width_threshold[R_MAX]; unsigned int max_tile_height = 1; bool parallel_fetch_qualified = true; bool has_tiled_rect = false; for (i = 0; i < R_MAX; i++) { enum sde_sspp_multirect_mode mode = SDE_SSPP_MULTIRECT_NONE; const struct msm_format *msm_fmt; for (i = 0; i < R_MAX; i++) { drm_state[i] = i ? plane->r1 : plane->r0; msm_fmt = msm_framebuffer_format(drm_state[i]->fb); fmt[i] = to_sde_format(msm_fmt); if (SDE_FORMAT_IS_UBWC(fmt[i])) { has_tiled_rect = true; if (fmt[i]->tile_height > max_tile_height) max_tile_height = fmt[i]->tile_height; } if (!drm_state[i]) { SDE_ERROR("drm plane state is NULL\n"); return -EINVAL; } for (i = 0; i < R_MAX; i++) { int width_threshold; pstate[i] = to_sde_plane_state(drm_state[i]); sde_plane[i] = to_sde_plane(drm_state[i]->plane); xin_id[i] = sde_plane[i]->pipe_hw->cap->xin_id; if (pstate[i] == NULL) { SDE_ERROR("SDE plane state of plane id %d is NULL\n", drm_state[i]->plane->base.id); for (j = 0; j < i; j++) { if (xin_id[i] != xin_id[j]) { SDE_ERROR_PLANE(sde_plane[i], "invalid multirect validate call base:%d xin_id:%d curr:%d xin:%d\n", j, xin_id[j], i, xin_id[i]); return -EINVAL; } } msm_fmt = msm_framebuffer_format(drm_state[i]->fb); if (!msm_fmt) { SDE_ERROR_PLANE(sde_plane[i], "null fb\n"); return -EINVAL; } fmt[i] = to_sde_format(msm_fmt); if (SDE_FORMAT_IS_UBWC(fmt[i]) && (fmt[i]->tile_height > max_tile_height)) max_tile_height = fmt[i]->tile_height; POPULATE_RECT(&src[i], drm_state[i]->src_x, drm_state[i]->src_y, drm_state[i]->src_w, drm_state[i]->src_h, q16_data); Loading @@ -2851,41 +2867,81 @@ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane) * So we cannot support more than half of the supported SSPP * width for tiled formats. */ width_threshold = sde_plane[i]->pipe_sblk->maxlinewidth; if (has_tiled_rect) width_threshold /= 2; width_threshold[i] = sde_plane[i]->pipe_sblk->maxlinewidth; if (SDE_FORMAT_IS_UBWC(fmt[i])) width_threshold[i] /= 2; if (parallel_fetch_qualified && src[i].w > width_threshold) if (parallel_fetch_qualified && src[i].w > width_threshold[i]) parallel_fetch_qualified = false; if (sde_plane[i]->is_virtual) mode = sde_plane_get_property(pstate[i], PLANE_PROP_MULTIRECT_MODE); } /* Validate RECT's and set the mode */ /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */ if (parallel_fetch_qualified) { pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL; pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL; goto done; } /* TIME_MX Mode */ buffer_lines = 2 * max_tile_height; if ((dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) || (dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines)) { pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX; pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX; } else { /** * fallback to driver mode selection logic if client is using * multirect plane without setting property. * * validate multirect mode configuration based on rectangle */ switch (mode) { case SDE_SSPP_MULTIRECT_NONE: if (parallel_fetch_qualified) mode = SDE_SSPP_MULTIRECT_PARALLEL; else if (TIME_MULTIPLEX_RECT(dst[R1], dst[R0], buffer_lines) || TIME_MULTIPLEX_RECT(dst[R0], dst[R1], buffer_lines)) mode = SDE_SSPP_MULTIRECT_TIME_MX; else SDE_ERROR( "No multirect mode possible for the planes (%d - %d)\n", "planes(%d - %d) multirect mode selection fail\n", drm_state[R0]->plane->base.id, drm_state[R1]->plane->base.id); return -EINVAL; break; case SDE_SSPP_MULTIRECT_PARALLEL: if (!parallel_fetch_qualified) { SDE_ERROR("R0 plane:%d width_threshold:%d src_w:%d\n", drm_state[R0]->plane->base.id, width_threshold[R0], src[R0].w); SDE_ERROR("R1 plane:%d width_threshold:%d src_w:%d\n", drm_state[R1]->plane->base.id, width_threshold[R1], src[R1].w); SDE_ERROR("parallel fetch not qualified\n"); mode = SDE_SSPP_MULTIRECT_NONE; } break; case SDE_SSPP_MULTIRECT_TIME_MX: if (!TIME_MULTIPLEX_RECT(dst[R1], dst[R0], buffer_lines) && !TIME_MULTIPLEX_RECT(dst[R0], dst[R1], buffer_lines)) { SDE_ERROR( "buffer_lines:%d R0 plane:%d dst_y:%d dst_h:%d\n", buffer_lines, drm_state[R0]->plane->base.id, dst[R0].y, dst[R0].h); SDE_ERROR( "buffer_lines:%d R1 plane:%d dst_y:%d dst_h:%d\n", buffer_lines, drm_state[R1]->plane->base.id, dst[R1].y, dst[R1].h); SDE_ERROR("time multiplexed fetch not qualified\n"); mode = SDE_SSPP_MULTIRECT_NONE; } break; default: SDE_ERROR("bad mode:%d selection\n", mode); mode = SDE_SSPP_MULTIRECT_NONE; break; } for (i = 0; i < R_MAX; i++) pstate[i]->multirect_mode = mode; if (mode == SDE_SSPP_MULTIRECT_NONE) return -EINVAL; done: if (sde_plane[R0]->is_virtual) { pstate[R0]->multirect_index = SDE_SSPP_RECT_1; pstate[R1]->multirect_index = SDE_SSPP_RECT_0; Loading @@ -2898,6 +2954,7 @@ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane) pstate[R0]->multirect_mode, pstate[R0]->multirect_index); SDE_DEBUG_PLANE(sde_plane[R1], "R1: %d - %d\n", pstate[R1]->multirect_mode, pstate[R1]->multirect_index); return 0; } Loading Loading @@ -3609,6 +3666,7 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane, case PLANE_PROP_CSC_V1: pstate->dirty |= SDE_PLANE_DIRTY_FORMAT; break; case PLANE_PROP_MULTIRECT_MODE: case PLANE_PROP_COLOR_FILL: /* potentially need to refresh everything */ pstate->dirty = SDE_PLANE_DIRTY_ALL; Loading Loading @@ -4029,6 +4087,11 @@ static void _sde_plane_install_properties(struct drm_plane *plane, {SDE_DRM_FB_NON_SEC_DIR_TRANS, "non_sec_direct_translation"}, {SDE_DRM_FB_SEC_DIR_TRANS, "sec_direct_translation"}, }; static const struct drm_prop_enum_list e_multirect_mode[] = { {SDE_SSPP_MULTIRECT_NONE, "none"}, {SDE_SSPP_MULTIRECT_PARALLEL, "parallel"}, {SDE_SSPP_MULTIRECT_TIME_MX, "serial"}, }; const struct sde_format_extended *format_list; struct sde_kms_info *info; struct sde_plane *psde = to_sde_plane(plane); Loading Loading @@ -4178,6 +4241,10 @@ static void _sde_plane_install_properties(struct drm_plane *plane, format_list = psde->pipe_sblk->virt_format_list; sde_kms_info_add_keyint(info, "primary_smart_plane_id", master_plane_id); msm_property_install_enum(&psde->property_info, "multirect_mode", 0x0, 0, e_multirect_mode, ARRAY_SIZE(e_multirect_mode), PLANE_PROP_MULTIRECT_MODE); } if (format_list) { Loading Loading
drivers/gpu/drm/msm/msm_drv.h +1 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,7 @@ enum msm_mdp_plane_property { PLANE_PROP_BLEND_OP, PLANE_PROP_SRC_CONFIG, PLANE_PROP_FB_TRANSLATION_MODE, PLANE_PROP_MULTIRECT_MODE, /* total # of properties */ PLANE_PROP_COUNT Loading
drivers/gpu/drm/msm/sde/sde_plane.c +108 −41 Original line number Diff line number Diff line Loading @@ -58,6 +58,9 @@ #define SDE_PLANE_COLOR_FILL_FLAG BIT(31) #define TIME_MULTIPLEX_RECT(r0, r1, buffer_lines) \ ((r0).y >= ((r1).y + (r1).h + buffer_lines)) /* multirect rect index */ enum { R0, Loading Loading @@ -2787,6 +2790,12 @@ void sde_plane_clear_multirect(const struct drm_plane_state *drm_state) pstate->multirect_mode = SDE_SSPP_MULTIRECT_NONE; } /** * multi_rect validate API allows to validate only R0 and R1 RECT * passing for each plane. Client of this API must not pass multiple * plane which are not sharing same XIN client. Such calls will fail * even though kernel client is passing valid multirect configuration. */ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane) { struct sde_plane_state *pstate[R_MAX]; Loading @@ -2794,37 +2803,44 @@ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane) struct sde_rect src[R_MAX], dst[R_MAX]; struct sde_plane *sde_plane[R_MAX]; const struct sde_format *fmt[R_MAX]; int xin_id[R_MAX]; bool q16_data = true; int i, buffer_lines; int i, j, buffer_lines, width_threshold[R_MAX]; unsigned int max_tile_height = 1; bool parallel_fetch_qualified = true; bool has_tiled_rect = false; for (i = 0; i < R_MAX; i++) { enum sde_sspp_multirect_mode mode = SDE_SSPP_MULTIRECT_NONE; const struct msm_format *msm_fmt; for (i = 0; i < R_MAX; i++) { drm_state[i] = i ? plane->r1 : plane->r0; msm_fmt = msm_framebuffer_format(drm_state[i]->fb); fmt[i] = to_sde_format(msm_fmt); if (SDE_FORMAT_IS_UBWC(fmt[i])) { has_tiled_rect = true; if (fmt[i]->tile_height > max_tile_height) max_tile_height = fmt[i]->tile_height; } if (!drm_state[i]) { SDE_ERROR("drm plane state is NULL\n"); return -EINVAL; } for (i = 0; i < R_MAX; i++) { int width_threshold; pstate[i] = to_sde_plane_state(drm_state[i]); sde_plane[i] = to_sde_plane(drm_state[i]->plane); xin_id[i] = sde_plane[i]->pipe_hw->cap->xin_id; if (pstate[i] == NULL) { SDE_ERROR("SDE plane state of plane id %d is NULL\n", drm_state[i]->plane->base.id); for (j = 0; j < i; j++) { if (xin_id[i] != xin_id[j]) { SDE_ERROR_PLANE(sde_plane[i], "invalid multirect validate call base:%d xin_id:%d curr:%d xin:%d\n", j, xin_id[j], i, xin_id[i]); return -EINVAL; } } msm_fmt = msm_framebuffer_format(drm_state[i]->fb); if (!msm_fmt) { SDE_ERROR_PLANE(sde_plane[i], "null fb\n"); return -EINVAL; } fmt[i] = to_sde_format(msm_fmt); if (SDE_FORMAT_IS_UBWC(fmt[i]) && (fmt[i]->tile_height > max_tile_height)) max_tile_height = fmt[i]->tile_height; POPULATE_RECT(&src[i], drm_state[i]->src_x, drm_state[i]->src_y, drm_state[i]->src_w, drm_state[i]->src_h, q16_data); Loading @@ -2851,41 +2867,81 @@ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane) * So we cannot support more than half of the supported SSPP * width for tiled formats. */ width_threshold = sde_plane[i]->pipe_sblk->maxlinewidth; if (has_tiled_rect) width_threshold /= 2; width_threshold[i] = sde_plane[i]->pipe_sblk->maxlinewidth; if (SDE_FORMAT_IS_UBWC(fmt[i])) width_threshold[i] /= 2; if (parallel_fetch_qualified && src[i].w > width_threshold) if (parallel_fetch_qualified && src[i].w > width_threshold[i]) parallel_fetch_qualified = false; if (sde_plane[i]->is_virtual) mode = sde_plane_get_property(pstate[i], PLANE_PROP_MULTIRECT_MODE); } /* Validate RECT's and set the mode */ /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */ if (parallel_fetch_qualified) { pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL; pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL; goto done; } /* TIME_MX Mode */ buffer_lines = 2 * max_tile_height; if ((dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) || (dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines)) { pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX; pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX; } else { /** * fallback to driver mode selection logic if client is using * multirect plane without setting property. * * validate multirect mode configuration based on rectangle */ switch (mode) { case SDE_SSPP_MULTIRECT_NONE: if (parallel_fetch_qualified) mode = SDE_SSPP_MULTIRECT_PARALLEL; else if (TIME_MULTIPLEX_RECT(dst[R1], dst[R0], buffer_lines) || TIME_MULTIPLEX_RECT(dst[R0], dst[R1], buffer_lines)) mode = SDE_SSPP_MULTIRECT_TIME_MX; else SDE_ERROR( "No multirect mode possible for the planes (%d - %d)\n", "planes(%d - %d) multirect mode selection fail\n", drm_state[R0]->plane->base.id, drm_state[R1]->plane->base.id); return -EINVAL; break; case SDE_SSPP_MULTIRECT_PARALLEL: if (!parallel_fetch_qualified) { SDE_ERROR("R0 plane:%d width_threshold:%d src_w:%d\n", drm_state[R0]->plane->base.id, width_threshold[R0], src[R0].w); SDE_ERROR("R1 plane:%d width_threshold:%d src_w:%d\n", drm_state[R1]->plane->base.id, width_threshold[R1], src[R1].w); SDE_ERROR("parallel fetch not qualified\n"); mode = SDE_SSPP_MULTIRECT_NONE; } break; case SDE_SSPP_MULTIRECT_TIME_MX: if (!TIME_MULTIPLEX_RECT(dst[R1], dst[R0], buffer_lines) && !TIME_MULTIPLEX_RECT(dst[R0], dst[R1], buffer_lines)) { SDE_ERROR( "buffer_lines:%d R0 plane:%d dst_y:%d dst_h:%d\n", buffer_lines, drm_state[R0]->plane->base.id, dst[R0].y, dst[R0].h); SDE_ERROR( "buffer_lines:%d R1 plane:%d dst_y:%d dst_h:%d\n", buffer_lines, drm_state[R1]->plane->base.id, dst[R1].y, dst[R1].h); SDE_ERROR("time multiplexed fetch not qualified\n"); mode = SDE_SSPP_MULTIRECT_NONE; } break; default: SDE_ERROR("bad mode:%d selection\n", mode); mode = SDE_SSPP_MULTIRECT_NONE; break; } for (i = 0; i < R_MAX; i++) pstate[i]->multirect_mode = mode; if (mode == SDE_SSPP_MULTIRECT_NONE) return -EINVAL; done: if (sde_plane[R0]->is_virtual) { pstate[R0]->multirect_index = SDE_SSPP_RECT_1; pstate[R1]->multirect_index = SDE_SSPP_RECT_0; Loading @@ -2898,6 +2954,7 @@ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane) pstate[R0]->multirect_mode, pstate[R0]->multirect_index); SDE_DEBUG_PLANE(sde_plane[R1], "R1: %d - %d\n", pstate[R1]->multirect_mode, pstate[R1]->multirect_index); return 0; } Loading Loading @@ -3609,6 +3666,7 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane, case PLANE_PROP_CSC_V1: pstate->dirty |= SDE_PLANE_DIRTY_FORMAT; break; case PLANE_PROP_MULTIRECT_MODE: case PLANE_PROP_COLOR_FILL: /* potentially need to refresh everything */ pstate->dirty = SDE_PLANE_DIRTY_ALL; Loading Loading @@ -4029,6 +4087,11 @@ static void _sde_plane_install_properties(struct drm_plane *plane, {SDE_DRM_FB_NON_SEC_DIR_TRANS, "non_sec_direct_translation"}, {SDE_DRM_FB_SEC_DIR_TRANS, "sec_direct_translation"}, }; static const struct drm_prop_enum_list e_multirect_mode[] = { {SDE_SSPP_MULTIRECT_NONE, "none"}, {SDE_SSPP_MULTIRECT_PARALLEL, "parallel"}, {SDE_SSPP_MULTIRECT_TIME_MX, "serial"}, }; const struct sde_format_extended *format_list; struct sde_kms_info *info; struct sde_plane *psde = to_sde_plane(plane); Loading Loading @@ -4178,6 +4241,10 @@ static void _sde_plane_install_properties(struct drm_plane *plane, format_list = psde->pipe_sblk->virt_format_list; sde_kms_info_add_keyint(info, "primary_smart_plane_id", master_plane_id); msm_property_install_enum(&psde->property_info, "multirect_mode", 0x0, 0, e_multirect_mode, ARRAY_SIZE(e_multirect_mode), PLANE_PROP_MULTIRECT_MODE); } if (format_list) { Loading