xref: /linux/drivers/gpu/drm/i915/display/intel_link_bw.c (revision fd7d598270724cc787982ea48bbe17ad383a8b7f)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2023 Intel Corporation
4  */
5 
6 #include "i915_drv.h"
7 
8 #include "intel_atomic.h"
9 #include "intel_display_types.h"
10 #include "intel_fdi.h"
11 #include "intel_link_bw.h"
12 
13 /**
14  * intel_link_bw_init_limits - initialize BW limits
15  * @i915: device instance
16  * @limits: link BW limits
17  *
18  * Initialize @limits.
19  */
20 void intel_link_bw_init_limits(struct drm_i915_private *i915, struct intel_link_bw_limits *limits)
21 {
22 	enum pipe pipe;
23 
24 	limits->bpp_limit_reached_pipes = 0;
25 	for_each_pipe(i915, pipe)
26 		limits->max_bpp_x16[pipe] = INT_MAX;
27 }
28 
29 /**
30  * intel_link_bw_reduce_bpp - reduce maximum link bpp for a selected pipe
31  * @state: atomic state
32  * @limits: link BW limits
33  * @pipe_mask: mask of pipes to select from
34  * @reason: explanation of why bpp reduction is needed
35  *
36  * Select the pipe from @pipe_mask with the biggest link bpp value and set the
37  * maximum of link bpp in @limits below this value. Modeset the selected pipe,
38  * so that its state will get recomputed.
39  *
40  * This function can be called to resolve a link's BW overallocation by reducing
41  * the link bpp of one pipe on the link and hence reducing the total link BW.
42  *
43  * Returns
44  *   - 0 in case of success
45  *   - %-ENOSPC if no pipe can further reduce its link bpp
46  *   - Other negative error, if modesetting the selected pipe failed
47  */
48 int intel_link_bw_reduce_bpp(struct intel_atomic_state *state,
49 			     struct intel_link_bw_limits *limits,
50 			     u8 pipe_mask,
51 			     const char *reason)
52 {
53 	struct drm_i915_private *i915 = to_i915(state->base.dev);
54 	enum pipe max_bpp_pipe = INVALID_PIPE;
55 	struct intel_crtc *crtc;
56 	int max_bpp = 0;
57 
58 	for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) {
59 		struct intel_crtc_state *crtc_state;
60 		int link_bpp;
61 
62 		if (limits->bpp_limit_reached_pipes & BIT(crtc->pipe))
63 			continue;
64 
65 		crtc_state = intel_atomic_get_crtc_state(&state->base,
66 							 crtc);
67 		if (IS_ERR(crtc_state))
68 			return PTR_ERR(crtc_state);
69 
70 		if (crtc_state->dsc.compression_enable)
71 			link_bpp = crtc_state->dsc.compressed_bpp;
72 		else
73 			/*
74 			 * TODO: for YUV420 the actual link bpp is only half
75 			 * of the pipe bpp value. The MST encoder's BW allocation
76 			 * is based on the pipe bpp value, set the actual link bpp
77 			 * limit here once the MST BW allocation is fixed.
78 			 */
79 			link_bpp = crtc_state->pipe_bpp;
80 
81 		if (link_bpp > max_bpp) {
82 			max_bpp = link_bpp;
83 			max_bpp_pipe = crtc->pipe;
84 		}
85 	}
86 
87 	if (max_bpp_pipe == INVALID_PIPE)
88 		return -ENOSPC;
89 
90 	limits->max_bpp_x16[max_bpp_pipe] = to_bpp_x16(max_bpp) - 1;
91 
92 	return intel_modeset_pipes_in_mask_early(state, reason,
93 						 BIT(max_bpp_pipe));
94 }
95 
96 /**
97  * intel_link_bw_set_bpp_limit_for_pipe - set link bpp limit for a pipe to its minimum
98  * @state: atomic state
99  * @old_limits: link BW limits
100  * @new_limits: link BW limits
101  * @pipe: pipe
102  *
103  * Set the link bpp limit for @pipe in @new_limits to its value in
104  * @old_limits and mark this limit as the minimum. This function must be
105  * called after a pipe's compute config function failed, @old_limits
106  * containing the bpp limit with which compute config previously passed.
107  *
108  * The function will fail if setting a minimum is not possible, either
109  * because the old and new limits match (and so would lead to a pipe compute
110  * config failure) or the limit is already at the minimum.
111  *
112  * Returns %true in case of success.
113  */
114 bool
115 intel_link_bw_set_bpp_limit_for_pipe(struct intel_atomic_state *state,
116 				     const struct intel_link_bw_limits *old_limits,
117 				     struct intel_link_bw_limits *new_limits,
118 				     enum pipe pipe)
119 {
120 	struct drm_i915_private *i915 = to_i915(state->base.dev);
121 
122 	if (pipe == INVALID_PIPE)
123 		return false;
124 
125 	if (new_limits->max_bpp_x16[pipe] ==
126 	    old_limits->max_bpp_x16[pipe])
127 		return false;
128 
129 	if (drm_WARN_ON(&i915->drm,
130 			new_limits->bpp_limit_reached_pipes & BIT(pipe)))
131 		return false;
132 
133 	new_limits->max_bpp_x16[pipe] =
134 		old_limits->max_bpp_x16[pipe];
135 	new_limits->bpp_limit_reached_pipes |= BIT(pipe);
136 
137 	return true;
138 }
139 
140 static int check_all_link_config(struct intel_atomic_state *state,
141 				 struct intel_link_bw_limits *limits)
142 {
143 	/* TODO: Check additional shared display link configurations like MST */
144 	int ret;
145 
146 	ret = intel_fdi_atomic_check_link(state, limits);
147 	if (ret)
148 		return ret;
149 
150 	return 0;
151 }
152 
153 static bool
154 assert_link_limit_change_valid(struct drm_i915_private *i915,
155 			       const struct intel_link_bw_limits *old_limits,
156 			       const struct intel_link_bw_limits *new_limits)
157 {
158 	bool bpps_changed = false;
159 	enum pipe pipe;
160 
161 	for_each_pipe(i915, pipe) {
162 		/* The bpp limit can only decrease. */
163 		if (drm_WARN_ON(&i915->drm,
164 				new_limits->max_bpp_x16[pipe] >
165 				old_limits->max_bpp_x16[pipe]))
166 			return false;
167 
168 		if (new_limits->max_bpp_x16[pipe] <
169 		    old_limits->max_bpp_x16[pipe])
170 			bpps_changed = true;
171 	}
172 
173 	/* At least one limit must change. */
174 	if (drm_WARN_ON(&i915->drm,
175 			!bpps_changed))
176 		return false;
177 
178 	return true;
179 }
180 
181 /**
182  * intel_link_bw_atomic_check - check display link states and set a fallback config if needed
183  * @state: atomic state
184  * @new_limits: link BW limits
185  *
186  * Check the configuration of all shared display links in @state and set new BW
187  * limits in @new_limits if there is a BW limitation.
188  *
189  * Returns:
190  *   - 0 if the confugration is valid
191  *   - %-EAGAIN, if the configuration is invalid and @new_limits got updated
192  *     with fallback values with which the configuration of all CRTCs
193  *     in @state must be recomputed
194  *   - Other negative error, if the configuration is invalid without a
195  *     fallback possibility, or the check failed for another reason
196  */
197 int intel_link_bw_atomic_check(struct intel_atomic_state *state,
198 			       struct intel_link_bw_limits *new_limits)
199 {
200 	struct drm_i915_private *i915 = to_i915(state->base.dev);
201 	struct intel_link_bw_limits old_limits = *new_limits;
202 	int ret;
203 
204 	ret = check_all_link_config(state, new_limits);
205 	if (ret != -EAGAIN)
206 		return ret;
207 
208 	if (!assert_link_limit_change_valid(i915, &old_limits, new_limits))
209 		return -EINVAL;
210 
211 	return -EAGAIN;
212 }
213