]> Git Repo - linux.git/blob - drivers/gpu/drm/i915/display/intel_link_bw.c
net: wan: Add framer framework support
[linux.git] / drivers / gpu / drm / i915 / display / intel_link_bw.c
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 }
This page took 0.048582 seconds and 4 git commands to generate.