13a1627b0SNicholas Kazlauskas /*
23a1627b0SNicholas Kazlauskas  * Copyright 2019 Advanced Micro Devices, Inc.
33a1627b0SNicholas Kazlauskas  *
43a1627b0SNicholas Kazlauskas  * Permission is hereby granted, free of charge, to any person obtaining a
53a1627b0SNicholas Kazlauskas  * copy of this software and associated documentation files (the "Software"),
63a1627b0SNicholas Kazlauskas  * to deal in the Software without restriction, including without limitation
73a1627b0SNicholas Kazlauskas  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
83a1627b0SNicholas Kazlauskas  * and/or sell copies of the Software, and to permit persons to whom the
93a1627b0SNicholas Kazlauskas  * Software is furnished to do so, subject to the following conditions:
103a1627b0SNicholas Kazlauskas  *
113a1627b0SNicholas Kazlauskas  * The above copyright notice and this permission notice shall be included in
123a1627b0SNicholas Kazlauskas  * all copies or substantial portions of the Software.
133a1627b0SNicholas Kazlauskas  *
143a1627b0SNicholas Kazlauskas  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
153a1627b0SNicholas Kazlauskas  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
163a1627b0SNicholas Kazlauskas  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
173a1627b0SNicholas Kazlauskas  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
183a1627b0SNicholas Kazlauskas  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
193a1627b0SNicholas Kazlauskas  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
203a1627b0SNicholas Kazlauskas  * OTHER DEALINGS IN THE SOFTWARE.
213a1627b0SNicholas Kazlauskas  *
223a1627b0SNicholas Kazlauskas  * Authors: AMD
233a1627b0SNicholas Kazlauskas  *
243a1627b0SNicholas Kazlauskas  */
253a1627b0SNicholas Kazlauskas 
263a1627b0SNicholas Kazlauskas #include "dc.h"
273a1627b0SNicholas Kazlauskas #include "dc_dmub_srv.h"
28cdca3f21SAnthony Koo #include "../dmub/dmub_srv.h"
2970732504SYongqiang Sun #include "dm_helpers.h"
303a1627b0SNicholas Kazlauskas 
31ecdfc5c9SNicholas Kazlauskas #define CTX dc_dmub_srv->ctx
32ecdfc5c9SNicholas Kazlauskas #define DC_LOGGER CTX->logger
33ecdfc5c9SNicholas Kazlauskas 
343a1627b0SNicholas Kazlauskas static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc,
353a1627b0SNicholas Kazlauskas 				  struct dmub_srv *dmub)
363a1627b0SNicholas Kazlauskas {
373a1627b0SNicholas Kazlauskas 	dc_srv->dmub = dmub;
383a1627b0SNicholas Kazlauskas 	dc_srv->ctx = dc->ctx;
393a1627b0SNicholas Kazlauskas }
403a1627b0SNicholas Kazlauskas 
413a1627b0SNicholas Kazlauskas struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub)
423a1627b0SNicholas Kazlauskas {
433a1627b0SNicholas Kazlauskas 	struct dc_dmub_srv *dc_srv =
443a1627b0SNicholas Kazlauskas 		kzalloc(sizeof(struct dc_dmub_srv), GFP_KERNEL);
453a1627b0SNicholas Kazlauskas 
463a1627b0SNicholas Kazlauskas 	if (dc_srv == NULL) {
473a1627b0SNicholas Kazlauskas 		BREAK_TO_DEBUGGER();
483a1627b0SNicholas Kazlauskas 		return NULL;
493a1627b0SNicholas Kazlauskas 	}
503a1627b0SNicholas Kazlauskas 
513a1627b0SNicholas Kazlauskas 	dc_dmub_srv_construct(dc_srv, dc, dmub);
523a1627b0SNicholas Kazlauskas 
533a1627b0SNicholas Kazlauskas 	return dc_srv;
543a1627b0SNicholas Kazlauskas }
553a1627b0SNicholas Kazlauskas 
563a1627b0SNicholas Kazlauskas void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv)
573a1627b0SNicholas Kazlauskas {
583a1627b0SNicholas Kazlauskas 	if (*dmub_srv) {
593a1627b0SNicholas Kazlauskas 		kfree(*dmub_srv);
603a1627b0SNicholas Kazlauskas 		*dmub_srv = NULL;
613a1627b0SNicholas Kazlauskas 	}
623a1627b0SNicholas Kazlauskas }
633a1627b0SNicholas Kazlauskas 
643a1627b0SNicholas Kazlauskas void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv,
650ed3bcc4SNicholas Kazlauskas 			   union dmub_rb_cmd *cmd)
663a1627b0SNicholas Kazlauskas {
673a1627b0SNicholas Kazlauskas 	struct dmub_srv *dmub = dc_dmub_srv->dmub;
683a1627b0SNicholas Kazlauskas 	struct dc_context *dc_ctx = dc_dmub_srv->ctx;
693a1627b0SNicholas Kazlauskas 	enum dmub_status status;
703a1627b0SNicholas Kazlauskas 
713a1627b0SNicholas Kazlauskas 	status = dmub_srv_cmd_queue(dmub, cmd);
723a1627b0SNicholas Kazlauskas 	if (status == DMUB_STATUS_OK)
733a1627b0SNicholas Kazlauskas 		return;
743a1627b0SNicholas Kazlauskas 
753a1627b0SNicholas Kazlauskas 	if (status != DMUB_STATUS_QUEUE_FULL)
763a1627b0SNicholas Kazlauskas 		goto error;
773a1627b0SNicholas Kazlauskas 
783a1627b0SNicholas Kazlauskas 	/* Execute and wait for queue to become empty again. */
793a1627b0SNicholas Kazlauskas 	dc_dmub_srv_cmd_execute(dc_dmub_srv);
803a1627b0SNicholas Kazlauskas 	dc_dmub_srv_wait_idle(dc_dmub_srv);
813a1627b0SNicholas Kazlauskas 
823a1627b0SNicholas Kazlauskas 	/* Requeue the command. */
833a1627b0SNicholas Kazlauskas 	status = dmub_srv_cmd_queue(dmub, cmd);
843a1627b0SNicholas Kazlauskas 	if (status == DMUB_STATUS_OK)
853a1627b0SNicholas Kazlauskas 		return;
863a1627b0SNicholas Kazlauskas 
873a1627b0SNicholas Kazlauskas error:
883a1627b0SNicholas Kazlauskas 	DC_ERROR("Error queuing DMUB command: status=%d\n", status);
893a1627b0SNicholas Kazlauskas }
903a1627b0SNicholas Kazlauskas 
913a1627b0SNicholas Kazlauskas void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv)
923a1627b0SNicholas Kazlauskas {
933a1627b0SNicholas Kazlauskas 	struct dmub_srv *dmub = dc_dmub_srv->dmub;
943a1627b0SNicholas Kazlauskas 	struct dc_context *dc_ctx = dc_dmub_srv->ctx;
953a1627b0SNicholas Kazlauskas 	enum dmub_status status;
963a1627b0SNicholas Kazlauskas 
973a1627b0SNicholas Kazlauskas 	status = dmub_srv_cmd_execute(dmub);
983a1627b0SNicholas Kazlauskas 	if (status != DMUB_STATUS_OK)
99243a8f41SColin Ian King 		DC_ERROR("Error starting DMUB execution: status=%d\n", status);
1003a1627b0SNicholas Kazlauskas }
1013a1627b0SNicholas Kazlauskas 
1023a1627b0SNicholas Kazlauskas void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv)
1033a1627b0SNicholas Kazlauskas {
1043a1627b0SNicholas Kazlauskas 	struct dmub_srv *dmub = dc_dmub_srv->dmub;
1053a1627b0SNicholas Kazlauskas 	struct dc_context *dc_ctx = dc_dmub_srv->ctx;
1063a1627b0SNicholas Kazlauskas 	enum dmub_status status;
1073a1627b0SNicholas Kazlauskas 
1083a1627b0SNicholas Kazlauskas 	status = dmub_srv_wait_for_idle(dmub, 100000);
1093a1627b0SNicholas Kazlauskas 	if (status != DMUB_STATUS_OK)
1103a1627b0SNicholas Kazlauskas 		DC_ERROR("Error waiting for DMUB idle: status=%d\n", status);
1113a1627b0SNicholas Kazlauskas }
1123a1627b0SNicholas Kazlauskas 
113*f2973d2aSAlvin Lee void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv,
114*f2973d2aSAlvin Lee 		union dmub_inbox0_data_register data)
115*f2973d2aSAlvin Lee {
116*f2973d2aSAlvin Lee 	struct dmub_srv *dmub = dmub_srv->dmub;
117*f2973d2aSAlvin Lee 	if (dmub->hw_funcs.send_inbox0_cmd)
118*f2973d2aSAlvin Lee 		dmub->hw_funcs.send_inbox0_cmd(dmub, data);
119*f2973d2aSAlvin Lee 	// TODO: Add wait command -- poll register for ACK
120*f2973d2aSAlvin Lee }
121*f2973d2aSAlvin Lee 
122ecdfc5c9SNicholas Kazlauskas bool dc_dmub_srv_cmd_with_reply_data(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd)
123ecdfc5c9SNicholas Kazlauskas {
124ecdfc5c9SNicholas Kazlauskas 	struct dmub_srv *dmub;
125ecdfc5c9SNicholas Kazlauskas 	enum dmub_status status;
126ecdfc5c9SNicholas Kazlauskas 
127ecdfc5c9SNicholas Kazlauskas 	if (!dc_dmub_srv || !dc_dmub_srv->dmub)
128ecdfc5c9SNicholas Kazlauskas 		return false;
129ecdfc5c9SNicholas Kazlauskas 
130ecdfc5c9SNicholas Kazlauskas 	dmub = dc_dmub_srv->dmub;
131ecdfc5c9SNicholas Kazlauskas 
132ecdfc5c9SNicholas Kazlauskas 	status = dmub_srv_cmd_with_reply_data(dmub, cmd);
133ecdfc5c9SNicholas Kazlauskas 	if (status != DMUB_STATUS_OK) {
134ecdfc5c9SNicholas Kazlauskas 		DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status);
135ecdfc5c9SNicholas Kazlauskas 		return false;
136ecdfc5c9SNicholas Kazlauskas 	}
137ecdfc5c9SNicholas Kazlauskas 
138ecdfc5c9SNicholas Kazlauskas 	return true;
139ecdfc5c9SNicholas Kazlauskas }
140ecdfc5c9SNicholas Kazlauskas 
1413a1627b0SNicholas Kazlauskas void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv)
1423a1627b0SNicholas Kazlauskas {
1433a1627b0SNicholas Kazlauskas 	struct dmub_srv *dmub = dc_dmub_srv->dmub;
1443a1627b0SNicholas Kazlauskas 	struct dc_context *dc_ctx = dc_dmub_srv->ctx;
1453a1627b0SNicholas Kazlauskas 	enum dmub_status status;
1463a1627b0SNicholas Kazlauskas 
147a6e4da40SNicholas Kazlauskas 	for (;;) {
148a6e4da40SNicholas Kazlauskas 		/* Wait up to a second for PHY init. */
149a6e4da40SNicholas Kazlauskas 		status = dmub_srv_wait_for_phy_init(dmub, 1000000);
150a6e4da40SNicholas Kazlauskas 		if (status == DMUB_STATUS_OK)
151a6e4da40SNicholas Kazlauskas 			/* Initialization OK */
152a6e4da40SNicholas Kazlauskas 			break;
153a6e4da40SNicholas Kazlauskas 
154a6e4da40SNicholas Kazlauskas 		DC_ERROR("DMCUB PHY init failed: status=%d\n", status);
15556fc13feSNicholas Kazlauskas 		ASSERT(0);
156a6e4da40SNicholas Kazlauskas 
157a6e4da40SNicholas Kazlauskas 		if (status != DMUB_STATUS_TIMEOUT)
158a6e4da40SNicholas Kazlauskas 			/*
159a6e4da40SNicholas Kazlauskas 			 * Server likely initialized or we don't have
160a6e4da40SNicholas Kazlauskas 			 * DMCUB HW support - this won't end.
161a6e4da40SNicholas Kazlauskas 			 */
162a6e4da40SNicholas Kazlauskas 			break;
163a6e4da40SNicholas Kazlauskas 
164a6e4da40SNicholas Kazlauskas 		/* Continue spinning so we don't hang the ASIC. */
16556fc13feSNicholas Kazlauskas 	}
1663a1627b0SNicholas Kazlauskas }
1670825d965SEric Yang 
1680825d965SEric Yang bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv,
1690825d965SEric Yang 				    unsigned int stream_mask)
1700825d965SEric Yang {
1710825d965SEric Yang 	struct dmub_srv *dmub;
1720825d965SEric Yang 	const uint32_t timeout = 30;
1730825d965SEric Yang 
1740825d965SEric Yang 	if (!dc_dmub_srv || !dc_dmub_srv->dmub)
1750825d965SEric Yang 		return false;
1760825d965SEric Yang 
1770825d965SEric Yang 	dmub = dc_dmub_srv->dmub;
1780825d965SEric Yang 
1790825d965SEric Yang 	return dmub_srv_send_gpint_command(
1800825d965SEric Yang 		       dmub, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK,
1810825d965SEric Yang 		       stream_mask, timeout) == DMUB_STATUS_OK;
1820825d965SEric Yang }
18370732504SYongqiang Sun 
1846804287bSYongqiang Sun bool dc_dmub_srv_get_dmub_outbox0_msg(const struct dc *dc, struct dmcub_trace_buf_entry *entry)
18570732504SYongqiang Sun {
18670732504SYongqiang Sun 	struct dmub_srv *dmub = dc->ctx->dmub_srv->dmub;
1876804287bSYongqiang Sun 	return dmub_srv_get_outbox0_msg(dmub, entry);
18870732504SYongqiang Sun }
18970732504SYongqiang Sun 
19070732504SYongqiang Sun void dc_dmub_trace_event_control(struct dc *dc, bool enable)
19170732504SYongqiang Sun {
19281927e28SJude Shih 	dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable);
19370732504SYongqiang Sun }
194