/**************************************************************************** * * The MIT License (MIT) * * Copyright (c) 2014 - 2020 Vivante Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * *****************************************************************************/ #include "vg_lite_platform.h" #include "vg_lite_kernel.h" #include "vg_lite_hal.h" #include "vg_lite_hw.h" #if defined(__linux__) && !EMULATOR #include #include #endif static int s_reference = 0; #if !defined(VG_DRIVER_SINGLE_THREAD) static int task_num = 0; static vg_lite_kernel_initialize_t ts_initialize = {0}; static uint8_t ts_init = 0; #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ #if defined(VG_DRIVER_SINGLE_THREAD) #define VG_LITE_OS_LOCK() VG_LITE_SUCCESS #define VG_LITE_OS_UNLOCK() #else #define VG_LITE_OS_LOCK() vg_lite_os_lock() #define VG_LITE_OS_UNLOCK() vg_lite_os_unlock() #endif /* VG_DRIVER_SINGLE_THREAD */ static vg_lite_error_t do_terminate(vg_lite_kernel_terminate_t * data); static void soft_reset(void); static void gpu(int enable) { vg_lite_hw_clock_control_t value; uint32_t reset_timer = 2; #ifdef VG_GPU_AUTO_CLOCK_GATING uint32_t temp; #endif /* VG_GPU_AUTO_CLOCK_GATING */ const uint32_t reset_timer_limit = 1000; if (enable) { /* Disable clock gating. */ value.data = vg_lite_hal_peek(VG_LITE_HW_CLOCK_CONTROL); value.control.clock_gate = 0; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); vg_lite_hal_delay(1); /* Set clock speed. */ value.control.scale = 64; value.control.scale_load = 1; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); vg_lite_hal_delay(1); value.control.scale_load = 0; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); vg_lite_hal_delay(5); do { /* Perform a soft reset. */ soft_reset(); vg_lite_hal_delay(reset_timer); reset_timer *= 2; // If reset failed, try again with a longer wait. Need to check why if dead lopp happens here. } while (!VG_LITE_KERNEL_IS_GPU_IDLE()); #ifdef VG_GPU_AUTO_CLOCK_GATING temp = vg_lite_hal_peek(VG_LITE_HW_POWER_CONTROL); temp |= 0x1; vg_lite_hal_poke(VG_LITE_HW_POWER_CONTROL, temp); vg_lite_hal_delay(1); #endif /* VG_GPU_AUTO_CLOCK_GATING */ } else { while (!VG_LITE_KERNEL_IS_GPU_IDLE() && (reset_timer < reset_timer_limit) // Force shutdown if timeout. ) { vg_lite_hal_delay(reset_timer); reset_timer *= 2; } /* Set idle speed. */ value.data = vg_lite_hal_peek(VG_LITE_HW_CLOCK_CONTROL); value.control.scale = 1; value.control.scale_load = 1; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); vg_lite_hal_delay(1); value.control.scale_load = 0; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); vg_lite_hal_delay(5); /* Enable clock gating. */ value.control.clock_gate = 1; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); vg_lite_hal_delay(1); } } /* Initialize some customized modeuls [DDRLess]. */ static vg_lite_error_t init_3rd(vg_lite_kernel_initialize_t * data) { vg_lite_error_t error = VG_LITE_SUCCESS; /* TODO: Init the YUV<->RGB converters. Reserved for SOC. */ /* vg_lite_hal_poke(0x00514, data->yuv_pre); vg_lite_hal_poke(0x00518, data->yuv_post); */ return error; } #if defined(VG_DRIVER_SINGLE_THREAD) static vg_lite_error_t init_vglite(vg_lite_kernel_initialize_t * data) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_kernel_context_t * context; uint32_t id; int i; uint32_t chip_id = 0; #if defined(__linux__) && !EMULATOR vg_lite_kernel_context_t __user * context_usr; vg_lite_kernel_context_t mycontext = { 0 }; // Construct the context. context_usr = (vg_lite_kernel_context_t __user *) data->context; #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) if (!access_ok(VERIFY_READ, context_usr, sizeof(*context_usr)) || !access_ok(VERIFY_WRITE, context_usr, sizeof(*context_usr))) { #else if (!access_ok(context_usr, sizeof(*context_usr)) || !access_ok(context_usr, sizeof(*context_usr))) { #endif /* Out of memory. */ return VG_LITE_OUT_OF_MEMORY; } context = &mycontext; #else // Construct the context. context = data->context; if (context == NULL) { /* Out of memory. */ return VG_LITE_OUT_OF_MEMORY; } #endif /* Zero out all pointers. */ for (i = 0; i < CMDBUF_COUNT; i++){ context->command_buffer[i] = NULL; context->command_buffer_logical[i] = NULL; context->command_buffer_physical[i] = 0; } context->tessellation_buffer = NULL; context->tessellation_buffer_logical = NULL; context->tessellation_buffer_physical = 0; /* Increment reference counter. */ if (s_reference++ == 0) { /* Initialize the SOC. */ vg_lite_hal_initialize(); /* Enable the GPU. */ gpu(1); } /* Fill in hardware capabilities. */ data->capabilities.data = 0; id = vg_lite_hal_peek(VG_LITE_HW_CHIP_ID); if (id >= 0x300) { data->capabilities.cap.l2_cache = 1; } /* Allocate the command buffer. */ if (data->command_buffer_size) { int32_t i; for (i = 0; i < 2; i ++) { /* Allocate the memory. */ error = vg_lite_hal_allocate_contiguous(data->command_buffer_size, &context->command_buffer_logical[i], &context->command_buffer_physical[i], &context->command_buffer[i]); if (error != VG_LITE_SUCCESS) { /* Free any allocated memory. */ vg_lite_kernel_terminate_t terminate = { context }; do_terminate(&terminate); /* Out of memory. */ return error; } /* Return command buffer logical pointer and GPU address. */ data->command_buffer[i] = context->command_buffer_logical[i]; data->command_buffer_gpu[i] = context->command_buffer_physical[i]; } } /* Allocate the tessellation buffer. */ if ((data->tessellation_width > 0) && (data->tessellation_height > 0)) { int width = data->tessellation_width; int height = 0; unsigned long stride, buffer_size, l1_size, l2_size; height = VG_LITE_ALIGN(data->tessellation_height, 16); chip_id = vg_lite_hal_peek(0x20); if(chip_id == GPU_CHIP_ID_GC355) width = VG_LITE_ALIGN(width, 128); /* Check if we can used tiled tessellation (128x16). */ if (((width & 127) == 0) && ((height & 15) == 0)) { data->capabilities.cap.tiled = 0x3; } else { data->capabilities.cap.tiled = 0x2; } /* Compute tessellation buffer size. */ stride = VG_LITE_ALIGN(width * 8, 64); buffer_size = VG_LITE_ALIGN(stride * height, 64); /* Each bit in the L1 cache represents 64 bytes of tessellation data. */ l1_size = VG_LITE_ALIGN(VG_LITE_ALIGN(buffer_size / 64, 64) / 8, 64); /* Each bit in the L2 cache represents 32 bytes of L1 data. */ l2_size = data->capabilities.cap.l2_cache ? VG_LITE_ALIGN(VG_LITE_ALIGN(l1_size / 32, 64) / 8, 64) : 0; /* Allocate the memory. */ error = vg_lite_hal_allocate_contiguous(buffer_size + l1_size + l2_size, &context->tessellation_buffer_logical, &context->tessellation_buffer_physical, &context->tessellation_buffer); if (error != VG_LITE_SUCCESS) { /* Free any allocated memory. */ vg_lite_kernel_terminate_t terminate = { context }; do_terminate(&terminate); /* Out of memory. */ return error; } /* Return the tessellation buffer pointers and GPU addresses. */ data->tessellation_buffer_gpu[0] = context->tessellation_buffer_physical; data->tessellation_buffer_gpu[1] = context->tessellation_buffer_physical + buffer_size; data->tessellation_buffer_gpu[2] = (l2_size ? data->tessellation_buffer_gpu[1] + l1_size : data->tessellation_buffer_gpu[1]); data->tessellation_buffer_logic[0] = (uint8_t *)context->tessellation_buffer_logical; data->tessellation_buffer_logic[1] = data->tessellation_buffer_logic[0] + buffer_size; data->tessellation_buffer_logic[2] = (l2_size ? data->tessellation_buffer_logic[1] + l1_size : data->tessellation_buffer_logic[1]); data->tessellation_buffer_size[0] = buffer_size; data->tessellation_buffer_size[1] = l1_size; data->tessellation_buffer_size[2] = l2_size; data->tessellation_stride = stride; data->tessellation_width_height = width | (height << 16); data->tessellation_shift = 0; } /* Enable all interrupts. */ vg_lite_hal_poke(VG_LITE_INTR_ENABLE, 0xFFFFFFFF); #if defined(__linux__) && !EMULATOR if (copy_to_user(context_usr, context, sizeof(vg_lite_kernel_context_t)) != 0) { // Free any allocated memory. vg_lite_kernel_terminate_t terminate = { context }; do_terminate(&terminate); return VG_LITE_NO_CONTEXT; } #endif return error; } #else static vg_lite_error_t init_vglite(vg_lite_kernel_initialize_t * data) { vg_lite_error_t error = VG_LITE_SUCCESS; vg_lite_kernel_context_t * context; uint32_t id; int i; uint32_t chip_id = 0; uint32_t semaphore_id = 0; #if defined(__linux__) && !EMULATOR vg_lite_kernel_context_t __user * context_usr; vg_lite_kernel_context_t mycontext = { 0 }; // Construct the context. context_usr = (vg_lite_kernel_context_t __user *) data->context; #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) if (!access_ok(VERIFY_READ, context_usr, sizeof(*context_usr)) || !access_ok(VERIFY_WRITE, context_usr, sizeof(*context_usr))) { #else if (!access_ok(context_usr, sizeof(*context_usr)) || !access_ok(context_usr, sizeof(*context_usr))) { #endif /* Out of memory. */ return VG_LITE_OUT_OF_MEMORY; } context = &mycontext; #else // Construct the context. context = data->context; if (context == NULL) { /* Out of memory. */ return VG_LITE_OUT_OF_MEMORY; } #endif /* Zero out all pointers. */ for (i = 0; i < CMDBUF_COUNT; i++){ context->command_buffer[i] = NULL; context->command_buffer_logical[i] = NULL; context->command_buffer_physical[i] = 0; } context->tessellation_buffer = NULL; context->tessellation_buffer_logical = NULL; context->tessellation_buffer_physical = 0; /* Increment reference counter. */ if (s_reference++ == 0) { /* Initialize the SOC. */ error = vg_lite_hal_initialize(); if(error != VG_LITE_SUCCESS) { s_reference--; vg_lite_hal_free_os_heap(); vg_lite_hal_deinitialize(); return error; } /* Enable the GPU. */ gpu(1); } else { while(!task_num) { vg_lite_hal_delay(5); } } if((error = (vg_lite_error_t)VG_LITE_OS_LOCK()) == VG_LITE_SUCCESS){ ++task_num; for(semaphore_id = 0; semaphore_id < THREAD_LENGTH ; semaphore_id++) { if (vg_lite_os_init_event(&context->async_event[0], semaphore_id, VG_LITE_IDLE) == VG_LITE_SUCCESS) { for (i = 1; i < CMDBUF_COUNT; i++) vg_lite_os_config_event(&context->async_event[i], semaphore_id, VG_LITE_IDLE); break; } } VG_LITE_OS_UNLOCK(); } else return error; if(semaphore_id == THREAD_LENGTH) return VG_LITE_MULTI_THREAD_FAIL; /* Fill in hardware capabilities. */ data->capabilities.data = 0; id = vg_lite_hal_peek(VG_LITE_HW_CHIP_ID); if (id >= 0x300) { data->capabilities.cap.l2_cache = 1; } /* Allocate the command buffer. */ if (data->command_buffer_size) { int32_t i; for (i = 0; i < CMDBUF_COUNT; i ++) { /* Allocate the memory. */ VG_LITE_OS_LOCK(); error = vg_lite_hal_allocate_contiguous(data->command_buffer_size, &context->command_buffer_logical[i], &context->command_buffer_physical[i], &context->command_buffer[i]); VG_LITE_OS_UNLOCK(); if (error != VG_LITE_SUCCESS) { /* Free any allocated memory. */ vg_lite_kernel_terminate_t terminate = { context }; do_terminate(&terminate); /* Out of memory. */ return error; } /* Return command buffer logical pointer and GPU address. */ data->command_buffer[i] = context->command_buffer_logical[i]; data->command_buffer_gpu[i] = context->command_buffer_physical[i]; } } /* Allocate the context buffer. */ if (data->context_buffer_size) { int32_t i; for (i = 0; i < CMDBUF_COUNT; i ++) { /* Allocate the memory. */ VG_LITE_OS_LOCK(); error = vg_lite_hal_allocate_contiguous(data->context_buffer_size, &context->context_buffer_logical[i], &context->context_buffer_physical[i], &context->context_buffer[i]); VG_LITE_OS_UNLOCK(); if (error != VG_LITE_SUCCESS) { /* Free any allocated memory. */ vg_lite_kernel_terminate_t terminate = { context }; do_terminate(&terminate); /* Out of memory. */ return error; } /* Return context buffer logical pointer and GPU address. */ data->context_buffer[i] = context->context_buffer_logical[i]; data->context_buffer_gpu[i] = context->context_buffer_physical[i]; } } /* Allocate the tessellation buffer. */ if ((data->tessellation_width > 0) && (data->tessellation_height > 0)) { int width = data->tessellation_width; int height = 0; height = VG_LITE_ALIGN(data->tessellation_height, 16); chip_id = vg_lite_hal_peek(0x20); if(chip_id == GPU_CHIP_ID_GC355) width = VG_LITE_ALIGN(width, 128); /* Check if we can used tiled tessellation (128x16). */ if (((width & 127) == 0) && ((height & 15) == 0)) { data->capabilities.cap.tiled = 0x3; } else { data->capabilities.cap.tiled = 0x2; } if(ts_init++ == 0) { unsigned long stride, buffer_size, l1_size, l2_size; /* Compute tessellation buffer size. */ stride = VG_LITE_ALIGN(width * 8, 64); buffer_size = VG_LITE_ALIGN(stride * height, 64); /* Each bit in the L1 cache represents 64 bytes of tessellation data. */ l1_size = VG_LITE_ALIGN(VG_LITE_ALIGN(buffer_size / 64, 64) / 8, 64); /* Each bit in the L2 cache represents 32 bytes of L1 data. */ l2_size = data->capabilities.cap.l2_cache ? VG_LITE_ALIGN(VG_LITE_ALIGN(l1_size / 32, 64) / 8, 64) : 0; /* Allocate the memory. */ VG_LITE_OS_LOCK(); error = vg_lite_hal_allocate_contiguous(buffer_size + l1_size + l2_size, &context->tessellation_buffer_logical, &context->tessellation_buffer_physical, &context->tessellation_buffer); VG_LITE_OS_UNLOCK(); if (error != VG_LITE_SUCCESS) { /* Free any allocated memory. */ vg_lite_kernel_terminate_t terminate = { context }; do_terminate(&terminate); /* Out of memory. */ return error; } /* Return the tessellation buffer pointers and GPU addresses. */ ts_initialize.tessellation_buffer_gpu[0] = context->tessellation_buffer_physical; ts_initialize.tessellation_buffer_gpu[1] = context->tessellation_buffer_physical + buffer_size; ts_initialize.tessellation_buffer_gpu[2] = (l2_size ? ts_initialize.tessellation_buffer_gpu[1] + l1_size : ts_initialize.tessellation_buffer_gpu[1]); ts_initialize.tessellation_buffer_logic[0] = (uint8_t *)context->tessellation_buffer_logical; ts_initialize.tessellation_buffer_logic[1] = ts_initialize.tessellation_buffer_logic[0] + buffer_size; ts_initialize.tessellation_buffer_logic[2] = (l2_size ? ts_initialize.tessellation_buffer_logic[1] + l1_size : ts_initialize.tessellation_buffer_logic[1]); ts_initialize.tessellation_buffer_size[0] = buffer_size; ts_initialize.tessellation_buffer_size[1] = l1_size; ts_initialize.tessellation_buffer_size[2] = l2_size; ts_initialize.tessellation_stride = stride; ts_initialize.tessellation_width_height = width | (height << 16); ts_initialize.tessellation_shift = 0; } data->tessellation_buffer_gpu[0] = ts_initialize.tessellation_buffer_gpu[0]; data->tessellation_buffer_gpu[1] = ts_initialize.tessellation_buffer_gpu[1]; data->tessellation_buffer_gpu[2] = ts_initialize.tessellation_buffer_gpu[2]; data->tessellation_buffer_logic[0] = ts_initialize.tessellation_buffer_logic[0]; data->tessellation_buffer_logic[1] = ts_initialize.tessellation_buffer_logic[1]; data->tessellation_buffer_logic[2] = ts_initialize.tessellation_buffer_logic[2]; data->tessellation_buffer_size[0] = ts_initialize.tessellation_buffer_size[0]; data->tessellation_buffer_size[1] = ts_initialize.tessellation_buffer_size[1]; data->tessellation_buffer_size[2] = ts_initialize.tessellation_buffer_size[2]; data->tessellation_stride = ts_initialize.tessellation_stride; data->tessellation_width_height = ts_initialize.tessellation_width_height; data->tessellation_shift = ts_initialize.tessellation_shift; } if(task_num == 1) /* Enable all interrupts. */ vg_lite_hal_poke(VG_LITE_INTR_ENABLE, 0xFFFFFFFF); #if defined(__linux__) && !EMULATOR if (copy_to_user(context_usr, context, sizeof(vg_lite_kernel_context_t)) != 0) { // Free any allocated memory. vg_lite_kernel_terminate_t terminate = { context }; do_terminate(&terminate); return VG_LITE_NO_CONTEXT; } #endif return error; } #endif /* VG_DRIVER_SINGLE_THREAD */ static vg_lite_error_t do_initialize(vg_lite_kernel_initialize_t * data) { vg_lite_error_t error = VG_LITE_SUCCESS; /* Free any allocated memory for the context. */ do { error = init_vglite(data); if (error != VG_LITE_SUCCESS) break; error = init_3rd(data); if (error != VG_LITE_SUCCESS) break; } while (0); return error; } #if defined(VG_DRIVER_SINGLE_THREAD) static vg_lite_error_t terminate_vglite(vg_lite_kernel_terminate_t * data) { vg_lite_kernel_context_t *context = NULL; #if defined(__linux__) && !EMULATOR vg_lite_kernel_context_t mycontext = {0}; if (copy_from_user(&mycontext, data->context, sizeof(vg_lite_kernel_context_t)) != 0) { return VG_LITE_NO_CONTEXT; } context = &mycontext; #else context = data->context; #endif /* Free any allocated memory for the context. */ if (context->command_buffer[0]) { /* Free the command buffer. */ vg_lite_hal_free_contiguous(context->command_buffer[0]); context->command_buffer[0] = NULL; } if (context->command_buffer[1]) { /* Free the command buffer. */ vg_lite_hal_free_contiguous(context->command_buffer[1]); context->command_buffer[1] = NULL; } if (context->tessellation_buffer) { /* Free the tessellation buffer. */ vg_lite_hal_free_contiguous(context->tessellation_buffer); context->tessellation_buffer = NULL; } vg_lite_hal_free_os_heap(); /* Decrement reference counter. */ if (--s_reference == 0) { /* Disable the GPU. */ gpu(0); /* De-initialize the SOC. */ vg_lite_hal_deinitialize(); } #if defined(__linux__) && !EMULATOR if (copy_to_user((vg_lite_kernel_context_t __user *) data->context, &mycontext, sizeof(vg_lite_kernel_context_t)) != 0) { return VG_LITE_NO_CONTEXT; } #endif return VG_LITE_SUCCESS; } #else static vg_lite_error_t terminate_vglite(vg_lite_kernel_terminate_t * data) { vg_lite_kernel_context_t *context = NULL; vg_lite_error_t error = VG_LITE_SUCCESS; int32_t i; #if defined(__linux__) && !EMULATOR vg_lite_kernel_context_t mycontext = {0}; if (copy_from_user(&mycontext, data->context, sizeof(vg_lite_kernel_context_t)) != 0) { return VG_LITE_NO_CONTEXT; } context = &mycontext; #else context = data->context; #endif /* Free any allocated memory for the context. */ if (context->command_buffer[0]) { /* Free the command buffer. */ vg_lite_hal_free_contiguous(context->command_buffer[0]); context->command_buffer[0] = NULL; } if (context->command_buffer[1]) { /* Free the command buffer. */ vg_lite_hal_free_contiguous(context->command_buffer[1]); context->command_buffer[1] = NULL; } if (context->context_buffer[0]) { /* Free the context buffer. */ vg_lite_hal_free_contiguous(context->context_buffer[0]); context->context_buffer[0] = NULL; } if (context->context_buffer[1]) { /* Free the context buffer. */ vg_lite_hal_free_contiguous(context->context_buffer[1]); context->context_buffer[1] = NULL; } if((error = (vg_lite_error_t)VG_LITE_OS_LOCK()) == VG_LITE_SUCCESS){ --task_num; --s_reference; VG_LITE_OS_UNLOCK(); } else return error; /* Delete all async events associated to command buffers */ for (i = 0; i < CMDBUF_COUNT; i++) vg_lite_os_delete_event(&context->async_event[i]); if(task_num == 0){ if (context->tessellation_buffer) { /* Free the tessellation buffer. */ vg_lite_hal_free_contiguous(context->tessellation_buffer); context->tessellation_buffer = NULL; } ts_init = 0; /* Disable the GPU. */ gpu(0); vg_lite_hal_free_os_heap(); /* De-initialize the SOC. */ vg_lite_hal_deinitialize(); } #if defined(__linux__) && !EMULATOR if (copy_to_user((vg_lite_kernel_context_t __user *) data->context, &mycontext, sizeof(vg_lite_kernel_context_t)) != 0) { return VG_LITE_NO_CONTEXT; } #endif return VG_LITE_SUCCESS; } #endif /* VG_DRIVER_SINGLE_THREAD */ static vg_lite_error_t terminate_3rd(vg_lite_kernel_terminate_t * data) { /* TODO: Terminate the converters. */ return VG_LITE_SUCCESS; } static vg_lite_error_t do_terminate(vg_lite_kernel_terminate_t * data) { terminate_vglite(data); terminate_3rd(data); return VG_LITE_SUCCESS; } static vg_lite_error_t do_allocate(vg_lite_kernel_allocate_t * data) { vg_lite_error_t error; if((error = (vg_lite_error_t)VG_LITE_OS_LOCK()) == VG_LITE_SUCCESS) { error = vg_lite_hal_allocate_contiguous(data->bytes, &data->memory, &data->memory_gpu, &data->memory_handle); VG_LITE_OS_UNLOCK(); } return error; } static vg_lite_error_t do_free(vg_lite_kernel_free_t * data) { vg_lite_hal_free_contiguous(data->memory_handle); return VG_LITE_SUCCESS; } #if defined(VG_DRIVER_SINGLE_THREAD) static vg_lite_error_t do_submit(vg_lite_kernel_submit_t * data) { uint32_t offset; vg_lite_kernel_context_t *context = NULL; uint32_t physical = data->context->command_buffer_physical[data->command_id]; #if defined(__linux__) && !EMULATOR vg_lite_kernel_context_t mycontext = { 0 }; if (copy_from_user(&mycontext, data->context, sizeof(vg_lite_kernel_context_t)) != 0) { return VG_LITE_NO_CONTEXT; } context = &mycontext; physical = context->command_buffer_physical[data->command_id]; #else context = data->context; if (context == NULL) { return VG_LITE_NO_CONTEXT; } #endif /* Perform a memory barrier. */ vg_lite_hal_barrier(); offset = (uint8_t *) data->commands - (uint8_t *)context->command_buffer_logical[data->command_id]; #if defined(PRINT_COMMAND_BUFFER) int i = 0; for(i=0;i < (peek_queue->cmd_size + 3) / 4; i++) { if(i % 4 == 0) printf("\r\n"); printf("0x%08x ",((uint32_t*)(peek_queue->cmd_physical + peek_queue->cmd_offset))[i]); } #endif /* Write the registers to kick off the command execution (CMDBUF_SIZE). */ vg_lite_hal_poke(VG_LITE_HW_CMDBUF_ADDRESS, physical + offset); vg_lite_hal_poke(VG_LITE_HW_CMDBUF_SIZE, (data->command_size + 7) / 8); return VG_LITE_SUCCESS; } static vg_lite_error_t do_wait(vg_lite_kernel_wait_t * data) { /* Wait for interrupt. */ if (!vg_lite_hal_wait_interrupt(data->timeout_ms, data->event_mask, &data->event_got)) { /* Timeout. */ #if defined(PRINT_DEBUG_REGISTER) unsigned int debug; unsigned int iter; for(iter =0; iter < 16 ; iter ++) { vg_lite_hal_poke(0x470, iter); debug = vg_lite_hal_peek(0x450); printf("0x450[%d] = 0x%x\n", iter,debug); } for(iter =0; iter < 16 ; iter ++) { vg_lite_hal_poke(0x470, iter <<16); debug = vg_lite_hal_peek(0x454); printf("0x454[%d] = 0x%x\n", iter,debug); } for(iter =0; iter < 16 ; iter ++) { vg_lite_hal_poke(0x478, iter); debug = vg_lite_hal_peek(0x468); printf("0x468[%d] = 0x%x\n", iter,debug); } for(iter =0; iter < 16 ; iter ++) { vg_lite_hal_poke(0x478, iter); debug = vg_lite_hal_peek(0x46C); printf("0x46C[%d] = 0x%x\n", iter,debug); } #endif return VG_LITE_TIMEOUT; } return VG_LITE_SUCCESS; } #else static vg_lite_error_t do_submit(vg_lite_kernel_submit_t * data) { vg_lite_error_t error; uint32_t offset; vg_lite_kernel_context_t *context = NULL; uint32_t physical; #if defined(__linux__) && !EMULATOR vg_lite_kernel_context_t mycontext = { 0 }; if (copy_from_user(&mycontext, data->context, sizeof(vg_lite_kernel_context_t)) != 0) { return VG_LITE_NO_CONTEXT; } context = &mycontext; physical = context->command_buffer_physical[data->command_id]; #else context = data->context; if (context == NULL) { return VG_LITE_NO_CONTEXT; } #endif /* Perform a memory barrier. */ vg_lite_hal_barrier(); physical = data->context->command_buffer_physical[data->command_id]; offset = (uint8_t *) data->commands - (uint8_t *)context->command_buffer_logical[data->command_id]; /* Send the current command buffer to the command queue. */ error = vg_lite_hal_submit((uint32_t)context, physical, offset, data->command_size, &data->context->async_event[data->command_id]); if(error != VG_LITE_SUCCESS) return error; return VG_LITE_SUCCESS; } static vg_lite_error_t do_wait(vg_lite_kernel_wait_t * data) { vg_lite_error_t error; /* Wait for the signal of current command buffer to 1. */ error = vg_lite_hal_wait(data->timeout_ms, &data->context->async_event[data->command_id]); return error; } #endif /* VG_DRIVER_SINGLE_THREAD */ static vg_lite_error_t do_reset(void) { /* Disable and enable the GPU. */ gpu(1); vg_lite_hal_poke(VG_LITE_INTR_ENABLE, 0xFFFFFFFF); return VG_LITE_SUCCESS; } static vg_lite_error_t do_debug(void) { return VG_LITE_SUCCESS; } static vg_lite_error_t do_map(vg_lite_kernel_map_t * data) { data->memory_handle = vg_lite_hal_map(data->bytes, data->logical, data->physical, &data->memory_gpu); if (data->memory_handle == NULL) { return VG_LITE_OUT_OF_RESOURCES; } return VG_LITE_SUCCESS; } static vg_lite_error_t do_unmap(vg_lite_kernel_unmap_t * data) { vg_lite_hal_unmap(data->memory_handle); return VG_LITE_SUCCESS; } static vg_lite_error_t do_peek(vg_lite_kernel_info_t * data) { data->reg = vg_lite_hal_peek(data->addr); return VG_LITE_SUCCESS; } static vg_lite_error_t do_query_mem(vg_lite_kernel_mem_t * data) { vg_lite_error_t error = VG_LITE_SUCCESS; error = vg_lite_hal_query_mem(data); return error; } #if !defined(VG_DRIVER_SINGLE_THREAD) static vg_lite_error_t do_query_context_switch(vg_lite_kernel_context_switch_t * data) { data->isContextSwitched = vg_lite_os_query_context_switch(data->context); return VG_LITE_SUCCESS; } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ static void soft_reset(void) { vg_lite_hw_clock_control_t value; value.data = vg_lite_hal_peek(VG_LITE_HW_CLOCK_CONTROL); /* Perform a soft reset. */ value.control.isolate = 1; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); value.control.soft_reset = 1; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); vg_lite_hal_delay(5); value.control.soft_reset = 0; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); value.control.isolate = 0; vg_lite_hal_poke(VG_LITE_HW_CLOCK_CONTROL, value.data); } #if !defined(VG_DRIVER_SINGLE_THREAD) static vg_lite_error_t do_mutex_lock() { return (vg_lite_error_t)VG_LITE_OS_LOCK(); } static vg_lite_error_t do_mutex_unlock() { return (vg_lite_error_t)VG_LITE_OS_UNLOCK(); } #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ vg_lite_error_t vg_lite_kernel(vg_lite_kernel_command_t command, void * data) { /* Dispatch on command. */ switch (command) { case VG_LITE_INITIALIZE: /* Initialize the context. */ return do_initialize(data); case VG_LITE_TERMINATE: /* Terminate the context. */ return do_terminate(data); case VG_LITE_ALLOCATE: /* Allocate contiguous memory. */ return do_allocate(data); case VG_LITE_FREE: /* Free contiguous memory. */ return do_free(data); case VG_LITE_SUBMIT: /* Submit a command buffer. */ return do_submit(data); case VG_LITE_WAIT: /* Wait for the GPU. */ return do_wait(data); case VG_LITE_RESET: /* Reset the GPU. */ return do_reset(); case VG_LITE_DEBUG: /* Perform debugging features. */ return do_debug(); case VG_LITE_MAP: /* Map some memory. */ return do_map(data); case VG_LITE_UNMAP: /* Unmap some memory. */ return do_unmap(data); /* Get register info. */ case VG_LITE_CHECK: /* Get register value. */ return do_peek(data); case VG_LITE_QUERY_MEM: return do_query_mem(data); #if !defined(VG_DRIVER_SINGLE_THREAD) case VG_LITE_LOCK: /* Mutex lock */ return do_mutex_lock(); case VG_LITE_UNLOCK: /* Mutex unlock */ return do_mutex_unlock(); case VG_LITE_QUERY_CONTEXT_SWITCH: /* query context switch */ return do_query_context_switch(data); #endif /* not defined(VG_DRIVER_SINGLE_THREAD) */ default: break; } /* Invalid command. */ return VG_LITE_INVALID_ARGUMENT; }