1 | /* |
2 | * Copyright 2012-15 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 | #include "dm_services.h" |
27 | |
28 | #include "link_encoder.h" |
29 | #include "stream_encoder.h" |
30 | |
31 | #include "resource.h" |
32 | #include "dce110/dce110_resource.h" |
33 | #include "include/irq_service_interface.h" |
34 | #include "dce/dce_audio.h" |
35 | #include "dce110/dce110_timing_generator.h" |
36 | #include "irq/dce110/irq_service_dce110.h" |
37 | #include "dce110/dce110_timing_generator_v.h" |
38 | #include "dce/dce_link_encoder.h" |
39 | #include "dce/dce_stream_encoder.h" |
40 | #include "dce/dce_mem_input.h" |
41 | #include "dce110/dce110_mem_input_v.h" |
42 | #include "dce/dce_ipp.h" |
43 | #include "dce/dce_transform.h" |
44 | #include "dce110/dce110_transform_v.h" |
45 | #include "dce/dce_opp.h" |
46 | #include "dce110/dce110_opp_v.h" |
47 | #include "dce/dce_clock_source.h" |
48 | #include "dce/dce_hwseq.h" |
49 | #include "dce110/dce110_hwseq.h" |
50 | #include "dce/dce_aux.h" |
51 | #include "dce/dce_abm.h" |
52 | #include "dce/dce_dmcu.h" |
53 | #include "dce/dce_i2c.h" |
54 | #include "dce/dce_panel_cntl.h" |
55 | |
56 | #define DC_LOGGER \ |
57 | dc->ctx->logger |
58 | |
59 | #include "dce110/dce110_compressor.h" |
60 | |
61 | #include "reg_helper.h" |
62 | |
63 | #include "dce/dce_11_0_d.h" |
64 | #include "dce/dce_11_0_sh_mask.h" |
65 | |
66 | #ifndef mmMC_HUB_RDREQ_DMIF_LIMIT |
67 | #include "gmc/gmc_8_2_d.h" |
68 | #include "gmc/gmc_8_2_sh_mask.h" |
69 | #endif |
70 | |
71 | #ifndef mmDP_DPHY_INTERNAL_CTRL |
72 | #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7 |
73 | #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7 |
74 | #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7 |
75 | #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7 |
76 | #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7 |
77 | #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7 |
78 | #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7 |
79 | #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7 |
80 | #define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7 |
81 | #define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7 |
82 | #endif |
83 | |
84 | #ifndef mmBIOS_SCRATCH_2 |
85 | #define mmBIOS_SCRATCH_2 0x05CB |
86 | #define mmBIOS_SCRATCH_3 0x05CC |
87 | #define mmBIOS_SCRATCH_6 0x05CF |
88 | #endif |
89 | |
90 | #ifndef mmDP_DPHY_BS_SR_SWAP_CNTL |
91 | #define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4ADC |
92 | #define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4ADC |
93 | #define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4BDC |
94 | #define mmDP2_DP_DPHY_BS_SR_SWAP_CNTL 0x4CDC |
95 | #define mmDP3_DP_DPHY_BS_SR_SWAP_CNTL 0x4DDC |
96 | #define mmDP4_DP_DPHY_BS_SR_SWAP_CNTL 0x4EDC |
97 | #define mmDP5_DP_DPHY_BS_SR_SWAP_CNTL 0x4FDC |
98 | #define mmDP6_DP_DPHY_BS_SR_SWAP_CNTL 0x54DC |
99 | #endif |
100 | |
101 | #ifndef mmDP_DPHY_FAST_TRAINING |
102 | #define mmDP_DPHY_FAST_TRAINING 0x4ABC |
103 | #define mmDP0_DP_DPHY_FAST_TRAINING 0x4ABC |
104 | #define mmDP1_DP_DPHY_FAST_TRAINING 0x4BBC |
105 | #define mmDP2_DP_DPHY_FAST_TRAINING 0x4CBC |
106 | #define mmDP3_DP_DPHY_FAST_TRAINING 0x4DBC |
107 | #define mmDP4_DP_DPHY_FAST_TRAINING 0x4EBC |
108 | #define mmDP5_DP_DPHY_FAST_TRAINING 0x4FBC |
109 | #define mmDP6_DP_DPHY_FAST_TRAINING 0x54BC |
110 | #endif |
111 | |
112 | #ifndef DPHY_RX_FAST_TRAINING_CAPABLE |
113 | #define DPHY_RX_FAST_TRAINING_CAPABLE 0x1 |
114 | #endif |
115 | |
116 | static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = { |
117 | { |
118 | .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), |
119 | .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL), |
120 | }, |
121 | { |
122 | .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), |
123 | .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), |
124 | }, |
125 | { |
126 | .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), |
127 | .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), |
128 | }, |
129 | { |
130 | .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), |
131 | .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), |
132 | }, |
133 | { |
134 | .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), |
135 | .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), |
136 | }, |
137 | { |
138 | .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), |
139 | .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), |
140 | } |
141 | }; |
142 | |
143 | /* set register offset */ |
144 | #define SR(reg_name)\ |
145 | .reg_name = mm ## reg_name |
146 | |
147 | /* set register offset with instance */ |
148 | #define SRI(reg_name, block, id)\ |
149 | .reg_name = mm ## block ## id ## _ ## reg_name |
150 | |
151 | static const struct dce_dmcu_registers dmcu_regs = { |
152 | DMCU_DCE110_COMMON_REG_LIST() |
153 | }; |
154 | |
155 | static const struct dce_dmcu_shift dmcu_shift = { |
156 | DMCU_MASK_SH_LIST_DCE110(__SHIFT) |
157 | }; |
158 | |
159 | static const struct dce_dmcu_mask dmcu_mask = { |
160 | DMCU_MASK_SH_LIST_DCE110(_MASK) |
161 | }; |
162 | |
163 | static const struct dce_abm_registers abm_regs = { |
164 | ABM_DCE110_COMMON_REG_LIST() |
165 | }; |
166 | |
167 | static const struct dce_abm_shift abm_shift = { |
168 | ABM_MASK_SH_LIST_DCE110(__SHIFT) |
169 | }; |
170 | |
171 | static const struct dce_abm_mask abm_mask = { |
172 | ABM_MASK_SH_LIST_DCE110(_MASK) |
173 | }; |
174 | |
175 | #define ipp_regs(id)\ |
176 | [id] = {\ |
177 | IPP_DCE110_REG_LIST_DCE_BASE(id)\ |
178 | } |
179 | |
180 | static const struct dce_ipp_registers ipp_regs[] = { |
181 | ipp_regs(0), |
182 | ipp_regs(1), |
183 | ipp_regs(2) |
184 | }; |
185 | |
186 | static const struct dce_ipp_shift ipp_shift = { |
187 | IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) |
188 | }; |
189 | |
190 | static const struct dce_ipp_mask ipp_mask = { |
191 | IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) |
192 | }; |
193 | |
194 | #define transform_regs(id)\ |
195 | [id] = {\ |
196 | XFM_COMMON_REG_LIST_DCE110(id)\ |
197 | } |
198 | |
199 | static const struct dce_transform_registers xfm_regs[] = { |
200 | transform_regs(0), |
201 | transform_regs(1), |
202 | transform_regs(2) |
203 | }; |
204 | |
205 | static const struct dce_transform_shift xfm_shift = { |
206 | XFM_COMMON_MASK_SH_LIST_DCE110(__SHIFT) |
207 | }; |
208 | |
209 | static const struct dce_transform_mask xfm_mask = { |
210 | XFM_COMMON_MASK_SH_LIST_DCE110(_MASK) |
211 | }; |
212 | |
213 | #define aux_regs(id)\ |
214 | [id] = {\ |
215 | AUX_REG_LIST(id)\ |
216 | } |
217 | |
218 | static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { |
219 | aux_regs(0), |
220 | aux_regs(1), |
221 | aux_regs(2), |
222 | aux_regs(3), |
223 | aux_regs(4), |
224 | aux_regs(5) |
225 | }; |
226 | |
227 | #define hpd_regs(id)\ |
228 | [id] = {\ |
229 | HPD_REG_LIST(id)\ |
230 | } |
231 | |
232 | static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { |
233 | hpd_regs(0), |
234 | hpd_regs(1), |
235 | hpd_regs(2), |
236 | hpd_regs(3), |
237 | hpd_regs(4), |
238 | hpd_regs(5) |
239 | }; |
240 | |
241 | |
242 | #define link_regs(id)\ |
243 | [id] = {\ |
244 | LE_DCE110_REG_LIST(id)\ |
245 | } |
246 | |
247 | static const struct dce110_link_enc_registers link_enc_regs[] = { |
248 | link_regs(0), |
249 | link_regs(1), |
250 | link_regs(2), |
251 | link_regs(3), |
252 | link_regs(4), |
253 | link_regs(5), |
254 | link_regs(6), |
255 | }; |
256 | |
257 | #define stream_enc_regs(id)\ |
258 | [id] = {\ |
259 | SE_COMMON_REG_LIST(id),\ |
260 | .TMDS_CNTL = 0,\ |
261 | } |
262 | |
263 | static const struct dce110_stream_enc_registers stream_enc_regs[] = { |
264 | stream_enc_regs(0), |
265 | stream_enc_regs(1), |
266 | stream_enc_regs(2) |
267 | }; |
268 | |
269 | static const struct dce_stream_encoder_shift se_shift = { |
270 | SE_COMMON_MASK_SH_LIST_DCE110(__SHIFT) |
271 | }; |
272 | |
273 | static const struct dce_stream_encoder_mask se_mask = { |
274 | SE_COMMON_MASK_SH_LIST_DCE110(_MASK) |
275 | }; |
276 | |
277 | static const struct dce_panel_cntl_registers panel_cntl_regs[] = { |
278 | { DCE_PANEL_CNTL_REG_LIST() } |
279 | }; |
280 | |
281 | static const struct dce_panel_cntl_shift panel_cntl_shift = { |
282 | DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) |
283 | }; |
284 | |
285 | static const struct dce_panel_cntl_mask panel_cntl_mask = { |
286 | DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) |
287 | }; |
288 | |
289 | static const struct dce110_aux_registers_shift aux_shift = { |
290 | DCE_AUX_MASK_SH_LIST(__SHIFT) |
291 | }; |
292 | |
293 | static const struct dce110_aux_registers_mask aux_mask = { |
294 | DCE_AUX_MASK_SH_LIST(_MASK) |
295 | }; |
296 | |
297 | #define opp_regs(id)\ |
298 | [id] = {\ |
299 | OPP_DCE_110_REG_LIST(id),\ |
300 | } |
301 | |
302 | static const struct dce_opp_registers opp_regs[] = { |
303 | opp_regs(0), |
304 | opp_regs(1), |
305 | opp_regs(2), |
306 | opp_regs(3), |
307 | opp_regs(4), |
308 | opp_regs(5) |
309 | }; |
310 | |
311 | static const struct dce_opp_shift opp_shift = { |
312 | OPP_COMMON_MASK_SH_LIST_DCE_110(__SHIFT) |
313 | }; |
314 | |
315 | static const struct dce_opp_mask opp_mask = { |
316 | OPP_COMMON_MASK_SH_LIST_DCE_110(_MASK) |
317 | }; |
318 | |
319 | #define aux_engine_regs(id)\ |
320 | [id] = {\ |
321 | AUX_COMMON_REG_LIST(id), \ |
322 | .AUX_RESET_MASK = 0 \ |
323 | } |
324 | |
325 | static const struct dce110_aux_registers aux_engine_regs[] = { |
326 | aux_engine_regs(0), |
327 | aux_engine_regs(1), |
328 | aux_engine_regs(2), |
329 | aux_engine_regs(3), |
330 | aux_engine_regs(4), |
331 | aux_engine_regs(5) |
332 | }; |
333 | |
334 | #define audio_regs(id)\ |
335 | [id] = {\ |
336 | AUD_COMMON_REG_LIST(id)\ |
337 | } |
338 | |
339 | static const struct dce_audio_registers audio_regs[] = { |
340 | audio_regs(0), |
341 | audio_regs(1), |
342 | audio_regs(2), |
343 | audio_regs(3), |
344 | audio_regs(4), |
345 | audio_regs(5), |
346 | audio_regs(6), |
347 | }; |
348 | |
349 | static const struct dce_audio_shift audio_shift = { |
350 | AUD_COMMON_MASK_SH_LIST(__SHIFT) |
351 | }; |
352 | |
353 | static const struct dce_audio_mask audio_mask = { |
354 | AUD_COMMON_MASK_SH_LIST(_MASK) |
355 | }; |
356 | |
357 | /* AG TBD Needs to be reduced back to 3 pipes once dce10 hw sequencer implemented. */ |
358 | |
359 | |
360 | #define clk_src_regs(id)\ |
361 | [id] = {\ |
362 | CS_COMMON_REG_LIST_DCE_100_110(id),\ |
363 | } |
364 | |
365 | static const struct dce110_clk_src_regs clk_src_regs[] = { |
366 | clk_src_regs(0), |
367 | clk_src_regs(1), |
368 | clk_src_regs(2) |
369 | }; |
370 | |
371 | static const struct dce110_clk_src_shift cs_shift = { |
372 | CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) |
373 | }; |
374 | |
375 | static const struct dce110_clk_src_mask cs_mask = { |
376 | CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) |
377 | }; |
378 | |
379 | static const struct bios_registers bios_regs = { |
380 | .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, |
381 | .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 |
382 | }; |
383 | |
384 | static const struct resource_caps carrizo_resource_cap = { |
385 | .num_timing_generator = 3, |
386 | .num_video_plane = 1, |
387 | .num_audio = 3, |
388 | .num_stream_encoder = 3, |
389 | .num_pll = 2, |
390 | .num_ddc = 3, |
391 | }; |
392 | |
393 | static const struct resource_caps stoney_resource_cap = { |
394 | .num_timing_generator = 2, |
395 | .num_video_plane = 1, |
396 | .num_audio = 3, |
397 | .num_stream_encoder = 3, |
398 | .num_pll = 2, |
399 | .num_ddc = 3, |
400 | }; |
401 | |
402 | static const struct dc_plane_cap plane_cap = { |
403 | .type = DC_PLANE_TYPE_DCE_RGB, |
404 | .per_pixel_alpha = 1, |
405 | |
406 | .pixel_format_support = { |
407 | .argb8888 = true, |
408 | .nv12 = false, |
409 | .fp16 = true |
410 | }, |
411 | |
412 | .max_upscale_factor = { |
413 | .argb8888 = 16000, |
414 | .nv12 = 1, |
415 | .fp16 = 1 |
416 | }, |
417 | |
418 | .max_downscale_factor = { |
419 | .argb8888 = 250, |
420 | .nv12 = 1, |
421 | .fp16 = 1 |
422 | }, |
423 | 64, |
424 | 64 |
425 | }; |
426 | |
427 | static const struct dc_debug_options debug_defaults = { |
428 | .enable_legacy_fast_update = true, |
429 | }; |
430 | |
431 | static const struct dc_plane_cap underlay_plane_cap = { |
432 | .type = DC_PLANE_TYPE_DCE_UNDERLAY, |
433 | .per_pixel_alpha = 1, |
434 | |
435 | .pixel_format_support = { |
436 | .argb8888 = false, |
437 | .nv12 = true, |
438 | .fp16 = false |
439 | }, |
440 | |
441 | .max_upscale_factor = { |
442 | .argb8888 = 1, |
443 | .nv12 = 16000, |
444 | .fp16 = 1 |
445 | }, |
446 | |
447 | .max_downscale_factor = { |
448 | .argb8888 = 1, |
449 | .nv12 = 250, |
450 | .fp16 = 1 |
451 | }, |
452 | 64, |
453 | 64 |
454 | }; |
455 | |
456 | #define CTX ctx |
457 | #define REG(reg) mm ## reg |
458 | |
459 | #ifndef mmCC_DC_HDMI_STRAPS |
460 | #define mmCC_DC_HDMI_STRAPS 0x4819 |
461 | #define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 |
462 | #define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 |
463 | #define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 |
464 | #define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 |
465 | #endif |
466 | |
467 | static int map_transmitter_id_to_phy_instance( |
468 | enum transmitter transmitter) |
469 | { |
470 | switch (transmitter) { |
471 | case TRANSMITTER_UNIPHY_A: |
472 | return 0; |
473 | case TRANSMITTER_UNIPHY_B: |
474 | return 1; |
475 | case TRANSMITTER_UNIPHY_C: |
476 | return 2; |
477 | case TRANSMITTER_UNIPHY_D: |
478 | return 3; |
479 | case TRANSMITTER_UNIPHY_E: |
480 | return 4; |
481 | case TRANSMITTER_UNIPHY_F: |
482 | return 5; |
483 | case TRANSMITTER_UNIPHY_G: |
484 | return 6; |
485 | default: |
486 | ASSERT(0); |
487 | return 0; |
488 | } |
489 | } |
490 | |
491 | static void read_dce_straps( |
492 | struct dc_context *ctx, |
493 | struct resource_straps *straps) |
494 | { |
495 | REG_GET_2(CC_DC_HDMI_STRAPS, |
496 | HDMI_DISABLE, &straps->hdmi_disable, |
497 | AUDIO_STREAM_NUMBER, &straps->audio_stream_number); |
498 | |
499 | REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); |
500 | } |
501 | |
502 | static struct audio *create_audio( |
503 | struct dc_context *ctx, unsigned int inst) |
504 | { |
505 | return dce_audio_create(ctx, inst, |
506 | reg: &audio_regs[inst], shifts: &audio_shift, masks: &audio_mask); |
507 | } |
508 | |
509 | static struct timing_generator *dce110_timing_generator_create( |
510 | struct dc_context *ctx, |
511 | uint32_t instance, |
512 | const struct dce110_timing_generator_offsets *offsets) |
513 | { |
514 | struct dce110_timing_generator *tg110 = |
515 | kzalloc(size: sizeof(struct dce110_timing_generator), GFP_KERNEL); |
516 | |
517 | if (!tg110) |
518 | return NULL; |
519 | |
520 | dce110_timing_generator_construct(tg: tg110, ctx, instance, offsets); |
521 | return &tg110->base; |
522 | } |
523 | |
524 | static struct stream_encoder *dce110_stream_encoder_create( |
525 | enum engine_id eng_id, |
526 | struct dc_context *ctx) |
527 | { |
528 | struct dce110_stream_encoder *enc110 = |
529 | kzalloc(size: sizeof(struct dce110_stream_encoder), GFP_KERNEL); |
530 | |
531 | if (!enc110) |
532 | return NULL; |
533 | |
534 | dce110_stream_encoder_construct(enc110, ctx, bp: ctx->dc_bios, eng_id, |
535 | regs: &stream_enc_regs[eng_id], |
536 | se_shift: &se_shift, se_mask: &se_mask); |
537 | return &enc110->base; |
538 | } |
539 | |
540 | #define SRII(reg_name, block, id)\ |
541 | .reg_name[id] = mm ## block ## id ## _ ## reg_name |
542 | |
543 | static const struct dce_hwseq_registers hwseq_stoney_reg = { |
544 | HWSEQ_ST_REG_LIST() |
545 | }; |
546 | |
547 | static const struct dce_hwseq_registers hwseq_cz_reg = { |
548 | HWSEQ_CZ_REG_LIST() |
549 | }; |
550 | |
551 | static const struct dce_hwseq_shift hwseq_shift = { |
552 | HWSEQ_DCE11_MASK_SH_LIST(__SHIFT), |
553 | }; |
554 | |
555 | static const struct dce_hwseq_mask hwseq_mask = { |
556 | HWSEQ_DCE11_MASK_SH_LIST(_MASK), |
557 | }; |
558 | |
559 | static struct dce_hwseq *dce110_hwseq_create( |
560 | struct dc_context *ctx) |
561 | { |
562 | struct dce_hwseq *hws = kzalloc(size: sizeof(struct dce_hwseq), GFP_KERNEL); |
563 | |
564 | if (hws) { |
565 | hws->ctx = ctx; |
566 | hws->regs = ASIC_REV_IS_STONEY(ctx->asic_id.hw_internal_rev) ? |
567 | &hwseq_stoney_reg : &hwseq_cz_reg; |
568 | hws->shifts = &hwseq_shift; |
569 | hws->masks = &hwseq_mask; |
570 | hws->wa.blnd_crtc_trigger = true; |
571 | } |
572 | return hws; |
573 | } |
574 | |
575 | static const struct resource_create_funcs res_create_funcs = { |
576 | .read_dce_straps = read_dce_straps, |
577 | .create_audio = create_audio, |
578 | .create_stream_encoder = dce110_stream_encoder_create, |
579 | .create_hwseq = dce110_hwseq_create, |
580 | }; |
581 | |
582 | #define mi_inst_regs(id) { \ |
583 | MI_DCE11_REG_LIST(id), \ |
584 | .MC_HUB_RDREQ_DMIF_LIMIT = mmMC_HUB_RDREQ_DMIF_LIMIT \ |
585 | } |
586 | static const struct dce_mem_input_registers mi_regs[] = { |
587 | mi_inst_regs(0), |
588 | mi_inst_regs(1), |
589 | mi_inst_regs(2), |
590 | }; |
591 | |
592 | static const struct dce_mem_input_shift mi_shifts = { |
593 | MI_DCE11_MASK_SH_LIST(__SHIFT), |
594 | .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE__SHIFT |
595 | }; |
596 | |
597 | static const struct dce_mem_input_mask mi_masks = { |
598 | MI_DCE11_MASK_SH_LIST(_MASK), |
599 | .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE_MASK |
600 | }; |
601 | |
602 | |
603 | static struct mem_input *dce110_mem_input_create( |
604 | struct dc_context *ctx, |
605 | uint32_t inst) |
606 | { |
607 | struct dce_mem_input *dce_mi = kzalloc(size: sizeof(struct dce_mem_input), |
608 | GFP_KERNEL); |
609 | |
610 | if (!dce_mi) { |
611 | BREAK_TO_DEBUGGER(); |
612 | return NULL; |
613 | } |
614 | |
615 | dce_mem_input_construct(dce_mi, ctx, inst, regs: &mi_regs[inst], mi_shift: &mi_shifts, mi_mask: &mi_masks); |
616 | dce_mi->wa.single_head_rdreq_dmif_limit = 3; |
617 | return &dce_mi->base; |
618 | } |
619 | |
620 | static void dce110_transform_destroy(struct transform **xfm) |
621 | { |
622 | kfree(TO_DCE_TRANSFORM(*xfm)); |
623 | *xfm = NULL; |
624 | } |
625 | |
626 | static struct transform *dce110_transform_create( |
627 | struct dc_context *ctx, |
628 | uint32_t inst) |
629 | { |
630 | struct dce_transform *transform = |
631 | kzalloc(size: sizeof(struct dce_transform), GFP_KERNEL); |
632 | |
633 | if (!transform) |
634 | return NULL; |
635 | |
636 | dce_transform_construct(xfm_dce: transform, ctx, inst, |
637 | regs: &xfm_regs[inst], xfm_shift: &xfm_shift, xfm_mask: &xfm_mask); |
638 | return &transform->base; |
639 | } |
640 | |
641 | static struct input_pixel_processor *dce110_ipp_create( |
642 | struct dc_context *ctx, uint32_t inst) |
643 | { |
644 | struct dce_ipp *ipp = kzalloc(size: sizeof(struct dce_ipp), GFP_KERNEL); |
645 | |
646 | if (!ipp) { |
647 | BREAK_TO_DEBUGGER(); |
648 | return NULL; |
649 | } |
650 | |
651 | dce_ipp_construct(ipp_dce: ipp, ctx, inst, |
652 | regs: &ipp_regs[inst], ipp_shift: &ipp_shift, ipp_mask: &ipp_mask); |
653 | return &ipp->base; |
654 | } |
655 | |
656 | static const struct encoder_feature_support link_enc_feature = { |
657 | .max_hdmi_deep_color = COLOR_DEPTH_121212, |
658 | .max_hdmi_pixel_clock = 300000, |
659 | .flags.bits.IS_HBR2_CAPABLE = true, |
660 | .flags.bits.IS_TPS3_CAPABLE = true |
661 | }; |
662 | |
663 | static struct link_encoder *dce110_link_encoder_create( |
664 | struct dc_context *ctx, |
665 | const struct encoder_init_data *enc_init_data) |
666 | { |
667 | struct dce110_link_encoder *enc110 = |
668 | kzalloc(size: sizeof(struct dce110_link_encoder), GFP_KERNEL); |
669 | int link_regs_id; |
670 | |
671 | if (!enc110) |
672 | return NULL; |
673 | |
674 | link_regs_id = |
675 | map_transmitter_id_to_phy_instance(transmitter: enc_init_data->transmitter); |
676 | |
677 | dce110_link_encoder_construct(enc110, |
678 | init_data: enc_init_data, |
679 | enc_features: &link_enc_feature, |
680 | link_regs: &link_enc_regs[link_regs_id], |
681 | aux_regs: &link_enc_aux_regs[enc_init_data->channel - 1], |
682 | hpd_regs: &link_enc_hpd_regs[enc_init_data->hpd_source]); |
683 | return &enc110->base; |
684 | } |
685 | |
686 | static struct panel_cntl *dce110_panel_cntl_create(const struct panel_cntl_init_data *init_data) |
687 | { |
688 | struct dce_panel_cntl *panel_cntl = |
689 | kzalloc(size: sizeof(struct dce_panel_cntl), GFP_KERNEL); |
690 | |
691 | if (!panel_cntl) |
692 | return NULL; |
693 | |
694 | dce_panel_cntl_construct(panel_cntl, |
695 | init_data, |
696 | regs: &panel_cntl_regs[init_data->inst], |
697 | shift: &panel_cntl_shift, |
698 | mask: &panel_cntl_mask); |
699 | |
700 | return &panel_cntl->base; |
701 | } |
702 | |
703 | static struct output_pixel_processor *dce110_opp_create( |
704 | struct dc_context *ctx, |
705 | uint32_t inst) |
706 | { |
707 | struct dce110_opp *opp = |
708 | kzalloc(size: sizeof(struct dce110_opp), GFP_KERNEL); |
709 | |
710 | if (!opp) |
711 | return NULL; |
712 | |
713 | dce110_opp_construct(opp110: opp, |
714 | ctx, inst, regs: &opp_regs[inst], opp_shift: &opp_shift, opp_mask: &opp_mask); |
715 | return &opp->base; |
716 | } |
717 | |
718 | static struct dce_aux *dce110_aux_engine_create( |
719 | struct dc_context *ctx, |
720 | uint32_t inst) |
721 | { |
722 | struct aux_engine_dce110 *aux_engine = |
723 | kzalloc(size: sizeof(struct aux_engine_dce110), GFP_KERNEL); |
724 | |
725 | if (!aux_engine) |
726 | return NULL; |
727 | |
728 | dce110_aux_engine_construct(aux_engine110: aux_engine, ctx, inst, |
729 | timeout_period: SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, |
730 | regs: &aux_engine_regs[inst], |
731 | mask: &aux_mask, |
732 | shift: &aux_shift, |
733 | is_ext_aux_timeout_configurable: ctx->dc->caps.extended_aux_timeout_support); |
734 | |
735 | return &aux_engine->base; |
736 | } |
737 | #define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } |
738 | |
739 | static const struct dce_i2c_registers i2c_hw_regs[] = { |
740 | i2c_inst_regs(1), |
741 | i2c_inst_regs(2), |
742 | i2c_inst_regs(3), |
743 | i2c_inst_regs(4), |
744 | i2c_inst_regs(5), |
745 | i2c_inst_regs(6), |
746 | }; |
747 | |
748 | static const struct dce_i2c_shift i2c_shifts = { |
749 | I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) |
750 | }; |
751 | |
752 | static const struct dce_i2c_mask i2c_masks = { |
753 | I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) |
754 | }; |
755 | |
756 | static struct dce_i2c_hw *dce110_i2c_hw_create( |
757 | struct dc_context *ctx, |
758 | uint32_t inst) |
759 | { |
760 | struct dce_i2c_hw *dce_i2c_hw = |
761 | kzalloc(size: sizeof(struct dce_i2c_hw), GFP_KERNEL); |
762 | |
763 | if (!dce_i2c_hw) |
764 | return NULL; |
765 | |
766 | dce100_i2c_hw_construct(dce_i2c_hw, ctx, engine_id: inst, |
767 | regs: &i2c_hw_regs[inst], shifts: &i2c_shifts, masks: &i2c_masks); |
768 | |
769 | return dce_i2c_hw; |
770 | } |
771 | static struct clock_source *dce110_clock_source_create( |
772 | struct dc_context *ctx, |
773 | struct dc_bios *bios, |
774 | enum clock_source_id id, |
775 | const struct dce110_clk_src_regs *regs, |
776 | bool dp_clk_src) |
777 | { |
778 | struct dce110_clk_src *clk_src = |
779 | kzalloc(size: sizeof(struct dce110_clk_src), GFP_KERNEL); |
780 | |
781 | if (!clk_src) |
782 | return NULL; |
783 | |
784 | if (dce110_clk_src_construct(clk_src, ctx, bios, id, |
785 | regs, cs_shift: &cs_shift, cs_mask: &cs_mask)) { |
786 | clk_src->base.dp_clk_src = dp_clk_src; |
787 | return &clk_src->base; |
788 | } |
789 | |
790 | kfree(objp: clk_src); |
791 | BREAK_TO_DEBUGGER(); |
792 | return NULL; |
793 | } |
794 | |
795 | static void dce110_clock_source_destroy(struct clock_source **clk_src) |
796 | { |
797 | struct dce110_clk_src *dce110_clk_src; |
798 | |
799 | if (!clk_src) |
800 | return; |
801 | |
802 | dce110_clk_src = TO_DCE110_CLK_SRC(*clk_src); |
803 | |
804 | kfree(objp: dce110_clk_src->dp_ss_params); |
805 | kfree(objp: dce110_clk_src->hdmi_ss_params); |
806 | kfree(objp: dce110_clk_src->dvi_ss_params); |
807 | |
808 | kfree(objp: dce110_clk_src); |
809 | *clk_src = NULL; |
810 | } |
811 | |
812 | static void dce110_resource_destruct(struct dce110_resource_pool *pool) |
813 | { |
814 | unsigned int i; |
815 | |
816 | for (i = 0; i < pool->base.pipe_count; i++) { |
817 | if (pool->base.opps[i] != NULL) |
818 | dce110_opp_destroy(opp: &pool->base.opps[i]); |
819 | |
820 | if (pool->base.transforms[i] != NULL) |
821 | dce110_transform_destroy(xfm: &pool->base.transforms[i]); |
822 | |
823 | if (pool->base.ipps[i] != NULL) |
824 | dce_ipp_destroy(ipp: &pool->base.ipps[i]); |
825 | |
826 | if (pool->base.mis[i] != NULL) { |
827 | kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); |
828 | pool->base.mis[i] = NULL; |
829 | } |
830 | |
831 | if (pool->base.timing_generators[i] != NULL) { |
832 | kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); |
833 | pool->base.timing_generators[i] = NULL; |
834 | } |
835 | } |
836 | |
837 | for (i = 0; i < pool->base.res_cap->num_ddc; i++) { |
838 | if (pool->base.engines[i] != NULL) |
839 | dce110_engine_destroy(engine: &pool->base.engines[i]); |
840 | if (pool->base.hw_i2cs[i] != NULL) { |
841 | kfree(objp: pool->base.hw_i2cs[i]); |
842 | pool->base.hw_i2cs[i] = NULL; |
843 | } |
844 | if (pool->base.sw_i2cs[i] != NULL) { |
845 | kfree(objp: pool->base.sw_i2cs[i]); |
846 | pool->base.sw_i2cs[i] = NULL; |
847 | } |
848 | } |
849 | |
850 | for (i = 0; i < pool->base.stream_enc_count; i++) { |
851 | if (pool->base.stream_enc[i] != NULL) |
852 | kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); |
853 | } |
854 | |
855 | for (i = 0; i < pool->base.clk_src_count; i++) { |
856 | if (pool->base.clock_sources[i] != NULL) { |
857 | dce110_clock_source_destroy(clk_src: &pool->base.clock_sources[i]); |
858 | } |
859 | } |
860 | |
861 | if (pool->base.dp_clock_source != NULL) |
862 | dce110_clock_source_destroy(clk_src: &pool->base.dp_clock_source); |
863 | |
864 | for (i = 0; i < pool->base.audio_count; i++) { |
865 | if (pool->base.audios[i] != NULL) { |
866 | dce_aud_destroy(audio: &pool->base.audios[i]); |
867 | } |
868 | } |
869 | |
870 | if (pool->base.abm != NULL) |
871 | dce_abm_destroy(abm: &pool->base.abm); |
872 | |
873 | if (pool->base.dmcu != NULL) |
874 | dce_dmcu_destroy(dmcu: &pool->base.dmcu); |
875 | |
876 | if (pool->base.irqs != NULL) { |
877 | dal_irq_service_destroy(irq_service: &pool->base.irqs); |
878 | } |
879 | } |
880 | |
881 | |
882 | static void get_pixel_clock_parameters( |
883 | const struct pipe_ctx *pipe_ctx, |
884 | struct pixel_clk_params *pixel_clk_params) |
885 | { |
886 | const struct dc_stream_state *stream = pipe_ctx->stream; |
887 | |
888 | /*TODO: is this halved for YCbCr 420? in that case we might want to move |
889 | * the pixel clock normalization for hdmi up to here instead of doing it |
890 | * in pll_adjust_pix_clk |
891 | */ |
892 | pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; |
893 | pixel_clk_params->encoder_object_id = stream->link->link_enc->id; |
894 | pixel_clk_params->signal_type = pipe_ctx->stream->signal; |
895 | pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; |
896 | /* TODO: un-hardcode*/ |
897 | pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * |
898 | LINK_RATE_REF_FREQ_IN_KHZ; |
899 | pixel_clk_params->flags.ENABLE_SS = 0; |
900 | pixel_clk_params->color_depth = |
901 | stream->timing.display_color_depth; |
902 | pixel_clk_params->flags.DISPLAY_BLANKED = 1; |
903 | pixel_clk_params->flags.SUPPORT_YCBCR420 = (stream->timing.pixel_encoding == |
904 | PIXEL_ENCODING_YCBCR420); |
905 | pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding; |
906 | if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) { |
907 | pixel_clk_params->color_depth = COLOR_DEPTH_888; |
908 | } |
909 | if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) { |
910 | pixel_clk_params->requested_pix_clk_100hz = pixel_clk_params->requested_pix_clk_100hz / 2; |
911 | } |
912 | if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) |
913 | pixel_clk_params->requested_pix_clk_100hz *= 2; |
914 | |
915 | } |
916 | |
917 | void dce110_resource_build_pipe_hw_param(struct pipe_ctx *pipe_ctx) |
918 | { |
919 | get_pixel_clock_parameters(pipe_ctx, pixel_clk_params: &pipe_ctx->stream_res.pix_clk_params); |
920 | pipe_ctx->clock_source->funcs->get_pix_clk_dividers( |
921 | pipe_ctx->clock_source, |
922 | &pipe_ctx->stream_res.pix_clk_params, |
923 | &pipe_ctx->pll_settings); |
924 | resource_build_bit_depth_reduction_params(stream: pipe_ctx->stream, |
925 | fmt_bit_depth: &pipe_ctx->stream->bit_depth_params); |
926 | pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; |
927 | } |
928 | |
929 | static bool is_surface_pixel_format_supported(struct pipe_ctx *pipe_ctx, unsigned int underlay_idx) |
930 | { |
931 | if (pipe_ctx->pipe_idx != underlay_idx) |
932 | return true; |
933 | if (!pipe_ctx->plane_state) |
934 | return false; |
935 | if (pipe_ctx->plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) |
936 | return false; |
937 | return true; |
938 | } |
939 | |
940 | static enum dc_status build_mapped_resource( |
941 | const struct dc *dc, |
942 | struct dc_state *context, |
943 | struct dc_stream_state *stream) |
944 | { |
945 | struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(res_ctx: &context->res_ctx, stream); |
946 | |
947 | if (!pipe_ctx) |
948 | return DC_ERROR_UNEXPECTED; |
949 | |
950 | if (!is_surface_pixel_format_supported(pipe_ctx, |
951 | underlay_idx: dc->res_pool->underlay_pipe_index)) |
952 | return DC_SURFACE_PIXEL_FORMAT_UNSUPPORTED; |
953 | |
954 | dce110_resource_build_pipe_hw_param(pipe_ctx); |
955 | |
956 | /* TODO: validate audio ASIC caps, encoder */ |
957 | |
958 | resource_build_info_frame(pipe_ctx); |
959 | |
960 | return DC_OK; |
961 | } |
962 | |
963 | static bool dce110_validate_bandwidth( |
964 | struct dc *dc, |
965 | struct dc_state *context, |
966 | bool fast_validate) |
967 | { |
968 | bool result = false; |
969 | |
970 | DC_LOG_BANDWIDTH_CALCS( |
971 | "%s: start" , |
972 | __func__); |
973 | |
974 | if (bw_calcs( |
975 | ctx: dc->ctx, |
976 | dceip: dc->bw_dceip, |
977 | vbios: dc->bw_vbios, |
978 | pipe: context->res_ctx.pipe_ctx, |
979 | pipe_count: dc->res_pool->pipe_count, |
980 | calcs_output: &context->bw_ctx.bw.dce)) |
981 | result = true; |
982 | |
983 | if (!result) |
984 | DC_LOG_BANDWIDTH_VALIDATION("%s: %dx%d@%d Bandwidth validation failed!\n" , |
985 | __func__, |
986 | context->streams[0]->timing.h_addressable, |
987 | context->streams[0]->timing.v_addressable, |
988 | context->streams[0]->timing.pix_clk_100hz / 10); |
989 | |
990 | if (memcmp(p: &dc->current_state->bw_ctx.bw.dce, |
991 | q: &context->bw_ctx.bw.dce, size: sizeof(context->bw_ctx.bw.dce))) { |
992 | |
993 | DC_LOG_BANDWIDTH_CALCS( |
994 | "%s: finish,\n" |
995 | "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" |
996 | "stutMark_b: %d stutMark_a: %d\n" |
997 | "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" |
998 | "stutMark_b: %d stutMark_a: %d\n" |
999 | "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" |
1000 | "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n" |
1001 | "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" |
1002 | "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n" |
1003 | , |
1004 | __func__, |
1005 | context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].b_mark, |
1006 | context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].a_mark, |
1007 | context->bw_ctx.bw.dce.urgent_wm_ns[0].b_mark, |
1008 | context->bw_ctx.bw.dce.urgent_wm_ns[0].a_mark, |
1009 | context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].b_mark, |
1010 | context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].a_mark, |
1011 | context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].b_mark, |
1012 | context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].a_mark, |
1013 | context->bw_ctx.bw.dce.urgent_wm_ns[1].b_mark, |
1014 | context->bw_ctx.bw.dce.urgent_wm_ns[1].a_mark, |
1015 | context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].b_mark, |
1016 | context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].a_mark, |
1017 | context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].b_mark, |
1018 | context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].a_mark, |
1019 | context->bw_ctx.bw.dce.urgent_wm_ns[2].b_mark, |
1020 | context->bw_ctx.bw.dce.urgent_wm_ns[2].a_mark, |
1021 | context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].b_mark, |
1022 | context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].a_mark, |
1023 | context->bw_ctx.bw.dce.stutter_mode_enable, |
1024 | context->bw_ctx.bw.dce.cpuc_state_change_enable, |
1025 | context->bw_ctx.bw.dce.cpup_state_change_enable, |
1026 | context->bw_ctx.bw.dce.nbp_state_change_enable, |
1027 | context->bw_ctx.bw.dce.all_displays_in_sync, |
1028 | context->bw_ctx.bw.dce.dispclk_khz, |
1029 | context->bw_ctx.bw.dce.sclk_khz, |
1030 | context->bw_ctx.bw.dce.sclk_deep_sleep_khz, |
1031 | context->bw_ctx.bw.dce.yclk_khz, |
1032 | context->bw_ctx.bw.dce.blackout_recovery_time_us); |
1033 | } |
1034 | return result; |
1035 | } |
1036 | |
1037 | static enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state, |
1038 | struct dc_caps *caps) |
1039 | { |
1040 | if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) || |
1041 | ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height)) |
1042 | return DC_FAIL_SURFACE_VALIDATE; |
1043 | |
1044 | return DC_OK; |
1045 | } |
1046 | |
1047 | static bool dce110_validate_surface_sets( |
1048 | struct dc_state *context) |
1049 | { |
1050 | int i, j; |
1051 | |
1052 | for (i = 0; i < context->stream_count; i++) { |
1053 | if (context->stream_status[i].plane_count == 0) |
1054 | continue; |
1055 | |
1056 | if (context->stream_status[i].plane_count > 2) |
1057 | return false; |
1058 | |
1059 | for (j = 0; j < context->stream_status[i].plane_count; j++) { |
1060 | struct dc_plane_state *plane = |
1061 | context->stream_status[i].plane_states[j]; |
1062 | |
1063 | /* underlay validation */ |
1064 | if (plane->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { |
1065 | |
1066 | if ((plane->src_rect.width > 1920 || |
1067 | plane->src_rect.height > 1080)) |
1068 | return false; |
1069 | |
1070 | /* we don't have the logic to support underlay |
1071 | * only yet so block the use case where we get |
1072 | * NV12 plane as top layer |
1073 | */ |
1074 | if (j == 0) |
1075 | return false; |
1076 | |
1077 | /* irrespective of plane format, |
1078 | * stream should be RGB encoded |
1079 | */ |
1080 | if (context->streams[i]->timing.pixel_encoding |
1081 | != PIXEL_ENCODING_RGB) |
1082 | return false; |
1083 | |
1084 | } |
1085 | |
1086 | } |
1087 | } |
1088 | |
1089 | return true; |
1090 | } |
1091 | |
1092 | static enum dc_status dce110_validate_global( |
1093 | struct dc *dc, |
1094 | struct dc_state *context) |
1095 | { |
1096 | if (!dce110_validate_surface_sets(context)) |
1097 | return DC_FAIL_SURFACE_VALIDATE; |
1098 | |
1099 | return DC_OK; |
1100 | } |
1101 | |
1102 | static enum dc_status dce110_add_stream_to_ctx( |
1103 | struct dc *dc, |
1104 | struct dc_state *new_ctx, |
1105 | struct dc_stream_state *dc_stream) |
1106 | { |
1107 | enum dc_status result = DC_ERROR_UNEXPECTED; |
1108 | |
1109 | result = resource_map_pool_resources(dc, context: new_ctx, stream: dc_stream); |
1110 | |
1111 | if (result == DC_OK) |
1112 | result = resource_map_clock_resources(dc, context: new_ctx, stream: dc_stream); |
1113 | |
1114 | |
1115 | if (result == DC_OK) |
1116 | result = build_mapped_resource(dc, context: new_ctx, stream: dc_stream); |
1117 | |
1118 | return result; |
1119 | } |
1120 | |
1121 | static struct pipe_ctx *dce110_acquire_underlay( |
1122 | const struct dc_state *cur_ctx, |
1123 | struct dc_state *new_ctx, |
1124 | const struct resource_pool *pool, |
1125 | const struct pipe_ctx *opp_head_pipe) |
1126 | { |
1127 | struct dc_stream_state *stream = opp_head_pipe->stream; |
1128 | struct dc *dc = stream->ctx->dc; |
1129 | struct dce_hwseq *hws = dc->hwseq; |
1130 | struct resource_context *res_ctx = &new_ctx->res_ctx; |
1131 | unsigned int underlay_idx = pool->underlay_pipe_index; |
1132 | struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[underlay_idx]; |
1133 | |
1134 | if (res_ctx->pipe_ctx[underlay_idx].stream) |
1135 | return NULL; |
1136 | |
1137 | pipe_ctx->stream_res.tg = pool->timing_generators[underlay_idx]; |
1138 | pipe_ctx->plane_res.mi = pool->mis[underlay_idx]; |
1139 | /*pipe_ctx->plane_res.ipp = res_ctx->pool->ipps[underlay_idx];*/ |
1140 | pipe_ctx->plane_res.xfm = pool->transforms[underlay_idx]; |
1141 | pipe_ctx->stream_res.opp = pool->opps[underlay_idx]; |
1142 | pipe_ctx->pipe_idx = underlay_idx; |
1143 | |
1144 | pipe_ctx->stream = stream; |
1145 | |
1146 | if (!dc->current_state->res_ctx.pipe_ctx[underlay_idx].stream) { |
1147 | struct tg_color black_color = {0}; |
1148 | struct dc_bios *dcb = dc->ctx->dc_bios; |
1149 | |
1150 | hws->funcs.enable_display_power_gating( |
1151 | dc, |
1152 | pipe_ctx->stream_res.tg->inst, |
1153 | dcb, PIPE_GATING_CONTROL_DISABLE); |
1154 | |
1155 | /* |
1156 | * This is for powering on underlay, so crtc does not |
1157 | * need to be enabled |
1158 | */ |
1159 | |
1160 | pipe_ctx->stream_res.tg->funcs->program_timing(pipe_ctx->stream_res.tg, |
1161 | &stream->timing, |
1162 | 0, |
1163 | 0, |
1164 | 0, |
1165 | 0, |
1166 | pipe_ctx->stream->signal, |
1167 | false); |
1168 | |
1169 | pipe_ctx->stream_res.tg->funcs->enable_advanced_request( |
1170 | pipe_ctx->stream_res.tg, |
1171 | true, |
1172 | &stream->timing); |
1173 | |
1174 | pipe_ctx->plane_res.mi->funcs->allocate_mem_input(pipe_ctx->plane_res.mi, |
1175 | stream->timing.h_total, |
1176 | stream->timing.v_total, |
1177 | stream->timing.pix_clk_100hz / 10, |
1178 | new_ctx->stream_count); |
1179 | |
1180 | color_space_to_black_color(dc, |
1181 | colorspace: COLOR_SPACE_YCBCR601, black_color: &black_color); |
1182 | pipe_ctx->stream_res.tg->funcs->set_blank_color( |
1183 | pipe_ctx->stream_res.tg, |
1184 | &black_color); |
1185 | } |
1186 | |
1187 | return pipe_ctx; |
1188 | } |
1189 | |
1190 | static void dce110_destroy_resource_pool(struct resource_pool **pool) |
1191 | { |
1192 | struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); |
1193 | |
1194 | dce110_resource_destruct(pool: dce110_pool); |
1195 | kfree(objp: dce110_pool); |
1196 | *pool = NULL; |
1197 | } |
1198 | |
1199 | struct stream_encoder *dce110_find_first_free_match_stream_enc_for_link( |
1200 | struct resource_context *res_ctx, |
1201 | const struct resource_pool *pool, |
1202 | struct dc_stream_state *stream) |
1203 | { |
1204 | int i; |
1205 | int j = -1; |
1206 | struct dc_link *link = stream->link; |
1207 | |
1208 | for (i = 0; i < pool->stream_enc_count; i++) { |
1209 | if (!res_ctx->is_stream_enc_acquired[i] && |
1210 | pool->stream_enc[i]) { |
1211 | /* Store first available for MST second display |
1212 | * in daisy chain use case |
1213 | */ |
1214 | j = i; |
1215 | if (pool->stream_enc[i]->id == |
1216 | link->link_enc->preferred_engine) |
1217 | return pool->stream_enc[i]; |
1218 | } |
1219 | } |
1220 | |
1221 | /* |
1222 | * For CZ and later, we can allow DIG FE and BE to differ for all display types |
1223 | */ |
1224 | |
1225 | if (j >= 0) |
1226 | return pool->stream_enc[j]; |
1227 | |
1228 | return NULL; |
1229 | } |
1230 | |
1231 | |
1232 | static const struct resource_funcs dce110_res_pool_funcs = { |
1233 | .destroy = dce110_destroy_resource_pool, |
1234 | .link_enc_create = dce110_link_encoder_create, |
1235 | .panel_cntl_create = dce110_panel_cntl_create, |
1236 | .validate_bandwidth = dce110_validate_bandwidth, |
1237 | .validate_plane = dce110_validate_plane, |
1238 | .acquire_free_pipe_as_secondary_dpp_pipe = dce110_acquire_underlay, |
1239 | .add_stream_to_ctx = dce110_add_stream_to_ctx, |
1240 | .validate_global = dce110_validate_global, |
1241 | .find_first_free_match_stream_enc_for_link = dce110_find_first_free_match_stream_enc_for_link |
1242 | }; |
1243 | |
1244 | static bool underlay_create(struct dc_context *ctx, struct resource_pool *pool) |
1245 | { |
1246 | struct dce110_timing_generator *dce110_tgv = kzalloc(size: sizeof(*dce110_tgv), |
1247 | GFP_KERNEL); |
1248 | struct dce_transform *dce110_xfmv = kzalloc(size: sizeof(*dce110_xfmv), |
1249 | GFP_KERNEL); |
1250 | struct dce_mem_input *dce110_miv = kzalloc(size: sizeof(*dce110_miv), |
1251 | GFP_KERNEL); |
1252 | struct dce110_opp *dce110_oppv = kzalloc(size: sizeof(*dce110_oppv), |
1253 | GFP_KERNEL); |
1254 | |
1255 | if (!dce110_tgv || !dce110_xfmv || !dce110_miv || !dce110_oppv) { |
1256 | kfree(objp: dce110_tgv); |
1257 | kfree(objp: dce110_xfmv); |
1258 | kfree(objp: dce110_miv); |
1259 | kfree(objp: dce110_oppv); |
1260 | return false; |
1261 | } |
1262 | |
1263 | dce110_opp_v_construct(opp110: dce110_oppv, ctx); |
1264 | |
1265 | dce110_timing_generator_v_construct(tg110: dce110_tgv, ctx); |
1266 | dce110_mem_input_v_construct(dce_mi: dce110_miv, ctx); |
1267 | dce110_transform_v_construct(xfm110: dce110_xfmv, ctx); |
1268 | |
1269 | pool->opps[pool->pipe_count] = &dce110_oppv->base; |
1270 | pool->timing_generators[pool->pipe_count] = &dce110_tgv->base; |
1271 | pool->mis[pool->pipe_count] = &dce110_miv->base; |
1272 | pool->transforms[pool->pipe_count] = &dce110_xfmv->base; |
1273 | pool->pipe_count++; |
1274 | |
1275 | /* update the public caps to indicate an underlay is available */ |
1276 | ctx->dc->caps.max_slave_planes = 1; |
1277 | ctx->dc->caps.max_slave_yuv_planes = 1; |
1278 | ctx->dc->caps.max_slave_rgb_planes = 0; |
1279 | |
1280 | return true; |
1281 | } |
1282 | |
1283 | static void bw_calcs_data_update_from_pplib(struct dc *dc) |
1284 | { |
1285 | struct dm_pp_clock_levels clks = {0}; |
1286 | |
1287 | /*do system clock*/ |
1288 | dm_pp_get_clock_levels_by_type( |
1289 | ctx: dc->ctx, |
1290 | clk_type: DM_PP_CLOCK_TYPE_ENGINE_CLK, |
1291 | clk_level_info: &clks); |
1292 | /* convert all the clock fro kHz to fix point mHz */ |
1293 | dc->bw_vbios->high_sclk = bw_frc_to_fixed( |
1294 | num: clks.clocks_in_khz[clks.num_levels-1], denum: 1000); |
1295 | dc->bw_vbios->mid1_sclk = bw_frc_to_fixed( |
1296 | num: clks.clocks_in_khz[clks.num_levels/8], denum: 1000); |
1297 | dc->bw_vbios->mid2_sclk = bw_frc_to_fixed( |
1298 | num: clks.clocks_in_khz[clks.num_levels*2/8], denum: 1000); |
1299 | dc->bw_vbios->mid3_sclk = bw_frc_to_fixed( |
1300 | num: clks.clocks_in_khz[clks.num_levels*3/8], denum: 1000); |
1301 | dc->bw_vbios->mid4_sclk = bw_frc_to_fixed( |
1302 | num: clks.clocks_in_khz[clks.num_levels*4/8], denum: 1000); |
1303 | dc->bw_vbios->mid5_sclk = bw_frc_to_fixed( |
1304 | num: clks.clocks_in_khz[clks.num_levels*5/8], denum: 1000); |
1305 | dc->bw_vbios->mid6_sclk = bw_frc_to_fixed( |
1306 | num: clks.clocks_in_khz[clks.num_levels*6/8], denum: 1000); |
1307 | dc->bw_vbios->low_sclk = bw_frc_to_fixed( |
1308 | num: clks.clocks_in_khz[0], denum: 1000); |
1309 | dc->sclk_lvls = clks; |
1310 | |
1311 | /*do display clock*/ |
1312 | dm_pp_get_clock_levels_by_type( |
1313 | ctx: dc->ctx, |
1314 | clk_type: DM_PP_CLOCK_TYPE_DISPLAY_CLK, |
1315 | clk_level_info: &clks); |
1316 | dc->bw_vbios->high_voltage_max_dispclk = bw_frc_to_fixed( |
1317 | num: clks.clocks_in_khz[clks.num_levels-1], denum: 1000); |
1318 | dc->bw_vbios->mid_voltage_max_dispclk = bw_frc_to_fixed( |
1319 | num: clks.clocks_in_khz[clks.num_levels>>1], denum: 1000); |
1320 | dc->bw_vbios->low_voltage_max_dispclk = bw_frc_to_fixed( |
1321 | num: clks.clocks_in_khz[0], denum: 1000); |
1322 | |
1323 | /*do memory clock*/ |
1324 | dm_pp_get_clock_levels_by_type( |
1325 | ctx: dc->ctx, |
1326 | clk_type: DM_PP_CLOCK_TYPE_MEMORY_CLK, |
1327 | clk_level_info: &clks); |
1328 | |
1329 | dc->bw_vbios->low_yclk = bw_frc_to_fixed( |
1330 | num: clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER_CZ, denum: 1000); |
1331 | dc->bw_vbios->mid_yclk = bw_frc_to_fixed( |
1332 | num: clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER_CZ, |
1333 | denum: 1000); |
1334 | dc->bw_vbios->high_yclk = bw_frc_to_fixed( |
1335 | num: clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER_CZ, |
1336 | denum: 1000); |
1337 | } |
1338 | |
1339 | static const struct resource_caps *dce110_resource_cap( |
1340 | struct hw_asic_id *asic_id) |
1341 | { |
1342 | if (ASIC_REV_IS_STONEY(asic_id->hw_internal_rev)) |
1343 | return &stoney_resource_cap; |
1344 | else |
1345 | return &carrizo_resource_cap; |
1346 | } |
1347 | |
1348 | static bool dce110_resource_construct( |
1349 | uint8_t num_virtual_links, |
1350 | struct dc *dc, |
1351 | struct dce110_resource_pool *pool, |
1352 | struct hw_asic_id asic_id) |
1353 | { |
1354 | unsigned int i; |
1355 | struct dc_context *ctx = dc->ctx; |
1356 | struct dc_bios *bp; |
1357 | |
1358 | ctx->dc_bios->regs = &bios_regs; |
1359 | |
1360 | pool->base.res_cap = dce110_resource_cap(asic_id: &ctx->asic_id); |
1361 | pool->base.funcs = &dce110_res_pool_funcs; |
1362 | |
1363 | /************************************************* |
1364 | * Resource + asic cap harcoding * |
1365 | *************************************************/ |
1366 | |
1367 | pool->base.pipe_count = pool->base.res_cap->num_timing_generator; |
1368 | pool->base.underlay_pipe_index = pool->base.pipe_count; |
1369 | pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; |
1370 | dc->caps.max_downscale_ratio = 150; |
1371 | dc->caps.i2c_speed_in_khz = 40; |
1372 | dc->caps.i2c_speed_in_khz_hdcp = 40; |
1373 | dc->caps.max_cursor_size = 128; |
1374 | dc->caps.min_horizontal_blanking_period = 80; |
1375 | dc->caps.is_apu = true; |
1376 | dc->caps.extended_aux_timeout_support = false; |
1377 | dc->debug = debug_defaults; |
1378 | |
1379 | /************************************************* |
1380 | * Create resources * |
1381 | *************************************************/ |
1382 | |
1383 | bp = ctx->dc_bios; |
1384 | |
1385 | if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { |
1386 | pool->base.dp_clock_source = |
1387 | dce110_clock_source_create(ctx, bios: bp, id: CLOCK_SOURCE_ID_EXTERNAL, NULL, dp_clk_src: true); |
1388 | |
1389 | pool->base.clock_sources[0] = |
1390 | dce110_clock_source_create(ctx, bios: bp, id: CLOCK_SOURCE_ID_PLL0, |
1391 | regs: &clk_src_regs[0], dp_clk_src: false); |
1392 | pool->base.clock_sources[1] = |
1393 | dce110_clock_source_create(ctx, bios: bp, id: CLOCK_SOURCE_ID_PLL1, |
1394 | regs: &clk_src_regs[1], dp_clk_src: false); |
1395 | |
1396 | pool->base.clk_src_count = 2; |
1397 | |
1398 | /* TODO: find out if CZ support 3 PLLs */ |
1399 | } |
1400 | |
1401 | if (pool->base.dp_clock_source == NULL) { |
1402 | dm_error("DC: failed to create dp clock source!\n" ); |
1403 | BREAK_TO_DEBUGGER(); |
1404 | goto res_create_fail; |
1405 | } |
1406 | |
1407 | for (i = 0; i < pool->base.clk_src_count; i++) { |
1408 | if (pool->base.clock_sources[i] == NULL) { |
1409 | dm_error("DC: failed to create clock sources!\n" ); |
1410 | BREAK_TO_DEBUGGER(); |
1411 | goto res_create_fail; |
1412 | } |
1413 | } |
1414 | |
1415 | pool->base.dmcu = dce_dmcu_create(ctx, |
1416 | regs: &dmcu_regs, |
1417 | dmcu_shift: &dmcu_shift, |
1418 | dmcu_mask: &dmcu_mask); |
1419 | if (pool->base.dmcu == NULL) { |
1420 | dm_error("DC: failed to create dmcu!\n" ); |
1421 | BREAK_TO_DEBUGGER(); |
1422 | goto res_create_fail; |
1423 | } |
1424 | |
1425 | pool->base.abm = dce_abm_create(ctx, |
1426 | regs: &abm_regs, |
1427 | abm_shift: &abm_shift, |
1428 | abm_mask: &abm_mask); |
1429 | if (pool->base.abm == NULL) { |
1430 | dm_error("DC: failed to create abm!\n" ); |
1431 | BREAK_TO_DEBUGGER(); |
1432 | goto res_create_fail; |
1433 | } |
1434 | |
1435 | { |
1436 | struct irq_service_init_data init_data; |
1437 | init_data.ctx = dc->ctx; |
1438 | pool->base.irqs = dal_irq_service_dce110_create(init_data: &init_data); |
1439 | if (!pool->base.irqs) |
1440 | goto res_create_fail; |
1441 | } |
1442 | |
1443 | for (i = 0; i < pool->base.pipe_count; i++) { |
1444 | pool->base.timing_generators[i] = dce110_timing_generator_create( |
1445 | ctx, instance: i, offsets: &dce110_tg_offsets[i]); |
1446 | if (pool->base.timing_generators[i] == NULL) { |
1447 | BREAK_TO_DEBUGGER(); |
1448 | dm_error("DC: failed to create tg!\n" ); |
1449 | goto res_create_fail; |
1450 | } |
1451 | |
1452 | pool->base.mis[i] = dce110_mem_input_create(ctx, inst: i); |
1453 | if (pool->base.mis[i] == NULL) { |
1454 | BREAK_TO_DEBUGGER(); |
1455 | dm_error( |
1456 | "DC: failed to create memory input!\n" ); |
1457 | goto res_create_fail; |
1458 | } |
1459 | |
1460 | pool->base.ipps[i] = dce110_ipp_create(ctx, inst: i); |
1461 | if (pool->base.ipps[i] == NULL) { |
1462 | BREAK_TO_DEBUGGER(); |
1463 | dm_error( |
1464 | "DC: failed to create input pixel processor!\n" ); |
1465 | goto res_create_fail; |
1466 | } |
1467 | |
1468 | pool->base.transforms[i] = dce110_transform_create(ctx, inst: i); |
1469 | if (pool->base.transforms[i] == NULL) { |
1470 | BREAK_TO_DEBUGGER(); |
1471 | dm_error( |
1472 | "DC: failed to create transform!\n" ); |
1473 | goto res_create_fail; |
1474 | } |
1475 | |
1476 | pool->base.opps[i] = dce110_opp_create(ctx, inst: i); |
1477 | if (pool->base.opps[i] == NULL) { |
1478 | BREAK_TO_DEBUGGER(); |
1479 | dm_error( |
1480 | "DC: failed to create output pixel processor!\n" ); |
1481 | goto res_create_fail; |
1482 | } |
1483 | } |
1484 | |
1485 | for (i = 0; i < pool->base.res_cap->num_ddc; i++) { |
1486 | pool->base.engines[i] = dce110_aux_engine_create(ctx, inst: i); |
1487 | if (pool->base.engines[i] == NULL) { |
1488 | BREAK_TO_DEBUGGER(); |
1489 | dm_error( |
1490 | "DC:failed to create aux engine!!\n" ); |
1491 | goto res_create_fail; |
1492 | } |
1493 | pool->base.hw_i2cs[i] = dce110_i2c_hw_create(ctx, inst: i); |
1494 | if (pool->base.hw_i2cs[i] == NULL) { |
1495 | BREAK_TO_DEBUGGER(); |
1496 | dm_error( |
1497 | "DC:failed to create i2c engine!!\n" ); |
1498 | goto res_create_fail; |
1499 | } |
1500 | pool->base.sw_i2cs[i] = NULL; |
1501 | } |
1502 | |
1503 | if (dc->config.fbc_support) |
1504 | dc->fbc_compressor = dce110_compressor_create(ctx); |
1505 | |
1506 | if (!underlay_create(ctx, pool: &pool->base)) |
1507 | goto res_create_fail; |
1508 | |
1509 | if (!resource_construct(num_virtual_links, dc, pool: &pool->base, |
1510 | create_funcs: &res_create_funcs)) |
1511 | goto res_create_fail; |
1512 | |
1513 | /* Create hardware sequencer */ |
1514 | dce110_hw_sequencer_construct(dc); |
1515 | |
1516 | dc->caps.max_planes = pool->base.pipe_count; |
1517 | |
1518 | for (i = 0; i < pool->base.underlay_pipe_index; ++i) |
1519 | dc->caps.planes[i] = plane_cap; |
1520 | |
1521 | dc->caps.planes[pool->base.underlay_pipe_index] = underlay_plane_cap; |
1522 | |
1523 | bw_calcs_init(bw_dceip: dc->bw_dceip, bw_vbios: dc->bw_vbios, asic_id: dc->ctx->asic_id); |
1524 | |
1525 | bw_calcs_data_update_from_pplib(dc); |
1526 | |
1527 | return true; |
1528 | |
1529 | res_create_fail: |
1530 | dce110_resource_destruct(pool); |
1531 | return false; |
1532 | } |
1533 | |
1534 | struct resource_pool *dce110_create_resource_pool( |
1535 | uint8_t num_virtual_links, |
1536 | struct dc *dc, |
1537 | struct hw_asic_id asic_id) |
1538 | { |
1539 | struct dce110_resource_pool *pool = |
1540 | kzalloc(size: sizeof(struct dce110_resource_pool), GFP_KERNEL); |
1541 | |
1542 | if (!pool) |
1543 | return NULL; |
1544 | |
1545 | if (dce110_resource_construct(num_virtual_links, dc, pool, asic_id)) |
1546 | return &pool->base; |
1547 | |
1548 | kfree(objp: pool); |
1549 | BREAK_TO_DEBUGGER(); |
1550 | return NULL; |
1551 | } |
1552 | |