]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drm/amd/display: fix enable_optc_clock reg_wait timeouts
[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
70ccab60
HW
128 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK,
129 OTG_MASTER_UPDATE_LOCK, 1);
70ccab60
HW
130}
131
132static bool unlock_master_tg_and_wait(
133 struct dc_context *ctx,
134 uint8_t inst)
135{
136 uint32_t inst_offset = reg_offsets[inst].otg;
137
138 HWSEQ_REG_UPDATE(OTG0_OTG_GLOBAL_SYNC_STATUS,
139 VUPDATE_NO_LOCK_EVENT_CLEAR, 1);
140 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, 0);
141
142 if (!wait_reg(ctx, inst_offset, OTG0_OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_OCCURRED, 1)) {
143 dm_logger_write(ctx->logger, LOG_ERROR,
144 "wait for VUPDATE_NO_LOCK_EVENT_OCCURRED failed\n");
145 BREAK_TO_DEBUGGER();
146 return false;
147 }
148 return true;
149}
150
151/* TODO: should be moved to OTG ? */
152static void unlock_otg_master(
153 struct dc_context *ctx,
154 uint8_t inst)
155{
156 uint32_t inst_offset = reg_offsets[inst].otg;
157
158 /* unlock master locker */
159 HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK,
160 OTG_MASTER_UPDATE_LOCK, 0);
161}
162
163
164static void wait_no_outstanding_request(
165 struct dc_context *ctx,
166 uint8_t plane_id)
167{
168 uint32_t inst_offset = reg_offsets[plane_id].dchubp;
169
170 if (!wait_reg(ctx, inst_offset, HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, 1))
171 BREAK_TO_DEBUGGER();
172}
173
174static void disable_clocks(
175 struct dc_context *ctx,
176 uint8_t plane_id)
177{
178 uint32_t inst_offset = reg_offsets[plane_id].dchubp;
179
180 generic_reg_update_soc15(ctx, inst_offset, HUBP0_HUBP_CLK_CNTL, 1,
181 FD(HUBP0_HUBP_CLK_CNTL__HUBP_CLOCK_ENABLE), 0);
182
183 inst_offset = reg_offsets[plane_id].dpp;
184 generic_reg_update_soc15(ctx, inst_offset, DPP_TOP0_DPP_CONTROL, 1,
185 FD(DPP_TOP0_DPP_CONTROL__DPP_CLOCK_ENABLE), 0);
186}
187
188/* TODO: This is one time program during system boot up,
189 * this should be done within BIOS or CAIL
190 */
191static void dchubp_map_fb_to_mc(struct dc_context *ctx)
192{
193 /* TODO: do not know where to program
194 * DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
195 */
196 /*
197 * TODO: For real ASIC, FB_OFFSET may be need change to the same value
198 * as FB_BASE. Need re-visit this for real ASIC.
199 */
200 dm_write_reg_soc15(ctx, mmDCHUBBUB_SDPIF_FB_BASE, 0, 0x80);
201 dm_write_reg_soc15(ctx, mmDCHUBBUB_SDPIF_FB_OFFSET, 0, 0);
202 dm_write_reg_soc15(ctx, mmDCHUBBUB_SDPIF_FB_TOP, 0, 0xFF);
203
204 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_CFG0, 7,
205 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_DATA_RESPONSE_STATUS_CLEAR), 0,
206 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_REQ_CREDIT_ERROR_CLEAR), 0,
207 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_FLUSH_REQ_CREDIT_EN), 0,
208 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_REQ_CREDIT_EN), 0,
209 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_PORT_CONTROL), 1,
210 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_UNIT_ID_BITMASK), 0xd3,
211 FD(DCHUBBUB_SDPIF_CFG0__SDPIF_CREDIT_DISCONNECT_DELAY), 0xc);
212
213
214 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_CFG1, 4,
215 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_INSIDE_FB_IO), 0,
216 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_INSIDE_FB_VC), 6,
217 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_OUTSIDE_FB_IO), 1,
218 FD(DCHUBBUB_SDPIF_CFG1__SDPIF_OUTSIDE_FB_VC), 6);
219
220 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_FB_BASE, 1,
221 FD(DCHUBBUB_SDPIF_FB_BASE__SDPIF_FB_BASE), 0x000080);
222
223 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_FB_TOP, 1,
224 FD(DCHUBBUB_SDPIF_FB_TOP__SDPIF_FB_TOP), 0x0000ff);
225
226 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_AGP_BOT, 1,
227 FD(DCHUBBUB_SDPIF_AGP_BOT__SDPIF_AGP_BOT), 0x0000040);
228
229 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_AGP_TOP, 1,
230 FD(DCHUBBUB_SDPIF_AGP_TOP__SDPIF_AGP_TOP), 0x00001ff);
231
232 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_AGP_BASE, 1,
233 FD(DCHUBBUB_SDPIF_AGP_BASE__SDPIF_AGP_BASE), 0x0000080);
234
235 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_APER_TOP, 1,
236 FD(DCHUBBUB_SDPIF_APER_TOP__SDPIF_APER_TOP), 0x00007ff);
237
238 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_APER_DEF_0, 1,
239 FD(DCHUBBUB_SDPIF_APER_DEF_0__SDPIF_APER_DEF_0), 0xdeadbeef);
240
241 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_0, 2,
242 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_0__SDPIF_MARC_EN_0), 0,
243 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_0__SDPIF_MARC_RELOC_LO_0), 0x90000);
244
245 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_0, 1,
246 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_0__SDPIF_MARC_LENGTH_LO_0), 0x10000);
247
248 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_1, 1,
249 FD(DCHUBBUB_SDPIF_MARC_BASE_LO_1__SDPIF_MARC_BASE_LO_1), 0x10000);
250
251 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_1, 2,
252 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_1__SDPIF_MARC_EN_1), 0,
253 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_1__SDPIF_MARC_RELOC_LO_1), 0xa0000);
254
255 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_1, 1,
256 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_1__SDPIF_MARC_LENGTH_LO_1), 0x10000);
257
258 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_2, 1,
259 FD(DCHUBBUB_SDPIF_MARC_BASE_LO_2__SDPIF_MARC_BASE_LO_2), 0x20000);
260
261 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_2, 2,
262 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_2__SDPIF_MARC_EN_2), 0,
263 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_2__SDPIF_MARC_RELOC_LO_2), 0xb0000);
264
265 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_2, 1,
266 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_2__SDPIF_MARC_LENGTH_LO_2), 0x10000);
267
268 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_3, 1,
269 FD(DCHUBBUB_SDPIF_MARC_BASE_LO_3__SDPIF_MARC_BASE_LO_3), 0x30000);
270
271 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_3, 2,
272 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_3__SDPIF_MARC_EN_3), 0,
273 FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_3__SDPIF_MARC_RELOC_LO_3), 0xc0000);
274
275 generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_3, 1,
276 FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_3__SDPIF_MARC_LENGTH_LO_3), 0x10000);
277
278 /* TODO: Is DCN_VM_SYSTEM_APERTURE address one time programming?
279 * Are all 4 hubp programmed with the same address?
280 */
281 dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, 0x80000);
282 dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, 0);
283 dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, 0x100000);
284 dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, 0);
285 dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, 0x80000);
286 dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, 0);
287
288 dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, 0x80000);
289 dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, 0);
290 dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, 0x100000);
291 dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, 0);
292 dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, 0x80000);
293 dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, 0);
294
295 dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, 0x80000);
296 dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, 0);
297 dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, 0x100000);
298 dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, 0);
299 dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, 0x80000);
300 dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, 0);
301
302 dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, 0x80000);
303 dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, 0);
304 dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, 0x100000);
305 dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, 0);
306 dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, 0x80000);
307 dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, 0);
308}
309
310/* TODO: This is one time program during system boot up,
311 * this should be done within BIOS
312 */
313static void dchubup_setup_timer(struct dc_context *ctx)
314{
315 dm_write_reg_soc15(ctx, mmREFCLK_CNTL, 0, 0);
316
317 generic_reg_update_soc15(ctx, 0, DCHUBBUB_GLOBAL_TIMER_CNTL, 1,
318 FD(DCHUBBUB_GLOBAL_TIMER_CNTL__DCHUBBUB_GLOBAL_TIMER_ENABLE), 1);
319}
320
321/* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
322 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
323 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
324 */
325static void select_vtg(
326 struct dc_context *ctx,
327 uint8_t plane_id,
328 uint8_t inst)
329{
330 uint32_t inst_offset = reg_offsets[plane_id].dchubp;
331
332 HWSEQ_REG_UPDATE(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, inst);
333}
334
335static void enable_dcfclk(
336 struct dc_context *ctx,
337 uint8_t plane_id,
338 uint32_t requested_pix_clk,
339 bool dppclk_div)
340{
341 uint32_t inst_offset = reg_offsets[plane_id].dchubp;
342
343 HWSEQ_REG_UPDATE(HUBP0_HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, 1);
344}
345
346static void enable_dppclk(
347 struct dc_context *ctx,
348 uint8_t plane_id,
349 uint32_t requested_pix_clk,
350 bool dppclk_div)
351{
352 uint32_t inst_offset = reg_offsets[plane_id].dpp;
353
354 dm_logger_write(ctx->logger, LOG_SURFACE,
355 "dppclk_rate_control for pipe %d programed to %d\n",
356 plane_id,
357 dppclk_div);
358
359 /* TODO: find condition for DPP clock to DISPCLK or 1/2 DISPCLK */
360 if (dppclk_div) {
361 /* 1/2 DISPCLK*/
362 HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL,
363 DPPCLK_RATE_CONTROL, 1,
364 DPP_CLOCK_ENABLE, 1);
365 } else {
366 /* DISPCLK */
367 HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL,
368 DPPCLK_RATE_CONTROL, 0,
369 DPP_CLOCK_ENABLE, 1);
370 }
371}
372
373static void enable_power_gating_plane(
374 struct dc_context *ctx,
375 bool enable)
376{
377 uint32_t inst_offset = 0; /* each register only has one instance */
378 bool force_on = 1; /* disable power gating */
379
380 if (enable)
381 force_on = 0;
382
383 /* DCHUBP0/1/2/3 */
384 HWSEQ_REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
385 HWSEQ_REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
386 HWSEQ_REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
387 HWSEQ_REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
388
389 /* DPP0/1/2/3 */
390 HWSEQ_REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
391 HWSEQ_REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
392 HWSEQ_REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
393 HWSEQ_REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
70ccab60
HW
394}
395
396static void dpp_pg_control(
397 struct dc_context *ctx,
398 unsigned int dpp_inst,
399 bool power_on)
400{
401 uint32_t inst_offset = 0;
402 uint32_t power_gate = power_on ? 0 : 1;
403 uint32_t pwr_status = power_on ? 0 : 2;
404
405 if (ctx->dc->debug.disable_dpp_power_gate)
406 return;
407
408 switch (dpp_inst) {
409 case 0: /* DPP0 */
410 HWSEQ_REG_UPDATE(DOMAIN1_PG_CONFIG,
411 DOMAIN1_POWER_GATE, power_gate);
412
413 wait_reg(ctx, 0, DOMAIN1_PG_STATUS,
414 DOMAIN1_PGFSM_PWR_STATUS, pwr_status);
415 break;
416 case 1: /* DPP1 */
417 HWSEQ_REG_UPDATE(DOMAIN3_PG_CONFIG,
418 DOMAIN3_POWER_GATE, power_gate);
419
420 wait_reg(ctx, 0, DOMAIN3_PG_STATUS,
421 DOMAIN3_PGFSM_PWR_STATUS, pwr_status);
422 break;
423 case 2: /* DPP2 */
424 HWSEQ_REG_UPDATE(DOMAIN5_PG_CONFIG,
425 DOMAIN5_POWER_GATE, power_gate);
426
427 wait_reg(ctx, 0, DOMAIN5_PG_STATUS,
428 DOMAIN5_PGFSM_PWR_STATUS, pwr_status);
429 break;
430 case 3: /* DPP3 */
431 HWSEQ_REG_UPDATE(DOMAIN7_PG_CONFIG,
432 DOMAIN7_POWER_GATE, power_gate);
433
434 wait_reg(ctx, 0, DOMAIN7_PG_STATUS,
435 DOMAIN7_PGFSM_PWR_STATUS, pwr_status);
436 break;
437 default:
438 BREAK_TO_DEBUGGER();
439 break;
440 }
441}
442
443static void hubp_pg_control(
444 struct dc_context *ctx,
445 unsigned int hubp_inst,
446 bool power_on)
447{
448 uint32_t inst_offset = 0;
449 uint32_t power_gate = power_on ? 0 : 1;
450 uint32_t pwr_status = power_on ? 0 : 2;
451
452 if (ctx->dc->debug.disable_hubp_power_gate)
453 return;
454
455 switch (hubp_inst) {
456 case 0: /* DCHUBP0 */
457 HWSEQ_REG_UPDATE(DOMAIN0_PG_CONFIG,
458 DOMAIN0_POWER_GATE, power_gate);
459
460 wait_reg(ctx, 0, DOMAIN0_PG_STATUS,
461 DOMAIN0_PGFSM_PWR_STATUS, pwr_status);
462 break;
463 case 1: /* DCHUBP1 */
464 HWSEQ_REG_UPDATE(DOMAIN2_PG_CONFIG,
465 DOMAIN2_POWER_GATE, power_gate);
466
467 wait_reg(ctx, 0, DOMAIN2_PG_STATUS,
468 DOMAIN2_PGFSM_PWR_STATUS, pwr_status);
469 break;
470 case 2: /* DCHUBP2 */
471 HWSEQ_REG_UPDATE(DOMAIN4_PG_CONFIG,
472 DOMAIN4_POWER_GATE, power_gate);
473
474 wait_reg(ctx, 0, DOMAIN4_PG_STATUS,
475 DOMAIN4_PGFSM_PWR_STATUS, pwr_status);
476 break;
477 case 3: /* DCHUBP3 */
478 HWSEQ_REG_UPDATE(DOMAIN6_PG_CONFIG,
479 DOMAIN6_POWER_GATE, power_gate);
480
481 wait_reg(ctx, 0, DOMAIN6_PG_STATUS,
482 DOMAIN6_PGFSM_PWR_STATUS, pwr_status);
483 break;
484 default:
485 BREAK_TO_DEBUGGER();
486 break;
487 }
488}
489
490static void power_on_plane(
491 struct dc_context *ctx,
492 uint8_t plane_id,
493 uint8_t inst)
494{
495 uint32_t inst_offset = 0;
496
70ccab60
HW
497 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
498 IP_REQUEST_EN, 1);
499 dpp_pg_control(ctx, plane_id, true);
500 hubp_pg_control(ctx, plane_id, true);
501 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
502 IP_REQUEST_EN, 0);
70ccab60
HW
503}
504
505/* fully check bios enabledisplaypowergating table. dal only need dce init
506 * other power, clock gate register will be handle by dal itself.
507 * further may be put within init_hw
508 */
509static bool dcn10_enable_display_power_gating(
510 struct core_dc *dc,
511 uint8_t controller_id,
512 struct dc_bios *dcb,
513 enum pipe_gating_control power_gating)
514{
515 /* TODOFPGA */
516#if 0
517 if (power_gating != PIPE_GATING_CONTROL_ENABLE)
518 dce110_init_pte(ctx);
519#endif
520
521 return true;
522}
523
524static void bios_golden_init(struct core_dc *dc)
525{
526 struct dc_bios *bp = dc->ctx->dc_bios;
527 int i;
528
529 /* initialize dcn global */
530 bp->funcs->enable_disp_power_gating(bp,
531 CONTROLLER_ID_D0, ASIC_PIPE_INIT);
532
533 for (i = 0; i < dc->res_pool->pipe_count; i++) {
534 /* initialize dcn per pipe */
535 bp->funcs->enable_disp_power_gating(bp,
536 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE);
537 }
538}
539
540static void init_hw(struct core_dc *dc)
541{
542 int i;
543 struct dc_bios *bp;
544 struct transform *xfm;
545 struct abm *abm;
546
547 bp = dc->ctx->dc_bios;
548
549 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
550 /* TODO: this will be moved to Diag or BIOS */
551 dchubup_setup_timer(dc->ctx);
552
553 /* TODO: dchubp_map_fb_to_mc will be moved to dchub interface
554 * between dc and kmd
555 */
556 dchubp_map_fb_to_mc(dc->ctx);
557
558 enable_power_gating_plane(dc->ctx, true);
559 return;
560 }
561 /* end of FPGA. Below if real ASIC */
562
563 bios_golden_init(dc);
564
565 for (i = 0; i < dc->res_pool->pipe_count; i++) {
566 xfm = dc->res_pool->transforms[i];
567 xfm->funcs->transform_reset(xfm);
568
569 /* TODOFPGA: may need later */
570#if 0
571 xfm->funcs->transform_power_up(xfm);
572 dc->hwss.enable_display_pipe_clock_gating(
573 dc->ctx,
574 true);
575#endif
576 }
577 /* TODOFPGA: light sleep */
578#if 0
579 dc->hwss.clock_gating_power_up(dc->ctx, false);
580#endif
581
582 for (i = 0; i < dc->link_count; i++) {
583 /* Power up AND update implementation according to the
584 * required signal (which may be different from the
585 * default signal on connector).
586 */
587 struct core_link *link = dc->links[i];
588
589 link->link_enc->funcs->hw_init(link->link_enc);
590 }
591
592 for (i = 0; i < dc->res_pool->pipe_count; i++) {
593 struct timing_generator *tg =
594 dc->res_pool->timing_generators[i];
595
596 tg->funcs->disable_vga(tg);
597
598 /* Blank controller using driver code instead of
599 * command table.
600 */
601 tg->funcs->set_blank(tg, true);
602 hwss_wait_for_blank_complete(tg);
603 }
604
605 for (i = 0; i < dc->res_pool->audio_count; i++) {
606 struct audio *audio = dc->res_pool->audios[i];
607
608 audio->funcs->hw_init(audio);
609 }
610
611 abm = dc->res_pool->abm;
612 if (abm != NULL) {
613 abm->funcs->init_backlight(abm);
614 abm->funcs->abm_init(abm);
615 }
616
617 /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
618 generic_reg_set_soc15(dc->ctx, 0, DIO_MEM_PWR_CTRL, 7,
619 FD(DIO_MEM_PWR_CTRL__HDMI0_MEM_PWR_FORCE), 0,
620 FD(DIO_MEM_PWR_CTRL__HDMI1_MEM_PWR_FORCE), 0,
621 FD(DIO_MEM_PWR_CTRL__HDMI2_MEM_PWR_FORCE), 0,
622 FD(DIO_MEM_PWR_CTRL__HDMI3_MEM_PWR_FORCE), 0,
623 FD(DIO_MEM_PWR_CTRL__HDMI4_MEM_PWR_FORCE), 0,
624 FD(DIO_MEM_PWR_CTRL__HDMI5_MEM_PWR_FORCE), 0,
625 FD(DIO_MEM_PWR_CTRL__HDMI6_MEM_PWR_FORCE), 0);
626
5970f2ae
HW
627 if (!dc->public.debug.disable_clock_gate) {
628 /* enable all DCN clock gating */
629 generic_reg_set_soc15(dc->ctx, 0, DCCG_GATE_DISABLE_CNTL, 19,
630 FD(DCCG_GATE_DISABLE_CNTL__DISPCLK_DCCG_GATE_DISABLE), 0,
631 FD(DCCG_GATE_DISABLE_CNTL__DISPCLK_R_DCCG_GATE_DISABLE), 0,
632 FD(DCCG_GATE_DISABLE_CNTL__SOCCLK_GATE_DISABLE), 0,
633 FD(DCCG_GATE_DISABLE_CNTL__DPREFCLK_GATE_DISABLE), 0,
634 FD(DCCG_GATE_DISABLE_CNTL__DACACLK_GATE_DISABLE), 0,
635 FD(DCCG_GATE_DISABLE_CNTL__DVOACLK_GATE_DISABLE), 0,
636 FD(DCCG_GATE_DISABLE_CNTL__DPREFCLK_R_DCCG_GATE_DISABLE), 0,
637 FD(DCCG_GATE_DISABLE_CNTL__DPPCLK_GATE_DISABLE), 0,
638 FD(DCCG_GATE_DISABLE_CNTL__AOMCLK0_GATE_DISABLE), 0,
639 FD(DCCG_GATE_DISABLE_CNTL__AOMCLK1_GATE_DISABLE), 0,
640 FD(DCCG_GATE_DISABLE_CNTL__AOMCLK2_GATE_DISABLE), 0,
641 FD(DCCG_GATE_DISABLE_CNTL__AUDIO_DTO2_CLK_GATE_DISABLE), 0,
642 FD(DCCG_GATE_DISABLE_CNTL__DPREFCLK_GTC_GATE_DISABLE), 0,
643 FD(DCCG_GATE_DISABLE_CNTL__UNB_DB_CLK_GATE_DISABLE), 0,
644 FD(DCCG_GATE_DISABLE_CNTL__REFCLK_GATE_DISABLE), 0,
645 FD(DCCG_GATE_DISABLE_CNTL__REFCLK_R_DIG_GATE_DISABLE), 0,
646 FD(DCCG_GATE_DISABLE_CNTL__DSICLK_GATE_DISABLE), 0,
647 FD(DCCG_GATE_DISABLE_CNTL__BYTECLK_GATE_DISABLE), 0,
648 FD(DCCG_GATE_DISABLE_CNTL__ESCCLK_GATE_DISABLE), 0);
649
650 generic_reg_set_soc15(dc->ctx, 0, DCCG_GATE_DISABLE_CNTL2, 14,
651 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKA_FE_GATE_DISABLE), 0,
652 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKB_FE_GATE_DISABLE), 0,
653 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKC_FE_GATE_DISABLE), 0,
654 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKD_FE_GATE_DISABLE), 0,
655 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKE_FE_GATE_DISABLE), 0,
656 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKF_FE_GATE_DISABLE), 0,
657 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKG_FE_GATE_DISABLE), 0,
658 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKA_GATE_DISABLE), 0,
659 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKB_GATE_DISABLE), 0,
660 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKC_GATE_DISABLE), 0,
661 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKD_GATE_DISABLE), 0,
662 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKE_GATE_DISABLE), 0,
663 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKF_GATE_DISABLE), 0,
664 FD(DCCG_GATE_DISABLE_CNTL2__SYMCLKG_GATE_DISABLE), 0);
665
666 generic_reg_update_soc15(dc->ctx, 0, DCFCLK_CNTL, 1,
667 FD(DCFCLK_CNTL__DCFCLK_GATE_DIS), 0);
668 }
669
70ccab60
HW
670 /* This power gating should be one-time program for DAL.
671 * It can only change by registry key
672 * TODO: new task will for this.
673 * if power gating is disable, power_on_plane and power_off_plane
674 * should be skip. Otherwise, hand will be met in power_off_plane
675 */
70ccab60 676 enable_power_gating_plane(dc->ctx, true);
5970f2ae
HW
677
678
70ccab60
HW
679}
680
681static enum dc_status dcn10_prog_pixclk_crtc_otg(
682 struct pipe_ctx *pipe_ctx,
683 struct validate_context *context,
684 struct core_dc *dc)
685{
686 struct core_stream *stream = pipe_ctx->stream;
687 enum dc_color_space color_space;
688 struct tg_color black_color = {0};
689 bool enableStereo = stream->public.timing.timing_3d_format == TIMING_3D_FORMAT_NONE ?
690 false:true;
691 bool rightEyePolarity = stream->public.timing.flags.RIGHT_EYE_3D_POLARITY;
692
693
694 /* by upper caller loop, pipe0 is parent pipe and be called first.
695 * back end is set up by for pipe0. Other children pipe share back end
696 * with pipe 0. No program is needed.
697 */
698 if (pipe_ctx->top_pipe != NULL)
699 return DC_OK;
700
701 /* TODO check if timing_changed, disable stream if timing changed */
702
703 /* HW program guide assume display already disable
704 * by unplug sequence. OTG assume stop.
705 */
706 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, true);
707
708 if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
709 pipe_ctx->clock_source,
710 &pipe_ctx->pix_clk_params,
711 &pipe_ctx->pll_settings)) {
712 BREAK_TO_DEBUGGER();
713 return DC_ERROR_UNEXPECTED;
714 }
715 pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
716 pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
717 pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
718 pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
719
720 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
721
722 pipe_ctx->tg->funcs->program_timing(
723 pipe_ctx->tg,
724 &stream->public.timing,
725 true);
726
727 pipe_ctx->opp->funcs->opp_set_stereo_polarity(
728 pipe_ctx->opp,
729 enableStereo,
730 rightEyePolarity);
731
732#if 0 /* move to after enable_crtc */
733 /* TODO: OPP FMT, ABM. etc. should be done here. */
734 /* or FPGA now. instance 0 only. TODO: move to opp.c */
735
736 inst_offset = reg_offsets[pipe_ctx->tg->inst].fmt;
737
738 pipe_ctx->opp->funcs->opp_program_fmt(
739 pipe_ctx->opp,
740 &stream->bit_depth_params,
741 &stream->clamping);
742#endif
743 /* program otg blank color */
744 color_space = stream->public.output_color_space;
745 color_space_to_black_color(dc, color_space, &black_color);
746 pipe_ctx->tg->funcs->set_blank_color(
747 pipe_ctx->tg,
748 &black_color);
749
750 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
751 hwss_wait_for_blank_complete(pipe_ctx->tg);
752
753 /* VTG is within DCHUB command block. DCFCLK is always on */
754 if (false == pipe_ctx->tg->funcs->enable_crtc(pipe_ctx->tg)) {
755 BREAK_TO_DEBUGGER();
756 return DC_ERROR_UNEXPECTED;
757 }
758
759 /* TODO program crtc source select for non-virtual signal*/
760 /* TODO program FMT */
761 /* TODO setup link_enc */
762 /* TODO set stream attributes */
763 /* TODO program audio */
764 /* TODO enable stream if timing changed */
765 /* TODO unblank stream if DP */
766
767 return DC_OK;
768}
769
770static void reset_back_end_for_pipe(
771 struct core_dc *dc,
772 struct pipe_ctx *pipe_ctx,
773 struct validate_context *context)
774{
775 int i;
776 struct dc_bios *bp;
777
778 bp = dc->ctx->dc_bios;
779
780 if (pipe_ctx->stream_enc == NULL) {
781 pipe_ctx->stream = NULL;
782 return;
783 }
784
785 /* TODOFPGA break core_link_disable_stream into 2 functions:
786 * disable_stream and disable_link. disable_link will disable PHYPLL
787 * which is used by otg. Move disable_link after disable_crtc
788 */
789 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
790 core_link_disable_stream(pipe_ctx);
791
792 /* by upper caller loop, parent pipe: pipe0, will be reset last.
793 * back end share by all pipes and will be disable only when disable
794 * parent pipe.
795 */
796 if (pipe_ctx->top_pipe == NULL) {
797 pipe_ctx->tg->funcs->disable_crtc(pipe_ctx->tg);
798
799 pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, false);
800 }
801
802 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
803 resource_unreference_clock_source(
804 &context->res_ctx, dc->res_pool,
805 &pipe_ctx->clock_source);
806
807 for (i = 0; i < dc->res_pool->pipe_count; i++)
808 if (&dc->current_context->res_ctx.pipe_ctx[i] == pipe_ctx)
809 break;
810
811 if (i == dc->res_pool->pipe_count)
812 return;
813
814 pipe_ctx->stream = NULL;
815}
816
817static void reset_front_end_for_pipe(
818 struct core_dc *dc,
819 struct pipe_ctx *pipe_ctx,
820 struct validate_context *context)
821{
822 struct dcn10_mpc *mpc = TO_DCN10_MPC(dc->res_pool->mpc);
823 struct mpc_tree_cfg *tree_cfg = NULL;
824
825 if (!pipe_ctx->surface)
826 return;
827
828 lock_otg_master_update(dc->ctx, pipe_ctx->tg->inst);
829
830 /* TODO: build stream pipes group id. For now, use stream otg
831 * id as pipe group id
832 */
cbfd33fd 833 tree_cfg = &dc->current_context->res_ctx.mpc_tree[pipe_ctx->mpc_idx];
70ccab60 834
dcf6c145
DL
835 if (!dcn10_remove_dpp(mpc, tree_cfg, pipe_ctx->pipe_idx)) {
836 dm_logger_write(dc->ctx->logger, LOG_RESOURCE,
837 "%s: failed to find dpp to be removed!\n",
838 __func__);
70ccab60
HW
839 }
840
841 pipe_ctx->top_pipe = NULL;
842 pipe_ctx->bottom_pipe = NULL;
843 pipe_ctx->mpc_idx = -1;
844
845 unlock_master_tg_and_wait(dc->ctx, pipe_ctx->tg->inst);
846
4b28b76b 847 pipe_ctx->mi->funcs->set_blank(pipe_ctx->mi, true);
70ccab60
HW
848
849 wait_no_outstanding_request(dc->ctx, pipe_ctx->pipe_idx);
850
851 wait_mpcc_idle(mpc, pipe_ctx->pipe_idx);
852
853 disable_clocks(dc->ctx, pipe_ctx->pipe_idx);
854
855 pipe_ctx->xfm->funcs->transform_reset(pipe_ctx->xfm);
856
857 dm_logger_write(dc->ctx->logger, LOG_DC,
858 "Reset front end for pipe %d\n",
859 pipe_ctx->pipe_idx);
860
861 pipe_ctx->surface = NULL;
862}
863
864static void reset_hw_ctx(struct core_dc *dc,
865 struct validate_context *context,
866 void (*reset)(struct core_dc *dc,
867 struct pipe_ctx *pipe_ctx,
868 struct validate_context *context))
869{
870 int i;
871
872 for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
873 struct pipe_ctx *pipe_ctx_old =
874 &dc->current_context->res_ctx.pipe_ctx[i];
875 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
876
877 if (!pipe_ctx_old->stream)
878 continue;
879
880 if (!pipe_ctx->stream ||
881 pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
882 reset(dc, pipe_ctx_old, dc->current_context);
883 }
884}
885
886static void reset_hw_ctx_wrap(
887 struct core_dc *dc,
888 struct validate_context *context)
889{
890 /* Reset Front End*/
891 reset_hw_ctx(dc, context, reset_front_end_for_pipe);
892 /* Reset Back End*/
893 reset_hw_ctx(dc, context, reset_back_end_for_pipe);
894
895 memcpy(context->res_ctx.mpc_tree,
896 dc->current_context->res_ctx.mpc_tree,
897 sizeof(struct mpc_tree_cfg) * dc->res_pool->pipe_count);
898}
899
900static bool patch_address_for_sbs_tb_stereo(struct pipe_ctx *pipe_ctx,
901 PHYSICAL_ADDRESS_LOC *addr)
902{
903 struct core_surface *surface = pipe_ctx->surface;
904 bool sec_split = pipe_ctx->top_pipe &&
905 pipe_ctx->top_pipe->surface == pipe_ctx->surface;
906 if (sec_split && surface->public.address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
907 (pipe_ctx->stream->public.timing.timing_3d_format ==
908 TIMING_3D_FORMAT_SIDE_BY_SIDE ||
909 pipe_ctx->stream->public.timing.timing_3d_format ==
910 TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
911 *addr = surface->public.address.grph_stereo.left_addr;
912 surface->public.address.grph_stereo.left_addr =\
913 surface->public.address.grph_stereo.right_addr;
914 return true;
915 }
916 return false;
917}
918
919static void update_plane_addr(const struct core_dc *dc, struct pipe_ctx *pipe_ctx)
920{
921 bool addr_patched = false;
922 PHYSICAL_ADDRESS_LOC addr;
923 struct core_surface *surface = pipe_ctx->surface;
924
925 if (surface == NULL)
926 return;
927 addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
928 pipe_ctx->mi->funcs->mem_input_program_surface_flip_and_addr(
929 pipe_ctx->mi,
930 &surface->public.address,
931 surface->public.flip_immediate);
932 surface->status.requested_address = surface->public.address;
933 if (addr_patched)
934 pipe_ctx->surface->public.address.grph_stereo.left_addr = addr;
935}
936
937static bool dcn10_set_input_transfer_func(
938 struct pipe_ctx *pipe_ctx,
939 const struct core_surface *surface)
940{
941 struct input_pixel_processor *ipp = pipe_ctx->ipp;
942 const struct core_transfer_func *tf = NULL;
943 bool result = true;
944
945 if (ipp == NULL)
946 return false;
947
948 if (surface->public.in_transfer_func)
949 tf = DC_TRANSFER_FUNC_TO_CORE(surface->public.in_transfer_func);
950
5aff86c1
LSL
951 if (surface->public.gamma_correction && dce_use_lut(surface))
952 ipp->funcs->ipp_program_input_lut(ipp,
953 surface->public.gamma_correction);
954
70ccab60
HW
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*/
988static 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
1116static 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
1302static bool dcn10_set_output_transfer_func(
1303 struct pipe_ctx *pipe_ctx,
70ccab60
HW
1304 const struct core_stream *stream)
1305{
1306 struct output_pixel_processor *opp = pipe_ctx->opp;
1307
f46661dd
AZ
1308 if (opp == NULL)
1309 return false;
1310
70ccab60
HW
1311 opp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
1312
1313 if (stream->public.out_transfer_func &&
1314 stream->public.out_transfer_func->type ==
1315 TF_TYPE_PREDEFINED &&
1316 stream->public.out_transfer_func->tf ==
1317 TRANSFER_FUNCTION_SRGB) {
1318 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_SRGB);
1319 } else if (dcn10_translate_regamma_to_hw_format(
1320 stream->public.out_transfer_func, &opp->regamma_params)) {
1321 opp->funcs->opp_program_regamma_pwl(opp, &opp->regamma_params);
1322 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_USER);
1323 } else {
1324 opp->funcs->opp_set_regamma_mode(opp, OPP_REGAMMA_BYPASS);
1325 }
1326
1327 return true;
1328}
1329
1330static void dcn10_pipe_control_lock(
1331 struct core_dc *dc,
1332 struct pipe_ctx *pipe,
1333 bool lock)
1334{
1335 struct dce_hwseq *hws = hws = dc->hwseq;
1336
1337 /* use TG master update lock to lock everything on the TG
1338 * therefore only top pipe need to lock
1339 */
1340 if (pipe->top_pipe)
1341 return;
1342
1343 if (lock)
1344 dcn10_lock(pipe->tg);
1345 else
1346 dcn10_unlock(pipe->tg);
1347}
1348
1349static bool wait_for_reset_trigger_to_occur(
1350 struct dc_context *dc_ctx,
1351 struct timing_generator *tg)
1352{
1353 bool rc = false;
1354
1355 /* To avoid endless loop we wait at most
1356 * frames_to_wait_on_triggered_reset frames for the reset to occur. */
1357 const uint32_t frames_to_wait_on_triggered_reset = 10;
1358 int i;
1359
1360 for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
1361
1362 if (!tg->funcs->is_counter_moving(tg)) {
1363 DC_ERROR("TG counter is not moving!\n");
1364 break;
1365 }
1366
1367 if (tg->funcs->did_triggered_reset_occur(tg)) {
1368 rc = true;
1369 /* usually occurs at i=1 */
1370 DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
1371 i);
1372 break;
1373 }
1374
1375 /* Wait for one frame. */
1376 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
1377 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
1378 }
1379
1380 if (false == rc)
1381 DC_ERROR("GSL: Timeout on reset trigger!\n");
1382
1383 return rc;
1384}
1385
1386static void dcn10_enable_timing_synchronization(
1387 struct core_dc *dc,
1388 int group_index,
1389 int group_size,
1390 struct pipe_ctx *grouped_pipes[])
1391{
1392 struct dc_context *dc_ctx = dc->ctx;
1393 int i;
1394
1395 DC_SYNC_INFO("Setting up OTG reset trigger\n");
1396
1397 for (i = 1; i < group_size; i++)
1398 grouped_pipes[i]->tg->funcs->enable_reset_trigger(
1399 grouped_pipes[i]->tg, grouped_pipes[0]->tg->inst);
1400
1401
1402 DC_SYNC_INFO("Waiting for trigger\n");
1403
1404 /* Need to get only check 1 pipe for having reset as all the others are
1405 * synchronized. Look at last pipe programmed to reset.
1406 */
1407 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->tg);
1408 for (i = 1; i < group_size; i++)
1409 grouped_pipes[i]->tg->funcs->disable_reset_trigger(
1410 grouped_pipes[i]->tg);
1411
1412 DC_SYNC_INFO("Sync complete\n");
1413}
1414
1415static void dcn10_power_on_fe(
1416 struct core_dc *dc,
1417 struct pipe_ctx *pipe_ctx,
1418 struct validate_context *context)
1419{
1420 struct dc_surface *dc_surface = &pipe_ctx->surface->public;
1421
1422 /* power up DCHUP and DPP from pseudo code pipe_move.c */
1423 /*TODO: function: power_on_plane. If already power up, skip
1424 */
1425 {
1426 power_on_plane(dc->ctx,
1427 pipe_ctx->pipe_idx, pipe_ctx->tg->inst);
1428
1429 /* enable DCFCLK current DCHUB */
1430 enable_dcfclk(dc->ctx,
1431 pipe_ctx->pipe_idx,
1432 pipe_ctx->pix_clk_params.requested_pix_clk,
9037d802 1433 context->bw.dcn.calc_clk.dppclk_div);
c66a54dc
DL
1434 dc->current_context->bw.dcn.cur_clk.dppclk_div =
1435 context->bw.dcn.calc_clk.dppclk_div;
1436 context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div;
70ccab60
HW
1437
1438 if (dc_surface) {
1439 dm_logger_write(dc->ctx->logger, LOG_DC,
1440 "Pipe:%d 0x%x: addr hi:0x%x, "
1441 "addr low:0x%x, "
1442 "src: %d, %d, %d,"
1443 " %d; dst: %d, %d, %d, %d;\n",
1444 pipe_ctx->pipe_idx,
1445 dc_surface,
1446 dc_surface->address.grph.addr.high_part,
1447 dc_surface->address.grph.addr.low_part,
1448 dc_surface->src_rect.x,
1449 dc_surface->src_rect.y,
1450 dc_surface->src_rect.width,
1451 dc_surface->src_rect.height,
1452 dc_surface->dst_rect.x,
1453 dc_surface->dst_rect.y,
1454 dc_surface->dst_rect.width,
1455 dc_surface->dst_rect.height);
1456
1457 dm_logger_write(dc->ctx->logger, LOG_HW_SET_MODE,
1458 "Pipe %d: width, height, x, y\n"
1459 "viewport:%d, %d, %d, %d\n"
1460 "recout: %d, %d, %d, %d\n",
1461 pipe_ctx->pipe_idx,
1462 pipe_ctx->scl_data.viewport.width,
1463 pipe_ctx->scl_data.viewport.height,
1464 pipe_ctx->scl_data.viewport.x,
1465 pipe_ctx->scl_data.viewport.y,
1466 pipe_ctx->scl_data.recout.width,
1467 pipe_ctx->scl_data.recout.height,
1468 pipe_ctx->scl_data.recout.x,
1469 pipe_ctx->scl_data.recout.y);
1470 }
1471 }
1472
1473}
1474
1475static void program_gamut_remap(struct pipe_ctx *pipe_ctx)
1476{
1477 struct xfm_grph_csc_adjustment adjust;
1478 memset(&adjust, 0, sizeof(adjust));
1479 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
1480
1481
1482 if (pipe_ctx->stream->public.gamut_remap_matrix.enable_remap == true) {
1483 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
1484 adjust.temperature_matrix[0] =
1485 pipe_ctx->stream->
1486 public.gamut_remap_matrix.matrix[0];
1487 adjust.temperature_matrix[1] =
1488 pipe_ctx->stream->
1489 public.gamut_remap_matrix.matrix[1];
1490 adjust.temperature_matrix[2] =
1491 pipe_ctx->stream->
1492 public.gamut_remap_matrix.matrix[2];
1493 adjust.temperature_matrix[3] =
1494 pipe_ctx->stream->
1495 public.gamut_remap_matrix.matrix[4];
1496 adjust.temperature_matrix[4] =
1497 pipe_ctx->stream->
1498 public.gamut_remap_matrix.matrix[5];
1499 adjust.temperature_matrix[5] =
1500 pipe_ctx->stream->
1501 public.gamut_remap_matrix.matrix[6];
1502 adjust.temperature_matrix[6] =
1503 pipe_ctx->stream->
1504 public.gamut_remap_matrix.matrix[8];
1505 adjust.temperature_matrix[7] =
1506 pipe_ctx->stream->
1507 public.gamut_remap_matrix.matrix[9];
1508 adjust.temperature_matrix[8] =
1509 pipe_ctx->stream->
1510 public.gamut_remap_matrix.matrix[10];
1511 }
1512
1513 pipe_ctx->xfm->funcs->transform_set_gamut_remap(pipe_ctx->xfm, &adjust);
1514}
1515
4b28b76b
DL
1516static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1517{
1518 if (pipe_ctx->surface->public.visible)
1519 return true;
1520 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1521 return true;
1522 return false;
1523}
1524
1525static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1526{
1527 if (pipe_ctx->surface->public.visible)
1528 return true;
1529 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1530 return true;
1531 return false;
1532}
1533
1534static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx)
1535{
1536 if (pipe_ctx->surface->public.visible)
1537 return true;
1538 if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe))
1539 return true;
1540 if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe))
1541 return true;
1542 return false;
1543}
1544
70ccab60
HW
1545static void update_dchubp_dpp(
1546 struct core_dc *dc,
1547 struct pipe_ctx *pipe_ctx,
1548 struct validate_context *context)
1549{
1550 struct mem_input *mi = pipe_ctx->mi;
1551 struct input_pixel_processor *ipp = pipe_ctx->ipp;
1552 struct core_surface *surface = pipe_ctx->surface;
1553 union plane_size size = surface->public.plane_size;
1554 struct mpc_tree_cfg *tree_cfg = NULL;
1555 struct default_adjustment ocsc = {0};
1556 enum dc_color_space color_space;
1557 struct tg_color black_color = {0};
1558 struct dcn10_mpc *mpc = TO_DCN10_MPC(dc->res_pool->mpc);
1a2c82a2
DL
1559 struct pipe_ctx *temp_pipe;
1560 int i;
1561 int tree_pos = 0;
ba326a91 1562 bool per_pixel_alpha = surface->public.per_pixel_alpha && pipe_ctx->bottom_pipe;
cbfd33fd 1563
ba326a91 1564 /* TODO: proper fix once fpga works */
70ccab60
HW
1565 /* depends on DML calculation, DPP clock value may change dynamically */
1566 enable_dppclk(
1567 dc->ctx,
1568 pipe_ctx->pipe_idx,
1569 pipe_ctx->pix_clk_params.requested_pix_clk,
9037d802 1570 context->bw.dcn.calc_clk.dppclk_div);
c66a54dc
DL
1571 dc->current_context->bw.dcn.cur_clk.dppclk_div =
1572 context->bw.dcn.calc_clk.dppclk_div;
1573 context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div;
70ccab60
HW
1574
1575 select_vtg(dc->ctx, pipe_ctx->pipe_idx, pipe_ctx->tg->inst);
1576
1577 update_plane_addr(dc, pipe_ctx);
1578
1579 mi->funcs->mem_input_setup(
1580 mi,
1581 &pipe_ctx->dlg_regs,
1582 &pipe_ctx->ttu_regs,
1583 &pipe_ctx->rq_regs,
1584 &pipe_ctx->pipe_dlg_param);
1585
1586 size.grph.surface_size = pipe_ctx->scl_data.viewport;
1587
1588 if (dc->public.config.gpu_vm_support)
1589 mi->funcs->mem_input_program_pte_vm(
1590 pipe_ctx->mi,
1591 surface->public.format,
1592 &surface->public.tiling_info,
1593 surface->public.rotation);
1594
1595 ipp->funcs->ipp_setup(ipp,
1596 surface->public.format,
1597 1,
1598 IPP_OUTPUT_FORMAT_12_BIT_FIX);
1599
1600 /* mpc TODO un-hardcode object ids
1601 * for pseudo code pipe_move.c :
1602 * add_plane_mpcc(added_plane_inst, mpcc_inst, ...);
1603 * Do we want to cache the tree_cfg?
1604 */
1605
1606 /* TODO: build stream pipes group id. For now, use stream otg
1607 * id as pipe group id
1608 */
ba326a91 1609 pipe_ctx->scl_data.lb_params.alpha_en = per_pixel_alpha;
1a2c82a2
DL
1610 pipe_ctx->mpc_idx = pipe_ctx->tg->inst;
1611 tree_cfg = &context->res_ctx.mpc_tree[pipe_ctx->mpc_idx];
1612 if (tree_cfg->num_pipes == 0) {
70ccab60 1613 tree_cfg->opp_id = pipe_ctx->tg->inst;
1a2c82a2
DL
1614 for (i = 0; i < MAX_PIPES; i++) {
1615 tree_cfg->dpp[i] = 0xf;
1616 tree_cfg->mpcc[i] = 0xf;
1617 }
cbfd33fd
TC
1618 }
1619
1a2c82a2
DL
1620 for (temp_pipe = pipe_ctx->top_pipe;
1621 temp_pipe != NULL; temp_pipe = temp_pipe->top_pipe)
1622 tree_pos++;
70ccab60 1623
1a2c82a2
DL
1624 tree_cfg->dpp[tree_pos] = pipe_ctx->pipe_idx;
1625 tree_cfg->mpcc[tree_pos] = pipe_ctx->pipe_idx;
ba326a91 1626 tree_cfg->per_pixel_alpha[tree_pos] = per_pixel_alpha;
1a2c82a2
DL
1627 tree_cfg->num_pipes = tree_pos + 1;
1628 dcn10_set_mpc_tree(mpc, tree_cfg);
cbfd33fd 1629
70ccab60
HW
1630 color_space = pipe_ctx->stream->public.output_color_space;
1631 color_space_to_black_color(dc, color_space, &black_color);
1632 dcn10_set_mpc_background_color(mpc, pipe_ctx->pipe_idx, &black_color);
1633
1634 pipe_ctx->scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
1635 /* scaler configuration */
1636 pipe_ctx->xfm->funcs->transform_set_scaler(
1637 pipe_ctx->xfm, &pipe_ctx->scl_data);
1638
1639 /*gamut remap*/
1640 program_gamut_remap(pipe_ctx);
1641
1642 /*TODO add adjustments parameters*/
1643 ocsc.out_color_space = pipe_ctx->stream->public.output_color_space;
1644 pipe_ctx->opp->funcs->opp_set_csc_default(pipe_ctx->opp, &ocsc);
1645
1646 mi->funcs->mem_input_program_surface_config(
1647 mi,
1648 surface->public.format,
1649 &surface->public.tiling_info,
1650 &size,
1651 surface->public.rotation,
1652 &surface->public.dcc,
4b28b76b 1653 surface->public.horizontal_mirror);
70ccab60 1654
4b28b76b 1655 mi->funcs->set_blank(mi, !is_pipe_tree_visible(pipe_ctx));
70ccab60
HW
1656}
1657
1658static void program_all_pipe_in_tree(
1659 struct core_dc *dc,
1660 struct pipe_ctx *pipe_ctx,
1661 struct validate_context *context)
1662{
1663 unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000;
1664
1a2c82a2 1665 if (pipe_ctx->top_pipe == NULL) {
70ccab60
HW
1666
1667 /* lock otg_master_update to process all pipes associated with
1668 * this OTG. this is done only one time.
1669 */
1a2c82a2
DL
1670 /* watermark is for all pipes */
1671 pipe_ctx->mi->funcs->program_watermarks(
1672 pipe_ctx->mi, &context->bw.dcn.watermarks, ref_clk_mhz);
1673 lock_otg_master_update(dc->ctx, pipe_ctx->tg->inst);
cbfd33fd 1674
70ccab60
HW
1675 pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
1676 pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
1677 pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
1678 pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
1679 pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
cbfd33fd 1680
70ccab60
HW
1681 pipe_ctx->tg->funcs->program_global_sync(
1682 pipe_ctx->tg);
4b28b76b 1683 pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, !is_pipe_tree_visible(pipe_ctx));
1a2c82a2 1684 }
cbfd33fd 1685
1a2c82a2
DL
1686 if (pipe_ctx->surface->public.visible) {
1687 dcn10_power_on_fe(dc, pipe_ctx, context);
70ccab60
HW
1688 update_dchubp_dpp(dc, pipe_ctx, context);
1689 }
1690
1691 if (pipe_ctx->bottom_pipe != NULL)
1692 program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context);
1693}
1694
1695static void dcn10_pplib_apply_display_requirements(
1696 struct core_dc *dc,
1697 struct validate_context *context)
1698{
1699 struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg;
1700
1701 pp_display_cfg->all_displays_in_sync = false;/*todo*/
1702 pp_display_cfg->nb_pstate_switch_disable = false;
c66a54dc
DL
1703 pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
1704 pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz;
1705 pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
1706 pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz;
70ccab60 1707 pp_display_cfg->avail_mclk_switch_time_us =
c66a54dc 1708 context->bw.dcn.cur_clk.dram_ccm_us > 0 ? context->bw.dcn.cur_clk.dram_ccm_us : 0;
70ccab60 1709 pp_display_cfg->avail_mclk_switch_time_in_disp_active_us =
c66a54dc
DL
1710 context->bw.dcn.cur_clk.min_active_dram_ccm_us > 0 ? context->bw.dcn.cur_clk.min_active_dram_ccm_us : 0;
1711 pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz;
1712 pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz;
70ccab60
HW
1713 dce110_fill_display_configs(context, pp_display_cfg);
1714
1715 if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof(
1716 struct dm_pp_display_configuration)) != 0)
1717 dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg);
1718
1719 dc->prev_display_config = *pp_display_cfg;
1720}
1721
1722static void dcn10_apply_ctx_for_surface(
1723 struct core_dc *dc,
1724 struct core_surface *surface,
1725 struct validate_context *context)
1726{
1727 int i;
1728
70ccab60
HW
1729 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1730 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1731
8d1b4047 1732 if (!pipe_ctx->surface || pipe_ctx->surface != surface)
70ccab60
HW
1733 continue;
1734
8d1b4047 1735
70ccab60 1736 /* looking for top pipe to program */
8d1b4047
YS
1737 if (!pipe_ctx->top_pipe) {
1738 memcpy(context->res_ctx.mpc_tree,
1739 dc->current_context->res_ctx.mpc_tree,
1740 sizeof(struct mpc_tree_cfg) * dc->res_pool->pipe_count);
1741
70ccab60 1742 program_all_pipe_in_tree(dc, pipe_ctx, context);
8d1b4047 1743 }
70ccab60
HW
1744 }
1745
1746 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1747 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1748
1749 if (!pipe_ctx->surface || pipe_ctx->top_pipe)
1750 continue;
1751
1752 /* unlock master update lock */
1753 unlock_otg_master(dc->ctx, pipe_ctx->tg->inst);
1754 }
1755
1756 /* reset unused pipe */
1757 for (i = 0; i < dc->res_pool->pipe_count; i++) {
1758 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1759 struct pipe_ctx *old_pipe_ctx =
1760 &dc->current_context->res_ctx.pipe_ctx[i];
1761
1762 if ((!pipe_ctx->surface && old_pipe_ctx->surface)
1763 || (!pipe_ctx->stream && old_pipe_ctx->stream))
1764 reset_front_end_for_pipe(dc,
1765 old_pipe_ctx, dc->current_context);
1766 }
1767}
1768
1769static void dcn10_set_bandwidth(
1770 struct core_dc *dc,
1771 struct validate_context *context,
1772 bool decrease_allowed)
1773{
1774 struct dm_pp_clock_for_voltage_req clock;
1775
1776 if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
1777 return;
1778
c66a54dc
DL
1779 if (decrease_allowed || context->bw.dcn.calc_clk.dispclk_khz
1780 > dc->current_context->bw.dcn.cur_clk.dispclk_khz) {
70ccab60
HW
1781 dc->res_pool->display_clock->funcs->set_clock(
1782 dc->res_pool->display_clock,
9037d802 1783 context->bw.dcn.calc_clk.dispclk_khz);
c66a54dc
DL
1784 dc->current_context->bw.dcn.cur_clk.dispclk_khz =
1785 context->bw.dcn.calc_clk.dispclk_khz;
70ccab60 1786 }
c66a54dc
DL
1787 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz
1788 > dc->current_context->bw.dcn.cur_clk.dcfclk_khz) {
70ccab60 1789 clock.clk_type = DM_PP_CLOCK_TYPE_DCFCLK;
9037d802 1790 clock.clocks_in_khz = context->bw.dcn.calc_clk.dcfclk_khz;
70ccab60 1791 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
c66a54dc
DL
1792 dc->current_context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz;
1793 context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz;
70ccab60 1794 }
c66a54dc
DL
1795 if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz
1796 > dc->current_context->bw.dcn.cur_clk.fclk_khz) {
70ccab60 1797 clock.clk_type = DM_PP_CLOCK_TYPE_FCLK;
9037d802 1798 clock.clocks_in_khz = context->bw.dcn.calc_clk.fclk_khz;
70ccab60 1799 dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock);
9037d802 1800 dc->current_context->bw.dcn.calc_clk.fclk_khz = clock.clocks_in_khz;
c66a54dc
DL
1801 context->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz;
1802 }
1803 if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz
1804 > dc->current_context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) {
1805 dc->current_context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz =
1806 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
1807 context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz =
1808 context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz;
1809 }
1810 /* Decrease in freq is increase in period so opposite comparison for dram_ccm */
1811 if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us
1812 < dc->current_context->bw.dcn.cur_clk.dram_ccm_us) {
1813 dc->current_context->bw.dcn.calc_clk.dram_ccm_us =
1814 context->bw.dcn.calc_clk.dram_ccm_us;
1815 context->bw.dcn.cur_clk.dram_ccm_us =
1816 context->bw.dcn.calc_clk.dram_ccm_us;
1817 }
1818 if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us
1819 < dc->current_context->bw.dcn.cur_clk.min_active_dram_ccm_us) {
1820 dc->current_context->bw.dcn.calc_clk.min_active_dram_ccm_us =
1821 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
1822 context->bw.dcn.cur_clk.min_active_dram_ccm_us =
1823 context->bw.dcn.calc_clk.min_active_dram_ccm_us;
70ccab60
HW
1824 }
1825 dcn10_pplib_apply_display_requirements(dc, context);
1826}
1827
1828static void dcn10_power_down_fe(struct core_dc *dc, struct pipe_ctx *pipe)
1829{
1830 struct dc_context *ctx = dc->ctx;
1831 uint32_t inst_offset = 0;
1832
1833 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
1834 IP_REQUEST_EN, 1);
1835 dpp_pg_control(ctx, pipe->pipe_idx, false);
1836 hubp_pg_control(ctx, pipe->pipe_idx, false);
1837 HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
1838 IP_REQUEST_EN, 0);
1839
1840 if (pipe->xfm)
1841 pipe->xfm->funcs->transform_reset(pipe->xfm);
1842 memset(&pipe->scl_data, 0, sizeof(pipe->scl_data));
1843}
1844
1845static void set_drr(struct pipe_ctx **pipe_ctx,
1846 int num_pipes, int vmin, int vmax)
1847{
1848 int i = 0;
1849 struct drr_params params = {0};
1850
1851 params.vertical_total_max = vmax;
1852 params.vertical_total_min = vmin;
1853
1854 /* TODO: If multiple pipes are to be supported, you need
1855 * some GSL stuff
1856 */
1857 for (i = 0; i < num_pipes; i++) {
1858 pipe_ctx[i]->tg->funcs->set_drr(pipe_ctx[i]->tg, &params);
1859 }
1860}
1861
1862static void get_position(struct pipe_ctx **pipe_ctx,
1863 int num_pipes,
1864 struct crtc_position *position)
1865{
1866 int i = 0;
1867
1868 /* TODO: handle pipes > 1
1869 */
1870 for (i = 0; i < num_pipes; i++)
1871 pipe_ctx[i]->tg->funcs->get_position(pipe_ctx[i]->tg, position);
1872}
1873
1874static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
1875 int num_pipes, const struct dc_static_screen_events *events)
1876{
1877 unsigned int i;
1878 unsigned int value = 0;
1879
1880 if (events->surface_update)
1881 value |= 0x80;
1882 if (events->cursor_update)
1883 value |= 0x2;
1884
1885 for (i = 0; i < num_pipes; i++)
1886 pipe_ctx[i]->tg->funcs->
1887 set_static_screen_control(pipe_ctx[i]->tg, value);
1888}
1889
1890static void set_plane_config(
1891 const struct core_dc *dc,
1892 struct pipe_ctx *pipe_ctx,
1893 struct resource_context *res_ctx)
1894{
1895 /* TODO */
1896 program_gamut_remap(pipe_ctx);
1897}
1898
1899static const struct hw_sequencer_funcs dcn10_funcs = {
1bf56e62 1900 .program_gamut_remap = program_gamut_remap,
70ccab60
HW
1901 .init_hw = init_hw,
1902 .apply_ctx_to_hw = dce110_apply_ctx_to_hw,
1903 .apply_ctx_for_surface = dcn10_apply_ctx_for_surface,
1904 .set_plane_config = set_plane_config,
1905 .update_plane_addr = update_plane_addr,
1906 .update_pending_status = dce110_update_pending_status,
1907 .set_input_transfer_func = dcn10_set_input_transfer_func,
1908 .set_output_transfer_func = dcn10_set_output_transfer_func,
1909 .power_down = dce110_power_down,
1910 .enable_accelerated_mode = dce110_enable_accelerated_mode,
1911 .enable_timing_synchronization = dcn10_enable_timing_synchronization,
1912 .update_info_frame = dce110_update_info_frame,
1913 .enable_stream = dce110_enable_stream,
1914 .disable_stream = dce110_disable_stream,
1915 .unblank_stream = dce110_unblank_stream,
1916 .enable_display_pipe_clock_gating = NULL, /* TODOFPGA */
1917 .enable_display_power_gating = dcn10_enable_display_power_gating,
1918 .power_down_front_end = dcn10_power_down_fe,
1919 .power_on_front_end = dcn10_power_on_fe,
1920 .pipe_control_lock = dcn10_pipe_control_lock,
1921 .set_bandwidth = dcn10_set_bandwidth,
1922 .reset_hw_ctx_wrap = reset_hw_ctx_wrap,
1923 .prog_pixclk_crtc_otg = dcn10_prog_pixclk_crtc_otg,
1924 .set_drr = set_drr,
1925 .get_position = get_position,
1926 .set_static_screen_control = set_static_screen_control
1927};
1928
1929
1930bool dcn10_hw_sequencer_construct(struct core_dc *dc)
1931{
1932 dc->hwss = dcn10_funcs;
1933 return true;
1934}
1935