| /* Copyright 2021 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "amd_stt.h" |
| #include "chipset.h" |
| #include "common.h" |
| #include "console.h" |
| #include "driver/sb_rmi.h" |
| #include "hooks.h" |
| #include "math_util.h" |
| #include "temp_sensor.h" |
| #include "util.h" |
| |
| /* Debug flag can be toggled with console command: stt debug */ |
| static bool amd_stt_debug; |
| |
| /* Console output macros */ |
| #define CPUTS(outstr) cputs(CC_THERMAL, outstr) |
| #define CPRINTS(format, args...) cprints(CC_THERMAL, format, ##args) |
| |
| static const char *const amd_stt_sensor_name[] = { |
| [AMD_STT_PCB_SENSOR_APU] = "APU", |
| [AMD_STT_PCB_SENSOR_REMOTE] = "Ambient", |
| [AMD_STT_PCB_SENSOR_GPU] = "GPU", |
| }; |
| |
| /** |
| * Write temperature sensor value to AP via SB-RMI |
| * |
| * sensor: |
| * AMD_STT_PCB_SENSOR_APU |
| * AMD_STT_PCB_SENSOR_REMOTE |
| * AMD_STT_PCB_SENSOR_GPU |
| * |
| * temp_mk: |
| * Temperature in degrees milli kelvin |
| */ |
| static int write_stt_sensor_val(enum amd_stt_pcb_sensor sensor, int temp_mk) |
| { |
| uint32_t msgIn = 0; |
| uint32_t msgOut; |
| int temp_mc; |
| int temp_c_fp_msb; |
| int temp_c_fp_lsb; |
| |
| temp_mc = MILLI_KELVIN_TO_MILLI_CELSIUS(temp_mk); |
| |
| if (amd_stt_debug) |
| CPRINTS("STT: %s = %d.%d °C", amd_stt_sensor_name[sensor], |
| temp_mc / 1000, temp_mc % 1000); |
| |
| /* Divide by 1000 to get MSB of fixed point temp */ |
| temp_c_fp_msb = temp_mc / 1000; |
| /* Modulus 1000 and multiply by 256/1000 to get LSB of fixed point*/ |
| temp_c_fp_lsb = ((temp_mc % 1000) << 8) / 1000; |
| |
| /* |
| * [15:0]: temperature as signed integer with 8 fractional bits. |
| * [23:16]: sensor index |
| * [31:24]: unused |
| */ |
| msgIn |= (temp_c_fp_lsb & 0xff); |
| msgIn |= (temp_c_fp_msb & 0xff) << 8; |
| msgIn |= (sensor & 0xff) << 16; |
| return sb_rmi_mailbox_xfer(SB_RMI_WRITE_STT_SENSOR_CMD, msgIn, &msgOut); |
| } |
| |
| static void amd_stt_handler(void) |
| { |
| int rv; |
| int soc_temp_mk; |
| int ambient_temp_mk; |
| |
| /* STT interface is only active in S0 */ |
| if (!chipset_in_state(CHIPSET_STATE_ON)) |
| return; |
| |
| /* |
| * TODO(b/192391025): Replace with temp_sensor_read_mk(TEMP_SENSOR_SOC) |
| */ |
| rv = board_get_soc_temp_mk(&soc_temp_mk); |
| if (rv) { |
| CPRINTS("STT: Failed to read SOC temp rv:%d", rv); |
| return; |
| } |
| |
| rv = write_stt_sensor_val(AMD_STT_PCB_SENSOR_APU, soc_temp_mk); |
| if (rv) { |
| /* Failure reason will be logged by write_stt_sensor_val(), so |
| * no need to log it here too. |
| */ |
| return; |
| } |
| |
| /* |
| * TODO(b/192391025): Replace with |
| * temp_sensor_read_mk(TEMP_SENSOR_AMBIENT) |
| */ |
| rv = board_get_ambient_temp_mk(&ambient_temp_mk); |
| if (rv) { |
| CPRINTS("STT: Failed to read AMBIENT temp rv:%d", rv); |
| return; |
| } |
| |
| rv = write_stt_sensor_val(AMD_STT_PCB_SENSOR_REMOTE, ambient_temp_mk); |
| if (rv) { |
| /* Failure reason will be logged by write_stt_sensor_val(), so |
| * no need to log it here too. |
| */ |
| return; |
| } |
| } |
| DECLARE_HOOK(HOOK_SECOND, amd_stt_handler, HOOK_PRIO_TEMP_SENSOR + 1); |
| |
| static int command_stt(int argc, const char **argv) |
| { |
| int sensor_id; |
| int temp; |
| |
| if (argc < 2) |
| return EC_ERROR_PARAM1; |
| else if (!strcasecmp(argv[1], "debug")) { |
| amd_stt_debug = !amd_stt_debug; |
| return EC_SUCCESS; |
| } else if (argc != 3) |
| return EC_ERROR_PARAM2; |
| else if (!strcasecmp(argv[1], |
| amd_stt_sensor_name[AMD_STT_PCB_SENSOR_APU])) |
| sensor_id = AMD_STT_PCB_SENSOR_APU; |
| else if (!strcasecmp(argv[1], |
| amd_stt_sensor_name[AMD_STT_PCB_SENSOR_REMOTE])) |
| sensor_id = AMD_STT_PCB_SENSOR_REMOTE; |
| else if (!strcasecmp(argv[1], |
| amd_stt_sensor_name[AMD_STT_PCB_SENSOR_GPU])) |
| sensor_id = AMD_STT_PCB_SENSOR_GPU; |
| else |
| return EC_ERROR_PARAM2; |
| |
| temp = atoi(argv[2]); |
| |
| return write_stt_sensor_val(sensor_id, temp); |
| } |
| DECLARE_CONSOLE_COMMAND(stt, command_stt, |
| "<apu|ambient|gpu|debug> <temp in mK>", |
| "Write an STT mK temperature to AP"); |