2 * Copyright 2016 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include "dm_services.h"
29 #include "core_types.h"
30 #include "core_status.h"
32 #include "dcn10_hw_sequencer.h"
33 #include "dce110/dce110_hw_sequencer.h"
34 #include "dce/dce_hwseq.h"
37 #include "dcn10/dcn10_transform.h"
38 #include "dcn10/dcn10_mpc.h"
39 #include "dcn10/dcn10_timing_generator.h"
41 #include "mem_input.h"
42 #include "timing_generator.h"
46 #include "dc_bios_types.h"
48 #include "raven1/DCN/dcn_1_0_offset.h"
49 #include "raven1/DCN/dcn_1_0_sh_mask.h"
50 #include "vega10/soc15ip.h"
52 #include "custom_float.h"
55 struct dcn10_hwseq_reg_offsets
{
63 /* TODO: move to resource */
64 static const struct dcn10_hwseq_reg_offsets reg_offsets
[] = {
66 .dchubp
= (mmHUBP0_DCHUBP_CNTL
- mmHUBP0_DCHUBP_CNTL
),
67 .dpp
= (mmCM0_CM_DGAM_CONTROL
- mmCM0_CM_DGAM_CONTROL
),
68 .otg
= (mmOTG0_OTG_CONTROL
- mmOTG0_OTG_CONTROL
),
69 .vtg
= (mmVTG0_CONTROL
- mmVTG0_CONTROL
),
70 .fmt
= (mmFMT0_FMT_BIT_DEPTH_CONTROL
-
71 mmFMT0_FMT_BIT_DEPTH_CONTROL
),
74 .dchubp
= (mmHUBP1_DCHUBP_CNTL
- mmHUBP0_DCHUBP_CNTL
),
75 .dpp
= (mmCM1_CM_DGAM_CONTROL
- mmCM0_CM_DGAM_CONTROL
),
76 .otg
= (mmOTG1_OTG_CONTROL
- mmOTG0_OTG_CONTROL
),
77 .vtg
= (mmVTG1_CONTROL
- mmVTG0_CONTROL
),
78 .fmt
= (mmFMT1_FMT_BIT_DEPTH_CONTROL
-
79 mmFMT0_FMT_BIT_DEPTH_CONTROL
),
82 .dchubp
= (mmHUBP2_DCHUBP_CNTL
- mmHUBP0_DCHUBP_CNTL
),
83 .dpp
= (mmCM2_CM_DGAM_CONTROL
- mmCM0_CM_DGAM_CONTROL
),
84 .otg
= (mmOTG2_OTG_CONTROL
- mmOTG0_OTG_CONTROL
),
85 .vtg
= (mmVTG2_CONTROL
- mmVTG0_CONTROL
),
86 .fmt
= (mmFMT2_FMT_BIT_DEPTH_CONTROL
-
87 mmFMT0_FMT_BIT_DEPTH_CONTROL
),
90 .dchubp
= (mmHUBP3_DCHUBP_CNTL
- mmHUBP0_DCHUBP_CNTL
),
91 .dpp
= (mmCM3_CM_DGAM_CONTROL
- mmCM0_CM_DGAM_CONTROL
),
92 .otg
= (mmOTG3_OTG_CONTROL
- mmOTG0_OTG_CONTROL
),
93 .vtg
= (mmVTG3_CONTROL
- mmVTG0_CONTROL
),
94 .fmt
= (mmFMT3_FMT_BIT_DEPTH_CONTROL
-
95 mmFMT0_FMT_BIT_DEPTH_CONTROL
),
99 #define HWSEQ_REG_UPDATE_N(reg_name, n, ...) \
100 generic_reg_update_soc15(ctx, inst_offset, reg_name, n, __VA_ARGS__)
102 #define HWSEQ_REG_SET_N(reg_name, n, ...) \
103 generic_reg_set_soc15(ctx, inst_offset, reg_name, n, __VA_ARGS__)
105 #define HWSEQ_REG_UPDATE(reg, field, val) \
106 HWSEQ_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
108 #define HWSEQ_REG_UPDATE_2(reg, field1, val1, field2, val2) \
109 HWSEQ_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
111 #define HWSEQ_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3) \
112 HWSEQ_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
115 #define HWSEQ_REG_SET(reg, field, val) \
116 HWSEQ_REG_SET_N(reg, 1, FD(reg##__##field), val)
118 /* TODO should be moved to OTG */
119 static void lock_otg_master_update(
120 struct dc_context
*ctx
,
123 uint32_t inst_offset
= reg_offsets
[inst
].otg
;
125 HWSEQ_REG_UPDATE(OTG0_OTG_GLOBAL_CONTROL0
,
126 OTG_MASTER_UPDATE_LOCK_SEL
, inst
);
128 /* unlock master locker */
129 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK
,
130 OTG_MASTER_UPDATE_LOCK
, 1);
132 /* wait for unlock happens */
133 if (!wait_reg(ctx
, inst_offset
, OTG0_OTG_MASTER_UPDATE_LOCK
, UPDATE_LOCK_STATUS
, 1))
138 static bool unlock_master_tg_and_wait(
139 struct dc_context
*ctx
,
142 uint32_t inst_offset
= reg_offsets
[inst
].otg
;
144 HWSEQ_REG_UPDATE(OTG0_OTG_GLOBAL_SYNC_STATUS
,
145 VUPDATE_NO_LOCK_EVENT_CLEAR
, 1);
146 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK
, OTG_MASTER_UPDATE_LOCK
, 0);
148 if (!wait_reg(ctx
, inst_offset
, OTG0_OTG_GLOBAL_SYNC_STATUS
, VUPDATE_NO_LOCK_EVENT_OCCURRED
, 1)) {
149 dm_logger_write(ctx
->logger
, LOG_ERROR
,
150 "wait for VUPDATE_NO_LOCK_EVENT_OCCURRED failed\n");
157 /* TODO: should be moved to OTG ? */
158 static void unlock_otg_master(
159 struct dc_context
*ctx
,
162 uint32_t inst_offset
= reg_offsets
[inst
].otg
;
164 /* unlock master locker */
165 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK
,
166 OTG_MASTER_UPDATE_LOCK
, 0);
170 static void wait_no_outstanding_request(
171 struct dc_context
*ctx
,
174 uint32_t inst_offset
= reg_offsets
[plane_id
].dchubp
;
176 if (!wait_reg(ctx
, inst_offset
, HUBP0_DCHUBP_CNTL
, HUBP_NO_OUTSTANDING_REQ
, 1))
180 static void disable_clocks(
181 struct dc_context
*ctx
,
184 uint32_t inst_offset
= reg_offsets
[plane_id
].dchubp
;
186 generic_reg_update_soc15(ctx
, inst_offset
, HUBP0_HUBP_CLK_CNTL
, 1,
187 FD(HUBP0_HUBP_CLK_CNTL__HUBP_CLOCK_ENABLE
), 0);
189 inst_offset
= reg_offsets
[plane_id
].dpp
;
190 generic_reg_update_soc15(ctx
, inst_offset
, DPP_TOP0_DPP_CONTROL
, 1,
191 FD(DPP_TOP0_DPP_CONTROL__DPP_CLOCK_ENABLE
), 0);
194 /* TODO: This is one time program during system boot up,
195 * this should be done within BIOS or CAIL
197 static void dchubp_map_fb_to_mc(struct dc_context
*ctx
)
199 /* TODO: do not know where to program
200 * DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
203 * TODO: For real ASIC, FB_OFFSET may be need change to the same value
204 * as FB_BASE. Need re-visit this for real ASIC.
206 dm_write_reg_soc15(ctx
, mmDCHUBBUB_SDPIF_FB_BASE
, 0, 0x80);
207 dm_write_reg_soc15(ctx
, mmDCHUBBUB_SDPIF_FB_OFFSET
, 0, 0);
208 dm_write_reg_soc15(ctx
, mmDCHUBBUB_SDPIF_FB_TOP
, 0, 0xFF);
210 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_CFG0
, 7,
211 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_DATA_RESPONSE_STATUS_CLEAR
), 0,
212 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_REQ_CREDIT_ERROR_CLEAR
), 0,
213 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_FLUSH_REQ_CREDIT_EN
), 0,
214 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_REQ_CREDIT_EN
), 0,
215 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_PORT_CONTROL
), 1,
216 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_UNIT_ID_BITMASK
), 0xd3,
217 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_CREDIT_DISCONNECT_DELAY
), 0xc);
220 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_CFG1
, 4,
221 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_INSIDE_FB_IO
), 0,
222 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_INSIDE_FB_VC
), 6,
223 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_OUTSIDE_FB_IO
), 1,
224 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_OUTSIDE_FB_VC
), 6);
226 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_FB_BASE
, 1,
227 FD(DCHUBBUB_SDPIF_FB_BASE__SDPIF_FB_BASE
), 0x000080);
229 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_FB_TOP
, 1,
230 FD(DCHUBBUB_SDPIF_FB_TOP__SDPIF_FB_TOP
), 0x0000ff);
232 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_AGP_BOT
, 1,
233 FD(DCHUBBUB_SDPIF_AGP_BOT__SDPIF_AGP_BOT
), 0x0000040);
235 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_AGP_TOP
, 1,
236 FD(DCHUBBUB_SDPIF_AGP_TOP__SDPIF_AGP_TOP
), 0x00001ff);
238 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_AGP_BASE
, 1,
239 FD(DCHUBBUB_SDPIF_AGP_BASE__SDPIF_AGP_BASE
), 0x0000080);
241 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_APER_TOP
, 1,
242 FD(DCHUBBUB_SDPIF_APER_TOP__SDPIF_APER_TOP
), 0x00007ff);
244 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_APER_DEF_0
, 1,
245 FD(DCHUBBUB_SDPIF_APER_DEF_0__SDPIF_APER_DEF_0
), 0xdeadbeef);
247 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_0
, 2,
248 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_0__SDPIF_MARC_EN_0
), 0,
249 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_0__SDPIF_MARC_RELOC_LO_0
), 0x90000);
251 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_0
, 1,
252 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_0__SDPIF_MARC_LENGTH_LO_0
), 0x10000);
254 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_1
, 1,
255 FD(DCHUBBUB_SDPIF_MARC_BASE_LO_1__SDPIF_MARC_BASE_LO_1
), 0x10000);
257 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_1
, 2,
258 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_1__SDPIF_MARC_EN_1
), 0,
259 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_1__SDPIF_MARC_RELOC_LO_1
), 0xa0000);
261 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_1
, 1,
262 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_1__SDPIF_MARC_LENGTH_LO_1
), 0x10000);
264 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_2
, 1,
265 FD(DCHUBBUB_SDPIF_MARC_BASE_LO_2__SDPIF_MARC_BASE_LO_2
), 0x20000);
267 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_2
, 2,
268 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_2__SDPIF_MARC_EN_2
), 0,
269 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_2__SDPIF_MARC_RELOC_LO_2
), 0xb0000);
271 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_2
, 1,
272 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_2__SDPIF_MARC_LENGTH_LO_2
), 0x10000);
274 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_3
, 1,
275 FD(DCHUBBUB_SDPIF_MARC_BASE_LO_3__SDPIF_MARC_BASE_LO_3
), 0x30000);
277 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_3
, 2,
278 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_3__SDPIF_MARC_EN_3
), 0,
279 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_3__SDPIF_MARC_RELOC_LO_3
), 0xc0000);
281 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_3
, 1,
282 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_3__SDPIF_MARC_LENGTH_LO_3
), 0x10000);
284 /* TODO: Is DCN_VM_SYSTEM_APERTURE address one time programming?
285 * Are all 4 hubp programmed with the same address?
287 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
, 0, 0x80000);
288 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB
, 0, 0);
289 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB
, 0, 0x100000);
290 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB
, 0, 0);
291 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB
, 0, 0x80000);
292 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB
, 0, 0);
294 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
, 0, 0x80000);
295 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB
, 0, 0);
296 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB
, 0, 0x100000);
297 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB
, 0, 0);
298 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB
, 0, 0x80000);
299 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB
, 0, 0);
301 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
, 0, 0x80000);
302 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB
, 0, 0);
303 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB
, 0, 0x100000);
304 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB
, 0, 0);
305 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB
, 0, 0x80000);
306 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB
, 0, 0);
308 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
, 0, 0x80000);
309 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB
, 0, 0);
310 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB
, 0, 0x100000);
311 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB
, 0, 0);
312 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB
, 0, 0x80000);
313 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB
, 0, 0);
316 /* TODO: This is one time program during system boot up,
317 * this should be done within BIOS
319 static void dchubup_setup_timer(struct dc_context
*ctx
)
321 dm_write_reg_soc15(ctx
, mmREFCLK_CNTL
, 0, 0);
323 generic_reg_update_soc15(ctx
, 0, DCHUBBUB_GLOBAL_TIMER_CNTL
, 1,
324 FD(DCHUBBUB_GLOBAL_TIMER_CNTL__DCHUBBUB_GLOBAL_TIMER_ENABLE
), 1);
327 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
328 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
329 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
331 static void select_vtg(
332 struct dc_context
*ctx
,
336 uint32_t inst_offset
= reg_offsets
[plane_id
].dchubp
;
338 HWSEQ_REG_UPDATE(HUBP0_DCHUBP_CNTL
, HUBP_VTG_SEL
, inst
);
341 static void enable_dcfclk(
342 struct dc_context
*ctx
,
344 uint32_t requested_pix_clk
,
347 uint32_t inst_offset
= reg_offsets
[plane_id
].dchubp
;
349 HWSEQ_REG_UPDATE(HUBP0_HUBP_CLK_CNTL
, HUBP_CLOCK_ENABLE
, 1);
352 static void enable_dppclk(
353 struct dc_context
*ctx
,
355 uint32_t requested_pix_clk
,
358 uint32_t inst_offset
= reg_offsets
[plane_id
].dpp
;
360 dm_logger_write(ctx
->logger
, LOG_SURFACE
,
361 "dppclk_rate_control for pipe %d programed to %d\n",
365 /* TODO: find condition for DPP clock to DISPCLK or 1/2 DISPCLK */
368 HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL
,
369 DPPCLK_RATE_CONTROL
, 1,
370 DPP_CLOCK_ENABLE
, 1);
373 HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL
,
374 DPPCLK_RATE_CONTROL
, 0,
375 DPP_CLOCK_ENABLE
, 1);
379 static void enable_power_gating_plane(
380 struct dc_context
*ctx
,
383 uint32_t inst_offset
= 0; /* each register only has one instance */
384 bool force_on
= 1; /* disable power gating */
390 HWSEQ_REG_UPDATE(DOMAIN0_PG_CONFIG
, DOMAIN0_POWER_FORCEON
, force_on
);
391 HWSEQ_REG_UPDATE(DOMAIN2_PG_CONFIG
, DOMAIN2_POWER_FORCEON
, force_on
);
392 HWSEQ_REG_UPDATE(DOMAIN4_PG_CONFIG
, DOMAIN4_POWER_FORCEON
, force_on
);
393 HWSEQ_REG_UPDATE(DOMAIN6_PG_CONFIG
, DOMAIN6_POWER_FORCEON
, force_on
);
396 HWSEQ_REG_UPDATE(DOMAIN1_PG_CONFIG
, DOMAIN1_POWER_FORCEON
, force_on
);
397 HWSEQ_REG_UPDATE(DOMAIN3_PG_CONFIG
, DOMAIN3_POWER_FORCEON
, force_on
);
398 HWSEQ_REG_UPDATE(DOMAIN5_PG_CONFIG
, DOMAIN5_POWER_FORCEON
, force_on
);
399 HWSEQ_REG_UPDATE(DOMAIN7_PG_CONFIG
, DOMAIN7_POWER_FORCEON
, force_on
);
401 if (ctx
->dc
->debug
.disable_clock_gate
) {
402 /* probably better to just write entire register to 0xffff to
403 * ensure all clock gating is disabled
405 HWSEQ_REG_UPDATE_3(DCCG_GATE_DISABLE_CNTL
,
406 DISPCLK_R_DCCG_GATE_DISABLE
, 1,
407 DPREFCLK_R_DCCG_GATE_DISABLE
, 1,
408 REFCLK_R_DIG_GATE_DISABLE
, 1);
409 HWSEQ_REG_UPDATE(DCFCLK_CNTL
,
415 static void dpp_pg_control(
416 struct dc_context
*ctx
,
417 unsigned int dpp_inst
,
420 uint32_t inst_offset
= 0;
421 uint32_t power_gate
= power_on
? 0 : 1;
422 uint32_t pwr_status
= power_on
? 0 : 2;
424 if (ctx
->dc
->debug
.disable_dpp_power_gate
)
429 HWSEQ_REG_UPDATE(DOMAIN1_PG_CONFIG
,
430 DOMAIN1_POWER_GATE
, power_gate
);
432 wait_reg(ctx
, 0, DOMAIN1_PG_STATUS
,
433 DOMAIN1_PGFSM_PWR_STATUS
, pwr_status
);
436 HWSEQ_REG_UPDATE(DOMAIN3_PG_CONFIG
,
437 DOMAIN3_POWER_GATE
, power_gate
);
439 wait_reg(ctx
, 0, DOMAIN3_PG_STATUS
,
440 DOMAIN3_PGFSM_PWR_STATUS
, pwr_status
);
443 HWSEQ_REG_UPDATE(DOMAIN5_PG_CONFIG
,
444 DOMAIN5_POWER_GATE
, power_gate
);
446 wait_reg(ctx
, 0, DOMAIN5_PG_STATUS
,
447 DOMAIN5_PGFSM_PWR_STATUS
, pwr_status
);
450 HWSEQ_REG_UPDATE(DOMAIN7_PG_CONFIG
,
451 DOMAIN7_POWER_GATE
, power_gate
);
453 wait_reg(ctx
, 0, DOMAIN7_PG_STATUS
,
454 DOMAIN7_PGFSM_PWR_STATUS
, pwr_status
);
462 static void hubp_pg_control(
463 struct dc_context
*ctx
,
464 unsigned int hubp_inst
,
467 uint32_t inst_offset
= 0;
468 uint32_t power_gate
= power_on
? 0 : 1;
469 uint32_t pwr_status
= power_on
? 0 : 2;
471 if (ctx
->dc
->debug
.disable_hubp_power_gate
)
475 case 0: /* DCHUBP0 */
476 HWSEQ_REG_UPDATE(DOMAIN0_PG_CONFIG
,
477 DOMAIN0_POWER_GATE
, power_gate
);
479 wait_reg(ctx
, 0, DOMAIN0_PG_STATUS
,
480 DOMAIN0_PGFSM_PWR_STATUS
, pwr_status
);
482 case 1: /* DCHUBP1 */
483 HWSEQ_REG_UPDATE(DOMAIN2_PG_CONFIG
,
484 DOMAIN2_POWER_GATE
, power_gate
);
486 wait_reg(ctx
, 0, DOMAIN2_PG_STATUS
,
487 DOMAIN2_PGFSM_PWR_STATUS
, pwr_status
);
489 case 2: /* DCHUBP2 */
490 HWSEQ_REG_UPDATE(DOMAIN4_PG_CONFIG
,
491 DOMAIN4_POWER_GATE
, power_gate
);
493 wait_reg(ctx
, 0, DOMAIN4_PG_STATUS
,
494 DOMAIN4_PGFSM_PWR_STATUS
, pwr_status
);
496 case 3: /* DCHUBP3 */
497 HWSEQ_REG_UPDATE(DOMAIN6_PG_CONFIG
,
498 DOMAIN6_POWER_GATE
, power_gate
);
500 wait_reg(ctx
, 0, DOMAIN6_PG_STATUS
,
501 DOMAIN6_PGFSM_PWR_STATUS
, pwr_status
);
509 static void power_on_plane(
510 struct dc_context
*ctx
,
514 uint32_t inst_offset
= 0;
516 /* disable clock power gating */
518 /* DCCG_GATE_DISABLE_CNTL only has one instance */
519 if (ctx
->dc
->debug
.disable_clock_gate
) {
520 HWSEQ_REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL
,
521 DISPCLK_DCCG_GATE_DISABLE
, 1,
522 DPPCLK_GATE_DISABLE
, 1);
523 /* DCFCLK_CNTL only has one instance */
524 HWSEQ_REG_UPDATE(DCFCLK_CNTL
,
528 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL
,
530 dpp_pg_control(ctx
, plane_id
, true);
531 hubp_pg_control(ctx
, plane_id
, true);
532 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL
,
535 if (ctx
->dc
->debug
.disable_clock_gate
) {
536 HWSEQ_REG_UPDATE(DCCG_GATE_DISABLE_CNTL
,
537 DISPCLK_DCCG_GATE_DISABLE
, 0);
541 /* fully check bios enabledisplaypowergating table. dal only need dce init
542 * other power, clock gate register will be handle by dal itself.
543 * further may be put within init_hw
545 static bool dcn10_enable_display_power_gating(
547 uint8_t controller_id
,
549 enum pipe_gating_control power_gating
)
553 if (power_gating
!= PIPE_GATING_CONTROL_ENABLE
)
554 dce110_init_pte(ctx
);
560 static void bios_golden_init(struct core_dc
*dc
)
562 struct dc_bios
*bp
= dc
->ctx
->dc_bios
;
565 /* initialize dcn global */
566 bp
->funcs
->enable_disp_power_gating(bp
,
567 CONTROLLER_ID_D0
, ASIC_PIPE_INIT
);
569 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
570 /* initialize dcn per pipe */
571 bp
->funcs
->enable_disp_power_gating(bp
,
572 CONTROLLER_ID_D0
+ i
, ASIC_PIPE_DISABLE
);
576 static void init_hw(struct core_dc
*dc
)
580 struct transform
*xfm
;
583 bp
= dc
->ctx
->dc_bios
;
585 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
)) {
586 /* TODO: this will be moved to Diag or BIOS */
587 dchubup_setup_timer(dc
->ctx
);
589 /* TODO: dchubp_map_fb_to_mc will be moved to dchub interface
592 dchubp_map_fb_to_mc(dc
->ctx
);
594 enable_power_gating_plane(dc
->ctx
, true);
597 /* end of FPGA. Below if real ASIC */
599 bios_golden_init(dc
);
601 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
602 xfm
= dc
->res_pool
->transforms
[i
];
603 xfm
->funcs
->transform_reset(xfm
);
605 /* TODOFPGA: may need later */
607 xfm
->funcs
->transform_power_up(xfm
);
608 dc
->hwss
.enable_display_pipe_clock_gating(
613 /* TODOFPGA: light sleep */
615 dc
->hwss
.clock_gating_power_up(dc
->ctx
, false);
618 for (i
= 0; i
< dc
->link_count
; i
++) {
619 /* Power up AND update implementation according to the
620 * required signal (which may be different from the
621 * default signal on connector).
623 struct core_link
*link
= dc
->links
[i
];
625 link
->link_enc
->funcs
->hw_init(link
->link_enc
);
628 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
629 struct timing_generator
*tg
=
630 dc
->res_pool
->timing_generators
[i
];
632 tg
->funcs
->disable_vga(tg
);
634 /* Blank controller using driver code instead of
637 tg
->funcs
->set_blank(tg
, true);
638 hwss_wait_for_blank_complete(tg
);
641 for (i
= 0; i
< dc
->res_pool
->audio_count
; i
++) {
642 struct audio
*audio
= dc
->res_pool
->audios
[i
];
644 audio
->funcs
->hw_init(audio
);
647 abm
= dc
->res_pool
->abm
;
649 abm
->funcs
->init_backlight(abm
);
650 abm
->funcs
->abm_init(abm
);
653 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
654 generic_reg_set_soc15(dc
->ctx
, 0, DIO_MEM_PWR_CTRL
, 7,
655 FD(DIO_MEM_PWR_CTRL__HDMI0_MEM_PWR_FORCE
), 0,
656 FD(DIO_MEM_PWR_CTRL__HDMI1_MEM_PWR_FORCE
), 0,
657 FD(DIO_MEM_PWR_CTRL__HDMI2_MEM_PWR_FORCE
), 0,
658 FD(DIO_MEM_PWR_CTRL__HDMI3_MEM_PWR_FORCE
), 0,
659 FD(DIO_MEM_PWR_CTRL__HDMI4_MEM_PWR_FORCE
), 0,
660 FD(DIO_MEM_PWR_CTRL__HDMI5_MEM_PWR_FORCE
), 0,
661 FD(DIO_MEM_PWR_CTRL__HDMI6_MEM_PWR_FORCE
), 0);
663 if (!dc
->public.debug
.disable_clock_gate
) {
664 /* enable all DCN clock gating */
665 generic_reg_set_soc15(dc
->ctx
, 0, DCCG_GATE_DISABLE_CNTL
, 19,
666 FD(DCCG_GATE_DISABLE_CNTL__DISPCLK_DCCG_GATE_DISABLE
), 0,
667 FD(DCCG_GATE_DISABLE_CNTL__DISPCLK_R_DCCG_GATE_DISABLE
), 0,
668 FD(DCCG_GATE_DISABLE_CNTL__SOCCLK_GATE_DISABLE
), 0,
669 FD(DCCG_GATE_DISABLE_CNTL__DPREFCLK_GATE_DISABLE
), 0,
670 FD(DCCG_GATE_DISABLE_CNTL__DACACLK_GATE_DISABLE
), 0,
671 FD(DCCG_GATE_DISABLE_CNTL__DVOACLK_GATE_DISABLE
), 0,
672 FD(DCCG_GATE_DISABLE_CNTL__DPREFCLK_R_DCCG_GATE_DISABLE
), 0,
673 FD(DCCG_GATE_DISABLE_CNTL__DPPCLK_GATE_DISABLE
), 0,
674 FD(DCCG_GATE_DISABLE_CNTL__AOMCLK0_GATE_DISABLE
), 0,
675 FD(DCCG_GATE_DISABLE_CNTL__AOMCLK1_GATE_DISABLE
), 0,
676 FD(DCCG_GATE_DISABLE_CNTL__AOMCLK2_GATE_DISABLE
), 0,
677 FD(DCCG_GATE_DISABLE_CNTL__AUDIO_DTO2_CLK_GATE_DISABLE
), 0,
678 FD(DCCG_GATE_DISABLE_CNTL__DPREFCLK_GTC_GATE_DISABLE
), 0,
679 FD(DCCG_GATE_DISABLE_CNTL__UNB_DB_CLK_GATE_DISABLE
), 0,
680 FD(DCCG_GATE_DISABLE_CNTL__REFCLK_GATE_DISABLE
), 0,
681 FD(DCCG_GATE_DISABLE_CNTL__REFCLK_R_DIG_GATE_DISABLE
), 0,
682 FD(DCCG_GATE_DISABLE_CNTL__DSICLK_GATE_DISABLE
), 0,
683 FD(DCCG_GATE_DISABLE_CNTL__BYTECLK_GATE_DISABLE
), 0,
684 FD(DCCG_GATE_DISABLE_CNTL__ESCCLK_GATE_DISABLE
), 0);
686 generic_reg_set_soc15(dc
->ctx
, 0, DCCG_GATE_DISABLE_CNTL2
, 14,
687 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKA_FE_GATE_DISABLE
), 0,
688 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKB_FE_GATE_DISABLE
), 0,
689 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKC_FE_GATE_DISABLE
), 0,
690 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKD_FE_GATE_DISABLE
), 0,
691 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKE_FE_GATE_DISABLE
), 0,
692 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKF_FE_GATE_DISABLE
), 0,
693 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKG_FE_GATE_DISABLE
), 0,
694 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKA_GATE_DISABLE
), 0,
695 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKB_GATE_DISABLE
), 0,
696 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKC_GATE_DISABLE
), 0,
697 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKD_GATE_DISABLE
), 0,
698 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKE_GATE_DISABLE
), 0,
699 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKF_GATE_DISABLE
), 0,
700 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKG_GATE_DISABLE
), 0);
702 generic_reg_update_soc15(dc
->ctx
, 0, DCFCLK_CNTL
, 1,
703 FD(DCFCLK_CNTL__DCFCLK_GATE_DIS
), 0);
706 /* This power gating should be one-time program for DAL.
707 * It can only change by registry key
708 * TODO: new task will for this.
709 * if power gating is disable, power_on_plane and power_off_plane
710 * should be skip. Otherwise, hand will be met in power_off_plane
712 enable_power_gating_plane(dc
->ctx
, true);
717 static enum dc_status
dcn10_prog_pixclk_crtc_otg(
718 struct pipe_ctx
*pipe_ctx
,
719 struct validate_context
*context
,
722 struct core_stream
*stream
= pipe_ctx
->stream
;
723 enum dc_color_space color_space
;
724 struct tg_color black_color
= {0};
725 bool enableStereo
= stream
->public.timing
.timing_3d_format
== TIMING_3D_FORMAT_NONE
?
727 bool rightEyePolarity
= stream
->public.timing
.flags
.RIGHT_EYE_3D_POLARITY
;
730 /* by upper caller loop, pipe0 is parent pipe and be called first.
731 * back end is set up by for pipe0. Other children pipe share back end
732 * with pipe 0. No program is needed.
734 if (pipe_ctx
->top_pipe
!= NULL
)
737 /* TODO check if timing_changed, disable stream if timing changed */
739 /* HW program guide assume display already disable
740 * by unplug sequence. OTG assume stop.
742 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, true);
744 if (false == pipe_ctx
->clock_source
->funcs
->program_pix_clk(
745 pipe_ctx
->clock_source
,
746 &pipe_ctx
->pix_clk_params
,
747 &pipe_ctx
->pll_settings
)) {
749 return DC_ERROR_UNEXPECTED
;
751 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
752 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
753 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
754 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
756 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
758 pipe_ctx
->tg
->funcs
->program_timing(
760 &stream
->public.timing
,
763 pipe_ctx
->opp
->funcs
->opp_set_stereo_polarity(
768 #if 0 /* move to after enable_crtc */
769 /* TODO: OPP FMT, ABM. etc. should be done here. */
770 /* or FPGA now. instance 0 only. TODO: move to opp.c */
772 inst_offset
= reg_offsets
[pipe_ctx
->tg
->inst
].fmt
;
774 pipe_ctx
->opp
->funcs
->opp_program_fmt(
776 &stream
->bit_depth_params
,
779 /* program otg blank color */
780 color_space
= stream
->public.output_color_space
;
781 color_space_to_black_color(dc
, color_space
, &black_color
);
782 pipe_ctx
->tg
->funcs
->set_blank_color(
786 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, true);
787 hwss_wait_for_blank_complete(pipe_ctx
->tg
);
789 /* VTG is within DCHUB command block. DCFCLK is always on */
790 if (false == pipe_ctx
->tg
->funcs
->enable_crtc(pipe_ctx
->tg
)) {
792 return DC_ERROR_UNEXPECTED
;
795 /* TODO program crtc source select for non-virtual signal*/
796 /* TODO program FMT */
797 /* TODO setup link_enc */
798 /* TODO set stream attributes */
799 /* TODO program audio */
800 /* TODO enable stream if timing changed */
801 /* TODO unblank stream if DP */
806 static void reset_back_end_for_pipe(
808 struct pipe_ctx
*pipe_ctx
,
809 struct validate_context
*context
)
814 bp
= dc
->ctx
->dc_bios
;
816 if (pipe_ctx
->stream_enc
== NULL
) {
817 pipe_ctx
->stream
= NULL
;
821 /* TODOFPGA break core_link_disable_stream into 2 functions:
822 * disable_stream and disable_link. disable_link will disable PHYPLL
823 * which is used by otg. Move disable_link after disable_crtc
825 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
826 core_link_disable_stream(pipe_ctx
);
828 /* by upper caller loop, parent pipe: pipe0, will be reset last.
829 * back end share by all pipes and will be disable only when disable
832 if (pipe_ctx
->top_pipe
== NULL
) {
833 pipe_ctx
->tg
->funcs
->disable_crtc(pipe_ctx
->tg
);
835 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, false);
838 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
839 resource_unreference_clock_source(
840 &context
->res_ctx
, dc
->res_pool
,
841 &pipe_ctx
->clock_source
);
843 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
844 if (&dc
->current_context
->res_ctx
.pipe_ctx
[i
] == pipe_ctx
)
847 if (i
== dc
->res_pool
->pipe_count
)
850 pipe_ctx
->stream
= NULL
;
853 static void reset_front_end_for_pipe(
855 struct pipe_ctx
*pipe_ctx
,
856 struct validate_context
*context
)
858 struct dcn10_mpc
*mpc
= TO_DCN10_MPC(dc
->res_pool
->mpc
);
859 struct mpc_tree_cfg
*tree_cfg
= NULL
;
861 if (!pipe_ctx
->surface
)
864 lock_otg_master_update(dc
->ctx
, pipe_ctx
->tg
->inst
);
866 /* TODO: build stream pipes group id. For now, use stream otg
867 * id as pipe group id
869 tree_cfg
= &dc
->current_context
->res_ctx
.mpc_tree
[pipe_ctx
->mpc_idx
];
871 if (pipe_ctx
->top_pipe
== NULL
)
872 dcn10_delete_mpc_tree(mpc
, tree_cfg
);
874 if (dcn10_remove_dpp(mpc
, tree_cfg
, pipe_ctx
->pipe_idx
))
875 pipe_ctx
->top_pipe
->bottom_pipe
= NULL
;
877 dm_logger_write(dc
->ctx
->logger
, LOG_RESOURCE
,
878 "%s: failed to find dpp to be removed!\n",
883 pipe_ctx
->top_pipe
= NULL
;
884 pipe_ctx
->bottom_pipe
= NULL
;
885 pipe_ctx
->mpc_idx
= -1;
887 unlock_master_tg_and_wait(dc
->ctx
, pipe_ctx
->tg
->inst
);
889 pipe_ctx
->mi
->funcs
->set_blank(pipe_ctx
->mi
, true);
891 wait_no_outstanding_request(dc
->ctx
, pipe_ctx
->pipe_idx
);
893 wait_mpcc_idle(mpc
, pipe_ctx
->pipe_idx
);
895 disable_clocks(dc
->ctx
, pipe_ctx
->pipe_idx
);
897 pipe_ctx
->xfm
->funcs
->transform_reset(pipe_ctx
->xfm
);
899 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
900 "Reset front end for pipe %d\n",
903 pipe_ctx
->surface
= NULL
;
906 static void reset_hw_ctx(struct core_dc
*dc
,
907 struct validate_context
*context
,
908 void (*reset
)(struct core_dc
*dc
,
909 struct pipe_ctx
*pipe_ctx
,
910 struct validate_context
*context
))
914 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
915 struct pipe_ctx
*pipe_ctx_old
=
916 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
917 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
919 if (!pipe_ctx_old
->stream
)
922 if (!pipe_ctx
->stream
||
923 pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
))
924 reset(dc
, pipe_ctx_old
, dc
->current_context
);
928 static void reset_hw_ctx_wrap(
930 struct validate_context
*context
)
933 reset_hw_ctx(dc
, context
, reset_front_end_for_pipe
);
935 reset_hw_ctx(dc
, context
, reset_back_end_for_pipe
);
937 memcpy(context
->res_ctx
.mpc_tree
,
938 dc
->current_context
->res_ctx
.mpc_tree
,
939 sizeof(struct mpc_tree_cfg
) * dc
->res_pool
->pipe_count
);
942 static bool patch_address_for_sbs_tb_stereo(struct pipe_ctx
*pipe_ctx
,
943 PHYSICAL_ADDRESS_LOC
*addr
)
945 struct core_surface
*surface
= pipe_ctx
->surface
;
946 bool sec_split
= pipe_ctx
->top_pipe
&&
947 pipe_ctx
->top_pipe
->surface
== pipe_ctx
->surface
;
948 if (sec_split
&& surface
->public.address
.type
== PLN_ADDR_TYPE_GRPH_STEREO
&&
949 (pipe_ctx
->stream
->public.timing
.timing_3d_format
==
950 TIMING_3D_FORMAT_SIDE_BY_SIDE
||
951 pipe_ctx
->stream
->public.timing
.timing_3d_format
==
952 TIMING_3D_FORMAT_TOP_AND_BOTTOM
)) {
953 *addr
= surface
->public.address
.grph_stereo
.left_addr
;
954 surface
->public.address
.grph_stereo
.left_addr
=\
955 surface
->public.address
.grph_stereo
.right_addr
;
961 static void update_plane_addr(const struct core_dc
*dc
, struct pipe_ctx
*pipe_ctx
)
963 bool addr_patched
= false;
964 PHYSICAL_ADDRESS_LOC addr
;
965 struct core_surface
*surface
= pipe_ctx
->surface
;
969 addr_patched
= patch_address_for_sbs_tb_stereo(pipe_ctx
, &addr
);
970 pipe_ctx
->mi
->funcs
->mem_input_program_surface_flip_and_addr(
972 &surface
->public.address
,
973 surface
->public.flip_immediate
);
974 surface
->status
.requested_address
= surface
->public.address
;
976 pipe_ctx
->surface
->public.address
.grph_stereo
.left_addr
= addr
;
979 static bool dcn10_set_input_transfer_func(
980 struct pipe_ctx
*pipe_ctx
,
981 const struct core_surface
*surface
)
983 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
984 const struct core_transfer_func
*tf
= NULL
;
990 if (surface
->public.in_transfer_func
)
991 tf
= DC_TRANSFER_FUNC_TO_CORE(surface
->public.in_transfer_func
);
993 if (surface
->public.gamma_correction
&& dce_use_lut(surface
))
994 ipp
->funcs
->ipp_program_input_lut(ipp
,
995 surface
->public.gamma_correction
);
998 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
999 else if (tf
->public.type
== TF_TYPE_PREDEFINED
) {
1000 switch (tf
->public.tf
) {
1001 case TRANSFER_FUNCTION_SRGB
:
1002 ipp
->funcs
->ipp_set_degamma(ipp
,
1003 IPP_DEGAMMA_MODE_HW_sRGB
);
1005 case TRANSFER_FUNCTION_BT709
:
1006 ipp
->funcs
->ipp_set_degamma(ipp
,
1007 IPP_DEGAMMA_MODE_HW_xvYCC
);
1009 case TRANSFER_FUNCTION_LINEAR
:
1010 ipp
->funcs
->ipp_set_degamma(ipp
,
1011 IPP_DEGAMMA_MODE_BYPASS
);
1013 case TRANSFER_FUNCTION_PQ
:
1020 } else if (tf
->public.type
== TF_TYPE_BYPASS
) {
1021 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
1023 /*TF_TYPE_DISTRIBUTED_POINTS*/
1029 /*modify the method to handle rgb for arr_points*/
1030 static bool convert_to_custom_float(
1031 struct pwl_result_data
*rgb_resulted
,
1032 struct curve_points
*arr_points
,
1033 uint32_t hw_points_num
)
1035 struct custom_float_format fmt
;
1037 struct pwl_result_data
*rgb
= rgb_resulted
;
1041 fmt
.exponenta_bits
= 6;
1042 fmt
.mantissa_bits
= 12;
1045 if (!convert_to_custom_float_format(
1048 &arr_points
[0].custom_float_x
)) {
1049 BREAK_TO_DEBUGGER();
1053 if (!convert_to_custom_float_format(
1054 arr_points
[0].offset
,
1056 &arr_points
[0].custom_float_offset
)) {
1057 BREAK_TO_DEBUGGER();
1061 if (!convert_to_custom_float_format(
1062 arr_points
[0].slope
,
1064 &arr_points
[0].custom_float_slope
)) {
1065 BREAK_TO_DEBUGGER();
1069 fmt
.mantissa_bits
= 10;
1072 if (!convert_to_custom_float_format(
1075 &arr_points
[1].custom_float_x
)) {
1076 BREAK_TO_DEBUGGER();
1080 if (!convert_to_custom_float_format(
1083 &arr_points
[1].custom_float_y
)) {
1084 BREAK_TO_DEBUGGER();
1088 if (!convert_to_custom_float_format(
1089 arr_points
[1].slope
,
1091 &arr_points
[1].custom_float_slope
)) {
1092 BREAK_TO_DEBUGGER();
1096 fmt
.mantissa_bits
= 12;
1099 while (i
!= hw_points_num
) {
1100 if (!convert_to_custom_float_format(
1104 BREAK_TO_DEBUGGER();
1108 if (!convert_to_custom_float_format(
1112 BREAK_TO_DEBUGGER();
1116 if (!convert_to_custom_float_format(
1120 BREAK_TO_DEBUGGER();
1124 if (!convert_to_custom_float_format(
1127 &rgb
->delta_red_reg
)) {
1128 BREAK_TO_DEBUGGER();
1132 if (!convert_to_custom_float_format(
1135 &rgb
->delta_green_reg
)) {
1136 BREAK_TO_DEBUGGER();
1140 if (!convert_to_custom_float_format(
1143 &rgb
->delta_blue_reg
)) {
1144 BREAK_TO_DEBUGGER();
1154 #define MAX_REGIONS_NUMBER 34
1155 #define MAX_LOW_POINT 25
1156 #define NUMBER_SEGMENTS 32
1158 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
1159 *output_tf
, struct pwl_params
*regamma_params
)
1161 struct curve_points
*arr_points
;
1162 struct pwl_result_data
*rgb_resulted
;
1163 struct pwl_result_data
*rgb
;
1164 struct pwl_result_data
*rgb_plus_1
;
1165 struct fixed31_32 y_r
;
1166 struct fixed31_32 y_g
;
1167 struct fixed31_32 y_b
;
1168 struct fixed31_32 y1_min
;
1169 struct fixed31_32 y3_max
;
1171 int32_t segment_start
, segment_end
;
1173 uint32_t j
, k
, seg_distr
[MAX_REGIONS_NUMBER
], increment
, start_index
, hw_points
;
1175 if (output_tf
== NULL
|| regamma_params
== NULL
||
1176 output_tf
->type
== TF_TYPE_BYPASS
)
1179 arr_points
= regamma_params
->arr_points
;
1180 rgb_resulted
= regamma_params
->rgb_resulted
;
1183 memset(regamma_params
, 0, sizeof(struct pwl_params
));
1184 memset(seg_distr
, 0, sizeof(seg_distr
));
1186 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
1188 * segments are from 2^-25 to 2^7
1190 for (i
= 0; i
< 32 ; i
++)
1193 segment_start
= -25;
1197 * segment is from 2^-10 to 2^0
1198 * There are less than 256 points, for optimization
1211 segment_start
= -10;
1215 for (i
= segment_end
- segment_start
; i
< MAX_REGIONS_NUMBER
; i
++)
1218 for (k
= 0; k
< MAX_REGIONS_NUMBER
; k
++) {
1219 if (seg_distr
[k
] != -1)
1220 hw_points
+= (1 << seg_distr
[k
]);
1224 for (k
= 0; k
< (segment_end
- segment_start
); k
++) {
1225 increment
= NUMBER_SEGMENTS
/ (1 << seg_distr
[k
]);
1226 start_index
= (segment_start
+ k
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
1227 for (i
= start_index
; i
< start_index
+ NUMBER_SEGMENTS
; i
+= increment
) {
1228 if (j
== hw_points
- 1)
1230 rgb_resulted
[j
].red
= output_tf
->tf_pts
.red
[i
];
1231 rgb_resulted
[j
].green
= output_tf
->tf_pts
.green
[i
];
1232 rgb_resulted
[j
].blue
= output_tf
->tf_pts
.blue
[i
];
1238 start_index
= (segment_end
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
1239 rgb_resulted
[hw_points
- 1].red
=
1240 output_tf
->tf_pts
.red
[start_index
];
1241 rgb_resulted
[hw_points
- 1].green
=
1242 output_tf
->tf_pts
.green
[start_index
];
1243 rgb_resulted
[hw_points
- 1].blue
=
1244 output_tf
->tf_pts
.blue
[start_index
];
1246 arr_points
[0].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1247 dal_fixed31_32_from_int(segment_start
));
1248 arr_points
[1].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1249 dal_fixed31_32_from_int(segment_end
));
1250 arr_points
[2].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1251 dal_fixed31_32_from_int(segment_end
));
1253 y_r
= rgb_resulted
[0].red
;
1254 y_g
= rgb_resulted
[0].green
;
1255 y_b
= rgb_resulted
[0].blue
;
1257 y1_min
= dal_fixed31_32_min(y_r
, dal_fixed31_32_min(y_g
, y_b
));
1259 arr_points
[0].y
= y1_min
;
1260 arr_points
[0].slope
= dal_fixed31_32_div(
1263 y_r
= rgb_resulted
[hw_points
- 1].red
;
1264 y_g
= rgb_resulted
[hw_points
- 1].green
;
1265 y_b
= rgb_resulted
[hw_points
- 1].blue
;
1267 /* see comment above, m_arrPoints[1].y should be the Y value for the
1268 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
1270 y3_max
= dal_fixed31_32_max(y_r
, dal_fixed31_32_max(y_g
, y_b
));
1272 arr_points
[1].y
= y3_max
;
1273 arr_points
[2].y
= y3_max
;
1275 arr_points
[1].slope
= dal_fixed31_32_zero
;
1276 arr_points
[2].slope
= dal_fixed31_32_zero
;
1278 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
1279 /* for PQ, we want to have a straight line from last HW X point,
1280 * and the slope to be such that we hit 1.0 at 10000 nits.
1282 const struct fixed31_32 end_value
=
1283 dal_fixed31_32_from_int(125);
1285 arr_points
[1].slope
= dal_fixed31_32_div(
1286 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
1287 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
1288 arr_points
[2].slope
= dal_fixed31_32_div(
1289 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
1290 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
1293 regamma_params
->hw_points_num
= hw_points
;
1296 for (k
= 0; k
< MAX_REGIONS_NUMBER
&& i
< MAX_REGIONS_NUMBER
; k
++) {
1297 if (seg_distr
[k
] != -1) {
1298 regamma_params
->arr_curve_points
[k
].segments_num
=
1300 regamma_params
->arr_curve_points
[i
].offset
=
1301 regamma_params
->arr_curve_points
[k
].
1302 offset
+ (1 << seg_distr
[k
]);
1307 if (seg_distr
[k
] != -1)
1308 regamma_params
->arr_curve_points
[k
].segments_num
=
1312 rgb_plus_1
= rgb_resulted
+ 1;
1316 while (i
!= hw_points
+ 1) {
1317 if (dal_fixed31_32_lt(rgb_plus_1
->red
, rgb
->red
))
1318 rgb_plus_1
->red
= rgb
->red
;
1319 if (dal_fixed31_32_lt(rgb_plus_1
->green
, rgb
->green
))
1320 rgb_plus_1
->green
= rgb
->green
;
1321 if (dal_fixed31_32_lt(rgb_plus_1
->blue
, rgb
->blue
))
1322 rgb_plus_1
->blue
= rgb
->blue
;
1324 rgb
->delta_red
= dal_fixed31_32_sub(
1327 rgb
->delta_green
= dal_fixed31_32_sub(
1330 rgb
->delta_blue
= dal_fixed31_32_sub(
1339 convert_to_custom_float(rgb_resulted
, arr_points
, hw_points
);
1344 static bool dcn10_set_output_transfer_func(
1345 struct pipe_ctx
*pipe_ctx
,
1346 const struct core_stream
*stream
)
1348 struct output_pixel_processor
*opp
= pipe_ctx
->opp
;
1353 opp
->regamma_params
.hw_points_num
= GAMMA_HW_POINTS_NUM
;
1355 if (stream
->public.out_transfer_func
&&
1356 stream
->public.out_transfer_func
->type
==
1357 TF_TYPE_PREDEFINED
&&
1358 stream
->public.out_transfer_func
->tf
==
1359 TRANSFER_FUNCTION_SRGB
) {
1360 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_SRGB
);
1361 } else if (dcn10_translate_regamma_to_hw_format(
1362 stream
->public.out_transfer_func
, &opp
->regamma_params
)) {
1363 opp
->funcs
->opp_program_regamma_pwl(opp
, &opp
->regamma_params
);
1364 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_USER
);
1366 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_BYPASS
);
1372 static void dcn10_pipe_control_lock(
1374 struct pipe_ctx
*pipe
,
1377 struct dce_hwseq
*hws
= hws
= dc
->hwseq
;
1379 /* use TG master update lock to lock everything on the TG
1380 * therefore only top pipe need to lock
1386 dcn10_lock(pipe
->tg
);
1388 dcn10_unlock(pipe
->tg
);
1391 static bool wait_for_reset_trigger_to_occur(
1392 struct dc_context
*dc_ctx
,
1393 struct timing_generator
*tg
)
1397 /* To avoid endless loop we wait at most
1398 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1399 const uint32_t frames_to_wait_on_triggered_reset
= 10;
1402 for (i
= 0; i
< frames_to_wait_on_triggered_reset
; i
++) {
1404 if (!tg
->funcs
->is_counter_moving(tg
)) {
1405 DC_ERROR("TG counter is not moving!\n");
1409 if (tg
->funcs
->did_triggered_reset_occur(tg
)) {
1411 /* usually occurs at i=1 */
1412 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1417 /* Wait for one frame. */
1418 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VACTIVE
);
1419 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VBLANK
);
1423 DC_ERROR("GSL: Timeout on reset trigger!\n");
1428 static void dcn10_enable_timing_synchronization(
1432 struct pipe_ctx
*grouped_pipes
[])
1434 struct dc_context
*dc_ctx
= dc
->ctx
;
1437 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1439 for (i
= 1; i
< group_size
; i
++)
1440 grouped_pipes
[i
]->tg
->funcs
->enable_reset_trigger(
1441 grouped_pipes
[i
]->tg
, grouped_pipes
[0]->tg
->inst
);
1444 DC_SYNC_INFO("Waiting for trigger\n");
1446 /* Need to get only check 1 pipe for having reset as all the others are
1447 * synchronized. Look at last pipe programmed to reset.
1449 wait_for_reset_trigger_to_occur(dc_ctx
, grouped_pipes
[1]->tg
);
1450 for (i
= 1; i
< group_size
; i
++)
1451 grouped_pipes
[i
]->tg
->funcs
->disable_reset_trigger(
1452 grouped_pipes
[i
]->tg
);
1454 DC_SYNC_INFO("Sync complete\n");
1457 static void dcn10_power_on_fe(
1459 struct pipe_ctx
*pipe_ctx
,
1460 struct validate_context
*context
)
1462 struct dc_surface
*dc_surface
= &pipe_ctx
->surface
->public;
1464 /* power up DCHUP and DPP from pseudo code pipe_move.c */
1465 /*TODO: function: power_on_plane. If already power up, skip
1468 power_on_plane(dc
->ctx
,
1469 pipe_ctx
->pipe_idx
, pipe_ctx
->tg
->inst
);
1471 /* enable DCFCLK current DCHUB */
1472 enable_dcfclk(dc
->ctx
,
1474 pipe_ctx
->pix_clk_params
.requested_pix_clk
,
1475 context
->bw
.dcn
.calc_clk
.dppclk_div
);
1476 dc
->current_context
->bw
.dcn
.cur_clk
.dppclk_div
=
1477 context
->bw
.dcn
.calc_clk
.dppclk_div
;
1478 context
->bw
.dcn
.cur_clk
.dppclk_div
= context
->bw
.dcn
.calc_clk
.dppclk_div
;
1481 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
1482 "Pipe:%d 0x%x: addr hi:0x%x, "
1485 " %d; dst: %d, %d, %d, %d;\n",
1488 dc_surface
->address
.grph
.addr
.high_part
,
1489 dc_surface
->address
.grph
.addr
.low_part
,
1490 dc_surface
->src_rect
.x
,
1491 dc_surface
->src_rect
.y
,
1492 dc_surface
->src_rect
.width
,
1493 dc_surface
->src_rect
.height
,
1494 dc_surface
->dst_rect
.x
,
1495 dc_surface
->dst_rect
.y
,
1496 dc_surface
->dst_rect
.width
,
1497 dc_surface
->dst_rect
.height
);
1499 dm_logger_write(dc
->ctx
->logger
, LOG_HW_SET_MODE
,
1500 "Pipe %d: width, height, x, y\n"
1501 "viewport:%d, %d, %d, %d\n"
1502 "recout: %d, %d, %d, %d\n",
1504 pipe_ctx
->scl_data
.viewport
.width
,
1505 pipe_ctx
->scl_data
.viewport
.height
,
1506 pipe_ctx
->scl_data
.viewport
.x
,
1507 pipe_ctx
->scl_data
.viewport
.y
,
1508 pipe_ctx
->scl_data
.recout
.width
,
1509 pipe_ctx
->scl_data
.recout
.height
,
1510 pipe_ctx
->scl_data
.recout
.x
,
1511 pipe_ctx
->scl_data
.recout
.y
);
1517 static void program_gamut_remap(struct pipe_ctx
*pipe_ctx
)
1519 struct xfm_grph_csc_adjustment adjust
;
1520 memset(&adjust
, 0, sizeof(adjust
));
1521 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS
;
1524 if (pipe_ctx
->stream
->public.gamut_remap_matrix
.enable_remap
== true) {
1525 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_SW
;
1526 adjust
.temperature_matrix
[0] =
1528 public.gamut_remap_matrix
.matrix
[0];
1529 adjust
.temperature_matrix
[1] =
1531 public.gamut_remap_matrix
.matrix
[1];
1532 adjust
.temperature_matrix
[2] =
1534 public.gamut_remap_matrix
.matrix
[2];
1535 adjust
.temperature_matrix
[3] =
1537 public.gamut_remap_matrix
.matrix
[4];
1538 adjust
.temperature_matrix
[4] =
1540 public.gamut_remap_matrix
.matrix
[5];
1541 adjust
.temperature_matrix
[5] =
1543 public.gamut_remap_matrix
.matrix
[6];
1544 adjust
.temperature_matrix
[6] =
1546 public.gamut_remap_matrix
.matrix
[8];
1547 adjust
.temperature_matrix
[7] =
1549 public.gamut_remap_matrix
.matrix
[9];
1550 adjust
.temperature_matrix
[8] =
1552 public.gamut_remap_matrix
.matrix
[10];
1555 pipe_ctx
->xfm
->funcs
->transform_set_gamut_remap(pipe_ctx
->xfm
, &adjust
);
1558 static bool is_lower_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1560 if (pipe_ctx
->surface
->public.visible
)
1562 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1567 static bool is_upper_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1569 if (pipe_ctx
->surface
->public.visible
)
1571 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1576 static bool is_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1578 if (pipe_ctx
->surface
->public.visible
)
1580 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1582 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1587 static void update_dchubp_dpp(
1589 struct pipe_ctx
*pipe_ctx
,
1590 struct validate_context
*context
)
1592 struct mem_input
*mi
= pipe_ctx
->mi
;
1593 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
1594 struct core_surface
*surface
= pipe_ctx
->surface
;
1595 union plane_size size
= surface
->public.plane_size
;
1596 struct mpc_tree_cfg
*tree_cfg
= NULL
;
1597 struct default_adjustment ocsc
= {0};
1598 enum dc_color_space color_space
;
1599 struct tg_color black_color
= {0};
1600 struct dcn10_mpc
*mpc
= TO_DCN10_MPC(dc
->res_pool
->mpc
);
1602 struct pipe_ctx
*cur_pipe_ctx
= &dc
->current_context
->res_ctx
.pipe_ctx
[pipe_ctx
->pipe_idx
];
1604 /* depends on DML calculation, DPP clock value may change dynamically */
1608 pipe_ctx
->pix_clk_params
.requested_pix_clk
,
1609 context
->bw
.dcn
.calc_clk
.dppclk_div
);
1610 dc
->current_context
->bw
.dcn
.cur_clk
.dppclk_div
=
1611 context
->bw
.dcn
.calc_clk
.dppclk_div
;
1612 context
->bw
.dcn
.cur_clk
.dppclk_div
= context
->bw
.dcn
.calc_clk
.dppclk_div
;
1614 select_vtg(dc
->ctx
, pipe_ctx
->pipe_idx
, pipe_ctx
->tg
->inst
);
1616 update_plane_addr(dc
, pipe_ctx
);
1618 mi
->funcs
->mem_input_setup(
1620 &pipe_ctx
->dlg_regs
,
1621 &pipe_ctx
->ttu_regs
,
1623 &pipe_ctx
->pipe_dlg_param
);
1625 size
.grph
.surface_size
= pipe_ctx
->scl_data
.viewport
;
1627 if (dc
->public.config
.gpu_vm_support
)
1628 mi
->funcs
->mem_input_program_pte_vm(
1630 surface
->public.format
,
1631 &surface
->public.tiling_info
,
1632 surface
->public.rotation
);
1634 ipp
->funcs
->ipp_setup(ipp
,
1635 surface
->public.format
,
1637 IPP_OUTPUT_FORMAT_12_BIT_FIX
);
1639 /* mpc TODO un-hardcode object ids
1640 * for pseudo code pipe_move.c :
1641 * add_plane_mpcc(added_plane_inst, mpcc_inst, ...);
1642 * Do we want to cache the tree_cfg?
1645 /* TODO: build stream pipes group id. For now, use stream otg
1646 * id as pipe group id
1648 pipe_ctx
->mpc_idx
= pipe_ctx
->tg
->inst
;
1649 tree_cfg
= &context
->res_ctx
.mpc_tree
[pipe_ctx
->mpc_idx
];
1651 /* enable when bottom pipe is present and
1652 * it does not share a surface with current pipe
1654 if (pipe_ctx
->bottom_pipe
&& surface
!= pipe_ctx
->bottom_pipe
->surface
) {
1655 pipe_ctx
->scl_data
.lb_params
.alpha_en
= 1;
1656 tree_cfg
->mode
= TOP_BLND
;
1658 pipe_ctx
->scl_data
.lb_params
.alpha_en
= 0;
1659 tree_cfg
->mode
= TOP_PASSTHRU
;
1661 if (!pipe_ctx
->top_pipe
&& !cur_pipe_ctx
->bottom_pipe
) {
1662 /* primary pipe, set mpc tree index 0 only */
1663 tree_cfg
->num_pipes
= 1;
1664 tree_cfg
->opp_id
= pipe_ctx
->tg
->inst
;
1665 tree_cfg
->dpp
[0] = pipe_ctx
->pipe_idx
;
1666 tree_cfg
->mpcc
[0] = pipe_ctx
->pipe_idx
;
1669 if (!cur_pipe_ctx
->top_pipe
&& !pipe_ctx
->top_pipe
) {
1671 if (!cur_pipe_ctx
->bottom_pipe
)
1672 dcn10_set_mpc_tree(mpc
, tree_cfg
);
1674 } else if (!cur_pipe_ctx
->top_pipe
&& pipe_ctx
->top_pipe
) {
1676 dcn10_add_dpp(mpc
, tree_cfg
,
1677 pipe_ctx
->pipe_idx
, pipe_ctx
->pipe_idx
, 1);
1679 /* nothing to be done here */
1680 ASSERT(cur_pipe_ctx
->top_pipe
&& pipe_ctx
->top_pipe
);
1684 color_space
= pipe_ctx
->stream
->public.output_color_space
;
1685 color_space_to_black_color(dc
, color_space
, &black_color
);
1686 dcn10_set_mpc_background_color(mpc
, pipe_ctx
->pipe_idx
, &black_color
);
1688 pipe_ctx
->scl_data
.lb_params
.depth
= LB_PIXEL_DEPTH_30BPP
;
1689 /* scaler configuration */
1690 pipe_ctx
->xfm
->funcs
->transform_set_scaler(
1691 pipe_ctx
->xfm
, &pipe_ctx
->scl_data
);
1694 program_gamut_remap(pipe_ctx
);
1696 /*TODO add adjustments parameters*/
1697 ocsc
.out_color_space
= pipe_ctx
->stream
->public.output_color_space
;
1698 pipe_ctx
->opp
->funcs
->opp_set_csc_default(pipe_ctx
->opp
, &ocsc
);
1700 mi
->funcs
->mem_input_program_surface_config(
1702 surface
->public.format
,
1703 &surface
->public.tiling_info
,
1705 surface
->public.rotation
,
1706 &surface
->public.dcc
,
1707 surface
->public.horizontal_mirror
);
1709 mi
->funcs
->set_blank(mi
, !is_pipe_tree_visible(pipe_ctx
));
1712 static void program_all_pipe_in_tree(
1714 struct pipe_ctx
*pipe_ctx
,
1715 struct validate_context
*context
)
1717 unsigned int ref_clk_mhz
= dc
->res_pool
->ref_clock_inKhz
/1000;
1719 if (pipe_ctx
->surface
->public.visible
|| pipe_ctx
->top_pipe
== NULL
) {
1720 dcn10_power_on_fe(dc
, pipe_ctx
, context
);
1722 /* lock otg_master_update to process all pipes associated with
1723 * this OTG. this is done only one time.
1725 if (pipe_ctx
->top_pipe
== NULL
) {
1726 /* watermark is for all pipes */
1727 pipe_ctx
->mi
->funcs
->program_watermarks(
1728 pipe_ctx
->mi
, &context
->bw
.dcn
.watermarks
, ref_clk_mhz
);
1729 lock_otg_master_update(dc
->ctx
, pipe_ctx
->tg
->inst
);
1732 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
1733 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
1734 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
1735 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
1736 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
1738 pipe_ctx
->tg
->funcs
->program_global_sync(
1740 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, !is_pipe_tree_visible(pipe_ctx
));
1744 update_dchubp_dpp(dc
, pipe_ctx
, context
);
1746 /* Only support one plane for now. */
1749 if (pipe_ctx
->bottom_pipe
!= NULL
)
1750 program_all_pipe_in_tree(dc
, pipe_ctx
->bottom_pipe
, context
);
1753 static void dcn10_pplib_apply_display_requirements(
1755 struct validate_context
*context
)
1757 struct dm_pp_display_configuration
*pp_display_cfg
= &context
->pp_display_cfg
;
1759 pp_display_cfg
->all_displays_in_sync
= false;/*todo*/
1760 pp_display_cfg
->nb_pstate_switch_disable
= false;
1761 pp_display_cfg
->min_engine_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
1762 pp_display_cfg
->min_memory_clock_khz
= context
->bw
.dcn
.cur_clk
.fclk_khz
;
1763 pp_display_cfg
->min_engine_clock_deep_sleep_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
1764 pp_display_cfg
->min_dcfc_deep_sleep_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
1765 pp_display_cfg
->avail_mclk_switch_time_us
=
1766 context
->bw
.dcn
.cur_clk
.dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.dram_ccm_us
: 0;
1767 pp_display_cfg
->avail_mclk_switch_time_in_disp_active_us
=
1768 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
: 0;
1769 pp_display_cfg
->min_dcfclock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
1770 pp_display_cfg
->disp_clk_khz
= context
->bw
.dcn
.cur_clk
.dispclk_khz
;
1771 dce110_fill_display_configs(context
, pp_display_cfg
);
1773 if (memcmp(&dc
->prev_display_config
, pp_display_cfg
, sizeof(
1774 struct dm_pp_display_configuration
)) != 0)
1775 dm_pp_apply_display_requirements(dc
->ctx
, pp_display_cfg
);
1777 dc
->prev_display_config
= *pp_display_cfg
;
1780 static void dcn10_apply_ctx_for_surface(
1782 struct core_surface
*surface
,
1783 struct validate_context
*context
)
1787 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1788 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1790 if (!pipe_ctx
->surface
|| pipe_ctx
->surface
!= surface
)
1794 /* looking for top pipe to program */
1795 if (!pipe_ctx
->top_pipe
) {
1796 memcpy(context
->res_ctx
.mpc_tree
,
1797 dc
->current_context
->res_ctx
.mpc_tree
,
1798 sizeof(struct mpc_tree_cfg
) * dc
->res_pool
->pipe_count
);
1800 program_all_pipe_in_tree(dc
, pipe_ctx
, context
);
1804 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1805 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1807 if (!pipe_ctx
->surface
|| pipe_ctx
->top_pipe
)
1810 /* unlock master update lock */
1811 unlock_otg_master(dc
->ctx
, pipe_ctx
->tg
->inst
);
1814 /* reset unused pipe */
1815 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1816 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1817 struct pipe_ctx
*old_pipe_ctx
=
1818 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
1820 if ((!pipe_ctx
->surface
&& old_pipe_ctx
->surface
)
1821 || (!pipe_ctx
->stream
&& old_pipe_ctx
->stream
))
1822 reset_front_end_for_pipe(dc
,
1823 old_pipe_ctx
, dc
->current_context
);
1827 static void dcn10_set_bandwidth(
1829 struct validate_context
*context
,
1830 bool decrease_allowed
)
1832 struct dm_pp_clock_for_voltage_req clock
;
1834 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
1837 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dispclk_khz
1838 > dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
) {
1839 dc
->res_pool
->display_clock
->funcs
->set_clock(
1840 dc
->res_pool
->display_clock
,
1841 context
->bw
.dcn
.calc_clk
.dispclk_khz
);
1842 dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
=
1843 context
->bw
.dcn
.calc_clk
.dispclk_khz
;
1845 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_khz
1846 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
) {
1847 clock
.clk_type
= DM_PP_CLOCK_TYPE_DCFCLK
;
1848 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.dcfclk_khz
;
1849 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
1850 dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
1851 context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
1853 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.fclk_khz
1854 > dc
->current_context
->bw
.dcn
.cur_clk
.fclk_khz
) {
1855 clock
.clk_type
= DM_PP_CLOCK_TYPE_FCLK
;
1856 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.fclk_khz
;
1857 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
1858 dc
->current_context
->bw
.dcn
.calc_clk
.fclk_khz
= clock
.clocks_in_khz
;
1859 context
->bw
.dcn
.cur_clk
.fclk_khz
= clock
.clocks_in_khz
;
1861 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
1862 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
) {
1863 dc
->current_context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
=
1864 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
1865 context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
=
1866 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
1868 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
1869 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dram_ccm_us
1870 < dc
->current_context
->bw
.dcn
.cur_clk
.dram_ccm_us
) {
1871 dc
->current_context
->bw
.dcn
.calc_clk
.dram_ccm_us
=
1872 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
1873 context
->bw
.dcn
.cur_clk
.dram_ccm_us
=
1874 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
1876 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
1877 < dc
->current_context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
) {
1878 dc
->current_context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
=
1879 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
1880 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
=
1881 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
1883 dcn10_pplib_apply_display_requirements(dc
, context
);
1886 static void dcn10_power_down_fe(struct core_dc
*dc
, struct pipe_ctx
*pipe
)
1888 struct dc_context
*ctx
= dc
->ctx
;
1889 uint32_t inst_offset
= 0;
1891 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL
,
1893 dpp_pg_control(ctx
, pipe
->pipe_idx
, false);
1894 hubp_pg_control(ctx
, pipe
->pipe_idx
, false);
1895 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL
,
1899 pipe
->xfm
->funcs
->transform_reset(pipe
->xfm
);
1900 memset(&pipe
->scl_data
, 0, sizeof(pipe
->scl_data
));
1903 static void set_drr(struct pipe_ctx
**pipe_ctx
,
1904 int num_pipes
, int vmin
, int vmax
)
1907 struct drr_params params
= {0};
1909 params
.vertical_total_max
= vmax
;
1910 params
.vertical_total_min
= vmin
;
1912 /* TODO: If multiple pipes are to be supported, you need
1915 for (i
= 0; i
< num_pipes
; i
++) {
1916 pipe_ctx
[i
]->tg
->funcs
->set_drr(pipe_ctx
[i
]->tg
, ¶ms
);
1920 static void get_position(struct pipe_ctx
**pipe_ctx
,
1922 struct crtc_position
*position
)
1926 /* TODO: handle pipes > 1
1928 for (i
= 0; i
< num_pipes
; i
++)
1929 pipe_ctx
[i
]->tg
->funcs
->get_position(pipe_ctx
[i
]->tg
, position
);
1932 static void set_static_screen_control(struct pipe_ctx
**pipe_ctx
,
1933 int num_pipes
, const struct dc_static_screen_events
*events
)
1936 unsigned int value
= 0;
1938 if (events
->surface_update
)
1940 if (events
->cursor_update
)
1943 for (i
= 0; i
< num_pipes
; i
++)
1944 pipe_ctx
[i
]->tg
->funcs
->
1945 set_static_screen_control(pipe_ctx
[i
]->tg
, value
);
1948 static void set_plane_config(
1949 const struct core_dc
*dc
,
1950 struct pipe_ctx
*pipe_ctx
,
1951 struct resource_context
*res_ctx
)
1954 program_gamut_remap(pipe_ctx
);
1957 static const struct hw_sequencer_funcs dcn10_funcs
= {
1959 .apply_ctx_to_hw
= dce110_apply_ctx_to_hw
,
1960 .apply_ctx_for_surface
= dcn10_apply_ctx_for_surface
,
1961 .set_plane_config
= set_plane_config
,
1962 .update_plane_addr
= update_plane_addr
,
1963 .update_pending_status
= dce110_update_pending_status
,
1964 .set_input_transfer_func
= dcn10_set_input_transfer_func
,
1965 .set_output_transfer_func
= dcn10_set_output_transfer_func
,
1966 .power_down
= dce110_power_down
,
1967 .enable_accelerated_mode
= dce110_enable_accelerated_mode
,
1968 .enable_timing_synchronization
= dcn10_enable_timing_synchronization
,
1969 .update_info_frame
= dce110_update_info_frame
,
1970 .enable_stream
= dce110_enable_stream
,
1971 .disable_stream
= dce110_disable_stream
,
1972 .unblank_stream
= dce110_unblank_stream
,
1973 .enable_display_pipe_clock_gating
= NULL
, /* TODOFPGA */
1974 .enable_display_power_gating
= dcn10_enable_display_power_gating
,
1975 .power_down_front_end
= dcn10_power_down_fe
,
1976 .power_on_front_end
= dcn10_power_on_fe
,
1977 .pipe_control_lock
= dcn10_pipe_control_lock
,
1978 .set_bandwidth
= dcn10_set_bandwidth
,
1979 .reset_hw_ctx_wrap
= reset_hw_ctx_wrap
,
1980 .prog_pixclk_crtc_otg
= dcn10_prog_pixclk_crtc_otg
,
1982 .get_position
= get_position
,
1983 .set_static_screen_control
= set_static_screen_control
1987 bool dcn10_hw_sequencer_construct(struct core_dc
*dc
)
1989 dc
->hwss
= dcn10_funcs
;