Files
luban-lite-t3e-pro/packages/artinchip/mpp/ve/encoder/jpeg/jpeg_enc_hal.c
刘可亮 803cac77d5 V1.0.6
2024-09-03 11:16:08 +08:00

245 lines
6.9 KiB
C

/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <qi.xu@artinchip.com>
* Desc: jpeg encoder hal
*/
#include <stdlib.h>
#include "ve_top_register.h"
#include "jpeg_register.h"
#include "mpp_log.h"
#include "ve_buffer.h"
#include "ve.h"
#include "jpeg_enc_ctx.h"
static void config_ve_top_reg(struct jpeg_ctx *s)
{
logd("config mjpeg reg");
write_reg_u32(s->regs_base + VE_CLK_REG, 1);
write_reg_u32(s->regs_base + VE_RST_REG, RST_JPG_PIC_MODULE);
while (1) {
uint32_t val = read_reg_u32(s->regs_base + VE_RST_REG);
if ((val >> 16) == 0)
break;
}
write_reg_u32(s->regs_base + VE_INIT_REG, 1);
write_reg_u32(s->regs_base + VE_IRQ_REG, 1);
write_reg_u32(s->regs_base + VE_JPG_EN_REG, 1);
}
static void config_header_info(struct jpeg_ctx *s)
{
uint32_t val = 0;
write_reg_u32(s->regs_base + JPG_START_POS_REG, 0);
write_reg_u32(s->regs_base + JPG_CTRL_REG, (3 << 12) | (3 << 8) | (3 << 3));
int width_align = (s->width + 15) & (~15);
val = s->height | (width_align << 16);
write_reg_u32(s->regs_base + JPG_SIZE_REG, val);
int total_blks = s->h_count[0] * s->v_count[0] +
s->h_count[1] * s->v_count[1] + s->h_count[2] * s->v_count[2];
val = s->v_count[2] | (s->h_count[2] << 2) |
(s->v_count[1] << 4) | (s->h_count[1] << 6) |
(s->v_count[0] << 8) | (s->h_count[0] << 10) |
(s->comp_num << 12) | (total_blks << 16);
write_reg_u32(s->regs_base + JPG_MCU_INFO_REG, val);
val = 12 / total_blks;
write_reg_u32(s->regs_base + JPG_HANDLE_NUM_REG, val);
write_reg_u32(s->regs_base + JPG_UV_REG, s->uv_interleave);
write_reg_u32(s->regs_base + JPG_FRAME_IDX_REG, 0);
write_reg_u32(s->regs_base + JPG_RST_INTERVAL_REG, 0);
write_reg_u32(s->regs_base + JPG_INTRRUPT_EN_REG, 0);
}
static void config_picture_info_register(struct jpeg_ctx *s)
{
uint32_t val = 0;
uint32_t color_mode = 0;
if (s->cur_frame->buf.format == MPP_FMT_YUV420P || s->cur_frame->buf.format == MPP_FMT_NV12) {
color_mode = 0;
} else if (s->cur_frame->buf.format == MPP_FMT_YUV444P) {
color_mode = 3;
} else if (s->cur_frame->buf.format == MPP_FMT_YUV400) {
color_mode = 4;
} else if (s->cur_frame->buf.format == MPP_FMT_YUV422P) {
color_mode = 1;
} else {
loge("not supprt this format(%d)", s->cur_frame->buf.format);
}
val = s->y_stride | (s->uv_interleave << 16) | (color_mode << 17);
write_reg_u32(s->regs_base + PIC_INFO_START_REG, val);
val = s->height | (s->y_stride << 16);
write_reg_u32(s->regs_base + PIC_INFO_START_REG + 4, val);
write_reg_u32(s->regs_base + PIC_INFO_START_REG + 8, s->phy_addr[0]);
write_reg_u32(s->regs_base + PIC_INFO_START_REG + 12, s->phy_addr[1]);
write_reg_u32(s->regs_base + PIC_INFO_START_REG + 16, s->phy_addr[2]);
}
/*
quant matrix store in zigzag order
*/
static void ve_config_quant_matrix(struct jpeg_ctx *s)
{
int i, j;
uint32_t val;
unsigned int* quant_tab[3] = { s->luma_quant_table, s->chroma_quant_table, s->chroma_quant_table };
for (int comp = 0; comp < 3; comp++) {
write_reg_u32(s->regs_base + JPG_QMAT_INFO_REG, (comp << 6) | 3);
write_reg_u32(s->regs_base + JPG_QMAT_ADDR_REG, comp << 6);
for (i = 0; i < 64; i++) {
j = zigzag_direct[i];
// qmatrix should be (1<<19)/q
val = (1 << QUANT_FIXED_POINT_BITS) / quant_tab[comp][j];
write_reg_u32(s->regs_base + JPG_QMAT_VAL_REG, val);
}
}
write_reg_u32(s->regs_base + JPG_QMAT_INFO_REG, 0);
}
/*
huffman table include 4 tables: DC_Luma\DC_Chroma\AC_LUMA\AC_Chroma
internal SRAM in VE is 544x20bit
20bit data: [19:16]: code_length-1; [15:0]: code word
address of the 4 tables:
Luma_AC: 0-255
Chroma_AC: 256-511
Luma_DC: 512-528
Chroma_DC: 528-544
*/
static void ve_config_huffman_table(struct jpeg_ctx *s)
{
int i;
uint32_t val;
write_reg_u32(s->regs_base + JPG_HUFF_INFO_REG, 3);
write_reg_u32(s->regs_base + JPG_HUFF_ADDR_REG, 0);
// luma ac
for (i = 0; i < 256; i++) {
val = ((s->huff_size_ac_luminance[i] - 1) << 16) | s->huff_code_ac_luminance[i];
write_reg_u32(s->regs_base + JPG_HUFF_VAL_REG, val);
}
// chroma ac
for (i = 0; i < 256; i++) {
val = ((s->huff_size_ac_chrominance[i] - 1) << 16) | s->huff_code_ac_chrominance[i];
write_reg_u32(s->regs_base + JPG_HUFF_VAL_REG, val);
}
// luma dc
for (i = 0; i < 12; i++) {
val = ((s->huff_size_dc_luminance[i] - 1) << 16) | s->huff_code_dc_luminance[i];
write_reg_u32(s->regs_base + JPG_HUFF_VAL_REG, val);
}
// chroma dc
write_reg_u32(s->regs_base + JPG_HUFF_INFO_REG, 3);
write_reg_u32(s->regs_base + JPG_HUFF_ADDR_REG, 528);
for (i = 0; i < 12; i++) {
val = ((s->huff_size_dc_chrominance[i] - 1) << 16) | s->huff_code_dc_chrominance[i];
write_reg_u32(s->regs_base + JPG_HUFF_VAL_REG, val);
}
// clear
write_reg_u32(s->regs_base + JPG_HUFF_INFO_REG, 0);
}
static void ve_config_stream_register(struct jpeg_ctx *s)
{
int head_offset = s->header_offset;
int stream_num = s->stream_num;
// end addr of output stream
unsigned int align_256_addr = s->bitstream_phy_addr + stream_num * 256;
write_reg_u32(s->regs_base + JPG_STREAM_END_ADDR_REG, align_256_addr);
// base addr of output stream
write_reg_u32(s->regs_base + JPG_BAS_ADDR_REG, s->bitstream_phy_addr + head_offset);
// start addr of output stream
write_reg_u32(s->regs_base + JPG_STREAM_START_ADDR_REG, s->bitstream_phy_addr + head_offset);
write_reg_u32(s->regs_base + JPG_STREAM_WRITE_PTR_REG, s->bitstream_phy_addr + head_offset);
write_reg_u32(s->regs_base + JPG_STREAM_READ_PTR_REG, s->bitstream_phy_addr + head_offset);
// current stream pos
write_reg_u32(s->regs_base + JPG_CUR_POS_REG, 0);
write_reg_u32(s->regs_base + JPG_DATA_CNT_REG, 64);
write_reg_u32(s->regs_base + JPG_MEM_EA_REG, 0x7f);
write_reg_u32(s->regs_base + JPG_MEM_IA_REG, 0x40);
write_reg_u32(s->regs_base + JPG_MEM_HA_REG, 0x40);
write_reg_u32(s->regs_base + JPG_BITREQ_EN_REG, 1);
}
int jpeg_hw_encode(struct jpeg_ctx *s)
{
int ret = 0;
uint32_t status;
ve_get_client();
// 1. config ve top
config_ve_top_reg(s);
// 2. config jpeg header
config_header_info(s);
// 3. config picture info
config_picture_info_register(s);
// 4. config quant/huffman table
ve_config_quant_matrix(s);
ve_config_huffman_table(s);
// 5. config bitstream
ve_config_stream_register(s);
write_reg_u32(s->regs_base + JPG_STATUS_REG, 0xf);
write_reg_u32(s->regs_base + JPG_START_REG, 1);
if (ve_wait((unsigned int*)&status) < 0) {
loge("ve wait irq timeout");
logi("read JPG_STATUS_REG %x", read_reg_u32(s->regs_base + JPG_STATUS_REG));
ve_reset();
ret = -1;
goto out;
}
if(status > 1) {
loge("status error");
ve_reset();
ret = -1;
goto out;
}
uint32_t cycles = 0;
cycles = read_reg_u32(s->regs_base + JPG_CYCLES_REG);
uint32_t end_addr = 0;
end_addr = read_reg_u32(s->regs_base + JPG_STREAM_WRITE_PTR_REG);
s->encode_data_len = end_addr - s->bitstream_phy_addr;
logi("cycles: %"PRIu32", data len: %d", cycles, s->encode_data_len);
// disable jpeg module
write_reg_u32(s->regs_base + VE_JPG_EN_REG, 0);
out:
ve_put_client();
return ret;
}