mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

The present sbrmi module only support reporting power via hwmon. However, AMD data center range of processors support various system management functionality using custom protocols defined in Advanced Platform Management Link (APML) specification. Register a miscdevice, which creates a device /dev/sbrmiX with an IOCTL interface for the user space to invoke the APML Mailbox protocol, which is already defined in sbrmi_mailbox_xfer(). The APML protocols depend on a set of RMI registers. Having an IOCTL as a single entry point will help in providing synchronization among these protocols as multiple transactions on RMI register set may create race condition. Support for other protocols will be added in subsequent patches. APML mailbox protocol returns additional error codes written by SMU firmware in the out-bound register 0x37. These errors include, invalid core, message not supported over platform and others. This additional error codes can be used to provide more details to user space. Open-sourced and widely used https://github.com/amd/esmi_oob_library will continue to provide user-space programmable API. Reviewed-by: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com> Signed-off-by: Akshay Gupta <akshay.gupta@amd.com> Link: https://lore.kernel.org/r/20250428063034.2145566-7-akshay.gupta@amd.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
133 lines
2.9 KiB
C
133 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* rmi-i2c.c - Side band RMI over I2C support for AMD out
|
|
* of band management
|
|
*
|
|
* Copyright (C) 2024 Advanced Micro Devices, Inc.
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/err.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/of.h>
|
|
#include <linux/regmap.h>
|
|
#include "rmi-core.h"
|
|
|
|
static int sbrmi_enable_alert(struct sbrmi_data *data)
|
|
{
|
|
int ctrl, ret;
|
|
|
|
/*
|
|
* Enable the SB-RMI Software alert status
|
|
* by writing 0 to bit 4 of Control register(0x1)
|
|
*/
|
|
ret = regmap_read(data->regmap, SBRMI_CTRL, &ctrl);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (ctrl & 0x10) {
|
|
ctrl &= ~0x10;
|
|
return regmap_write(data->regmap, SBRMI_CTRL, ctrl);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data)
|
|
{
|
|
struct apml_mbox_msg msg = { 0 };
|
|
int ret;
|
|
|
|
msg.cmd = SBRMI_READ_PKG_MAX_PWR_LIMIT;
|
|
ret = rmi_mailbox_xfer(data, &msg);
|
|
if (ret < 0)
|
|
return ret;
|
|
data->pwr_limit_max = msg.mb_in_out;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int sbrmi_i2c_probe(struct i2c_client *client)
|
|
{
|
|
struct device *dev = &client->dev;
|
|
struct sbrmi_data *data;
|
|
struct regmap_config sbrmi_i2c_regmap_config = {
|
|
.reg_bits = 8,
|
|
.val_bits = 8,
|
|
};
|
|
int ret;
|
|
|
|
data = devm_kzalloc(dev, sizeof(struct sbrmi_data), GFP_KERNEL);
|
|
if (!data)
|
|
return -ENOMEM;
|
|
|
|
mutex_init(&data->lock);
|
|
|
|
data->regmap = devm_regmap_init_i2c(client, &sbrmi_i2c_regmap_config);
|
|
if (IS_ERR(data->regmap))
|
|
return PTR_ERR(data->regmap);
|
|
|
|
/* Enable alert for SB-RMI sequence */
|
|
ret = sbrmi_enable_alert(data);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/* Cache maximum power limit */
|
|
ret = sbrmi_get_max_pwr_limit(data);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
data->dev_static_addr = client->addr;
|
|
dev_set_drvdata(dev, data);
|
|
|
|
ret = create_hwmon_sensor_device(dev, data);
|
|
if (ret < 0)
|
|
return ret;
|
|
return create_misc_rmi_device(data, dev);
|
|
}
|
|
|
|
static void sbrmi_i2c_remove(struct i2c_client *client)
|
|
{
|
|
struct sbrmi_data *data = dev_get_drvdata(&client->dev);
|
|
|
|
misc_deregister(&data->sbrmi_misc_dev);
|
|
/* Assign fops and parent of misc dev to NULL */
|
|
data->sbrmi_misc_dev.fops = NULL;
|
|
data->sbrmi_misc_dev.parent = NULL;
|
|
dev_info(&client->dev, "Removed sbrmi-i2c driver\n");
|
|
return;
|
|
}
|
|
|
|
static const struct i2c_device_id sbrmi_id[] = {
|
|
{"sbrmi-i2c"},
|
|
{}
|
|
};
|
|
MODULE_DEVICE_TABLE(i2c, sbrmi_id);
|
|
|
|
static const struct of_device_id __maybe_unused sbrmi_of_match[] = {
|
|
{
|
|
.compatible = "amd,sbrmi",
|
|
},
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(of, sbrmi_of_match);
|
|
|
|
static struct i2c_driver sbrmi_driver = {
|
|
.driver = {
|
|
.name = "sbrmi-i2c",
|
|
.of_match_table = of_match_ptr(sbrmi_of_match),
|
|
},
|
|
.probe = sbrmi_i2c_probe,
|
|
.remove = sbrmi_i2c_remove,
|
|
.id_table = sbrmi_id,
|
|
};
|
|
|
|
module_i2c_driver(sbrmi_driver);
|
|
|
|
MODULE_AUTHOR("Akshay Gupta <akshay.gupta@amd.com>");
|
|
MODULE_AUTHOR("Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>");
|
|
MODULE_DESCRIPTION("Hwmon driver for AMD SB-RMI emulated sensor");
|
|
MODULE_LICENSE("GPL");
|