blob: 44163785684ceb1d948431129406fe1611460104 [file] [log] [blame]
/*
* drivers/amlogic/amports/jpegenc.c
*
* Copyright (C) 2015 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#define LOG_LINE()
//pr_err("[%s:%d]\n", __FUNCTION__, __LINE__);
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/compat.h>
#include <linux/ktime.h>
#include <linux/timekeeping.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/ctype.h>
#include <linux/amlogic/media/frame_sync/ptsserv.h>
#include <linux/amlogic/media/utils/amstream.h>
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#include <linux/amlogic/media/utils/vdec_reg.h>
#include "../../../frame_provider/decoder/utils/vdec_canvas_utils.h"
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/dma-contiguous.h>
#include "../../../common/chips/decoder_cpu_ver_info.h"
#include "../../../frame_provider/decoder/utils/amvdec.h"
#include "../../../stream_input/amports/amports_priv.h"
#include "../../../frame_provider/decoder/utils/firmware.h"
#include "../../../frame_provider/decoder/utils/vdec.h"
#include "../../../frame_provider/decoder/utils/vdec_power_ctrl.h"
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include "jpegenc.h"
#include <linux/of_reserved_mem.h>
#include <linux/amlogic/power_ctrl.h>
#include <dt-bindings/power/t7-pd.h>
#include <linux/amlogic/power_domain.h>
#include <linux/clk.h>
#define HCODEC_MFDIN_REG17 0x101f
#define HCODEC_MFDIN_REG18 0x1020
#define HCODEC_MFDIN_REG19 0x1021
#ifdef CONFIG_AM_ENCODER
#include "encoder.h"
#endif
#define JPEGENC_CANVAS_INDEX 0x64
#define JPEGENC_CANVAS_MAX_INDEX 0x67
#define ENC_CANVAS_OFFSET JPEGENC_CANVAS_INDEX
#define LOG_ALL 0
#define LOG_INFO 1
#define LOG_DEBUG 2
#define LOG_ERROR 3
#define jenc_pr(level, x...) \
do { \
if (level >= jpegenc_print_level) \
printk(x); \
} while (0)
#define DRIVER_NAME "jpegenc"
#define CLASS_NAME "jpegenc"
#define DEVICE_NAME "jpegenc"
/* #define EXTEAN_QUANT_TABLE */
/*######### DEBUG-BRINGUP#########*/
static u32 manual_clock;
static u32 manual_irq_num = 2;
static u32 manual_interrupt = 0;
/*################################*/
static s32 jpegenc_device_major;
static struct device *jpegenc_dev;
static u32 jpegenc_print_level = LOG_ERROR;
static s32 reg_offset;
static u32 use_dma_io = 1;
static u32 use_quality=1;
static u32 legacy_load=0;
static u32 dumpmem_line = 0;
static u32 pointer = 0;
static u32 clock_level = 1;
static u16 gQuantTable[2][DCTSIZE2];
#ifdef EXTEAN_QUANT_TABLE
static u16 *gExternalQuantTablePtr;
static bool external_quant_table_available;
#endif
static u32 simulation_enable;
static u32 g_block_mode;
static u32 g_canv0_stride;
static u32 g_canv1_stride;
static u32 g_canv2_stride;
static u32 g_canvas_height;
static u32 jpeg_in_full_hcodec;
static u32 mfdin_ambus_canv_conv;
#define MHz (1000000)
//static DEFINE_SPINLOCK(lock);
#define JPEGENC_BUFFER_LEVEL_VGA 0
#define JPEGENC_BUFFER_LEVEL_2M 1
#define JPEGENC_BUFFER_LEVEL_3M 2
#define JPEGENC_BUFFER_LEVEL_5M 3
#define JPEGENC_BUFFER_LEVEL_8M 4
#define JPEGENC_BUFFER_LEVEL_13M 5
#define JPEGENC_BUFFER_LEVEL_HD 6
const s8 *glevel_str[] = {
"VGA",
"2M",
"3M",
"5M",
"8M",
"13M",
"HD",
};
const struct Jpegenc_BuffInfo_s jpegenc_buffspec[] = {
{
.lev_id = JPEGENC_BUFFER_LEVEL_VGA,
.max_width = 640,
.max_height = 640,
.min_buffsize = 0x330000,
.input = {
.buf_start = 0,
.buf_size = 0x12c000,
},
.assit = {
.buf_start = 0x12d000,
.buf_size = 0x2000,
},
.bitstream = {
.buf_start = 0x130000,
.buf_size = 0x200000,
}
}, {
.lev_id = JPEGENC_BUFFER_LEVEL_2M,
.max_width = 1600,
.max_height = 1600,
.min_buffsize = 0x960000,
.input = {
.buf_start = 0,
.buf_size = 0x753000,
},
.assit = {
.buf_start = 0x754000,
.buf_size = 0x2000,
},
.bitstream = {
.buf_start = 0x760000,
.buf_size = 0x200000,
}
}, {
.lev_id = JPEGENC_BUFFER_LEVEL_3M,
.max_width = 2048,
.max_height = 2048,
.min_buffsize = 0xe10000,
.input = {
.buf_start = 0,
.buf_size = 0xc00000,
},
.assit = {
.buf_start = 0xc01000,
.buf_size = 0x2000,
},
.bitstream = {
.buf_start = 0xc10000,
.buf_size = 0x200000,
}
}, {
.lev_id = JPEGENC_BUFFER_LEVEL_5M,
.max_width = 2624,
.max_height = 2624,
.min_buffsize = 0x1800000,
.input = {
.buf_start = 0,
.buf_size = 0x13B3000,
},
.assit = {
.buf_start = 0x13B4000,
.buf_size = 0x2000,
},
.bitstream = {
.buf_start = 0x1400000,
.buf_size = 0x400000,
}
}, {
.lev_id = JPEGENC_BUFFER_LEVEL_8M,
.max_width = 3264,
.max_height = 3264,
.min_buffsize = 0x2300000,
.input = {
.buf_start = 0,
.buf_size = 0x1e7b000,
},
.assit = {
.buf_start = 0x1e7c000,
.buf_size = 0x2000,
},
.bitstream = {
.buf_start = 0x1f00000,
.buf_size = 0x400000,
}
}, {
.lev_id = JPEGENC_BUFFER_LEVEL_13M,
.max_width = 8192,
.max_height = 8192,
.min_buffsize = 0xc400000,
.input = {
.buf_start = 0,
.buf_size = 0xc000000,
},
.assit = {
.buf_start = 0xc001000,
.buf_size = 0x2000,
},
.bitstream = {
.buf_start = 0xc010000,
.buf_size = 0x3f0000,
}
}, {
.lev_id = JPEGENC_BUFFER_LEVEL_HD,
.max_width = 8192,
.max_height = 8192,
.min_buffsize = 0xc400000,
.input = {
.buf_start = 0,
.buf_size = 0xc000000,
},
.assit = {
.buf_start = 0xc001000,
.buf_size = 0x2000,
},
.bitstream = {
.buf_start = 0xc010000,
.buf_size = 0x3f0000,
}
}
};
const char *jpegenc_ucode[] = {
"jpegenc_mc",
};
static struct jpegenc_manager_s gJpegenc;
static const u16 jpeg_quant[7][DCTSIZE2] = {
{ /* jpeg_quant[0][] : Luma, Canon */
0x06, 0x06, 0x08, 0x0A, 0x0A, 0x10, 0x15, 0x19,
0x06, 0x0A, 0x0A, 0x0E, 0x12, 0x1F, 0x29, 0x29,
0x08, 0x0A, 0x0E, 0x12, 0x21, 0x29, 0x29, 0x29,
0x0A, 0x0E, 0x12, 0x14, 0x23, 0x29, 0x29, 0x29,
0x0A, 0x12, 0x21, 0x23, 0x27, 0x29, 0x29, 0x29,
0x10, 0x1F, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
0x15, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
0x19, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29
},
{ /* jpeg_quant[1][] : Chroma, Canon */
0x0A, 0x0E, 0x10, 0x14, 0x15, 0x1D, 0x2B, 0x35,
0x0E, 0x12, 0x14, 0x1D, 0x25, 0x3E, 0x54, 0x54,
0x10, 0x14, 0x19, 0x25, 0x40, 0x54, 0x54, 0x54,
0x14, 0x1D, 0x25, 0x27, 0x48, 0x54, 0x54, 0x54,
0x15, 0x25, 0x40, 0x48, 0x4E, 0x54, 0x54, 0x54,
0x1D, 0x3E, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
0x2B, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
0x35, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54
},
{ /* jpeg_quant[2][] : Luma, spec example Table K.1 */
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
},
{ /* jpeg_quant[3][] : Chroma, spec example Table K.2 */
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
},
{ /* jpeg_quant[4][] : Luma, spec example Table K.1,
modified to create long ZRL */
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 16
},
{ /* jpeg_quant[5][] : Chroma, spec example Table K.2,
modified to create long ZRL */
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 17
},
{ /* jpeg_quant[6][] : no compression */
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1
}
}; /* jpeg_quant */
static const u8 jpeg_huffman_dc[2][16 + 12] = {
{ /* jpeg_huffman_dc[0][] */
0x00, /* number of code length=1 */
0x01,
0x05,
0x01,
0x01,
0x01,
0x01,
0x01,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00, /* number of code length=16 */
/* Entry index for code with
minimum code length (=2 in this case) */
0x00,
0x01, 0x02, 0x03, 0x04, 0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B
},
{ /* jpeg_huffman_dc[1][] */
0x00, /* number of code length=1 */
0x03,
0x01,
0x01,
0x01,
0x01,
0x01,
0x01,
0x01,
0x01,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00, /* number of code length=16 */
/* Entry index for code with
minimum code length (=2 in this case) */
0x00, 0x01, 0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
0x0B
}
}; /* jpeg_huffman_dc */
static const u8 jpeg_huffman_ac[2][16 + 162] = {
{ /* jpeg_huffman_ac[0][] */
0x00, /* number of code length=1 */
0x02,
0x01,
0x03,
0x03,
0x02,
0x04,
0x03,
0x05,
0x05,
0x04,
0x04,
0x00,
0x00,
0x01,
0x7D, /* number of code length=16 */
/* Entry index for code with
minimum code length (=2 in this case) */
0x01, 0x02,
0x03,
0x00, 0x04, 0x11,
0x05, 0x12, 0x21,
0x31, 0x41,
0x06, 0x13, 0x51, 0x61,
0x07, 0x22, 0x71,
0x14, 0x32, 0x81, 0x91, 0xA1,
0x08, 0x23, 0x42, 0xB1, 0xC1,
0x15, 0x52, 0xD1, 0xF0,
0x24, 0x33, 0x62, 0x72,
0x82,
0x09, 0x0A, 0x16, 0x17, 0x18, 0x19,
0x1A, 0x25, 0x26, 0x27, 0x28, 0x29,
0x2A, 0x34, 0x35, 0x36,
0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
0x53, 0x54, 0x55, 0x56,
0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
0x73, 0x74, 0x75, 0x76,
0x77, 0x78, 0x79, 0x7A, 0x83, 0x84,
0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
0x92, 0x93, 0x94, 0x95,
0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2,
0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
0xA9, 0xAA, 0xB2, 0xB3,
0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6,
0xC7, 0xC8, 0xC9, 0xCA,
0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3,
0xE4, 0xE5, 0xE6, 0xE7,
0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3,
0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9,
0xFA
},
{ /* jpeg_huffman_ac[1][] */
0x00, /* number of code length=1 */
0x02,
0x01,
0x02,
0x04,
0x04,
0x03,
0x04,
0x07,
0x05,
0x04,
0x04,
0x00,
0x01,
0x02,
0x77, /* number of code length=16 */
/* Entry index for code with
minimum code length (=2 in this case) */
0x00, 0x01,
0x02,
0x03, 0x11,
0x04, 0x05, 0x21, 0x31,
0x06, 0x12, 0x41, 0x51,
0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81,
0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1,
0x09, 0x23, 0x33, 0x52, 0xF0,
0x15, 0x62, 0x72, 0xD1,
0x0A, 0x16, 0x24, 0x34,
0xE1,
0x25, 0xF1,
0x17, 0x18, 0x19, 0x1A, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x43,
0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4A, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5A, 0x63,
0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7A, 0x82,
0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
0x89, 0x8A, 0x92, 0x93, 0x94, 0x95,
0x96, 0x97, 0x98, 0x99,
0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3,
0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4,
0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
0xD2, 0xD3, 0xD4, 0xD5,
0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2,
0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,
0xE9, 0xEA, 0xF2, 0xF3,
0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
}
}; /* jpeg_huffman_ac */
static u64 time_cnt = 0;
static int enc_dma_buf_get_phys(struct enc_dma_cfg *cfg, unsigned long *addr);
static void enc_dma_buf_unmap(struct enc_dma_cfg *cfg);
static void dump_requst(struct jpegenc_request_s *request) {
jenc_pr(LOG_DEBUG, "jpegenc: dump request start\n");
jenc_pr(LOG_DEBUG, "src=%u\n", request->src);
jenc_pr(LOG_DEBUG, "encoder_width=%u\n", request->encoder_width);
jenc_pr(LOG_DEBUG, "encoder_height=%u\n", request->encoder_height);
jenc_pr(LOG_DEBUG, "framesize=%u\n", request->framesize);
jenc_pr(LOG_DEBUG, "jpeg_quality=%u\n", request->jpeg_quality);
jenc_pr(LOG_DEBUG, "QuantTable_id=%u\n", request->QuantTable_id);
jenc_pr(LOG_DEBUG, "flush_flag=%u\n", request->flush_flag);
jenc_pr(LOG_DEBUG, "block_mode=%u\n", request->block_mode);
jenc_pr(LOG_DEBUG, "type=%d\n", request->type);
jenc_pr(LOG_DEBUG, "input_fmt=%d\n", request->input_fmt);
jenc_pr(LOG_DEBUG, "output_fmt=%d\n", request->output_fmt);
jenc_pr(LOG_DEBUG, "y_off=%u\n", request->y_off);
jenc_pr(LOG_DEBUG, "u_off=%u\n", request->u_off);
jenc_pr(LOG_DEBUG, "v_off=%u\n", request->v_off);
jenc_pr(LOG_DEBUG, "y_stride=%u\n", request->y_stride);
jenc_pr(LOG_DEBUG, "u_stride=%u\n", request->u_stride);
jenc_pr(LOG_DEBUG, "v_stride=%u\n", request->v_stride);
jenc_pr(LOG_DEBUG, "h_stride=%u\n", request->h_stride);
jenc_pr(LOG_DEBUG, "jpegenc: dump request end\n");
}
static void canvas_config_proxy(u32 index, ulong addr, u32 width, u32 height,
u32 wrap, u32 blkmode) {
unsigned long datah_temp, datal_temp;
if (!is_support_vdec_canvas()) {
canvas_config(index, addr, width, height, wrap, blkmode);
} else {
#if 1
ulong start_addr = addr >> 3;
u32 cav_width = (((width + 31)>>5)<<2);
u32 cav_height = height;
u32 x_wrap_en = 0;
u32 y_wrap_en = 0;
u32 blk_mode = 0;//blkmode;
u32 cav_endian = 0;
datal_temp = (start_addr & 0x1fffffff) |
((cav_width & 0x7 ) << 29 );
datah_temp = ((cav_width >> 3) & 0x1ff) |
((cav_height & 0x1fff) <<9 ) |
((x_wrap_en & 1) << 22 ) |
((y_wrap_en & 1) << 23) |
((blk_mode & 0x3) << 24) |
( cav_endian << 26);
#else
u32 endian = 0;
u32 addr_bits_l = ((((addr + 7) >> 3) & CANVAS_ADDR_LMASK) << CAV_WADDR_LBIT);
u32 width_l = ((((width + 7) >> 3) & CANVAS_WIDTH_LMASK) << CAV_WIDTH_LBIT);
u32 width_h = ((((width + 7) >> 3) >> CANVAS_WIDTH_LWID) << CAV_WIDTH_HBIT);
u32 height_h = (height & CANVAS_HEIGHT_MASK) << CAV_HEIGHT_HBIT;
u32 blkmod_h = (blkmode & CANVAS_BLKMODE_MASK) << CAV_BLKMODE_HBIT;
u32 switch_bits_ctl = (endian & 0xf) << CAV_ENDIAN_HBIT;
u32 wrap_h = (0 << 23);
datal_temp = addr_bits_l | width_l;
datah_temp = width_h | height_h | wrap_h | blkmod_h | switch_bits_ctl;
#endif
/*
if (core == VDEC_1) {
WRITE_VREG(MDEC_CAV_CFG0, 0); //[0]canv_mode, by default is non-canv-mode
WRITE_VREG(MDEC_CAV_LUT_DATAL, datal_temp);
WRITE_VREG(MDEC_CAV_LUT_DATAH, datah_temp);
WRITE_VREG(MDEC_CAV_LUT_ADDR, index);
} else if (core == VDEC_HCODEC) */ {
WRITE_HREG(HCODEC_MDEC_CAV_CFG0, 0); //[0]canv_mode, by default is non-canv-mode
WRITE_HREG(HCODEC_MDEC_CAV_LUT_DATAL, datal_temp);
WRITE_HREG(HCODEC_MDEC_CAV_LUT_DATAH, datah_temp);
WRITE_HREG(HCODEC_MDEC_CAV_LUT_ADDR, index);
}
/*
cav_lut_info_store(index, addr, width, height, wrap, blkmode, 0);
if (vdec_get_debug() & 0x40000000) {
pr_info("(%s %2d) addr: %lx, width: %d, height: %d, blkm: %d, endian: %d\n",
__func__, index, addr, width, height, blkmode, 0);
pr_info("data(h,l): 0x%8lx, 0x%8lx\n", datah_temp, datal_temp);
}
*/
}
}
static u64 jpegenc_time_count_start(void)
{
//struct timeval tv;
//do_gettimeofday(&tv);
//efi_gettimeofday(&tv);
//return div64_u64(timeval_to_ns(&tv), 1000);
return 0;
}
static void jpegenc_time_count_end(u64 *time)
{
jenc_pr(LOG_INFO, "the encoder takes time %lld us.\n",
jpegenc_time_count_start() - *time);
*time = 0;
}
static int is_oversize(int w, int h, int max)
{
if (w < 0 || h < 0)
return true;
if (h != 0 && (w > max / h))
return true;
return false;
}
struct jpeg_enc_clks {
struct clk *dos_clk;
struct clk *dos_apb_clk;
struct clk *jpeg_enc_clk;
};
static struct jpeg_enc_clks g_jpeg_enc_clks;
static void jpeg_enc_clk_put(struct device *dev, struct jpeg_enc_clks *clks)
{
if (!(clks->jpeg_enc_clk == NULL || IS_ERR(clks->jpeg_enc_clk)))
devm_clk_put(dev, clks->jpeg_enc_clk);
if (!(clks->dos_apb_clk == NULL || IS_ERR(clks->dos_apb_clk)))
devm_clk_put(dev, clks->dos_apb_clk);
if (!(clks->dos_clk == NULL || IS_ERR(clks->dos_clk)))
devm_clk_put(dev, clks->dos_clk);
}
static int jpeg_enc_clk_get(struct device *dev, struct jpeg_enc_clks *clks)
{
//int ret = 0;
clks->dos_clk = devm_clk_get(dev, "clk_dos");
if (IS_ERR(clks->dos_clk)) {
jenc_pr(LOG_ERROR, "cannot get clk_dos clock\n");
clks->dos_clk = NULL;
//ret = -ENOENT;
//goto err;
} else
pr_err("jpeg_enc_clk_get: get clk_dos OK\n");
clks->dos_apb_clk = devm_clk_get(dev, "clk_apb_dos");
if (IS_ERR(clks->dos_apb_clk)) {
jenc_pr(LOG_ERROR, "cannot get clk_apb_dos clock\n");
clks->dos_apb_clk = NULL;
//ret = -ENOENT;
//goto err;
} else
pr_err("jpeg_enc_clk_get: get clk_apb_dos OK\n");
clks->jpeg_enc_clk = devm_clk_get(dev, "clk_jpeg_enc");
if (IS_ERR(clks->jpeg_enc_clk)) {
jenc_pr(LOG_ERROR, "cannot get clk_jpeg_enc clock\n");
clks->jpeg_enc_clk = NULL;
//ret = -ENOENT;
//goto err;
} else
pr_err("jpeg_enc_clk_get: get clk_jpeg_enc OK\n");
return 0;
//err:
// jpeg_enc_clk_put(dev, clks);
// return ret;
}
static void jpeg_enc_clk_enable(struct jpeg_enc_clks *clks, u32 frq)
{
if (clks->dos_clk != NULL) {
clk_set_rate(clks->dos_clk, 400 * MHz);
clk_prepare_enable(clks->dos_clk);
pr_err("dos clk: %ld\n", clk_get_rate(clks->dos_clk));
}
if (clks->dos_apb_clk != NULL) {
clk_set_rate(clks->dos_apb_clk, 400 * MHz);
clk_prepare_enable(clks->dos_apb_clk);
pr_err("apb clk: %ld\n", clk_get_rate(clks->dos_apb_clk));
}
if (clks->jpeg_enc_clk != NULL) {
clk_set_rate(clks->jpeg_enc_clk, 666666666);
clk_prepare_enable(clks->jpeg_enc_clk);
pr_err("jpegenc clk: %ld\n", clk_get_rate(clks->jpeg_enc_clk));
}
/*
clk_prepare_enable(clks->dos_clk);
clk_prepare_enable(clks->dos_apb_clk);
clk_prepare_enable(clks->jpeg_enc_clk);
*/
pr_err("dos: %ld, dos_apb: %ld, jpeg clk: %ld\n",
clk_get_rate(clks->dos_clk),
clk_get_rate(clks->dos_apb_clk),
clk_get_rate(clks->jpeg_enc_clk));
}
static void jpeg_enc_clk_disable(struct jpeg_enc_clks *clks)
{
pr_err("set jpeg_enc_clk rate to 0\n");
clk_set_rate(clks->jpeg_enc_clk, 0);
clk_disable_unprepare(clks->jpeg_enc_clk);
//clk_disable_unprepare(clks->dos_apb_clk);
//clk_disable_unprepare(clks->dos_clk);
}
static void dma_flush(u32 buf_start, u32 buf_size);
static s32 zigzag(s32 i)
{
s32 zigzag_i;
switch (i) {
case 0:
zigzag_i = 0;
break;
case 1:
zigzag_i = 1;
break;
case 2:
zigzag_i = 8;
break;
case 3:
zigzag_i = 16;
break;
case 4:
zigzag_i = 9;
break;
case 5:
zigzag_i = 2;
break;
case 6:
zigzag_i = 3;
break;
case 7:
zigzag_i = 10;
break;
case 8:
zigzag_i = 17;
break;
case 9:
zigzag_i = 24;
break;
case 10:
zigzag_i = 32;
break;
case 11:
zigzag_i = 25;
break;
case 12:
zigzag_i = 18;
break;
case 13:
zigzag_i = 11;
break;
case 14:
zigzag_i = 4;
break;
case 15:
zigzag_i = 5;
break;
case 16:
zigzag_i = 12;
break;
case 17:
zigzag_i = 19;
break;
case 18:
zigzag_i = 26;
break;
case 19:
zigzag_i = 33;
break;
case 20:
zigzag_i = 40;
break;
case 21:
zigzag_i = 48;
break;
case 22:
zigzag_i = 41;
break;
case 23:
zigzag_i = 34;
break;
case 24:
zigzag_i = 27;
break;
case 25:
zigzag_i = 20;
break;
case 26:
zigzag_i = 13;
break;
case 27:
zigzag_i = 6;
break;
case 28:
zigzag_i = 7;
break;
case 29:
zigzag_i = 14;
break;
case 30:
zigzag_i = 21;
break;
case 31:
zigzag_i = 28;
break;
case 32:
zigzag_i = 35;
break;
case 33:
zigzag_i = 42;
break;
case 34:
zigzag_i = 49;
break;
case 35:
zigzag_i = 56;
break;
case 36:
zigzag_i = 57;
break;
case 37:
zigzag_i = 50;
break;
case 38:
zigzag_i = 43;
break;
case 39:
zigzag_i = 36;
break;
case 40:
zigzag_i = 29;
break;
case 41:
zigzag_i = 22;
break;
case 42:
zigzag_i = 15;
break;
case 43:
zigzag_i = 23;
break;
case 44:
zigzag_i = 30;
break;
case 45:
zigzag_i = 37;
break;
case 46:
zigzag_i = 44;
break;
case 47:
zigzag_i = 51;
break;
case 48:
zigzag_i = 58;
break;
case 49:
zigzag_i = 59;
break;
case 50:
zigzag_i = 52;
break;
case 51:
zigzag_i = 45;
break;
case 52:
zigzag_i = 38;
break;
case 53:
zigzag_i = 31;
break;
case 54:
zigzag_i = 39;
break;
case 55:
zigzag_i = 46;
break;
case 56:
zigzag_i = 53;
break;
case 57:
zigzag_i = 60;
break;
case 58:
zigzag_i = 61;
break;
case 59:
zigzag_i = 54;
break;
case 60:
zigzag_i = 47;
break;
case 61:
zigzag_i = 55;
break;
case 62:
zigzag_i = 62;
break;
default:
zigzag_i = 63;
break;
}
return zigzag_i;
}
/* Perform convertion from Q to 1/Q */
u32 reciprocal(u32 q)
{
u32 q_recip;
/* 65535 * (1/q) */
switch (q) {
case 0:
q_recip = 0;
break;
case 1:
q_recip = 65535;
break;
case 2:
q_recip = 32768;
break;
case 3:
q_recip = 21845;
break;
case 4:
q_recip = 16384;
break;
case 5:
q_recip = 13107;
break;
case 6:
q_recip = 10923;
break;
case 7:
q_recip = 9362;
break;
case 8:
q_recip = 8192;
break;
case 9:
q_recip = 7282;
break;
case 10:
q_recip = 6554;
break;
case 11:
q_recip = 5958;
break;
case 12:
q_recip = 5461;
break;
case 13:
q_recip = 5041;
break;
case 14:
q_recip = 4681;
break;
case 15:
q_recip = 4369;
break;
case 16:
q_recip = 4096;
break;
case 17:
q_recip = 3855;
break;
case 18:
q_recip = 3641;
break;
case 19:
q_recip = 3449;
break;
case 20:
q_recip = 3277;
break;
case 21:
q_recip = 3121;
break;
case 22:
q_recip = 2979;
break;
case 23:
q_recip = 2849;
break;
case 24:
q_recip = 2731;
break;
case 25:
q_recip = 2621;
break;
case 26:
q_recip = 2521;
break;
case 27:
q_recip = 2427;
break;
case 28:
q_recip = 2341;
break;
case 29:
q_recip = 2260;
break;
case 30:
q_recip = 2185;
break;
case 31:
q_recip = 2114;
break;
case 32:
q_recip = 2048;
break;
case 33:
q_recip = 1986;
break;
case 34:
q_recip = 1928;
break;
case 35:
q_recip = 1872;
break;
case 36:
q_recip = 1820;
break;
case 37:
q_recip = 1771;
break;
case 38:
q_recip = 1725;
break;
case 39:
q_recip = 1680;
break;
case 40:
q_recip = 1638;
break;
case 41:
q_recip = 1598;
break;
case 42:
q_recip = 1560;
break;
case 43:
q_recip = 1524;
break;
case 44:
q_recip = 1489;
break;
case 45:
q_recip = 1456;
break;
case 46:
q_recip = 1425;
break;
case 47:
q_recip = 1394;
break;
case 48:
q_recip = 1365;
break;
case 49:
q_recip = 1337;
break;
case 50:
q_recip = 1311;
break;
case 51:
q_recip = 1285;
break;
case 52:
q_recip = 1260;
break;
case 53:
q_recip = 1237;
break;
case 54:
q_recip = 1214;
break;
case 55:
q_recip = 1192;
break;
case 56:
q_recip = 1170;
break;
case 57:
q_recip = 1150;
break;
case 58:
q_recip = 1130;
break;
case 59:
q_recip = 1111;
break;
case 60:
q_recip = 1092;
break;
case 61:
q_recip = 1074;
break;
case 62:
q_recip = 1057;
break;
case 63:
q_recip = 1040;
break;
case 64:
q_recip = 1024;
break;
case 65:
q_recip = 1008;
break;
case 66:
q_recip = 993;
break;
case 67:
q_recip = 978;
break;
case 68:
q_recip = 964;
break;
case 69:
q_recip = 950;
break;
case 70:
q_recip = 936;
break;
case 71:
q_recip = 923;
break;
case 72:
q_recip = 910;
break;
case 73:
q_recip = 898;
break;
case 74:
q_recip = 886;
break;
case 75:
q_recip = 874;
break;
case 76:
q_recip = 862;
break;
case 77:
q_recip = 851;
break;
case 78:
q_recip = 840;
break;
case 79:
q_recip = 830;
break;
case 80:
q_recip = 819;
break;
case 81:
q_recip = 809;
break;
case 82:
q_recip = 799;
break;
case 83:
q_recip = 790;
break;
case 84:
q_recip = 780;
break;
case 85:
q_recip = 771;
break;
case 86:
q_recip = 762;
break;
case 87:
q_recip = 753;
break;
case 88:
q_recip = 745;
break;
case 89:
q_recip = 736;
break;
case 90:
q_recip = 728;
break;
case 91:
q_recip = 720;
break;
case 92:
q_recip = 712;
break;
case 93:
q_recip = 705;
break;
case 94:
q_recip = 697;
break;
case 95:
q_recip = 690;
break;
case 96:
q_recip = 683;
break;
case 97:
q_recip = 676;
break;
case 98:
q_recip = 669;
break;
case 99:
q_recip = 662;
break;
case 100:
q_recip = 655;
break;
case 101:
q_recip = 649;
break;
case 102:
q_recip = 643;
break;
case 103:
q_recip = 636;
break;
case 104:
q_recip = 630;
break;
case 105:
q_recip = 624;
break;
case 106:
q_recip = 618;
break;
case 107:
q_recip = 612;
break;
case 108:
q_recip = 607;
break;
case 109:
q_recip = 601;
break;
case 110:
q_recip = 596;
break;
case 111:
q_recip = 590;
break;
case 112:
q_recip = 585;
break;
case 113:
q_recip = 580;
break;
case 114:
q_recip = 575;
break;
case 115:
q_recip = 570;
break;
case 116:
q_recip = 565;
break;
case 117:
q_recip = 560;
break;
case 118:
q_recip = 555;
break;
case 119:
q_recip = 551;
break;
case 120:
q_recip = 546;
break;
case 121:
q_recip = 542;
break;
case 122:
q_recip = 537;
break;
case 123:
q_recip = 533;
break;
case 124:
q_recip = 529;
break;
case 125:
q_recip = 524;
break;
case 126:
q_recip = 520;
break;
case 127:
q_recip = 516;
break;
case 128:
q_recip = 512;
break;
case 129:
q_recip = 508;
break;
case 130:
q_recip = 504;
break;
case 131:
q_recip = 500;
break;
case 132:
q_recip = 496;
break;
case 133:
q_recip = 493;
break;
case 134:
q_recip = 489;
break;
case 135:
q_recip = 485;
break;
case 136:
q_recip = 482;
break;
case 137:
q_recip = 478;
break;
case 138:
q_recip = 475;
break;
case 139:
q_recip = 471;
break;
case 140:
q_recip = 468;
break;
case 141:
q_recip = 465;
break;
case 142:
q_recip = 462;
break;
case 143:
q_recip = 458;
break;
case 144:
q_recip = 455;
break;
case 145:
q_recip = 452;
break;
case 146:
q_recip = 449;
break;
case 147:
q_recip = 446;
break;
case 148:
q_recip = 443;
break;
case 149:
q_recip = 440;
break;
case 150:
q_recip = 437;
break;
case 151:
q_recip = 434;
break;
case 152:
q_recip = 431;
break;
case 153:
q_recip = 428;
break;
case 154:
q_recip = 426;
break;
case 155:
q_recip = 423;
break;
case 156:
q_recip = 420;
break;
case 157:
q_recip = 417;
break;
case 158:
q_recip = 415;
break;
case 159:
q_recip = 412;
break;
case 160:
q_recip = 410;
break;
case 161:
q_recip = 407;
break;
case 162:
q_recip = 405;
break;
case 163:
q_recip = 402;
break;
case 164:
q_recip = 400;
break;
case 165:
q_recip = 397;
break;
case 166:
q_recip = 395;
break;
case 167:
q_recip = 392;
break;
case 168:
q_recip = 390;
break;
case 169:
q_recip = 388;
break;
case 170:
q_recip = 386;
break;
case 171:
q_recip = 383;
break;
case 172:
q_recip = 381;
break;
case 173:
q_recip = 379;
break;
case 174:
q_recip = 377;
break;
case 175:
q_recip = 374;
break;
case 176:
q_recip = 372;
break;
case 177:
q_recip = 370;
break;
case 178:
q_recip = 368;
break;
case 179:
q_recip = 366;
break;
case 180:
q_recip = 364;
break;
case 181:
q_recip = 362;
break;
case 182:
q_recip = 360;
break;
case 183:
q_recip = 358;
break;
case 184:
q_recip = 356;
break;
case 185:
q_recip = 354;
break;
case 186:
q_recip = 352;
break;
case 187:
q_recip = 350;
break;
case 188:
q_recip = 349;
break;
case 189:
q_recip = 347;
break;
case 190:
q_recip = 345;
break;
case 191:
q_recip = 343;
break;
case 192:
q_recip = 341;
break;
case 193:
q_recip = 340;
break;
case 194:
q_recip = 338;
break;
case 195:
q_recip = 336;
break;
case 196:
q_recip = 334;
break;
case 197:
q_recip = 333;
break;
case 198:
q_recip = 331;
break;
case 199:
q_recip = 329;
break;
case 200:
q_recip = 328;
break;
case 201:
q_recip = 326;
break;
case 202:
q_recip = 324;
break;
case 203:
q_recip = 323;
break;
case 204:
q_recip = 321;
break;
case 205:
q_recip = 320;
break;
case 206:
q_recip = 318;
break;
case 207:
q_recip = 317;
break;
case 208:
q_recip = 315;
break;
case 209:
q_recip = 314;
break;
case 210:
q_recip = 312;
break;
case 211:
q_recip = 311;
break;
case 212:
q_recip = 309;
break;
case 213:
q_recip = 308;
break;
case 214:
q_recip = 306;
break;
case 215:
q_recip = 305;
break;
case 216:
q_recip = 303;
break;
case 217:
q_recip = 302;
break;
case 218:
q_recip = 301;
break;
case 219:
q_recip = 299;
break;
case 220:
q_recip = 298;
break;
case 221:
q_recip = 297;
break;
case 222:
q_recip = 295;
break;
case 223:
q_recip = 294;
break;
case 224:
q_recip = 293;
break;
case 225:
q_recip = 291;
break;
case 226:
q_recip = 290;
break;
case 227:
q_recip = 289;
break;
case 228:
q_recip = 287;
break;
case 229:
q_recip = 286;
break;
case 230:
q_recip = 285;
break;
case 231:
q_recip = 284;
break;
case 232:
q_recip = 282;
break;
case 233:
q_recip = 281;
break;
case 234:
q_recip = 280;
break;
case 235:
q_recip = 279;
break;
case 236:
q_recip = 278;
break;
case 237:
q_recip = 277;
break;
case 238:
q_recip = 275;
break;
case 239:
q_recip = 274;
break;
case 240:
q_recip = 273;
break;
case 241:
q_recip = 272;
break;
case 242:
q_recip = 271;
break;
case 243:
q_recip = 270;
break;
case 244:
q_recip = 269;
break;
case 245:
q_recip = 267;
break;
case 246:
q_recip = 266;
break;
case 247:
q_recip = 265;
break;
case 248:
q_recip = 264;
break;
case 249:
q_recip = 263;
break;
case 250:
q_recip = 262;
break;
case 251:
q_recip = 261;
break;
case 252:
q_recip = 260;
break;
case 253:
q_recip = 259;
break;
case 254:
q_recip = 258;
break;
default:
q_recip = 257;
break;
}
return q_recip;
} /* reciprocal */
static void push_word(u8 *base, s32 *offset, u32 word)
{
u8 *ptr;
s32 i;
s32 bytes = (word >> 24) & 0xff;
for (i = bytes - 1; i >= 0; i--) {
ptr = base + *offset;
(*offset)++;
if (i == 0)
*ptr = word & 0xff;
else if (i == 1)
*ptr = (word >> 8) & 0xff;
else if (i == 2)
*ptr = (word >> 16) & 0xff;
}
}
static s32 jpeg_quality_scaling(s32 quality)
{
if (quality <= 0)
quality = 1;
if (quality > 100)
quality = 100;
if (quality < 50)
quality = 5000 / quality;
else
quality = 200 - quality * 2;
return quality;
}
static void _convert_quant_table(u16 *qtable, u16 *basic_table,
s32 scale_factor, bool force_baseline)
{
s32 i = 0;
s32 temp;
for (i = 0; i < DCTSIZE2; i++) {
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_C1) {
if (use_quality) {
//jenc_pr(LOG_ALL, "c1 using quality factor %d\n", scale_factor);
temp = ((s32)basic_table[i] * scale_factor + 50) / 100;
} else {
//jenc_pr(LOG_INFO, "c1 ignore quality factor\n");
temp = (s32)basic_table[i];
}
}else
temp = ((s32)basic_table[i] * scale_factor + 50) / 100;
/* limit the values to the valid range */
if (temp <= 0)
temp = 1;
/* max quantizer needed for 12 bits */
if (temp > 32767)
temp = 32767;
/* limit to baseline range if requested */
if (force_baseline && temp > 255)
temp = 255;
qtable[i] = (u16)temp;
}
}
static void convert_quant_table(u16 *qtable, u16 *basic_table,
s32 scale_factor)
{
_convert_quant_table(qtable, basic_table, scale_factor, true);
}
static void write_jpeg_quant_lut(s32 table_num)
{
s32 i;
u32 data32;
for (i = 0; i < DCTSIZE2; i += 2) {
data32 = reciprocal(gQuantTable[table_num][i]);
data32 |= reciprocal(gQuantTable[table_num][i + 1]) << 16;
WRITE_HREG(HCODEC_QDCT_JPEG_QUANT_DATA, data32);
}
}
static void write_jpeg_huffman_lut_dc(s32 table_num)
{
u32 code_len, code_word, pos, addr;
u32 num_code_len;
u32 lut[12];
u32 i, j;
code_len = 1;
code_word = 1;
pos = 16;
/* Construct DC Huffman table */
for (i = 0; i < 16; i++) {
num_code_len = jpeg_huffman_dc[table_num][i];
for (j = 0; j < num_code_len; j++) {
code_word = (code_word + 1) & ((1 << code_len) - 1);
if (code_len < i + 1) {
code_word <<= (i + 1 - code_len);
code_len = i + 1;
}
addr = jpeg_huffman_dc[table_num][pos];
lut[addr] = ((code_len - 1) << 16) | (code_word);
pos++;
}
}
/* Write DC Huffman table to HW */
for (i = 0; i < 12; i++)
WRITE_HREG(HCODEC_VLC_HUFFMAN_DATA, lut[i]);
}
static void write_jpeg_huffman_lut_ac(s32 table_num)
{
u32 code_len, code_word, pos;
u32 num_code_len;
u32 run, size;
u32 data, addr = 0;
u32 *lut = NULL;
u32 i, j;
code_len = 1;
code_word = 1;
pos = 16;
lut = (u32 *)vmalloc(162 * sizeof(u32));
if (!lut) {
pr_err("alloc lut failed.\n");
return;
}
/* Construct AC Huffman table */
for (i = 0; i < 16; i++) {
num_code_len = jpeg_huffman_ac[table_num][i];
for (j = 0; j < num_code_len; j++) {
code_word = (code_word + 1) & ((1 << code_len) - 1);
if (code_len < i + 1) {
code_word <<= (i + 1 - code_len);
code_len = i + 1;
}
run = jpeg_huffman_ac[table_num][pos] >> 4;
size = jpeg_huffman_ac[table_num][pos] & 0xf;
data = ((code_len - 1) << 16) | (code_word);
if (size == 0) {
if (run == 0)
addr = 0; /* EOB */
else if (run == 0xf)
addr = 161; /* ZRL */
else
jenc_pr(LOG_ERROR,
"Error: Illegal AC Huffman table format!\n");
} else if (size <= 0xa)
addr = 1 + 16 * (size - 1) + run;
else
jenc_pr(LOG_ERROR,
"Error: Illegal AC Huffman table format!\n");
lut[addr] = data;
pos++;
}
}
/* Write AC Huffman table to HW */
for (i = 0; i < 162; i++)
WRITE_HREG(HCODEC_VLC_HUFFMAN_DATA, lut[i]);
vfree(lut);
}
static void prepare_jpeg_header(struct jpegenc_wq_s *wq)
{
s32 pic_format;
s32 pic_width, pic_height;
s32 q_sel_comp0, q_sel_comp1, q_sel_comp2;
s32 dc_huff_sel_comp0, dc_huff_sel_comp1, dc_huff_sel_comp2;
s32 ac_huff_sel_comp0, ac_huff_sel_comp1, ac_huff_sel_comp2;
s32 lastcoeff_sel;
s32 jdct_intr_sel;
s32 h_factor_comp0, v_factor_comp0;
s32 h_factor_comp1, v_factor_comp1;
s32 h_factor_comp2, v_factor_comp2;
s32 q_num;
s32 tq[2];
s32 dc_huff_num, ac_huff_num;
s32 dc_th[2], ac_th[2];
u32 header_bytes = 0;
u32 bak_header_bytes = 0;
s32 i, j;
u8 *assitbuf = (u8 *)wq->AssitstreamStartVirtAddr;
if (wq->cmd.output_fmt >= JPEGENC_MAX_FRAME_FMT)
jenc_pr(LOG_ERROR, "Input format is wrong!\n");
switch (wq->cmd.output_fmt) {
case JPEGENC_FMT_NV21:
case JPEGENC_FMT_NV12:
case JPEGENC_FMT_YUV420:
pic_format = 3;
break;
case JPEGENC_FMT_YUV422_SINGLE:
pic_format = 2;
break;
case JPEGENC_FMT_YUV444_SINGLE:
case JPEGENC_FMT_YUV444_PLANE:
pic_format = 1;
break;
default:
pic_format = 0;
break;
}
pic_width = wq->cmd.encoder_width;
pic_height = wq->cmd.encoder_height;
q_sel_comp0 = QUANT_SEL_COMP0;
q_sel_comp1 = QUANT_SEL_COMP1;
q_sel_comp2 = QUANT_SEL_COMP2;
dc_huff_sel_comp0 = DC_HUFF_SEL_COMP0;
dc_huff_sel_comp1 = DC_HUFF_SEL_COMP1;
dc_huff_sel_comp2 = DC_HUFF_SEL_COMP2;
ac_huff_sel_comp0 = AC_HUFF_SEL_COMP0;
ac_huff_sel_comp1 = AC_HUFF_SEL_COMP1;
ac_huff_sel_comp2 = AC_HUFF_SEL_COMP2;
lastcoeff_sel = JDCT_LASTCOEFF_SEL;
jdct_intr_sel = JDCT_INTR_SEL;
if (pic_format == 2) {
/* YUV422 */
h_factor_comp0 = 1;
v_factor_comp0 = 0;
h_factor_comp1 = 0;
v_factor_comp1 = 0;
h_factor_comp2 = 0;
v_factor_comp2 = 0;
} else if (pic_format == 3) {
/* YUV420 */
h_factor_comp0 = 1;
v_factor_comp0 = 1;
h_factor_comp1 = 0;
v_factor_comp1 = 0;
h_factor_comp2 = 0;
v_factor_comp2 = 0;
} else {
/* RGB or YUV */
h_factor_comp0 = 0;
v_factor_comp0 = 0;
h_factor_comp1 = 0;
v_factor_comp1 = 0;
h_factor_comp2 = 0;
v_factor_comp2 = 0;
}
/* SOI marke */
push_word(assitbuf, &header_bytes,
(2 << 24) | /* Number of bytes */
(0xffd8 << 0)); /* data: SOI marker */
/* Define quantization tables */
q_num = 1;
#if 0
if ((q_sel_comp0 != q_sel_comp1) ||
(q_sel_comp0 != q_sel_comp2) ||
(q_sel_comp1 != q_sel_comp2))
#endif
q_num++;
#if 0
tq[0] = q_sel_comp0;
tq[1] = (q_sel_comp0 != q_sel_comp1) ? q_sel_comp1 :
(q_sel_comp0 != q_sel_comp2) ? q_sel_comp2 :
q_sel_comp0;
#endif
tq[0] = 0;
tq[1] = q_num - 1;
/* data: DQT marker */
push_word(assitbuf, &header_bytes,
(2 << 24) | (0xffdb << 0));
/* data: Lq */
push_word(assitbuf, &header_bytes,
(2 << 24) | ((2 + 65 * q_num) << 0));
/* Add Quantization table bytes */
/* header_bytes += (2 + (2 + 65 * q_num)); */
for (i = 0; i < q_num; i++) {
/* data: {Pq,Tq} */
push_word(assitbuf, &header_bytes,
(1 << 24) | (i << 0));
for (j = 0; j < DCTSIZE2; j++) {
/* data: Qk */
push_word(assitbuf, &header_bytes,
(1 << 24) |
((gQuantTable[tq[i]][zigzag(j)]) << 0));
}
}
/* Define Huffman tables */
dc_huff_num = 1;
if ((dc_huff_sel_comp0 != dc_huff_sel_comp1) ||
(dc_huff_sel_comp0 != dc_huff_sel_comp2) ||
(dc_huff_sel_comp1 != dc_huff_sel_comp2))
dc_huff_num++;
ac_huff_num = 1;
if ((ac_huff_sel_comp0 != ac_huff_sel_comp1) ||
(ac_huff_sel_comp0 != ac_huff_sel_comp2) ||
(ac_huff_sel_comp1 != ac_huff_sel_comp2))
ac_huff_num++;
dc_th[0] = dc_huff_sel_comp0;
dc_th[1] = (dc_huff_sel_comp0 != dc_huff_sel_comp1) ?
dc_huff_sel_comp1 : (dc_huff_sel_comp0 != dc_huff_sel_comp2) ?
dc_huff_sel_comp2 : dc_huff_sel_comp0;
ac_th[0] = ac_huff_sel_comp0;
ac_th[1] = (ac_huff_sel_comp0 != ac_huff_sel_comp1) ?
ac_huff_sel_comp1 : (ac_huff_sel_comp0 != ac_huff_sel_comp2) ?
ac_huff_sel_comp2 : ac_huff_sel_comp0;
/* data: DHT marker */
push_word(assitbuf, &header_bytes,
(2 << 24) | (0xffc4 << 0));
/* data: Lh */
push_word(assitbuf, &header_bytes,
(2 << 24) |
((2 + (1 + 16 + 12) * dc_huff_num +
(1 + 16 + 162) * ac_huff_num) << 0));
/* Add Huffman table bytes */
/* data: {Tc,Th} */
for (i = 0; i < dc_huff_num; i++) {
push_word(assitbuf, &header_bytes,
(1 << 24) | (i << 0));
for (j = 0; j < 16 + 12; j++) {
/* data: Li then Vi,j */
push_word(assitbuf, &header_bytes,
(1 << 24) |
((jpeg_huffman_dc[dc_th[i]][j]) << 0));
}
}
for (i = 0; i < ac_huff_num; i++) {
push_word(assitbuf, &header_bytes,
(1 << 24) |
(1 << 4) | /* data: Tc */
(i << 0)); /* data: Th */
for (j = 0; j < 16 + 162; j++) {
/* data: Li then Vi,j */
push_word(assitbuf, &header_bytes,
(1 << 24) |
((jpeg_huffman_ac[ac_th[i]][j]) << 0));
}
}
/* Frame header */
/* Add Frame header bytes */
/* header_bytes += (2 + (8 + 3 * 3)); */
push_word(assitbuf, &header_bytes,
(2 << 24) | /* Number of bytes */
(0xffc0 << 0)); /* data: SOF_0 marker */
/* data: Lf */
push_word(assitbuf, &header_bytes,
(2 << 24) | ((8 + 3 * 3) << 0));
/* data: P -- Sample precision */
push_word(assitbuf,
&header_bytes, (1 << 24) | (8 << 0));
/* data: Y -- Number of lines */
push_word(assitbuf,
&header_bytes, (2 << 24) | (pic_height << 0));
/* data: X -- Number of samples per line */
push_word(assitbuf,
&header_bytes, (2 << 24) | (pic_width << 0));
/* data: Nf -- Number of components in a frame */
push_word(assitbuf,
&header_bytes, (1 << 24) | (3 << 0));
/* data: C0 -- Comp0 identifier */
push_word(assitbuf,
&header_bytes, (1 << 24) | (0 << 0));
push_word(assitbuf,
&header_bytes, (1 << 24) |
/* data: H0 -- Comp0 horizontal sampling factor */
((h_factor_comp0 + 1) << 4) |
/* data: V0 -- Comp0 vertical sampling factor */
((v_factor_comp0 + 1) << 0));
/* data: Tq0 -- Comp0 quantization table seletor */
push_word(assitbuf,
&header_bytes, (1 << 24) | (0 << 0));
/* data: C1 -- Comp1 identifier */
push_word(assitbuf,
&header_bytes, (1 << 24) | (1 << 0));
push_word(assitbuf,
&header_bytes, (1 << 24) |
/* data: H1 -- Comp1 horizontal sampling factor */
((h_factor_comp1 + 1) << 4) |
/* data: V1 -- Comp1 vertical sampling factor */
((v_factor_comp1 + 1) << 0));
/* data: Tq1 -- Comp1 quantization table seletor */
push_word(assitbuf,
&header_bytes, (1 << 24) |
(((q_sel_comp0 != q_sel_comp1) ? 1 : 0) << 0));
/* data: C2 -- Comp2 identifier */
push_word(assitbuf,
&header_bytes, (1 << 24) | (2 << 0));
push_word(assitbuf,
&header_bytes, (1 << 24) |
/* data: H2 -- Comp2 horizontal sampling factor */
((h_factor_comp2 + 1) << 4) |
/* data: V2 -- Comp2 vertical sampling factor */
((v_factor_comp2 + 1) << 0));
/* data: Tq2 -- Comp2 quantization table seletor */
push_word(assitbuf,
&header_bytes, (1 << 24) |
(((q_sel_comp0 != q_sel_comp2) ? 1 : 0) << 0));
/* Scan header */
bak_header_bytes = header_bytes + (2 + (6 + 2 * 3));
/* Add Scan header bytes */
/* header_bytes += (2 + (6+2*3)); */
/* If total header bytes is not multiple of 8,
then fill 0xff byte between Frame header segment
and the Scan header segment. */
/* header_bytes = ((header_bytes + 7)/8)*8; */
bak_header_bytes = ((bak_header_bytes + 7) / 8) * 8 - bak_header_bytes;
for (i = 0; i < bak_header_bytes; i++)
push_word(assitbuf,
&header_bytes,
(1 << 24) | (0xff << 0)); /* 0xff filler */
push_word(assitbuf,
&header_bytes,
(2 << 24) | /* Number of bytes */
(0xffda << 0)); /* data: SOS marker */
/* data: Ls */
push_word(assitbuf,
&header_bytes, (2 << 24) | ((6 + 2 * 3) << 0));
/* data: Ns -- Number of components in a scan */
push_word(assitbuf,
&header_bytes, (1 << 24) | (3 << 0));
/* data: Cs0 -- Comp0 identifier */
push_word(assitbuf,
&header_bytes, (1 << 24) | (0 << 0));
push_word(assitbuf,
&header_bytes, (1 << 24) |
(0 << 4) | /* data: Td0 -- Comp0 DC Huffman table selector */
(0 << 0)); /* data: Ta0 -- Comp0 AC Huffman table selector */
/* data: Cs1 -- Comp1 identifier */
push_word(assitbuf,
&header_bytes, (1 << 24) | (1 << 0));
push_word(assitbuf,
&header_bytes, (1 << 24) |
/* data: Td1 -- Comp1 DC Huffman table selector */
(((dc_huff_sel_comp0 != dc_huff_sel_comp1) ? 1 : 0) << 4) |
/* data: Ta1 -- Comp1 AC Huffman table selector */
(((ac_huff_sel_comp0 != ac_huff_sel_comp1) ? 1 : 0) << 0));
/* data: Cs2 -- Comp2 identifier */
push_word(assitbuf,
&header_bytes, (1 << 24) | (2 << 0));
push_word(assitbuf,
&header_bytes, (1 << 24) |
/* data: Td2 -- Comp2 DC Huffman table selector */
(((dc_huff_sel_comp0 != dc_huff_sel_comp2) ? 1 : 0) << 4) |
/* data: Ta2 -- Comp2 AC Huffman table selector */
(((ac_huff_sel_comp0 != ac_huff_sel_comp2) ? 1 : 0) << 0));
push_word(assitbuf, &header_bytes,
(3 << 24) |
(0 << 16) | /* data: Ss = 0 */
(63 << 8) | /* data: Se = 63 */
(0 << 4) | /* data: Ah = 0 */
(0 << 0)); /* data: Al = 0 */
jenc_pr(LOG_INFO, "jpeg header bytes is %d\n", header_bytes);
wq->headbytes = header_bytes;
}
static void init_jpeg_encoder(struct jpegenc_wq_s *wq)
{
u32 data32;
s32 pic_format; /* 0=RGB; 1=YUV; 2=YUV422; 3=YUV420 */
s32 pic_x_start, pic_x_end, pic_y_start, pic_y_end;
s32 pic_width, pic_height;
u32 q_sel_comp0, q_sel_comp1, q_sel_comp2;
s32 dc_huff_sel_comp0, dc_huff_sel_comp1, dc_huff_sel_comp2;
s32 ac_huff_sel_comp0, ac_huff_sel_comp1, ac_huff_sel_comp2;
s32 lastcoeff_sel;
s32 jdct_intr_sel;
s32 h_factor_comp0, v_factor_comp0;
s32 h_factor_comp1, v_factor_comp1;
s32 h_factor_comp2, v_factor_comp2;
jenc_pr(LOG_INFO, "Initialize JPEG Encoder ....\n");
if (wq->cmd.output_fmt >= JPEGENC_MAX_FRAME_FMT)
jenc_pr(LOG_ERROR, "Input format is wrong!\n");
switch (wq->cmd.output_fmt) {
case JPEGENC_FMT_NV21:
case JPEGENC_FMT_NV12:
case JPEGENC_FMT_YUV420:
pic_format = 3;
break;
case JPEGENC_FMT_YUV422_SINGLE:
pic_format = 2;
break;
case JPEGENC_FMT_YUV444_SINGLE:
case JPEGENC_FMT_YUV444_PLANE:
pic_format = 1;
break;
default:
pic_format = 0;
break;
}
pic_x_start = 0;
pic_x_end = wq->cmd.encoder_width - 1;
pic_y_start = 0;
pic_y_end = wq->cmd.encoder_height - 1;
pic_width = wq->cmd.encoder_width;
pic_height = wq->cmd.encoder_height;
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_C1) {
q_sel_comp0 = QUANT_SEL_COMP0 & 0xff;
q_sel_comp1 = QUANT_SEL_COMP1 & 0xff;
q_sel_comp2 = QUANT_SEL_COMP2 & 0xff;
} else {
q_sel_comp0 = wq->cmd.QuantTable_id * 2;
q_sel_comp1 = q_sel_comp0 + 1;
q_sel_comp2 = q_sel_comp1;
}
if (q_sel_comp0 >= 6 || q_sel_comp1 >= 6)
{
jenc_pr(LOG_ERROR, "error, q_sel_comp0, q_sel_comp1 is invalid %d,%d\n",
q_sel_comp0, q_sel_comp1);
return;
}
dc_huff_sel_comp0 = DC_HUFF_SEL_COMP0;
dc_huff_sel_comp1 = DC_HUFF_SEL_COMP1;
dc_huff_sel_comp2 = DC_HUFF_SEL_COMP2;
ac_huff_sel_comp0 = AC_HUFF_SEL_COMP0;
ac_huff_sel_comp1 = AC_HUFF_SEL_COMP1;
ac_huff_sel_comp2 = AC_HUFF_SEL_COMP2;
lastcoeff_sel = JDCT_LASTCOEFF_SEL;
jdct_intr_sel = JDCT_INTR_SEL;
if (pic_format == 2) {
/* YUV422 */
h_factor_comp0 = 1;
v_factor_comp0 = 0;
h_factor_comp1 = 0;
v_factor_comp1 = 0;
h_factor_comp2 = 0;
v_factor_comp2 = 0;
} else if (pic_format == 3) {
/* YUV420 */
h_factor_comp0 = 1;
v_factor_comp0 = 1;
h_factor_comp1 = 0;
v_factor_comp1 = 0;
h_factor_comp2 = 0;
v_factor_comp2 = 0;
} else {
/* RGB or YUV */
h_factor_comp0 = 0;
v_factor_comp0 = 0;
h_factor_comp1 = 0;
v_factor_comp1 = 0;
h_factor_comp2 = 0;
v_factor_comp2 = 0;
}
/* Configure picture size and format */
WRITE_HREG(HCODEC_VLC_PIC_SIZE, pic_width | (pic_height << 16));
WRITE_HREG(HCODEC_VLC_PIC_POSITION, pic_format | (lastcoeff_sel << 4));
WRITE_HREG(HCODEC_QDCT_JPEG_X_START_END,
((pic_x_end << 16) | (pic_x_start << 0)));
WRITE_HREG(HCODEC_QDCT_JPEG_Y_START_END,
((pic_y_end << 16) | (pic_y_start << 0)));
/* Configure quantization tables */
#ifdef EXTEAN_QUANT_TABLE
if (external_quant_table_available) {
convert_quant_table(&gQuantTable[0][0],
&gExternalQuantTablePtr[0],
wq->cmd.jpeg_quality);
convert_quant_table(&gQuantTable[1][0],
&gExternalQuantTablePtr[DCTSIZE2],
wq->cmd.jpeg_quality);
q_sel_comp0 = 0;
q_sel_comp1 = 1;
q_sel_comp2 = 1;
} else
#endif
{
s32 tq[2];
tq[0] = q_sel_comp0;
tq[1] = (q_sel_comp0 != q_sel_comp1) ?
q_sel_comp1 : (q_sel_comp0 != q_sel_comp2) ?
q_sel_comp2 : q_sel_comp0;
convert_quant_table(&gQuantTable[0][0],
(u16 *)&jpeg_quant[tq[0]],
wq->cmd.jpeg_quality);
if (tq[0] != tq[1])
convert_quant_table(&gQuantTable[1][0],
(u16 *)&jpeg_quant[tq[1]],
wq->cmd.jpeg_quality);
q_sel_comp0 = tq[0];
q_sel_comp1 = tq[1];
q_sel_comp2 = tq[1];
}
/* Set Quantization LUT start address */
data32 = 0;
data32 |= 0 << 8; /* [8] 0=Write LUT, 1=Read */
data32 |= 0 << 0; /* [5:0] Start addr = 0 */
WRITE_HREG(HCODEC_QDCT_JPEG_QUANT_ADDR, data32);
/* Burst-write Quantization LUT data */
if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_C1) {
write_jpeg_quant_lut(0);
if (q_sel_comp0 != q_sel_comp1)
write_jpeg_quant_lut(1);
} else {
write_jpeg_quant_lut(q_sel_comp0);
if (q_sel_comp1 != q_sel_comp0)
write_jpeg_quant_lut(q_sel_comp1);
if ((q_sel_comp2 != q_sel_comp0) && (q_sel_comp2 != q_sel_comp1))
write_jpeg_quant_lut(q_sel_comp2);
}
/* Configure Huffman tables */
/* Set DC Huffman LUT start address */
data32 = 0;
data32 |= 0 << 16; /* [16] 0=Write LUT, 1=Read */
data32 |= 0 << 0; /* [8:0] Start addr = 0 */
WRITE_HREG(HCODEC_VLC_HUFFMAN_ADDR, data32);
/* Burst-write DC Huffman LUT data */
write_jpeg_huffman_lut_dc(dc_huff_sel_comp0);
if (dc_huff_sel_comp1 != dc_huff_sel_comp0)
write_jpeg_huffman_lut_dc(dc_huff_sel_comp1);
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_C1) {
if ((dc_huff_sel_comp2 != dc_huff_sel_comp0)
&& (dc_huff_sel_comp2 != dc_huff_sel_comp1))
write_jpeg_huffman_lut_dc(dc_huff_sel_comp2);
}
/* Set AC Huffman LUT start address */
data32 = 0;
data32 |= 0 << 16; /* [16] 0=Write LUT, 1=Read */
data32 |= 24 << 0; /* [8:0] Start addr = 0 */
WRITE_HREG(HCODEC_VLC_HUFFMAN_ADDR, data32);
/* Burst-write AC Huffman LUT data */
write_jpeg_huffman_lut_ac(ac_huff_sel_comp0);
if (ac_huff_sel_comp1 != ac_huff_sel_comp0)
write_jpeg_huffman_lut_ac(ac_huff_sel_comp1);
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_C1) {
if ((ac_huff_sel_comp2 != ac_huff_sel_comp0)
&& (ac_huff_sel_comp2 != ac_huff_sel_comp1))
write_jpeg_huffman_lut_ac(ac_huff_sel_comp2);
}
/* Configure general control registers */
data32 = 0;
/* [19:18] dct_inflow_ctrl: 0=No halt; */
/* 1=DCT halts request at end of each 8x8 block; */
/* 2=DCT halts request at end of each MCU. */
data32 |= 0 << 18;
/* [17:16] jpeg_coeff_last_sel: */
/* 0=Mark last coeff at the end of an 8x8 block, */
/* 1=Mark last coeff at the end of an MCU */
/* 2=Mark last coeff at the end of a scan */
data32 |= lastcoeff_sel << 16;
/* [15] jpeg_quant_sel_comp2 */
data32 |= ((q_sel_comp2 == q_sel_comp0) ? 0 : 1) << 15;
/* [14] jpeg_v_factor_comp2 */
data32 |= v_factor_comp2 << 14;
/* [13] jpeg_h_factor_comp2 */
data32 |= h_factor_comp2 << 13;
/* [12] jpeg_comp2_en */
data32 |= 1 << 12;
/* [11] jpeg_quant_sel_comp1 */
data32 |= ((q_sel_comp1 == q_sel_comp0) ? 0 : 1) << 11;
/* [10] jpeg_v_factor_comp1 */
data32 |= v_factor_comp1 << 10;
/* [9] jpeg_h_factor_comp1 */
data32 |= h_factor_comp1 << 9;
/* [8] jpeg_comp1_en */
data32 |= 1 << 8;
/* [7] jpeg_quant_sel_comp0 */
data32 |= 0 << 7;
/* [6] jpeg_v_factor_comp0 */
data32 |= v_factor_comp0 << 6;
/* [5] jpeg_h_factor_comp0 */
data32 |= h_factor_comp0 << 5;
/* [4] jpeg_comp0_en */
data32 |= 1 << 4;
/* [3:1] jdct_intr_sel:0=Disable intr; */
/* 1=Intr at end of each 8x8 block of DCT input; */
/* 2=Intr at end of each MCU of DCT input; */
/* 3=Intr at end of a scan of DCT input; */
/* 4=Intr at end of each 8x8 block of DCT output; */
/* 5=Intr at end of each MCU of DCT output; */
/* 6=Intr at end of a scan of DCT output. */
data32 |= jdct_intr_sel << 1;
/* [0] jpeg_en */
data32 |= 1 << 0;
WRITE_HREG(HCODEC_QDCT_JPEG_CTRL, data32);
data32 = 0;
data32 |= ((ac_huff_sel_comp2 == ac_huff_sel_comp0)? 0 : 1) << 29; // [ 29] jpeg_comp2_ac_table_sel
data32 |= ((dc_huff_sel_comp2 == dc_huff_sel_comp0)? 0 : 1) << 28; // [ 28] jpeg_comp2_dc_table_sel
/* [26:25] jpeg_comp2_cnt_max */
data32 |= ((h_factor_comp2 + 1) * (v_factor_comp2 + 1) - 1) << 25;
/* [24] jpeg_comp2_en */
data32 |= 1 << 24;
data32 |= ((ac_huff_sel_comp1 == ac_huff_sel_comp0)? 0 : 1) << 21; // [ 21] jpeg_comp1_ac_table_sel
data32 |= ((dc_huff_sel_comp1 == dc_huff_sel_comp0)? 0 : 1) << 20; // [ 20] jpeg_comp1_dc_table_sel
/* [18:17] jpeg_comp1_cnt_max */
data32 |= ((h_factor_comp1 + 1) * (v_factor_comp1 + 1) - 1) << 17;
/* [16] jpeg_comp1_en */
data32 |= 1 << 16;
/* [13] jpeg_comp0_ac_table_sel */
data32 |= 0 << 13;
/* [12] jpeg_comp0_dc_table_sel */
data32 |= 0 << 12;
/* [10:9] jpeg_comp0_cnt_max */
data32 |= ((h_factor_comp0 + 1) * (v_factor_comp0 + 1) - 1) << 9;
/* [8] jpeg_comp0_en */
data32 |= 1 << 8;
/* [0] jpeg_en, will be enbled by amrisc */
data32 |= 0 << 0;
WRITE_HREG(HCODEC_VLC_JPEG_CTRL, data32);
WRITE_HREG(HCODEC_QDCT_MB_CONTROL,
(1 << 9) | /* mb_info_soft_reset */
(1 << 0)); /* mb read buffer soft reset */
WRITE_HREG(HCODEC_QDCT_MB_CONTROL,
(0 << 28) | /* ignore_t_p8x8 */
(0 << 27) | /* zero_mc_out_null_non_skipped_mb */
(0 << 26) | /* no_mc_out_null_non_skipped_mb */
(0 << 25) | /* mc_out_even_skipped_mb */
(0 << 24) | /* mc_out_wait_cbp_ready */
(0 << 23) | /* mc_out_wait_mb_type_ready */
(0 << 29) | /* ie_start_int_enable */
(0 << 19) | /* i_pred_enable */
(0 << 20) | /* ie_sub_enable */
(0 << 18) | /* iq_enable */
(0 << 17) | /* idct_enable */
(0 << 14) | /* mb_pause_enable */
(1 << 13) | /* q_enable */
(1 << 12) | /* dct_enable */
(0 << 10) | /* mb_info_en */
(0 << 3) | /* endian */
(0 << 1) | /* mb_read_en */
(0 << 0)); /* soft reset */
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_C1) {
// INIT_ENCODER
WRITE_HREG(HCODEC_VLC_TOTAL_BYTES, 0);
WRITE_HREG(HCODEC_VLC_INT_CONTROL, 0);// disable vlc interrupt
WRITE_HREG(HCODEC_HENC_SCRATCH_0, 0);// mtspi ENCODER_IDLE = ( ENCODER_STATUS
WRITE_HREG(HCODEC_HENC_SCRATCH_1, 0xffffffff);// reset MCU_XY_REG
WRITE_HREG(HCODEC_ASSIST_AMR1_INT0, 0x15);// vb_full_isr
WRITE_HREG(HCODEC_ASSIST_AMR1_INT1, 8);// vlc_isr
WRITE_HREG(HCODEC_ASSIST_AMR1_INT3, 0x14);// qdct_isr
}
/* Assember JPEG file header */
prepare_jpeg_header(wq);
}
static void jpegenc_init_output_buffer(struct jpegenc_wq_s *wq)
{
WRITE_HREG(HCODEC_VLC_VB_MEM_CTL,
((1 << 31) | (0x3f << 24) |
(0x20 << 16) | (2 << 0)));
WRITE_HREG(HCODEC_VLC_VB_START_PTR, wq->BitstreamStart);
WRITE_HREG(HCODEC_VLC_VB_WR_PTR, wq->BitstreamStart);
WRITE_HREG(HCODEC_VLC_VB_SW_RD_PTR, wq->BitstreamStart);
WRITE_HREG(HCODEC_VLC_VB_END_PTR, wq->BitstreamEnd);
WRITE_HREG(HCODEC_VLC_VB_CONTROL, 1);
WRITE_HREG(HCODEC_VLC_VB_CONTROL,
((0 << 14) | (7 << 3) |
(1 << 1) | (0 << 0)));
}
static void jpegenc_buffspec_init(struct jpegenc_wq_s *wq)
{
/* input dct buffer config */
wq->InputBuffStart = wq->buf_start + gJpegenc.mem.bufspec->input.buf_start;
wq->InputBuffEnd = wq->InputBuffStart + gJpegenc.mem.bufspec->input.buf_size - 1;
jenc_pr(LOG_INFO, "InputBuffStart is 0x%x\n", wq->InputBuffStart);
/* assit stream buffer config */
wq->AssitStart = wq->buf_start + gJpegenc.mem.bufspec->assit.buf_start;
wq->AssitEnd = wq->AssitStart + gJpegenc.mem.bufspec->assit.buf_size - 1;
/* output stream buffer config */
wq->BitstreamStart = wq->buf_start + gJpegenc.mem.bufspec->bitstream.buf_start;
wq->BitstreamEnd = wq->BitstreamStart + gJpegenc.mem.bufspec->bitstream.buf_size - 1;
jenc_pr(LOG_INFO, "BitstreamStart is 0x%x\n", wq->BitstreamStart);
wq->AssitstreamStartVirtAddr = phys_to_virt(wq->AssitStart);
jenc_pr(LOG_INFO, "AssitstreamStartVirtAddr is %p\n", wq->AssitstreamStartVirtAddr);
}
/* for temp */
#define HCODEC_MFDIN_REGC_MBLP (HCODEC_MFDIN_REGB_AMPC + 0x1)
#define HCODEC_MFDIN_REG0D (HCODEC_MFDIN_REGB_AMPC + 0x2)
#define HCODEC_MFDIN_REG0E (HCODEC_MFDIN_REGB_AMPC + 0x3)
#define HCODEC_MFDIN_REG0F (HCODEC_MFDIN_REGB_AMPC + 0x4)
#define HCODEC_MFDIN_REG10 (HCODEC_MFDIN_REGB_AMPC + 0x5)
#define HCODEC_MFDIN_REG11 (HCODEC_MFDIN_REGB_AMPC + 0x6)
#define HCODEC_MFDIN_REG12 (HCODEC_MFDIN_REGB_AMPC + 0x7)
#define HCODEC_MFDIN_REG13 (HCODEC_MFDIN_REGB_AMPC + 0x8)
#define HCODEC_MFDIN_REG14 (HCODEC_MFDIN_REGB_AMPC + 0x9)
#define HCODEC_MFDIN_REG15 (HCODEC_MFDIN_REGB_AMPC + 0xa)
#define HCODEC_MFDIN_REG16 (HCODEC_MFDIN_REGB_AMPC + 0xb)
static void mfdin_basic_jpeg(
u32 input, u8 iformat, u8 oformat, u32 picsize_x,
u32 picsize_y, u8 r2y_en, u8 ifmt_extra,
int mfdin_canvas0_stride,
int mfdin_canvas1_stride,
int mfdin_canvas2_stride,
int mfdin_canvas0_blkmode,
int mfdin_canvas1_blkmode,
int mfdin_canvas2_blkmode,
int mfdin_canvas0_addr,
int mfdin_canvas1_addr,
int mfdin_canvas2_addr,
int mfdin_canvas_bias,
bool mfdin_big_endian)
{
u8 dsample_en; /* Downsample Enable */
u8 interp_en; /* Interpolation Enable */
u8 y_size; /* 0:16 Pixels for y direction pickup; 1:8 pixels */
u8 r2y_mode; /* RGB2YUV Mode, range(0~3) */
/* mfdin_reg3_canv[25:24]; */
/* bytes per pixel in x direction for index0, 0:half 1:1 2:2 3:3 */
u8 canv_idx0_bppx;
/* mfdin_reg3_canv[27:26]; */
/* bytes per pixel in x direction for index1-2, 0:half 1:1 2:2 3:3 */
u8 canv_idx1_bppx;
/* mfdin_reg3_canv[29:28]; */
/* bytes per pixel in y direction for index0, 0:half 1:1 2:2 3:3 */
u8 canv_idx0_bppy;
/* mfdin_reg3_canv[31:30]; */
/* bytes per pixel in y direction for index1-2, 0:half 1:1 2:2 3:3 */
u8 canv_idx1_bppy;
u8 ifmt444, ifmt422, ifmt420, linear_bytes4p;
u32 linear_bytesperline;
int mfdin_input_mode = 0;
//s32 reg_offset;
bool format_err = false;
u32 data32;
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_TXL) {
if ((iformat == 7) && (ifmt_extra > 2))
format_err = true;
} else if (iformat == 7)
format_err = true;
if (format_err) {
jenc_pr(LOG_ERROR,
"mfdin format err, iformat:%d, ifmt_extra:%d\n",
iformat, ifmt_extra);
return;
}
if (iformat != 7)
ifmt_extra = 0;
ifmt444 = ((iformat == 1) || (iformat == 5) || (iformat == 8)
|| (iformat == 9) || (iformat == 12)) ? 1 : 0;
if (iformat == 7 && ifmt_extra == 1)
ifmt444 = 1;
ifmt422 = ((iformat == 0) || (iformat == 10)) ? 1 : 0;
if (iformat == 7 && ifmt_extra != 1)
ifmt422 = 1;
ifmt420 = ((iformat == 2) || (iformat == 3) || (iformat == 4)
|| (iformat == 11)) ? 1 : 0;
dsample_en = ((ifmt444 && (oformat != 2))
|| (ifmt422 && (oformat == 0))) ? 1 : 0;
interp_en = ((ifmt422 && (oformat == 2))
|| (ifmt420 && (oformat != 0))) ? 1 : 0;
y_size = (oformat != 0) ? 1 : 0;
/* r2y_mode = (r2y_en == 1) ? 1 : 0; */
r2y_mode = 1;
canv_idx0_bppx = (iformat == 1) ? 3 : (iformat == 0) ? 2 : 1;
canv_idx1_bppx = (iformat == 4) ? 0 : 1;
canv_idx0_bppy = 1;
canv_idx1_bppy = (iformat == 5) ? 1 : 0;
if ((iformat == 8) || (iformat == 9) || (iformat == 12))
linear_bytes4p = 3;
else if (iformat == 10)
linear_bytes4p = 2;
else if (iformat == 11)
linear_bytes4p = 1;
else
linear_bytes4p = 0;
linear_bytesperline = picsize_x * linear_bytes4p;
if (iformat < 8)
mfdin_input_mode = 0;
else
mfdin_input_mode = 1;
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_C1)
mfdin_input_mode = 2;
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB) {
reg_offset = -8;
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_C1)
WRITE_HREG((HCODEC_MFDIN_REG8_DMBL + reg_offset),
(picsize_x << 16) | (picsize_y << 0));
else
WRITE_HREG((HCODEC_MFDIN_REG8_DMBL + reg_offset),
(picsize_x << 14) | (picsize_y << 0));
} else {
reg_offset = 0;
WRITE_HREG((HCODEC_MFDIN_REG8_DMBL + reg_offset),
(picsize_x << 12) | (picsize_y << 0));
}
WRITE_HREG((HCODEC_MFDIN_REG1_CTRL + reg_offset),
(iformat << 0) |
(oformat << 4) |
(dsample_en << 6) |
(y_size << 8) |
(interp_en << 9) |
(r2y_en << 12) |
(r2y_mode << 13) |
(ifmt_extra << 16) |
(0 <<19) | // 0:NR Not Enabled
(2 <<29) | // 0:H264_I_PIC_ALL_4x4, 1:H264_P_PIC_Y_16x16_C_8x8, 2:JPEG_ALL_8x8, 3:Reserved
(0 <<31)); // 0:YC interleaved 1:YC non-interleaved(for JPEG)
if (mfdin_input_mode == 0) {
WRITE_HREG((HCODEC_MFDIN_REG3_CANV + reg_offset),
(input & 0xffffff) |
(canv_idx1_bppy << 30) |
(canv_idx0_bppy << 28) |
(canv_idx1_bppx << 26) |
(canv_idx0_bppx << 24));
WRITE_HREG((HCODEC_MFDIN_REG4_LNR0 + reg_offset),
(0 << 16) | (0 << 0));
WRITE_HREG((HCODEC_MFDIN_REG5_LNR1 + reg_offset), 0);
} else if (mfdin_input_mode == 1) {
WRITE_HREG((HCODEC_MFDIN_REG3_CANV + reg_offset),
(canv_idx1_bppy << 30) |
(canv_idx0_bppy << 28) |
(canv_idx1_bppx << 26) |
(canv_idx0_bppx << 24));
WRITE_HREG((HCODEC_MFDIN_REG4_LNR0 + reg_offset),
(linear_bytes4p << 16) | (linear_bytesperline << 0));
WRITE_HREG((HCODEC_MFDIN_REG5_LNR1 + reg_offset), input);
} else if (mfdin_input_mode == 2) {
WRITE_HREG((HCODEC_MFDIN_REG3_CANV + reg_offset),
(canv_idx1_bppy << 30) |
(canv_idx0_bppy << 28) |
(canv_idx1_bppx << 26) |
(canv_idx0_bppx << 24));
WRITE_HREG((HCODEC_MFDIN_REG4_LNR0 + reg_offset),
mfdin_canvas0_stride << 0);
WRITE_HREG((HCODEC_MFDIN_REG5_LNR1 + reg_offset), mfdin_canvas0_addr);
WRITE_HREG(HCODEC_MFDIN_REG17, mfdin_canvas1_addr); // U canvas initial address
WRITE_HREG(HCODEC_MFDIN_REG18, mfdin_canvas2_addr); // V canvas initial address
WRITE_HREG(HCODEC_MFDIN_REG19, (mfdin_canvas1_stride << 16) | // U canvas stride
(mfdin_canvas2_stride << 0));
data32 = READ_HREG(HCODEC_MFDIN_REG6_DCFG + reg_offset);
data32 = data32 & 0x3ff;
if (jpeg_in_full_hcodec) {
pr_err("JPEG_IN_FULL_HCODEC\n");
data32 |= (0<<16);
if(mfdin_ambus_canv_conv) {
data32 |= (1<<17); // AMBUS
}
} else {
data32 |= (1 << 16); // AXI Enable
}
data32 |= (mfdin_canvas0_blkmode << 14) | // V canvas block mode
(mfdin_canvas1_blkmode << 12) | // U canvas block mode
(mfdin_canvas2_blkmode << 10); // Y canvas block mode
WRITE_HREG(HCODEC_MFDIN_REG6_DCFG + reg_offset, data32);
if (mfdin_canvas_bias)
WRITE_HREG(HCODEC_MFDIN_REGA_CAV1 + reg_offset, mfdin_canvas_bias);
}
if (!mfdin_big_endian) {
WRITE_HREG((HCODEC_MFDIN_REG9_ENDN + reg_offset),
(7 << 0) | (6 << 3) | (5 << 6) |
(4 << 9) | (3 << 12) | (2 << 15) |
(1 << 18) | (0 << 21));
}
if (jpeg_in_full_hcodec) {//#ifdef JPEG_IN_FULL_HCODEC
data32 = READ_HREG(HCODEC_MFDIN_REG3_CANV + reg_offset);
WRITE_HREG(HCODEC_MFDIN_REG3_CANV + reg_offset, data32|(0x1 << 8)|(0x2 << 16));
}
data32 = READ_HREG(HCODEC_MFDIN_REG7_SCMD + reg_offset);
WRITE_HREG(HCODEC_MFDIN_REG7_SCMD + reg_offset, data32 | (0x1 << 28)); // MFDIN Enabled
jenc_pr(LOG_INFO, "MFDIN Enabled\n");
return;
}
//#define CONFIG_AMLOGIC_MEDIA_CANVAS
static s32 set_jpeg_input_format(struct jpegenc_wq_s *wq,
struct jpegenc_request_s *cmd)
{
s32 ret = 0;
u8 iformat = JPEGENC_MAX_FRAME_FMT;
u8 oformat = JPEGENC_MAX_FRAME_FMT;
u8 r2y_en = 0;
u32 picsize_x = 0, picsize_y = 0;
u32 input = cmd->src;
u8 ifmt_extra = 0;
int mfdin_canvas0_stride = 0, mfdin_canvas1_stride = 0, mfdin_canvas2_stride = 0;
int mfdin_canvas0_blkmode = 0, mfdin_canvas1_blkmode = 0, mfdin_canvas2_blkmode = 0;
int mfdin_canvas0_addr = 0, mfdin_canvas1_addr = 0, mfdin_canvas2_addr = 0;
int mfdin_canvas_height = 0;
int mfdin_canvas_bias = 0;
bool mfdin_big_endian = false;
u32 block_mode = 0;
#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS
u32 canvas_w = 0;
#endif
jenc_pr(LOG_INFO, "************begin set input format**************\n");
jenc_pr(LOG_INFO, "type is %d\n", cmd->type);
jenc_pr(LOG_INFO, "input_fmt is %d\n", cmd->input_fmt);
jenc_pr(LOG_INFO, "output_fmt is %d\n", cmd->output_fmt);
jenc_pr(LOG_INFO, "input is 0x%x\n", cmd->src);
jenc_pr(LOG_INFO, "size is %d\n", cmd->framesize);
jenc_pr(LOG_INFO, "quality is %d\n", cmd->jpeg_quality);
jenc_pr(LOG_INFO, "quant tbl_id is %d\n", cmd->QuantTable_id);
jenc_pr(LOG_INFO, "flush flag is %d\n", cmd->flush_flag);
jenc_pr(LOG_INFO, "block mode is %d\n", cmd->block_mode);
jenc_pr(LOG_INFO, "************end set input format**************\n");
if ((cmd->type == JPEGENC_LOCAL_BUFF) ||
(cmd->type == JPEGENC_DMA_BUFF) ||
(cmd->type == JPEGENC_PHYSICAL_BUFF)) {
if (cmd->type == JPEGENC_LOCAL_BUFF) {
if (cmd->flush_flag & JPEGENC_FLUSH_FLAG_INPUT)
dma_flush(wq->InputBuffStart, cmd->framesize);
}
if (cmd->type == JPEGENC_LOCAL_BUFF || cmd->type == JPEGENC_DMA_BUFF)
input = wq->InputBuffStart;
picsize_x = ((cmd->encoder_width + 15) >> 4) << 4;
picsize_y = ((cmd->encoder_height + 15) >> 4) << 4;
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_C1) {
/*
* mfdin in fmt: 0:422 single, 1:444 single, 2:NV21, 3:NV12, 4:420 plane, 5:444 plane
* mfdin out fmt: 0:420, 1:422, 2:444
* picture fmt: 0:RGB, 1:444, 2:422, 3:420
* (out, pic) : (0,3), (1,2), (2,1)
*/
if (cmd->input_fmt == JPEGENC_FMT_YUV422_SINGLE)
iformat = 0;
else if (cmd->input_fmt == JPEGENC_FMT_YUV444_SINGLE)
iformat = 1;
else if (cmd->input_fmt == JPEGENC_FMT_NV21)
iformat = 2;
else if (cmd->input_fmt == JPEGENC_FMT_NV12)
iformat = 3;
else if (cmd->input_fmt == JPEGENC_FMT_YUV420)
iformat = 4;
else if (cmd->input_fmt == JPEGENC_FMT_YUV444_PLANE)
iformat = 5;
if (cmd->output_fmt == JPEGENC_FMT_YUV420)
oformat = 0;
else if (cmd->output_fmt == JPEGENC_FMT_YUV422_SINGLE)
oformat = 1;
else if (cmd->output_fmt == JPEGENC_FMT_YUV444_SINGLE)
oformat = 2;
block_mode = cmd->block_mode;
mfdin_canvas0_stride = cmd->y_stride;
mfdin_canvas1_stride = cmd->u_stride;
mfdin_canvas2_stride = cmd->v_stride;
mfdin_canvas_height = cmd->h_stride;
if (simulation_enable) {
if (g_block_mode)
block_mode = g_block_mode;
if (g_canv0_stride)
mfdin_canvas0_stride = g_canv0_stride;
if (g_canv1_stride)
mfdin_canvas1_stride = g_canv1_stride;
if (g_canv2_stride)
mfdin_canvas2_stride = g_canv2_stride;
if (g_canvas_height)
mfdin_canvas_height = g_canvas_height;
}
if (block_mode) {
mfdin_canvas0_blkmode = 1;
mfdin_canvas1_blkmode = 1;
mfdin_canvas2_blkmode = 1;
} else {
mfdin_canvas0_blkmode = 0;
mfdin_canvas1_blkmode = 0;
mfdin_canvas2_blkmode = 0;
}
if ((iformat == 0 && oformat == 0) || /*case1013, 422 single -> 420*/
(iformat == 0 && oformat == 1) || /*case1002, 422 single -> 422*/
(iformat == 0 && oformat == 2) || /*case1004, 422 single -> 444*/
(iformat == 1 && oformat == 1) || /*case1003, 444 single -> 444*/
(iformat == 1 && oformat