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

source code of linux/include/linux/mailbox/riscv-rpmi-message.h