Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/*
  2 * Copyright 2019 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 20 * OTHER DEALINGS IN THE SOFTWARE.
 21 *
 22 * Authors: AMD
 23 *
 24 */
 25
 26#include "../dmub_srv.h"
 27#include "dmub_reg.h"
 28#include "dmub_dcn20.h"
 29
 30#include "dcn/dcn_2_0_0_offset.h"
 31#include "dcn/dcn_2_0_0_sh_mask.h"
 32#include "soc15_hw_ip.h"
 33#include "vega10_ip_offset.h"
 34
 35#define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg
 36#define CTX dmub
 37#define REGS dmub->regs
 38
 39/* Registers. */
 40
 41const struct dmub_srv_common_regs dmub_srv_dcn20_regs = {
 42#define DMUB_SR(reg) REG_OFFSET(reg),
 43	{ DMUB_COMMON_REGS() },
 44#undef DMUB_SR
 45
 46#define DMUB_SF(reg, field) FD_MASK(reg, field),
 47	{ DMUB_COMMON_FIELDS() },
 48#undef DMUB_SF
 49
 50#define DMUB_SF(reg, field) FD_SHIFT(reg, field),
 51	{ DMUB_COMMON_FIELDS() },
 52#undef DMUB_SF
 53};
 54
 55/* Shared functions. */
 56
 57static void dmub_dcn20_get_fb_base_offset(struct dmub_srv *dmub,
 58					  uint64_t *fb_base,
 59					  uint64_t *fb_offset)
 60{
 61	uint32_t tmp;
 62
 63	if (dmub->fb_base || dmub->fb_offset) {
 64		*fb_base = dmub->fb_base;
 65		*fb_offset = dmub->fb_offset;
 66		return;
 67	}
 68
 69	REG_GET(DCN_VM_FB_LOCATION_BASE, FB_BASE, &tmp);
 70	*fb_base = (uint64_t)tmp << 24;
 71
 72	REG_GET(DCN_VM_FB_OFFSET, FB_OFFSET, &tmp);
 73	*fb_offset = (uint64_t)tmp << 24;
 74}
 75
 76static inline void dmub_dcn20_translate_addr(const union dmub_addr *addr_in,
 77					     uint64_t fb_base,
 78					     uint64_t fb_offset,
 79					     union dmub_addr *addr_out)
 80{
 81	addr_out->quad_part = addr_in->quad_part - fb_base + fb_offset;
 82}
 83
 84void dmub_dcn20_reset(struct dmub_srv *dmub)
 85{
 86	union dmub_gpint_data_register cmd;
 87	const uint32_t timeout = 30;
 88	uint32_t in_reset, scratch, i;
 89
 90	REG_GET(DMCUB_CNTL, DMCUB_SOFT_RESET, &in_reset);
 91
 92	if (in_reset == 0) {
 93		cmd.bits.status = 1;
 94		cmd.bits.command_code = DMUB_GPINT__STOP_FW;
 95		cmd.bits.param = 0;
 96
 97		dmub->hw_funcs.set_gpint(dmub, cmd);
 98
 99		/**
100		 * Timeout covers both the ACK and the wait
101		 * for remaining work to finish.
102		 *
103		 * This is mostly bound by the PHY disable sequence.
104		 * Each register check will be greater than 1us, so
105		 * don't bother using udelay.
106		 */
107
108		for (i = 0; i < timeout; ++i) {
109			if (dmub->hw_funcs.is_gpint_acked(dmub, cmd))
110				break;
111		}
112
113		for (i = 0; i < timeout; ++i) {
114			scratch = dmub->hw_funcs.get_gpint_response(dmub);
115			if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
116				break;
117		}
118
119		/* Clear the GPINT command manually so we don't reset again. */
120		cmd.all = 0;
121		dmub->hw_funcs.set_gpint(dmub, cmd);
122
123		/* Force reset in case we timed out, DMCUB is likely hung. */
124	}
125
126	REG_UPDATE(DMCUB_CNTL, DMCUB_SOFT_RESET, 1);
127	REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
128	REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
129	REG_WRITE(DMCUB_INBOX1_RPTR, 0);
130	REG_WRITE(DMCUB_INBOX1_WPTR, 0);
131	REG_WRITE(DMCUB_SCRATCH0, 0);
132}
133
134void dmub_dcn20_reset_release(struct dmub_srv *dmub)
135{
136	REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 0);
137	REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF);
138	REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1);
139	REG_UPDATE(DMCUB_CNTL, DMCUB_SOFT_RESET, 0);
140}
141
142void dmub_dcn20_backdoor_load(struct dmub_srv *dmub,
143			      const struct dmub_window *cw0,
144			      const struct dmub_window *cw1)
145{
146	union dmub_addr offset;
147	uint64_t fb_base, fb_offset;
148
149	dmub_dcn20_get_fb_base_offset(dmub, &fb_base, &fb_offset);
150
151	REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1);
152	REG_UPDATE_2(DMCUB_MEM_CNTL, DMCUB_MEM_READ_SPACE, 0x3,
153		     DMCUB_MEM_WRITE_SPACE, 0x3);
154
155	dmub_dcn20_translate_addr(&cw0->offset, fb_base, fb_offset, &offset);
156
157	REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part);
158	REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part);
159	REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base);
160	REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0,
161		  DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top,
162		  DMCUB_REGION3_CW0_ENABLE, 1);
163
164	dmub_dcn20_translate_addr(&cw1->offset, fb_base, fb_offset, &offset);
165
166	REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part);
167	REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part);
168	REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base);
169	REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0,
170		  DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top,
171		  DMCUB_REGION3_CW1_ENABLE, 1);
172
173	REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID,
174		     0x20);
175}
176
177void dmub_dcn20_setup_windows(struct dmub_srv *dmub,
178			      const struct dmub_window *cw2,
179			      const struct dmub_window *cw3,
180			      const struct dmub_window *cw4,
181			      const struct dmub_window *cw5,
182			      const struct dmub_window *cw6)
183{
184	union dmub_addr offset;
185	uint64_t fb_base, fb_offset;
186
187	dmub_dcn20_get_fb_base_offset(dmub, &fb_base, &fb_offset);
188
189	if (cw2->region.base != cw2->region.top) {
190		dmub_dcn20_translate_addr(&cw2->offset, fb_base, fb_offset,
191					  &offset);
192
193		REG_WRITE(DMCUB_REGION3_CW2_OFFSET, offset.u.low_part);
194		REG_WRITE(DMCUB_REGION3_CW2_OFFSET_HIGH, offset.u.high_part);
195		REG_WRITE(DMCUB_REGION3_CW2_BASE_ADDRESS, cw2->region.base);
196		REG_SET_2(DMCUB_REGION3_CW2_TOP_ADDRESS, 0,
197			  DMCUB_REGION3_CW2_TOP_ADDRESS, cw2->region.top,
198			  DMCUB_REGION3_CW2_ENABLE, 1);
199	} else {
200		REG_WRITE(DMCUB_REGION3_CW2_OFFSET, 0);
201		REG_WRITE(DMCUB_REGION3_CW2_OFFSET_HIGH, 0);
202		REG_WRITE(DMCUB_REGION3_CW2_BASE_ADDRESS, 0);
203		REG_WRITE(DMCUB_REGION3_CW2_TOP_ADDRESS, 0);
204	}
205
206	dmub_dcn20_translate_addr(&cw3->offset, fb_base, fb_offset, &offset);
207
208	REG_WRITE(DMCUB_REGION3_CW3_OFFSET, offset.u.low_part);
209	REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, offset.u.high_part);
210	REG_WRITE(DMCUB_REGION3_CW3_BASE_ADDRESS, cw3->region.base);
211	REG_SET_2(DMCUB_REGION3_CW3_TOP_ADDRESS, 0,
212		  DMCUB_REGION3_CW3_TOP_ADDRESS, cw3->region.top,
213		  DMCUB_REGION3_CW3_ENABLE, 1);
214
215	/* TODO: Move this to CW4. */
216	dmub_dcn20_translate_addr(&cw4->offset, fb_base, fb_offset, &offset);
217
218	/* New firmware can support CW4. */
219	if (dmub->fw_version > DMUB_FW_VERSION(1, 0, 10)) {
220		REG_WRITE(DMCUB_REGION3_CW4_OFFSET, offset.u.low_part);
221		REG_WRITE(DMCUB_REGION3_CW4_OFFSET_HIGH, offset.u.high_part);
222		REG_WRITE(DMCUB_REGION3_CW4_BASE_ADDRESS, cw4->region.base);
223		REG_SET_2(DMCUB_REGION3_CW4_TOP_ADDRESS, 0,
224			  DMCUB_REGION3_CW4_TOP_ADDRESS, cw4->region.top,
225			  DMCUB_REGION3_CW4_ENABLE, 1);
226	} else {
227		REG_WRITE(DMCUB_REGION4_OFFSET, offset.u.low_part);
228		REG_WRITE(DMCUB_REGION4_OFFSET_HIGH, offset.u.high_part);
229		REG_SET_2(DMCUB_REGION4_TOP_ADDRESS, 0,
230			  DMCUB_REGION4_TOP_ADDRESS,
231			  cw4->region.top - cw4->region.base - 1,
232			  DMCUB_REGION4_ENABLE, 1);
233	}
234
235	dmub_dcn20_translate_addr(&cw5->offset, fb_base, fb_offset, &offset);
236
237	REG_WRITE(DMCUB_REGION3_CW5_OFFSET, offset.u.low_part);
238	REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, offset.u.high_part);
239	REG_WRITE(DMCUB_REGION3_CW5_BASE_ADDRESS, cw5->region.base);
240	REG_SET_2(DMCUB_REGION3_CW5_TOP_ADDRESS, 0,
241		  DMCUB_REGION3_CW5_TOP_ADDRESS, cw5->region.top,
242		  DMCUB_REGION3_CW5_ENABLE, 1);
243
244	dmub_dcn20_translate_addr(&cw6->offset, fb_base, fb_offset, &offset);
245
246	REG_WRITE(DMCUB_REGION3_CW6_OFFSET, offset.u.low_part);
247	REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, offset.u.high_part);
248	REG_WRITE(DMCUB_REGION3_CW6_BASE_ADDRESS, cw6->region.base);
249	REG_SET_2(DMCUB_REGION3_CW6_TOP_ADDRESS, 0,
250		  DMCUB_REGION3_CW6_TOP_ADDRESS, cw6->region.top,
251		  DMCUB_REGION3_CW6_ENABLE, 1);
252}
253
254void dmub_dcn20_setup_mailbox(struct dmub_srv *dmub,
255			      const struct dmub_region *inbox1)
256{
257	/* New firmware can support CW4 for the inbox. */
258	if (dmub->fw_version > DMUB_FW_VERSION(1, 0, 10))
259		REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, inbox1->base);
260	else
261		REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, 0x80000000);
262
263	REG_WRITE(DMCUB_INBOX1_SIZE, inbox1->top - inbox1->base);
264}
265
266uint32_t dmub_dcn20_get_inbox1_rptr(struct dmub_srv *dmub)
267{
268	return REG_READ(DMCUB_INBOX1_RPTR);
269}
270
271void dmub_dcn20_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset)
272{
273	REG_WRITE(DMCUB_INBOX1_WPTR, wptr_offset);
274}
275
276bool dmub_dcn20_is_hw_init(struct dmub_srv *dmub)
277{
278	uint32_t is_hw_init;
279
280	REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_hw_init);
281
282	return is_hw_init != 0;
283}
284
285bool dmub_dcn20_is_supported(struct dmub_srv *dmub)
286{
287	uint32_t supported = 0;
288
289	REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported);
290
291	return supported;
292}
293
294void dmub_dcn20_set_gpint(struct dmub_srv *dmub,
295			  union dmub_gpint_data_register reg)
296{
297	REG_WRITE(DMCUB_GPINT_DATAIN1, reg.all);
298}
299
300bool dmub_dcn20_is_gpint_acked(struct dmub_srv *dmub,
301			       union dmub_gpint_data_register reg)
302{
303	union dmub_gpint_data_register test;
304
305	reg.bits.status = 0;
306	test.all = REG_READ(DMCUB_GPINT_DATAIN1);
307
308	return test.all == reg.all;
309}
310
311uint32_t dmub_dcn20_get_gpint_response(struct dmub_srv *dmub)
312{
313	return REG_READ(DMCUB_SCRATCH7);
314}