18ca0b875SImre Deak // SPDX-License-Identifier: MIT
28ca0b875SImre Deak /*
38ca0b875SImre Deak * Copyright © 2023 Intel Corporation
48ca0b875SImre Deak */
58ca0b875SImre Deak
631967638SImre Deak #include <drm/drm_fixed.h>
731967638SImre Deak
88ca0b875SImre Deak #include "i915_drv.h"
98ca0b875SImre Deak
108ca0b875SImre Deak #include "intel_atomic.h"
111dd9d86aSImre Deak #include "intel_crtc.h"
128ca0b875SImre Deak #include "intel_display_types.h"
1336f579ffSImre Deak #include "intel_dp_mst.h"
1439818c06SImre Deak #include "intel_dp_tunnel.h"
15998d2cd3SImre Deak #include "intel_fdi.h"
168ca0b875SImre Deak #include "intel_link_bw.h"
178ca0b875SImre Deak
188ca0b875SImre Deak /**
198ca0b875SImre Deak * intel_link_bw_init_limits - initialize BW limits
201dd9d86aSImre Deak * @state: Atomic state
218ca0b875SImre Deak * @limits: link BW limits
228ca0b875SImre Deak *
238ca0b875SImre Deak * Initialize @limits.
248ca0b875SImre Deak */
intel_link_bw_init_limits(struct intel_atomic_state * state,struct intel_link_bw_limits * limits)251dd9d86aSImre Deak void intel_link_bw_init_limits(struct intel_atomic_state *state,
261dd9d86aSImre Deak struct intel_link_bw_limits *limits)
278ca0b875SImre Deak {
28*9aec90f9SJani Nikula struct intel_display *display = to_intel_display(state);
291dd9d86aSImre Deak struct drm_i915_private *i915 = to_i915(state->base.dev);
308ca0b875SImre Deak enum pipe pipe;
318ca0b875SImre Deak
3236f579ffSImre Deak limits->force_fec_pipes = 0;
338ca0b875SImre Deak limits->bpp_limit_reached_pipes = 0;
34*9aec90f9SJani Nikula for_each_pipe(display, pipe) {
351dd9d86aSImre Deak const struct intel_crtc_state *crtc_state =
361dd9d86aSImre Deak intel_atomic_get_new_crtc_state(state,
371dd9d86aSImre Deak intel_crtc_for_pipe(i915, pipe));
381dd9d86aSImre Deak
391dd9d86aSImre Deak if (state->base.duplicated && crtc_state) {
401dd9d86aSImre Deak limits->max_bpp_x16[pipe] = crtc_state->max_link_bpp_x16;
411dd9d86aSImre Deak if (crtc_state->fec_enable)
421dd9d86aSImre Deak limits->force_fec_pipes |= BIT(pipe);
431dd9d86aSImre Deak } else {
448ca0b875SImre Deak limits->max_bpp_x16[pipe] = INT_MAX;
458ca0b875SImre Deak }
461dd9d86aSImre Deak }
471dd9d86aSImre Deak }
488ca0b875SImre Deak
498ca0b875SImre Deak /**
508ca0b875SImre Deak * intel_link_bw_reduce_bpp - reduce maximum link bpp for a selected pipe
518ca0b875SImre Deak * @state: atomic state
528ca0b875SImre Deak * @limits: link BW limits
538ca0b875SImre Deak * @pipe_mask: mask of pipes to select from
548ca0b875SImre Deak * @reason: explanation of why bpp reduction is needed
558ca0b875SImre Deak *
568ca0b875SImre Deak * Select the pipe from @pipe_mask with the biggest link bpp value and set the
578ca0b875SImre Deak * maximum of link bpp in @limits below this value. Modeset the selected pipe,
588ca0b875SImre Deak * so that its state will get recomputed.
598ca0b875SImre Deak *
608ca0b875SImre Deak * This function can be called to resolve a link's BW overallocation by reducing
618ca0b875SImre Deak * the link bpp of one pipe on the link and hence reducing the total link BW.
628ca0b875SImre Deak *
638ca0b875SImre Deak * Returns
648ca0b875SImre Deak * - 0 in case of success
658ca0b875SImre Deak * - %-ENOSPC if no pipe can further reduce its link bpp
668ca0b875SImre Deak * - Other negative error, if modesetting the selected pipe failed
678ca0b875SImre Deak */
intel_link_bw_reduce_bpp(struct intel_atomic_state * state,struct intel_link_bw_limits * limits,u8 pipe_mask,const char * reason)688ca0b875SImre Deak int intel_link_bw_reduce_bpp(struct intel_atomic_state *state,
698ca0b875SImre Deak struct intel_link_bw_limits *limits,
708ca0b875SImre Deak u8 pipe_mask,
718ca0b875SImre Deak const char *reason)
728ca0b875SImre Deak {
73*9aec90f9SJani Nikula struct intel_display *display = to_intel_display(state);
748ca0b875SImre Deak enum pipe max_bpp_pipe = INVALID_PIPE;
758ca0b875SImre Deak struct intel_crtc *crtc;
767c8601aeSImre Deak int max_bpp_x16 = 0;
778ca0b875SImre Deak
78*9aec90f9SJani Nikula for_each_intel_crtc_in_pipe_mask(display->drm, crtc, pipe_mask) {
798ca0b875SImre Deak struct intel_crtc_state *crtc_state;
807c8601aeSImre Deak int link_bpp_x16;
818ca0b875SImre Deak
828ca0b875SImre Deak if (limits->bpp_limit_reached_pipes & BIT(crtc->pipe))
838ca0b875SImre Deak continue;
848ca0b875SImre Deak
858ca0b875SImre Deak crtc_state = intel_atomic_get_crtc_state(&state->base,
868ca0b875SImre Deak crtc);
878ca0b875SImre Deak if (IS_ERR(crtc_state))
888ca0b875SImre Deak return PTR_ERR(crtc_state);
898ca0b875SImre Deak
908ca0b875SImre Deak if (crtc_state->dsc.compression_enable)
917c8601aeSImre Deak link_bpp_x16 = crtc_state->dsc.compressed_bpp_x16;
928ca0b875SImre Deak else
938ca0b875SImre Deak /*
948ca0b875SImre Deak * TODO: for YUV420 the actual link bpp is only half
958ca0b875SImre Deak * of the pipe bpp value. The MST encoder's BW allocation
968ca0b875SImre Deak * is based on the pipe bpp value, set the actual link bpp
978ca0b875SImre Deak * limit here once the MST BW allocation is fixed.
988ca0b875SImre Deak */
9931967638SImre Deak link_bpp_x16 = fxp_q4_from_int(crtc_state->pipe_bpp);
1008ca0b875SImre Deak
1017c8601aeSImre Deak if (link_bpp_x16 > max_bpp_x16) {
1027c8601aeSImre Deak max_bpp_x16 = link_bpp_x16;
1038ca0b875SImre Deak max_bpp_pipe = crtc->pipe;
1048ca0b875SImre Deak }
1058ca0b875SImre Deak }
1068ca0b875SImre Deak
1078ca0b875SImre Deak if (max_bpp_pipe == INVALID_PIPE)
1088ca0b875SImre Deak return -ENOSPC;
1098ca0b875SImre Deak
1107c8601aeSImre Deak limits->max_bpp_x16[max_bpp_pipe] = max_bpp_x16 - 1;
1118ca0b875SImre Deak
1128ca0b875SImre Deak return intel_modeset_pipes_in_mask_early(state, reason,
1138ca0b875SImre Deak BIT(max_bpp_pipe));
1148ca0b875SImre Deak }
1158ca0b875SImre Deak
1168ca0b875SImre Deak /**
1178ca0b875SImre Deak * intel_link_bw_set_bpp_limit_for_pipe - set link bpp limit for a pipe to its minimum
1188ca0b875SImre Deak * @state: atomic state
1198ca0b875SImre Deak * @old_limits: link BW limits
1208ca0b875SImre Deak * @new_limits: link BW limits
1218ca0b875SImre Deak * @pipe: pipe
1228ca0b875SImre Deak *
1238ca0b875SImre Deak * Set the link bpp limit for @pipe in @new_limits to its value in
1248ca0b875SImre Deak * @old_limits and mark this limit as the minimum. This function must be
1258ca0b875SImre Deak * called after a pipe's compute config function failed, @old_limits
1268ca0b875SImre Deak * containing the bpp limit with which compute config previously passed.
1278ca0b875SImre Deak *
1288ca0b875SImre Deak * The function will fail if setting a minimum is not possible, either
1298ca0b875SImre Deak * because the old and new limits match (and so would lead to a pipe compute
1308ca0b875SImre Deak * config failure) or the limit is already at the minimum.
1318ca0b875SImre Deak *
1328ca0b875SImre Deak * Returns %true in case of success.
1338ca0b875SImre Deak */
1348ca0b875SImre Deak bool
intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state * state,const struct intel_link_bw_limits * old_limits,struct intel_link_bw_limits * new_limits,enum pipe pipe)1358ca0b875SImre Deak intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state,
1368ca0b875SImre Deak const struct intel_link_bw_limits *old_limits,
1378ca0b875SImre Deak struct intel_link_bw_limits *new_limits,
1388ca0b875SImre Deak enum pipe pipe)
1398ca0b875SImre Deak {
140*9aec90f9SJani Nikula struct intel_display *display = to_intel_display(state);
1418ca0b875SImre Deak
1428ca0b875SImre Deak if (pipe == INVALID_PIPE)
1438ca0b875SImre Deak return false;
1448ca0b875SImre Deak
1458ca0b875SImre Deak if (new_limits->max_bpp_x16[pipe] ==
1468ca0b875SImre Deak old_limits->max_bpp_x16[pipe])
1478ca0b875SImre Deak return false;
1488ca0b875SImre Deak
149*9aec90f9SJani Nikula if (drm_WARN_ON(display->drm,
1508ca0b875SImre Deak new_limits->bpp_limit_reached_pipes & BIT(pipe)))
1518ca0b875SImre Deak return false;
1528ca0b875SImre Deak
1538ca0b875SImre Deak new_limits->max_bpp_x16[pipe] =
1548ca0b875SImre Deak old_limits->max_bpp_x16[pipe];
1558ca0b875SImre Deak new_limits->bpp_limit_reached_pipes |= BIT(pipe);
1568ca0b875SImre Deak
1578ca0b875SImre Deak return true;
1588ca0b875SImre Deak }
1598ca0b875SImre Deak
check_all_link_config(struct intel_atomic_state * state,struct intel_link_bw_limits * limits)1608ca0b875SImre Deak static int check_all_link_config(struct intel_atomic_state *state,
1618ca0b875SImre Deak struct intel_link_bw_limits *limits)
1628ca0b875SImre Deak {
163998d2cd3SImre Deak /* TODO: Check additional shared display link configurations like MST */
164998d2cd3SImre Deak int ret;
165998d2cd3SImre Deak
16636f579ffSImre Deak ret = intel_dp_mst_atomic_check_link(state, limits);
16736f579ffSImre Deak if (ret)
16836f579ffSImre Deak return ret;
16936f579ffSImre Deak
17039818c06SImre Deak ret = intel_dp_tunnel_atomic_check_link(state, limits);
17139818c06SImre Deak if (ret)
17239818c06SImre Deak return ret;
17339818c06SImre Deak
174998d2cd3SImre Deak ret = intel_fdi_atomic_check_link(state, limits);
175998d2cd3SImre Deak if (ret)
176998d2cd3SImre Deak return ret;
177998d2cd3SImre Deak
1788ca0b875SImre Deak return 0;
1798ca0b875SImre Deak }
1808ca0b875SImre Deak
1818ca0b875SImre Deak static bool
assert_link_limit_change_valid(struct intel_display * display,const struct intel_link_bw_limits * old_limits,const struct intel_link_bw_limits * new_limits)182*9aec90f9SJani Nikula assert_link_limit_change_valid(struct intel_display *display,
1838ca0b875SImre Deak const struct intel_link_bw_limits *old_limits,
1848ca0b875SImre Deak const struct intel_link_bw_limits *new_limits)
1858ca0b875SImre Deak {
1868ca0b875SImre Deak bool bpps_changed = false;
1878ca0b875SImre Deak enum pipe pipe;
1888ca0b875SImre Deak
18936f579ffSImre Deak /* FEC can't be forced off after it was forced on. */
190*9aec90f9SJani Nikula if (drm_WARN_ON(display->drm,
19136f579ffSImre Deak (old_limits->force_fec_pipes & new_limits->force_fec_pipes) !=
19236f579ffSImre Deak old_limits->force_fec_pipes))
19336f579ffSImre Deak return false;
19436f579ffSImre Deak
195*9aec90f9SJani Nikula for_each_pipe(display, pipe) {
1968ca0b875SImre Deak /* The bpp limit can only decrease. */
197*9aec90f9SJani Nikula if (drm_WARN_ON(display->drm,
1988ca0b875SImre Deak new_limits->max_bpp_x16[pipe] >
1998ca0b875SImre Deak old_limits->max_bpp_x16[pipe]))
2008ca0b875SImre Deak return false;
2018ca0b875SImre Deak
2028ca0b875SImre Deak if (new_limits->max_bpp_x16[pipe] <
2038ca0b875SImre Deak old_limits->max_bpp_x16[pipe])
2048ca0b875SImre Deak bpps_changed = true;
2058ca0b875SImre Deak }
2068ca0b875SImre Deak
2078ca0b875SImre Deak /* At least one limit must change. */
208*9aec90f9SJani Nikula if (drm_WARN_ON(display->drm,
20936f579ffSImre Deak !bpps_changed &&
21036f579ffSImre Deak new_limits->force_fec_pipes ==
21136f579ffSImre Deak old_limits->force_fec_pipes))
2128ca0b875SImre Deak return false;
2138ca0b875SImre Deak
2148ca0b875SImre Deak return true;
2158ca0b875SImre Deak }
2168ca0b875SImre Deak
2178ca0b875SImre Deak /**
2188ca0b875SImre Deak * intel_link_bw_atomic_check - check display link states and set a fallback config if needed
2198ca0b875SImre Deak * @state: atomic state
2208ca0b875SImre Deak * @new_limits: link BW limits
2218ca0b875SImre Deak *
2228ca0b875SImre Deak * Check the configuration of all shared display links in @state and set new BW
2238ca0b875SImre Deak * limits in @new_limits if there is a BW limitation.
2248ca0b875SImre Deak *
2258ca0b875SImre Deak * Returns:
2268ca0b875SImre Deak * - 0 if the confugration is valid
2278ca0b875SImre Deak * - %-EAGAIN, if the configuration is invalid and @new_limits got updated
2288ca0b875SImre Deak * with fallback values with which the configuration of all CRTCs
2298ca0b875SImre Deak * in @state must be recomputed
2308ca0b875SImre Deak * - Other negative error, if the configuration is invalid without a
2318ca0b875SImre Deak * fallback possibility, or the check failed for another reason
2328ca0b875SImre Deak */
intel_link_bw_atomic_check(struct intel_atomic_state * state,struct intel_link_bw_limits * new_limits)2338ca0b875SImre Deak int intel_link_bw_atomic_check(struct intel_atomic_state *state,
2348ca0b875SImre Deak struct intel_link_bw_limits *new_limits)
2358ca0b875SImre Deak {
236*9aec90f9SJani Nikula struct intel_display *display = to_intel_display(state);
2378ca0b875SImre Deak struct intel_link_bw_limits old_limits = *new_limits;
2388ca0b875SImre Deak int ret;
2398ca0b875SImre Deak
2408ca0b875SImre Deak ret = check_all_link_config(state, new_limits);
2418ca0b875SImre Deak if (ret != -EAGAIN)
2428ca0b875SImre Deak return ret;
2438ca0b875SImre Deak
244*9aec90f9SJani Nikula if (!assert_link_limit_change_valid(display, &old_limits, new_limits))
2458ca0b875SImre Deak return -EINVAL;
2468ca0b875SImre Deak
2478ca0b875SImre Deak return -EAGAIN;
2488ca0b875SImre Deak }
249