if (state->base.duplicated && crtc_state) {
limits->max_bpp_x16[pipe] = crtc_state->max_link_bpp_x16; if (crtc_state->fec_enable)
limits->force_fec_pipes |= BIT(pipe);
} else {
limits->max_bpp_x16[pipe] = INT_MAX;
}
if (forced_bpp_x16)
limits->max_bpp_x16[pipe] = min(limits->max_bpp_x16[pipe], forced_bpp_x16);
}
}
/** * __intel_link_bw_reduce_bpp - reduce maximum link bpp for a selected pipe * @state: atomic state * @limits: link BW limits * @pipe_mask: mask of pipes to select from * @reason: explanation of why bpp reduction is needed * @reduce_forced_bpp: allow reducing bpps below their forced link bpp * * Select the pipe from @pipe_mask with the biggest link bpp value and set the * maximum of link bpp in @limits below this value. Modeset the selected pipe, * so that its state will get recomputed. * * This function can be called to resolve a link's BW overallocation by reducing * the link bpp of one pipe on the link and hence reducing the total link BW. * * Returns * - 0 in case of success * - %-ENOSPC if no pipe can further reduce its link bpp * - Other negative error, if modesetting the selected pipe failed
*/ staticint __intel_link_bw_reduce_bpp(struct intel_atomic_state *state, struct intel_link_bw_limits *limits,
u8 pipe_mask, constchar *reason, bool reduce_forced_bpp)
{ struct intel_display *display = to_intel_display(state); enum pipe max_bpp_pipe = INVALID_PIPE; struct intel_crtc *crtc; int max_bpp_x16 = 0;
for_each_intel_crtc_in_pipe_mask(display->drm, crtc, pipe_mask) { struct intel_crtc_state *crtc_state; int link_bpp_x16;
if (limits->bpp_limit_reached_pipes & BIT(crtc->pipe)) continue;
crtc_state = intel_atomic_get_crtc_state(&state->base,
crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state);
if (crtc_state->dsc.compression_enable)
link_bpp_x16 = crtc_state->dsc.compressed_bpp_x16; else /* * TODO: for YUV420 the actual link bpp is only half * of the pipe bpp value. The MST encoder's BW allocation * is based on the pipe bpp value, set the actual link bpp * limit here once the MST BW allocation is fixed.
*/
link_bpp_x16 = fxp_q4_from_int(crtc_state->pipe_bpp);
if (!reduce_forced_bpp &&
link_bpp_x16 <= get_forced_link_bpp_x16(state, crtc)) continue;
int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, struct intel_link_bw_limits *limits,
u8 pipe_mask, constchar *reason)
{ int ret;
/* Try to keep any forced link BPP. */
ret = __intel_link_bw_reduce_bpp(state, limits, pipe_mask, reason, false); if (ret == -ENOSPC)
ret = __intel_link_bw_reduce_bpp(state, limits, pipe_mask, reason, true);
return ret;
}
/** * intel_link_bw_set_bpp_limit_for_pipe - set link bpp limit for a pipe to its minimum * @state: atomic state * @old_limits: link BW limits * @new_limits: link BW limits * @pipe: pipe * * Set the link bpp limit for @pipe in @new_limits to its value in * @old_limits and mark this limit as the minimum. This function must be * called after a pipe's compute config function failed, @old_limits * containing the bpp limit with which compute config previously passed. * * The function will fail if setting a minimum is not possible, either * because the old and new limits match (and so would lead to a pipe compute * config failure) or the limit is already at the minimum. * * Returns %true in case of success.
*/ bool
intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state, conststruct intel_link_bw_limits *old_limits, struct intel_link_bw_limits *new_limits, enum pipe pipe)
{ struct intel_display *display = to_intel_display(state);
if (pipe == INVALID_PIPE) returnfalse;
if (new_limits->max_bpp_x16[pipe] ==
old_limits->max_bpp_x16[pipe]) returnfalse;
if (drm_WARN_ON(display->drm,
new_limits->bpp_limit_reached_pipes & BIT(pipe))) returnfalse;
/* FEC can't be forced off after it was forced on. */ if (drm_WARN_ON(display->drm,
(old_limits->force_fec_pipes & new_limits->force_fec_pipes) !=
old_limits->force_fec_pipes)) returnfalse;
for_each_pipe(display, pipe) { /* The bpp limit can only decrease. */ if (drm_WARN_ON(display->drm,
new_limits->max_bpp_x16[pipe] >
old_limits->max_bpp_x16[pipe])) returnfalse;
if (new_limits->max_bpp_x16[pipe] <
old_limits->max_bpp_x16[pipe])
bpps_changed = true;
}
/* At least one limit must change. */ if (drm_WARN_ON(display->drm,
!bpps_changed &&
new_limits->force_fec_pipes ==
old_limits->force_fec_pipes)) returnfalse;
returntrue;
}
/** * intel_link_bw_atomic_check - check display link states and set a fallback config if needed * @state: atomic state * @new_limits: link BW limits * * Check the configuration of all shared display links in @state and set new BW * limits in @new_limits if there is a BW limitation. * * Returns: * - 0 if the configuration is valid * - %-EAGAIN, if the configuration is invalid and @new_limits got updated * with fallback values with which the configuration of all CRTCs * in @state must be recomputed * - Other negative error, if the configuration is invalid without a * fallback possibility, or the check failed for another reason
*/ int intel_link_bw_atomic_check(struct intel_atomic_state *state, struct intel_link_bw_limits *new_limits)
{ struct intel_display *display = to_intel_display(state); struct intel_link_bw_limits old_limits = *new_limits; int ret;
ret = check_all_link_config(state, new_limits); if (ret != -EAGAIN) return ret;
if (!assert_link_limit_change_valid(display, &old_limits, new_limits)) return -EINVAL;
staticint str_to_fxp_q4_nonneg_int(constchar *str, int *val_x16)
{ unsignedint val; int err;
err = kstrtouint(str, 10, &val); if (err) return err;
if (val > INT_MAX >> 4) return -ERANGE;
*val_x16 = fxp_q4_from_int(val);
return 0;
}
/* modifies str */ staticint str_to_fxp_q4_nonneg(char *str, int *val_x16)
{ constchar *int_str; char *frac_str; int frac_digits; int frac_val; int err;
switch (connector->base.connector_type) { case DRM_MODE_CONNECTOR_eDP: return intel_dp_has_dsc(connector); case DRM_MODE_CONNECTOR_DisplayPort: if (connector->mst.dp) return HAS_DSC_MST(display);
err = user_str_to_fxp_q4_nonneg(ubuf, len, &bpp_x16); if (err) return err;
/* TODO: Make the non-DSC min_bpp value connector specific. */ if (connector_supports_dsc(connector))
min_bpp = intel_dp_dsc_min_src_compressed_bpp(); else
min_bpp = intel_display_min_pipe_bpp();
switch (connector->base.connector_type) { case DRM_MODE_CONNECTOR_DisplayPort: case DRM_MODE_CONNECTOR_eDP: break; case DRM_MODE_CONNECTOR_VGA: case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_DVID: if (HAS_FDI(display)) break;
return; case DRM_MODE_CONNECTOR_HDMIA: if (HAS_FDI(display) && !HAS_DDI(display)) break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.