mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
misc: amd-sbi: Move protocol functionality to core file
- This is done to utilize the protocol functionality into other domains. - Increase the scalability of the module with different bus(i2c/i3c) 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-3-akshay.gupta@amd.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
e156586764
commit
43470595e7
|
|
@ -1,9 +1,10 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config AMD_SBRMI_I2C
|
||||
tristate "AMD side band RMI support"
|
||||
depends on I2C
|
||||
help
|
||||
Side band RMI over I2C support for AMD out of band management.
|
||||
tristate "AMD side band RMI support"
|
||||
depends on I2C
|
||||
depends on HWMON
|
||||
help
|
||||
Side band RMI over I2C support for AMD out of band management.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called sbrmi-i2c.
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_AMD_SBRMI_I2C) += sbrmi.o
|
||||
sbrmi-i2c-objs := rmi-i2c.o rmi-core.o
|
||||
obj-$(CONFIG_AMD_SBRMI_I2C) += sbrmi-i2c.o
|
||||
|
|
|
|||
113
drivers/misc/amd-sbi/rmi-core.c
Normal file
113
drivers/misc/amd-sbi/rmi-core.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* sbrmi-core.c - file defining SB-RMI protocols compliant
|
||||
* AMD SoC device.
|
||||
*
|
||||
* Copyright (C) 2025 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "rmi-core.h"
|
||||
|
||||
/* Mask for Status Register bit[1] */
|
||||
#define SW_ALERT_MASK 0x2
|
||||
|
||||
/* Software Interrupt for triggering */
|
||||
#define START_CMD 0x80
|
||||
#define TRIGGER_MAILBOX 0x01
|
||||
|
||||
int rmi_mailbox_xfer(struct sbrmi_data *data,
|
||||
struct sbrmi_mailbox_msg *msg)
|
||||
{
|
||||
int i, ret, retry = 10;
|
||||
int sw_status;
|
||||
u8 byte;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
/* Indicate firmware a command is to be serviced */
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
SBRMI_INBNDMSG7, START_CMD);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
|
||||
/* Write the command to SBRMI::InBndMsg_inst0 */
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
SBRMI_INBNDMSG0, msg->cmd);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
|
||||
/*
|
||||
* For both read and write the initiator (BMC) writes
|
||||
* Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1]
|
||||
* SBRMI_x3C(MSB):SBRMI_x39(LSB)
|
||||
*/
|
||||
for (i = 0; i < 4; i++) {
|
||||
byte = (msg->data_in >> i * 8) & 0xff;
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
SBRMI_INBNDMSG1 + i, byte);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to
|
||||
* perform the requested read or write command
|
||||
*/
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
|
||||
/*
|
||||
* Firmware will write SBRMI::Status[SwAlertSts]=1 to generate
|
||||
* an ALERT (if enabled) to initiator (BMC) to indicate completion
|
||||
* of the requested command
|
||||
*/
|
||||
do {
|
||||
sw_status = i2c_smbus_read_byte_data(data->client,
|
||||
SBRMI_STATUS);
|
||||
if (sw_status < 0) {
|
||||
ret = sw_status;
|
||||
goto exit_unlock;
|
||||
}
|
||||
if (sw_status & SW_ALERT_MASK)
|
||||
break;
|
||||
usleep_range(50, 100);
|
||||
} while (retry--);
|
||||
|
||||
if (retry < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"Firmware fail to indicate command completion\n");
|
||||
ret = -EIO;
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a read operation, the initiator (BMC) reads the firmware
|
||||
* response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1]
|
||||
* {SBRMI_x34(MSB):SBRMI_x31(LSB)}.
|
||||
*/
|
||||
if (msg->read) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = i2c_smbus_read_byte_data(data->client,
|
||||
SBRMI_OUTBNDMSG1 + i);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
msg->data_out |= ret << i * 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the
|
||||
* ALERT to initiator
|
||||
*/
|
||||
ret = i2c_smbus_write_byte_data(data->client, SBRMI_STATUS,
|
||||
sw_status | SW_ALERT_MASK);
|
||||
|
||||
exit_unlock:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
63
drivers/misc/amd-sbi/rmi-core.h
Normal file
63
drivers/misc/amd-sbi/rmi-core.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2025 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SBRMI_CORE_H_
|
||||
#define _SBRMI_CORE_H_
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* SB-RMI registers */
|
||||
enum sbrmi_reg {
|
||||
SBRMI_CTRL = 0x01,
|
||||
SBRMI_STATUS,
|
||||
SBRMI_OUTBNDMSG0 = 0x30,
|
||||
SBRMI_OUTBNDMSG1,
|
||||
SBRMI_OUTBNDMSG2,
|
||||
SBRMI_OUTBNDMSG3,
|
||||
SBRMI_OUTBNDMSG4,
|
||||
SBRMI_OUTBNDMSG5,
|
||||
SBRMI_OUTBNDMSG6,
|
||||
SBRMI_OUTBNDMSG7,
|
||||
SBRMI_INBNDMSG0,
|
||||
SBRMI_INBNDMSG1,
|
||||
SBRMI_INBNDMSG2,
|
||||
SBRMI_INBNDMSG3,
|
||||
SBRMI_INBNDMSG4,
|
||||
SBRMI_INBNDMSG5,
|
||||
SBRMI_INBNDMSG6,
|
||||
SBRMI_INBNDMSG7,
|
||||
SBRMI_SW_INTERRUPT,
|
||||
};
|
||||
|
||||
/*
|
||||
* SB-RMI supports soft mailbox service request to MP1 (power management
|
||||
* firmware) through SBRMI inbound/outbound message registers.
|
||||
* SB-RMI message IDs
|
||||
*/
|
||||
enum sbrmi_msg_id {
|
||||
SBRMI_READ_PKG_PWR_CONSUMPTION = 0x1,
|
||||
SBRMI_WRITE_PKG_PWR_LIMIT,
|
||||
SBRMI_READ_PKG_PWR_LIMIT,
|
||||
SBRMI_READ_PKG_MAX_PWR_LIMIT,
|
||||
};
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct sbrmi_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
u32 pwr_limit_max;
|
||||
};
|
||||
|
||||
struct sbrmi_mailbox_msg {
|
||||
u8 cmd;
|
||||
bool read;
|
||||
u32 data_in;
|
||||
u32 data_out;
|
||||
};
|
||||
|
||||
int rmi_mailbox_xfer(struct sbrmi_data *data, struct sbrmi_mailbox_msg *msg);
|
||||
#endif /*_SBRMI_CORE_H_*/
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* sbrmi.c - hwmon driver for a SB-RMI mailbox
|
||||
* compliant AMD SoC device.
|
||||
* rmi-i2c.c - Side band RMI over I2C support for AMD out
|
||||
* of band management
|
||||
*
|
||||
* Copyright (C) 2020-2021 Advanced Micro Devices, Inc.
|
||||
* Copyright (C) 2024 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
|
@ -14,64 +14,10 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include "rmi-core.h"
|
||||
|
||||
/* Do not allow setting negative power limit */
|
||||
#define SBRMI_PWR_MIN 0
|
||||
/* Mask for Status Register bit[1] */
|
||||
#define SW_ALERT_MASK 0x2
|
||||
|
||||
/* Software Interrupt for triggering */
|
||||
#define START_CMD 0x80
|
||||
#define TRIGGER_MAILBOX 0x01
|
||||
|
||||
/*
|
||||
* SB-RMI supports soft mailbox service request to MP1 (power management
|
||||
* firmware) through SBRMI inbound/outbound message registers.
|
||||
* SB-RMI message IDs
|
||||
*/
|
||||
enum sbrmi_msg_id {
|
||||
SBRMI_READ_PKG_PWR_CONSUMPTION = 0x1,
|
||||
SBRMI_WRITE_PKG_PWR_LIMIT,
|
||||
SBRMI_READ_PKG_PWR_LIMIT,
|
||||
SBRMI_READ_PKG_MAX_PWR_LIMIT,
|
||||
};
|
||||
|
||||
/* SB-RMI registers */
|
||||
enum sbrmi_reg {
|
||||
SBRMI_CTRL = 0x01,
|
||||
SBRMI_STATUS,
|
||||
SBRMI_OUTBNDMSG0 = 0x30,
|
||||
SBRMI_OUTBNDMSG1,
|
||||
SBRMI_OUTBNDMSG2,
|
||||
SBRMI_OUTBNDMSG3,
|
||||
SBRMI_OUTBNDMSG4,
|
||||
SBRMI_OUTBNDMSG5,
|
||||
SBRMI_OUTBNDMSG6,
|
||||
SBRMI_OUTBNDMSG7,
|
||||
SBRMI_INBNDMSG0,
|
||||
SBRMI_INBNDMSG1,
|
||||
SBRMI_INBNDMSG2,
|
||||
SBRMI_INBNDMSG3,
|
||||
SBRMI_INBNDMSG4,
|
||||
SBRMI_INBNDMSG5,
|
||||
SBRMI_INBNDMSG6,
|
||||
SBRMI_INBNDMSG7,
|
||||
SBRMI_SW_INTERRUPT,
|
||||
};
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct sbrmi_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
u32 pwr_limit_max;
|
||||
};
|
||||
|
||||
struct sbrmi_mailbox_msg {
|
||||
u8 cmd;
|
||||
bool read;
|
||||
u32 data_in;
|
||||
u32 data_out;
|
||||
};
|
||||
|
||||
static int sbrmi_enable_alert(struct i2c_client *client)
|
||||
{
|
||||
|
|
@ -94,100 +40,6 @@ static int sbrmi_enable_alert(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_mailbox_xfer(struct sbrmi_data *data,
|
||||
struct sbrmi_mailbox_msg *msg)
|
||||
{
|
||||
int i, ret, retry = 10;
|
||||
int sw_status;
|
||||
u8 byte;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
/* Indicate firmware a command is to be serviced */
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
SBRMI_INBNDMSG7, START_CMD);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
|
||||
/* Write the command to SBRMI::InBndMsg_inst0 */
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
SBRMI_INBNDMSG0, msg->cmd);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
|
||||
/*
|
||||
* For both read and write the initiator (BMC) writes
|
||||
* Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1]
|
||||
* SBRMI_x3C(MSB):SBRMI_x39(LSB)
|
||||
*/
|
||||
for (i = 0; i < 4; i++) {
|
||||
byte = (msg->data_in >> i * 8) & 0xff;
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
SBRMI_INBNDMSG1 + i, byte);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to
|
||||
* perform the requested read or write command
|
||||
*/
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
|
||||
/*
|
||||
* Firmware will write SBRMI::Status[SwAlertSts]=1 to generate
|
||||
* an ALERT (if enabled) to initiator (BMC) to indicate completion
|
||||
* of the requested command
|
||||
*/
|
||||
do {
|
||||
sw_status = i2c_smbus_read_byte_data(data->client,
|
||||
SBRMI_STATUS);
|
||||
if (sw_status < 0) {
|
||||
ret = sw_status;
|
||||
goto exit_unlock;
|
||||
}
|
||||
if (sw_status & SW_ALERT_MASK)
|
||||
break;
|
||||
usleep_range(50, 100);
|
||||
} while (retry--);
|
||||
|
||||
if (retry < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"Firmware fail to indicate command completion\n");
|
||||
ret = -EIO;
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a read operation, the initiator (BMC) reads the firmware
|
||||
* response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1]
|
||||
* {SBRMI_x34(MSB):SBRMI_x31(LSB)}.
|
||||
*/
|
||||
if (msg->read) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = i2c_smbus_read_byte_data(data->client,
|
||||
SBRMI_OUTBNDMSG1 + i);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
msg->data_out |= ret << i * 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the
|
||||
* ALERT to initiator
|
||||
*/
|
||||
ret = i2c_smbus_write_byte_data(data->client, SBRMI_STATUS,
|
||||
sw_status | SW_ALERT_MASK);
|
||||
|
||||
exit_unlock:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
|
|
@ -297,7 +149,7 @@ static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int sbrmi_probe(struct i2c_client *client)
|
||||
static int sbrmi_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
|
|
@ -323,12 +175,11 @@ static int sbrmi_probe(struct i2c_client *client)
|
|||
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
|
||||
&sbrmi_chip_info, NULL);
|
||||
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sbrmi_id[] = {
|
||||
{"sbrmi"},
|
||||
{"sbrmi-i2c"},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sbrmi_id);
|
||||
|
|
@ -343,15 +194,16 @@ MODULE_DEVICE_TABLE(of, sbrmi_of_match);
|
|||
|
||||
static struct i2c_driver sbrmi_driver = {
|
||||
.driver = {
|
||||
.name = "sbrmi",
|
||||
.name = "sbrmi-i2c",
|
||||
.of_match_table = of_match_ptr(sbrmi_of_match),
|
||||
},
|
||||
.probe = sbrmi_probe,
|
||||
.probe = sbrmi_i2c_probe,
|
||||
.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");
|
||||
Loading…
Reference in New Issue
Block a user