1 /* $NetBSD: vcprop_subr.c,v 1.10 2021/03/08 13:53:08 mlelstv Exp $ */
2
3 /*
4 * Copyright (c) 2014 Michael Lorenz
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 * Mailbox property interface wrapper functions
30 */
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: vcprop_subr.c,v 1.10 2021/03/08 13:53:08 mlelstv Exp $");
33
34 #include <sys/param.h>
35 #include <sys/bus.h>
36 #include <sys/device.h>
37 #include <sys/endian.h>
38
39 #include <uvm/uvm_extern.h>
40
41 #include <arm/broadcom/bcm2835reg.h>
42 #include <arm/broadcom/bcm2835var.h>
43 #include <arm/broadcom/bcm2835_mbox.h>
44
45 #include <evbarm/rpi/vcio.h>
46 #include <evbarm/rpi/vcpm.h>
47 #include <evbarm/rpi/vcprop.h>
48
49 #include <dev/wscons/wsconsio.h>
50
51 int
rpi_fb_set_video(int b)52 rpi_fb_set_video(int b)
53 {
54 int error;
55 uint32_t res;
56
57 /*
58 * might as well put it here since we need to re-init it every time
59 * and it's not like this is going to be called very often anyway
60 */
61 struct __aligned(16) {
62 struct vcprop_buffer_hdr vb_hdr;
63 struct vcprop_tag_blankscreen vbt_blank;
64 struct vcprop_tag end;
65 } vb_setblank =
66 {
67 .vb_hdr = {
68 .vpb_len = htole32(sizeof(vb_setblank)),
69 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
70 },
71 .vbt_blank = {
72 .tag = {
73 .vpt_tag = htole32(VCPROPTAG_BLANK_SCREEN),
74 .vpt_len = htole32(VCPROPTAG_LEN(
75 vb_setblank.vbt_blank)),
76 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
77 },
78 .state = htole32((b != 0) ?
79 VCPROP_BLANK_OFF : VCPROP_BLANK_ON),
80 },
81 .end = {
82 .vpt_tag = htole32(VCPROPTAG_NULL),
83 },
84 };
85
86 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_setblank,
87 sizeof(vb_setblank), &res);
88 #ifdef RPI_IOCTL_DEBUG
89 printf("%s: %d %d %d %08x %08x\n", __func__, b,
90 le32toh(vb_setblank.vbt_blank.state), error, res,
91 le32toh(vb_setblank.vbt_blank.tag.vpt_rcode));
92 #endif
93 if (error)
94 return error;
95
96 if (!vcprop_buffer_success_p(&vb_setblank.vb_hdr) ||
97 !vcprop_tag_success_p(&vb_setblank.vbt_blank.tag)) {
98 return EIO;
99 }
100
101 return 0;
102 }
103
104 uint32_t
rpi_alloc_mem(uint32_t size,uint32_t align,uint32_t flags)105 rpi_alloc_mem(uint32_t size, uint32_t align, uint32_t flags)
106 {
107 int error;
108 uint32_t res;
109
110 struct __aligned(16) {
111 struct vcprop_buffer_hdr vb_hdr;
112 struct vcprop_tag_allocmem vbt_am;
113 struct vcprop_tag end;
114 } vb_allocmem =
115 {
116 .vb_hdr = {
117 .vpb_len = htole32(sizeof(vb_allocmem)),
118 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
119 },
120 .vbt_am = {
121 .tag = {
122 .vpt_tag = htole32(VCPROPTAG_ALLOCMEM),
123 .vpt_len =
124 htole32(VCPROPTAG_LEN(vb_allocmem.vbt_am)),
125 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
126 },
127 .size = htole32(size),
128 .align = htole32(align),
129 .flags = htole32(flags),
130 },
131 .end = {
132 .vpt_tag = htole32(VCPROPTAG_NULL),
133 },
134 };
135
136 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_allocmem,
137 sizeof(vb_allocmem), &res);
138 #ifdef RPI_IOCTL_DEBUG
139 printf("%s: %d %d %08x %08x\n", __func__,
140 le32toh(vb_allocmem.vbt_am.size), error, res,
141 le32toh(vb_allocmem.vbt_am.tag.vpt_rcode));
142 #endif
143 if (error)
144 return error;
145
146 if (!vcprop_buffer_success_p(&vb_allocmem.vb_hdr) ||
147 !vcprop_tag_success_p(&vb_allocmem.vbt_am.tag)) {
148 return EIO;
149 }
150
151 /* Return the handle from the VC */
152 return le32toh(vb_allocmem.vbt_am.size);
153 }
154
155 bus_addr_t
rpi_lock_mem(uint32_t handle)156 rpi_lock_mem(uint32_t handle)
157 {
158 int error;
159 uint32_t res;
160
161 struct __aligned(16) {
162 struct vcprop_buffer_hdr vb_hdr;
163 struct vcprop_tag_lockmem vbt_lm;
164 struct vcprop_tag end;
165 } vb_lockmem =
166 {
167 .vb_hdr = {
168 .vpb_len = htole32(sizeof(vb_lockmem)),
169 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
170 },
171 .vbt_lm = {
172 .tag = {
173 .vpt_tag = htole32(VCPROPTAG_LOCKMEM),
174 .vpt_len =
175 htole32(VCPROPTAG_LEN(vb_lockmem.vbt_lm)),
176 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
177 },
178 .handle = htole32(handle),
179 },
180 .end = {
181 .vpt_tag = htole32(VCPROPTAG_NULL),
182 },
183 };
184
185 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_lockmem,
186 sizeof(vb_lockmem), &res);
187 #ifdef RPI_IOCTL_DEBUG
188 printf("%s: %d %d %08x %08x\n", __func__,
189 le32toh(vb_lockmem.vbt_lm.handle), error, res,
190 le32toh(vb_lockmem.vbt_lm.tag.vpt_rcode));
191 #endif
192 if (error)
193 return 0;
194
195 if (!vcprop_buffer_success_p(&vb_lockmem.vb_hdr) ||
196 !vcprop_tag_success_p(&vb_lockmem.vbt_lm.tag)) {
197 return 0;
198 }
199
200 return le32toh(vb_lockmem.vbt_lm.handle);
201 }
202
203 int
rpi_unlock_mem(uint32_t handle)204 rpi_unlock_mem(uint32_t handle)
205 {
206 int error;
207 uint32_t res;
208
209 struct __aligned(16) {
210 struct vcprop_buffer_hdr vb_hdr;
211 struct vcprop_tag_lockmem vbt_lm;
212 struct vcprop_tag end;
213 } vb_unlockmem =
214 {
215 .vb_hdr = {
216 .vpb_len = htole32(sizeof(vb_unlockmem)),
217 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
218 },
219 .vbt_lm = {
220 .tag = {
221 .vpt_tag = htole32(VCPROPTAG_UNLOCKMEM),
222 .vpt_len =
223 htole32(VCPROPTAG_LEN(vb_unlockmem.vbt_lm)),
224 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
225 },
226 .handle = htole32(handle),
227 },
228 .end = {
229 .vpt_tag = htole32(VCPROPTAG_NULL),
230 },
231 };
232
233 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_unlockmem,
234 sizeof(vb_unlockmem), &res);
235 #ifdef RPI_IOCTL_DEBUG
236 printf("%s: %d %d %08x %08x\n", __func__,
237 le32toh(vb_unlockmem.vbt_lm.handle), error, res,
238 le32toh(vb_unlockmem.vbt_lm.tag.vpt_rcode));
239 #endif
240 if (error)
241 return error;
242
243 if (!vcprop_buffer_success_p(&vb_unlockmem.vb_hdr) ||
244 !vcprop_tag_success_p(&vb_unlockmem.vbt_lm.tag)) {
245 return EIO;
246 }
247
248 return 0;
249 }
250
251 int
rpi_release_mem(uint32_t handle)252 rpi_release_mem(uint32_t handle)
253 {
254 int error;
255 uint32_t res;
256
257 struct __aligned(16) {
258 struct vcprop_buffer_hdr vb_hdr;
259 struct vcprop_tag_lockmem vbt_lm;
260 struct vcprop_tag end;
261 } vb_releasemem =
262 {
263 .vb_hdr = {
264 .vpb_len = htole32(sizeof(vb_releasemem)),
265 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
266 },
267 .vbt_lm = {
268 .tag = {
269 .vpt_tag = htole32(VCPROPTAG_RELEASEMEM),
270 .vpt_len = htole32(VCPROPTAG_LEN(
271 vb_releasemem.vbt_lm)),
272 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
273 },
274 .handle = htole32(handle),
275 },
276 .end = {
277 .vpt_tag = htole32(VCPROPTAG_NULL),
278 },
279 };
280
281 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_releasemem,
282 sizeof(vb_releasemem), &res);
283 #ifdef RPI_IOCTL_DEBUG
284 printf("%s: %d %d %08x %08x\n", __func__,
285 le32toh(vb_releasemem.vbt_lm.handle), error, res,
286 le32toh(vb_releasemem.vbt_lm.tag.vpt_rcode));
287 #endif
288 if (error)
289 return error;
290
291 if (!vcprop_buffer_success_p(&vb_releasemem.vb_hdr) ||
292 !vcprop_tag_success_p(&vb_releasemem.vbt_lm.tag)) {
293 return EIO;
294 }
295
296 return 0;
297 }
298
299 int
rpi_fb_movecursor(int x,int y,int on)300 rpi_fb_movecursor(int x, int y, int on)
301 {
302 int error;
303 uint32_t res;
304
305 struct __aligned(16) {
306 struct vcprop_buffer_hdr vb_hdr;
307 struct vcprop_tag_cursorstate vbt_cs;
308 struct vcprop_tag end;
309 } vb_cursorstate =
310 {
311 .vb_hdr = {
312 .vpb_len = htole32(sizeof(vb_cursorstate)),
313 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
314 },
315 .vbt_cs = {
316 .tag = {
317 .vpt_tag = htole32(VCPROPTAG_SET_CURSOR_STATE),
318 .vpt_len = htole32(VCPROPTAG_LEN(
319 vb_cursorstate.vbt_cs)),
320 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
321 },
322 .enable = htole32((on != 0) ? 1 : 0),
323 .x = htole32(x),
324 .y = htole32(y),
325 .flags = htole32(1),
326 },
327 .end = {
328 .vpt_tag = htole32(VCPROPTAG_NULL),
329 },
330 };
331
332 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_cursorstate,
333 sizeof(vb_cursorstate), &res);
334 #ifdef RPI_IOCTL_DEBUG
335 printf("%s: %08x %d %08x %08x\n", __func__,
336 le32toh(vb_cursorstate.vbt_cs.enable), error, res,
337 le32toh(vb_cursorstate.vbt_cs.tag.vpt_rcode));
338 #endif
339 if (error)
340 return error;
341
342 if (!vcprop_buffer_success_p(&vb_cursorstate.vb_hdr) ||
343 !vcprop_tag_success_p(&vb_cursorstate.vbt_cs.tag)) {
344 return EIO;
345 }
346
347 return 0;
348 }
349
350 int
rpi_fb_initcursor(bus_addr_t pixels,int hx,int hy)351 rpi_fb_initcursor(bus_addr_t pixels, int hx, int hy)
352 {
353 int error;
354 uint32_t res;
355
356
357 struct __aligned(16) {
358 struct vcprop_buffer_hdr vb_hdr;
359 struct vcprop_tag_cursorinfo vbt_ci;
360 struct vcprop_tag end;
361 } vb_cursorinfo =
362 {
363 .vb_hdr = {
364 .vpb_len = htole32(sizeof(vb_cursorinfo)),
365 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
366 },
367 .vbt_ci = {
368 .tag = {
369 .vpt_tag = htole32(VCPROPTAG_SET_CURSOR_INFO),
370 .vpt_len = htole32(VCPROPTAG_LEN(
371 vb_cursorinfo.vbt_ci)),
372 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
373 },
374 .width = htole32(64),
375 .height = htole32(64),
376 .format = htole32(0),
377 .pixels = htole32(pixels),
378 .hotspot_x = htole32(hx),
379 .hotspot_y = htole32(hy),
380 },
381 .end = {
382 .vpt_tag = htole32(VCPROPTAG_NULL),
383 },
384 };
385
386 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_cursorinfo,
387 sizeof(vb_cursorinfo), &res);
388 #ifdef RPI_IOCTL_DEBUG
389 printf("%s: %d %d %08x %08x\n", __func__,
390 le32toh(vb_cursorinfo.vbt_ci.width), error, res,
391 le32toh(vb_cursorinfo.vbt_ci.tag.vpt_rcode));
392 #endif
393 if (error)
394 return error;
395
396 if (!vcprop_buffer_success_p(&vb_cursorinfo.vb_hdr) ||
397 !vcprop_tag_success_p(&vb_cursorinfo.vbt_ci.tag)) {
398 return EIO;
399 }
400
401 return 0;
402 }
403
404 int
rpi_fb_get_pixelorder(uint32_t * orderp)405 rpi_fb_get_pixelorder(uint32_t *orderp)
406 {
407 int error;
408 uint32_t res;
409
410
411 struct __aligned(16) {
412 struct vcprop_buffer_hdr vb_hdr;
413 struct vcprop_tag_fbpixelorder vbt_po;
414 struct vcprop_tag end;
415 } vb_pixelorder =
416 {
417 .vb_hdr = {
418 .vpb_len = htole32(sizeof(vb_pixelorder)),
419 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
420 },
421 .vbt_po = {
422 .tag = {
423 .vpt_tag = htole32(VCPROPTAG_GET_FB_PIXEL_ORDER),
424 .vpt_len = htole32(VCPROPTAG_LEN(
425 vb_pixelorder.vbt_po)),
426 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
427 },
428 },
429 .end = {
430 .vpt_tag = htole32(VCPROPTAG_NULL),
431 },
432 };
433
434 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_pixelorder,
435 sizeof(vb_pixelorder), &res);
436 #ifdef RPI_IOCTL_DEBUG
437 printf("%s: %d %d %08x %08x\n", __func__,
438 le32toh(vb_pixelorder.vbt_po.order), error, res,
439 le32toh(vb_pixelorder.vbt_po.tag.vpt_rcode));
440 #endif
441 if (error)
442 return error;
443
444 if (!vcprop_buffer_success_p(&vb_pixelorder.vb_hdr) ||
445 !vcprop_tag_success_p(&vb_pixelorder.vbt_po.tag)) {
446 return EIO;
447 }
448
449 *orderp = vb_pixelorder.vbt_po.order;
450
451 return 0;
452 }
453
454 int
rpi_fb_set_pixelorder(uint32_t order)455 rpi_fb_set_pixelorder(uint32_t order)
456 {
457 int error;
458 uint32_t res;
459
460
461 struct __aligned(16) {
462 struct vcprop_buffer_hdr vb_hdr;
463 struct vcprop_tag_fbpixelorder vbt_po;
464 struct vcprop_tag end;
465 } vb_pixelorder =
466 {
467 .vb_hdr = {
468 .vpb_len = htole32(sizeof(vb_pixelorder)),
469 .vpb_rcode = htole32(VCPROP_PROCESS_REQUEST),
470 },
471 .vbt_po = {
472 .tag = {
473 .vpt_tag = htole32(VCPROPTAG_SET_FB_PIXEL_ORDER),
474 .vpt_len = htole32(VCPROPTAG_LEN(
475 vb_pixelorder.vbt_po)),
476 .vpt_rcode = htole32(VCPROPTAG_REQUEST),
477 },
478 .order = order
479 },
480 .end = {
481 .vpt_tag = htole32(VCPROPTAG_NULL),
482 },
483 };
484
485 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_pixelorder,
486 sizeof(vb_pixelorder), &res);
487 #ifdef RPI_IOCTL_DEBUG
488 printf("%s: %d %d %08x %08x\n", __func__,
489 le32toh(vb_pixelorder.vbt_po.order), error, res,
490 le32toh(vb_pixelorder.vbt_po.tag.vpt_rcode));
491 #endif
492 if (error)
493 return error;
494
495 if (!vcprop_buffer_success_p(&vb_pixelorder.vb_hdr) ||
496 !vcprop_tag_success_p(&vb_pixelorder.vbt_po.tag)) {
497 return EIO;
498 }
499
500 return 0;
501 }
502
503 int
rpi_set_domain(uint32_t domain,uint32_t state)504 rpi_set_domain(uint32_t domain, uint32_t state)
505 {
506 int error;
507 uint32_t tag, res;
508
509 tag = VCPROPTAG_SET_DOMAIN_STATE;
510 if (domain == VCPROP_DOMAIN_USB) {
511 /* use old interface */
512 tag = VCPROPTAG_SET_POWERSTATE;
513 domain = VCPROP_POWER_USB;
514 }
515
516 /*
517 * might as well put it here since we need to re-init it every time
518 * and it's not like this is going to be called very often anyway
519 */
520 struct __aligned(16) {
521 struct vcprop_buffer_hdr vb_hdr;
522 struct vcprop_tag_powerstate vbt_power;
523 struct vcprop_tag end;
524 } vb_setpower =
525 {
526 .vb_hdr = {
527 .vpb_len = sizeof(vb_setpower),
528 .vpb_rcode = VCPROP_PROCESS_REQUEST,
529 },
530 .vbt_power = {
531 .tag = {
532 .vpt_tag = tag,
533 .vpt_len = VCPROPTAG_LEN(vb_setpower.vbt_power),
534 .vpt_rcode = VCPROPTAG_REQUEST,
535 },
536 .id = domain,
537 .state = state
538 },
539 .end = {
540 .vpt_tag = VCPROPTAG_NULL,
541 },
542 };
543
544 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_setpower,
545 sizeof(vb_setpower), &res);
546 #ifdef RPI_IOCTL_DEBUG
547 printf("%s: %08x %08x %d %08x %08x %d %d %08x %08x\n", __func__,
548 tag, domain, state,
549 vb_setpower.vbt_power.tag.vpt_tag,
550 vb_setpower.vbt_power.id,
551 vb_setpower.vbt_power.state,
552 error, res,
553 vb_setpower.vbt_power.tag.vpt_rcode);
554 #endif
555 if (error)
556 return error;
557
558 if (!vcprop_buffer_success_p(&vb_setpower.vb_hdr) ||
559 !vcprop_tag_success_p(&vb_setpower.vbt_power.tag)) {
560 return EIO;
561 }
562
563 return 0;
564 }
565
566 int
rpi_get_domain(uint32_t domain,uint32_t * statep)567 rpi_get_domain(uint32_t domain, uint32_t *statep)
568 {
569 int error;
570 uint32_t tag, res;
571
572 tag = VCPROPTAG_GET_DOMAIN_STATE;
573 if (domain == VCPROP_DOMAIN_USB) {
574 /* use old interface */
575 tag = VCPROPTAG_GET_POWERSTATE;
576 domain = VCPROP_POWER_USB;
577 }
578
579 /*
580 * might as well put it here since we need to re-init it every time
581 * and it's not like this is going to be called very often anyway
582 */
583 struct __aligned(16) {
584 struct vcprop_buffer_hdr vb_hdr;
585 struct vcprop_tag_powerstate vbt_power;
586 struct vcprop_tag end;
587 } vb_setpower =
588 {
589 .vb_hdr = {
590 .vpb_len = sizeof(vb_setpower),
591 .vpb_rcode = VCPROP_PROCESS_REQUEST,
592 },
593 .vbt_power = {
594 .tag = {
595 .vpt_tag = tag,
596 .vpt_len = VCPROPTAG_LEN(vb_setpower.vbt_power),
597 .vpt_rcode = VCPROPTAG_REQUEST,
598 },
599 .id = domain,
600 .state = ~0
601 },
602 .end = {
603 .vpt_tag = VCPROPTAG_NULL,
604 },
605 };
606
607 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb_setpower,
608 sizeof(vb_setpower), &res);
609 #ifdef RPI_IOCTL_DEBUG
610 printf("%s: %08x %08x %d %08x %08x %d %d %08x %08x\n", __func__,
611 tag, domain, *statep,
612 vb_setpower.vbt_power.tag.vpt_tag,
613 vb_setpower.vbt_power.id,
614 vb_setpower.vbt_power.state,
615 error, res,
616 vb_setpower.vbt_power.tag.vpt_rcode);
617 #endif
618 if (error)
619 return error;
620
621 if (!vcprop_buffer_success_p(&vb_setpower.vb_hdr) ||
622 !vcprop_tag_success_p(&vb_setpower.vbt_power.tag)) {
623 return EIO;
624 }
625
626 *statep = vb_setpower.vbt_power.state;
627
628 return 0;
629 }
630
631 int
rpi_vchiq_init(uint32_t * channelbasep)632 rpi_vchiq_init(uint32_t *channelbasep)
633 {
634 int error;
635 uint32_t tag, res;
636 struct __aligned(16) {
637 struct vcprop_buffer_hdr vb_hdr;
638 struct vcprop_tag_vchiqinit vbt_vchiq;
639 struct vcprop_tag end;
640 } vb;
641
642 tag = VCPROPTAG_VCHIQ_INIT;
643
644 VCPROP_INIT_REQUEST(vb);
645 VCPROP_INIT_TAG(vb.vbt_vchiq, tag);
646 vb.vbt_vchiq.base = *channelbasep;
647
648 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb, sizeof(vb), &res);
649 if (error)
650 return error;
651
652 if (!vcprop_buffer_success_p(&vb.vb_hdr) ||
653 !vcprop_tag_success_p(&vb.vbt_vchiq.tag)) {
654 return EIO;
655 }
656 *channelbasep = vb.vbt_vchiq.base;
657
658 return 0;
659 }
660
661 int
rpi_notify_xhci_reset(uint32_t address)662 rpi_notify_xhci_reset(uint32_t address)
663 {
664 int error;
665 uint32_t tag, res;
666 struct __aligned(16) {
667 struct vcprop_buffer_hdr vb_hdr;
668 struct vcprop_tag_notifyxhcireset vbt_nhr;
669 struct vcprop_tag end;
670 } vb;
671
672 tag = VCPROPTAG_NOTIFY_XHCI_RESET;
673
674 VCPROP_INIT_REQUEST(vb);
675 VCPROP_INIT_TAG(vb.vbt_nhr, tag);
676 vb.vbt_nhr.deviceaddress = address;
677
678 error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb, sizeof(vb), &res);
679 if (error)
680 return error;
681
682 if (!vcprop_buffer_success_p(&vb.vb_hdr) ||
683 !vcprop_tag_success_p(&vb.vbt_nhr.tag)) {
684 return EIO;
685 }
686
687 return 0;
688 }
689
690