]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drm/amd/display: Enable DCN clock gating
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / amd / display / dc / dcn10 / dcn10_hw_sequencer.c
1 /*
2 * Copyright 2016 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26 #include "dm_services.h"
27 #include "dc.h"
28 #include "core_dc.h"
29 #include "core_types.h"
30 #include "core_status.h"
31 #include "resource.h"
32 #include "dcn10_hw_sequencer.h"
33 #include "dce110/dce110_hw_sequencer.h"
34 #include "dce/dce_hwseq.h"
35 #include "abm.h"
36
37 #include "dcn10/dcn10_transform.h"
38 #include "dcn10/dcn10_mpc.h"
39 #include "dcn10/dcn10_timing_generator.h"
40
41 #include "mem_input.h"
42 #include "timing_generator.h"
43 #include "opp.h"
44 #include "ipp.h"
45
46 #include "dc_bios_types.h"
47
48 #include "raven1/DCN/dcn_1_0_offset.h"
49 #include "raven1/DCN/dcn_1_0_sh_mask.h"
50 #include "vega10/soc15ip.h"
51
52 #include "custom_float.h"
53
54
55 struct dcn10_hwseq_reg_offsets {
56 uint32_t dchubp;
57 uint32_t dpp;
58 uint32_t otg;
59 uint32_t vtg;
60 uint32_t fmt;
61 };
62
63 /* TODO: move to resource */
64 static const struct dcn10_hwseq_reg_offsets reg_offsets[] = {
65 {
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),
72 },
73 {
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),
80 },
81 {
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),
88 },
89 {
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),
96 }
97 };
98
99 #define HWSEQ_REG_UPDATE_N(reg_name, n, ...) \
100 generic_reg_update_soc15(ctx, inst_offset, reg_name, n, __VA_ARGS__)
101
102 #define HWSEQ_REG_SET_N(reg_name, n, ...) \
103 generic_reg_set_soc15(ctx, inst_offset, reg_name, n, __VA_ARGS__)
104
105 #define HWSEQ_REG_UPDATE(reg, field, val) \
106 HWSEQ_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
107
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)
110
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)
113
114
115 #define HWSEQ_REG_SET(reg, field, val) \
116 HWSEQ_REG_SET_N(reg, 1, FD(reg##__##field), val)
117
118 /* TODO should be moved to OTG */
119 static void lock_otg_master_update(
120 struct dc_context *ctx,
121 uint8_t inst)
122 {
123 uint32_t inst_offset = reg_offsets[inst].otg;
124
125 HWSEQ_REG_UPDATE(OTG0_OTG_GLOBAL_CONTROL0,
126 OTG_MASTER_UPDATE_LOCK_SEL, inst);
127
128 /* unlock master locker */
129 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK,
130 OTG_MASTER_UPDATE_LOCK, 1);
131
132 /* wait for unlock happens */
133 if (!wait_reg(ctx, inst_offset, OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, 1))
134 BREAK_TO_DEBUGGER();
135
136 }
137
138 static bool unlock_master_tg_and_wait(
139 struct dc_context *ctx,
140 uint8_t inst)
141 {
142 uint32_t inst_offset = reg_offsets[inst].otg;
143
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);
147
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");
151 BREAK_TO_DEBUGGER();
152 return false;
153 }
154 return true;
155 }
156
157 /* TODO: should be moved to OTG ? */
158 static void unlock_otg_master(
159 struct dc_context *ctx,
160 uint8_t inst)
161 {
162 uint32_t inst_offset = reg_offsets[inst].otg;
163
164 /* unlock master locker */
165 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK,
166 OTG_MASTER_UPDATE_LOCK, 0);
167 }
168
169
170 static void wait_no_outstanding_request(
171 struct dc_context *ctx,
172 uint8_t plane_id)
173 {
174 uint32_t inst_offset = reg_offsets[plane_id].dchubp;
175
176 if (!wait_reg(ctx, inst_offset, HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, 1))
177 BREAK_TO_DEBUGGER();
178 }
179
180 static void disable_clocks(
181 struct dc_context *ctx,
182 uint8_t plane_id)
183 {
184 uint32_t inst_offset = reg_offsets[plane_id].dchubp;
185
186 generic_reg_update_soc15(ctx, inst_offset, HUBP0_HUBP_CLK_CNTL, 1,
187 FD(HUBP0_HUBP_CLK_CNTL__HUBP_CLOCK_ENABLE), 0);
188
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);
192 }
193
194 /* TODO: This is one time program during system boot up,
195 * this should be done within BIOS or CAIL
196 */
197 static void dchubp_map_fb_to_mc(struct dc_context *ctx)
198 {
199 /* TODO: do not know where to program
200 * DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
201 */
202 /*
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.
205 */
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);
209
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);
218
219
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);
225
226 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_FB_BASE, 1,
227 FD(DCHUBBUB_SDPIF_FB_BASE__SDPIF_FB_BASE), 0x000080);
228
229 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_FB_TOP, 1,
230 FD(DCHUBBUB_SDPIF_FB_TOP__SDPIF_FB_TOP), 0x0000ff);
231
232 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_AGP_BOT, 1,
233 FD(DCHUBBUB_SDPIF_AGP_BOT__SDPIF_AGP_BOT), 0x0000040);
234
235 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_AGP_TOP, 1,
236 FD(DCHUBBUB_SDPIF_AGP_TOP__SDPIF_AGP_TOP), 0x00001ff);
237
238 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_AGP_BASE, 1,
239 FD(DCHUBBUB_SDPIF_AGP_BASE__SDPIF_AGP_BASE), 0x0000080);
240
241 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_APER_TOP, 1,
242 FD(DCHUBBUB_SDPIF_APER_TOP__SDPIF_APER_TOP), 0x00007ff);
243
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);
246
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);
250
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);
253
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);
256
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);
260
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);
263
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);
266
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);
270
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);
273
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);
276
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);
280
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);
283
284 /* TODO: Is DCN_VM_SYSTEM_APERTURE address one time programming?
285 * Are all 4 hubp programmed with the same address?
286 */
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);
293
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);
300
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);
307
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);
314 }
315
316 /* TODO: This is one time program during system boot up,
317 * this should be done within BIOS
318 */
319 static void dchubup_setup_timer(struct dc_context *ctx)
320 {
321 dm_write_reg_soc15(ctx, mmREFCLK_CNTL, 0, 0);
322
323 generic_reg_update_soc15(ctx, 0, DCHUBBUB_GLOBAL_TIMER_CNTL, 1,
324 FD(DCHUBBUB_GLOBAL_TIMER_CNTL__DCHUBBUB_GLOBAL_TIMER_ENABLE), 1);
325 }
326
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
330 */
331 static void select_vtg(
332 struct dc_context *ctx,
333 uint8_t plane_id,
334 uint8_t inst)
335 {
336 uint32_t inst_offset = reg_offsets[plane_id].dchubp;
337
338 HWSEQ_REG_UPDATE(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, inst);
339 }
340
341 static void enable_dcfclk(
342 struct dc_context *ctx,
343 uint8_t plane_id,
344 uint32_t requested_pix_clk,
345 bool dppclk_div)
346 {
347 uint32_t inst_offset = reg_offsets[plane_id].dchubp;
348
349 HWSEQ_REG_UPDATE(HUBP0_HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, 1);
350 }
351
352 static void enable_dppclk(
353 struct dc_context *ctx,
354 uint8_t plane_id,
355 uint32_t requested_pix_clk,
356 bool dppclk_div)
357 {
358 uint32_t inst_offset = reg_offsets[plane_id].dpp;
359
360 dm_logger_write(ctx->logger, LOG_SURFACE,
361 "dppclk_rate_control for pipe %d programed to %d\n",
362 plane_id,
363 dppclk_div);
364
365 /* TODO: find condition for DPP clock to DISPCLK or 1/2 DISPCLK */
366 if (dppclk_div) {
367 /* 1/2 DISPCLK*/
368 HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL,
369 DPPCLK_RATE_CONTROL, 1,
370 DPP_CLOCK_ENABLE, 1);
371 } else {
372 /* DISPCLK */
373 HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL,
374 DPPCLK_RATE_CONTROL, 0,
375 DPP_CLOCK_ENABLE, 1);
376 }
377 }
378
379 static void enable_power_gating_plane(
380 struct dc_context *ctx,
381 bool enable)
382 {
383 uint32_t inst_offset = 0; /* each register only has one instance */
384 bool force_on = 1; /* disable power gating */
385
386 if (enable)
387 force_on = 0;
388
389 /* DCHUBP0/1/2/3 */
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);
394
395 /* DPP0/1/2/3 */
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);
400
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
404 */
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,
410 DCFCLK_GATE_DIS, 1);
411 }
412
413 }
414
415 static void dpp_pg_control(
416 struct dc_context *ctx,
417 unsigned int dpp_inst,
418 bool power_on)
419 {
420 uint32_t inst_offset = 0;
421 uint32_t power_gate = power_on ? 0 : 1;
422 uint32_t pwr_status = power_on ? 0 : 2;
423
424 if (ctx->dc->debug.disable_dpp_power_gate)
425 return;
426
427 switch (dpp_inst) {
428 case 0: /* DPP0 */
429 HWSEQ_REG_UPDATE(DOMAIN1_PG_CONFIG,
430 DOMAIN1_POWER_GATE, power_gate);
431
432 wait_reg(ctx, 0, DOMAIN1_PG_STATUS,
433 DOMAIN1_PGFSM_PWR_STATUS, pwr_status);
434 break;
435 case 1: /* DPP1 */
436 HWSEQ_REG_UPDATE(DOMAIN3_PG_CONFIG,
437 DOMAIN3_POWER_GATE, power_gate);
438
439 wait_reg(ctx, 0, DOMAIN3_PG_STATUS,
440 DOMAIN3_PGFSM_PWR_STATUS, pwr_status);
441 break;
442 case 2: /* DPP2 */
443 HWSEQ_REG_UPDATE(DOMAIN5_PG_CONFIG,
444 DOMAIN5_POWER_GATE, power_gate);
445
446 wait_reg(ctx, 0, DOMAIN5_PG_STATUS,
447 DOMAIN5_PGFSM_PWR_STATUS, pwr_status);
448 break;
449 case 3: /* DPP3 */
450 HWSEQ_REG_UPDATE(DOMAIN7_PG_CONFIG,
451 DOMAIN7_POWER_GATE, power_gate);
452
453 wait_reg(ctx, 0, DOMAIN7_PG_STATUS,
454 DOMAIN7_PGFSM_PWR_STATUS, pwr_status);
455 break;
456 default:
457 BREAK_TO_DEBUGGER();
458 break;
459 }
460 }
461
462 static void hubp_pg_control(
463 struct dc_context *ctx,
464 unsigned int hubp_inst,
465 bool power_on)
466 {
467 uint32_t inst_offset = 0;
468 uint32_t power_gate = power_on ? 0 : 1;
469 uint32_t pwr_status = power_on ? 0 : 2;
470
471 if (ctx->dc->debug.disable_hubp_power_gate)
472 return;
473
474 switch (hubp_inst) {
475 case 0: /* DCHUBP0 */
476 HWSEQ_REG_UPDATE(DOMAIN0_PG_CONFIG,
477 DOMAIN0_POWER_GATE, power_gate);
478
479 wait_reg(ctx, 0, DOMAIN0_PG_STATUS,
480 DOMAIN0_PGFSM_PWR_STATUS, pwr_status);
481 break;
482 case 1: /* DCHUBP1 */
483 HWSEQ_REG_UPDATE(DOMAIN2_PG_CONFIG,
484 DOMAIN2_POWER_GATE, power_gate);
485
486 wait_reg(ctx, 0, DOMAIN2_PG_STATUS,
487 DOMAIN2_PGFSM_PWR_STATUS, pwr_status);
488 break;
489 case 2: /* DCHUBP2 */
490 HWSEQ_REG_UPDATE(DOMAIN4_PG_CONFIG,
491 DOMAIN4_POWER_GATE, power_gate);
492
493 wait_reg(ctx, 0, DOMAIN4_PG_STATUS,
494 DOMAIN4_PGFSM_PWR_STATUS, pwr_status);
495 break;
496 case 3: /* DCHUBP3 */
497 HWSEQ_REG_UPDATE(DOMAIN6_PG_CONFIG,
498 DOMAIN6_POWER_GATE, power_gate);
499
500 wait_reg(ctx, 0, DOMAIN6_PG_STATUS,
501 DOMAIN6_PGFSM_PWR_STATUS, pwr_status);
502 break;
503 default:
504 BREAK_TO_DEBUGGER();
505 break;
506 }
507 }
508
509 static void power_on_plane(
510 struct dc_context *ctx,
511 uint8_t plane_id,
512 uint8_t inst)
513 {
514 uint32_t inst_offset = 0;
515
516 /* disable clock power gating */
517
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,
525 DCFCLK_GATE_DIS, 1);
526 }
527
528 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
529 IP_REQUEST_EN, 1);
530 dpp_pg_control(ctx, plane_id, true);
531 hubp_pg_control(ctx, plane_id, true);
532 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
533 IP_REQUEST_EN, 0);
534
535 if (ctx->dc->debug.disable_clock_gate) {
536 HWSEQ_REG_UPDATE(DCCG_GATE_DISABLE_CNTL,
537 DISPCLK_DCCG_GATE_DISABLE, 0);
538 }
539 }
540
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
544 */
545 static bool dcn10_enable_display_power_gating(
546 struct core_dc *dc,
547 uint8_t controller_id,
548 struct dc_bios *dcb,
549 enum pipe_gating_control power_gating)
550 {
551 /* TODOFPGA */
552 #if 0
553 if (power_gating != PIPE_GATING_CONTROL_ENABLE)
554 dce110_init_pte(ctx);
555 #endif
556
557 return true;
558 }
559
560 static void bios_golden_init(struct core_dc *dc)
561 {
562 struct dc_bios *bp = dc->ctx->dc_bios;
563 int i;
564
565 /* initialize dcn global */
566 bp->funcs->enable_disp_power_gating(bp,
567 CONTROLLER_ID_D0, ASIC_PIPE_INIT);
568
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);
573 }
574 }
575
576 static void init_hw(struct core_dc *dc)
577 {
578 int i;
579 struct dc_bios *bp;
580 struct transform *xfm;
581 struct abm *abm;
582
583 bp = dc->ctx->dc_bios;
584
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);
588
589 /* TODO: dchubp_map_fb_to_mc will be moved to dchub interface
590 * between dc and kmd
591 */
592 dchubp_map_fb_to_mc(dc->ctx);
593
594 enable_power_gating_plane(dc->ctx, true);
595 return;
596 }
597 /* end of FPGA. Below if real ASIC */
598
599 bios_golden_init(dc);
600
601 for (i = 0; i < dc->res_pool->pipe_count; i++) {
602 xfm = dc->res_pool->transforms[i];
603 xfm->funcs->transform_reset(xfm);
604
605 /* TODOFPGA: may need later */
606 #if 0
607 xfm->funcs->transform_power_up(xfm);
608 dc->hwss.enable_display_pipe_clock_gating(
609 dc->ctx,
610 true);
611 #endif
612 }
613 /* TODOFPGA: light sleep */
614 #if 0
615 dc->hwss.clock_gating_power_up(dc->ctx, false);
616 #endif
617
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).
622 */
623 struct core_link *link = dc->links[i];
624
625 link->link_enc->funcs->hw_init(link->link_enc);
626 }
627
628 for (i = 0; i < dc->res_pool->pipe_count; i++) {
629 struct timing_generator *tg =
630 dc->res_pool->timing_generators[i];
631
632 tg->funcs->disable_vga(tg);
633
634 /* Blank controller using driver code instead of
635 * command table.
636 */
637 tg->funcs->set_blank(tg, true);
638 hwss_wait_for_blank_complete(tg);
639 }
640
641 for (i = 0; i < dc->res_pool->audio_count; i++) {
642 struct audio *audio = dc->res_pool->audios[i];
643
644 audio->funcs->hw_init(audio);
645 }
646
647 abm = dc->res_pool->abm;
648 if (abm != NULL) {
649 abm->funcs->init_backlight(abm);
650 abm->funcs->abm_init(abm);
651 }
652
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);
662
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);
685
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);
701
702 generic_reg_update_soc15(dc->ctx, 0, DCFCLK_CNTL, 1,
703 FD(DCFCLK_CNTL__DCFCLK_GATE_DIS), 0);
704 }
705
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
711 */
712 enable_power_gating_plane(dc->ctx, true);
713
714
715 }
716
717 static enum dc_status dcn10_prog_pixclk_crtc_otg(
718 struct pipe_ctx *pipe_ctx,
719 struct validate_context *context,
720 struct core_dc *dc)
721 {
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 ?
726 false:true;
727 bool rightEyePolarity = stream->public.timing.flags.RIGHT_EYE_3D_POLARITY;
728
729
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.
733 */
734 if (pipe_ctx->top_pipe != NULL)
735 return DC_OK;
736
737 /* TODO check if timing_changed, disable stream if timing changed */
738
739 /* HW program guide assume display already disable
740 * by unplug sequence. OTG assume stop.
741 */
742 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, true);
743
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)) {
748 BREAK_TO_DEBUGGER();
749 return DC_ERROR_UNEXPECTED;
750 }
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;
755
756 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
757
758 pipe_ctx->tg->funcs->program_timing(
759 pipe_ctx->tg,
760 &stream->public.timing,
761 true);
762
763 pipe_ctx->opp->funcs->opp_set_stereo_polarity(
764 pipe_ctx->opp,
765 enableStereo,
766 rightEyePolarity);
767
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 */
771
772 inst_offset = reg_offsets[pipe_ctx->tg->inst].fmt;
773
774 pipe_ctx->opp->funcs->opp_program_fmt(
775 pipe_ctx->opp,
776 &stream->bit_depth_params,
777 &stream->clamping);
778 #endif
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(
783 pipe_ctx->tg,
784 &black_color);
785
786 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
787 hwss_wait_for_blank_complete(pipe_ctx->tg);
788
789 /* VTG is within DCHUB command block. DCFCLK is always on */
790 if (false == pipe_ctx->tg->funcs->enable_crtc(pipe_ctx->tg)) {
791 BREAK_TO_DEBUGGER();
792 return DC_ERROR_UNEXPECTED;
793 }
794
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 */
802
803 return DC_OK;
804 }
805
806 static void reset_back_end_for_pipe(
807 struct core_dc *dc,
808 struct pipe_ctx *pipe_ctx,
809 struct validate_context *context)
810 {
811 int i;
812 struct dc_bios *bp;
813
814 bp = dc->ctx->dc_bios;
815
816 if (pipe_ctx->stream_enc == NULL) {
817 pipe_ctx->stream = NULL;
818 return;
819 }
820
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
824 */
825 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
826 core_link_disable_stream(pipe_ctx);
827
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
830 * parent pipe.
831 */
832 if (pipe_ctx->top_pipe == NULL) {
833 pipe_ctx->tg->funcs->disable_crtc(pipe_ctx->tg);
834
835 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, false);
836 }
837
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);
842
843 for (i = 0; i < dc->res_pool->pipe_count; i++)
844 if (&dc->current_context->res_ctx.pipe_ctx[i] == pipe_ctx)
845 break;
846
847 if (i == dc->res_pool->pipe_count)
848 return;
849
850 pipe_ctx->stream = NULL;
851 }
852
853 static void reset_front_end_for_pipe(
854 struct core_dc *dc,
855 struct pipe_ctx *pipe_ctx,
856 struct validate_context *context)
857 {
858 struct dcn10_mpc *mpc = TO_DCN10_MPC(dc->res_pool->mpc);
859 struct mpc_tree_cfg *tree_cfg = NULL;
860
861 if (!pipe_ctx->surface)
862 return;
863
864 lock_otg_master_update(dc->ctx, pipe_ctx->tg->inst);
865
866 /* TODO: build stream pipes group id. For now, use stream otg
867 * id as pipe group id
868 */
869 tree_cfg = &dc->current_context->res_ctx.mpc_tree[pipe_ctx->mpc_idx];
870
871 if (pipe_ctx->top_pipe == NULL)
872 dcn10_delete_mpc_tree(mpc, tree_cfg);
873 else {
874 if (dcn10_remove_dpp(mpc, tree_cfg, pipe_ctx->pipe_idx))
875 pipe_ctx->top_pipe->bottom_pipe = NULL;
876 else {
877 dm_logger_write(dc->ctx->logger, LOG_RESOURCE,
878 "%s: failed to find dpp to be removed!\n",
879 __func__);
880 }
881 }
882
883 pipe_ctx->top_pipe = NULL;
884 pipe_ctx->bottom_pipe = NULL;
885 pipe_ctx->mpc_idx = -1;
886
887 unlock_master_tg_and_wait(dc->ctx, pipe_ctx->tg->inst);
888
889 pipe_ctx->mi->funcs->set_blank(pipe_ctx->mi, true);
890
891 wait_no_outstanding_request(dc->ctx, pipe_ctx->pipe_idx);
892
893 wait_mpcc_idle(mpc, pipe_ctx->pipe_idx);
894
895 disable_clocks(dc->ctx, pipe_ctx->pipe_idx);
896
897 pipe_ctx->xfm->funcs->transform_reset(pipe_ctx->xfm);
898
899 dm_logger_write(dc->ctx->logger, LOG_DC,
900 "Reset front end for pipe %d\n",
901 pipe_ctx->pipe_idx);
902
903 pipe_ctx->surface = NULL;
904 }
905
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))
911 {
912 int i;
913
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];
918
919 if (!pipe_ctx_old->stream)
920 continue;
921
922 if (!pipe_ctx->stream ||
923 pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
924 reset(dc, pipe_ctx_old, dc->current_context);
925 }
926 }
927
928 static void reset_hw_ctx_wrap(
929 struct core_dc *dc,
930 struct validate_context *context)
931 {
932 /* Reset Front End*/
933 reset_hw_ctx(dc, context, reset_front_end_for_pipe);
934 /* Reset Back End*/
935 reset_hw_ctx(dc, context, reset_back_end_for_pipe);
936
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);
940 }
941
942 static bool patch_address_for_sbs_tb_stereo(struct pipe_ctx *pipe_ctx,
943 PHYSICAL_ADDRESS_LOC *addr)
944 {
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;
956 return true;
957 }
958 return false;
959 }
960
961 static void update_plane_addr(const struct core_dc *dc, struct pipe_ctx *pipe_ctx)
962 {
963 bool addr_patched = false;
964 PHYSICAL_ADDRESS_LOC addr;
965 struct core_surface *surface = pipe_ctx->surface;
966
967 if (surface == NULL)
968 return;
969 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
970 pipe_ctx->mi->funcs->mem_input_program_surface_flip_and_addr(
971 pipe_ctx->mi,
972 &surface->public.address,
973 surface->public.flip_immediate);
974 surface->status.requested_address = surface->public.address;
975 if (addr_patched)
976 pipe_ctx->surface->public.address.grph_stereo.left_addr = addr;
977 }
978
979 static bool dcn10_set_input_transfer_func(
980 struct pipe_ctx *pipe_ctx,
981 const struct core_surface *surface)
982 {
983 struct input_pixel_processor *ipp = pipe_ctx->ipp;
984 const struct core_transfer_func *tf = NULL;
985 bool result = true;
986
987 if (ipp == NULL)
988 return false;
989
990 if (surface->public.in_transfer_func)
991 tf = DC_TRANSFER_FUNC_TO_CORE(surface->public.in_transfer_func);
992
993 if (surface->public.gamma_correction && dce_use_lut(surface))
994 ipp->funcs->ipp_program_input_lut(ipp,
995 surface->public.gamma_correction);
996
997 if (tf == NULL)
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);
1004 break;
1005 case TRANSFER_FUNCTION_BT709:
1006 ipp->funcs->ipp_set_degamma(ipp,
1007 IPP_DEGAMMA_MODE_HW_xvYCC);
1008 break;
1009 case TRANSFER_FUNCTION_LINEAR:
1010 ipp->funcs->ipp_set_degamma(ipp,
1011 IPP_DEGAMMA_MODE_BYPASS);
1012 break;
1013 case TRANSFER_FUNCTION_PQ:
1014 result = false;
1015 break;
1016 default:
1017 result = false;
1018 break;
1019 }
1020 } else if (tf->public.type == TF_TYPE_BYPASS) {
1021 ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
1022 } else {
1023 /*TF_TYPE_DISTRIBUTED_POINTS*/
1024 result = false;
1025 }
1026
1027 return result;
1028 }
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)
1034 {
1035 struct custom_float_format fmt;
1036
1037 struct pwl_result_data *rgb = rgb_resulted;
1038
1039 uint32_t i = 0;
1040
1041 fmt.exponenta_bits = 6;
1042 fmt.mantissa_bits = 12;
1043 fmt.sign = false;
1044
1045 if (!convert_to_custom_float_format(
1046 arr_points[0].x,
1047 &fmt,
1048 &arr_points[0].custom_float_x)) {
1049 BREAK_TO_DEBUGGER();
1050 return false;
1051 }
1052
1053 if (!convert_to_custom_float_format(
1054 arr_points[0].offset,
1055 &fmt,
1056 &arr_points[0].custom_float_offset)) {
1057 BREAK_TO_DEBUGGER();
1058 return false;
1059 }
1060
1061 if (!convert_to_custom_float_format(
1062 arr_points[0].slope,
1063 &fmt,
1064 &arr_points[0].custom_float_slope)) {
1065 BREAK_TO_DEBUGGER();
1066 return false;
1067 }
1068
1069 fmt.mantissa_bits = 10;
1070 fmt.sign = false;
1071
1072 if (!convert_to_custom_float_format(
1073 arr_points[1].x,
1074 &fmt,
1075 &arr_points[1].custom_float_x)) {
1076 BREAK_TO_DEBUGGER();
1077 return false;
1078 }
1079
1080 if (!convert_to_custom_float_format(
1081 arr_points[1].y,
1082 &fmt,
1083 &arr_points[1].custom_float_y)) {
1084 BREAK_TO_DEBUGGER();
1085 return false;
1086 }
1087
1088 if (!convert_to_custom_float_format(
1089 arr_points[1].slope,
1090 &fmt,
1091 &arr_points[1].custom_float_slope)) {
1092 BREAK_TO_DEBUGGER();
1093 return false;
1094 }
1095
1096 fmt.mantissa_bits = 12;
1097 fmt.sign = true;
1098
1099 while (i != hw_points_num) {
1100 if (!convert_to_custom_float_format(
1101 rgb->red,
1102 &fmt,
1103 &rgb->red_reg)) {
1104 BREAK_TO_DEBUGGER();
1105 return false;
1106 }
1107
1108 if (!convert_to_custom_float_format(
1109 rgb->green,
1110 &fmt,
1111 &rgb->green_reg)) {
1112 BREAK_TO_DEBUGGER();
1113 return false;
1114 }
1115
1116 if (!convert_to_custom_float_format(
1117 rgb->blue,
1118 &fmt,
1119 &rgb->blue_reg)) {
1120 BREAK_TO_DEBUGGER();
1121 return false;
1122 }
1123
1124 if (!convert_to_custom_float_format(
1125 rgb->delta_red,
1126 &fmt,
1127 &rgb->delta_red_reg)) {
1128 BREAK_TO_DEBUGGER();
1129 return false;
1130 }
1131
1132 if (!convert_to_custom_float_format(
1133 rgb->delta_green,
1134 &fmt,
1135 &rgb->delta_green_reg)) {
1136 BREAK_TO_DEBUGGER();
1137 return false;
1138 }
1139
1140 if (!convert_to_custom_float_format(
1141 rgb->delta_blue,
1142 &fmt,
1143 &rgb->delta_blue_reg)) {
1144 BREAK_TO_DEBUGGER();
1145 return false;
1146 }
1147
1148 ++rgb;
1149 ++i;
1150 }
1151
1152 return true;
1153 }
1154 #define MAX_REGIONS_NUMBER 34
1155 #define MAX_LOW_POINT 25
1156 #define NUMBER_SEGMENTS 32
1157
1158 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
1159 *output_tf, struct pwl_params *regamma_params)
1160 {
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;
1170
1171 int32_t segment_start, segment_end;
1172 int32_t i;
1173 uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
1174
1175 if (output_tf == NULL || regamma_params == NULL ||
1176 output_tf->type == TF_TYPE_BYPASS)
1177 return false;
1178
1179 arr_points = regamma_params->arr_points;
1180 rgb_resulted = regamma_params->rgb_resulted;
1181 hw_points = 0;
1182
1183 memset(regamma_params, 0, sizeof(struct pwl_params));
1184 memset(seg_distr, 0, sizeof(seg_distr));
1185
1186 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
1187 /* 32 segments
1188 * segments are from 2^-25 to 2^7
1189 */
1190 for (i = 0; i < 32 ; i++)
1191 seg_distr[i] = 3;
1192
1193 segment_start = -25;
1194 segment_end = 7;
1195 } else {
1196 /* 10 segments
1197 * segment is from 2^-10 to 2^0
1198 * There are less than 256 points, for optimization
1199 */
1200 seg_distr[0] = 3;
1201 seg_distr[1] = 4;
1202 seg_distr[2] = 4;
1203 seg_distr[3] = 4;
1204 seg_distr[4] = 4;
1205 seg_distr[5] = 4;
1206 seg_distr[6] = 4;
1207 seg_distr[7] = 4;
1208 seg_distr[8] = 5;
1209 seg_distr[9] = 5;
1210
1211 segment_start = -10;
1212 segment_end = 0;
1213 }
1214
1215 for (i = segment_end - segment_start; i < MAX_REGIONS_NUMBER ; i++)
1216 seg_distr[i] = -1;
1217
1218 for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
1219 if (seg_distr[k] != -1)
1220 hw_points += (1 << seg_distr[k]);
1221 }
1222
1223 j = 0;
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)
1229 break;
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];
1233 j++;
1234 }
1235 }
1236
1237 /* last point */
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];
1245
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));
1252
1253 y_r = rgb_resulted[0].red;
1254 y_g = rgb_resulted[0].green;
1255 y_b = rgb_resulted[0].blue;
1256
1257 y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b));
1258
1259 arr_points[0].y = y1_min;
1260 arr_points[0].slope = dal_fixed31_32_div(
1261 arr_points[0].y,
1262 arr_points[0].x);
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;
1266
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)
1269 */
1270 y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
1271
1272 arr_points[1].y = y3_max;
1273 arr_points[2].y = y3_max;
1274
1275 arr_points[1].slope = dal_fixed31_32_zero;
1276 arr_points[2].slope = dal_fixed31_32_zero;
1277
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.
1281 */
1282 const struct fixed31_32 end_value =
1283 dal_fixed31_32_from_int(125);
1284
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));
1291 }
1292
1293 regamma_params->hw_points_num = hw_points;
1294
1295 i = 1;
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 =
1299 seg_distr[k];
1300 regamma_params->arr_curve_points[i].offset =
1301 regamma_params->arr_curve_points[k].
1302 offset + (1 << seg_distr[k]);
1303 }
1304 i++;
1305 }
1306
1307 if (seg_distr[k] != -1)
1308 regamma_params->arr_curve_points[k].segments_num =
1309 seg_distr[k];
1310
1311 rgb = rgb_resulted;
1312 rgb_plus_1 = rgb_resulted + 1;
1313
1314 i = 1;
1315
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;
1323
1324 rgb->delta_red = dal_fixed31_32_sub(
1325 rgb_plus_1->red,
1326 rgb->red);
1327 rgb->delta_green = dal_fixed31_32_sub(
1328 rgb_plus_1->green,
1329 rgb->green);
1330 rgb->delta_blue = dal_fixed31_32_sub(
1331 rgb_plus_1->blue,
1332 rgb->blue);
1333
1334 ++rgb_plus_1;
1335 ++rgb;
1336 ++i;
1337 }
1338
1339 convert_to_custom_float(rgb_resulted, arr_points, hw_points);
1340
1341 return true;
1342 }
1343
1344 static bool dcn10_set_output_transfer_func(
1345 struct pipe_ctx *pipe_ctx,
1346 const struct core_stream *stream)
1347 {
1348 struct output_pixel_processor *opp = pipe_ctx->opp;
1349
1350 if (opp == NULL)
1351 return false;
1352
1353 opp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
1354
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);
1365 } else {
1366 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_BYPASS);
1367 }
1368
1369 return true;
1370 }
1371
1372 static void dcn10_pipe_control_lock(
1373 struct core_dc *dc,
1374 struct pipe_ctx *pipe,
1375 bool lock)
1376 {
1377 struct dce_hwseq *hws = hws = dc->hwseq;
1378
1379 /* use TG master update lock to lock everything on the TG
1380 * therefore only top pipe need to lock
1381 */
1382 if (pipe->top_pipe)
1383 return;
1384
1385 if (lock)
1386 dcn10_lock(pipe->tg);
1387 else
1388 dcn10_unlock(pipe->tg);
1389 }
1390
1391 static bool wait_for_reset_trigger_to_occur(
1392 struct dc_context *dc_ctx,
1393 struct timing_generator *tg)
1394 {
1395 bool rc = false;
1396
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;
1400 int i;
1401
1402 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
1403
1404 if (!tg->funcs->is_counter_moving(tg)) {
1405 DC_ERROR("TG counter is not moving!\n");
1406 break;
1407 }
1408
1409 if (tg->funcs->did_triggered_reset_occur(tg)) {
1410 rc = true;
1411 /* usually occurs at i=1 */
1412 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1413 i);
1414 break;
1415 }
1416
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);
1420 }
1421
1422 if (false == rc)
1423 DC_ERROR("GSL: Timeout on reset trigger!\n");
1424
1425 return rc;
1426 }
1427
1428 static void dcn10_enable_timing_synchronization(
1429 struct core_dc *dc,
1430 int group_index,
1431 int group_size,
1432 struct pipe_ctx *grouped_pipes[])
1433 {
1434 struct dc_context *dc_ctx = dc->ctx;
1435 int i;
1436
1437 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1438
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);
1442
1443
1444 DC_SYNC_INFO("Waiting for trigger\n");
1445
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.
1448 */
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);
1453
1454 DC_SYNC_INFO("Sync complete\n");
1455 }
1456
1457 static void dcn10_power_on_fe(
1458 struct core_dc *dc,
1459 struct pipe_ctx *pipe_ctx,
1460 struct validate_context *context)
1461 {
1462 struct dc_surface *dc_surface = &pipe_ctx->surface->public;
1463
1464 /* power up DCHUP and DPP from pseudo code pipe_move.c */
1465 /*TODO: function: power_on_plane. If already power up, skip
1466 */
1467 {
1468 power_on_plane(dc->ctx,
1469 pipe_ctx->pipe_idx, pipe_ctx->tg->inst);
1470
1471 /* enable DCFCLK current DCHUB */
1472 enable_dcfclk(dc->ctx,
1473 pipe_ctx->pipe_idx,
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;
1479
1480 if (dc_surface) {
1481 dm_logger_write(dc->ctx->logger, LOG_DC,
1482 "Pipe:%d 0x%x: addr hi:0x%x, "
1483 "addr low:0x%x, "
1484 "src: %d, %d, %d,"
1485 " %d; dst: %d, %d, %d, %d;\n",
1486 pipe_ctx->pipe_idx,
1487 dc_surface,
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);
1498
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",
1503 pipe_ctx->pipe_idx,
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);
1512 }
1513 }
1514
1515 }
1516
1517 static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
1518 {
1519 struct xfm_grph_csc_adjustment adjust;
1520 memset(&adjust, 0, sizeof(adjust));
1521 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
1522
1523
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] =
1527 pipe_ctx->stream->
1528 public.gamut_remap_matrix.matrix[0];
1529 adjust.temperature_matrix[1] =
1530 pipe_ctx->stream->
1531 public.gamut_remap_matrix.matrix[1];
1532 adjust.temperature_matrix[2] =
1533 pipe_ctx->stream->
1534 public.gamut_remap_matrix.matrix[2];
1535 adjust.temperature_matrix[3] =
1536 pipe_ctx->stream->
1537 public.gamut_remap_matrix.matrix[4];
1538 adjust.temperature_matrix[4] =
1539 pipe_ctx->stream->
1540 public.gamut_remap_matrix.matrix[5];
1541 adjust.temperature_matrix[5] =
1542 pipe_ctx->stream->
1543 public.gamut_remap_matrix.matrix[6];
1544 adjust.temperature_matrix[6] =
1545 pipe_ctx->stream->
1546 public.gamut_remap_matrix.matrix[8];
1547 adjust.temperature_matrix[7] =
1548 pipe_ctx->stream->
1549 public.gamut_remap_matrix.matrix[9];
1550 adjust.temperature_matrix[8] =
1551 pipe_ctx->stream->
1552 public.gamut_remap_matrix.matrix[10];
1553 }
1554
1555 pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
1556 }
1557
1558 static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1559 {
1560 if (pipe_ctx->surface->public.visible)
1561 return true;
1562 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1563 return true;
1564 return false;
1565 }
1566
1567 static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1568 {
1569 if (pipe_ctx->surface->public.visible)
1570 return true;
1571 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1572 return true;
1573 return false;
1574 }
1575
1576 static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1577 {
1578 if (pipe_ctx->surface->public.visible)
1579 return true;
1580 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1581 return true;
1582 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1583 return true;
1584 return false;
1585 }
1586
1587 static void update_dchubp_dpp(
1588 struct core_dc *dc,
1589 struct pipe_ctx *pipe_ctx,
1590 struct validate_context *context)
1591 {
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);
1601
1602 struct pipe_ctx *cur_pipe_ctx = &dc->current_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
1603
1604 /* depends on DML calculation, DPP clock value may change dynamically */
1605 enable_dppclk(
1606 dc->ctx,
1607 pipe_ctx->pipe_idx,
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;
1613
1614 select_vtg(dc->ctx, pipe_ctx->pipe_idx, pipe_ctx->tg->inst);
1615
1616 update_plane_addr(dc, pipe_ctx);
1617
1618 mi->funcs->mem_input_setup(
1619 mi,
1620 &pipe_ctx->dlg_regs,
1621 &pipe_ctx->ttu_regs,
1622 &pipe_ctx->rq_regs,
1623 &pipe_ctx->pipe_dlg_param);
1624
1625 size.grph.surface_size = pipe_ctx->scl_data.viewport;
1626
1627 if (dc->public.config.gpu_vm_support)
1628 mi->funcs->mem_input_program_pte_vm(
1629 pipe_ctx->mi,
1630 surface->public.format,
1631 &surface->public.tiling_info,
1632 surface->public.rotation);
1633
1634 ipp->funcs->ipp_setup(ipp,
1635 surface->public.format,
1636 1,
1637 IPP_OUTPUT_FORMAT_12_BIT_FIX);
1638
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?
1643 */
1644
1645 /* TODO: build stream pipes group id. For now, use stream otg
1646 * id as pipe group id
1647 */
1648 pipe_ctx->mpc_idx = pipe_ctx->tg->inst;
1649 tree_cfg = &context->res_ctx.mpc_tree[pipe_ctx->mpc_idx];
1650
1651 /* enable when bottom pipe is present and
1652 * it does not share a surface with current pipe
1653 */
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;
1657 } else {
1658 pipe_ctx->scl_data.lb_params.alpha_en = 0;
1659 tree_cfg->mode = TOP_PASSTHRU;
1660 }
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;
1667 }
1668
1669 if (!cur_pipe_ctx->top_pipe && !pipe_ctx->top_pipe) {
1670
1671 if (!cur_pipe_ctx->bottom_pipe)
1672 dcn10_set_mpc_tree(mpc, tree_cfg);
1673
1674 } else if (!cur_pipe_ctx->top_pipe && pipe_ctx->top_pipe) {
1675
1676 dcn10_add_dpp(mpc, tree_cfg,
1677 pipe_ctx->pipe_idx, pipe_ctx->pipe_idx, 1);
1678 } else {
1679 /* nothing to be done here */
1680 ASSERT(cur_pipe_ctx->top_pipe && pipe_ctx->top_pipe);
1681 }
1682
1683
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);
1687
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);
1692
1693 /*gamut remap*/
1694 program_gamut_remap(pipe_ctx);
1695
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);
1699
1700 mi->funcs->mem_input_program_surface_config(
1701 mi,
1702 surface->public.format,
1703 &surface->public.tiling_info,
1704 &size,
1705 surface->public.rotation,
1706 &surface->public.dcc,
1707 surface->public.horizontal_mirror);
1708
1709 mi->funcs->set_blank(mi, !is_pipe_tree_visible(pipe_ctx));
1710 }
1711
1712 static void program_all_pipe_in_tree(
1713 struct core_dc *dc,
1714 struct pipe_ctx *pipe_ctx,
1715 struct validate_context *context)
1716 {
1717 unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000;
1718
1719 if (pipe_ctx->surface->public.visible || pipe_ctx->top_pipe == NULL) {
1720 dcn10_power_on_fe(dc, pipe_ctx, context);
1721
1722 /* lock otg_master_update to process all pipes associated with
1723 * this OTG. this is done only one time.
1724 */
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);
1730 }
1731
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;
1737
1738 pipe_ctx->tg->funcs->program_global_sync(
1739 pipe_ctx->tg);
1740 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, !is_pipe_tree_visible(pipe_ctx));
1741
1742
1743
1744 update_dchubp_dpp(dc, pipe_ctx, context);
1745
1746 /* Only support one plane for now. */
1747 }
1748
1749 if (pipe_ctx->bottom_pipe != NULL)
1750 program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context);
1751 }
1752
1753 static void dcn10_pplib_apply_display_requirements(
1754 struct core_dc *dc,
1755 struct validate_context *context)
1756 {
1757 struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
1758
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);
1772
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);
1776
1777 dc->prev_display_config = *pp_display_cfg;
1778 }
1779
1780 static void dcn10_apply_ctx_for_surface(
1781 struct core_dc *dc,
1782 struct core_surface *surface,
1783 struct validate_context *context)
1784 {
1785 int i;
1786
1787 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1788 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1789
1790 if (!pipe_ctx->surface || pipe_ctx->surface != surface)
1791 continue;
1792
1793
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);
1799
1800 program_all_pipe_in_tree(dc, pipe_ctx, context);
1801 }
1802 }
1803
1804 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1805 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1806
1807 if (!pipe_ctx->surface || pipe_ctx->top_pipe)
1808 continue;
1809
1810 /* unlock master update lock */
1811 unlock_otg_master(dc->ctx, pipe_ctx->tg->inst);
1812 }
1813
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];
1819
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);
1824 }
1825 }
1826
1827 static void dcn10_set_bandwidth(
1828 struct core_dc *dc,
1829 struct validate_context *context,
1830 bool decrease_allowed)
1831 {
1832 struct dm_pp_clock_for_voltage_req clock;
1833
1834 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
1835 return;
1836
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;
1844 }
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;
1852 }
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;
1860 }
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;
1867 }
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;
1875 }
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;
1882 }
1883 dcn10_pplib_apply_display_requirements(dc, context);
1884 }
1885
1886 static void dcn10_power_down_fe(struct core_dc *dc, struct pipe_ctx *pipe)
1887 {
1888 struct dc_context *ctx = dc->ctx;
1889 uint32_t inst_offset = 0;
1890
1891 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
1892 IP_REQUEST_EN, 1);
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,
1896 IP_REQUEST_EN, 0);
1897
1898 if (pipe->xfm)
1899 pipe->xfm->funcs->transform_reset(pipe->xfm);
1900 memset(&pipe->scl_data, 0, sizeof(pipe->scl_data));
1901 }
1902
1903 static void set_drr(struct pipe_ctx **pipe_ctx,
1904 int num_pipes, int vmin, int vmax)
1905 {
1906 int i = 0;
1907 struct drr_params params = {0};
1908
1909 params.vertical_total_max = vmax;
1910 params.vertical_total_min = vmin;
1911
1912 /* TODO: If multiple pipes are to be supported, you need
1913 * some GSL stuff
1914 */
1915 for (i = 0; i < num_pipes; i++) {
1916 pipe_ctx[i]->tg->funcs->set_drr(pipe_ctx[i]->tg, &params);
1917 }
1918 }
1919
1920 static void get_position(struct pipe_ctx **pipe_ctx,
1921 int num_pipes,
1922 struct crtc_position *position)
1923 {
1924 int i = 0;
1925
1926 /* TODO: handle pipes > 1
1927 */
1928 for (i = 0; i < num_pipes; i++)
1929 pipe_ctx[i]->tg->funcs->get_position(pipe_ctx[i]->tg, position);
1930 }
1931
1932 static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
1933 int num_pipes, const struct dc_static_screen_events *events)
1934 {
1935 unsigned int i;
1936 unsigned int value = 0;
1937
1938 if (events->surface_update)
1939 value |= 0x80;
1940 if (events->cursor_update)
1941 value |= 0x2;
1942
1943 for (i = 0; i < num_pipes; i++)
1944 pipe_ctx[i]->tg->funcs->
1945 set_static_screen_control(pipe_ctx[i]->tg, value);
1946 }
1947
1948 static void set_plane_config(
1949 const struct core_dc *dc,
1950 struct pipe_ctx *pipe_ctx,
1951 struct resource_context *res_ctx)
1952 {
1953 /* TODO */
1954 program_gamut_remap(pipe_ctx);
1955 }
1956
1957 static const struct hw_sequencer_funcs dcn10_funcs = {
1958 .init_hw = init_hw,
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,
1981 .set_drr = set_drr,
1982 .get_position = get_position,
1983 .set_static_screen_control = set_static_screen_control
1984 };
1985
1986
1987 bool dcn10_hw_sequencer_construct(struct core_dc *dc)
1988 {
1989 dc->hwss = dcn10_funcs;
1990 return true;
1991 }
1992