@@ -32,10 +32,16 @@
#define CPUID_WR_DATA_LEN 0x8
#define CPUID_RD_REG_LEN 0xa
#define CPUID_WR_REG_LEN 0x9
+/* MSR */
+#define MSR_RD_REG_LEN 0xa
+#define MSR_WR_REG_LEN 0x8
+#define MSR_RD_DATA_LEN 0x8
+#define MSR_WR_DATA_LEN 0x7
/* CPUID MSR Command Ids */
#define CPUID_MCA_CMD 0x73
#define RD_CPUID_CMD 0x91
+#define RD_MCA_CMD 0x86
/* input for bulk write to CPUID protocol */
struct cpu_msr_indata {
@@ -72,6 +78,16 @@ static inline void prepare_cpuid_input_message(struct cpu_msr_indata *input,
input->ext = ext_func;
}
+static inline void prepare_mca_msr_input_message(struct cpu_msr_indata *input,
+ u8 thread_id, u32 data_in)
+{
+ input->rd_len = MSR_RD_DATA_LEN;
+ input->wr_len = MSR_WR_DATA_LEN;
+ input->proto_cmd = RD_MCA_CMD;
+ input->thread = thread_id << 1;
+ input->value = data_in;
+}
+
static int sbrmi_get_rev(struct sbrmi_data *data)
{
struct apml_message msg = { 0 };
@@ -169,6 +185,86 @@ static int rmi_cpuid_read(struct sbrmi_data *data,
return ret;
}
+/* MCA MSR protocol */
+static int rmi_mca_msr_read(struct sbrmi_data *data,
+ struct apml_message *msg)
+{
+ struct cpu_msr_outdata output = {0};
+ struct cpu_msr_indata input = {0};
+ int ret, val = 0;
+ int hw_status;
+ u16 thread;
+
+ mutex_lock(&data->lock);
+ /* cache the rev value to identify if protocol is supported or not */
+ if (!data->rev) {
+ ret = sbrmi_get_rev(data);
+ if (ret < 0)
+ goto exit_unlock;
+ }
+ /* MCA MSR protocol for REV 0x10 is not supported*/
+ if (data->rev == 0x10) {
+ ret = -EOPNOTSUPP;
+ goto exit_unlock;
+ }
+
+ thread = msg->data_in.reg_in[AMD_SBI_THREAD_LOW_INDEX] |
+ msg->data_in.reg_in[AMD_SBI_THREAD_HI_INDEX] << 8;
+
+ /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */
+ if (thread > 127) {
+ thread -= 128;
+ val = 1;
+ }
+ ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val);
+ if (ret < 0)
+ goto exit_unlock;
+
+ prepare_mca_msr_input_message(&input, thread,
+ msg->data_in.mb_in[AMD_SBI_RD_WR_DATA_INDEX]);
+
+ ret = regmap_bulk_write(data->regmap, CPUID_MCA_CMD,
+ &input, MSR_WR_REG_LEN);
+ if (ret < 0)
+ goto exit_unlock;
+
+ /*
+ * For RMI Rev 0x20, new h/w status bit is introduced. which is used
+ * by firmware to indicate completion of commands (0x71, 0x72, 0x73).
+ * wait for the status bit to be set by the hardware before
+ * reading the data out.
+ */
+ ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status,
+ hw_status & HW_ALERT_MASK, 500, 2000000);
+ if (ret)
+ goto exit_unlock;
+
+ ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD,
+ &output, MSR_RD_REG_LEN);
+ if (ret < 0)
+ goto exit_unlock;
+
+ ret = regmap_write(data->regmap, SBRMI_STATUS,
+ HW_ALERT_MASK);
+ if (ret < 0)
+ goto exit_unlock;
+
+ if (output.num_bytes != MSR_RD_REG_LEN - 1) {
+ ret = -EMSGSIZE;
+ goto exit_unlock;
+ }
+ if (output.status) {
+ ret = -EPROTOTYPE;
+ msg->fw_ret_code = output.status;
+ goto exit_unlock;
+ }
+ msg->data_out.cpu_msr_out = output.value;
+
+exit_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
int rmi_mailbox_xfer(struct sbrmi_data *data,
struct apml_message *msg)
{
@@ -284,6 +380,10 @@ static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
case APML_CPUID:
ret = rmi_cpuid_read(data, &msg);
break;
+ case APML_MCA_MSR:
+ /* MCAMSR protocol */
+ ret = rmi_mca_msr_read(data, &msg);
+ break;
default:
pr_err("Command:0x%x not recognized\n", msg.cmd);
break;
@@ -7,8 +7,11 @@
#include <linux/types.h>
-/* command ID to identify CPUID protocol */
-#define APML_CPUID 0x1000
+enum apml_protocol {
+ APML_CPUID = 0x1000,
+ APML_MCA_MSR,
+};
+
/* These are byte indexes into data_in and data_out arrays */
#define AMD_SBI_RD_WR_DATA_INDEX 0
#define AMD_SBI_REG_OFF_INDEX 0
@@ -24,13 +27,14 @@ struct apml_message {
/* message ids:
* Mailbox Messages: 0x0 ... 0x999
* APML_CPUID: 0x1000
+ * APML_MCA_MSR: 0x1001
*/
__u32 cmd;
/*
* 8 bit data for reg read,
* 32 bit data in case of mailbox,
- * up to 64 bit in case of cpuid
+ * up to 64 bit in case of cpuid and mca msr
*/
union {
__u64 cpu_msr_out;
@@ -40,8 +44,9 @@ struct apml_message {
/*
* [0]...[3] mailbox 32bit input
- * cpuid,
- * [4][5] cpuid: thread
+ * cpuid & mca msr,
+ * [4][5] cpuid & mca msr: thread
+ * [4] rmi reg wr: value
* [6] cpuid: ext function & read eax/ebx or ecx/edx
* [7:0] -> bits [7:4] -> ext function &
* bit [0] read eax/ebx or ecx/edx
@@ -53,7 +58,7 @@ struct apml_message {
__u8 reg_in[8];
} data_in;
/*
- * Status code is returned in case of CPUID access
+ * Status code is returned in case of CPUID/MCA access
* Error code is returned in case of soft mailbox
*/
__u32 fw_ret_code;
@@ -79,6 +84,7 @@ struct apml_message {
* The APML RMI module checks whether the cmd is
* - Mailbox message read/write(0x0~0x999)
* - CPUID read(0x1000)
+ * - MCAMSR read(0x1001)
* - returning "-EFAULT" if none of the above
* "-EPROTOTYPE" error is returned to provide additional error details
*/