1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2025 Ventana Micro Systems Inc. */
#ifndef _LINUX_RISCV_RPMI_MESSAGE_H_
#define _LINUX_RISCV_RPMI_MESSAGE_H_
#include <linux/errno.h>
#include <linux/mailbox_client.h>
#include <linux/types.h>
#include <linux/wordpart.h>
/* RPMI version encode/decode macros */
#define RPMI_VER_MAJOR(__ver) upper_16_bits(__ver)
#define RPMI_VER_MINOR(__ver) lower_16_bits(__ver)
#define RPMI_MKVER(__maj, __min) (((u32)(__maj) << 16) | (u16)(__min))
/* RPMI message header */
struct rpmi_message_header {
__le16 servicegroup_id;
u8 service_id;
u8 flags;
__le16 datalen;
__le16 token;
};
/* RPMI message */
struct rpmi_message {
struct rpmi_message_header header;
u8 data[];
};
/* RPMI notification event */
struct rpmi_notification_event {
__le16 event_datalen;
u8 event_id;
u8 reserved;
u8 event_data[];
};
/* RPMI error codes */
enum rpmi_error_codes {
RPMI_SUCCESS = 0,
RPMI_ERR_FAILED = -1,
RPMI_ERR_NOTSUPP = -2,
RPMI_ERR_INVALID_PARAM = -3,
RPMI_ERR_DENIED = -4,
RPMI_ERR_INVALID_ADDR = -5,
RPMI_ERR_ALREADY = -6,
RPMI_ERR_EXTENSION = -7,
RPMI_ERR_HW_FAULT = -8,
RPMI_ERR_BUSY = -9,
RPMI_ERR_INVALID_STATE = -10,
RPMI_ERR_BAD_RANGE = -11,
RPMI_ERR_TIMEOUT = -12,
RPMI_ERR_IO = -13,
RPMI_ERR_NO_DATA = -14,
RPMI_ERR_RESERVED_START = -15,
RPMI_ERR_RESERVED_END = -127,
RPMI_ERR_VENDOR_START = -128,
};
static inline int rpmi_to_linux_error(int rpmi_error)
{
switch (rpmi_error) {
case RPMI_SUCCESS:
return 0;
case RPMI_ERR_INVALID_PARAM:
case RPMI_ERR_BAD_RANGE:
case RPMI_ERR_INVALID_STATE:
return -EINVAL;
case RPMI_ERR_DENIED:
return -EPERM;
case RPMI_ERR_INVALID_ADDR:
case RPMI_ERR_HW_FAULT:
return -EFAULT;
case RPMI_ERR_ALREADY:
return -EALREADY;
case RPMI_ERR_BUSY:
return -EBUSY;
case RPMI_ERR_TIMEOUT:
return -ETIMEDOUT;
case RPMI_ERR_IO:
return -ECOMM;
case RPMI_ERR_FAILED:
case RPMI_ERR_NOTSUPP:
case RPMI_ERR_NO_DATA:
case RPMI_ERR_EXTENSION:
default:
return -EOPNOTSUPP;
}
}
/* RPMI service group IDs */
#define RPMI_SRVGRP_SYSTEM_MSI 0x00002
#define RPMI_SRVGRP_CLOCK 0x00008
/* RPMI clock service IDs */
enum rpmi_clock_service_id {
RPMI_CLK_SRV_ENABLE_NOTIFICATION = 0x01,
RPMI_CLK_SRV_GET_NUM_CLOCKS = 0x02,
RPMI_CLK_SRV_GET_ATTRIBUTES = 0x03,
RPMI_CLK_SRV_GET_SUPPORTED_RATES = 0x04,
RPMI_CLK_SRV_SET_CONFIG = 0x05,
RPMI_CLK_SRV_GET_CONFIG = 0x06,
RPMI_CLK_SRV_SET_RATE = 0x07,
RPMI_CLK_SRV_GET_RATE = 0x08,
RPMI_CLK_SRV_ID_MAX_COUNT
};
/* RPMI system MSI service IDs */
enum rpmi_sysmsi_service_id {
RPMI_SYSMSI_SRV_ENABLE_NOTIFICATION = 0x01,
RPMI_SYSMSI_SRV_GET_ATTRIBUTES = 0x02,
RPMI_SYSMSI_SRV_GET_MSI_ATTRIBUTES = 0x03,
RPMI_SYSMSI_SRV_SET_MSI_STATE = 0x04,
RPMI_SYSMSI_SRV_GET_MSI_STATE = 0x05,
RPMI_SYSMSI_SRV_SET_MSI_TARGET = 0x06,
RPMI_SYSMSI_SRV_GET_MSI_TARGET = 0x07,
RPMI_SYSMSI_SRV_ID_MAX_COUNT
};
/* RPMI Linux mailbox attribute IDs */
enum rpmi_mbox_attribute_id {
RPMI_MBOX_ATTR_SPEC_VERSION,
RPMI_MBOX_ATTR_MAX_MSG_DATA_SIZE,
RPMI_MBOX_ATTR_SERVICEGROUP_ID,
RPMI_MBOX_ATTR_SERVICEGROUP_VERSION,
RPMI_MBOX_ATTR_IMPL_ID,
RPMI_MBOX_ATTR_IMPL_VERSION,
RPMI_MBOX_ATTR_MAX_ID
};
/* RPMI Linux mailbox message types */
enum rpmi_mbox_message_type {
RPMI_MBOX_MSG_TYPE_GET_ATTRIBUTE,
RPMI_MBOX_MSG_TYPE_SET_ATTRIBUTE,
RPMI_MBOX_MSG_TYPE_SEND_WITH_RESPONSE,
RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE,
RPMI_MBOX_MSG_TYPE_NOTIFICATION_EVENT,
RPMI_MBOX_MSG_MAX_TYPE
};
/* RPMI Linux mailbox message instance */
struct rpmi_mbox_message {
enum rpmi_mbox_message_type type;
union {
struct {
enum rpmi_mbox_attribute_id id;
u32 value;
} attr;
struct {
u32 service_id;
void *request;
unsigned long request_len;
void *response;
unsigned long max_response_len;
unsigned long out_response_len;
} data;
struct {
u16 event_datalen;
u8 event_id;
u8 *event_data;
} notif;
};
int error;
};
/* RPMI Linux mailbox message helper routines */
static inline void rpmi_mbox_init_get_attribute(struct rpmi_mbox_message *msg,
enum rpmi_mbox_attribute_id id)
{
msg->type = RPMI_MBOX_MSG_TYPE_GET_ATTRIBUTE;
msg->attr.id = id;
msg->attr.value = 0;
msg->error = 0;
}
static inline void rpmi_mbox_init_set_attribute(struct rpmi_mbox_message *msg,
enum rpmi_mbox_attribute_id id,
u32 value)
{
msg->type = RPMI_MBOX_MSG_TYPE_SET_ATTRIBUTE;
msg->attr.id = id;
msg->attr.value = value;
msg->error = 0;
}
static inline void rpmi_mbox_init_send_with_response(struct rpmi_mbox_message *msg,
u32 service_id,
void *request,
unsigned long request_len,
void *response,
unsigned long max_response_len)
{
msg->type = RPMI_MBOX_MSG_TYPE_SEND_WITH_RESPONSE;
msg->data.service_id = service_id;
msg->data.request = request;
msg->data.request_len = request_len;
msg->data.response = response;
msg->data.max_response_len = max_response_len;
msg->data.out_response_len = 0;
msg->error = 0;
}
static inline void rpmi_mbox_init_send_without_response(struct rpmi_mbox_message *msg,
u32 service_id,
void *request,
unsigned long request_len)
{
msg->type = RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE;
msg->data.service_id = service_id;
msg->data.request = request;
msg->data.request_len = request_len;
msg->data.response = NULL;
msg->data.max_response_len = 0;
msg->data.out_response_len = 0;
msg->error = 0;
}
static inline void *rpmi_mbox_get_msg_response(struct rpmi_mbox_message *msg)
{
return msg ? msg->data.response : NULL;
}
static inline int rpmi_mbox_send_message(struct mbox_chan *chan,
struct rpmi_mbox_message *msg)
{
int ret;
/* Send message for the underlying mailbox channel */
ret = mbox_send_message(chan, msg);
if (ret < 0)
return ret;
/* Explicitly signal txdone for mailbox channel */
ret = msg->error;
mbox_client_txdone(chan, ret);
return ret;
}
#endif /* _LINUX_RISCV_RPMI_MESSAGE_H_ */
|