Commit | Line | Data |
---|---|---|
4562236b HW |
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 "include/irq_service_interface.h" | |
33 | #include "dce110/dce110_resource.h" | |
34 | #include "dce110/dce110_timing_generator.h" | |
4562236b HW |
35 | |
36 | #include "irq/dce110/irq_service_dce110.h" | |
c3489214 DL |
37 | |
38 | #include "dce/dce_mem_input.h" | |
4562236b HW |
39 | #include "dce/dce_transform.h" |
40 | #include "dce/dce_link_encoder.h" | |
41 | #include "dce/dce_stream_encoder.h" | |
42 | #include "dce/dce_audio.h" | |
ab3ee7a5 | 43 | #include "dce/dce_opp.h" |
e6303950 | 44 | #include "dce/dce_ipp.h" |
9a70eba7 | 45 | #include "dce/dce_clocks.h" |
4562236b HW |
46 | #include "dce/dce_clock_source.h" |
47 | ||
48 | #include "dce/dce_hwseq.h" | |
49 | #include "dce112/dce112_hw_sequencer.h" | |
5e7773a2 AK |
50 | #include "dce/dce_abm.h" |
51 | #include "dce/dce_dmcu.h" | |
4562236b HW |
52 | |
53 | #include "reg_helper.h" | |
54 | ||
55 | #include "dce/dce_11_2_d.h" | |
56 | #include "dce/dce_11_2_sh_mask.h" | |
57 | ||
792671d7 AG |
58 | #include "dce100/dce100_resource.h" |
59 | ||
4562236b HW |
60 | #ifndef mmDP_DPHY_INTERNAL_CTRL |
61 | #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7 | |
62 | #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7 | |
63 | #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7 | |
64 | #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7 | |
65 | #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7 | |
66 | #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7 | |
67 | #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7 | |
68 | #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7 | |
69 | #define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7 | |
70 | #define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7 | |
71 | #endif | |
72 | ||
73 | #ifndef mmBIOS_SCRATCH_2 | |
74 | #define mmBIOS_SCRATCH_2 0x05CB | |
75 | #define mmBIOS_SCRATCH_6 0x05CF | |
76 | #endif | |
77 | ||
78 | #ifndef mmDP_DPHY_BS_SR_SWAP_CNTL | |
79 | #define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4ADC | |
80 | #define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4ADC | |
81 | #define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4BDC | |
82 | #define mmDP2_DP_DPHY_BS_SR_SWAP_CNTL 0x4CDC | |
83 | #define mmDP3_DP_DPHY_BS_SR_SWAP_CNTL 0x4DDC | |
84 | #define mmDP4_DP_DPHY_BS_SR_SWAP_CNTL 0x4EDC | |
85 | #define mmDP5_DP_DPHY_BS_SR_SWAP_CNTL 0x4FDC | |
86 | #define mmDP6_DP_DPHY_BS_SR_SWAP_CNTL 0x54DC | |
87 | #endif | |
88 | ||
89 | #ifndef mmDP_DPHY_FAST_TRAINING | |
90 | #define mmDP_DPHY_FAST_TRAINING 0x4ABC | |
91 | #define mmDP0_DP_DPHY_FAST_TRAINING 0x4ABC | |
92 | #define mmDP1_DP_DPHY_FAST_TRAINING 0x4BBC | |
93 | #define mmDP2_DP_DPHY_FAST_TRAINING 0x4CBC | |
94 | #define mmDP3_DP_DPHY_FAST_TRAINING 0x4DBC | |
95 | #define mmDP4_DP_DPHY_FAST_TRAINING 0x4EBC | |
96 | #define mmDP5_DP_DPHY_FAST_TRAINING 0x4FBC | |
97 | #define mmDP6_DP_DPHY_FAST_TRAINING 0x54BC | |
98 | #endif | |
99 | ||
100 | enum dce112_clk_src_array_id { | |
101 | DCE112_CLK_SRC_PLL0, | |
102 | DCE112_CLK_SRC_PLL1, | |
103 | DCE112_CLK_SRC_PLL2, | |
104 | DCE112_CLK_SRC_PLL3, | |
105 | DCE112_CLK_SRC_PLL4, | |
106 | DCE112_CLK_SRC_PLL5, | |
107 | ||
108 | DCE112_CLK_SRC_TOTAL | |
109 | }; | |
110 | ||
111 | static const struct dce110_timing_generator_offsets dce112_tg_offsets[] = { | |
112 | { | |
113 | .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), | |
114 | .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL), | |
115 | }, | |
116 | { | |
117 | .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), | |
118 | .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), | |
119 | }, | |
120 | { | |
121 | .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), | |
122 | .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), | |
123 | }, | |
124 | { | |
125 | .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), | |
126 | .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), | |
127 | }, | |
128 | { | |
129 | .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), | |
130 | .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), | |
131 | }, | |
132 | { | |
133 | .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), | |
134 | .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), | |
135 | } | |
136 | }; | |
137 | ||
4562236b HW |
138 | /* set register offset */ |
139 | #define SR(reg_name)\ | |
140 | .reg_name = mm ## reg_name | |
141 | ||
142 | /* set register offset with instance */ | |
143 | #define SRI(reg_name, block, id)\ | |
144 | .reg_name = mm ## block ## id ## _ ## reg_name | |
145 | ||
9a70eba7 DL |
146 | |
147 | static const struct dce_disp_clk_registers disp_clk_regs = { | |
148 | CLK_COMMON_REG_LIST_DCE_BASE() | |
149 | }; | |
150 | ||
151 | static const struct dce_disp_clk_shift disp_clk_shift = { | |
152 | CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) | |
153 | }; | |
154 | ||
155 | static const struct dce_disp_clk_mask disp_clk_mask = { | |
156 | CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) | |
157 | }; | |
158 | ||
5e7773a2 AK |
159 | static const struct dce_dmcu_registers dmcu_regs = { |
160 | DMCU_DCE110_COMMON_REG_LIST() | |
161 | }; | |
162 | ||
163 | static const struct dce_dmcu_shift dmcu_shift = { | |
164 | DMCU_MASK_SH_LIST_DCE110(__SHIFT) | |
165 | }; | |
166 | ||
167 | static const struct dce_dmcu_mask dmcu_mask = { | |
168 | DMCU_MASK_SH_LIST_DCE110(_MASK) | |
169 | }; | |
170 | ||
171 | static const struct dce_abm_registers abm_regs = { | |
172 | ABM_DCE110_COMMON_REG_LIST() | |
173 | }; | |
174 | ||
175 | static const struct dce_abm_shift abm_shift = { | |
176 | ABM_MASK_SH_LIST_DCE110(__SHIFT) | |
177 | }; | |
178 | ||
179 | static const struct dce_abm_mask abm_mask = { | |
180 | ABM_MASK_SH_LIST_DCE110(_MASK) | |
181 | }; | |
182 | ||
e6303950 DL |
183 | #define ipp_regs(id)\ |
184 | [id] = {\ | |
185 | IPP_DCE110_REG_LIST_DCE_BASE(id)\ | |
186 | } | |
187 | ||
188 | static const struct dce_ipp_registers ipp_regs[] = { | |
189 | ipp_regs(0), | |
190 | ipp_regs(1), | |
191 | ipp_regs(2), | |
192 | ipp_regs(3), | |
193 | ipp_regs(4), | |
194 | ipp_regs(5) | |
195 | }; | |
196 | ||
197 | static const struct dce_ipp_shift ipp_shift = { | |
198 | IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) | |
199 | }; | |
200 | ||
201 | static const struct dce_ipp_mask ipp_mask = { | |
202 | IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) | |
203 | }; | |
204 | ||
4562236b HW |
205 | #define transform_regs(id)\ |
206 | [id] = {\ | |
207 | XFM_COMMON_REG_LIST_DCE110(id)\ | |
208 | } | |
209 | ||
210 | static const struct dce_transform_registers xfm_regs[] = { | |
211 | transform_regs(0), | |
212 | transform_regs(1), | |
213 | transform_regs(2), | |
214 | transform_regs(3), | |
215 | transform_regs(4), | |
216 | transform_regs(5) | |
217 | }; | |
218 | ||
219 | static const struct dce_transform_shift xfm_shift = { | |
220 | XFM_COMMON_MASK_SH_LIST_DCE110(__SHIFT) | |
221 | }; | |
222 | ||
223 | static const struct dce_transform_mask xfm_mask = { | |
224 | XFM_COMMON_MASK_SH_LIST_DCE110(_MASK) | |
225 | }; | |
226 | ||
227 | #define aux_regs(id)\ | |
228 | [id] = {\ | |
229 | AUX_REG_LIST(id)\ | |
230 | } | |
231 | ||
232 | static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { | |
233 | aux_regs(0), | |
234 | aux_regs(1), | |
235 | aux_regs(2), | |
236 | aux_regs(3), | |
237 | aux_regs(4), | |
238 | aux_regs(5) | |
239 | }; | |
240 | ||
241 | #define hpd_regs(id)\ | |
242 | [id] = {\ | |
243 | HPD_REG_LIST(id)\ | |
244 | } | |
245 | ||
246 | static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { | |
247 | hpd_regs(0), | |
248 | hpd_regs(1), | |
249 | hpd_regs(2), | |
250 | hpd_regs(3), | |
251 | hpd_regs(4), | |
252 | hpd_regs(5) | |
253 | }; | |
254 | ||
255 | #define link_regs(id)\ | |
256 | [id] = {\ | |
257 | LE_DCE110_REG_LIST(id)\ | |
258 | } | |
259 | ||
260 | static const struct dce110_link_enc_registers link_enc_regs[] = { | |
261 | link_regs(0), | |
262 | link_regs(1), | |
263 | link_regs(2), | |
264 | link_regs(3), | |
265 | link_regs(4), | |
266 | link_regs(5), | |
267 | link_regs(6), | |
268 | }; | |
269 | ||
270 | #define stream_enc_regs(id)\ | |
271 | [id] = {\ | |
272 | SE_COMMON_REG_LIST(id),\ | |
273 | .TMDS_CNTL = 0,\ | |
274 | } | |
275 | ||
276 | static const struct dce110_stream_enc_registers stream_enc_regs[] = { | |
277 | stream_enc_regs(0), | |
278 | stream_enc_regs(1), | |
279 | stream_enc_regs(2), | |
280 | stream_enc_regs(3), | |
281 | stream_enc_regs(4), | |
282 | stream_enc_regs(5) | |
283 | }; | |
284 | ||
285 | static const struct dce_stream_encoder_shift se_shift = { | |
286 | SE_COMMON_MASK_SH_LIST_DCE112(__SHIFT) | |
287 | }; | |
288 | ||
289 | static const struct dce_stream_encoder_mask se_mask = { | |
290 | SE_COMMON_MASK_SH_LIST_DCE112(_MASK) | |
291 | }; | |
292 | ||
ab3ee7a5 ZF |
293 | #define opp_regs(id)\ |
294 | [id] = {\ | |
295 | OPP_DCE_112_REG_LIST(id),\ | |
296 | } | |
297 | ||
298 | static const struct dce_opp_registers opp_regs[] = { | |
299 | opp_regs(0), | |
300 | opp_regs(1), | |
301 | opp_regs(2), | |
302 | opp_regs(3), | |
303 | opp_regs(4), | |
304 | opp_regs(5) | |
305 | }; | |
306 | ||
307 | static const struct dce_opp_shift opp_shift = { | |
308 | OPP_COMMON_MASK_SH_LIST_DCE_112(__SHIFT) | |
309 | }; | |
310 | ||
311 | static const struct dce_opp_mask opp_mask = { | |
312 | OPP_COMMON_MASK_SH_LIST_DCE_112(_MASK) | |
313 | }; | |
314 | ||
4562236b HW |
315 | #define audio_regs(id)\ |
316 | [id] = {\ | |
317 | AUD_COMMON_REG_LIST(id)\ | |
318 | } | |
319 | ||
320 | static const struct dce_audio_registers audio_regs[] = { | |
321 | audio_regs(0), | |
322 | audio_regs(1), | |
323 | audio_regs(2), | |
324 | audio_regs(3), | |
325 | audio_regs(4), | |
326 | audio_regs(5) | |
327 | }; | |
328 | ||
329 | static const struct dce_audio_shift audio_shift = { | |
330 | AUD_COMMON_MASK_SH_LIST(__SHIFT) | |
331 | }; | |
332 | ||
333 | static const struct dce_aduio_mask audio_mask = { | |
334 | AUD_COMMON_MASK_SH_LIST(_MASK) | |
335 | }; | |
336 | ||
4562236b HW |
337 | #define clk_src_regs(index, id)\ |
338 | [index] = {\ | |
339 | CS_COMMON_REG_LIST_DCE_112(id),\ | |
340 | } | |
341 | ||
342 | static const struct dce110_clk_src_regs clk_src_regs[] = { | |
343 | clk_src_regs(0, A), | |
344 | clk_src_regs(1, B), | |
345 | clk_src_regs(2, C), | |
346 | clk_src_regs(3, D), | |
347 | clk_src_regs(4, E), | |
348 | clk_src_regs(5, F) | |
349 | }; | |
350 | ||
351 | static const struct dce110_clk_src_shift cs_shift = { | |
352 | CS_COMMON_MASK_SH_LIST_DCE_112(__SHIFT) | |
353 | }; | |
354 | ||
355 | static const struct dce110_clk_src_mask cs_mask = { | |
356 | CS_COMMON_MASK_SH_LIST_DCE_112(_MASK) | |
357 | }; | |
358 | ||
359 | static const struct bios_registers bios_regs = { | |
360 | .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 | |
361 | }; | |
362 | ||
363 | static const struct resource_caps polaris_10_resource_cap = { | |
364 | .num_timing_generator = 6, | |
365 | .num_audio = 6, | |
366 | .num_stream_encoder = 6, | |
367 | .num_pll = 8, /* why 8? 6 combo PHY PLL + 2 regular PLLs? */ | |
368 | }; | |
369 | ||
370 | static const struct resource_caps polaris_11_resource_cap = { | |
371 | .num_timing_generator = 5, | |
372 | .num_audio = 5, | |
373 | .num_stream_encoder = 5, | |
374 | .num_pll = 8, /* why 8? 6 combo PHY PLL + 2 regular PLLs? */ | |
375 | }; | |
376 | ||
377 | #define CTX ctx | |
378 | #define REG(reg) mm ## reg | |
379 | ||
380 | #ifndef mmCC_DC_HDMI_STRAPS | |
381 | #define mmCC_DC_HDMI_STRAPS 0x4819 | |
382 | #define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 | |
383 | #define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 | |
384 | #define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 | |
385 | #define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 | |
386 | #endif | |
387 | ||
388 | static void read_dce_straps( | |
389 | struct dc_context *ctx, | |
390 | struct resource_straps *straps) | |
391 | { | |
392 | REG_GET_2(CC_DC_HDMI_STRAPS, | |
393 | HDMI_DISABLE, &straps->hdmi_disable, | |
394 | AUDIO_STREAM_NUMBER, &straps->audio_stream_number); | |
395 | ||
396 | REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); | |
397 | } | |
398 | ||
399 | static struct audio *create_audio( | |
400 | struct dc_context *ctx, unsigned int inst) | |
401 | { | |
402 | return dce_audio_create(ctx, inst, | |
403 | &audio_regs[inst], &audio_shift, &audio_mask); | |
404 | } | |
405 | ||
406 | ||
407 | static struct timing_generator *dce112_timing_generator_create( | |
408 | struct dc_context *ctx, | |
409 | uint32_t instance, | |
410 | const struct dce110_timing_generator_offsets *offsets) | |
411 | { | |
412 | struct dce110_timing_generator *tg110 = | |
413 | dm_alloc(sizeof(struct dce110_timing_generator)); | |
414 | ||
415 | if (!tg110) | |
416 | return NULL; | |
417 | ||
418 | if (dce110_timing_generator_construct(tg110, ctx, instance, offsets)) | |
419 | return &tg110->base; | |
420 | ||
421 | BREAK_TO_DEBUGGER(); | |
422 | dm_free(tg110); | |
423 | return NULL; | |
424 | } | |
425 | ||
426 | static struct stream_encoder *dce112_stream_encoder_create( | |
427 | enum engine_id eng_id, | |
428 | struct dc_context *ctx) | |
429 | { | |
430 | struct dce110_stream_encoder *enc110 = | |
431 | dm_alloc(sizeof(struct dce110_stream_encoder)); | |
432 | ||
433 | if (!enc110) | |
434 | return NULL; | |
435 | ||
436 | if (dce110_stream_encoder_construct( | |
437 | enc110, ctx, ctx->dc_bios, eng_id, | |
438 | &stream_enc_regs[eng_id], &se_shift, &se_mask)) | |
439 | return &enc110->base; | |
440 | ||
441 | BREAK_TO_DEBUGGER(); | |
442 | dm_free(enc110); | |
443 | return NULL; | |
444 | } | |
445 | ||
446 | #define SRII(reg_name, block, id)\ | |
447 | .reg_name[id] = mm ## block ## id ## _ ## reg_name | |
448 | ||
449 | static const struct dce_hwseq_registers hwseq_reg = { | |
450 | HWSEQ_DCE112_REG_LIST() | |
451 | }; | |
452 | ||
453 | static const struct dce_hwseq_shift hwseq_shift = { | |
454 | HWSEQ_DCE112_MASK_SH_LIST(__SHIFT) | |
455 | }; | |
456 | ||
457 | static const struct dce_hwseq_mask hwseq_mask = { | |
458 | HWSEQ_DCE112_MASK_SH_LIST(_MASK) | |
459 | }; | |
460 | ||
461 | static struct dce_hwseq *dce112_hwseq_create( | |
462 | struct dc_context *ctx) | |
463 | { | |
464 | struct dce_hwseq *hws = dm_alloc(sizeof(struct dce_hwseq)); | |
465 | ||
466 | if (hws) { | |
467 | hws->ctx = ctx; | |
468 | hws->regs = &hwseq_reg; | |
469 | hws->shifts = &hwseq_shift; | |
470 | hws->masks = &hwseq_mask; | |
471 | } | |
472 | return hws; | |
473 | } | |
474 | ||
475 | static const struct resource_create_funcs res_create_funcs = { | |
476 | .read_dce_straps = read_dce_straps, | |
477 | .create_audio = create_audio, | |
478 | .create_stream_encoder = dce112_stream_encoder_create, | |
479 | .create_hwseq = dce112_hwseq_create, | |
480 | }; | |
481 | ||
197062bf | 482 | #define mi_inst_regs(id) { MI_DCE11_2_REG_LIST(id) } |
4562236b HW |
483 | static const struct dce_mem_input_registers mi_regs[] = { |
484 | mi_inst_regs(0), | |
485 | mi_inst_regs(1), | |
486 | mi_inst_regs(2), | |
487 | mi_inst_regs(3), | |
488 | mi_inst_regs(4), | |
489 | mi_inst_regs(5), | |
490 | }; | |
491 | ||
492 | static const struct dce_mem_input_shift mi_shifts = { | |
197062bf | 493 | MI_DCE11_2_MASK_SH_LIST(__SHIFT) |
4562236b HW |
494 | }; |
495 | ||
496 | static const struct dce_mem_input_mask mi_masks = { | |
197062bf | 497 | MI_DCE11_2_MASK_SH_LIST(_MASK) |
4562236b HW |
498 | }; |
499 | ||
500 | static struct mem_input *dce112_mem_input_create( | |
501 | struct dc_context *ctx, | |
c3489214 | 502 | uint32_t inst) |
4562236b | 503 | { |
c3489214 | 504 | struct dce_mem_input *dce_mi = dm_alloc(sizeof(struct dce_mem_input)); |
4562236b | 505 | |
c3489214 DL |
506 | if (!dce_mi) { |
507 | BREAK_TO_DEBUGGER(); | |
4562236b | 508 | return NULL; |
4562236b HW |
509 | } |
510 | ||
c3489214 DL |
511 | dce112_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); |
512 | return &dce_mi->base; | |
4562236b HW |
513 | } |
514 | ||
515 | static void dce112_transform_destroy(struct transform **xfm) | |
516 | { | |
517 | dm_free(TO_DCE_TRANSFORM(*xfm)); | |
518 | *xfm = NULL; | |
519 | } | |
520 | ||
521 | static struct transform *dce112_transform_create( | |
522 | struct dc_context *ctx, | |
523 | uint32_t inst) | |
524 | { | |
525 | struct dce_transform *transform = | |
526 | dm_alloc(sizeof(struct dce_transform)); | |
527 | ||
528 | if (!transform) | |
529 | return NULL; | |
530 | ||
531 | if (dce_transform_construct(transform, ctx, inst, | |
532 | &xfm_regs[inst], &xfm_shift, &xfm_mask)) { | |
533 | transform->lb_memory_size = 0x1404; /*5124*/ | |
534 | return &transform->base; | |
535 | } | |
536 | ||
537 | BREAK_TO_DEBUGGER(); | |
538 | dm_free(transform); | |
539 | return NULL; | |
540 | } | |
7fc698a0 TC |
541 | |
542 | static const struct encoder_feature_support link_enc_feature = { | |
543 | .max_hdmi_deep_color = COLOR_DEPTH_121212, | |
544 | .max_hdmi_pixel_clock = 600000, | |
545 | .ycbcr420_supported = true, | |
546 | .flags.bits.IS_HBR2_CAPABLE = true, | |
547 | .flags.bits.IS_HBR3_CAPABLE = true, | |
548 | .flags.bits.IS_TPS3_CAPABLE = true, | |
549 | .flags.bits.IS_TPS4_CAPABLE = true, | |
550 | .flags.bits.IS_YCBCR_CAPABLE = true | |
551 | }; | |
552 | ||
4562236b HW |
553 | struct link_encoder *dce112_link_encoder_create( |
554 | const struct encoder_init_data *enc_init_data) | |
555 | { | |
556 | struct dce110_link_encoder *enc110 = | |
557 | dm_alloc(sizeof(struct dce110_link_encoder)); | |
558 | ||
559 | if (!enc110) | |
560 | return NULL; | |
561 | ||
562 | if (dce110_link_encoder_construct( | |
563 | enc110, | |
564 | enc_init_data, | |
7fc698a0 | 565 | &link_enc_feature, |
4562236b HW |
566 | &link_enc_regs[enc_init_data->transmitter], |
567 | &link_enc_aux_regs[enc_init_data->channel - 1], | |
568 | &link_enc_hpd_regs[enc_init_data->hpd_source])) { | |
569 | ||
4562236b HW |
570 | return &enc110->base; |
571 | } | |
572 | ||
573 | BREAK_TO_DEBUGGER(); | |
574 | dm_free(enc110); | |
575 | return NULL; | |
576 | } | |
577 | ||
e6303950 DL |
578 | static struct input_pixel_processor *dce112_ipp_create( |
579 | struct dc_context *ctx, uint32_t inst) | |
4562236b | 580 | { |
e6303950 | 581 | struct dce_ipp *ipp = dm_alloc(sizeof(struct dce_ipp)); |
4562236b | 582 | |
e6303950 DL |
583 | if (!ipp) { |
584 | BREAK_TO_DEBUGGER(); | |
4562236b | 585 | return NULL; |
e6303950 | 586 | } |
4562236b | 587 | |
e6303950 DL |
588 | dce_ipp_construct(ipp, ctx, inst, |
589 | &ipp_regs[inst], &ipp_shift, &ipp_mask); | |
590 | return &ipp->base; | |
4562236b HW |
591 | } |
592 | ||
593 | struct output_pixel_processor *dce112_opp_create( | |
594 | struct dc_context *ctx, | |
ab3ee7a5 | 595 | uint32_t inst) |
4562236b HW |
596 | { |
597 | struct dce110_opp *opp = | |
598 | dm_alloc(sizeof(struct dce110_opp)); | |
599 | ||
600 | if (!opp) | |
601 | return NULL; | |
602 | ||
ab3ee7a5 ZF |
603 | if (dce110_opp_construct(opp, |
604 | ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask)) | |
4562236b HW |
605 | return &opp->base; |
606 | ||
607 | BREAK_TO_DEBUGGER(); | |
608 | dm_free(opp); | |
609 | return NULL; | |
610 | } | |
611 | ||
4562236b HW |
612 | struct clock_source *dce112_clock_source_create( |
613 | struct dc_context *ctx, | |
614 | struct dc_bios *bios, | |
615 | enum clock_source_id id, | |
616 | const struct dce110_clk_src_regs *regs, | |
617 | bool dp_clk_src) | |
618 | { | |
619 | struct dce110_clk_src *clk_src = | |
620 | dm_alloc(sizeof(struct dce110_clk_src)); | |
621 | ||
622 | if (!clk_src) | |
623 | return NULL; | |
624 | ||
625 | if (dce110_clk_src_construct(clk_src, ctx, bios, id, | |
626 | regs, &cs_shift, &cs_mask)) { | |
627 | clk_src->base.dp_clk_src = dp_clk_src; | |
628 | return &clk_src->base; | |
629 | } | |
630 | ||
631 | BREAK_TO_DEBUGGER(); | |
632 | return NULL; | |
633 | } | |
634 | ||
635 | void dce112_clock_source_destroy(struct clock_source **clk_src) | |
636 | { | |
637 | dm_free(TO_DCE110_CLK_SRC(*clk_src)); | |
638 | *clk_src = NULL; | |
639 | } | |
640 | ||
641 | static void destruct(struct dce110_resource_pool *pool) | |
642 | { | |
643 | unsigned int i; | |
644 | ||
645 | for (i = 0; i < pool->base.pipe_count; i++) { | |
646 | if (pool->base.opps[i] != NULL) | |
4d35b093 | 647 | dce110_opp_destroy(&pool->base.opps[i]); |
4562236b HW |
648 | |
649 | if (pool->base.transforms[i] != NULL) | |
650 | dce112_transform_destroy(&pool->base.transforms[i]); | |
651 | ||
652 | if (pool->base.ipps[i] != NULL) | |
e6303950 | 653 | dce_ipp_destroy(&pool->base.ipps[i]); |
4562236b HW |
654 | |
655 | if (pool->base.mis[i] != NULL) { | |
c3489214 | 656 | dm_free(TO_DCE_MEM_INPUT(pool->base.mis[i])); |
4562236b HW |
657 | pool->base.mis[i] = NULL; |
658 | } | |
659 | ||
660 | if (pool->base.timing_generators[i] != NULL) { | |
661 | dm_free(DCE110TG_FROM_TG(pool->base.timing_generators[i])); | |
662 | pool->base.timing_generators[i] = NULL; | |
663 | } | |
664 | } | |
665 | ||
666 | for (i = 0; i < pool->base.stream_enc_count; i++) { | |
667 | if (pool->base.stream_enc[i] != NULL) | |
668 | dm_free(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); | |
669 | } | |
670 | ||
671 | for (i = 0; i < pool->base.clk_src_count; i++) { | |
672 | if (pool->base.clock_sources[i] != NULL) { | |
673 | dce112_clock_source_destroy(&pool->base.clock_sources[i]); | |
674 | } | |
675 | } | |
676 | ||
677 | if (pool->base.dp_clock_source != NULL) | |
678 | dce112_clock_source_destroy(&pool->base.dp_clock_source); | |
679 | ||
680 | for (i = 0; i < pool->base.audio_count; i++) { | |
681 | if (pool->base.audios[i] != NULL) { | |
682 | dce_aud_destroy(&pool->base.audios[i]); | |
683 | } | |
684 | } | |
685 | ||
5e7773a2 AK |
686 | if (pool->base.abm != NULL) |
687 | dce_abm_destroy(&pool->base.abm); | |
688 | ||
689 | if (pool->base.dmcu != NULL) | |
690 | dce_dmcu_destroy(&pool->base.dmcu); | |
691 | ||
9a70eba7 DL |
692 | if (pool->base.display_clock != NULL) |
693 | dce_disp_clk_destroy(&pool->base.display_clock); | |
4562236b HW |
694 | |
695 | if (pool->base.irqs != NULL) { | |
696 | dal_irq_service_destroy(&pool->base.irqs); | |
697 | } | |
698 | } | |
699 | ||
a2b8659d TC |
700 | static struct clock_source *find_matching_pll( |
701 | struct resource_context *res_ctx, | |
702 | const struct resource_pool *pool, | |
0971c40e | 703 | const struct dc_stream_state *const stream) |
4562236b HW |
704 | { |
705 | switch (stream->sink->link->link_enc->transmitter) { | |
706 | case TRANSMITTER_UNIPHY_A: | |
a2b8659d | 707 | return pool->clock_sources[DCE112_CLK_SRC_PLL0]; |
4562236b | 708 | case TRANSMITTER_UNIPHY_B: |
a2b8659d | 709 | return pool->clock_sources[DCE112_CLK_SRC_PLL1]; |
4562236b | 710 | case TRANSMITTER_UNIPHY_C: |
a2b8659d | 711 | return pool->clock_sources[DCE112_CLK_SRC_PLL2]; |
4562236b | 712 | case TRANSMITTER_UNIPHY_D: |
a2b8659d | 713 | return pool->clock_sources[DCE112_CLK_SRC_PLL3]; |
4562236b | 714 | case TRANSMITTER_UNIPHY_E: |
a2b8659d | 715 | return pool->clock_sources[DCE112_CLK_SRC_PLL4]; |
4562236b | 716 | case TRANSMITTER_UNIPHY_F: |
a2b8659d | 717 | return pool->clock_sources[DCE112_CLK_SRC_PLL5]; |
4562236b HW |
718 | default: |
719 | return NULL; | |
720 | }; | |
721 | ||
722 | return 0; | |
723 | } | |
724 | ||
9345d987 | 725 | static enum dc_status build_mapped_resource( |
4562236b | 726 | const struct core_dc *dc, |
430ef426 DL |
727 | struct validate_context *context, |
728 | struct validate_context *old_context) | |
4562236b HW |
729 | { |
730 | enum dc_status status = DC_OK; | |
ab2541b6 | 731 | uint8_t i, j; |
4562236b | 732 | |
ab2541b6 | 733 | for (i = 0; i < context->stream_count; i++) { |
0971c40e | 734 | struct dc_stream_state *stream = context->streams[i]; |
4562236b | 735 | |
430ef426 | 736 | if (old_context && resource_is_stream_unchanged(old_context, stream)) |
ab2541b6 | 737 | continue; |
4562236b | 738 | |
ab2541b6 AC |
739 | for (j = 0; j < MAX_PIPES; j++) { |
740 | struct pipe_ctx *pipe_ctx = | |
741 | &context->res_ctx.pipe_ctx[j]; | |
4562236b | 742 | |
ab2541b6 AC |
743 | if (context->res_ctx.pipe_ctx[j].stream != stream) |
744 | continue; | |
4562236b | 745 | |
ab2541b6 | 746 | status = dce110_resource_build_pipe_hw_param(pipe_ctx); |
4562236b | 747 | |
ab2541b6 AC |
748 | if (status != DC_OK) |
749 | return status; | |
4562236b | 750 | |
ab2541b6 | 751 | resource_build_info_frame(pipe_ctx); |
4562236b | 752 | |
ab2541b6 AC |
753 | /* do not need to validate non root pipes */ |
754 | break; | |
4562236b HW |
755 | } |
756 | } | |
757 | ||
758 | return DC_OK; | |
759 | } | |
760 | ||
45209ef7 | 761 | bool dce112_validate_bandwidth( |
4562236b HW |
762 | const struct core_dc *dc, |
763 | struct validate_context *context) | |
764 | { | |
45209ef7 | 765 | bool result = false; |
4562236b HW |
766 | |
767 | dm_logger_write( | |
768 | dc->ctx->logger, LOG_BANDWIDTH_CALCS, | |
769 | "%s: start", | |
770 | __func__); | |
771 | ||
45209ef7 | 772 | if (bw_calcs( |
4562236b HW |
773 | dc->ctx, |
774 | &dc->bw_dceip, | |
775 | &dc->bw_vbios, | |
776 | context->res_ctx.pipe_ctx, | |
a2b8659d | 777 | dc->res_pool->pipe_count, |
9037d802 | 778 | &context->bw.dce)) |
45209ef7 | 779 | result = true; |
4562236b | 780 | |
45209ef7 | 781 | if (!result) |
4562236b HW |
782 | dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_VALIDATION, |
783 | "%s: Bandwidth validation failed!", | |
784 | __func__); | |
785 | ||
9037d802 DL |
786 | if (memcmp(&dc->current_context->bw.dce, |
787 | &context->bw.dce, sizeof(context->bw.dce))) { | |
4562236b HW |
788 | struct log_entry log_entry; |
789 | dm_logger_open( | |
790 | dc->ctx->logger, | |
791 | &log_entry, | |
792 | LOG_BANDWIDTH_CALCS); | |
793 | dm_logger_append(&log_entry, "%s: finish,\n" | |
794 | "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" | |
795 | "stutMark_b: %d stutMark_a: %d\n", | |
796 | __func__, | |
9037d802 DL |
797 | context->bw.dce.nbp_state_change_wm_ns[0].b_mark, |
798 | context->bw.dce.nbp_state_change_wm_ns[0].a_mark, | |
799 | context->bw.dce.urgent_wm_ns[0].b_mark, | |
800 | context->bw.dce.urgent_wm_ns[0].a_mark, | |
801 | context->bw.dce.stutter_exit_wm_ns[0].b_mark, | |
802 | context->bw.dce.stutter_exit_wm_ns[0].a_mark); | |
4562236b HW |
803 | dm_logger_append(&log_entry, |
804 | "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" | |
805 | "stutMark_b: %d stutMark_a: %d\n", | |
9037d802 DL |
806 | context->bw.dce.nbp_state_change_wm_ns[1].b_mark, |
807 | context->bw.dce.nbp_state_change_wm_ns[1].a_mark, | |
808 | context->bw.dce.urgent_wm_ns[1].b_mark, | |
809 | context->bw.dce.urgent_wm_ns[1].a_mark, | |
810 | context->bw.dce.stutter_exit_wm_ns[1].b_mark, | |
811 | context->bw.dce.stutter_exit_wm_ns[1].a_mark); | |
4562236b HW |
812 | dm_logger_append(&log_entry, |
813 | "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" | |
814 | "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n", | |
9037d802 DL |
815 | context->bw.dce.nbp_state_change_wm_ns[2].b_mark, |
816 | context->bw.dce.nbp_state_change_wm_ns[2].a_mark, | |
817 | context->bw.dce.urgent_wm_ns[2].b_mark, | |
818 | context->bw.dce.urgent_wm_ns[2].a_mark, | |
819 | context->bw.dce.stutter_exit_wm_ns[2].b_mark, | |
820 | context->bw.dce.stutter_exit_wm_ns[2].a_mark, | |
821 | context->bw.dce.stutter_mode_enable); | |
4562236b HW |
822 | dm_logger_append(&log_entry, |
823 | "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" | |
824 | "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n", | |
9037d802 DL |
825 | context->bw.dce.cpuc_state_change_enable, |
826 | context->bw.dce.cpup_state_change_enable, | |
827 | context->bw.dce.nbp_state_change_enable, | |
828 | context->bw.dce.all_displays_in_sync, | |
829 | context->bw.dce.dispclk_khz, | |
830 | context->bw.dce.sclk_khz, | |
831 | context->bw.dce.sclk_deep_sleep_khz, | |
832 | context->bw.dce.yclk_khz, | |
833 | context->bw.dce.blackout_recovery_time_us); | |
4562236b HW |
834 | dm_logger_close(&log_entry); |
835 | } | |
836 | return result; | |
837 | } | |
838 | ||
839 | enum dc_status resource_map_phy_clock_resources( | |
840 | const struct core_dc *dc, | |
430ef426 DL |
841 | struct validate_context *context, |
842 | struct validate_context *old_context) | |
4562236b | 843 | { |
ab2541b6 | 844 | uint8_t i, j; |
4562236b HW |
845 | |
846 | /* acquire new resources */ | |
ab2541b6 | 847 | for (i = 0; i < context->stream_count; i++) { |
0971c40e | 848 | struct dc_stream_state *stream = context->streams[i]; |
4562236b | 849 | |
430ef426 | 850 | if (old_context && resource_is_stream_unchanged(old_context, stream)) |
ab2541b6 | 851 | continue; |
4562236b | 852 | |
ab2541b6 AC |
853 | for (j = 0; j < MAX_PIPES; j++) { |
854 | struct pipe_ctx *pipe_ctx = | |
855 | &context->res_ctx.pipe_ctx[j]; | |
4562236b | 856 | |
ab2541b6 AC |
857 | if (context->res_ctx.pipe_ctx[j].stream != stream) |
858 | continue; | |
4562236b | 859 | |
ab2541b6 AC |
860 | if (dc_is_dp_signal(pipe_ctx->stream->signal) |
861 | || pipe_ctx->stream->signal == SIGNAL_TYPE_VIRTUAL) | |
862 | pipe_ctx->clock_source = | |
a2b8659d | 863 | dc->res_pool->dp_clock_source; |
ab2541b6 | 864 | else |
a2b8659d TC |
865 | pipe_ctx->clock_source = find_matching_pll( |
866 | &context->res_ctx, dc->res_pool, | |
867 | stream); | |
4562236b | 868 | |
ab2541b6 AC |
869 | if (pipe_ctx->clock_source == NULL) |
870 | return DC_NO_CLOCK_SOURCE_RESOURCE; | |
4562236b | 871 | |
ab2541b6 AC |
872 | resource_reference_clock_source( |
873 | &context->res_ctx, | |
a2b8659d | 874 | dc->res_pool, |
ab2541b6 | 875 | pipe_ctx->clock_source); |
4562236b | 876 | |
ab2541b6 AC |
877 | /* only one cs per stream regardless of mpo */ |
878 | break; | |
4562236b HW |
879 | } |
880 | } | |
881 | ||
882 | return DC_OK; | |
883 | } | |
884 | ||
885 | static bool dce112_validate_surface_sets( | |
886 | const struct dc_validation_set set[], | |
887 | int set_count) | |
888 | { | |
889 | int i; | |
890 | ||
891 | for (i = 0; i < set_count; i++) { | |
892 | if (set[i].surface_count == 0) | |
893 | continue; | |
894 | ||
895 | if (set[i].surface_count > 1) | |
896 | return false; | |
897 | ||
4562236b HW |
898 | if (set[i].surfaces[0]->format |
899 | >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) | |
900 | return false; | |
901 | } | |
902 | ||
903 | return true; | |
904 | } | |
905 | ||
906 | enum dc_status dce112_validate_with_context( | |
907 | const struct core_dc *dc, | |
908 | const struct dc_validation_set set[], | |
909 | int set_count, | |
430ef426 DL |
910 | struct validate_context *context, |
911 | struct validate_context *old_context) | |
4562236b HW |
912 | { |
913 | struct dc_context *dc_ctx = dc->ctx; | |
914 | enum dc_status result = DC_ERROR_UNEXPECTED; | |
915 | int i; | |
916 | ||
917 | if (!dce112_validate_surface_sets(set, set_count)) | |
918 | return DC_FAIL_SURFACE_VALIDATE; | |
919 | ||
4562236b | 920 | for (i = 0; i < set_count; i++) { |
4fa086b9 LSL |
921 | context->streams[i] = set[i].stream; |
922 | dc_stream_retain(context->streams[i]); | |
ab2541b6 | 923 | context->stream_count++; |
4562236b HW |
924 | } |
925 | ||
430ef426 | 926 | result = resource_map_pool_resources(dc, context, old_context); |
4562236b HW |
927 | |
928 | if (result == DC_OK) | |
430ef426 | 929 | result = resource_map_phy_clock_resources(dc, context, old_context); |
4562236b | 930 | |
a2b8659d | 931 | if (!resource_validate_attach_surfaces(set, set_count, |
430ef426 | 932 | old_context, context, dc->res_pool)) { |
ab2541b6 | 933 | DC_ERROR("Failed to attach surface to stream!\n"); |
4562236b HW |
934 | return DC_FAIL_ATTACH_SURFACES; |
935 | } | |
936 | ||
937 | if (result == DC_OK) | |
9345d987 | 938 | result = build_mapped_resource(dc, context, old_context); |
4562236b HW |
939 | |
940 | if (result == DC_OK) | |
941 | result = resource_build_scaling_params_for_context(dc, context); | |
942 | ||
943 | if (result == DC_OK) | |
45209ef7 DL |
944 | if (!dce112_validate_bandwidth(dc, context)) |
945 | result = DC_FAIL_BANDWIDTH_VALIDATE; | |
4562236b HW |
946 | |
947 | return result; | |
948 | } | |
949 | ||
950 | enum dc_status dce112_validate_guaranteed( | |
951 | const struct core_dc *dc, | |
0971c40e | 952 | struct dc_stream_state *stream, |
4562236b HW |
953 | struct validate_context *context) |
954 | { | |
955 | enum dc_status result = DC_ERROR_UNEXPECTED; | |
956 | ||
4fa086b9 LSL |
957 | context->streams[0] = stream; |
958 | dc_stream_retain(context->streams[0]); | |
ab2541b6 | 959 | context->stream_count++; |
4562236b | 960 | |
430ef426 | 961 | result = resource_map_pool_resources(dc, context, NULL); |
4562236b HW |
962 | |
963 | if (result == DC_OK) | |
430ef426 | 964 | result = resource_map_phy_clock_resources(dc, context, NULL); |
4562236b HW |
965 | |
966 | if (result == DC_OK) | |
9345d987 | 967 | result = build_mapped_resource(dc, context, NULL); |
4562236b HW |
968 | |
969 | if (result == DC_OK) { | |
ab2541b6 AC |
970 | validate_guaranteed_copy_streams( |
971 | context, dc->public.caps.max_streams); | |
4562236b HW |
972 | result = resource_build_scaling_params_for_context(dc, context); |
973 | } | |
974 | ||
975 | if (result == DC_OK) | |
45209ef7 DL |
976 | if (!dce112_validate_bandwidth(dc, context)) |
977 | result = DC_FAIL_BANDWIDTH_VALIDATE; | |
4562236b HW |
978 | |
979 | return result; | |
980 | } | |
981 | ||
982 | static void dce112_destroy_resource_pool(struct resource_pool **pool) | |
983 | { | |
984 | struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); | |
985 | ||
986 | destruct(dce110_pool); | |
987 | dm_free(dce110_pool); | |
988 | *pool = NULL; | |
989 | } | |
990 | ||
991 | static const struct resource_funcs dce112_res_pool_funcs = { | |
992 | .destroy = dce112_destroy_resource_pool, | |
993 | .link_enc_create = dce112_link_encoder_create, | |
994 | .validate_with_context = dce112_validate_with_context, | |
995 | .validate_guaranteed = dce112_validate_guaranteed, | |
529cad0f | 996 | .validate_bandwidth = dce112_validate_bandwidth, |
c9614aeb | 997 | .validate_plane = dce100_validate_plane |
4562236b HW |
998 | }; |
999 | ||
1000 | static void bw_calcs_data_update_from_pplib(struct core_dc *dc) | |
1001 | { | |
1002 | struct dm_pp_clock_levels_with_latency eng_clks = {0}; | |
1003 | struct dm_pp_clock_levels_with_latency mem_clks = {0}; | |
1004 | struct dm_pp_wm_sets_with_clock_ranges clk_ranges = {0}; | |
1005 | struct dm_pp_clock_levels clks = {0}; | |
1006 | ||
1007 | /*do system clock TODO PPLIB: after PPLIB implement, | |
1008 | * then remove old way | |
1009 | */ | |
1010 | if (!dm_pp_get_clock_levels_by_type_with_latency( | |
1011 | dc->ctx, | |
1012 | DM_PP_CLOCK_TYPE_ENGINE_CLK, | |
1013 | &eng_clks)) { | |
1014 | ||
1015 | /* This is only for temporary */ | |
1016 | dm_pp_get_clock_levels_by_type( | |
1017 | dc->ctx, | |
1018 | DM_PP_CLOCK_TYPE_ENGINE_CLK, | |
1019 | &clks); | |
1020 | /* convert all the clock fro kHz to fix point mHz */ | |
1021 | dc->bw_vbios.high_sclk = bw_frc_to_fixed( | |
1022 | clks.clocks_in_khz[clks.num_levels-1], 1000); | |
1023 | dc->bw_vbios.mid1_sclk = bw_frc_to_fixed( | |
1024 | clks.clocks_in_khz[clks.num_levels/8], 1000); | |
1025 | dc->bw_vbios.mid2_sclk = bw_frc_to_fixed( | |
1026 | clks.clocks_in_khz[clks.num_levels*2/8], 1000); | |
1027 | dc->bw_vbios.mid3_sclk = bw_frc_to_fixed( | |
1028 | clks.clocks_in_khz[clks.num_levels*3/8], 1000); | |
1029 | dc->bw_vbios.mid4_sclk = bw_frc_to_fixed( | |
1030 | clks.clocks_in_khz[clks.num_levels*4/8], 1000); | |
1031 | dc->bw_vbios.mid5_sclk = bw_frc_to_fixed( | |
1032 | clks.clocks_in_khz[clks.num_levels*5/8], 1000); | |
1033 | dc->bw_vbios.mid6_sclk = bw_frc_to_fixed( | |
1034 | clks.clocks_in_khz[clks.num_levels*6/8], 1000); | |
1035 | dc->bw_vbios.low_sclk = bw_frc_to_fixed( | |
1036 | clks.clocks_in_khz[0], 1000); | |
1037 | ||
1038 | /*do memory clock*/ | |
1039 | dm_pp_get_clock_levels_by_type( | |
1040 | dc->ctx, | |
1041 | DM_PP_CLOCK_TYPE_MEMORY_CLK, | |
1042 | &clks); | |
1043 | ||
1044 | dc->bw_vbios.low_yclk = bw_frc_to_fixed( | |
1045 | clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER, 1000); | |
1046 | dc->bw_vbios.mid_yclk = bw_frc_to_fixed( | |
1047 | clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER, | |
1048 | 1000); | |
1049 | dc->bw_vbios.high_yclk = bw_frc_to_fixed( | |
1050 | clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER, | |
1051 | 1000); | |
1052 | ||
1053 | return; | |
1054 | } | |
1055 | ||
1056 | /* convert all the clock fro kHz to fix point mHz TODO: wloop data */ | |
1057 | dc->bw_vbios.high_sclk = bw_frc_to_fixed( | |
1058 | eng_clks.data[eng_clks.num_levels-1].clocks_in_khz, 1000); | |
1059 | dc->bw_vbios.mid1_sclk = bw_frc_to_fixed( | |
1060 | eng_clks.data[eng_clks.num_levels/8].clocks_in_khz, 1000); | |
1061 | dc->bw_vbios.mid2_sclk = bw_frc_to_fixed( | |
1062 | eng_clks.data[eng_clks.num_levels*2/8].clocks_in_khz, 1000); | |
1063 | dc->bw_vbios.mid3_sclk = bw_frc_to_fixed( | |
1064 | eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz, 1000); | |
1065 | dc->bw_vbios.mid4_sclk = bw_frc_to_fixed( | |
1066 | eng_clks.data[eng_clks.num_levels*4/8].clocks_in_khz, 1000); | |
1067 | dc->bw_vbios.mid5_sclk = bw_frc_to_fixed( | |
1068 | eng_clks.data[eng_clks.num_levels*5/8].clocks_in_khz, 1000); | |
1069 | dc->bw_vbios.mid6_sclk = bw_frc_to_fixed( | |
1070 | eng_clks.data[eng_clks.num_levels*6/8].clocks_in_khz, 1000); | |
1071 | dc->bw_vbios.low_sclk = bw_frc_to_fixed( | |
1072 | eng_clks.data[0].clocks_in_khz, 1000); | |
1073 | ||
1074 | /*do memory clock*/ | |
1075 | dm_pp_get_clock_levels_by_type_with_latency( | |
1076 | dc->ctx, | |
1077 | DM_PP_CLOCK_TYPE_MEMORY_CLK, | |
1078 | &mem_clks); | |
1079 | ||
1080 | /* we don't need to call PPLIB for validation clock since they | |
1081 | * also give us the highest sclk and highest mclk (UMA clock). | |
1082 | * ALSO always convert UMA clock (from PPLIB) to YCLK (HW formula): | |
1083 | * YCLK = UMACLK*m_memoryTypeMultiplier | |
1084 | */ | |
1085 | dc->bw_vbios.low_yclk = bw_frc_to_fixed( | |
1086 | mem_clks.data[0].clocks_in_khz * MEMORY_TYPE_MULTIPLIER, 1000); | |
1087 | dc->bw_vbios.mid_yclk = bw_frc_to_fixed( | |
1088 | mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER, | |
1089 | 1000); | |
1090 | dc->bw_vbios.high_yclk = bw_frc_to_fixed( | |
1091 | mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * MEMORY_TYPE_MULTIPLIER, | |
1092 | 1000); | |
1093 | ||
1094 | /* Now notify PPLib/SMU about which Watermarks sets they should select | |
1095 | * depending on DPM state they are in. And update BW MGR GFX Engine and | |
1096 | * Memory clock member variables for Watermarks calculations for each | |
1097 | * Watermark Set | |
1098 | */ | |
1099 | clk_ranges.num_wm_sets = 4; | |
1100 | clk_ranges.wm_clk_ranges[0].wm_set_id = WM_SET_A; | |
1101 | clk_ranges.wm_clk_ranges[0].wm_min_eng_clk_in_khz = | |
1102 | eng_clks.data[0].clocks_in_khz; | |
1103 | clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = | |
1104 | eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; | |
1105 | clk_ranges.wm_clk_ranges[0].wm_min_memg_clk_in_khz = | |
1106 | mem_clks.data[0].clocks_in_khz; | |
1107 | clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = | |
1108 | mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; | |
1109 | ||
1110 | clk_ranges.wm_clk_ranges[1].wm_set_id = WM_SET_B; | |
1111 | clk_ranges.wm_clk_ranges[1].wm_min_eng_clk_in_khz = | |
1112 | eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; | |
1113 | /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ | |
1114 | clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; | |
1115 | clk_ranges.wm_clk_ranges[1].wm_min_memg_clk_in_khz = | |
1116 | mem_clks.data[0].clocks_in_khz; | |
1117 | clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = | |
1118 | mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; | |
1119 | ||
1120 | clk_ranges.wm_clk_ranges[2].wm_set_id = WM_SET_C; | |
1121 | clk_ranges.wm_clk_ranges[2].wm_min_eng_clk_in_khz = | |
1122 | eng_clks.data[0].clocks_in_khz; | |
1123 | clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = | |
1124 | eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; | |
1125 | clk_ranges.wm_clk_ranges[2].wm_min_memg_clk_in_khz = | |
1126 | mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; | |
1127 | /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ | |
1128 | clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; | |
1129 | ||
1130 | clk_ranges.wm_clk_ranges[3].wm_set_id = WM_SET_D; | |
1131 | clk_ranges.wm_clk_ranges[3].wm_min_eng_clk_in_khz = | |
1132 | eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; | |
1133 | /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ | |
1134 | clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; | |
1135 | clk_ranges.wm_clk_ranges[3].wm_min_memg_clk_in_khz = | |
1136 | mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; | |
1137 | /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ | |
1138 | clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; | |
1139 | ||
1140 | /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ | |
1141 | dm_pp_notify_wm_clock_changes(dc->ctx, &clk_ranges); | |
1142 | } | |
1143 | ||
1144 | const struct resource_caps *dce112_resource_cap( | |
1145 | struct hw_asic_id *asic_id) | |
1146 | { | |
b264d345 JL |
1147 | if (ASIC_REV_IS_POLARIS11_M(asic_id->hw_internal_rev) || |
1148 | ASIC_REV_IS_POLARIS12_V(asic_id->hw_internal_rev)) | |
4562236b HW |
1149 | return &polaris_11_resource_cap; |
1150 | else | |
1151 | return &polaris_10_resource_cap; | |
1152 | } | |
1153 | ||
1154 | static bool construct( | |
1155 | uint8_t num_virtual_links, | |
1156 | struct core_dc *dc, | |
1157 | struct dce110_resource_pool *pool) | |
1158 | { | |
1159 | unsigned int i; | |
1160 | struct dc_context *ctx = dc->ctx; | |
1161 | struct dm_pp_static_clock_info static_clk_info = {0}; | |
1162 | ||
1163 | ctx->dc_bios->regs = &bios_regs; | |
1164 | ||
1165 | pool->base.res_cap = dce112_resource_cap(&ctx->asic_id); | |
1166 | pool->base.funcs = &dce112_res_pool_funcs; | |
1167 | ||
1168 | /************************************************* | |
1169 | * Resource + asic cap harcoding * | |
1170 | *************************************************/ | |
f0e3db90 | 1171 | pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; |
4562236b HW |
1172 | pool->base.pipe_count = pool->base.res_cap->num_timing_generator; |
1173 | dc->public.caps.max_downscale_ratio = 200; | |
1174 | dc->public.caps.i2c_speed_in_khz = 100; | |
a37656b9 | 1175 | dc->public.caps.max_cursor_size = 128; |
4562236b HW |
1176 | |
1177 | /************************************************* | |
1178 | * Create resources * | |
1179 | *************************************************/ | |
1180 | ||
1181 | pool->base.clock_sources[DCE112_CLK_SRC_PLL0] = | |
1182 | dce112_clock_source_create( | |
1183 | ctx, ctx->dc_bios, | |
1184 | CLOCK_SOURCE_COMBO_PHY_PLL0, | |
1185 | &clk_src_regs[0], false); | |
1186 | pool->base.clock_sources[DCE112_CLK_SRC_PLL1] = | |
1187 | dce112_clock_source_create( | |
1188 | ctx, ctx->dc_bios, | |
1189 | CLOCK_SOURCE_COMBO_PHY_PLL1, | |
1190 | &clk_src_regs[1], false); | |
1191 | pool->base.clock_sources[DCE112_CLK_SRC_PLL2] = | |
1192 | dce112_clock_source_create( | |
1193 | ctx, ctx->dc_bios, | |
1194 | CLOCK_SOURCE_COMBO_PHY_PLL2, | |
1195 | &clk_src_regs[2], false); | |
1196 | pool->base.clock_sources[DCE112_CLK_SRC_PLL3] = | |
1197 | dce112_clock_source_create( | |
1198 | ctx, ctx->dc_bios, | |
1199 | CLOCK_SOURCE_COMBO_PHY_PLL3, | |
1200 | &clk_src_regs[3], false); | |
1201 | pool->base.clock_sources[DCE112_CLK_SRC_PLL4] = | |
1202 | dce112_clock_source_create( | |
1203 | ctx, ctx->dc_bios, | |
1204 | CLOCK_SOURCE_COMBO_PHY_PLL4, | |
1205 | &clk_src_regs[4], false); | |
1206 | pool->base.clock_sources[DCE112_CLK_SRC_PLL5] = | |
1207 | dce112_clock_source_create( | |
1208 | ctx, ctx->dc_bios, | |
1209 | CLOCK_SOURCE_COMBO_PHY_PLL5, | |
1210 | &clk_src_regs[5], false); | |
1211 | pool->base.clk_src_count = DCE112_CLK_SRC_TOTAL; | |
1212 | ||
1213 | pool->base.dp_clock_source = dce112_clock_source_create( | |
1214 | ctx, ctx->dc_bios, | |
1215 | CLOCK_SOURCE_ID_DP_DTO, &clk_src_regs[0], true); | |
1216 | ||
1217 | ||
1218 | for (i = 0; i < pool->base.clk_src_count; i++) { | |
1219 | if (pool->base.clock_sources[i] == NULL) { | |
1220 | dm_error("DC: failed to create clock sources!\n"); | |
1221 | BREAK_TO_DEBUGGER(); | |
1222 | goto res_create_fail; | |
1223 | } | |
1224 | } | |
1225 | ||
9a70eba7 DL |
1226 | pool->base.display_clock = dce112_disp_clk_create(ctx, |
1227 | &disp_clk_regs, | |
1228 | &disp_clk_shift, | |
1229 | &disp_clk_mask); | |
4562236b HW |
1230 | if (pool->base.display_clock == NULL) { |
1231 | dm_error("DC: failed to create display clock!\n"); | |
1232 | BREAK_TO_DEBUGGER(); | |
1233 | goto res_create_fail; | |
1234 | } | |
1235 | ||
5e7773a2 AK |
1236 | pool->base.dmcu = dce_dmcu_create(ctx, |
1237 | &dmcu_regs, | |
1238 | &dmcu_shift, | |
1239 | &dmcu_mask); | |
1240 | if (pool->base.dmcu == NULL) { | |
1241 | dm_error("DC: failed to create dmcu!\n"); | |
1242 | BREAK_TO_DEBUGGER(); | |
1243 | goto res_create_fail; | |
1244 | } | |
1245 | ||
1246 | pool->base.abm = dce_abm_create(ctx, | |
1247 | &abm_regs, | |
1248 | &abm_shift, | |
1249 | &abm_mask); | |
1250 | if (pool->base.abm == NULL) { | |
1251 | dm_error("DC: failed to create abm!\n"); | |
1252 | BREAK_TO_DEBUGGER(); | |
1253 | goto res_create_fail; | |
1254 | } | |
4562236b HW |
1255 | |
1256 | /* get static clock information for PPLIB or firmware, save | |
1257 | * max_clock_state | |
1258 | */ | |
3bad7c5c DL |
1259 | if (dm_pp_get_static_clocks(ctx, &static_clk_info)) |
1260 | pool->base.display_clock->max_clks_state = | |
e9c58bb4 | 1261 | static_clk_info.max_clocks_state; |
4562236b | 1262 | |
4562236b HW |
1263 | { |
1264 | struct irq_service_init_data init_data; | |
1265 | init_data.ctx = dc->ctx; | |
1266 | pool->base.irqs = dal_irq_service_dce110_create(&init_data); | |
1267 | if (!pool->base.irqs) | |
1268 | goto res_create_fail; | |
1269 | } | |
1270 | ||
1271 | for (i = 0; i < pool->base.pipe_count; i++) { | |
1272 | pool->base.timing_generators[i] = | |
1273 | dce112_timing_generator_create( | |
1274 | ctx, | |
1275 | i, | |
1276 | &dce112_tg_offsets[i]); | |
1277 | if (pool->base.timing_generators[i] == NULL) { | |
1278 | BREAK_TO_DEBUGGER(); | |
1279 | dm_error("DC: failed to create tg!\n"); | |
1280 | goto res_create_fail; | |
1281 | } | |
1282 | ||
c3489214 | 1283 | pool->base.mis[i] = dce112_mem_input_create(ctx, i); |
4562236b HW |
1284 | if (pool->base.mis[i] == NULL) { |
1285 | BREAK_TO_DEBUGGER(); | |
1286 | dm_error( | |
1287 | "DC: failed to create memory input!\n"); | |
1288 | goto res_create_fail; | |
1289 | } | |
1290 | ||
e6303950 | 1291 | pool->base.ipps[i] = dce112_ipp_create(ctx, i); |
4562236b HW |
1292 | if (pool->base.ipps[i] == NULL) { |
1293 | BREAK_TO_DEBUGGER(); | |
1294 | dm_error( | |
1295 | "DC:failed to create input pixel processor!\n"); | |
1296 | goto res_create_fail; | |
1297 | } | |
1298 | ||
1299 | pool->base.transforms[i] = dce112_transform_create(ctx, i); | |
1300 | if (pool->base.transforms[i] == NULL) { | |
1301 | BREAK_TO_DEBUGGER(); | |
1302 | dm_error( | |
1303 | "DC: failed to create transform!\n"); | |
1304 | goto res_create_fail; | |
1305 | } | |
1306 | ||
1307 | pool->base.opps[i] = dce112_opp_create( | |
1308 | ctx, | |
ab3ee7a5 | 1309 | i); |
4562236b HW |
1310 | if (pool->base.opps[i] == NULL) { |
1311 | BREAK_TO_DEBUGGER(); | |
1312 | dm_error( | |
1313 | "DC:failed to create output pixel processor!\n"); | |
1314 | goto res_create_fail; | |
1315 | } | |
1316 | } | |
1317 | ||
1318 | if (!resource_construct(num_virtual_links, dc, &pool->base, | |
1319 | &res_create_funcs)) | |
1320 | goto res_create_fail; | |
1321 | ||
d4e13b0d AD |
1322 | dc->public.caps.max_surfaces = pool->base.pipe_count; |
1323 | ||
4562236b HW |
1324 | /* Create hardware sequencer */ |
1325 | if (!dce112_hw_sequencer_construct(dc)) | |
1326 | goto res_create_fail; | |
1327 | ||
00c91d0d | 1328 | bw_calcs_init(&dc->bw_dceip, &dc->bw_vbios, dc->ctx->asic_id); |
4562236b HW |
1329 | |
1330 | bw_calcs_data_update_from_pplib(dc); | |
1331 | ||
1332 | return true; | |
1333 | ||
1334 | res_create_fail: | |
1335 | destruct(pool); | |
1336 | return false; | |
1337 | } | |
1338 | ||
1339 | struct resource_pool *dce112_create_resource_pool( | |
1340 | uint8_t num_virtual_links, | |
1341 | struct core_dc *dc) | |
1342 | { | |
1343 | struct dce110_resource_pool *pool = | |
1344 | dm_alloc(sizeof(struct dce110_resource_pool)); | |
1345 | ||
1346 | if (!pool) | |
1347 | return NULL; | |
1348 | ||
1349 | if (construct(num_virtual_links, dc, pool)) | |
1350 | return &pool->base; | |
1351 | ||
1352 | BREAK_TO_DEBUGGER(); | |
1353 | return NULL; | |
1354 | } |