1*92c025dbSSuma Hegde // SPDX-License-Identifier: GPL-2.0 2*92c025dbSSuma Hegde /* 3*92c025dbSSuma Hegde * AMD HSMP hwmon support 4*92c025dbSSuma Hegde * Copyright (c) 2025, AMD. 5*92c025dbSSuma Hegde * All Rights Reserved. 6*92c025dbSSuma Hegde * 7*92c025dbSSuma Hegde * This file provides hwmon implementation for HSMP interface. 8*92c025dbSSuma Hegde */ 9*92c025dbSSuma Hegde 10*92c025dbSSuma Hegde #include <asm/amd_hsmp.h> 11*92c025dbSSuma Hegde 12*92c025dbSSuma Hegde #include <linux/device.h> 13*92c025dbSSuma Hegde #include <linux/err.h> 14*92c025dbSSuma Hegde #include <linux/hwmon.h> 15*92c025dbSSuma Hegde #include <linux/types.h> 16*92c025dbSSuma Hegde #include <linux/units.h> 17*92c025dbSSuma Hegde 18*92c025dbSSuma Hegde #include "hsmp.h" 19*92c025dbSSuma Hegde 20*92c025dbSSuma Hegde #define HSMP_HWMON_NAME "amd_hsmp_hwmon" 21*92c025dbSSuma Hegde 22*92c025dbSSuma Hegde static int hsmp_hwmon_write(struct device *dev, enum hwmon_sensor_types type, 23*92c025dbSSuma Hegde u32 attr, int channel, long val) 24*92c025dbSSuma Hegde { 25*92c025dbSSuma Hegde u16 sock_ind = (uintptr_t)dev_get_drvdata(dev); 26*92c025dbSSuma Hegde struct hsmp_message msg = {}; 27*92c025dbSSuma Hegde 28*92c025dbSSuma Hegde if (type != hwmon_power) 29*92c025dbSSuma Hegde return -EOPNOTSUPP; 30*92c025dbSSuma Hegde 31*92c025dbSSuma Hegde if (attr != hwmon_power_cap) 32*92c025dbSSuma Hegde return -EOPNOTSUPP; 33*92c025dbSSuma Hegde 34*92c025dbSSuma Hegde msg.num_args = 1; 35*92c025dbSSuma Hegde msg.args[0] = val / MICROWATT_PER_MILLIWATT; 36*92c025dbSSuma Hegde msg.msg_id = HSMP_SET_SOCKET_POWER_LIMIT; 37*92c025dbSSuma Hegde msg.sock_ind = sock_ind; 38*92c025dbSSuma Hegde return hsmp_send_message(&msg); 39*92c025dbSSuma Hegde } 40*92c025dbSSuma Hegde 41*92c025dbSSuma Hegde static int hsmp_hwmon_read(struct device *dev, 42*92c025dbSSuma Hegde enum hwmon_sensor_types type, 43*92c025dbSSuma Hegde u32 attr, int channel, long *val) 44*92c025dbSSuma Hegde { 45*92c025dbSSuma Hegde u16 sock_ind = (uintptr_t)dev_get_drvdata(dev); 46*92c025dbSSuma Hegde struct hsmp_message msg = {}; 47*92c025dbSSuma Hegde int ret; 48*92c025dbSSuma Hegde 49*92c025dbSSuma Hegde if (type != hwmon_power) 50*92c025dbSSuma Hegde return -EOPNOTSUPP; 51*92c025dbSSuma Hegde 52*92c025dbSSuma Hegde msg.sock_ind = sock_ind; 53*92c025dbSSuma Hegde msg.response_sz = 1; 54*92c025dbSSuma Hegde 55*92c025dbSSuma Hegde switch (attr) { 56*92c025dbSSuma Hegde case hwmon_power_input: 57*92c025dbSSuma Hegde msg.msg_id = HSMP_GET_SOCKET_POWER; 58*92c025dbSSuma Hegde break; 59*92c025dbSSuma Hegde case hwmon_power_cap: 60*92c025dbSSuma Hegde msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT; 61*92c025dbSSuma Hegde break; 62*92c025dbSSuma Hegde case hwmon_power_cap_max: 63*92c025dbSSuma Hegde msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT_MAX; 64*92c025dbSSuma Hegde break; 65*92c025dbSSuma Hegde default: 66*92c025dbSSuma Hegde return -EOPNOTSUPP; 67*92c025dbSSuma Hegde } 68*92c025dbSSuma Hegde 69*92c025dbSSuma Hegde ret = hsmp_send_message(&msg); 70*92c025dbSSuma Hegde if (!ret) 71*92c025dbSSuma Hegde *val = msg.args[0] * MICROWATT_PER_MILLIWATT; 72*92c025dbSSuma Hegde 73*92c025dbSSuma Hegde return ret; 74*92c025dbSSuma Hegde } 75*92c025dbSSuma Hegde 76*92c025dbSSuma Hegde static umode_t hsmp_hwmon_is_visble(const void *data, 77*92c025dbSSuma Hegde enum hwmon_sensor_types type, 78*92c025dbSSuma Hegde u32 attr, int channel) 79*92c025dbSSuma Hegde { 80*92c025dbSSuma Hegde if (type != hwmon_power) 81*92c025dbSSuma Hegde return 0; 82*92c025dbSSuma Hegde 83*92c025dbSSuma Hegde switch (attr) { 84*92c025dbSSuma Hegde case hwmon_power_input: 85*92c025dbSSuma Hegde return 0444; 86*92c025dbSSuma Hegde case hwmon_power_cap: 87*92c025dbSSuma Hegde return 0644; 88*92c025dbSSuma Hegde case hwmon_power_cap_max: 89*92c025dbSSuma Hegde return 0444; 90*92c025dbSSuma Hegde default: 91*92c025dbSSuma Hegde return 0; 92*92c025dbSSuma Hegde } 93*92c025dbSSuma Hegde } 94*92c025dbSSuma Hegde 95*92c025dbSSuma Hegde static const struct hwmon_ops hsmp_hwmon_ops = { 96*92c025dbSSuma Hegde .read = hsmp_hwmon_read, 97*92c025dbSSuma Hegde .is_visible = hsmp_hwmon_is_visble, 98*92c025dbSSuma Hegde .write = hsmp_hwmon_write, 99*92c025dbSSuma Hegde }; 100*92c025dbSSuma Hegde 101*92c025dbSSuma Hegde static const struct hwmon_channel_info * const hsmp_info[] = { 102*92c025dbSSuma Hegde HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX), 103*92c025dbSSuma Hegde NULL 104*92c025dbSSuma Hegde }; 105*92c025dbSSuma Hegde 106*92c025dbSSuma Hegde static const struct hwmon_chip_info hsmp_chip_info = { 107*92c025dbSSuma Hegde .ops = &hsmp_hwmon_ops, 108*92c025dbSSuma Hegde .info = hsmp_info, 109*92c025dbSSuma Hegde }; 110*92c025dbSSuma Hegde 111*92c025dbSSuma Hegde int hsmp_create_sensor(struct device *dev, u16 sock_ind) 112*92c025dbSSuma Hegde { 113*92c025dbSSuma Hegde struct device *hwmon_dev; 114*92c025dbSSuma Hegde 115*92c025dbSSuma Hegde hwmon_dev = devm_hwmon_device_register_with_info(dev, HSMP_HWMON_NAME, 116*92c025dbSSuma Hegde (void *)(uintptr_t)sock_ind, 117*92c025dbSSuma Hegde &hsmp_chip_info, 118*92c025dbSSuma Hegde NULL); 119*92c025dbSSuma Hegde return PTR_ERR_OR_ZERO(hwmon_dev); 120*92c025dbSSuma Hegde } 121*92c025dbSSuma Hegde EXPORT_SYMBOL_NS(hsmp_create_sensor, "AMD_HSMP"); 122