text: /*
   * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
   * Copyright (c) Imagination Technologies Limited, UK
   *
   * 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:
   *    Waldo Bastian <waldo.bastian@intel.com>
   *
   */
  
  #include <wsbm_manager.h>
  
  #include "psb_def.h"
  #include "psb_surface.h"
  #include "psb_drv_debug.h"
  
  /*
   * Create surface
   */
  VAStatus psb_surface_create(psb_driver_data_p driver_data,
                              int width, int height, int fourcc, unsigned int flags,
                              psb_surface_p psb_surface /* out */
                             )
  {
      int ret = 0;
      int buffer_type = psb_bt_surface;
  
  #ifndef BAYTRAIL
      if ((flags & IS_ROTATED) || (driver_data->render_mode & VA_RENDER_MODE_LOCAL_OVERLAY))
          buffer_type = psb_bt_surface_tt;
  #endif
  
  #ifdef PSBVIDEO_MSVDX_DEC_TILING
      int tiling = GET_SURFACE_INFO_tiling(psb_surface);
      if (tiling)
          buffer_type = psb_bt_surface_tiling;
  #endif
  
      if (fourcc == VA_FOURCC_NV12) {
          if ((width <= 0) || (width * height > 5120 * 5120) || (height <= 0)) {
              return VA_STATUS_ERROR_ALLOCATION_FAILED;
          }
  
          if (0) {
              ;
          } else if (512 >= width) {
              psb_surface->stride_mode = STRIDE_512;
              psb_surface->stride = 512;
          } else if (1024 >= width) {
              psb_surface->stride_mode = STRIDE_1024;
              psb_surface->stride = 1024;
          } else if (1280 >= width) {
              psb_surface->stride_mode = STRIDE_1280;
              psb_surface->stride = 1280;
  #ifdef PSBVIDEO_MSVDX_DEC_TILING
              if (tiling) {
                  psb_surface->stride_mode = STRIDE_2048;
                  psb_surface->stride = 2048;
              }
  #endif
          } else if (2048 >= width) {
              psb_surface->stride_mode = STRIDE_2048;
              psb_surface->stride = 2048;
          } else if (4096 >= width) {
              psb_surface->stride_mode = STRIDE_4096;
              psb_surface->stride = 4096;
          } else {
              psb_surface->stride_mode = STRIDE_NA;
              psb_surface->stride = (width + 0x3f) & ~0x3f;
          }
  
          psb_surface->luma_offset = 0;
          psb_surface->chroma_offset = psb_surface->stride * height;
          psb_surface->size = (psb_surface->stride * height * 3) / 2;
          psb_surface->extra_info[4] = VA_FOURCC_NV12;
      } else if (fourcc == VA_FOURCC_RGBA) {
          unsigned int pitchAlignMask = 63;
          psb_surface->stride_mode = STRIDE_NA;
          psb_surface->stride = (width * 4 + pitchAlignMask) & ~pitchAlignMask;;
          psb_surface->luma_offset = 0;
          psb_surface->chroma_offset = 0;
          psb_surface->size = psb_surface->stride * height;
          psb_surface->extra_info[4] = VA_FOURCC_RGBA;
      } else if (fourcc == VA_FOURCC_YV16) {
          if ((width <= 0) || (width * height > 5120 * 5120) || (height <= 0)) {
              return VA_STATUS_ERROR_ALLOCATION_FAILED;
          }
  
          if (0) {
              ;
          } else if (512 >= width) {
              psb_surface->stride_mode = STRIDE_512;
              psb_surface->stride = 512;
          } else if (1024 >= width) {
              psb_surface->stride_mode = STRIDE_1024;
              psb_surface->stride = 1024;
          } else if (1280 >= width) {
              psb_surface->stride_mode = STRIDE_1280;
              psb_surface->stride = 1280;
  #ifdef PSBVIDEO_MSVDX_DEC_TILING
              if (tiling) {
                  psb_surface->stride_mode = STRIDE_2048;
                  psb_surface->stride = 2048;
              }
  #endif
          } else if (2048 >= width) {
              psb_surface->stride_mode = STRIDE_2048;
              psb_surface->stride = 2048;
          } else if (4096 >= width) {
              psb_surface->stride_mode = STRIDE_4096;
              psb_surface->stride = 4096;
          } else {
              psb_surface->stride_mode = STRIDE_NA;
              psb_surface->stride = (width + 0x3f) & ~0x3f;
          }
  
          psb_surface->luma_offset = 0;
          psb_surface->chroma_offset = psb_surface->stride * height;
          psb_surface->size = psb_surface->stride * height * 2;
          psb_surface->extra_info[4] = VA_FOURCC_YV16;
      } else if (fourcc == VA_FOURCC_YV32) {
          psb_surface->stride_mode = STRIDE_NA;
          psb_surface->stride = (width + 0x3f) & ~0x3f; /*round up to 16 */
          psb_surface->luma_offset = 0;
          psb_surface->chroma_offset = psb_surface->stride * height;
          psb_surface->size = psb_surface->stride * height * 4;
          psb_surface->extra_info[4] = VA_FOURCC_YV32;
      }
  
      if (flags & IS_PROTECTED)
          SET_SURFACE_INFO_protect(psb_surface, 1);
  
      ret = psb_buffer_create(driver_data, psb_surface->size, buffer_type, &psb_surface->buf);
  
      return ret ? VA_STATUS_ERROR_ALLOCATION_FAILED : VA_STATUS_SUCCESS;
  }
  
  
  
  VAStatus psb_surface_create_for_userptr(
      psb_driver_data_p driver_data,
      int width, int height,
      unsigned size, /* total buffer size need to be allocated */
      unsigned int __maybe_unused fourcc, /* expected fourcc */
      unsigned int luma_stride, /* luma stride, could be width aligned with a special value */
      unsigned int __maybe_unused chroma_u_stride, /* chroma stride */
      unsigned int __maybe_unused chroma_v_stride,
      unsigned int luma_offset, /* could be 0 */
      unsigned int chroma_u_offset, /* UV offset from the beginning of the memory */
      unsigned int __maybe_unused chroma_v_offset,
      psb_surface_p psb_surface /* out */
  )
  {
      int ret;
  
      if ((width <= 0) || (width > 5120) || (height <= 0) || (height > 5120))
          return VA_STATUS_ERROR_ALLOCATION_FAILED;
  
      psb_surface->stride_mode = STRIDE_NA;
      psb_surface->stride = luma_stride;
  
  
      psb_surface->luma_offset = luma_offset;
      psb_surface->chroma_offset = chroma_u_offset;
      psb_surface->size = size;
      psb_surface->extra_info[4] = VA_FOURCC_NV12;
      psb_surface->extra_info[8] = VA_FOURCC_NV12;
  
      ret = psb_buffer_create(driver_data, psb_surface->size, psb_bt_cpu_vpu_shared, &psb_surface->buf);
  
      return ret ? VA_STATUS_ERROR_ALLOCATION_FAILED : VA_STATUS_SUCCESS;
  }
  
  VAStatus psb_surface_create_from_kbuf(
      psb_driver_data_p driver_data,
      int width, int height,
      unsigned size, /* total buffer size need to be allocated */
      unsigned int __maybe_unused fourcc, /* expected fourcc */
      int __maybe_unused kbuf_handle,
      unsigned int luma_stride, /* luma stride, could be width aligned with a special value */
      unsigned int __maybe_unused chroma_u_stride, /* chroma stride */
      unsigned int __maybe_unused chroma_v_stride,
      unsigned int __maybe_unused luma_offset, /* could be 0 */
      unsigned int chroma_u_offset, /* UV offset from the beginning of the memory */
      unsigned int __maybe_unused chroma_v_offset,
      psb_surface_p psb_surface /* out */
  )
  {
      int ret;
  
      if ((width <= 0) || (width > 5120) || (height <= 0) || (height > 5120))
          return VA_STATUS_ERROR_ALLOCATION_FAILED;
  
      psb_surface->stride = luma_stride;
  
      if (0) {
          ;
      } else if (512 == luma_stride) {
          psb_surface->stride_mode = STRIDE_512;
      } else if (1024 == luma_stride) {
          psb_surface->stride_mode = STRIDE_1024;
      } else if (1280 == luma_stride) {
          psb_surface->stride_mode = STRIDE_1280;
      } else if (2048 == luma_stride) {
          psb_surface->stride_mode = STRIDE_2048;
      } else if (4096 == luma_stride) {
          psb_surface->stride_mode = STRIDE_4096;
      } else {
          psb_surface->stride_mode = STRIDE_NA;
      }
  
      psb_surface->luma_offset = luma_offset;
      psb_surface->chroma_offset = chroma_u_offset;
      psb_surface->size = size;
      psb_surface->extra_info[4] = VA_FOURCC_NV12;
      psb_surface->extra_info[8] = VA_FOURCC_NV12;
  
      ret = psb_kbuffer_reference(driver_data, &psb_surface->buf, kbuf_handle);
  
      return ret ? VA_STATUS_ERROR_ALLOCATION_FAILED : VA_STATUS_SUCCESS;
  }
  
  #if PSB_MFLD_DUMMY_CODE
  /* id_or_ofs: it is frame ID or frame offset in camear device memory
   *     for CI frame: it it always frame offset currently
   *     for v4l2 buf: it is offset used in V4L2 buffer mmap
   */
  VAStatus psb_surface_create_camera(psb_driver_data_p driver_data,
                                     int width, int height, int stride, int size,
                                     psb_surface_p psb_surface, /* out */
                                     int is_v4l2,
                                     unsigned int id_or_ofs
                                    )
  {
      int ret;
  
      if ((width <= 0) || (width > 4096) || (height <= 0) || (height > 4096)) {
          return VA_STATUS_ERROR_ALLOCATION_FAILED;
      }
  
      psb_surface->stride = stride;
      if ((width == 640) && (height == 360)) {
          drv_debug_msg(VIDEO_DEBUG_GENERAL, "CI Frame is 640x360, and allocated as 640x368,adjust chroma_offset\n");
          psb_surface->chroma_offset = psb_surface->stride * 368;
      } else
          psb_surface->chroma_offset = psb_surface->stride * height;
      psb_surface->size = (psb_surface->stride * height * 3) / 2;
  
      ret = psb_buffer_create_camera(driver_data, &psb_surface->buf,
                                     is_v4l2, id_or_ofs);
  
      if (ret != VA_STATUS_SUCCESS) {
          psb_surface_destroy(psb_surface);
  
          drv_debug_msg(VIDEO_DEBUG_ERROR, "Get surfae offset of camear device memory failed!\n");
          return ret;
      }
  
      return VA_STATUS_SUCCESS;
  }
  
  /* id_or_ofs: it is frame ID or frame offset in camear device memory
   *     for CI frame: it it always frame offset currently
   *     for v4l2 buf: it is offset used in V4L2 buffer mmap
   * user_ptr: virtual address of user buffer.
   */
  VAStatus psb_surface_create_camera_from_ub(psb_driver_data_p driver_data,
          int width, int height, int stride, int size,
          psb_surface_p psb_surface, /* out */
          int is_v4l2,
          unsigned int id_or_ofs,
          const unsigned long *user_ptr)
  {
      int ret;
  
      if ((width <= 0) || (width > 4096) || (height <= 0) || (height > 4096)) {
          return VA_STATUS_ERROR_ALLOCATION_FAILED;
      }
  
      psb_surface->stride = stride;
      psb_surface->chroma_offset = psb_surface->stride * height;
      psb_surface->size = (psb_surface->stride * height * 3) / 2;
  
      ret = psb_buffer_create_camera_from_ub(driver_data, &psb_surface->buf,
                                             is_v4l2, psb_surface->size, user_ptr);
  
      if (ret != VA_STATUS_SUCCESS) {
          psb_surface_destroy(psb_surface);
  
          drv_debug_msg(VIDEO_DEBUG_ERROR, "Get surfae offset of camear device memory failed!\n");
          return ret;
      }
  
      return VA_STATUS_SUCCESS;
  }
  #endif
  
  /*
   * Temporarily map surface and set all chroma values of surface to 'chroma'
   */
  VAStatus psb_surface_set_chroma(psb_surface_p psb_surface, int chroma)
  {
      unsigned char *surface_data;
      int ret = psb_buffer_map(&psb_surface->buf, &surface_data);
  
      if (ret) return VA_STATUS_ERROR_UNKNOWN;
  
      memset(surface_data + psb_surface->chroma_offset, chroma, psb_surface->size - psb_surface->chroma_offset);
  
      psb_buffer_unmap(&psb_surface->buf);
  
      return VA_STATUS_SUCCESS;
  }
  
  /*
   * Destroy surface
   */
  void psb_surface_destroy(psb_surface_p psb_surface)
  {
      psb_buffer_destroy(&psb_surface->buf);
      if (NULL != psb_surface->in_loop_buf)
          psb_buffer_destroy(psb_surface->in_loop_buf);
  
  }
  
  VAStatus psb_surface_sync(psb_surface_p psb_surface)
  {
      wsbmBOWaitIdle(psb_surface->buf.drm_buf, 0);
  
      return VA_STATUS_SUCCESS;
  }
  
  VAStatus psb_surface_query_status(psb_surface_p psb_surface, VASurfaceStatus *status)
  {
      int ret;
      uint32_t synccpu_flag = WSBM_SYNCCPU_READ | WSBM_SYNCCPU_WRITE | WSBM_SYNCCPU_DONT_BLOCK;
  
      ret = wsbmBOSyncForCpu(psb_surface->buf.drm_buf, synccpu_flag);
  
      if (ret == 0) {
          (void) wsbmBOReleaseFromCpu(psb_surface->buf.drm_buf, synccpu_flag);
          *status = VASurfaceReady;
      } else {
          *status = VASurfaceRendering;
      }
      return VA_STATUS_SUCCESS;
  }
  
  /*
   * Set current displaying surface info to kernel
   * so that other component can access it in another process
   */
  int psb_surface_set_displaying(psb_driver_data_p driver_data,
                                 int width, int height,
                                 psb_surface_p psb_surface)
  {
      struct drm_lnc_video_getparam_arg arg;
      struct drm_video_displaying_frameinfo value;
      int ret = 0;
  
      if (psb_surface) {
          value.buf_handle = (uint32_t)(wsbmKBufHandle(wsbmKBuf(psb_surface->buf.drm_buf)));
          value.width = width;
          value.height = height;
          value.size = psb_surface->size;
          value.format = psb_surface->extra_info[4];
          value.luma_stride = psb_surface->stride;
          value.chroma_u_stride = psb_surface->stride;
          value.chroma_v_stride = psb_surface->stride;
          value.luma_offset = psb_surface->luma_offset;
          value.chroma_u_offset = psb_surface->chroma_offset;
          value.chroma_v_offset = psb_surface->chroma_offset;
      } else /* clean kernel displaying surface info */
          memset(&value, 0, sizeof(value));
  
      arg.key = IMG_VIDEO_SET_DISPLAYING_FRAME;
      arg.value = (uint64_t)((unsigned long) & value);
      ret = drmCommandWriteRead(driver_data->drm_fd, driver_data->getParamIoctlOffset,
                                &arg, sizeof(arg));
      if (ret != 0)
          drv_debug_msg(VIDEO_DEBUG_ERROR, "IMG_VIDEO_SET_DISPLAYING_FRAME failed\n");
  
      return ret;
  }
  