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#include "qemu/osdep.h"
31#include "hw/sysbus.h"
32#include "qapi/error.h"
33#include "qemu/log.h"
34
35#include "hw/stream.h"
36#include "qemu/bitops.h"
37#include "qapi/qmp/qerror.h"
38#include "hw/register-dep.h"
39
40#ifndef ZYNQMP_CSU_SSS_ERR_DEBUG
41#define ZYNQMP_CSU_SSS_ERR_DEBUG 0
42#endif
43
44#define TYPE_ZYNQMP_CSU_SSS "zynqmp.csu-sss"
45#define TYPE_ZYNQMP_CSU_SSS_STREAM "zynqmp.csu-sss-stream"
46
47#define ZYNQMP_CSU_SSS(obj) \
48 OBJECT_CHECK(ZynqMPCSUSSS, (obj), TYPE_ZYNQMP_CSU_SSS)
49
50#define ZYNQMP_CSU_SSS_STREAM(obj) \
51 OBJECT_CHECK(ZynqMPCSUSSSStream, (obj), TYPE_ZYNQMP_CSU_SSS_STREAM)
52
53
54typedef enum {
55 DMA,
56 PCAP,
57 AES,
58 SHA,
59 PSTP,
60 ROM,
61 NUM_REMOTES
62} ZynqMPCSUSSSRemote;
63
64#define NO_REMOTE NUM_REMOTES
65
66static const char *zynqmp_csu_sss_remote_names[] = {
67 [PCAP] = "pcap",
68 [DMA] = "dma",
69 [AES] = "aes",
70 [SHA] = "sha",
71 [PSTP] = "pstp",
72 [ROM] = "rom",
73
74};
75
76static const uint32_t zynqmp_csu_sss_population[] = {
77 [PCAP] = (1 << DMA) | (1 << AES) | (1 << PSTP),
78 [DMA] = (1 << DMA) | (1 << AES) | (1 << PCAP) | (1 << PSTP),
79 [AES] = (1 << DMA),
80 [SHA] = (1 << DMA) | (1 << ROM),
81 [PSTP] = (1 << PCAP),
82 [NO_REMOTE] = 0,
83};
84
85#define R_CFG 0
86
87static const int r_cfg_sss_shifts[] = {
88 [PCAP] = 0,
89 [DMA] = 4,
90 [AES] = 8,
91 [SHA] = 12,
92 [PSTP] = 16,
93 [ROM] = -1,
94};
95
96static const uint8_t r_cfg_sss_encodings[] = {
97 [PCAP] = 0x3,
98 [DMA] = 0x5,
99 [AES] = 0xa,
100 [SHA] = 0,
101 [PSTP] = 0xc,
102 [ROM] = 0x0,
103};
104
105#define R_CFG_SSS_LENGTH 4
106#define R_CFG_RSVD 0xFFF00000
107
108#define R_MAX (R_CFG + 1)
109
110typedef struct ZynqMPCSUSSS ZynqMPCSUSSS;
111typedef struct ZynqMPCSUSSSStream ZynqMPCSUSSSStream;
112
113struct ZynqMPCSUSSSStream {
114 DeviceState parent_obj;
115
116 ZynqMPCSUSSS *sss;
117};
118
119struct ZynqMPCSUSSS {
120 SysBusDevice busdev;
121 MemoryRegion iomem;
122 StreamSlave *tx_devs[NUM_REMOTES];
123 ZynqMPCSUSSSStream rx_devs[NUM_REMOTES];
124
125 uint32_t regs[R_MAX];
126 DepRegisterInfo regs_info[R_MAX];
127
128 StreamCanPushNotifyFn notifys[NUM_REMOTES];
129 void *notify_opaques[NUM_REMOTES];
130};
131
132static void zynqmp_csu_sss_notify_all(ZynqMPCSUSSS *s)
133{
134 ZynqMPCSUSSSRemote remote;
135
136 for (remote = 0; remote < NUM_REMOTES; ++remote) {
137 if (s->notifys[remote]) {
138 s->notifys[remote](s->notify_opaques[remote]);
139 s->notifys[remote] = NULL;
140 }
141 }
142}
143
144static void zynqmp_csu_sss_reset(DeviceState *dev)
145{
146 ZynqMPCSUSSS *s = ZYNQMP_CSU_SSS(dev);
147 int i;
148
149 for (i = 0; i < R_MAX; ++i) {
150 dep_register_reset(&s->regs_info[i]);
151 }
152 zynqmp_csu_sss_notify_all(s);
153}
154
155static inline ZynqMPCSUSSSRemote
156zynqmp_csu_sss_lookup_rx_remote(ZynqMPCSUSSS *s, ZynqMPCSUSSSStream *ss)
157{
158 ZynqMPCSUSSSRemote ret;
159
160 for (ret = 0; ret < NUM_REMOTES; ++ret) {
161 if (ss == &s->rx_devs[ret]) {
162 break;
163 }
164 }
165 return ret;
166}
167
168static inline ZynqMPCSUSSSRemote
169zynqmp_csu_sss_lookup_tx_remote(ZynqMPCSUSSS *s,
170 ZynqMPCSUSSSRemote rx_remote)
171{
172 uint32_t enc;
173 if (rx_remote == NO_REMOTE) {
174 return NO_REMOTE;
175 }
176
177 ZynqMPCSUSSSRemote ret;
178
179 for (ret = 0; ret < NUM_REMOTES; ++ret) {
180 if (r_cfg_sss_shifts[ret] == -1) {
181
182 continue;
183 }
184
185 enc = extract32(s->regs[R_CFG], r_cfg_sss_shifts[ret],
186 R_CFG_SSS_LENGTH);
187 if (r_cfg_sss_encodings[rx_remote] == enc) {
188 break;
189 }
190 }
191 return (zynqmp_csu_sss_population[ret] & (1 << rx_remote)) ?
192 ret : NO_REMOTE;
193}
194static bool
195zynqmp_csu_sss_stream_can_push(StreamSlave *obj, StreamCanPushNotifyFn notify,
196 void *notify_opaque)
197{
198 ZynqMPCSUSSSStream *ss = ZYNQMP_CSU_SSS_STREAM(obj);
199 ZynqMPCSUSSS *s = ZYNQMP_CSU_SSS(ss->sss);
200 ZynqMPCSUSSSRemote rx = zynqmp_csu_sss_lookup_rx_remote(s, ss);
201 ZynqMPCSUSSSRemote tx = zynqmp_csu_sss_lookup_tx_remote(s, rx);
202
203 if (tx != NO_REMOTE && s->tx_devs[tx] &&
204 stream_can_push(s->tx_devs[tx], notify, notify_opaque)) {
205 return true;
206 }
207
208 s->notifys[rx] = notify;
209 s->notify_opaques[rx] = notify_opaque;
210 return false;
211}
212
213
214
215static size_t zynqmp_csu_sss_stream_push(StreamSlave *obj, uint8_t *buf,
216 size_t len, uint32_t attr)
217{
218 ZynqMPCSUSSSStream *ss = ZYNQMP_CSU_SSS_STREAM(obj);
219 ZynqMPCSUSSS *s = ZYNQMP_CSU_SSS(ss->sss);
220 ZynqMPCSUSSSRemote rx = zynqmp_csu_sss_lookup_rx_remote(s, ss);
221 ZynqMPCSUSSSRemote tx = zynqmp_csu_sss_lookup_tx_remote(s, rx);
222
223 return (tx != NO_REMOTE) ? stream_push(s->tx_devs[tx], buf, len, attr) : 0;
224}
225
226static void r_cfg_post_write(DepRegisterInfo *reg, uint64_t val) {
227 ZynqMPCSUSSS *s = ZYNQMP_CSU_SSS(reg->opaque);
228
229 zynqmp_csu_sss_notify_all(s);
230}
231
232static const DepRegisterAccessInfo zynqmp_csu_sss_regs_info[] = {
233 [R_CFG] = { .name = "R_CFG", .ro = R_CFG_RSVD, .post_write = r_cfg_post_write },
234};
235
236static const MemoryRegionOps zynqmp_csu_sss_ops = {
237 .read = dep_register_read_memory_le,
238 .write = dep_register_write_memory_le,
239 .endianness = DEVICE_LITTLE_ENDIAN,
240 .valid = {
241 .min_access_size = 4,
242 .max_access_size = 4,
243 }
244};
245
246static void zynqmp_csu_sss_realize(DeviceState *dev, Error **errp)
247{
248 ZynqMPCSUSSS *s = ZYNQMP_CSU_SSS(dev);
249 Error *local_errp = NULL;
250 ZynqMPCSUSSSRemote r;
251 const char *prefix = object_get_canonical_path(OBJECT(dev));
252 int i;
253
254 for (i = 0; i < R_MAX; ++i) {
255 DepRegisterInfo *r = &s->regs_info[i];
256
257 *r = (DepRegisterInfo) {
258 .data = (uint8_t *)&s->regs[i],
259 .data_size = sizeof(uint32_t),
260 .access = &zynqmp_csu_sss_regs_info[i],
261 .debug = ZYNQMP_CSU_SSS_ERR_DEBUG,
262 .prefix = prefix,
263 .opaque = s,
264 };
265 memory_region_init_io(&r->mem, OBJECT(dev), &zynqmp_csu_sss_ops, r,
266 "sss-regs", 4);
267 memory_region_add_subregion(&s->iomem, i * 4, &r->mem);
268 }
269
270 for (r = 0; r < NUM_REMOTES; ++r) {
271 ZynqMPCSUSSSStream *ss = ZYNQMP_CSU_SSS_STREAM(&s->rx_devs[r]);
272
273 object_property_add_link(OBJECT(ss), "sss", TYPE_ZYNQMP_CSU_SSS,
274 (Object **)&ss->sss,
275 qdev_prop_allow_set_link_before_realize,
276 OBJ_PROP_LINK_UNREF_ON_RELEASE,
277 &local_errp);
278 if (local_errp) {
279 goto zynqmp_csu_sss_realize_fail;
280 }
281 object_property_set_link(OBJECT(ss), OBJECT(s), "sss", &local_errp);
282 if (local_errp) {
283 goto zynqmp_csu_sss_realize_fail;
284 }
285 }
286 return;
287
288zynqmp_csu_sss_realize_fail:
289 if (!*errp) {
290 *errp = local_errp;
291 }
292}
293
294static void zynqmp_csu_sss_init(Object *obj)
295{
296 ZynqMPCSUSSS *s = ZYNQMP_CSU_SSS(obj);
297 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
298 ZynqMPCSUSSSRemote r;
299
300 for (r = 0; r < NUM_REMOTES; ++r) {
301 char *name = g_strdup_printf("stream-connected-%s",
302 zynqmp_csu_sss_remote_names[r]);
303 object_property_add_link(obj, name, TYPE_STREAM_SLAVE,
304 (Object **)&s->tx_devs[r],
305 qdev_prop_allow_set_link_before_realize,
306 OBJ_PROP_LINK_UNREF_ON_RELEASE,
307 NULL);
308 g_free(name);
309 name = g_strdup_printf("stream-connected-%s-target",
310 zynqmp_csu_sss_remote_names[r]);
311 object_initialize(&s->rx_devs[r], sizeof(s->rx_devs[r]),
312 TYPE_ZYNQMP_CSU_SSS_STREAM);
313 object_property_add_child(OBJECT(s), name, (Object *)&s->rx_devs[r],
314 &error_abort);
315 g_free(name);
316 }
317
318 memory_region_init_io(&s->iomem, obj, &zynqmp_csu_sss_ops, s,
319 "zynqmp.csu-stream-switch", R_MAX * 4);
320 sysbus_init_mmio(sbd, &s->iomem);
321}
322
323
324
325
326
327static const VMStateDescription vmstate_zynqmp_csu_sss = {
328 .name = "zynqmp_csu_sss",
329 .version_id = 1,
330 .minimum_version_id = 1,
331 .minimum_version_id_old = 1,
332 .fields = (VMStateField[]) {
333 VMSTATE_UINT32_ARRAY(regs, ZynqMPCSUSSS, R_MAX),
334 VMSTATE_END_OF_LIST(),
335 }
336};
337
338static void zynqmp_csu_sss_stream_class_init(ObjectClass *klass, void *data)
339{
340 StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
341
342 ssc->push = zynqmp_csu_sss_stream_push;
343 ssc->can_push = zynqmp_csu_sss_stream_can_push;
344}
345
346static void zynqmp_csu_sss_class_init(ObjectClass *klass, void *data)
347{
348 DeviceClass *dc = DEVICE_CLASS(klass);
349
350 dc->reset = zynqmp_csu_sss_reset;
351 dc->realize = zynqmp_csu_sss_realize;
352 dc->vmsd = &vmstate_zynqmp_csu_sss;
353}
354
355static const TypeInfo zynqmp_csu_sss_info = {
356 .name = TYPE_ZYNQMP_CSU_SSS,
357 .parent = TYPE_SYS_BUS_DEVICE,
358 .instance_size = sizeof(ZynqMPCSUSSS),
359 .class_init = zynqmp_csu_sss_class_init,
360 .instance_init = zynqmp_csu_sss_init,
361};
362
363static const TypeInfo zynqmp_csu_sss_stream_info = {
364 .name = TYPE_ZYNQMP_CSU_SSS_STREAM,
365 .parent = TYPE_DEVICE,
366 .instance_size = sizeof(ZynqMPCSUSSSStream),
367 .class_init = zynqmp_csu_sss_stream_class_init,
368 .interfaces = (InterfaceInfo[]) {
369 { TYPE_STREAM_SLAVE },
370 { }
371 }
372};
373
374static void zynqmp_csu_sss_register_types(void)
375{
376 type_register_static(&zynqmp_csu_sss_info);
377 type_register_static(&zynqmp_csu_sss_stream_info);
378}
379
380type_init(zynqmp_csu_sss_register_types)
381