global: Migrate CONFIG_SYS_FSL* symbols to the CFG_SYS namespace
[platform/kernel/u-boot.git] / arch / arm / mach-apple / rtkit.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
4  * (C) Copyright 2021 Copyright The Asahi Linux Contributors
5  */
6
7 #include <common.h>
8 #include <mailbox.h>
9 #include <malloc.h>
10
11 #include <asm/arch/rtkit.h>
12 #include <linux/apple-mailbox.h>
13 #include <linux/bitfield.h>
14
15 #define APPLE_RTKIT_EP_MGMT 0
16 #define APPLE_RTKIT_EP_CRASHLOG 1
17 #define APPLE_RTKIT_EP_SYSLOG 2
18 #define APPLE_RTKIT_EP_DEBUG 3
19 #define APPLE_RTKIT_EP_IOREPORT 4
20 #define APPLE_RTKIT_EP_TRACEKIT 10
21
22 /* Messages for management endpoint. */
23 #define APPLE_RTKIT_MGMT_TYPE GENMASK(59, 52)
24
25 #define APPLE_RTKIT_MGMT_PWR_STATE GENMASK(15, 0)
26
27 #define APPLE_RTKIT_MGMT_HELLO 1
28 #define APPLE_RTKIT_MGMT_HELLO_REPLY 2
29 #define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK(15, 0)
30 #define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK(31, 16)
31
32 #define APPLE_RTKIT_MGMT_STARTEP 5
33 #define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK(39, 32)
34 #define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT(1)
35
36 #define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE 6
37 #define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK 7
38
39 #define APPLE_RTKIT_MGMT_EPMAP 8
40 #define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51)
41 #define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK(34, 32)
42 #define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK(31, 0)
43
44 #define APPLE_RTKIT_MGMT_EPMAP_REPLY 8
45 #define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0)
46
47 #define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
48 #define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
49
50 /* Messages for internal endpoints. */
51 #define APPLE_RTKIT_BUFFER_REQUEST 1
52 #define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK(51, 44)
53 #define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK(41, 0)
54
55 #define TIMEOUT_1SEC_US 1000000
56
57 struct apple_rtkit {
58         struct mbox_chan *chan;
59         void *cookie;
60         apple_rtkit_shmem_setup shmem_setup;
61         apple_rtkit_shmem_destroy shmem_destroy;
62
63         struct apple_rtkit_buffer syslog_buffer;
64         struct apple_rtkit_buffer crashlog_buffer;
65         struct apple_rtkit_buffer ioreport_buffer;
66 };
67
68 struct apple_rtkit *apple_rtkit_init(struct mbox_chan *chan, void *cookie,
69                                      apple_rtkit_shmem_setup shmem_setup,
70                                      apple_rtkit_shmem_destroy shmem_destroy)
71 {
72         struct apple_rtkit *rtk;
73
74         rtk = calloc(sizeof(*rtk), 1);
75         if (!rtk)
76                 return NULL;
77
78         rtk->chan = chan;
79         rtk->cookie = cookie;
80         rtk->shmem_setup = shmem_setup;
81         rtk->shmem_destroy = shmem_destroy;
82
83         return rtk;
84 }
85
86 void apple_rtkit_free(struct apple_rtkit *rtk)
87 {
88         if (rtk->shmem_destroy) {
89                 if (rtk->syslog_buffer.buffer)
90                         rtk->shmem_destroy(rtk->cookie, &rtk->syslog_buffer);
91                 if (rtk->crashlog_buffer.buffer)
92                         rtk->shmem_destroy(rtk->cookie, &rtk->crashlog_buffer);
93                 if (rtk->ioreport_buffer.buffer)
94                         rtk->shmem_destroy(rtk->cookie, &rtk->ioreport_buffer);
95         }
96         free(rtk);
97 }
98
99 static int rtkit_handle_buf_req(struct apple_rtkit *rtk, int endpoint, struct apple_mbox_msg *msg)
100 {
101         struct apple_rtkit_buffer *buf;
102         size_t num_4kpages;
103         int ret;
104
105         num_4kpages = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg->msg0);
106
107         if (num_4kpages == 0) {
108                 printf("%s: unexpected request for buffer without size\n", __func__);
109                 return -1;
110         }
111
112         switch (endpoint) {
113         case APPLE_RTKIT_EP_CRASHLOG:
114                 buf = &rtk->crashlog_buffer;
115                 break;
116         case APPLE_RTKIT_EP_SYSLOG:
117                 buf = &rtk->syslog_buffer;
118                 break;
119         case APPLE_RTKIT_EP_IOREPORT:
120                 buf = &rtk->ioreport_buffer;
121                 break;
122         default:
123                 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
124                 return -1;
125         }
126
127         buf->dva = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg->msg0);
128         buf->size = num_4kpages << 12;
129         buf->is_mapped = false;
130
131         if (rtk->shmem_setup) {
132                 ret = rtk->shmem_setup(rtk->cookie, buf);
133                 if (ret < 0) {
134                         printf("%s: shmen_setup failed for endpoint %d\n", __func__,
135                                endpoint);
136                         return ret;
137                 }
138         }
139
140         if (!buf->is_mapped) {
141                 msg->msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) |
142                                 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, num_4kpages) |
143                                 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, buf->dva);
144                 msg->msg1 = endpoint;
145
146                 return mbox_send(rtk->chan, msg);
147         }
148
149         return 0;
150 }
151
152 int apple_rtkit_boot(struct apple_rtkit *rtk)
153 {
154         struct apple_mbox_msg msg;
155         int endpoints[256];
156         int nendpoints = 0;
157         int endpoint;
158         int min_ver, max_ver, want_ver;
159         int msgtype, pwrstate;
160         u64 reply;
161         u32 bitmap, base;
162         int i, ret;
163
164         /* Wakup the IOP. */
165         msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
166                 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
167         msg.msg1 = APPLE_RTKIT_EP_MGMT;
168         ret = mbox_send(rtk->chan, &msg);
169         if (ret < 0)
170                 return ret;
171
172         /* Wait for protocol version negotiation message. */
173         ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
174         if (ret < 0)
175                 return ret;
176
177         endpoint = msg.msg1;
178         msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
179         if (endpoint != APPLE_RTKIT_EP_MGMT) {
180                 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
181                 return -EINVAL;
182         }
183         if (msgtype != APPLE_RTKIT_MGMT_HELLO) {
184                 printf("%s: unexpected message type %d\n", __func__, msgtype);
185                 return -EINVAL;
186         }
187
188         min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg.msg0);
189         max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg.msg0);
190         want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver);
191
192         if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) {
193                 printf("%s: firmware min version %d is too new\n",
194                        __func__, min_ver);
195                 return -ENOTSUPP;
196         }
197
198         if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) {
199                 printf("%s: firmware max version %d is too old\n",
200                        __func__, max_ver);
201                 return -ENOTSUPP;
202         }
203
204         /* Ack version. */
205         msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_HELLO_REPLY) |
206                 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver) |
207                 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
208         msg.msg1 = APPLE_RTKIT_EP_MGMT;
209         ret = mbox_send(rtk->chan, &msg);
210         if (ret < 0)
211                 return ret;
212
213 wait_epmap:
214         /* Wait for endpoint map message. */
215         ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
216         if (ret < 0)
217                 return ret;
218
219         endpoint = msg.msg1;
220         msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
221         if (endpoint != APPLE_RTKIT_EP_MGMT) {
222                 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
223                 return -EINVAL;
224         }
225         if (msgtype != APPLE_RTKIT_MGMT_EPMAP) {
226                 printf("%s: unexpected message type %d\n", __func__, msgtype);
227                 return -EINVAL;
228         }
229
230         bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg.msg0);
231         base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg.msg0);
232         for (i = 0; i < 32; i++) {
233                 if (bitmap & (1U << i))
234                         endpoints[nendpoints++] = base * 32 + i;
235         }
236
237         /* Ack endpoint map. */
238         reply = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_EPMAP_REPLY) |
239                 FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
240         if (msg.msg0 & APPLE_RTKIT_MGMT_EPMAP_LAST)
241                 reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
242         else
243                 reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
244         msg.msg0 = reply;
245         msg.msg1 = APPLE_RTKIT_EP_MGMT;
246         ret = mbox_send(rtk->chan, &msg);
247         if (ret < 0)
248                 return ret;
249
250         if (reply & APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE)
251                 goto wait_epmap;
252
253         for (i = 0; i < nendpoints; i++) {
254                 /* Start only necessary endpoints. The syslog endpoint is
255                  * particularly noisy and its message can't easily be handled
256                  * within U-Boot.
257                  */
258                 switch (endpoints[i]) {
259                 case APPLE_RTKIT_EP_MGMT:
260                 case APPLE_RTKIT_EP_SYSLOG:
261                 case APPLE_RTKIT_EP_DEBUG:
262                 case APPLE_RTKIT_EP_TRACEKIT:
263                         continue;
264                 default:
265                         break;
266                 }
267
268                 /* Request endpoint. */
269                 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_STARTEP) |
270                         FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoints[i]) |
271                         APPLE_RTKIT_MGMT_STARTEP_FLAG;
272                 msg.msg1 = APPLE_RTKIT_EP_MGMT;
273                 ret = mbox_send(rtk->chan, &msg);
274                 if (ret < 0)
275                         return ret;
276         }
277
278         pwrstate = APPLE_RTKIT_PWR_STATE_SLEEP;
279         while (pwrstate != APPLE_RTKIT_PWR_STATE_ON) {
280                 ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
281                 if (ret < 0)
282                         return ret;
283
284                 endpoint = msg.msg1;
285                 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
286
287                 if (endpoint == APPLE_RTKIT_EP_CRASHLOG ||
288                     endpoint == APPLE_RTKIT_EP_SYSLOG ||
289                     endpoint == APPLE_RTKIT_EP_IOREPORT) {
290                         if (msgtype == APPLE_RTKIT_BUFFER_REQUEST) {
291                                 ret = rtkit_handle_buf_req(rtk, endpoint, &msg);
292                                 if (ret < 0)
293                                         return ret;
294                                 continue;
295                         }
296                 }
297
298                 if (endpoint == APPLE_RTKIT_EP_IOREPORT) {
299                         // these two messages have to be ack-ed for proper startup
300                         if (msgtype == 0xc || msgtype == 0x8) {
301                                 ret = mbox_send(rtk->chan, &msg);
302                                 if (ret < 0)
303                                         return ret;
304                                 continue;
305                         }
306                 }
307
308                 if (endpoint != APPLE_RTKIT_EP_MGMT) {
309                         printf("%s: unexpected endpoint %d\n", __func__, endpoint);
310                         return -EINVAL;
311                 }
312                 if (msgtype != APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK) {
313                         printf("%s: unexpected message type %d\n", __func__, msgtype);
314                         return -EINVAL;
315                 }
316
317                 pwrstate = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
318         }
319
320         return 0;
321 }
322
323 int apple_rtkit_shutdown(struct apple_rtkit *rtk, int pwrstate)
324 {
325         struct apple_mbox_msg msg;
326         int ret;
327
328         msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
329                 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
330         msg.msg1 = APPLE_RTKIT_EP_MGMT;
331         ret = mbox_send(rtk->chan, &msg);
332         if (ret < 0)
333                 return ret;
334
335         ret = mbox_recv(rtk->chan, &msg, TIMEOUT_1SEC_US);
336         if (ret < 0)
337                 return ret;
338
339         return 0;
340 }