| /* Copyright (c) 2010, Code Aurora Forum. 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. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301, USA. |
| * |
| */ |
| |
| #include "video_core_type.h" |
| #include "vcd_ddl_utils.h" |
| #include "vcd_ddl.h" |
| |
| #if DEBUG |
| #define DBG(x...) printk(KERN_DEBUG x) |
| #else |
| #define DBG(x...) |
| #endif |
| |
| #define ERR(x...) printk(KERN_ERR x) |
| |
| #define INVALID_CHANNEL_NUMBER 1 |
| #define INVALID_COMMAND_ID 2 |
| #define CHANNEL_ALREADY_IN_USE 3 |
| #define CHANNEL_NOT_SET_BEFORE_CHANNEL_CLOSE 4 |
| #define CHANNEL_SET_ERROR_INIT_CODEC 5 |
| #define INIT_CODEC_ALREADY_CALLED 6 |
| #define CHANNEL_SET_ERROR_INIT_BUFFERS 7 |
| #define INIT_CODEC_ERROR_INIT_BUFFERS 8 |
| #define INIT_BUFFER_ALREADY_CALLED 9 |
| #define CHANNEL_SET_ERROR_FRAME_RUN 10 |
| #define INIT_CODEC_ERROR_FRAME_RUN 11 |
| #define INIT_BUFFERS_ERROR_FRAME_RUN 12 |
| #define CODEC_LIMIT_EXCEEDED 13 |
| #define FIRMWARE_SIZE_ZERO 14 |
| #define FIRMWARE_ADDRESS_EXT_ZERO 15 |
| #define CONTEXT_DMA_IN_ERROR 16 |
| #define CONTEXT_DMA_OUT_ERROR 17 |
| #define PROGRAM_DMA_ERROR 18 |
| #define CONTEXT_STORE_EXT_ADD_ZERO 19 |
| #define MEM_ALLOCATION_FAILED 20 |
| |
| |
| #define UNSUPPORTED_FEATURE_IN_PROFILE 27 |
| #define RESOLUTION_NOT_SUPPORTED 28 |
| #define HEADER_NOT_FOUND 52 |
| #define MB_NUM_INVALID 61 |
| #define FRAME_RATE_NOT_SUPPORTED 62 |
| #define INVALID_QP_VALUE 63 |
| #define INVALID_RC_REACTION_COEFFICIENT 64 |
| #define INVALID_CPB_SIZE_AT_GIVEN_LEVEL 65 |
| |
| #define ALLOC_DPB_SIZE_NOT_SUFFICIENT 71 |
| #define ALLOC_DB_SIZE_NOT_SUFFICIENT 72 |
| #define ALLOC_COMV_SIZE_NOT_SUFFICIENT 73 |
| #define NUM_BUF_OUT_OF_RANGE 74 |
| #define NULL_CONTEXT_POINTER 75 |
| #define NULL_COMAMND_CONTROL_COMM_POINTER 76 |
| #define NULL_METADATA_INPUT_POINTER 77 |
| #define NULL_DPB_POINTER 78 |
| #define NULL_DB_POINTER 79 |
| #define NULL_COMV_POINTER 80 |
| |
| #define DIVIDE_BY_ZERO 81 |
| #define BIT_STREAM_BUF_EXHAUST 82 |
| #define DMA_NOT_STOPPED 83 |
| #define DMA_TX_NOT_COMPLETE 84 |
| |
| #define MB_HEADER_NOT_DONE 85 |
| #define MB_COEFF_NOT_DONE 86 |
| #define CODEC_SLICE_NOT_DONE 87 |
| #define VME_NOT_READY 88 |
| #define VC1_BITPLANE_DECODE_ERR 89 |
| |
| |
| #define VSP_NOT_READY 90 |
| #define BUFFER_FULL_STATE 91 |
| |
| #define RESOLUTION_MISMATCH 112 |
| #define NV_QUANT_ERR 113 |
| #define SYNC_MARKER_ERR 114 |
| #define FEATURE_NOT_SUPPORTED 115 |
| #define MEM_CORRUPTION 116 |
| #define INVALID_REFERENCE_FRAME 117 |
| #define PICTURE_CODING_TYPE_ERR 118 |
| #define MV_RANGE_ERR 119 |
| #define PICTURE_STRUCTURE_ERR 120 |
| #define SLICE_ADDR_INVALID 121 |
| #define NON_PAIRED_FIELD_NOT_SUPPORTED 122 |
| #define NON_FRAME_DATA_RECEIVED 123 |
| #define INCOMPLETE_FRAME 124 |
| #define NO_BUFFER_RELEASED_FROM_HOST 125 |
| #define PICTURE_MANAGEMENT_ERROR 128 |
| #define INVALID_MMCO 129 |
| #define INVALID_PIC_REORDERING 130 |
| #define INVALID_POC_TYPE 131 |
| #define ACTIVE_SPS_NOT_PRESENT 132 |
| #define ACTIVE_PPS_NOT_PRESENT 133 |
| #define INVALID_SPS_ID 134 |
| #define INVALID_PPS_ID 135 |
| |
| |
| #define METADATA_NO_SPACE_QP 151 |
| #define METADATA_NO_SAPCE_CONCEAL_MB 152 |
| #define METADATA_NO_SPACE_VC1_PARAM 153 |
| #define METADATA_NO_SPACE_SEI 154 |
| #define METADATA_NO_SPACE_VUI 155 |
| #define METADATA_NO_SPACE_EXTRA 156 |
| #define METADATA_NO_SPACE_DATA_NONE 157 |
| #define FRAME_RATE_UNKNOWN 158 |
| #define ASPECT_RATIO_UNKOWN 159 |
| #define COLOR_PRIMARIES_UNKNOWN 160 |
| #define TRANSFER_CHAR_UNKWON 161 |
| #define MATRIX_COEFF_UNKNOWN 162 |
| #define NON_SEQ_SLICE_ADDR 163 |
| #define BROKEN_LINK 164 |
| #define FRAME_CONCEALED 165 |
| #define PROFILE_UNKOWN 166 |
| #define LEVEL_UNKOWN 167 |
| #define BIT_RATE_NOT_SUPPORTED 168 |
| #define COLOR_DIFF_FORMAT_NOT_SUPPORTED 169 |
| #define NULL_EXTRA_METADATA_POINTER 170 |
| #define SYNC_POINT_NOT_RECEIVED_STARTED_DECODING 171 |
| #define NULL_FW_DEBUG_INFO_POINTER 172 |
| #define ALLOC_DEBUG_INFO_SIZE_INSUFFICIENT 173 |
| #define MAX_STAGE_COUNTER_EXCEEDED 174 |
| |
| #define METADATA_NO_SPACE_MB_INFO 180 |
| #define METADATA_NO_SPACE_SLICE_SIZE 181 |
| #define RESOLUTION_WARNING 182 |
| |
| void ddl_hw_fatal_cb(struct ddl_context *ddl_context) |
| { |
| /* Invalidate the command state */ |
| ddl_move_command_state(ddl_context, DDL_CMD_INVALID); |
| ddl_context->device_state = DDL_DEVICE_HWFATAL; |
| |
| /* callback to the client to indicate hw fatal error */ |
| ddl_context->ddl_callback(VCD_EVT_IND_HWERRFATAL, |
| VCD_ERR_HW_FATAL, NULL, 0, |
| (void *)ddl_context->current_ddl, |
| ddl_context->client_data); |
| |
| DDL_IDLE(ddl_context); |
| } |
| |
| static u32 ddl_handle_hw_fatal_errors(struct ddl_context |
| *ddl_context) |
| { |
| u32 status = false; |
| |
| switch (ddl_context->cmd_err_status) { |
| |
| case INVALID_CHANNEL_NUMBER: |
| case INVALID_COMMAND_ID: |
| case CHANNEL_ALREADY_IN_USE: |
| case CHANNEL_NOT_SET_BEFORE_CHANNEL_CLOSE: |
| case CHANNEL_SET_ERROR_INIT_CODEC: |
| case INIT_CODEC_ALREADY_CALLED: |
| case CHANNEL_SET_ERROR_INIT_BUFFERS: |
| case INIT_CODEC_ERROR_INIT_BUFFERS: |
| case INIT_BUFFER_ALREADY_CALLED: |
| case CHANNEL_SET_ERROR_FRAME_RUN: |
| case INIT_CODEC_ERROR_FRAME_RUN: |
| case INIT_BUFFERS_ERROR_FRAME_RUN: |
| case CODEC_LIMIT_EXCEEDED: |
| case FIRMWARE_SIZE_ZERO: |
| case FIRMWARE_ADDRESS_EXT_ZERO: |
| |
| case CONTEXT_DMA_IN_ERROR: |
| case CONTEXT_DMA_OUT_ERROR: |
| case PROGRAM_DMA_ERROR: |
| case CONTEXT_STORE_EXT_ADD_ZERO: |
| case MEM_ALLOCATION_FAILED: |
| |
| case DIVIDE_BY_ZERO: |
| case DMA_NOT_STOPPED: |
| case DMA_TX_NOT_COMPLETE: |
| |
| case VSP_NOT_READY: |
| case BUFFER_FULL_STATE: |
| ERR("HW FATAL ERROR"); |
| ddl_hw_fatal_cb(ddl_context); |
| status = true; |
| break; |
| } |
| return status; |
| } |
| |
| void ddl_client_fatal_cb(struct ddl_context *ddl_context) |
| { |
| struct ddl_client_context *ddl = |
| ddl_context->current_ddl; |
| |
| if (ddl_context->cmd_state == DDL_CMD_DECODE_FRAME) |
| ddl_decode_dynamic_property(ddl, false); |
| else if (ddl_context->cmd_state == DDL_CMD_ENCODE_FRAME) |
| ddl_encode_dynamic_property(ddl, false); |
| |
| ddl_move_command_state(ddl_context, DDL_CMD_INVALID); |
| |
| ddl_move_client_state(ddl, DDL_CLIENT_FATAL_ERROR); |
| |
| ddl_context->ddl_callback |
| ( |
| VCD_EVT_IND_HWERRFATAL, |
| VCD_ERR_CLIENT_FATAL, |
| NULL, |
| 0, |
| (void *)ddl, |
| ddl_context->client_data |
| ); |
| |
| DDL_IDLE(ddl_context); |
| } |
| |
| static u32 ddl_handle_client_fatal_errors(struct ddl_context |
| *ddl_context) |
| { |
| u32 status = false; |
| |
| switch (ddl_context->cmd_err_status) { |
| case UNSUPPORTED_FEATURE_IN_PROFILE: |
| case RESOLUTION_NOT_SUPPORTED: |
| case HEADER_NOT_FOUND: |
| case INVALID_SPS_ID: |
| case INVALID_PPS_ID: |
| |
| case MB_NUM_INVALID: |
| case FRAME_RATE_NOT_SUPPORTED: |
| case INVALID_QP_VALUE: |
| case INVALID_RC_REACTION_COEFFICIENT: |
| case INVALID_CPB_SIZE_AT_GIVEN_LEVEL: |
| |
| case ALLOC_DPB_SIZE_NOT_SUFFICIENT: |
| case ALLOC_DB_SIZE_NOT_SUFFICIENT: |
| case ALLOC_COMV_SIZE_NOT_SUFFICIENT: |
| case NUM_BUF_OUT_OF_RANGE: |
| case NULL_CONTEXT_POINTER: |
| case NULL_COMAMND_CONTROL_COMM_POINTER: |
| case NULL_METADATA_INPUT_POINTER: |
| case NULL_DPB_POINTER: |
| case NULL_DB_POINTER: |
| case NULL_COMV_POINTER: |
| { |
| status = true; |
| break; |
| } |
| } |
| |
| if (!status) |
| ERR("UNKNOWN-OP-FAILED"); |
| |
| ddl_client_fatal_cb(ddl_context); |
| |
| return true; |
| } |
| |
| static void ddl_input_failed_cb(struct ddl_context *ddl_context, |
| u32 vcd_event, u32 vcd_status) |
| { |
| struct ddl_client_context *ddl = ddl_context->current_ddl; |
| |
| ddl_move_command_state(ddl_context, DDL_CMD_INVALID); |
| |
| if (ddl->decoding) |
| ddl_decode_dynamic_property(ddl, false); |
| else |
| ddl_encode_dynamic_property(ddl, false); |
| |
| ddl_context->ddl_callback(vcd_event, |
| vcd_status, &ddl->input_frame, |
| sizeof(struct ddl_frame_data_tag), |
| (void *)ddl, ddl_context->client_data); |
| |
| ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME); |
| } |
| |
| static u32 ddl_handle_core_recoverable_errors(struct ddl_context \ |
| *ddl_context) |
| { |
| struct ddl_client_context *ddl = ddl_context->current_ddl; |
| u32 vcd_status = VCD_S_SUCCESS; |
| u32 vcd_event = VCD_EVT_RESP_INPUT_DONE; |
| u32 eos = false, pending_display = 0, release_mask = 0; |
| |
| if (ddl_context->cmd_state != DDL_CMD_DECODE_FRAME && |
| ddl_context->cmd_state != DDL_CMD_ENCODE_FRAME) { |
| return false; |
| } |
| switch (ddl_context->cmd_err_status) { |
| case NON_PAIRED_FIELD_NOT_SUPPORTED: |
| { |
| vcd_status = VCD_ERR_INTRLCD_FIELD_DROP; |
| break; |
| } |
| case NO_BUFFER_RELEASED_FROM_HOST: |
| { |
| /* lets check sanity of this error */ |
| release_mask = |
| ddl->codec_data.decoder.dpb_mask.hw_mask; |
| while (release_mask > 0) { |
| if ((release_mask & 0x1)) |
| pending_display += 1; |
| release_mask >>= 1; |
| } |
| |
| if (pending_display >= |
| ddl->codec_data.decoder.min_dpb_num) { |
| DBG("FWISSUE-REQBUF!!"); |
| /* callback to client for client fatal error */ |
| ddl_client_fatal_cb(ddl_context); |
| return true ; |
| } |
| vcd_event = VCD_EVT_RESP_OUTPUT_REQ; |
| break; |
| } |
| case BIT_STREAM_BUF_EXHAUST: |
| case MB_HEADER_NOT_DONE: |
| case MB_COEFF_NOT_DONE: |
| case CODEC_SLICE_NOT_DONE: |
| case VME_NOT_READY: |
| case VC1_BITPLANE_DECODE_ERR: |
| { |
| u32 reset_core; |
| /* need to reset the internal core hw engine */ |
| reset_core = ddl_hal_engine_reset(ddl_context); |
| if (!reset_core) |
| return true; |
| /* fall through to process bitstream error handling */ |
| } |
| case RESOLUTION_MISMATCH: |
| case NV_QUANT_ERR: |
| case SYNC_MARKER_ERR: |
| case FEATURE_NOT_SUPPORTED: |
| case MEM_CORRUPTION: |
| case INVALID_REFERENCE_FRAME: |
| case PICTURE_CODING_TYPE_ERR: |
| case MV_RANGE_ERR: |
| case PICTURE_STRUCTURE_ERR: |
| case SLICE_ADDR_INVALID: |
| case NON_FRAME_DATA_RECEIVED: |
| case INCOMPLETE_FRAME: |
| case PICTURE_MANAGEMENT_ERROR: |
| case INVALID_MMCO: |
| case INVALID_PIC_REORDERING: |
| case INVALID_POC_TYPE: |
| case ACTIVE_SPS_NOT_PRESENT: |
| case ACTIVE_PPS_NOT_PRESENT: |
| { |
| vcd_status = VCD_ERR_BITSTREAM_ERR; |
| break; |
| } |
| } |
| |
| if (!vcd_status && vcd_event == VCD_EVT_RESP_INPUT_DONE) |
| return false; |
| |
| ddl->input_frame.frm_trans_end = true; |
| |
| eos = ((vcd_event == VCD_EVT_RESP_INPUT_DONE) && |
| ((VCD_FRAME_FLAG_EOS & ddl->input_frame. |
| vcd_frm.flags))); |
| |
| if ((ddl->decoding && eos) || |
| (!ddl->decoding)) |
| ddl->input_frame.frm_trans_end = false; |
| |
| if (vcd_event == VCD_EVT_RESP_INPUT_DONE && |
| ddl->decoding && |
| !ddl->codec_data.decoder.header_in_start && |
| !ddl->codec_data.decoder.dec_disp_info.img_size_x && |
| !ddl->codec_data.decoder.dec_disp_info.img_size_y |
| ) { |
| /* this is first frame seq. header only case */ |
| vcd_status = VCD_S_SUCCESS; |
| ddl->input_frame.vcd_frm.flags |= |
| VCD_FRAME_FLAG_CODECCONFIG; |
| ddl->input_frame.frm_trans_end = !eos; |
| /* put just some non - zero value */ |
| ddl->codec_data.decoder.dec_disp_info.img_size_x = 0xff; |
| } |
| /* inform client about input failed */ |
| ddl_input_failed_cb(ddl_context, vcd_event, vcd_status); |
| |
| /* for Encoder case, we need to send output done also */ |
| if (!ddl->decoding) { |
| /* transaction is complete after this callback */ |
| ddl->output_frame.frm_trans_end = !eos; |
| /* error case: NO data present */ |
| ddl->output_frame.vcd_frm.data_len = 0; |
| /* call back to client for output frame done */ |
| ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE, |
| VCD_ERR_FAIL, &(ddl->output_frame), |
| sizeof(struct ddl_frame_data_tag), |
| (void *)ddl, ddl_context->client_data); |
| |
| if (eos) { |
| DBG("ENC-EOS_DONE"); |
| /* send client EOS DONE callback */ |
| ddl_context->ddl_callback(VCD_EVT_RESP_EOS_DONE, |
| VCD_S_SUCCESS, NULL, 0, (void *)ddl, |
| ddl_context->client_data); |
| } |
| } |
| |
| /* if it is decoder EOS case */ |
| if (ddl->decoding && eos) |
| ddl_decode_eos_run(ddl); |
| else |
| DDL_IDLE(ddl_context); |
| |
| return true; |
| } |
| |
| static u32 ddl_handle_core_warnings(u32 err_status) |
| { |
| u32 status = false; |
| |
| switch (err_status) { |
| case FRAME_RATE_UNKNOWN: |
| case ASPECT_RATIO_UNKOWN: |
| case COLOR_PRIMARIES_UNKNOWN: |
| case TRANSFER_CHAR_UNKWON: |
| case MATRIX_COEFF_UNKNOWN: |
| case NON_SEQ_SLICE_ADDR: |
| case BROKEN_LINK: |
| case FRAME_CONCEALED: |
| case PROFILE_UNKOWN: |
| case LEVEL_UNKOWN: |
| case BIT_RATE_NOT_SUPPORTED: |
| case COLOR_DIFF_FORMAT_NOT_SUPPORTED: |
| case NULL_EXTRA_METADATA_POINTER: |
| case SYNC_POINT_NOT_RECEIVED_STARTED_DECODING: |
| |
| case NULL_FW_DEBUG_INFO_POINTER: |
| case ALLOC_DEBUG_INFO_SIZE_INSUFFICIENT: |
| case MAX_STAGE_COUNTER_EXCEEDED: |
| |
| case METADATA_NO_SPACE_MB_INFO: |
| case METADATA_NO_SPACE_SLICE_SIZE: |
| case RESOLUTION_WARNING: |
| |
| /* decoder warnings */ |
| case METADATA_NO_SPACE_QP: |
| case METADATA_NO_SAPCE_CONCEAL_MB: |
| case METADATA_NO_SPACE_VC1_PARAM: |
| case METADATA_NO_SPACE_SEI: |
| case METADATA_NO_SPACE_VUI: |
| case METADATA_NO_SPACE_EXTRA: |
| case METADATA_NO_SPACE_DATA_NONE: |
| { |
| status = true; |
| DBG("CMD-WARNING-IGNORED!!"); |
| break; |
| } |
| } |
| return status; |
| } |
| |
| u32 ddl_handle_core_errors(struct ddl_context *ddl_context) |
| { |
| u32 status = false; |
| |
| if (!ddl_context->cmd_err_status && |
| !ddl_context->disp_pic_err_status) |
| return false; |
| |
| if (ddl_context->cmd_state == DDL_CMD_INVALID) { |
| DBG("SPURIOUS_INTERRUPT_ERROR"); |
| return true; |
| } |
| |
| if (!ddl_context->op_failed) { |
| u32 disp_status; |
| status = ddl_handle_core_warnings(ddl_context-> |
| cmd_err_status); |
| disp_status = ddl_handle_core_warnings( |
| ddl_context->disp_pic_err_status); |
| if (!status && !disp_status) |
| DBG("ddl_warning:Unknown"); |
| |
| return false; |
| } |
| |
| ERR("\n %s(): OPFAILED!!", __func__); |
| ERR("\n CMD_ERROR_STATUS = %u, DISP_ERR_STATUS = %u", |
| ddl_context->cmd_err_status, |
| ddl_context->disp_pic_err_status); |
| |
| status = ddl_handle_hw_fatal_errors(ddl_context); |
| |
| if (!status) |
| status = ddl_handle_core_recoverable_errors(ddl_context); |
| |
| if (!status) |
| status = ddl_handle_client_fatal_errors(ddl_context); |
| |
| return status; |
| } |