1 /**
2  * Copyright (c) 2010-2012 Broadcom. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions, and the following disclaimer,
9  *    without modification.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The names of the above-listed copyright holders may not be used
14  *    to endorse or promote products derived from this software without
15  *    specific prior written permission.
16  *
17  * ALTERNATIVELY, this software may be distributed under the terms of the
18  * GNU General Public License ("GPL") version 2, as published by the Free
19  * Software Foundation.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <interface/compat/vchi_bsd.h>
35 
36 #include <sys/param.h>
37 #include <sys/malloc.h>
38 #include <sys/bus.h>
39 #include <sys/kmem.h>
40 
41 #include <linux/completion.h>
42 
43 #include <uvm/uvm_extern.h>
44 
45 #include <arm/cpufunc.h>
46 
47 #include <arch/arm/broadcom/bcm2835_mbox.h>
48 #include <arch/arm/broadcom/bcm2835var.h>
49 
50 #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
51 
52 #define VCHIQ_DOORBELL_IRQ IRQ_ARM_DOORBELL_0
53 
54 #define IS_USER_ADDRESS(va)   \
55           ((vaddr_t)(va) >= VM_MIN_ADDRESS && (vaddr_t)(va) < VM_MAX_ADDRESS)
56 
57 #include "vchiq_arm.h"
58 #include "vchiq_2835.h"
59 #include "vchiq_netbsd.h"
60 #include "vchiq_connected.h"
61 
62 #define VCPAGE_OFFSET 0x0fff
63 #define VCPAGE_SHIFT  12
64 
65 #define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
66 
67 typedef struct vchiq_2835_state_struct {
68    int inited;
69    VCHIQ_ARM_STATE_T arm_state;
70 } VCHIQ_2835_ARM_STATE_T;
71 
72 /* BSD DMA */
73 static bus_dma_tag_t dma_tag;
74 static bus_dmamap_t dma_map;
75 
76 static unsigned int g_cache_line_size = CACHE_LINE_SIZE;
77 static unsigned int g_fragments_size;
78 static char *g_fragments_base;
79 static char *g_free_fragments;
80 
81 struct semaphore g_free_fragments_sema;
82 static struct semaphore g_free_fragments_mutex;
83 
84 void
vchiq_platform_attach(bus_dma_tag_t tag)85 vchiq_platform_attach(bus_dma_tag_t tag)
86 {
87           dma_tag = tag;
88 }
89 
90 int __init
vchiq_platform_init(VCHIQ_STATE_T * state)91 vchiq_platform_init(VCHIQ_STATE_T *state)
92 {
93           VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
94           bus_dma_segment_t dma_segs[1];
95           int dma_nsegs;
96           void *slot_mem;
97           bus_addr_t slot_phys;
98           int slot_mem_size, frag_mem_size;
99           int err;
100           int i;
101 
102           _sema_init(&g_free_fragments_mutex, 1);
103 
104           g_cache_line_size = 32;
105 
106           g_fragments_size = 2 * g_cache_line_size;
107 
108           /* Allocate space for the channels in coherent memory */
109           slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
110           frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
111 
112           dma_nsegs = __arraycount(dma_segs);
113           err = bus_dmamem_alloc(dma_tag,
114               slot_mem_size + frag_mem_size, PAGE_SIZE, 0,
115               dma_segs, dma_nsegs, &dma_nsegs, BUS_DMA_WAITOK);
116           if (err) {
117                     vchiq_log_error(vchiq_core_log_level, "Unable to allocate channel memory");
118                     err = -ENOMEM;
119                     goto failed_alloc;
120           }
121 
122           err = bus_dmamem_map(dma_tag,
123               dma_segs, dma_nsegs, slot_mem_size + frag_mem_size,
124               (void **)&slot_mem, BUS_DMA_COHERENT | BUS_DMA_WAITOK);
125           if (err) {
126                     vchiq_log_error(vchiq_core_log_level, "Unable to map channel memory");
127                     err = -ENOMEM;
128                     goto failed_alloc;
129           }
130 
131           err = bus_dmamap_create(dma_tag,
132               slot_mem_size + frag_mem_size, 1,   /* maxsize, nsegments */
133               slot_mem_size + frag_mem_size, 0,   /* maxsegsize, boundary */
134               BUS_DMA_WAITOK,
135               &dma_map);
136           if (err) {
137                     vchiq_log_error(vchiq_core_log_level, "Unable to create DMA map");
138                     err = -ENOMEM;
139                     goto failed_alloc;
140           }
141 
142           err = bus_dmamap_load(dma_tag, dma_map, slot_mem,
143               slot_mem_size + frag_mem_size, NULL, BUS_DMA_WAITOK);
144           if (err) {
145                     vchiq_log_error(vchiq_core_log_level, "cannot load DMA map (%d)", err);
146                     err = -ENOMEM;
147                     goto failed_load;
148           }
149           slot_phys = dma_map->dm_segs[0].ds_addr;
150 
151           vchiq_log_info(vchiq_arm_log_level,
152               "%s: slot_phys = %lx\n", __func__, slot_phys);
153 
154           WARN_ON(((uintptr_t)slot_mem & (PAGE_SIZE - 1)) != 0);
155 
156           vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
157           if (!vchiq_slot_zero) {
158                     err = -EINVAL;
159                     goto failed_init_slots;
160           }
161 
162           vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
163                     (int)slot_phys + slot_mem_size;
164           vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
165                     MAX_FRAGMENTS;
166 
167           g_fragments_base = (char *)slot_mem + slot_mem_size;
168           slot_mem_size += frag_mem_size;
169 
170           g_free_fragments = g_fragments_base;
171           for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
172                     *(char **)&g_fragments_base[i*g_fragments_size] =
173                               &g_fragments_base[(i + 1)*g_fragments_size];
174           }
175           *(char **)&g_fragments_base[i * g_fragments_size] = NULL;
176 
177           _sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
178 
179           if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) !=
180                     VCHIQ_SUCCESS) {
181                     err = -EINVAL;
182                     goto failed_vchiq_init;
183           }
184 
185           /* Send the base address of the slots to VideoCore */
186           dsb(sy); /* Ensure all writes have completed */
187 
188           bus_dmamap_sync(dma_tag, dma_map, 0, slot_mem_size,
189               BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
190           bcm_mbox_write(BCM2835_MBOX_CHAN_VCHIQ, (unsigned int)slot_phys);
191           bus_dmamap_sync(dma_tag, dma_map, 0, slot_mem_size,
192               BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
193 
194           vchiq_log_info(vchiq_arm_log_level,
195                     "vchiq_init - done (slots %p, phys %x)",
196                     vchiq_slot_zero, (unsigned int)slot_phys);
197 
198           vchiq_call_connected_callbacks();
199 
200           return 0;
201 
202 failed_vchiq_init:
203 failed_init_slots:
204 failed_load:
205           bus_dmamap_unload(dma_tag, dma_map);
206 failed_alloc:
207           bus_dmamap_destroy(dma_tag, dma_map);
208 
209    return err;
210 }
211 
212 void __exit
vchiq_platform_exit(VCHIQ_STATE_T * state)213 vchiq_platform_exit(VCHIQ_STATE_T *state)
214 {
215 
216           bus_dmamap_unload(dma_tag, dma_map);
217           bus_dmamap_destroy(dma_tag, dma_map);
218 }
219 
220 
221 VCHIQ_STATUS_T
vchiq_platform_init_state(VCHIQ_STATE_T * state)222 vchiq_platform_init_state(VCHIQ_STATE_T *state)
223 {
224    VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
225    state->platform_state = kzalloc(sizeof(VCHIQ_2835_ARM_STATE_T), GFP_KERNEL);
226    ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 1;
227    status = vchiq_arm_init_state(state, &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state);
228    if(status != VCHIQ_SUCCESS)
229    {
230       ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 0;
231    }
232    return status;
233 }
234 
235 VCHIQ_ARM_STATE_T*
vchiq_platform_get_arm_state(VCHIQ_STATE_T * state)236 vchiq_platform_get_arm_state(VCHIQ_STATE_T *state)
237 {
238    if(!((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited)
239    {
240       BUG();
241    }
242    return &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state;
243 }
244 
245 int
vchiq_copy_from_user(void * dst,const void * src,int size)246 vchiq_copy_from_user(void *dst, const void *src, int size)
247 {
248           vaddr_t va = (vaddr_t)src;
249 
250           if (IS_USER_ADDRESS(va)) {
251                     int error = copyin(src, dst, size);
252                     return error ? VCHIQ_ERROR : VCHIQ_SUCCESS;
253           } else {
254                     kcopy(src, dst, size);
255                     return VCHIQ_SUCCESS;
256           }
257 }
258 
259 typedef struct bulkinfo_struct {
260           void                *pagelist;
261           bus_dma_segment_t pagelist_sgs[1];
262           bus_size_t          pagelist_size;
263           bus_dmamap_t        pagelist_map;
264           bus_dmamap_t        dmamap;
265           struct proc         *proc;
266           void                *buf;
267           int                 size;
268 } BULKINFO_T;
269 
270 /* There is a potential problem with partial cache lines (pages?)
271 ** at the ends of the block when reading. If the CPU accessed anything in
272 ** the same line (page?) then it may have pulled old data into the cache,
273 ** obscuring the new data underneath. We can solve this by transferring the
274 ** partial cache lines separately, and allowing the ARM to copy into the
275 ** cached area.
276 */
277 VCHIQ_STATUS_T
vchiq_prepare_bulk_data(VCHIQ_BULK_T * bulk,VCHI_MEM_HANDLE_T memhandle,void * buf,int size,int dir)278 vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
279           void *buf, int size, int dir)
280 {
281           PAGELIST_T *pagelist;
282           BULKINFO_T *bi;
283           int nsegs;
284           int ret;
285 
286           vchiq_log_info(vchiq_arm_log_level,
287               "%s: buf %p size %08x dir %s", __func__, buf, size,
288               dir == VCHIQ_BULK_RECEIVE ? "read" : "write");
289 
290           vaddr_t va = (vaddr_t)buf;
291           const size_t maxsegs = atop(round_page(va + size) - trunc_page(va));
292           const int uvmflags = (dir == VCHIQ_BULK_RECEIVE ?
293               VM_PROT_READ : VM_PROT_WRITE);
294           const int dmaflags = (dir == VCHIQ_BULK_RECEIVE ?
295               BUS_DMA_READ : BUS_DMA_WRITE);
296 
297           WARN_ON(memhandle != VCHI_MEM_HANDLE_INVALID);
298 
299           bi = kmem_alloc(sizeof(*bi), KM_SLEEP);
300           bi->buf = buf;
301           bi->size = size;
302           bi->pagelist_size = sizeof(PAGELIST_T) +
303               (maxsegs * sizeof(unsigned long));
304           bi->proc = curproc;
305 
306           ret = bus_dmamem_alloc(dma_tag, bi->pagelist_size,
307               0 /*CACHE_LINE_SIZE*/, 0, bi->pagelist_sgs,
308               __arraycount(bi->pagelist_sgs), &nsegs, BUS_DMA_WAITOK);
309 
310           if (ret != 0)
311                     goto fail1;
312 
313           ret = bus_dmamem_map(dma_tag, bi->pagelist_sgs, nsegs,
314               bi->pagelist_size, &bi->pagelist, BUS_DMA_COHERENT | BUS_DMA_WAITOK);
315           if (ret != 0)
316                     goto fail2;
317 
318           pagelist = bi->pagelist;
319 
320           ret = bus_dmamap_create(dma_tag, bi->pagelist_size,
321               nsegs, bi->pagelist_size, 0, BUS_DMA_WAITOK, &bi->pagelist_map);
322           if (ret != 0)
323                     goto fail3;
324 
325           ret = bus_dmamap_load(dma_tag, bi->pagelist_map, pagelist,
326               bi->pagelist_size, NULL, BUS_DMA_WAITOK | BUS_DMA_WRITE);
327           if (ret != 0)
328                     goto fail4;
329 
330           /*
331            * Need to wire the buffer pages in.
332            */
333           if (IS_USER_ADDRESS(buf)) {
334                     ret = uvm_vslock(bi->proc->p_vmspace, buf, size, uvmflags);
335                     if (ret != 0) {
336                               printf("%s: uvm_vslock failed (%d)\n", __func__, ret);
337                               goto fail5;
338                     }
339           }
340 
341           ret = bus_dmamap_create(dma_tag, size, maxsegs, size, 0,
342               BUS_DMA_WAITOK, &bi->dmamap);
343 
344           if (ret != 0)
345                     goto fail6;
346 
347           ret = bus_dmamap_load(dma_tag, bi->dmamap, buf, size,
348               curproc, BUS_DMA_WAITOK | dmaflags);
349 
350           if (ret != 0)
351                     goto fail7;
352 
353           bulk->handle = memhandle;
354           /*
355            * We've now got the bus_addr_t for the pagelist we want the transfer
356            * to use.
357            */
358           bulk->data = (void *)bi->pagelist_map->dm_segs[0].ds_addr;
359 
360           pagelist->type = (dir == VCHIQ_BULK_RECEIVE) ?
361               PAGELIST_READ : PAGELIST_WRITE;
362           pagelist->length = size;
363           pagelist->offset = va & VCPAGE_OFFSET;
364 
365           /*
366            * busdma already coalesces contiguous pages for us
367            */
368           for (int i = 0; i < bi->dmamap->dm_nsegs; i++) {
369                     bus_addr_t addr = bi->dmamap->dm_segs[i].ds_addr;
370                     bus_size_t len = bi->dmamap->dm_segs[i].ds_len;
371                     bus_size_t off = addr & VCPAGE_OFFSET;
372                     int npgs = ((off + len + VCPAGE_OFFSET) >> VCPAGE_SHIFT);
373 
374                     pagelist->addrs[i] = addr & ~VCPAGE_OFFSET;
375                     pagelist->addrs[i] |= npgs - 1;
376           }
377 
378           /* Partial cache lines (fragments) require special measures */
379           if ((pagelist->type == PAGELIST_READ) &&
380               ((pagelist->offset & (g_cache_line_size - 1)) ||
381               ((pagelist->offset + pagelist->length) & (g_cache_line_size - 1)))) {
382                     char *fragments;
383 
384                     if (down_interruptible(&g_free_fragments_sema) != 0) {
385                               goto fail7;
386                     }
387 
388                     WARN_ON(g_free_fragments == NULL);
389 
390                     down(&g_free_fragments_mutex);
391                     fragments = g_free_fragments;
392                     WARN_ON(fragments == NULL);
393                     g_free_fragments = *(char **) g_free_fragments;
394                     up(&g_free_fragments_mutex);
395                     pagelist->type = PAGELIST_READ_WITH_FRAGMENTS +
396                         (fragments - g_fragments_base) / g_fragments_size;
397                     bus_dmamap_sync(dma_tag, dma_map,
398                         (char *)fragments - g_fragments_base, sizeof(*fragments),
399                         BUS_DMASYNC_PREREAD);
400           }
401 
402           /*
403            * Store the BULKINFO_T address in remote_data, which isn't used by the
404            * slave.
405            */
406           bulk->remote_data = bi;
407 
408           bus_dmamap_sync(dma_tag, bi->pagelist_map, 0,
409               bi->pagelist_size, BUS_DMASYNC_PREWRITE);
410 
411           bus_dmamap_sync(dma_tag, bi->dmamap, 0, bi->size,
412               pagelist->type == PAGELIST_WRITE ?
413               BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
414 
415           return VCHIQ_SUCCESS;
416 
417 fail7:
418           bus_dmamap_destroy(dma_tag, bi->dmamap);
419 
420 fail6:
421           if (IS_USER_ADDRESS(bi->buf))
422                     uvm_vsunlock(curproc->p_vmspace, bi->buf, bi->size);
423 
424 fail5:
425           bus_dmamap_unload(dma_tag, bi->pagelist_map);
426 
427 fail4:
428           bus_dmamap_destroy(dma_tag, bi->pagelist_map);
429 
430 fail3:
431           bus_dmamem_unmap(dma_tag, bi->pagelist, bi->pagelist_size);
432 
433 fail2:
434           bus_dmamem_free(dma_tag, bi->pagelist_sgs,
435               __arraycount(bi->pagelist_sgs));
436 
437 fail1:
438           kmem_free(bi, sizeof(*bi));
439           return VCHIQ_ERROR;
440 }
441 
442 void
vchiq_complete_bulk(VCHIQ_BULK_T * bulk)443 vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
444 {
445           if (bulk && bulk->remote_data && bulk->actual) {
446                     int actual = bulk->actual;
447                     BULKINFO_T *bi = bulk->remote_data;
448                     PAGELIST_T *pagelist = bi->pagelist;
449 
450                     vchiq_log_trace(vchiq_arm_log_level,
451                               "free_pagelist - %p, %d", pagelist, actual);
452 
453                     bus_dmamap_sync(dma_tag, bi->pagelist_map, 0,
454                         bi->pagelist_size, BUS_DMASYNC_POSTWRITE);
455 
456                     bus_dmamap_sync(dma_tag, bi->dmamap, 0, bi->size,
457                         pagelist->type == PAGELIST_WRITE ?
458                         BUS_DMASYNC_POSTWRITE : BUS_DMASYNC_POSTREAD);
459 
460                     /* Deal with any partial cache lines (fragments) */
461                     if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
462                               char *fragments = g_fragments_base +
463                                   (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) *
464                                   g_fragments_size;
465                               int head_bytes, tail_bytes;
466 
467                               bus_dmamap_sync(dma_tag, dma_map,
468                                   (char *)fragments - g_fragments_base, g_fragments_size,
469                                   BUS_DMASYNC_POSTREAD);
470 
471                               head_bytes = (g_cache_line_size - pagelist->offset) &
472                                         (g_cache_line_size - 1);
473                               tail_bytes = (pagelist->offset + actual) &
474                                         (g_cache_line_size - 1);
475 
476                               if ((actual >= 0) && (head_bytes != 0)) {
477                                         if (head_bytes > actual)
478                                                   head_bytes = actual;
479 
480                                         if (IS_USER_ADDRESS(bi->buf)) {
481                                                   copyout_proc(bi->proc, fragments,
482                                                       bi->buf, head_bytes);
483                                         } else {
484                                                   kcopy(fragments, bi->buf, head_bytes);
485                                         }
486                               }
487                               if ((actual >= 0) && (head_bytes < actual) &&
488                                   (tail_bytes != 0)) {
489                                         void *t = (char *)bi->buf + bi->size -
490                                             tail_bytes;
491 
492                                          if (IS_USER_ADDRESS(bi->buf)) {
493                                                   copyout_proc(bi->proc,
494                                                       fragments + g_cache_line_size, t,
495                                                       tail_bytes);
496                                         } else {
497                                                   kcopy(fragments + g_cache_line_size, t,
498                                                       tail_bytes);
499                                         }
500                               }
501 
502                               down(&g_free_fragments_mutex);
503                               *(char **)fragments = g_free_fragments;
504                               g_free_fragments = fragments;
505                               up(&g_free_fragments_mutex);
506                               up(&g_free_fragments_sema);
507                     }
508                     bus_dmamap_unload(dma_tag, bi->dmamap);
509                     bus_dmamap_destroy(dma_tag, bi->dmamap);
510                     if (IS_USER_ADDRESS(bi->buf))
511                               uvm_vsunlock(bi->proc->p_vmspace, bi->buf, bi->size);
512 
513                     bus_dmamap_unload(dma_tag, bi->pagelist_map);
514                     bus_dmamap_destroy(dma_tag, bi->pagelist_map);
515                     bus_dmamem_unmap(dma_tag, bi->pagelist,
516                         bi->pagelist_size);
517                     bus_dmamem_free(dma_tag, bi->pagelist_sgs,
518                         __arraycount(bi->pagelist_sgs));
519                     kmem_free(bi, sizeof(*bi));
520           }
521 }
522 
523 void
vchiq_transfer_bulk(VCHIQ_BULK_T * bulk)524 vchiq_transfer_bulk(VCHIQ_BULK_T *bulk)
525 {
526           /*
527            * This should only be called on the master (VideoCore) side, but
528            * provide an implementation to avoid the need for ifdefery.
529            */
530           BUG();
531 }
532 
533 void
vchiq_dump_platform_state(void * dump_context)534 vchiq_dump_platform_state(void *dump_context)
535 {
536           char buf[80];
537           int len;
538           len = snprintf(buf, sizeof(buf),
539                     "  Platform: 2835 (VC master)");
540           vchiq_dump(dump_context, buf, len + 1);
541 }
542 
543 VCHIQ_STATUS_T
vchiq_platform_suspend(VCHIQ_STATE_T * state)544 vchiq_platform_suspend(VCHIQ_STATE_T *state)
545 {
546    return VCHIQ_ERROR;
547 }
548 
549 VCHIQ_STATUS_T
vchiq_platform_resume(VCHIQ_STATE_T * state)550 vchiq_platform_resume(VCHIQ_STATE_T *state)
551 {
552    return VCHIQ_SUCCESS;
553 }
554 
555 void
vchiq_platform_paused(VCHIQ_STATE_T * state)556 vchiq_platform_paused(VCHIQ_STATE_T *state)
557 {
558 }
559 
560 void
vchiq_platform_resumed(VCHIQ_STATE_T * state)561 vchiq_platform_resumed(VCHIQ_STATE_T *state)
562 {
563 }
564 
565 int
vchiq_platform_videocore_wanted(VCHIQ_STATE_T * state)566 vchiq_platform_videocore_wanted(VCHIQ_STATE_T* state)
567 {
568    return 1; // autosuspend not supported - videocore always wanted
569 }
570 
571 int
vchiq_platform_use_suspend_timer(void)572 vchiq_platform_use_suspend_timer(void)
573 {
574    return 0;
575 }
576 void
vchiq_dump_platform_use_state(VCHIQ_STATE_T * state)577 vchiq_dump_platform_use_state(VCHIQ_STATE_T *state)
578 {
579           vchiq_log_info(vchiq_arm_log_level, "Suspend timer not in use");
580 }
581 void
vchiq_platform_handle_timeout(VCHIQ_STATE_T * state)582 vchiq_platform_handle_timeout(VCHIQ_STATE_T *state)
583 {
584           (void)state;
585 }
586