File: | dev/pci/drm/amd/display/dc/dcn32/dcn32_hwseq.c |
Warning: | line 670, column 2 Called function pointer is null (null dereference) |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright 2016 Advanced Micro Devices, Inc. | |||
3 | * | |||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |||
5 | * copy of this software and associated documentation files (the "Software"), | |||
6 | * to deal in the Software without restriction, including without limitation | |||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
8 | * and/or sell copies of the Software, and to permit persons to whom the | |||
9 | * Software is furnished to do so, subject to the following conditions: | |||
10 | * | |||
11 | * The above copyright notice and this permission notice shall be included in | |||
12 | * all copies or substantial portions of the Software. | |||
13 | * | |||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |||
20 | * OTHER DEALINGS IN THE SOFTWARE. | |||
21 | * | |||
22 | * Authors: AMD | |||
23 | * | |||
24 | */ | |||
25 | ||||
26 | ||||
27 | #include "dm_services.h" | |||
28 | #include "dm_helpers.h" | |||
29 | #include "core_types.h" | |||
30 | #include "resource.h" | |||
31 | #include "dccg.h" | |||
32 | #include "dce/dce_hwseq.h" | |||
33 | #include "dcn30/dcn30_cm_common.h" | |||
34 | #include "reg_helper.h" | |||
35 | #include "abm.h" | |||
36 | #include "hubp.h" | |||
37 | #include "dchubbub.h" | |||
38 | #include "timing_generator.h" | |||
39 | #include "opp.h" | |||
40 | #include "ipp.h" | |||
41 | #include "mpc.h" | |||
42 | #include "mcif_wb.h" | |||
43 | #include "dc_dmub_srv.h" | |||
44 | #include "link_hwss.h" | |||
45 | #include "dpcd_defs.h" | |||
46 | #include "dcn32_hwseq.h" | |||
47 | #include "clk_mgr.h" | |||
48 | #include "dsc.h" | |||
49 | #include "dcn20/dcn20_optc.h" | |||
50 | #include "dmub_subvp_state.h" | |||
51 | #include "dce/dmub_hw_lock_mgr.h" | |||
52 | #include "dcn32_resource.h" | |||
53 | #include "dc_link_dp.h" | |||
54 | #include "dmub/inc/dmub_subvp_state.h" | |||
55 | ||||
56 | #define DC_LOGGER_INIT(logger) | |||
57 | ||||
58 | #define CTXhws->ctx \ | |||
59 | hws->ctx | |||
60 | #define REG(reg)hws->regs->reg\ | |||
61 | hws->regs->reg | |||
62 | #define DC_LOGGERdc->ctx->logger \ | |||
63 | dc->ctx->logger | |||
64 | ||||
65 | ||||
66 | #undef FN | |||
67 | #define FN(reg_name, field_name)hws->shifts->field_name, hws->masks->field_name \ | |||
68 | hws->shifts->field_name, hws->masks->field_name | |||
69 | ||||
70 | void dcn32_dsc_pg_control( | |||
71 | struct dce_hwseq *hws, | |||
72 | unsigned int dsc_inst, | |||
73 | bool_Bool power_on) | |||
74 | { | |||
75 | uint32_t power_gate = power_on ? 0 : 1; | |||
76 | uint32_t pwr_status = power_on ? 0 : 2; | |||
77 | uint32_t org_ip_request_cntl = 0; | |||
78 | ||||
79 | if (hws->ctx->dc->debug.disable_dsc_power_gate) | |||
80 | return; | |||
81 | ||||
82 | if (!hws->ctx->dc->debug.enable_double_buffered_dsc_pg_support) | |||
83 | return; | |||
84 | ||||
85 | REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl)generic_reg_get(hws->ctx, hws->regs->DC_IP_REQUEST_CNTL , hws->shifts->IP_REQUEST_EN, hws->masks->IP_REQUEST_EN , &org_ip_request_cntl); | |||
86 | if (org_ip_request_cntl == 0) | |||
87 | REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1)generic_reg_set_ex(hws->ctx, hws->regs->DC_IP_REQUEST_CNTL , 0, 1, hws->shifts->IP_REQUEST_EN, hws->masks->IP_REQUEST_EN , 1); | |||
88 | ||||
89 | switch (dsc_inst) { | |||
90 | case 0: /* DSC0 */ | |||
91 | REG_UPDATE(DOMAIN16_PG_CONFIG,generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN16_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate) | |||
92 | DOMAIN_POWER_GATE, power_gate)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN16_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate); | |||
93 | ||||
94 | REG_WAIT(DOMAIN16_PG_STATUS,generic_reg_wait(hws->ctx, hws->regs->DOMAIN16_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 96) | |||
95 | DOMAIN_PGFSM_PWR_STATUS, pwr_status,generic_reg_wait(hws->ctx, hws->regs->DOMAIN16_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 96) | |||
96 | 1, 1000)generic_reg_wait(hws->ctx, hws->regs->DOMAIN16_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 96); | |||
97 | break; | |||
98 | case 1: /* DSC1 */ | |||
99 | REG_UPDATE(DOMAIN17_PG_CONFIG,generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN17_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate) | |||
100 | DOMAIN_POWER_GATE, power_gate)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN17_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate); | |||
101 | ||||
102 | REG_WAIT(DOMAIN17_PG_STATUS,generic_reg_wait(hws->ctx, hws->regs->DOMAIN17_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 104) | |||
103 | DOMAIN_PGFSM_PWR_STATUS, pwr_status,generic_reg_wait(hws->ctx, hws->regs->DOMAIN17_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 104) | |||
104 | 1, 1000)generic_reg_wait(hws->ctx, hws->regs->DOMAIN17_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 104); | |||
105 | break; | |||
106 | case 2: /* DSC2 */ | |||
107 | REG_UPDATE(DOMAIN18_PG_CONFIG,generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN18_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate) | |||
108 | DOMAIN_POWER_GATE, power_gate)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN18_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate); | |||
109 | ||||
110 | REG_WAIT(DOMAIN18_PG_STATUS,generic_reg_wait(hws->ctx, hws->regs->DOMAIN18_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 112) | |||
111 | DOMAIN_PGFSM_PWR_STATUS, pwr_status,generic_reg_wait(hws->ctx, hws->regs->DOMAIN18_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 112) | |||
112 | 1, 1000)generic_reg_wait(hws->ctx, hws->regs->DOMAIN18_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 112); | |||
113 | break; | |||
114 | case 3: /* DSC3 */ | |||
115 | REG_UPDATE(DOMAIN19_PG_CONFIG,generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN19_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate) | |||
116 | DOMAIN_POWER_GATE, power_gate)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN19_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate); | |||
117 | ||||
118 | REG_WAIT(DOMAIN19_PG_STATUS,generic_reg_wait(hws->ctx, hws->regs->DOMAIN19_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 120) | |||
119 | DOMAIN_PGFSM_PWR_STATUS, pwr_status,generic_reg_wait(hws->ctx, hws->regs->DOMAIN19_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 120) | |||
120 | 1, 1000)generic_reg_wait(hws->ctx, hws->regs->DOMAIN19_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 120); | |||
121 | break; | |||
122 | default: | |||
123 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 123); do {} while (0); } while (0); | |||
124 | break; | |||
125 | } | |||
126 | ||||
127 | if (org_ip_request_cntl == 0) | |||
128 | REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0)generic_reg_set_ex(hws->ctx, hws->regs->DC_IP_REQUEST_CNTL , 0, 1, hws->shifts->IP_REQUEST_EN, hws->masks->IP_REQUEST_EN , 0); | |||
129 | } | |||
130 | ||||
131 | ||||
132 | void dcn32_enable_power_gating_plane( | |||
133 | struct dce_hwseq *hws, | |||
134 | bool_Bool enable) | |||
135 | { | |||
136 | bool_Bool force_on = true1; /* disable power gating */ | |||
137 | ||||
138 | if (enable) | |||
139 | force_on = false0; | |||
140 | ||||
141 | /* DCHUBP0/1/2/3 */ | |||
142 | REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN0_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_FORCEON, hws->masks-> DOMAIN_POWER_FORCEON, force_on); | |||
143 | REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN1_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_FORCEON, hws->masks-> DOMAIN_POWER_FORCEON, force_on); | |||
144 | REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN2_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_FORCEON, hws->masks-> DOMAIN_POWER_FORCEON, force_on); | |||
145 | REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN3_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_FORCEON, hws->masks-> DOMAIN_POWER_FORCEON, force_on); | |||
146 | ||||
147 | /* DCS0/1/2/3 */ | |||
148 | REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN16_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_FORCEON, hws->masks-> DOMAIN_POWER_FORCEON, force_on); | |||
149 | REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN17_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_FORCEON, hws->masks-> DOMAIN_POWER_FORCEON, force_on); | |||
150 | REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN18_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_FORCEON, hws->masks-> DOMAIN_POWER_FORCEON, force_on); | |||
151 | REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on)generic_reg_update_ex(hws->ctx, hws->regs->DOMAIN19_PG_CONFIG , 1, hws->shifts->DOMAIN_POWER_FORCEON, hws->masks-> DOMAIN_POWER_FORCEON, force_on); | |||
152 | } | |||
153 | ||||
154 | void dcn32_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool_Bool power_on) | |||
155 | { | |||
156 | uint32_t power_gate = power_on ? 0 : 1; | |||
157 | uint32_t pwr_status = power_on ? 0 : 2; | |||
158 | ||||
159 | if (hws->ctx->dc->debug.disable_hubp_power_gate) | |||
160 | return; | |||
161 | ||||
162 | if (REG(DOMAIN0_PG_CONFIG)hws->regs->DOMAIN0_PG_CONFIG == 0) | |||
163 | return; | |||
164 | ||||
165 | switch (hubp_inst) { | |||
166 | case 0: | |||
167 | REG_SET(DOMAIN0_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate)generic_reg_set_ex(hws->ctx, hws->regs->DOMAIN0_PG_CONFIG , 0, 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate); | |||
168 | REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000)generic_reg_wait(hws->ctx, hws->regs->DOMAIN0_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 168); | |||
169 | break; | |||
170 | case 1: | |||
171 | REG_SET(DOMAIN1_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate)generic_reg_set_ex(hws->ctx, hws->regs->DOMAIN1_PG_CONFIG , 0, 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate); | |||
172 | REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000)generic_reg_wait(hws->ctx, hws->regs->DOMAIN1_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 172); | |||
173 | break; | |||
174 | case 2: | |||
175 | REG_SET(DOMAIN2_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate)generic_reg_set_ex(hws->ctx, hws->regs->DOMAIN2_PG_CONFIG , 0, 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate); | |||
176 | REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000)generic_reg_wait(hws->ctx, hws->regs->DOMAIN2_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 176); | |||
177 | break; | |||
178 | case 3: | |||
179 | REG_SET(DOMAIN3_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate)generic_reg_set_ex(hws->ctx, hws->regs->DOMAIN3_PG_CONFIG , 0, 1, hws->shifts->DOMAIN_POWER_GATE, hws->masks-> DOMAIN_POWER_GATE, power_gate); | |||
180 | REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000)generic_reg_wait(hws->ctx, hws->regs->DOMAIN3_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000, __func__, 180); | |||
181 | break; | |||
182 | default: | |||
183 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 183); do {} while (0); } while (0); | |||
184 | break; | |||
185 | } | |||
186 | } | |||
187 | ||||
188 | static bool_Bool dcn32_check_no_memory_request_for_cab(struct dc *dc) | |||
189 | { | |||
190 | int i; | |||
191 | ||||
192 | /* First, check no-memory-request case */ | |||
193 | for (i = 0; i < dc->current_state->stream_count; i++) { | |||
194 | if (dc->current_state->stream_status[i].plane_count) | |||
195 | /* Fail eligibility on a visible stream */ | |||
196 | break; | |||
197 | } | |||
198 | ||||
199 | if (i == dc->current_state->stream_count) | |||
200 | return true1; | |||
201 | ||||
202 | return false0; | |||
203 | } | |||
204 | ||||
205 | ||||
206 | /* This function loops through every surface that needs to be cached in CAB for SS, | |||
207 | * and calculates the total number of ways required to store all surfaces (primary, | |||
208 | * meta, cursor). | |||
209 | */ | |||
210 | static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx) | |||
211 | { | |||
212 | int i, j; | |||
213 | struct dc_stream_state *stream = NULL((void *)0); | |||
214 | struct dc_plane_state *plane = NULL((void *)0); | |||
215 | uint32_t cursor_size = 0; | |||
216 | uint32_t total_lines = 0; | |||
217 | uint32_t lines_per_way = 0; | |||
218 | uint8_t num_ways = 0; | |||
219 | uint8_t bytes_per_pixel = 0; | |||
220 | uint8_t cursor_bpp = 0; | |||
221 | uint16_t mblk_width = 0; | |||
222 | uint16_t mblk_height = 0; | |||
223 | uint16_t mall_alloc_width_blk_aligned = 0; | |||
224 | uint16_t mall_alloc_height_blk_aligned = 0; | |||
225 | uint16_t num_mblks = 0; | |||
226 | uint32_t bytes_in_mall = 0; | |||
227 | uint32_t cache_lines_used = 0; | |||
228 | uint32_t cache_lines_per_plane = 0; | |||
229 | ||||
230 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
231 | struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; | |||
232 | ||||
233 | if (!pipe->stream || !pipe->plane_state || | |||
234 | pipe->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED || | |||
235 | pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) | |||
236 | continue; | |||
237 | ||||
238 | bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4; | |||
239 | mblk_width = DCN3_2_MBLK_WIDTH128; | |||
240 | mblk_height = bytes_per_pixel == 4 ? DCN3_2_MBLK_HEIGHT_4BPE128 : DCN3_2_MBLK_HEIGHT_8BPE64; | |||
241 | ||||
242 | /* full_vp_width_blk_aligned = FLOOR(vp_x_start + full_vp_width + blk_width - 1, blk_width) - | |||
243 | * FLOOR(vp_x_start, blk_width) | |||
244 | * | |||
245 | * mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c | |||
246 | */ | |||
247 | mall_alloc_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x + | |||
248 | pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) - | |||
249 | (pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width); | |||
250 | ||||
251 | /* full_vp_height_blk_aligned = FLOOR(vp_y_start + full_vp_height + blk_height - 1, blk_height) - | |||
252 | * FLOOR(vp_y_start, blk_height) | |||
253 | * | |||
254 | * mall_alloc_height_blk_aligned_l/c = full_vp_height_blk_aligned_l/c | |||
255 | */ | |||
256 | mall_alloc_height_blk_aligned = ((pipe->plane_res.scl_data.viewport.y + | |||
257 | pipe->plane_res.scl_data.viewport.height + mblk_height - 1) / mblk_height * mblk_height) - | |||
258 | (pipe->plane_res.scl_data.viewport.y / mblk_height * mblk_height); | |||
259 | ||||
260 | num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) * | |||
261 | ((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height); | |||
262 | ||||
263 | /* For DCC: | |||
264 | * meta_num_mblk = CEILING(full_mblk_width_ub_l*full_mblk_height_ub_l*Bpe/256/mblk_bytes, 1) | |||
265 | */ | |||
266 | if (pipe->plane_state->dcc.enable) | |||
267 | num_mblks += (mall_alloc_width_blk_aligned * mall_alloc_width_blk_aligned * bytes_per_pixel + | |||
268 | (256 * DCN3_2_MALL_MBLK_SIZE_BYTES65536) - 1) / (256 * DCN3_2_MALL_MBLK_SIZE_BYTES65536); | |||
269 | ||||
270 | bytes_in_mall = num_mblks * DCN3_2_MALL_MBLK_SIZE_BYTES65536; | |||
271 | ||||
272 | /* (cache lines used is total bytes / cache_line size. Add +2 for worst case alignment | |||
273 | * (MALL is 64-byte aligned) | |||
274 | */ | |||
275 | cache_lines_per_plane = bytes_in_mall / dc->caps.cache_line_size + 2; | |||
276 | cache_lines_used += cache_lines_per_plane; | |||
277 | } | |||
278 | ||||
279 | // Include cursor size for CAB allocation | |||
280 | for (j = 0; j < dc->res_pool->pipe_count; j++) { | |||
281 | struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[j]; | |||
282 | struct hubp *hubp = pipe->plane_res.hubp; | |||
283 | ||||
284 | if (pipe->stream && pipe->plane_state && hubp) | |||
285 | /* Find the cursor plane and use the exact size instead of | |||
286 | using the max for calculation */ | |||
287 | ||||
288 | if (hubp->curs_attr.width > 0) { | |||
289 | cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height; | |||
290 | ||||
291 | switch (pipe->stream->cursor_attributes.color_format) { | |||
292 | case CURSOR_MODE_MONO: | |||
293 | cursor_size /= 2; | |||
294 | cursor_bpp = 4; | |||
295 | break; | |||
296 | case CURSOR_MODE_COLOR_1BIT_AND: | |||
297 | case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: | |||
298 | case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: | |||
299 | cursor_size *= 4; | |||
300 | cursor_bpp = 4; | |||
301 | break; | |||
302 | ||||
303 | case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: | |||
304 | case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: | |||
305 | cursor_size *= 8; | |||
306 | cursor_bpp = 8; | |||
307 | break; | |||
308 | } | |||
309 | ||||
310 | if (pipe->stream->cursor_position.enable && !dc->debug.alloc_extra_way_for_cursor && | |||
311 | cursor_size > 16384) { | |||
312 | /* cursor_num_mblk = CEILING(num_cursors*cursor_width*cursor_width*cursor_Bpe/mblk_bytes, 1) | |||
313 | */ | |||
314 | cache_lines_used += (((cursor_size + DCN3_2_MALL_MBLK_SIZE_BYTES65536 - 1) / | |||
315 | DCN3_2_MALL_MBLK_SIZE_BYTES65536) * DCN3_2_MALL_MBLK_SIZE_BYTES65536) / | |||
316 | dc->caps.cache_line_size + 2; | |||
317 | } | |||
318 | break; | |||
319 | } | |||
320 | } | |||
321 | ||||
322 | // Convert number of cache lines required to number of ways | |||
323 | total_lines = dc->caps.max_cab_allocation_bytes / dc->caps.cache_line_size; | |||
324 | lines_per_way = total_lines / dc->caps.cache_num_ways; | |||
325 | num_ways = cache_lines_used / lines_per_way; | |||
326 | ||||
327 | if (cache_lines_used % lines_per_way > 0) | |||
328 | num_ways++; | |||
329 | ||||
330 | for (i = 0; i < ctx->stream_count; i++) { | |||
331 | stream = ctx->streams[i]; | |||
332 | for (j = 0; j < ctx->stream_status[i].plane_count; j++) { | |||
333 | plane = ctx->stream_status[i].plane_states[j]; | |||
334 | ||||
335 | if (stream->cursor_position.enable && plane && | |||
336 | dc->debug.alloc_extra_way_for_cursor && | |||
337 | cursor_size > 16384) { | |||
338 | /* Cursor caching is not supported since it won't be on the same line. | |||
339 | * So we need an extra line to accommodate it. With large cursors and a single 4k monitor | |||
340 | * this case triggers corruption. If we're at the edge, then dont trigger display refresh | |||
341 | * from MALL. We only need to cache cursor if its greater that 64x64 at 4 bpp. | |||
342 | */ | |||
343 | num_ways++; | |||
344 | /* We only expect one cursor plane */ | |||
345 | break; | |||
346 | } | |||
347 | } | |||
348 | } | |||
349 | if (dc->debug.force_mall_ss_num_ways > 0) { | |||
350 | num_ways = dc->debug.force_mall_ss_num_ways; | |||
351 | } | |||
352 | return num_ways; | |||
353 | } | |||
354 | ||||
355 | bool_Bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool_Bool enable) | |||
356 | { | |||
357 | union dmub_rb_cmd cmd; | |||
358 | uint8_t ways, i; | |||
359 | int j; | |||
360 | bool_Bool mall_ss_unsupported = false0; | |||
361 | struct dc_plane_state *plane = NULL((void *)0); | |||
362 | ||||
363 | if (!dc->ctx->dmub_srv) | |||
364 | return false0; | |||
365 | ||||
366 | if (enable) { | |||
367 | if (dc->current_state) { | |||
368 | ||||
369 | /* 1. Check no memory request case for CAB. | |||
370 | * If no memory request case, send CAB_ACTION NO_DF_REQ DMUB message | |||
371 | */ | |||
372 | if (dcn32_check_no_memory_request_for_cab(dc)) { | |||
373 | /* Enable no-memory-requests case */ | |||
374 | memset(&cmd, 0, sizeof(cmd))__builtin_memset((&cmd), (0), (sizeof(cmd))); | |||
375 | cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; | |||
376 | cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ; | |||
377 | cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); | |||
378 | ||||
379 | dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd); | |||
380 | dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv); | |||
381 | ||||
382 | return true1; | |||
383 | } | |||
384 | ||||
385 | /* 2. Check if all surfaces can fit in CAB. | |||
386 | * If surfaces can fit into CAB, send CAB_ACTION_ALLOW DMUB message | |||
387 | * and configure HUBP's to fetch from MALL | |||
388 | */ | |||
389 | ways = dcn32_calculate_cab_allocation(dc, dc->current_state); | |||
390 | ||||
391 | /* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo, | |||
392 | * or TMZ surface, don't try to enter MALL. | |||
393 | */ | |||
394 | for (i = 0; i < dc->current_state->stream_count; i++) { | |||
395 | for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) { | |||
396 | plane = dc->current_state->stream_status[i].plane_states[j]; | |||
397 | ||||
398 | if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO || | |||
399 | plane->address.tmz_surface) { | |||
400 | mall_ss_unsupported = true1; | |||
401 | break; | |||
402 | } | |||
403 | } | |||
404 | if (mall_ss_unsupported) | |||
405 | break; | |||
406 | } | |||
407 | if (ways <= dc->caps.cache_num_ways && !mall_ss_unsupported) { | |||
408 | memset(&cmd, 0, sizeof(cmd))__builtin_memset((&cmd), (0), (sizeof(cmd))); | |||
409 | cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; | |||
410 | cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB; | |||
411 | cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); | |||
412 | cmd.cab.cab_alloc_ways = ways; | |||
413 | ||||
414 | dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd); | |||
415 | dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv); | |||
416 | ||||
417 | return true1; | |||
418 | } | |||
419 | ||||
420 | } | |||
421 | return false0; | |||
422 | } | |||
423 | ||||
424 | /* Disable CAB */ | |||
425 | memset(&cmd, 0, sizeof(cmd))__builtin_memset((&cmd), (0), (sizeof(cmd))); | |||
426 | cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS; | |||
427 | cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION; | |||
428 | cmd.cab.header.payload_bytes = | |||
429 | sizeof(cmd.cab) - sizeof(cmd.cab.header); | |||
430 | ||||
431 | dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd); | |||
432 | dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv); | |||
433 | dc_dmub_srv_wait_idle(dc->ctx->dmub_srv); | |||
434 | ||||
435 | return true1; | |||
436 | } | |||
437 | ||||
438 | /* Send DMCUB message with SubVP pipe info | |||
439 | * - For each pipe in context, populate payload with required SubVP information | |||
440 | * if the pipe is using SubVP for MCLK switch | |||
441 | * - This function must be called while the DMUB HW lock is acquired by driver | |||
442 | */ | |||
443 | void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context) | |||
444 | { | |||
445 | int i; | |||
446 | bool_Bool enable_subvp = false0; | |||
447 | ||||
448 | if (!dc->ctx || !dc->ctx->dmub_srv) | |||
449 | return; | |||
450 | ||||
451 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
452 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; | |||
453 | ||||
454 | if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.paired_stream && | |||
455 | pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN) { | |||
456 | // There is at least 1 SubVP pipe, so enable SubVP | |||
457 | enable_subvp = true1; | |||
458 | break; | |||
459 | } | |||
460 | } | |||
461 | dc_dmub_setup_subvp_dmub_command(dc, context, enable_subvp); | |||
462 | } | |||
463 | ||||
464 | /* Sub-Viewport DMUB lock needs to be acquired by driver whenever SubVP is active and: | |||
465 | * 1. Any full update for any SubVP main pipe | |||
466 | * 2. Any immediate flip for any SubVP pipe | |||
467 | * 3. Any flip for DRR pipe | |||
468 | * 4. If SubVP was previously in use (i.e. in old context) | |||
469 | */ | |||
470 | void dcn32_subvp_pipe_control_lock(struct dc *dc, | |||
471 | struct dc_state *context, | |||
472 | bool_Bool lock, | |||
473 | bool_Bool should_lock_all_pipes, | |||
474 | struct pipe_ctx *top_pipe_to_program, | |||
475 | bool_Bool subvp_prev_use) | |||
476 | { | |||
477 | unsigned int i = 0; | |||
478 | bool_Bool subvp_immediate_flip = false0; | |||
479 | bool_Bool subvp_in_use = false0; | |||
480 | struct pipe_ctx *pipe; | |||
481 | ||||
482 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
483 | pipe = &context->res_ctx.pipe_ctx[i]; | |||
484 | ||||
485 | if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { | |||
486 | subvp_in_use = true1; | |||
487 | break; | |||
488 | } | |||
489 | } | |||
490 | ||||
491 | if (top_pipe_to_program && top_pipe_to_program->stream && top_pipe_to_program->plane_state) { | |||
492 | if (top_pipe_to_program->stream->mall_stream_config.type == SUBVP_MAIN && | |||
493 | top_pipe_to_program->plane_state->flip_immediate) | |||
494 | subvp_immediate_flip = true1; | |||
495 | } | |||
496 | ||||
497 | // Don't need to lock for DRR VSYNC flips -- FW will wait for DRR pending update cleared. | |||
498 | if ((subvp_in_use && (should_lock_all_pipes || subvp_immediate_flip)) || (!subvp_in_use && subvp_prev_use)) { | |||
499 | union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; | |||
500 | ||||
501 | if (!lock) { | |||
502 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
503 | pipe = &context->res_ctx.pipe_ctx[i]; | |||
504 | if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN && | |||
505 | should_lock_all_pipes) | |||
506 | pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK); | |||
507 | } | |||
508 | } | |||
509 | ||||
510 | hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK; | |||
511 | hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER; | |||
512 | hw_lock_cmd.bits.lock = lock; | |||
513 | hw_lock_cmd.bits.should_release = !lock; | |||
514 | dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd); | |||
515 | } | |||
516 | } | |||
517 | ||||
518 | ||||
519 | static bool_Bool dcn32_set_mpc_shaper_3dlut( | |||
520 | struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) | |||
521 | { | |||
522 | struct dpp *dpp_base = pipe_ctx->plane_res.dpp; | |||
523 | int mpcc_id = pipe_ctx->plane_res.hubp->inst; | |||
524 | struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; | |||
525 | bool_Bool result = false0; | |||
526 | ||||
527 | const struct pwl_params *shaper_lut = NULL((void *)0); | |||
528 | //get the shaper lut params | |||
529 | if (stream->func_shaper) { | |||
530 | if (stream->func_shaper->type == TF_TYPE_HWPWL) | |||
531 | shaper_lut = &stream->func_shaper->pwl; | |||
532 | else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { | |||
533 | cm_helper_translate_curve_to_hw_format(stream->ctx, | |||
534 | stream->func_shaper, | |||
535 | &dpp_base->shaper_params, true1); | |||
536 | shaper_lut = &dpp_base->shaper_params; | |||
537 | } | |||
538 | } | |||
539 | ||||
540 | if (stream->lut3d_func && | |||
541 | stream->lut3d_func->state.bits.initialized == 1) { | |||
542 | ||||
543 | result = mpc->funcs->program_3dlut(mpc, | |||
544 | &stream->lut3d_func->lut_3d, | |||
545 | mpcc_id); | |||
546 | ||||
547 | result = mpc->funcs->program_shaper(mpc, | |||
548 | shaper_lut, | |||
549 | mpcc_id); | |||
550 | } | |||
551 | ||||
552 | return result; | |||
553 | } | |||
554 | ||||
555 | bool_Bool dcn32_set_mcm_luts( | |||
556 | struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) | |||
557 | { | |||
558 | struct dpp *dpp_base = pipe_ctx->plane_res.dpp; | |||
559 | int mpcc_id = pipe_ctx->plane_res.hubp->inst; | |||
560 | struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; | |||
561 | bool_Bool result = true1; | |||
562 | struct pwl_params *lut_params = NULL((void *)0); | |||
563 | ||||
564 | // 1D LUT | |||
565 | if (plane_state->blend_tf) { | |||
566 | if (plane_state->blend_tf->type == TF_TYPE_HWPWL) | |||
567 | lut_params = &plane_state->blend_tf->pwl; | |||
568 | else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { | |||
569 | cm3_helper_translate_curve_to_hw_format(plane_state->blend_tf, | |||
570 | &dpp_base->regamma_params, false0); | |||
571 | lut_params = &dpp_base->regamma_params; | |||
572 | } | |||
573 | } | |||
574 | result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id); | |||
575 | ||||
576 | // Shaper | |||
577 | if (plane_state->in_shaper_func) { | |||
578 | if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL) | |||
579 | lut_params = &plane_state->in_shaper_func->pwl; | |||
580 | else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) { | |||
581 | // TODO: dpp_base replace | |||
582 | ASSERT(false)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn32/dcn32_hwseq.c" , 582); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
583 | cm3_helper_translate_curve_to_hw_format(plane_state->in_shaper_func, | |||
584 | &dpp_base->shaper_params, true1); | |||
585 | lut_params = &dpp_base->shaper_params; | |||
586 | } | |||
587 | } | |||
588 | ||||
589 | result = mpc->funcs->program_shaper(mpc, lut_params, mpcc_id); | |||
590 | ||||
591 | // 3D | |||
592 | if (plane_state->lut3d_func && plane_state->lut3d_func->state.bits.initialized == 1) | |||
593 | result = mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func->lut_3d, mpcc_id); | |||
594 | else | |||
595 | result = mpc->funcs->program_3dlut(mpc, NULL((void *)0), mpcc_id); | |||
596 | ||||
597 | return result; | |||
598 | } | |||
599 | ||||
600 | bool_Bool dcn32_set_input_transfer_func(struct dc *dc, | |||
601 | struct pipe_ctx *pipe_ctx, | |||
602 | const struct dc_plane_state *plane_state) | |||
603 | { | |||
604 | struct dce_hwseq *hws = dc->hwseq; | |||
605 | struct mpc *mpc = dc->res_pool->mpc; | |||
606 | struct dpp *dpp_base = pipe_ctx->plane_res.dpp; | |||
607 | ||||
608 | enum dc_transfer_func_predefined tf; | |||
609 | bool_Bool result = true1; | |||
610 | struct pwl_params *params = NULL((void *)0); | |||
611 | ||||
612 | if (mpc == NULL((void *)0) || plane_state == NULL((void *)0)) | |||
613 | return false0; | |||
614 | ||||
615 | tf = TRANSFER_FUNCTION_UNITY; | |||
616 | ||||
617 | if (plane_state->in_transfer_func && | |||
618 | plane_state->in_transfer_func->type == TF_TYPE_PREDEFINED) | |||
619 | tf = plane_state->in_transfer_func->tf; | |||
620 | ||||
621 | dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf); | |||
622 | ||||
623 | if (plane_state->in_transfer_func) { | |||
624 | if (plane_state->in_transfer_func->type == TF_TYPE_HWPWL) | |||
625 | params = &plane_state->in_transfer_func->pwl; | |||
626 | else if (plane_state->in_transfer_func->type == TF_TYPE_DISTRIBUTED_POINTS && | |||
627 | cm3_helper_translate_curve_to_hw_format(plane_state->in_transfer_func, | |||
628 | &dpp_base->degamma_params, false0)) | |||
629 | params = &dpp_base->degamma_params; | |||
630 | } | |||
631 | ||||
632 | dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params); | |||
633 | ||||
634 | if (pipe_ctx->stream_res.opp && | |||
635 | pipe_ctx->stream_res.opp->ctx && | |||
636 | hws->funcs.set_mcm_luts) | |||
637 | result = hws->funcs.set_mcm_luts(pipe_ctx, plane_state); | |||
638 | ||||
639 | return result; | |||
640 | } | |||
641 | ||||
642 | bool_Bool dcn32_set_output_transfer_func(struct dc *dc, | |||
643 | struct pipe_ctx *pipe_ctx, | |||
644 | const struct dc_stream_state *stream) | |||
645 | { | |||
646 | int mpcc_id = pipe_ctx->plane_res.hubp->inst; | |||
647 | struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; | |||
648 | struct pwl_params *params = NULL((void *)0); | |||
649 | bool_Bool ret = false0; | |||
650 | ||||
651 | /* program OGAM or 3DLUT only for the top pipe*/ | |||
652 | if (pipe_ctx->top_pipe == NULL((void *)0)) { | |||
| ||||
653 | /*program shaper and 3dlut in MPC*/ | |||
654 | ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream); | |||
655 | if (ret
| |||
656 | if (stream->out_transfer_func->type == TF_TYPE_HWPWL) | |||
657 | params = &stream->out_transfer_func->pwl; | |||
658 | else if (pipe_ctx->stream->out_transfer_func->type == | |||
659 | TF_TYPE_DISTRIBUTED_POINTS && | |||
660 | cm3_helper_translate_curve_to_hw_format( | |||
661 | stream->out_transfer_func, | |||
662 | &mpc->blender_params, false0)) | |||
663 | params = &mpc->blender_params; | |||
664 | /* there are no ROM LUTs in OUTGAM */ | |||
665 | if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED) | |||
666 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 666); do {} while (0); } while (0); | |||
667 | } | |||
668 | } | |||
669 | ||||
670 | mpc->funcs->set_output_gamma(mpc, mpcc_id, params); | |||
| ||||
671 | return ret; | |||
672 | } | |||
673 | ||||
674 | /* Program P-State force value according to if pipe is using SubVP or not: | |||
675 | * 1. Reset P-State force on all pipes first | |||
676 | * 2. For each main pipe, force P-State disallow (P-State allow moderated by DMUB) | |||
677 | */ | |||
678 | void dcn32_subvp_update_force_pstate(struct dc *dc, struct dc_state *context) | |||
679 | { | |||
680 | int i; | |||
681 | int num_subvp = 0; | |||
682 | /* Unforce p-state for each pipe | |||
683 | */ | |||
684 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
685 | struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; | |||
686 | struct hubp *hubp = pipe->plane_res.hubp; | |||
687 | ||||
688 | if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) | |||
689 | hubp->funcs->hubp_update_force_pstate_disallow(hubp, false0); | |||
690 | if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN) | |||
691 | num_subvp++; | |||
692 | } | |||
693 | ||||
694 | if (num_subvp == 0) | |||
695 | return; | |||
696 | ||||
697 | /* Loop through each pipe -- for each subvp main pipe force p-state allow equal to false. | |||
698 | */ | |||
699 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
700 | struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; | |||
701 | ||||
702 | // For SubVP + DRR, also force disallow on the DRR pipe | |||
703 | // (We will force allow in the DMUB sequence -- some DRR timings by default won't allow P-State so we have | |||
704 | // to force once the vblank is stretched). | |||
705 | if (pipe->stream && pipe->plane_state && (pipe->stream->mall_stream_config.type == SUBVP_MAIN || | |||
706 | (pipe->stream->mall_stream_config.type == SUBVP_NONE && pipe->stream->ignore_msa_timing_param))) { | |||
707 | struct hubp *hubp = pipe->plane_res.hubp; | |||
708 | ||||
709 | if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) | |||
710 | hubp->funcs->hubp_update_force_pstate_disallow(hubp, true1); | |||
711 | } | |||
712 | } | |||
713 | } | |||
714 | ||||
715 | /* Update MALL_SEL register based on if pipe / plane | |||
716 | * is a phantom pipe, main pipe, and if using MALL | |||
717 | * for SS. | |||
718 | */ | |||
719 | void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context) | |||
720 | { | |||
721 | int i; | |||
722 | unsigned int num_ways = dcn32_calculate_cab_allocation(dc, context); | |||
723 | bool_Bool cache_cursor = false0; | |||
724 | ||||
725 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
726 | struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; | |||
727 | struct hubp *hubp = pipe->plane_res.hubp; | |||
728 | ||||
729 | if (pipe->stream && pipe->plane_state && hubp && hubp->funcs->hubp_update_mall_sel) { | |||
730 | int cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height; | |||
731 | ||||
732 | switch (hubp->curs_attr.color_format) { | |||
733 | case CURSOR_MODE_MONO: | |||
734 | cursor_size /= 2; | |||
735 | break; | |||
736 | case CURSOR_MODE_COLOR_1BIT_AND: | |||
737 | case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA: | |||
738 | case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA: | |||
739 | cursor_size *= 4; | |||
740 | break; | |||
741 | ||||
742 | case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED: | |||
743 | case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED: | |||
744 | default: | |||
745 | cursor_size *= 8; | |||
746 | break; | |||
747 | } | |||
748 | ||||
749 | if (cursor_size > 16384) | |||
750 | cache_cursor = true1; | |||
751 | ||||
752 | if (pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { | |||
753 | hubp->funcs->hubp_update_mall_sel(hubp, 1, false0); | |||
754 | } else { | |||
755 | // MALL not supported with Stereo3D | |||
756 | hubp->funcs->hubp_update_mall_sel(hubp, | |||
757 | num_ways <= dc->caps.cache_num_ways && | |||
758 | pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED && | |||
759 | pipe->plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO && | |||
760 | !pipe->plane_state->address.tmz_surface ? 2 : 0, | |||
761 | cache_cursor); | |||
762 | } | |||
763 | } | |||
764 | } | |||
765 | } | |||
766 | ||||
767 | /* Program the sub-viewport pipe configuration after the main / phantom pipes | |||
768 | * have been programmed in hardware. | |||
769 | * 1. Update force P-State for all the main pipes (disallow P-state) | |||
770 | * 2. Update MALL_SEL register | |||
771 | * 3. Program FORCE_ONE_ROW_FOR_FRAME for main subvp pipes | |||
772 | */ | |||
773 | void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context) | |||
774 | { | |||
775 | int i; | |||
776 | struct dce_hwseq *hws = dc->hwseq; | |||
777 | ||||
778 | // Don't force p-state disallow -- can't block dummy p-state | |||
779 | ||||
780 | // Update MALL_SEL register for each pipe | |||
781 | if (hws && hws->funcs.update_mall_sel) | |||
782 | hws->funcs.update_mall_sel(dc, context); | |||
783 | ||||
784 | // Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes | |||
785 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
786 | struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; | |||
787 | struct hubp *hubp = pipe->plane_res.hubp; | |||
788 | ||||
789 | if (pipe->stream && hubp && hubp->funcs->hubp_prepare_subvp_buffering) { | |||
790 | /* TODO - remove setting CURSOR_REQ_MODE to 0 for legacy cases | |||
791 | * - need to investigate single pipe MPO + SubVP case to | |||
792 | * see if CURSOR_REQ_MODE will be back to 1 for SubVP | |||
793 | * when it should be 0 for MPO | |||
794 | */ | |||
795 | if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { | |||
796 | hubp->funcs->hubp_prepare_subvp_buffering(hubp, true1); | |||
797 | } | |||
798 | } | |||
799 | } | |||
800 | } | |||
801 | ||||
802 | void dcn32_init_hw(struct dc *dc) | |||
803 | { | |||
804 | struct abm **abms = dc->res_pool->multiple_abms; | |||
805 | struct dce_hwseq *hws = dc->hwseq; | |||
806 | struct dc_bios *dcb = dc->ctx->dc_bios; | |||
807 | struct resource_pool *res_pool = dc->res_pool; | |||
808 | int i; | |||
809 | int edp_num; | |||
810 | uint32_t backlight = MAX_BACKLIGHT_LEVEL0xFFFF; | |||
811 | ||||
812 | if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) | |||
813 | dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); | |||
814 | ||||
815 | // Initialize the dccg | |||
816 | if (res_pool->dccg->funcs->dccg_init) | |||
817 | res_pool->dccg->funcs->dccg_init(res_pool->dccg); | |||
818 | ||||
819 | if (!dcb->funcs->is_accelerated_mode(dcb)) { | |||
820 | hws->funcs.bios_golden_init(dc); | |||
821 | hws->funcs.disable_vga(dc->hwseq); | |||
822 | } | |||
823 | ||||
824 | // Set default OPTC memory power states | |||
825 | if (dc->debug.enable_mem_low_power.bits.optc) { | |||
826 | // Shutdown when unassigned and light sleep in VBLANK | |||
827 | REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1)generic_reg_set_ex(hws->ctx, hws->regs->ODM_MEM_PWR_CTRL3 , 0, 2, hws->shifts->ODM_MEM_UNASSIGNED_PWR_MODE, hws-> masks->ODM_MEM_UNASSIGNED_PWR_MODE, 3, hws->shifts-> ODM_MEM_VBLANK_PWR_MODE, hws->masks->ODM_MEM_VBLANK_PWR_MODE , 1); | |||
828 | } | |||
829 | ||||
830 | if (dc->debug.enable_mem_low_power.bits.vga) { | |||
831 | // Power down VGA memory | |||
832 | REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1)generic_reg_update_ex(hws->ctx, hws->regs->MMHUBBUB_MEM_PWR_CNTL , 1, hws->shifts->VGA_MEM_PWR_FORCE, hws->masks-> VGA_MEM_PWR_FORCE, 1); | |||
833 | } | |||
834 | ||||
835 | if (dc->ctx->dc_bios->fw_info_valid) { | |||
836 | res_pool->ref_clocks.xtalin_clock_inKhz = | |||
837 | dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; | |||
838 | ||||
839 | if (res_pool->dccg && res_pool->hubbub) { | |||
840 | (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, | |||
841 | dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, | |||
842 | &res_pool->ref_clocks.dccg_ref_clock_inKhz); | |||
843 | ||||
844 | (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, | |||
845 | res_pool->ref_clocks.dccg_ref_clock_inKhz, | |||
846 | &res_pool->ref_clocks.dchub_ref_clock_inKhz); | |||
847 | } else { | |||
848 | // Not all ASICs have DCCG sw component | |||
849 | res_pool->ref_clocks.dccg_ref_clock_inKhz = | |||
850 | res_pool->ref_clocks.xtalin_clock_inKhz; | |||
851 | res_pool->ref_clocks.dchub_ref_clock_inKhz = | |||
852 | res_pool->ref_clocks.xtalin_clock_inKhz; | |||
853 | } | |||
854 | } else | |||
855 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn32/dcn32_hwseq.c" , 855); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
856 | ||||
857 | for (i = 0; i < dc->link_count; i++) { | |||
858 | /* Power up AND update implementation according to the | |||
859 | * required signal (which may be different from the | |||
860 | * default signal on connector). | |||
861 | */ | |||
862 | struct dc_link *link = dc->links[i]; | |||
863 | ||||
864 | link->link_enc->funcs->hw_init(link->link_enc); | |||
865 | ||||
866 | /* Check for enabled DIG to identify enabled display */ | |||
867 | if (link->link_enc->funcs->is_dig_enabled && | |||
868 | link->link_enc->funcs->is_dig_enabled(link->link_enc)) { | |||
869 | link->link_status.link_active = true1; | |||
870 | link->phy_state.symclk_state = SYMCLK_ON_TX_ON; | |||
871 | if (link->link_enc->funcs->fec_is_active && | |||
872 | link->link_enc->funcs->fec_is_active(link->link_enc)) | |||
873 | link->fec_state = dc_link_fec_enabled; | |||
874 | } | |||
875 | } | |||
876 | ||||
877 | /* Power gate DSCs */ | |||
878 | for (i = 0; i < res_pool->res_cap->num_dsc; i++) | |||
879 | if (hws->funcs.dsc_pg_control != NULL((void *)0)) | |||
880 | hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false0); | |||
881 | ||||
882 | /* we want to turn off all dp displays before doing detection */ | |||
883 | dc_link_blank_all_dp_displays(dc); | |||
884 | ||||
885 | /* If taking control over from VBIOS, we may want to optimize our first | |||
886 | * mode set, so we need to skip powering down pipes until we know which | |||
887 | * pipes we want to use. | |||
888 | * Otherwise, if taking control is not possible, we need to power | |||
889 | * everything down. | |||
890 | */ | |||
891 | if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) { | |||
892 | hws->funcs.init_pipes(dc, dc->current_state); | |||
893 | if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) | |||
894 | dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, | |||
895 | !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter); | |||
896 | } | |||
897 | ||||
898 | /* In headless boot cases, DIG may be turned | |||
899 | * on which causes HW/SW discrepancies. | |||
900 | * To avoid this, power down hardware on boot | |||
901 | * if DIG is turned on and seamless boot not enabled | |||
902 | */ | |||
903 | if (!dc->config.seamless_boot_edp_requested) { | |||
904 | struct dc_link *edp_links[MAX_NUM_EDP2]; | |||
905 | struct dc_link *edp_link; | |||
906 | ||||
907 | get_edp_links(dc, edp_links, &edp_num); | |||
908 | if (edp_num) { | |||
909 | for (i = 0; i < edp_num; i++) { | |||
910 | edp_link = edp_links[i]; | |||
911 | if (edp_link->link_enc->funcs->is_dig_enabled && | |||
912 | edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) && | |||
913 | dc->hwss.edp_backlight_control && | |||
914 | dc->hwss.power_down && | |||
915 | dc->hwss.edp_power_control) { | |||
916 | dc->hwss.edp_backlight_control(edp_link, false0); | |||
917 | dc->hwss.power_down(dc); | |||
918 | dc->hwss.edp_power_control(edp_link, false0); | |||
919 | } | |||
920 | } | |||
921 | } else { | |||
922 | for (i = 0; i < dc->link_count; i++) { | |||
923 | struct dc_link *link = dc->links[i]; | |||
924 | ||||
925 | if (link->link_enc->funcs->is_dig_enabled && | |||
926 | link->link_enc->funcs->is_dig_enabled(link->link_enc) && | |||
927 | dc->hwss.power_down) { | |||
928 | dc->hwss.power_down(dc); | |||
929 | break; | |||
930 | } | |||
931 | ||||
932 | } | |||
933 | } | |||
934 | } | |||
935 | ||||
936 | for (i = 0; i < res_pool->audio_count; i++) { | |||
937 | struct audio *audio = res_pool->audios[i]; | |||
938 | ||||
939 | audio->funcs->hw_init(audio); | |||
940 | } | |||
941 | ||||
942 | for (i = 0; i < dc->link_count; i++) { | |||
943 | struct dc_link *link = dc->links[i]; | |||
944 | ||||
945 | if (link->panel_cntl) | |||
946 | backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); | |||
947 | } | |||
948 | ||||
949 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
950 | if (abms[i] != NULL((void *)0) && abms[i]->funcs != NULL((void *)0)) | |||
951 | abms[i]->funcs->abm_init(abms[i], backlight); | |||
952 | } | |||
953 | ||||
954 | /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ | |||
955 | REG_WRITE(DIO_MEM_PWR_CTRL, 0)dm_write_reg_func(hws->ctx, hws->regs->DIO_MEM_PWR_CTRL , 0, __func__); | |||
956 | ||||
957 | if (!dc->debug.disable_clock_gate) { | |||
958 | /* enable all DCN clock gating */ | |||
959 | REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0)dm_write_reg_func(hws->ctx, hws->regs->DCCG_GATE_DISABLE_CNTL , 0, __func__); | |||
960 | ||||
961 | REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0)dm_write_reg_func(hws->ctx, hws->regs->DCCG_GATE_DISABLE_CNTL2 , 0, __func__); | |||
962 | ||||
963 | REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0)generic_reg_update_ex(hws->ctx, hws->regs->DCFCLK_CNTL , 1, hws->shifts->DCFCLK_GATE_DIS, hws->masks->DCFCLK_GATE_DIS , 0); | |||
964 | } | |||
965 | if (hws->funcs.enable_power_gating_plane) | |||
966 | hws->funcs.enable_power_gating_plane(dc->hwseq, true1); | |||
967 | ||||
968 | if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) | |||
969 | dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); | |||
970 | ||||
971 | if (dc->clk_mgr->funcs->notify_wm_ranges) | |||
972 | dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); | |||
973 | ||||
974 | if (dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled) | |||
975 | dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr); | |||
976 | ||||
977 | if (dc->res_pool->hubbub->funcs->force_pstate_change_control) | |||
978 | dc->res_pool->hubbub->funcs->force_pstate_change_control( | |||
979 | dc->res_pool->hubbub, false0, false0); | |||
980 | ||||
981 | if (dc->res_pool->hubbub->funcs->init_crb) | |||
982 | dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub); | |||
983 | ||||
984 | // Get DMCUB capabilities | |||
985 | if (dc->ctx->dmub_srv) { | |||
986 | dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub); | |||
987 | dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; | |||
988 | dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch; | |||
989 | } | |||
990 | ||||
991 | /* Enable support for ODM and windowed MPO if policy flag is set */ | |||
992 | if (dc->debug.enable_single_display_2to1_odm_policy) | |||
993 | dc->config.enable_windowed_mpo_odm = true1; | |||
994 | } | |||
995 | ||||
996 | static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, | |||
997 | int opp_cnt) | |||
998 | { | |||
999 | bool_Bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing); | |||
1000 | int flow_ctrl_cnt; | |||
1001 | ||||
1002 | if (opp_cnt >= 2) | |||
1003 | hblank_halved = true1; | |||
1004 | ||||
1005 | flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable - | |||
1006 | stream->timing.h_border_left - | |||
1007 | stream->timing.h_border_right; | |||
1008 | ||||
1009 | if (hblank_halved) | |||
1010 | flow_ctrl_cnt /= 2; | |||
1011 | ||||
1012 | /* ODM combine 4:1 case */ | |||
1013 | if (opp_cnt == 4) | |||
1014 | flow_ctrl_cnt /= 2; | |||
1015 | ||||
1016 | return flow_ctrl_cnt; | |||
1017 | } | |||
1018 | ||||
1019 | static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool_Bool enable) | |||
1020 | { | |||
1021 | struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; | |||
1022 | struct dc_stream_state *stream = pipe_ctx->stream; | |||
1023 | struct pipe_ctx *odm_pipe; | |||
1024 | int opp_cnt = 1; | |||
1025 | ||||
1026 | ASSERT(dsc)do { if (({ static int __warned; int __ret = !!(!(dsc)); if ( __ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(dsc)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn32/dcn32_hwseq.c" , 1026); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1027 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) | |||
1028 | opp_cnt++; | |||
1029 | ||||
1030 | if (enable) { | |||
1031 | struct dsc_config dsc_cfg; | |||
1032 | struct dsc_optc_config dsc_optc_cfg; | |||
1033 | enum optc_dsc_mode optc_dsc_mode; | |||
1034 | ||||
1035 | /* Enable DSC hw block */ | |||
1036 | dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; | |||
1037 | dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; | |||
1038 | dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; | |||
1039 | dsc_cfg.color_depth = stream->timing.display_color_depth; | |||
1040 | dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true1 : false0; | |||
1041 | dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; | |||
1042 | ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0)do { if (({ static int __warned; int __ret = !!(!(dsc_cfg.dc_dsc_cfg .num_slices_h % opp_cnt == 0)); if (__ret && !__warned ) { printf("WARNING %s failed at %s:%d\n", "!(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn32/dcn32_hwseq.c" , 1042); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1043 | dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; | |||
1044 | ||||
1045 | dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); | |||
1046 | dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); | |||
1047 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { | |||
1048 | struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; | |||
1049 | ||||
1050 | ASSERT(odm_dsc)do { if (({ static int __warned; int __ret = !!(!(odm_dsc)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(odm_dsc)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn32/dcn32_hwseq.c" , 1050); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1051 | odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); | |||
1052 | odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); | |||
1053 | } | |||
1054 | dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; | |||
1055 | dsc_cfg.pic_width *= opp_cnt; | |||
1056 | ||||
1057 | optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; | |||
1058 | ||||
1059 | /* Enable DSC in OPTC */ | |||
1060 | DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst)___drm_dbg(((void *)0), DRM_UT_KMS, "Setting optc DSC config for tg instance %d:" , pipe_ctx->stream_res.tg->inst); | |||
1061 | pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, | |||
1062 | optc_dsc_mode, | |||
1063 | dsc_optc_cfg.bytes_per_pixel, | |||
1064 | dsc_optc_cfg.slice_width); | |||
1065 | } else { | |||
1066 | /* disable DSC in OPTC */ | |||
1067 | pipe_ctx->stream_res.tg->funcs->set_dsc_config( | |||
1068 | pipe_ctx->stream_res.tg, | |||
1069 | OPTC_DSC_DISABLED, 0, 0); | |||
1070 | ||||
1071 | /* disable DSC block */ | |||
1072 | dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); | |||
1073 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { | |||
1074 | ASSERT(odm_pipe->stream_res.dsc)do { if (({ static int __warned; int __ret = !!(!(odm_pipe-> stream_res.dsc)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(odm_pipe->stream_res.dsc)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn32/dcn32_hwseq.c" , 1074); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1075 | odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); | |||
1076 | } | |||
1077 | } | |||
1078 | } | |||
1079 | ||||
1080 | /* | |||
1081 | * Given any pipe_ctx, return the total ODM combine factor, and optionally return | |||
1082 | * the OPPids which are used | |||
1083 | * */ | |||
1084 | static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances) | |||
1085 | { | |||
1086 | unsigned int opp_count = 1; | |||
1087 | struct pipe_ctx *odm_pipe; | |||
1088 | ||||
1089 | /* First get to the top pipe */ | |||
1090 | for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe) | |||
1091 | ; | |||
1092 | ||||
1093 | /* First pipe is always used */ | |||
1094 | if (opp_instances) | |||
1095 | opp_instances[0] = odm_pipe->stream_res.opp->inst; | |||
1096 | ||||
1097 | /* Find and count odm pipes, if any */ | |||
1098 | for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { | |||
1099 | if (opp_instances) | |||
1100 | opp_instances[opp_count] = odm_pipe->stream_res.opp->inst; | |||
1101 | opp_count++; | |||
1102 | } | |||
1103 | ||||
1104 | return opp_count; | |||
1105 | } | |||
1106 | ||||
1107 | void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) | |||
1108 | { | |||
1109 | struct pipe_ctx *odm_pipe; | |||
1110 | int opp_cnt = 0; | |||
1111 | int opp_inst[MAX_PIPES6] = {0}; | |||
1112 | bool_Bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing)); | |||
1113 | struct mpc_dwb_flow_control flow_control; | |||
1114 | struct mpc *mpc = dc->res_pool->mpc; | |||
1115 | int i; | |||
1116 | ||||
1117 | opp_cnt = get_odm_config(pipe_ctx, opp_inst); | |||
1118 | ||||
1119 | if (opp_cnt > 1) | |||
1120 | pipe_ctx->stream_res.tg->funcs->set_odm_combine( | |||
1121 | pipe_ctx->stream_res.tg, | |||
1122 | opp_inst, opp_cnt, | |||
1123 | &pipe_ctx->stream->timing); | |||
1124 | else | |||
1125 | pipe_ctx->stream_res.tg->funcs->set_odm_bypass( | |||
1126 | pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); | |||
1127 | ||||
1128 | rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1; | |||
1129 | flow_control.flow_ctrl_mode = 0; | |||
1130 | flow_control.flow_ctrl_cnt0 = 0x80; | |||
1131 | flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(pipe_ctx->stream, opp_cnt); | |||
1132 | if (mpc->funcs->set_out_rate_control) { | |||
1133 | for (i = 0; i < opp_cnt; ++i) { | |||
1134 | mpc->funcs->set_out_rate_control( | |||
1135 | mpc, opp_inst[i], | |||
1136 | true1, | |||
1137 | rate_control_2x_pclk, | |||
1138 | &flow_control); | |||
1139 | } | |||
1140 | } | |||
1141 | ||||
1142 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { | |||
1143 | odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( | |||
1144 | odm_pipe->stream_res.opp, | |||
1145 | true1); | |||
1146 | } | |||
1147 | ||||
1148 | if (pipe_ctx->stream_res.dsc) { | |||
1149 | struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; | |||
1150 | ||||
1151 | update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC); | |||
1152 | ||||
1153 | /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */ | |||
1154 | if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && | |||
1155 | current_pipe_ctx->next_odm_pipe->stream_res.dsc) { | |||
1156 | struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; | |||
1157 | /* disconnect DSC block from stream */ | |||
1158 | dsc->funcs->dsc_disconnect(dsc); | |||
1159 | } | |||
1160 | } | |||
1161 | } | |||
1162 | ||||
1163 | unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div) | |||
1164 | { | |||
1165 | struct dc_stream_state *stream = pipe_ctx->stream; | |||
1166 | unsigned int odm_combine_factor = 0; | |||
1167 | bool_Bool two_pix_per_container = false0; | |||
1168 | ||||
1169 | two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing); | |||
1170 | odm_combine_factor = get_odm_config(pipe_ctx, NULL((void *)0)); | |||
1171 | ||||
1172 | if (is_dp_128b_132b_signal(pipe_ctx)) { | |||
1173 | *k1_div = PIXEL_RATE_DIV_BY_1; | |||
1174 | *k2_div = PIXEL_RATE_DIV_BY_1; | |||
1175 | } else if (dc_is_hdmi_tmds_signal(stream->signal) || dc_is_dvi_signal(stream->signal)) { | |||
1176 | *k1_div = PIXEL_RATE_DIV_BY_1; | |||
1177 | if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) | |||
1178 | *k2_div = PIXEL_RATE_DIV_BY_2; | |||
1179 | else | |||
1180 | *k2_div = PIXEL_RATE_DIV_BY_4; | |||
1181 | } else if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) { | |||
1182 | if (two_pix_per_container) { | |||
1183 | *k1_div = PIXEL_RATE_DIV_BY_1; | |||
1184 | *k2_div = PIXEL_RATE_DIV_BY_2; | |||
1185 | } else { | |||
1186 | *k1_div = PIXEL_RATE_DIV_BY_1; | |||
1187 | *k2_div = PIXEL_RATE_DIV_BY_4; | |||
1188 | if ((odm_combine_factor == 2) || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) | |||
1189 | *k2_div = PIXEL_RATE_DIV_BY_2; | |||
1190 | } | |||
1191 | } | |||
1192 | ||||
1193 | if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA)) | |||
1194 | ASSERT(false)do { if (({ static int __warned; int __ret = !!(!(0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn32/dcn32_hwseq.c" , 1194); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); | |||
1195 | ||||
1196 | return odm_combine_factor; | |||
1197 | } | |||
1198 | ||||
1199 | void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx) | |||
1200 | { | |||
1201 | uint32_t pix_per_cycle = 1; | |||
1202 | uint32_t odm_combine_factor = 1; | |||
1203 | ||||
1204 | if (!pipe_ctx || !pipe_ctx->stream || !pipe_ctx->stream_res.stream_enc) | |||
1205 | return; | |||
1206 | ||||
1207 | odm_combine_factor = get_odm_config(pipe_ctx, NULL((void *)0)); | |||
1208 | if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1 | |||
1209 | || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) | |||
1210 | pix_per_cycle = 2; | |||
1211 | ||||
1212 | if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode) | |||
1213 | pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc, | |||
1214 | pix_per_cycle); | |||
1215 | } | |||
1216 | ||||
1217 | void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx, | |||
1218 | struct dc_link_settings *link_settings) | |||
1219 | { | |||
1220 | struct encoder_unblank_param params = {0}; | |||
1221 | struct dc_stream_state *stream = pipe_ctx->stream; | |||
1222 | struct dc_link *link = stream->link; | |||
1223 | struct dce_hwseq *hws = link->dc->hwseq; | |||
1224 | struct pipe_ctx *odm_pipe; | |||
1225 | uint32_t pix_per_cycle = 1; | |||
1226 | ||||
1227 | params.opp_cnt = 1; | |||
1228 | for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) | |||
1229 | params.opp_cnt++; | |||
1230 | ||||
1231 | /* only 3 items below are used by unblank */ | |||
1232 | params.timing = pipe_ctx->stream->timing; | |||
1233 | ||||
1234 | params.link_settings.link_rate = link_settings->link_rate; | |||
1235 | ||||
1236 | if (is_dp_128b_132b_signal(pipe_ctx)) { | |||
1237 | /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */ | |||
1238 | pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank( | |||
1239 | pipe_ctx->stream_res.hpo_dp_stream_enc, | |||
1240 | pipe_ctx->stream_res.tg->inst); | |||
1241 | } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) { | |||
1242 | if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1 | |||
1243 | || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) { | |||
1244 | params.timing.pix_clk_100hz /= 2; | |||
1245 | pix_per_cycle = 2; | |||
1246 | } | |||
1247 | pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( | |||
1248 | pipe_ctx->stream_res.stream_enc, pix_per_cycle > 1); | |||
1249 | pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); | |||
1250 | } | |||
1251 | ||||
1252 | if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) | |||
1253 | hws->funcs.edp_backlight_control(link, true1); | |||
1254 | } | |||
1255 | ||||
1256 | bool_Bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx) | |||
1257 | { | |||
1258 | struct dc *dc = pipe_ctx->stream->ctx->dc; | |||
1259 | ||||
1260 | if (!is_h_timing_divisible_by_2(pipe_ctx->stream)) | |||
1261 | return false0; | |||
1262 | ||||
1263 | if (dc_is_dp_signal(pipe_ctx->stream->signal) && !is_dp_128b_132b_signal(pipe_ctx) && | |||
1264 | dc->debug.enable_dp_dig_pixel_rate_div_policy) | |||
1265 | return true1; | |||
1266 | return false0; | |||
1267 | } | |||
1268 | ||||
1269 | static void apply_symclk_on_tx_off_wa(struct dc_link *link) | |||
1270 | { | |||
1271 | /* There are use cases where SYMCLK is referenced by OTG. For instance | |||
1272 | * for TMDS signal, OTG relies SYMCLK even if TX video output is off. | |||
1273 | * However current link interface will power off PHY when disabling link | |||
1274 | * output. This will turn off SYMCLK generated by PHY. The workaround is | |||
1275 | * to identify such case where SYMCLK is still in use by OTG when we | |||
1276 | * power off PHY. When this is detected, we will temporarily power PHY | |||
1277 | * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling | |||
1278 | * program_pix_clk interface. When OTG is disabled, we will then power | |||
1279 | * off PHY by calling disable link output again. | |||
1280 | * | |||
1281 | * In future dcn generations, we plan to rework transmitter control | |||
1282 | * interface so that we could have an option to set SYMCLK ON TX OFF | |||
1283 | * state in one step without this workaround | |||
1284 | */ | |||
1285 | ||||
1286 | struct dc *dc = link->ctx->dc; | |||
1287 | struct pipe_ctx *pipe_ctx = NULL((void *)0); | |||
1288 | uint8_t i; | |||
1289 | ||||
1290 | if (link->phy_state.symclk_ref_cnts.otg > 0) { | |||
1291 | for (i = 0; i < MAX_PIPES6; i++) { | |||
1292 | pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; | |||
1293 | if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL((void *)0)) { | |||
1294 | pipe_ctx->clock_source->funcs->program_pix_clk( | |||
1295 | pipe_ctx->clock_source, | |||
1296 | &pipe_ctx->stream_res.pix_clk_params, | |||
1297 | dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings), | |||
1298 | &pipe_ctx->pll_settings); | |||
1299 | link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; | |||
1300 | break; | |||
1301 | } | |||
1302 | } | |||
1303 | } | |||
1304 | } | |||
1305 | ||||
1306 | void dcn32_disable_link_output(struct dc_link *link, | |||
1307 | const struct link_resource *link_res, | |||
1308 | enum amd_signal_type signal) | |||
1309 | { | |||
1310 | struct dc *dc = link->ctx->dc; | |||
1311 | const struct link_hwss *link_hwss = get_link_hwss(link, link_res); | |||
1312 | struct dmcu *dmcu = dc->res_pool->dmcu; | |||
1313 | ||||
1314 | if (signal == SIGNAL_TYPE_EDP && | |||
1315 | link->dc->hwss.edp_backlight_control) | |||
1316 | link->dc->hwss.edp_backlight_control(link, false0); | |||
1317 | else if (dmcu != NULL((void *)0) && dmcu->funcs->lock_phy) | |||
1318 | dmcu->funcs->lock_phy(dmcu); | |||
1319 | ||||
1320 | link_hwss->disable_link_output(link, link_res, signal); | |||
1321 | link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; | |||
1322 | ||||
1323 | if (signal == SIGNAL_TYPE_EDP && | |||
1324 | link->dc->hwss.edp_backlight_control) | |||
1325 | link->dc->hwss.edp_power_control(link, false0); | |||
1326 | else if (dmcu != NULL((void *)0) && dmcu->funcs->lock_phy) | |||
1327 | dmcu->funcs->unlock_phy(dmcu); | |||
1328 | ||||
1329 | dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); | |||
1330 | ||||
1331 | apply_symclk_on_tx_off_wa(link); | |||
1332 | } | |||
1333 | ||||
1334 | /* For SubVP the main pipe can have a viewport position change | |||
1335 | * without a full update. In this case we must also update the | |||
1336 | * viewport positions for the phantom pipe accordingly. | |||
1337 | */ | |||
1338 | void dcn32_update_phantom_vp_position(struct dc *dc, | |||
1339 | struct dc_state *context, | |||
1340 | struct pipe_ctx *phantom_pipe) | |||
1341 | { | |||
1342 | uint32_t i; | |||
1343 | struct dc_plane_state *phantom_plane = phantom_pipe->plane_state; | |||
1344 | ||||
1345 | for (i = 0; i < dc->res_pool->pipe_count; i++) { | |||
1346 | struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; | |||
1347 | ||||
1348 | if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN && | |||
1349 | pipe->stream->mall_stream_config.paired_stream == phantom_pipe->stream) { | |||
1350 | if (pipe->plane_state && pipe->plane_state->update_flags.bits.position_change) { | |||
1351 | ||||
1352 | phantom_plane->src_rect.x = pipe->plane_state->src_rect.x; | |||
1353 | phantom_plane->src_rect.y = pipe->plane_state->src_rect.y; | |||
1354 | phantom_plane->clip_rect.x = pipe->plane_state->clip_rect.x; | |||
1355 | phantom_plane->dst_rect.x = pipe->plane_state->dst_rect.x; | |||
1356 | phantom_plane->dst_rect.y = pipe->plane_state->dst_rect.y; | |||
1357 | ||||
1358 | phantom_pipe->plane_state->update_flags.bits.position_change = 1; | |||
1359 | resource_build_scaling_params(phantom_pipe); | |||
1360 | return; | |||
1361 | } | |||
1362 | } | |||
1363 | } | |||
1364 | } | |||
1365 | ||||
1366 | bool_Bool dcn32_dsc_pg_status( | |||
1367 | struct dce_hwseq *hws, | |||
1368 | unsigned int dsc_inst) | |||
1369 | { | |||
1370 | uint32_t pwr_status = 0; | |||
1371 | ||||
1372 | switch (dsc_inst) { | |||
1373 | case 0: /* DSC0 */ | |||
1374 | REG_GET(DOMAIN16_PG_STATUS,generic_reg_get(hws->ctx, hws->regs->DOMAIN16_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, &pwr_status) | |||
1375 | DOMAIN_PGFSM_PWR_STATUS, &pwr_status)generic_reg_get(hws->ctx, hws->regs->DOMAIN16_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, &pwr_status); | |||
1376 | break; | |||
1377 | case 1: /* DSC1 */ | |||
1378 | ||||
1379 | REG_GET(DOMAIN17_PG_STATUS,generic_reg_get(hws->ctx, hws->regs->DOMAIN17_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, &pwr_status) | |||
1380 | DOMAIN_PGFSM_PWR_STATUS, &pwr_status)generic_reg_get(hws->ctx, hws->regs->DOMAIN17_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, &pwr_status); | |||
1381 | break; | |||
1382 | case 2: /* DSC2 */ | |||
1383 | REG_GET(DOMAIN18_PG_STATUS,generic_reg_get(hws->ctx, hws->regs->DOMAIN18_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, &pwr_status) | |||
1384 | DOMAIN_PGFSM_PWR_STATUS, &pwr_status)generic_reg_get(hws->ctx, hws->regs->DOMAIN18_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, &pwr_status); | |||
1385 | break; | |||
1386 | case 3: /* DSC3 */ | |||
1387 | REG_GET(DOMAIN19_PG_STATUS,generic_reg_get(hws->ctx, hws->regs->DOMAIN19_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, &pwr_status) | |||
1388 | DOMAIN_PGFSM_PWR_STATUS, &pwr_status)generic_reg_get(hws->ctx, hws->regs->DOMAIN19_PG_STATUS , hws->shifts->DOMAIN_PGFSM_PWR_STATUS, hws->masks-> DOMAIN_PGFSM_PWR_STATUS, &pwr_status); | |||
1389 | break; | |||
1390 | default: | |||
1391 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 1391); do {} while (0); } while (0); | |||
1392 | break; | |||
1393 | } | |||
1394 | ||||
1395 | return pwr_status == 0; | |||
1396 | } | |||
1397 | ||||
1398 | void dcn32_update_dsc_pg(struct dc *dc, | |||
1399 | struct dc_state *context, | |||
1400 | bool_Bool safe_to_disable) | |||
1401 | { | |||
1402 | struct dce_hwseq *hws = dc->hwseq; | |||
1403 | int i; | |||
1404 | ||||
1405 | for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { | |||
1406 | struct display_stream_compressor *dsc = dc->res_pool->dscs[i]; | |||
1407 | bool_Bool is_dsc_ungated = hws->funcs.dsc_pg_status(hws, dsc->inst); | |||
1408 | ||||
1409 | if (context->res_ctx.is_dsc_acquired[i]) { | |||
1410 | if (!is_dsc_ungated) { | |||
1411 | hws->funcs.dsc_pg_control(hws, dsc->inst, true1); | |||
1412 | } | |||
1413 | } else if (safe_to_disable) { | |||
1414 | if (is_dsc_ungated) { | |||
1415 | hws->funcs.dsc_pg_control(hws, dsc->inst, false0); | |||
1416 | } | |||
1417 | } | |||
1418 | } | |||
1419 | } |