blob: 2dcb8bdd3e444cc6f9af3e96a0c40b7315a2eb8c [file] [log] [blame]
Mark Kettenis02e25882022-01-22 20:38:14 +01001// 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
21/* Messages for management endpoint. */
22#define APPLE_RTKIT_MGMT_TYPE GENMASK(59, 52)
23
24#define APPLE_RTKIT_MGMT_PWR_STATE GENMASK(15, 0)
25
26#define APPLE_RTKIT_MGMT_HELLO 1
27#define APPLE_RTKIT_MGMT_HELLO_REPLY 2
28#define APPLE_RTKIT_MGMT_HELLO_MINVER GENMASK(15, 0)
29#define APPLE_RTKIT_MGMT_HELLO_MAXVER GENMASK(31, 16)
30
31#define APPLE_RTKIT_MGMT_STARTEP 5
32#define APPLE_RTKIT_MGMT_STARTEP_EP GENMASK(39, 32)
33#define APPLE_RTKIT_MGMT_STARTEP_FLAG BIT(1)
34
35#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE 6
36#define APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK 7
37
38#define APPLE_RTKIT_MGMT_EPMAP 8
39#define APPLE_RTKIT_MGMT_EPMAP_LAST BIT(51)
40#define APPLE_RTKIT_MGMT_EPMAP_BASE GENMASK(34, 32)
41#define APPLE_RTKIT_MGMT_EPMAP_BITMAP GENMASK(31, 0)
42
43#define APPLE_RTKIT_MGMT_EPMAP_REPLY 8
44#define APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE BIT(0)
45
46#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
47#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
48
49/* Messages for internal endpoints. */
50#define APPLE_RTKIT_BUFFER_REQUEST 1
51#define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK(51, 44)
52#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK(41, 0)
53
54int apple_rtkit_init(struct mbox_chan *chan)
55{
56 struct apple_mbox_msg msg;
57 int endpoints[256];
58 int nendpoints = 0;
59 int endpoint;
60 int min_ver, max_ver, want_ver;
61 int msgtype, pwrstate;
62 u64 reply;
63 u32 bitmap, base;
64 int i, ret;
65
66 /* Wakup the IOP. */
67 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
68 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, APPLE_RTKIT_PWR_STATE_ON);
69 msg.msg1 = APPLE_RTKIT_EP_MGMT;
70 ret = mbox_send(chan, &msg);
71 if (ret < 0)
72 return ret;
73
74 /* Wait for protocol version negotiation message. */
75 ret = mbox_recv(chan, &msg, 10000);
76 if (ret < 0)
77 return ret;
78
79 endpoint = msg.msg1;
80 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
81 if (endpoint != APPLE_RTKIT_EP_MGMT) {
82 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
83 return -EINVAL;
84 }
85 if (msgtype != APPLE_RTKIT_MGMT_HELLO) {
86 printf("%s: unexpected message type %d\n", __func__, msgtype);
87 return -EINVAL;
88 }
89
90 min_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MINVER, msg.msg0);
91 max_ver = FIELD_GET(APPLE_RTKIT_MGMT_HELLO_MAXVER, msg.msg0);
92 want_ver = min(APPLE_RTKIT_MAX_SUPPORTED_VERSION, max_ver);
93
94 if (min_ver > APPLE_RTKIT_MAX_SUPPORTED_VERSION) {
95 printf("%s: firmware min version %d is too new\n",
96 __func__, min_ver);
97 return -ENOTSUPP;
98 }
99
100 if (max_ver < APPLE_RTKIT_MIN_SUPPORTED_VERSION) {
101 printf("%s: firmware max version %d is too old\n",
102 __func__, max_ver);
103 return -ENOTSUPP;
104 }
105
106 /* Ack version. */
107 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_HELLO_REPLY) |
108 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MINVER, want_ver) |
109 FIELD_PREP(APPLE_RTKIT_MGMT_HELLO_MAXVER, want_ver);
110 msg.msg1 = APPLE_RTKIT_EP_MGMT;
111 ret = mbox_send(chan, &msg);
112 if (ret < 0)
113 return ret;
114
115wait_epmap:
116 /* Wait for endpoint map message. */
117 ret = mbox_recv(chan, &msg, 10000);
118 if (ret < 0)
119 return ret;
120
121 endpoint = msg.msg1;
122 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
123 if (endpoint != APPLE_RTKIT_EP_MGMT) {
124 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
125 return -EINVAL;
126 }
127 if (msgtype != APPLE_RTKIT_MGMT_EPMAP) {
128 printf("%s: unexpected message type %d\n", __func__, msgtype);
129 return -EINVAL;
130 }
131
132 bitmap = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BITMAP, msg.msg0);
133 base = FIELD_GET(APPLE_RTKIT_MGMT_EPMAP_BASE, msg.msg0);
134 for (i = 0; i < 32; i++) {
135 if (bitmap & (1U << i))
136 endpoints[nendpoints++] = base * 32 + i;
137 }
138
139 /* Ack endpoint map. */
140 reply = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_EPMAP_REPLY) |
141 FIELD_PREP(APPLE_RTKIT_MGMT_EPMAP_BASE, base);
142 if (msg.msg0 & APPLE_RTKIT_MGMT_EPMAP_LAST)
143 reply |= APPLE_RTKIT_MGMT_EPMAP_LAST;
144 else
145 reply |= APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE;
146 msg.msg0 = reply;
147 msg.msg1 = APPLE_RTKIT_EP_MGMT;
148 ret = mbox_send(chan, &msg);
149 if (ret < 0)
150 return ret;
151
152 if (reply & APPLE_RTKIT_MGMT_EPMAP_REPLY_MORE)
153 goto wait_epmap;
154
155 for (i = 0; i < nendpoints; i++) {
156 /* Don't start the syslog endpoint since we can't
157 easily handle its messages in U-Boot. */
158 if (endpoints[i] == APPLE_RTKIT_EP_SYSLOG)
159 continue;
160
161 /* Request endpoint. */
162 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_STARTEP) |
163 FIELD_PREP(APPLE_RTKIT_MGMT_STARTEP_EP, endpoints[i]) |
164 APPLE_RTKIT_MGMT_STARTEP_FLAG;
165 msg.msg1 = APPLE_RTKIT_EP_MGMT;
166 ret = mbox_send(chan, &msg);
167 if (ret < 0)
168 return ret;
169 }
170
171 pwrstate = APPLE_RTKIT_PWR_STATE_SLEEP;
172 while (pwrstate != APPLE_RTKIT_PWR_STATE_ON) {
Hector Martin66899c82022-03-21 22:36:05 +0100173 ret = mbox_recv(chan, &msg, 1000000);
Mark Kettenis02e25882022-01-22 20:38:14 +0100174 if (ret < 0)
175 return ret;
176
177 endpoint = msg.msg1;
178 msgtype = FIELD_GET(APPLE_RTKIT_MGMT_TYPE, msg.msg0);
179
180 if (endpoint == APPLE_RTKIT_EP_CRASHLOG ||
181 endpoint == APPLE_RTKIT_EP_SYSLOG ||
182 endpoint == APPLE_RTKIT_EP_IOREPORT) {
183 u64 addr = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_IOVA, msg.msg0);
184 u64 size = FIELD_GET(APPLE_RTKIT_BUFFER_REQUEST_SIZE, msg.msg0);
185
186 if (msgtype == APPLE_RTKIT_BUFFER_REQUEST && addr != 0)
187 continue;
188
189 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_BUFFER_REQUEST) |
190 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_SIZE, size) |
191 FIELD_PREP(APPLE_RTKIT_BUFFER_REQUEST_IOVA, addr);
192 msg.msg1 = endpoint;
193 ret = mbox_send(chan, &msg);
194 if (ret < 0)
195 return ret;
196 continue;
197 }
198
199 if (endpoint != APPLE_RTKIT_EP_MGMT) {
200 printf("%s: unexpected endpoint %d\n", __func__, endpoint);
201 return -EINVAL;
202 }
203 if (msgtype != APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE_ACK) {
204 printf("%s: unexpected message type %d\n", __func__, msgtype);
205 return -EINVAL;
206 }
207
208 pwrstate = FIELD_GET(APPLE_RTKIT_MGMT_PWR_STATE, msg.msg0);
209 }
210
211 return 0;
212}
213
214int apple_rtkit_shutdown(struct mbox_chan *chan, int pwrstate)
215{
216 struct apple_mbox_msg msg;
217 int ret;
218
219 msg.msg0 = FIELD_PREP(APPLE_RTKIT_MGMT_TYPE, APPLE_RTKIT_MGMT_SET_IOP_PWR_STATE) |
220 FIELD_PREP(APPLE_RTKIT_MGMT_PWR_STATE, pwrstate);
221 msg.msg1 = APPLE_RTKIT_EP_MGMT;
222 ret = mbox_send(chan, &msg);
223 if (ret < 0)
224 return ret;
225
226 ret = mbox_recv(chan, &msg, 100000);
227 if (ret < 0)
228 return ret;
229
230 return 0;
231}