xref: /dflybsd-src/sys/dev/drm/amd/display/dc/dce/dce_dmcu.c (revision 789731325bde747251c28a37e0a00ed4efb88c46)
1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev  * Copyright 2012-16 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev  *
4b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
5b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
6b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
7b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
9b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
10b843c749SSergey Zigachev  *
11b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
12b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
13b843c749SSergey Zigachev  *
14b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
21b843c749SSergey Zigachev  *
22b843c749SSergey Zigachev  * Authors: AMD
23b843c749SSergey Zigachev  *
24b843c749SSergey Zigachev  */
25b843c749SSergey Zigachev 
26b843c749SSergey Zigachev #include "core_types.h"
27b843c749SSergey Zigachev #include "link_encoder.h"
28b843c749SSergey Zigachev #include "dce_dmcu.h"
29b843c749SSergey Zigachev #include "dm_services.h"
30b843c749SSergey Zigachev #include "reg_helper.h"
31b843c749SSergey Zigachev #include "fixed31_32.h"
32b843c749SSergey Zigachev #include "dc.h"
33b843c749SSergey Zigachev 
34b843c749SSergey Zigachev #define TO_DCE_DMCU(dmcu)\
35b843c749SSergey Zigachev 	container_of(dmcu, struct dce_dmcu, base)
36b843c749SSergey Zigachev 
37b843c749SSergey Zigachev #define REG(reg) \
38b843c749SSergey Zigachev 	(dmcu_dce->regs->reg)
39b843c749SSergey Zigachev 
40b843c749SSergey Zigachev #undef FN
41b843c749SSergey Zigachev #define FN(reg_name, field_name) \
42b843c749SSergey Zigachev 	dmcu_dce->dmcu_shift->field_name, dmcu_dce->dmcu_mask->field_name
43b843c749SSergey Zigachev 
44b843c749SSergey Zigachev #define CTX \
45b843c749SSergey Zigachev 	dmcu_dce->base.ctx
46b843c749SSergey Zigachev 
47b843c749SSergey Zigachev /* PSR related commands */
48b843c749SSergey Zigachev #define PSR_ENABLE 0x20
49b843c749SSergey Zigachev #define PSR_EXIT 0x21
50b843c749SSergey Zigachev #define PSR_SET 0x23
51b843c749SSergey Zigachev #define PSR_SET_WAITLOOP 0x31
52b843c749SSergey Zigachev #define MCP_INIT_DMCU 0x88
53b843c749SSergey Zigachev #define MCP_INIT_IRAM 0x89
54b843c749SSergey Zigachev #define MCP_DMCU_VERSION 0x90
55b843c749SSergey Zigachev #define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK   0x00000001L
56b843c749SSergey Zigachev 
dce_dmcu_init(struct dmcu * dmcu)57b843c749SSergey Zigachev static bool dce_dmcu_init(struct dmcu *dmcu)
58b843c749SSergey Zigachev {
59b843c749SSergey Zigachev 	// Do nothing
60b843c749SSergey Zigachev 	return true;
61b843c749SSergey Zigachev }
62b843c749SSergey Zigachev 
63*78973132SSergey Zigachev static
dce_dmcu_load_iram(struct dmcu * dmcu,unsigned int start_offset,const char * src,unsigned int bytes)64b843c749SSergey Zigachev bool dce_dmcu_load_iram(struct dmcu *dmcu,
65b843c749SSergey Zigachev 		unsigned int start_offset,
66b843c749SSergey Zigachev 		const char *src,
67b843c749SSergey Zigachev 		unsigned int bytes)
68b843c749SSergey Zigachev {
69b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
70b843c749SSergey Zigachev 	unsigned int count = 0;
71b843c749SSergey Zigachev 
72b843c749SSergey Zigachev 	/* Enable write access to IRAM */
73b843c749SSergey Zigachev 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
74b843c749SSergey Zigachev 			IRAM_HOST_ACCESS_EN, 1,
75b843c749SSergey Zigachev 			IRAM_WR_ADDR_AUTO_INC, 1);
76b843c749SSergey Zigachev 
77b843c749SSergey Zigachev 	REG_WAIT(DCI_MEM_PWR_STATUS, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
78b843c749SSergey Zigachev 
79b843c749SSergey Zigachev 	REG_WRITE(DMCU_IRAM_WR_CTRL, start_offset);
80b843c749SSergey Zigachev 
81b843c749SSergey Zigachev 	for (count = 0; count < bytes; count++)
82b843c749SSergey Zigachev 		REG_WRITE(DMCU_IRAM_WR_DATA, src[count]);
83b843c749SSergey Zigachev 
84b843c749SSergey Zigachev 	/* Disable write access to IRAM to allow dynamic sleep state */
85b843c749SSergey Zigachev 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
86b843c749SSergey Zigachev 			IRAM_HOST_ACCESS_EN, 0,
87b843c749SSergey Zigachev 			IRAM_WR_ADDR_AUTO_INC, 0);
88b843c749SSergey Zigachev 
89b843c749SSergey Zigachev 	return true;
90b843c749SSergey Zigachev }
91b843c749SSergey Zigachev 
dce_get_dmcu_psr_state(struct dmcu * dmcu,uint32_t * psr_state)92b843c749SSergey Zigachev static void dce_get_dmcu_psr_state(struct dmcu *dmcu, uint32_t *psr_state)
93b843c749SSergey Zigachev {
94b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
95b843c749SSergey Zigachev 
96b843c749SSergey Zigachev 	uint32_t psr_state_offset = 0xf0;
97b843c749SSergey Zigachev 
98b843c749SSergey Zigachev 	/* Enable write access to IRAM */
99b843c749SSergey Zigachev 	REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1);
100b843c749SSergey Zigachev 
101b843c749SSergey Zigachev 	REG_WAIT(DCI_MEM_PWR_STATUS, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
102b843c749SSergey Zigachev 
103b843c749SSergey Zigachev 	/* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
104b843c749SSergey Zigachev 	REG_WRITE(DMCU_IRAM_RD_CTRL, psr_state_offset);
105b843c749SSergey Zigachev 
106b843c749SSergey Zigachev 	/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
107b843c749SSergey Zigachev 	*psr_state = REG_READ(DMCU_IRAM_RD_DATA);
108b843c749SSergey Zigachev 
109b843c749SSergey Zigachev 	/* Disable write access to IRAM after finished using IRAM
110b843c749SSergey Zigachev 	 * in order to allow dynamic sleep state
111b843c749SSergey Zigachev 	 */
112b843c749SSergey Zigachev 	REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0);
113b843c749SSergey Zigachev }
114b843c749SSergey Zigachev 
dce_dmcu_set_psr_enable(struct dmcu * dmcu,bool enable,bool wait)115b843c749SSergey Zigachev static void dce_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait)
116b843c749SSergey Zigachev {
117b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
118b843c749SSergey Zigachev 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
119b843c749SSergey Zigachev 	unsigned int dmcu_wait_reg_ready_interval = 100;
120b843c749SSergey Zigachev 
121b843c749SSergey Zigachev 	unsigned int retryCount;
122b843c749SSergey Zigachev 	uint32_t psr_state = 0;
123b843c749SSergey Zigachev 
124b843c749SSergey Zigachev 	/* waitDMCUReadyForCmd */
125b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
126b843c749SSergey Zigachev 				dmcu_wait_reg_ready_interval,
127b843c749SSergey Zigachev 				dmcu_max_retry_on_wait_reg_ready);
128b843c749SSergey Zigachev 
129b843c749SSergey Zigachev 	/* setDMCUParam_Cmd */
130b843c749SSergey Zigachev 	if (enable)
131b843c749SSergey Zigachev 		REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
132b843c749SSergey Zigachev 				PSR_ENABLE);
133b843c749SSergey Zigachev 	else
134b843c749SSergey Zigachev 		REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
135b843c749SSergey Zigachev 				PSR_EXIT);
136b843c749SSergey Zigachev 
137b843c749SSergey Zigachev 	/* notifyDMCUMsg */
138b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
139b843c749SSergey Zigachev 	if (wait == true) {
140b843c749SSergey Zigachev 		for (retryCount = 0; retryCount <= 100; retryCount++) {
141b843c749SSergey Zigachev 			dce_get_dmcu_psr_state(dmcu, &psr_state);
142b843c749SSergey Zigachev 			if (enable) {
143b843c749SSergey Zigachev 				if (psr_state != 0)
144b843c749SSergey Zigachev 					break;
145b843c749SSergey Zigachev 			} else {
146b843c749SSergey Zigachev 				if (psr_state == 0)
147b843c749SSergey Zigachev 					break;
148b843c749SSergey Zigachev 			}
149b843c749SSergey Zigachev 			udelay(10);
150b843c749SSergey Zigachev 		}
151b843c749SSergey Zigachev 	}
152b843c749SSergey Zigachev }
153b843c749SSergey Zigachev 
dce_dmcu_setup_psr(struct dmcu * dmcu,struct dc_link * link,struct psr_context * psr_context)154b843c749SSergey Zigachev static bool dce_dmcu_setup_psr(struct dmcu *dmcu,
155b843c749SSergey Zigachev 		struct dc_link *link,
156b843c749SSergey Zigachev 		struct psr_context *psr_context)
157b843c749SSergey Zigachev {
158b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
159b843c749SSergey Zigachev 
160b843c749SSergey Zigachev 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
161b843c749SSergey Zigachev 	unsigned int dmcu_wait_reg_ready_interval = 100;
162b843c749SSergey Zigachev 
163b843c749SSergey Zigachev 	union dce_dmcu_psr_config_data_reg1 masterCmdData1;
164b843c749SSergey Zigachev 	union dce_dmcu_psr_config_data_reg2 masterCmdData2;
165b843c749SSergey Zigachev 	union dce_dmcu_psr_config_data_reg3 masterCmdData3;
166b843c749SSergey Zigachev 
167b843c749SSergey Zigachev 	link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc,
168b843c749SSergey Zigachev 			psr_context->psrExitLinkTrainingRequired);
169b843c749SSergey Zigachev 
170b843c749SSergey Zigachev 	/* Enable static screen interrupts for PSR supported display */
171b843c749SSergey Zigachev 	/* Disable the interrupt coming from other displays. */
172b843c749SSergey Zigachev 	REG_UPDATE_4(DMCU_INTERRUPT_TO_UC_EN_MASK,
173b843c749SSergey Zigachev 			STATIC_SCREEN1_INT_TO_UC_EN, 0,
174b843c749SSergey Zigachev 			STATIC_SCREEN2_INT_TO_UC_EN, 0,
175b843c749SSergey Zigachev 			STATIC_SCREEN3_INT_TO_UC_EN, 0,
176b843c749SSergey Zigachev 			STATIC_SCREEN4_INT_TO_UC_EN, 0);
177b843c749SSergey Zigachev 
178b843c749SSergey Zigachev 	switch (psr_context->controllerId) {
179b843c749SSergey Zigachev 	/* Driver uses case 1 for unconfigured */
180b843c749SSergey Zigachev 	case 1:
181b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
182b843c749SSergey Zigachev 				STATIC_SCREEN1_INT_TO_UC_EN, 1);
183b843c749SSergey Zigachev 		break;
184b843c749SSergey Zigachev 	case 2:
185b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
186b843c749SSergey Zigachev 				STATIC_SCREEN2_INT_TO_UC_EN, 1);
187b843c749SSergey Zigachev 		break;
188b843c749SSergey Zigachev 	case 3:
189b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
190b843c749SSergey Zigachev 				STATIC_SCREEN3_INT_TO_UC_EN, 1);
191b843c749SSergey Zigachev 		break;
192b843c749SSergey Zigachev 	case 4:
193b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
194b843c749SSergey Zigachev 				STATIC_SCREEN4_INT_TO_UC_EN, 1);
195b843c749SSergey Zigachev 		break;
196b843c749SSergey Zigachev 	case 5:
197b843c749SSergey Zigachev 		/* CZ/NL only has 4 CRTC!!
198b843c749SSergey Zigachev 		 * really valid.
199b843c749SSergey Zigachev 		 * There is no interrupt enable mask for these instances.
200b843c749SSergey Zigachev 		 */
201b843c749SSergey Zigachev 		break;
202b843c749SSergey Zigachev 	case 6:
203b843c749SSergey Zigachev 		/* CZ/NL only has 4 CRTC!!
204b843c749SSergey Zigachev 		 * These are here because they are defined in HW regspec,
205b843c749SSergey Zigachev 		 * but not really valid. There is no interrupt enable mask
206b843c749SSergey Zigachev 		 * for these instances.
207b843c749SSergey Zigachev 		 */
208b843c749SSergey Zigachev 		break;
209b843c749SSergey Zigachev 	default:
210b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
211b843c749SSergey Zigachev 				STATIC_SCREEN1_INT_TO_UC_EN, 1);
212b843c749SSergey Zigachev 		break;
213b843c749SSergey Zigachev 	}
214b843c749SSergey Zigachev 
215b843c749SSergey Zigachev 	link->link_enc->funcs->psr_program_secondary_packet(link->link_enc,
216b843c749SSergey Zigachev 			psr_context->sdpTransmitLineNumDeadline);
217b843c749SSergey Zigachev 
218b843c749SSergey Zigachev 	if (psr_context->psr_level.bits.SKIP_SMU_NOTIFICATION)
219b843c749SSergey Zigachev 		REG_UPDATE(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, 1);
220b843c749SSergey Zigachev 
221b843c749SSergey Zigachev 	/* waitDMCUReadyForCmd */
222b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
223b843c749SSergey Zigachev 					dmcu_wait_reg_ready_interval,
224b843c749SSergey Zigachev 					dmcu_max_retry_on_wait_reg_ready);
225b843c749SSergey Zigachev 
226b843c749SSergey Zigachev 	/* setDMCUParam_PSRHostConfigData */
227b843c749SSergey Zigachev 	masterCmdData1.u32All = 0;
228b843c749SSergey Zigachev 	masterCmdData1.bits.timehyst_frames = psr_context->timehyst_frames;
229b843c749SSergey Zigachev 	masterCmdData1.bits.hyst_lines = psr_context->hyst_lines;
230b843c749SSergey Zigachev 	masterCmdData1.bits.rfb_update_auto_en =
231b843c749SSergey Zigachev 			psr_context->rfb_update_auto_en;
232b843c749SSergey Zigachev 	masterCmdData1.bits.dp_port_num = psr_context->transmitterId;
233b843c749SSergey Zigachev 	masterCmdData1.bits.dcp_sel = psr_context->controllerId;
234b843c749SSergey Zigachev 	masterCmdData1.bits.phy_type  = psr_context->phyType;
235b843c749SSergey Zigachev 	masterCmdData1.bits.frame_cap_ind =
236b843c749SSergey Zigachev 			psr_context->psrFrameCaptureIndicationReq;
237b843c749SSergey Zigachev 	masterCmdData1.bits.aux_chan = psr_context->channel;
238b843c749SSergey Zigachev 	masterCmdData1.bits.aux_repeat = psr_context->aux_repeats;
239b843c749SSergey Zigachev 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1),
240b843c749SSergey Zigachev 					masterCmdData1.u32All);
241b843c749SSergey Zigachev 
242b843c749SSergey Zigachev 	masterCmdData2.u32All = 0;
243b843c749SSergey Zigachev 	masterCmdData2.bits.dig_fe = psr_context->engineId;
244b843c749SSergey Zigachev 	masterCmdData2.bits.dig_be = psr_context->transmitterId;
245b843c749SSergey Zigachev 	masterCmdData2.bits.skip_wait_for_pll_lock =
246b843c749SSergey Zigachev 			psr_context->skipPsrWaitForPllLock;
247b843c749SSergey Zigachev 	masterCmdData2.bits.frame_delay = psr_context->frame_delay;
248b843c749SSergey Zigachev 	masterCmdData2.bits.smu_phy_id = psr_context->smuPhyId;
249b843c749SSergey Zigachev 	masterCmdData2.bits.num_of_controllers =
250b843c749SSergey Zigachev 			psr_context->numberOfControllers;
251b843c749SSergey Zigachev 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2),
252b843c749SSergey Zigachev 			masterCmdData2.u32All);
253b843c749SSergey Zigachev 
254b843c749SSergey Zigachev 	masterCmdData3.u32All = 0;
255b843c749SSergey Zigachev 	masterCmdData3.bits.psr_level = psr_context->psr_level.u32all;
256b843c749SSergey Zigachev 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3),
257b843c749SSergey Zigachev 			masterCmdData3.u32All);
258b843c749SSergey Zigachev 
259b843c749SSergey Zigachev 	/* setDMCUParam_Cmd */
260b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CMD_REG,
261b843c749SSergey Zigachev 			MASTER_COMM_CMD_REG_BYTE0, PSR_SET);
262b843c749SSergey Zigachev 
263b843c749SSergey Zigachev 	/* notifyDMCUMsg */
264b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
265b843c749SSergey Zigachev 
266b843c749SSergey Zigachev 	return true;
267b843c749SSergey Zigachev }
268b843c749SSergey Zigachev 
dce_is_dmcu_initialized(struct dmcu * dmcu)269b843c749SSergey Zigachev static bool dce_is_dmcu_initialized(struct dmcu *dmcu)
270b843c749SSergey Zigachev {
271b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
272b843c749SSergey Zigachev 	unsigned int dmcu_uc_reset;
273b843c749SSergey Zigachev 
274b843c749SSergey Zigachev 	/* microcontroller is not running */
275b843c749SSergey Zigachev 	REG_GET(DMCU_STATUS, UC_IN_RESET, &dmcu_uc_reset);
276b843c749SSergey Zigachev 
277b843c749SSergey Zigachev 	/* DMCU is not running */
278b843c749SSergey Zigachev 	if (dmcu_uc_reset)
279b843c749SSergey Zigachev 		return false;
280b843c749SSergey Zigachev 
281b843c749SSergey Zigachev 	return true;
282b843c749SSergey Zigachev }
283b843c749SSergey Zigachev 
dce_psr_wait_loop(struct dmcu * dmcu,unsigned int wait_loop_number)284b843c749SSergey Zigachev static void dce_psr_wait_loop(
285b843c749SSergey Zigachev 	struct dmcu *dmcu,
286b843c749SSergey Zigachev 	unsigned int wait_loop_number)
287b843c749SSergey Zigachev {
288b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
289b843c749SSergey Zigachev 	union dce_dmcu_psr_config_data_wait_loop_reg1 masterCmdData1;
290b843c749SSergey Zigachev 
291b843c749SSergey Zigachev 	if (dmcu->cached_wait_loop_number == wait_loop_number)
292b843c749SSergey Zigachev 		return;
293b843c749SSergey Zigachev 
294b843c749SSergey Zigachev 	/* DMCU is not running */
295b843c749SSergey Zigachev 	if (!dce_is_dmcu_initialized(dmcu))
296b843c749SSergey Zigachev 		return;
297b843c749SSergey Zigachev 
298b843c749SSergey Zigachev 	/* waitDMCUReadyForCmd */
299b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
300b843c749SSergey Zigachev 
301b843c749SSergey Zigachev 	masterCmdData1.u32 = 0;
302b843c749SSergey Zigachev 	masterCmdData1.bits.wait_loop = wait_loop_number;
303b843c749SSergey Zigachev 	dmcu->cached_wait_loop_number = wait_loop_number;
304b843c749SSergey Zigachev 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), masterCmdData1.u32);
305b843c749SSergey Zigachev 
306b843c749SSergey Zigachev 	/* setDMCUParam_Cmd */
307b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_SET_WAITLOOP);
308b843c749SSergey Zigachev 
309b843c749SSergey Zigachev 	/* notifyDMCUMsg */
310b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
311b843c749SSergey Zigachev }
312b843c749SSergey Zigachev 
dce_get_psr_wait_loop(struct dmcu * dmcu,unsigned int * psr_wait_loop_number)313b843c749SSergey Zigachev static void dce_get_psr_wait_loop(
314b843c749SSergey Zigachev 		struct dmcu *dmcu, unsigned int *psr_wait_loop_number)
315b843c749SSergey Zigachev {
316b843c749SSergey Zigachev 	*psr_wait_loop_number = dmcu->cached_wait_loop_number;
317b843c749SSergey Zigachev 	return;
318b843c749SSergey Zigachev }
319b843c749SSergey Zigachev 
320b843c749SSergey Zigachev #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
dcn10_get_dmcu_state(struct dmcu * dmcu)321b843c749SSergey Zigachev static void dcn10_get_dmcu_state(struct dmcu *dmcu)
322b843c749SSergey Zigachev {
323b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
324b843c749SSergey Zigachev 	uint32_t dmcu_state_offset = 0xf6;
325b843c749SSergey Zigachev 
326b843c749SSergey Zigachev 	/* Enable write access to IRAM */
327b843c749SSergey Zigachev 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
328b843c749SSergey Zigachev 			IRAM_HOST_ACCESS_EN, 1,
329b843c749SSergey Zigachev 			IRAM_RD_ADDR_AUTO_INC, 1);
330b843c749SSergey Zigachev 
331b843c749SSergey Zigachev 	REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
332b843c749SSergey Zigachev 
333b843c749SSergey Zigachev 	/* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
334b843c749SSergey Zigachev 	REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_state_offset);
335b843c749SSergey Zigachev 
336b843c749SSergey Zigachev 	/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
337b843c749SSergey Zigachev 	dmcu->dmcu_state = REG_READ(DMCU_IRAM_RD_DATA);
338b843c749SSergey Zigachev 
339b843c749SSergey Zigachev 	/* Disable write access to IRAM to allow dynamic sleep state */
340b843c749SSergey Zigachev 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
341b843c749SSergey Zigachev 			IRAM_HOST_ACCESS_EN, 0,
342b843c749SSergey Zigachev 			IRAM_RD_ADDR_AUTO_INC, 0);
343b843c749SSergey Zigachev }
344b843c749SSergey Zigachev 
dcn10_get_dmcu_version(struct dmcu * dmcu)345b843c749SSergey Zigachev static void dcn10_get_dmcu_version(struct dmcu *dmcu)
346b843c749SSergey Zigachev {
347b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
348b843c749SSergey Zigachev 	uint32_t dmcu_version_offset = 0xf1;
349b843c749SSergey Zigachev 
350b843c749SSergey Zigachev 	/* Clear scratch */
351b843c749SSergey Zigachev 	REG_WRITE(DC_DMCU_SCRATCH, 0);
352b843c749SSergey Zigachev 
353b843c749SSergey Zigachev 	/* Enable write access to IRAM */
354b843c749SSergey Zigachev 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
355b843c749SSergey Zigachev 			IRAM_HOST_ACCESS_EN, 1,
356b843c749SSergey Zigachev 			IRAM_RD_ADDR_AUTO_INC, 1);
357b843c749SSergey Zigachev 
358b843c749SSergey Zigachev 	REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
359b843c749SSergey Zigachev 
360b843c749SSergey Zigachev 	/* Write address to IRAM_RD_ADDR and read from DATA register */
361b843c749SSergey Zigachev 	REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_version_offset);
362b843c749SSergey Zigachev 	dmcu->dmcu_version.interface_version = REG_READ(DMCU_IRAM_RD_DATA);
363b843c749SSergey Zigachev 	dmcu->dmcu_version.year = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) |
364b843c749SSergey Zigachev 						REG_READ(DMCU_IRAM_RD_DATA));
365b843c749SSergey Zigachev 	dmcu->dmcu_version.month = REG_READ(DMCU_IRAM_RD_DATA);
366b843c749SSergey Zigachev 	dmcu->dmcu_version.date = REG_READ(DMCU_IRAM_RD_DATA);
367b843c749SSergey Zigachev 
368b843c749SSergey Zigachev 	/* Disable write access to IRAM to allow dynamic sleep state */
369b843c749SSergey Zigachev 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
370b843c749SSergey Zigachev 			IRAM_HOST_ACCESS_EN, 0,
371b843c749SSergey Zigachev 			IRAM_RD_ADDR_AUTO_INC, 0);
372b843c749SSergey Zigachev 
373b843c749SSergey Zigachev 	/* Send MCP command message to DMCU to get version reply from FW.
374b843c749SSergey Zigachev 	 * We expect this version should match the one in IRAM, otherwise
375b843c749SSergey Zigachev 	 * something is wrong with DMCU and we should fail and disable UC.
376b843c749SSergey Zigachev 	 */
377b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
378b843c749SSergey Zigachev 
379b843c749SSergey Zigachev 	/* Set command to get DMCU version from microcontroller */
380b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
381b843c749SSergey Zigachev 			MCP_DMCU_VERSION);
382b843c749SSergey Zigachev 
383b843c749SSergey Zigachev 	/* Notify microcontroller of new command */
384b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
385b843c749SSergey Zigachev 
386b843c749SSergey Zigachev 	/* Ensure command has been executed before continuing */
387b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
388b843c749SSergey Zigachev 
389b843c749SSergey Zigachev 	/* Somehow version does not match, so fail and return version 0 */
390b843c749SSergey Zigachev 	if (dmcu->dmcu_version.interface_version != REG_READ(DC_DMCU_SCRATCH))
391b843c749SSergey Zigachev 		dmcu->dmcu_version.interface_version = 0;
392b843c749SSergey Zigachev }
393b843c749SSergey Zigachev 
dcn10_dmcu_init(struct dmcu * dmcu)394b843c749SSergey Zigachev static bool dcn10_dmcu_init(struct dmcu *dmcu)
395b843c749SSergey Zigachev {
396b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
397b843c749SSergey Zigachev 
398b843c749SSergey Zigachev 	/* DMCU FW should populate the scratch register if running */
399b843c749SSergey Zigachev 	if (REG_READ(DC_DMCU_SCRATCH) == 0)
400b843c749SSergey Zigachev 		return false;
401b843c749SSergey Zigachev 
402b843c749SSergey Zigachev 	/* Check state is uninitialized */
403b843c749SSergey Zigachev 	dcn10_get_dmcu_state(dmcu);
404b843c749SSergey Zigachev 
405b843c749SSergey Zigachev 	/* If microcontroller is already initialized, do nothing */
406b843c749SSergey Zigachev 	if (dmcu->dmcu_state == DMCU_RUNNING)
407b843c749SSergey Zigachev 		return true;
408b843c749SSergey Zigachev 
409b843c749SSergey Zigachev 	/* Retrieve and cache the DMCU firmware version. */
410b843c749SSergey Zigachev 	dcn10_get_dmcu_version(dmcu);
411b843c749SSergey Zigachev 
412b843c749SSergey Zigachev 	/* Check interface version to confirm firmware is loaded and running */
413b843c749SSergey Zigachev 	if (dmcu->dmcu_version.interface_version == 0)
414b843c749SSergey Zigachev 		return false;
415b843c749SSergey Zigachev 
416b843c749SSergey Zigachev 	/* Wait until microcontroller is ready to process interrupt */
417b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
418b843c749SSergey Zigachev 
419b843c749SSergey Zigachev 	/* Set initialized ramping boundary value */
420b843c749SSergey Zigachev 	REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF);
421b843c749SSergey Zigachev 
422b843c749SSergey Zigachev 	/* Set command to initialize microcontroller */
423b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
424b843c749SSergey Zigachev 			MCP_INIT_DMCU);
425b843c749SSergey Zigachev 
426b843c749SSergey Zigachev 	/* Notify microcontroller of new command */
427b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
428b843c749SSergey Zigachev 
429b843c749SSergey Zigachev 	/* Ensure command has been executed before continuing */
430b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
431b843c749SSergey Zigachev 
432b843c749SSergey Zigachev 	// Check state is initialized
433b843c749SSergey Zigachev 	dcn10_get_dmcu_state(dmcu);
434b843c749SSergey Zigachev 
435b843c749SSergey Zigachev 	// If microcontroller is not in running state, fail
436b843c749SSergey Zigachev 	if (dmcu->dmcu_state != DMCU_RUNNING)
437b843c749SSergey Zigachev 		return false;
438b843c749SSergey Zigachev 
439b843c749SSergey Zigachev 	return true;
440b843c749SSergey Zigachev }
441b843c749SSergey Zigachev 
dcn10_dmcu_load_iram(struct dmcu * dmcu,unsigned int start_offset,const char * src,unsigned int bytes)442b843c749SSergey Zigachev static bool dcn10_dmcu_load_iram(struct dmcu *dmcu,
443b843c749SSergey Zigachev 		unsigned int start_offset,
444b843c749SSergey Zigachev 		const char *src,
445b843c749SSergey Zigachev 		unsigned int bytes)
446b843c749SSergey Zigachev {
447b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
448b843c749SSergey Zigachev 	unsigned int count = 0;
449b843c749SSergey Zigachev 
450b843c749SSergey Zigachev 	/* If microcontroller is not running, do nothing */
451b843c749SSergey Zigachev 	if (dmcu->dmcu_state != DMCU_RUNNING)
452b843c749SSergey Zigachev 		return false;
453b843c749SSergey Zigachev 
454b843c749SSergey Zigachev 	/* Enable write access to IRAM */
455b843c749SSergey Zigachev 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
456b843c749SSergey Zigachev 			IRAM_HOST_ACCESS_EN, 1,
457b843c749SSergey Zigachev 			IRAM_WR_ADDR_AUTO_INC, 1);
458b843c749SSergey Zigachev 
459b843c749SSergey Zigachev 	REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
460b843c749SSergey Zigachev 
461b843c749SSergey Zigachev 	REG_WRITE(DMCU_IRAM_WR_CTRL, start_offset);
462b843c749SSergey Zigachev 
463b843c749SSergey Zigachev 	for (count = 0; count < bytes; count++)
464b843c749SSergey Zigachev 		REG_WRITE(DMCU_IRAM_WR_DATA, src[count]);
465b843c749SSergey Zigachev 
466b843c749SSergey Zigachev 	/* Disable write access to IRAM to allow dynamic sleep state */
467b843c749SSergey Zigachev 	REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
468b843c749SSergey Zigachev 			IRAM_HOST_ACCESS_EN, 0,
469b843c749SSergey Zigachev 			IRAM_WR_ADDR_AUTO_INC, 0);
470b843c749SSergey Zigachev 
471b843c749SSergey Zigachev 	/* Wait until microcontroller is ready to process interrupt */
472b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
473b843c749SSergey Zigachev 
474b843c749SSergey Zigachev 	/* Set command to signal IRAM is loaded and to initialize IRAM */
475b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
476b843c749SSergey Zigachev 			MCP_INIT_IRAM);
477b843c749SSergey Zigachev 
478b843c749SSergey Zigachev 	/* Notify microcontroller of new command */
479b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
480b843c749SSergey Zigachev 
481b843c749SSergey Zigachev 	/* Ensure command has been executed before continuing */
482b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
483b843c749SSergey Zigachev 
484b843c749SSergey Zigachev 	return true;
485b843c749SSergey Zigachev }
486b843c749SSergey Zigachev 
dcn10_get_dmcu_psr_state(struct dmcu * dmcu,uint32_t * psr_state)487b843c749SSergey Zigachev static void dcn10_get_dmcu_psr_state(struct dmcu *dmcu, uint32_t *psr_state)
488b843c749SSergey Zigachev {
489b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
490b843c749SSergey Zigachev 
491b843c749SSergey Zigachev 	uint32_t psr_state_offset = 0xf0;
492b843c749SSergey Zigachev 
493b843c749SSergey Zigachev 	/* If microcontroller is not running, do nothing */
494b843c749SSergey Zigachev 	if (dmcu->dmcu_state != DMCU_RUNNING)
495b843c749SSergey Zigachev 		return;
496b843c749SSergey Zigachev 
497b843c749SSergey Zigachev 	/* Enable write access to IRAM */
498b843c749SSergey Zigachev 	REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1);
499b843c749SSergey Zigachev 
500b843c749SSergey Zigachev 	REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
501b843c749SSergey Zigachev 
502b843c749SSergey Zigachev 	/* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
503b843c749SSergey Zigachev 	REG_WRITE(DMCU_IRAM_RD_CTRL, psr_state_offset);
504b843c749SSergey Zigachev 
505b843c749SSergey Zigachev 	/* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
506b843c749SSergey Zigachev 	*psr_state = REG_READ(DMCU_IRAM_RD_DATA);
507b843c749SSergey Zigachev 
508b843c749SSergey Zigachev 	/* Disable write access to IRAM after finished using IRAM
509b843c749SSergey Zigachev 	 * in order to allow dynamic sleep state
510b843c749SSergey Zigachev 	 */
511b843c749SSergey Zigachev 	REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0);
512b843c749SSergey Zigachev }
513b843c749SSergey Zigachev 
dcn10_dmcu_set_psr_enable(struct dmcu * dmcu,bool enable,bool wait)514b843c749SSergey Zigachev static void dcn10_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait)
515b843c749SSergey Zigachev {
516b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
517b843c749SSergey Zigachev 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
518b843c749SSergey Zigachev 	unsigned int dmcu_wait_reg_ready_interval = 100;
519b843c749SSergey Zigachev 
520b843c749SSergey Zigachev 	unsigned int retryCount;
521b843c749SSergey Zigachev 	uint32_t psr_state = 0;
522b843c749SSergey Zigachev 
523b843c749SSergey Zigachev 	/* If microcontroller is not running, do nothing */
524b843c749SSergey Zigachev 	if (dmcu->dmcu_state != DMCU_RUNNING)
525b843c749SSergey Zigachev 		return;
526b843c749SSergey Zigachev 
527b843c749SSergey Zigachev 	dcn10_get_dmcu_psr_state(dmcu, &psr_state);
528b843c749SSergey Zigachev 	if (psr_state == 0 && !enable)
529b843c749SSergey Zigachev 		return;
530b843c749SSergey Zigachev 	/* waitDMCUReadyForCmd */
531b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
532b843c749SSergey Zigachev 				dmcu_wait_reg_ready_interval,
533b843c749SSergey Zigachev 				dmcu_max_retry_on_wait_reg_ready);
534b843c749SSergey Zigachev 
535b843c749SSergey Zigachev 	/* setDMCUParam_Cmd */
536b843c749SSergey Zigachev 	if (enable)
537b843c749SSergey Zigachev 		REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
538b843c749SSergey Zigachev 				PSR_ENABLE);
539b843c749SSergey Zigachev 	else
540b843c749SSergey Zigachev 		REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
541b843c749SSergey Zigachev 				PSR_EXIT);
542b843c749SSergey Zigachev 
543b843c749SSergey Zigachev 	/* notifyDMCUMsg */
544b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
545b843c749SSergey Zigachev 
546b843c749SSergey Zigachev 	/* Below loops 1000 x 500us = 500 ms.
547b843c749SSergey Zigachev 	 *  Exit PSR may need to wait 1-2 frames to power up. Timeout after at
548b843c749SSergey Zigachev 	 *  least a few frames. Should never hit the max retry assert below.
549b843c749SSergey Zigachev 	 */
550b843c749SSergey Zigachev 	if (wait == true) {
551b843c749SSergey Zigachev 		for (retryCount = 0; retryCount <= 1000; retryCount++) {
552b843c749SSergey Zigachev 			dcn10_get_dmcu_psr_state(dmcu, &psr_state);
553b843c749SSergey Zigachev 			if (enable) {
554b843c749SSergey Zigachev 				if (psr_state != 0)
555b843c749SSergey Zigachev 					break;
556b843c749SSergey Zigachev 			} else {
557b843c749SSergey Zigachev 				if (psr_state == 0)
558b843c749SSergey Zigachev 					break;
559b843c749SSergey Zigachev 			}
560b843c749SSergey Zigachev 			udelay(500);
561b843c749SSergey Zigachev 		}
562b843c749SSergey Zigachev 
563b843c749SSergey Zigachev 		/* assert if max retry hit */
564b843c749SSergey Zigachev 		if (retryCount >= 1000)
565b843c749SSergey Zigachev 			ASSERT(0);
566b843c749SSergey Zigachev 	}
567b843c749SSergey Zigachev }
568b843c749SSergey Zigachev 
dcn10_dmcu_setup_psr(struct dmcu * dmcu,struct dc_link * link,struct psr_context * psr_context)569b843c749SSergey Zigachev static bool dcn10_dmcu_setup_psr(struct dmcu *dmcu,
570b843c749SSergey Zigachev 		struct dc_link *link,
571b843c749SSergey Zigachev 		struct psr_context *psr_context)
572b843c749SSergey Zigachev {
573b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
574b843c749SSergey Zigachev 
575b843c749SSergey Zigachev 	unsigned int dmcu_max_retry_on_wait_reg_ready = 801;
576b843c749SSergey Zigachev 	unsigned int dmcu_wait_reg_ready_interval = 100;
577b843c749SSergey Zigachev 
578b843c749SSergey Zigachev 	union dce_dmcu_psr_config_data_reg1 masterCmdData1;
579b843c749SSergey Zigachev 	union dce_dmcu_psr_config_data_reg2 masterCmdData2;
580b843c749SSergey Zigachev 	union dce_dmcu_psr_config_data_reg3 masterCmdData3;
581b843c749SSergey Zigachev 
582b843c749SSergey Zigachev 	/* If microcontroller is not running, do nothing */
583b843c749SSergey Zigachev 	if (dmcu->dmcu_state != DMCU_RUNNING)
584b843c749SSergey Zigachev 		return false;
585b843c749SSergey Zigachev 
586b843c749SSergey Zigachev 	link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc,
587b843c749SSergey Zigachev 			psr_context->psrExitLinkTrainingRequired);
588b843c749SSergey Zigachev 
589b843c749SSergey Zigachev 	/* Enable static screen interrupts for PSR supported display */
590b843c749SSergey Zigachev 	/* Disable the interrupt coming from other displays. */
591b843c749SSergey Zigachev 	REG_UPDATE_4(DMCU_INTERRUPT_TO_UC_EN_MASK,
592b843c749SSergey Zigachev 			STATIC_SCREEN1_INT_TO_UC_EN, 0,
593b843c749SSergey Zigachev 			STATIC_SCREEN2_INT_TO_UC_EN, 0,
594b843c749SSergey Zigachev 			STATIC_SCREEN3_INT_TO_UC_EN, 0,
595b843c749SSergey Zigachev 			STATIC_SCREEN4_INT_TO_UC_EN, 0);
596b843c749SSergey Zigachev 
597b843c749SSergey Zigachev 	switch (psr_context->controllerId) {
598b843c749SSergey Zigachev 	/* Driver uses case 1 for unconfigured */
599b843c749SSergey Zigachev 	case 1:
600b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
601b843c749SSergey Zigachev 				STATIC_SCREEN1_INT_TO_UC_EN, 1);
602b843c749SSergey Zigachev 		break;
603b843c749SSergey Zigachev 	case 2:
604b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
605b843c749SSergey Zigachev 				STATIC_SCREEN2_INT_TO_UC_EN, 1);
606b843c749SSergey Zigachev 		break;
607b843c749SSergey Zigachev 	case 3:
608b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
609b843c749SSergey Zigachev 				STATIC_SCREEN3_INT_TO_UC_EN, 1);
610b843c749SSergey Zigachev 		break;
611b843c749SSergey Zigachev 	case 4:
612b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
613b843c749SSergey Zigachev 				STATIC_SCREEN4_INT_TO_UC_EN, 1);
614b843c749SSergey Zigachev 		break;
615b843c749SSergey Zigachev 	case 5:
616b843c749SSergey Zigachev 		/* CZ/NL only has 4 CRTC!!
617b843c749SSergey Zigachev 		 * really valid.
618b843c749SSergey Zigachev 		 * There is no interrupt enable mask for these instances.
619b843c749SSergey Zigachev 		 */
620b843c749SSergey Zigachev 		break;
621b843c749SSergey Zigachev 	case 6:
622b843c749SSergey Zigachev 		/* CZ/NL only has 4 CRTC!!
623b843c749SSergey Zigachev 		 * These are here because they are defined in HW regspec,
624b843c749SSergey Zigachev 		 * but not really valid. There is no interrupt enable mask
625b843c749SSergey Zigachev 		 * for these instances.
626b843c749SSergey Zigachev 		 */
627b843c749SSergey Zigachev 		break;
628b843c749SSergey Zigachev 	default:
629b843c749SSergey Zigachev 		REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK,
630b843c749SSergey Zigachev 				STATIC_SCREEN1_INT_TO_UC_EN, 1);
631b843c749SSergey Zigachev 		break;
632b843c749SSergey Zigachev 	}
633b843c749SSergey Zigachev 
634b843c749SSergey Zigachev 	link->link_enc->funcs->psr_program_secondary_packet(link->link_enc,
635b843c749SSergey Zigachev 			psr_context->sdpTransmitLineNumDeadline);
636b843c749SSergey Zigachev 
637b843c749SSergey Zigachev 	if (psr_context->psr_level.bits.SKIP_SMU_NOTIFICATION)
638b843c749SSergey Zigachev 		REG_UPDATE(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, 1);
639b843c749SSergey Zigachev 
640b843c749SSergey Zigachev 	/* waitDMCUReadyForCmd */
641b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0,
642b843c749SSergey Zigachev 			dmcu_wait_reg_ready_interval,
643b843c749SSergey Zigachev 			dmcu_max_retry_on_wait_reg_ready);
644b843c749SSergey Zigachev 
645b843c749SSergey Zigachev 	/* setDMCUParam_PSRHostConfigData */
646b843c749SSergey Zigachev 	masterCmdData1.u32All = 0;
647b843c749SSergey Zigachev 	masterCmdData1.bits.timehyst_frames = psr_context->timehyst_frames;
648b843c749SSergey Zigachev 	masterCmdData1.bits.hyst_lines = psr_context->hyst_lines;
649b843c749SSergey Zigachev 	masterCmdData1.bits.rfb_update_auto_en =
650b843c749SSergey Zigachev 			psr_context->rfb_update_auto_en;
651b843c749SSergey Zigachev 	masterCmdData1.bits.dp_port_num = psr_context->transmitterId;
652b843c749SSergey Zigachev 	masterCmdData1.bits.dcp_sel = psr_context->controllerId;
653b843c749SSergey Zigachev 	masterCmdData1.bits.phy_type  = psr_context->phyType;
654b843c749SSergey Zigachev 	masterCmdData1.bits.frame_cap_ind =
655b843c749SSergey Zigachev 			psr_context->psrFrameCaptureIndicationReq;
656b843c749SSergey Zigachev 	masterCmdData1.bits.aux_chan = psr_context->channel;
657b843c749SSergey Zigachev 	masterCmdData1.bits.aux_repeat = psr_context->aux_repeats;
658b843c749SSergey Zigachev 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1),
659b843c749SSergey Zigachev 					masterCmdData1.u32All);
660b843c749SSergey Zigachev 
661b843c749SSergey Zigachev 	masterCmdData2.u32All = 0;
662b843c749SSergey Zigachev 	masterCmdData2.bits.dig_fe = psr_context->engineId;
663b843c749SSergey Zigachev 	masterCmdData2.bits.dig_be = psr_context->transmitterId;
664b843c749SSergey Zigachev 	masterCmdData2.bits.skip_wait_for_pll_lock =
665b843c749SSergey Zigachev 			psr_context->skipPsrWaitForPllLock;
666b843c749SSergey Zigachev 	masterCmdData2.bits.frame_delay = psr_context->frame_delay;
667b843c749SSergey Zigachev 	masterCmdData2.bits.smu_phy_id = psr_context->smuPhyId;
668b843c749SSergey Zigachev 	masterCmdData2.bits.num_of_controllers =
669b843c749SSergey Zigachev 			psr_context->numberOfControllers;
670b843c749SSergey Zigachev 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2),
671b843c749SSergey Zigachev 			masterCmdData2.u32All);
672b843c749SSergey Zigachev 
673b843c749SSergey Zigachev 	masterCmdData3.u32All = 0;
674b843c749SSergey Zigachev 	masterCmdData3.bits.psr_level = psr_context->psr_level.u32all;
675b843c749SSergey Zigachev 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3),
676b843c749SSergey Zigachev 			masterCmdData3.u32All);
677b843c749SSergey Zigachev 
678b843c749SSergey Zigachev 	/* setDMCUParam_Cmd */
679b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CMD_REG,
680b843c749SSergey Zigachev 			MASTER_COMM_CMD_REG_BYTE0, PSR_SET);
681b843c749SSergey Zigachev 
682b843c749SSergey Zigachev 	/* notifyDMCUMsg */
683b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
684b843c749SSergey Zigachev 
685b843c749SSergey Zigachev 	/* waitDMCUReadyForCmd */
686b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
687b843c749SSergey Zigachev 
688b843c749SSergey Zigachev 	return true;
689b843c749SSergey Zigachev }
690b843c749SSergey Zigachev 
dcn10_psr_wait_loop(struct dmcu * dmcu,unsigned int wait_loop_number)691b843c749SSergey Zigachev static void dcn10_psr_wait_loop(
692b843c749SSergey Zigachev 	struct dmcu *dmcu,
693b843c749SSergey Zigachev 	unsigned int wait_loop_number)
694b843c749SSergey Zigachev {
695b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
696b843c749SSergey Zigachev 	union dce_dmcu_psr_config_data_wait_loop_reg1 masterCmdData1;
697b843c749SSergey Zigachev 
698b843c749SSergey Zigachev 	/* If microcontroller is not running, do nothing */
699b843c749SSergey Zigachev 	if (dmcu->dmcu_state != DMCU_RUNNING)
700b843c749SSergey Zigachev 		return;
701b843c749SSergey Zigachev 
702b843c749SSergey Zigachev 	if (wait_loop_number != 0) {
703b843c749SSergey Zigachev 	/* waitDMCUReadyForCmd */
704b843c749SSergey Zigachev 	REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
705b843c749SSergey Zigachev 
706b843c749SSergey Zigachev 	masterCmdData1.u32 = 0;
707b843c749SSergey Zigachev 	masterCmdData1.bits.wait_loop = wait_loop_number;
708b843c749SSergey Zigachev 	dmcu->cached_wait_loop_number = wait_loop_number;
709b843c749SSergey Zigachev 	dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), masterCmdData1.u32);
710b843c749SSergey Zigachev 
711b843c749SSergey Zigachev 	/* setDMCUParam_Cmd */
712b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_SET_WAITLOOP);
713b843c749SSergey Zigachev 
714b843c749SSergey Zigachev 	/* notifyDMCUMsg */
715b843c749SSergey Zigachev 	REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
716b843c749SSergey Zigachev 	}
717b843c749SSergey Zigachev }
718b843c749SSergey Zigachev 
dcn10_get_psr_wait_loop(struct dmcu * dmcu,unsigned int * psr_wait_loop_number)719b843c749SSergey Zigachev static void dcn10_get_psr_wait_loop(
720b843c749SSergey Zigachev 		struct dmcu *dmcu, unsigned int *psr_wait_loop_number)
721b843c749SSergey Zigachev {
722b843c749SSergey Zigachev 	*psr_wait_loop_number = dmcu->cached_wait_loop_number;
723b843c749SSergey Zigachev 	return;
724b843c749SSergey Zigachev }
725b843c749SSergey Zigachev 
dcn10_is_dmcu_initialized(struct dmcu * dmcu)726b843c749SSergey Zigachev static bool dcn10_is_dmcu_initialized(struct dmcu *dmcu)
727b843c749SSergey Zigachev {
728b843c749SSergey Zigachev 	/* microcontroller is not running */
729b843c749SSergey Zigachev 	if (dmcu->dmcu_state != DMCU_RUNNING)
730b843c749SSergey Zigachev 		return false;
731b843c749SSergey Zigachev 	return true;
732b843c749SSergey Zigachev }
733b843c749SSergey Zigachev 
734b843c749SSergey Zigachev #endif
735b843c749SSergey Zigachev 
736b843c749SSergey Zigachev static const struct dmcu_funcs dce_funcs = {
737b843c749SSergey Zigachev 	.dmcu_init = dce_dmcu_init,
738b843c749SSergey Zigachev 	.load_iram = dce_dmcu_load_iram,
739b843c749SSergey Zigachev 	.set_psr_enable = dce_dmcu_set_psr_enable,
740b843c749SSergey Zigachev 	.setup_psr = dce_dmcu_setup_psr,
741b843c749SSergey Zigachev 	.get_psr_state = dce_get_dmcu_psr_state,
742b843c749SSergey Zigachev 	.set_psr_wait_loop = dce_psr_wait_loop,
743b843c749SSergey Zigachev 	.get_psr_wait_loop = dce_get_psr_wait_loop,
744b843c749SSergey Zigachev 	.is_dmcu_initialized = dce_is_dmcu_initialized
745b843c749SSergey Zigachev };
746b843c749SSergey Zigachev 
747b843c749SSergey Zigachev #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
748b843c749SSergey Zigachev static const struct dmcu_funcs dcn10_funcs = {
749b843c749SSergey Zigachev 	.dmcu_init = dcn10_dmcu_init,
750b843c749SSergey Zigachev 	.load_iram = dcn10_dmcu_load_iram,
751b843c749SSergey Zigachev 	.set_psr_enable = dcn10_dmcu_set_psr_enable,
752b843c749SSergey Zigachev 	.setup_psr = dcn10_dmcu_setup_psr,
753b843c749SSergey Zigachev 	.get_psr_state = dcn10_get_dmcu_psr_state,
754b843c749SSergey Zigachev 	.set_psr_wait_loop = dcn10_psr_wait_loop,
755b843c749SSergey Zigachev 	.get_psr_wait_loop = dcn10_get_psr_wait_loop,
756b843c749SSergey Zigachev 	.is_dmcu_initialized = dcn10_is_dmcu_initialized
757b843c749SSergey Zigachev };
758b843c749SSergey Zigachev #endif
759b843c749SSergey Zigachev 
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)760b843c749SSergey Zigachev static void dce_dmcu_construct(
761b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce,
762b843c749SSergey Zigachev 	struct dc_context *ctx,
763b843c749SSergey Zigachev 	const struct dce_dmcu_registers *regs,
764b843c749SSergey Zigachev 	const struct dce_dmcu_shift *dmcu_shift,
765b843c749SSergey Zigachev 	const struct dce_dmcu_mask *dmcu_mask)
766b843c749SSergey Zigachev {
767b843c749SSergey Zigachev 	struct dmcu *base = &dmcu_dce->base;
768b843c749SSergey Zigachev 
769b843c749SSergey Zigachev 	base->ctx = ctx;
770b843c749SSergey Zigachev 	base->funcs = &dce_funcs;
771b843c749SSergey Zigachev 	base->cached_wait_loop_number = 0;
772b843c749SSergey Zigachev 
773b843c749SSergey Zigachev 	dmcu_dce->regs = regs;
774b843c749SSergey Zigachev 	dmcu_dce->dmcu_shift = dmcu_shift;
775b843c749SSergey Zigachev 	dmcu_dce->dmcu_mask = dmcu_mask;
776b843c749SSergey Zigachev }
777b843c749SSergey Zigachev 
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)778b843c749SSergey Zigachev struct dmcu *dce_dmcu_create(
779b843c749SSergey Zigachev 	struct dc_context *ctx,
780b843c749SSergey Zigachev 	const struct dce_dmcu_registers *regs,
781b843c749SSergey Zigachev 	const struct dce_dmcu_shift *dmcu_shift,
782b843c749SSergey Zigachev 	const struct dce_dmcu_mask *dmcu_mask)
783b843c749SSergey Zigachev {
784b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = kzalloc(sizeof(*dmcu_dce), GFP_KERNEL);
785b843c749SSergey Zigachev 
786b843c749SSergey Zigachev 	if (dmcu_dce == NULL) {
787b843c749SSergey Zigachev 		BREAK_TO_DEBUGGER();
788b843c749SSergey Zigachev 		return NULL;
789b843c749SSergey Zigachev 	}
790b843c749SSergey Zigachev 
791b843c749SSergey Zigachev 	dce_dmcu_construct(
792b843c749SSergey Zigachev 		dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask);
793b843c749SSergey Zigachev 
794b843c749SSergey Zigachev 	dmcu_dce->base.funcs = &dce_funcs;
795b843c749SSergey Zigachev 
796b843c749SSergey Zigachev 	return &dmcu_dce->base;
797b843c749SSergey Zigachev }
798b843c749SSergey Zigachev 
799b843c749SSergey Zigachev #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
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)800b843c749SSergey Zigachev struct dmcu *dcn10_dmcu_create(
801b843c749SSergey Zigachev 	struct dc_context *ctx,
802b843c749SSergey Zigachev 	const struct dce_dmcu_registers *regs,
803b843c749SSergey Zigachev 	const struct dce_dmcu_shift *dmcu_shift,
804b843c749SSergey Zigachev 	const struct dce_dmcu_mask *dmcu_mask)
805b843c749SSergey Zigachev {
806b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = kzalloc(sizeof(*dmcu_dce), GFP_KERNEL);
807b843c749SSergey Zigachev 
808b843c749SSergey Zigachev 	if (dmcu_dce == NULL) {
809b843c749SSergey Zigachev 		BREAK_TO_DEBUGGER();
810b843c749SSergey Zigachev 		return NULL;
811b843c749SSergey Zigachev 	}
812b843c749SSergey Zigachev 
813b843c749SSergey Zigachev 	dce_dmcu_construct(
814b843c749SSergey Zigachev 		dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask);
815b843c749SSergey Zigachev 
816b843c749SSergey Zigachev 	dmcu_dce->base.funcs = &dcn10_funcs;
817b843c749SSergey Zigachev 
818b843c749SSergey Zigachev 	return &dmcu_dce->base;
819b843c749SSergey Zigachev }
820b843c749SSergey Zigachev #endif
821b843c749SSergey Zigachev 
dce_dmcu_destroy(struct dmcu ** dmcu)822b843c749SSergey Zigachev void dce_dmcu_destroy(struct dmcu **dmcu)
823b843c749SSergey Zigachev {
824b843c749SSergey Zigachev 	struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(*dmcu);
825b843c749SSergey Zigachev 
826b843c749SSergey Zigachev 	kfree(dmcu_dce);
827b843c749SSergey Zigachev 	*dmcu = NULL;
828b843c749SSergey Zigachev }
829