| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <linux/bitops.h> |
| #include <linux/slab.h> |
| #include <linux/list.h> |
| #include <linux/interrupt.h> |
| #include <linux/hash.h> |
| #include <linux/soc/qcom/smem.h> |
| #include <soc/qcom/socinfo.h> |
| #include "vidc_hfi_helper.h" |
| #include "vidc_hfi_io.h" |
| #include "msm_vidc_debug.h" |
| #include "vidc_hfi.h" |
| |
| static enum vidc_status hfi_parse_init_done_properties( |
| struct msm_vidc_capability *capability, |
| u32 num_sessions, u8 *data_ptr, u32 num_properties, |
| u32 rem_bytes, u32 codec, u32 domain); |
| |
| static enum vidc_status hfi_map_err_status(u32 hfi_err) |
| { |
| enum vidc_status vidc_err; |
| |
| switch (hfi_err) { |
| case HFI_ERR_NONE: |
| case HFI_ERR_SESSION_SAME_STATE_OPERATION: |
| vidc_err = VIDC_ERR_NONE; |
| break; |
| case HFI_ERR_SYS_FATAL: |
| vidc_err = VIDC_ERR_HW_FATAL; |
| break; |
| case HFI_ERR_SYS_VERSION_MISMATCH: |
| case HFI_ERR_SYS_INVALID_PARAMETER: |
| case HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE: |
| case HFI_ERR_SESSION_INVALID_PARAMETER: |
| case HFI_ERR_SESSION_INVALID_SESSION_ID: |
| case HFI_ERR_SESSION_INVALID_STREAM_ID: |
| vidc_err = VIDC_ERR_BAD_PARAM; |
| break; |
| case HFI_ERR_SYS_INSUFFICIENT_RESOURCES: |
| case HFI_ERR_SYS_UNSUPPORTED_DOMAIN: |
| case HFI_ERR_SYS_UNSUPPORTED_CODEC: |
| case HFI_ERR_SESSION_UNSUPPORTED_PROPERTY: |
| case HFI_ERR_SESSION_UNSUPPORTED_SETTING: |
| case HFI_ERR_SESSION_INSUFFICIENT_RESOURCES: |
| case HFI_ERR_SESSION_UNSUPPORTED_STREAM: |
| vidc_err = VIDC_ERR_NOT_SUPPORTED; |
| break; |
| case HFI_ERR_SYS_MAX_SESSIONS_REACHED: |
| vidc_err = VIDC_ERR_MAX_CLIENTS; |
| break; |
| case HFI_ERR_SYS_SESSION_IN_USE: |
| vidc_err = VIDC_ERR_CLIENT_PRESENT; |
| break; |
| case HFI_ERR_SESSION_FATAL: |
| vidc_err = VIDC_ERR_CLIENT_FATAL; |
| break; |
| case HFI_ERR_SESSION_BAD_POINTER: |
| vidc_err = VIDC_ERR_BAD_PARAM; |
| break; |
| case HFI_ERR_SESSION_INCORRECT_STATE_OPERATION: |
| vidc_err = VIDC_ERR_BAD_STATE; |
| break; |
| case HFI_ERR_SESSION_STREAM_CORRUPT: |
| case HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED: |
| vidc_err = VIDC_ERR_BITSTREAM_ERR; |
| break; |
| case HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED: |
| vidc_err = VIDC_ERR_IFRAME_EXPECTED; |
| break; |
| case HFI_ERR_SESSION_START_CODE_NOT_FOUND: |
| vidc_err = VIDC_ERR_START_CODE_NOT_FOUND; |
| break; |
| case HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING: |
| default: |
| vidc_err = VIDC_ERR_FAIL; |
| break; |
| } |
| return vidc_err; |
| } |
| |
| static enum msm_vidc_pixel_depth get_hal_pixel_depth(u32 hfi_bit_depth) |
| { |
| switch (hfi_bit_depth) { |
| case HFI_BITDEPTH_8: return MSM_VIDC_BIT_DEPTH_8; |
| case HFI_BITDEPTH_9: |
| case HFI_BITDEPTH_10: return MSM_VIDC_BIT_DEPTH_10; |
| } |
| dprintk(VIDC_ERR, "Unsupported bit depth: %d\n", hfi_bit_depth); |
| return MSM_VIDC_BIT_DEPTH_UNSUPPORTED; |
| } |
| |
| static inline int validate_pkt_size(u32 rem_size, u32 msg_size) |
| { |
| if (rem_size < msg_size) { |
| dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", |
| __func__, rem_size); |
| return false; |
| } |
| return true; |
| } |
| |
| static int hfi_process_sess_evt_seq_changed(u32 device_id, |
| struct hfi_msg_event_notify_packet *pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct msm_vidc_cb_event event_notify = {0}; |
| u32 num_properties_changed, rem_size; |
| struct hfi_frame_size *frame_sz; |
| struct hfi_profile_level *profile_level; |
| struct hfi_bit_depth *pixel_depth; |
| struct hfi_pic_struct *pic_struct; |
| u8 *data_ptr; |
| int prop_id; |
| enum msm_vidc_pixel_depth luma_bit_depth, chroma_bit_depth; |
| struct hfi_colour_space *colour_info; |
| /* Initialize pic_struct to unknown as default */ |
| event_notify.pic_struct = MSM_VIDC_PIC_STRUCT_UNKNOWN; |
| if (!validate_pkt_size(pkt->size, |
| sizeof(struct hfi_msg_event_notify_packet))) |
| return -E2BIG; |
| |
| event_notify.device_id = device_id; |
| event_notify.session_id = (void *)(uintptr_t)pkt->session_id; |
| event_notify.status = VIDC_ERR_NONE; |
| num_properties_changed = pkt->event_data2; |
| switch (pkt->event_data1) { |
| case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES: |
| event_notify.hal_event_type = |
| HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES; |
| break; |
| case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES: |
| event_notify.hal_event_type = |
| HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES; |
| break; |
| default: |
| break; |
| } |
| |
| if (num_properties_changed) { |
| data_ptr = (u8 *) &pkt->rg_ext_event_data[0]; |
| rem_size = pkt->size - sizeof(struct |
| hfi_msg_event_notify_packet) + sizeof(u32); |
| do { |
| if (!validate_pkt_size(rem_size, sizeof(u32))) |
| return -E2BIG; |
| prop_id = (int) *((u32 *)data_ptr); |
| rem_size -= sizeof(u32); |
| switch (prop_id) { |
| case HFI_PROPERTY_PARAM_FRAME_SIZE: |
| if (!validate_pkt_size(rem_size, sizeof(struct |
| hfi_frame_size))) |
| return -E2BIG; |
| data_ptr = data_ptr + sizeof(u32); |
| frame_sz = |
| (struct hfi_frame_size *) data_ptr; |
| event_notify.width = frame_sz->width; |
| event_notify.height = frame_sz->height; |
| dprintk(VIDC_DBG, "height: %d width: %d\n", |
| frame_sz->height, frame_sz->width); |
| data_ptr += |
| sizeof(struct hfi_frame_size); |
| rem_size -= sizeof(struct hfi_frame_size); |
| break; |
| case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: |
| if (!validate_pkt_size(rem_size, sizeof(struct |
| hfi_profile_level))) |
| return -E2BIG; |
| data_ptr = data_ptr + sizeof(u32); |
| profile_level = |
| (struct hfi_profile_level *) data_ptr; |
| dprintk(VIDC_DBG, "profile: %d level: %d\n", |
| profile_level->profile, |
| profile_level->level); |
| data_ptr += |
| sizeof(struct hfi_profile_level); |
| rem_size -= sizeof(struct hfi_profile_level); |
| break; |
| case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: |
| if (!validate_pkt_size(rem_size, sizeof(struct |
| hfi_bit_depth))) |
| return -E2BIG; |
| data_ptr = data_ptr + sizeof(u32); |
| pixel_depth = (struct hfi_bit_depth *) data_ptr; |
| /* |
| * Luma and chroma can have different bitdepths. |
| * Driver should rely on luma and chroma |
| * bitdepth for determining output bitdepth |
| * type. |
| * |
| * pixel_depth->bitdepth will include luma |
| * bitdepth info in bits 0..15 and chroma |
| * bitdept in bits 16..31. |
| */ |
| luma_bit_depth = get_hal_pixel_depth( |
| pixel_depth->bit_depth & |
| GENMASK(15, 0)); |
| chroma_bit_depth = get_hal_pixel_depth( |
| (pixel_depth->bit_depth & |
| GENMASK(31, 16)) >> 16); |
| if (luma_bit_depth == MSM_VIDC_BIT_DEPTH_10 || |
| chroma_bit_depth == |
| MSM_VIDC_BIT_DEPTH_10) |
| event_notify.bit_depth = |
| MSM_VIDC_BIT_DEPTH_10; |
| else |
| event_notify.bit_depth = luma_bit_depth; |
| dprintk(VIDC_DBG, |
| "bitdepth(%d), luma_bit_depth(%d), chroma_bit_depth(%d)\n", |
| event_notify.bit_depth, luma_bit_depth, |
| chroma_bit_depth); |
| data_ptr += sizeof(struct hfi_bit_depth); |
| rem_size -= sizeof(struct hfi_bit_depth); |
| break; |
| case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: |
| if (!validate_pkt_size(rem_size, sizeof(struct |
| hfi_pic_struct))) |
| return -E2BIG; |
| data_ptr = data_ptr + sizeof(u32); |
| pic_struct = (struct hfi_pic_struct *) data_ptr; |
| event_notify.pic_struct = |
| pic_struct->progressive_only; |
| dprintk(VIDC_DBG, |
| "Progressive only flag: %d\n", |
| pic_struct->progressive_only); |
| data_ptr += |
| sizeof(struct hfi_pic_struct); |
| rem_size -= sizeof(struct hfi_pic_struct); |
| break; |
| case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: |
| if (!validate_pkt_size(rem_size, sizeof(struct |
| hfi_colour_space))) |
| return -E2BIG; |
| data_ptr = data_ptr + sizeof(u32); |
| colour_info = |
| (struct hfi_colour_space *) data_ptr; |
| event_notify.colour_space = |
| colour_info->colour_space; |
| dprintk(VIDC_DBG, |
| "Colour space value is: %d\n", |
| colour_info->colour_space); |
| data_ptr += |
| sizeof(struct hfi_colour_space); |
| rem_size -= sizeof(struct hfi_colour_space); |
| break; |
| break; |
| default: |
| dprintk(VIDC_ERR, |
| "%s cmd: %#x not supported\n", |
| __func__, prop_id); |
| break; |
| } |
| num_properties_changed--; |
| } while (num_properties_changed > 0); |
| } |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_EVENT_CHANGE, |
| .response.event = event_notify, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_evt_release_buffer_ref(u32 device_id, |
| struct hfi_msg_event_notify_packet *pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct msm_vidc_cb_event event_notify = {0}; |
| struct hfi_msg_release_buffer_ref_event_packet *data; |
| |
| dprintk(VIDC_DBG, |
| "RECEIVED: EVENT_NOTIFY - release_buffer_reference\n"); |
| if (sizeof(struct hfi_msg_event_notify_packet) |
| > pkt->size) { |
| dprintk(VIDC_ERR, |
| "hal_process_session_init_done: bad_pkt_size\n"); |
| return -E2BIG; |
| } |
| if (pkt->size < sizeof(struct hfi_msg_event_notify_packet) - sizeof(u32) |
| + sizeof(struct hfi_msg_release_buffer_ref_event_packet)) { |
| dprintk(VIDC_ERR, |
| "hfi_msg_release_buffer_ref_event: bad_pkt_size\n"); |
| return -E2BIG; |
| } |
| |
| data = (struct hfi_msg_release_buffer_ref_event_packet *) |
| pkt->rg_ext_event_data; |
| |
| event_notify.device_id = device_id; |
| event_notify.session_id = (void *)(uintptr_t)pkt->session_id; |
| event_notify.status = VIDC_ERR_NONE; |
| event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE; |
| event_notify.packet_buffer = data->packet_buffer; |
| event_notify.extra_data_buffer = data->extra_data_buffer; |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_EVENT_CHANGE, |
| .response.event = event_notify, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_sys_error(u32 device_id, struct msm_vidc_cb_info *info) |
| { |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| cmd_done.device_id = device_id; |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SYS_ERROR, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_error(u32 device_id, |
| struct hfi_msg_event_notify_packet *pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->event_data1); |
| dprintk(VIDC_INFO, "Received: SESSION_ERROR with event id : %d\n", |
| pkt->event_data1); |
| switch (pkt->event_data1) { |
| case HFI_ERR_SESSION_INVALID_SCALE_FACTOR: |
| case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE: |
| case HFI_ERR_SESSION_UNSUPPORTED_SETTING: |
| case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED: |
| cmd_done.status = VIDC_ERR_NONE; |
| dprintk(VIDC_INFO, "Non Fatal: HFI_EVENT_SESSION_ERROR\n"); |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_RESPONSE_UNUSED, |
| .response.cmd = cmd_done, |
| }; |
| return 0; |
| default: |
| dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR\n"); |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_ERROR, |
| .response.cmd = cmd_done, |
| }; |
| return 0; |
| } |
| } |
| |
| static int hfi_process_event_notify(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_event_notify_packet *pkt = _pkt; |
| |
| dprintk(VIDC_DBG, "Received: EVENT_NOTIFY\n"); |
| if (pkt->size < sizeof(struct hfi_msg_event_notify_packet)) { |
| dprintk(VIDC_ERR, "Invalid Params\n"); |
| return -E2BIG; |
| } |
| |
| switch (pkt->event_id) { |
| case HFI_EVENT_SYS_ERROR: |
| dprintk(VIDC_ERR, "HFI_EVENT_SYS_ERROR: %d, %#x\n", |
| pkt->event_data1, pkt->event_data2); |
| return hfi_process_sys_error(device_id, info); |
| case HFI_EVENT_SESSION_ERROR: |
| dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR[%#x]\n", |
| pkt->session_id); |
| return hfi_process_session_error(device_id, pkt, info); |
| |
| case HFI_EVENT_SESSION_SEQUENCE_CHANGED: |
| dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED[%#x]\n", |
| pkt->session_id); |
| return hfi_process_sess_evt_seq_changed(device_id, pkt, info); |
| |
| case HFI_EVENT_RELEASE_BUFFER_REFERENCE: |
| dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE[%#x]\n", |
| pkt->session_id); |
| return hfi_process_evt_release_buffer_ref(device_id, pkt, info); |
| |
| case HFI_EVENT_SESSION_PROPERTY_CHANGED: |
| default: |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_RESPONSE_UNUSED, |
| }; |
| |
| return 0; |
| } |
| } |
| |
| static int hfi_process_sys_init_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_sys_init_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| enum vidc_status status = VIDC_ERR_NONE; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SYS_INIT_DONE\n"); |
| if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) { |
| dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", __func__, |
| pkt->size); |
| return -E2BIG; |
| } |
| if (!pkt->num_properties) { |
| dprintk(VIDC_ERR, |
| "hal_process_sys_init_done: no_properties\n"); |
| status = VIDC_ERR_FAIL; |
| goto err_no_prop; |
| } |
| |
| status = hfi_map_err_status(pkt->error_type); |
| if (status) { |
| dprintk(VIDC_ERR, "%s: status %#x\n", |
| __func__, status); |
| goto err_no_prop; |
| } |
| |
| err_no_prop: |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = NULL; |
| cmd_done.status = (u32)status; |
| cmd_done.size = sizeof(struct vidc_hal_sys_init_done); |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SYS_INIT_DONE, |
| .response.cmd = cmd_done, |
| }; |
| return 0; |
| } |
| |
| static int hfi_process_sys_rel_resource_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_sys_release_resource_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| enum vidc_status status = VIDC_ERR_NONE; |
| u32 pkt_size; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SYS_RELEASE_RESOURCE_DONE\n"); |
| pkt_size = sizeof(struct hfi_msg_sys_release_resource_done_packet); |
| if (pkt_size > pkt->size) { |
| dprintk(VIDC_ERR, |
| "hal_process_sys_rel_resource_done: bad size: %d\n", |
| pkt->size); |
| return -E2BIG; |
| } |
| |
| status = hfi_map_err_status(pkt->error_type); |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = NULL; |
| cmd_done.status = (u32) status; |
| cmd_done.size = 0; |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SYS_RELEASE_RESOURCE_DONE, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| enum hal_capability get_hal_cap_type(u32 capability_type) |
| { |
| enum hal_capability hal_cap = 0; |
| |
| switch (capability_type) { |
| case HFI_CAPABILITY_FRAME_WIDTH: |
| hal_cap = HAL_CAPABILITY_FRAME_WIDTH; |
| break; |
| case HFI_CAPABILITY_FRAME_HEIGHT: |
| hal_cap = HAL_CAPABILITY_FRAME_HEIGHT; |
| break; |
| case HFI_CAPABILITY_MBS_PER_FRAME: |
| hal_cap = HAL_CAPABILITY_MBS_PER_FRAME; |
| break; |
| case HFI_CAPABILITY_MBS_PER_SECOND: |
| hal_cap = HAL_CAPABILITY_MBS_PER_SECOND; |
| break; |
| case HFI_CAPABILITY_FRAMERATE: |
| hal_cap = HAL_CAPABILITY_FRAMERATE; |
| break; |
| case HFI_CAPABILITY_SCALE_X: |
| hal_cap = HAL_CAPABILITY_SCALE_X; |
| break; |
| case HFI_CAPABILITY_SCALE_Y: |
| hal_cap = HAL_CAPABILITY_SCALE_Y; |
| break; |
| case HFI_CAPABILITY_BITRATE: |
| hal_cap = HAL_CAPABILITY_BITRATE; |
| break; |
| case HFI_CAPABILITY_BFRAME: |
| hal_cap = HAL_CAPABILITY_BFRAME; |
| break; |
| case HFI_CAPABILITY_PEAKBITRATE: |
| hal_cap = HAL_CAPABILITY_PEAKBITRATE; |
| break; |
| case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS: |
| hal_cap = HAL_CAPABILITY_HIER_P_NUM_ENH_LAYERS; |
| break; |
| case HFI_CAPABILITY_ENC_LTR_COUNT: |
| hal_cap = HAL_CAPABILITY_ENC_LTR_COUNT; |
| break; |
| case HFI_CAPABILITY_CP_OUTPUT2_THRESH: |
| hal_cap = HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD; |
| break; |
| case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS: |
| hal_cap = HAL_CAPABILITY_HIER_B_NUM_ENH_LAYERS; |
| break; |
| case HFI_CAPABILITY_LCU_SIZE: |
| hal_cap = HAL_CAPABILITY_LCU_SIZE; |
| break; |
| case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS: |
| hal_cap = HAL_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS; |
| break; |
| case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE: |
| hal_cap = HAL_CAPABILITY_MBS_PER_SECOND_POWER_SAVE; |
| break; |
| default: |
| dprintk(VIDC_DBG, "%s: unknown capablity %#x\n", |
| __func__, capability_type); |
| break; |
| } |
| |
| return hal_cap; |
| } |
| |
| static inline void copy_cap_prop( |
| struct hfi_capability_supported *in, |
| struct msm_vidc_capability *capability) |
| { |
| struct hal_capability_supported *out = NULL; |
| |
| if (!in || !capability) { |
| dprintk(VIDC_ERR, "%s Invalid input parameters\n", |
| __func__); |
| return; |
| } |
| |
| switch (in->capability_type) { |
| case HFI_CAPABILITY_FRAME_WIDTH: |
| out = &capability->width; |
| break; |
| case HFI_CAPABILITY_FRAME_HEIGHT: |
| out = &capability->height; |
| break; |
| case HFI_CAPABILITY_MBS_PER_FRAME: |
| out = &capability->mbs_per_frame; |
| break; |
| case HFI_CAPABILITY_MBS_PER_SECOND: |
| out = &capability->mbs_per_sec; |
| break; |
| case HFI_CAPABILITY_FRAMERATE: |
| out = &capability->frame_rate; |
| break; |
| case HFI_CAPABILITY_SCALE_X: |
| out = &capability->scale_x; |
| break; |
| case HFI_CAPABILITY_SCALE_Y: |
| out = &capability->scale_y; |
| break; |
| case HFI_CAPABILITY_BITRATE: |
| out = &capability->bitrate; |
| break; |
| case HFI_CAPABILITY_BFRAME: |
| out = &capability->bframe; |
| break; |
| case HFI_CAPABILITY_PEAKBITRATE: |
| out = &capability->peakbitrate; |
| break; |
| case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS: |
| out = &capability->hier_p; |
| break; |
| case HFI_CAPABILITY_ENC_LTR_COUNT: |
| out = &capability->ltr_count; |
| break; |
| case HFI_CAPABILITY_CP_OUTPUT2_THRESH: |
| out = &capability->secure_output2_threshold; |
| break; |
| case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS: |
| out = &capability->hier_b; |
| break; |
| case HFI_CAPABILITY_LCU_SIZE: |
| out = &capability->lcu_size; |
| break; |
| case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS: |
| out = &capability->hier_p_hybrid; |
| break; |
| case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE: |
| out = &capability->mbs_per_sec_power_save; |
| break; |
| default: |
| dprintk(VIDC_DBG, "%s: unknown capablity %#x\n", |
| __func__, in->capability_type); |
| break; |
| } |
| |
| if (out) { |
| out->capability_type = get_hal_cap_type(in->capability_type); |
| out->min = in->min; |
| out->max = in->max; |
| out->step_size = in->step_size; |
| } |
| } |
| |
| static int hfi_fill_codec_info(u8 *data_ptr, |
| struct vidc_hal_sys_init_done *sys_init_done, u32 rem_size) |
| { |
| u32 i; |
| u32 codecs = 0, codec_count = 0, size = 0; |
| struct msm_vidc_capability *capability; |
| u32 prop_id = *((u32 *)data_ptr); |
| u8 *orig_data_ptr = data_ptr; |
| |
| if (prop_id == HFI_PROPERTY_PARAM_CODEC_SUPPORTED) { |
| struct hfi_codec_supported *prop; |
| |
| if (!validate_pkt_size(rem_size - sizeof(u32), |
| sizeof(struct hfi_codec_supported))) |
| return -E2BIG; |
| data_ptr = data_ptr + sizeof(u32); |
| prop = (struct hfi_codec_supported *) data_ptr; |
| sys_init_done->dec_codec_supported = |
| prop->decoder_codec_supported; |
| sys_init_done->enc_codec_supported = |
| prop->encoder_codec_supported; |
| size = sizeof(struct hfi_codec_supported) + sizeof(u32); |
| rem_size -= |
| sizeof(struct hfi_codec_supported) + sizeof(u32); |
| } else { |
| dprintk(VIDC_WARN, |
| "%s: prop_id %#x, expected codec_supported property\n", |
| __func__, prop_id); |
| } |
| |
| codecs = sys_init_done->dec_codec_supported; |
| for (i = 0; i < 8 * sizeof(codecs); i++) { |
| if ((1 << i) & codecs) { |
| capability = |
| &sys_init_done->capabilities[codec_count++]; |
| capability->codec = |
| vidc_get_hal_codec((1 << i) & codecs); |
| capability->domain = |
| vidc_get_hal_domain(HFI_VIDEO_DOMAIN_DECODER); |
| if (codec_count == VIDC_MAX_DECODE_SESSIONS) { |
| dprintk(VIDC_ERR, |
| "Max supported decoder sessions reached\n"); |
| break; |
| } |
| } |
| } |
| codecs = sys_init_done->enc_codec_supported; |
| for (i = 0; i < 8 * sizeof(codecs); i++) { |
| if ((1 << i) & codecs) { |
| capability = |
| &sys_init_done->capabilities[codec_count++]; |
| capability->codec = |
| vidc_get_hal_codec((1 << i) & codecs); |
| capability->domain = |
| vidc_get_hal_domain(HFI_VIDEO_DOMAIN_ENCODER); |
| if (codec_count == VIDC_MAX_SESSIONS) { |
| dprintk(VIDC_ERR, |
| "Max supported sessions reached\n"); |
| break; |
| } |
| } |
| } |
| sys_init_done->codec_count = codec_count; |
| |
| if (!validate_pkt_size(rem_size, sizeof(u32))) |
| return -E2BIG; |
| prop_id = *((u32 *)(orig_data_ptr + size)); |
| if (prop_id == HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED) { |
| struct hfi_max_sessions_supported *prop; |
| |
| if (!validate_pkt_size(rem_size - sizeof(u32), sizeof(struct |
| hfi_max_sessions_supported))) |
| return -E2BIG; |
| prop = (struct hfi_max_sessions_supported *) |
| (orig_data_ptr + size + sizeof(u32)); |
| |
| sys_init_done->max_sessions_supported = prop->max_sessions; |
| size += sizeof(struct hfi_max_sessions_supported) + sizeof(u32); |
| rem_size -= |
| sizeof(struct hfi_max_sessions_supported) + sizeof(u32); |
| dprintk(VIDC_DBG, "max_sessions_supported %d\n", |
| prop->max_sessions); |
| } |
| return size; |
| } |
| |
| enum vidc_status hfi_process_session_init_done_prop_read( |
| struct hfi_msg_sys_session_init_done_packet *pkt, |
| struct vidc_hal_session_init_done *session_init_done) |
| { |
| enum vidc_status status = VIDC_ERR_NONE; |
| struct msm_vidc_capability *capability = NULL; |
| u32 rem_bytes, num_properties; |
| u8 *data_ptr; |
| |
| rem_bytes = pkt->size - sizeof(struct |
| hfi_msg_sys_session_init_done_packet) + sizeof(u32); |
| if (!rem_bytes) { |
| dprintk(VIDC_ERR, "%s: invalid property info\n", __func__); |
| return VIDC_ERR_FAIL; |
| } |
| |
| status = hfi_map_err_status(pkt->error_type); |
| if (status) { |
| dprintk(VIDC_ERR, "%s: error status 0x%x\n", __func__, status); |
| return status; |
| } |
| |
| data_ptr = (u8 *)&pkt->rg_property_data[0]; |
| num_properties = pkt->num_properties; |
| |
| capability = &session_init_done->capability; |
| status = hfi_parse_init_done_properties( |
| capability, 1, data_ptr, num_properties, rem_bytes, |
| vidc_get_hfi_codec(capability->codec), |
| vidc_get_hfi_domain(capability->domain)); |
| if (status) { |
| dprintk(VIDC_ERR, "%s: parse status 0x%x\n", __func__, status); |
| return status; |
| } |
| |
| return status; |
| } |
| |
| static int copy_caps_to_sessions(struct hfi_capability_supported *cap, |
| u32 num_caps, struct msm_vidc_capability *capabilities, |
| u32 num_sessions, u32 codecs, u32 domain) |
| { |
| u32 i = 0, j = 0; |
| struct msm_vidc_capability *capability; |
| u32 sess_codec; |
| u32 sess_domain; |
| |
| /* |
| * iterate over num_sessions and copy all the capabilities |
| * to matching sessions. |
| */ |
| for (i = 0; i < num_sessions; i++) { |
| sess_codec = 0; |
| sess_domain = 0; |
| capability = &capabilities[i]; |
| |
| if (capability->codec) |
| sess_codec = |
| vidc_get_hfi_codec(capability->codec); |
| if (capability->domain) |
| sess_domain = |
| vidc_get_hfi_domain(capability->domain); |
| |
| if (!(sess_codec & codecs && sess_domain & domain)) |
| continue; |
| |
| for (j = 0; j < num_caps; j++) |
| copy_cap_prop(&cap[j], capability); |
| } |
| |
| return 0; |
| } |
| |
| static int copy_alloc_mode_to_sessions( |
| struct hfi_buffer_alloc_mode_supported *prop, |
| struct msm_vidc_capability *capabilities, |
| u32 num_sessions, u32 codecs, u32 domain) |
| { |
| u32 i = 0, j = 0; |
| struct msm_vidc_capability *capability; |
| u32 sess_codec; |
| u32 sess_domain; |
| |
| /* |
| * iterate over num_sessions and copy all the entries |
| * to matching sessions. |
| */ |
| for (i = 0; i < num_sessions; i++) { |
| sess_codec = 0; |
| sess_domain = 0; |
| capability = &capabilities[i]; |
| |
| if (capability->codec) |
| sess_codec = |
| vidc_get_hfi_codec(capability->codec); |
| if (capability->domain) |
| sess_domain = |
| vidc_get_hfi_domain(capability->domain); |
| |
| if (!(sess_codec & codecs && sess_domain & domain)) |
| continue; |
| |
| for (j = 0; j < prop->num_entries; j++) { |
| if (prop->buffer_type == HFI_BUFFER_OUTPUT || |
| prop->buffer_type == HFI_BUFFER_OUTPUT2) { |
| switch (prop->rg_data[j]) { |
| case HFI_BUFFER_MODE_STATIC: |
| capability->alloc_mode_out |= |
| HAL_BUFFER_MODE_STATIC; |
| break; |
| case HFI_BUFFER_MODE_RING: |
| capability->alloc_mode_out |= |
| HAL_BUFFER_MODE_RING; |
| break; |
| case HFI_BUFFER_MODE_DYNAMIC: |
| capability->alloc_mode_out |= |
| HAL_BUFFER_MODE_DYNAMIC; |
| break; |
| } |
| } else if (prop->buffer_type == HFI_BUFFER_INPUT) { |
| switch (prop->rg_data[j]) { |
| case HFI_BUFFER_MODE_STATIC: |
| capability->alloc_mode_in |= |
| HAL_BUFFER_MODE_STATIC; |
| break; |
| case HFI_BUFFER_MODE_RING: |
| capability->alloc_mode_in |= |
| HAL_BUFFER_MODE_RING; |
| break; |
| case HFI_BUFFER_MODE_DYNAMIC: |
| capability->alloc_mode_in |= |
| HAL_BUFFER_MODE_DYNAMIC; |
| break; |
| } |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| static enum vidc_status hfi_parse_init_done_properties( |
| struct msm_vidc_capability *capabilities, |
| u32 num_sessions, u8 *data_ptr, u32 num_properties, |
| u32 rem_bytes, u32 codecs, u32 domain) |
| { |
| enum vidc_status status = VIDC_ERR_NONE; |
| u32 prop_id, next_offset; |
| #define VALIDATE_PROPERTY_STRUCTURE_SIZE(pkt_size, property_size) ({\ |
| if (pkt_size < property_size) { \ |
| status = VIDC_ERR_BAD_PARAM; \ |
| break; \ |
| } \ |
| }) |
| |
| #define VALIDATE_PROPERTY_PAYLOAD_SIZE(pkt_size, payload_size, \ |
| property_count) ({\ |
| if (pkt_size/payload_size < property_count) { \ |
| status = VIDC_ERR_BAD_PARAM; \ |
| break; \ |
| } \ |
| }) |
| |
| while (status == VIDC_ERR_NONE && num_properties && |
| rem_bytes >= sizeof(u32)) { |
| |
| prop_id = *((u32 *)data_ptr); |
| next_offset = sizeof(u32); |
| |
| switch (prop_id) { |
| case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED: |
| { |
| struct hfi_codec_mask_supported *prop = |
| (struct hfi_codec_mask_supported *) |
| (data_ptr + next_offset); |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(*prop)); |
| |
| codecs = prop->codecs; |
| domain = prop->video_domains; |
| next_offset += sizeof(struct hfi_codec_mask_supported); |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED: |
| { |
| struct hfi_capability_supported_info *prop = |
| (struct hfi_capability_supported_info *) |
| (data_ptr + next_offset); |
| |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(*prop)); |
| VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - |
| next_offset - sizeof(u32), |
| sizeof(struct hfi_capability_supported), |
| prop->num_capabilities); |
| |
| next_offset += sizeof(u32) + |
| prop->num_capabilities * |
| sizeof(struct hfi_capability_supported); |
| |
| copy_caps_to_sessions(&prop->rg_data[0], |
| prop->num_capabilities, |
| capabilities, num_sessions, |
| codecs, domain); |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: |
| { |
| struct hfi_uncompressed_format_supported *prop = |
| (struct hfi_uncompressed_format_supported *) |
| (data_ptr + next_offset); |
| u32 num_format_entries; |
| char *fmt_ptr; |
| struct hfi_uncompressed_plane_info *plane_info; |
| |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(*prop)); |
| |
| num_format_entries = prop->format_entries; |
| next_offset = sizeof(*prop); |
| fmt_ptr = (char *)&prop->rg_format_info[0]; |
| |
| while (num_format_entries) { |
| u32 bytes_to_skip; |
| |
| plane_info = |
| (struct hfi_uncompressed_plane_info *) fmt_ptr; |
| |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(*plane_info)); |
| |
| bytes_to_skip = sizeof(*plane_info) - |
| sizeof(struct |
| hfi_uncompressed_plane_constraints) + |
| plane_info->num_planes * |
| sizeof(struct |
| hfi_uncompressed_plane_constraints); |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| bytes_to_skip); |
| |
| fmt_ptr += bytes_to_skip; |
| next_offset += bytes_to_skip; |
| num_format_entries--; |
| } |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED: |
| { |
| struct hfi_properties_supported *prop = |
| (struct hfi_properties_supported *) |
| (data_ptr + next_offset); |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(*prop)); |
| VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - |
| next_offset - sizeof(*prop) + |
| sizeof(u32), sizeof(u32), |
| prop->num_properties); |
| next_offset += sizeof(*prop) - sizeof(u32) |
| + prop->num_properties * sizeof(u32); |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED: |
| { |
| struct msm_vidc_capability capability; |
| char *ptr = NULL; |
| u32 count = 0; |
| u32 prof_count = 0; |
| struct hfi_profile_level *prof_level; |
| struct hfi_profile_level_supported *prop = |
| (struct hfi_profile_level_supported *) |
| (data_ptr + next_offset); |
| |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(*prop)); |
| ptr = (char *) &prop->rg_profile_level[0]; |
| prof_count = prop->profile_count; |
| next_offset += sizeof(u32); |
| |
| if (prof_count > MAX_PROFILE_COUNT) { |
| prof_count = MAX_PROFILE_COUNT; |
| dprintk(VIDC_WARN, |
| "prop count exceeds max profile count\n"); |
| break; |
| } |
| while (prof_count) { |
| struct hal_profile_level_supported *caps_pl; |
| |
| caps_pl = &capability.profile_level; |
| prof_level = (struct hfi_profile_level *)ptr; |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(*prof_level)); |
| caps_pl->profile_level[count].profile = |
| prof_level->profile; |
| caps_pl->profile_level[count].level = |
| prof_level->level; |
| prof_count--; |
| count++; |
| ptr += sizeof(struct hfi_profile_level); |
| next_offset += sizeof(struct hfi_profile_level); |
| } |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED: |
| { |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(struct hfi_interlace_format_supported)); |
| next_offset += |
| sizeof(struct hfi_interlace_format_supported); |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED: |
| { |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(struct hfi_nal_stream_format_supported)); |
| next_offset += |
| sizeof(struct hfi_nal_stream_format_supported); |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: |
| { |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(u32)); |
| next_offset += sizeof(u32); |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE: |
| { |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(u32)); |
| next_offset += sizeof(u32); |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: |
| { |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(struct hfi_intra_refresh)); |
| next_offset += |
| sizeof(struct hfi_intra_refresh); |
| num_properties--; |
| break; |
| } |
| case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED: |
| { |
| struct hfi_buffer_alloc_mode_supported *prop = |
| (struct hfi_buffer_alloc_mode_supported *) |
| (data_ptr + next_offset); |
| VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - |
| next_offset, |
| sizeof(*prop)); |
| if (prop->num_entries >= 32) { |
| dprintk(VIDC_ERR, |
| "%s - num_entries: %d from f/w seems suspect\n", |
| __func__, prop->num_entries); |
| break; |
| } |
| VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - |
| next_offset - |
| sizeof(struct hfi_buffer_alloc_mode_supported) + |
| sizeof(u32), |
| sizeof(u32), |
| prop->num_entries); |
| next_offset += |
| sizeof(struct hfi_buffer_alloc_mode_supported) - |
| sizeof(u32) + prop->num_entries * sizeof(u32); |
| |
| copy_alloc_mode_to_sessions(prop, |
| capabilities, num_sessions, |
| codecs, domain); |
| |
| num_properties--; |
| break; |
| } |
| default: |
| dprintk(VIDC_DBG, |
| "%s: default case - data_ptr %pK, prop_id 0x%x\n", |
| __func__, data_ptr, prop_id); |
| break; |
| } |
| if (rem_bytes > next_offset) { |
| rem_bytes -= next_offset; |
| data_ptr += next_offset; |
| } else { |
| rem_bytes = 0; |
| } |
| } |
| |
| return status; |
| } |
| |
| enum vidc_status hfi_process_sys_init_done_prop_read( |
| struct hfi_msg_sys_init_done_packet *pkt, |
| struct vidc_hal_sys_init_done *sys_init_done) |
| { |
| enum vidc_status status = VIDC_ERR_NONE; |
| int bytes_read; |
| u32 rem_bytes, num_properties; |
| u8 *data_ptr; |
| u32 codecs = 0, domain = 0; |
| |
| if (!pkt || !sys_init_done) { |
| dprintk(VIDC_ERR, |
| "hfi_msg_sys_init_done: Invalid input\n"); |
| return VIDC_ERR_FAIL; |
| } |
| if (pkt->size < sizeof(struct hfi_msg_sys_init_done_packet)) { |
| dprintk(VIDC_ERR, "%s: bad packet size: %d\n", |
| __func__, pkt->size); |
| return VIDC_ERR_FAIL; |
| } |
| |
| rem_bytes = pkt->size - sizeof(struct |
| hfi_msg_sys_init_done_packet) + sizeof(u32); |
| |
| if (!rem_bytes) { |
| dprintk(VIDC_ERR, |
| "hfi_msg_sys_init_done: missing_prop_info\n"); |
| return VIDC_ERR_FAIL; |
| } |
| |
| status = hfi_map_err_status(pkt->error_type); |
| if (status) { |
| dprintk(VIDC_ERR, "%s: status %#x\n", __func__, status); |
| return status; |
| } |
| |
| data_ptr = (u8 *) &pkt->rg_property_data[0]; |
| num_properties = pkt->num_properties; |
| dprintk(VIDC_DBG, |
| "%s: data_start %pK, num_properties %#x\n", |
| __func__, data_ptr, num_properties); |
| if (!num_properties) { |
| sys_init_done->capabilities = NULL; |
| dprintk(VIDC_DBG, |
| "Venus didn't set any properties in SYS_INIT_DONE"); |
| return status; |
| } |
| bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done, rem_bytes); |
| if (bytes_read < 0) |
| return VIDC_ERR_FAIL; |
| data_ptr += bytes_read; |
| rem_bytes -= bytes_read; |
| num_properties--; |
| |
| status = hfi_parse_init_done_properties( |
| sys_init_done->capabilities, |
| VIDC_MAX_SESSIONS, data_ptr, num_properties, |
| rem_bytes, codecs, domain); |
| if (status) { |
| dprintk(VIDC_ERR, "%s: parse status %#x\n", |
| __func__, status); |
| return status; |
| } |
| |
| return status; |
| } |
| |
| static void hfi_process_sess_get_prop_dec_entropy( |
| struct hfi_msg_session_property_info_packet *prop, |
| enum hal_h264_entropy *entropy) |
| { |
| u32 req_bytes, hfi_entropy; |
| |
| req_bytes = prop->size - sizeof( |
| struct hfi_msg_session_property_info_packet); |
| |
| if (!req_bytes || req_bytes % sizeof(hfi_entropy)) { |
| dprintk(VIDC_ERR, "%s: bad packet: %d\n", __func__, req_bytes); |
| return; |
| } |
| |
| hfi_entropy = prop->rg_property_data[1]; |
| *entropy = |
| hfi_entropy == HFI_H264_ENTROPY_CAVLC ? HAL_H264_ENTROPY_CAVLC : |
| hfi_entropy == HFI_H264_ENTROPY_CABAC ? HAL_H264_ENTROPY_CABAC : |
| HAL_UNUSED_ENTROPY; |
| } |
| |
| static void hfi_process_sess_get_prop_profile_level( |
| struct hfi_msg_session_property_info_packet *prop, |
| struct hfi_profile_level *profile_level) |
| { |
| struct hfi_profile_level *hfi_profile_level; |
| u32 req_bytes; |
| |
| dprintk(VIDC_DBG, "Entered %s\n", __func__); |
| if (!prop) { |
| dprintk(VIDC_ERR, |
| "hal_process_sess_get_profile_level: bad_prop: %pK\n", |
| prop); |
| return; |
| } |
| req_bytes = prop->size - sizeof( |
| struct hfi_msg_session_property_info_packet); |
| |
| if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level)) { |
| dprintk(VIDC_ERR, |
| "hal_process_sess_get_profile_level: bad_pkt: %d\n", |
| req_bytes); |
| return; |
| } |
| hfi_profile_level = (struct hfi_profile_level *) |
| &prop->rg_property_data[1]; |
| profile_level->profile = hfi_profile_level->profile; |
| profile_level->level = hfi_profile_level->level; |
| dprintk(VIDC_DBG, "%s profile: %d level: %d\n", |
| __func__, profile_level->profile, |
| profile_level->level); |
| } |
| |
| static void hfi_process_sess_get_prop_buf_req( |
| struct hfi_msg_session_property_info_packet *prop, |
| struct buffer_requirements *buffreq) |
| { |
| struct hfi_buffer_requirements *hfi_buf_req; |
| u32 req_bytes; |
| u32 count_min = 0, count_actual = 0; |
| |
| if (!prop) { |
| dprintk(VIDC_ERR, |
| "hal_process_sess_get_prop_buf_req: bad_prop: %pK\n", |
| prop); |
| return; |
| } |
| |
| req_bytes = prop->size - sizeof( |
| struct hfi_msg_session_property_info_packet); |
| if (!req_bytes || req_bytes % sizeof(struct hfi_buffer_requirements) || |
| !prop->rg_property_data[1]) { |
| dprintk(VIDC_ERR, |
| "hal_process_sess_get_prop_buf_req: bad_pkt: %d\n", |
| req_bytes); |
| return; |
| } |
| |
| hfi_buf_req = (struct hfi_buffer_requirements *) |
| &prop->rg_property_data[1]; |
| |
| if (!hfi_buf_req) { |
| dprintk(VIDC_ERR, "%s - invalid buffer req pointer\n", |
| __func__); |
| return; |
| } |
| |
| while (req_bytes) { |
| count_min = hfi_buf_req->buffer_count_min; |
| count_actual = hfi_buf_req->buffer_count_actual; |
| if (hfi_buf_req->buffer_size && count_min > count_actual) |
| dprintk(VIDC_WARN, |
| "Bad buff req for %#x: min %d, actual %d\n", |
| hfi_buf_req->buffer_type, |
| hfi_buf_req->buffer_count_min, |
| hfi_buf_req->buffer_count_actual); |
| |
| dprintk(VIDC_DBG, "got buffer requirements for: %d\n", |
| hfi_buf_req->buffer_type); |
| switch (hfi_buf_req->buffer_type) { |
| case HFI_BUFFER_INPUT: |
| memcpy(&buffreq->buffer[0], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[0].buffer_type = HAL_BUFFER_INPUT; |
| break; |
| case HFI_BUFFER_OUTPUT: |
| memcpy(&buffreq->buffer[1], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[1].buffer_type = HAL_BUFFER_OUTPUT; |
| break; |
| case HFI_BUFFER_OUTPUT2: |
| memcpy(&buffreq->buffer[2], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[2].buffer_type = HAL_BUFFER_OUTPUT2; |
| break; |
| case HFI_BUFFER_EXTRADATA_INPUT: |
| memcpy(&buffreq->buffer[3], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[3].buffer_type = |
| HAL_BUFFER_EXTRADATA_INPUT; |
| break; |
| case HFI_BUFFER_EXTRADATA_OUTPUT: |
| memcpy(&buffreq->buffer[4], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[4].buffer_type = |
| HAL_BUFFER_EXTRADATA_OUTPUT; |
| break; |
| case HFI_BUFFER_EXTRADATA_OUTPUT2: |
| memcpy(&buffreq->buffer[5], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[5].buffer_type = |
| HAL_BUFFER_EXTRADATA_OUTPUT2; |
| break; |
| case HFI_BUFFER_INTERNAL_SCRATCH: |
| memcpy(&buffreq->buffer[6], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[6].buffer_type = |
| HAL_BUFFER_INTERNAL_SCRATCH; |
| break; |
| case HFI_BUFFER_INTERNAL_SCRATCH_1: |
| memcpy(&buffreq->buffer[7], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[7].buffer_type = |
| HAL_BUFFER_INTERNAL_SCRATCH_1; |
| break; |
| case HFI_BUFFER_INTERNAL_SCRATCH_2: |
| memcpy(&buffreq->buffer[8], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[8].buffer_type = |
| HAL_BUFFER_INTERNAL_SCRATCH_2; |
| break; |
| case HFI_BUFFER_INTERNAL_PERSIST: |
| memcpy(&buffreq->buffer[9], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[9].buffer_type = |
| HAL_BUFFER_INTERNAL_PERSIST; |
| break; |
| case HFI_BUFFER_INTERNAL_PERSIST_1: |
| memcpy(&buffreq->buffer[10], hfi_buf_req, |
| sizeof(struct hfi_buffer_requirements)); |
| buffreq->buffer[10].buffer_type = |
| HAL_BUFFER_INTERNAL_PERSIST_1; |
| break; |
| default: |
| dprintk(VIDC_ERR, |
| "hal_process_sess_get_prop_buf_req: bad_buffer_type: %d\n", |
| hfi_buf_req->buffer_type); |
| break; |
| } |
| req_bytes -= sizeof(struct hfi_buffer_requirements); |
| hfi_buf_req++; |
| } |
| } |
| |
| static int hfi_process_session_prop_info(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_session_property_info_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| struct hfi_profile_level profile_level = {0}; |
| enum hal_h264_entropy entropy = HAL_UNUSED_ENTROPY; |
| struct buffer_requirements buff_req = { { {0} } }; |
| |
| dprintk(VIDC_DBG, "Received SESSION_PROPERTY_INFO[%#x]\n", |
| pkt->session_id); |
| |
| if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) { |
| dprintk(VIDC_ERR, |
| "hal_process_session_prop_info: bad_pkt_size\n"); |
| return -E2BIG; |
| } else if (!pkt->num_properties) { |
| dprintk(VIDC_ERR, |
| "hal_process_session_prop_info: no_properties\n"); |
| return -EINVAL; |
| } |
| |
| switch (pkt->rg_property_data[0]) { |
| case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: |
| hfi_process_sess_get_prop_buf_req(pkt, &buff_req); |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = VIDC_ERR_NONE; |
| cmd_done.data.property.buf_req = buff_req; |
| cmd_done.size = sizeof(buff_req); |
| break; |
| |
| case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: |
| hfi_process_sess_get_prop_profile_level(pkt, &profile_level); |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = VIDC_ERR_NONE; |
| cmd_done.data.property.profile_level = |
| (struct hal_profile_level) { |
| .profile = profile_level.profile, |
| .level = profile_level.level, |
| }; |
| cmd_done.size = sizeof(struct hal_profile_level); |
| break; |
| |
| case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: |
| hfi_process_sess_get_prop_dec_entropy(pkt, &entropy); |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = VIDC_ERR_NONE; |
| cmd_done.data.property.h264_entropy = entropy; |
| cmd_done.size = sizeof(enum hal_h264_entropy); |
| break; |
| |
| default: |
| dprintk(VIDC_DBG, |
| "hal_process_session_prop_info: unknown_prop_id: %x\n", |
| pkt->rg_property_data[0]); |
| return -ENOTSUPP; |
| } |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_PROPERTY_INFO, |
| .response.cmd = cmd_done, |
| }; |
| return 0; |
| } |
| |
| static int hfi_process_session_init_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_sys_session_init_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| struct vidc_hal_session_init_done session_init_done = { {0} }; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_INIT_DONE[%x]\n", pkt->session_id); |
| |
| if (sizeof(struct hfi_msg_sys_session_init_done_packet) > pkt->size) { |
| dprintk(VIDC_ERR, |
| "hal_process_session_init_done: bad_pkt_size\n"); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| if (!cmd_done.status) { |
| cmd_done.status = hfi_process_session_init_done_prop_read( |
| pkt, &session_init_done); |
| } |
| |
| cmd_done.data.session_init_done = session_init_done; |
| cmd_done.size = sizeof(struct vidc_hal_session_init_done); |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_INIT_DONE, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_load_res_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_session_load_resources_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_LOAD_RESOURCES_DONE[%#x]\n", |
| pkt->session_id); |
| |
| if (sizeof(struct hfi_msg_session_load_resources_done_packet) != |
| pkt->size) { |
| dprintk(VIDC_ERR, |
| "hal_process_session_load_res_done: bad packet size: %d\n", |
| pkt->size); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_LOAD_RESOURCE_DONE, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_flush_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_session_flush_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_FLUSH_DONE[%#x]\n", |
| pkt->session_id); |
| |
| if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) { |
| dprintk(VIDC_ERR, |
| "hal_process_session_flush_done: bad packet size: %d\n", |
| pkt->size); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = sizeof(u32); |
| |
| switch (pkt->flush_type) { |
| case HFI_FLUSH_OUTPUT: |
| cmd_done.data.flush_type = HAL_FLUSH_OUTPUT; |
| break; |
| case HFI_FLUSH_INPUT: |
| cmd_done.data.flush_type = HAL_FLUSH_INPUT; |
| break; |
| case HFI_FLUSH_ALL: |
| cmd_done.data.flush_type = HAL_FLUSH_ALL; |
| break; |
| default: |
| dprintk(VIDC_ERR, |
| "%s: invalid flush type!", __func__); |
| return -EINVAL; |
| } |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_FLUSH_DONE, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_etb_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_session_empty_buffer_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_data_done data_done = {0}; |
| struct hfi_picture_type *hfi_picture_type = NULL; |
| u32 is_sync_frame; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%#x]\n", pkt->session_id); |
| |
| if (!pkt || pkt->size < |
| sizeof(struct hfi_msg_session_empty_buffer_done_packet)) |
| goto bad_packet_size; |
| |
| data_done.device_id = device_id; |
| data_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| data_done.status = hfi_map_err_status(pkt->error_type); |
| data_done.size = sizeof(struct msm_vidc_cb_data_done); |
| data_done.clnt_data = pkt->input_tag; |
| data_done.input_done.offset = pkt->offset; |
| data_done.input_done.filled_len = pkt->filled_len; |
| data_done.input_done.packet_buffer = |
| (phys_addr_t)pkt->packet_buffer; |
| data_done.input_done.extra_data_buffer = |
| (phys_addr_t)pkt->extra_data_buffer; |
| data_done.input_done.status = |
| hfi_map_err_status(pkt->error_type); |
| is_sync_frame = pkt->rgData[0]; |
| if (is_sync_frame == 1) { |
| if (pkt->size < |
| sizeof(struct hfi_msg_session_empty_buffer_done_packet) |
| + sizeof(struct hfi_picture_type)) |
| goto bad_packet_size; |
| hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[1]; |
| if (hfi_picture_type->picture_type) |
| data_done.input_done.flags = |
| hfi_picture_type->picture_type; |
| else |
| dprintk(VIDC_DBG, |
| "Non-Sync frame sent for H264/HEVC\n"); |
| } |
| |
| trace_msm_v4l2_vidc_buffer_event_end("ETB", |
| (u32)pkt->packet_buffer, -1, -1, |
| pkt->filled_len, pkt->offset); |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_ETB_DONE, |
| .response.data = data_done, |
| }; |
| |
| return 0; |
| bad_packet_size: |
| dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", |
| __func__, pkt ? pkt->size : 0); |
| return -E2BIG; |
| } |
| |
| static int hfi_process_session_ftb_done( |
| u32 device_id, void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct vidc_hal_msg_pkt_hdr *msg_hdr = _pkt; |
| struct msm_vidc_cb_data_done data_done = {0}; |
| bool is_decoder = false, is_encoder = false; |
| |
| if (!msg_hdr) { |
| dprintk(VIDC_ERR, "Invalid Params\n"); |
| return -EINVAL; |
| } |
| |
| is_encoder = msg_hdr->size == sizeof(struct |
| hfi_msg_session_fill_buffer_done_compressed_packet) + 4; |
| is_decoder = msg_hdr->size == sizeof(struct |
| hfi_msg_session_fbd_uncompressed_plane0_packet) + 4; |
| |
| if (!(is_encoder ^ is_decoder)) { |
| dprintk(VIDC_ERR, "Ambiguous packet (%#x) received (size %d)\n", |
| msg_hdr->packet, msg_hdr->size); |
| return -EBADHANDLE; |
| } |
| |
| if (is_encoder) { |
| struct hfi_msg_session_fill_buffer_done_compressed_packet *pkt = |
| (struct hfi_msg_session_fill_buffer_done_compressed_packet *) |
| msg_hdr; |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%#x]\n", |
| pkt->session_id); |
| if (sizeof(struct |
| hfi_msg_session_fill_buffer_done_compressed_packet) |
| > pkt->size) { |
| dprintk(VIDC_ERR, |
| "hal_process_session_ftb_done: bad_pkt_size\n"); |
| return -E2BIG; |
| } else if (pkt->error_type != HFI_ERR_NONE) { |
| dprintk(VIDC_ERR, |
| "got buffer back with error %x\n", |
| pkt->error_type); |
| /* Proceed with the FBD */ |
| } |
| |
| data_done.device_id = device_id; |
| data_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| data_done.status = hfi_map_err_status(pkt->error_type); |
| data_done.size = sizeof(struct msm_vidc_cb_data_done); |
| data_done.clnt_data = 0; |
| |
| data_done.output_done.timestamp_hi = pkt->time_stamp_hi; |
| data_done.output_done.timestamp_lo = pkt->time_stamp_lo; |
| data_done.output_done.flags1 = pkt->flags; |
| data_done.output_done.mark_target = pkt->mark_target; |
| data_done.output_done.mark_data = pkt->mark_data; |
| data_done.output_done.stats = pkt->stats; |
| data_done.output_done.offset1 = pkt->offset; |
| data_done.output_done.alloc_len1 = pkt->alloc_len; |
| data_done.output_done.filled_len1 = pkt->filled_len; |
| data_done.output_done.picture_type = pkt->picture_type; |
| data_done.output_done.packet_buffer1 = |
| (phys_addr_t)pkt->packet_buffer; |
| data_done.output_done.extra_data_buffer = |
| (phys_addr_t)pkt->extra_data_buffer; |
| data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT; |
| } else /* if (is_decoder) */ { |
| struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt = |
| (struct hfi_msg_session_fbd_uncompressed_plane0_packet *) |
| msg_hdr; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%#x]\n", |
| pkt->session_id); |
| if (sizeof( |
| struct hfi_msg_session_fbd_uncompressed_plane0_packet) > |
| pkt->size) { |
| dprintk(VIDC_ERR, |
| "hal_process_session_ftb_done: bad_pkt_size\n"); |
| return -E2BIG; |
| } |
| |
| data_done.device_id = device_id; |
| data_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| data_done.status = hfi_map_err_status(pkt->error_type); |
| data_done.size = sizeof(struct msm_vidc_cb_data_done); |
| data_done.clnt_data = 0; |
| |
| data_done.output_done.stream_id = pkt->stream_id; |
| data_done.output_done.view_id = pkt->view_id; |
| data_done.output_done.timestamp_hi = pkt->time_stamp_hi; |
| data_done.output_done.timestamp_lo = pkt->time_stamp_lo; |
| data_done.output_done.flags1 = pkt->flags; |
| data_done.output_done.mark_target = pkt->mark_target; |
| data_done.output_done.mark_data = pkt->mark_data; |
| data_done.output_done.stats = pkt->stats; |
| data_done.output_done.alloc_len1 = pkt->alloc_len; |
| data_done.output_done.filled_len1 = pkt->filled_len; |
| data_done.output_done.offset1 = pkt->offset; |
| data_done.output_done.frame_width = pkt->frame_width; |
| data_done.output_done.frame_height = pkt->frame_height; |
| data_done.output_done.start_x_coord = pkt->start_x_coord; |
| data_done.output_done.start_y_coord = pkt->start_y_coord; |
| data_done.output_done.input_tag1 = pkt->input_tag; |
| data_done.output_done.picture_type = pkt->picture_type; |
| data_done.output_done.packet_buffer1 = pkt->packet_buffer; |
| data_done.output_done.extra_data_buffer = |
| pkt->extra_data_buffer; |
| |
| if (!pkt->stream_id) |
| data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT; |
| else if (pkt->stream_id == 1) |
| data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT2; |
| } |
| |
| trace_msm_v4l2_vidc_buffer_event_end("FTB", |
| (u32)data_done.output_done.packet_buffer1, |
| (((u64)data_done.output_done.timestamp_hi) << 32) |
| + ((u64)data_done.output_done.timestamp_lo), |
| data_done.output_done.alloc_len1, |
| data_done.output_done.filled_len1, |
| data_done.output_done.offset1); |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_FTB_DONE, |
| .response.data = data_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_start_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_session_start_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_START_DONE[%#x]\n", |
| pkt->session_id); |
| |
| if (!pkt || pkt->size != |
| sizeof(struct hfi_msg_session_start_done_packet)) { |
| dprintk(VIDC_ERR, "%s: bad packet/packet size\n", |
| __func__); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_START_DONE, |
| .response.cmd = cmd_done, |
| }; |
| return 0; |
| } |
| |
| static int hfi_process_session_stop_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_session_stop_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_STOP_DONE[%#x]\n", |
| pkt->session_id); |
| |
| if (!pkt || pkt->size != |
| sizeof(struct hfi_msg_session_stop_done_packet)) { |
| dprintk(VIDC_ERR, "%s: bad packet/packet size\n", |
| __func__); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_STOP_DONE, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_rel_res_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_session_release_resources_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE[%#x]\n", |
| pkt->session_id); |
| |
| if (!pkt || pkt->size != |
| sizeof(struct hfi_msg_session_release_resources_done_packet)) { |
| dprintk(VIDC_ERR, "%s: bad packet/packet size\n", |
| __func__); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_RELEASE_RESOURCE_DONE, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_rel_buf_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_session_release_buffers_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| if (!pkt || pkt->size < |
| sizeof(struct hfi_msg_session_release_buffers_done_packet)) { |
| dprintk(VIDC_ERR, "bad packet/packet size %d\n", |
| pkt ? pkt->size : 0); |
| return -E2BIG; |
| } |
| dprintk(VIDC_DBG, "RECEIVED:SESSION_RELEASE_BUFFER_DONE[%#x]\n", |
| pkt->session_id); |
| |
| cmd_done.device_id = device_id; |
| cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done); |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.data.buffer_info.buffer_addr = *pkt->rg_buffer_info; |
| cmd_done.size = sizeof(struct hal_buffer_info); |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_RELEASE_BUFFER_DONE, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_end_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_sys_session_end_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_END_DONE[%#x]\n", pkt->session_id); |
| |
| if (!pkt || pkt->size != |
| sizeof(struct hfi_msg_sys_session_end_done_packet)) { |
| dprintk(VIDC_ERR, "%s: bad packet/packet size\n", __func__); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_END_DONE, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_abort_done(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_sys_session_abort_done_packet *pkt = _pkt; |
| struct msm_vidc_cb_cmd_done cmd_done = {0}; |
| |
| dprintk(VIDC_DBG, "RECEIVED: SESSION_ABORT_DONE[%#x]\n", |
| pkt->session_id); |
| |
| if (!pkt || pkt->size != |
| sizeof(struct hfi_msg_sys_session_abort_done_packet)) { |
| dprintk(VIDC_ERR, "%s: bad packet/packet size: %d\n", |
| __func__, pkt ? pkt->size : 0); |
| return -E2BIG; |
| } |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_ABORT_DONE, |
| .response.cmd = cmd_done, |
| }; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_get_seq_hdr_done( |
| u32 device_id, |
| struct hfi_msg_session_get_sequence_header_done_packet *pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct msm_vidc_cb_data_done data_done = {0}; |
| |
| if (!pkt || pkt->size != |
| sizeof(struct |
| hfi_msg_session_get_sequence_header_done_packet)) { |
| dprintk(VIDC_ERR, "%s: bad packet/packet size\n", |
| __func__); |
| return -E2BIG; |
| } |
| |
| dprintk(VIDC_DBG, "RECEIVED:SESSION_GET_SEQ_HDR_DONE[%#x]\n", |
| pkt->session_id); |
| |
| data_done.device_id = device_id; |
| data_done.size = sizeof(struct msm_vidc_cb_data_done); |
| data_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| data_done.status = hfi_map_err_status(pkt->error_type); |
| data_done.output_done.packet_buffer1 = |
| (phys_addr_t)pkt->sequence_header; |
| data_done.output_done.filled_len1 = pkt->header_len; |
| dprintk(VIDC_INFO, "seq_hdr: %#x, Length: %d\n", |
| pkt->sequence_header, pkt->header_len); |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_SESSION_GET_SEQ_HDR_DONE, |
| .response.data = data_done, |
| }; |
| |
| return 0; |
| } |
| |
| static void hfi_process_sys_get_prop_image_version( |
| struct hfi_msg_sys_property_info_packet *pkt) |
| { |
| int i = 0; |
| size_t smem_block_size = 0; |
| u8 *smem_table_ptr; |
| char version[256]; |
| const u32 version_string_size = 128; |
| const u32 smem_image_index_venus = 14 * 128; |
| u8 *str_image_version; |
| int req_bytes; |
| |
| req_bytes = pkt->size - sizeof(*pkt); |
| if (req_bytes < version_string_size || |
| !pkt->rg_property_data[1] || |
| pkt->num_properties > 1) { |
| dprintk(VIDC_ERR, |
| "%s: bad_pkt: %d\n", __func__, req_bytes); |
| return; |
| } |
| str_image_version = (u8 *)&pkt->rg_property_data[1]; |
| /* |
| * The version string returned by firmware includes null |
| * characters at the start and in between. Replace the null |
| * characters with space, to print the version info. |
| */ |
| for (i = 0; i < version_string_size; i++) { |
| if (str_image_version[i] != '\0') |
| version[i] = str_image_version[i]; |
| else |
| version[i] = ' '; |
| } |
| version[i] = '\0'; |
| dprintk(VIDC_DBG, "F/W version: %s\n", version); |
| |
| smem_table_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY, |
| SMEM_IMAGE_VERSION_TABLE, &smem_block_size); |
| if ((smem_image_index_venus + version_string_size) <= smem_block_size && |
| smem_table_ptr) |
| memcpy(smem_table_ptr + smem_image_index_venus, |
| str_image_version, version_string_size); |
| } |
| |
| static int hfi_process_sys_property_info(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| struct hfi_msg_sys_property_info_packet *pkt = _pkt; |
| |
| if (!pkt) { |
| dprintk(VIDC_ERR, "%s: invalid param\n", __func__); |
| return -EINVAL; |
| } else if (pkt->size < sizeof(*pkt)) { |
| dprintk(VIDC_ERR, |
| "%s: bad_pkt_size\n", __func__); |
| return -E2BIG; |
| } else if (!pkt->num_properties) { |
| dprintk(VIDC_ERR, |
| "%s: no_properties\n", __func__); |
| return -EINVAL; |
| } |
| |
| switch (pkt->rg_property_data[0]) { |
| case HFI_PROPERTY_SYS_IMAGE_VERSION: |
| hfi_process_sys_get_prop_image_version(pkt); |
| |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_RESPONSE_UNUSED, |
| }; |
| return 0; |
| default: |
| dprintk(VIDC_DBG, |
| "%s: unknown_prop_id: %x\n", __func__, |
| pkt->rg_property_data[0]); |
| return -ENOTSUPP; |
| } |
| |
| } |
| |
| static int hfi_process_ignore(u32 device_id, |
| void *_pkt, |
| struct msm_vidc_cb_info *info) |
| { |
| *info = (struct msm_vidc_cb_info) { |
| .response_type = HAL_RESPONSE_UNUSED, |
| }; |
| |
| return 0; |
| } |
| |
| int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, |
| struct msm_vidc_cb_info *info) |
| { |
| typedef int (*pkt_func_def)(u32, void *, struct msm_vidc_cb_info *info); |
| pkt_func_def pkt_func = NULL; |
| |
| if (!info || !msg_hdr || msg_hdr->size < VIDC_IFACEQ_MIN_PKT_SIZE) { |
| dprintk(VIDC_ERR, "%s: bad packet/packet size\n", |
| __func__); |
| return -EINVAL; |
| } |
| |
| dprintk(VIDC_DBG, "Parse response %#x\n", msg_hdr->packet); |
| switch (msg_hdr->packet) { |
| case HFI_MSG_EVENT_NOTIFY: |
| pkt_func = (pkt_func_def)hfi_process_event_notify; |
| break; |
| case HFI_MSG_SYS_INIT_DONE: |
| pkt_func = (pkt_func_def)hfi_process_sys_init_done; |
| break; |
| case HFI_MSG_SYS_SESSION_INIT_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_init_done; |
| break; |
| case HFI_MSG_SYS_PROPERTY_INFO: |
| pkt_func = (pkt_func_def)hfi_process_sys_property_info; |
| break; |
| case HFI_MSG_SYS_SESSION_END_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_end_done; |
| break; |
| case HFI_MSG_SESSION_LOAD_RESOURCES_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_load_res_done; |
| break; |
| case HFI_MSG_SESSION_START_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_start_done; |
| break; |
| case HFI_MSG_SESSION_STOP_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_stop_done; |
| break; |
| case HFI_MSG_SESSION_EMPTY_BUFFER_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_etb_done; |
| break; |
| case HFI_MSG_SESSION_FILL_BUFFER_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_ftb_done; |
| break; |
| case HFI_MSG_SESSION_FLUSH_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_flush_done; |
| break; |
| case HFI_MSG_SESSION_PROPERTY_INFO: |
| pkt_func = (pkt_func_def)hfi_process_session_prop_info; |
| break; |
| case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_rel_res_done; |
| break; |
| case HFI_MSG_SYS_RELEASE_RESOURCE: |
| pkt_func = (pkt_func_def)hfi_process_sys_rel_resource_done; |
| break; |
| case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE: |
| pkt_func = (pkt_func_def) hfi_process_session_get_seq_hdr_done; |
| break; |
| case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_rel_buf_done; |
| break; |
| case HFI_MSG_SYS_SESSION_ABORT_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_abort_done; |
| break; |
| case HFI_MSG_SESSION_SYNC_DONE: |
| pkt_func = (pkt_func_def)hfi_process_ignore; |
| break; |
| default: |
| dprintk(VIDC_DBG, "Unable to parse message: %#x\n", |
| msg_hdr->packet); |
| break; |
| } |
| |
| return pkt_func ? |
| pkt_func(device_id, (void *)msg_hdr, info) : -ENOTSUPP; |
| } |