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