]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drm/amd/display: do not set_mpc_tree if tree is already setup
[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 "hw_sequencer.h"
33 #include "dcn10_hw_sequencer.h"
34 #include "dce110/dce110_hw_sequencer.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 HWSEQ_REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL,
520 DISPCLK_DCCG_GATE_DISABLE, 1,
521 DPPCLK_GATE_DISABLE, 1);
522 /* DCFCLK_CNTL only has one instance */
523 HWSEQ_REG_UPDATE(DCFCLK_CNTL,
524 DCFCLK_GATE_DIS, 1);
525
526 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
527 IP_REQUEST_EN, 1);
528 dpp_pg_control(ctx, plane_id, true);
529 hubp_pg_control(ctx, plane_id, true);
530 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
531 IP_REQUEST_EN, 0);
532
533 if (ctx->dc->debug.disable_clock_gate) {
534 HWSEQ_REG_UPDATE(DCCG_GATE_DISABLE_CNTL,
535 DISPCLK_DCCG_GATE_DISABLE, 0);
536 } else {
537 /* DCCG_GATE_DISABLE_CNTL only has one instance. inst_offset = 0 */
538 HWSEQ_REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL,
539 DISPCLK_DCCG_GATE_DISABLE, 0,
540 DPPCLK_GATE_DISABLE, 0);
541 /* DCFCLK_CNTL only has one instance. inst_offset = 0 */
542 HWSEQ_REG_UPDATE(DCFCLK_CNTL,
543 DCFCLK_GATE_DIS, 0);
544 }
545 }
546
547 /* fully check bios enabledisplaypowergating table. dal only need dce init
548 * other power, clock gate register will be handle by dal itself.
549 * further may be put within init_hw
550 */
551 static bool dcn10_enable_display_power_gating(
552 struct core_dc *dc,
553 uint8_t controller_id,
554 struct dc_bios *dcb,
555 enum pipe_gating_control power_gating)
556 {
557 /* TODOFPGA */
558 #if 0
559 if (power_gating != PIPE_GATING_CONTROL_ENABLE)
560 dce110_init_pte(ctx);
561 #endif
562
563 return true;
564 }
565
566 static void bios_golden_init(struct core_dc *dc)
567 {
568 struct dc_bios *bp = dc->ctx->dc_bios;
569 int i;
570
571 /* initialize dcn global */
572 bp->funcs->enable_disp_power_gating(bp,
573 CONTROLLER_ID_D0, ASIC_PIPE_INIT);
574
575 for (i = 0; i < dc->res_pool->pipe_count; i++) {
576 /* initialize dcn per pipe */
577 bp->funcs->enable_disp_power_gating(bp,
578 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE);
579 }
580 }
581
582 static void init_hw(struct core_dc *dc)
583 {
584 int i;
585 struct dc_bios *bp;
586 struct transform *xfm;
587 struct abm *abm;
588
589 bp = dc->ctx->dc_bios;
590
591 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
592 /* TODO: this will be moved to Diag or BIOS */
593 dchubup_setup_timer(dc->ctx);
594
595 /* TODO: dchubp_map_fb_to_mc will be moved to dchub interface
596 * between dc and kmd
597 */
598 dchubp_map_fb_to_mc(dc->ctx);
599
600 enable_power_gating_plane(dc->ctx, true);
601 return;
602 }
603 /* end of FPGA. Below if real ASIC */
604
605 bios_golden_init(dc);
606
607 for (i = 0; i < dc->res_pool->pipe_count; i++) {
608 xfm = dc->res_pool->transforms[i];
609 xfm->funcs->transform_reset(xfm);
610
611 /* TODOFPGA: may need later */
612 #if 0
613 xfm->funcs->transform_power_up(xfm);
614 dc->hwss.enable_display_pipe_clock_gating(
615 dc->ctx,
616 true);
617 #endif
618 }
619 /* TODOFPGA: light sleep */
620 #if 0
621 dc->hwss.clock_gating_power_up(dc->ctx, false);
622 #endif
623
624 for (i = 0; i < dc->link_count; i++) {
625 /* Power up AND update implementation according to the
626 * required signal (which may be different from the
627 * default signal on connector).
628 */
629 struct core_link *link = dc->links[i];
630
631 link->link_enc->funcs->hw_init(link->link_enc);
632 }
633
634 for (i = 0; i < dc->res_pool->pipe_count; i++) {
635 struct timing_generator *tg =
636 dc->res_pool->timing_generators[i];
637
638 tg->funcs->disable_vga(tg);
639
640 /* Blank controller using driver code instead of
641 * command table.
642 */
643 tg->funcs->set_blank(tg, true);
644 hwss_wait_for_blank_complete(tg);
645 }
646
647 for (i = 0; i < dc->res_pool->audio_count; i++) {
648 struct audio *audio = dc->res_pool->audios[i];
649
650 audio->funcs->hw_init(audio);
651 }
652
653 abm = dc->res_pool->abm;
654 if (abm != NULL) {
655 abm->funcs->init_backlight(abm);
656 abm->funcs->abm_init(abm);
657 }
658
659 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
660 generic_reg_set_soc15(dc->ctx, 0, DIO_MEM_PWR_CTRL, 7,
661 FD(DIO_MEM_PWR_CTRL__HDMI0_MEM_PWR_FORCE), 0,
662 FD(DIO_MEM_PWR_CTRL__HDMI1_MEM_PWR_FORCE), 0,
663 FD(DIO_MEM_PWR_CTRL__HDMI2_MEM_PWR_FORCE), 0,
664 FD(DIO_MEM_PWR_CTRL__HDMI3_MEM_PWR_FORCE), 0,
665 FD(DIO_MEM_PWR_CTRL__HDMI4_MEM_PWR_FORCE), 0,
666 FD(DIO_MEM_PWR_CTRL__HDMI5_MEM_PWR_FORCE), 0,
667 FD(DIO_MEM_PWR_CTRL__HDMI6_MEM_PWR_FORCE), 0);
668
669 /* This power gating should be one-time program for DAL.
670 * It can only change by registry key
671 * TODO: new task will for this.
672 * if power gating is disable, power_on_plane and power_off_plane
673 * should be skip. Otherwise, hand will be met in power_off_plane
674 */
675
676 enable_power_gating_plane(dc->ctx, true);
677 }
678
679 static enum dc_status dcn10_prog_pixclk_crtc_otg(
680 struct pipe_ctx *pipe_ctx,
681 struct validate_context *context,
682 struct core_dc *dc)
683 {
684 struct core_stream *stream = pipe_ctx->stream;
685 enum dc_color_space color_space;
686 struct tg_color black_color = {0};
687 bool enableStereo = stream->public.timing.timing_3d_format == TIMING_3D_FORMAT_NONE ?
688 false:true;
689 bool rightEyePolarity = stream->public.timing.flags.RIGHT_EYE_3D_POLARITY;
690
691
692 /* by upper caller loop, pipe0 is parent pipe and be called first.
693 * back end is set up by for pipe0. Other children pipe share back end
694 * with pipe 0. No program is needed.
695 */
696 if (pipe_ctx->top_pipe != NULL)
697 return DC_OK;
698
699 /* TODO check if timing_changed, disable stream if timing changed */
700
701 /* HW program guide assume display already disable
702 * by unplug sequence. OTG assume stop.
703 */
704 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, true);
705
706 if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
707 pipe_ctx->clock_source,
708 &pipe_ctx->pix_clk_params,
709 &pipe_ctx->pll_settings)) {
710 BREAK_TO_DEBUGGER();
711 return DC_ERROR_UNEXPECTED;
712 }
713 pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
714 pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
715 pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
716 pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
717
718 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
719
720 pipe_ctx->tg->funcs->program_timing(
721 pipe_ctx->tg,
722 &stream->public.timing,
723 true);
724
725 pipe_ctx->opp->funcs->opp_set_stereo_polarity(
726 pipe_ctx->opp,
727 enableStereo,
728 rightEyePolarity);
729
730 #if 0 /* move to after enable_crtc */
731 /* TODO: OPP FMT, ABM. etc. should be done here. */
732 /* or FPGA now. instance 0 only. TODO: move to opp.c */
733
734 inst_offset = reg_offsets[pipe_ctx->tg->inst].fmt;
735
736 pipe_ctx->opp->funcs->opp_program_fmt(
737 pipe_ctx->opp,
738 &stream->bit_depth_params,
739 &stream->clamping);
740 #endif
741 /* program otg blank color */
742 color_space = stream->public.output_color_space;
743 color_space_to_black_color(dc, color_space, &black_color);
744 pipe_ctx->tg->funcs->set_blank_color(
745 pipe_ctx->tg,
746 &black_color);
747
748 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
749 hwss_wait_for_blank_complete(pipe_ctx->tg);
750
751 /* VTG is within DCHUB command block. DCFCLK is always on */
752 if (false == pipe_ctx->tg->funcs->enable_crtc(pipe_ctx->tg)) {
753 BREAK_TO_DEBUGGER();
754 return DC_ERROR_UNEXPECTED;
755 }
756
757 /* TODO program crtc source select for non-virtual signal*/
758 /* TODO program FMT */
759 /* TODO setup link_enc */
760 /* TODO set stream attributes */
761 /* TODO program audio */
762 /* TODO enable stream if timing changed */
763 /* TODO unblank stream if DP */
764
765 return DC_OK;
766 }
767
768 static void reset_back_end_for_pipe(
769 struct core_dc *dc,
770 struct pipe_ctx *pipe_ctx,
771 struct validate_context *context)
772 {
773 int i;
774 struct dc_bios *bp;
775
776 bp = dc->ctx->dc_bios;
777
778 if (pipe_ctx->stream_enc == NULL) {
779 pipe_ctx->stream = NULL;
780 return;
781 }
782
783 /* TODOFPGA break core_link_disable_stream into 2 functions:
784 * disable_stream and disable_link. disable_link will disable PHYPLL
785 * which is used by otg. Move disable_link after disable_crtc
786 */
787 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
788 core_link_disable_stream(pipe_ctx);
789
790 /* by upper caller loop, parent pipe: pipe0, will be reset last.
791 * back end share by all pipes and will be disable only when disable
792 * parent pipe.
793 */
794 if (pipe_ctx->top_pipe == NULL) {
795 pipe_ctx->tg->funcs->disable_crtc(pipe_ctx->tg);
796
797 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, false);
798 }
799
800 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
801 resource_unreference_clock_source(
802 &context->res_ctx, dc->res_pool,
803 &pipe_ctx->clock_source);
804
805 for (i = 0; i < dc->res_pool->pipe_count; i++)
806 if (&dc->current_context->res_ctx.pipe_ctx[i] == pipe_ctx)
807 break;
808
809 if (i == dc->res_pool->pipe_count)
810 return;
811
812 pipe_ctx->stream = NULL;
813 }
814
815 static void reset_front_end_for_pipe(
816 struct core_dc *dc,
817 struct pipe_ctx *pipe_ctx,
818 struct validate_context *context)
819 {
820 struct dcn10_mpc *mpc = TO_DCN10_MPC(dc->res_pool->mpc);
821 struct mpc_tree_cfg *tree_cfg = NULL;
822
823 if (!pipe_ctx->surface)
824 return;
825
826 lock_otg_master_update(dc->ctx, pipe_ctx->tg->inst);
827
828 /* TODO: build stream pipes group id. For now, use stream otg
829 * id as pipe group id
830 */
831 tree_cfg = &dc->current_context->res_ctx.mpc_tree[pipe_ctx->mpc_idx];
832
833 if (pipe_ctx->top_pipe == NULL)
834 dcn10_delete_mpc_tree(mpc, tree_cfg);
835 else {
836 if (dcn10_remove_dpp(mpc, tree_cfg, pipe_ctx->pipe_idx))
837 pipe_ctx->top_pipe->bottom_pipe = NULL;
838 else {
839 dm_logger_write(dc->ctx->logger, LOG_RESOURCE,
840 "%s: failed to find dpp to be removed!\n",
841 __func__);
842 }
843 }
844
845 pipe_ctx->top_pipe = NULL;
846 pipe_ctx->bottom_pipe = NULL;
847 pipe_ctx->mpc_idx = -1;
848
849 unlock_master_tg_and_wait(dc->ctx, pipe_ctx->tg->inst);
850
851 pipe_ctx->mi->funcs->disable_request(pipe_ctx->mi);
852
853 wait_no_outstanding_request(dc->ctx, pipe_ctx->pipe_idx);
854
855 wait_mpcc_idle(mpc, pipe_ctx->pipe_idx);
856
857 disable_clocks(dc->ctx, pipe_ctx->pipe_idx);
858
859 pipe_ctx->xfm->funcs->transform_reset(pipe_ctx->xfm);
860
861 dm_logger_write(dc->ctx->logger, LOG_DC,
862 "Reset front end for pipe %d\n",
863 pipe_ctx->pipe_idx);
864
865 pipe_ctx->surface = NULL;
866 }
867
868 static void reset_hw_ctx(struct core_dc *dc,
869 struct validate_context *context,
870 void (*reset)(struct core_dc *dc,
871 struct pipe_ctx *pipe_ctx,
872 struct validate_context *context))
873 {
874 int i;
875
876 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
877 struct pipe_ctx *pipe_ctx_old =
878 &dc->current_context->res_ctx.pipe_ctx[i];
879 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
880
881 if (!pipe_ctx_old->stream)
882 continue;
883
884 if (!pipe_ctx->stream ||
885 pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
886 reset(dc, pipe_ctx_old, dc->current_context);
887 }
888 }
889
890 static void reset_hw_ctx_wrap(
891 struct core_dc *dc,
892 struct validate_context *context)
893 {
894 /* Reset Front End*/
895 reset_hw_ctx(dc, context, reset_front_end_for_pipe);
896 /* Reset Back End*/
897 reset_hw_ctx(dc, context, reset_back_end_for_pipe);
898
899 memcpy(context->res_ctx.mpc_tree,
900 dc->current_context->res_ctx.mpc_tree,
901 sizeof(struct mpc_tree_cfg) * dc->res_pool->pipe_count);
902 }
903
904 static bool patch_address_for_sbs_tb_stereo(struct pipe_ctx *pipe_ctx,
905 PHYSICAL_ADDRESS_LOC *addr)
906 {
907 struct core_surface *surface = pipe_ctx->surface;
908 bool sec_split = pipe_ctx->top_pipe &&
909 pipe_ctx->top_pipe->surface == pipe_ctx->surface;
910 if (sec_split && surface->public.address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
911 (pipe_ctx->stream->public.timing.timing_3d_format ==
912 TIMING_3D_FORMAT_SIDE_BY_SIDE ||
913 pipe_ctx->stream->public.timing.timing_3d_format ==
914 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
915 *addr = surface->public.address.grph_stereo.left_addr;
916 surface->public.address.grph_stereo.left_addr =\
917 surface->public.address.grph_stereo.right_addr;
918 return true;
919 }
920 return false;
921 }
922
923 static void update_plane_addr(const struct core_dc *dc, struct pipe_ctx *pipe_ctx)
924 {
925 bool addr_patched = false;
926 PHYSICAL_ADDRESS_LOC addr;
927 struct core_surface *surface = pipe_ctx->surface;
928
929 if (surface == NULL)
930 return;
931 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
932 pipe_ctx->mi->funcs->mem_input_program_surface_flip_and_addr(
933 pipe_ctx->mi,
934 &surface->public.address,
935 surface->public.flip_immediate);
936 surface->status.requested_address = surface->public.address;
937 if (addr_patched)
938 pipe_ctx->surface->public.address.grph_stereo.left_addr = addr;
939 }
940
941 static bool dcn10_set_input_transfer_func(
942 struct pipe_ctx *pipe_ctx,
943 const struct core_surface *surface)
944 {
945 struct input_pixel_processor *ipp = pipe_ctx->ipp;
946 const struct core_transfer_func *tf = NULL;
947 bool result = true;
948
949 if (ipp == NULL)
950 return false;
951
952 if (surface->public.in_transfer_func)
953 tf = DC_TRANSFER_FUNC_TO_CORE(surface->public.in_transfer_func);
954
955 if (tf == NULL)
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);
962 break;
963 case TRANSFER_FUNCTION_BT709:
964 ipp->funcs->ipp_set_degamma(ipp,
965 IPP_DEGAMMA_MODE_HW_xvYCC);
966 break;
967 case TRANSFER_FUNCTION_LINEAR:
968 ipp->funcs->ipp_set_degamma(ipp,
969 IPP_DEGAMMA_MODE_BYPASS);
970 break;
971 case TRANSFER_FUNCTION_PQ:
972 result = false;
973 break;
974 default:
975 result = false;
976 break;
977 }
978 } else if (tf->public.type == TF_TYPE_BYPASS) {
979 ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS);
980 } else {
981 /*TF_TYPE_DISTRIBUTED_POINTS*/
982 result = false;
983 }
984
985 return result;
986 }
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)
992 {
993 struct custom_float_format fmt;
994
995 struct pwl_result_data *rgb = rgb_resulted;
996
997 uint32_t i = 0;
998
999 fmt.exponenta_bits = 6;
1000 fmt.mantissa_bits = 12;
1001 fmt.sign = false;
1002
1003 if (!convert_to_custom_float_format(
1004 arr_points[0].x,
1005 &fmt,
1006 &arr_points[0].custom_float_x)) {
1007 BREAK_TO_DEBUGGER();
1008 return false;
1009 }
1010
1011 if (!convert_to_custom_float_format(
1012 arr_points[0].offset,
1013 &fmt,
1014 &arr_points[0].custom_float_offset)) {
1015 BREAK_TO_DEBUGGER();
1016 return false;
1017 }
1018
1019 if (!convert_to_custom_float_format(
1020 arr_points[0].slope,
1021 &fmt,
1022 &arr_points[0].custom_float_slope)) {
1023 BREAK_TO_DEBUGGER();
1024 return false;
1025 }
1026
1027 fmt.mantissa_bits = 10;
1028 fmt.sign = false;
1029
1030 if (!convert_to_custom_float_format(
1031 arr_points[1].x,
1032 &fmt,
1033 &arr_points[1].custom_float_x)) {
1034 BREAK_TO_DEBUGGER();
1035 return false;
1036 }
1037
1038 if (!convert_to_custom_float_format(
1039 arr_points[1].y,
1040 &fmt,
1041 &arr_points[1].custom_float_y)) {
1042 BREAK_TO_DEBUGGER();
1043 return false;
1044 }
1045
1046 if (!convert_to_custom_float_format(
1047 arr_points[1].slope,
1048 &fmt,
1049 &arr_points[1].custom_float_slope)) {
1050 BREAK_TO_DEBUGGER();
1051 return false;
1052 }
1053
1054 fmt.mantissa_bits = 12;
1055 fmt.sign = true;
1056
1057 while (i != hw_points_num) {
1058 if (!convert_to_custom_float_format(
1059 rgb->red,
1060 &fmt,
1061 &rgb->red_reg)) {
1062 BREAK_TO_DEBUGGER();
1063 return false;
1064 }
1065
1066 if (!convert_to_custom_float_format(
1067 rgb->green,
1068 &fmt,
1069 &rgb->green_reg)) {
1070 BREAK_TO_DEBUGGER();
1071 return false;
1072 }
1073
1074 if (!convert_to_custom_float_format(
1075 rgb->blue,
1076 &fmt,
1077 &rgb->blue_reg)) {
1078 BREAK_TO_DEBUGGER();
1079 return false;
1080 }
1081
1082 if (!convert_to_custom_float_format(
1083 rgb->delta_red,
1084 &fmt,
1085 &rgb->delta_red_reg)) {
1086 BREAK_TO_DEBUGGER();
1087 return false;
1088 }
1089
1090 if (!convert_to_custom_float_format(
1091 rgb->delta_green,
1092 &fmt,
1093 &rgb->delta_green_reg)) {
1094 BREAK_TO_DEBUGGER();
1095 return false;
1096 }
1097
1098 if (!convert_to_custom_float_format(
1099 rgb->delta_blue,
1100 &fmt,
1101 &rgb->delta_blue_reg)) {
1102 BREAK_TO_DEBUGGER();
1103 return false;
1104 }
1105
1106 ++rgb;
1107 ++i;
1108 }
1109
1110 return true;
1111 }
1112 #define MAX_REGIONS_NUMBER 34
1113 #define MAX_LOW_POINT 25
1114 #define NUMBER_SEGMENTS 32
1115
1116 static bool dcn10_translate_regamma_to_hw_format(const struct dc_transfer_func
1117 *output_tf, struct pwl_params *regamma_params)
1118 {
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;
1128
1129 int32_t segment_start, segment_end;
1130 int32_t i;
1131 uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
1132
1133 if (output_tf == NULL || regamma_params == NULL ||
1134 output_tf->type == TF_TYPE_BYPASS)
1135 return false;
1136
1137 arr_points = regamma_params->arr_points;
1138 rgb_resulted = regamma_params->rgb_resulted;
1139 hw_points = 0;
1140
1141 memset(regamma_params, 0, sizeof(struct pwl_params));
1142 memset(seg_distr, 0, sizeof(seg_distr));
1143
1144 if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
1145 /* 32 segments
1146 * segments are from 2^-25 to 2^7
1147 */
1148 for (i = 0; i < 32 ; i++)
1149 seg_distr[i] = 3;
1150
1151 segment_start = -25;
1152 segment_end = 7;
1153 } else {
1154 /* 10 segments
1155 * segment is from 2^-10 to 2^0
1156 * There are less than 256 points, for optimization
1157 */
1158 seg_distr[0] = 3;
1159 seg_distr[1] = 4;
1160 seg_distr[2] = 4;
1161 seg_distr[3] = 4;
1162 seg_distr[4] = 4;
1163 seg_distr[5] = 4;
1164 seg_distr[6] = 4;
1165 seg_distr[7] = 4;
1166 seg_distr[8] = 5;
1167 seg_distr[9] = 5;
1168
1169 segment_start = -10;
1170 segment_end = 0;
1171 }
1172
1173 for (i = segment_end - segment_start; i < MAX_REGIONS_NUMBER ; i++)
1174 seg_distr[i] = -1;
1175
1176 for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
1177 if (seg_distr[k] != -1)
1178 hw_points += (1 << seg_distr[k]);
1179 }
1180
1181 j = 0;
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)
1187 break;
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];
1191 j++;
1192 }
1193 }
1194
1195 /* last point */
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];
1203
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));
1210
1211 y_r = rgb_resulted[0].red;
1212 y_g = rgb_resulted[0].green;
1213 y_b = rgb_resulted[0].blue;
1214
1215 y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b));
1216
1217 arr_points[0].y = y1_min;
1218 arr_points[0].slope = dal_fixed31_32_div(
1219 arr_points[0].y,
1220 arr_points[0].x);
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;
1224
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)
1227 */
1228 y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
1229
1230 arr_points[1].y = y3_max;
1231 arr_points[2].y = y3_max;
1232
1233 arr_points[1].slope = dal_fixed31_32_zero;
1234 arr_points[2].slope = dal_fixed31_32_zero;
1235
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.
1239 */
1240 const struct fixed31_32 end_value =
1241 dal_fixed31_32_from_int(125);
1242
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));
1249 }
1250
1251 regamma_params->hw_points_num = hw_points;
1252
1253 i = 1;
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 =
1257 seg_distr[k];
1258 regamma_params->arr_curve_points[i].offset =
1259 regamma_params->arr_curve_points[k].
1260 offset + (1 << seg_distr[k]);
1261 }
1262 i++;
1263 }
1264
1265 if (seg_distr[k] != -1)
1266 regamma_params->arr_curve_points[k].segments_num =
1267 seg_distr[k];
1268
1269 rgb = rgb_resulted;
1270 rgb_plus_1 = rgb_resulted + 1;
1271
1272 i = 1;
1273
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;
1281
1282 rgb->delta_red = dal_fixed31_32_sub(
1283 rgb_plus_1->red,
1284 rgb->red);
1285 rgb->delta_green = dal_fixed31_32_sub(
1286 rgb_plus_1->green,
1287 rgb->green);
1288 rgb->delta_blue = dal_fixed31_32_sub(
1289 rgb_plus_1->blue,
1290 rgb->blue);
1291
1292 ++rgb_plus_1;
1293 ++rgb;
1294 ++i;
1295 }
1296
1297 convert_to_custom_float(rgb_resulted, arr_points, hw_points);
1298
1299 return true;
1300 }
1301
1302 static bool dcn10_set_output_transfer_func(
1303 struct pipe_ctx *pipe_ctx,
1304 const struct core_surface *surface,
1305 const struct core_stream *stream)
1306 {
1307 struct output_pixel_processor *opp = pipe_ctx->opp;
1308
1309 opp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
1310
1311 if (stream->public.out_transfer_func &&
1312 stream->public.out_transfer_func->type ==
1313 TF_TYPE_PREDEFINED &&
1314 stream->public.out_transfer_func->tf ==
1315 TRANSFER_FUNCTION_SRGB) {
1316 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_SRGB);
1317 } else if (dcn10_translate_regamma_to_hw_format(
1318 stream->public.out_transfer_func, &opp->regamma_params)) {
1319 opp->funcs->opp_program_regamma_pwl(opp, &opp->regamma_params);
1320 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER);
1321 } else {
1322 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_BYPASS);
1323 }
1324
1325 return true;
1326 }
1327
1328 static void dcn10_pipe_control_lock(
1329 struct core_dc *dc,
1330 struct pipe_ctx *pipe,
1331 bool lock)
1332 {
1333 struct dce_hwseq *hws = hws = dc->hwseq;
1334
1335 /* use TG master update lock to lock everything on the TG
1336 * therefore only top pipe need to lock
1337 */
1338 if (pipe->top_pipe)
1339 return;
1340
1341 if (lock)
1342 dcn10_lock(pipe->tg);
1343 else
1344 dcn10_unlock(pipe->tg);
1345 }
1346
1347 static bool wait_for_reset_trigger_to_occur(
1348 struct dc_context *dc_ctx,
1349 struct timing_generator *tg)
1350 {
1351 bool rc = false;
1352
1353 /* To avoid endless loop we wait at most
1354 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1355 const uint32_t frames_to_wait_on_triggered_reset = 10;
1356 int i;
1357
1358 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
1359
1360 if (!tg->funcs->is_counter_moving(tg)) {
1361 DC_ERROR("TG counter is not moving!\n");
1362 break;
1363 }
1364
1365 if (tg->funcs->did_triggered_reset_occur(tg)) {
1366 rc = true;
1367 /* usually occurs at i=1 */
1368 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1369 i);
1370 break;
1371 }
1372
1373 /* Wait for one frame. */
1374 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
1375 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
1376 }
1377
1378 if (false == rc)
1379 DC_ERROR("GSL: Timeout on reset trigger!\n");
1380
1381 return rc;
1382 }
1383
1384 static void dcn10_enable_timing_synchronization(
1385 struct core_dc *dc,
1386 int group_index,
1387 int group_size,
1388 struct pipe_ctx *grouped_pipes[])
1389 {
1390 struct dc_context *dc_ctx = dc->ctx;
1391 int i;
1392
1393 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1394
1395 for (i = 1; i < group_size; i++)
1396 grouped_pipes[i]->tg->funcs->enable_reset_trigger(
1397 grouped_pipes[i]->tg, grouped_pipes[0]->tg->inst);
1398
1399
1400 DC_SYNC_INFO("Waiting for trigger\n");
1401
1402 /* Need to get only check 1 pipe for having reset as all the others are
1403 * synchronized. Look at last pipe programmed to reset.
1404 */
1405 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->tg);
1406 for (i = 1; i < group_size; i++)
1407 grouped_pipes[i]->tg->funcs->disable_reset_trigger(
1408 grouped_pipes[i]->tg);
1409
1410 DC_SYNC_INFO("Sync complete\n");
1411 }
1412
1413 static void dcn10_power_on_fe(
1414 struct core_dc *dc,
1415 struct pipe_ctx *pipe_ctx,
1416 struct validate_context *context)
1417 {
1418 struct dc_surface *dc_surface = &pipe_ctx->surface->public;
1419
1420 /* power up DCHUP and DPP from pseudo code pipe_move.c */
1421 /*TODO: function: power_on_plane. If already power up, skip
1422 */
1423 {
1424 power_on_plane(dc->ctx,
1425 pipe_ctx->pipe_idx, pipe_ctx->tg->inst);
1426
1427 /* enable DCFCLK current DCHUB */
1428 enable_dcfclk(dc->ctx,
1429 pipe_ctx->pipe_idx,
1430 pipe_ctx->pix_clk_params.requested_pix_clk,
1431 context->dppclk_div);
1432
1433 if (dc_surface) {
1434 dm_logger_write(dc->ctx->logger, LOG_DC,
1435 "Pipe:%d 0x%x: addr hi:0x%x, "
1436 "addr low:0x%x, "
1437 "src: %d, %d, %d,"
1438 " %d; dst: %d, %d, %d, %d;\n",
1439 pipe_ctx->pipe_idx,
1440 dc_surface,
1441 dc_surface->address.grph.addr.high_part,
1442 dc_surface->address.grph.addr.low_part,
1443 dc_surface->src_rect.x,
1444 dc_surface->src_rect.y,
1445 dc_surface->src_rect.width,
1446 dc_surface->src_rect.height,
1447 dc_surface->dst_rect.x,
1448 dc_surface->dst_rect.y,
1449 dc_surface->dst_rect.width,
1450 dc_surface->dst_rect.height);
1451
1452 dm_logger_write(dc->ctx->logger, LOG_HW_SET_MODE,
1453 "Pipe %d: width, height, x, y\n"
1454 "viewport:%d, %d, %d, %d\n"
1455 "recout: %d, %d, %d, %d\n",
1456 pipe_ctx->pipe_idx,
1457 pipe_ctx->scl_data.viewport.width,
1458 pipe_ctx->scl_data.viewport.height,
1459 pipe_ctx->scl_data.viewport.x,
1460 pipe_ctx->scl_data.viewport.y,
1461 pipe_ctx->scl_data.recout.width,
1462 pipe_ctx->scl_data.recout.height,
1463 pipe_ctx->scl_data.recout.x,
1464 pipe_ctx->scl_data.recout.y);
1465 }
1466 }
1467
1468 }
1469
1470 static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
1471 {
1472 struct xfm_grph_csc_adjustment adjust;
1473 memset(&adjust, 0, sizeof(adjust));
1474 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
1475
1476
1477 if (pipe_ctx->stream->public.gamut_remap_matrix.enable_remap == true) {
1478 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
1479 adjust.temperature_matrix[0] =
1480 pipe_ctx->stream->
1481 public.gamut_remap_matrix.matrix[0];
1482 adjust.temperature_matrix[1] =
1483 pipe_ctx->stream->
1484 public.gamut_remap_matrix.matrix[1];
1485 adjust.temperature_matrix[2] =
1486 pipe_ctx->stream->
1487 public.gamut_remap_matrix.matrix[2];
1488 adjust.temperature_matrix[3] =
1489 pipe_ctx->stream->
1490 public.gamut_remap_matrix.matrix[4];
1491 adjust.temperature_matrix[4] =
1492 pipe_ctx->stream->
1493 public.gamut_remap_matrix.matrix[5];
1494 adjust.temperature_matrix[5] =
1495 pipe_ctx->stream->
1496 public.gamut_remap_matrix.matrix[6];
1497 adjust.temperature_matrix[6] =
1498 pipe_ctx->stream->
1499 public.gamut_remap_matrix.matrix[8];
1500 adjust.temperature_matrix[7] =
1501 pipe_ctx->stream->
1502 public.gamut_remap_matrix.matrix[9];
1503 adjust.temperature_matrix[8] =
1504 pipe_ctx->stream->
1505 public.gamut_remap_matrix.matrix[10];
1506 }
1507
1508 pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
1509 }
1510
1511 static void update_dchubp_dpp(
1512 struct core_dc *dc,
1513 struct pipe_ctx *pipe_ctx,
1514 struct validate_context *context)
1515 {
1516 struct mem_input *mi = pipe_ctx->mi;
1517 struct input_pixel_processor *ipp = pipe_ctx->ipp;
1518 struct core_surface *surface = pipe_ctx->surface;
1519 union plane_size size = surface->public.plane_size;
1520 struct mpc_tree_cfg *tree_cfg = NULL;
1521 struct default_adjustment ocsc = {0};
1522 enum dc_color_space color_space;
1523 struct tg_color black_color = {0};
1524 struct dcn10_mpc *mpc = TO_DCN10_MPC(dc->res_pool->mpc);
1525
1526 struct pipe_ctx *cur_pipe_ctx = &dc->current_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
1527
1528 /* depends on DML calculation, DPP clock value may change dynamically */
1529 enable_dppclk(
1530 dc->ctx,
1531 pipe_ctx->pipe_idx,
1532 pipe_ctx->pix_clk_params.requested_pix_clk,
1533 context->dppclk_div);
1534
1535 select_vtg(dc->ctx, pipe_ctx->pipe_idx, pipe_ctx->tg->inst);
1536
1537 update_plane_addr(dc, pipe_ctx);
1538
1539 mi->funcs->mem_input_setup(
1540 mi,
1541 &pipe_ctx->dlg_regs,
1542 &pipe_ctx->ttu_regs,
1543 &pipe_ctx->rq_regs,
1544 &pipe_ctx->pipe_dlg_param);
1545
1546 size.grph.surface_size = pipe_ctx->scl_data.viewport;
1547
1548 if (dc->public.config.gpu_vm_support)
1549 mi->funcs->mem_input_program_pte_vm(
1550 pipe_ctx->mi,
1551 surface->public.format,
1552 &surface->public.tiling_info,
1553 surface->public.rotation);
1554
1555 ipp->funcs->ipp_setup(ipp,
1556 surface->public.format,
1557 1,
1558 IPP_OUTPUT_FORMAT_12_BIT_FIX);
1559
1560 /* mpc TODO un-hardcode object ids
1561 * for pseudo code pipe_move.c :
1562 * add_plane_mpcc(added_plane_inst, mpcc_inst, ...);
1563 * Do we want to cache the tree_cfg?
1564 */
1565
1566 /* TODO: build stream pipes group id. For now, use stream otg
1567 * id as pipe group id
1568 */
1569 pipe_ctx->mpc_idx = pipe_ctx->tg->inst;
1570 tree_cfg = &context->res_ctx.mpc_tree[pipe_ctx->mpc_idx];
1571
1572 /* enable when bottom pipe is present and
1573 * it does not share a surface with current pipe
1574 */
1575 if (pipe_ctx->bottom_pipe && surface != pipe_ctx->bottom_pipe->surface) {
1576 pipe_ctx->scl_data.lb_params.alpha_en = 1;
1577 tree_cfg->mode = TOP_BLND;
1578 } else {
1579 pipe_ctx->scl_data.lb_params.alpha_en = 0;
1580 tree_cfg->mode = TOP_PASSTHRU;
1581 }
1582 if (!pipe_ctx->top_pipe && !cur_pipe_ctx->bottom_pipe) {
1583 /* primary pipe, set mpc tree index 0 only */
1584 tree_cfg->num_pipes = 1;
1585 tree_cfg->opp_id = pipe_ctx->tg->inst;
1586 tree_cfg->dpp[0] = pipe_ctx->pipe_idx;
1587 tree_cfg->mpcc[0] = pipe_ctx->pipe_idx;
1588 }
1589
1590 if (!cur_pipe_ctx->top_pipe && !pipe_ctx->top_pipe) {
1591
1592 if (!cur_pipe_ctx->bottom_pipe)
1593 dcn10_set_mpc_tree(mpc, tree_cfg);
1594
1595 } else if (!cur_pipe_ctx->top_pipe && pipe_ctx->top_pipe) {
1596
1597 dcn10_add_dpp(mpc, tree_cfg,
1598 pipe_ctx->pipe_idx, pipe_ctx->pipe_idx, 1);
1599 } else {
1600 /* nothing to be done here */
1601 ASSERT(cur_pipe_ctx->top_pipe && pipe_ctx->top_pipe);
1602 }
1603
1604
1605 color_space = pipe_ctx->stream->public.output_color_space;
1606 color_space_to_black_color(dc, color_space, &black_color);
1607 dcn10_set_mpc_background_color(mpc, pipe_ctx->pipe_idx, &black_color);
1608
1609 pipe_ctx->scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1610 /* scaler configuration */
1611 pipe_ctx->xfm->funcs->transform_set_scaler(
1612 pipe_ctx->xfm, &pipe_ctx->scl_data);
1613
1614 /*gamut remap*/
1615 program_gamut_remap(pipe_ctx);
1616
1617 /*TODO add adjustments parameters*/
1618 ocsc.out_color_space = pipe_ctx->stream->public.output_color_space;
1619 pipe_ctx->opp->funcs->opp_set_csc_default(pipe_ctx->opp, &ocsc);
1620
1621 mi->funcs->mem_input_program_surface_config(
1622 mi,
1623 surface->public.format,
1624 &surface->public.tiling_info,
1625 &size,
1626 surface->public.rotation,
1627 &surface->public.dcc,
1628 surface->public.horizontal_mirror,
1629 surface->public.visible);
1630
1631 /* Only support one plane for now. */
1632 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, !surface->public.visible);
1633
1634 }
1635
1636 static void program_all_pipe_in_tree(
1637 struct core_dc *dc,
1638 struct pipe_ctx *pipe_ctx,
1639 struct validate_context *context)
1640 {
1641 unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000;
1642
1643 if (pipe_ctx->surface->public.visible || pipe_ctx->top_pipe == NULL) {
1644 dcn10_power_on_fe(dc, pipe_ctx, context);
1645
1646 /* lock otg_master_update to process all pipes associated with
1647 * this OTG. this is done only one time.
1648 */
1649 if (pipe_ctx->top_pipe == NULL) {
1650 /* watermark is for all pipes */
1651 pipe_ctx->mi->funcs->program_watermarks(
1652 pipe_ctx->mi, &context->watermarks, ref_clk_mhz);
1653 lock_otg_master_update(dc->ctx, pipe_ctx->tg->inst);
1654 }
1655
1656 pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
1657 pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
1658 pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
1659 pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
1660 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
1661
1662 pipe_ctx->tg->funcs->program_global_sync(
1663 pipe_ctx->tg);
1664
1665
1666
1667 update_dchubp_dpp(dc, pipe_ctx, context);
1668 }
1669
1670 if (pipe_ctx->bottom_pipe != NULL)
1671 program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context);
1672 }
1673
1674 static void dcn10_pplib_apply_display_requirements(
1675 struct core_dc *dc,
1676 struct validate_context *context)
1677 {
1678 struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
1679
1680 pp_display_cfg->all_displays_in_sync = false;/*todo*/
1681 pp_display_cfg->nb_pstate_switch_disable = false;
1682 pp_display_cfg->min_engine_clock_khz = context->dcfclk_khz;
1683 pp_display_cfg->min_memory_clock_khz = context->fclk_khz;
1684 pp_display_cfg->min_engine_clock_deep_sleep_khz = context->dcfclk_deep_sleep_khz;
1685 pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->dcfclk_deep_sleep_khz;
1686 pp_display_cfg->avail_mclk_switch_time_us =
1687 context->dram_ccm_us > 0 ? context->dram_ccm_us : 0;
1688 pp_display_cfg->avail_mclk_switch_time_in_disp_active_us =
1689 context->min_active_dram_ccm_us > 0 ? context->min_active_dram_ccm_us : 0;
1690 pp_display_cfg->min_dcfclock_khz = context->dcfclk_khz;
1691 pp_display_cfg->disp_clk_khz = context->dispclk_khz;
1692 dce110_fill_display_configs(context, pp_display_cfg);
1693
1694 if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
1695 struct dm_pp_display_configuration)) != 0)
1696 dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
1697
1698 dc->prev_display_config = *pp_display_cfg;
1699 }
1700
1701 static void dcn10_apply_ctx_for_surface(
1702 struct core_dc *dc,
1703 struct core_surface *surface,
1704 struct validate_context *context)
1705 {
1706 int i;
1707
1708 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1709 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1710
1711 if (!pipe_ctx->surface || pipe_ctx->surface != surface)
1712 continue;
1713
1714
1715 /* looking for top pipe to program */
1716 if (!pipe_ctx->top_pipe) {
1717 memcpy(context->res_ctx.mpc_tree,
1718 dc->current_context->res_ctx.mpc_tree,
1719 sizeof(struct mpc_tree_cfg) * dc->res_pool->pipe_count);
1720
1721 program_all_pipe_in_tree(dc, pipe_ctx, context);
1722 }
1723 }
1724
1725 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1726 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1727
1728 if (!pipe_ctx->surface || pipe_ctx->top_pipe)
1729 continue;
1730
1731 /* unlock master update lock */
1732 unlock_otg_master(dc->ctx, pipe_ctx->tg->inst);
1733 }
1734
1735 /* reset unused pipe */
1736 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1737 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1738 struct pipe_ctx *old_pipe_ctx =
1739 &dc->current_context->res_ctx.pipe_ctx[i];
1740
1741 if ((!pipe_ctx->surface && old_pipe_ctx->surface)
1742 || (!pipe_ctx->stream && old_pipe_ctx->stream))
1743 reset_front_end_for_pipe(dc,
1744 old_pipe_ctx, dc->current_context);
1745 }
1746 }
1747
1748 static void dcn10_set_bandwidth(
1749 struct core_dc *dc,
1750 struct validate_context *context,
1751 bool decrease_allowed)
1752 {
1753 struct dm_pp_clock_for_voltage_req clock;
1754
1755 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
1756 return;
1757
1758 if (decrease_allowed || context->dispclk_khz > dc->current_context->dispclk_khz) {
1759 dc->res_pool->display_clock->funcs->set_clock(
1760 dc->res_pool->display_clock,
1761 context->dispclk_khz);
1762 dc->current_context->dispclk_khz = context->dispclk_khz;
1763 }
1764 if (decrease_allowed || context->dcfclk_khz > dc->current_context->dcfclk_khz) {
1765 clock.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
1766 clock.clocks_in_khz = context->dcfclk_khz;
1767 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
1768 }
1769 if (decrease_allowed || context->fclk_khz > dc->current_context->fclk_khz) {
1770 clock.clk_type = DM_PP_CLOCK_TYPE_FCLK;
1771 clock.clocks_in_khz = context->fclk_khz;
1772 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
1773 dc->current_context->fclk_khz = clock.clocks_in_khz ;
1774 }
1775 dcn10_pplib_apply_display_requirements(dc, context);
1776 }
1777
1778 static void dcn10_power_down_fe(struct core_dc *dc, struct pipe_ctx *pipe)
1779 {
1780 struct dc_context *ctx = dc->ctx;
1781 uint32_t inst_offset = 0;
1782
1783 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
1784 IP_REQUEST_EN, 1);
1785 dpp_pg_control(ctx, pipe->pipe_idx, false);
1786 hubp_pg_control(ctx, pipe->pipe_idx, false);
1787 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
1788 IP_REQUEST_EN, 0);
1789
1790 if (pipe->xfm)
1791 pipe->xfm->funcs->transform_reset(pipe->xfm);
1792 memset(&pipe->scl_data, 0, sizeof(pipe->scl_data));
1793 }
1794
1795 static void set_drr(struct pipe_ctx **pipe_ctx,
1796 int num_pipes, int vmin, int vmax)
1797 {
1798 int i = 0;
1799 struct drr_params params = {0};
1800
1801 params.vertical_total_max = vmax;
1802 params.vertical_total_min = vmin;
1803
1804 /* TODO: If multiple pipes are to be supported, you need
1805 * some GSL stuff
1806 */
1807 for (i = 0; i < num_pipes; i++) {
1808 pipe_ctx[i]->tg->funcs->set_drr(pipe_ctx[i]->tg, &params);
1809 }
1810 }
1811
1812 static void get_position(struct pipe_ctx **pipe_ctx,
1813 int num_pipes,
1814 struct crtc_position *position)
1815 {
1816 int i = 0;
1817
1818 /* TODO: handle pipes > 1
1819 */
1820 for (i = 0; i < num_pipes; i++)
1821 pipe_ctx[i]->tg->funcs->get_position(pipe_ctx[i]->tg, position);
1822 }
1823
1824 static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
1825 int num_pipes, const struct dc_static_screen_events *events)
1826 {
1827 unsigned int i;
1828 unsigned int value = 0;
1829
1830 if (events->surface_update)
1831 value |= 0x80;
1832 if (events->cursor_update)
1833 value |= 0x2;
1834
1835 for (i = 0; i < num_pipes; i++)
1836 pipe_ctx[i]->tg->funcs->
1837 set_static_screen_control(pipe_ctx[i]->tg, value);
1838 }
1839
1840 static void set_plane_config(
1841 const struct core_dc *dc,
1842 struct pipe_ctx *pipe_ctx,
1843 struct resource_context *res_ctx)
1844 {
1845 /* TODO */
1846 program_gamut_remap(pipe_ctx);
1847 }
1848
1849 static const struct hw_sequencer_funcs dcn10_funcs = {
1850 .init_hw = init_hw,
1851 .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
1852 .apply_ctx_for_surface = dcn10_apply_ctx_for_surface,
1853 .set_plane_config = set_plane_config,
1854 .update_plane_addr = update_plane_addr,
1855 .update_pending_status = dce110_update_pending_status,
1856 .set_input_transfer_func = dcn10_set_input_transfer_func,
1857 .set_output_transfer_func = dcn10_set_output_transfer_func,
1858 .power_down = dce110_power_down,
1859 .enable_accelerated_mode = dce110_enable_accelerated_mode,
1860 .enable_timing_synchronization = dcn10_enable_timing_synchronization,
1861 .update_info_frame = dce110_update_info_frame,
1862 .enable_stream = dce110_enable_stream,
1863 .disable_stream = dce110_disable_stream,
1864 .unblank_stream = dce110_unblank_stream,
1865 .enable_display_pipe_clock_gating = NULL, /* TODOFPGA */
1866 .enable_display_power_gating = dcn10_enable_display_power_gating,
1867 .power_down_front_end = dcn10_power_down_fe,
1868 .power_on_front_end = dcn10_power_on_fe,
1869 .pipe_control_lock = dcn10_pipe_control_lock,
1870 .set_bandwidth = dcn10_set_bandwidth,
1871 .reset_hw_ctx_wrap = reset_hw_ctx_wrap,
1872 .prog_pixclk_crtc_otg = dcn10_prog_pixclk_crtc_otg,
1873 .set_drr = set_drr,
1874 .get_position = get_position,
1875 .set_static_screen_control = set_static_screen_control
1876 };
1877
1878
1879 bool dcn10_hw_sequencer_construct(struct core_dc *dc)
1880 {
1881 dc->hwss = dcn10_funcs;
1882 return true;
1883 }
1884