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