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