1 /****************************************************************************
2 *
3 *    The MIT License (MIT)
4 *
5 *    Copyright (c) 2014 - 2020 Vivante Corporation
6 *
7 *    Permission is hereby granted, free of charge, to any person obtaining a
8 *    copy of this software and associated documentation files (the "Software"),
9 *    to deal in the Software without restriction, including without limitation
10 *    the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 *    and/or sell copies of the Software, and to permit persons to whom the
12 *    Software is furnished to do so, subject to the following conditions:
13 *
14 *    The above copyright notice and this permission notice shall be included in
15 *    all copies or substantial portions of the Software.
16 *
17 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 *    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 *    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 *    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 *    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 *    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 *    DEALINGS IN THE SOFTWARE.
24 *
25 *****************************************************************************/
26 
27 #include "vg_lite_platform.h"
28 #include "vg_lite_kernel.h"
29 #include "vg_lite_hal.h"
30 #include "vg_lite_hw.h"
31 #include "vg_lite_os.h"
32 
33 #if !_BAREMETAL
34 #include "rtthread.h"
35 #else
36 #include "xil_cache.h"
37 #endif
38 
39 #if _BAREMETAL
40 /* The followings should be configured by FPGA. */
41 static    uint32_t    registerMemBase    = 0x43c80000;
42 #else
43 static    uint32_t    registerMemBase    = 0x40240000;
44 #endif
45 
46 #define HEAP_NODE_USED  0xABBAF00D
47 
48 volatile void* contiguousMem = NULL;
49 uint32_t gpuMemBase = 0;
50 
51 /* Default heap size is 16MB. */
52 static int heap_size = MAX_CONTIGUOUS_SIZE;
53 
vg_lite_init_mem(uint32_t register_mem_base,uint32_t gpu_mem_base,volatile void * contiguous_mem_base,uint32_t contiguous_mem_size)54 void vg_lite_init_mem(uint32_t register_mem_base,
55           uint32_t gpu_mem_base,
56           volatile void * contiguous_mem_base,
57           uint32_t contiguous_mem_size)
58 {
59     registerMemBase = register_mem_base;
60     gpuMemBase      = gpu_mem_base;
61     contiguousMem   = contiguous_mem_base;
62     heap_size       = contiguous_mem_size;
63 }
64 
65 /* Implementation of list. ****************************************/
66 typedef struct list_head {
67     struct list_head *next;
68     struct list_head *prev;
69 }list_head_t;
70 
71 #define INIT_LIST_HEAD(entry) \
72         (entry)->next = (entry);\
73         (entry)->prev = (entry);
74 
75 /* Add the list item in front of "head". */
add_list(list_head_t * to_add,list_head_t * head)76 static inline void add_list(list_head_t *to_add, list_head_t *head)
77 {
78     /* Link the new item. */
79     to_add->next = head;
80     to_add->prev = head->prev;
81 
82   /* Modify the neighbor. */
83     head->prev = to_add;
84     if (to_add->prev != NULL) {
85         to_add->prev->next = to_add;
86     }
87 }
88 
89 /* Remove an entry out of the list. */
delete_list(list_head_t * entry)90 static inline void delete_list(list_head_t *entry)
91 {
92     if (entry->prev != NULL) {
93         entry->prev->next = entry->next;
94     }
95     if (entry->next != NULL) {
96         entry->next->prev = entry->prev;
97     }
98 }
99 
100 /* End of list implementation. ***********/
_memset(void * mem,unsigned char value,int size)101 static inline void _memset(void *mem, unsigned char value, int size)
102 {
103     int i;
104     for (i = 0; i < size; i++) {
105         ((unsigned char*)mem)[i] = value;
106     }
107 }
108 
109 typedef struct heap_node {
110     list_head_t list; /* TODO: Linux specific, needs to rewrite. */
111     uint32_t offset;
112     unsigned long size;
113     uint32_t status;
114 }heap_node_t;
115 
116 struct memory_heap {
117     uint32_t free;
118     list_head_t list;
119 };
120 
121 struct mapped_memory {
122     void * logical;
123     uint32_t physical;
124     int page_count;
125     struct page ** pages;
126 };
127 
128 struct vg_lite_device {
129     /* void * gpu; */
130     uint32_t gpu;    /* Always use physical for register access in RTOS. */
131     /* struct page * pages; */
132     volatile void * contiguous;
133     unsigned int order;
134     unsigned int heap_size;
135     void * virtual;
136     uint32_t physical;
137     uint32_t size;
138     struct memory_heap heap;
139     int irq_enabled;
140 
141 #if defined(VG_DRIVER_SINGLE_THREAD)
142     volatile uint32_t int_flags;
143 #if _BAREMETAL
144         /* wait_queue_head_t int_queue; */
145         xSemaphoreHandle int_queue;
146 #else
147         /* wait_queue_head_t int_queue; */
148         rt_sem_t int_queue;
149 #endif
150 #endif /* VG_DRIVER_SINGLE_THREAD */
151 
152     void * device;
153     int registered;
154     int major;
155     struct class * class;
156     int created;
157 };
158 
159 struct client_data {
160     struct vg_lite_device * device;
161     struct vm_area_struct * vm;
162     void * contiguous_mapped;
163 };
164 
165 static struct vg_lite_device Device, * device;
166 
vg_lite_hal_delay(uint32_t ms)167 void vg_lite_hal_delay(uint32_t ms)
168 {
169     vg_lite_os_sleep(ms);
170 }
171 
vg_lite_hal_barrier(void)172 void vg_lite_hal_barrier(void)
173 {
174      /*Memory barrier. */
175 #if _BAREMETAL
176      Xil_DCacheFlush();
177 #else
178     __asm("DSB");
179 #endif
180 }
181 
182 static int vg_lite_init(void);
vg_lite_hal_initialize(void)183 vg_lite_error_t vg_lite_hal_initialize(void)
184 {
185     int32_t error = VG_LITE_SUCCESS;
186     /* TODO: Turn on the power. */
187     vg_lite_init();
188     /* TODO: Turn on the clock. */
189     error = vg_lite_os_initialize();
190 
191     return (vg_lite_error_t)error;
192 }
193 
vg_lite_hal_deinitialize(void)194 void vg_lite_hal_deinitialize(void)
195 {
196     /* TODO: Remove clock. */
197     vg_lite_os_deinitialize();
198     /* TODO: Remove power. */
199 }
200 
split_node(heap_node_t * node,unsigned long size)201 static int split_node(heap_node_t * node, unsigned long size)
202 {
203     /* TODO: the original is linux specific list based, needs rewrite.
204     */
205     heap_node_t * split;
206 
207     /*
208      * If the newly allocated object fits exactly the size of the free
209      * node, there is no need to split.
210      */
211     if (node->size - size == 0)
212         return 0;
213 
214     /* Allocate a new node. */
215     split = (heap_node_t *)vg_lite_os_malloc(sizeof(heap_node_t));
216 
217     if (split == NULL)
218         return -1;
219 
220     /* Fill in the data of this node of the remaning size. */
221     split->offset = node->offset + size;
222     split->size = node->size - size;
223     split->status = 0;
224 
225     /* Add the new node behind the current node. */
226     add_list(&split->list, &node->list);
227 
228     /* Adjust the size of the current node. */
229     node->size = size;
230     return 0;
231 }
232 
vg_lite_hal_allocate_contiguous(unsigned long size,void ** logical,uint32_t * physical,void ** node)233 vg_lite_error_t vg_lite_hal_allocate_contiguous(unsigned long size, void ** logical, uint32_t * physical,void ** node)
234 {
235     unsigned long aligned_size;
236     heap_node_t * pos;
237 
238     /* Align the size to 64 bytes. */
239     aligned_size = (size + 63) & ~63;
240 
241     /* Check if there is enough free memory available. */
242     if (aligned_size > device->heap.free) {
243         return VG_LITE_OUT_OF_MEMORY;
244     }
245 
246     /* Walk the heap backwards. */
247     for (pos = (heap_node_t*)device->heap.list.prev;
248                  &pos->list != &device->heap.list;
249                  pos = (heap_node_t*) pos->list.prev) {
250         /* Check if the current node is free and is big enough. */
251         if (pos->status == 0 && pos->size >= aligned_size) {
252             /* See if we the current node is big enough to split. */
253                 if (0 != split_node(pos, aligned_size))
254                 {
255                     return VG_LITE_OUT_OF_RESOURCES;
256                 }
257             /* Mark the current node as used. */
258             pos->status = HEAP_NODE_USED;
259 
260             /*  Return the logical/physical address. */
261             /* *logical = (uint8_t *) private_data->contiguous_mapped + pos->offset; */
262             *logical = (uint8_t *)device->virtual + pos->offset;
263             *physical = gpuMemBase + (uint32_t)(*logical);/* device->physical + pos->offset; */
264             device->heap.free -= aligned_size;
265 
266             *node = pos;
267             return VG_LITE_SUCCESS;
268         }
269     }
270 
271     /* Out of memory. */
272     return VG_LITE_OUT_OF_MEMORY;
273 }
274 
vg_lite_hal_free_contiguous(void * memory_handle)275 void vg_lite_hal_free_contiguous(void * memory_handle)
276 {
277     /* TODO: no list available in RTOS. */
278     heap_node_t * pos, * node;
279 
280     /* Get pointer to node. */
281     node = memory_handle;
282 
283     if (node->status != HEAP_NODE_USED) {
284         return;
285     }
286 
287     /* Mark node as free. */
288     node->status = 0;
289 
290     /* Add node size to free count. */
291     device->heap.free += node->size;
292 
293     /* Check if next node is free. */
294     pos = node;
295     for (pos = (heap_node_t *)pos->list.next;
296          &pos->list != &device->heap.list;
297          pos = (heap_node_t *)pos->list.next) {
298         if (pos->status == 0) {
299             /* Merge the nodes. */
300             node->size += pos->size;
301             if(node->offset > pos->offset)
302                 node->offset = pos->offset;
303             /* Delete the next node from the list. */
304             delete_list(&pos->list);
305             vg_lite_os_free(pos);
306         }
307         break;
308     }
309 
310     /* Check if the previous node is free. */
311     pos = node;
312     for (pos = (heap_node_t *)pos->list.prev;
313          &pos->list != &device->heap.list;
314          pos = (heap_node_t *)pos->list.prev) {
315         if (pos->status == 0) {
316             /* Merge the nodes. */
317             pos->size += node->size;
318             if(pos->offset > node->offset)
319                 pos->offset = node->offset;
320             /* Delete the current node from the list. */
321             delete_list(&node->list);
322             vg_lite_os_free(node);
323         }
324         break;
325     }
326     /* when release command buffer node and ts buffer node to exit,release the linked list*/
327     if(device->heap.list.next == device->heap.list.prev) {
328         delete_list(&pos->list);
329         vg_lite_os_free(pos);
330     }
331 }
332 
vg_lite_hal_free_os_heap(void)333 void vg_lite_hal_free_os_heap(void)
334 {
335     struct heap_node    *pos, *n;
336 
337     /* Check for valid device. */
338     if (device != NULL) {
339         /* Process each node. */
340         for (pos = (heap_node_t *)device->heap.list.next,
341              n = (heap_node_t *)pos->list.next;
342              &pos->list != &device->heap.list;
343              pos = n, n = (heap_node_t *)n->list.next) {
344                 /* Remove it from the linked list. */
345                 delete_list(&pos->list);
346                 /* Free up the memory. */
347                 vg_lite_os_free(pos);
348         }
349     }
350 }
351 
352 /* Portable: read register value. */
vg_lite_hal_peek(uint32_t address)353 uint32_t vg_lite_hal_peek(uint32_t address)
354 {
355     /* Read data from the GPU register. */
356     return (uint32_t) (*(volatile uint32_t *) (device->gpu + address));
357 }
358 
359 /* Portable: write register. */
vg_lite_hal_poke(uint32_t address,uint32_t data)360 void vg_lite_hal_poke(uint32_t address, uint32_t data)
361 {
362     /* Write data to the GPU register. */
363     uint32_t *LocalAddr = (uint32_t *)(device->gpu + address);
364     *LocalAddr = data;
365 }
366 
vg_lite_hal_query_mem(vg_lite_kernel_mem_t * mem)367 vg_lite_error_t vg_lite_hal_query_mem(vg_lite_kernel_mem_t *mem)
368 {
369     if(device != NULL){
370         mem->bytes  = device->heap.free;
371         return VG_LITE_SUCCESS;
372     }
373     mem->bytes = 0;
374     return VG_LITE_NO_CONTEXT;
375 }
376 
vg_lite_IRQHandler(void)377 void vg_lite_IRQHandler(void)
378 {
379     vg_lite_os_IRQHandler();
380 }
381 
vg_lite_hal_wait_interrupt(uint32_t timeout,uint32_t mask,uint32_t * value)382 int32_t vg_lite_hal_wait_interrupt(uint32_t timeout, uint32_t mask, uint32_t * value)
383 {
384     return vg_lite_os_wait_interrupt(timeout,mask,value);
385 }
386 
vg_lite_hal_map(unsigned long bytes,void * logical,uint32_t physical,uint32_t * gpu)387 void * vg_lite_hal_map(unsigned long bytes, void * logical, uint32_t physical, uint32_t * gpu)
388 {
389 
390     (void) bytes;
391     (void) logical;
392     (void) physical;
393     (void) gpu;
394     return (void *)0;
395 }
396 
vg_lite_hal_unmap(void * handle)397 void vg_lite_hal_unmap(void * handle)
398 {
399 
400     (void) handle;
401 }
402 
403 #if !defined(VG_DRIVER_SINGLE_THREAD)
vg_lite_hal_submit(uint32_t context,uint32_t physical,uint32_t offset,uint32_t size,vg_lite_os_async_event_t * event)404 vg_lite_error_t vg_lite_hal_submit(uint32_t context,uint32_t physical, uint32_t offset, uint32_t size, vg_lite_os_async_event_t *event)
405 {
406     return (vg_lite_error_t)vg_lite_os_submit(context,physical,offset,size,event);
407 }
408 
vg_lite_hal_wait(uint32_t timeout,vg_lite_os_async_event_t * event)409 vg_lite_error_t vg_lite_hal_wait(uint32_t timeout, vg_lite_os_async_event_t *event)
410 {
411     return  (vg_lite_error_t)vg_lite_os_wait(timeout,event);
412 }
413 #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */
414 
vg_lite_exit(void)415 static void vg_lite_exit(void)
416 {
417     heap_node_t * pos;
418     heap_node_t * n;
419 
420     /* Check for valid device. */
421     if (device != NULL) {
422         /* TODO: unmap register mem should be unnecessary. */
423         device->gpu = 0;
424 
425         /* Process each node. */
426         for (pos = (heap_node_t *)device->heap.list.next, n = (heap_node_t *)pos->list.next;
427              &pos->list != &device->heap.list;
428              pos = n, n = (heap_node_t *)n->list.next) {
429             /* Remove it from the linked list. */
430             delete_list(&pos->list);
431 
432             /* Free up the memory. */
433             vg_lite_os_free(pos);
434         }
435 
436         /* Free up the device structure. */
437         vg_lite_os_free(device);
438     }
439 }
440 
vg_lite_init(void)441 static int vg_lite_init(void)
442 {
443     heap_node_t * node;
444 
445     /* Initialize memory and objects ***************************************/
446     /* Create device structure. */
447     device = &Device;
448 
449     /* Zero out the enture structure. */
450     _memset(device, 0, sizeof(struct vg_lite_device));
451 
452     /* Setup register memory. **********************************************/
453     device->gpu = registerMemBase;
454 
455     /* Initialize contiguous memory. ***************************************/
456     /* Allocate the contiguous memory. */
457     device->heap_size = heap_size;
458     device->contiguous = (volatile void *)contiguousMem;
459     _memset((void *)device->contiguous, 0, heap_size);
460     /* Make 64byte aligned. */
461     while ((((uint32_t)device->contiguous) & 63) != 0)
462     {
463         device->contiguous = ((unsigned char*) device->contiguous) + 4;
464         device->heap_size -= 4;
465     }
466 
467     /* Check if we allocated any contiguous memory or not. */
468     if (device->contiguous == NULL) {
469         vg_lite_exit();
470         return -1;
471     }
472 
473     device->virtual = (void *)device->contiguous;
474     device->physical = gpuMemBase + (uint32_t)device->virtual;
475     device->size = device->heap_size;
476 
477     /* Create the heap. */
478     INIT_LIST_HEAD(&device->heap.list);
479     device->heap.free = device->size;
480 
481     node = (heap_node_t *)vg_lite_os_malloc(sizeof(heap_node_t));
482 
483     if (node == NULL) {
484         vg_lite_exit();
485         return -1;
486     }
487     node->offset = 0;
488     node->size = device->size;
489     node->status = 0;
490     add_list(&node->list, &device->heap.list);
491 #if defined(VG_DRIVER_SINGLE_THREAD)
492 #if !_BAREMETAL /*for rt500*/
493         device->int_queue = rt_sem_create("diq", 0, RT_IPC_FLAG_PRIO);
494         device->int_flags = 0;
495 #endif
496 #endif /* VG_DRIVER_SINGLE_THREAD */
497     /* Success. */
498     return 0;
499 }
500