17
17
18
18
/* Mask for Status Register bit[1] */
19
19
#define SW_ALERT_MASK 0x2
20
+ /* Mask to check H/W Alert status bit */
21
+ #define HW_ALERT_MASK 0x80
20
22
21
23
/* Software Interrupt for triggering */
22
24
#define START_CMD 0x80
23
25
#define TRIGGER_MAILBOX 0x01
24
26
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
+
25
174
int rmi_mailbox_xfer (struct sbrmi_data * data ,
26
175
struct apml_mbox_msg * msg )
27
176
{
@@ -123,6 +272,23 @@ static int apml_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg __use
123
272
return copy_to_user (arg , & msg , sizeof (struct apml_mbox_msg ));
124
273
}
125
274
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
+
126
292
static long sbrmi_ioctl (struct file * fp , unsigned int cmd , unsigned long arg )
127
293
{
128
294
void __user * argp = (void __user * )arg ;
@@ -132,6 +298,8 @@ static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
132
298
switch (cmd ) {
133
299
case SBRMI_IOCTL_MBOX_CMD :
134
300
return apml_mailbox_xfer (data , argp );
301
+ case SBRMI_IOCTL_CPUID_CMD :
302
+ return apml_cpuid_xfer (data , argp );
135
303
default :
136
304
return - ENOTTY ;
137
305
}
0 commit comments