1 | |
2 | /* |
3 | * Copyright 2022 Advanced Micro Devices, Inc. |
4 | * |
5 | * Permission is hereby granted, free of charge, to any person obtaining a |
6 | * copy of this software and associated documentation files (the "Software"), |
7 | * to deal in the Software without restriction, including without limitation |
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
9 | * and/or sell copies of the Software, and to permit persons to whom the |
10 | * Software is furnished to do so, subject to the following conditions: |
11 | * |
12 | * The above copyright notice and this permission notice shall be included in |
13 | * all copies or substantial portions of the Software. |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
21 | * OTHER DEALINGS IN THE SOFTWARE. |
22 | * |
23 | * Authors: AMD |
24 | * |
25 | */ |
26 | /*********************************************************************/ |
27 | // USB4 DPIA BANDWIDTH ALLOCATION LOGIC |
28 | /*********************************************************************/ |
29 | #include "link_dp_dpia_bw.h" |
30 | #include "link_dpcd.h" |
31 | #include "dc_dmub_srv.h" |
32 | |
33 | #define DC_LOGGER \ |
34 | link->ctx->logger |
35 | |
36 | #define Kbps_TO_Gbps (1000 * 1000) |
37 | |
38 | // ------------------------------------------------------------------ |
39 | // PRIVATE FUNCTIONS |
40 | // ------------------------------------------------------------------ |
41 | /* |
42 | * Always Check the following: |
43 | * - Is it USB4 link? |
44 | * - Is HPD HIGH? |
45 | * - Is BW Allocation Support Mode enabled on DP-Tx? |
46 | */ |
47 | static bool get_bw_alloc_proceed_flag(struct dc_link *tmp) |
48 | { |
49 | return (tmp && DISPLAY_ENDPOINT_USB4_DPIA == tmp->ep_type |
50 | && tmp->hpd_status |
51 | && tmp->dpia_bw_alloc_config.bw_alloc_enabled); |
52 | } |
53 | |
54 | static void reset_bw_alloc_struct(struct dc_link *link) |
55 | { |
56 | link->dpia_bw_alloc_config.bw_alloc_enabled = false; |
57 | link->dpia_bw_alloc_config.link_verified_bw = 0; |
58 | link->dpia_bw_alloc_config.link_max_bw = 0; |
59 | link->dpia_bw_alloc_config.allocated_bw = 0; |
60 | link->dpia_bw_alloc_config.estimated_bw = 0; |
61 | link->dpia_bw_alloc_config.bw_granularity = 0; |
62 | link->dpia_bw_alloc_config.dp_overhead = 0; |
63 | link->dpia_bw_alloc_config.response_ready = false; |
64 | link->dpia_bw_alloc_config.nrd_max_lane_count = 0; |
65 | link->dpia_bw_alloc_config.nrd_max_link_rate = 0; |
66 | for (int i = 0; i < MAX_SINKS_PER_LINK; i++) |
67 | link->dpia_bw_alloc_config.remote_sink_req_bw[i] = 0; |
68 | DC_LOG_DEBUG("reset usb4 bw alloc of link(%d)\n" , link->link_index); |
69 | } |
70 | |
71 | #define BW_GRANULARITY_0 4 // 0.25 Gbps |
72 | #define BW_GRANULARITY_1 2 // 0.5 Gbps |
73 | #define BW_GRANULARITY_2 1 // 1 Gbps |
74 | |
75 | static uint8_t get_bw_granularity(struct dc_link *link) |
76 | { |
77 | uint8_t bw_granularity = 0; |
78 | |
79 | core_link_read_dpcd( |
80 | link, |
81 | DP_BW_GRANULALITY, |
82 | data: &bw_granularity, |
83 | size: sizeof(uint8_t)); |
84 | |
85 | switch (bw_granularity & 0x3) { |
86 | case 0: |
87 | bw_granularity = BW_GRANULARITY_0; |
88 | break; |
89 | case 1: |
90 | bw_granularity = BW_GRANULARITY_1; |
91 | break; |
92 | case 2: |
93 | default: |
94 | bw_granularity = BW_GRANULARITY_2; |
95 | break; |
96 | } |
97 | |
98 | return bw_granularity; |
99 | } |
100 | |
101 | static int get_estimated_bw(struct dc_link *link) |
102 | { |
103 | uint8_t bw_estimated_bw = 0; |
104 | |
105 | core_link_read_dpcd( |
106 | link, |
107 | ESTIMATED_BW, |
108 | data: &bw_estimated_bw, |
109 | size: sizeof(uint8_t)); |
110 | |
111 | return bw_estimated_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); |
112 | } |
113 | |
114 | static int get_non_reduced_max_link_rate(struct dc_link *link) |
115 | { |
116 | uint8_t nrd_max_link_rate = 0; |
117 | |
118 | core_link_read_dpcd( |
119 | link, |
120 | DP_TUNNELING_MAX_LINK_RATE, |
121 | data: &nrd_max_link_rate, |
122 | size: sizeof(uint8_t)); |
123 | |
124 | return nrd_max_link_rate; |
125 | } |
126 | |
127 | static int get_non_reduced_max_lane_count(struct dc_link *link) |
128 | { |
129 | uint8_t nrd_max_lane_count = 0; |
130 | |
131 | core_link_read_dpcd( |
132 | link, |
133 | DP_TUNNELING_MAX_LANE_COUNT, |
134 | data: &nrd_max_lane_count, |
135 | size: sizeof(uint8_t)); |
136 | |
137 | return nrd_max_lane_count; |
138 | } |
139 | |
140 | /* |
141 | * Read all New BW alloc configuration ex: estimated_bw, allocated_bw, |
142 | * granuality, Driver_ID, CM_Group, & populate the BW allocation structs |
143 | * for host router and dpia |
144 | */ |
145 | static void init_usb4_bw_struct(struct dc_link *link) |
146 | { |
147 | reset_bw_alloc_struct(link); |
148 | |
149 | /* init the known values */ |
150 | link->dpia_bw_alloc_config.bw_granularity = get_bw_granularity(link); |
151 | link->dpia_bw_alloc_config.estimated_bw = get_estimated_bw(link); |
152 | link->dpia_bw_alloc_config.nrd_max_link_rate = get_non_reduced_max_link_rate(link); |
153 | link->dpia_bw_alloc_config.nrd_max_lane_count = get_non_reduced_max_lane_count(link); |
154 | |
155 | DC_LOG_DEBUG("%s: bw_granularity(%d), estimated_bw(%d)\n" , |
156 | __func__, link->dpia_bw_alloc_config.bw_granularity, |
157 | link->dpia_bw_alloc_config.estimated_bw); |
158 | DC_LOG_DEBUG("%s: nrd_max_link_rate(%d), nrd_max_lane_count(%d)\n" , |
159 | __func__, link->dpia_bw_alloc_config.nrd_max_link_rate, |
160 | link->dpia_bw_alloc_config.nrd_max_lane_count); |
161 | } |
162 | |
163 | static uint8_t get_lowest_dpia_index(struct dc_link *link) |
164 | { |
165 | const struct dc *dc_struct = link->dc; |
166 | uint8_t idx = 0xFF; |
167 | int i; |
168 | |
169 | for (i = 0; i < MAX_PIPES * 2; ++i) { |
170 | |
171 | if (!dc_struct->links[i] || |
172 | dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) |
173 | continue; |
174 | |
175 | if (idx > dc_struct->links[i]->link_index) { |
176 | idx = dc_struct->links[i]->link_index; |
177 | break; |
178 | } |
179 | } |
180 | |
181 | return idx; |
182 | } |
183 | |
184 | /* |
185 | * Get the maximum dp tunnel banwidth of host router |
186 | * |
187 | * @dc: pointer to the dc struct instance |
188 | * @hr_index: host router index |
189 | * |
190 | * return: host router maximum dp tunnel bandwidth |
191 | */ |
192 | static int get_host_router_total_dp_tunnel_bw(const struct dc *dc, uint8_t hr_index) |
193 | { |
194 | uint8_t lowest_dpia_index = get_lowest_dpia_index(link: dc->links[0]); |
195 | uint8_t hr_index_temp = 0; |
196 | struct dc_link *link_dpia_primary, *link_dpia_secondary; |
197 | int total_bw = 0; |
198 | |
199 | for (uint8_t i = 0; i < (MAX_PIPES * 2) - 1; ++i) { |
200 | |
201 | if (!dc->links[i] || dc->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) |
202 | continue; |
203 | |
204 | hr_index_temp = (dc->links[i]->link_index - lowest_dpia_index) / 2; |
205 | |
206 | if (hr_index_temp == hr_index) { |
207 | link_dpia_primary = dc->links[i]; |
208 | link_dpia_secondary = dc->links[i + 1]; |
209 | |
210 | /** |
211 | * If BW allocation enabled on both DPIAs, then |
212 | * HR BW = Estimated(dpia_primary) + Allocated(dpia_secondary) |
213 | * otherwise HR BW = Estimated(bw alloc enabled dpia) |
214 | */ |
215 | if ((link_dpia_primary->hpd_status && |
216 | link_dpia_primary->dpia_bw_alloc_config.bw_alloc_enabled) && |
217 | (link_dpia_secondary->hpd_status && |
218 | link_dpia_secondary->dpia_bw_alloc_config.bw_alloc_enabled)) { |
219 | total_bw += link_dpia_primary->dpia_bw_alloc_config.estimated_bw + |
220 | link_dpia_secondary->dpia_bw_alloc_config.allocated_bw; |
221 | } else if (link_dpia_primary->hpd_status && |
222 | link_dpia_primary->dpia_bw_alloc_config.bw_alloc_enabled) { |
223 | total_bw = link_dpia_primary->dpia_bw_alloc_config.estimated_bw; |
224 | } else if (link_dpia_secondary->hpd_status && |
225 | link_dpia_secondary->dpia_bw_alloc_config.bw_alloc_enabled) { |
226 | total_bw += link_dpia_secondary->dpia_bw_alloc_config.estimated_bw; |
227 | } |
228 | break; |
229 | } |
230 | } |
231 | |
232 | return total_bw; |
233 | } |
234 | |
235 | /* |
236 | * Cleanup function for when the dpia is unplugged to reset struct |
237 | * and perform any required clean up |
238 | * |
239 | * @link: pointer to the dc_link struct instance |
240 | * |
241 | * return: none |
242 | */ |
243 | static void dpia_bw_alloc_unplug(struct dc_link *link) |
244 | { |
245 | if (link) { |
246 | DC_LOG_DEBUG("%s: resetting bw alloc config for link(%d)\n" , |
247 | __func__, link->link_index); |
248 | reset_bw_alloc_struct(link); |
249 | } |
250 | } |
251 | |
252 | static void set_usb4_req_bw_req(struct dc_link *link, int req_bw) |
253 | { |
254 | uint8_t requested_bw; |
255 | uint32_t temp; |
256 | |
257 | /* Error check whether request bw greater than allocated */ |
258 | if (req_bw > link->dpia_bw_alloc_config.estimated_bw) { |
259 | DC_LOG_ERROR("%s: Request bw greater than estimated bw for link(%d)\n" , |
260 | __func__, link->link_index); |
261 | req_bw = link->dpia_bw_alloc_config.estimated_bw; |
262 | } |
263 | |
264 | temp = req_bw * link->dpia_bw_alloc_config.bw_granularity; |
265 | requested_bw = temp / Kbps_TO_Gbps; |
266 | |
267 | /* Always make sure to add more to account for floating points */ |
268 | if (temp % Kbps_TO_Gbps) |
269 | ++requested_bw; |
270 | |
271 | /* Error check whether requested and allocated are equal */ |
272 | req_bw = requested_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); |
273 | if (req_bw == link->dpia_bw_alloc_config.allocated_bw) { |
274 | DC_LOG_ERROR("%s: Request bw equals to allocated bw for link(%d)\n" , |
275 | __func__, link->link_index); |
276 | } |
277 | |
278 | link->dpia_bw_alloc_config.response_ready = false; // Reset flag |
279 | core_link_write_dpcd( |
280 | link, |
281 | REQUESTED_BW, |
282 | data: &requested_bw, |
283 | size: sizeof(uint8_t)); |
284 | } |
285 | |
286 | /* |
287 | * Return the response_ready flag from dc_link struct |
288 | * |
289 | * @link: pointer to the dc_link struct instance |
290 | * |
291 | * return: response_ready flag from dc_link struct |
292 | */ |
293 | static bool get_cm_response_ready_flag(struct dc_link *link) |
294 | { |
295 | return link->dpia_bw_alloc_config.response_ready; |
296 | } |
297 | |
298 | // ------------------------------------------------------------------ |
299 | // PUBLIC FUNCTIONS |
300 | // ------------------------------------------------------------------ |
301 | bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link) |
302 | { |
303 | bool ret = false; |
304 | uint8_t response = 0, |
305 | bw_support_dpia = 0, |
306 | bw_support_cm = 0; |
307 | |
308 | if (!(link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->hpd_status)) |
309 | goto out; |
310 | |
311 | if (core_link_read_dpcd( |
312 | link, |
313 | DP_TUNNELING_CAPABILITIES, |
314 | data: &response, |
315 | size: sizeof(uint8_t)) == DC_OK) |
316 | bw_support_dpia = (response >> 7) & 1; |
317 | |
318 | if (core_link_read_dpcd( |
319 | link, |
320 | USB4_DRIVER_BW_CAPABILITY, |
321 | data: &response, |
322 | size: sizeof(uint8_t)) == DC_OK) |
323 | bw_support_cm = (response >> 7) & 1; |
324 | |
325 | /* Send request acknowledgment to Turn ON DPTX support */ |
326 | if (bw_support_cm && bw_support_dpia) { |
327 | |
328 | response = 0x80; |
329 | if (core_link_write_dpcd( |
330 | link, |
331 | DPTX_BW_ALLOCATION_MODE_CONTROL, |
332 | data: &response, |
333 | size: sizeof(uint8_t)) != DC_OK) { |
334 | DC_LOG_DEBUG("%s: FAILURE Enabling DPtx BW Allocation Mode Support for link(%d)\n" , |
335 | __func__, link->link_index); |
336 | } else { |
337 | // SUCCESS Enabled DPtx BW Allocation Mode Support |
338 | DC_LOG_DEBUG("%s: SUCCESS Enabling DPtx BW Allocation Mode Support for link(%d)\n" , |
339 | __func__, link->link_index); |
340 | |
341 | ret = true; |
342 | init_usb4_bw_struct(link); |
343 | link->dpia_bw_alloc_config.bw_alloc_enabled = true; |
344 | } |
345 | } |
346 | |
347 | out: |
348 | return ret; |
349 | } |
350 | |
351 | void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t result) |
352 | { |
353 | int bw_needed = 0; |
354 | int estimated = 0; |
355 | |
356 | if (!get_bw_alloc_proceed_flag(tmp: (link))) |
357 | return; |
358 | |
359 | switch (result) { |
360 | |
361 | case DPIA_BW_REQ_FAILED: |
362 | |
363 | /* |
364 | * Ideally, we shouldn't run into this case as we always validate available |
365 | * bandwidth and request within that limit |
366 | */ |
367 | estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); |
368 | |
369 | DC_LOG_ERROR("%s: BW REQ FAILURE for DP-TX Request for link(%d)\n" , |
370 | __func__, link->link_index); |
371 | DC_LOG_ERROR("%s: current estimated_bw(%d), new estimated_bw(%d)\n" , |
372 | __func__, link->dpia_bw_alloc_config.estimated_bw, estimated); |
373 | |
374 | /* Update the new Estimated BW value updated by CM */ |
375 | link->dpia_bw_alloc_config.estimated_bw = estimated; |
376 | |
377 | /* Allocate the previously requested bandwidth */ |
378 | set_usb4_req_bw_req(link, req_bw: link->dpia_bw_alloc_config.estimated_bw); |
379 | |
380 | /* |
381 | * If FAIL then it is either: |
382 | * 1. Due to DP-Tx trying to allocate more than available i.e. it failed locally |
383 | * => get estimated and allocate that |
384 | * 2. Due to the fact that DP-Tx tried to allocated ESTIMATED BW and failed then |
385 | * CM will have to update 0xE0023 with new ESTIMATED BW value. |
386 | */ |
387 | break; |
388 | |
389 | case DPIA_BW_REQ_SUCCESS: |
390 | |
391 | bw_needed = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); |
392 | |
393 | DC_LOG_DEBUG("%s: BW REQ SUCCESS for DP-TX Request for link(%d)\n" , |
394 | __func__, link->link_index); |
395 | DC_LOG_DEBUG("%s: current allocated_bw(%d), new allocated_bw(%d)\n" , |
396 | __func__, link->dpia_bw_alloc_config.allocated_bw, bw_needed); |
397 | |
398 | link->dpia_bw_alloc_config.allocated_bw = bw_needed; |
399 | |
400 | link->dpia_bw_alloc_config.response_ready = true; |
401 | break; |
402 | |
403 | case DPIA_EST_BW_CHANGED: |
404 | |
405 | estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); |
406 | |
407 | DC_LOG_DEBUG("%s: ESTIMATED BW CHANGED for link(%d)\n" , |
408 | __func__, link->link_index); |
409 | DC_LOG_DEBUG("%s: current estimated_bw(%d), new estimated_bw(%d)\n" , |
410 | __func__, link->dpia_bw_alloc_config.estimated_bw, estimated); |
411 | |
412 | link->dpia_bw_alloc_config.estimated_bw = estimated; |
413 | break; |
414 | |
415 | case DPIA_BW_ALLOC_CAPS_CHANGED: |
416 | |
417 | DC_LOG_ERROR("%s: BW ALLOC CAPABILITY CHANGED to Disabled for link(%d)\n" , |
418 | __func__, link->link_index); |
419 | link->dpia_bw_alloc_config.bw_alloc_enabled = false; |
420 | break; |
421 | } |
422 | } |
423 | int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int peak_bw) |
424 | { |
425 | int ret = 0; |
426 | uint8_t timeout = 10; |
427 | |
428 | if (!(link && DISPLAY_ENDPOINT_USB4_DPIA == link->ep_type |
429 | && link->dpia_bw_alloc_config.bw_alloc_enabled)) |
430 | goto out; |
431 | |
432 | //1. Hot Plug |
433 | if (link->hpd_status && peak_bw > 0) { |
434 | |
435 | // If DP over USB4 then we need to check BW allocation |
436 | link->dpia_bw_alloc_config.link_max_bw = peak_bw; |
437 | set_usb4_req_bw_req(link, req_bw: link->dpia_bw_alloc_config.link_max_bw); |
438 | |
439 | do { |
440 | if (timeout > 0) |
441 | timeout--; |
442 | else |
443 | break; |
444 | msleep(msecs: 10); |
445 | } while (!get_cm_response_ready_flag(link)); |
446 | |
447 | if (!timeout) |
448 | ret = 0;// ERROR TIMEOUT waiting for response for allocating bw |
449 | else if (link->dpia_bw_alloc_config.allocated_bw > 0) |
450 | ret = link->dpia_bw_alloc_config.allocated_bw; |
451 | } |
452 | //2. Cold Unplug |
453 | else if (!link->hpd_status) |
454 | dpia_bw_alloc_unplug(link); |
455 | |
456 | out: |
457 | return ret; |
458 | } |
459 | bool link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw) |
460 | { |
461 | bool ret = false; |
462 | uint8_t timeout = 10; |
463 | |
464 | DC_LOG_DEBUG("%s: ENTER: link(%d), hpd_status(%d), current allocated_bw(%d), req_bw(%d)\n" , |
465 | __func__, link->link_index, link->hpd_status, |
466 | link->dpia_bw_alloc_config.allocated_bw, req_bw); |
467 | |
468 | if (!get_bw_alloc_proceed_flag(tmp: link)) |
469 | goto out; |
470 | |
471 | set_usb4_req_bw_req(link, req_bw); |
472 | do { |
473 | if (timeout > 0) |
474 | timeout--; |
475 | else |
476 | break; |
477 | msleep(msecs: 10); |
478 | } while (!get_cm_response_ready_flag(link)); |
479 | |
480 | if (timeout) |
481 | ret = true; |
482 | |
483 | out: |
484 | DC_LOG_DEBUG("%s: EXIT: timeout(%d), ret(%d)\n" , __func__, timeout, ret); |
485 | return ret; |
486 | } |
487 | |
488 | bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const unsigned int num_dpias) |
489 | { |
490 | bool ret = true; |
491 | int bw_needed_per_hr[MAX_HR_NUM] = { 0, 0 }, host_router_total_dp_bw = 0; |
492 | uint8_t lowest_dpia_index, i, hr_index; |
493 | |
494 | if (!num_dpias || num_dpias > MAX_DPIA_NUM) |
495 | return ret; |
496 | |
497 | lowest_dpia_index = get_lowest_dpia_index(link: link[0]); |
498 | |
499 | /* get total Host Router BW with granularity for the given modes */ |
500 | for (i = 0; i < num_dpias; ++i) { |
501 | int granularity_Gbps = 0; |
502 | int bw_granularity = 0; |
503 | |
504 | if (!link[i]->dpia_bw_alloc_config.bw_alloc_enabled) |
505 | continue; |
506 | |
507 | if (link[i]->link_index < lowest_dpia_index) |
508 | continue; |
509 | |
510 | granularity_Gbps = (Kbps_TO_Gbps / link[i]->dpia_bw_alloc_config.bw_granularity); |
511 | bw_granularity = (bw_needed_per_dpia[i] / granularity_Gbps) * granularity_Gbps + |
512 | ((bw_needed_per_dpia[i] % granularity_Gbps) ? granularity_Gbps : 0); |
513 | |
514 | hr_index = (link[i]->link_index - lowest_dpia_index) / 2; |
515 | bw_needed_per_hr[hr_index] += bw_granularity; |
516 | } |
517 | |
518 | /* validate against each Host Router max BW */ |
519 | for (hr_index = 0; hr_index < MAX_HR_NUM; ++hr_index) { |
520 | if (bw_needed_per_hr[hr_index]) { |
521 | host_router_total_dp_bw = get_host_router_total_dp_tunnel_bw(dc: link[0]->dc, hr_index); |
522 | if (bw_needed_per_hr[hr_index] > host_router_total_dp_bw) { |
523 | ret = false; |
524 | break; |
525 | } |
526 | } |
527 | } |
528 | |
529 | return ret; |
530 | } |
531 | |
532 | int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link) |
533 | { |
534 | int dp_overhead = 0, link_mst_overhead = 0; |
535 | |
536 | if (!get_bw_alloc_proceed_flag(tmp: (link))) |
537 | return dp_overhead; |
538 | |
539 | /* if its mst link, add MTPH overhead */ |
540 | if ((link->type == dc_connection_mst_branch) && |
541 | !link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) { |
542 | /* For 8b/10b encoding: MTP is 64 time slots long, slot 0 is used for MTPH |
543 | * MST overhead is 1/64 of link bandwidth (excluding any overhead) |
544 | */ |
545 | const struct dc_link_settings *link_cap = |
546 | dc_link_get_link_cap(link); |
547 | uint32_t link_bw_in_kbps = (uint32_t)link_cap->link_rate * |
548 | (uint32_t)link_cap->lane_count * |
549 | LINK_RATE_REF_FREQ_IN_KHZ * 8; |
550 | link_mst_overhead = (link_bw_in_kbps / 64) + ((link_bw_in_kbps % 64) ? 1 : 0); |
551 | } |
552 | |
553 | /* add all the overheads */ |
554 | dp_overhead = link_mst_overhead; |
555 | |
556 | return dp_overhead; |
557 | } |
558 | |