1717
1818/* Mask for Status Register bit[1] */
1919#define SW_ALERT_MASK 0x2
20+ /* Mask to check H/W Alert status bit */
21+ #define HW_ALERT_MASK 0x80
2022
2123/* Software Interrupt for triggering */
2224#define START_CMD 0x80
2325#define TRIGGER_MAILBOX 0x01
2426
27+ /* Default message lengths as per APML command protocol */
28+ /* CPUID */
29+ #define CPUID_RD_DATA_LEN 0x8
30+ #define CPUID_WR_DATA_LEN 0x8
31+ #define CPUID_RD_REG_LEN 0xa
32+ #define CPUID_WR_REG_LEN 0x9
33+
34+ /* CPUID MSR Command Ids */
35+ #define CPUID_MCA_CMD 0x73
36+ #define RD_CPUID_CMD 0x91
37+
38+ /* CPUID MCAMSR mask & index */
39+ #define CPUID_MCA_THRD_MASK GENMASK(15, 0)
40+ #define CPUID_MCA_THRD_INDEX 32
41+ #define CPUID_MCA_FUNC_MASK GENMASK(31, 0)
42+ #define CPUID_EXT_FUNC_INDEX 56
43+
44+ /* input for bulk write to CPUID protocol */
45+ struct cpu_msr_indata {
46+ u8 wr_len ; /* const value */
47+ u8 rd_len ; /* const value */
48+ u8 proto_cmd ; /* const value */
49+ u8 thread ; /* thread number */
50+ union {
51+ u8 reg_offset [4 ]; /* input value */
52+ u32 value ;
53+ } __packed ;
54+ u8 ext ; /* extended function */
55+ };
56+
57+ /* output for bulk read from CPUID protocol */
58+ struct cpu_msr_outdata {
59+ u8 num_bytes ; /* number of bytes return */
60+ u8 status ; /* Protocol status code */
61+ union {
62+ u64 value ;
63+ u8 reg_data [8 ];
64+ } __packed ;
65+ };
66+
67+ static inline void prepare_cpuid_input_message (struct cpu_msr_indata * input ,
68+ u8 thread_id , u32 func ,
69+ u8 ext_func )
70+ {
71+ input -> rd_len = CPUID_RD_DATA_LEN ;
72+ input -> wr_len = CPUID_WR_DATA_LEN ;
73+ input -> proto_cmd = RD_CPUID_CMD ;
74+ input -> thread = thread_id << 1 ;
75+ input -> value = func ;
76+ input -> ext = ext_func ;
77+ }
78+
79+ static int sbrmi_get_rev (struct sbrmi_data * data )
80+ {
81+ unsigned int rev ;
82+ u16 offset = SBRMI_REV ;
83+ int ret ;
84+
85+ ret = regmap_read (data -> regmap , offset , & rev );
86+ if (ret < 0 )
87+ return ret ;
88+
89+ data -> rev = rev ;
90+ return 0 ;
91+ }
92+
93+ /* Read CPUID function protocol */
94+ static int rmi_cpuid_read (struct sbrmi_data * data ,
95+ struct apml_cpuid_msg * msg )
96+ {
97+ struct cpu_msr_indata input = {0 };
98+ struct cpu_msr_outdata output = {0 };
99+ int val = 0 ;
100+ int ret , hw_status ;
101+ u16 thread ;
102+
103+ mutex_lock (& data -> lock );
104+ /* cache the rev value to identify if protocol is supported or not */
105+ if (!data -> rev ) {
106+ ret = sbrmi_get_rev (data );
107+ if (ret < 0 )
108+ goto exit_unlock ;
109+ }
110+ /* CPUID protocol for REV 0x10 is not supported*/
111+ if (data -> rev == 0x10 ) {
112+ ret = - EOPNOTSUPP ;
113+ goto exit_unlock ;
114+ }
115+
116+ thread = msg -> cpu_in_out << CPUID_MCA_THRD_INDEX & CPUID_MCA_THRD_MASK ;
117+
118+ /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */
119+ if (thread > 127 ) {
120+ thread -= 128 ;
121+ val = 1 ;
122+ }
123+ ret = regmap_write (data -> regmap , SBRMI_THREAD128CS , val );
124+ if (ret < 0 )
125+ goto exit_unlock ;
126+
127+ prepare_cpuid_input_message (& input , thread ,
128+ msg -> cpu_in_out & CPUID_MCA_FUNC_MASK ,
129+ msg -> cpu_in_out >> CPUID_EXT_FUNC_INDEX );
130+
131+ ret = regmap_bulk_write (data -> regmap , CPUID_MCA_CMD ,
132+ & input , CPUID_WR_REG_LEN );
133+ if (ret < 0 )
134+ goto exit_unlock ;
135+
136+ /*
137+ * For RMI Rev 0x20, new h/w status bit is introduced. which is used
138+ * by firmware to indicate completion of commands (0x71, 0x72, 0x73).
139+ * wait for the status bit to be set by the hardware before
140+ * reading the data out.
141+ */
142+ ret = regmap_read_poll_timeout (data -> regmap , SBRMI_STATUS , hw_status ,
143+ hw_status & HW_ALERT_MASK , 500 , 2000000 );
144+ if (ret )
145+ goto exit_unlock ;
146+
147+ ret = regmap_bulk_read (data -> regmap , CPUID_MCA_CMD ,
148+ & output , CPUID_RD_REG_LEN );
149+ if (ret < 0 )
150+ goto exit_unlock ;
151+
152+ ret = regmap_write (data -> regmap , SBRMI_STATUS ,
153+ HW_ALERT_MASK );
154+ if (ret < 0 )
155+ goto exit_unlock ;
156+
157+ if (output .num_bytes != CPUID_RD_REG_LEN - 1 ) {
158+ ret = - EMSGSIZE ;
159+ goto exit_unlock ;
160+ }
161+ if (output .status ) {
162+ ret = - EPROTOTYPE ;
163+ msg -> fw_ret_code = output .status ;
164+ goto exit_unlock ;
165+ }
166+ msg -> cpu_in_out = output .value ;
167+ exit_unlock :
168+ if (ret < 0 )
169+ msg -> cpu_in_out = 0 ;
170+ mutex_unlock (& data -> lock );
171+ return ret ;
172+ }
173+
25174int rmi_mailbox_xfer (struct sbrmi_data * data ,
26175 struct apml_mbox_msg * msg )
27176{
@@ -123,6 +272,23 @@ static int apml_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg __use
123272 return copy_to_user (arg , & msg , sizeof (struct apml_mbox_msg ));
124273}
125274
275+ static int apml_cpuid_xfer (struct sbrmi_data * data , struct apml_cpuid_msg __user * arg )
276+ {
277+ struct apml_cpuid_msg msg = { 0 };
278+ int ret ;
279+
280+ /* Copy the structure from user */
281+ if (copy_from_user (& msg , arg , sizeof (struct apml_cpuid_msg )))
282+ return - EFAULT ;
283+
284+ /* CPUID Protocol */
285+ ret = rmi_cpuid_read (data , & msg );
286+ if (ret && ret != - EPROTOTYPE )
287+ return ret ;
288+
289+ return copy_to_user (arg , & msg , sizeof (struct apml_cpuid_msg ));
290+ }
291+
126292static long sbrmi_ioctl (struct file * fp , unsigned int cmd , unsigned long arg )
127293{
128294 void __user * argp = (void __user * )arg ;
@@ -132,6 +298,8 @@ static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
132298 switch (cmd ) {
133299 case SBRMI_IOCTL_MBOX_CMD :
134300 return apml_mailbox_xfer (data , argp );
301+ case SBRMI_IOCTL_CPUID_CMD :
302+ return apml_cpuid_xfer (data , argp );
135303 default :
136304 return - ENOTTY ;
137305 }
0 commit comments