xref: /aosp_15_r20/external/coreboot/src/soc/amd/common/block/smu/smu.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <timer.h>
4 #include <console/console.h>
5 #include <amdblocks/smn.h>
6 #include <amdblocks/smu.h>
7 #include <soc/smu.h>
8 #include <types.h>
9 
10 #define SMU_MESG_RESP_TIMEOUT	0x00
11 #define SMU_MESG_RESP_OK	0x01
12 
13 /* returns SMU_MESG_RESP_OK, SMU_MESG_RESP_TIMEOUT or a negative number */
smu_poll_response(bool print_command_duration)14 static int32_t smu_poll_response(bool print_command_duration)
15 {
16 	struct stopwatch sw;
17 	const long timeout_ms = 10 * MSECS_PER_SEC;
18 	int32_t result;
19 
20 	stopwatch_init_msecs_expire(&sw, timeout_ms);
21 
22 	do {
23 		result = smn_read32(SMN_SMU_MESG_RESP);
24 		if (result) {
25 			if (print_command_duration)
26 				printk(BIOS_SPEW, "SMU command consumed %lld usecs\n",
27 					stopwatch_duration_usecs(&sw));
28 			return result;
29 		}
30 	} while (!stopwatch_expired(&sw));
31 
32 	printk(BIOS_ERR, "timeout sending SMU message\n");
33 	return SMU_MESG_RESP_TIMEOUT;
34 }
35 
36 /*
37  * Send a message and bi-directional payload to the SMU. SMU response, if any, is returned via
38  * *arg.
39  */
send_smu_message(enum smu_message_id message_id,struct smu_payload * arg)40 enum cb_err send_smu_message(enum smu_message_id message_id, struct smu_payload *arg)
41 {
42 	size_t i;
43 
44 	/* wait until SMU can process a new request; don't care if an old request failed */
45 	if (smu_poll_response(false) == SMU_MESG_RESP_TIMEOUT)
46 		return CB_ERR;
47 
48 	/* clear response register */
49 	smn_write32(SMN_SMU_MESG_RESP, 0);
50 
51 	/* populate arguments */
52 	for (i = 0 ; i < SMU_NUM_ARGS ; i++)
53 		smn_write32(SMN_SMU_MESG_ARG(i), arg->msg[i]);
54 
55 	/* send message to SMU */
56 	smn_write32(SMN_SMU_MESG_ID, message_id);
57 
58 	/* wait until SMU has processed the message and check if it was successful */
59 	if (smu_poll_response(true) != SMU_MESG_RESP_OK)
60 		return CB_ERR;
61 
62 	/* copy returned values */
63 	for (i = 0 ; i < SMU_NUM_ARGS ; i++)
64 		arg->msg[i] = smn_read32(SMN_SMU_MESG_ARG(i));
65 
66 	return CB_SUCCESS;
67 }
68