192c025dbSSuma Hegde // SPDX-License-Identifier: GPL-2.0
292c025dbSSuma Hegde /*
392c025dbSSuma Hegde * AMD HSMP hwmon support
492c025dbSSuma Hegde * Copyright (c) 2025, AMD.
592c025dbSSuma Hegde * All Rights Reserved.
692c025dbSSuma Hegde *
792c025dbSSuma Hegde * This file provides hwmon implementation for HSMP interface.
892c025dbSSuma Hegde */
992c025dbSSuma Hegde
10*1193e205SLinus Torvalds #include <asm/amd/hsmp.h>
1192c025dbSSuma Hegde
1292c025dbSSuma Hegde #include <linux/device.h>
1392c025dbSSuma Hegde #include <linux/err.h>
1492c025dbSSuma Hegde #include <linux/hwmon.h>
1592c025dbSSuma Hegde #include <linux/types.h>
1692c025dbSSuma Hegde #include <linux/units.h>
1792c025dbSSuma Hegde
1892c025dbSSuma Hegde #include "hsmp.h"
1992c025dbSSuma Hegde
2092c025dbSSuma Hegde #define HSMP_HWMON_NAME "amd_hsmp_hwmon"
2192c025dbSSuma Hegde
hsmp_hwmon_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)2292c025dbSSuma Hegde static int hsmp_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
2392c025dbSSuma Hegde u32 attr, int channel, long val)
2492c025dbSSuma Hegde {
2592c025dbSSuma Hegde u16 sock_ind = (uintptr_t)dev_get_drvdata(dev);
2692c025dbSSuma Hegde struct hsmp_message msg = {};
2792c025dbSSuma Hegde
2892c025dbSSuma Hegde if (type != hwmon_power)
2992c025dbSSuma Hegde return -EOPNOTSUPP;
3092c025dbSSuma Hegde
3192c025dbSSuma Hegde if (attr != hwmon_power_cap)
3292c025dbSSuma Hegde return -EOPNOTSUPP;
3392c025dbSSuma Hegde
3492c025dbSSuma Hegde msg.num_args = 1;
3592c025dbSSuma Hegde msg.args[0] = val / MICROWATT_PER_MILLIWATT;
3692c025dbSSuma Hegde msg.msg_id = HSMP_SET_SOCKET_POWER_LIMIT;
3792c025dbSSuma Hegde msg.sock_ind = sock_ind;
3892c025dbSSuma Hegde return hsmp_send_message(&msg);
3992c025dbSSuma Hegde }
4092c025dbSSuma Hegde
hsmp_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)4192c025dbSSuma Hegde static int hsmp_hwmon_read(struct device *dev,
4292c025dbSSuma Hegde enum hwmon_sensor_types type,
4392c025dbSSuma Hegde u32 attr, int channel, long *val)
4492c025dbSSuma Hegde {
4592c025dbSSuma Hegde u16 sock_ind = (uintptr_t)dev_get_drvdata(dev);
4692c025dbSSuma Hegde struct hsmp_message msg = {};
4792c025dbSSuma Hegde int ret;
4892c025dbSSuma Hegde
4992c025dbSSuma Hegde if (type != hwmon_power)
5092c025dbSSuma Hegde return -EOPNOTSUPP;
5192c025dbSSuma Hegde
5292c025dbSSuma Hegde msg.sock_ind = sock_ind;
5392c025dbSSuma Hegde msg.response_sz = 1;
5492c025dbSSuma Hegde
5592c025dbSSuma Hegde switch (attr) {
5692c025dbSSuma Hegde case hwmon_power_input:
5792c025dbSSuma Hegde msg.msg_id = HSMP_GET_SOCKET_POWER;
5892c025dbSSuma Hegde break;
5992c025dbSSuma Hegde case hwmon_power_cap:
6092c025dbSSuma Hegde msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT;
6192c025dbSSuma Hegde break;
6292c025dbSSuma Hegde case hwmon_power_cap_max:
6392c025dbSSuma Hegde msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT_MAX;
6492c025dbSSuma Hegde break;
6592c025dbSSuma Hegde default:
6692c025dbSSuma Hegde return -EOPNOTSUPP;
6792c025dbSSuma Hegde }
6892c025dbSSuma Hegde
6992c025dbSSuma Hegde ret = hsmp_send_message(&msg);
7092c025dbSSuma Hegde if (!ret)
7192c025dbSSuma Hegde *val = msg.args[0] * MICROWATT_PER_MILLIWATT;
7292c025dbSSuma Hegde
7392c025dbSSuma Hegde return ret;
7492c025dbSSuma Hegde }
7592c025dbSSuma Hegde
hsmp_hwmon_is_visble(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)7692c025dbSSuma Hegde static umode_t hsmp_hwmon_is_visble(const void *data,
7792c025dbSSuma Hegde enum hwmon_sensor_types type,
7892c025dbSSuma Hegde u32 attr, int channel)
7992c025dbSSuma Hegde {
8092c025dbSSuma Hegde if (type != hwmon_power)
8192c025dbSSuma Hegde return 0;
8292c025dbSSuma Hegde
8392c025dbSSuma Hegde switch (attr) {
8492c025dbSSuma Hegde case hwmon_power_input:
8592c025dbSSuma Hegde return 0444;
8692c025dbSSuma Hegde case hwmon_power_cap:
8792c025dbSSuma Hegde return 0644;
8892c025dbSSuma Hegde case hwmon_power_cap_max:
8992c025dbSSuma Hegde return 0444;
9092c025dbSSuma Hegde default:
9192c025dbSSuma Hegde return 0;
9292c025dbSSuma Hegde }
9392c025dbSSuma Hegde }
9492c025dbSSuma Hegde
9592c025dbSSuma Hegde static const struct hwmon_ops hsmp_hwmon_ops = {
9692c025dbSSuma Hegde .read = hsmp_hwmon_read,
9792c025dbSSuma Hegde .is_visible = hsmp_hwmon_is_visble,
9892c025dbSSuma Hegde .write = hsmp_hwmon_write,
9992c025dbSSuma Hegde };
10092c025dbSSuma Hegde
10192c025dbSSuma Hegde static const struct hwmon_channel_info * const hsmp_info[] = {
10292c025dbSSuma Hegde HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
10392c025dbSSuma Hegde NULL
10492c025dbSSuma Hegde };
10592c025dbSSuma Hegde
10692c025dbSSuma Hegde static const struct hwmon_chip_info hsmp_chip_info = {
10792c025dbSSuma Hegde .ops = &hsmp_hwmon_ops,
10892c025dbSSuma Hegde .info = hsmp_info,
10992c025dbSSuma Hegde };
11092c025dbSSuma Hegde
hsmp_create_sensor(struct device * dev,u16 sock_ind)11192c025dbSSuma Hegde int hsmp_create_sensor(struct device *dev, u16 sock_ind)
11292c025dbSSuma Hegde {
11392c025dbSSuma Hegde struct device *hwmon_dev;
11492c025dbSSuma Hegde
11592c025dbSSuma Hegde hwmon_dev = devm_hwmon_device_register_with_info(dev, HSMP_HWMON_NAME,
11692c025dbSSuma Hegde (void *)(uintptr_t)sock_ind,
11792c025dbSSuma Hegde &hsmp_chip_info,
11892c025dbSSuma Hegde NULL);
11992c025dbSSuma Hegde return PTR_ERR_OR_ZERO(hwmon_dev);
12092c025dbSSuma Hegde }
12192c025dbSSuma Hegde EXPORT_SYMBOL_NS(hsmp_create_sensor, "AMD_HSMP");
122