xref: /openbsd-src/sys/dev/pci/drm/amd/display/dc/dce/dce_dmcu.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
1fb4d8502Sjsg /*
2fb4d8502Sjsg  * Copyright 2012-16 Advanced Micro Devices, Inc.
3fb4d8502Sjsg  *
4fb4d8502Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
5fb4d8502Sjsg  * copy of this software and associated documentation files (the "Software"),
6fb4d8502Sjsg  * to deal in the Software without restriction, including without limitation
7fb4d8502Sjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8fb4d8502Sjsg  * and/or sell copies of the Software, and to permit persons to whom the
9fb4d8502Sjsg  * Software is furnished to do so, subject to the following conditions:
10fb4d8502Sjsg  *
11fb4d8502Sjsg  * The above copyright notice and this permission notice shall be included in
12fb4d8502Sjsg  * all copies or substantial portions of the Software.
13fb4d8502Sjsg  *
14fb4d8502Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15fb4d8502Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16fb4d8502Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17fb4d8502Sjsg  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18fb4d8502Sjsg  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19fb4d8502Sjsg  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20fb4d8502Sjsg  * OTHER DEALINGS IN THE SOFTWARE.
21fb4d8502Sjsg  *
22fb4d8502Sjsg  * Authors: AMD
23fb4d8502Sjsg  *
24fb4d8502Sjsg  */
25fb4d8502Sjsg 
26fb4d8502Sjsg #include "core_types.h"
27fb4d8502Sjsg #include "link_encoder.h"
28fb4d8502Sjsg #include "dce_dmcu.h"
29fb4d8502Sjsg #include "dm_services.h"
30fb4d8502Sjsg #include "reg_helper.h"
31fb4d8502Sjsg #include "fixed31_32.h"
32fb4d8502Sjsg #include "dc.h"
33fb4d8502Sjsg 
34fb4d8502Sjsg #define TO_DCE_DMCU(dmcu)\
35fb4d8502Sjsg 	container_of(dmcu, struct dce_dmcu, base)
36fb4d8502Sjsg 
37fb4d8502Sjsg #define REG(reg) \
38fb4d8502Sjsg 	(dmcu_dce->regs->reg)
39fb4d8502Sjsg 
40fb4d8502Sjsg #undef FN
41fb4d8502Sjsg #define FN(reg_name, field_name) \
42fb4d8502Sjsg 	dmcu_dce->dmcu_shift->field_name, dmcu_dce->dmcu_mask->field_name
43fb4d8502Sjsg 
44fb4d8502Sjsg #define CTX \
45fb4d8502Sjsg 	dmcu_dce->base.ctx
46fb4d8502Sjsg 
47fb4d8502Sjsg /* PSR related commands */
48fb4d8502Sjsg #define PSR_ENABLE 0x20
49fb4d8502Sjsg #define PSR_EXIT 0x21
50fb4d8502Sjsg #define PSR_SET 0x23
51fb4d8502Sjsg #define PSR_SET_WAITLOOP 0x31
52fb4d8502Sjsg #define MCP_INIT_DMCU 0x88
53fb4d8502Sjsg #define MCP_INIT_IRAM 0x89
54c349dbc7Sjsg #define MCP_SYNC_PHY_LOCK 0x90
55c349dbc7Sjsg #define MCP_SYNC_PHY_UNLOCK 0x91
56c349dbc7Sjsg #define MCP_BL_SET_PWM_FRAC 0x6A  /* Enable or disable Fractional PWM */
575ca02815Sjsg #define CRC_WIN_NOTIFY 0x92
585ca02815Sjsg #define CRC_STOP_UPDATE 0x93
595ca02815Sjsg #define MCP_SEND_EDID_CEA 0xA0
605ca02815Sjsg #define EDID_CEA_CMD_ACK 1
615ca02815Sjsg #define EDID_CEA_CMD_NACK 2
62fb4d8502Sjsg #define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK   0x00000001L
63fb4d8502Sjsg 
64c349dbc7Sjsg // PSP FW version
65c349dbc7Sjsg #define mmMP0_SMN_C2PMSG_58				0x1607A
66c349dbc7Sjsg 
67c349dbc7Sjsg //Register access policy version
68c349dbc7Sjsg #define mmMP0_SMN_C2PMSG_91				0x1609B
69c349dbc7Sjsg 
705ca02815Sjsg static const uint32_t abm_gain_stepsize = 0x0060;
715ca02815Sjsg 
dce_dmcu_init(struct dmcu * dmcu)72fb4d8502Sjsg static bool dce_dmcu_init(struct dmcu *dmcu)
73fb4d8502Sjsg {
74fb4d8502Sjsg 	// Do nothing
75fb4d8502Sjsg 	return true;
76fb4d8502Sjsg }
77fb4d8502Sjsg 
dce_dmcu_load_iram(struct dmcu * dmcu,unsigned int start_offset,const char * src,unsigned int bytes)785ca02815Sjsg static bool dce_dmcu_load_iram(struct dmcu *dmcu,
79fb4d8502Sjsg 			       unsigned int start_offset,
80fb4d8502Sjsg 			       const char *src,
81fb4d8502Sjsg 			       unsigned int bytes)
82fb4d8502Sjsg {
83fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
84fb4d8502Sjsg 	unsigned int count = 0;
85fb4d8502Sjsg 
86fb4d8502Sjsg 	/* Enable write access to IRAM */
87fb4d8502Sjsg 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
88fb4d8502Sjsg 			IRAM_HOST_ACCESS_EN, 1,
89fb4d8502Sjsg 			IRAM_WR_ADDR_AUTO_INC, 1);
90fb4d8502Sjsg 
91fb4d8502Sjsg 	REG_WAIT(DCI_MEM_PWR_STATUS, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
92fb4d8502Sjsg 
93fb4d8502Sjsg 	REG_WRITE(DMCU_IRAM_WR_CTRL, start_offset);
94fb4d8502Sjsg 
95fb4d8502Sjsg 	for (count = 0; count < bytes; count++)
96fb4d8502Sjsg 		REG_WRITE(DMCU_IRAM_WR_DATA, src[count]);
97fb4d8502Sjsg 
98fb4d8502Sjsg 	/* Disable write access to IRAM to allow dynamic sleep state */
99fb4d8502Sjsg 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
100fb4d8502Sjsg 			IRAM_HOST_ACCESS_EN, 0,
101fb4d8502Sjsg 			IRAM_WR_ADDR_AUTO_INC, 0);
102fb4d8502Sjsg 
103fb4d8502Sjsg 	return true;
104fb4d8502Sjsg }
105fb4d8502Sjsg 
dce_get_dmcu_psr_state(struct dmcu * dmcu,enum dc_psr_state * state)1065ca02815Sjsg static void dce_get_dmcu_psr_state(struct dmcu *dmcu, enum dc_psr_state *state)
107fb4d8502Sjsg {
108fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
109fb4d8502Sjsg 
110fb4d8502Sjsg 	uint32_t psr_state_offset = 0xf0;
111fb4d8502Sjsg 
112fb4d8502Sjsg 	/* Enable write access to IRAM */
113fb4d8502Sjsg 	REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1);
114fb4d8502Sjsg 
115fb4d8502Sjsg 	REG_WAIT(DCI_MEM_PWR_STATUS, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
116fb4d8502Sjsg 
117fb4d8502Sjsg 	/* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
118fb4d8502Sjsg 	REG_WRITE(DMCU_IRAM_RD_CTRL, psr_state_offset);
119fb4d8502Sjsg 
120fb4d8502Sjsg 	/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
1215ca02815Sjsg 	*state = (enum dc_psr_state)REG_READ(DMCU_IRAM_RD_DATA);
122fb4d8502Sjsg 
123fb4d8502Sjsg 	/* Disable write access to IRAM after finished using IRAM
124fb4d8502Sjsg 	 * in order to allow dynamic sleep state
125fb4d8502Sjsg 	 */
126fb4d8502Sjsg 	REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0);
127fb4d8502Sjsg }
128fb4d8502Sjsg 
dce_dmcu_set_psr_enable(struct dmcu * dmcu,bool enable,bool wait)129fb4d8502Sjsg static void dce_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait)
130fb4d8502Sjsg {
131fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
132fb4d8502Sjsg 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
133fb4d8502Sjsg 	unsigned int dmcu_wait_reg_ready_interval = 100;
134fb4d8502Sjsg 
135fb4d8502Sjsg 	unsigned int retryCount;
1365ca02815Sjsg 	enum dc_psr_state state = PSR_STATE0;
137fb4d8502Sjsg 
138fb4d8502Sjsg 	/* waitDMCUReadyForCmd */
139fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
140fb4d8502Sjsg 				dmcu_wait_reg_ready_interval,
141fb4d8502Sjsg 				dmcu_max_retry_on_wait_reg_ready);
142fb4d8502Sjsg 
143fb4d8502Sjsg 	/* setDMCUParam_Cmd */
144fb4d8502Sjsg 	if (enable)
145fb4d8502Sjsg 		REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
146fb4d8502Sjsg 				PSR_ENABLE);
147fb4d8502Sjsg 	else
148fb4d8502Sjsg 		REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
149fb4d8502Sjsg 				PSR_EXIT);
150fb4d8502Sjsg 
151fb4d8502Sjsg 	/* notifyDMCUMsg */
152fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
153fb4d8502Sjsg 	if (wait == true) {
154fb4d8502Sjsg 		for (retryCount = 0; retryCount <= 100; retryCount++) {
1555ca02815Sjsg 			dce_get_dmcu_psr_state(dmcu, &state);
156fb4d8502Sjsg 			if (enable) {
1575ca02815Sjsg 				if (state != PSR_STATE0)
158fb4d8502Sjsg 					break;
159fb4d8502Sjsg 			} else {
1605ca02815Sjsg 				if (state == PSR_STATE0)
161fb4d8502Sjsg 					break;
162fb4d8502Sjsg 			}
163fb4d8502Sjsg 			udelay(10);
164fb4d8502Sjsg 		}
165fb4d8502Sjsg 	}
166fb4d8502Sjsg }
167fb4d8502Sjsg 
dce_dmcu_setup_psr(struct dmcu * dmcu,struct dc_link * link,struct psr_context * psr_context)168fb4d8502Sjsg static bool dce_dmcu_setup_psr(struct dmcu *dmcu,
169fb4d8502Sjsg 		struct dc_link *link,
170fb4d8502Sjsg 		struct psr_context *psr_context)
171fb4d8502Sjsg {
172fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
173fb4d8502Sjsg 
174fb4d8502Sjsg 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
175fb4d8502Sjsg 	unsigned int dmcu_wait_reg_ready_interval = 100;
176fb4d8502Sjsg 
177fb4d8502Sjsg 	union dce_dmcu_psr_config_data_reg1 masterCmdData1;
178fb4d8502Sjsg 	union dce_dmcu_psr_config_data_reg2 masterCmdData2;
179fb4d8502Sjsg 	union dce_dmcu_psr_config_data_reg3 masterCmdData3;
180fb4d8502Sjsg 
181fb4d8502Sjsg 	link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc,
182fb4d8502Sjsg 			psr_context->psrExitLinkTrainingRequired);
183fb4d8502Sjsg 
184fb4d8502Sjsg 	/* Enable static screen interrupts for PSR supported display */
185fb4d8502Sjsg 	/* Disable the interrupt coming from other displays. */
186fb4d8502Sjsg 	REG_UPDATE_4(DMCU_INTERRUPT_TO_UC_EN_MASK,
187fb4d8502Sjsg 			STATIC_SCREEN1_INT_TO_UC_EN, 0,
188fb4d8502Sjsg 			STATIC_SCREEN2_INT_TO_UC_EN, 0,
189fb4d8502Sjsg 			STATIC_SCREEN3_INT_TO_UC_EN, 0,
190fb4d8502Sjsg 			STATIC_SCREEN4_INT_TO_UC_EN, 0);
191fb4d8502Sjsg 
192fb4d8502Sjsg 	switch (psr_context->controllerId) {
193fb4d8502Sjsg 	/* Driver uses case 1 for unconfigured */
194fb4d8502Sjsg 	case 1:
195fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
196fb4d8502Sjsg 				STATIC_SCREEN1_INT_TO_UC_EN, 1);
197fb4d8502Sjsg 		break;
198fb4d8502Sjsg 	case 2:
199fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
200fb4d8502Sjsg 				STATIC_SCREEN2_INT_TO_UC_EN, 1);
201fb4d8502Sjsg 		break;
202fb4d8502Sjsg 	case 3:
203fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
204fb4d8502Sjsg 				STATIC_SCREEN3_INT_TO_UC_EN, 1);
205fb4d8502Sjsg 		break;
206fb4d8502Sjsg 	case 4:
207fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
208fb4d8502Sjsg 				STATIC_SCREEN4_INT_TO_UC_EN, 1);
209fb4d8502Sjsg 		break;
210fb4d8502Sjsg 	case 5:
211fb4d8502Sjsg 		/* CZ/NL only has 4 CRTC!!
212fb4d8502Sjsg 		 * really valid.
213fb4d8502Sjsg 		 * There is no interrupt enable mask for these instances.
214fb4d8502Sjsg 		 */
215fb4d8502Sjsg 		break;
216fb4d8502Sjsg 	case 6:
217fb4d8502Sjsg 		/* CZ/NL only has 4 CRTC!!
218fb4d8502Sjsg 		 * These are here because they are defined in HW regspec,
219fb4d8502Sjsg 		 * but not really valid. There is no interrupt enable mask
220fb4d8502Sjsg 		 * for these instances.
221fb4d8502Sjsg 		 */
222fb4d8502Sjsg 		break;
223fb4d8502Sjsg 	default:
224fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
225fb4d8502Sjsg 				STATIC_SCREEN1_INT_TO_UC_EN, 1);
226fb4d8502Sjsg 		break;
227fb4d8502Sjsg 	}
228fb4d8502Sjsg 
229fb4d8502Sjsg 	link->link_enc->funcs->psr_program_secondary_packet(link->link_enc,
230fb4d8502Sjsg 			psr_context->sdpTransmitLineNumDeadline);
231fb4d8502Sjsg 
232fb4d8502Sjsg 	/* waitDMCUReadyForCmd */
233fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
234fb4d8502Sjsg 					dmcu_wait_reg_ready_interval,
235fb4d8502Sjsg 					dmcu_max_retry_on_wait_reg_ready);
236fb4d8502Sjsg 
237fb4d8502Sjsg 	/* setDMCUParam_PSRHostConfigData */
238fb4d8502Sjsg 	masterCmdData1.u32All = 0;
239fb4d8502Sjsg 	masterCmdData1.bits.timehyst_frames = psr_context->timehyst_frames;
240fb4d8502Sjsg 	masterCmdData1.bits.hyst_lines = psr_context->hyst_lines;
241fb4d8502Sjsg 	masterCmdData1.bits.rfb_update_auto_en =
242fb4d8502Sjsg 			psr_context->rfb_update_auto_en;
243fb4d8502Sjsg 	masterCmdData1.bits.dp_port_num = psr_context->transmitterId;
244fb4d8502Sjsg 	masterCmdData1.bits.dcp_sel = psr_context->controllerId;
245fb4d8502Sjsg 	masterCmdData1.bits.phy_type  = psr_context->phyType;
246fb4d8502Sjsg 	masterCmdData1.bits.frame_cap_ind =
247fb4d8502Sjsg 			psr_context->psrFrameCaptureIndicationReq;
248fb4d8502Sjsg 	masterCmdData1.bits.aux_chan = psr_context->channel;
249fb4d8502Sjsg 	masterCmdData1.bits.aux_repeat = psr_context->aux_repeats;
250fb4d8502Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1),
251fb4d8502Sjsg 					masterCmdData1.u32All);
252fb4d8502Sjsg 
253fb4d8502Sjsg 	masterCmdData2.u32All = 0;
254fb4d8502Sjsg 	masterCmdData2.bits.dig_fe = psr_context->engineId;
255fb4d8502Sjsg 	masterCmdData2.bits.dig_be = psr_context->transmitterId;
256fb4d8502Sjsg 	masterCmdData2.bits.skip_wait_for_pll_lock =
257fb4d8502Sjsg 			psr_context->skipPsrWaitForPllLock;
258fb4d8502Sjsg 	masterCmdData2.bits.frame_delay = psr_context->frame_delay;
259fb4d8502Sjsg 	masterCmdData2.bits.smu_phy_id = psr_context->smuPhyId;
260fb4d8502Sjsg 	masterCmdData2.bits.num_of_controllers =
261fb4d8502Sjsg 			psr_context->numberOfControllers;
262fb4d8502Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2),
263fb4d8502Sjsg 			masterCmdData2.u32All);
264fb4d8502Sjsg 
265fb4d8502Sjsg 	masterCmdData3.u32All = 0;
266fb4d8502Sjsg 	masterCmdData3.bits.psr_level = psr_context->psr_level.u32all;
267fb4d8502Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3),
268fb4d8502Sjsg 			masterCmdData3.u32All);
269fb4d8502Sjsg 
270fb4d8502Sjsg 	/* setDMCUParam_Cmd */
271fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG,
272fb4d8502Sjsg 			MASTER_COMM_CMD_REG_BYTE0, PSR_SET);
273fb4d8502Sjsg 
274fb4d8502Sjsg 	/* notifyDMCUMsg */
275fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
276fb4d8502Sjsg 
277fb4d8502Sjsg 	return true;
278fb4d8502Sjsg }
279fb4d8502Sjsg 
dce_is_dmcu_initialized(struct dmcu * dmcu)280fb4d8502Sjsg static bool dce_is_dmcu_initialized(struct dmcu *dmcu)
281fb4d8502Sjsg {
282fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
283fb4d8502Sjsg 	unsigned int dmcu_uc_reset;
284fb4d8502Sjsg 
285fb4d8502Sjsg 	/* microcontroller is not running */
286fb4d8502Sjsg 	REG_GET(DMCU_STATUS, UC_IN_RESET, &dmcu_uc_reset);
287fb4d8502Sjsg 
288fb4d8502Sjsg 	/* DMCU is not running */
289fb4d8502Sjsg 	if (dmcu_uc_reset)
290fb4d8502Sjsg 		return false;
291fb4d8502Sjsg 
292fb4d8502Sjsg 	return true;
293fb4d8502Sjsg }
294fb4d8502Sjsg 
dce_psr_wait_loop(struct dmcu * dmcu,unsigned int wait_loop_number)295fb4d8502Sjsg static void dce_psr_wait_loop(
296fb4d8502Sjsg 	struct dmcu *dmcu,
297fb4d8502Sjsg 	unsigned int wait_loop_number)
298fb4d8502Sjsg {
299fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
300fb4d8502Sjsg 	union dce_dmcu_psr_config_data_wait_loop_reg1 masterCmdData1;
301fb4d8502Sjsg 
302fb4d8502Sjsg 	if (dmcu->cached_wait_loop_number == wait_loop_number)
303fb4d8502Sjsg 		return;
304fb4d8502Sjsg 
305fb4d8502Sjsg 	/* DMCU is not running */
306fb4d8502Sjsg 	if (!dce_is_dmcu_initialized(dmcu))
307fb4d8502Sjsg 		return;
308fb4d8502Sjsg 
309fb4d8502Sjsg 	/* waitDMCUReadyForCmd */
310fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
311fb4d8502Sjsg 
312fb4d8502Sjsg 	masterCmdData1.u32 = 0;
313fb4d8502Sjsg 	masterCmdData1.bits.wait_loop = wait_loop_number;
314fb4d8502Sjsg 	dmcu->cached_wait_loop_number = wait_loop_number;
315fb4d8502Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), masterCmdData1.u32);
316fb4d8502Sjsg 
317fb4d8502Sjsg 	/* setDMCUParam_Cmd */
318fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_SET_WAITLOOP);
319fb4d8502Sjsg 
320fb4d8502Sjsg 	/* notifyDMCUMsg */
321fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
322fb4d8502Sjsg }
323fb4d8502Sjsg 
dce_get_psr_wait_loop(struct dmcu * dmcu,unsigned int * psr_wait_loop_number)324fb4d8502Sjsg static void dce_get_psr_wait_loop(
325fb4d8502Sjsg 		struct dmcu *dmcu, unsigned int *psr_wait_loop_number)
326fb4d8502Sjsg {
327fb4d8502Sjsg 	*psr_wait_loop_number = dmcu->cached_wait_loop_number;
328fb4d8502Sjsg 	return;
329fb4d8502Sjsg }
330fb4d8502Sjsg 
dcn10_get_dmcu_version(struct dmcu * dmcu)331fb4d8502Sjsg static void dcn10_get_dmcu_version(struct dmcu *dmcu)
332fb4d8502Sjsg {
333fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
334fb4d8502Sjsg 	uint32_t dmcu_version_offset = 0xf1;
335fb4d8502Sjsg 
336fb4d8502Sjsg 	/* Enable write access to IRAM */
337fb4d8502Sjsg 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
338fb4d8502Sjsg 			IRAM_HOST_ACCESS_EN, 1,
339fb4d8502Sjsg 			IRAM_RD_ADDR_AUTO_INC, 1);
340fb4d8502Sjsg 
341fb4d8502Sjsg 	REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
342fb4d8502Sjsg 
343fb4d8502Sjsg 	/* Write address to IRAM_RD_ADDR and read from DATA register */
344fb4d8502Sjsg 	REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_version_offset);
345fb4d8502Sjsg 	dmcu->dmcu_version.interface_version = REG_READ(DMCU_IRAM_RD_DATA);
346c349dbc7Sjsg 	dmcu->dmcu_version.abm_version = REG_READ(DMCU_IRAM_RD_DATA);
347c349dbc7Sjsg 	dmcu->dmcu_version.psr_version = REG_READ(DMCU_IRAM_RD_DATA);
348c349dbc7Sjsg 	dmcu->dmcu_version.build_version = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) |
349fb4d8502Sjsg 						REG_READ(DMCU_IRAM_RD_DATA));
350fb4d8502Sjsg 
351fb4d8502Sjsg 	/* Disable write access to IRAM to allow dynamic sleep state */
352fb4d8502Sjsg 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
353fb4d8502Sjsg 			IRAM_HOST_ACCESS_EN, 0,
354fb4d8502Sjsg 			IRAM_RD_ADDR_AUTO_INC, 0);
355c349dbc7Sjsg }
356fb4d8502Sjsg 
dcn10_dmcu_enable_fractional_pwm(struct dmcu * dmcu,uint32_t fractional_pwm)357c349dbc7Sjsg static void dcn10_dmcu_enable_fractional_pwm(struct dmcu *dmcu,
358c349dbc7Sjsg 		uint32_t fractional_pwm)
359c349dbc7Sjsg {
360c349dbc7Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
361c349dbc7Sjsg 
362c349dbc7Sjsg 	/* Wait until microcontroller is ready to process interrupt */
363fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
364fb4d8502Sjsg 
365c349dbc7Sjsg 	/* Set PWM fractional enable/disable */
366c349dbc7Sjsg 	REG_WRITE(MASTER_COMM_DATA_REG1, fractional_pwm);
367c349dbc7Sjsg 
368c349dbc7Sjsg 	/* Set command to enable or disable fractional PWM microcontroller */
369fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
370c349dbc7Sjsg 			MCP_BL_SET_PWM_FRAC);
371fb4d8502Sjsg 
372fb4d8502Sjsg 	/* Notify microcontroller of new command */
373fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
374fb4d8502Sjsg 
375fb4d8502Sjsg 	/* Ensure command has been executed before continuing */
376fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
377fb4d8502Sjsg }
378fb4d8502Sjsg 
dcn10_dmcu_init(struct dmcu * dmcu)379fb4d8502Sjsg static bool dcn10_dmcu_init(struct dmcu *dmcu)
380fb4d8502Sjsg {
381fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
382c349dbc7Sjsg 	const struct dc_config *config = &dmcu->ctx->dc->config;
383c349dbc7Sjsg 	bool status = false;
384c349dbc7Sjsg 	struct dc_context *ctx = dmcu->ctx;
385c349dbc7Sjsg 	unsigned int i;
386c349dbc7Sjsg 	//  5 4 3 2 1 0
387c349dbc7Sjsg 	//  F E D C B A - bit 0 is A, bit 5 is F
388c349dbc7Sjsg 	unsigned int tx_interrupt_mask = 0;
389fb4d8502Sjsg 
390c349dbc7Sjsg 	PERF_TRACE();
391c349dbc7Sjsg 	/*  Definition of DC_DMCU_SCRATCH
392c349dbc7Sjsg 	 *  0 : firmare not loaded
393c349dbc7Sjsg 	 *  1 : PSP load DMCU FW but not initialized
394c349dbc7Sjsg 	 *  2 : Firmware already initialized
395c349dbc7Sjsg 	 */
396c349dbc7Sjsg 	dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH);
397fb4d8502Sjsg 
398c349dbc7Sjsg 	for (i = 0; i < ctx->dc->link_count; i++) {
399c349dbc7Sjsg 		if (ctx->dc->links[i]->link_enc->features.flags.bits.DP_IS_USB_C) {
400c349dbc7Sjsg 			if (ctx->dc->links[i]->link_enc->transmitter >= TRANSMITTER_UNIPHY_A &&
401c349dbc7Sjsg 					ctx->dc->links[i]->link_enc->transmitter <= TRANSMITTER_UNIPHY_F) {
402c349dbc7Sjsg 				tx_interrupt_mask |= 1 << ctx->dc->links[i]->link_enc->transmitter;
403c349dbc7Sjsg 			}
404c349dbc7Sjsg 		}
405c349dbc7Sjsg 	}
406fb4d8502Sjsg 
407c349dbc7Sjsg 	switch (dmcu->dmcu_state) {
408c349dbc7Sjsg 	case DMCU_UNLOADED:
409c349dbc7Sjsg 		status = false;
410c349dbc7Sjsg 		break;
411c349dbc7Sjsg 	case DMCU_LOADED_UNINITIALIZED:
412fb4d8502Sjsg 		/* Wait until microcontroller is ready to process interrupt */
413fb4d8502Sjsg 		REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
414fb4d8502Sjsg 
415fb4d8502Sjsg 		/* Set initialized ramping boundary value */
416fb4d8502Sjsg 		REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF);
417fb4d8502Sjsg 
418c349dbc7Sjsg 		/* Set backlight ramping stepsize */
419c349dbc7Sjsg 		REG_WRITE(MASTER_COMM_DATA_REG2, abm_gain_stepsize);
420c349dbc7Sjsg 
421c349dbc7Sjsg 		REG_WRITE(MASTER_COMM_DATA_REG3, tx_interrupt_mask);
422c349dbc7Sjsg 
423fb4d8502Sjsg 		/* Set command to initialize microcontroller */
424fb4d8502Sjsg 		REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
425fb4d8502Sjsg 			MCP_INIT_DMCU);
426fb4d8502Sjsg 
427fb4d8502Sjsg 		/* Notify microcontroller of new command */
428fb4d8502Sjsg 		REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
429fb4d8502Sjsg 
430fb4d8502Sjsg 		/* Ensure command has been executed before continuing */
431fb4d8502Sjsg 		REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
432fb4d8502Sjsg 
433fb4d8502Sjsg 		// Check state is initialized
434c349dbc7Sjsg 		dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH);
435fb4d8502Sjsg 
436fb4d8502Sjsg 		// If microcontroller is not in running state, fail
437c349dbc7Sjsg 		if (dmcu->dmcu_state == DMCU_RUNNING) {
438c349dbc7Sjsg 			/* Retrieve and cache the DMCU firmware version. */
439c349dbc7Sjsg 			dcn10_get_dmcu_version(dmcu);
440fb4d8502Sjsg 
441c349dbc7Sjsg 			/* Initialize DMCU to use fractional PWM or not */
442c349dbc7Sjsg 			dcn10_dmcu_enable_fractional_pwm(dmcu,
443c349dbc7Sjsg 				(config->disable_fractional_pwm == false) ? 1 : 0);
444c349dbc7Sjsg 			status = true;
445c349dbc7Sjsg 		} else {
446c349dbc7Sjsg 			status = false;
447c349dbc7Sjsg 		}
448c349dbc7Sjsg 
449c349dbc7Sjsg 		break;
450c349dbc7Sjsg 	case DMCU_RUNNING:
451c349dbc7Sjsg 		status = true;
452c349dbc7Sjsg 		break;
453c349dbc7Sjsg 	default:
454c349dbc7Sjsg 		status = false;
455c349dbc7Sjsg 		break;
456c349dbc7Sjsg 	}
457c349dbc7Sjsg 
458c349dbc7Sjsg 	PERF_TRACE();
459c349dbc7Sjsg 	return status;
460c349dbc7Sjsg }
461c349dbc7Sjsg 
dcn21_dmcu_init(struct dmcu * dmcu)462c349dbc7Sjsg static bool dcn21_dmcu_init(struct dmcu *dmcu)
463c349dbc7Sjsg {
464c349dbc7Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
465c349dbc7Sjsg 	uint32_t dmcub_psp_version = REG_READ(DMCUB_SCRATCH15);
466c349dbc7Sjsg 
467c349dbc7Sjsg 	if (dmcu->auto_load_dmcu && dmcub_psp_version == 0) {
468c349dbc7Sjsg 		return false;
469c349dbc7Sjsg 	}
470c349dbc7Sjsg 
471c349dbc7Sjsg 	return dcn10_dmcu_init(dmcu);
472fb4d8502Sjsg }
473fb4d8502Sjsg 
dcn10_dmcu_load_iram(struct dmcu * dmcu,unsigned int start_offset,const char * src,unsigned int bytes)474fb4d8502Sjsg static bool dcn10_dmcu_load_iram(struct dmcu *dmcu,
475fb4d8502Sjsg 		unsigned int start_offset,
476fb4d8502Sjsg 		const char *src,
477fb4d8502Sjsg 		unsigned int bytes)
478fb4d8502Sjsg {
479fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
480fb4d8502Sjsg 	unsigned int count = 0;
481fb4d8502Sjsg 
482fb4d8502Sjsg 	/* If microcontroller is not running, do nothing */
483fb4d8502Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
484fb4d8502Sjsg 		return false;
485fb4d8502Sjsg 
486fb4d8502Sjsg 	/* Enable write access to IRAM */
487fb4d8502Sjsg 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
488fb4d8502Sjsg 			IRAM_HOST_ACCESS_EN, 1,
489fb4d8502Sjsg 			IRAM_WR_ADDR_AUTO_INC, 1);
490fb4d8502Sjsg 
491fb4d8502Sjsg 	REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
492fb4d8502Sjsg 
493fb4d8502Sjsg 	REG_WRITE(DMCU_IRAM_WR_CTRL, start_offset);
494fb4d8502Sjsg 
495fb4d8502Sjsg 	for (count = 0; count < bytes; count++)
496fb4d8502Sjsg 		REG_WRITE(DMCU_IRAM_WR_DATA, src[count]);
497fb4d8502Sjsg 
498fb4d8502Sjsg 	/* Disable write access to IRAM to allow dynamic sleep state */
499fb4d8502Sjsg 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
500fb4d8502Sjsg 			IRAM_HOST_ACCESS_EN, 0,
501fb4d8502Sjsg 			IRAM_WR_ADDR_AUTO_INC, 0);
502fb4d8502Sjsg 
503fb4d8502Sjsg 	/* Wait until microcontroller is ready to process interrupt */
504fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
505fb4d8502Sjsg 
506fb4d8502Sjsg 	/* Set command to signal IRAM is loaded and to initialize IRAM */
507fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
508fb4d8502Sjsg 			MCP_INIT_IRAM);
509fb4d8502Sjsg 
510fb4d8502Sjsg 	/* Notify microcontroller of new command */
511fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
512fb4d8502Sjsg 
513fb4d8502Sjsg 	/* Ensure command has been executed before continuing */
514fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
515fb4d8502Sjsg 
516fb4d8502Sjsg 	return true;
517fb4d8502Sjsg }
518fb4d8502Sjsg 
dcn10_get_dmcu_psr_state(struct dmcu * dmcu,enum dc_psr_state * state)5195ca02815Sjsg static void dcn10_get_dmcu_psr_state(struct dmcu *dmcu, enum dc_psr_state *state)
520fb4d8502Sjsg {
521fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
522fb4d8502Sjsg 
523fb4d8502Sjsg 	uint32_t psr_state_offset = 0xf0;
524fb4d8502Sjsg 
525fb4d8502Sjsg 	/* If microcontroller is not running, do nothing */
526fb4d8502Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
527fb4d8502Sjsg 		return;
528fb4d8502Sjsg 
529fb4d8502Sjsg 	/* Enable write access to IRAM */
530fb4d8502Sjsg 	REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1);
531fb4d8502Sjsg 
532fb4d8502Sjsg 	REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
533fb4d8502Sjsg 
534fb4d8502Sjsg 	/* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
535fb4d8502Sjsg 	REG_WRITE(DMCU_IRAM_RD_CTRL, psr_state_offset);
536fb4d8502Sjsg 
537fb4d8502Sjsg 	/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
5385ca02815Sjsg 	*state = (enum dc_psr_state)REG_READ(DMCU_IRAM_RD_DATA);
539fb4d8502Sjsg 
540fb4d8502Sjsg 	/* Disable write access to IRAM after finished using IRAM
541fb4d8502Sjsg 	 * in order to allow dynamic sleep state
542fb4d8502Sjsg 	 */
543fb4d8502Sjsg 	REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0);
544fb4d8502Sjsg }
545fb4d8502Sjsg 
dcn10_dmcu_set_psr_enable(struct dmcu * dmcu,bool enable,bool wait)546fb4d8502Sjsg static void dcn10_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait)
547fb4d8502Sjsg {
548fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
549fb4d8502Sjsg 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
550fb4d8502Sjsg 	unsigned int dmcu_wait_reg_ready_interval = 100;
551fb4d8502Sjsg 
552fb4d8502Sjsg 	unsigned int retryCount;
5535ca02815Sjsg 	enum dc_psr_state state = PSR_STATE0;
554fb4d8502Sjsg 
555fb4d8502Sjsg 	/* If microcontroller is not running, do nothing */
556fb4d8502Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
557fb4d8502Sjsg 		return;
558fb4d8502Sjsg 
559fb4d8502Sjsg 	/* waitDMCUReadyForCmd */
560fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
561fb4d8502Sjsg 				dmcu_wait_reg_ready_interval,
562fb4d8502Sjsg 				dmcu_max_retry_on_wait_reg_ready);
563fb4d8502Sjsg 
564fb4d8502Sjsg 	/* setDMCUParam_Cmd */
565fb4d8502Sjsg 	if (enable)
566fb4d8502Sjsg 		REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
567fb4d8502Sjsg 				PSR_ENABLE);
568fb4d8502Sjsg 	else
569fb4d8502Sjsg 		REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
570fb4d8502Sjsg 				PSR_EXIT);
571fb4d8502Sjsg 
572fb4d8502Sjsg 	/* notifyDMCUMsg */
573fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
574fb4d8502Sjsg 
575fb4d8502Sjsg 	/* Below loops 1000 x 500us = 500 ms.
576fb4d8502Sjsg 	 *  Exit PSR may need to wait 1-2 frames to power up. Timeout after at
577fb4d8502Sjsg 	 *  least a few frames. Should never hit the max retry assert below.
578fb4d8502Sjsg 	 */
579fb4d8502Sjsg 	if (wait == true) {
580fb4d8502Sjsg 		for (retryCount = 0; retryCount <= 1000; retryCount++) {
5815ca02815Sjsg 			dcn10_get_dmcu_psr_state(dmcu, &state);
582fb4d8502Sjsg 			if (enable) {
5835ca02815Sjsg 				if (state != PSR_STATE0)
584fb4d8502Sjsg 					break;
585fb4d8502Sjsg 			} else {
5865ca02815Sjsg 				if (state == PSR_STATE0)
587fb4d8502Sjsg 					break;
588fb4d8502Sjsg 			}
589*f005ef32Sjsg 			/* must *not* be fsleep - this can be called from high irq levels */
590fb4d8502Sjsg 			udelay(500);
591fb4d8502Sjsg 		}
592fb4d8502Sjsg 
593fb4d8502Sjsg 		/* assert if max retry hit */
594fb4d8502Sjsg 		if (retryCount >= 1000)
595fb4d8502Sjsg 			ASSERT(0);
596fb4d8502Sjsg 	}
597fb4d8502Sjsg }
598fb4d8502Sjsg 
dcn10_dmcu_setup_psr(struct dmcu * dmcu,struct dc_link * link,struct psr_context * psr_context)599fb4d8502Sjsg static bool dcn10_dmcu_setup_psr(struct dmcu *dmcu,
600fb4d8502Sjsg 		struct dc_link *link,
601fb4d8502Sjsg 		struct psr_context *psr_context)
602fb4d8502Sjsg {
603fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
604fb4d8502Sjsg 
605fb4d8502Sjsg 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
606fb4d8502Sjsg 	unsigned int dmcu_wait_reg_ready_interval = 100;
607fb4d8502Sjsg 
608fb4d8502Sjsg 	union dce_dmcu_psr_config_data_reg1 masterCmdData1;
609fb4d8502Sjsg 	union dce_dmcu_psr_config_data_reg2 masterCmdData2;
610fb4d8502Sjsg 	union dce_dmcu_psr_config_data_reg3 masterCmdData3;
611fb4d8502Sjsg 
612fb4d8502Sjsg 	/* If microcontroller is not running, do nothing */
613fb4d8502Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
614fb4d8502Sjsg 		return false;
615fb4d8502Sjsg 
616fb4d8502Sjsg 	link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc,
617fb4d8502Sjsg 			psr_context->psrExitLinkTrainingRequired);
618fb4d8502Sjsg 
619fb4d8502Sjsg 	/* Enable static screen interrupts for PSR supported display */
620fb4d8502Sjsg 	/* Disable the interrupt coming from other displays. */
621fb4d8502Sjsg 	REG_UPDATE_4(DMCU_INTERRUPT_TO_UC_EN_MASK,
622fb4d8502Sjsg 			STATIC_SCREEN1_INT_TO_UC_EN, 0,
623fb4d8502Sjsg 			STATIC_SCREEN2_INT_TO_UC_EN, 0,
624fb4d8502Sjsg 			STATIC_SCREEN3_INT_TO_UC_EN, 0,
625fb4d8502Sjsg 			STATIC_SCREEN4_INT_TO_UC_EN, 0);
626fb4d8502Sjsg 
627fb4d8502Sjsg 	switch (psr_context->controllerId) {
628fb4d8502Sjsg 	/* Driver uses case 1 for unconfigured */
629fb4d8502Sjsg 	case 1:
630fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
631fb4d8502Sjsg 				STATIC_SCREEN1_INT_TO_UC_EN, 1);
632fb4d8502Sjsg 		break;
633fb4d8502Sjsg 	case 2:
634fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
635fb4d8502Sjsg 				STATIC_SCREEN2_INT_TO_UC_EN, 1);
636fb4d8502Sjsg 		break;
637fb4d8502Sjsg 	case 3:
638fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
639fb4d8502Sjsg 				STATIC_SCREEN3_INT_TO_UC_EN, 1);
640fb4d8502Sjsg 		break;
641fb4d8502Sjsg 	case 4:
642fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
643fb4d8502Sjsg 				STATIC_SCREEN4_INT_TO_UC_EN, 1);
644fb4d8502Sjsg 		break;
645fb4d8502Sjsg 	case 5:
646fb4d8502Sjsg 		/* CZ/NL only has 4 CRTC!!
647fb4d8502Sjsg 		 * really valid.
648fb4d8502Sjsg 		 * There is no interrupt enable mask for these instances.
649fb4d8502Sjsg 		 */
650fb4d8502Sjsg 		break;
651fb4d8502Sjsg 	case 6:
652fb4d8502Sjsg 		/* CZ/NL only has 4 CRTC!!
653fb4d8502Sjsg 		 * These are here because they are defined in HW regspec,
654fb4d8502Sjsg 		 * but not really valid. There is no interrupt enable mask
655fb4d8502Sjsg 		 * for these instances.
656fb4d8502Sjsg 		 */
657fb4d8502Sjsg 		break;
658fb4d8502Sjsg 	default:
659fb4d8502Sjsg 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
660fb4d8502Sjsg 				STATIC_SCREEN1_INT_TO_UC_EN, 1);
661fb4d8502Sjsg 		break;
662fb4d8502Sjsg 	}
663fb4d8502Sjsg 
664fb4d8502Sjsg 	link->link_enc->funcs->psr_program_secondary_packet(link->link_enc,
665fb4d8502Sjsg 			psr_context->sdpTransmitLineNumDeadline);
666fb4d8502Sjsg 
667c349dbc7Sjsg 	if (psr_context->allow_smu_optimizations)
668fb4d8502Sjsg 		REG_UPDATE(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, 1);
669fb4d8502Sjsg 
670fb4d8502Sjsg 	/* waitDMCUReadyForCmd */
671fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
672fb4d8502Sjsg 			dmcu_wait_reg_ready_interval,
673fb4d8502Sjsg 			dmcu_max_retry_on_wait_reg_ready);
674fb4d8502Sjsg 
675fb4d8502Sjsg 	/* setDMCUParam_PSRHostConfigData */
676fb4d8502Sjsg 	masterCmdData1.u32All = 0;
677fb4d8502Sjsg 	masterCmdData1.bits.timehyst_frames = psr_context->timehyst_frames;
678fb4d8502Sjsg 	masterCmdData1.bits.hyst_lines = psr_context->hyst_lines;
679fb4d8502Sjsg 	masterCmdData1.bits.rfb_update_auto_en =
680fb4d8502Sjsg 			psr_context->rfb_update_auto_en;
681fb4d8502Sjsg 	masterCmdData1.bits.dp_port_num = psr_context->transmitterId;
682fb4d8502Sjsg 	masterCmdData1.bits.dcp_sel = psr_context->controllerId;
683fb4d8502Sjsg 	masterCmdData1.bits.phy_type  = psr_context->phyType;
684fb4d8502Sjsg 	masterCmdData1.bits.frame_cap_ind =
685fb4d8502Sjsg 			psr_context->psrFrameCaptureIndicationReq;
686fb4d8502Sjsg 	masterCmdData1.bits.aux_chan = psr_context->channel;
687fb4d8502Sjsg 	masterCmdData1.bits.aux_repeat = psr_context->aux_repeats;
688c349dbc7Sjsg 	masterCmdData1.bits.allow_smu_optimizations = psr_context->allow_smu_optimizations;
689fb4d8502Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1),
690fb4d8502Sjsg 					masterCmdData1.u32All);
691fb4d8502Sjsg 
692fb4d8502Sjsg 	masterCmdData2.u32All = 0;
693fb4d8502Sjsg 	masterCmdData2.bits.dig_fe = psr_context->engineId;
694fb4d8502Sjsg 	masterCmdData2.bits.dig_be = psr_context->transmitterId;
695fb4d8502Sjsg 	masterCmdData2.bits.skip_wait_for_pll_lock =
696fb4d8502Sjsg 			psr_context->skipPsrWaitForPllLock;
697fb4d8502Sjsg 	masterCmdData2.bits.frame_delay = psr_context->frame_delay;
698fb4d8502Sjsg 	masterCmdData2.bits.smu_phy_id = psr_context->smuPhyId;
699fb4d8502Sjsg 	masterCmdData2.bits.num_of_controllers =
700fb4d8502Sjsg 			psr_context->numberOfControllers;
701fb4d8502Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2),
702fb4d8502Sjsg 			masterCmdData2.u32All);
703fb4d8502Sjsg 
704fb4d8502Sjsg 	masterCmdData3.u32All = 0;
705fb4d8502Sjsg 	masterCmdData3.bits.psr_level = psr_context->psr_level.u32all;
706fb4d8502Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3),
707fb4d8502Sjsg 			masterCmdData3.u32All);
708fb4d8502Sjsg 
709c349dbc7Sjsg 
710fb4d8502Sjsg 	/* setDMCUParam_Cmd */
711fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG,
712fb4d8502Sjsg 			MASTER_COMM_CMD_REG_BYTE0, PSR_SET);
713fb4d8502Sjsg 
714fb4d8502Sjsg 	/* notifyDMCUMsg */
715fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
716fb4d8502Sjsg 
717fb4d8502Sjsg 	/* waitDMCUReadyForCmd */
718fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
719fb4d8502Sjsg 
720fb4d8502Sjsg 	return true;
721fb4d8502Sjsg }
722fb4d8502Sjsg 
dcn10_psr_wait_loop(struct dmcu * dmcu,unsigned int wait_loop_number)723fb4d8502Sjsg static void dcn10_psr_wait_loop(
724fb4d8502Sjsg 	struct dmcu *dmcu,
725fb4d8502Sjsg 	unsigned int wait_loop_number)
726fb4d8502Sjsg {
727fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
728fb4d8502Sjsg 	union dce_dmcu_psr_config_data_wait_loop_reg1 masterCmdData1;
729fb4d8502Sjsg 
730fb4d8502Sjsg 	/* If microcontroller is not running, do nothing */
731fb4d8502Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
732fb4d8502Sjsg 		return;
733fb4d8502Sjsg 
734fb4d8502Sjsg 	if (wait_loop_number != 0) {
735fb4d8502Sjsg 	/* waitDMCUReadyForCmd */
736fb4d8502Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
737fb4d8502Sjsg 
738fb4d8502Sjsg 	masterCmdData1.u32 = 0;
739fb4d8502Sjsg 	masterCmdData1.bits.wait_loop = wait_loop_number;
740fb4d8502Sjsg 	dmcu->cached_wait_loop_number = wait_loop_number;
741fb4d8502Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), masterCmdData1.u32);
742fb4d8502Sjsg 
743fb4d8502Sjsg 	/* setDMCUParam_Cmd */
744fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_SET_WAITLOOP);
745fb4d8502Sjsg 
746fb4d8502Sjsg 	/* notifyDMCUMsg */
747fb4d8502Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
748fb4d8502Sjsg 	}
749fb4d8502Sjsg }
750fb4d8502Sjsg 
dcn10_get_psr_wait_loop(struct dmcu * dmcu,unsigned int * psr_wait_loop_number)751fb4d8502Sjsg static void dcn10_get_psr_wait_loop(
752fb4d8502Sjsg 		struct dmcu *dmcu, unsigned int *psr_wait_loop_number)
753fb4d8502Sjsg {
754fb4d8502Sjsg 	*psr_wait_loop_number = dmcu->cached_wait_loop_number;
755fb4d8502Sjsg 	return;
756fb4d8502Sjsg }
757fb4d8502Sjsg 
dcn10_is_dmcu_initialized(struct dmcu * dmcu)758fb4d8502Sjsg static bool dcn10_is_dmcu_initialized(struct dmcu *dmcu)
759fb4d8502Sjsg {
760fb4d8502Sjsg 	/* microcontroller is not running */
761fb4d8502Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
762fb4d8502Sjsg 		return false;
763fb4d8502Sjsg 	return true;
764fb4d8502Sjsg }
765fb4d8502Sjsg 
766c349dbc7Sjsg 
767c349dbc7Sjsg 
dcn20_lock_phy(struct dmcu * dmcu)768c349dbc7Sjsg static bool dcn20_lock_phy(struct dmcu *dmcu)
769c349dbc7Sjsg {
770c349dbc7Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
771c349dbc7Sjsg 
772c349dbc7Sjsg 	/* If microcontroller is not running, do nothing */
773c349dbc7Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
774c349dbc7Sjsg 		return false;
775c349dbc7Sjsg 
776c349dbc7Sjsg 	/* waitDMCUReadyForCmd */
777c349dbc7Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
778c349dbc7Sjsg 
779c349dbc7Sjsg 	/* setDMCUParam_Cmd */
780c349dbc7Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SYNC_PHY_LOCK);
781c349dbc7Sjsg 
782c349dbc7Sjsg 	/* notifyDMCUMsg */
783c349dbc7Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
784c349dbc7Sjsg 
785c349dbc7Sjsg 	/* waitDMCUReadyForCmd */
786c349dbc7Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
787c349dbc7Sjsg 
788c349dbc7Sjsg 	return true;
789c349dbc7Sjsg }
790c349dbc7Sjsg 
dcn20_unlock_phy(struct dmcu * dmcu)791c349dbc7Sjsg static bool dcn20_unlock_phy(struct dmcu *dmcu)
792c349dbc7Sjsg {
793c349dbc7Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
794c349dbc7Sjsg 
795c349dbc7Sjsg 	/* If microcontroller is not running, do nothing */
796c349dbc7Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
797c349dbc7Sjsg 		return false;
798c349dbc7Sjsg 
799c349dbc7Sjsg 	/* waitDMCUReadyForCmd */
800c349dbc7Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
801c349dbc7Sjsg 
802c349dbc7Sjsg 	/* setDMCUParam_Cmd */
803c349dbc7Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SYNC_PHY_UNLOCK);
804c349dbc7Sjsg 
805c349dbc7Sjsg 	/* notifyDMCUMsg */
806c349dbc7Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
807c349dbc7Sjsg 
808c349dbc7Sjsg 	/* waitDMCUReadyForCmd */
809c349dbc7Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
810c349dbc7Sjsg 
811c349dbc7Sjsg 	return true;
812c349dbc7Sjsg }
813c349dbc7Sjsg 
dcn10_send_edid_cea(struct dmcu * dmcu,int offset,int total_length,uint8_t * data,int length)8145ca02815Sjsg static bool dcn10_send_edid_cea(struct dmcu *dmcu,
8155ca02815Sjsg 		int offset,
8165ca02815Sjsg 		int total_length,
8175ca02815Sjsg 		uint8_t *data,
8185ca02815Sjsg 		int length)
8195ca02815Sjsg {
8205ca02815Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
8215ca02815Sjsg 	uint32_t header, data1, data2;
8225ca02815Sjsg 
8235ca02815Sjsg 	/* If microcontroller is not running, do nothing */
8245ca02815Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
8255ca02815Sjsg 		return false;
8265ca02815Sjsg 
8275ca02815Sjsg 	if (length > 8 || length <= 0)
8285ca02815Sjsg 		return false;
8295ca02815Sjsg 
8305ca02815Sjsg 	header = ((uint32_t)offset & 0xFFFF) << 16 | (total_length & 0xFFFF);
8315ca02815Sjsg 	data1 = (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) |
8325ca02815Sjsg 		(((uint32_t)data[2]) << 8) | ((uint32_t)data[3]);
8335ca02815Sjsg 	data2 = (((uint32_t)data[4]) << 24) | (((uint32_t)data[5]) << 16) |
8345ca02815Sjsg 		(((uint32_t)data[6]) << 8) | ((uint32_t)data[7]);
8355ca02815Sjsg 
8365ca02815Sjsg 	/* waitDMCUReadyForCmd */
8375ca02815Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
8385ca02815Sjsg 
8395ca02815Sjsg 	/* setDMCUParam_Cmd */
8405ca02815Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SEND_EDID_CEA);
8415ca02815Sjsg 
8425ca02815Sjsg 	REG_WRITE(MASTER_COMM_DATA_REG1, header);
8435ca02815Sjsg 	REG_WRITE(MASTER_COMM_DATA_REG2, data1);
8445ca02815Sjsg 	REG_WRITE(MASTER_COMM_DATA_REG3, data2);
8455ca02815Sjsg 
8465ca02815Sjsg 	/* notifyDMCUMsg */
8475ca02815Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
8485ca02815Sjsg 
8495ca02815Sjsg 	/* waitDMCUReadyForCmd */
8505ca02815Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
8515ca02815Sjsg 
8525ca02815Sjsg 	return true;
8535ca02815Sjsg }
8545ca02815Sjsg 
dcn10_get_scp_results(struct dmcu * dmcu,uint32_t * cmd,uint32_t * data1,uint32_t * data2,uint32_t * data3)8555ca02815Sjsg static bool dcn10_get_scp_results(struct dmcu *dmcu,
8565ca02815Sjsg 		uint32_t *cmd,
8575ca02815Sjsg 		uint32_t *data1,
8585ca02815Sjsg 		uint32_t *data2,
8595ca02815Sjsg 		uint32_t *data3)
8605ca02815Sjsg {
8615ca02815Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
8625ca02815Sjsg 
8635ca02815Sjsg 	/* If microcontroller is not running, do nothing */
8645ca02815Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
8655ca02815Sjsg 		return false;
8665ca02815Sjsg 
8675ca02815Sjsg 	*cmd = REG_READ(SLAVE_COMM_CMD_REG);
8685ca02815Sjsg 	*data1 =  REG_READ(SLAVE_COMM_DATA_REG1);
8695ca02815Sjsg 	*data2 =  REG_READ(SLAVE_COMM_DATA_REG2);
8705ca02815Sjsg 	*data3 =  REG_READ(SLAVE_COMM_DATA_REG3);
8715ca02815Sjsg 
8725ca02815Sjsg 	/* clear SCP interrupt */
8735ca02815Sjsg 	REG_UPDATE(SLAVE_COMM_CNTL_REG, SLAVE_COMM_INTERRUPT, 0);
8745ca02815Sjsg 
8755ca02815Sjsg 	return true;
8765ca02815Sjsg }
8775ca02815Sjsg 
dcn10_recv_amd_vsdb(struct dmcu * dmcu,int * version,int * min_frame_rate,int * max_frame_rate)8785ca02815Sjsg static bool dcn10_recv_amd_vsdb(struct dmcu *dmcu,
8795ca02815Sjsg 		int *version,
8805ca02815Sjsg 		int *min_frame_rate,
8815ca02815Sjsg 		int *max_frame_rate)
8825ca02815Sjsg {
8835ca02815Sjsg 	uint32_t data[4];
8845ca02815Sjsg 	int cmd, ack, len;
8855ca02815Sjsg 
8865ca02815Sjsg 	if (!dcn10_get_scp_results(dmcu, &data[0], &data[1], &data[2], &data[3]))
8875ca02815Sjsg 		return false;
8885ca02815Sjsg 
8895ca02815Sjsg 	cmd = data[0] & 0x3FF;
8905ca02815Sjsg 	len = (data[0] >> 10) & 0x3F;
8915ca02815Sjsg 	ack = data[1];
8925ca02815Sjsg 
8935ca02815Sjsg 	if (cmd != MCP_SEND_EDID_CEA || ack != EDID_CEA_CMD_ACK || len != 12)
8945ca02815Sjsg 		return false;
8955ca02815Sjsg 
8965ca02815Sjsg 	if ((data[2] & 0xFF)) {
8975ca02815Sjsg 		*version = (data[2] >> 8) & 0xFF;
8985ca02815Sjsg 		*min_frame_rate = (data[3] >> 16) & 0xFFFF;
8995ca02815Sjsg 		*max_frame_rate = data[3] & 0xFFFF;
9005ca02815Sjsg 		return true;
9015ca02815Sjsg 	}
9025ca02815Sjsg 
9035ca02815Sjsg 	return false;
9045ca02815Sjsg }
9055ca02815Sjsg 
dcn10_recv_edid_cea_ack(struct dmcu * dmcu,int * offset)9065ca02815Sjsg static bool dcn10_recv_edid_cea_ack(struct dmcu *dmcu, int *offset)
9075ca02815Sjsg {
9085ca02815Sjsg 	uint32_t data[4];
9095ca02815Sjsg 	int cmd, ack;
9105ca02815Sjsg 
9115ca02815Sjsg 	if (!dcn10_get_scp_results(dmcu,
9125ca02815Sjsg 				&data[0], &data[1], &data[2], &data[3]))
9135ca02815Sjsg 		return false;
9145ca02815Sjsg 
9155ca02815Sjsg 	cmd = data[0] & 0x3FF;
9165ca02815Sjsg 	ack = data[1];
9175ca02815Sjsg 
9185ca02815Sjsg 	if (cmd != MCP_SEND_EDID_CEA)
9195ca02815Sjsg 		return false;
9205ca02815Sjsg 
9215ca02815Sjsg 	if (ack == EDID_CEA_CMD_ACK)
9225ca02815Sjsg 		return true;
9235ca02815Sjsg 
9245ca02815Sjsg 	*offset = data[2]; /* nack */
9255ca02815Sjsg 	return false;
9265ca02815Sjsg }
9275ca02815Sjsg 
928fb4d8502Sjsg 
9295ca02815Sjsg #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
dcn10_forward_crc_window(struct dmcu * dmcu,struct rect * rect,struct otg_phy_mux * mux_mapping)9305ca02815Sjsg static void dcn10_forward_crc_window(struct dmcu *dmcu,
931*f005ef32Sjsg 					struct rect *rect,
9325ca02815Sjsg 					struct otg_phy_mux *mux_mapping)
9335ca02815Sjsg {
9345ca02815Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
9355ca02815Sjsg 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
9365ca02815Sjsg 	unsigned int dmcu_wait_reg_ready_interval = 100;
9375ca02815Sjsg 	unsigned int crc_start = 0, crc_end = 0, otg_phy_mux = 0;
938*f005ef32Sjsg 	int x_start, y_start, x_end, y_end;
9395ca02815Sjsg 
9405ca02815Sjsg 	/* If microcontroller is not running, do nothing */
9415ca02815Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
9425ca02815Sjsg 		return;
9435ca02815Sjsg 
944*f005ef32Sjsg 	if (!rect)
9455ca02815Sjsg 		return;
9465ca02815Sjsg 
9475ca02815Sjsg 	/* waitDMCUReadyForCmd */
9485ca02815Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
9495ca02815Sjsg 				dmcu_wait_reg_ready_interval,
9505ca02815Sjsg 				dmcu_max_retry_on_wait_reg_ready);
9515ca02815Sjsg 
952*f005ef32Sjsg 	x_start = rect->x;
953*f005ef32Sjsg 	y_start = rect->y;
954*f005ef32Sjsg 	x_end = x_start + rect->width;
955*f005ef32Sjsg 	y_end = y_start + rect->height;
956*f005ef32Sjsg 
9575ca02815Sjsg 	/* build up nitification data */
958*f005ef32Sjsg 	crc_start = (((unsigned int) x_start) << 16) | y_start;
959*f005ef32Sjsg 	crc_end = (((unsigned int) x_end) << 16) | y_end;
9605ca02815Sjsg 	otg_phy_mux =
9615ca02815Sjsg 		(((unsigned int) mux_mapping->otg_output_num) << 16) | mux_mapping->phy_output_num;
9625ca02815Sjsg 
9635ca02815Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1),
9645ca02815Sjsg 					crc_start);
9655ca02815Sjsg 
9665ca02815Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2),
9675ca02815Sjsg 			crc_end);
9685ca02815Sjsg 
9695ca02815Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3),
9705ca02815Sjsg 			otg_phy_mux);
9715ca02815Sjsg 
9725ca02815Sjsg 	/* setDMCUParam_Cmd */
9735ca02815Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
9745ca02815Sjsg 				CRC_WIN_NOTIFY);
9755ca02815Sjsg 
9765ca02815Sjsg 	/* notifyDMCUMsg */
9775ca02815Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
9785ca02815Sjsg }
9795ca02815Sjsg 
dcn10_stop_crc_win_update(struct dmcu * dmcu,struct otg_phy_mux * mux_mapping)9805ca02815Sjsg static void dcn10_stop_crc_win_update(struct dmcu *dmcu,
9815ca02815Sjsg 					struct otg_phy_mux *mux_mapping)
9825ca02815Sjsg {
9835ca02815Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
9845ca02815Sjsg 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
9855ca02815Sjsg 	unsigned int dmcu_wait_reg_ready_interval = 100;
9865ca02815Sjsg 	unsigned int otg_phy_mux = 0;
9875ca02815Sjsg 
9885ca02815Sjsg 	/* If microcontroller is not running, do nothing */
9895ca02815Sjsg 	if (dmcu->dmcu_state != DMCU_RUNNING)
9905ca02815Sjsg 		return;
9915ca02815Sjsg 
9925ca02815Sjsg 	/* waitDMCUReadyForCmd */
9935ca02815Sjsg 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
9945ca02815Sjsg 				dmcu_wait_reg_ready_interval,
9955ca02815Sjsg 				dmcu_max_retry_on_wait_reg_ready);
9965ca02815Sjsg 
9975ca02815Sjsg 	/* build up nitification data */
9985ca02815Sjsg 	otg_phy_mux =
9995ca02815Sjsg 		(((unsigned int) mux_mapping->otg_output_num) << 16) | mux_mapping->phy_output_num;
10005ca02815Sjsg 
10015ca02815Sjsg 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1),
10025ca02815Sjsg 					otg_phy_mux);
10035ca02815Sjsg 
10045ca02815Sjsg 	/* setDMCUParam_Cmd */
10055ca02815Sjsg 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
10065ca02815Sjsg 				CRC_STOP_UPDATE);
10075ca02815Sjsg 
10085ca02815Sjsg 	/* notifyDMCUMsg */
10095ca02815Sjsg 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
10105ca02815Sjsg }
10115ca02815Sjsg #endif
10125ca02815Sjsg 
1013fb4d8502Sjsg static const struct dmcu_funcs dce_funcs = {
1014fb4d8502Sjsg 	.dmcu_init = dce_dmcu_init,
1015fb4d8502Sjsg 	.load_iram = dce_dmcu_load_iram,
1016fb4d8502Sjsg 	.set_psr_enable = dce_dmcu_set_psr_enable,
1017fb4d8502Sjsg 	.setup_psr = dce_dmcu_setup_psr,
1018fb4d8502Sjsg 	.get_psr_state = dce_get_dmcu_psr_state,
1019fb4d8502Sjsg 	.set_psr_wait_loop = dce_psr_wait_loop,
1020fb4d8502Sjsg 	.get_psr_wait_loop = dce_get_psr_wait_loop,
1021fb4d8502Sjsg 	.is_dmcu_initialized = dce_is_dmcu_initialized
1022fb4d8502Sjsg };
1023fb4d8502Sjsg 
1024fb4d8502Sjsg static const struct dmcu_funcs dcn10_funcs = {
1025fb4d8502Sjsg 	.dmcu_init = dcn10_dmcu_init,
1026fb4d8502Sjsg 	.load_iram = dcn10_dmcu_load_iram,
1027fb4d8502Sjsg 	.set_psr_enable = dcn10_dmcu_set_psr_enable,
1028fb4d8502Sjsg 	.setup_psr = dcn10_dmcu_setup_psr,
1029fb4d8502Sjsg 	.get_psr_state = dcn10_get_dmcu_psr_state,
1030fb4d8502Sjsg 	.set_psr_wait_loop = dcn10_psr_wait_loop,
1031fb4d8502Sjsg 	.get_psr_wait_loop = dcn10_get_psr_wait_loop,
10325ca02815Sjsg 	.send_edid_cea = dcn10_send_edid_cea,
10335ca02815Sjsg 	.recv_amd_vsdb = dcn10_recv_amd_vsdb,
10345ca02815Sjsg 	.recv_edid_cea_ack = dcn10_recv_edid_cea_ack,
10355ca02815Sjsg #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
10365ca02815Sjsg 	.forward_crc_window = dcn10_forward_crc_window,
10375ca02815Sjsg 	.stop_crc_win_update = dcn10_stop_crc_win_update,
10385ca02815Sjsg #endif
1039fb4d8502Sjsg 	.is_dmcu_initialized = dcn10_is_dmcu_initialized
1040fb4d8502Sjsg };
1041c349dbc7Sjsg 
1042c349dbc7Sjsg static const struct dmcu_funcs dcn20_funcs = {
1043c349dbc7Sjsg 	.dmcu_init = dcn10_dmcu_init,
1044c349dbc7Sjsg 	.load_iram = dcn10_dmcu_load_iram,
1045c349dbc7Sjsg 	.set_psr_enable = dcn10_dmcu_set_psr_enable,
1046c349dbc7Sjsg 	.setup_psr = dcn10_dmcu_setup_psr,
1047c349dbc7Sjsg 	.get_psr_state = dcn10_get_dmcu_psr_state,
1048c349dbc7Sjsg 	.set_psr_wait_loop = dcn10_psr_wait_loop,
1049c349dbc7Sjsg 	.get_psr_wait_loop = dcn10_get_psr_wait_loop,
1050c349dbc7Sjsg 	.is_dmcu_initialized = dcn10_is_dmcu_initialized,
1051c349dbc7Sjsg 	.lock_phy = dcn20_lock_phy,
1052c349dbc7Sjsg 	.unlock_phy = dcn20_unlock_phy
1053c349dbc7Sjsg };
1054c349dbc7Sjsg 
1055c349dbc7Sjsg static const struct dmcu_funcs dcn21_funcs = {
1056c349dbc7Sjsg 	.dmcu_init = dcn21_dmcu_init,
1057c349dbc7Sjsg 	.load_iram = dcn10_dmcu_load_iram,
1058c349dbc7Sjsg 	.set_psr_enable = dcn10_dmcu_set_psr_enable,
1059c349dbc7Sjsg 	.setup_psr = dcn10_dmcu_setup_psr,
1060c349dbc7Sjsg 	.get_psr_state = dcn10_get_dmcu_psr_state,
1061c349dbc7Sjsg 	.set_psr_wait_loop = dcn10_psr_wait_loop,
1062c349dbc7Sjsg 	.get_psr_wait_loop = dcn10_get_psr_wait_loop,
1063c349dbc7Sjsg 	.is_dmcu_initialized = dcn10_is_dmcu_initialized,
1064c349dbc7Sjsg 	.lock_phy = dcn20_lock_phy,
1065c349dbc7Sjsg 	.unlock_phy = dcn20_unlock_phy
1066c349dbc7Sjsg };
1067fb4d8502Sjsg 
dce_dmcu_construct(struct dce_dmcu * dmcu_dce,struct dc_context * ctx,const struct dce_dmcu_registers * regs,const struct dce_dmcu_shift * dmcu_shift,const struct dce_dmcu_mask * dmcu_mask)1068fb4d8502Sjsg static void dce_dmcu_construct(
1069fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce,
1070fb4d8502Sjsg 	struct dc_context *ctx,
1071fb4d8502Sjsg 	const struct dce_dmcu_registers *regs,
1072fb4d8502Sjsg 	const struct dce_dmcu_shift *dmcu_shift,
1073fb4d8502Sjsg 	const struct dce_dmcu_mask *dmcu_mask)
1074fb4d8502Sjsg {
1075fb4d8502Sjsg 	struct dmcu *base = &dmcu_dce->base;
1076fb4d8502Sjsg 
1077fb4d8502Sjsg 	base->ctx = ctx;
1078fb4d8502Sjsg 	base->funcs = &dce_funcs;
1079fb4d8502Sjsg 	base->cached_wait_loop_number = 0;
1080fb4d8502Sjsg 
1081fb4d8502Sjsg 	dmcu_dce->regs = regs;
1082fb4d8502Sjsg 	dmcu_dce->dmcu_shift = dmcu_shift;
1083fb4d8502Sjsg 	dmcu_dce->dmcu_mask = dmcu_mask;
1084fb4d8502Sjsg }
1085fb4d8502Sjsg 
dcn21_dmcu_construct(struct dce_dmcu * dmcu_dce,struct dc_context * ctx,const struct dce_dmcu_registers * regs,const struct dce_dmcu_shift * dmcu_shift,const struct dce_dmcu_mask * dmcu_mask)1086c349dbc7Sjsg static void dcn21_dmcu_construct(
1087c349dbc7Sjsg 		struct dce_dmcu *dmcu_dce,
1088c349dbc7Sjsg 		struct dc_context *ctx,
1089c349dbc7Sjsg 		const struct dce_dmcu_registers *regs,
1090c349dbc7Sjsg 		const struct dce_dmcu_shift *dmcu_shift,
1091c349dbc7Sjsg 		const struct dce_dmcu_mask *dmcu_mask)
1092c349dbc7Sjsg {
1093c349dbc7Sjsg 	uint32_t psp_version = 0;
1094c349dbc7Sjsg 
1095c349dbc7Sjsg 	dce_dmcu_construct(dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask);
1096c349dbc7Sjsg 
1097c349dbc7Sjsg 	psp_version = dm_read_reg(ctx, mmMP0_SMN_C2PMSG_58);
1098c349dbc7Sjsg 	dmcu_dce->base.auto_load_dmcu = ((psp_version & 0x00FF00FF) > 0x00110029);
1099c349dbc7Sjsg 	dmcu_dce->base.psp_version = psp_version;
1100c349dbc7Sjsg }
1101c349dbc7Sjsg 
dce_dmcu_create(struct dc_context * ctx,const struct dce_dmcu_registers * regs,const struct dce_dmcu_shift * dmcu_shift,const struct dce_dmcu_mask * dmcu_mask)1102fb4d8502Sjsg struct dmcu *dce_dmcu_create(
1103fb4d8502Sjsg 	struct dc_context *ctx,
1104fb4d8502Sjsg 	const struct dce_dmcu_registers *regs,
1105fb4d8502Sjsg 	const struct dce_dmcu_shift *dmcu_shift,
1106fb4d8502Sjsg 	const struct dce_dmcu_mask *dmcu_mask)
1107fb4d8502Sjsg {
1108fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = kzalloc(sizeof(*dmcu_dce), GFP_KERNEL);
1109fb4d8502Sjsg 
1110fb4d8502Sjsg 	if (dmcu_dce == NULL) {
1111fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
1112fb4d8502Sjsg 		return NULL;
1113fb4d8502Sjsg 	}
1114fb4d8502Sjsg 
1115fb4d8502Sjsg 	dce_dmcu_construct(
1116fb4d8502Sjsg 		dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask);
1117fb4d8502Sjsg 
1118fb4d8502Sjsg 	dmcu_dce->base.funcs = &dce_funcs;
1119fb4d8502Sjsg 
1120fb4d8502Sjsg 	return &dmcu_dce->base;
1121fb4d8502Sjsg }
1122fb4d8502Sjsg 
dcn10_dmcu_create(struct dc_context * ctx,const struct dce_dmcu_registers * regs,const struct dce_dmcu_shift * dmcu_shift,const struct dce_dmcu_mask * dmcu_mask)1123fb4d8502Sjsg struct dmcu *dcn10_dmcu_create(
1124fb4d8502Sjsg 	struct dc_context *ctx,
1125fb4d8502Sjsg 	const struct dce_dmcu_registers *regs,
1126fb4d8502Sjsg 	const struct dce_dmcu_shift *dmcu_shift,
1127fb4d8502Sjsg 	const struct dce_dmcu_mask *dmcu_mask)
1128fb4d8502Sjsg {
1129ad8b1aafSjsg 	struct dce_dmcu *dmcu_dce = kzalloc(sizeof(*dmcu_dce), GFP_ATOMIC);
1130fb4d8502Sjsg 
1131fb4d8502Sjsg 	if (dmcu_dce == NULL) {
1132fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
1133fb4d8502Sjsg 		return NULL;
1134fb4d8502Sjsg 	}
1135fb4d8502Sjsg 
1136fb4d8502Sjsg 	dce_dmcu_construct(
1137fb4d8502Sjsg 		dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask);
1138fb4d8502Sjsg 
1139fb4d8502Sjsg 	dmcu_dce->base.funcs = &dcn10_funcs;
1140fb4d8502Sjsg 
1141fb4d8502Sjsg 	return &dmcu_dce->base;
1142fb4d8502Sjsg }
1143c349dbc7Sjsg 
dcn20_dmcu_create(struct dc_context * ctx,const struct dce_dmcu_registers * regs,const struct dce_dmcu_shift * dmcu_shift,const struct dce_dmcu_mask * dmcu_mask)1144c349dbc7Sjsg struct dmcu *dcn20_dmcu_create(
1145c349dbc7Sjsg 	struct dc_context *ctx,
1146c349dbc7Sjsg 	const struct dce_dmcu_registers *regs,
1147c349dbc7Sjsg 	const struct dce_dmcu_shift *dmcu_shift,
1148c349dbc7Sjsg 	const struct dce_dmcu_mask *dmcu_mask)
1149c349dbc7Sjsg {
1150ad8b1aafSjsg 	struct dce_dmcu *dmcu_dce = kzalloc(sizeof(*dmcu_dce), GFP_ATOMIC);
1151c349dbc7Sjsg 
1152c349dbc7Sjsg 	if (dmcu_dce == NULL) {
1153c349dbc7Sjsg 		BREAK_TO_DEBUGGER();
1154c349dbc7Sjsg 		return NULL;
1155c349dbc7Sjsg 	}
1156c349dbc7Sjsg 
1157c349dbc7Sjsg 	dce_dmcu_construct(
1158c349dbc7Sjsg 		dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask);
1159c349dbc7Sjsg 
1160c349dbc7Sjsg 	dmcu_dce->base.funcs = &dcn20_funcs;
1161c349dbc7Sjsg 
1162c349dbc7Sjsg 	return &dmcu_dce->base;
1163c349dbc7Sjsg }
1164c349dbc7Sjsg 
dcn21_dmcu_create(struct dc_context * ctx,const struct dce_dmcu_registers * regs,const struct dce_dmcu_shift * dmcu_shift,const struct dce_dmcu_mask * dmcu_mask)1165c349dbc7Sjsg struct dmcu *dcn21_dmcu_create(
1166c349dbc7Sjsg 	struct dc_context *ctx,
1167c349dbc7Sjsg 	const struct dce_dmcu_registers *regs,
1168c349dbc7Sjsg 	const struct dce_dmcu_shift *dmcu_shift,
1169c349dbc7Sjsg 	const struct dce_dmcu_mask *dmcu_mask)
1170c349dbc7Sjsg {
1171ad8b1aafSjsg 	struct dce_dmcu *dmcu_dce = kzalloc(sizeof(*dmcu_dce), GFP_ATOMIC);
1172c349dbc7Sjsg 
1173c349dbc7Sjsg 	if (dmcu_dce == NULL) {
1174c349dbc7Sjsg 		BREAK_TO_DEBUGGER();
1175c349dbc7Sjsg 		return NULL;
1176c349dbc7Sjsg 	}
1177c349dbc7Sjsg 
1178c349dbc7Sjsg 	dcn21_dmcu_construct(
1179c349dbc7Sjsg 		dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask);
1180c349dbc7Sjsg 
1181c349dbc7Sjsg 	dmcu_dce->base.funcs = &dcn21_funcs;
1182c349dbc7Sjsg 
1183c349dbc7Sjsg 	return &dmcu_dce->base;
1184c349dbc7Sjsg }
1185fb4d8502Sjsg 
dce_dmcu_destroy(struct dmcu ** dmcu)1186fb4d8502Sjsg void dce_dmcu_destroy(struct dmcu **dmcu)
1187fb4d8502Sjsg {
1188fb4d8502Sjsg 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(*dmcu);
1189fb4d8502Sjsg 
1190fb4d8502Sjsg 	kfree(dmcu_dce);
1191fb4d8502Sjsg 	*dmcu = NULL;
1192fb4d8502Sjsg }
1193