M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,637 @@
/* Copyright (c) 2010-2012, 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 <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#include "vcd_ddl_metadata.h"
#include "vcd_res_tracker_api.h"
u32 ddl_device_init(struct ddl_init_config *ddl_init_config,
void *client_data)
{
struct ddl_context *ddl_context;
u32 status = VCD_S_SUCCESS;
if ((!ddl_init_config) ||
(!ddl_init_config->ddl_callback) ||
(!ddl_init_config->core_virtual_base_addr)
) {
VIDC_LOGERR_STRING("ddl_dev_init:Bad_argument");
return VCD_ERR_ILLEGAL_PARM;
}
ddl_context = ddl_get_context();
if (DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dev_init:Multiple_init");
return VCD_ERR_ILLEGAL_OP;
}
if (DDL_IS_BUSY(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dev_init:Ddl_busy");
return VCD_ERR_BUSY;
}
DDL_MEMSET(ddl_context, 0, sizeof(struct ddl_context));
DDL_BUSY(ddl_context);
if (res_trk_get_enable_ion()) {
VIDC_LOGERR_STRING("ddl_dev_init: ION framework enabled");
ddl_context->video_ion_client =
res_trk_get_ion_client();
if (!ddl_context->video_ion_client) {
VIDC_LOGERR_STRING("ION client create failed");
return VCD_ERR_ILLEGAL_OP;
}
}
ddl_context->memtype = res_trk_get_mem_type();
if (ddl_context->memtype == -1) {
VIDC_LOGERR_STRING("ddl_dev_init:Invalid Memtype");
return VCD_ERR_ILLEGAL_PARM;
}
ddl_context->ddl_callback = ddl_init_config->ddl_callback;
ddl_context->interrupt_clr = ddl_init_config->interrupt_clr;
ddl_context->core_virtual_base_addr =
ddl_init_config->core_virtual_base_addr;
ddl_context->client_data = client_data;
vidc_720p_set_device_virtual_base(ddl_context->
core_virtual_base_addr);
ddl_context->current_ddl = NULL;
ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
ddl_client_transact(DDL_INIT_CLIENTS, NULL);
ddl_pmem_alloc(&ddl_context->context_buf_addr,
DDL_CONTEXT_MEMORY, DDL_LINEAR_BUFFER_ALIGN_BYTES);
if (!ddl_context->context_buf_addr.virtual_base_addr) {
VIDC_LOGERR_STRING("ddl_dev_init:Context_alloc_fail");
status = VCD_ERR_ALLOC_FAIL;
}
if (!status) {
ddl_pmem_alloc(&ddl_context->db_line_buffer,
DDL_DB_LINE_BUF_SIZE,
DDL_TILE_BUFFER_ALIGN_BYTES);
if (!ddl_context->db_line_buffer.virtual_base_addr) {
VIDC_LOGERR_STRING("ddl_dev_init:Line_buf_alloc_fail");
status = VCD_ERR_ALLOC_FAIL;
}
}
if (!status) {
ddl_pmem_alloc(&ddl_context->data_partition_tempbuf,
DDL_MPEG4_DATA_PARTITION_BUF_SIZE,
DDL_TILE_BUFFER_ALIGN_BYTES);
if (ddl_context->data_partition_tempbuf.virtual_base_addr \
== NULL) {
VIDC_LOGERR_STRING
("ddl_dev_init:Data_partition_buf_alloc_fail");
status = VCD_ERR_ALLOC_FAIL;
}
}
if (!status) {
ddl_pmem_alloc(&ddl_context->metadata_shared_input,
DDL_METADATA_TOTAL_INPUTBUFSIZE,
DDL_LINEAR_BUFFER_ALIGN_BYTES);
if (!ddl_context->metadata_shared_input.virtual_base_addr) {
VIDC_LOGERR_STRING
("ddl_dev_init:metadata_shared_input_alloc_fail");
status = VCD_ERR_ALLOC_FAIL;
}
}
if (!status) {
ddl_pmem_alloc(&ddl_context->dbg_core_dump, \
DDL_DBG_CORE_DUMP_SIZE, \
DDL_LINEAR_BUFFER_ALIGN_BYTES);
if (!ddl_context->dbg_core_dump.virtual_base_addr) {
VIDC_LOGERR_STRING
("ddl_dev_init:dbg_core_dump_alloc_failed");
status = VCD_ERR_ALLOC_FAIL;
}
ddl_context->enable_dbg_core_dump = 0;
}
if (!status && !vcd_fw_init()) {
VIDC_LOGERR_STRING("ddl_dev_init:fw_init_failed");
status = VCD_ERR_ALLOC_FAIL;
}
if (status) {
ddl_release_context_buffers(ddl_context);
DDL_IDLE(ddl_context);
return status;
}
ddl_move_command_state(ddl_context, DDL_CMD_DMA_INIT);
ddl_core_init(ddl_context);
return status;
}
u32 ddl_device_release(void *client_data)
{
struct ddl_context *ddl_context;
ddl_context = ddl_get_context();
if (DDL_IS_BUSY(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dev_rel:Ddl_busy");
return VCD_ERR_BUSY;
}
if (!DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dev_rel:Not_inited");
return VCD_ERR_ILLEGAL_OP;
}
if (!ddl_client_transact(DDL_ACTIVE_CLIENT, NULL)) {
VIDC_LOGERR_STRING("ddl_dev_rel:Client_present_err");
return VCD_ERR_CLIENT_PRESENT;
}
DDL_BUSY(ddl_context);
ddl_context->device_state = DDL_DEVICE_NOTINIT;
ddl_context->client_data = client_data;
ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
vidc_720p_stop_fw();
VIDC_LOG_STRING("FW_ENDDONE");
ddl_release_context_buffers(ddl_context);
ddl_context->video_ion_client = NULL;
DDL_IDLE(ddl_context);
return VCD_S_SUCCESS;
}
u32 ddl_open(u32 **ddl_handle, u32 decoding)
{
struct ddl_context *ddl_context;
struct ddl_client_context *ddl;
u32 status;
if (!ddl_handle) {
VIDC_LOGERR_STRING("ddl_open:Bad_handle");
return VCD_ERR_BAD_HANDLE;
}
ddl_context = ddl_get_context();
if (!DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_open:Not_inited");
return VCD_ERR_ILLEGAL_OP;
}
status = ddl_client_transact(DDL_GET_CLIENT, &ddl);
if (status) {
VIDC_LOGERR_STRING("ddl_open:Client_trasac_failed");
return status;
}
ddl_move_client_state(ddl, DDL_CLIENT_OPEN);
ddl->codec_data.hdr.decoding = decoding;
ddl->decoding = decoding;
ddl_set_default_meta_data_hdr(ddl);
ddl_set_initial_default_values(ddl);
*ddl_handle = (u32 *) ddl;
return VCD_S_SUCCESS;
}
u32 ddl_close(u32 **ddl_handle)
{
struct ddl_context *ddl_context;
struct ddl_client_context **ddl =
(struct ddl_client_context **)ddl_handle;
if (!ddl || !*ddl) {
VIDC_LOGERR_STRING("ddl_close:Bad_handle");
return VCD_ERR_BAD_HANDLE;
}
ddl_context = ddl_get_context();
if (!DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_close:Not_inited");
return VCD_ERR_ILLEGAL_OP;
}
if (!DDLCLIENT_STATE_IS(*ddl, DDL_CLIENT_OPEN)) {
VIDC_LOGERR_STRING("ddl_close:Not_in_open_state");
return VCD_ERR_ILLEGAL_OP;
}
ddl_move_client_state(*ddl, DDL_CLIENT_INVALID);
if ((*ddl)->decoding) {
vcd_fw_transact(false, true,
(*ddl)->codec_data.decoder.codec.codec);
} else {
vcd_fw_transact(false, false,
(*ddl)->codec_data.encoder.codec.codec);
}
ddl_client_transact(DDL_FREE_CLIENT, ddl);
return VCD_S_SUCCESS;
}
u32 ddl_encode_start(u32 *ddl_handle, void *client_data)
{
struct ddl_client_context *ddl =
(struct ddl_client_context *)ddl_handle;
struct ddl_context *ddl_context;
struct ddl_encoder_data *encoder;
u32 dpb_size;
ddl_context = ddl_get_context();
if (!DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_enc_start:Not_inited");
return VCD_ERR_ILLEGAL_OP;
}
if (DDL_IS_BUSY(ddl_context)) {
VIDC_LOGERR_STRING("ddl_enc_start:Ddl_busy");
return VCD_ERR_BUSY;
}
if (!ddl || ddl->decoding) {
VIDC_LOGERR_STRING("ddl_enc_start:Bad_handle");
return VCD_ERR_BAD_HANDLE;
}
if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN)) {
VIDC_LOGERR_STRING("ddl_enc_start:Not_opened");
return VCD_ERR_ILLEGAL_OP;
}
if (!ddl_encoder_ready_to_start(ddl)) {
VIDC_LOGERR_STRING("ddl_enc_start:Err_param_settings");
return VCD_ERR_ILLEGAL_OP;
}
encoder = &ddl->codec_data.encoder;
dpb_size = ddl_get_yuv_buffer_size(&encoder->frame_size,
&encoder->re_con_buf_format, false,
encoder->codec.codec);
dpb_size *= DDL_ENC_NUM_DPB_BUFFERS;
ddl_pmem_alloc(&encoder->enc_dpb_addr,
dpb_size, DDL_TILE_BUFFER_ALIGN_BYTES);
if (!encoder->enc_dpb_addr.virtual_base_addr) {
VIDC_LOGERR_STRING("ddl_enc_start:Dpb_alloc_failed");
return VCD_ERR_ALLOC_FAIL;
}
if ((encoder->codec.codec == VCD_CODEC_MPEG4 &&
!encoder->short_header.short_header) ||
encoder->codec.codec == VCD_CODEC_H264) {
ddl_pmem_alloc(&encoder->seq_header,
DDL_ENC_SEQHEADER_SIZE,
DDL_LINEAR_BUFFER_ALIGN_BYTES);
if (!encoder->seq_header.virtual_base_addr) {
ddl_pmem_free(&encoder->enc_dpb_addr);
VIDC_LOGERR_STRING
("ddl_enc_start:Seq_hdr_alloc_failed");
return VCD_ERR_ALLOC_FAIL;
}
} else {
encoder->seq_header.buffer_size = 0;
encoder->seq_header.virtual_base_addr = 0;
}
DDL_BUSY(ddl_context);
ddl_context->current_ddl = ddl;
ddl_context->client_data = client_data;
ddl_channel_set(ddl);
return VCD_S_SUCCESS;
}
u32 ddl_decode_start(u32 *ddl_handle,
struct vcd_sequence_hdr *header, void *client_data)
{
struct ddl_client_context *ddl =
(struct ddl_client_context *)ddl_handle;
struct ddl_context *ddl_context;
struct ddl_decoder_data *decoder;
ddl_context = ddl_get_context();
if (!DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dec_start:Not_inited");
return VCD_ERR_ILLEGAL_OP;
}
if (DDL_IS_BUSY(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dec_start:Ddl_busy");
return VCD_ERR_BUSY;
}
if (!ddl || !ddl->decoding) {
VIDC_LOGERR_STRING("ddl_dec_start:Bad_handle");
return VCD_ERR_BAD_HANDLE;
}
if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN)) {
VIDC_LOGERR_STRING("ddl_dec_start:Not_in_opened_state");
return VCD_ERR_ILLEGAL_OP;
}
if ((header) &&
((!header->sequence_header_len) ||
(!header->sequence_header)
)
) {
VIDC_LOGERR_STRING("ddl_dec_start:Bad_param_seq_header");
return VCD_ERR_ILLEGAL_PARM;
}
if (!ddl_decoder_ready_to_start(ddl, header)) {
VIDC_LOGERR_STRING("ddl_dec_start:Err_param_settings");
return VCD_ERR_ILLEGAL_OP;
}
DDL_BUSY(ddl_context);
decoder = &ddl->codec_data.decoder;
if (header) {
decoder->header_in_start = true;
decoder->decode_config = *header;
} else {
decoder->header_in_start = false;
decoder->decode_config.sequence_header_len = 0;
}
if (decoder->codec.codec == VCD_CODEC_H264) {
ddl_pmem_alloc(&decoder->h264Vsp_temp_buffer,
DDL_DECODE_H264_VSPTEMP_BUFSIZE,
DDL_LINEAR_BUFFER_ALIGN_BYTES);
if (!decoder->h264Vsp_temp_buffer.virtual_base_addr) {
DDL_IDLE(ddl_context);
VIDC_LOGERR_STRING
("ddl_dec_start:H264Sps_alloc_failed");
return VCD_ERR_ALLOC_FAIL;
}
}
ddl_context->current_ddl = ddl;
ddl_context->client_data = client_data;
ddl_channel_set(ddl);
return VCD_S_SUCCESS;
}
u32 ddl_decode_frame(u32 *ddl_handle,
struct ddl_frame_data_tag *input_bits, void *client_data)
{
u32 vcd_status = VCD_S_SUCCESS;
struct ddl_client_context *ddl =
(struct ddl_client_context *)ddl_handle;
struct ddl_context *ddl_context = ddl_get_context();
if (!DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dec_frame:Not_inited");
return VCD_ERR_ILLEGAL_OP;
}
if (DDL_IS_BUSY(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dec_frame:Ddl_busy");
return VCD_ERR_BUSY;
}
if (!ddl || !ddl->decoding) {
VIDC_LOGERR_STRING("ddl_dec_frame:Bad_handle");
return VCD_ERR_BAD_HANDLE;
}
if (!input_bits ||
((!input_bits->vcd_frm.physical ||
!input_bits->vcd_frm.data_len) &&
(!(VCD_FRAME_FLAG_EOS & input_bits->vcd_frm.flags))
)
) {
VIDC_LOGERR_STRING("ddl_dec_frame:Bad_input_param");
return VCD_ERR_ILLEGAL_PARM;
}
DDL_BUSY(ddl_context);
ddl_context->current_ddl = ddl;
ddl_context->client_data = client_data;
ddl->input_frame = *input_bits;
if (DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME)) {
ddl_decode_frame_run(ddl);
} else {
if (!ddl->codec_data.decoder.dp_buf.no_of_dec_pic_buf) {
VIDC_LOGERR_STRING("ddl_dec_frame:Dpbs_requied");
vcd_status = VCD_ERR_ILLEGAL_OP;
} else if (DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_DPB)) {
vcd_status = ddl_decode_set_buffers(ddl);
} else
if (DDLCLIENT_STATE_IS
(ddl, DDL_CLIENT_WAIT_FOR_INITCODEC)) {
ddl->codec_data.decoder.decode_config.
sequence_header =
ddl->input_frame.vcd_frm.physical;
ddl->codec_data.decoder.decode_config.
sequence_header_len =
ddl->input_frame.vcd_frm.data_len;
ddl_decode_init_codec(ddl);
} else {
VIDC_LOGERR_STRING("Dec_frame:Wrong_state");
vcd_status = VCD_ERR_ILLEGAL_OP;
}
if (vcd_status)
DDL_IDLE(ddl_context);
}
return vcd_status;
}
u32 ddl_encode_frame(u32 *ddl_handle,
struct ddl_frame_data_tag *input_frame,
struct ddl_frame_data_tag *output_bit, void *client_data)
{
struct ddl_client_context *ddl =
(struct ddl_client_context *)ddl_handle;
struct ddl_context *ddl_context = ddl_get_context();
if (vidc_msg_timing)
ddl_set_core_start_time(__func__, ENC_OP_TIME);
if (!DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_enc_frame:Not_inited");
return VCD_ERR_ILLEGAL_OP;
}
if (DDL_IS_BUSY(ddl_context)) {
VIDC_LOGERR_STRING("ddl_enc_frame:Ddl_busy");
return VCD_ERR_BUSY;
}
if (!ddl || ddl->decoding) {
VIDC_LOGERR_STRING("ddl_enc_frame:Bad_handle");
return VCD_ERR_BAD_HANDLE;
}
if (!input_frame ||
!input_frame->vcd_frm.physical ||
!input_frame->vcd_frm.data_len) {
VIDC_LOGERR_STRING("ddl_enc_frame:Bad_input_params");
return VCD_ERR_ILLEGAL_PARM;
}
if ((((u32) input_frame->vcd_frm.physical +
input_frame->vcd_frm.offset) &
(DDL_STREAMBUF_ALIGN_GUARD_BYTES)
)
) {
VIDC_LOGERR_STRING
("ddl_enc_frame:Un_aligned_yuv_start_address");
return VCD_ERR_ILLEGAL_PARM;
}
if (!output_bit ||
!output_bit->vcd_frm.physical ||
!output_bit->vcd_frm.alloc_len) {
VIDC_LOGERR_STRING("ddl_enc_frame:Bad_output_params");
return VCD_ERR_ILLEGAL_PARM;
}
if ((ddl->codec_data.encoder.output_buf_req.sz +
output_bit->vcd_frm.offset) >
output_bit->vcd_frm.alloc_len) {
VIDC_LOGERR_STRING
("ddl_enc_frame:offset_large, Exceeds_min_buf_size");
}
if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME)) {
VIDC_LOGERR_STRING("ddl_enc_frame:Wrong_state");
return VCD_ERR_ILLEGAL_OP;
}
DDL_BUSY(ddl_context);
ddl_context->current_ddl = ddl;
ddl_context->client_data = client_data;
ddl->input_frame = *input_frame;
ddl->output_frame = *output_bit;
ddl_encode_frame_run(ddl);
return VCD_S_SUCCESS;
}
u32 ddl_decode_end(u32 *ddl_handle, void *client_data)
{
struct ddl_client_context *ddl =
(struct ddl_client_context *)ddl_handle;
struct ddl_context *ddl_context;
ddl_context = ddl_get_context();
if (vidc_msg_timing) {
ddl_reset_core_time_variables(DEC_OP_TIME);
ddl_reset_core_time_variables(DEC_IP_TIME);
}
if (!DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dec_end:Not_inited");
return VCD_ERR_ILLEGAL_OP;
}
if (DDL_IS_BUSY(ddl_context)) {
VIDC_LOGERR_STRING("ddl_dec_end:Ddl_busy");
return VCD_ERR_BUSY;
}
if (!ddl || !ddl->decoding) {
VIDC_LOGERR_STRING("ddl_dec_end:Bad_handle");
return VCD_ERR_BAD_HANDLE;
}
if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME) &&
!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_INITCODEC) &&
!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_DPB) &&
!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_FATAL_ERROR)
) {
VIDC_LOGERR_STRING("ddl_dec_end:Wrong_state");
return VCD_ERR_ILLEGAL_OP;
}
DDL_BUSY(ddl_context);
ddl_context->current_ddl = ddl;
ddl_context->client_data = client_data;
ddl_channel_end(ddl);
return VCD_S_SUCCESS;
}
u32 ddl_encode_end(u32 *ddl_handle, void *client_data)
{
struct ddl_client_context *ddl =
(struct ddl_client_context *)ddl_handle;
struct ddl_context *ddl_context;
ddl_context = ddl_get_context();
if (vidc_msg_timing)
ddl_reset_core_time_variables(ENC_OP_TIME);
if (!DDL_IS_INITIALIZED(ddl_context)) {
VIDC_LOGERR_STRING("ddl_enc_end:Not_inited");
return VCD_ERR_ILLEGAL_OP;
}
if (DDL_IS_BUSY(ddl_context)) {
VIDC_LOGERR_STRING("ddl_enc_end:Ddl_busy");
return VCD_ERR_BUSY;
}
if (!ddl || ddl->decoding) {
VIDC_LOGERR_STRING("ddl_enc_end:Bad_handle");
return VCD_ERR_BAD_HANDLE;
}
if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME) &&
!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_INITCODEC) &&
!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_FATAL_ERROR)) {
VIDC_LOGERR_STRING("ddl_enc_end:Wrong_state");
return VCD_ERR_ILLEGAL_OP;
}
DDL_BUSY(ddl_context);
ddl_context->current_ddl = ddl;
ddl_context->client_data = client_data;
ddl_channel_end(ddl);
return VCD_S_SUCCESS;
}
u32 ddl_reset_hw(u32 mode)
{
struct ddl_context *ddl_context;
struct ddl_client_context *ddl;
int i_client_num;
VIDC_LOG_STRING("ddl_reset_hw:called");
ddl_context = ddl_get_context();
ddl_move_command_state(ddl_context, DDL_CMD_INVALID);
DDL_BUSY(ddl_context);
if (ddl_context->core_virtual_base_addr)
vidc_720p_do_sw_reset();
ddl_context->device_state = DDL_DEVICE_NOTINIT;
for (i_client_num = 0; i_client_num < VCD_MAX_NO_CLIENT;
++i_client_num) {
ddl = ddl_context->ddl_clients[i_client_num];
ddl_context->ddl_clients[i_client_num] = NULL;
if (ddl) {
ddl_release_client_internal_buffers(ddl);
ddl_client_transact(DDL_FREE_CLIENT, &ddl);
}
}
ddl_release_context_buffers(ddl_context);
DDL_MEMSET(ddl_context, 0, sizeof(struct ddl_context));
return true;
}
@@ -0,0 +1,293 @@
/* Copyright (c) 2010-2012 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.
*
*/
#ifndef _VCD_DDL_H_
#define _VCD_DDL_H_
#include "vcd_ddl_api.h"
#include "vcd_ddl_utils.h"
#include "vcd_ddl_firmware.h"
#include "vidc.h"
#undef DDL_INLINE
#define DDL_INLINE
#define DDL_BUSY_STATE 1
#define DDL_IDLE_STATE 0
#define DDL_ERROR_STATE 2
#define DDL_IS_BUSY(ddl_context) \
(((ddl_context)->ddl_busy != DDL_IDLE_STATE))
#define DDL_BUSY(ddl_context) \
((ddl_context)->ddl_busy = DDL_BUSY_STATE)
#define DDL_IDLE(ddl_context) \
((ddl_context)->ddl_busy = DDL_IDLE_STATE)
#define DDL_ERROR(ddl_context) \
((ddl_context)->ddl_busy = DDL_ERROR_STATE)
#define DDL_DEVICE_NOTINIT 0
#define DDL_DEVICE_INITED 1
#define DDL_DEVICE_HWFATAL 2
#define DDL_IS_INITIALIZED(ddl_context) \
(ddl_context->device_state == DDL_DEVICE_INITED)
#define DDLCOMMAND_STATE_IS(ddl_context, command_state) \
(command_state == (ddl_context)->cmd_state)
#define DDLCLIENT_STATE_IS(ddl, current_state) \
(current_state == (ddl)->client_state)
#define DDL_DPB_OP_INIT 1
#define DDL_DPB_OP_MARK_FREE 2
#define DDL_DPB_OP_MARK_BUSY 3
#define DDL_DPB_OP_SET_MASK 4
#define DDL_DPB_OP_RETRIEVE 5
#define DDL_INIT_CLIENTS 0
#define DDL_GET_CLIENT 1
#define DDL_FREE_CLIENT 2
#define DDL_ACTIVE_CLIENT 3
#define DDL_INVALID_CHANNEL_ID ((u32)~0)
#define DDL_INVALID_CODEC_TYPE ((u32)~0)
#define DDL_ENC_REQ_IFRAME 0x01
#define DDL_ENC_CHANGE_IPERIOD 0x02
#define DDL_ENC_CHANGE_BITRATE 0x04
#define DDL_ENC_CHANGE_FRAMERATE 0x08
#define DDL_ENC_CHANGE_CIR 0x10
#define DDL_DEC_REQ_OUTPUT_FLUSH 0x1
enum ddl_mem_area {
DDL_MM_MEM = 0x0
};
struct ddl_buf_addr {
u32 *physical_base_addr;
u32 *virtual_base_addr;
u32 *align_physical_addr;
u32 *align_virtual_addr;
struct msm_mapped_buffer *mapped_buffer;
struct ion_handle *alloc_handle;
u32 buffer_size;
enum ddl_mem_area mem_type;
};
enum ddl_cmd_state {
DDL_CMD_INVALID = 0x0,
DDL_CMD_DMA_INIT = 0x1,
DDL_CMD_CPU_RESET = 0x2,
DDL_CMD_CHANNEL_SET = 0x3,
DDL_CMD_INIT_CODEC = 0x4,
DDL_CMD_HEADER_PARSE = 0x5,
DDL_CMD_DECODE_SET_DPB = 0x6,
DDL_CMD_DECODE_FRAME = 0x7,
DDL_CMD_ENCODE_FRAME = 0x8,
DDL_CMD_EOS = 0x9,
DDL_CMD_CHANNEL_END = 0xA,
DDL_CMD_32BIT = 0x7FFFFFFF
};
enum ddl_client_state {
DDL_CLIENT_INVALID = 0x0,
DDL_CLIENT_OPEN = 0x1,
DDL_CLIENT_WAIT_FOR_CHDONE = 0x2,
DDL_CLIENT_WAIT_FOR_INITCODEC = 0x3,
DDL_CLIENT_WAIT_FOR_INITCODECDONE = 0x4,
DDL_CLIENT_WAIT_FOR_DPB = 0x5,
DDL_CLIENT_WAIT_FOR_DPBDONE = 0x6,
DDL_CLIENT_WAIT_FOR_FRAME = 0x7,
DDL_CLIENT_WAIT_FOR_FRAME_DONE = 0x8,
DDL_CLIENT_WAIT_FOR_EOS_DONE = 0x9,
DDL_CLIENT_WAIT_FOR_CHEND = 0xA,
DDL_CLIENT_FATAL_ERROR = 0xB,
DDL_CLIENT_32BIT = 0x7FFFFFFF
};
struct ddl_mask {
u32 client_mask;
u32 hw_mask;
};
struct ddl_context;
struct ddl_client_context;
struct ddl_codec_data_hdr {
u32 decoding;
};
struct ddl_encoder_data {
struct ddl_codec_data_hdr hdr;
struct vcd_property_codec codec;
struct vcd_property_frame_size frame_size;
struct vcd_property_frame_rate frame_rate;
struct vcd_property_target_bitrate target_bit_rate;
struct vcd_property_profile profile;
struct vcd_property_level level;
struct vcd_property_rate_control rc;
struct vcd_property_multi_slice multi_slice;
u32 meta_data_enable_flag;
u32 suffix;
struct ddl_buf_addr meta_data_input;
u32 meta_data_offset;
struct vcd_property_short_header short_header;
struct vcd_property_vop_timing vop_timing;
u32 hdr_ext_control;
struct vcd_property_db_config db_control;
struct vcd_property_entropy_control entropy_control;
struct vcd_property_i_period i_period;
struct vcd_property_session_qp session_qp;
struct vcd_property_qp_range qp_range;
struct vcd_property_rc_level rc_level;
u32 r_cframe_skip;
u32 vb_vbuffer_size;
struct vcd_property_frame_level_rc_params frame_level_rc;
struct vcd_property_adaptive_rc_params adaptive_rc;
struct vcd_property_intra_refresh_mb_number intra_refresh;
struct vcd_property_buffer_format buf_format;
struct vcd_property_buffer_format re_con_buf_format;
u32 dynamic_prop_change;
u32 dynmic_prop_change_req;
u32 ext_enc_control_val;
struct vidc_720p_enc_frame_info enc_frame_info;
struct ddl_buf_addr enc_dpb_addr;
struct ddl_buf_addr seq_header;
struct vcd_buffer_requirement input_buf_req;
struct vcd_buffer_requirement output_buf_req;
struct vcd_buffer_requirement client_input_buf_req;
struct vcd_buffer_requirement client_output_buf_req;
};
struct ddl_decoder_data {
struct ddl_codec_data_hdr hdr;
struct vcd_property_codec codec;
struct vcd_property_buffer_format buf_format;
struct vcd_property_frame_size frame_size;
struct vcd_property_frame_size client_frame_size;
struct vcd_property_profile profile;
struct vcd_property_level level;
u32 progressive_only;
u32 output_order;
u32 meta_data_enable_flag;
u32 suffix;
struct ddl_buf_addr meta_data_input;
struct ddl_buf_addr ref_buffer;
u32 meta_data_offset;
struct vcd_property_post_filter post_filter;
struct vcd_sequence_hdr decode_config;
u32 header_in_start;
u32 min_dpb_num;
u32 y_cb_cr_size;
struct ddl_property_dec_pic_buffers dp_buf;
struct ddl_mask dpb_mask;
u32 dynamic_prop_change;
u32 dynmic_prop_change_req;
struct vidc_720p_dec_disp_info dec_disp_info;
struct ddl_buf_addr dpb_comv_buffer;
struct ddl_buf_addr h264Vsp_temp_buffer;
struct vcd_buffer_requirement actual_input_buf_req;
struct vcd_buffer_requirement min_input_buf_req;
struct vcd_buffer_requirement client_input_buf_req;
struct vcd_buffer_requirement actual_output_buf_req;
struct vcd_buffer_requirement min_output_buf_req;
struct vcd_buffer_requirement client_output_buf_req;
u32 idr_only_decoding;
};
union ddl_codec_data {
struct ddl_codec_data_hdr hdr;
struct ddl_decoder_data decoder;
struct ddl_encoder_data encoder;
};
struct ddl_context {
int memtype;
u8 *core_virtual_base_addr;
void (*ddl_callback) (u32 event, u32 status, void *payload, size_t sz,
u32 *ddl_handle, void *const client_data);
void *client_data;
void (*interrupt_clr) (void);
enum ddl_cmd_state cmd_state;
struct ddl_client_context *current_ddl;
struct ddl_buf_addr context_buf_addr;
struct ddl_buf_addr db_line_buffer;
struct ddl_buf_addr data_partition_tempbuf;
struct ddl_buf_addr metadata_shared_input;
struct ddl_buf_addr dbg_core_dump;
u32 enable_dbg_core_dump;
struct ddl_client_context *ddl_clients[VCD_MAX_NO_CLIENT];
struct ion_client *video_ion_client;
u32 device_state;
u32 ddl_busy;
u32 intr_status;
u32 cmd_err_status;
u32 disp_pic_err_status;
u32 op_failed;
};
struct ddl_client_context {
struct ddl_context *ddl_context;
enum ddl_client_state client_state;
u32 decoding;
u32 channel_id;
struct ddl_frame_data_tag input_frame;
struct ddl_frame_data_tag output_frame;
union ddl_codec_data codec_data;
};
DDL_INLINE struct ddl_context *ddl_get_context(void);
DDL_INLINE void ddl_move_command_state(struct ddl_context *ddl_context,
enum ddl_cmd_state command_state);
DDL_INLINE void ddl_move_client_state(struct ddl_client_context *ddl,
enum ddl_client_state client_state);
void ddl_core_init(struct ddl_context *);
void ddl_core_start_cpu(struct ddl_context *);
void ddl_channel_set(struct ddl_client_context *);
void ddl_channel_end(struct ddl_client_context *);
void ddl_encode_init_codec(struct ddl_client_context *);
void ddl_decode_init_codec(struct ddl_client_context *);
void ddl_encode_frame_run(struct ddl_client_context *);
void ddl_decode_frame_run(struct ddl_client_context *);
void ddl_decode_eos_run(struct ddl_client_context *);
void ddl_release_context_buffers(struct ddl_context *);
void ddl_release_client_internal_buffers(struct ddl_client_context *ddl);
u32 ddl_decode_set_buffers(struct ddl_client_context *);
u32 ddl_decoder_dpb_transact(struct ddl_decoder_data *decoder,
struct ddl_frame_data_tag *in_out_frame,
u32 operation);
u32 ddl_client_transact(u32, struct ddl_client_context **);
void ddl_set_default_decoder_buffer_req
(struct ddl_decoder_data *decoder, u32 estimate);
void ddl_set_default_encoder_buffer_req
(struct ddl_encoder_data *encoder);
void ddl_set_default_dec_property(struct ddl_client_context *);
u32 ddl_encoder_ready_to_start(struct ddl_client_context *);
u32 ddl_decoder_ready_to_start(struct ddl_client_context *,
struct vcd_sequence_hdr *);
u32 ddl_get_yuv_buffer_size
(struct vcd_property_frame_size *frame_size,
struct vcd_property_buffer_format *buf_format, u32 inter_lace,
enum vcd_codec codec);
void ddl_calculate_stride(struct vcd_property_frame_size *frame_size,
u32 inter_lace, enum vcd_codec codec);
void ddl_encode_dynamic_property(struct ddl_client_context *ddl,
u32 enable);
void ddl_decode_dynamic_property(struct ddl_client_context *ddl,
u32 enable);
void ddl_set_initial_default_values(struct ddl_client_context *ddl);
u32 ddl_handle_core_errors(struct ddl_context *ddl_context);
void ddl_client_fatal_cb(struct ddl_context *ddl_context);
void ddl_hw_fatal_cb(struct ddl_context *ddl_context);
u32 ddl_hal_engine_reset(struct ddl_context *ddl_context);
void ddl_pmem_alloc(struct ddl_buf_addr *addr, size_t sz, u32 alignment);
void ddl_pmem_free(struct ddl_buf_addr *addr);
#endif
@@ -0,0 +1,53 @@
/* Copyright (c) 2010, 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.
*
*/
#ifndef _VCD_DDL_API_H_
#define _VCD_DDL_API_H_
#include "vcd_ddl_internal_property.h"
struct ddl_init_config {
int memtype;
u8 *core_virtual_base_addr;
void (*interrupt_clr) (void);
void (*ddl_callback) (u32 event, u32 status, void *payload, size_t sz,
u32 *ddl_handle, void *const client_data);
};
struct ddl_frame_data_tag {
struct vcd_frame_data vcd_frm;
u32 frm_trans_end;
u32 frm_delta;
};
u32 ddl_device_init(struct ddl_init_config *ddl_init_config,
void *client_data);
u32 ddl_device_release(void *client_data);
u32 ddl_open(u32 **ddl_handle, u32 decoding);
u32 ddl_close(u32 **ddl_handle);
u32 ddl_encode_start(u32 *ddl_handle, void *client_data);
u32 ddl_encode_frame(u32 *ddl_handle,
struct ddl_frame_data_tag *input_frame,
struct ddl_frame_data_tag *output_bit, void *client_data);
u32 ddl_encode_end(u32 *ddl_handle, void *client_data);
u32 ddl_decode_start(u32 *ddl_handle, struct vcd_sequence_hdr *header,
void *client_data);
u32 ddl_decode_frame(u32 *ddl_handle,
struct ddl_frame_data_tag *input_bits, void *client_data);
u32 ddl_decode_end(u32 *ddl_handle, void *client_data);
u32 ddl_set_property(u32 *ddl_handle,
struct vcd_property_hdr *property_hdr, void *property_value);
u32 ddl_get_property(u32 *ddl_handle,
struct vcd_property_hdr *property_hdr, void *property_value);
void ddl_read_and_clear_interrupt(void);
u32 ddl_process_core_response(void);
u32 ddl_reset_hw(u32 mode);
#endif
@@ -0,0 +1,99 @@
/* Copyright (c) 2010-2011, 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.
*
*/
#ifndef _VCD_DDL_CORE_H_
#define _VCD_DDL_CORE_H_
#define DDL_LINEAR_BUF_ALIGN_MASK 0xFFFFFFF8U
#define DDL_LINEAR_BUF_ALIGN_GUARD_BYTES 0x7
#define DDL_LINEAR_BUFFER_ALIGN_BYTES 8
#define DDL_TILE_BUF_ALIGN_MASK 0xFFFFE000U
#define DDL_TILE_BUF_ALIGN_GUARD_BYTES 0x1FFF
#define DDL_TILE_BUFFER_ALIGN_BYTES 8192
#define DDL_MAX_FRAME_WIDTH (1280)
#define DDL_MAX_FRAME_HEIGHT (720)
#define DDL_MAX_DP_FRAME_WIDTH 352
#define DDL_MAX_DP_FRAME_HEIGHT 288
#define DDL_MAX_BIT_RATE (14*1000*1000)
#define DDL_SW_RESET_SLEEP 10
#define VCD_MAX_NO_CLIENT 4
#define VCD_FRAME_COMMAND_DEPTH 1
#define VCD_GENERAL_COMMAND_DEPTH 1
#define VCD_COMMAND_EXCLUSIVE true
#define DDL_HW_TIMEOUT_IN_MS 1000
#define DDL_STREAMBUF_ALIGN_GUARD_BYTES 0x7
#define DDL_CONTEXT_MEMORY (1024 * 15 * (VCD_MAX_NO_CLIENT + 1))
#define DDL_DB_LINE_BUF_SIZE \
(((((DDL_MAX_FRAME_WIDTH * 4) - 1) / 256) + 1) * 8 * 1024)
#define DDL_MPEG4_DATA_PARTITION_BUF_SIZE (64 * 1024)
#define DDL_DECODE_H264_VSPTEMP_BUFSIZE 0x59c00
#define DDL_ENC_NUM_DPB_BUFFERS 2
#define DDL_DBG_CORE_DUMP_SIZE (10 * 1024)
#define DDL_BUFEND_PAD 256
#define DDL_ENC_SEQHEADER_SIZE (256+DDL_BUFEND_PAD)
#define DDL_MAX_BUFFER_COUNT 32
#define DDL_MPEG_REFBUF_COUNT 2
#define DDL_MPEG_COMV_BUF_NO 2
#define DDL_H263_COMV_BUF_NO 2
#define DDL_COMV_BUFLINE_NO 128
#define DDL_VC1_COMV_BUFLINE_NO 32
#define DDL_MINIMUM_BYTE_PER_SLICE 1920
#define DDL_MAX_H264_QP 51
#define DDL_MAX_MPEG4_QP 31
#define DDL_PADDING_HACK(addr) \
(addr) = (u32)((((u32)(addr) + DDL_STREAMBUF_ALIGN_GUARD_BYTES) & \
~(DDL_STREAMBUF_ALIGN_GUARD_BYTES)) + DDL_BUFEND_PAD)
#define DDL_QCIF_MBS 99
#define DDL_CIF_MBS 396
#define DDL_QVGA_MBS 300
#define DDL_VGA_MBS 1200
#define DDL_WVGA_MBS 1500
#define DDL_720P_MBS 3600
#define DDL_FRAMESIZE_DIV_FACTOR (0xF)
#define DDL_NO_OF_MB(width, height) \
(((width + 15) >> 4) * ((height + 15) >> 4))
#define DDL_ALLOW_ENC_FRAMESIZE(width, height) \
((DDL_NO_OF_MB(width, height) <= DDL_720P_MBS) \
&& (((width) <= DDL_MAX_FRAME_WIDTH) && \
((height) <= DDL_MAX_FRAME_WIDTH)) \
&& ((width) >= 32 && (height) >= 32))
#define DDL_VALIDATE_ENC_FRAMESIZE(width, height) \
(!((width) & DDL_FRAMESIZE_DIV_FACTOR) && \
!((height) & DDL_FRAMESIZE_DIV_FACTOR))
#define DDL_TILE_ALIGN_WIDTH 128
#define DDL_TILE_ALIGN_HEIGHT 32
#define DDL_TILE_MULTIPLY_FACTOR 8192
#define DDL_TILE_ALIGN(val, grid) \
(((val) + (grid) - 1) / (grid) * (grid))
#endif
@@ -0,0 +1,612 @@
/* Copyright (c) 2010-2012, 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 <media/msm/vidc_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
static void ddl_handle_npf_decoding_error(
struct ddl_context *ddl_context);
static u32 ddl_handle_seqhdr_fail_error(
struct ddl_context *ddl_context);
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:
case NULL_DB_POINTER:
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 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_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->decoding)
if (ddl_handle_seqhdr_fail_error(ddl_context))
return true;
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:
{
ddl_handle_npf_decoding_error(ddl_context);
return true;
}
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:
{
vcd_status = VCD_ERR_BITSTREAM_ERR;
break;
}
case ACTIVE_SPS_NOT_PRESENT:
case ACTIVE_PPS_NOT_PRESENT:
{
if (ddl->codec_data.decoder.idr_only_decoding) {
DBG("Consider warnings as errors in idr mode");
ddl_client_fatal_cb(ddl_context);
return true;
}
vcd_status = VCD_ERR_BITSTREAM_ERR;
break;
}
case PROFILE_UNKOWN:
if (ddl->decoding)
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 &&
!eos) {
DBG("Treat header in start error %u as success",
vcd_status);
/* 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) {
DBG("DEC-EOS_RUN");
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 &&
!ddl_context->op_failed)
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;
}
void ddl_handle_npf_decoding_error(struct ddl_context *ddl_context)
{
struct ddl_client_context *ddl = ddl_context->current_ddl;
struct ddl_decoder_data *decoder = &ddl->codec_data.decoder;
if (!ddl->decoding) {
ERR("FWISSUE-ENC-NPF!!!");
ddl_client_fatal_cb(ddl_context);
return;
}
vidc_720p_decode_display_info(&decoder->dec_disp_info);
ddl_decode_dynamic_property(ddl, false);
ddl->output_frame.vcd_frm.ip_frm_tag =
decoder->dec_disp_info.tag_top;
ddl->output_frame.vcd_frm.physical = NULL;
ddl->output_frame.frm_trans_end = false;
ddl->ddl_context->ddl_callback(
VCD_EVT_RESP_OUTPUT_DONE,
VCD_ERR_INTRLCD_FIELD_DROP,
&ddl->output_frame,
sizeof(struct ddl_frame_data_tag),
(void *)ddl,
ddl->ddl_context->client_data);
ddl_decode_frame_run(ddl);
}
u32 ddl_handle_seqhdr_fail_error(struct ddl_context *ddl_context)
{
struct ddl_client_context *ddl = ddl_context->current_ddl;
struct ddl_decoder_data *decoder = &ddl->codec_data.decoder;
u32 status = false;
if (ddl_context->cmd_state == DDL_CMD_HEADER_PARSE &&
DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_INITCODECDONE)) {
switch (ddl_context->cmd_err_status) {
case UNSUPPORTED_FEATURE_IN_PROFILE:
case HEADER_NOT_FOUND:
case INVALID_SPS_ID:
case INVALID_PPS_ID:
case RESOLUTION_NOT_SUPPORTED:
case PROFILE_UNKOWN:
ERR("SEQ-HDR-FAILED!!!");
if ((ddl_context->cmd_err_status ==
RESOLUTION_NOT_SUPPORTED) &&
(decoder->codec.codec == VCD_CODEC_H264 ||
decoder->codec.codec == VCD_CODEC_H263 ||
decoder->codec.codec == VCD_CODEC_MPEG4 ||
decoder->codec.codec == VCD_CODEC_VC1_RCV ||
decoder->codec.codec == VCD_CODEC_VC1)) {
ddl_client_fatal_cb(ddl_context);
status = true;
break;
}
if (decoder->header_in_start) {
decoder->header_in_start = false;
ddl_context->ddl_callback(VCD_EVT_RESP_START,
VCD_ERR_SEQHDR_PARSE_FAIL,
NULL, 0, (void *)ddl,
ddl_context->client_data);
} else {
if (ddl->input_frame.vcd_frm.flags &
VCD_FRAME_FLAG_EOS)
ddl->input_frame.frm_trans_end = false;
else
ddl->input_frame.frm_trans_end = true;
ddl_decode_dynamic_property(ddl, false);
ddl_context->ddl_callback(
VCD_EVT_RESP_INPUT_DONE,
VCD_ERR_SEQHDR_PARSE_FAIL,
&ddl->input_frame,
sizeof(struct ddl_frame_data_tag),
(void *)ddl, ddl_context->client_data);
if (ddl->input_frame.vcd_frm.flags &
VCD_FRAME_FLAG_EOS)
ddl_context->ddl_callback(
VCD_EVT_RESP_EOS_DONE,
VCD_S_SUCCESS, NULL,
0, (void *)ddl,
ddl_context->client_data);
}
ddl_move_client_state(ddl,
DDL_CLIENT_WAIT_FOR_INITCODEC);
DDL_IDLE(ddl_context);
status = true;
}
}
return status;
}
@@ -0,0 +1,352 @@
/* Copyright (c) 2010-2012, 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 <media/msm/vidc_type.h>
#include "vcd_ddl_firmware.h"
#include "vcd_ddl_utils.h"
#define VCDFW_TOTALNUM_IMAGE 7
#define VCDFW_MAX_NO_IMAGE 2
struct vcd_firmware {
u32 active_fw_img[VCDFW_TOTALNUM_IMAGE];
struct ddl_buf_addr boot_code;
struct ddl_buf_addr enc_mpeg4;
struct ddl_buf_addr encH264;
struct ddl_buf_addr dec_mpeg4;
struct ddl_buf_addr decH264;
struct ddl_buf_addr decH263;
struct ddl_buf_addr dec_mpeg2;
struct ddl_buf_addr dec_vc1;
};
static struct vcd_firmware vcd_firmware;
static void vcd_fw_change_endian(unsigned char *fw, u32 fw_size)
{
u32 i = 0;
unsigned char temp;
for (i = 0; i < fw_size; i = i + 4) {
temp = fw[i];
fw[i] = fw[i + 3];
fw[i + 3] = temp;
temp = fw[i + 1];
fw[i + 1] = fw[i + 2];
fw[i + 2] = temp;
}
return;
}
static u32 vcd_fw_prepare(struct ddl_buf_addr *fw_details,
const unsigned char fw_array[],
const unsigned int fw_array_size, u32 change_endian)
{
u32 *buffer;
ddl_pmem_alloc(fw_details, fw_array_size,
DDL_LINEAR_BUFFER_ALIGN_BYTES);
if (!fw_details->virtual_base_addr)
return false;
fw_details->buffer_size = fw_array_size / 4;
buffer = fw_details->align_virtual_addr;
memcpy(buffer, fw_array, fw_array_size);
if (change_endian)
vcd_fw_change_endian((unsigned char *)buffer, fw_array_size);
return true;
}
u32 vcd_fw_init(void)
{
u32 status = false;
status = vcd_fw_prepare(&vcd_firmware.boot_code,
vidc_command_control_fw,
vidc_command_control_fw_size, false);
if (status) {
status = vcd_fw_prepare(&vcd_firmware.dec_mpeg4,
vidc_mpg4_dec_fw,
vidc_mpg4_dec_fw_size, true);
}
if (status) {
status = vcd_fw_prepare(&vcd_firmware.decH264,
vidc_h264_dec_fw,
vidc_h264_dec_fw_size, true);
}
if (status) {
status = vcd_fw_prepare(&vcd_firmware.decH263,
vidc_h263_dec_fw,
vidc_h263_dec_fw_size, true);
}
if (status) {
status = vcd_fw_prepare(&vcd_firmware.enc_mpeg4,
vidc_mpg4_enc_fw,
vidc_mpg4_enc_fw_size, true);
}
if (status) {
status = vcd_fw_prepare(&vcd_firmware.encH264,
vidc_h264_enc_fw,
vidc_h264_enc_fw_size, true);
}
if (status) {
status = vcd_fw_prepare(&vcd_firmware.dec_vc1,
vidc_vc1_dec_fw,
vidc_vc1_dec_fw_size, true);
}
return status;
}
static u32 get_dec_fw_image(struct vcd_fw_details *fw_details)
{
u32 status = true;
switch (fw_details->codec) {
case VCD_CODEC_DIVX_4:
case VCD_CODEC_DIVX_5:
case VCD_CODEC_DIVX_6:
case VCD_CODEC_XVID:
case VCD_CODEC_MPEG4:
{
fw_details->fw_buffer_addr =
vcd_firmware.dec_mpeg4.align_physical_addr;
fw_details->fw_size =
vcd_firmware.dec_mpeg4.buffer_size;
break;
}
case VCD_CODEC_H264:
{
fw_details->fw_buffer_addr =
vcd_firmware.decH264.align_physical_addr;
fw_details->fw_size =
vcd_firmware.decH264.buffer_size;
break;
}
case VCD_CODEC_VC1:
case VCD_CODEC_VC1_RCV:
{
fw_details->fw_buffer_addr =
vcd_firmware.dec_vc1.align_physical_addr;
fw_details->fw_size =
vcd_firmware.dec_vc1.buffer_size;
break;
}
case VCD_CODEC_MPEG2:
{
fw_details->fw_buffer_addr =
vcd_firmware.dec_mpeg2.align_physical_addr;
fw_details->fw_size =
vcd_firmware.dec_mpeg2.buffer_size;
break;
}
case VCD_CODEC_H263:
{
fw_details->fw_buffer_addr =
vcd_firmware.decH263.align_physical_addr;
fw_details->fw_size =
vcd_firmware.decH263.buffer_size;
break;
}
default:
{
status = false;
break;
}
}
return status;
}
static u32 get_enc_fw_image(struct vcd_fw_details *fw_details)
{
u32 status = true;
switch (fw_details->codec) {
case VCD_CODEC_H263:
case VCD_CODEC_MPEG4:
{
fw_details->fw_buffer_addr =
vcd_firmware.enc_mpeg4.align_physical_addr;
fw_details->fw_size =
vcd_firmware.enc_mpeg4.buffer_size;
break;
}
case VCD_CODEC_H264:
{
fw_details->fw_buffer_addr =
vcd_firmware.encH264.align_physical_addr;
fw_details->fw_size =
vcd_firmware.encH264.buffer_size;
break;
}
default:
{
status = false;
break;
}
}
return status;
}
u32 vcd_get_fw_property(u32 prop_id, void *prop_details)
{
u32 status = true;
struct vcd_fw_details *fw_details;
switch (prop_id) {
case VCD_FW_ENDIAN:
{
*(u32 *) prop_details = VCD_FW_BIG_ENDIAN;
break;
}
case VCD_FW_BOOTCODE:
{
fw_details =
(struct vcd_fw_details *)prop_details;
fw_details->fw_buffer_addr =
vcd_firmware.boot_code.align_physical_addr;
fw_details->fw_size =
vcd_firmware.boot_code.buffer_size;
break;
}
case VCD_FW_DECODE:
{
fw_details =
(struct vcd_fw_details *)prop_details;
status = get_dec_fw_image(fw_details);
break;
}
case VCD_FW_ENCODE:
{
fw_details =
(struct vcd_fw_details *)prop_details;
status = get_enc_fw_image(fw_details);
break;
}
default:
{
status = false;
break;
}
}
return status;
}
u32 vcd_fw_transact(u32 add, u32 decoding, enum vcd_codec codec)
{
u32 status = true;
u32 index = 0, active_fw = 0, loop_count;
if (decoding) {
switch (codec) {
case VCD_CODEC_DIVX_4:
case VCD_CODEC_DIVX_5:
case VCD_CODEC_DIVX_6:
case VCD_CODEC_XVID:
case VCD_CODEC_MPEG4:
{
index = 0;
break;
}
case VCD_CODEC_H264:
{
index = 1;
break;
}
case VCD_CODEC_H263:
{
index = 2;
break;
}
case VCD_CODEC_MPEG2:
{
index = 3;
break;
}
case VCD_CODEC_VC1:
case VCD_CODEC_VC1_RCV:
{
index = 4;
break;
}
default:
{
status = false;
break;
}
}
} else {
switch (codec) {
case VCD_CODEC_H263:
case VCD_CODEC_MPEG4:
{
index = 5;
break;
}
case VCD_CODEC_H264:
{
index = 6;
break;
}
default:
{
status = false;
break;
}
}
}
if (!status)
return status;
if (!add &&
vcd_firmware.active_fw_img[index]
) {
--vcd_firmware.active_fw_img[index];
return status;
}
for (loop_count = 0; loop_count < VCDFW_TOTALNUM_IMAGE;
++loop_count) {
if (vcd_firmware.active_fw_img[loop_count])
++active_fw;
}
if (active_fw < VCDFW_MAX_NO_IMAGE ||
vcd_firmware.active_fw_img[index] > 0) {
++vcd_firmware.active_fw_img[index];
} else {
status = false;
}
return status;
}
void vcd_fw_release(void)
{
ddl_pmem_free(&vcd_firmware.boot_code);
ddl_pmem_free(&vcd_firmware.enc_mpeg4);
ddl_pmem_free(&vcd_firmware.encH264);
ddl_pmem_free(&vcd_firmware.dec_mpeg4);
ddl_pmem_free(&vcd_firmware.decH264);
ddl_pmem_free(&vcd_firmware.decH263);
ddl_pmem_free(&vcd_firmware.dec_mpeg2);
ddl_pmem_free(&vcd_firmware.dec_vc1);
}
@@ -0,0 +1,53 @@
/* Copyright (c) 2010-2012, 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.
*
*/
#ifndef _VCD_DDL_FIRMWARE_H_
#define _VCD_DDL_FIRMWARE_H_
#include <media/msm/vcd_property.h>
#define VCD_FW_BIG_ENDIAN 0x0
#define VCD_FW_LITTLE_ENDIAN 0x1
struct vcd_fw_details {
enum vcd_codec codec;
u32 *fw_buffer_addr;
u32 fw_size;
};
#define VCD_FW_PROP_BASE 0x0
#define VCD_FW_ENDIAN (VCD_FW_PROP_BASE + 0x1)
#define VCD_FW_BOOTCODE (VCD_FW_PROP_BASE + 0x2)
#define VCD_FW_DECODE (VCD_FW_PROP_BASE + 0x3)
#define VCD_FW_ENCODE (VCD_FW_PROP_BASE + 0x4)
extern unsigned char *vidc_command_control_fw;
extern u32 vidc_command_control_fw_size;
extern unsigned char *vidc_mpg4_dec_fw;
extern u32 vidc_mpg4_dec_fw_size;
extern unsigned char *vidc_h263_dec_fw;
extern u32 vidc_h263_dec_fw_size;
extern unsigned char *vidc_h264_dec_fw;
extern u32 vidc_h264_dec_fw_size;
extern unsigned char *vidc_mpg4_enc_fw;
extern u32 vidc_mpg4_enc_fw_size;
extern unsigned char *vidc_h264_enc_fw;
extern u32 vidc_h264_enc_fw_size;
extern unsigned char *vidc_vc1_dec_fw;
extern u32 vidc_vc1_dec_fw_size;
u32 vcd_fw_init(void);
u32 vcd_get_fw_property(u32 prop_id, void *prop_details);
u32 vcd_fw_transact(u32 add, u32 decoding, enum vcd_codec codec);
void vcd_fw_release(void);
#endif
@@ -0,0 +1,971 @@
/* Copyright (c) 2010-2012, 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 <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#include "vcd_ddl_metadata.h"
#if DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
#else
#define DBG(x...)
#endif
#define DBG_INFO(x...) pr_info(x)
void ddl_core_init(struct ddl_context *ddl_context)
{
char *psz_version;
struct vcd_fw_details fw_details;
u32 fw_endianness;
enum vidc_720p_endian dma_endian;
u32 interrupt_off;
enum vidc_720p_interrupt_level_selection interrupt_sel;
u32 intr_mask = 0x0;
vcd_get_fw_property(VCD_FW_BOOTCODE, &fw_details);
vcd_get_fw_property(VCD_FW_ENDIAN, &fw_endianness);
if (fw_endianness == VCD_FW_BIG_ENDIAN)
dma_endian = VIDC_720P_BIG_ENDIAN;
else
dma_endian = VIDC_720P_LITTLE_ENDIAN;
interrupt_off = false;
interrupt_sel = VIDC_720P_INTERRUPT_LEVEL_SEL;
intr_mask |= VIDC_720P_INTR_BUFFER_FULL;
intr_mask |= VIDC_720P_INTR_FW_DONE;
intr_mask |= VIDC_720P_INTR_DMA_DONE;
intr_mask |= VIDC_720P_INTR_FRAME_DONE;
vidc_720p_do_sw_reset();
DBG_INFO("Loading CONTROL_FW of FW_SIZE %u\n",
fw_details.fw_size*4);
vidc_720p_init(&psz_version,
fw_details.fw_size,
fw_details.fw_buffer_addr,
dma_endian,
interrupt_off, interrupt_sel, intr_mask);
return;
}
void ddl_core_start_cpu(struct ddl_context *ddl_context)
{
u32 fw_endianness;
enum vidc_720p_endian dma_endian;
u32 dbg_core_dump_buf_size = 0;
vcd_get_fw_property(VCD_FW_ENDIAN, &fw_endianness);
if (fw_endianness == VCD_FW_BIG_ENDIAN)
dma_endian = VIDC_720P_LITTLE_ENDIAN;
else
dma_endian = VIDC_720P_BIG_ENDIAN;
ddl_move_command_state(ddl_context, DDL_CMD_CPU_RESET);
DBG("VSP_BUF_ADDR_SIZE %d",
ddl_context->context_buf_addr.buffer_size);
if (ddl_context->enable_dbg_core_dump) {
dbg_core_dump_buf_size = ddl_context->dbg_core_dump.
buffer_size;
}
vidc_720p_start_cpu(dma_endian,
ddl_context->context_buf_addr.align_physical_addr,
ddl_context->dbg_core_dump.align_physical_addr,
dbg_core_dump_buf_size);
VIDC_DEBUG_REGISTER_LOG;
}
void ddl_channel_set(struct ddl_client_context *ddl)
{
enum vidc_720p_enc_dec_selection enc_dec_sel;
enum vidc_720p_codec codec;
enum vcd_codec *vcd_codec;
u32 fw_property_id;
struct vcd_fw_details fw_details;
if (ddl->decoding) {
if (vidc_msg_timing)
ddl_set_core_start_time(__func__, DEC_OP_TIME);
enc_dec_sel = VIDC_720P_DECODER;
fw_property_id = VCD_FW_DECODE;
vcd_codec = &(ddl->codec_data.decoder.codec.codec);
} else {
enc_dec_sel = VIDC_720P_ENCODER;
fw_property_id = VCD_FW_ENCODE;
vcd_codec = &(ddl->codec_data.encoder.codec.codec);
}
switch (*vcd_codec) {
default:
case VCD_CODEC_MPEG4:
{
codec = VIDC_720P_MPEG4;
if (ddl->decoding) {
vidc_720p_decode_set_mpeg4_data_partitionbuffer
(ddl->ddl_context->data_partition_tempbuf.
align_physical_addr);
}
break;
}
case VCD_CODEC_H264:
{
codec = VIDC_720P_H264;
break;
}
case VCD_CODEC_DIVX_4:
case VCD_CODEC_DIVX_5:
case VCD_CODEC_DIVX_6:
{
codec = VIDC_720P_DIVX;
break;
}
case VCD_CODEC_XVID:
{
codec = VIDC_720P_XVID;
break;
}
case VCD_CODEC_H263:
{
codec = VIDC_720P_H263;
break;
}
case VCD_CODEC_MPEG2:
{
codec = VIDC_720P_MPEG2;
break;
}
case VCD_CODEC_VC1:
case VCD_CODEC_VC1_RCV:
{
codec = VIDC_720P_VC1;
break;
}
}
fw_details.codec = *vcd_codec;
vcd_get_fw_property(fw_property_id, &fw_details);
VIDC_DEBUG_REGISTER_LOG;
ddl_move_command_state(ddl->ddl_context, DDL_CMD_CHANNEL_SET);
ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_CHDONE);
DBG_INFO("Loading firmware for CODEC:%u of FW_SIZE:%u\n",
fw_details.codec, fw_details.fw_size*4);
vidc_720p_set_channel(ddl->channel_id,
enc_dec_sel,
codec,
fw_details.fw_buffer_addr,
fw_details.fw_size);
}
void ddl_decode_init_codec(struct ddl_client_context *ddl)
{
u32 seq_h = 0, seq_e = 0, start_byte_num = 0;
struct ddl_decoder_data *decoder = &(ddl->codec_data.decoder);
struct vcd_sequence_hdr *seq_hdr = &decoder->decode_config;
enum vidc_720p_memory_access_method mem_access_method;
if (vidc_msg_timing)
ddl_set_core_start_time(__func__, DEC_OP_TIME);
ddl_metadata_enable(ddl);
vidc_720p_decode_set_error_control(true);
vidc_720p_decode_set_mpeg4Post_filter(decoder->post_filter.
post_filter);
if (decoder->codec.codec == VCD_CODEC_H264) {
vidc_720p_decode_setH264VSPBuffer(decoder->
h264Vsp_temp_buffer.
align_physical_addr);
VIDC_LOG1("VSP_BUF_ADDR_SIZE",
decoder->h264Vsp_temp_buffer.buffer_size);
}
if (decoder->codec.codec == VCD_CODEC_VC1_RCV ||
decoder->codec.codec == VCD_CODEC_VC1) {
vidc_720p_set_frame_size(decoder->client_frame_size.width,
decoder->client_frame_size.height);
} else {
vidc_720p_set_frame_size(0x0, 0x0);
}
switch (decoder->buf_format.buffer_format) {
default:
case VCD_BUFFER_FORMAT_NV12:
{
mem_access_method = VIDC_720P_TILE_LINEAR;
break;
}
case VCD_BUFFER_FORMAT_TILE_4x2:
{
mem_access_method = VIDC_720P_TILE_64x32;
break;
}
}
VIDC_LOG_STRING("HEADER-PARSE-START");
VIDC_DEBUG_REGISTER_LOG;
seq_h = (u32) seq_hdr->sequence_header;
start_byte_num = 8 - (seq_h & DDL_STREAMBUF_ALIGN_GUARD_BYTES);
seq_e = seq_h + seq_hdr->sequence_header_len;
seq_h &= ~(DDL_STREAMBUF_ALIGN_GUARD_BYTES);
DDL_PADDING_HACK(seq_e);
ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_INITCODECDONE);
ddl_move_command_state(ddl->ddl_context, DDL_CMD_HEADER_PARSE);
vidc_720p_decode_bitstream_header(ddl->channel_id,
seq_hdr->sequence_header_len,
start_byte_num,
seq_h,
seq_e,
mem_access_method,
decoder->output_order);
}
void ddl_decode_dynamic_property(struct ddl_client_context *ddl,
u32 enable)
{
uint8_t *temp = NULL;
u32 extra_datastart = 0;
struct ddl_decoder_data *decoder = &(ddl->codec_data.decoder);
struct vcd_frame_data *bit_stream =
&(ddl->input_frame.vcd_frm);
if (!enable) {
if (decoder->dynmic_prop_change_req) {
decoder->dynmic_prop_change_req = false;
vidc_720p_decode_dynamic_req_reset();
}
return;
}
if ((decoder->dynamic_prop_change &
DDL_DEC_REQ_OUTPUT_FLUSH)) {
decoder->dynmic_prop_change_req = true;
decoder->dynamic_prop_change &= ~(DDL_DEC_REQ_OUTPUT_FLUSH);
decoder->dpb_mask.hw_mask = 0;
vidc_720p_decode_dynamic_req_set(VIDC_720P_FLUSH_REQ);
}
if (((decoder->meta_data_enable_flag & VCD_METADATA_PASSTHROUGH))
&& ((VCD_FRAME_FLAG_EXTRADATA & bit_stream->flags))
) {
temp = ((uint8_t *)bit_stream->physical +
bit_stream->offset +
bit_stream->data_len + 3);
extra_datastart = (u32) ((u32)temp & ~3);
decoder->dynmic_prop_change_req = true;
vidc_720p_decode_setpassthrough_start(extra_datastart);
vidc_720p_decode_dynamic_req_set(VIDC_720P_EXTRADATA);
}
}
void ddl_encode_dynamic_property(struct ddl_client_context *ddl,
u32 enable)
{
struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
u32 enc_param_change = 0;
if (!enable) {
if (encoder->dynmic_prop_change_req) {
encoder->dynmic_prop_change_req = false;
encoder->ext_enc_control_val &=
~(VIDC_720P_ENC_IFRAME_REQ);
vidc_720p_encode_set_control_param
(encoder->ext_enc_control_val);
vidc_720p_encoder_set_param_change(enc_param_change);
}
return;
}
if ((encoder->dynamic_prop_change & DDL_ENC_REQ_IFRAME)) {
encoder->dynamic_prop_change &= ~(DDL_ENC_REQ_IFRAME);
encoder->ext_enc_control_val |= VIDC_720P_ENC_IFRAME_REQ;
vidc_720p_encode_set_control_param
(encoder->ext_enc_control_val);
}
if ((encoder->dynamic_prop_change & DDL_ENC_CHANGE_BITRATE)) {
vidc_720p_encode_set_bit_rate(
encoder->target_bit_rate.target_bitrate);
enc_param_change |= VIDC_720P_ENC_BITRATE_CHANGE;
encoder->dynamic_prop_change &= ~(DDL_ENC_CHANGE_BITRATE);
}
if ((encoder->dynamic_prop_change & DDL_ENC_CHANGE_CIR)) {
vidc_720p_encode_set_intra_refresh_mb_number(
encoder->intra_refresh.cir_mb_number);
encoder->dynamic_prop_change &= ~(DDL_ENC_CHANGE_CIR);
}
if ((encoder->dynamic_prop_change & DDL_ENC_CHANGE_IPERIOD)) {
vidc_720p_encode_set_i_period
(encoder->i_period.p_frames);
enc_param_change |= VIDC_720P_ENC_IPERIOD_CHANGE;
encoder->dynamic_prop_change &= ~(DDL_ENC_CHANGE_IPERIOD);
}
if ((encoder->dynamic_prop_change &
DDL_ENC_CHANGE_FRAMERATE)) {
vidc_720p_encode_set_fps
((encoder->frame_rate.fps_numerator * 1000) /
encoder->frame_rate.fps_denominator);
enc_param_change |= VIDC_720P_ENC_FRAMERATE_CHANGE;
encoder->dynamic_prop_change &= ~(DDL_ENC_CHANGE_FRAMERATE);
}
if (enc_param_change)
vidc_720p_encoder_set_param_change(enc_param_change);
}
static void ddl_encode_set_profile_level(struct ddl_client_context *ddl)
{
struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
u32 profile;
u32 level;
switch (encoder->profile.profile) {
default:
case VCD_PROFILE_MPEG4_SP:
{
profile = VIDC_720P_PROFILE_MPEG4_SP;
break;
}
case VCD_PROFILE_MPEG4_ASP:
{
profile = VIDC_720P_PROFILE_MPEG4_ASP;
break;
}
case VCD_PROFILE_H264_BASELINE:
{
profile = VIDC_720P_PROFILE_H264_CPB;
break;
}
case VCD_PROFILE_H264_MAIN:
{
profile = VIDC_720P_PROFILE_H264_MAIN;
break;
}
case VCD_PROFILE_H264_HIGH:
{
profile = VIDC_720P_PROFILE_H264_HIGH;
break;
}
case VCD_PROFILE_H263_BASELINE:
{
profile = VIDC_720P_PROFILE_H263_BASELINE;
break;
}
}
switch (encoder->level.level) {
default:
case VCD_LEVEL_MPEG4_0:
{
level = VIDC_720P_MPEG4_LEVEL0;
break;
}
case VCD_LEVEL_MPEG4_0b:
{
level = VIDC_720P_MPEG4_LEVEL0b;
break;
}
case VCD_LEVEL_MPEG4_1:
{
level = VIDC_720P_MPEG4_LEVEL1;
break;
}
case VCD_LEVEL_MPEG4_2:
{
level = VIDC_720P_MPEG4_LEVEL2;
break;
}
case VCD_LEVEL_MPEG4_3:
{
level = VIDC_720P_MPEG4_LEVEL3;
break;
}
case VCD_LEVEL_MPEG4_3b:
{
level = VIDC_720P_MPEG4_LEVEL3b;
break;
}
case VCD_LEVEL_MPEG4_4:
case VCD_LEVEL_MPEG4_4a:
{
level = VIDC_720P_MPEG4_LEVEL4a;
break;
}
case VCD_LEVEL_MPEG4_5:
{
level = VIDC_720P_MPEG4_LEVEL5;
break;
}
case VCD_LEVEL_MPEG4_6:
{
level = VIDC_720P_MPEG4_LEVEL6;
break;
}
case VCD_LEVEL_H264_1:
{
level = VIDC_720P_H264_LEVEL1;
break;
}
case VCD_LEVEL_H264_1b:
{
level = VIDC_720P_H264_LEVEL1b;
break;
}
case VCD_LEVEL_H264_1p1:
{
level = VIDC_720P_H264_LEVEL1p1;
break;
}
case VCD_LEVEL_H264_1p2:
{
level = VIDC_720P_H264_LEVEL1p2;
break;
}
case VCD_LEVEL_H264_1p3:
{
level = VIDC_720P_H264_LEVEL1p3;
break;
}
case VCD_LEVEL_H264_2:
{
level = VIDC_720P_H264_LEVEL2;
break;
}
case VCD_LEVEL_H264_2p1:
{
level = VIDC_720P_H264_LEVEL2p1;
break;
}
case VCD_LEVEL_H264_2p2:
{
level = VIDC_720P_H264_LEVEL2p2;
break;
}
case VCD_LEVEL_H264_3:
{
level = VIDC_720P_H264_LEVEL3;
break;
}
case VCD_LEVEL_H264_3p1:
{
level = VIDC_720P_H264_LEVEL3p1;
break;
}
case VCD_LEVEL_H263_10:
{
level = VIDC_720P_H263_LEVEL10;
break;
}
case VCD_LEVEL_H263_20:
{
level = VIDC_720P_H263_LEVEL20;
break;
}
case VCD_LEVEL_H263_30:
{
level = VIDC_720P_H263_LEVEL30;
break;
}
case VCD_LEVEL_H263_40:
{
level = VIDC_720P_H263_LEVEL40;
break;
}
case VCD_LEVEL_H263_45:
{
level = VIDC_720P_H263_LEVEL45;
break;
}
case VCD_LEVEL_H263_50:
{
level = VIDC_720P_H263_LEVEL50;
break;
}
case VCD_LEVEL_H263_60:
{
level = VIDC_720P_H263_LEVEL60;
break;
}
case VCD_LEVEL_H263_70:
{
level = VIDC_720P_H263_LEVEL70;
break;
}
}
vidc_720p_encode_set_profile(profile, level);
}
void ddl_encode_init_codec(struct ddl_client_context *ddl)
{
struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
enum vidc_720p_memory_access_method mem_access_method;
enum vidc_720p_DBConfig db_config;
enum vidc_720p_MSlice_selection m_slice_sel;
ddl_encode_set_profile_level(ddl);
vidc_720p_set_frame_size
(encoder->frame_size.width, encoder->frame_size.height);
vidc_720p_encode_set_qp_params
(encoder->qp_range.max_qp, encoder->qp_range.min_qp);
vidc_720p_encode_set_rc_config
(encoder->rc_level.frame_level_rc,
encoder->rc_level.mb_level_rc,
encoder->session_qp.i_frame_qp,
encoder->session_qp.p_frame_qp);
if (encoder->r_cframe_skip) {
if (encoder->vb_vbuffer_size) {
encoder->ext_enc_control_val = (0x2 << 0x2) |
(encoder->vb_vbuffer_size << 0x10);
} else
encoder->ext_enc_control_val = (0x1 << 2);
} else
encoder->ext_enc_control_val = 0;
vidc_720p_encode_set_fps
((encoder->frame_rate.fps_numerator * 1000) /
encoder->frame_rate.fps_denominator);
vidc_720p_encode_set_vop_time(
encoder->vop_timing.vop_time_resolution, 0);
if (encoder->rc_level.frame_level_rc) {
vidc_720p_encode_set_bit_rate
(encoder->target_bit_rate.target_bitrate);
vidc_720p_encode_set_frame_level_rc_params
(encoder->frame_level_rc.reaction_coeff);
}
if (encoder->rc_level.mb_level_rc) {
vidc_720p_encode_set_mb_level_rc_params
(encoder->adaptive_rc.dark_region_as_flag,
encoder->adaptive_rc.smooth_region_as_flag,
encoder->adaptive_rc.static_region_as_flag,
encoder->adaptive_rc.activity_region_flag);
}
if (encoder->codec.codec == VCD_CODEC_MPEG4) {
vidc_720p_encode_set_short_header
(encoder->short_header.short_header);
if (encoder->hdr_ext_control) {
vidc_720p_encode_set_hec_period
(encoder->hdr_ext_control);
encoder->ext_enc_control_val |= (0x1 << 0x1);
}
}
/* set extended encoder control settings */
vidc_720p_encode_set_control_param
(encoder->ext_enc_control_val);
if (encoder->codec.codec == VCD_CODEC_H264) {
enum vidc_720p_entropy_sel entropy_sel;
enum vidc_720p_cabac_model cabac_model_number;
switch (encoder->entropy_control.entropy_sel) {
default:
case VCD_ENTROPY_SEL_CAVLC:
{
entropy_sel = VIDC_720P_ENTROPY_SEL_CAVLC;
break;
}
case VCD_ENTROPY_SEL_CABAC:
{
entropy_sel = VIDC_720P_ENTROPY_SEL_CABAC;
break;
}
}
switch (encoder->entropy_control.cabac_model) {
default:
case VCD_CABAC_MODEL_NUMBER_0:
{
cabac_model_number =
VIDC_720P_CABAC_MODEL_NUMBER_0;
break;
}
case VCD_CABAC_MODEL_NUMBER_1:
{
cabac_model_number =
VIDC_720P_CABAC_MODEL_NUMBER_1;
break;
}
case VCD_CABAC_MODEL_NUMBER_2:
{
cabac_model_number =
VIDC_720P_CABAC_MODEL_NUMBER_2;
break;
}
}
vidc_720p_encode_set_entropy_control
(entropy_sel, cabac_model_number);
switch (encoder->db_control.db_config) {
default:
case VCD_DB_ALL_BLOCKING_BOUNDARY:
{
db_config =
VIDC_720P_DB_ALL_BLOCKING_BOUNDARY;
break;
}
case VCD_DB_DISABLE:
{
db_config =
VIDC_720P_DB_DISABLE;
break;
}
case VCD_DB_SKIP_SLICE_BOUNDARY:
{
db_config =
VIDC_720P_DB_SKIP_SLICE_BOUNDARY;
break;
}
}
vidc_720p_encode_set_db_filter_control
(db_config,
encoder->db_control.slice_alpha_offset,
encoder->db_control.slice_beta_offset);
}
vidc_720p_encode_set_intra_refresh_mb_number
(encoder->intra_refresh.cir_mb_number);
switch (encoder->multi_slice.m_slice_sel) {
default:
case VCD_MSLICE_OFF:
m_slice_sel = VIDC_720P_MSLICE_OFF;
break;
case VCD_MSLICE_BY_MB_COUNT:
{
m_slice_sel = VIDC_720P_MSLICE_BY_MB_COUNT;
break;
}
case VCD_MSLICE_BY_BYTE_COUNT:
{
m_slice_sel = VIDC_720P_MSLICE_BY_BYTE_COUNT;
break;
}
case VCD_MSLICE_BY_GOB:
{
m_slice_sel = VIDC_720P_MSLICE_BY_GOB;
break;
}
}
vidc_720p_encode_set_multi_slice_info
(m_slice_sel, encoder->multi_slice.m_slice_size);
vidc_720p_encode_set_dpb_buffer
(encoder->enc_dpb_addr.align_physical_addr,
encoder->enc_dpb_addr.buffer_size);
VIDC_LOG1("ENC_DPB_ADDR_SIZE", encoder->enc_dpb_addr.buffer_size);
vidc_720p_encode_set_i_period(encoder->i_period.p_frames);
ddl_metadata_enable(ddl);
if (encoder->seq_header.virtual_base_addr) {
u32 ext_buffer_start, ext_buffer_end, start_byte_num;
ext_buffer_start =
(u32) encoder->seq_header.align_physical_addr;
ext_buffer_end =
ext_buffer_start + encoder->seq_header.buffer_size;
start_byte_num =
(ext_buffer_start & DDL_STREAMBUF_ALIGN_GUARD_BYTES);
ext_buffer_start &= ~(DDL_STREAMBUF_ALIGN_GUARD_BYTES);
ext_buffer_end &= ~(DDL_STREAMBUF_ALIGN_GUARD_BYTES);
VIDC_LOG1("ENC_SEQHDR_ALLOC_SIZE",
encoder->seq_header.buffer_size);
vidc_720p_encode_set_seq_header_buffer(ext_buffer_start,
ext_buffer_end,
start_byte_num);
}
if (encoder->re_con_buf_format.buffer_format ==
VCD_BUFFER_FORMAT_NV12)
mem_access_method = VIDC_720P_TILE_LINEAR;
else
mem_access_method = VIDC_720P_TILE_16x16;
ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_INITCODECDONE);
ddl_move_command_state(ddl->ddl_context, DDL_CMD_INIT_CODEC);
vidc_720p_encode_init_codec(ddl->channel_id, mem_access_method);
}
void ddl_channel_end(struct ddl_client_context *ddl)
{
VIDC_DEBUG_REGISTER_LOG;
ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_CHEND);
ddl_move_command_state(ddl->ddl_context, DDL_CMD_CHANNEL_END);
vidc_720p_submit_command(ddl->channel_id, VIDC_720P_CMD_CHEND);
}
void ddl_encode_frame_run(struct ddl_client_context *ddl)
{
u32 ext_buffer_start, ext_buffer_end;
u32 y_addr, c_addr;
u32 start_byte_number = 0;
struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
struct vcd_frame_data *stream = &(ddl->output_frame.vcd_frm);
ext_buffer_start = (u32) stream->physical + stream->offset;
ext_buffer_end = ddl_encode_set_metadata_output_buf(ddl);
start_byte_number =
(ext_buffer_start & DDL_STREAMBUF_ALIGN_GUARD_BYTES);
if (start_byte_number) {
u32 upper_data, lower_data;
u32 *align_virtual_addr;
ext_buffer_start &= ~(DDL_STREAMBUF_ALIGN_GUARD_BYTES);
align_virtual_addr = (u32 *) (((u32) stream->virtual +
stream->offset) -
start_byte_number);
upper_data = *align_virtual_addr;
align_virtual_addr++;
lower_data = *align_virtual_addr;
vidc_720p_encode_unalign_bitstream(upper_data, lower_data);
}
y_addr = (u32) ddl->input_frame.vcd_frm.physical +
ddl->input_frame.vcd_frm.offset;
c_addr = (y_addr + (encoder->frame_size.scan_lines *
encoder->frame_size.stride));
ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE);
ddl_move_command_state(ddl->ddl_context, DDL_CMD_ENCODE_FRAME);
if (encoder->dynamic_prop_change) {
encoder->dynmic_prop_change_req = true;
ddl_encode_dynamic_property(ddl, true);
}
vidc_720p_encode_set_vop_time(
encoder->vop_timing.vop_time_resolution,
ddl->input_frame.frm_delta
);
vidc_720p_encode_frame(ddl->channel_id,
ext_buffer_start,
ext_buffer_end,
start_byte_number, y_addr, c_addr);
}
u32 ddl_decode_set_buffers(struct ddl_client_context *ddl)
{
struct ddl_decoder_data *decoder = &(ddl->codec_data.decoder);
u32 comv_buf_size = DDL_COMV_BUFLINE_NO, comv_buf_no = 0;
u32 ref_buf_no = 0;
struct ddl_context *ddl_ctxt = NULL;
if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_DPB)) {
VIDC_LOG_STRING("STATE-CRITICAL");
return VCD_ERR_FAIL;
}
if (vidc_msg_timing)
ddl_set_core_start_time(__func__, DEC_OP_TIME);
switch (decoder->codec.codec) {
default:
case VCD_CODEC_DIVX_4:
case VCD_CODEC_DIVX_5:
case VCD_CODEC_DIVX_6:
case VCD_CODEC_XVID:
case VCD_CODEC_MPEG2:
case VCD_CODEC_MPEG4:
{
comv_buf_no = DDL_MPEG_COMV_BUF_NO;
ref_buf_no = DDL_MPEG_REFBUF_COUNT;
break;
}
case VCD_CODEC_H263:
{
comv_buf_no = DDL_H263_COMV_BUF_NO;
break;
}
case VCD_CODEC_VC1:
case VCD_CODEC_VC1_RCV:
{
comv_buf_no =
decoder->client_output_buf_req.actual_count + 1;
comv_buf_size = DDL_VC1_COMV_BUFLINE_NO;
break;
}
case VCD_CODEC_H264:
{
if (decoder->idr_only_decoding)
comv_buf_no = decoder->min_dpb_num;
else
comv_buf_no =
decoder->
client_output_buf_req.
actual_count;
break;
}
}
if (comv_buf_no) {
comv_buf_size *= (comv_buf_no *
(decoder->client_frame_size.stride >> 4) *
((decoder->client_frame_size.scan_lines >> 4) + 1));
if (decoder->dpb_comv_buffer.virtual_base_addr)
ddl_pmem_free(&decoder->dpb_comv_buffer);
ddl_pmem_alloc(&decoder->dpb_comv_buffer, comv_buf_size,
DDL_LINEAR_BUFFER_ALIGN_BYTES);
if (!decoder->dpb_comv_buffer.virtual_base_addr) {
VIDC_LOGERR_STRING
("Dec_set_buf:Comv_buf_alloc_failed");
return VCD_ERR_ALLOC_FAIL;
}
vidc_720p_decode_set_comv_buffer(decoder->dpb_comv_buffer.
align_physical_addr,
decoder->dpb_comv_buffer.
buffer_size);
}
decoder->ref_buffer.align_physical_addr = NULL;
if (ref_buf_no) {
size_t sz, align_bytes, y_sz, frm_sz;
u32 i = 0;
sz = decoder->dp_buf.dec_pic_buffers[0].vcd_frm.alloc_len;
frm_sz = sz;
y_sz = decoder->client_frame_size.height *
decoder->client_frame_size.width;
sz *= ref_buf_no;
align_bytes = decoder->client_output_buf_req.align;
if (decoder->ref_buffer.virtual_base_addr)
ddl_pmem_free(&decoder->ref_buffer);
ddl_pmem_alloc(&decoder->ref_buffer, sz, align_bytes);
if (!decoder->ref_buffer.virtual_base_addr) {
ddl_pmem_free(&decoder->dpb_comv_buffer);
VIDC_LOGERR_STRING
("Dec_set_buf:mpeg_ref_buf_alloc_failed");
return VCD_ERR_ALLOC_FAIL;
}
memset((u8 *)decoder->ref_buffer.virtual_base_addr,
0x80, sz);
for (i = 0; i < ref_buf_no; i++)
memset((u8 *)decoder->ref_buffer.align_virtual_addr +
i*frm_sz, 0x10, y_sz);
}
ddl_decode_set_metadata_output(decoder);
ddl_decoder_dpb_transact(decoder, NULL, DDL_DPB_OP_INIT);
ddl_ctxt = ddl_get_context();
vidc_720p_set_deblock_line_buffer(
ddl_ctxt->db_line_buffer.align_physical_addr,
ddl_ctxt->db_line_buffer.buffer_size);
ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_DPBDONE);
ddl_move_command_state(ddl->ddl_context, DDL_CMD_DECODE_SET_DPB);
vidc_720p_submit_command(ddl->channel_id,
VIDC_720P_CMD_INITBUFFERS);
return VCD_S_SUCCESS;
}
void ddl_decode_frame_run(struct ddl_client_context *ddl)
{
u32 ext_buffer_start = 0, ext_buffer_end = 0;
u32 start_byte_num = 8;
struct ddl_decoder_data *decoder = &ddl->codec_data.decoder;
struct vcd_frame_data *bit_stream =
&(ddl->input_frame.vcd_frm);
if (vidc_msg_timing) {
ddl_set_core_start_time(__func__, DEC_OP_TIME);
ddl_set_core_start_time(__func__, DEC_IP_TIME);
}
if (!bit_stream->data_len ||
!bit_stream->physical) {
ddl_decode_eos_run(ddl);
return;
}
ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE);
ddl_decode_dynamic_property(ddl, true);
ddl_decoder_dpb_transact(decoder, NULL, DDL_DPB_OP_SET_MASK);
ext_buffer_start = (u32)bit_stream->physical +
bit_stream->offset;
start_byte_num = 8 - (ext_buffer_start &
DDL_STREAMBUF_ALIGN_GUARD_BYTES);
ext_buffer_end = ext_buffer_start + bit_stream->data_len;
ext_buffer_start &= ~(DDL_STREAMBUF_ALIGN_GUARD_BYTES);
DDL_PADDING_HACK(ext_buffer_end);
ddl_move_command_state(ddl->ddl_context, DDL_CMD_DECODE_FRAME);
vidc_720p_decode_frame(ddl->channel_id,
ext_buffer_start,
ext_buffer_end,
bit_stream->data_len,
start_byte_num, bit_stream->ip_frm_tag);
}
void ddl_decode_eos_run(struct ddl_client_context *ddl)
{
struct ddl_decoder_data *decoder = &ddl->codec_data.decoder;
ddl_move_client_state(ddl, DDL_CLIENT_WAIT_FOR_EOS_DONE);
ddl_decode_dynamic_property(ddl, true);
ddl_decoder_dpb_transact(decoder, NULL, DDL_DPB_OP_SET_MASK);
decoder->dynmic_prop_change_req = true;
ddl_move_command_state(ddl->ddl_context, DDL_CMD_EOS);
vidc_720p_issue_eos(ddl->channel_id);
}
u32 ddl_hal_engine_reset(struct ddl_context *ddl_context)
{
u32 eng_reset;
u32 channel_id = 0;
u32 fw_endianness;
enum vidc_720p_endian dma_endian;
enum vidc_720p_interrupt_level_selection interrupt_sel;
u32 intr_mask = 0x0;
if (ddl_context->current_ddl)
channel_id = ddl_context->current_ddl->channel_id;
interrupt_sel = VIDC_720P_INTERRUPT_LEVEL_SEL;
/* Enable all the supported interrupt */
intr_mask |= VIDC_720P_INTR_BUFFER_FULL;
intr_mask |= VIDC_720P_INTR_FW_DONE;
intr_mask |= VIDC_720P_INTR_DMA_DONE;
intr_mask |= VIDC_720P_INTR_FRAME_DONE;
vcd_get_fw_property(VCD_FW_ENDIAN, &fw_endianness);
/* Reverse the endianness settings after boot code download */
if (fw_endianness == VCD_FW_BIG_ENDIAN)
dma_endian = VIDC_720P_LITTLE_ENDIAN;
else
dma_endian = VIDC_720P_BIG_ENDIAN;
/* Need to reset MFC silently */
eng_reset = vidc_720p_engine_reset(
channel_id,
dma_endian, interrupt_sel,
intr_mask);
if (!eng_reset) {
/* call the hw fatal callback if engine reset fails */
ddl_hw_fatal_cb(ddl_context);
}
return eng_reset ;
}
@@ -0,0 +1,297 @@
/* Copyright (c) 2010-2012, 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 <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
DDL_INLINE struct ddl_context *ddl_get_context(void)
{
static struct ddl_context ddl_context;
return &ddl_context;
}
DDL_INLINE void ddl_move_client_state(struct ddl_client_context *ddl,
enum ddl_client_state client_state)
{
ddl->client_state = client_state;
}
DDL_INLINE void ddl_move_command_state(struct ddl_context *ddl_context,
enum ddl_cmd_state command_state)
{
ddl_context->cmd_state = command_state;
}
u32 ddl_client_transact(u32 operation,
struct ddl_client_context **pddl_client)
{
u32 ret_status = VCD_ERR_FAIL;
u32 counter;
struct ddl_context *ddl_context;
ddl_context = ddl_get_context();
switch (operation) {
case DDL_FREE_CLIENT:
{
if (pddl_client && *pddl_client) {
u32 channel_id;
channel_id = (*pddl_client)->channel_id;
if (channel_id < VCD_MAX_NO_CLIENT) {
ddl_context->
ddl_clients[channel_id] = NULL;
} else {
VIDC_LOG_STRING("CHID_CORRUPTION");
}
DDL_FREE(*pddl_client);
ret_status = VCD_S_SUCCESS;
}
break;
}
case DDL_GET_CLIENT:
{
ret_status = VCD_ERR_MAX_CLIENT;
for (counter = 0; counter < VCD_MAX_NO_CLIENT &&
ret_status == VCD_ERR_MAX_CLIENT; ++counter) {
if (!ddl_context->ddl_clients[counter]) {
*pddl_client =
(struct ddl_client_context *)
DDL_MALLOC(sizeof
(struct ddl_client_context)
);
if (!*pddl_client) {
ret_status = VCD_ERR_ALLOC_FAIL;
} else {
DDL_MEMSET(*pddl_client, 0,
sizeof(struct
ddl_client_context));
ddl_context->
ddl_clients[counter] =
*pddl_client;
(*pddl_client)->channel_id =
counter;
(*pddl_client)->ddl_context =
ddl_context;
ret_status = VCD_S_SUCCESS;
}
}
}
break;
}
case DDL_INIT_CLIENTS:
{
for (counter = 0; counter < VCD_MAX_NO_CLIENT;
++counter) {
ddl_context->ddl_clients[counter] = NULL;
}
ret_status = VCD_S_SUCCESS;
break;
}
case DDL_ACTIVE_CLIENT:
{
for (counter = 0; counter < VCD_MAX_NO_CLIENT;
++counter) {
if (ddl_context->ddl_clients[counter]) {
ret_status = VCD_S_SUCCESS;
break;
}
}
break;
}
default:
{
ret_status = VCD_ERR_ILLEGAL_PARM;
break;
}
}
return ret_status;
}
u32 ddl_decoder_dpb_transact(struct ddl_decoder_data *decoder,
struct ddl_frame_data_tag *in_out_frame,
u32 operation)
{
u32 vcd_status = VCD_S_SUCCESS;
u32 loopc;
struct ddl_frame_data_tag *found_frame = NULL;
struct ddl_mask *dpb_mask = &decoder->dpb_mask;
u32 temp_mask;
switch (operation) {
case DDL_DPB_OP_MARK_BUSY:
case DDL_DPB_OP_MARK_FREE:
{
for (loopc = 0; !found_frame &&
loopc < decoder->dp_buf.no_of_dec_pic_buf;
++loopc) {
if (in_out_frame->vcd_frm.physical ==
decoder->dp_buf.
dec_pic_buffers[loopc].vcd_frm.
physical) {
found_frame =
&(decoder->dp_buf.
dec_pic_buffers[loopc]);
break;
}
}
if (found_frame) {
if (operation == DDL_DPB_OP_MARK_BUSY) {
temp_mask = (~(0x1 << loopc));
if (decoder->idr_only_decoding)
temp_mask = ~(0xffffffff);
dpb_mask->hw_mask &= temp_mask;
*in_out_frame = *found_frame;
} else if (operation ==
DDL_DPB_OP_MARK_FREE) {
temp_mask = (0x1 << loopc);
if (decoder->idr_only_decoding)
temp_mask = 0xffffffff;
dpb_mask->client_mask |= temp_mask;
*found_frame = *in_out_frame;
}
} else {
in_out_frame->vcd_frm.physical = NULL;
in_out_frame->vcd_frm.virtual = NULL;
vcd_status = VCD_ERR_BAD_POINTER;
VIDC_LOG_STRING("BUF_NOT_FOUND");
}
break;
}
case DDL_DPB_OP_SET_MASK:
{
dpb_mask->hw_mask |= dpb_mask->client_mask;
dpb_mask->client_mask = 0;
vidc_720p_decode_set_dpb_release_buffer_mask
(dpb_mask->hw_mask);
break;
}
case DDL_DPB_OP_INIT:
{
u32 dpb_size, index, num_dpb;
dpb_size = (!decoder->meta_data_offset) ?
decoder->dp_buf.dec_pic_buffers[0].vcd_frm.
alloc_len : decoder->meta_data_offset;
if (decoder->idr_only_decoding)
num_dpb = decoder->min_dpb_num;
else
num_dpb = decoder->dp_buf.no_of_dec_pic_buf;
vidc_720p_decode_set_dpb_details(
num_dpb,
dpb_size,
decoder->ref_buffer.
align_physical_addr);
for (loopc = 0; loopc < num_dpb; ++loopc) {
if (decoder->idr_only_decoding)
index = 0;
else
index = loopc;
vidc_720p_decode_set_dpb_buffers(loopc,
(u32 *)
decoder->
dp_buf.
dec_pic_buffers
[index].
vcd_frm.
physical);
VIDC_LOG1("DEC_DPB_BUFn_SIZE=%d",
decoder->dp_buf.
dec_pic_buffers[index].vcd_frm.
alloc_len);
}
break;
}
case DDL_DPB_OP_RETRIEVE:
{
u32 position;
if (dpb_mask->client_mask) {
position = 0x1;
for (loopc = 0;
loopc <
decoder->dp_buf.no_of_dec_pic_buf
&& !found_frame; ++loopc) {
if (dpb_mask->
client_mask & position) {
found_frame =
&decoder->dp_buf.
dec_pic_buffers[loopc];
dpb_mask->client_mask &=
~(position);
}
position <<= 1;
}
} else if (dpb_mask->hw_mask) {
position = 0x1;
for (loopc = 0;
loopc <
decoder->dp_buf.no_of_dec_pic_buf
&& !found_frame; ++loopc) {
if (dpb_mask->hw_mask
& position) {
found_frame =
&decoder->dp_buf.
dec_pic_buffers[loopc];
dpb_mask->hw_mask &=
~(position);
}
position <<= 1;
}
}
if (found_frame)
*in_out_frame = *found_frame;
else {
in_out_frame->vcd_frm.physical = NULL;
in_out_frame->vcd_frm.virtual = NULL;
}
break;
}
}
return vcd_status;
}
void ddl_release_context_buffers(struct ddl_context *ddl_context)
{
ddl_pmem_free(&ddl_context->context_buf_addr);
ddl_pmem_free(&ddl_context->db_line_buffer);
ddl_pmem_free(&ddl_context->data_partition_tempbuf);
ddl_pmem_free(&ddl_context->metadata_shared_input);
ddl_pmem_free(&ddl_context->dbg_core_dump);
vcd_fw_release();
}
void ddl_release_client_internal_buffers(struct ddl_client_context *ddl)
{
if (ddl->decoding) {
struct ddl_decoder_data *decoder =
&(ddl->codec_data.decoder);
ddl_pmem_free(&decoder->h264Vsp_temp_buffer);
ddl_pmem_free(&decoder->dpb_comv_buffer);
ddl_pmem_free(&decoder->ref_buffer);
DDL_FREE(decoder->dp_buf.dec_pic_buffers);
ddl_decode_dynamic_property(ddl, false);
decoder->decode_config.sequence_header_len = 0;
decoder->decode_config.sequence_header = NULL;
decoder->dpb_mask.client_mask = 0;
decoder->dpb_mask.hw_mask = 0;
decoder->dp_buf.no_of_dec_pic_buf = 0;
decoder->dynamic_prop_change = 0;
} else {
struct ddl_encoder_data *encoder =
&(ddl->codec_data.encoder);
ddl_pmem_free(&encoder->enc_dpb_addr);
ddl_pmem_free(&encoder->seq_header);
ddl_encode_dynamic_property(ddl, false);
encoder->dynamic_prop_change = 0;
}
}
@@ -0,0 +1,81 @@
/* Copyright (c) 2010-2012, 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.
*
*/
#ifndef _VCD_DDL_INTERNAL_PROPERTY_H_
#define _VCD_DDL_INTERNAL_PROPERTY_H_
#include <media/msm/vcd_api.h>
#define VCD_EVT_RESP_DDL_BASE 0x3000
#define VCD_EVT_RESP_DEVICE_INIT (VCD_EVT_RESP_DDL_BASE + 0x1)
#define VCD_EVT_RESP_OUTPUT_REQ (VCD_EVT_RESP_DDL_BASE + 0x2)
#define VCD_EVT_RESP_EOS_DONE (VCD_EVT_RESP_DDL_BASE + 0x3)
#define VCD_EVT_RESP_TRANSACTION_PENDING (VCD_EVT_RESP_DDL_BASE + 0x4)
#define VCD_S_DDL_ERR_BASE 0x90000000
#define VCD_ERR_MAX_NO_CODEC (VCD_S_DDL_ERR_BASE + 0x1)
#define VCD_ERR_CLIENT_PRESENT (VCD_S_DDL_ERR_BASE + 0x2)
#define VCD_ERR_CLIENT_FATAL (VCD_S_DDL_ERR_BASE + 0x3)
#define VCD_I_CUSTOM_BASE (VCD_I_RESERVED_BASE)
#define VCD_I_RC_LEVEL_CONFIG (VCD_I_CUSTOM_BASE + 0x1)
#define VCD_I_FRAME_LEVEL_RC (VCD_I_CUSTOM_BASE + 0x2)
#define VCD_I_ADAPTIVE_RC (VCD_I_CUSTOM_BASE + 0x3)
#define VCD_I_CUSTOM_DDL_BASE (VCD_I_RESERVED_BASE + 0x100)
#define DDL_I_INPUT_BUF_REQ (VCD_I_CUSTOM_DDL_BASE + 0x1)
#define DDL_I_OUTPUT_BUF_REQ (VCD_I_CUSTOM_DDL_BASE + 0x2)
#define DDL_I_DPB (VCD_I_CUSTOM_DDL_BASE + 0x3)
#define DDL_I_DPB_RELEASE (VCD_I_CUSTOM_DDL_BASE + 0x4)
#define DDL_I_DPB_RETRIEVE (VCD_I_CUSTOM_DDL_BASE + 0x5)
#define DDL_I_REQ_OUTPUT_FLUSH (VCD_I_CUSTOM_DDL_BASE + 0x6)
#define DDL_I_SEQHDR_ALIGN_BYTES (VCD_I_CUSTOM_DDL_BASE + 0x7)
#define DDL_I_SEQHDR_PRESENT (VCD_I_CUSTOM_DDL_BASE + 0xb)
#define DDL_I_CAPABILITY (VCD_I_CUSTOM_DDL_BASE + 0x8)
#define DDL_I_FRAME_PROC_UNITS (VCD_I_CUSTOM_DDL_BASE + 0x9)
struct vcd_property_rc_level {
u32 frame_level_rc;
u32 mb_level_rc;
};
struct vcd_property_frame_level_rc_params {
u32 reaction_coeff;
};
struct vcd_property_adaptive_rc_params {
u32 dark_region_as_flag;
u32 smooth_region_as_flag;
u32 static_region_as_flag;
u32 activity_region_flag;
};
struct vcd_property_slice_delivery_info {
u32 enable;
u32 num_slices;
u32 num_slices_enc;
};
struct ddl_frame_data_tag;
struct ddl_property_dec_pic_buffers {
struct ddl_frame_data_tag *dec_pic_buffers;
u32 no_of_dec_pic_buf;
};
struct ddl_property_capability {
u32 max_num_client;
u32 general_command_depth;
u32 frame_command_depth;
u32 exclusive;
u32 ddl_time_out_in_ms;
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,580 @@
/* Copyright (c) 2010-2012, 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 <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#include "vcd_ddl_metadata.h"
static u32 *ddl_metadata_hdr_entry(struct ddl_client_context *ddl,
u32 meta_data)
{
u32 skip_words = 0;
u32 *buffer;
if (ddl->decoding) {
buffer = (u32 *)
ddl->codec_data.decoder.meta_data_input.
align_virtual_addr;
skip_words = 32 + 1;
buffer += skip_words;
switch (meta_data) {
default:
case VCD_METADATA_DATANONE:
{
skip_words = 0;
break;
}
case VCD_METADATA_QPARRAY:
{
skip_words = 3;
break;
}
case VCD_METADATA_CONCEALMB:
{
skip_words = 6;
break;
}
case VCD_METADATA_VC1:
{
skip_words = 9;
break;
}
case VCD_METADATA_SEI:
{
skip_words = 12;
break;
}
case VCD_METADATA_VUI:
{
skip_words = 15;
break;
}
case VCD_METADATA_PASSTHROUGH:
{
skip_words = 18;
break;
}
case VCD_METADATA_QCOMFILLER:
{
skip_words = 21;
break;
}
}
} else {
buffer = (u32 *)
ddl->codec_data.encoder.meta_data_input.
align_virtual_addr;
skip_words = 2;
buffer += skip_words;
switch (meta_data) {
default:
case VCD_METADATA_DATANONE:
{
skip_words = 0;
break;
}
case VCD_METADATA_ENC_SLICE:
{
skip_words = 3;
break;
}
case VCD_METADATA_QCOMFILLER:
{
skip_words = 6;
break;
}
}
}
buffer += skip_words;
return buffer;
}
void ddl_set_default_meta_data_hdr(struct ddl_client_context *ddl)
{
struct ddl_buf_addr *main_buffer =
&ddl->ddl_context->metadata_shared_input;
struct ddl_buf_addr *client_buffer;
u32 *hdr_entry;
if (ddl->decoding)
client_buffer = &(ddl->codec_data.decoder.meta_data_input);
else
client_buffer = &(ddl->codec_data.encoder.meta_data_input);
DDL_METADATA_CLIENT_INPUTBUF(main_buffer, client_buffer,
ddl->channel_id);
hdr_entry = ddl_metadata_hdr_entry(ddl, VCD_METADATA_QCOMFILLER);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_QCOMFILLER;
hdr_entry = ddl_metadata_hdr_entry(ddl, VCD_METADATA_DATANONE);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_DATANONE;
if (ddl->decoding) {
hdr_entry =
ddl_metadata_hdr_entry(ddl, VCD_METADATA_QPARRAY);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_QPARRAY;
hdr_entry =
ddl_metadata_hdr_entry(ddl, VCD_METADATA_CONCEALMB);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_CONCEALMB;
hdr_entry = ddl_metadata_hdr_entry(ddl, VCD_METADATA_SEI);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_SEI;
hdr_entry = ddl_metadata_hdr_entry(ddl, VCD_METADATA_VUI);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_VUI;
hdr_entry = ddl_metadata_hdr_entry(ddl, VCD_METADATA_VC1);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] = VCD_METADATA_VC1;
hdr_entry =
ddl_metadata_hdr_entry(ddl, VCD_METADATA_PASSTHROUGH);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] =
VCD_METADATA_PASSTHROUGH;
} else {
hdr_entry =
ddl_metadata_hdr_entry(ddl, VCD_METADATA_ENC_SLICE);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] =
VCD_METADATA_ENC_SLICE;
}
}
static u32 ddl_supported_metadata_flag(struct ddl_client_context *ddl)
{
u32 flag = 0;
if (ddl->decoding) {
enum vcd_codec codec =
ddl->codec_data.decoder.codec.codec;
flag |= (VCD_METADATA_CONCEALMB |
VCD_METADATA_PASSTHROUGH | VCD_METADATA_QPARRAY);
if (codec == VCD_CODEC_H264) {
flag |= (VCD_METADATA_SEI | VCD_METADATA_VUI);
} else if (codec == VCD_CODEC_VC1 ||
codec == VCD_CODEC_VC1_RCV) {
flag |= VCD_METADATA_VC1;
}
} else {
flag |= VCD_METADATA_ENC_SLICE;
}
return flag;
}
void ddl_set_default_metadata_flag(struct ddl_client_context *ddl)
{
if (ddl->decoding)
ddl->codec_data.decoder.meta_data_enable_flag = 0;
else
ddl->codec_data.encoder.meta_data_enable_flag = 0;
}
void ddl_set_default_decoder_metadata_buffer_size(
struct ddl_decoder_data *decoder,
struct vcd_property_frame_size *frame_size,
struct vcd_buffer_requirement *output_buf_req)
{
u32 flag = decoder->meta_data_enable_flag;
u32 suffix = 0;
size_t sz = 0;
if (!flag) {
decoder->suffix = 0;
return;
}
if (flag & VCD_METADATA_QPARRAY) {
u32 num_of_mb =
((frame_size->width * frame_size->height) >> 8);
sz = DDL_METADATA_HDR_SIZE;
sz += num_of_mb;
DDL_METADATA_ALIGNSIZE(sz);
suffix += sz;
}
if (flag & VCD_METADATA_CONCEALMB) {
u32 num_of_mb =
((frame_size->width * frame_size->height) >> 8);
sz = DDL_METADATA_HDR_SIZE + (num_of_mb >> 3);
DDL_METADATA_ALIGNSIZE(sz);
suffix += sz;
}
if (flag & VCD_METADATA_VC1) {
sz = DDL_METADATA_HDR_SIZE;
sz += DDL_METADATA_VC1_PAYLOAD_SIZE;
DDL_METADATA_ALIGNSIZE(sz);
suffix += sz;
}
if (flag & VCD_METADATA_SEI) {
sz = DDL_METADATA_HDR_SIZE;
sz += DDL_METADATA_SEI_PAYLOAD_SIZE;
DDL_METADATA_ALIGNSIZE(sz);
suffix += (sz * DDL_METADATA_SEI_MAX);
}
if (flag & VCD_METADATA_VUI) {
sz = DDL_METADATA_HDR_SIZE;
sz += DDL_METADATA_VUI_PAYLOAD_SIZE;
DDL_METADATA_ALIGNSIZE(sz);
suffix += (sz);
}
if (flag & VCD_METADATA_PASSTHROUGH) {
sz = DDL_METADATA_HDR_SIZE;
sz += DDL_METADATA_PASSTHROUGH_PAYLOAD_SIZE;
DDL_METADATA_ALIGNSIZE(sz);
suffix += (sz);
}
sz = DDL_METADATA_EXTRADATANONE_SIZE;
DDL_METADATA_ALIGNSIZE(sz);
suffix += (sz);
suffix += DDL_METADATA_EXTRAPAD_SIZE;
DDL_METADATA_ALIGNSIZE(suffix);
decoder->suffix = suffix;
output_buf_req->sz += suffix;
return;
}
void ddl_set_default_encoder_metadata_buffer_size(struct ddl_encoder_data
*encoder)
{
u32 flag = encoder->meta_data_enable_flag;
u32 suffix = 0;
size_t sz = 0;
if (!flag) {
encoder->suffix = 0;
return;
}
if (flag & VCD_METADATA_ENC_SLICE) {
u32 num_of_mb = (encoder->frame_size.width *
encoder->frame_size.height / 16 / 16);
sz = DDL_METADATA_HDR_SIZE;
sz += 4;
sz += (8 * num_of_mb);
DDL_METADATA_ALIGNSIZE(sz);
suffix += sz;
}
sz = DDL_METADATA_EXTRADATANONE_SIZE;
DDL_METADATA_ALIGNSIZE(sz);
suffix += (sz);
suffix += DDL_METADATA_EXTRAPAD_SIZE;
DDL_METADATA_ALIGNSIZE(suffix);
encoder->suffix = suffix;
encoder->output_buf_req.sz += suffix;
}
u32 ddl_set_metadata_params(struct ddl_client_context *ddl,
struct vcd_property_hdr *property_hdr,
void *property_value)
{
u32 vcd_status = VCD_ERR_ILLEGAL_PARM;
if (property_hdr->prop_id == VCD_I_METADATA_ENABLE) {
struct vcd_property_meta_data_enable *meta_data_enable =
(struct vcd_property_meta_data_enable *)
property_value;
u32 *meta_data_enable_flag;
enum vcd_codec codec;
if (ddl->decoding) {
meta_data_enable_flag =
&(ddl->codec_data.decoder.
meta_data_enable_flag);
codec = ddl->codec_data.decoder.codec.codec;
} else {
meta_data_enable_flag =
&(ddl->codec_data.encoder.
meta_data_enable_flag);
codec = ddl->codec_data.encoder.codec.codec;
}
if (sizeof(struct vcd_property_meta_data_enable) ==
property_hdr->sz &&
DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN) &&
codec) {
u32 flag = ddl_supported_metadata_flag(ddl);
flag &= (meta_data_enable->meta_data_enable_flag);
if (flag)
flag |= DDL_METADATA_MANDATORY;
if (flag != *meta_data_enable_flag) {
*meta_data_enable_flag = flag;
if (ddl->decoding) {
ddl_set_default_decoder_buffer_req
(&ddl->codec_data.decoder,
true);
} else {
ddl_set_default_encoder_buffer_req
(&ddl->codec_data.encoder);
}
}
vcd_status = VCD_S_SUCCESS;
}
} else if (property_hdr->prop_id == VCD_I_METADATA_HEADER) {
struct vcd_property_metadata_hdr *hdr =
(struct vcd_property_metadata_hdr *)property_value;
if (sizeof(struct vcd_property_metadata_hdr) ==
property_hdr->sz) {
u32 flag = ddl_supported_metadata_flag(ddl);
flag |= DDL_METADATA_MANDATORY;
flag &= hdr->meta_data_id;
if (!(flag & (flag - 1))) {
u32 *hdr_entry =
ddl_metadata_hdr_entry(ddl, flag);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] =
hdr->version;
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] =
hdr->port_index;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] =
hdr->type;
vcd_status = VCD_S_SUCCESS;
}
}
}
return vcd_status;
}
u32 ddl_get_metadata_params(struct ddl_client_context *ddl,
struct vcd_property_hdr *property_hdr,
void *property_value)
{
u32 vcd_status = VCD_ERR_ILLEGAL_PARM ;
if (property_hdr->prop_id == VCD_I_METADATA_ENABLE &&
sizeof(struct vcd_property_meta_data_enable)
== property_hdr->sz) {
struct vcd_property_meta_data_enable *meta_data_enable =
(struct vcd_property_meta_data_enable *)
property_value;
meta_data_enable->meta_data_enable_flag =
((ddl->decoding) ?
(ddl->codec_data.decoder.meta_data_enable_flag)
: (ddl->codec_data.encoder.meta_data_enable_flag));
vcd_status = VCD_S_SUCCESS;
} else if (property_hdr->prop_id == VCD_I_METADATA_HEADER &&
sizeof(struct vcd_property_metadata_hdr) ==
property_hdr->sz) {
struct vcd_property_metadata_hdr *hdr =
(struct vcd_property_metadata_hdr *)
property_value;
u32 flag = ddl_supported_metadata_flag(ddl);
flag |= DDL_METADATA_MANDATORY;
flag &= hdr->meta_data_id;
if (!(flag & (flag - 1))) {
u32 *hdr_entry = ddl_metadata_hdr_entry(ddl,
flag);
hdr->version =
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX];
hdr->port_index =
hdr_entry[DDL_METADATA_HDR_PORT_INDEX];
hdr->type =
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX];
vcd_status = VCD_S_SUCCESS;
}
}
return vcd_status;
}
void ddl_metadata_enable(struct ddl_client_context *ddl)
{
u32 flag, hal_flag = 0;
u32 *metadata_input;
if (ddl->decoding) {
flag = ddl->codec_data.decoder.meta_data_enable_flag;
metadata_input =
ddl->codec_data.decoder.meta_data_input.
align_physical_addr;
} else {
flag = ddl->codec_data.encoder.meta_data_enable_flag;
metadata_input =
ddl->codec_data.encoder.meta_data_input.
align_physical_addr;
}
if (flag) {
if (flag & VCD_METADATA_QPARRAY)
hal_flag |= VIDC_720P_METADATA_ENABLE_QP;
if (flag & VCD_METADATA_CONCEALMB)
hal_flag |= VIDC_720P_METADATA_ENABLE_CONCEALMB;
if (flag & VCD_METADATA_VC1)
hal_flag |= VIDC_720P_METADATA_ENABLE_VC1;
if (flag & VCD_METADATA_SEI)
hal_flag |= VIDC_720P_METADATA_ENABLE_SEI;
if (flag & VCD_METADATA_VUI)
hal_flag |= VIDC_720P_METADATA_ENABLE_VUI;
if (flag & VCD_METADATA_ENC_SLICE)
hal_flag |= VIDC_720P_METADATA_ENABLE_ENCSLICE;
if (flag & VCD_METADATA_PASSTHROUGH)
hal_flag |= VIDC_720P_METADATA_ENABLE_PASSTHROUGH;
} else {
metadata_input = 0;
}
vidc_720p_metadata_enable(hal_flag, metadata_input);
}
u32 ddl_encode_set_metadata_output_buf(struct ddl_client_context *ddl)
{
struct ddl_encoder_data *encoder = &ddl->codec_data.encoder;
u32 *buffer;
struct vcd_frame_data *stream = &(ddl->output_frame.vcd_frm);
u32 ext_buffer_end, hw_metadata_start;
ext_buffer_end = (u32) stream->physical + stream->alloc_len;
if (!encoder->meta_data_enable_flag) {
ext_buffer_end &= ~(DDL_STREAMBUF_ALIGN_GUARD_BYTES);
return ext_buffer_end;
}
hw_metadata_start = (ext_buffer_end - encoder->suffix) &
~(DDL_STREAMBUF_ALIGN_GUARD_BYTES);
ext_buffer_end = (hw_metadata_start - 1) &
~(DDL_STREAMBUF_ALIGN_GUARD_BYTES);
buffer = encoder->meta_data_input.align_virtual_addr;
*buffer++ = encoder->suffix;
*buffer = hw_metadata_start;
encoder->meta_data_offset =
hw_metadata_start - (u32) stream->physical;
return ext_buffer_end;
}
void ddl_decode_set_metadata_output(struct ddl_decoder_data *decoder)
{
u32 *buffer;
u32 loopc;
if (!decoder->meta_data_enable_flag) {
decoder->meta_data_offset = 0;
return;
}
decoder->meta_data_offset = ddl_get_yuv_buffer_size(
&decoder->client_frame_size, &decoder->buf_format,
(!decoder->progressive_only), decoder->codec.codec);
buffer = decoder->meta_data_input.align_virtual_addr;
*buffer++ = decoder->suffix;
for (loopc = 0; loopc < decoder->dp_buf.no_of_dec_pic_buf;
++loopc) {
*buffer++ = (u32) (decoder->meta_data_offset + (u8 *)
decoder->dp_buf.
dec_pic_buffers[loopc].vcd_frm.
physical);
}
}
void ddl_process_encoder_metadata(struct ddl_client_context *ddl)
{
struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
struct vcd_frame_data *out_frame =
&(ddl->output_frame.vcd_frm);
u32 *qfiller_hdr, *qfiller, start_addr;
u32 qfiller_size;
if (!encoder->meta_data_enable_flag) {
out_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
return;
}
if (!encoder->enc_frame_info.metadata_exists) {
out_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
return;
}
out_frame->flags |= VCD_FRAME_FLAG_EXTRADATA;
start_addr = (u32) ((u8 *) out_frame->virtual +
out_frame->offset);
qfiller = (u32 *) ((out_frame->data_len + start_addr + 3) & ~3);
qfiller_size = (u32) ((encoder->meta_data_offset +
(u8 *) out_frame->virtual) -
(u8 *) qfiller);
qfiller_hdr = ddl_metadata_hdr_entry(ddl, VCD_METADATA_QCOMFILLER);
*qfiller++ = qfiller_size;
*qfiller++ = qfiller_hdr[DDL_METADATA_HDR_VERSION_INDEX];
*qfiller++ = qfiller_hdr[DDL_METADATA_HDR_PORT_INDEX];
*qfiller++ = qfiller_hdr[DDL_METADATA_HDR_TYPE_INDEX];
*qfiller = (u32) (qfiller_size - DDL_METADATA_HDR_SIZE);
}
void ddl_process_decoder_metadata(struct ddl_client_context *ddl)
{
struct ddl_decoder_data *decoder = &(ddl->codec_data.decoder);
struct vcd_frame_data *output_frame =
&(ddl->output_frame.vcd_frm);
u32 *qfiller_hdr, *qfiller;
u32 qfiller_size;
if (!decoder->meta_data_enable_flag) {
output_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
return;
}
if (!decoder->dec_disp_info.metadata_exists) {
output_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
return;
}
output_frame->flags |= VCD_FRAME_FLAG_EXTRADATA;
if (output_frame->data_len != decoder->meta_data_offset) {
qfiller = (u32 *) ((u32) ((output_frame->data_len +
output_frame->offset +
(u8 *) output_frame->virtual) +
3) & ~3);
qfiller_size = (u32) ((decoder->meta_data_offset +
(u8 *) output_frame->virtual) -
(u8 *) qfiller);
qfiller_hdr =
ddl_metadata_hdr_entry(ddl, VCD_METADATA_QCOMFILLER);
*qfiller++ = qfiller_size;
*qfiller++ = qfiller_hdr[DDL_METADATA_HDR_VERSION_INDEX];
*qfiller++ = qfiller_hdr[DDL_METADATA_HDR_PORT_INDEX];
*qfiller++ = qfiller_hdr[DDL_METADATA_HDR_TYPE_INDEX];
*qfiller = (u32) (qfiller_size - DDL_METADATA_HDR_SIZE);
}
}
@@ -0,0 +1,79 @@
/* Copyright (c) 2010, 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.
*
*/
#ifndef _VCD_DDL_METADATA_H_
#define _VCD_DDL_METADATA_H_
#define DDL_MAX_DEC_METADATATYPE (8)
#define DDL_MAX_ENC_METADATATYPE (3)
#define DDL_METADATA_EXTRAPAD_SIZE (256)
#define DDL_METADATA_HDR_SIZE (20)
#define DDL_METADATA_EXTRADATANONE_SIZE (24)
#define DDL_METADATA_ALIGNSIZE(x) ((x) = (((x) + 0x7) & ~0x7))
#define DDL_METADATA_MANDATORY (VCD_METADATA_DATANONE | \
VCD_METADATA_QCOMFILLER)
#define DDL_METADATA_VC1_PAYLOAD_SIZE (38*4)
#define DDL_METADATA_SEI_PAYLOAD_SIZE (100)
#define DDL_METADATA_SEI_MAX (5)
#define DDL_METADATA_VUI_PAYLOAD_SIZE (256)
#define DDL_METADATA_PASSTHROUGH_PAYLOAD_SIZE (68)
#define DDL_METADATA_CLIENT_INPUTBUFSIZE (256)
#define DDL_METADATA_TOTAL_INPUTBUFSIZE \
(DDL_METADATA_CLIENT_INPUTBUFSIZE * VCD_MAX_NO_CLIENT)
#define DDL_METADATA_CLIENT_INPUTBUF(main_buffer, client_buffer, \
channel_id) \
{ \
(client_buffer)->align_physical_addr = (u32 *)\
((u8 *)(main_buffer)->align_physical_addr + \
(DDL_METADATA_CLIENT_INPUTBUFSIZE * (channel_id)) \
); \
(client_buffer)->align_virtual_addr = (u32 *)\
((u8 *)(main_buffer)->align_virtual_addr + \
(DDL_METADATA_CLIENT_INPUTBUFSIZE * (channel_id)) \
); \
(client_buffer)->virtual_base_addr = 0; \
}
#define DDL_METADATA_HDR_VERSION_INDEX 0
#define DDL_METADATA_HDR_PORT_INDEX 1
#define DDL_METADATA_HDR_TYPE_INDEX 2
void ddl_set_default_meta_data_hdr(struct ddl_client_context *ddl);
u32 ddl_get_metadata_params(struct ddl_client_context *ddl,
struct vcd_property_hdr *property_hdr, void *property_value);
u32 ddl_set_metadata_params(struct ddl_client_context *ddl,
struct vcd_property_hdr *property_hdr,
void *property_value);
void ddl_set_default_metadata_flag(struct ddl_client_context *ddl);
void ddl_set_default_decoder_metadata_buffer_size
(struct ddl_decoder_data *decoder,
struct vcd_property_frame_size *frame_size,
struct vcd_buffer_requirement *output_buf_req);
void ddl_set_default_encoder_metadata_buffer_size(struct ddl_encoder_data
*encoder);
void ddl_metadata_enable(struct ddl_client_context *ddl);
u32 ddl_encode_set_metadata_output_buf(struct ddl_client_context *ddl);
void ddl_decode_set_metadata_output(struct ddl_decoder_data *decoder);
void ddl_process_encoder_metadata(struct ddl_client_context *ddl);
void ddl_process_decoder_metadata(struct ddl_client_context *ddl);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,269 @@
/* Copyright (c) 2010-2013, 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/memory_alloc.h>
#include <media/msm/vidc_type.h>
#include "vcd_ddl_utils.h"
#include "vcd_res_tracker_api.h"
#if DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
#else
#define DBG(x...)
#endif
#define DBG_TIME(x...) printk(KERN_DEBUG x)
#define ERR(x...) printk(KERN_ERR x)
struct time_data {
unsigned int ddl_t1;
unsigned int ddl_ttotal;
unsigned int ddl_count;
};
static struct time_data proc_time[MAX_TIME_DATA];
#ifdef NO_IN_KERNEL_PMEM
void ddl_pmem_alloc(struct ddl_buf_addr *buff_addr, size_t sz, u32 align)
{
u32 guard_bytes, align_mask;
u32 physical_addr, align_offset;
dma_addr_t phy_addr;
if (align == DDL_LINEAR_BUFFER_ALIGN_BYTES) {
guard_bytes = 31;
align_mask = 0xFFFFFFE0U;
} else {
guard_bytes = DDL_TILE_BUF_ALIGN_GUARD_BYTES;
align_mask = DDL_TILE_BUF_ALIGN_MASK;
}
buff_addr->virtual_base_addr =
kmalloc((sz + guard_bytes), GFP_KERNEL);
if (!buff_addr->virtual_base_addr) {
ERR("\n ERROR %s:%u kamlloc fails to allocate"
" sz + guard_bytes = %u\n", __func__, __LINE__,
(sz + guard_bytes));
return;
}
phy_addr = dma_map_single(NULL, buff_addr->virtual_base_addr,
sz + guard_bytes, DMA_TO_DEVICE);
buff_addr->buffer_size = sz;
physical_addr = (u32) phy_addr;
buff_addr->align_physical_addr =
(u32 *) ((physical_addr + guard_bytes) & align_mask);
align_offset =
(u32) (buff_addr->align_physical_addr) - physical_addr;
buff_addr->align_virtual_addr =
(u32 *) ((u32) (buff_addr->virtual_base_addr)
+ align_offset);
}
void ddl_pmem_free(struct ddl_buf_addr *buff_addr)
{
kfree(buff_addr->virtual_base_addr);
buff_addr->buffer_size = 0;
buff_addr->virtual_base_addr = NULL;
}
#else
void ddl_pmem_alloc(struct ddl_buf_addr *buff_addr, size_t sz, u32 align)
{
u32 guard_bytes, align_mask;
u32 align_offset;
u32 alloc_size;
struct ddl_context *ddl_context;
unsigned long *kernel_vaddr = NULL;
ion_phys_addr_t phyaddr = 0;
size_t len = 0;
int ret = -EINVAL;
if (!buff_addr) {
ERR("\n%s() Invalid Parameters\n", __func__);
return;
}
if (align == DDL_LINEAR_BUFFER_ALIGN_BYTES) {
guard_bytes = 31;
align_mask = 0xFFFFFFE0U;
} else {
guard_bytes = DDL_TILE_BUF_ALIGN_GUARD_BYTES;
align_mask = DDL_TILE_BUF_ALIGN_MASK;
}
ddl_context = ddl_get_context();
alloc_size = sz + guard_bytes;
if (res_trk_get_enable_ion()) {
if (!ddl_context->video_ion_client)
ddl_context->video_ion_client =
res_trk_get_ion_client();
if (!ddl_context->video_ion_client) {
ERR("\n%s(): DDL ION Client Invalid handle\n",
__func__);
goto bailout;
}
buff_addr->mem_type = res_trk_get_mem_type();
buff_addr->alloc_handle = ion_alloc(
ddl_context->video_ion_client,
alloc_size,
SZ_4K,
buff_addr->mem_type, 0);
if (IS_ERR_OR_NULL(buff_addr->alloc_handle)) {
ERR("\n%s(): DDL ION alloc failed\n", __func__);
goto bailout;
}
ret = ion_phys(ddl_context->video_ion_client,
buff_addr->alloc_handle,
&phyaddr,
&len);
if (ret || !phyaddr) {
ERR("\n%s(): DDL ION client physical failed\n",
__func__);
goto free_ion_buffer;
}
buff_addr->physical_base_addr = (u32 *)phyaddr;
kernel_vaddr = (unsigned long *) ion_map_kernel(
ddl_context->video_ion_client,
buff_addr->alloc_handle);
if (IS_ERR_OR_NULL(kernel_vaddr)) {
ERR("\n%s(): DDL ION map failed\n", __func__);
goto unmap_ion_buffer;
}
buff_addr->virtual_base_addr = (u32 *)kernel_vaddr;
DBG("ddl_ion_alloc: handle(0x%x), mem_type(0x%x), "\
"phys(0x%x), virt(0x%x), size(%u), align(%u), "\
"alloced_len(%u)", (u32)buff_addr->alloc_handle,
(u32)buff_addr->mem_type,
(u32)buff_addr->physical_base_addr,
(u32)buff_addr->virtual_base_addr,
alloc_size, align, len);
} else {
pr_err("ION must be enabled.");
goto bailout;
}
memset(buff_addr->virtual_base_addr, 0 , sz + guard_bytes);
buff_addr->buffer_size = sz;
buff_addr->align_physical_addr = (u32 *)
(((u32)buff_addr->physical_base_addr + guard_bytes) &
align_mask);
align_offset = (u32) (buff_addr->align_physical_addr) -
(u32)buff_addr->physical_base_addr;
buff_addr->align_virtual_addr =
(u32 *) ((u32) (buff_addr->virtual_base_addr)
+ align_offset);
DBG("%s(): phys(0x%x) align_phys(0x%x), virt(0x%x),"\
" align_virt(0x%x)", __func__,
(u32)buff_addr->physical_base_addr,
(u32)buff_addr->align_physical_addr,
(u32)buff_addr->virtual_base_addr,
(u32)buff_addr->align_virtual_addr);
return;
unmap_ion_buffer:
if (ddl_context->video_ion_client) {
if (buff_addr->alloc_handle)
ion_unmap_kernel(ddl_context->video_ion_client,
buff_addr->alloc_handle);
}
free_ion_buffer:
if (ddl_context->video_ion_client) {
if (buff_addr->alloc_handle)
ion_free(ddl_context->video_ion_client,
buff_addr->alloc_handle);
}
bailout:
memset(buff_addr, 0, sizeof(struct ddl_buf_addr));
}
void ddl_pmem_free(struct ddl_buf_addr *buff_addr)
{
struct ddl_context *ddl_context;
ddl_context = ddl_get_context();
if (!buff_addr) {
ERR("\n %s() invalid arguments %p", __func__, buff_addr);
return;
}
DBG("ddl_pmem_free: phys(0x%x) align_phys(0x%x), "\
"virt(0x%x), align_virt(0x%x), size(%u)",
(u32)buff_addr->physical_base_addr,
(u32)buff_addr->align_physical_addr,
(u32)buff_addr->virtual_base_addr,
(u32)buff_addr->align_virtual_addr,
buff_addr->buffer_size);
if (ddl_context->video_ion_client) {
if (buff_addr->alloc_handle) {
ion_unmap_kernel(ddl_context->video_ion_client,
buff_addr->alloc_handle);
ion_free(ddl_context->video_ion_client,
buff_addr->alloc_handle);
}
}
memset(buff_addr, 0, sizeof(struct ddl_buf_addr));
}
#endif
void ddl_set_core_start_time(const char *func_name, u32 index)
{
u32 act_time;
struct timeval ddl_tv;
struct time_data *time_data = &proc_time[index];
do_gettimeofday(&ddl_tv);
act_time = (ddl_tv.tv_sec * 1000) + (ddl_tv.tv_usec / 1000);
if (!time_data->ddl_t1) {
time_data->ddl_t1 = act_time;
DBG("\n%s(): Start Time (%u)", func_name, act_time);
} else {
DBG_TIME("\n%s(): Timer already started! St(%u) Act(%u)",
func_name, time_data->ddl_t1, act_time);
}
}
void ddl_calc_core_proc_time(const char *func_name, u32 index)
{
struct time_data *time_data = &proc_time[index];
if (time_data->ddl_t1) {
int ddl_t2;
struct timeval ddl_tv;
do_gettimeofday(&ddl_tv);
ddl_t2 = (ddl_tv.tv_sec * 1000) + (ddl_tv.tv_usec / 1000);
time_data->ddl_ttotal += (ddl_t2 - time_data->ddl_t1);
time_data->ddl_count++;
DBG_TIME("\n%s(): cnt(%u) Diff(%u) Avg(%u)",
func_name, time_data->ddl_count,
ddl_t2 - time_data->ddl_t1,
time_data->ddl_ttotal/time_data->ddl_count);
time_data->ddl_t1 = 0;
}
}
void ddl_reset_core_time_variables(u32 index)
{
proc_time[index].ddl_t1 = 0;
proc_time[index].ddl_ttotal = 0;
proc_time[index].ddl_count = 0;
}
int ddl_get_core_decode_proc_time(u32 *ddl_handle)
{
return 0;
}
void ddl_reset_avg_dec_time(u32 *ddl_handle)
{
return;
}
@@ -0,0 +1,60 @@
/* Copyright (c) 2010-2011, 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.
*
*/
#ifndef _VCD_DDL_UTILS_H_
#define _VCD_DDL_UTILS_H_
#include "vcd_ddl_core.h"
#include "vcd_ddl.h"
extern u32 vidc_msg_pmem;
extern u32 vidc_msg_timing;
enum timing_data {
DEC_OP_TIME,
DEC_IP_TIME,
ENC_OP_TIME,
MAX_TIME_DATA
};
#define DDL_INLINE
#define DDL_ALIGN_SIZE(sz, guard_bytes, align_mask) \
(((u32)(sz) + guard_bytes) & align_mask)
#define DDL_MALLOC(x) kmalloc(x, GFP_KERNEL)
#define DDL_FREE(x) { if ((x)) kfree((x)); (x) = NULL; }
#define DBG_PMEM(x...) \
do { \
if (vidc_msg_pmem) \
printk(KERN_DEBUG x); \
} while (0)
void ddl_set_core_start_time(const char *func_name, u32 index);
void ddl_calc_core_proc_time(const char *func_name, u32 index);
void ddl_reset_core_time_variables(u32 index);
int ddl_get_core_decode_proc_time(u32 *ddl_handle);
void ddl_reset_avg_dec_time(u32 *ddl_handle);
#define DDL_ASSERT(x)
#define DDL_MEMSET(src, value, len) memset((src), (value), (len))
#define DDL_MEMCPY(dest, src, len) memcpy((dest), (src), (len))
#define DDL_ADDR_IS_ALIGNED(addr, align_bytes) \
(!((u32)(addr) & ((align_bytes) - 1)))
#endif
@@ -0,0 +1,804 @@
/* Copyright (c) 2010-2012, 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/unistd.h>
#include <media/msm/vidc_type.h>
#include "vidc.h"
#if DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
#else
#define DBG(x...)
#endif
#define VIDC_720P_VERSION_STRING "VIDC_V1.0"
u8 *vidc_base_addr;
#ifdef VIDC_REGISTER_LOG_INTO_BUFFER
char vidclog[VIDC_REGLOG_BUFSIZE];
unsigned int vidclog_index;
#endif
void vidc_720p_set_device_virtual_base(u8 *core_virtual_base_addr)
{
vidc_base_addr = core_virtual_base_addr;
}
void vidc_720p_init(char **ppsz_version, u32 i_firmware_size,
u32 *pi_firmware_address,
enum vidc_720p_endian dma_endian,
u32 interrupt_off,
enum vidc_720p_interrupt_level_selection
interrupt_sel, u32 interrupt_mask)
{
if (ppsz_version)
*ppsz_version = VIDC_720P_VERSION_STRING;
if (interrupt_sel == VIDC_720P_INTERRUPT_LEVEL_SEL)
VIDC_IO_OUT(REG_491082, 0);
else
VIDC_IO_OUT(REG_491082, 1);
if (interrupt_off)
VIDC_IO_OUT(REG_609676, 1);
else
VIDC_IO_OUT(REG_609676, 0);
VIDC_IO_OUT(REG_614776, 1);
VIDC_IO_OUT(REG_418173, 0);
VIDC_IO_OUT(REG_418173, interrupt_mask);
VIDC_IO_OUT(REG_736316, dma_endian);
VIDC_IO_OUT(REG_215724, 0);
VIDC_IO_OUT(REG_361582, 1);
VIDC_IO_OUT(REG_591577, i_firmware_size);
VIDC_IO_OUT(REG_203921, pi_firmware_address);
VIDC_IO_OUT(REG_531515_ADDR, 0);
VIDC_IO_OUT(REG_614413, 1);
}
u32 vidc_720p_do_sw_reset(void)
{
u32 fw_start = 0;
VIDC_BUSY_WAIT(5);
VIDC_IO_OUT(REG_224135, 0);
VIDC_BUSY_WAIT(5);
VIDC_IO_OUT(REG_193553, 0);
VIDC_BUSY_WAIT(5);
VIDC_IO_OUT(REG_141269, 1);
VIDC_BUSY_WAIT(15);
VIDC_IO_OUT(REG_141269, 0);
VIDC_BUSY_WAIT(5);
VIDC_IO_IN(REG_193553, &fw_start);
if (!fw_start) {
DBG("\n VIDC-SW-RESET-FAILS!");
return false;
}
return true;
}
u32 vidc_720p_reset_is_success()
{
u32 stagecounter = 0;
VIDC_IO_IN(REG_352831, &stagecounter);
stagecounter &= 0xff;
if (stagecounter != 0xe5) {
DBG("\n VIDC-CPU_RESET-FAILS!");
VIDC_IO_OUT(REG_224135, 0);
msleep(10);
return false;
}
return true;
}
void vidc_720p_start_cpu(enum vidc_720p_endian dma_endian,
u32 *icontext_bufferstart,
u32 *debug_core_dump_addr,
u32 debug_buffer_size)
{
u32 dbg_info_input0_reg = 0x1;
VIDC_IO_OUT(REG_361582, 0);
VIDC_IO_OUT(REG_958768, icontext_bufferstart);
VIDC_IO_OUT(REG_736316, dma_endian);
if (debug_buffer_size) {
dbg_info_input0_reg = (debug_buffer_size << 0x10)
| (0x2 << 1) | 0x1;
VIDC_IO_OUT(REG_166247, debug_core_dump_addr);
}
VIDC_IO_OUT(REG_699747, dbg_info_input0_reg);
VIDC_IO_OUT(REG_224135, 1);
}
u32 vidc_720p_cpu_start()
{
u32 fw_status = 0x0;
VIDC_IO_IN(REG_381535, &fw_status);
if (fw_status != 0x02)
return false;
return true;
}
void vidc_720p_stop_fw(void)
{
VIDC_IO_OUT(REG_193553, 0);
VIDC_IO_OUT(REG_224135, 0);
}
void vidc_720p_get_interrupt_status(u32 *interrupt_status,
u32 *cmd_err_status, u32 *disp_pic_err_status, u32 *op_failed)
{
u32 err_status;
VIDC_IO_IN(REG_512143, interrupt_status);
VIDC_IO_IN(REG_300310, &err_status);
*cmd_err_status = err_status & 0xffff;
*disp_pic_err_status = (err_status & 0xffff0000) >> 16;
VIDC_IO_INF(REG_724381, OPERATION_FAILED, \
op_failed);
}
void vidc_720p_interrupt_done_clear(void)
{
VIDC_IO_OUT(REG_614776, 1);
VIDC_IO_OUT(REG_97293, 4);
}
void vidc_720p_submit_command(u32 ch_id, u32 cmd_id)
{
u32 fw_status;
VIDC_IO_OUT(REG_97293, ch_id);
VIDC_IO_OUT(REG_62325, cmd_id);
VIDC_DEBUG_REGISTER_LOG;
VIDC_IO_IN(REG_381535, &fw_status);
VIDC_IO_OUT(REG_926519, fw_status);
}
u32 vidc_720p_engine_reset(u32 ch_id,
enum vidc_720p_endian dma_endian,
enum vidc_720p_interrupt_level_selection interrupt_sel,
u32 interrupt_mask
)
{
u32 op_done = 0;
u32 counter = 0;
VIDC_LOGERR_STRING("ENG-RESET!!");
/* issue the engine reset command */
vidc_720p_submit_command(ch_id, VIDC_720P_CMD_MFC_ENGINE_RESET);
do {
VIDC_BUSY_WAIT(20);
VIDC_IO_IN(REG_982553, &op_done);
counter++;
} while (!op_done && counter < 10);
if (!op_done) {
/* Reset fails */
return false ;
}
/* write invalid channel id */
VIDC_IO_OUT(REG_97293, 4);
/* Set INT_PULSE_SEL */
if (interrupt_sel == VIDC_720P_INTERRUPT_LEVEL_SEL)
VIDC_IO_OUT(REG_491082, 0);
else
VIDC_IO_OUT(REG_491082, 1);
if (!interrupt_mask) {
/* Disable interrupt */
VIDC_IO_OUT(REG_609676, 1);
} else {
/* Enable interrupt */
VIDC_IO_OUT(REG_609676, 0);
}
/* Clear any pending interrupt */
VIDC_IO_OUT(REG_614776, 1);
/* Set INT_ENABLE_REG */
VIDC_IO_OUT(REG_418173, interrupt_mask);
/*Sets the DMA endianness */
VIDC_IO_OUT(REG_736316, dma_endian);
/*Restore ARM endianness */
VIDC_IO_OUT(REG_215724, 0);
/* retun engine reset success */
return true ;
}
void vidc_720p_set_channel(u32 i_ch_id,
enum vidc_720p_enc_dec_selection
enc_dec_sel, enum vidc_720p_codec codec,
u32 *pi_fw, u32 i_firmware_size)
{
u32 std_sel = 0;
VIDC_IO_OUT(REG_661565, 0);
if (enc_dec_sel)
std_sel = VIDC_REG_713080_ENC_ON_BMSK;
std_sel |= (u32) codec;
VIDC_IO_OUT(REG_713080, std_sel);
switch (codec) {
default:
case VIDC_720P_DIVX:
case VIDC_720P_XVID:
case VIDC_720P_MPEG4:
{
if (enc_dec_sel == VIDC_720P_ENCODER)
VIDC_IO_OUT(REG_765787, pi_fw);
else
VIDC_IO_OUT(REG_225040, pi_fw);
break;
}
case VIDC_720P_H264:
{
if (enc_dec_sel == VIDC_720P_ENCODER)
VIDC_IO_OUT(REG_942456, pi_fw);
else
VIDC_IO_OUT(REG_942170_ADDR_3, pi_fw);
break;
}
case VIDC_720P_H263:
{
if (enc_dec_sel == VIDC_720P_ENCODER)
VIDC_IO_OUT(REG_765787, pi_fw);
else
VIDC_IO_OUT(REG_942170_ADDR_6, pi_fw);
break;
}
case VIDC_720P_VC1:
{
VIDC_IO_OUT(REG_880188, pi_fw);
break;
}
case VIDC_720P_MPEG2:
{
VIDC_IO_OUT(REG_40293, pi_fw);
break;
}
}
VIDC_IO_OUT(REG_591577, i_firmware_size);
vidc_720p_submit_command(i_ch_id, VIDC_720P_CMD_CHSET);
}
void vidc_720p_encode_set_profile(u32 i_profile, u32 i_level)
{
u32 profile_level = i_profile|(i_level << 0x8);
VIDC_IO_OUT(REG_839021, profile_level);
}
void vidc_720p_set_frame_size(u32 i_size_x, u32 i_size_y)
{
VIDC_IO_OUT(REG_999267, i_size_x);
VIDC_IO_OUT(REG_345712, i_size_y);
}
void vidc_720p_encode_set_fps(u32 i_rc_frame_rate)
{
VIDC_IO_OUT(REG_625444, i_rc_frame_rate);
}
void vidc_720p_encode_set_short_header(u32 i_short_header)
{
VIDC_IO_OUT(REG_314290, i_short_header);
}
void vidc_720p_encode_set_vop_time(u32 vop_time_resolution,
u32 vop_time_increment)
{
u32 enable_vop, vop_timing_reg;
if (!vop_time_resolution)
VIDC_IO_OUT(REG_64895, 0x0);
else {
enable_vop = 0x1;
vop_timing_reg = (enable_vop << 0x1f) |
(vop_time_resolution << 0x10) | vop_time_increment;
VIDC_IO_OUT(REG_64895, vop_timing_reg);
}
}
void vidc_720p_encode_set_hec_period(u32 hec_period)
{
VIDC_IO_OUT(REG_407718, hec_period);
}
void vidc_720p_encode_set_qp_params(u32 i_max_qp, u32 i_min_qp)
{
u32 qp = i_min_qp | (i_max_qp << 0x8);
VIDC_IO_OUT(REG_734318, qp);
}
void vidc_720p_encode_set_rc_config(u32 enable_frame_level_rc,
u32 enable_mb_level_rc_flag,
u32 i_frame_qp, u32 pframe_qp)
{
u32 rc_config = i_frame_qp;
if (enable_frame_level_rc)
rc_config |= (0x1 << 0x9);
if (enable_mb_level_rc_flag)
rc_config |= (0x1 << 0x8);
VIDC_IO_OUT(REG_58211, rc_config);
VIDC_IO_OUT(REG_548359, pframe_qp);
}
void vidc_720p_encode_set_bit_rate(u32 i_target_bitrate)
{
VIDC_IO_OUT(REG_174150, i_target_bitrate);
}
void vidc_720p_encoder_set_param_change(u32 enc_param_change)
{
VIDC_IO_OUT(REG_804959, enc_param_change);
}
void vidc_720p_encode_set_control_param(u32 param_val)
{
VIDC_IO_OUT(REG_128234, param_val);
}
void vidc_720p_encode_set_frame_level_rc_params(u32 i_reaction_coeff)
{
VIDC_IO_OUT(REG_677784, i_reaction_coeff);
}
void vidc_720p_encode_set_mb_level_rc_params(u32 dark_region_as_flag,
u32 smooth_region_as_flag,
u32 static_region_as_flag,
u32 activity_region_flag)
{
u32 mb_level_rc = 0x0;
if (activity_region_flag)
mb_level_rc |= 0x1;
if (static_region_as_flag)
mb_level_rc |= (0x1 << 0x1);
if (smooth_region_as_flag)
mb_level_rc |= (0x1 << 0x2);
if (dark_region_as_flag)
mb_level_rc |= (0x1 << 0x3);
/* Write MB level rate control */
VIDC_IO_OUT(REG_995041, mb_level_rc);
}
void vidc_720p_encode_set_entropy_control(enum vidc_720p_entropy_sel
entropy_sel,
enum vidc_720p_cabac_model
cabac_model_number)
{
u32 num;
u32 entropy_params = (u32)entropy_sel;
/* Set Model Number */
if (entropy_sel == VIDC_720P_ENTROPY_SEL_CABAC) {
num = (u32)cabac_model_number;
entropy_params |= (num << 0x2);
}
/* Set Entropy parameters */
VIDC_IO_OUT(REG_504878, entropy_params);
}
void vidc_720p_encode_set_db_filter_control(enum vidc_720p_DBConfig
db_config,
u32 i_slice_alpha_offset,
u32 i_slice_beta_offset)
{
u32 deblock_params;
deblock_params = (u32)db_config;
deblock_params |=
((i_slice_beta_offset << 0x2) | (i_slice_alpha_offset << 0x7));
/* Write deblocking control settings */
VIDC_IO_OUT(REG_458130, deblock_params);
}
void vidc_720p_encode_set_intra_refresh_mb_number(u32 i_cir_mb_number)
{
VIDC_IO_OUT(REG_857491, i_cir_mb_number);
}
void vidc_720p_encode_set_multi_slice_info(enum
vidc_720p_MSlice_selection
m_slice_sel,
u32 multi_slice_size)
{
switch (m_slice_sel) {
case VIDC_720P_MSLICE_BY_MB_COUNT:
{
VIDC_IO_OUT(REG_588301, 0x1);
VIDC_IO_OUT(REG_1517, m_slice_sel);
VIDC_IO_OUT(REG_105335, multi_slice_size);
break;
}
case VIDC_720P_MSLICE_BY_BYTE_COUNT:
{
VIDC_IO_OUT(REG_588301, 0x1);
VIDC_IO_OUT(REG_1517, m_slice_sel);
VIDC_IO_OUT(REG_561679, multi_slice_size);
break;
}
case VIDC_720P_MSLICE_BY_GOB:
{
VIDC_IO_OUT(REG_588301, 0x1);
break;
}
default:
case VIDC_720P_MSLICE_OFF:
{
VIDC_IO_OUT(REG_588301, 0x0);
break;
}
}
}
void vidc_720p_encode_set_dpb_buffer(u32 *pi_enc_dpb_addr, u32 alloc_len)
{
VIDC_IO_OUT(REG_341928_ADDR, pi_enc_dpb_addr);
VIDC_IO_OUT(REG_319934, alloc_len);
}
void vidc_720p_encode_set_i_period(u32 i_i_period)
{
VIDC_IO_OUT(REG_950374, i_i_period);
}
void vidc_720p_encode_init_codec(u32 i_ch_id,
enum vidc_720p_memory_access_method
memory_access_model)
{
VIDC_IO_OUT(REG_841539, memory_access_model);
vidc_720p_submit_command(i_ch_id, VIDC_720P_CMD_INITCODEC);
}
void vidc_720p_encode_unalign_bitstream(u32 upper_unalign_word,
u32 lower_unalign_word)
{
VIDC_IO_OUT(REG_792026, upper_unalign_word);
VIDC_IO_OUT(REG_844152, lower_unalign_word);
}
void vidc_720p_encode_set_seq_header_buffer(u32 ext_buffer_start,
u32 ext_buffer_end,
u32 start_byte_num)
{
VIDC_IO_OUT(REG_275113_ADDR, ext_buffer_start);
VIDC_IO_OUT(REG_87912, ext_buffer_start);
VIDC_IO_OUT(REG_988007_ADDR, ext_buffer_end);
VIDC_IO_OUT(REG_66693, start_byte_num);
}
void vidc_720p_encode_frame(u32 ch_id,
u32 ext_buffer_start,
u32 ext_buffer_end,
u32 start_byte_number, u32 y_addr,
u32 c_addr)
{
VIDC_IO_OUT(REG_275113_ADDR, ext_buffer_start);
VIDC_IO_OUT(REG_988007_ADDR, ext_buffer_end);
VIDC_IO_OUT(REG_87912, ext_buffer_start);
VIDC_IO_OUT(REG_66693, start_byte_number);
VIDC_IO_OUT(REG_99105, y_addr);
VIDC_IO_OUT(REG_777113_ADDR, c_addr);
vidc_720p_submit_command(ch_id, VIDC_720P_CMD_FRAMERUN);
}
void vidc_720p_encode_get_header(u32 *pi_enc_header_size)
{
VIDC_IO_IN(REG_114286, pi_enc_header_size);
}
void vidc_720p_enc_frame_info(struct vidc_720p_enc_frame_info
*enc_frame_info)
{
VIDC_IO_IN(REG_782249, &enc_frame_info->enc_size);
VIDC_IO_IN(REG_441270, &enc_frame_info->frame);
enc_frame_info->frame &= 0x03;
VIDC_IO_IN(REG_613254,
&enc_frame_info->metadata_exists);
}
void vidc_720p_decode_bitstream_header(u32 ch_id,
u32 dec_unit_size,
u32 start_byte_num,
u32 ext_buffer_start,
u32 ext_buffer_end,
enum
vidc_720p_memory_access_method
memory_access_model,
u32 decode_order)
{
VIDC_IO_OUT(REG_965480, decode_order);
VIDC_IO_OUT(REG_639999, 0x8080);
VIDC_IO_OUT(REG_275113_ADDR, ext_buffer_start);
VIDC_IO_OUT(REG_988007_ADDR, ext_buffer_end);
VIDC_IO_OUT(REG_87912, ext_buffer_end);
VIDC_IO_OUT(REG_761892, dec_unit_size);
VIDC_IO_OUT(REG_66693, start_byte_num);
VIDC_IO_OUT(REG_841539, memory_access_model);
vidc_720p_submit_command(ch_id, VIDC_720P_CMD_INITCODEC);
}
void vidc_720p_decode_get_seq_hdr_info(struct vidc_720p_seq_hdr_info
*seq_hdr_info)
{
u32 display_status;
VIDC_IO_IN(REG_999267, &seq_hdr_info->img_size_x);
VIDC_IO_IN(REG_345712, &seq_hdr_info->img_size_y);
VIDC_IO_IN(REG_257463, &seq_hdr_info->min_num_dpb);
VIDC_IO_IN(REG_854281, &seq_hdr_info->min_dpb_size);
VIDC_IO_IN(REG_580603, &seq_hdr_info->dec_frm_size);
VIDC_IO_INF(REG_606447, DISP_PIC_PROFILE,
&seq_hdr_info->profile);
VIDC_IO_INF(REG_606447, DIS_PIC_LEVEL,
&seq_hdr_info->level);
VIDC_IO_INF(REG_612715, DISPLAY_STATUS,
&display_status);
seq_hdr_info->progressive =
((display_status & 0x4) >> 2);
/* bit 3 is for crop existence */
seq_hdr_info->crop_exists = ((display_status & 0x8) >> 3);
if (seq_hdr_info->crop_exists) {
/* read the cropping information */
VIDC_IO_INF(REG_881638, CROP_RIGHT_OFFSET, \
&seq_hdr_info->crop_right_offset);
VIDC_IO_INF(REG_881638, CROP_LEFT_OFFSET, \
&seq_hdr_info->crop_left_offset);
VIDC_IO_INF(REG_161486, CROP_BOTTOM_OFFSET, \
&seq_hdr_info->crop_bottom_offset);
VIDC_IO_INF(REG_161486, CROP_TOP_OFFSET, \
&seq_hdr_info->crop_top_offset);
}
/* Read the MPEG4 data partitioning indication */
VIDC_IO_INF(REG_441270, DATA_PARTITIONED, \
&seq_hdr_info->data_partitioned);
}
void vidc_720p_decode_set_dpb_release_buffer_mask(u32
i_dpb_release_buffer_mask)
{
VIDC_IO_OUT(REG_603032, i_dpb_release_buffer_mask);
}
void vidc_720p_decode_set_dpb_buffers(u32 i_buf_index, u32 *pi_dpb_buffer)
{
VIDC_IO_OUTI(REG_615716, i_buf_index, pi_dpb_buffer);
}
void vidc_720p_decode_set_comv_buffer(u32 *pi_dpb_comv_buffer,
u32 alloc_len)
{
VIDC_IO_OUT(REG_456376_ADDR, pi_dpb_comv_buffer);
VIDC_IO_OUT(REG_490443, alloc_len);
}
void vidc_720p_decode_set_dpb_details(u32 num_dpb, u32 alloc_len,
u32 *ref_buffer)
{
VIDC_IO_OUT(REG_518133, ref_buffer);
VIDC_IO_OUT(REG_267567, 0);
VIDC_IO_OUT(REG_883500, num_dpb);
VIDC_IO_OUT(REG_319934, alloc_len);
}
void vidc_720p_decode_set_mpeg4Post_filter(u32 enable_post_filter)
{
if (enable_post_filter)
VIDC_IO_OUT(REG_443811, 0x1);
else
VIDC_IO_OUT(REG_443811, 0x0);
}
void vidc_720p_decode_set_error_control(u32 enable_error_control)
{
if (enable_error_control)
VIDC_IO_OUT(REG_846346, 0);
else
VIDC_IO_OUT(REG_846346, 1);
}
void vidc_720p_set_deblock_line_buffer(u32 *pi_deblock_line_buffer_start,
u32 alloc_len)
{
VIDC_IO_OUT(REG_979942, pi_deblock_line_buffer_start);
VIDC_IO_OUT(REG_101184, alloc_len);
}
void vidc_720p_decode_set_mpeg4_data_partitionbuffer(u32 *vsp_buf_start)
{
VIDC_IO_OUT(REG_958768, vsp_buf_start);
}
void vidc_720p_decode_setH264VSPBuffer(u32 *pi_vsp_temp_buffer_start)
{
VIDC_IO_OUT(REG_958768, pi_vsp_temp_buffer_start);
}
void vidc_720p_decode_frame(u32 ch_id, u32 ext_buffer_start,
u32 ext_buffer_end, u32 dec_unit_size,
u32 start_byte_num, u32 input_frame_tag)
{
VIDC_IO_OUT(REG_275113_ADDR, ext_buffer_start);
VIDC_IO_OUT(REG_988007_ADDR, ext_buffer_end);
VIDC_IO_OUT(REG_87912, ext_buffer_end);
VIDC_IO_OUT(REG_66693, start_byte_num);
VIDC_IO_OUT(REG_94750, input_frame_tag);
VIDC_IO_OUT(REG_761892, dec_unit_size);
vidc_720p_submit_command(ch_id, VIDC_720P_CMD_FRAMERUN);
}
void vidc_720p_issue_eos(u32 i_ch_id)
{
VIDC_IO_OUT(REG_896825, 0x1);
VIDC_IO_OUT(REG_761892, 0);
vidc_720p_submit_command(i_ch_id, VIDC_720P_CMD_FRAMERUN);
}
void vidc_720p_eos_info(u32 *disp_status, u32 *resl_change)
{
VIDC_IO_INF(REG_612715, DISPLAY_STATUS, disp_status);
(*disp_status) = (*disp_status) & 0x3;
VIDC_IO_INF(REG_724381, RESOLUTION_CHANGE, resl_change);
}
void vidc_720p_decode_display_info(struct vidc_720p_dec_disp_info
*disp_info)
{
u32 display_status = 0;
VIDC_IO_INF(REG_612715, DISPLAY_STATUS, &display_status);
disp_info->disp_status =
(enum vidc_720p_display_status)((display_status & 0x3));
disp_info->disp_is_interlace = ((display_status & 0x4) >> 2);
disp_info->crop_exists = ((display_status & 0x8) >> 3);
disp_info->resl_change = ((display_status & 0x30) >> 4);
VIDC_IO_INF(REG_724381, RESOLUTION_CHANGE,
&disp_info->reconfig_flush_done);
VIDC_IO_IN(REG_999267, &disp_info->img_size_x);
VIDC_IO_IN(REG_345712, &disp_info->img_size_y);
VIDC_IO_IN(REG_151345, &disp_info->y_addr);
VIDC_IO_IN(REG_293983, &disp_info->c_addr);
VIDC_IO_IN(REG_370409, &disp_info->tag_top);
VIDC_IO_IN(REG_438677, &disp_info->tag_bottom);
VIDC_IO_IN(REG_679165, &disp_info->pic_time_top);
VIDC_IO_IN(REG_374150, &disp_info->pic_time_bottom);
if (disp_info->crop_exists) {
VIDC_IO_INF(REG_881638, CROP_RIGHT_OFFSET,
&disp_info->crop_right_offset);
VIDC_IO_INF(REG_881638, CROP_LEFT_OFFSET,
&disp_info->crop_left_offset);
VIDC_IO_INF(REG_161486, CROP_BOTTOM_OFFSET,
&disp_info->crop_bottom_offset);
VIDC_IO_INF(REG_161486, CROP_TOP_OFFSET,
&disp_info->crop_top_offset);
}
VIDC_IO_IN(REG_613254, &disp_info->metadata_exists);
VIDC_IO_IN(REG_580603,
&disp_info->input_bytes_consumed);
VIDC_IO_IN(REG_757835, &disp_info->input_frame_num);
VIDC_IO_INF(REG_441270, FRAME_TYPE,
&disp_info->input_frame);
disp_info->input_is_interlace =
((disp_info->input_frame & 0x4) >> 2);
if (disp_info->input_frame & 0x10)
disp_info->input_frame = VIDC_720P_IDRFRAME;
else
disp_info->input_frame &= 0x3;
}
void vidc_720p_decode_skip_frm_details(u32 *free_luma_dpb)
{
u32 disp_frm;
VIDC_IO_IN(REG_697961, &disp_frm);
if (disp_frm == VIDC_720P_NOTCODED)
VIDC_IO_IN(REG_347105, free_luma_dpb);
}
void vidc_720p_metadata_enable(u32 flag, u32 *input_buffer)
{
VIDC_IO_OUT(REG_854681, flag);
VIDC_IO_OUT(REG_988552, input_buffer);
}
void vidc_720p_decode_dynamic_req_reset(void)
{
VIDC_IO_OUT(REG_76706, 0x0);
VIDC_IO_OUT(REG_147682, 0x0);
VIDC_IO_OUT(REG_896825, 0x0);
}
void vidc_720p_decode_dynamic_req_set(u32 property)
{
if (property == VIDC_720P_FLUSH_REQ)
VIDC_IO_OUT(REG_76706, 0x1);
else if (property == VIDC_720P_EXTRADATA)
VIDC_IO_OUT(REG_147682, 0x1);
}
void vidc_720p_decode_setpassthrough_start(u32 pass_startaddr)
{
VIDC_IO_OUT(REG_486169, pass_startaddr);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,811 @@
/* Copyright (c) 2010-2012, 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/firmware.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <mach/clk.h>
#include <linux/interrupt.h>
#include <media/msm/vidc_init.h>
#include <media/msm/vidc_type.h>
#include "vcd_res_tracker.h"
#define MSM_AXI_QOS_NAME "msm_vidc_reg"
#define AXI_CLK_SCALING
#define QVGA_PERF_LEVEL (300 * 30)
#define VGA_PERF_LEVEL (1200 * 30)
#define WVGA_PERF_LEVEL (1500 * 30)
static unsigned int mfc_clk_freq_table[3] = {
61440000, 122880000, 170667000
};
static unsigned int axi_clk_freq_table_enc[2] = {
122880, 192000
};
static unsigned int axi_clk_freq_table_dec[2] = {
122880, 192000
};
static struct res_trk_context resource_context;
#define VIDC_BOOT_FW "vidc_720p_command_control.fw"
#define VIDC_MPG4_DEC_FW "vidc_720p_mp4_dec_mc.fw"
#define VIDC_H263_DEC_FW "vidc_720p_h263_dec_mc.fw"
#define VIDC_H264_DEC_FW "vidc_720p_h264_dec_mc.fw"
#define VIDC_MPG4_ENC_FW "vidc_720p_mp4_enc_mc.fw"
#define VIDC_H264_ENC_FW "vidc_720p_h264_enc_mc.fw"
#define VIDC_VC1_DEC_FW "vidc_720p_vc1_dec_mc.fw"
unsigned char *vidc_command_control_fw;
u32 vidc_command_control_fw_size;
unsigned char *vidc_mpg4_dec_fw;
u32 vidc_mpg4_dec_fw_size;
unsigned char *vidc_h263_dec_fw;
u32 vidc_h263_dec_fw_size;
unsigned char *vidc_h264_dec_fw;
u32 vidc_h264_dec_fw_size;
unsigned char *vidc_mpg4_enc_fw;
u32 vidc_mpg4_enc_fw_size;
unsigned char *vidc_h264_enc_fw;
u32 vidc_h264_enc_fw_size;
unsigned char *vidc_vc1_dec_fw;
u32 vidc_vc1_dec_fw_size;
static u32 res_trk_disable_videocore(void)
{
int rc = -1;
mutex_lock(&resource_context.lock);
if (!resource_context.rail_enabled) {
mutex_unlock(&resource_context.lock);
return false;
}
if (!resource_context.clock_enabled &&
resource_context.pclk &&
resource_context.hclk &&
resource_context.hclk_div2) {
VCDRES_MSG_LOW("\nEnabling clk before disabling pwr rail\n");
if (clk_set_rate(resource_context.hclk,
mfc_clk_freq_table[0])) {
VCDRES_MSG_ERROR("\n pwr_rail_disable:"
" set clk rate failed\n");
goto bail_out;
}
if (clk_prepare_enable(resource_context.pclk)) {
VCDRES_MSG_ERROR("vidc pclk Enable failed\n");
goto bail_out;
}
if (clk_prepare_enable(resource_context.hclk)) {
VCDRES_MSG_ERROR("vidc hclk Enable failed\n");
goto disable_pclk;
}
if (clk_prepare_enable(resource_context.hclk_div2)) {
VCDRES_MSG_ERROR("vidc hclk_div2 Enable failed\n");
goto disable_hclk;
}
} else {
VCDRES_MSG_ERROR("\ndisabling pwr rail: Enabling clk failed\n");
goto bail_out;
}
resource_context.rail_enabled = 0;
rc = clk_reset(resource_context.pclk, CLK_RESET_ASSERT);
if (rc) {
VCDRES_MSG_ERROR("\n clk_reset failed %d\n", rc);
mutex_unlock(&resource_context.lock);
return false;
}
msleep(20);
clk_disable_unprepare(resource_context.pclk);
clk_disable_unprepare(resource_context.hclk);
clk_disable_unprepare(resource_context.hclk_div2);
clk_put(resource_context.hclk_div2);
clk_put(resource_context.hclk);
clk_put(resource_context.pclk);
rc = regulator_disable(resource_context.regulator);
if (rc) {
VCDRES_MSG_ERROR("\n regulator disable failed %d\n", rc);
mutex_unlock(&resource_context.lock);
return false;
}
resource_context.hclk_div2 = NULL;
resource_context.hclk = NULL;
resource_context.pclk = NULL;
mutex_unlock(&resource_context.lock);
return true;
disable_hclk:
clk_disable_unprepare(resource_context.hclk);
disable_pclk:
clk_disable_unprepare(resource_context.pclk);
bail_out:
if (resource_context.pclk) {
clk_put(resource_context.pclk);
resource_context.pclk = NULL;
}
if (resource_context.hclk) {
clk_put(resource_context.hclk);
resource_context.hclk = NULL;
}
if (resource_context.hclk_div2) {
clk_put(resource_context.hclk_div2);
resource_context.hclk_div2 = NULL;
}
mutex_unlock(&resource_context.lock);
return false;
}
u32 res_trk_enable_clocks(void)
{
VCDRES_MSG_LOW("\n in res_trk_enable_clocks()");
mutex_lock(&resource_context.lock);
if (!resource_context.clock_enabled) {
VCDRES_MSG_LOW("Enabling IRQ in %s()\n", __func__);
enable_irq(resource_context.irq_num);
VCDRES_MSG_LOW("%s(): Enabling the clocks ...\n", __func__);
if (clk_prepare_enable(resource_context.pclk)) {
VCDRES_MSG_ERROR("vidc pclk Enable failed\n");
clk_put(resource_context.hclk);
clk_put(resource_context.hclk_div2);
mutex_unlock(&resource_context.lock);
return false;
}
if (clk_prepare_enable(resource_context.hclk)) {
VCDRES_MSG_ERROR("vidc hclk Enable failed\n");
clk_put(resource_context.pclk);
clk_put(resource_context.hclk_div2);
mutex_unlock(&resource_context.lock);
return false;
}
if (clk_prepare_enable(resource_context.hclk_div2)) {
VCDRES_MSG_ERROR("vidc hclk Enable failed\n");
clk_put(resource_context.hclk);
clk_put(resource_context.pclk);
mutex_unlock(&resource_context.lock);
return false;
}
}
resource_context.clock_enabled = 1;
mutex_unlock(&resource_context.lock);
return true;
}
static u32 res_trk_sel_clk_rate(unsigned long hclk_rate)
{
mutex_lock(&resource_context.lock);
if (clk_set_rate(resource_context.hclk,
hclk_rate)) {
VCDRES_MSG_ERROR("vidc hclk set rate failed\n");
mutex_unlock(&resource_context.lock);
return false;
}
resource_context.hclk_rate = hclk_rate;
mutex_unlock(&resource_context.lock);
return true;
}
static u32 res_trk_get_clk_rate(unsigned long *phclk_rate)
{
if (!phclk_rate) {
VCDRES_MSG_ERROR("%s(): phclk_rate is NULL\n", __func__);
return false;
}
mutex_lock(&resource_context.lock);
*phclk_rate = clk_get_rate(resource_context.hclk);
if (!(*phclk_rate)) {
VCDRES_MSG_ERROR("vidc hclk get rate failed\n");
mutex_unlock(&resource_context.lock);
return false;
}
mutex_unlock(&resource_context.lock);
return true;
}
u32 res_trk_disable_clocks(void)
{
VCDRES_MSG_LOW("in res_trk_disable_clocks()\n");
mutex_lock(&resource_context.lock);
if (!resource_context.clock_enabled) {
mutex_unlock(&resource_context.lock);
return false;
}
VCDRES_MSG_LOW("Disabling IRQ in %s()\n", __func__);
disable_irq_nosync(resource_context.irq_num);
VCDRES_MSG_LOW("%s(): Disabling the clocks ...\n", __func__);
resource_context.clock_enabled = 0;
clk_disable_unprepare(resource_context.hclk);
clk_disable_unprepare(resource_context.hclk_div2);
clk_disable_unprepare(resource_context.pclk);
mutex_unlock(&resource_context.lock);
return true;
}
static u32 res_trk_enable_videocore(void)
{
mutex_lock(&resource_context.lock);
if (!resource_context.rail_enabled) {
int rc = -1;
rc = regulator_enable(resource_context.regulator);
if (rc) {
VCDRES_MSG_ERROR("%s(): regulator_enable failed %d\n",
__func__, rc);
goto bail_out;
}
VCDRES_MSG_LOW("%s(): regulator enable Success %d\n",
__func__, rc);
resource_context.pclk = clk_get(resource_context.device,
"iface_clk");
if (IS_ERR(resource_context.pclk)) {
VCDRES_MSG_ERROR("%s(): iface_clk get failed\n"
, __func__);
goto disable_regulator;
}
resource_context.hclk = clk_get(resource_context.device,
"core_clk");
if (IS_ERR(resource_context.hclk)) {
VCDRES_MSG_ERROR("%s(): core_clk get failed\n"
, __func__);
goto release_pclk;
}
resource_context.hclk_div2 =
clk_get(resource_context.device, "core_div2_clk");
if (IS_ERR(resource_context.hclk_div2)) {
VCDRES_MSG_ERROR("%s(): core_div2_clk get failed\n"
, __func__);
goto release_hclk_pclk;
}
if (clk_set_rate(resource_context.hclk,
mfc_clk_freq_table[0])) {
VCDRES_MSG_ERROR("\n pwr_rail_enable:"
" set clk rate failed\n");
goto release_all_clks;
}
if (clk_prepare_enable(resource_context.pclk)) {
VCDRES_MSG_ERROR("vidc pclk Enable failed\n");
goto release_all_clks;
}
if (clk_prepare_enable(resource_context.hclk)) {
VCDRES_MSG_ERROR("vidc hclk Enable failed\n");
goto disable_pclk;
}
if (clk_prepare_enable(resource_context.hclk_div2)) {
VCDRES_MSG_ERROR("vidc hclk_div2 Enable failed\n");
goto disable_hclk_pclk;
}
rc = clk_reset(resource_context.pclk, CLK_RESET_DEASSERT);
if (rc) {
VCDRES_MSG_ERROR("\n clk_reset failed %d\n", rc);
goto disable_and_release_all_clks;
}
msleep(20);
clk_disable_unprepare(resource_context.pclk);
clk_disable_unprepare(resource_context.hclk);
clk_disable_unprepare(resource_context.hclk_div2);
}
resource_context.rail_enabled = 1;
mutex_unlock(&resource_context.lock);
return true;
disable_and_release_all_clks:
clk_disable_unprepare(resource_context.hclk_div2);
disable_hclk_pclk:
clk_disable_unprepare(resource_context.hclk);
disable_pclk:
clk_disable_unprepare(resource_context.pclk);
release_all_clks:
clk_put(resource_context.hclk_div2);
resource_context.hclk_div2 = NULL;
release_hclk_pclk:
clk_put(resource_context.hclk);
resource_context.hclk = NULL;
release_pclk:
clk_put(resource_context.pclk);
resource_context.pclk = NULL;
disable_regulator:
regulator_disable(resource_context.regulator);
bail_out:
mutex_unlock(&resource_context.lock);
return false;
}
static u32 res_trk_convert_freq_to_perf_lvl(u64 freq)
{
u64 perf_lvl;
u64 temp;
VCDRES_MSG_MED("\n %s():: freq = %u\n", __func__, (u32)freq);
if (!freq)
return 0;
temp = freq * 1000;
do_div(temp, VCD_RESTRK_HZ_PER_1000_PERFLVL);
perf_lvl = (u32)temp;
VCDRES_MSG_MED("\n %s(): perf_lvl = %u\n", __func__,
(u32)perf_lvl);
return (u32)perf_lvl;
}
static u32 res_trk_convert_perf_lvl_to_freq(u64 perf_lvl)
{
u64 freq, temp;
VCDRES_MSG_MED("\n %s():: perf_lvl = %u\n", __func__,
(u32)perf_lvl);
temp = (perf_lvl * VCD_RESTRK_HZ_PER_1000_PERFLVL) + 999;
do_div(temp, 1000);
freq = (u32)temp;
VCDRES_MSG_MED("\n %s(): freq = %u\n", __func__, (u32)freq);
return (u32)freq;
}
static struct clk *ebi1_clk;
u32 res_trk_power_up(void)
{
VCDRES_MSG_LOW("clk_regime_rail_enable");
VCDRES_MSG_LOW("clk_regime_sel_rail_control");
#ifdef AXI_CLK_SCALING
{
VCDRES_MSG_MED("\n res_trk_power_up():: "
"Calling AXI add requirement\n");
ebi1_clk = clk_get(resource_context.device, "mem_clk");
if (IS_ERR(ebi1_clk)) {
VCDRES_MSG_ERROR("Request AXI bus QOS fails.");
return false;
}
clk_prepare_enable(ebi1_clk);
}
#endif
VCDRES_MSG_MED("\n res_trk_power_up():: Calling "
"vidc_enable_pwr_rail()\n");
return res_trk_enable_videocore();
}
u32 res_trk_power_down(void)
{
VCDRES_MSG_LOW("clk_regime_rail_disable");
#ifdef AXI_CLK_SCALING
VCDRES_MSG_MED("\n res_trk_power_down()::"
"Calling AXI remove requirement\n");
clk_disable_unprepare(ebi1_clk);
clk_put(ebi1_clk);
#endif
VCDRES_MSG_MED("\n res_trk_power_down():: Calling "
"res_trk_disable_videocore()\n");
return res_trk_disable_videocore();
}
u32 res_trk_get_max_perf_level(u32 *pn_max_perf_lvl)
{
if (!pn_max_perf_lvl) {
VCDRES_MSG_ERROR("%s(): pn_max_perf_lvl is NULL\n",
__func__);
return false;
}
*pn_max_perf_lvl = VCD_RESTRK_MAX_PERF_LEVEL;
return true;
}
u32 res_trk_set_perf_level(u32 req_perf_lvl, u32 *pn_set_perf_lvl,
struct vcd_dev_ctxt *dev_ctxt)
{
struct vcd_clnt_ctxt *cctxt_itr = NULL;
u32 axi_freq = 0, mfc_freq = 0, calc_mfc_freq = 0;
u8 enc_clnt_present = false;
if (!pn_set_perf_lvl || !dev_ctxt) {
VCDRES_MSG_ERROR("%s(): NULL pointer! dev_ctxt(%p)\n",
__func__, dev_ctxt);
return false;
}
VCDRES_MSG_LOW("%s(), req_perf_lvl = %d", __func__, req_perf_lvl);
calc_mfc_freq = res_trk_convert_perf_lvl_to_freq(
(u64)req_perf_lvl);
if (calc_mfc_freq < VCD_RESTRK_MIN_FREQ_POINT)
calc_mfc_freq = VCD_RESTRK_MIN_FREQ_POINT;
else if (calc_mfc_freq > VCD_RESTRK_MAX_FREQ_POINT)
calc_mfc_freq = VCD_RESTRK_MAX_FREQ_POINT;
cctxt_itr = dev_ctxt->cctxt_list_head;
while (cctxt_itr) {
VCDRES_MSG_LOW("\n cctxt_itr = %p", cctxt_itr);
if (!cctxt_itr->decoding) {
VCDRES_MSG_LOW("\n Encoder client");
enc_clnt_present = true;
break;
} else {
VCDRES_MSG_LOW("\n Decoder client");
}
cctxt_itr = cctxt_itr->next;
}
if (enc_clnt_present) {
if (req_perf_lvl >= VGA_PERF_LEVEL) {
mfc_freq = mfc_clk_freq_table[2];
axi_freq = axi_clk_freq_table_enc[1];
} else {
mfc_freq = mfc_clk_freq_table[0];
axi_freq = axi_clk_freq_table_enc[0];
}
VCDRES_MSG_MED("\n ENCODER: axi_freq = %u"
", mfc_freq = %u, calc_mfc_freq = %u,"
" req_perf_lvl = %u", axi_freq,
mfc_freq, calc_mfc_freq,
req_perf_lvl);
} else {
if (req_perf_lvl <= QVGA_PERF_LEVEL) {
mfc_freq = mfc_clk_freq_table[0];
axi_freq = axi_clk_freq_table_dec[0];
} else {
axi_freq = axi_clk_freq_table_dec[0];
if (req_perf_lvl <= VGA_PERF_LEVEL)
mfc_freq = mfc_clk_freq_table[0];
else if (req_perf_lvl <= WVGA_PERF_LEVEL)
mfc_freq = mfc_clk_freq_table[1];
else {
mfc_freq = mfc_clk_freq_table[2];
axi_freq = axi_clk_freq_table_dec[1];
}
}
VCDRES_MSG_MED("\n DECODER: axi_freq = %u"
", mfc_freq = %u, calc_mfc_freq = %u,"
" req_perf_lvl = %u", axi_freq,
mfc_freq, calc_mfc_freq,
req_perf_lvl);
}
#ifdef AXI_CLK_SCALING
if (req_perf_lvl != VCD_RESTRK_MIN_PERF_LEVEL) {
VCDRES_MSG_MED("\n %s(): Setting AXI freq to %u",
__func__, axi_freq);
clk_set_rate(ebi1_clk, axi_freq * 1000);
}
#endif
#ifdef USE_RES_TRACKER
if (req_perf_lvl != VCD_RESTRK_MIN_PERF_LEVEL) {
VCDRES_MSG_MED("\n %s(): Setting MFC freq to %u",
__func__, mfc_freq);
if (!res_trk_sel_clk_rate(mfc_freq)) {
VCDRES_MSG_ERROR("%s(): res_trk_sel_clk_rate FAILED\n",
__func__);
*pn_set_perf_lvl = 0;
return false;
}
}
#endif
*pn_set_perf_lvl =
res_trk_convert_freq_to_perf_lvl((u64) mfc_freq);
return true;
}
u32 res_trk_get_curr_perf_level(u32 *pn_perf_lvl)
{
unsigned long freq;
if (!pn_perf_lvl) {
VCDRES_MSG_ERROR("%s(): pn_perf_lvl is NULL\n",
__func__);
return false;
}
VCDRES_MSG_LOW("clk_regime_msm_get_clk_freq_hz");
if (!res_trk_get_clk_rate(&freq)) {
VCDRES_MSG_ERROR("%s(): res_trk_get_clk_rate FAILED\n",
__func__);
*pn_perf_lvl = 0;
return false;
}
*pn_perf_lvl = res_trk_convert_freq_to_perf_lvl((u64) freq);
VCDRES_MSG_MED("%s(): freq = %lu, *pn_perf_lvl = %u", __func__,
freq, *pn_perf_lvl);
return true;
}
u32 res_trk_download_firmware(void)
{
const struct firmware *fw_boot = NULL;
const struct firmware *fw_mpg4_dec = NULL;
const struct firmware *fw_h263_dec = NULL;
const struct firmware *fw_h264_dec = NULL;
const struct firmware *fw_mpg4_enc = NULL;
const struct firmware *fw_h264_enc = NULL;
const struct firmware *fw_vc1_dec = NULL;
int rc = 0;
u32 status = true;
VCDRES_MSG_HIGH("%s(): Request firmware download\n",
__func__);
mutex_lock(&resource_context.lock);
rc = request_firmware(&fw_boot, VIDC_BOOT_FW,
resource_context.device);
if (rc) {
VCDRES_MSG_ERROR("request_firmware for %s error %d\n",
VIDC_BOOT_FW, rc);
mutex_unlock(&resource_context.lock);
return false;
}
vidc_command_control_fw = (unsigned char *)fw_boot->data;
vidc_command_control_fw_size = (u32) fw_boot->size;
rc = request_firmware(&fw_mpg4_dec, VIDC_MPG4_DEC_FW,
resource_context.device);
if (rc) {
VCDRES_MSG_ERROR("request_firmware for %s error %d\n",
VIDC_MPG4_DEC_FW, rc);
status = false;
goto boot_fw_free;
}
vidc_mpg4_dec_fw = (unsigned char *)fw_mpg4_dec->data;
vidc_mpg4_dec_fw_size = (u32) fw_mpg4_dec->size;
rc = request_firmware(&fw_h263_dec, VIDC_H263_DEC_FW,
resource_context.device);
if (rc) {
VCDRES_MSG_ERROR("request_firmware for %s error %d\n",
VIDC_H263_DEC_FW, rc);
status = false;
goto mp4dec_fw_free;
}
vidc_h263_dec_fw = (unsigned char *)fw_h263_dec->data;
vidc_h263_dec_fw_size = (u32) fw_h263_dec->size;
rc = request_firmware(&fw_h264_dec, VIDC_H264_DEC_FW,
resource_context.device);
if (rc) {
VCDRES_MSG_ERROR("request_firmware for %s error %d\n",
VIDC_H264_DEC_FW, rc);
status = false;
goto h263dec_fw_free;
}
vidc_h264_dec_fw = (unsigned char *)fw_h264_dec->data;
vidc_h264_dec_fw_size = (u32) fw_h264_dec->size;
rc = request_firmware(&fw_mpg4_enc, VIDC_MPG4_ENC_FW,
resource_context.device);
if (rc) {
VCDRES_MSG_ERROR("request_firmware for %s error %d\n",
VIDC_MPG4_ENC_FW, rc);
status = false;
goto h264dec_fw_free;
}
vidc_mpg4_enc_fw = (unsigned char *)fw_mpg4_enc->data;
vidc_mpg4_enc_fw_size = (u32) fw_mpg4_enc->size;
rc = request_firmware(&fw_h264_enc, VIDC_H264_ENC_FW,
resource_context.device);
if (rc) {
VCDRES_MSG_ERROR("request_firmware for %s error %d\n",
VIDC_H264_ENC_FW, rc);
status = false;
goto mp4enc_fw_free;
}
vidc_h264_enc_fw = (unsigned char *)fw_h264_enc->data;
vidc_h264_enc_fw_size = (u32) fw_h264_enc->size;
rc = request_firmware(&fw_vc1_dec, VIDC_VC1_DEC_FW,
resource_context.device);
if (rc) {
VCDRES_MSG_ERROR("request_firmware for %s error %d\n",
VIDC_VC1_DEC_FW, rc);
status = false;
goto h264enc_fw_free;
}
vidc_vc1_dec_fw = (unsigned char *)fw_vc1_dec->data;
vidc_vc1_dec_fw_size = (u32) fw_vc1_dec->size;
mutex_unlock(&resource_context.lock);
return status;
h264enc_fw_free:
release_firmware(fw_h264_enc);
mp4enc_fw_free:
release_firmware(fw_mpg4_enc);
h264dec_fw_free:
release_firmware(fw_h264_dec);
h263dec_fw_free:
release_firmware(fw_h263_dec);
mp4dec_fw_free:
release_firmware(fw_mpg4_dec);
boot_fw_free:
release_firmware(fw_boot);
mutex_unlock(&resource_context.lock);
return false;
}
static struct ion_client *res_trk_create_ion_client(void){
struct ion_client *video_client;
VCDRES_MSG_LOW("%s", __func__);
video_client = msm_ion_client_create(-1, "video_client");
if (IS_ERR_OR_NULL(video_client)) {
VCDRES_MSG_ERROR("%s: Unable to create ION client\n", __func__);
video_client = NULL;
}
return video_client;
}
void res_trk_init(struct device *device, u32 irq)
{
VCDRES_MSG_LOW("%s", __func__);
if (resource_context.device || resource_context.irq_num ||
!device) {
VCDRES_MSG_ERROR("%s() Resource Tracker Init error\n",
__func__);
return;
}
memset(&resource_context, 0, sizeof(resource_context));
mutex_init(&resource_context.lock);
resource_context.device = device;
resource_context.irq_num = irq;
resource_context.core_type = VCD_CORE_720P;
resource_context.regulator = regulator_get(NULL, "fs_mfc");
resource_context.vidc_platform_data =
(struct msm_vidc_platform_data *) device->platform_data;
if (resource_context.vidc_platform_data) {
resource_context.memtype =
resource_context.vidc_platform_data->memtype;
VCDRES_MSG_LOW("%s(): resource_context.memtype = 0x%x",
__func__, (u32)resource_context.memtype);
if (resource_context.vidc_platform_data->enable_ion) {
resource_context.res_ion_client =
res_trk_create_ion_client();
if (!(resource_context.res_ion_client)) {
VCDRES_MSG_ERROR("%s()ION createfail\n",
__func__);
return;
}
VCDRES_MSG_LOW("%s(): ion_client = 0x%x", __func__,
(u32)resource_context.res_ion_client);
} else {
VCDRES_MSG_ERROR("%s(): ION not disabled\n",
__func__);
}
} else {
resource_context.memtype = -1;
VCDRES_MSG_ERROR("%s(): vidc_platform_data is NULL",
__func__);
}
}
u32 res_trk_get_core_type(void){
return resource_context.core_type;
}
u32 res_trk_get_enable_ion(void)
{
if (resource_context.vidc_platform_data->enable_ion)
return 1;
else
return 0;
}
struct ion_client *res_trk_get_ion_client(void)
{
return resource_context.res_ion_client;
}
u32 res_trk_get_mem_type(void)
{
u32 mem_type = ION_HEAP(resource_context.memtype);
return mem_type;
}
void res_trk_set_mem_type(enum ddl_mem_area mem_type)
{
return;
}
u32 res_trk_get_disable_fullhd(void)
{
return 0;
}
u32 res_trk_get_ion_flags(void)
{
return 0;
}
int res_trk_check_for_sec_session()
{
return 0;
}
void res_trk_secure_unset(void)
{
return;
}
void res_trk_secure_set(void)
{
return;
}
int res_trk_open_secure_session()
{
return -EINVAL;
}
int res_trk_close_secure_session()
{
return 0;
}
u32 get_res_trk_perf_level(enum vcd_perf_level perf_level)
{
return -ENOTSUPP;
}
u32 res_trk_is_cp_enabled(void)
{
if (resource_context.vidc_platform_data->cp_enabled)
return 1;
else
return 0;
}
u32 res_trk_estimate_perf_level(u32 pn_perf_lvl)
{
return 0;
}
@@ -0,0 +1,60 @@
/* Copyright (c) 2010-2012, 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.
*
*/
#ifndef _VIDEO_720P_RESOURCE_TRACKER_H_
#define _VIDEO_720P_RESOURCE_TRACKER_H_
#include <mach/board.h>
#include <linux/msm_ion.h>
#include "vcd_res_tracker_api.h"
#define VCD_RESTRK_MIN_PERF_LEVEL 37900
#define VCD_RESTRK_MAX_PERF_LEVEL 108000
#define VCD_RESTRK_MIN_FREQ_POINT 61440000
#define VCD_RESTRK_MAX_FREQ_POINT 170667000
#define VCD_RESTRK_HZ_PER_1000_PERFLVL 1580250
struct res_trk_context {
struct device *device;
u32 irq_num;
struct mutex lock;
struct clk *hclk;
struct clk *hclk_div2;
struct clk *pclk;
unsigned long hclk_rate;
unsigned int clock_enabled;
unsigned int rail_enabled;
struct regulator *regulator;
struct msm_vidc_platform_data *vidc_platform_data;
u32 core_type;
int memtype;
u32 secure_session;
struct ion_client *res_ion_client;
enum ddl_mem_area res_mem_type;
};
#if DEBUG
#define VCDRES_MSG_LOW(xx_fmt...) printk(KERN_INFO "\n\t* " xx_fmt)
#define VCDRES_MSG_MED(xx_fmt...) printk(KERN_INFO "\n * " xx_fmt)
#else
#define VCDRES_MSG_LOW(xx_fmt...)
#define VCDRES_MSG_MED(xx_fmt...)
#endif
#define VCDRES_MSG_HIGH(xx_fmt...) printk(KERN_WARNING "\n" xx_fmt)
#define VCDRES_MSG_ERROR(xx_fmt...) printk(KERN_ERR "\n err: " xx_fmt)
#define VCDRES_MSG_FATAL(xx_fmt...) printk(KERN_ERR "\n<FATAL> " xx_fmt)
#endif
@@ -0,0 +1,44 @@
/* Copyright (c) 2010-2012, 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.
*
*/
#ifndef _VIDEO_720P_RESOURCE_TRACKER_API_H_
#define _VIDEO_720P_RESOURCE_TRACKER_API_H_
#include "vcd_core.h"
#include "vcd_ddl.h"
void res_trk_init(struct device *device, u32 irq);
u32 res_trk_power_up(void);
u32 res_trk_power_down(void);
u32 res_trk_enable_clocks(void);
u32 res_trk_disable_clocks(void);
u32 res_trk_get_max_perf_level(u32 *pn_max_perf_lvl);
u32 res_trk_set_perf_level(u32 req_perf_lvl, u32 *pn_set_perf_lvl,
struct vcd_dev_ctxt *dev_ctxt);
u32 res_trk_get_curr_perf_level(u32 *pn_perf_lvl);
u32 res_trk_download_firmware(void);
u32 res_trk_get_core_type(void);
u32 res_trk_get_mem_type(void);
u32 res_trk_get_disable_fullhd(void);
u32 res_trk_get_ion_flags(void);
u32 res_trk_get_enable_ion(void);
u32 res_trk_is_cp_enabled(void);
struct ion_client *res_trk_get_ion_client(void);
void res_trk_set_mem_type(enum ddl_mem_area mem_type);
int res_trk_check_for_sec_session(void);
int res_trk_open_secure_session(void);
int res_trk_close_secure_session(void);
void res_trk_secure_set(void);
void res_trk_secure_unset(void);
u32 get_res_trk_perf_level(enum vcd_perf_level perf_level);
u32 res_trk_estimate_perf_level(u32 pn_perf_lvl);
#endif