xref: /linux/drivers/misc/amd-sbi/rmi-core.c (revision c26f4fbd58375bd6ef74f95eb73d61762ad97c59)
143470595SAkshay Gupta // SPDX-License-Identifier: GPL-2.0-or-later
243470595SAkshay Gupta /*
343470595SAkshay Gupta  * sbrmi-core.c - file defining SB-RMI protocols compliant
443470595SAkshay Gupta  *		  AMD SoC device.
543470595SAkshay Gupta  *
643470595SAkshay Gupta  * Copyright (C) 2025 Advanced Micro Devices, Inc.
743470595SAkshay Gupta  */
843470595SAkshay Gupta #include <linux/delay.h>
943470595SAkshay Gupta #include <linux/err.h>
1035ac2034SAkshay Gupta #include <linux/fs.h>
1143470595SAkshay Gupta #include <linux/i2c.h>
1235ac2034SAkshay Gupta #include <linux/miscdevice.h>
1335ac2034SAkshay Gupta #include <linux/module.h>
1443470595SAkshay Gupta #include <linux/mutex.h>
15013f7e71SAkshay Gupta #include <linux/regmap.h>
1643470595SAkshay Gupta #include "rmi-core.h"
1743470595SAkshay Gupta 
1843470595SAkshay Gupta /* Mask for Status Register bit[1] */
1943470595SAkshay Gupta #define SW_ALERT_MASK	0x2
20bb13a84eSAkshay Gupta /* Mask to check H/W Alert status bit */
21bb13a84eSAkshay Gupta #define HW_ALERT_MASK	0x80
2243470595SAkshay Gupta 
2343470595SAkshay Gupta /* Software Interrupt for triggering */
2443470595SAkshay Gupta #define START_CMD	0x80
2543470595SAkshay Gupta #define TRIGGER_MAILBOX	0x01
2643470595SAkshay Gupta 
27bb13a84eSAkshay Gupta /* Default message lengths as per APML command protocol */
28bb13a84eSAkshay Gupta /* CPUID */
29bb13a84eSAkshay Gupta #define CPUID_RD_DATA_LEN	0x8
30bb13a84eSAkshay Gupta #define CPUID_WR_DATA_LEN	0x8
31bb13a84eSAkshay Gupta #define CPUID_RD_REG_LEN	0xa
32bb13a84eSAkshay Gupta #define CPUID_WR_REG_LEN	0x9
3369b1ba83SAkshay Gupta /* MSR */
3469b1ba83SAkshay Gupta #define MSR_RD_REG_LEN		0xa
3569b1ba83SAkshay Gupta #define MSR_WR_REG_LEN		0x8
3669b1ba83SAkshay Gupta #define MSR_RD_DATA_LEN		0x8
3769b1ba83SAkshay Gupta #define MSR_WR_DATA_LEN		0x7
38bb13a84eSAkshay Gupta 
39bb13a84eSAkshay Gupta /* CPUID MSR Command Ids */
40bb13a84eSAkshay Gupta #define CPUID_MCA_CMD	0x73
41bb13a84eSAkshay Gupta #define RD_CPUID_CMD	0x91
4269b1ba83SAkshay Gupta #define RD_MCA_CMD	0x86
43bb13a84eSAkshay Gupta 
44bb13a84eSAkshay Gupta /* CPUID MCAMSR mask & index */
45bb13a84eSAkshay Gupta #define CPUID_MCA_THRD_MASK	GENMASK(15, 0)
46bb13a84eSAkshay Gupta #define CPUID_MCA_THRD_INDEX	32
47bb13a84eSAkshay Gupta #define CPUID_MCA_FUNC_MASK	GENMASK(31, 0)
48bb13a84eSAkshay Gupta #define CPUID_EXT_FUNC_INDEX	56
49bb13a84eSAkshay Gupta 
50bb13a84eSAkshay Gupta /* input for bulk write to CPUID protocol */
51bb13a84eSAkshay Gupta struct cpu_msr_indata {
52bb13a84eSAkshay Gupta 	u8 wr_len;	/* const value */
53bb13a84eSAkshay Gupta 	u8 rd_len;	/* const value */
54bb13a84eSAkshay Gupta 	u8 proto_cmd;	/* const value */
55bb13a84eSAkshay Gupta 	u8 thread;	/* thread number */
56bb13a84eSAkshay Gupta 	union {
57bb13a84eSAkshay Gupta 		u8 reg_offset[4];	/* input value */
58bb13a84eSAkshay Gupta 		u32 value;
59bb13a84eSAkshay Gupta 	} __packed;
60bb13a84eSAkshay Gupta 	u8 ext; /* extended function */
61bb13a84eSAkshay Gupta };
62bb13a84eSAkshay Gupta 
63bb13a84eSAkshay Gupta /* output for bulk read from CPUID protocol */
64bb13a84eSAkshay Gupta struct cpu_msr_outdata {
65bb13a84eSAkshay Gupta 	u8 num_bytes;	/* number of bytes return */
66bb13a84eSAkshay Gupta 	u8 status;	/* Protocol status code */
67bb13a84eSAkshay Gupta 	union {
68bb13a84eSAkshay Gupta 		u64 value;
69bb13a84eSAkshay Gupta 		u8 reg_data[8];
70bb13a84eSAkshay Gupta 	} __packed;
71bb13a84eSAkshay Gupta };
72bb13a84eSAkshay Gupta 
prepare_cpuid_input_message(struct cpu_msr_indata * input,u8 thread_id,u32 func,u8 ext_func)73bb13a84eSAkshay Gupta static inline void prepare_cpuid_input_message(struct cpu_msr_indata *input,
74bb13a84eSAkshay Gupta 					       u8 thread_id, u32 func,
75bb13a84eSAkshay Gupta 					       u8 ext_func)
76bb13a84eSAkshay Gupta {
77bb13a84eSAkshay Gupta 	input->rd_len		= CPUID_RD_DATA_LEN;
78bb13a84eSAkshay Gupta 	input->wr_len		= CPUID_WR_DATA_LEN;
79bb13a84eSAkshay Gupta 	input->proto_cmd	= RD_CPUID_CMD;
80bb13a84eSAkshay Gupta 	input->thread		= thread_id << 1;
81bb13a84eSAkshay Gupta 	input->value		= func;
82bb13a84eSAkshay Gupta 	input->ext		= ext_func;
83bb13a84eSAkshay Gupta }
84bb13a84eSAkshay Gupta 
prepare_mca_msr_input_message(struct cpu_msr_indata * input,u8 thread_id,u32 data_in)8569b1ba83SAkshay Gupta static inline void prepare_mca_msr_input_message(struct cpu_msr_indata *input,
8669b1ba83SAkshay Gupta 						 u8 thread_id, u32 data_in)
8769b1ba83SAkshay Gupta {
8869b1ba83SAkshay Gupta 	input->rd_len		= MSR_RD_DATA_LEN;
8969b1ba83SAkshay Gupta 	input->wr_len		= MSR_WR_DATA_LEN;
9069b1ba83SAkshay Gupta 	input->proto_cmd	= RD_MCA_CMD;
9169b1ba83SAkshay Gupta 	input->thread		= thread_id << 1;
9269b1ba83SAkshay Gupta 	input->value		= data_in;
9369b1ba83SAkshay Gupta }
9469b1ba83SAkshay Gupta 
sbrmi_get_rev(struct sbrmi_data * data)95bb13a84eSAkshay Gupta static int sbrmi_get_rev(struct sbrmi_data *data)
96bb13a84eSAkshay Gupta {
97bb13a84eSAkshay Gupta 	unsigned int rev;
98bb13a84eSAkshay Gupta 	u16 offset = SBRMI_REV;
99bb13a84eSAkshay Gupta 	int ret;
100bb13a84eSAkshay Gupta 
101bb13a84eSAkshay Gupta 	ret = regmap_read(data->regmap, offset, &rev);
102bb13a84eSAkshay Gupta 	if (ret < 0)
103bb13a84eSAkshay Gupta 		return ret;
104bb13a84eSAkshay Gupta 
105bb13a84eSAkshay Gupta 	data->rev = rev;
106bb13a84eSAkshay Gupta 	return 0;
107bb13a84eSAkshay Gupta }
108bb13a84eSAkshay Gupta 
109bb13a84eSAkshay Gupta /* Read CPUID function protocol */
rmi_cpuid_read(struct sbrmi_data * data,struct apml_cpuid_msg * msg)110bb13a84eSAkshay Gupta static int rmi_cpuid_read(struct sbrmi_data *data,
111bb13a84eSAkshay Gupta 			  struct apml_cpuid_msg *msg)
112bb13a84eSAkshay Gupta {
113bb13a84eSAkshay Gupta 	struct cpu_msr_indata input = {0};
114bb13a84eSAkshay Gupta 	struct cpu_msr_outdata output = {0};
115bb13a84eSAkshay Gupta 	int val = 0;
116bb13a84eSAkshay Gupta 	int ret, hw_status;
117bb13a84eSAkshay Gupta 	u16 thread;
118bb13a84eSAkshay Gupta 
119bb13a84eSAkshay Gupta 	mutex_lock(&data->lock);
120bb13a84eSAkshay Gupta 	/* cache the rev value to identify if protocol is supported or not */
121bb13a84eSAkshay Gupta 	if (!data->rev) {
122bb13a84eSAkshay Gupta 		ret = sbrmi_get_rev(data);
123bb13a84eSAkshay Gupta 		if (ret < 0)
124bb13a84eSAkshay Gupta 			goto exit_unlock;
125bb13a84eSAkshay Gupta 	}
126bb13a84eSAkshay Gupta 	/* CPUID protocol for REV 0x10 is not supported*/
127bb13a84eSAkshay Gupta 	if (data->rev == 0x10) {
128bb13a84eSAkshay Gupta 		ret = -EOPNOTSUPP;
129bb13a84eSAkshay Gupta 		goto exit_unlock;
130bb13a84eSAkshay Gupta 	}
131bb13a84eSAkshay Gupta 
132bb13a84eSAkshay Gupta 	thread = msg->cpu_in_out << CPUID_MCA_THRD_INDEX & CPUID_MCA_THRD_MASK;
133bb13a84eSAkshay Gupta 
134bb13a84eSAkshay Gupta 	/* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */
135bb13a84eSAkshay Gupta 	if (thread > 127) {
136bb13a84eSAkshay Gupta 		thread -= 128;
137bb13a84eSAkshay Gupta 		val = 1;
138bb13a84eSAkshay Gupta 	}
139bb13a84eSAkshay Gupta 	ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val);
140bb13a84eSAkshay Gupta 	if (ret < 0)
141bb13a84eSAkshay Gupta 		goto exit_unlock;
142bb13a84eSAkshay Gupta 
143bb13a84eSAkshay Gupta 	prepare_cpuid_input_message(&input, thread,
144bb13a84eSAkshay Gupta 				    msg->cpu_in_out & CPUID_MCA_FUNC_MASK,
145bb13a84eSAkshay Gupta 				    msg->cpu_in_out >> CPUID_EXT_FUNC_INDEX);
146bb13a84eSAkshay Gupta 
147bb13a84eSAkshay Gupta 	ret = regmap_bulk_write(data->regmap, CPUID_MCA_CMD,
148bb13a84eSAkshay Gupta 				&input, CPUID_WR_REG_LEN);
149bb13a84eSAkshay Gupta 	if (ret < 0)
150bb13a84eSAkshay Gupta 		goto exit_unlock;
151bb13a84eSAkshay Gupta 
152bb13a84eSAkshay Gupta 	/*
153bb13a84eSAkshay Gupta 	 * For RMI Rev 0x20, new h/w status bit is introduced. which is used
154bb13a84eSAkshay Gupta 	 * by firmware to indicate completion of commands (0x71, 0x72, 0x73).
155bb13a84eSAkshay Gupta 	 * wait for the status bit to be set by the hardware before
156bb13a84eSAkshay Gupta 	 * reading the data out.
157bb13a84eSAkshay Gupta 	 */
158bb13a84eSAkshay Gupta 	ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status,
159bb13a84eSAkshay Gupta 				       hw_status & HW_ALERT_MASK, 500, 2000000);
160bb13a84eSAkshay Gupta 	if (ret)
161bb13a84eSAkshay Gupta 		goto exit_unlock;
162bb13a84eSAkshay Gupta 
163bb13a84eSAkshay Gupta 	ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD,
164bb13a84eSAkshay Gupta 			       &output, CPUID_RD_REG_LEN);
165bb13a84eSAkshay Gupta 	if (ret < 0)
166bb13a84eSAkshay Gupta 		goto exit_unlock;
167bb13a84eSAkshay Gupta 
168bb13a84eSAkshay Gupta 	ret = regmap_write(data->regmap, SBRMI_STATUS,
169bb13a84eSAkshay Gupta 			   HW_ALERT_MASK);
170bb13a84eSAkshay Gupta 	if (ret < 0)
171bb13a84eSAkshay Gupta 		goto exit_unlock;
172bb13a84eSAkshay Gupta 
173bb13a84eSAkshay Gupta 	if (output.num_bytes != CPUID_RD_REG_LEN - 1) {
174bb13a84eSAkshay Gupta 		ret = -EMSGSIZE;
175bb13a84eSAkshay Gupta 		goto exit_unlock;
176bb13a84eSAkshay Gupta 	}
177bb13a84eSAkshay Gupta 	if (output.status) {
178bb13a84eSAkshay Gupta 		ret = -EPROTOTYPE;
179bb13a84eSAkshay Gupta 		msg->fw_ret_code = output.status;
180bb13a84eSAkshay Gupta 		goto exit_unlock;
181bb13a84eSAkshay Gupta 	}
182bb13a84eSAkshay Gupta 	msg->cpu_in_out = output.value;
183bb13a84eSAkshay Gupta exit_unlock:
184bb13a84eSAkshay Gupta 	if (ret < 0)
185bb13a84eSAkshay Gupta 		msg->cpu_in_out = 0;
186bb13a84eSAkshay Gupta 	mutex_unlock(&data->lock);
187bb13a84eSAkshay Gupta 	return ret;
188bb13a84eSAkshay Gupta }
189bb13a84eSAkshay Gupta 
19069b1ba83SAkshay Gupta /* MCA MSR protocol */
rmi_mca_msr_read(struct sbrmi_data * data,struct apml_mcamsr_msg * msg)19169b1ba83SAkshay Gupta static int rmi_mca_msr_read(struct sbrmi_data *data,
19269b1ba83SAkshay Gupta 			    struct apml_mcamsr_msg  *msg)
19369b1ba83SAkshay Gupta {
19469b1ba83SAkshay Gupta 	struct cpu_msr_outdata output = {0};
19569b1ba83SAkshay Gupta 	struct cpu_msr_indata input = {0};
19669b1ba83SAkshay Gupta 	int ret, val = 0;
19769b1ba83SAkshay Gupta 	int hw_status;
19869b1ba83SAkshay Gupta 	u16 thread;
19969b1ba83SAkshay Gupta 
20069b1ba83SAkshay Gupta 	mutex_lock(&data->lock);
20169b1ba83SAkshay Gupta 	/* cache the rev value to identify if protocol is supported or not */
20269b1ba83SAkshay Gupta 	if (!data->rev) {
20369b1ba83SAkshay Gupta 		ret = sbrmi_get_rev(data);
20469b1ba83SAkshay Gupta 		if (ret < 0)
20569b1ba83SAkshay Gupta 			goto exit_unlock;
20669b1ba83SAkshay Gupta 	}
20769b1ba83SAkshay Gupta 	/* MCA MSR protocol for REV 0x10 is not supported*/
20869b1ba83SAkshay Gupta 	if (data->rev == 0x10) {
20969b1ba83SAkshay Gupta 		ret = -EOPNOTSUPP;
21069b1ba83SAkshay Gupta 		goto exit_unlock;
21169b1ba83SAkshay Gupta 	}
21269b1ba83SAkshay Gupta 
21369b1ba83SAkshay Gupta 	thread = msg->mcamsr_in_out << CPUID_MCA_THRD_INDEX & CPUID_MCA_THRD_MASK;
21469b1ba83SAkshay Gupta 
21569b1ba83SAkshay Gupta 	/* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */
21669b1ba83SAkshay Gupta 	if (thread > 127) {
21769b1ba83SAkshay Gupta 		thread -= 128;
21869b1ba83SAkshay Gupta 		val = 1;
21969b1ba83SAkshay Gupta 	}
22069b1ba83SAkshay Gupta 	ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val);
22169b1ba83SAkshay Gupta 	if (ret < 0)
22269b1ba83SAkshay Gupta 		goto exit_unlock;
22369b1ba83SAkshay Gupta 
22469b1ba83SAkshay Gupta 	prepare_mca_msr_input_message(&input, thread,
22569b1ba83SAkshay Gupta 				      msg->mcamsr_in_out & CPUID_MCA_FUNC_MASK);
22669b1ba83SAkshay Gupta 
22769b1ba83SAkshay Gupta 	ret = regmap_bulk_write(data->regmap, CPUID_MCA_CMD,
22869b1ba83SAkshay Gupta 				&input, MSR_WR_REG_LEN);
22969b1ba83SAkshay Gupta 	if (ret < 0)
23069b1ba83SAkshay Gupta 		goto exit_unlock;
23169b1ba83SAkshay Gupta 
23269b1ba83SAkshay Gupta 	/*
23369b1ba83SAkshay Gupta 	 * For RMI Rev 0x20, new h/w status bit is introduced. which is used
23469b1ba83SAkshay Gupta 	 * by firmware to indicate completion of commands (0x71, 0x72, 0x73).
23569b1ba83SAkshay Gupta 	 * wait for the status bit to be set by the hardware before
23669b1ba83SAkshay Gupta 	 * reading the data out.
23769b1ba83SAkshay Gupta 	 */
23869b1ba83SAkshay Gupta 	ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status,
23969b1ba83SAkshay Gupta 				       hw_status & HW_ALERT_MASK, 500, 2000000);
24069b1ba83SAkshay Gupta 	if (ret)
24169b1ba83SAkshay Gupta 		goto exit_unlock;
24269b1ba83SAkshay Gupta 
24369b1ba83SAkshay Gupta 	ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD,
24469b1ba83SAkshay Gupta 			       &output, MSR_RD_REG_LEN);
24569b1ba83SAkshay Gupta 	if (ret < 0)
24669b1ba83SAkshay Gupta 		goto exit_unlock;
24769b1ba83SAkshay Gupta 
24869b1ba83SAkshay Gupta 	ret = regmap_write(data->regmap, SBRMI_STATUS,
24969b1ba83SAkshay Gupta 			   HW_ALERT_MASK);
25069b1ba83SAkshay Gupta 	if (ret < 0)
25169b1ba83SAkshay Gupta 		goto exit_unlock;
25269b1ba83SAkshay Gupta 
25369b1ba83SAkshay Gupta 	if (output.num_bytes != MSR_RD_REG_LEN - 1) {
25469b1ba83SAkshay Gupta 		ret = -EMSGSIZE;
25569b1ba83SAkshay Gupta 		goto exit_unlock;
25669b1ba83SAkshay Gupta 	}
25769b1ba83SAkshay Gupta 	if (output.status) {
25869b1ba83SAkshay Gupta 		ret = -EPROTOTYPE;
25969b1ba83SAkshay Gupta 		msg->fw_ret_code = output.status;
26069b1ba83SAkshay Gupta 		goto exit_unlock;
26169b1ba83SAkshay Gupta 	}
26269b1ba83SAkshay Gupta 	msg->mcamsr_in_out = output.value;
26369b1ba83SAkshay Gupta 
26469b1ba83SAkshay Gupta exit_unlock:
26569b1ba83SAkshay Gupta 	mutex_unlock(&data->lock);
26669b1ba83SAkshay Gupta 	return ret;
26769b1ba83SAkshay Gupta }
26869b1ba83SAkshay Gupta 
rmi_mailbox_xfer(struct sbrmi_data * data,struct apml_mbox_msg * msg)26943470595SAkshay Gupta int rmi_mailbox_xfer(struct sbrmi_data *data,
27035ac2034SAkshay Gupta 		     struct apml_mbox_msg *msg)
27143470595SAkshay Gupta {
27235ac2034SAkshay Gupta 	unsigned int bytes, ec;
273587d2c62SAkshay Gupta 	int i, ret;
27443470595SAkshay Gupta 	int sw_status;
27543470595SAkshay Gupta 	u8 byte;
27643470595SAkshay Gupta 
27743470595SAkshay Gupta 	mutex_lock(&data->lock);
27843470595SAkshay Gupta 
27935ac2034SAkshay Gupta 	msg->fw_ret_code = 0;
28035ac2034SAkshay Gupta 
28143470595SAkshay Gupta 	/* Indicate firmware a command is to be serviced */
282013f7e71SAkshay Gupta 	ret = regmap_write(data->regmap, SBRMI_INBNDMSG7, START_CMD);
28343470595SAkshay Gupta 	if (ret < 0)
28443470595SAkshay Gupta 		goto exit_unlock;
28543470595SAkshay Gupta 
28643470595SAkshay Gupta 	/* Write the command to SBRMI::InBndMsg_inst0 */
287013f7e71SAkshay Gupta 	ret = regmap_write(data->regmap, SBRMI_INBNDMSG0, msg->cmd);
28843470595SAkshay Gupta 	if (ret < 0)
28943470595SAkshay Gupta 		goto exit_unlock;
29043470595SAkshay Gupta 
29143470595SAkshay Gupta 	/*
29243470595SAkshay Gupta 	 * For both read and write the initiator (BMC) writes
29343470595SAkshay Gupta 	 * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1]
29443470595SAkshay Gupta 	 * SBRMI_x3C(MSB):SBRMI_x39(LSB)
29543470595SAkshay Gupta 	 */
29635ac2034SAkshay Gupta 	for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) {
29735ac2034SAkshay Gupta 		byte = (msg->mb_in_out >> i * 8) & 0xff;
298013f7e71SAkshay Gupta 		ret = regmap_write(data->regmap, SBRMI_INBNDMSG1 + i, byte);
29943470595SAkshay Gupta 		if (ret < 0)
30043470595SAkshay Gupta 			goto exit_unlock;
30143470595SAkshay Gupta 	}
30243470595SAkshay Gupta 
30343470595SAkshay Gupta 	/*
30443470595SAkshay Gupta 	 * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to
30543470595SAkshay Gupta 	 * perform the requested read or write command
30643470595SAkshay Gupta 	 */
307013f7e71SAkshay Gupta 	ret = regmap_write(data->regmap, SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX);
30843470595SAkshay Gupta 	if (ret < 0)
30943470595SAkshay Gupta 		goto exit_unlock;
31043470595SAkshay Gupta 
31143470595SAkshay Gupta 	/*
31243470595SAkshay Gupta 	 * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate
31343470595SAkshay Gupta 	 * an ALERT (if enabled) to initiator (BMC) to indicate completion
31443470595SAkshay Gupta 	 * of the requested command
31543470595SAkshay Gupta 	 */
316587d2c62SAkshay Gupta 	ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, sw_status,
317587d2c62SAkshay Gupta 				       sw_status & SW_ALERT_MASK, 500, 2000000);
318587d2c62SAkshay Gupta 	if (ret)
31943470595SAkshay Gupta 		goto exit_unlock;
32043470595SAkshay Gupta 
32135ac2034SAkshay Gupta 	ret = regmap_read(data->regmap, SBRMI_OUTBNDMSG7, &ec);
32235ac2034SAkshay Gupta 	if (ret || ec)
32335ac2034SAkshay Gupta 		goto exit_clear_alert;
32443470595SAkshay Gupta 	/*
32543470595SAkshay Gupta 	 * For a read operation, the initiator (BMC) reads the firmware
32643470595SAkshay Gupta 	 * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1]
32743470595SAkshay Gupta 	 * {SBRMI_x34(MSB):SBRMI_x31(LSB)}.
32843470595SAkshay Gupta 	 */
32935ac2034SAkshay Gupta 	for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) {
330013f7e71SAkshay Gupta 		ret = regmap_read(data->regmap,
331013f7e71SAkshay Gupta 				  SBRMI_OUTBNDMSG1 + i, &bytes);
33243470595SAkshay Gupta 		if (ret < 0)
33335ac2034SAkshay Gupta 			break;
33435ac2034SAkshay Gupta 		msg->mb_in_out |= bytes << i * 8;
33543470595SAkshay Gupta 	}
33643470595SAkshay Gupta 
33735ac2034SAkshay Gupta exit_clear_alert:
33843470595SAkshay Gupta 	/*
33943470595SAkshay Gupta 	 * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the
34043470595SAkshay Gupta 	 * ALERT to initiator
34143470595SAkshay Gupta 	 */
342013f7e71SAkshay Gupta 	ret = regmap_write(data->regmap, SBRMI_STATUS,
34343470595SAkshay Gupta 			   sw_status | SW_ALERT_MASK);
34435ac2034SAkshay Gupta 	if (ec) {
34535ac2034SAkshay Gupta 		ret = -EPROTOTYPE;
34635ac2034SAkshay Gupta 		msg->fw_ret_code = ec;
34735ac2034SAkshay Gupta 	}
34843470595SAkshay Gupta exit_unlock:
34943470595SAkshay Gupta 	mutex_unlock(&data->lock);
35043470595SAkshay Gupta 	return ret;
35143470595SAkshay Gupta }
35235ac2034SAkshay Gupta 
apml_rmi_reg_xfer(struct sbrmi_data * data,struct apml_reg_xfer_msg __user * arg)353*cf141287SAkshay Gupta static int apml_rmi_reg_xfer(struct sbrmi_data *data,
354*cf141287SAkshay Gupta 			     struct apml_reg_xfer_msg __user *arg)
355*cf141287SAkshay Gupta {
356*cf141287SAkshay Gupta 	struct apml_reg_xfer_msg msg = { 0 };
357*cf141287SAkshay Gupta 	unsigned int data_read;
358*cf141287SAkshay Gupta 	int ret;
359*cf141287SAkshay Gupta 
360*cf141287SAkshay Gupta 	/* Copy the structure from user */
361*cf141287SAkshay Gupta 	if (copy_from_user(&msg, arg, sizeof(struct apml_reg_xfer_msg)))
362*cf141287SAkshay Gupta 		return -EFAULT;
363*cf141287SAkshay Gupta 
364*cf141287SAkshay Gupta 	mutex_lock(&data->lock);
365*cf141287SAkshay Gupta 	if (msg.rflag) {
366*cf141287SAkshay Gupta 		ret = regmap_read(data->regmap, msg.reg_addr, &data_read);
367*cf141287SAkshay Gupta 		if (!ret)
368*cf141287SAkshay Gupta 			msg.data_in_out = data_read;
369*cf141287SAkshay Gupta 	} else {
370*cf141287SAkshay Gupta 		ret = regmap_write(data->regmap, msg.reg_addr, msg.data_in_out);
371*cf141287SAkshay Gupta 	}
372*cf141287SAkshay Gupta 
373*cf141287SAkshay Gupta 	mutex_unlock(&data->lock);
374*cf141287SAkshay Gupta 
375*cf141287SAkshay Gupta 	if (msg.rflag && !ret)
376*cf141287SAkshay Gupta 		return copy_to_user(arg, &msg, sizeof(struct apml_reg_xfer_msg));
377*cf141287SAkshay Gupta 	return ret;
378*cf141287SAkshay Gupta }
379*cf141287SAkshay Gupta 
apml_mailbox_xfer(struct sbrmi_data * data,struct apml_mbox_msg __user * arg)38035ac2034SAkshay Gupta static int apml_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg __user *arg)
38135ac2034SAkshay Gupta {
38235ac2034SAkshay Gupta 	struct apml_mbox_msg msg = { 0 };
38335ac2034SAkshay Gupta 	int ret;
38435ac2034SAkshay Gupta 
38535ac2034SAkshay Gupta 	/* Copy the structure from user */
38635ac2034SAkshay Gupta 	if (copy_from_user(&msg, arg, sizeof(struct apml_mbox_msg)))
38735ac2034SAkshay Gupta 		return -EFAULT;
38835ac2034SAkshay Gupta 
38935ac2034SAkshay Gupta 	/* Mailbox protocol */
39035ac2034SAkshay Gupta 	ret = rmi_mailbox_xfer(data, &msg);
39135ac2034SAkshay Gupta 	if (ret && ret != -EPROTOTYPE)
39235ac2034SAkshay Gupta 		return ret;
39335ac2034SAkshay Gupta 
39435ac2034SAkshay Gupta 	return copy_to_user(arg, &msg, sizeof(struct apml_mbox_msg));
39535ac2034SAkshay Gupta }
39635ac2034SAkshay Gupta 
apml_cpuid_xfer(struct sbrmi_data * data,struct apml_cpuid_msg __user * arg)397bb13a84eSAkshay Gupta static int apml_cpuid_xfer(struct sbrmi_data *data, struct apml_cpuid_msg __user *arg)
398bb13a84eSAkshay Gupta {
399bb13a84eSAkshay Gupta 	struct apml_cpuid_msg msg = { 0 };
400bb13a84eSAkshay Gupta 	int ret;
401bb13a84eSAkshay Gupta 
402bb13a84eSAkshay Gupta 	/* Copy the structure from user */
403bb13a84eSAkshay Gupta 	if (copy_from_user(&msg, arg, sizeof(struct apml_cpuid_msg)))
404bb13a84eSAkshay Gupta 		return -EFAULT;
405bb13a84eSAkshay Gupta 
406bb13a84eSAkshay Gupta 	/* CPUID Protocol */
407bb13a84eSAkshay Gupta 	ret = rmi_cpuid_read(data, &msg);
408bb13a84eSAkshay Gupta 	if (ret && ret != -EPROTOTYPE)
409bb13a84eSAkshay Gupta 		return ret;
410bb13a84eSAkshay Gupta 
411bb13a84eSAkshay Gupta 	return copy_to_user(arg, &msg, sizeof(struct apml_cpuid_msg));
412bb13a84eSAkshay Gupta }
413bb13a84eSAkshay Gupta 
apml_mcamsr_xfer(struct sbrmi_data * data,struct apml_mcamsr_msg __user * arg)41469b1ba83SAkshay Gupta static int apml_mcamsr_xfer(struct sbrmi_data *data, struct apml_mcamsr_msg __user *arg)
41569b1ba83SAkshay Gupta {
41669b1ba83SAkshay Gupta 	struct apml_mcamsr_msg msg = { 0 };
41769b1ba83SAkshay Gupta 	int ret;
41869b1ba83SAkshay Gupta 
41969b1ba83SAkshay Gupta 	/* Copy the structure from user */
42069b1ba83SAkshay Gupta 	if (copy_from_user(&msg, arg, sizeof(struct apml_mcamsr_msg)))
42169b1ba83SAkshay Gupta 		return -EFAULT;
42269b1ba83SAkshay Gupta 
42369b1ba83SAkshay Gupta 	/* MCAMSR Protocol */
42469b1ba83SAkshay Gupta 	ret = rmi_mca_msr_read(data, &msg);
42569b1ba83SAkshay Gupta 	if (ret && ret != -EPROTOTYPE)
42669b1ba83SAkshay Gupta 		return ret;
42769b1ba83SAkshay Gupta 
42869b1ba83SAkshay Gupta 	return copy_to_user(arg, &msg, sizeof(struct apml_mcamsr_msg));
42969b1ba83SAkshay Gupta }
43069b1ba83SAkshay Gupta 
sbrmi_ioctl(struct file * fp,unsigned int cmd,unsigned long arg)43135ac2034SAkshay Gupta static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
43235ac2034SAkshay Gupta {
43335ac2034SAkshay Gupta 	void __user *argp = (void __user *)arg;
43435ac2034SAkshay Gupta 	struct sbrmi_data *data;
43535ac2034SAkshay Gupta 
43635ac2034SAkshay Gupta 	data = container_of(fp->private_data, struct sbrmi_data, sbrmi_misc_dev);
43735ac2034SAkshay Gupta 	switch (cmd) {
43835ac2034SAkshay Gupta 	case SBRMI_IOCTL_MBOX_CMD:
43935ac2034SAkshay Gupta 		return apml_mailbox_xfer(data, argp);
440bb13a84eSAkshay Gupta 	case SBRMI_IOCTL_CPUID_CMD:
441bb13a84eSAkshay Gupta 		return apml_cpuid_xfer(data, argp);
44269b1ba83SAkshay Gupta 	case SBRMI_IOCTL_MCAMSR_CMD:
44369b1ba83SAkshay Gupta 		return apml_mcamsr_xfer(data, argp);
444*cf141287SAkshay Gupta 	case SBRMI_IOCTL_REG_XFER_CMD:
445*cf141287SAkshay Gupta 		return apml_rmi_reg_xfer(data, argp);
44635ac2034SAkshay Gupta 	default:
44735ac2034SAkshay Gupta 		return -ENOTTY;
44835ac2034SAkshay Gupta 	}
44935ac2034SAkshay Gupta }
45035ac2034SAkshay Gupta 
45135ac2034SAkshay Gupta static const struct file_operations sbrmi_fops = {
45235ac2034SAkshay Gupta 	.owner		= THIS_MODULE,
45335ac2034SAkshay Gupta 	.unlocked_ioctl	= sbrmi_ioctl,
45435ac2034SAkshay Gupta 	.compat_ioctl	= compat_ptr_ioctl,
45535ac2034SAkshay Gupta };
45635ac2034SAkshay Gupta 
create_misc_rmi_device(struct sbrmi_data * data,struct device * dev)45735ac2034SAkshay Gupta int create_misc_rmi_device(struct sbrmi_data *data,
45835ac2034SAkshay Gupta 			   struct device *dev)
45935ac2034SAkshay Gupta {
46035ac2034SAkshay Gupta 	data->sbrmi_misc_dev.name	= devm_kasprintf(dev,
46135ac2034SAkshay Gupta 							 GFP_KERNEL,
46235ac2034SAkshay Gupta 							 "sbrmi-%x",
46335ac2034SAkshay Gupta 							 data->dev_static_addr);
46435ac2034SAkshay Gupta 	data->sbrmi_misc_dev.minor	= MISC_DYNAMIC_MINOR;
46535ac2034SAkshay Gupta 	data->sbrmi_misc_dev.fops	= &sbrmi_fops;
46635ac2034SAkshay Gupta 	data->sbrmi_misc_dev.parent	= dev;
46735ac2034SAkshay Gupta 	data->sbrmi_misc_dev.nodename	= devm_kasprintf(dev,
46835ac2034SAkshay Gupta 							 GFP_KERNEL,
46935ac2034SAkshay Gupta 							 "sbrmi-%x",
47035ac2034SAkshay Gupta 							 data->dev_static_addr);
47135ac2034SAkshay Gupta 	data->sbrmi_misc_dev.mode	= 0600;
47235ac2034SAkshay Gupta 
47335ac2034SAkshay Gupta 	return misc_register(&data->sbrmi_misc_dev);
47435ac2034SAkshay Gupta }
475