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 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK
,
129 OTG_MASTER_UPDATE_LOCK
, 1);
132 static bool unlock_master_tg_and_wait(
133 struct dc_context
*ctx
,
136 uint32_t inst_offset
= reg_offsets
[inst
].otg
;
138 HWSEQ_REG_UPDATE(OTG0_OTG_GLOBAL_SYNC_STATUS
,
139 VUPDATE_NO_LOCK_EVENT_CLEAR
, 1);
140 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK
, OTG_MASTER_UPDATE_LOCK
, 0);
142 if (!wait_reg(ctx
, inst_offset
, OTG0_OTG_GLOBAL_SYNC_STATUS
, VUPDATE_NO_LOCK_EVENT_OCCURRED
, 1)) {
143 dm_logger_write(ctx
->logger
, LOG_ERROR
,
144 "wait for VUPDATE_NO_LOCK_EVENT_OCCURRED failed\n");
151 /* TODO: should be moved to OTG ? */
152 static void unlock_otg_master(
153 struct dc_context
*ctx
,
156 uint32_t inst_offset
= reg_offsets
[inst
].otg
;
158 /* unlock master locker */
159 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK
,
160 OTG_MASTER_UPDATE_LOCK
, 0);
164 static void wait_no_outstanding_request(
165 struct dc_context
*ctx
,
168 uint32_t inst_offset
= reg_offsets
[plane_id
].dchubp
;
170 if (!wait_reg(ctx
, inst_offset
, HUBP0_DCHUBP_CNTL
, HUBP_NO_OUTSTANDING_REQ
, 1))
174 static void disable_clocks(
175 struct dc_context
*ctx
,
178 uint32_t inst_offset
= reg_offsets
[plane_id
].dchubp
;
180 generic_reg_update_soc15(ctx
, inst_offset
, HUBP0_HUBP_CLK_CNTL
, 1,
181 FD(HUBP0_HUBP_CLK_CNTL__HUBP_CLOCK_ENABLE
), 0);
183 inst_offset
= reg_offsets
[plane_id
].dpp
;
184 generic_reg_update_soc15(ctx
, inst_offset
, DPP_TOP0_DPP_CONTROL
, 1,
185 FD(DPP_TOP0_DPP_CONTROL__DPP_CLOCK_ENABLE
), 0);
188 /* TODO: This is one time program during system boot up,
189 * this should be done within BIOS or CAIL
191 static void dchubp_map_fb_to_mc(struct dc_context
*ctx
)
193 /* TODO: do not know where to program
194 * DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
197 * TODO: For real ASIC, FB_OFFSET may be need change to the same value
198 * as FB_BASE. Need re-visit this for real ASIC.
200 dm_write_reg_soc15(ctx
, mmDCHUBBUB_SDPIF_FB_BASE
, 0, 0x80);
201 dm_write_reg_soc15(ctx
, mmDCHUBBUB_SDPIF_FB_OFFSET
, 0, 0);
202 dm_write_reg_soc15(ctx
, mmDCHUBBUB_SDPIF_FB_TOP
, 0, 0xFF);
204 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_CFG0
, 7,
205 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_DATA_RESPONSE_STATUS_CLEAR
), 0,
206 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_REQ_CREDIT_ERROR_CLEAR
), 0,
207 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_FLUSH_REQ_CREDIT_EN
), 0,
208 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_REQ_CREDIT_EN
), 0,
209 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_PORT_CONTROL
), 1,
210 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_UNIT_ID_BITMASK
), 0xd3,
211 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_CREDIT_DISCONNECT_DELAY
), 0xc);
214 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_CFG1
, 4,
215 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_INSIDE_FB_IO
), 0,
216 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_INSIDE_FB_VC
), 6,
217 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_OUTSIDE_FB_IO
), 1,
218 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_OUTSIDE_FB_VC
), 6);
220 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_FB_BASE
, 1,
221 FD(DCHUBBUB_SDPIF_FB_BASE__SDPIF_FB_BASE
), 0x000080);
223 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_FB_TOP
, 1,
224 FD(DCHUBBUB_SDPIF_FB_TOP__SDPIF_FB_TOP
), 0x0000ff);
226 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_AGP_BOT
, 1,
227 FD(DCHUBBUB_SDPIF_AGP_BOT__SDPIF_AGP_BOT
), 0x0000040);
229 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_AGP_TOP
, 1,
230 FD(DCHUBBUB_SDPIF_AGP_TOP__SDPIF_AGP_TOP
), 0x00001ff);
232 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_AGP_BASE
, 1,
233 FD(DCHUBBUB_SDPIF_AGP_BASE__SDPIF_AGP_BASE
), 0x0000080);
235 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_APER_TOP
, 1,
236 FD(DCHUBBUB_SDPIF_APER_TOP__SDPIF_APER_TOP
), 0x00007ff);
238 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_APER_DEF_0
, 1,
239 FD(DCHUBBUB_SDPIF_APER_DEF_0__SDPIF_APER_DEF_0
), 0xdeadbeef);
241 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_0
, 2,
242 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_0__SDPIF_MARC_EN_0
), 0,
243 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_0__SDPIF_MARC_RELOC_LO_0
), 0x90000);
245 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_0
, 1,
246 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_0__SDPIF_MARC_LENGTH_LO_0
), 0x10000);
248 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_1
, 1,
249 FD(DCHUBBUB_SDPIF_MARC_BASE_LO_1__SDPIF_MARC_BASE_LO_1
), 0x10000);
251 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_1
, 2,
252 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_1__SDPIF_MARC_EN_1
), 0,
253 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_1__SDPIF_MARC_RELOC_LO_1
), 0xa0000);
255 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_1
, 1,
256 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_1__SDPIF_MARC_LENGTH_LO_1
), 0x10000);
258 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_2
, 1,
259 FD(DCHUBBUB_SDPIF_MARC_BASE_LO_2__SDPIF_MARC_BASE_LO_2
), 0x20000);
261 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_2
, 2,
262 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_2__SDPIF_MARC_EN_2
), 0,
263 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_2__SDPIF_MARC_RELOC_LO_2
), 0xb0000);
265 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_2
, 1,
266 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_2__SDPIF_MARC_LENGTH_LO_2
), 0x10000);
268 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_3
, 1,
269 FD(DCHUBBUB_SDPIF_MARC_BASE_LO_3__SDPIF_MARC_BASE_LO_3
), 0x30000);
271 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_3
, 2,
272 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_3__SDPIF_MARC_EN_3
), 0,
273 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_3__SDPIF_MARC_RELOC_LO_3
), 0xc0000);
275 generic_reg_set_soc15(ctx
, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_3
, 1,
276 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_3__SDPIF_MARC_LENGTH_LO_3
), 0x10000);
278 /* TODO: Is DCN_VM_SYSTEM_APERTURE address one time programming?
279 * Are all 4 hubp programmed with the same address?
281 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
, 0, 0x80000);
282 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB
, 0, 0);
283 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB
, 0, 0x100000);
284 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB
, 0, 0);
285 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB
, 0, 0x80000);
286 dm_write_reg_soc15(ctx
, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB
, 0, 0);
288 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
, 0, 0x80000);
289 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB
, 0, 0);
290 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB
, 0, 0x100000);
291 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB
, 0, 0);
292 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB
, 0, 0x80000);
293 dm_write_reg_soc15(ctx
, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB
, 0, 0);
295 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
, 0, 0x80000);
296 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB
, 0, 0);
297 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB
, 0, 0x100000);
298 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB
, 0, 0);
299 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB
, 0, 0x80000);
300 dm_write_reg_soc15(ctx
, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB
, 0, 0);
302 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
, 0, 0x80000);
303 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB
, 0, 0);
304 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB
, 0, 0x100000);
305 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB
, 0, 0);
306 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB
, 0, 0x80000);
307 dm_write_reg_soc15(ctx
, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB
, 0, 0);
310 /* TODO: This is one time program during system boot up,
311 * this should be done within BIOS
313 static void dchubup_setup_timer(struct dc_context
*ctx
)
315 dm_write_reg_soc15(ctx
, mmREFCLK_CNTL
, 0, 0);
317 generic_reg_update_soc15(ctx
, 0, DCHUBBUB_GLOBAL_TIMER_CNTL
, 1,
318 FD(DCHUBBUB_GLOBAL_TIMER_CNTL__DCHUBBUB_GLOBAL_TIMER_ENABLE
), 1);
321 /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
322 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
323 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
325 static void select_vtg(
326 struct dc_context
*ctx
,
330 uint32_t inst_offset
= reg_offsets
[plane_id
].dchubp
;
332 HWSEQ_REG_UPDATE(HUBP0_DCHUBP_CNTL
, HUBP_VTG_SEL
, inst
);
335 static void enable_dcfclk(
336 struct dc_context
*ctx
,
338 uint32_t requested_pix_clk
,
341 uint32_t inst_offset
= reg_offsets
[plane_id
].dchubp
;
343 HWSEQ_REG_UPDATE(HUBP0_HUBP_CLK_CNTL
, HUBP_CLOCK_ENABLE
, 1);
346 static void enable_dppclk(
347 struct dc_context
*ctx
,
349 uint32_t requested_pix_clk
,
352 uint32_t inst_offset
= reg_offsets
[plane_id
].dpp
;
354 dm_logger_write(ctx
->logger
, LOG_SURFACE
,
355 "dppclk_rate_control for pipe %d programed to %d\n",
359 /* TODO: find condition for DPP clock to DISPCLK or 1/2 DISPCLK */
362 HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL
,
363 DPPCLK_RATE_CONTROL
, 1,
364 DPP_CLOCK_ENABLE
, 1);
367 HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL
,
368 DPPCLK_RATE_CONTROL
, 0,
369 DPP_CLOCK_ENABLE
, 1);
373 static void enable_power_gating_plane(
374 struct dc_context
*ctx
,
377 uint32_t inst_offset
= 0; /* each register only has one instance */
378 bool force_on
= 1; /* disable power gating */
384 HWSEQ_REG_UPDATE(DOMAIN0_PG_CONFIG
, DOMAIN0_POWER_FORCEON
, force_on
);
385 HWSEQ_REG_UPDATE(DOMAIN2_PG_CONFIG
, DOMAIN2_POWER_FORCEON
, force_on
);
386 HWSEQ_REG_UPDATE(DOMAIN4_PG_CONFIG
, DOMAIN4_POWER_FORCEON
, force_on
);
387 HWSEQ_REG_UPDATE(DOMAIN6_PG_CONFIG
, DOMAIN6_POWER_FORCEON
, force_on
);
390 HWSEQ_REG_UPDATE(DOMAIN1_PG_CONFIG
, DOMAIN1_POWER_FORCEON
, force_on
);
391 HWSEQ_REG_UPDATE(DOMAIN3_PG_CONFIG
, DOMAIN3_POWER_FORCEON
, force_on
);
392 HWSEQ_REG_UPDATE(DOMAIN5_PG_CONFIG
, DOMAIN5_POWER_FORCEON
, force_on
);
393 HWSEQ_REG_UPDATE(DOMAIN7_PG_CONFIG
, DOMAIN7_POWER_FORCEON
, force_on
);
396 static void dpp_pg_control(
397 struct dc_context
*ctx
,
398 unsigned int dpp_inst
,
401 uint32_t inst_offset
= 0;
402 uint32_t power_gate
= power_on
? 0 : 1;
403 uint32_t pwr_status
= power_on
? 0 : 2;
405 if (ctx
->dc
->debug
.disable_dpp_power_gate
)
410 HWSEQ_REG_UPDATE(DOMAIN1_PG_CONFIG
,
411 DOMAIN1_POWER_GATE
, power_gate
);
413 wait_reg(ctx
, 0, DOMAIN1_PG_STATUS
,
414 DOMAIN1_PGFSM_PWR_STATUS
, pwr_status
);
417 HWSEQ_REG_UPDATE(DOMAIN3_PG_CONFIG
,
418 DOMAIN3_POWER_GATE
, power_gate
);
420 wait_reg(ctx
, 0, DOMAIN3_PG_STATUS
,
421 DOMAIN3_PGFSM_PWR_STATUS
, pwr_status
);
424 HWSEQ_REG_UPDATE(DOMAIN5_PG_CONFIG
,
425 DOMAIN5_POWER_GATE
, power_gate
);
427 wait_reg(ctx
, 0, DOMAIN5_PG_STATUS
,
428 DOMAIN5_PGFSM_PWR_STATUS
, pwr_status
);
431 HWSEQ_REG_UPDATE(DOMAIN7_PG_CONFIG
,
432 DOMAIN7_POWER_GATE
, power_gate
);
434 wait_reg(ctx
, 0, DOMAIN7_PG_STATUS
,
435 DOMAIN7_PGFSM_PWR_STATUS
, pwr_status
);
443 static void hubp_pg_control(
444 struct dc_context
*ctx
,
445 unsigned int hubp_inst
,
448 uint32_t inst_offset
= 0;
449 uint32_t power_gate
= power_on
? 0 : 1;
450 uint32_t pwr_status
= power_on
? 0 : 2;
452 if (ctx
->dc
->debug
.disable_hubp_power_gate
)
456 case 0: /* DCHUBP0 */
457 HWSEQ_REG_UPDATE(DOMAIN0_PG_CONFIG
,
458 DOMAIN0_POWER_GATE
, power_gate
);
460 wait_reg(ctx
, 0, DOMAIN0_PG_STATUS
,
461 DOMAIN0_PGFSM_PWR_STATUS
, pwr_status
);
463 case 1: /* DCHUBP1 */
464 HWSEQ_REG_UPDATE(DOMAIN2_PG_CONFIG
,
465 DOMAIN2_POWER_GATE
, power_gate
);
467 wait_reg(ctx
, 0, DOMAIN2_PG_STATUS
,
468 DOMAIN2_PGFSM_PWR_STATUS
, pwr_status
);
470 case 2: /* DCHUBP2 */
471 HWSEQ_REG_UPDATE(DOMAIN4_PG_CONFIG
,
472 DOMAIN4_POWER_GATE
, power_gate
);
474 wait_reg(ctx
, 0, DOMAIN4_PG_STATUS
,
475 DOMAIN4_PGFSM_PWR_STATUS
, pwr_status
);
477 case 3: /* DCHUBP3 */
478 HWSEQ_REG_UPDATE(DOMAIN6_PG_CONFIG
,
479 DOMAIN6_POWER_GATE
, power_gate
);
481 wait_reg(ctx
, 0, DOMAIN6_PG_STATUS
,
482 DOMAIN6_PGFSM_PWR_STATUS
, pwr_status
);
490 static void power_on_plane(
491 struct dc_context
*ctx
,
495 uint32_t inst_offset
= 0;
497 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL
,
499 dpp_pg_control(ctx
, plane_id
, true);
500 hubp_pg_control(ctx
, plane_id
, true);
501 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL
,
505 /* fully check bios enabledisplaypowergating table. dal only need dce init
506 * other power, clock gate register will be handle by dal itself.
507 * further may be put within init_hw
509 static bool dcn10_enable_display_power_gating(
511 uint8_t controller_id
,
513 enum pipe_gating_control power_gating
)
517 if (power_gating
!= PIPE_GATING_CONTROL_ENABLE
)
518 dce110_init_pte(ctx
);
524 static void bios_golden_init(struct core_dc
*dc
)
526 struct dc_bios
*bp
= dc
->ctx
->dc_bios
;
529 /* initialize dcn global */
530 bp
->funcs
->enable_disp_power_gating(bp
,
531 CONTROLLER_ID_D0
, ASIC_PIPE_INIT
);
533 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
534 /* initialize dcn per pipe */
535 bp
->funcs
->enable_disp_power_gating(bp
,
536 CONTROLLER_ID_D0
+ i
, ASIC_PIPE_DISABLE
);
540 static void init_hw(struct core_dc
*dc
)
544 struct transform
*xfm
;
547 bp
= dc
->ctx
->dc_bios
;
549 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
)) {
550 /* TODO: this will be moved to Diag or BIOS */
551 dchubup_setup_timer(dc
->ctx
);
553 /* TODO: dchubp_map_fb_to_mc will be moved to dchub interface
556 dchubp_map_fb_to_mc(dc
->ctx
);
558 enable_power_gating_plane(dc
->ctx
, true);
561 /* end of FPGA. Below if real ASIC */
563 bios_golden_init(dc
);
565 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
566 xfm
= dc
->res_pool
->transforms
[i
];
567 xfm
->funcs
->transform_reset(xfm
);
569 /* TODOFPGA: may need later */
571 xfm
->funcs
->transform_power_up(xfm
);
572 dc
->hwss
.enable_display_pipe_clock_gating(
577 /* TODOFPGA: light sleep */
579 dc
->hwss
.clock_gating_power_up(dc
->ctx
, false);
582 for (i
= 0; i
< dc
->link_count
; i
++) {
583 /* Power up AND update implementation according to the
584 * required signal (which may be different from the
585 * default signal on connector).
587 struct core_link
*link
= dc
->links
[i
];
589 link
->link_enc
->funcs
->hw_init(link
->link_enc
);
592 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
593 struct timing_generator
*tg
=
594 dc
->res_pool
->timing_generators
[i
];
596 tg
->funcs
->disable_vga(tg
);
598 /* Blank controller using driver code instead of
601 tg
->funcs
->set_blank(tg
, true);
602 hwss_wait_for_blank_complete(tg
);
605 for (i
= 0; i
< dc
->res_pool
->audio_count
; i
++) {
606 struct audio
*audio
= dc
->res_pool
->audios
[i
];
608 audio
->funcs
->hw_init(audio
);
611 abm
= dc
->res_pool
->abm
;
613 abm
->funcs
->init_backlight(abm
);
614 abm
->funcs
->abm_init(abm
);
617 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
618 generic_reg_set_soc15(dc
->ctx
, 0, DIO_MEM_PWR_CTRL
, 7,
619 FD(DIO_MEM_PWR_CTRL__HDMI0_MEM_PWR_FORCE
), 0,
620 FD(DIO_MEM_PWR_CTRL__HDMI1_MEM_PWR_FORCE
), 0,
621 FD(DIO_MEM_PWR_CTRL__HDMI2_MEM_PWR_FORCE
), 0,
622 FD(DIO_MEM_PWR_CTRL__HDMI3_MEM_PWR_FORCE
), 0,
623 FD(DIO_MEM_PWR_CTRL__HDMI4_MEM_PWR_FORCE
), 0,
624 FD(DIO_MEM_PWR_CTRL__HDMI5_MEM_PWR_FORCE
), 0,
625 FD(DIO_MEM_PWR_CTRL__HDMI6_MEM_PWR_FORCE
), 0);
627 if (!dc
->public.debug
.disable_clock_gate
) {
628 /* enable all DCN clock gating */
629 generic_reg_set_soc15(dc
->ctx
, 0, DCCG_GATE_DISABLE_CNTL
, 19,
630 FD(DCCG_GATE_DISABLE_CNTL__DISPCLK_DCCG_GATE_DISABLE
), 0,
631 FD(DCCG_GATE_DISABLE_CNTL__DISPCLK_R_DCCG_GATE_DISABLE
), 0,
632 FD(DCCG_GATE_DISABLE_CNTL__SOCCLK_GATE_DISABLE
), 0,
633 FD(DCCG_GATE_DISABLE_CNTL__DPREFCLK_GATE_DISABLE
), 0,
634 FD(DCCG_GATE_DISABLE_CNTL__DACACLK_GATE_DISABLE
), 0,
635 FD(DCCG_GATE_DISABLE_CNTL__DVOACLK_GATE_DISABLE
), 0,
636 FD(DCCG_GATE_DISABLE_CNTL__DPREFCLK_R_DCCG_GATE_DISABLE
), 0,
637 FD(DCCG_GATE_DISABLE_CNTL__DPPCLK_GATE_DISABLE
), 0,
638 FD(DCCG_GATE_DISABLE_CNTL__AOMCLK0_GATE_DISABLE
), 0,
639 FD(DCCG_GATE_DISABLE_CNTL__AOMCLK1_GATE_DISABLE
), 0,
640 FD(DCCG_GATE_DISABLE_CNTL__AOMCLK2_GATE_DISABLE
), 0,
641 FD(DCCG_GATE_DISABLE_CNTL__AUDIO_DTO2_CLK_GATE_DISABLE
), 0,
642 FD(DCCG_GATE_DISABLE_CNTL__DPREFCLK_GTC_GATE_DISABLE
), 0,
643 FD(DCCG_GATE_DISABLE_CNTL__UNB_DB_CLK_GATE_DISABLE
), 0,
644 FD(DCCG_GATE_DISABLE_CNTL__REFCLK_GATE_DISABLE
), 0,
645 FD(DCCG_GATE_DISABLE_CNTL__REFCLK_R_DIG_GATE_DISABLE
), 0,
646 FD(DCCG_GATE_DISABLE_CNTL__DSICLK_GATE_DISABLE
), 0,
647 FD(DCCG_GATE_DISABLE_CNTL__BYTECLK_GATE_DISABLE
), 0,
648 FD(DCCG_GATE_DISABLE_CNTL__ESCCLK_GATE_DISABLE
), 0);
650 generic_reg_set_soc15(dc
->ctx
, 0, DCCG_GATE_DISABLE_CNTL2
, 14,
651 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKA_FE_GATE_DISABLE
), 0,
652 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKB_FE_GATE_DISABLE
), 0,
653 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKC_FE_GATE_DISABLE
), 0,
654 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKD_FE_GATE_DISABLE
), 0,
655 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKE_FE_GATE_DISABLE
), 0,
656 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKF_FE_GATE_DISABLE
), 0,
657 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKG_FE_GATE_DISABLE
), 0,
658 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKA_GATE_DISABLE
), 0,
659 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKB_GATE_DISABLE
), 0,
660 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKC_GATE_DISABLE
), 0,
661 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKD_GATE_DISABLE
), 0,
662 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKE_GATE_DISABLE
), 0,
663 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKF_GATE_DISABLE
), 0,
664 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKG_GATE_DISABLE
), 0);
666 generic_reg_update_soc15(dc
->ctx
, 0, DCFCLK_CNTL
, 1,
667 FD(DCFCLK_CNTL__DCFCLK_GATE_DIS
), 0);
670 /* This power gating should be one-time program for DAL.
671 * It can only change by registry key
672 * TODO: new task will for this.
673 * if power gating is disable, power_on_plane and power_off_plane
674 * should be skip. Otherwise, hand will be met in power_off_plane
676 enable_power_gating_plane(dc
->ctx
, true);
681 static enum dc_status
dcn10_prog_pixclk_crtc_otg(
682 struct pipe_ctx
*pipe_ctx
,
683 struct validate_context
*context
,
686 struct core_stream
*stream
= pipe_ctx
->stream
;
687 enum dc_color_space color_space
;
688 struct tg_color black_color
= {0};
689 bool enableStereo
= stream
->public.timing
.timing_3d_format
== TIMING_3D_FORMAT_NONE
?
691 bool rightEyePolarity
= stream
->public.timing
.flags
.RIGHT_EYE_3D_POLARITY
;
694 /* by upper caller loop, pipe0 is parent pipe and be called first.
695 * back end is set up by for pipe0. Other children pipe share back end
696 * with pipe 0. No program is needed.
698 if (pipe_ctx
->top_pipe
!= NULL
)
701 /* TODO check if timing_changed, disable stream if timing changed */
703 /* HW program guide assume display already disable
704 * by unplug sequence. OTG assume stop.
706 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, true);
708 if (false == pipe_ctx
->clock_source
->funcs
->program_pix_clk(
709 pipe_ctx
->clock_source
,
710 &pipe_ctx
->pix_clk_params
,
711 &pipe_ctx
->pll_settings
)) {
713 return DC_ERROR_UNEXPECTED
;
715 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
716 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
717 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
718 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
720 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
722 pipe_ctx
->tg
->funcs
->program_timing(
724 &stream
->public.timing
,
727 pipe_ctx
->opp
->funcs
->opp_set_stereo_polarity(
732 #if 0 /* move to after enable_crtc */
733 /* TODO: OPP FMT, ABM. etc. should be done here. */
734 /* or FPGA now. instance 0 only. TODO: move to opp.c */
736 inst_offset
= reg_offsets
[pipe_ctx
->tg
->inst
].fmt
;
738 pipe_ctx
->opp
->funcs
->opp_program_fmt(
740 &stream
->bit_depth_params
,
743 /* program otg blank color */
744 color_space
= stream
->public.output_color_space
;
745 color_space_to_black_color(dc
, color_space
, &black_color
);
746 pipe_ctx
->tg
->funcs
->set_blank_color(
750 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, true);
751 hwss_wait_for_blank_complete(pipe_ctx
->tg
);
753 /* VTG is within DCHUB command block. DCFCLK is always on */
754 if (false == pipe_ctx
->tg
->funcs
->enable_crtc(pipe_ctx
->tg
)) {
756 return DC_ERROR_UNEXPECTED
;
759 /* TODO program crtc source select for non-virtual signal*/
760 /* TODO program FMT */
761 /* TODO setup link_enc */
762 /* TODO set stream attributes */
763 /* TODO program audio */
764 /* TODO enable stream if timing changed */
765 /* TODO unblank stream if DP */
770 static void reset_back_end_for_pipe(
772 struct pipe_ctx
*pipe_ctx
,
773 struct validate_context
*context
)
778 bp
= dc
->ctx
->dc_bios
;
780 if (pipe_ctx
->stream_enc
== NULL
) {
781 pipe_ctx
->stream
= NULL
;
785 /* TODOFPGA break core_link_disable_stream into 2 functions:
786 * disable_stream and disable_link. disable_link will disable PHYPLL
787 * which is used by otg. Move disable_link after disable_crtc
789 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
790 core_link_disable_stream(pipe_ctx
);
792 /* by upper caller loop, parent pipe: pipe0, will be reset last.
793 * back end share by all pipes and will be disable only when disable
796 if (pipe_ctx
->top_pipe
== NULL
) {
797 pipe_ctx
->tg
->funcs
->disable_crtc(pipe_ctx
->tg
);
799 pipe_ctx
->tg
->funcs
->enable_optc_clock(pipe_ctx
->tg
, false);
802 if (!IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
803 resource_unreference_clock_source(
804 &context
->res_ctx
, dc
->res_pool
,
805 &pipe_ctx
->clock_source
);
807 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++)
808 if (&dc
->current_context
->res_ctx
.pipe_ctx
[i
] == pipe_ctx
)
811 if (i
== dc
->res_pool
->pipe_count
)
814 pipe_ctx
->stream
= NULL
;
817 static void reset_front_end_for_pipe(
819 struct pipe_ctx
*pipe_ctx
,
820 struct validate_context
*context
)
822 struct dcn10_mpc
*mpc
= TO_DCN10_MPC(dc
->res_pool
->mpc
);
823 struct mpc_tree_cfg
*tree_cfg
= NULL
;
825 if (!pipe_ctx
->surface
)
828 lock_otg_master_update(dc
->ctx
, pipe_ctx
->tg
->inst
);
830 /* TODO: build stream pipes group id. For now, use stream otg
831 * id as pipe group id
833 tree_cfg
= &dc
->current_context
->res_ctx
.mpc_tree
[pipe_ctx
->mpc_idx
];
835 if (!dcn10_remove_dpp(mpc
, tree_cfg
, pipe_ctx
->pipe_idx
)) {
836 dm_logger_write(dc
->ctx
->logger
, LOG_RESOURCE
,
837 "%s: failed to find dpp to be removed!\n",
841 pipe_ctx
->top_pipe
= NULL
;
842 pipe_ctx
->bottom_pipe
= NULL
;
843 pipe_ctx
->mpc_idx
= -1;
845 unlock_master_tg_and_wait(dc
->ctx
, pipe_ctx
->tg
->inst
);
847 pipe_ctx
->mi
->funcs
->set_blank(pipe_ctx
->mi
, true);
849 wait_no_outstanding_request(dc
->ctx
, pipe_ctx
->pipe_idx
);
851 wait_mpcc_idle(mpc
, pipe_ctx
->pipe_idx
);
853 disable_clocks(dc
->ctx
, pipe_ctx
->pipe_idx
);
855 pipe_ctx
->xfm
->funcs
->transform_reset(pipe_ctx
->xfm
);
857 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
858 "Reset front end for pipe %d\n",
861 pipe_ctx
->surface
= NULL
;
864 static void reset_hw_ctx(struct core_dc
*dc
,
865 struct validate_context
*context
,
866 void (*reset
)(struct core_dc
*dc
,
867 struct pipe_ctx
*pipe_ctx
,
868 struct validate_context
*context
))
872 for (i
= dc
->res_pool
->pipe_count
- 1; i
>= 0 ; i
--) {
873 struct pipe_ctx
*pipe_ctx_old
=
874 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
875 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
877 if (!pipe_ctx_old
->stream
)
880 if (!pipe_ctx
->stream
||
881 pipe_need_reprogram(pipe_ctx_old
, pipe_ctx
))
882 reset(dc
, pipe_ctx_old
, dc
->current_context
);
886 static void reset_hw_ctx_wrap(
888 struct validate_context
*context
)
891 reset_hw_ctx(dc
, context
, reset_front_end_for_pipe
);
893 reset_hw_ctx(dc
, context
, reset_back_end_for_pipe
);
895 memcpy(context
->res_ctx
.mpc_tree
,
896 dc
->current_context
->res_ctx
.mpc_tree
,
897 sizeof(struct mpc_tree_cfg
) * dc
->res_pool
->pipe_count
);
900 static bool patch_address_for_sbs_tb_stereo(struct pipe_ctx
*pipe_ctx
,
901 PHYSICAL_ADDRESS_LOC
*addr
)
903 struct core_surface
*surface
= pipe_ctx
->surface
;
904 bool sec_split
= pipe_ctx
->top_pipe
&&
905 pipe_ctx
->top_pipe
->surface
== pipe_ctx
->surface
;
906 if (sec_split
&& surface
->public.address
.type
== PLN_ADDR_TYPE_GRPH_STEREO
&&
907 (pipe_ctx
->stream
->public.timing
.timing_3d_format
==
908 TIMING_3D_FORMAT_SIDE_BY_SIDE
||
909 pipe_ctx
->stream
->public.timing
.timing_3d_format
==
910 TIMING_3D_FORMAT_TOP_AND_BOTTOM
)) {
911 *addr
= surface
->public.address
.grph_stereo
.left_addr
;
912 surface
->public.address
.grph_stereo
.left_addr
=\
913 surface
->public.address
.grph_stereo
.right_addr
;
919 static void update_plane_addr(const struct core_dc
*dc
, struct pipe_ctx
*pipe_ctx
)
921 bool addr_patched
= false;
922 PHYSICAL_ADDRESS_LOC addr
;
923 struct core_surface
*surface
= pipe_ctx
->surface
;
927 addr_patched
= patch_address_for_sbs_tb_stereo(pipe_ctx
, &addr
);
928 pipe_ctx
->mi
->funcs
->mem_input_program_surface_flip_and_addr(
930 &surface
->public.address
,
931 surface
->public.flip_immediate
);
932 surface
->status
.requested_address
= surface
->public.address
;
934 pipe_ctx
->surface
->public.address
.grph_stereo
.left_addr
= addr
;
937 static bool dcn10_set_input_transfer_func(
938 struct pipe_ctx
*pipe_ctx
,
939 const struct core_surface
*surface
)
941 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
942 const struct core_transfer_func
*tf
= NULL
;
948 if (surface
->public.in_transfer_func
)
949 tf
= DC_TRANSFER_FUNC_TO_CORE(surface
->public.in_transfer_func
);
951 if (surface
->public.gamma_correction
&& dce_use_lut(surface
))
952 ipp
->funcs
->ipp_program_input_lut(ipp
,
953 surface
->public.gamma_correction
);
956 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
957 else if (tf
->public.type
== TF_TYPE_PREDEFINED
) {
958 switch (tf
->public.tf
) {
959 case TRANSFER_FUNCTION_SRGB
:
960 ipp
->funcs
->ipp_set_degamma(ipp
,
961 IPP_DEGAMMA_MODE_HW_sRGB
);
963 case TRANSFER_FUNCTION_BT709
:
964 ipp
->funcs
->ipp_set_degamma(ipp
,
965 IPP_DEGAMMA_MODE_HW_xvYCC
);
967 case TRANSFER_FUNCTION_LINEAR
:
968 ipp
->funcs
->ipp_set_degamma(ipp
,
969 IPP_DEGAMMA_MODE_BYPASS
);
971 case TRANSFER_FUNCTION_PQ
:
978 } else if (tf
->public.type
== TF_TYPE_BYPASS
) {
979 ipp
->funcs
->ipp_set_degamma(ipp
, IPP_DEGAMMA_MODE_BYPASS
);
981 /*TF_TYPE_DISTRIBUTED_POINTS*/
987 /*modify the method to handle rgb for arr_points*/
988 static bool convert_to_custom_float(
989 struct pwl_result_data
*rgb_resulted
,
990 struct curve_points
*arr_points
,
991 uint32_t hw_points_num
)
993 struct custom_float_format fmt
;
995 struct pwl_result_data
*rgb
= rgb_resulted
;
999 fmt
.exponenta_bits
= 6;
1000 fmt
.mantissa_bits
= 12;
1003 if (!convert_to_custom_float_format(
1006 &arr_points
[0].custom_float_x
)) {
1007 BREAK_TO_DEBUGGER();
1011 if (!convert_to_custom_float_format(
1012 arr_points
[0].offset
,
1014 &arr_points
[0].custom_float_offset
)) {
1015 BREAK_TO_DEBUGGER();
1019 if (!convert_to_custom_float_format(
1020 arr_points
[0].slope
,
1022 &arr_points
[0].custom_float_slope
)) {
1023 BREAK_TO_DEBUGGER();
1027 fmt
.mantissa_bits
= 10;
1030 if (!convert_to_custom_float_format(
1033 &arr_points
[1].custom_float_x
)) {
1034 BREAK_TO_DEBUGGER();
1038 if (!convert_to_custom_float_format(
1041 &arr_points
[1].custom_float_y
)) {
1042 BREAK_TO_DEBUGGER();
1046 if (!convert_to_custom_float_format(
1047 arr_points
[1].slope
,
1049 &arr_points
[1].custom_float_slope
)) {
1050 BREAK_TO_DEBUGGER();
1054 fmt
.mantissa_bits
= 12;
1057 while (i
!= hw_points_num
) {
1058 if (!convert_to_custom_float_format(
1062 BREAK_TO_DEBUGGER();
1066 if (!convert_to_custom_float_format(
1070 BREAK_TO_DEBUGGER();
1074 if (!convert_to_custom_float_format(
1078 BREAK_TO_DEBUGGER();
1082 if (!convert_to_custom_float_format(
1085 &rgb
->delta_red_reg
)) {
1086 BREAK_TO_DEBUGGER();
1090 if (!convert_to_custom_float_format(
1093 &rgb
->delta_green_reg
)) {
1094 BREAK_TO_DEBUGGER();
1098 if (!convert_to_custom_float_format(
1101 &rgb
->delta_blue_reg
)) {
1102 BREAK_TO_DEBUGGER();
1112 #define MAX_REGIONS_NUMBER 34
1113 #define MAX_LOW_POINT 25
1114 #define NUMBER_SEGMENTS 32
1116 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
1117 *output_tf
, struct pwl_params
*regamma_params
)
1119 struct curve_points
*arr_points
;
1120 struct pwl_result_data
*rgb_resulted
;
1121 struct pwl_result_data
*rgb
;
1122 struct pwl_result_data
*rgb_plus_1
;
1123 struct fixed31_32 y_r
;
1124 struct fixed31_32 y_g
;
1125 struct fixed31_32 y_b
;
1126 struct fixed31_32 y1_min
;
1127 struct fixed31_32 y3_max
;
1129 int32_t segment_start
, segment_end
;
1131 uint32_t j
, k
, seg_distr
[MAX_REGIONS_NUMBER
], increment
, start_index
, hw_points
;
1133 if (output_tf
== NULL
|| regamma_params
== NULL
||
1134 output_tf
->type
== TF_TYPE_BYPASS
)
1137 arr_points
= regamma_params
->arr_points
;
1138 rgb_resulted
= regamma_params
->rgb_resulted
;
1141 memset(regamma_params
, 0, sizeof(struct pwl_params
));
1142 memset(seg_distr
, 0, sizeof(seg_distr
));
1144 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
1146 * segments are from 2^-25 to 2^7
1148 for (i
= 0; i
< 32 ; i
++)
1151 segment_start
= -25;
1155 * segment is from 2^-10 to 2^0
1156 * There are less than 256 points, for optimization
1169 segment_start
= -10;
1173 for (i
= segment_end
- segment_start
; i
< MAX_REGIONS_NUMBER
; i
++)
1176 for (k
= 0; k
< MAX_REGIONS_NUMBER
; k
++) {
1177 if (seg_distr
[k
] != -1)
1178 hw_points
+= (1 << seg_distr
[k
]);
1182 for (k
= 0; k
< (segment_end
- segment_start
); k
++) {
1183 increment
= NUMBER_SEGMENTS
/ (1 << seg_distr
[k
]);
1184 start_index
= (segment_start
+ k
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
1185 for (i
= start_index
; i
< start_index
+ NUMBER_SEGMENTS
; i
+= increment
) {
1186 if (j
== hw_points
- 1)
1188 rgb_resulted
[j
].red
= output_tf
->tf_pts
.red
[i
];
1189 rgb_resulted
[j
].green
= output_tf
->tf_pts
.green
[i
];
1190 rgb_resulted
[j
].blue
= output_tf
->tf_pts
.blue
[i
];
1196 start_index
= (segment_end
+ MAX_LOW_POINT
) * NUMBER_SEGMENTS
;
1197 rgb_resulted
[hw_points
- 1].red
=
1198 output_tf
->tf_pts
.red
[start_index
];
1199 rgb_resulted
[hw_points
- 1].green
=
1200 output_tf
->tf_pts
.green
[start_index
];
1201 rgb_resulted
[hw_points
- 1].blue
=
1202 output_tf
->tf_pts
.blue
[start_index
];
1204 arr_points
[0].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1205 dal_fixed31_32_from_int(segment_start
));
1206 arr_points
[1].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1207 dal_fixed31_32_from_int(segment_end
));
1208 arr_points
[2].x
= dal_fixed31_32_pow(dal_fixed31_32_from_int(2),
1209 dal_fixed31_32_from_int(segment_end
));
1211 y_r
= rgb_resulted
[0].red
;
1212 y_g
= rgb_resulted
[0].green
;
1213 y_b
= rgb_resulted
[0].blue
;
1215 y1_min
= dal_fixed31_32_min(y_r
, dal_fixed31_32_min(y_g
, y_b
));
1217 arr_points
[0].y
= y1_min
;
1218 arr_points
[0].slope
= dal_fixed31_32_div(
1221 y_r
= rgb_resulted
[hw_points
- 1].red
;
1222 y_g
= rgb_resulted
[hw_points
- 1].green
;
1223 y_b
= rgb_resulted
[hw_points
- 1].blue
;
1225 /* see comment above, m_arrPoints[1].y should be the Y value for the
1226 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
1228 y3_max
= dal_fixed31_32_max(y_r
, dal_fixed31_32_max(y_g
, y_b
));
1230 arr_points
[1].y
= y3_max
;
1231 arr_points
[2].y
= y3_max
;
1233 arr_points
[1].slope
= dal_fixed31_32_zero
;
1234 arr_points
[2].slope
= dal_fixed31_32_zero
;
1236 if (output_tf
->tf
== TRANSFER_FUNCTION_PQ
) {
1237 /* for PQ, we want to have a straight line from last HW X point,
1238 * and the slope to be such that we hit 1.0 at 10000 nits.
1240 const struct fixed31_32 end_value
=
1241 dal_fixed31_32_from_int(125);
1243 arr_points
[1].slope
= dal_fixed31_32_div(
1244 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
1245 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
1246 arr_points
[2].slope
= dal_fixed31_32_div(
1247 dal_fixed31_32_sub(dal_fixed31_32_one
, arr_points
[1].y
),
1248 dal_fixed31_32_sub(end_value
, arr_points
[1].x
));
1251 regamma_params
->hw_points_num
= hw_points
;
1254 for (k
= 0; k
< MAX_REGIONS_NUMBER
&& i
< MAX_REGIONS_NUMBER
; k
++) {
1255 if (seg_distr
[k
] != -1) {
1256 regamma_params
->arr_curve_points
[k
].segments_num
=
1258 regamma_params
->arr_curve_points
[i
].offset
=
1259 regamma_params
->arr_curve_points
[k
].
1260 offset
+ (1 << seg_distr
[k
]);
1265 if (seg_distr
[k
] != -1)
1266 regamma_params
->arr_curve_points
[k
].segments_num
=
1270 rgb_plus_1
= rgb_resulted
+ 1;
1274 while (i
!= hw_points
+ 1) {
1275 if (dal_fixed31_32_lt(rgb_plus_1
->red
, rgb
->red
))
1276 rgb_plus_1
->red
= rgb
->red
;
1277 if (dal_fixed31_32_lt(rgb_plus_1
->green
, rgb
->green
))
1278 rgb_plus_1
->green
= rgb
->green
;
1279 if (dal_fixed31_32_lt(rgb_plus_1
->blue
, rgb
->blue
))
1280 rgb_plus_1
->blue
= rgb
->blue
;
1282 rgb
->delta_red
= dal_fixed31_32_sub(
1285 rgb
->delta_green
= dal_fixed31_32_sub(
1288 rgb
->delta_blue
= dal_fixed31_32_sub(
1297 convert_to_custom_float(rgb_resulted
, arr_points
, hw_points
);
1302 static bool dcn10_set_output_transfer_func(
1303 struct pipe_ctx
*pipe_ctx
,
1304 const struct core_stream
*stream
)
1306 struct output_pixel_processor
*opp
= pipe_ctx
->opp
;
1311 opp
->regamma_params
.hw_points_num
= GAMMA_HW_POINTS_NUM
;
1313 if (stream
->public.out_transfer_func
&&
1314 stream
->public.out_transfer_func
->type
==
1315 TF_TYPE_PREDEFINED
&&
1316 stream
->public.out_transfer_func
->tf
==
1317 TRANSFER_FUNCTION_SRGB
) {
1318 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_SRGB
);
1319 } else if (dcn10_translate_regamma_to_hw_format(
1320 stream
->public.out_transfer_func
, &opp
->regamma_params
)) {
1321 opp
->funcs
->opp_program_regamma_pwl(opp
, &opp
->regamma_params
);
1322 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_USER
);
1324 opp
->funcs
->opp_set_regamma_mode(opp
, OPP_REGAMMA_BYPASS
);
1330 static void dcn10_pipe_control_lock(
1332 struct pipe_ctx
*pipe
,
1335 struct dce_hwseq
*hws
= hws
= dc
->hwseq
;
1337 /* use TG master update lock to lock everything on the TG
1338 * therefore only top pipe need to lock
1344 dcn10_lock(pipe
->tg
);
1346 dcn10_unlock(pipe
->tg
);
1349 static bool wait_for_reset_trigger_to_occur(
1350 struct dc_context
*dc_ctx
,
1351 struct timing_generator
*tg
)
1355 /* To avoid endless loop we wait at most
1356 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1357 const uint32_t frames_to_wait_on_triggered_reset
= 10;
1360 for (i
= 0; i
< frames_to_wait_on_triggered_reset
; i
++) {
1362 if (!tg
->funcs
->is_counter_moving(tg
)) {
1363 DC_ERROR("TG counter is not moving!\n");
1367 if (tg
->funcs
->did_triggered_reset_occur(tg
)) {
1369 /* usually occurs at i=1 */
1370 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1375 /* Wait for one frame. */
1376 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VACTIVE
);
1377 tg
->funcs
->wait_for_state(tg
, CRTC_STATE_VBLANK
);
1381 DC_ERROR("GSL: Timeout on reset trigger!\n");
1386 static void dcn10_enable_timing_synchronization(
1390 struct pipe_ctx
*grouped_pipes
[])
1392 struct dc_context
*dc_ctx
= dc
->ctx
;
1395 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1397 for (i
= 1; i
< group_size
; i
++)
1398 grouped_pipes
[i
]->tg
->funcs
->enable_reset_trigger(
1399 grouped_pipes
[i
]->tg
, grouped_pipes
[0]->tg
->inst
);
1402 DC_SYNC_INFO("Waiting for trigger\n");
1404 /* Need to get only check 1 pipe for having reset as all the others are
1405 * synchronized. Look at last pipe programmed to reset.
1407 wait_for_reset_trigger_to_occur(dc_ctx
, grouped_pipes
[1]->tg
);
1408 for (i
= 1; i
< group_size
; i
++)
1409 grouped_pipes
[i
]->tg
->funcs
->disable_reset_trigger(
1410 grouped_pipes
[i
]->tg
);
1412 DC_SYNC_INFO("Sync complete\n");
1415 static void print_rq_dlg_ttu(
1416 struct core_dc
*core_dc
,
1417 struct pipe_ctx
*pipe_ctx
)
1419 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1420 "\n============== DML TTU Output parameters [%d] ==============\n"
1421 "qos_level_low_wm: %d, \n"
1422 "qos_level_high_wm: %d, \n"
1423 "min_ttu_vblank: %d, \n"
1424 "qos_level_flip: %d, \n"
1425 "refcyc_per_req_delivery_l: %d, \n"
1426 "qos_level_fixed_l: %d, \n"
1427 "qos_ramp_disable_l: %d, \n"
1428 "refcyc_per_req_delivery_pre_l: %d, \n"
1429 "refcyc_per_req_delivery_c: %d, \n"
1430 "qos_level_fixed_c: %d, \n"
1431 "qos_ramp_disable_c: %d, \n"
1432 "refcyc_per_req_delivery_pre_c: %d\n"
1433 "=============================================================\n",
1435 pipe_ctx
->ttu_regs
.qos_level_low_wm
,
1436 pipe_ctx
->ttu_regs
.qos_level_high_wm
,
1437 pipe_ctx
->ttu_regs
.min_ttu_vblank
,
1438 pipe_ctx
->ttu_regs
.qos_level_flip
,
1439 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_l
,
1440 pipe_ctx
->ttu_regs
.qos_level_fixed_l
,
1441 pipe_ctx
->ttu_regs
.qos_ramp_disable_l
,
1442 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_pre_l
,
1443 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_c
,
1444 pipe_ctx
->ttu_regs
.qos_level_fixed_c
,
1445 pipe_ctx
->ttu_regs
.qos_ramp_disable_c
,
1446 pipe_ctx
->ttu_regs
.refcyc_per_req_delivery_pre_c
1449 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1450 "\n============== DML DLG Output parameters [%d] ==============\n"
1451 "refcyc_h_blank_end: %d, \n"
1452 "dlg_vblank_end: %d, \n"
1453 "min_dst_y_next_start: %d, \n"
1454 "refcyc_per_htotal: %d, \n"
1455 "refcyc_x_after_scaler: %d, \n"
1456 "dst_y_after_scaler: %d, \n"
1457 "dst_y_prefetch: %d, \n"
1458 "dst_y_per_vm_vblank: %d, \n"
1459 "dst_y_per_row_vblank: %d, \n"
1460 "ref_freq_to_pix_freq: %d, \n"
1461 "vratio_prefetch: %d, \n"
1462 "refcyc_per_pte_group_vblank_l: %d, \n"
1463 "refcyc_per_meta_chunk_vblank_l: %d, \n"
1464 "dst_y_per_pte_row_nom_l: %d, \n"
1465 "refcyc_per_pte_group_nom_l: %d, \n",
1467 pipe_ctx
->dlg_regs
.refcyc_h_blank_end
,
1468 pipe_ctx
->dlg_regs
.dlg_vblank_end
,
1469 pipe_ctx
->dlg_regs
.min_dst_y_next_start
,
1470 pipe_ctx
->dlg_regs
.refcyc_per_htotal
,
1471 pipe_ctx
->dlg_regs
.refcyc_x_after_scaler
,
1472 pipe_ctx
->dlg_regs
.dst_y_after_scaler
,
1473 pipe_ctx
->dlg_regs
.dst_y_prefetch
,
1474 pipe_ctx
->dlg_regs
.dst_y_per_vm_vblank
,
1475 pipe_ctx
->dlg_regs
.dst_y_per_row_vblank
,
1476 pipe_ctx
->dlg_regs
.ref_freq_to_pix_freq
,
1477 pipe_ctx
->dlg_regs
.vratio_prefetch
,
1478 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_vblank_l
,
1479 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_vblank_l
,
1480 pipe_ctx
->dlg_regs
.dst_y_per_pte_row_nom_l
,
1481 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_nom_l
1484 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1485 "\ndst_y_per_meta_row_nom_l: %d, \n"
1486 "refcyc_per_meta_chunk_nom_l: %d, \n"
1487 "refcyc_per_line_delivery_pre_l: %d, \n"
1488 "refcyc_per_line_delivery_l: %d, \n"
1489 "vratio_prefetch_c: %d, \n"
1490 "refcyc_per_pte_group_vblank_c: %d, \n"
1491 "refcyc_per_meta_chunk_vblank_c: %d, \n"
1492 "dst_y_per_pte_row_nom_c: %d, \n"
1493 "refcyc_per_pte_group_nom_c: %d, \n"
1494 "dst_y_per_meta_row_nom_c: %d, \n"
1495 "refcyc_per_meta_chunk_nom_c: %d, \n"
1496 "refcyc_per_line_delivery_pre_c: %d, \n"
1497 "refcyc_per_line_delivery_c: %d \n"
1498 "========================================================\n",
1499 pipe_ctx
->dlg_regs
.dst_y_per_meta_row_nom_l
,
1500 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_nom_l
,
1501 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_pre_l
,
1502 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_l
,
1503 pipe_ctx
->dlg_regs
.vratio_prefetch_c
,
1504 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_vblank_c
,
1505 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_vblank_c
,
1506 pipe_ctx
->dlg_regs
.dst_y_per_pte_row_nom_c
,
1507 pipe_ctx
->dlg_regs
.refcyc_per_pte_group_nom_c
,
1508 pipe_ctx
->dlg_regs
.dst_y_per_meta_row_nom_c
,
1509 pipe_ctx
->dlg_regs
.refcyc_per_meta_chunk_nom_c
,
1510 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_pre_c
,
1511 pipe_ctx
->dlg_regs
.refcyc_per_line_delivery_c
1514 dm_logger_write(core_dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1515 "\n============== DML RQ Output parameters [%d] ==============\n"
1517 "min_chunk_size: %d \n"
1518 "meta_chunk_size: %d \n"
1519 "min_meta_chunk_size: %d \n"
1520 "dpte_group_size: %d \n"
1521 "mpte_group_size: %d \n"
1522 "swath_height: %d \n"
1523 "pte_row_height_linear: %d \n"
1524 "========================================================\n",
1526 pipe_ctx
->rq_regs
.rq_regs_l
.chunk_size
,
1527 pipe_ctx
->rq_regs
.rq_regs_l
.min_chunk_size
,
1528 pipe_ctx
->rq_regs
.rq_regs_l
.meta_chunk_size
,
1529 pipe_ctx
->rq_regs
.rq_regs_l
.min_meta_chunk_size
,
1530 pipe_ctx
->rq_regs
.rq_regs_l
.dpte_group_size
,
1531 pipe_ctx
->rq_regs
.rq_regs_l
.mpte_group_size
,
1532 pipe_ctx
->rq_regs
.rq_regs_l
.swath_height
,
1533 pipe_ctx
->rq_regs
.rq_regs_l
.pte_row_height_linear
1537 static void dcn10_power_on_fe(
1539 struct pipe_ctx
*pipe_ctx
,
1540 struct validate_context
*context
)
1542 struct dc_surface
*dc_surface
= &pipe_ctx
->surface
->public;
1544 power_on_plane(dc
->ctx
,
1545 pipe_ctx
->pipe_idx
, pipe_ctx
->tg
->inst
);
1547 /* enable DCFCLK current DCHUB */
1548 enable_dcfclk(dc
->ctx
,
1550 pipe_ctx
->pix_clk_params
.requested_pix_clk
,
1551 context
->bw
.dcn
.calc_clk
.dppclk_div
);
1552 dc
->current_context
->bw
.dcn
.cur_clk
.dppclk_div
=
1553 context
->bw
.dcn
.calc_clk
.dppclk_div
;
1554 context
->bw
.dcn
.cur_clk
.dppclk_div
= context
->bw
.dcn
.calc_clk
.dppclk_div
;
1557 dm_logger_write(dc
->ctx
->logger
, LOG_DC
,
1558 "Pipe:%d 0x%x: addr hi:0x%x, "
1561 " %d; dst: %d, %d, %d, %d;\n",
1564 dc_surface
->address
.grph
.addr
.high_part
,
1565 dc_surface
->address
.grph
.addr
.low_part
,
1566 dc_surface
->src_rect
.x
,
1567 dc_surface
->src_rect
.y
,
1568 dc_surface
->src_rect
.width
,
1569 dc_surface
->src_rect
.height
,
1570 dc_surface
->dst_rect
.x
,
1571 dc_surface
->dst_rect
.y
,
1572 dc_surface
->dst_rect
.width
,
1573 dc_surface
->dst_rect
.height
);
1575 dm_logger_write(dc
->ctx
->logger
, LOG_HW_SET_MODE
,
1576 "Pipe %d: width, height, x, y\n"
1577 "viewport:%d, %d, %d, %d\n"
1578 "recout: %d, %d, %d, %d\n",
1580 pipe_ctx
->scl_data
.viewport
.width
,
1581 pipe_ctx
->scl_data
.viewport
.height
,
1582 pipe_ctx
->scl_data
.viewport
.x
,
1583 pipe_ctx
->scl_data
.viewport
.y
,
1584 pipe_ctx
->scl_data
.recout
.width
,
1585 pipe_ctx
->scl_data
.recout
.height
,
1586 pipe_ctx
->scl_data
.recout
.x
,
1587 pipe_ctx
->scl_data
.recout
.y
);
1588 print_rq_dlg_ttu(dc
, pipe_ctx
);
1592 static void program_gamut_remap(struct pipe_ctx
*pipe_ctx
)
1594 struct xfm_grph_csc_adjustment adjust
;
1595 memset(&adjust
, 0, sizeof(adjust
));
1596 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS
;
1599 if (pipe_ctx
->stream
->public.gamut_remap_matrix
.enable_remap
== true) {
1600 adjust
.gamut_adjust_type
= GRAPHICS_GAMUT_ADJUST_TYPE_SW
;
1601 adjust
.temperature_matrix
[0] =
1603 public.gamut_remap_matrix
.matrix
[0];
1604 adjust
.temperature_matrix
[1] =
1606 public.gamut_remap_matrix
.matrix
[1];
1607 adjust
.temperature_matrix
[2] =
1609 public.gamut_remap_matrix
.matrix
[2];
1610 adjust
.temperature_matrix
[3] =
1612 public.gamut_remap_matrix
.matrix
[4];
1613 adjust
.temperature_matrix
[4] =
1615 public.gamut_remap_matrix
.matrix
[5];
1616 adjust
.temperature_matrix
[5] =
1618 public.gamut_remap_matrix
.matrix
[6];
1619 adjust
.temperature_matrix
[6] =
1621 public.gamut_remap_matrix
.matrix
[8];
1622 adjust
.temperature_matrix
[7] =
1624 public.gamut_remap_matrix
.matrix
[9];
1625 adjust
.temperature_matrix
[8] =
1627 public.gamut_remap_matrix
.matrix
[10];
1630 pipe_ctx
->xfm
->funcs
->transform_set_gamut_remap(pipe_ctx
->xfm
, &adjust
);
1633 static bool is_lower_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1635 if (pipe_ctx
->surface
->public.visible
)
1637 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1642 static bool is_upper_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1644 if (pipe_ctx
->surface
->public.visible
)
1646 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1651 static bool is_pipe_tree_visible(struct pipe_ctx
*pipe_ctx
)
1653 if (pipe_ctx
->surface
->public.visible
)
1655 if (pipe_ctx
->top_pipe
&& is_upper_pipe_tree_visible(pipe_ctx
->top_pipe
))
1657 if (pipe_ctx
->bottom_pipe
&& is_lower_pipe_tree_visible(pipe_ctx
->bottom_pipe
))
1662 static void update_dchubp_dpp(
1664 struct pipe_ctx
*pipe_ctx
,
1665 struct validate_context
*context
)
1667 struct mem_input
*mi
= pipe_ctx
->mi
;
1668 struct input_pixel_processor
*ipp
= pipe_ctx
->ipp
;
1669 struct core_surface
*surface
= pipe_ctx
->surface
;
1670 union plane_size size
= surface
->public.plane_size
;
1671 struct mpc_tree_cfg
*tree_cfg
= NULL
;
1672 struct default_adjustment ocsc
= {0};
1673 enum dc_color_space color_space
;
1674 struct tg_color black_color
= {0};
1675 struct dcn10_mpc
*mpc
= TO_DCN10_MPC(dc
->res_pool
->mpc
);
1676 struct pipe_ctx
*temp_pipe
;
1679 bool per_pixel_alpha
= surface
->public.per_pixel_alpha
&& pipe_ctx
->bottom_pipe
;
1681 /* TODO: proper fix once fpga works */
1682 /* depends on DML calculation, DPP clock value may change dynamically */
1686 pipe_ctx
->pix_clk_params
.requested_pix_clk
,
1687 context
->bw
.dcn
.calc_clk
.dppclk_div
);
1688 dc
->current_context
->bw
.dcn
.cur_clk
.dppclk_div
=
1689 context
->bw
.dcn
.calc_clk
.dppclk_div
;
1690 context
->bw
.dcn
.cur_clk
.dppclk_div
= context
->bw
.dcn
.calc_clk
.dppclk_div
;
1692 select_vtg(dc
->ctx
, pipe_ctx
->pipe_idx
, pipe_ctx
->tg
->inst
);
1694 update_plane_addr(dc
, pipe_ctx
);
1696 mi
->funcs
->mem_input_setup(
1698 &pipe_ctx
->dlg_regs
,
1699 &pipe_ctx
->ttu_regs
,
1701 &pipe_ctx
->pipe_dlg_param
);
1703 size
.grph
.surface_size
= pipe_ctx
->scl_data
.viewport
;
1705 if (dc
->public.config
.gpu_vm_support
)
1706 mi
->funcs
->mem_input_program_pte_vm(
1708 surface
->public.format
,
1709 &surface
->public.tiling_info
,
1710 surface
->public.rotation
);
1712 ipp
->funcs
->ipp_setup(ipp
,
1713 surface
->public.format
,
1715 IPP_OUTPUT_FORMAT_12_BIT_FIX
);
1717 /* mpc TODO un-hardcode object ids
1718 * for pseudo code pipe_move.c :
1719 * add_plane_mpcc(added_plane_inst, mpcc_inst, ...);
1720 * Do we want to cache the tree_cfg?
1723 /* TODO: build stream pipes group id. For now, use stream otg
1724 * id as pipe group id
1726 pipe_ctx
->scl_data
.lb_params
.alpha_en
= per_pixel_alpha
;
1727 pipe_ctx
->mpc_idx
= pipe_ctx
->tg
->inst
;
1728 tree_cfg
= &context
->res_ctx
.mpc_tree
[pipe_ctx
->mpc_idx
];
1729 if (tree_cfg
->num_pipes
== 0) {
1730 tree_cfg
->opp_id
= pipe_ctx
->tg
->inst
;
1731 for (i
= 0; i
< MAX_PIPES
; i
++) {
1732 tree_cfg
->dpp
[i
] = 0xf;
1733 tree_cfg
->mpcc
[i
] = 0xf;
1737 for (temp_pipe
= pipe_ctx
->top_pipe
;
1738 temp_pipe
!= NULL
; temp_pipe
= temp_pipe
->top_pipe
)
1741 tree_cfg
->dpp
[tree_pos
] = pipe_ctx
->pipe_idx
;
1742 tree_cfg
->mpcc
[tree_pos
] = pipe_ctx
->pipe_idx
;
1743 tree_cfg
->per_pixel_alpha
[tree_pos
] = per_pixel_alpha
;
1744 tree_cfg
->num_pipes
= tree_pos
+ 1;
1745 dcn10_set_mpc_tree(mpc
, tree_cfg
);
1747 color_space
= pipe_ctx
->stream
->public.output_color_space
;
1748 color_space_to_black_color(dc
, color_space
, &black_color
);
1749 dcn10_set_mpc_background_color(mpc
, pipe_ctx
->pipe_idx
, &black_color
);
1751 pipe_ctx
->scl_data
.lb_params
.depth
= LB_PIXEL_DEPTH_30BPP
;
1752 /* scaler configuration */
1753 pipe_ctx
->xfm
->funcs
->transform_set_scaler(
1754 pipe_ctx
->xfm
, &pipe_ctx
->scl_data
);
1757 program_gamut_remap(pipe_ctx
);
1759 /*TODO add adjustments parameters*/
1760 ocsc
.out_color_space
= pipe_ctx
->stream
->public.output_color_space
;
1761 pipe_ctx
->opp
->funcs
->opp_set_csc_default(pipe_ctx
->opp
, &ocsc
);
1763 mi
->funcs
->mem_input_program_surface_config(
1765 surface
->public.format
,
1766 &surface
->public.tiling_info
,
1768 surface
->public.rotation
,
1769 &surface
->public.dcc
,
1770 surface
->public.horizontal_mirror
);
1772 mi
->funcs
->set_blank(mi
, !is_pipe_tree_visible(pipe_ctx
));
1775 static void program_all_pipe_in_tree(
1777 struct pipe_ctx
*pipe_ctx
,
1778 struct validate_context
*context
)
1780 unsigned int ref_clk_mhz
= dc
->res_pool
->ref_clock_inKhz
/1000;
1782 if (pipe_ctx
->top_pipe
== NULL
) {
1784 /* lock otg_master_update to process all pipes associated with
1785 * this OTG. this is done only one time.
1787 /* watermark is for all pipes */
1788 pipe_ctx
->mi
->funcs
->program_watermarks(
1789 pipe_ctx
->mi
, &context
->bw
.dcn
.watermarks
, ref_clk_mhz
);
1790 lock_otg_master_update(dc
->ctx
, pipe_ctx
->tg
->inst
);
1792 pipe_ctx
->tg
->dlg_otg_param
.vready_offset
= pipe_ctx
->pipe_dlg_param
.vready_offset
;
1793 pipe_ctx
->tg
->dlg_otg_param
.vstartup_start
= pipe_ctx
->pipe_dlg_param
.vstartup_start
;
1794 pipe_ctx
->tg
->dlg_otg_param
.vupdate_offset
= pipe_ctx
->pipe_dlg_param
.vupdate_offset
;
1795 pipe_ctx
->tg
->dlg_otg_param
.vupdate_width
= pipe_ctx
->pipe_dlg_param
.vupdate_width
;
1796 pipe_ctx
->tg
->dlg_otg_param
.signal
= pipe_ctx
->stream
->signal
;
1798 pipe_ctx
->tg
->funcs
->program_global_sync(
1800 pipe_ctx
->tg
->funcs
->set_blank(pipe_ctx
->tg
, !is_pipe_tree_visible(pipe_ctx
));
1803 if (pipe_ctx
->surface
->public.visible
) {
1804 dcn10_power_on_fe(dc
, pipe_ctx
, context
);
1805 update_dchubp_dpp(dc
, pipe_ctx
, context
);
1808 if (pipe_ctx
->bottom_pipe
!= NULL
)
1809 program_all_pipe_in_tree(dc
, pipe_ctx
->bottom_pipe
, context
);
1812 static void dcn10_pplib_apply_display_requirements(
1814 struct validate_context
*context
)
1816 struct dm_pp_display_configuration
*pp_display_cfg
= &context
->pp_display_cfg
;
1818 pp_display_cfg
->all_displays_in_sync
= false;/*todo*/
1819 pp_display_cfg
->nb_pstate_switch_disable
= false;
1820 pp_display_cfg
->min_engine_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
1821 pp_display_cfg
->min_memory_clock_khz
= context
->bw
.dcn
.cur_clk
.fclk_khz
;
1822 pp_display_cfg
->min_engine_clock_deep_sleep_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
1823 pp_display_cfg
->min_dcfc_deep_sleep_clock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
;
1824 pp_display_cfg
->avail_mclk_switch_time_us
=
1825 context
->bw
.dcn
.cur_clk
.dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.dram_ccm_us
: 0;
1826 pp_display_cfg
->avail_mclk_switch_time_in_disp_active_us
=
1827 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
> 0 ? context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
: 0;
1828 pp_display_cfg
->min_dcfclock_khz
= context
->bw
.dcn
.cur_clk
.dcfclk_khz
;
1829 pp_display_cfg
->disp_clk_khz
= context
->bw
.dcn
.cur_clk
.dispclk_khz
;
1830 dce110_fill_display_configs(context
, pp_display_cfg
);
1832 if (memcmp(&dc
->prev_display_config
, pp_display_cfg
, sizeof(
1833 struct dm_pp_display_configuration
)) != 0)
1834 dm_pp_apply_display_requirements(dc
->ctx
, pp_display_cfg
);
1836 dc
->prev_display_config
= *pp_display_cfg
;
1839 static void dcn10_apply_ctx_for_surface(
1841 struct core_surface
*surface
,
1842 struct validate_context
*context
)
1846 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1847 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1849 if (!pipe_ctx
->surface
|| pipe_ctx
->surface
!= surface
)
1853 /* looking for top pipe to program */
1854 if (!pipe_ctx
->top_pipe
) {
1855 memcpy(context
->res_ctx
.mpc_tree
,
1856 dc
->current_context
->res_ctx
.mpc_tree
,
1857 sizeof(struct mpc_tree_cfg
) * dc
->res_pool
->pipe_count
);
1859 program_all_pipe_in_tree(dc
, pipe_ctx
, context
);
1863 dm_logger_write(dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1864 "\n============== Watermark parameters ==============\n"
1865 "a.urgent_ns: %d \n"
1866 "a.cstate_enter_plus_exit: %d \n"
1867 "a.cstate_exit: %d \n"
1868 "a.pstate_change: %d \n"
1869 "a.pte_meta_urgent: %d \n"
1870 "b.urgent_ns: %d \n"
1871 "b.cstate_enter_plus_exit: %d \n"
1872 "b.cstate_exit: %d \n"
1873 "b.pstate_change: %d \n"
1874 "b.pte_meta_urgent: %d \n",
1875 context
->bw
.dcn
.watermarks
.a
.urgent_ns
,
1876 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1877 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.cstate_exit_ns
,
1878 context
->bw
.dcn
.watermarks
.a
.cstate_pstate
.pstate_change_ns
,
1879 context
->bw
.dcn
.watermarks
.a
.pte_meta_urgent_ns
,
1880 context
->bw
.dcn
.watermarks
.b
.urgent_ns
,
1881 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1882 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.cstate_exit_ns
,
1883 context
->bw
.dcn
.watermarks
.b
.cstate_pstate
.pstate_change_ns
,
1884 context
->bw
.dcn
.watermarks
.b
.pte_meta_urgent_ns
1886 dm_logger_write(dc
->ctx
->logger
, LOG_BANDWIDTH_CALCS
,
1887 "\nc.urgent_ns: %d \n"
1888 "c.cstate_enter_plus_exit: %d \n"
1889 "c.cstate_exit: %d \n"
1890 "c.pstate_change: %d \n"
1891 "c.pte_meta_urgent: %d \n"
1892 "d.urgent_ns: %d \n"
1893 "d.cstate_enter_plus_exit: %d \n"
1894 "d.cstate_exit: %d \n"
1895 "d.pstate_change: %d \n"
1896 "d.pte_meta_urgent: %d \n"
1897 "========================================================\n",
1898 context
->bw
.dcn
.watermarks
.c
.urgent_ns
,
1899 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1900 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.cstate_exit_ns
,
1901 context
->bw
.dcn
.watermarks
.c
.cstate_pstate
.pstate_change_ns
,
1902 context
->bw
.dcn
.watermarks
.c
.pte_meta_urgent_ns
,
1903 context
->bw
.dcn
.watermarks
.d
.urgent_ns
,
1904 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.cstate_enter_plus_exit_ns
,
1905 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.cstate_exit_ns
,
1906 context
->bw
.dcn
.watermarks
.d
.cstate_pstate
.pstate_change_ns
,
1907 context
->bw
.dcn
.watermarks
.d
.pte_meta_urgent_ns
1910 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1911 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1913 if (!pipe_ctx
->surface
|| pipe_ctx
->top_pipe
)
1916 /* unlock master update lock */
1917 unlock_otg_master(dc
->ctx
, pipe_ctx
->tg
->inst
);
1920 /* reset unused pipe */
1921 for (i
= 0; i
< dc
->res_pool
->pipe_count
; i
++) {
1922 struct pipe_ctx
*pipe_ctx
= &context
->res_ctx
.pipe_ctx
[i
];
1923 struct pipe_ctx
*old_pipe_ctx
=
1924 &dc
->current_context
->res_ctx
.pipe_ctx
[i
];
1926 if ((!pipe_ctx
->surface
&& old_pipe_ctx
->surface
)
1927 || (!pipe_ctx
->stream
&& old_pipe_ctx
->stream
))
1928 reset_front_end_for_pipe(dc
,
1929 old_pipe_ctx
, dc
->current_context
);
1933 static void dcn10_set_bandwidth(
1935 struct validate_context
*context
,
1936 bool decrease_allowed
)
1938 struct dm_pp_clock_for_voltage_req clock
;
1940 if (IS_FPGA_MAXIMUS_DC(dc
->ctx
->dce_environment
))
1943 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dispclk_khz
1944 > dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
) {
1945 dc
->res_pool
->display_clock
->funcs
->set_clock(
1946 dc
->res_pool
->display_clock
,
1947 context
->bw
.dcn
.calc_clk
.dispclk_khz
);
1948 dc
->current_context
->bw
.dcn
.cur_clk
.dispclk_khz
=
1949 context
->bw
.dcn
.calc_clk
.dispclk_khz
;
1951 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_khz
1952 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
) {
1953 clock
.clk_type
= DM_PP_CLOCK_TYPE_DCFCLK
;
1954 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.dcfclk_khz
;
1955 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
1956 dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
1957 context
->bw
.dcn
.cur_clk
.dcfclk_khz
= clock
.clocks_in_khz
;
1959 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.fclk_khz
1960 > dc
->current_context
->bw
.dcn
.cur_clk
.fclk_khz
) {
1961 clock
.clk_type
= DM_PP_CLOCK_TYPE_FCLK
;
1962 clock
.clocks_in_khz
= context
->bw
.dcn
.calc_clk
.fclk_khz
;
1963 dm_pp_apply_clock_for_voltage_request(dc
->ctx
, &clock
);
1964 dc
->current_context
->bw
.dcn
.calc_clk
.fclk_khz
= clock
.clocks_in_khz
;
1965 context
->bw
.dcn
.cur_clk
.fclk_khz
= clock
.clocks_in_khz
;
1967 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
1968 > dc
->current_context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
) {
1969 dc
->current_context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
=
1970 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
1971 context
->bw
.dcn
.cur_clk
.dcfclk_deep_sleep_khz
=
1972 context
->bw
.dcn
.calc_clk
.dcfclk_deep_sleep_khz
;
1974 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
1975 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.dram_ccm_us
1976 < dc
->current_context
->bw
.dcn
.cur_clk
.dram_ccm_us
) {
1977 dc
->current_context
->bw
.dcn
.calc_clk
.dram_ccm_us
=
1978 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
1979 context
->bw
.dcn
.cur_clk
.dram_ccm_us
=
1980 context
->bw
.dcn
.calc_clk
.dram_ccm_us
;
1982 if (decrease_allowed
|| context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
1983 < dc
->current_context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
) {
1984 dc
->current_context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
=
1985 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
1986 context
->bw
.dcn
.cur_clk
.min_active_dram_ccm_us
=
1987 context
->bw
.dcn
.calc_clk
.min_active_dram_ccm_us
;
1989 dcn10_pplib_apply_display_requirements(dc
, context
);
1992 static void dcn10_power_down_fe(struct core_dc
*dc
, struct pipe_ctx
*pipe
)
1994 struct dc_context
*ctx
= dc
->ctx
;
1995 uint32_t inst_offset
= 0;
1997 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL
,
1999 dpp_pg_control(ctx
, pipe
->pipe_idx
, false);
2000 hubp_pg_control(ctx
, pipe
->pipe_idx
, false);
2001 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL
,
2005 pipe
->xfm
->funcs
->transform_reset(pipe
->xfm
);
2006 memset(&pipe
->scl_data
, 0, sizeof(pipe
->scl_data
));
2009 static void set_drr(struct pipe_ctx
**pipe_ctx
,
2010 int num_pipes
, int vmin
, int vmax
)
2013 struct drr_params params
= {0};
2015 params
.vertical_total_max
= vmax
;
2016 params
.vertical_total_min
= vmin
;
2018 /* TODO: If multiple pipes are to be supported, you need
2021 for (i
= 0; i
< num_pipes
; i
++) {
2022 pipe_ctx
[i
]->tg
->funcs
->set_drr(pipe_ctx
[i
]->tg
, ¶ms
);
2026 static void get_position(struct pipe_ctx
**pipe_ctx
,
2028 struct crtc_position
*position
)
2032 /* TODO: handle pipes > 1
2034 for (i
= 0; i
< num_pipes
; i
++)
2035 pipe_ctx
[i
]->tg
->funcs
->get_position(pipe_ctx
[i
]->tg
, position
);
2038 static void set_static_screen_control(struct pipe_ctx
**pipe_ctx
,
2039 int num_pipes
, const struct dc_static_screen_events
*events
)
2042 unsigned int value
= 0;
2044 if (events
->surface_update
)
2046 if (events
->cursor_update
)
2049 for (i
= 0; i
< num_pipes
; i
++)
2050 pipe_ctx
[i
]->tg
->funcs
->
2051 set_static_screen_control(pipe_ctx
[i
]->tg
, value
);
2054 static void set_plane_config(
2055 const struct core_dc
*dc
,
2056 struct pipe_ctx
*pipe_ctx
,
2057 struct resource_context
*res_ctx
)
2060 program_gamut_remap(pipe_ctx
);
2063 static const struct hw_sequencer_funcs dcn10_funcs
= {
2064 .program_gamut_remap
= program_gamut_remap
,
2066 .apply_ctx_to_hw
= dce110_apply_ctx_to_hw
,
2067 .apply_ctx_for_surface
= dcn10_apply_ctx_for_surface
,
2068 .set_plane_config
= set_plane_config
,
2069 .update_plane_addr
= update_plane_addr
,
2070 .update_pending_status
= dce110_update_pending_status
,
2071 .set_input_transfer_func
= dcn10_set_input_transfer_func
,
2072 .set_output_transfer_func
= dcn10_set_output_transfer_func
,
2073 .power_down
= dce110_power_down
,
2074 .enable_accelerated_mode
= dce110_enable_accelerated_mode
,
2075 .enable_timing_synchronization
= dcn10_enable_timing_synchronization
,
2076 .update_info_frame
= dce110_update_info_frame
,
2077 .enable_stream
= dce110_enable_stream
,
2078 .disable_stream
= dce110_disable_stream
,
2079 .unblank_stream
= dce110_unblank_stream
,
2080 .enable_display_pipe_clock_gating
= NULL
, /* TODOFPGA */
2081 .enable_display_power_gating
= dcn10_enable_display_power_gating
,
2082 .power_down_front_end
= dcn10_power_down_fe
,
2083 .power_on_front_end
= dcn10_power_on_fe
,
2084 .pipe_control_lock
= dcn10_pipe_control_lock
,
2085 .set_bandwidth
= dcn10_set_bandwidth
,
2086 .reset_hw_ctx_wrap
= reset_hw_ctx_wrap
,
2087 .prog_pixclk_crtc_otg
= dcn10_prog_pixclk_crtc_otg
,
2089 .get_position
= get_position
,
2090 .set_static_screen_control
= set_static_screen_control
2094 bool dcn10_hw_sequencer_construct(struct core_dc
*dc
)
2096 dc
->hwss
= dcn10_funcs
;