Felix Held | 60a4643 | 2020-11-12 00:14:16 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
| 3 | #include <timer.h> |
| 4 | #include <console/console.h> |
Felix Held | e995684 | 2021-03-10 22:55:22 +0100 | [diff] [blame] | 5 | #include <amdblocks/smn.h> |
Felix Held | 60a4643 | 2020-11-12 00:14:16 +0100 | [diff] [blame] | 6 | #include <amdblocks/smu.h> |
Felix Held | 60a4643 | 2020-11-12 00:14:16 +0100 | [diff] [blame] | 7 | #include <soc/smu.h> |
| 8 | #include <types.h> |
| 9 | |
Felix Held | 60a4643 | 2020-11-12 00:14:16 +0100 | [diff] [blame] | 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 */ |
| 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 { |
Felix Held | 03a4bfc | 2021-03-10 23:29:11 +0100 | [diff] [blame] | 23 | result = smn_read32(SMN_SMU_MESG_RESP); |
Felix Held | 60a4643 | 2020-11-12 00:14:16 +0100 | [diff] [blame] | 24 | if (result) { |
| 25 | if (print_command_duration) |
| 26 | printk(BIOS_SPEW, "SMU command consumed %ld usecs\n", |
| 27 | stopwatch_duration_usecs(&sw)); |
| 28 | return result; |
| 29 | } |
| 30 | } while (!stopwatch_expired(&sw)); |
| 31 | |
| 32 | printk(BIOS_ERR, "Error: 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 | */ |
| 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 */ |
Felix Held | 03a4bfc | 2021-03-10 23:29:11 +0100 | [diff] [blame] | 49 | smn_write32(SMN_SMU_MESG_RESP, 0); |
Felix Held | 60a4643 | 2020-11-12 00:14:16 +0100 | [diff] [blame] | 50 | |
| 51 | /* populate arguments */ |
| 52 | for (i = 0 ; i < SMU_NUM_ARGS ; i++) |
Felix Held | 03a4bfc | 2021-03-10 23:29:11 +0100 | [diff] [blame] | 53 | smn_write32(SMN_SMU_MESG_ARG(i), arg->msg[i]); |
Felix Held | 60a4643 | 2020-11-12 00:14:16 +0100 | [diff] [blame] | 54 | |
| 55 | /* send message to SMU */ |
Felix Held | 03a4bfc | 2021-03-10 23:29:11 +0100 | [diff] [blame] | 56 | smn_write32(SMN_SMU_MESG_ID, message_id); |
Felix Held | 60a4643 | 2020-11-12 00:14:16 +0100 | [diff] [blame] | 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++) |
Felix Held | 03a4bfc | 2021-03-10 23:29:11 +0100 | [diff] [blame] | 64 | arg->msg[i] = smn_read32(SMN_SMU_MESG_ARG(i)); |
Felix Held | 60a4643 | 2020-11-12 00:14:16 +0100 | [diff] [blame] | 65 | |
| 66 | return CB_SUCCESS; |
| 67 | } |