/* * Copyright (c) 2011 Intel Corporation. All Rights Reserved. * * 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, sub license, 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 (including the * next paragraph) 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 NON-INFRINGEMENT. * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. * * Authors: * Shengquan Yuan * Forrest Zhang * */ #include "psb_buffer.h" #include #include #include #include #include "psb_drm.h" #include "psb_def.h" static VAStatus psb_buffer_offset_camerav4l2(psb_driver_data_p driver_data, psb_buffer_p buf, unsigned int v4l2_buf_offset, unsigned int *bo_offset ) { *bo_offset = v4l2_buf_offset; return VA_STATUS_SUCCESS; } static VAStatus psb_buffer_offset_cameraci(psb_driver_data_p driver_data, psb_buffer_p buf, unsigned int ci_frame_offset_or_handle, unsigned int *bo_offset ) { *bo_offset = ci_frame_offset_or_handle; return VA_STATUS_SUCCESS; } static int psb_buffer_info_ci(psb_driver_data_p driver_data) { struct drm_lnc_video_getparam_arg arg; unsigned long camera_info[2] = {0, 0}; int ret = 0; driver_data->camera_phyaddr = driver_data->camera_size = 0; arg.key = LNC_VIDEO_GETPARAM_CI_INFO; arg.value = (uint64_t)((unsigned long) & camera_info[0]); ret = drmCommandWriteRead(driver_data->drm_fd, driver_data->getParamIoctlOffset, &arg, sizeof(arg)); if (ret == 0) { driver_data->camera_phyaddr = camera_info[0]; driver_data->camera_size = camera_info[1]; psb__information_message("CI region physical address = 0x%08x, size=%dK\n", driver_data->camera_phyaddr, driver_data->camera_size / 1024); return ret; } psb__information_message("CI region get_info failed\n"); return ret; } /* * Allocate global BO which maps camear device memory as encode MMU memory * the global BO shared by several encode surfaces created from camear memory */ static VAStatus psb_buffer_init_camera(psb_driver_data_p driver_data) { int ret = 0; /* hasn't grab camera device memory region * grab the whole 4M camera device memory */ driver_data->camera_bo = calloc(1, sizeof(struct psb_buffer_s)); if (driver_data->camera_bo == NULL) return VA_STATUS_ERROR_ALLOCATION_FAILED; psb__information_message("Grab whole camera device memory\n"); ret = psb_buffer_create(driver_data, driver_data->camera_size, psb_bt_camera, (psb_buffer_p) driver_data->camera_bo); if (ret != VA_STATUS_SUCCESS) { free(driver_data->camera_bo); driver_data->camera_bo = NULL; psb__error_message("Grab camera device memory failed\n"); } return ret; } /* * Create one buffer from camera device memory * is_v4l2 means if the buffer is V4L2 buffer * id_or_ofs is CI frame ID (actually now is frame offset), or V4L2 buffer offset */ VAStatus psb_buffer_create_camera(psb_driver_data_p driver_data, psb_buffer_p buf, int is_v4l2, int id_or_ofs ) { VAStatus vaStatus; int ret = 0; unsigned int camera_offset = 0; if (driver_data->camera_bo == NULL) { if (psb_buffer_info_ci(driver_data)) { psb__error_message("Can't get CI region information\n"); return VA_STATUS_ERROR_UNKNOWN; } vaStatus = psb_buffer_init_camera(driver_data); if (vaStatus != VA_STATUS_SUCCESS) { psb__error_message("Grab camera device memory failed\n"); return ret; } } /* reference the global camear BO */ ret = psb_buffer_reference(driver_data, buf, (psb_buffer_p) driver_data->camera_bo); if (ret != VA_STATUS_SUCCESS) { psb__error_message("Reference camera device memory failed\n"); return ret; } if (is_v4l2) ret = psb_buffer_offset_camerav4l2(driver_data, buf, id_or_ofs, &camera_offset); else ret = psb_buffer_offset_cameraci(driver_data, buf, id_or_ofs, &camera_offset); buf->buffer_ofs = camera_offset; return ret; } /* * Create one buffer from user buffer * id_or_ofs is CI frame ID (actually now is frame offset), or V4L2 buffer offset * user_ptr :virtual address of user buffer start. */ VAStatus psb_buffer_create_camera_from_ub(psb_driver_data_p driver_data, psb_buffer_p buf, int id_or_ofs, int size, const unsigned long * user_ptr) { VAStatus vaStatus = VA_STATUS_SUCCESS; int allignment; uint32_t placement; int ret; buf->rar_handle = 0; buf->buffer_ofs = 0; buf->type = psb_bt_user_buffer; buf->user_ptr = (unsigned char *)user_ptr; buf->driver_data = driver_data; allignment = 4096; placement = DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_TT | WSBM_PL_FLAG_CACHED | WSBM_PL_FLAG_SHARED ; ret = LOCK_HARDWARE(driver_data); if (ret) { UNLOCK_HARDWARE(driver_data); vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED; DEBUG_FAILURE_RET; return vaStatus; } ret = wsbmGenBuffers(driver_data->main_pool, 1, &buf->drm_buf, allignment, placement); if (!buf->drm_buf) { psb__error_message("failed to gen wsbm buffers\n"); UNLOCK_HARDWARE(driver_data); return VA_STATUS_ERROR_ALLOCATION_FAILED; } #ifndef ANDROID extern int wsbmBODataUB(struct _WsbmBufferObject * buf, unsigned size, const unsigned char * data, struct _WsbmBufferPool * newPool, uint32_t placement, const unsigned long * user_ptr); /* here use the placement when gen buffer setted */ ret = wsbmBODataUB(buf->drm_buf, size, NULL, NULL, 0, user_ptr); UNLOCK_HARDWARE(driver_data); if (ret) { psb__error_message("failed to alloc wsbm buffers\n"); return VA_STATUS_ERROR_ALLOCATION_FAILED; } psb__information_message("Create BO from user buffer 0x%08x (%d byte),BO GPU offset hint=0x%08x\n", user_ptr, size, wsbmBOOffsetHint(buf->drm_buf)); #endif buf->pl_flags = placement; buf->status = psb_bs_ready; buf->wsbm_synccpu_flag = 0; return VA_STATUS_SUCCESS; } static int psb_buffer_info_rar(psb_driver_data_p driver_data) { struct drm_lnc_video_getparam_arg arg; unsigned long rar_info[2] = {0, 0}; int ret = 0; driver_data->rar_phyaddr = driver_data->rar_size = 0; arg.key = LNC_VIDEO_GETPARAM_RAR_INFO; arg.value = (uint64_t)((unsigned long) & rar_info[0]); ret = drmCommandWriteRead(driver_data->drm_fd, driver_data->getParamIoctlOffset, &arg, sizeof(arg)); if (ret == 0) { driver_data->rar_phyaddr = rar_info[0]; driver_data->rar_size = rar_info[1]; driver_data->rar_size = driver_data->rar_size & 0xfffff000; /* page align */ psb__information_message("RAR region physical address = 0x%08x, size=%dK\n", driver_data->rar_phyaddr, driver_data->rar_size / 1024); return ret; } psb__information_message("RAR region get size failed\n"); return ret; } static VAStatus psb_buffer_init_imr(psb_driver_data_p driver_data) { int ret = 0; /* hasn't grab IMR device memory region * grab the whole IMR3 device memory */ driver_data->rar_bo = calloc(1, sizeof(struct psb_buffer_s)); if (driver_data->rar_bo == NULL) goto exit_error; psb__information_message("Init IMR device\n"); if (psb_buffer_info_rar(driver_data)) { psb__error_message("Get IMR region size failed\n"); goto exit_error; } psb__information_message("Grab whole camera device memory\n"); ret = psb_buffer_create(driver_data, driver_data->rar_size, psb_bt_rar, (psb_buffer_p) driver_data->rar_bo); if (ret != VA_STATUS_SUCCESS) { psb__error_message("Grab IMR device memory failed\n"); goto exit_error; } return VA_STATUS_SUCCESS; exit_error: if (driver_data->rar_bo) free(driver_data->rar_bo); driver_data->rar_bo = NULL; return VA_STATUS_ERROR_ALLOCATION_FAILED; } /* * Reference one IMR buffer from offset * only used to reference a slice IMR buffer which is created outside of video driver */ VAStatus psb_buffer_reference_imr(psb_driver_data_p driver_data, uint32_t imr_offset, psb_buffer_p buf ) { VAStatus vaStatus; int ret; if (driver_data->rar_bo == NULL) { vaStatus = psb_buffer_init_imr(driver_data); if (vaStatus != VA_STATUS_SUCCESS) { psb__error_message("IMR init failed!\n"); return vaStatus; } } /* don't need to assign the offset to buffer * so that when destroy the buffer, we just * need to unreference */ /* buf->imr_offset = imr_offset; */ /* reference the global IMR BO */ ret = psb_buffer_reference(driver_data, buf, (psb_buffer_p) driver_data->rar_bo); if (ret != VA_STATUS_SUCCESS) { psb__error_message("Reference IMR device memory failed\n"); return ret; } buf->rar_handle = imr_offset; buf->buffer_ofs = imr_offset; /* reference the global IMR buffer, reset buffer type */ buf->type = psb_bt_rar_slice; /* don't need to IMR_release */ psb__information_message("Reference IMR buffer, IMR region offset =0x%08x, IMR BO GPU offset hint=0x%08x\n", imr_offset, wsbmBOOffsetHint(buf->drm_buf)); return VA_STATUS_SUCCESS; }