/*
|
*
|
* Copyright 2015 Rockchip Electronics Co. LTD
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
#define MODULE_TAG "HAL_JPEG_VDPU2"
|
|
#include <stdio.h>
|
#include <string.h>
|
#include <stdint.h>
|
|
#include "mpp_env.h"
|
#include "mpp_mem.h"
|
#include "mpp_debug.h"
|
#include "mpp_frame.h"
|
#include "mpp_common.h"
|
|
#include "jpegd_syntax.h"
|
#include "hal_jpegd_common.h"
|
#include "hal_jpegd_vdpu2.h"
|
#include "hal_jpegd_vdpu2_reg.h"
|
|
extern RK_U32 jpegd_debug;
|
|
static MPP_RET jpegd_regs_init(JpegRegSet *reg)
|
{
|
jpegd_dbg_func("enter\n");
|
memset(reg, 0, sizeof(JpegRegSet));
|
reg->reg50_dec_ctrl.sw_dec_out_tiled_e = 0;
|
reg->reg50_dec_ctrl.sw_dec_scmd_dis = DEC_SCMD_DISABLE;
|
reg->reg50_dec_ctrl.sw_dec_latency = DEC_LATENCY_COMPENSATION;
|
|
reg->reg54_endian.sw_dec_in_endian = DEC_BIG_ENDIAN;
|
reg->reg54_endian.sw_dec_out_endian = DEC_LITTLE_ENDIAN;
|
reg->reg54_endian.sw_dec_strendian_e = DEC_LITTLE_ENDIAN;
|
reg->reg54_endian.sw_dec_outswap32_e = DEC_LITTLE_ENDIAN;
|
reg->reg54_endian.sw_dec_inswap32_e = 1;
|
reg->reg54_endian.sw_dec_strswap32_e = 1;
|
|
reg->reg55_Interrupt.sw_dec_irq_dis = 0;
|
|
reg->reg56_axi_ctrl.sw_dec_axi_rn_id = 0xff;
|
reg->reg56_axi_ctrl.sw_dec_axi_wr_id = 0;
|
reg->reg56_axi_ctrl.sw_dec_max_burst = DEC_BUS_BURST_LENGTH_16;
|
reg->reg56_axi_ctrl.sw_dec_data_disc_e = DEC_DATA_DISCARD_ENABLE;
|
|
reg->reg57_enable_ctrl.sw_dec_timeout_e = 1;
|
reg->reg57_enable_ctrl.sw_dec_clk_gate_e = 1;
|
|
jpegd_dbg_func("exit\n");
|
return MPP_OK;
|
}
|
|
static void jpegd_write_code_word_number(JpegdHalCtx *ctx,
|
JpegdSyntax *syntax)
|
{
|
jpegd_dbg_func("enter\n");
|
JpegdSyntax *s = syntax;
|
AcTable *ac_ptr0 = NULL, *ac_ptr1 = NULL;
|
DcTable *dc_ptr0 = NULL, *dc_ptr1 = NULL;
|
JpegdIocRegInfo *info = (JpegdIocRegInfo *)ctx->regs;
|
JpegRegSet *reg = &(info->regs);
|
|
/* first, select the table we'll use.
|
* this trick is done because hardware always wants luma
|
* table as AC hardware table 0.
|
*/
|
if (s->ac_index[0] == HUFFMAN_TABLE_ID_ZERO) {
|
/* Luma's AC uses Huffman table zero */
|
ac_ptr0 = &(s->ac_table[HUFFMAN_TABLE_ID_ZERO]);
|
ac_ptr1 = &(s->ac_table[HUFFMAN_TABLE_ID_ONE]);
|
} else {
|
ac_ptr0 = &(s->ac_table[HUFFMAN_TABLE_ID_ONE]);
|
ac_ptr1 = &(s->ac_table[HUFFMAN_TABLE_ID_ZERO]);
|
}
|
|
/* write AC table 0 (luma) */
|
reg->reg134.sw_ac1_code1_cnt = ac_ptr0->bits[0];
|
reg->reg134.sw_ac1_code2_cnt = ac_ptr0->bits[1];
|
reg->reg134.sw_ac1_code3_cnt = ac_ptr0->bits[2];
|
reg->reg134.sw_ac1_code4_cnt = ac_ptr0->bits[3];
|
reg->reg134.sw_ac1_code5_cnt = ac_ptr0->bits[4];
|
reg->reg134.sw_ac1_code6_cnt = ac_ptr0->bits[5];
|
|
reg->reg135.sw_ac1_code7_cnt = ac_ptr0->bits[6];
|
reg->reg135.sw_ac1_code8_cnt = ac_ptr0->bits[7];
|
reg->reg135.sw_ac1_code9_cnt = ac_ptr0->bits[8];
|
reg->reg135.sw_ac1_code10_cnt = ac_ptr0->bits[9];
|
|
reg->reg136.sw_ac1_code11_cnt = ac_ptr0->bits[10];
|
reg->reg136.sw_ac1_code12_cnt = ac_ptr0->bits[11];
|
reg->reg136.sw_ac1_code13_cnt = ac_ptr0->bits[12];
|
reg->reg136.sw_ac1_code14_cnt = ac_ptr0->bits[13];
|
|
reg->reg137.sw_ac1_code15_cnt = ac_ptr0->bits[14];
|
reg->reg137.sw_ac1_code16_cnt = ac_ptr0->bits[15];
|
|
/* AC table 1 (the not-luma table) */
|
reg->reg137.sw_ac2_code1_cnt = ac_ptr1->bits[0];
|
reg->reg137.sw_ac2_code2_cnt = ac_ptr1->bits[1];
|
reg->reg137.sw_ac2_code3_cnt = ac_ptr1->bits[2];
|
reg->reg137.sw_ac2_code4_cnt = ac_ptr1->bits[3];
|
|
reg->reg138.sw_ac2_code5_cnt = ac_ptr1->bits[4];
|
reg->reg138.sw_ac2_code6_cnt = ac_ptr1->bits[5];
|
reg->reg138.sw_ac2_code7_cnt = ac_ptr1->bits[6];
|
reg->reg138.sw_ac2_code8_cnt = ac_ptr1->bits[7];
|
|
reg->reg139.sw_ac2_code9_cnt = ac_ptr1->bits[8];
|
reg->reg139.sw_ac2_code10_cnt = ac_ptr1->bits[9];
|
reg->reg139.sw_ac2_code11_cnt = ac_ptr1->bits[10];
|
reg->reg139.sw_ac2_code12_cnt = ac_ptr1->bits[11];
|
|
reg->reg140.sw_ac2_code13_cnt = ac_ptr1->bits[12];
|
reg->reg140.sw_ac2_code14_cnt = ac_ptr1->bits[13];
|
reg->reg140.sw_ac2_code15_cnt = ac_ptr1->bits[14];
|
reg->reg140.sw_ac2_code16_cnt = ac_ptr1->bits[15];
|
|
/* first, select the table we'll use.
|
* this trick is done because hardware always wants luma
|
* table as DC hardware table 0.
|
*/
|
if (s->dc_index[0] == HUFFMAN_TABLE_ID_ZERO) {
|
/* Luma's DC uses Huffman table zero */
|
dc_ptr0 = &(s->dc_table[HUFFMAN_TABLE_ID_ZERO]);
|
dc_ptr1 = &(s->dc_table[HUFFMAN_TABLE_ID_ONE]);
|
} else {
|
dc_ptr0 = &(s->dc_table[HUFFMAN_TABLE_ID_ONE]);
|
dc_ptr1 = &(s->dc_table[HUFFMAN_TABLE_ID_ZERO]);
|
}
|
|
/* write DC table 0 (luma) */
|
reg->reg141.sw_dc1_code1_cnt = dc_ptr0->bits[0];
|
reg->reg141.sw_dc1_code2_cnt = dc_ptr0->bits[1];
|
reg->reg141.sw_dc1_code3_cnt = dc_ptr0->bits[2];
|
reg->reg141.sw_dc1_code4_cnt = dc_ptr0->bits[3];
|
reg->reg141.sw_dc1_code5_cnt = dc_ptr0->bits[4];
|
reg->reg141.sw_dc1_code6_cnt = dc_ptr0->bits[5];
|
reg->reg141.sw_dc1_code7_cnt = dc_ptr0->bits[6];
|
reg->reg141.sw_dc1_code8_cnt = dc_ptr0->bits[7];
|
|
reg->reg142.sw_dc1_code9_cnt = dc_ptr0->bits[8];
|
reg->reg142.sw_dc1_code10_cnt = dc_ptr0->bits[9];
|
reg->reg142.sw_dc1_code11_cnt = dc_ptr0->bits[10];
|
reg->reg142.sw_dc1_code12_cnt = dc_ptr0->bits[11];
|
reg->reg142.sw_dc1_code13_cnt = dc_ptr0->bits[12];
|
reg->reg142.sw_dc1_code14_cnt = dc_ptr0->bits[13];
|
reg->reg142.sw_dc1_code15_cnt = dc_ptr0->bits[14];
|
reg->reg142.sw_dc1_code16_cnt = dc_ptr0->bits[15];
|
|
/* DC table 1 (the not-luma table) */
|
reg->reg143.sw_dc2_code1_cnt = dc_ptr1->bits[0];
|
reg->reg143.sw_dc2_code2_cnt = dc_ptr1->bits[1];
|
reg->reg143.sw_dc2_code3_cnt = dc_ptr1->bits[2];
|
reg->reg143.sw_dc2_code4_cnt = dc_ptr1->bits[3];
|
reg->reg143.sw_dc2_code5_cnt = dc_ptr1->bits[4];
|
reg->reg143.sw_dc2_code6_cnt = dc_ptr1->bits[5];
|
reg->reg143.sw_dc2_code7_cnt = dc_ptr1->bits[6];
|
reg->reg143.sw_dc2_code8_cnt = dc_ptr1->bits[7];
|
|
reg->reg144.sw_dc2_code9_cnt = dc_ptr1->bits[8];
|
reg->reg144.sw_dc2_code10_cnt = dc_ptr1->bits[9];
|
reg->reg144.sw_dc2_code11_cnt = dc_ptr1->bits[10];
|
reg->reg144.sw_dc2_code12_cnt = dc_ptr1->bits[11];
|
reg->reg144.sw_dc2_code13_cnt = dc_ptr1->bits[12];
|
reg->reg144.sw_dc2_code14_cnt = dc_ptr1->bits[13];
|
reg->reg144.sw_dc2_code15_cnt = dc_ptr1->bits[14];
|
reg->reg144.sw_dc2_code16_cnt = dc_ptr1->bits[15];
|
|
jpegd_dbg_func("exit\n");
|
return;
|
}
|
|
static void
|
jpegd_set_chroma_table_id(JpegdHalCtx *ctx, JpegdSyntax *syntax)
|
{
|
jpegd_dbg_func("enter\n");
|
JpegdSyntax *s = syntax;
|
JpegdIocRegInfo *info = (JpegdIocRegInfo *)ctx->regs;
|
JpegRegSet *reg = &(info->regs);
|
|
/* this trick is done because hardware always wants
|
* luma table as ac hardward table 0
|
*/
|
if (s->ac_index[0] == HUFFMAN_TABLE_ID_ZERO) {
|
reg->reg122.sw_cb_ac_vlctable = s->ac_index[1];
|
reg->reg122.sw_cr_ac_vlctable = s->ac_index[2];
|
} else {
|
if (s->ac_index[0] == s->ac_index[1])
|
reg->reg122.sw_cb_ac_vlctable = 0;
|
else
|
reg->reg122.sw_cb_ac_vlctable = 1;
|
|
if (s->ac_index[0] == s->ac_index[2])
|
reg->reg122.sw_cr_ac_vlctable = 0;
|
else
|
reg->reg122.sw_cr_ac_vlctable = 1;
|
}
|
|
if (s->dc_index[0] == HUFFMAN_TABLE_ID_ZERO) {
|
reg->reg122.sw_cb_dc_vlctable = s->dc_index[1];
|
reg->reg122.sw_cr_dc_vlctable = s->dc_index[2];
|
} else {
|
if (s->dc_index[0] == s->dc_index[1])
|
reg->reg122.sw_cb_dc_vlctable = 0;
|
else
|
reg->reg122.sw_cb_dc_vlctable = 1;
|
|
if (s->dc_index[0] == s->dc_index[2])
|
reg->reg122.sw_cr_dc_vlctable = 0;
|
else
|
reg->reg122.sw_cr_dc_vlctable = 1;
|
}
|
|
reg->reg122.sw_cr_dc_vlctable3 = 0;
|
reg->reg122.sw_cb_dc_vlctable3 = 0;
|
|
jpegd_dbg_func("exit\n");
|
return;
|
}
|
|
static void
|
jpegd_set_stream_offset(JpegdHalCtx *ctx, JpegdSyntax *syntax)
|
{
|
jpegd_dbg_func("enter\n");
|
JpegdSyntax *s = syntax;
|
|
JpegdIocRegInfo *info = (JpegdIocRegInfo *)ctx->regs;
|
JpegRegSet *reg = &(info->regs);
|
RK_U32 offset = 0, byte_cnt = 0;
|
RK_U32 bit_pos_in_byte = 0;
|
RK_U32 strm_len_by_hw = 0;
|
/* calculate and set stream start address to hw,
|
* the offset must be 8-byte aligned.
|
*/
|
offset = (s->strm_offset & (~7));
|
reg->reg64_rlc_vlc_base = ctx->pkt_fd;
|
if (offset) {
|
mpp_dev_set_reg_offset(ctx->dev, 64, offset);
|
}
|
/* calculate and set stream start bit to hardware
|
* change current pos to bus address style
|
* remove three lowest bits and add the difference to bitPosInWord
|
* used as bit pos in word not as bit pos in byte actually...
|
*/
|
byte_cnt = ((uintptr_t) s->cur_pos & (7));
|
bit_pos_in_byte = byte_cnt * 8; /* 1 Byte = 8 bits */
|
reg->reg122.sw_strm_start_bit = bit_pos_in_byte;
|
|
/* set up stream length for HW.
|
* length = size of original buffer - stream we already decoded in SW
|
*/
|
strm_len_by_hw = s->pkt_len - offset;
|
reg->reg51_stream_info.sw_stream_len = strm_len_by_hw;
|
reg->reg122.sw_jpeg_stream_all = 1;
|
|
jpegd_dbg_func("exit\n");
|
return;
|
}
|
|
static MPP_RET jpegd_setup_pp(JpegdHalCtx *ctx, JpegdSyntax *syntax)
|
{
|
jpegd_dbg_func("enter\n");
|
JpegdIocRegInfo *info = (JpegdIocRegInfo *)ctx->regs;
|
JpegRegSet *reg = &(info->regs);
|
JpegdSyntax *s = syntax;
|
|
RK_U32 in_color = ctx->pp_info.pp_in_fmt;
|
RK_U32 out_color = ctx->pp_info.pp_out_fmt;
|
RK_U32 dither = ctx->pp_info.dither_enable;
|
RK_U32 crop_width = ctx->pp_info.crop_width;
|
RK_U32 crop_height = ctx->pp_info.crop_height;
|
RK_U32 crop_x = ctx->pp_info.crop_x;
|
RK_U32 crop_y = ctx->pp_info.crop_y;
|
RK_U32 in_width = s->hor_stride;
|
RK_U32 in_height = s->ver_stride;
|
RK_U32 out_width = s->hor_stride;
|
RK_U32 out_height = s->ver_stride;
|
RK_U32 uv_offset = s->hor_stride * s->ver_stride;
|
|
reg->reg0.sw_pp_axi_rd_id = 0;
|
reg->reg0.sw_pp_axi_wr_id = 0;
|
reg->reg0.sw_pp_scmd_dis = 1;
|
reg->reg0.sw_pp_max_burst = 16;
|
|
reg->reg18_pp_in_lu_base = 0;
|
reg->reg34.sw_ext_orig_width = in_width >> 4;
|
|
reg->reg37.sw_pp_in_a2_endsel = 1;
|
reg->reg37.sw_pp_in_a1_swap32 = 1;
|
reg->reg37.sw_pp_in_a1_endian = 1;
|
reg->reg37.sw_pp_in_swap32_e = 1;
|
reg->reg37.sw_pp_in_endian = 1;
|
reg->reg37.sw_pp_out_endian = 1;
|
reg->reg37.sw_pp_out_swap32_e = 1;
|
|
reg->reg41.sw_pp_clk_gate_e = 1;
|
reg->reg41.sw_pp_ahb_hlock_e = 1;
|
reg->reg41.sw_pp_data_disc_e = 1;
|
|
if (crop_width <= 0) {
|
reg->reg34.sw_pp_in_w_ext = (((in_width / 16) & 0xE00) >> 9);
|
reg->reg34.sw_pp_in_width = ((in_width / 16) & 0x1FF);
|
reg->reg34.sw_pp_in_h_ext = (((in_height / 16) & 0x700) >> 8);
|
reg->reg34.sw_pp_in_height = ((in_height / 16) & 0x0FF);
|
} else {
|
reg->reg34.sw_pp_in_w_ext = (((crop_width / 16) & 0xE00) >> 9);
|
reg->reg34.sw_pp_in_width = ((crop_width / 16) & 0x1FF);
|
reg->reg34.sw_pp_in_h_ext = (((crop_height / 16) & 0x700) >> 8);
|
reg->reg34.sw_pp_in_height = ((crop_height / 16) & 0x0FF);
|
|
reg->reg14.sw_crop_startx_ext = (((crop_x / 16) & 0xE00) >> 9);
|
reg->reg14.sw_crop_startx = ((crop_x / 16) & 0x1FF);
|
reg->reg14.sw_crop_starty_ext = (((crop_y / 16) & 0x700) >> 8);
|
reg->reg14.sw_crop_starty = ((crop_y / 16) & 0x0FF);
|
|
if (crop_width & 0x0F) {
|
reg->reg14.sw_pp_crop8_r_e = 1;
|
} else {
|
reg->reg14.sw_pp_crop8_r_e = 0;
|
}
|
if (crop_height & 0x0F) {
|
reg->reg14.sw_pp_crop8_d_e = 1;
|
} else {
|
reg->reg14.sw_pp_crop8_d_e = 0;
|
}
|
in_width = crop_width;
|
in_height = crop_height;
|
}
|
|
reg->reg39.sw_display_width = out_width;
|
reg->reg35.sw_pp_out_width = out_width;
|
reg->reg35.sw_pp_out_height = out_height;
|
|
switch (in_color) {
|
case PP_IN_FORMAT_YUV422INTERLAVE:
|
case PP_IN_FORMAT_YUV420SEMI:
|
case PP_IN_FORMAT_YUV420PLANAR:
|
case PP_IN_FORMAT_YUV400:
|
case PP_IN_FORMAT_YUV422SEMI:
|
case PP_IN_FORMAT_YUV420SEMITIELED:
|
case PP_IN_FORMAT_YUV440SEMI:
|
reg->reg38.sw_pp_in_format = in_color;
|
break;
|
case PP_IN_FORMAT_YUV444_SEMI:
|
reg->reg38.sw_pp_in_format = 7;
|
reg->reg38.sw_pp_in_format_es = 0;
|
break;
|
case PP_IN_FORMAT_YUV411_SEMI:
|
reg->reg38.sw_pp_in_format = 0;
|
reg->reg38.sw_pp_in_format_es = 1;
|
break;
|
default:
|
mpp_err_f("unsupported format:%d", in_color);
|
return MPP_NOK;
|
}
|
|
RK_U32 video_range = 1;
|
|
reg->reg15.sw_rangemap_coef_y = 9;
|
reg->reg15.sw_rangemap_coef_c = 9;
|
reg->reg3.sw_pp_color_coefff = BRIGHTNESS; /* brightness */
|
|
if (out_color <= PP_OUT_FORMAT_ARGB) {
|
/*Bt.601*/
|
unsigned int a = 298;
|
unsigned int b = 409;
|
unsigned int c = 208;
|
unsigned int d = 100;
|
unsigned int e = 516;
|
|
/*Bt.709
|
unsigned int a = 298;
|
unsigned int b = 459;
|
unsigned int c = 137;
|
unsigned int d = 55;
|
unsigned int e = 544;*/
|
|
int satur = 0, tmp;
|
if (video_range != 0) {
|
/*Bt.601*/
|
a = 256;
|
b = 350;
|
c = 179;
|
d = 86;
|
e = 443;
|
/*Bt.709
|
a = 256;
|
b = 403;
|
c = 120;
|
d = 48;
|
e = 475;*/
|
|
reg->reg15.sw_ycbcr_range = video_range;
|
}
|
int contrast = CONTRAST;
|
if (contrast != 0) {
|
int thr1y, thr2y, off1, off2, thr1, thr2, a1, a2;
|
if (video_range == 0) {
|
int tmp1, tmp2;
|
/* Contrast */
|
thr1 = (219 * (contrast + 128)) / 512;
|
thr1y = (219 - 2 * thr1) / 2;
|
thr2 = 219 - thr1;
|
thr2y = 219 - thr1y;
|
|
tmp1 = (thr1y * 256) / thr1;
|
tmp2 = ((thr2y - thr1y) * 256) / (thr2 - thr1);
|
off1 = ((thr1y - ((tmp2 * thr1) / 256)) * a) / 256;
|
off2 = ((thr2y - ((tmp1 * thr2) / 256)) * a) / 256;
|
|
tmp1 = (64 * (contrast + 128)) / 128;
|
tmp2 = 256 * (128 - tmp1);
|
a1 = (tmp2 + off2) / thr1;
|
a2 = a1 + (256 * (off2 - 1)) / (thr2 - thr1);
|
} else {
|
/* Contrast */
|
thr1 = (64 * (contrast + 128)) / 128;
|
thr1y = 128 - thr1;
|
thr2 = 256 - thr1;
|
thr2y = 256 - thr1y;
|
a1 = (thr1y * 256) / thr1;
|
a2 = ((thr2y - thr1y) * 256) / (thr2 - thr1);
|
off1 = thr1y - (a2 * thr1) / 256;
|
off2 = thr2y - (a1 * thr2) / 256;
|
}
|
|
if (a1 > 1023)
|
a1 = 1023;
|
else if (a1 < 0)
|
a1 = 0;
|
|
if (a2 > 1023)
|
a2 = 1023;
|
else if (a2 < 0)
|
a2 = 0;
|
|
if (thr1 > 255)
|
thr1 = 255;
|
else if (thr1 < 0)
|
thr1 = 0;
|
|
if (thr2 > 255)
|
thr2 = 255;
|
else if (thr2 < 0)
|
thr2 = 0;
|
|
if (off1 > 511)
|
off1 = 511;
|
else if (off1 < -512)
|
off1 = -512;
|
|
if (off2 > 511)
|
off2 = 511;
|
else if (off2 < -512)
|
off2 = -512;
|
|
reg->reg31.sw_contrast_thr1 = thr1;
|
reg->reg31.sw_contrast_thr2 = thr2;
|
reg->reg32.sw_contrast_off1 = off1;
|
reg->reg32.sw_contrast_off2 = off2;
|
|
reg->reg1.sw_color_coeffa1 = a1;
|
reg->reg1.sw_color_coeffa2 = a2;
|
} else {
|
reg->reg31.sw_contrast_thr1 = 55;
|
reg->reg31.sw_contrast_thr2 = 165;
|
reg->reg32.sw_contrast_off1 = 0;
|
reg->reg32.sw_contrast_off2 = 0;
|
|
tmp = a;
|
if (tmp > 1023)
|
tmp = 1023;
|
else if (tmp < 0)
|
tmp = 0;
|
|
reg->reg1.sw_color_coeffa1 = tmp;
|
reg->reg1.sw_color_coeffa2 = tmp;
|
}
|
|
reg->reg37.sw_pp_out_endian = 0;
|
|
satur = 64 + SATURATION; /* saturation */
|
tmp = (satur * (int) b) / 64;
|
if (tmp > 1023)
|
tmp = 1023;
|
else if (tmp < 0)
|
tmp = 0;
|
reg->reg1.sw_color_coeffb = (unsigned int) tmp;
|
|
tmp = (satur * (int) c) / 64;
|
if (tmp > 1023)
|
tmp = 1023;
|
else if (tmp < 0)
|
tmp = 0;
|
reg->reg2.sw_color_coeffc = (unsigned int) tmp;
|
|
tmp = (satur * (int) d) / 64;
|
if (tmp > 1023)
|
tmp = 1023;
|
else if (tmp < 0)
|
tmp = 0;
|
reg->reg2.sw_color_coeffd = (unsigned int) tmp;
|
|
tmp = (satur * (int) e) / 64;
|
if (tmp > 1023)
|
tmp = 1023;
|
else if (tmp < 0)
|
tmp = 0;
|
reg->reg2.sw_color_coeffe = (unsigned int) tmp;
|
}
|
|
if (out_color <= PP_OUT_FORMAT_ARGB) {
|
PpRgbCfg *cfg = get_pp_rgb_Cfg(ctx->output_fmt);
|
reg->reg9_r_mask = cfg->r_mask;
|
reg->reg10_g_mask = cfg->g_mask;
|
reg->reg11_b_mask = cfg->b_mask;
|
reg->reg16.sw_rgb_r_padd = cfg->r_padd;
|
reg->reg16.sw_rgb_g_padd = cfg->g_padd;
|
reg->reg16.sw_rgb_b_padd = cfg->b_padd;
|
|
if (dither) {
|
jpegd_dbg_hal("we do dither.");
|
reg->reg36.sw_dither_select_r = cfg->r_dither;
|
reg->reg36.sw_dither_select_g = cfg->g_dither;
|
reg->reg36.sw_dither_select_b = cfg->b_dither;
|
} else {
|
jpegd_dbg_hal("we do not dither.");
|
}
|
|
reg->reg37.sw_rgb_pix_in32 = cfg->rgb_in_32;
|
reg->reg37.sw_pp_out_swap16_e = cfg->swap_16;
|
reg->reg37.sw_pp_out_swap32_e = cfg->swap_32;
|
reg->reg37.sw_pp_out_endian = cfg->out_endian;
|
|
reg->reg38.sw_pp_out_format = 0;
|
|
} else if (out_color == PP_OUT_FORMAT_YUV422INTERLAVE) {
|
reg->reg38.sw_pp_out_format = 3;
|
} else if (out_color == PP_OUT_FORMAT_YUV420INTERLAVE) {
|
reg->reg38.sw_pp_out_format = 5;
|
} else {
|
mpp_err_f("unsuppotred format:%d", out_color);
|
return -1;
|
}
|
|
reg->reg38.sw_rotation_mode = 0;
|
|
unsigned int inw, inh;
|
unsigned int outw, outh;
|
|
inw = in_width - 1;
|
inh = in_height - 1;
|
outw = out_width - 1;
|
outh = out_height - 1;
|
|
if (inw < outw) {
|
reg->reg4.sw_hor_scale_mode = 1;
|
reg->reg4.sw_scale_wratio = (outw << 16) / inw;
|
reg->reg6.sw_wscale_invra = (inw << 16) / outw;
|
} else if (inw > outw) {
|
reg->reg4.sw_hor_scale_mode = 2;
|
reg->reg6.sw_wscale_invra = ((outw + 1) << 16) / (inw + 1);
|
} else
|
reg->reg4.sw_hor_scale_mode = 0;
|
|
if (inh < outh) {
|
reg->reg4.sw_ver_scale_mode = 1;
|
reg->reg5.sw_scale_hratio = (outh << 16) / inh;
|
reg->reg6.sw_hscale_invra = (inh << 16) / outh;
|
} else if (inh > outh) {
|
reg->reg4.sw_ver_scale_mode = 2;
|
reg->reg6.sw_hscale_invra = ((outh + 1) << 16) / (inh + 1) + 1;
|
} else
|
reg->reg4.sw_ver_scale_mode = 0;
|
|
reg->reg41.sw_pp_pipeline_e = ctx->pp_info.pp_enable;
|
|
jpegd_dbg_hal("pp_enable %d\n", ctx->pp_info.pp_enable);
|
|
if (ctx->pp_info.pp_enable) {
|
reg->reg41.sw_pp_pipeline_e = 1;
|
reg->reg57_enable_ctrl.sw_dec_out_dis = 1;
|
|
reg->reg63_dec_out_base = 0;
|
reg->reg131_jpg_ch_out_base = 0;
|
|
reg->reg21_pp_out_lu_base = ctx->frame_fd;
|
reg->reg22_pp_out_ch_base = ctx->frame_fd;
|
|
if (uv_offset)
|
mpp_dev_set_reg_offset(ctx->dev, 22, uv_offset);
|
|
jpegd_dbg_hal("output_frame_fd:%x, reg22:%x", ctx->frame_fd,
|
reg->reg22_pp_out_ch_base);
|
} else {
|
// output without pp
|
reg->reg41.sw_pp_pipeline_e = 0;
|
reg->reg57_enable_ctrl.sw_dec_out_dis = 0;
|
|
reg->reg21_pp_out_lu_base = 0;
|
reg->reg22_pp_out_ch_base = 0;
|
|
reg->reg63_dec_out_base = ctx->frame_fd;
|
reg->reg131_jpg_ch_out_base = ctx->frame_fd;
|
|
if (uv_offset)
|
mpp_dev_set_reg_offset(ctx->dev, 131, uv_offset);
|
|
jpegd_dbg_hal("output_frame_fd:%x, reg131:%x", ctx->frame_fd,
|
reg->reg131_jpg_ch_out_base);
|
}
|
|
jpegd_dbg_func("exit\n");
|
return MPP_OK;
|
}
|
|
static
|
MPP_RET jpegd_gen_regs(JpegdHalCtx *ctx, JpegdSyntax *syntax)
|
{
|
MPP_RET ret = MPP_OK;
|
jpegd_dbg_func("enter\n");
|
JpegdIocRegInfo *info = (JpegdIocRegInfo *)ctx->regs;
|
JpegRegSet *reg = &(info->regs);
|
JpegdSyntax *s = syntax;
|
|
jpegd_regs_init(reg);
|
|
reg->reg50_dec_ctrl.sw_filtering_dis = 1;
|
reg->reg53_dec_mode = DEC_MODE_JPEG;
|
|
reg->reg57_enable_ctrl.sw_dec_e = 1; /* Enable jpeg mode */
|
reg->reg57_enable_ctrl.sw_pjpeg_e = 0;
|
reg->reg57_enable_ctrl.sw_dec_out_dis = 0;
|
reg->reg57_enable_ctrl.sw_rlc_mode_e = 0;
|
|
/* frame size, round up the number of mbs */
|
reg->reg120.sw_pic_mb_h_ext = ((((s->ver_stride) >> (4)) & 0x700) >> 8);
|
reg->reg120.sw_pic_mb_w_ext = ((((s->hor_stride) >> (4)) & 0xE00) >> 9);
|
reg->reg120.sw_pic_mb_width = ((s->hor_stride) >> (4)) & 0x1FF;
|
reg->reg120.sw_pic_mb_hight_p = ((s->ver_stride) >> (4)) & 0x0FF;
|
|
reg->reg121.sw_pjpeg_fildown_e = s->fill_bottom;
|
/* Set spectral selection start coefficient */
|
reg->reg121.sw_pjpeg_ss = s->scan_start;
|
/* Set spectral selection end coefficient */
|
reg->reg121.sw_pjpeg_se = s->scan_end;
|
/* Set the point transform used in the preceding scan */
|
reg->reg121.sw_pjpeg_ah = s->prev_shift;
|
/* Set the point transform value */
|
reg->reg121.sw_pjpeg_al = s->point_transform;
|
|
reg->reg122.sw_jpeg_qtables = s->qtable_cnt;
|
reg->reg122.sw_jpeg_mode = s->yuv_mode;
|
reg->reg122.sw_jpeg_filright_e = s->fill_right;
|
|
reg->reg148.sw_slice_h = 0;
|
/* Set bit 21 of reg148 to 1, notifying hardware to decode jpeg
|
* including DRI segment
|
*/
|
reg->reg148.sw_syn_marker_e = 1;
|
|
/* tell hardware that height is 8-pixel aligned,
|
* but not 16-pixel aligned
|
*/
|
if ((s->height % 16) && ((s->height % 16) <= 8) &&
|
(!ctx->pp_info.pp_enable) &&
|
(s->yuv_mode == JPEGDEC_YUV422 ||
|
s->yuv_mode == JPEGDEC_YUV444 ||
|
s->yuv_mode == JPEGDEC_YUV411)) {
|
reg->reg148.sw_jpeg_height8_flag = 1;
|
}
|
|
/* write VLC code word number to register */
|
jpegd_write_code_word_number(ctx, s);
|
|
/* Create AC/DC/QP tables for hardware */
|
jpegd_write_qp_ac_dc_table(ctx, s);
|
|
/* Select which tables the chromas use */
|
jpegd_set_chroma_table_id(ctx, s);
|
|
/* write table base */
|
reg->reg61_qtable_base = mpp_buffer_get_fd(ctx->pTableBase);
|
|
/* set up stream position for HW decode */
|
jpegd_set_stream_offset(ctx, s);
|
|
/* set restart interval */
|
if (s->restart_interval) {
|
reg->reg122.sw_sync_marker_e = 1;
|
/* If exists DRI segment, bit 0 to bit 15 of reg123 is set
|
* to restart interval */
|
reg->reg123.sw_pjpeg_rest_freq = s->restart_interval;
|
} else {
|
reg->reg122.sw_sync_marker_e = 0;
|
}
|
|
jpegd_setup_pp(ctx, syntax);
|
|
jpegd_dbg_func("exit\n");
|
return ret;
|
}
|
|
MPP_RET hal_jpegd_vdpu2_init(void *hal, MppHalCfg *cfg)
|
{
|
MPP_RET ret = MPP_OK;
|
JpegdHalCtx *JpegHalCtx = (JpegdHalCtx *)hal;
|
|
mpp_assert(JpegHalCtx);
|
jpegd_dbg_func("enter\n");
|
|
//configure
|
JpegHalCtx->packet_slots = cfg->packet_slots;
|
JpegHalCtx->frame_slots = cfg->frame_slots;
|
JpegHalCtx->dev_type = VPU_CLIENT_VDPU2;
|
|
ret = mpp_dev_init(&JpegHalCtx->dev, JpegHalCtx->dev_type);
|
if (ret) {
|
mpp_err_f("mpp_dev_init failed. ret: %d\n", ret);
|
return ret;
|
}
|
cfg->dev = JpegHalCtx->dev;
|
//init regs
|
JpegdIocRegInfo *info = NULL;
|
info = mpp_calloc(JpegdIocRegInfo, 1);
|
if (info == NULL) {
|
mpp_err_f("allocate jpegd ioctl info failed\n");
|
return MPP_ERR_NOMEM;
|
}
|
memset(info, 0, sizeof(JpegdIocRegInfo));
|
JpegHalCtx->regs = (void *)info;
|
|
//malloc hw buf
|
if (JpegHalCtx->group == NULL) {
|
ret = mpp_buffer_group_get_internal(&JpegHalCtx->group,
|
MPP_BUFFER_TYPE_ION);
|
if (ret) {
|
mpp_err_f("mpp_buffer_group_get failed\n");
|
return ret;
|
}
|
}
|
|
ret = mpp_buffer_get(JpegHalCtx->group, &JpegHalCtx->frame_buf,
|
JPEGD_STREAM_BUFF_SIZE);
|
if (ret) {
|
mpp_err_f("get buffer failed\n");
|
return ret;
|
}
|
|
ret = mpp_buffer_get(JpegHalCtx->group, &JpegHalCtx->pTableBase,
|
JPEGD_BASELINE_TABLE_SIZE);
|
if (ret) {
|
mpp_err_f("get buffer failed\n");
|
return ret;
|
}
|
|
PPInfo *pp_info = &(JpegHalCtx->pp_info);
|
memset(pp_info, 0, sizeof(PPInfo));
|
pp_info->pp_enable = 0;
|
pp_info->pp_in_fmt = PP_IN_FORMAT_YUV420SEMI;
|
pp_info->pp_out_fmt = PP_OUT_FORMAT_YUV420INTERLAVE;
|
jpegd_check_have_pp(JpegHalCtx);
|
|
JpegHalCtx->output_fmt = MPP_FMT_YUV420SP;
|
JpegHalCtx->set_output_fmt_flag = 0;
|
|
//init dbg stuff
|
JpegHalCtx->hal_debug_enable = 0;
|
JpegHalCtx->frame_count = 0;
|
JpegHalCtx->output_yuv_count = 0;
|
|
jpegd_dbg_func("exit\n");
|
return MPP_OK;
|
}
|
|
MPP_RET hal_jpegd_vdpu2_deinit(void *hal)
|
{
|
MPP_RET ret = MPP_OK;
|
JpegdHalCtx *JpegHalCtx = (JpegdHalCtx *)hal;
|
|
jpegd_dbg_func("enter\n");
|
|
if (JpegHalCtx->dev) {
|
mpp_dev_deinit(JpegHalCtx->dev);
|
JpegHalCtx->dev = NULL;
|
}
|
|
if (JpegHalCtx->frame_buf) {
|
ret = mpp_buffer_put(JpegHalCtx->frame_buf);
|
if (ret) {
|
mpp_err_f("put frame buffer failed\n");
|
return ret;
|
}
|
}
|
|
if (JpegHalCtx->pTableBase) {
|
ret = mpp_buffer_put(JpegHalCtx->pTableBase);
|
if (ret) {
|
mpp_err_f("put table buffer failed\n");
|
return ret;
|
}
|
}
|
|
if (JpegHalCtx->group) {
|
ret = mpp_buffer_group_put(JpegHalCtx->group);
|
if (ret) {
|
mpp_err_f("group free buffer failed\n");
|
return ret;
|
}
|
}
|
|
if (JpegHalCtx->regs) {
|
mpp_free(JpegHalCtx->regs);
|
JpegHalCtx->regs = NULL;
|
}
|
|
JpegHalCtx->set_output_fmt_flag = 0;
|
JpegHalCtx->hal_debug_enable = 0;
|
JpegHalCtx->frame_count = 0;
|
JpegHalCtx->output_yuv_count = 0;
|
|
jpegd_dbg_func("exit\n");
|
return MPP_OK;
|
}
|
|
MPP_RET hal_jpegd_vdpu2_gen_regs(void *hal, HalTaskInfo *syn)
|
{
|
jpegd_dbg_func("enter\n");
|
if (NULL == hal || NULL == syn) {
|
mpp_err_f("NULL pointer");
|
return MPP_ERR_NULL_PTR;
|
}
|
|
MPP_RET ret = MPP_OK;
|
JpegdHalCtx *JpegHalCtx = (JpegdHalCtx *)hal;
|
JpegdSyntax *syntax = (JpegdSyntax *)syn->dec.syntax.data;
|
MppBuffer streambuf = NULL;
|
MppBuffer outputBuf = NULL;
|
|
ret = jpeg_image_check_size(syntax->hor_stride, syntax->ver_stride);
|
if (ret)
|
goto RET;
|
|
if (syn->dec.valid) {
|
ret = jpegd_setup_output_fmt(JpegHalCtx, syntax, syn->dec.output);
|
if (ret) {
|
mpp_err_f("setup output format %x failed\n", syntax->output_fmt);
|
goto RET;
|
}
|
|
/* input stream address */
|
mpp_buf_slot_get_prop(JpegHalCtx->packet_slots, syn->dec.input,
|
SLOT_BUFFER, &streambuf);
|
JpegHalCtx->pkt_fd = mpp_buffer_get_fd(streambuf);
|
syntax->pkt_len = jpegd_vdpu_tail_0xFF_patch(streambuf, syntax->pkt_len);
|
|
/* output picture address */
|
mpp_buf_slot_get_prop(JpegHalCtx->frame_slots, syn->dec.output,
|
SLOT_BUFFER, &outputBuf);
|
JpegHalCtx->frame_fd = mpp_buffer_get_fd(outputBuf);
|
|
ret = jpegd_gen_regs(JpegHalCtx, syntax);
|
if (ret) {
|
mpp_err_f("generate registers failed\n");
|
goto RET;
|
}
|
}
|
|
RET:
|
if (ret)
|
syn->dec.valid = 0;
|
|
jpegd_dbg_func("exit\n");
|
return ret;
|
}
|
|
MPP_RET hal_jpegd_vdpu2_start(void *hal, HalTaskInfo *task)
|
{
|
MPP_RET ret = MPP_OK;
|
JpegdHalCtx *JpegHalCtx = (JpegdHalCtx *)hal;
|
RK_U32 *regs = (RK_U32 *)JpegHalCtx->regs;
|
|
jpegd_dbg_func("enter\n");
|
|
do {
|
MppDevRegWrCfg wr_cfg;
|
MppDevRegRdCfg rd_cfg;
|
RK_U32 reg_size = mpp_get_ioctl_version() ?
|
sizeof(((JpegdIocRegInfo *)0)->regs) :
|
sizeof(JpegdIocRegInfo) - EXTRA_INFO_SIZE;
|
|
wr_cfg.reg = regs;
|
wr_cfg.size = reg_size;
|
wr_cfg.offset = 0;
|
|
ret = mpp_dev_ioctl(JpegHalCtx->dev, MPP_DEV_REG_WR, &wr_cfg);
|
if (ret) {
|
mpp_err_f("set register write failed %d\n", ret);
|
break;
|
}
|
|
rd_cfg.reg = regs;
|
rd_cfg.size = reg_size;
|
rd_cfg.offset = 0;
|
|
ret = mpp_dev_ioctl(JpegHalCtx->dev, MPP_DEV_REG_RD, &rd_cfg);
|
if (ret) {
|
mpp_err_f("set register read failed %d\n", ret);
|
break;
|
}
|
|
ret = mpp_dev_ioctl(JpegHalCtx->dev, MPP_DEV_CMD_SEND, NULL);
|
if (ret) {
|
mpp_err_f("send cmd failed %d\n", ret);
|
break;
|
}
|
} while (0);
|
|
(void)task;
|
jpegd_dbg_func("exit\n");
|
return ret;
|
}
|
|
MPP_RET hal_jpegd_vdpu2_wait(void *hal, HalTaskInfo *task)
|
{
|
MPP_RET ret = MPP_OK;
|
JpegdHalCtx *JpegHalCtx = (JpegdHalCtx *)hal;
|
JpegRegSet *reg_out = JpegHalCtx->regs;
|
RK_U32 errinfo = 1;
|
MppFrame tmp = NULL;
|
|
jpegd_dbg_func("enter\n");
|
|
ret = mpp_dev_ioctl(JpegHalCtx->dev, MPP_DEV_CMD_POLL, NULL);
|
if (ret)
|
mpp_err_f("poll cmd failed %d\n", ret);
|
|
if (reg_out->reg55_Interrupt.sw_dec_bus_int) {
|
mpp_err_f("IRQ BUS ERROR!");
|
} else if (reg_out->reg55_Interrupt.sw_dec_error_int) {
|
mpp_err_f("IRQ STREAM ERROR!");
|
} else if (reg_out->reg55_Interrupt.sw_dec_timeout) {
|
mpp_err_f("IRQ TIMEOUT!");
|
} else if (reg_out->reg55_Interrupt.sw_dec_buffer_int) {
|
mpp_err_f("IRQ BUFFER EMPTY!");
|
} else if (reg_out->reg55_Interrupt.sw_dec_irq) {
|
errinfo = 0;
|
jpegd_dbg_result("DECODE SUCCESS!");
|
}
|
|
mpp_buf_slot_get_prop(JpegHalCtx->frame_slots, task->dec.output,
|
SLOT_FRAME_PTR, &tmp);
|
mpp_frame_set_errinfo(tmp, errinfo);
|
|
/* debug information */
|
if (jpegd_debug & JPEGD_DBG_IO) {
|
static FILE *jpg_file;
|
static char name[32];
|
MppBuffer outputBuf = NULL;
|
void *base = NULL;
|
mpp_buf_slot_get_prop(JpegHalCtx->frame_slots, task->dec.output,
|
SLOT_BUFFER, &outputBuf);
|
base = mpp_buffer_get_ptr(outputBuf);
|
|
snprintf(name, sizeof(name) - 1, "/tmp/output%02d.yuv",
|
JpegHalCtx->output_yuv_count);
|
jpg_file = fopen(name, "wb+");
|
if (jpg_file) {
|
JpegdSyntax *syntax = (JpegdSyntax *)task->dec.syntax.data;
|
RK_U32 width = syntax->hor_stride;
|
RK_U32 height = syntax->ver_stride;
|
|
fwrite(base, width * height * 3 / 2, 1, jpg_file);
|
jpegd_dbg_io("frame_%02d output YUV(%d*%d) saving to %s\n",
|
JpegHalCtx->output_yuv_count,
|
width, height, name);
|
fclose(jpg_file);
|
JpegHalCtx->output_yuv_count++;
|
}
|
}
|
|
memset(®_out->reg55_Interrupt, 0, sizeof(RK_U32));
|
|
(void)task;
|
jpegd_dbg_func("exit\n");
|
return ret;
|
}
|
|
MPP_RET hal_jpegd_vdpu2_reset(void *hal)
|
{
|
jpegd_dbg_func("enter\n");
|
MPP_RET ret = MPP_OK;
|
JpegdHalCtx *JpegHalCtx = (JpegdHalCtx *)hal;
|
(void)JpegHalCtx;
|
|
jpegd_dbg_func("exit\n");
|
return ret;
|
}
|
|
MPP_RET hal_jpegd_vdpu2_flush(void *hal)
|
{
|
jpegd_dbg_func("enter\n");
|
MPP_RET ret = MPP_OK;
|
|
(void)hal;
|
return ret;
|
}
|
|
MPP_RET hal_jpegd_vdpu2_control(void *hal, MpiCmd cmd_type,
|
void *param)
|
{
|
jpegd_dbg_func("enter\n");
|
MPP_RET ret = MPP_OK;
|
JpegdHalCtx *JpegHalCtx = (JpegdHalCtx *)hal;
|
if (NULL == JpegHalCtx) {
|
mpp_err_f("NULL pointer");
|
return MPP_ERR_NULL_PTR;
|
}
|
|
switch (cmd_type) {
|
case MPP_DEC_SET_OUTPUT_FORMAT: {
|
JpegHalCtx->output_fmt = *((MppFrameFormat *)param);
|
JpegHalCtx->set_output_fmt_flag = 1;
|
jpegd_dbg_hal("output_format:%d\n", JpegHalCtx->output_fmt);
|
|
if (!MPP_FRAME_FMT_IS_YUV(JpegHalCtx->output_fmt) && !MPP_FRAME_FMT_IS_RGB(JpegHalCtx->output_fmt)) {
|
mpp_err_f("output format %d is invalid.\n", JpegHalCtx->output_fmt);
|
ret = MPP_ERR_VALUE;
|
}
|
} break;
|
default :
|
break;
|
}
|
|
jpegd_dbg_func("exit ret %d\n", ret);
|
return ret;
|
}
|