From 17580ae06ac2923a0c07baaed2d7b5a945284e75 Mon Sep 17 00:00:00 2001 From: sophgo-forum-service Date: Mon, 27 May 2024 17:20:20 +0800 Subject: [PATCH] u-boot: weekly rls 2024.05.22 - bf9a0a Change-Id: I0d8f19b2dfb78faf564af12d311557ac18b74c4d --- u-boot-2021.10/cmd/cvi_jpeg.c | 50 + u-boot-2021.10/drivers/jpeg/Makefile | 1 + u-boot-2021.10/drivers/jpeg/config.h | 48 + u-boot-2021.10/drivers/jpeg/cvi_jpeg_cfg.h | 54 + u-boot-2021.10/drivers/jpeg/jdi.c | 537 +++++ u-boot-2021.10/drivers/jpeg/jdi.h | 118 ++ u-boot-2021.10/drivers/jpeg/jdi_osal.c | 717 +++++++ u-boot-2021.10/drivers/jpeg/jdi_osal.h | 97 + u-boot-2021.10/drivers/jpeg/jpeg.c | 155 ++ u-boot-2021.10/drivers/jpeg/jpeg.h | 6 + u-boot-2021.10/drivers/jpeg/jpuapi.c | 1834 +++++++++++++++++ u-boot-2021.10/drivers/jpeg/jpuapi.h | 270 +++ u-boot-2021.10/drivers/jpeg/jpuapifunc.c | 2112 ++++++++++++++++++++ u-boot-2021.10/drivers/jpeg/jpuapifunc.h | 280 +++ u-boot-2021.10/drivers/jpeg/jpuconfig.h | 36 + u-boot-2021.10/drivers/jpeg/jpuhelper.c | 2017 +++++++++++++++++++ u-boot-2021.10/drivers/jpeg/jpuhelper.h | 165 ++ u-boot-2021.10/drivers/jpeg/jpulog.h | 79 + u-boot-2021.10/drivers/jpeg/jpurun.c | 704 +++++++ u-boot-2021.10/drivers/jpeg/jpurun.h | 114 ++ u-boot-2021.10/drivers/jpeg/jputable.h | 125 ++ u-boot-2021.10/drivers/jpeg/jputypes.h | 62 + u-boot-2021.10/drivers/jpeg/mixer.c | 373 ++++ u-boot-2021.10/drivers/jpeg/mixer.h | 47 + u-boot-2021.10/drivers/jpeg/mm.c | 582 ++++++ u-boot-2021.10/drivers/jpeg/mm.h | 71 + u-boot-2021.10/drivers/jpeg/regdefine.h | 162 ++ 27 files changed, 10816 insertions(+) create mode 100644 u-boot-2021.10/cmd/cvi_jpeg.c create mode 100644 u-boot-2021.10/drivers/jpeg/Makefile create mode 100644 u-boot-2021.10/drivers/jpeg/config.h create mode 100644 u-boot-2021.10/drivers/jpeg/cvi_jpeg_cfg.h create mode 100644 u-boot-2021.10/drivers/jpeg/jdi.c create mode 100644 u-boot-2021.10/drivers/jpeg/jdi.h create mode 100644 u-boot-2021.10/drivers/jpeg/jdi_osal.c create mode 100644 u-boot-2021.10/drivers/jpeg/jdi_osal.h create mode 100644 u-boot-2021.10/drivers/jpeg/jpeg.c create mode 100644 u-boot-2021.10/drivers/jpeg/jpeg.h create mode 100644 u-boot-2021.10/drivers/jpeg/jpuapi.c create mode 100644 u-boot-2021.10/drivers/jpeg/jpuapi.h create mode 100644 u-boot-2021.10/drivers/jpeg/jpuapifunc.c create mode 100644 u-boot-2021.10/drivers/jpeg/jpuapifunc.h create mode 100644 u-boot-2021.10/drivers/jpeg/jpuconfig.h create mode 100644 u-boot-2021.10/drivers/jpeg/jpuhelper.c create mode 100644 u-boot-2021.10/drivers/jpeg/jpuhelper.h create mode 100644 u-boot-2021.10/drivers/jpeg/jpulog.h create mode 100644 u-boot-2021.10/drivers/jpeg/jpurun.c create mode 100644 u-boot-2021.10/drivers/jpeg/jpurun.h create mode 100644 u-boot-2021.10/drivers/jpeg/jputable.h create mode 100644 u-boot-2021.10/drivers/jpeg/jputypes.h create mode 100644 u-boot-2021.10/drivers/jpeg/mixer.c create mode 100644 u-boot-2021.10/drivers/jpeg/mixer.h create mode 100644 u-boot-2021.10/drivers/jpeg/mm.c create mode 100644 u-boot-2021.10/drivers/jpeg/mm.h create mode 100644 u-boot-2021.10/drivers/jpeg/regdefine.h diff --git a/u-boot-2021.10/cmd/cvi_jpeg.c b/u-boot-2021.10/cmd/cvi_jpeg.c new file mode 100644 index 000000000..6cfe1b98a --- /dev/null +++ b/u-boot-2021.10/cmd/cvi_jpeg.c @@ -0,0 +1,50 @@ +#include +#include +#include + +extern int jpeg_decoder(void *bs_addr, void *yuv_addr, int size); +extern int get_jpeg_size(int *width_addr, int *height_addr); + +static int do_cvi_jpeg_dec(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + char *bs_addr = NULL; + char *yuv_addr = NULL; + int size = 0; + + + if (argc != 4) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + bs_addr = (char *)simple_strtol(argv[1], NULL, 16); + + if (!bs_addr) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + yuv_addr = (char *)simple_strtol(argv[2], NULL, 16); + + if (!yuv_addr) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + size = (int)simple_strtol(argv[3], NULL, 16); + + if (!size) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + printf("\nstart jpeg dec task!, bs_addr %p, yuv_addr %p, size %d\n", bs_addr, yuv_addr, size); + + jpeg_decoder(bs_addr, yuv_addr, size); + get_jpeg_size((int *)(bs_addr + size - 8), (int *)(bs_addr + size - 4)); + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD(cvi_jpeg_dec, 4, 0, do_cvi_jpeg_dec, "Jpeg decoder ", "\n" +); diff --git a/u-boot-2021.10/drivers/jpeg/Makefile b/u-boot-2021.10/drivers/jpeg/Makefile new file mode 100644 index 000000000..b1f34e8d0 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CMD_CVI_JPEG) += mm.o jdi.o jpuapifunc.o jpeg.o jpuhelper.o jdi_osal.o jpuapi.o jpurun.o mixer.o diff --git a/u-boot-2021.10/drivers/jpeg/config.h b/u-boot-2021.10/drivers/jpeg/config.h new file mode 100644 index 000000000..a53eaeaff --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/config.h @@ -0,0 +1,48 @@ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WIN32) || defined(__MINGW32__) +# define PLATFORM_WIN32 +#elif defined(linux) || defined(__linux) || defined(ANDROID) +# define PLATFORM_LINUX +#else +# define PLATFORM_NON_OS +#endif + +#if defined(_MSC_VER) +# include +# include +# define inline _inline +# define VPU_DELAY_MS(X) Sleep(X) +//should change to delay function which can be delay a microsecond unut. +# define VPU_DELAY_US(X) Sleep(X) +# define kbhit _kbhit +# define getch _getch +#elif defined(__GNUC__) +#ifdef _KERNEL_ +# define VPU_DELAY_MS(X) udelay((X) * 1000) +# define VPU_DELAY_US(X) udelay(X) +#else +# define VPU_DELAY_MS(X) usleep((X) * 1000) +# define VPU_DELAY_US(X) usleep(X) +#endif +#elif defined(__ARMCC__) +#else +# error "Unknown compiler." +#endif + +#define PROJECT_ROOT "..\\..\\..\\" + +#if defined(JPU_FPGA_PLATFORM) +#if defined(ANDROID) || defined(linux) +#else +#define SUPPORT_CONF_TEST +#endif +#endif + +#define API_VERSION 165 + +#define HAVE_STDIN_H 1 +//#define MJPEG_ERROR_CONCEAL + +#endif /* __CONFIG_H__ */ diff --git a/u-boot-2021.10/drivers/jpeg/cvi_jpeg_cfg.h b/u-boot-2021.10/drivers/jpeg/cvi_jpeg_cfg.h new file mode 100644 index 000000000..3d79d11c4 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/cvi_jpeg_cfg.h @@ -0,0 +1,54 @@ +/* + * Copyright CviTek Inc. + * + * Created Time: Feb, 2020 + */ +#ifndef __CVI_JPEG_CFG_H__ +#define __CVI_JPEG_CFG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define BM_DBG_MSG_ENABLE + +#define BM_MASK_ERR 0x1 +#define BM_MASK_FLOW 0x2 +#define BM_MASK_MEM 0x4 +#define BM_MASK_TRACE 0x10 +#define BM_MASK_PERF 0x20 +#define BM_MASK_ALL 0xFFFF + +#ifdef BM_DBG_MSG_ENABLE +#define BM_DBG_ERR(msg, ...) if (jpu_level & BM_MASK_ERR)\ + { printf("[ERR] %s = %d, " msg, __func__, __LINE__, ## __VA_ARGS__); } +#define BM_DBG_FLOW(msg, ...) if (jpu_level & BM_MASK_FLOW)\ + { printf("[FLOW] %s = %d, " msg, __func__, __LINE__, ## __VA_ARGS__); } +#define BM_DBG_MEM(msg, ...) if (jpu_level & BM_MASK_MEM)\ + { printf("[MEM] %s = %d, " msg, __func__, __LINE__, ## __VA_ARGS__); } +#define BM_DBG_TRACE(msg, ...) if (jpu_level & BM_MASK_TRACE)\ + { printf("[TRACE] %s = %d, " msg, __func__, __LINE__, ## __VA_ARGS__); } +#define BM_DBG_PERF(msg, ...) if (jpu_level & BM_MASK_PERF)\ + { printf("[PERF] %s = %d, " msg, __func__, __LINE__, ## __VA_ARGS__); } +extern int jpu_level; +#else +#define BM_DBG_ERR(msg, ...) +#define BM_DBG_FLOW(msg, ...) +#define BM_DBG_MEM(msg, ...) +#define BM_DBG_TRACE(msg, ...) +#define BM_DBG_PERF(msg, ...) +#endif + +//#define PROFILE_PERFORMANCE +#define JPEG_CODEC_INTR_NUM 75 +//#define SUPPORT_INTERRUPT + +#ifdef SUPPORT_INTERRUPT +int irq_handler_jpeg_codec(int irqn, void *priv); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/u-boot-2021.10/drivers/jpeg/jdi.c b/u-boot-2021.10/drivers/jpeg/jdi.c new file mode 100644 index 000000000..0634ef345 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jdi.c @@ -0,0 +1,537 @@ +#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WIN32) || defined(__MINGW32__) +#elif defined(linux) || defined(__linux) || defined(ANDROID) + +#include +#include "jdi.h" +#include "jpulog.h" +#include "jdi_osal.h" +#include "dm/device.h" +#include "timer.h" +#include "asm/cache.h" + +#define JPU_BIT_REG_SIZE 0x1000 +#define JPU_BIT_REG_BASE (0x0B000000) + +/* + * DRAM Total Size = 256MB = 0x10000000 + * DRAM_PHYSICAL_BASE = 0x100000000 + + | Offset | Size | Note + * System | 0x100000000 | 0x2000000 | 32MB + * System Mem | 0x102000000 | 0x4000000 | 64MB + * File Buf | 0x106000000 | 0x2000000 | 32MB + * Enc BS | 0x108000000 | 0x1000000 | 16MB + * ENC SRC | 0x10C000000 | 0x1000000 | 16MB + * LOAD SRC | 0x10D000000 + */ +//#define SYSTEM_SIZE 0x2000000 +#define JDI_DRAM_PHYSICAL_BASE (0x130000000) +#define JDI_DRAM_PHYSICAL_SIZE 0x00200000 //0x004000000 + +#define JDI_SYSTEM_ENDIAN JDI_LITTLE_ENDIAN + +#define SPM_MEM_PHYSICAL_BASE 0x140000000 +#define SPM_MEM_PHYSICAL_SIZE 0xC0000000 +typedef struct jpu_buffer_t jpudrv_buffer_t; + +typedef struct jpu_buffer_pool_t { + jpudrv_buffer_t jdb; + int inuse; +} jpu_buffer_pool_t; + +static int s_jpu_fd; +static jpu_instance_pool_t *s_pjip; +static jpu_instance_pool_t s_jip; +static int s_task_num; +static int s_clock_state; +static jpudrv_buffer_t s_jdb_video_memory; +static jpudrv_buffer_t s_jdb_register; +static jpu_buffer_pool_t s_jpu_buffer_pool[MAX_JPU_BUFFER_POOL]; +static int s_jpu_buffer_pool_count; + +static int jpu_swap_endian(unsigned char *data, int len, int endian); +int jdi_probe(void) +{ + int ret; + + ret = jdi_init(); + jdi_release(); + + return ret; +} + +int jdi_init(void) +{ + int ret; + void *buf = NULL; + + if (s_jpu_fd != -1 && s_jpu_fd != 0x00) { + s_task_num++; + return 0; + } + + s_jpu_fd = 1; + + memset((void *)&s_jpu_buffer_pool, 0x00, sizeof(jpu_buffer_pool_t) * MAX_JPU_BUFFER_POOL); + s_jpu_buffer_pool_count = 0; + + s_pjip = jdi_get_instance_pool(); + if (!s_pjip) { + JLOG(ERR, "[jdi] fail to create instance pool for saving context\n"); + goto ERR_JDI_INIT; + } + + buf = malloc(JDI_DRAM_PHYSICAL_SIZE); + + if (buf) { + s_jdb_video_memory.phys_addr = (unsigned long)buf; + s_jdb_video_memory.size = JDI_DRAM_PHYSICAL_SIZE; + JLOG(INFO, "alloc s_jdb_video_memory.phys_addr buf %p\n", buf); + } else { + JLOG(ERR, "alloc s_jdb_video_memory.phys_addr failed\n"); + goto ERR_JDI_INIT; + } + + if (!s_pjip->instance_pool_inited) { + memset(&s_pjip->vmem, 0x00, sizeof(jpeg_mm_t)); + ret = jmem_init(&s_pjip->vmem, (unsigned long)s_jdb_video_memory.phys_addr, s_jdb_video_memory.size); + if (ret < 0) { + JLOG(ERR, "[JDI] fail to init jpu memory management logic\n"); + goto ERR_JDI_INIT; + } + } + + s_jdb_register.phys_addr = JPU_BIT_REG_BASE; + s_jdb_register.virt_addr = JPU_BIT_REG_BASE; + s_jdb_register.size = JPU_BIT_REG_SIZE; + + jdi_set_clock_gate(1); + + s_task_num++; + + JLOG(INFO, "[jdi] success to init driver\n"); + return s_jpu_fd; + +ERR_JDI_INIT: + + jdi_release(); + return -1; +} + +int jdi_release(void) +{ + + if (s_jpu_fd == -1 || s_jpu_fd == 0x00) + return 0; + + if (jdi_lock() < 0) { + JLOG(ERR, "[jdi] fail to handle lock function\n"); + return -1; + } + + if (s_task_num > 1) {// means that the opened instance remains + s_task_num--; + jdi_unlock(); + return 0; + } + + if (s_jdb_video_memory.phys_addr) { + JLOG(INFO, "free s_jdb_video_memory.phys_addr buf %p\n", (void *)s_jdb_video_memory.phys_addr); + free((void *)s_jdb_video_memory.phys_addr); + } + s_task_num--; + + jmem_exit(&s_pjip->vmem); + + memset(&s_jdb_register, 0x00, sizeof(jpudrv_buffer_t)); + + if (s_jpu_fd != -1 && s_jpu_fd != 0x00) + s_jpu_fd = -1; + + s_pjip = NULL; + + jdi_unlock(); + + return 0; +} + +jpu_instance_pool_t *jdi_get_instance_pool(void) +{ + if (!s_pjip) { + s_pjip = &s_jip; + + memset(s_pjip, 0x00, sizeof(jpu_instance_pool_t)); + } + + return (jpu_instance_pool_t *)s_pjip; +} + +int jdi_open_instance(unsigned long instIdx) +{ + if (!s_pjip || s_jpu_fd == -1 || s_jpu_fd == 0x00) + return -1; + + s_pjip->jpu_instance_num++; + + return 0; +} + +int jdi_close_instance(unsigned long instIdx) +{ + if (!s_pjip || s_jpu_fd == -1 || s_jpu_fd == 0x00) + return -1; + + s_pjip->jpu_instance_num--; + + return 0; +} + +int jdi_get_instance_num(void) +{ + if (!s_pjip || s_jpu_fd == -1 || s_jpu_fd == 0x00) + return -1; + + return s_pjip->jpu_instance_num; +} + +int jdi_hw_reset(void) +{ + if (!s_pjip || s_jpu_fd == -1 || s_jpu_fd == 0x00) + return -1; + + // to do any action for hw reset + + return 0; +} + +int jdi_lock(void) +{ + return 0; +} + +void jdi_unlock(void) +{ + +} + +void jdi_write_register(unsigned int addr, unsigned int data) +{ + unsigned long reg_addr; + + if (!s_pjip || s_jpu_fd == -1 || s_jpu_fd == 0x00) + return; + + reg_addr = addr + (unsigned long)s_jdb_register.virt_addr; + *(unsigned int *)reg_addr = data; + flush_dcache_range(reg_addr, reg_addr + sizeof(unsigned int)); +// flush_dcache_all(); +} + +unsigned int jdi_read_register(unsigned int addr) +{ + unsigned long reg_addr; + + reg_addr = addr + (unsigned long)s_jdb_register.virt_addr; +// INV_DCACHE_RANGE((unsigned int)reg_addr, sizeof(unsigned int)); +// invalidate_dcache_all(); + invalidate_dcache_range(reg_addr, reg_addr + sizeof(unsigned int)); + + return *(unsigned int *)reg_addr; +} + +int jdi_write_memory(unsigned long addr, unsigned char *data, int len, int endian) +{ + jpudrv_buffer_t jdb = {0, }; + unsigned long offset; + int i; + + if (!s_pjip || s_jpu_fd == -1 || s_jpu_fd == 0x00) + return -1; + + for (i = 0; i < MAX_JPU_BUFFER_POOL; i++) { + if (s_jpu_buffer_pool[i].inuse == 1) { + jdb = s_jpu_buffer_pool[i].jdb; + if (addr >= jdb.phys_addr && addr < (jdb.phys_addr + jdb.size)) + break; + } + } + + if (!jdb.size) { + JLOG(ERR, "address 0x%08lx is not mapped address!!!\n", addr); + return -1; + } + + offset = addr - (unsigned long)jdb.phys_addr; + + jpu_swap_endian(data, len, endian); + + //by zhao for cache testing + OSAL_MEMCPY((void *)((unsigned long)jdb.virt_addr + offset), (void *)data, len); + //josal_memcpy_nocache((void *)((unsigned long)jdb.virt_addr+offset), (void *)data, len); + return len; +} + +int jdi_read_memory(unsigned long addr, unsigned char *data, int len, int endian) +{ + jpudrv_buffer_t jdb = {0}; + unsigned long offset; + int i; + + if (!s_pjip || s_jpu_fd == -1 || s_jpu_fd == 0x00) + return -1; + + for (i = 0; i < MAX_JPU_BUFFER_POOL; i++) { + if (s_jpu_buffer_pool[i].inuse == 1) { + jdb = s_jpu_buffer_pool[i].jdb; + if (addr >= jdb.phys_addr && addr < (jdb.phys_addr + jdb.size)) + break; + } + } + + if (!jdb.size) + return -1; + + offset = addr - (unsigned long)jdb.phys_addr; + + INV_DCACHE_RANGE(((unsigned long)jdb.virt_addr + offset), len); + OSAL_MEMCPY(data, (const void *)((unsigned long)jdb.virt_addr + offset), len); + jpu_swap_endian(data, len, endian); + + return len; +} + +int jdi_allocate_dma_memory(jpu_buffer_t *vb) +{ + int i; + + unsigned long offset; + jpudrv_buffer_t jdb = {0, }; + + if (!s_pjip || s_jpu_fd == -1 || s_jpu_fd == 0x00) + return -1; + + jdb.size = vb->size; + jdb.phys_addr = (unsigned long)jmem_alloc(&s_pjip->vmem, jdb.size, 0); + + if (jdb.phys_addr == (unsigned long)-1) + return -1; // not enough memory + + offset = (unsigned long)(jdb.phys_addr - s_jdb_video_memory.phys_addr); + jdb.base = (unsigned long)s_jdb_video_memory.base + offset; + jdb.virt_addr = jdb.phys_addr; + + vb->phys_addr = (unsigned long)jdb.phys_addr; + vb->base = (unsigned long)jdb.base; + vb->virt_addr = (unsigned long)vb->phys_addr; + + for (i = 0; i < MAX_JPU_BUFFER_POOL; i++) { + if (s_jpu_buffer_pool[i].inuse == 0) { + s_jpu_buffer_pool[i].jdb = jdb; + s_jpu_buffer_pool_count++; + s_jpu_buffer_pool[i].inuse = 1; + break; + } + } + + return 0; +} + +void jdi_free_dma_memory(jpu_buffer_t *vb) +{ + int i; +// int ret = 0; + jpudrv_buffer_t jdb = {0, }; + + if (!s_pjip || s_jpu_fd == -1 || s_jpu_fd == 0x00) + return; + + if (vb->size == 0) + return; + + for (i = 0; i < MAX_JPU_BUFFER_POOL; i++) { + if (s_jpu_buffer_pool[i].jdb.phys_addr == vb->phys_addr) { + s_jpu_buffer_pool[i].inuse = 0; + s_jpu_buffer_pool_count--; + jdb = s_jpu_buffer_pool[i].jdb; + break; + } + } + + if (!jdb.size) { + JLOG(ERR, "[JDI] invalid buffer to free address = 0x%x\n", (int)jdb.virt_addr); + return; + } + + jmem_free(&s_pjip->vmem, (unsigned long)jdb.phys_addr, 0); + memset(vb, 0, sizeof(jpu_buffer_t)); +} + +int jdi_set_clock_gate(int enable) +{ + s_clock_state = enable; + + return 0; +} + +int jdi_get_clock_gate(void) +{ + return s_clock_state; +} + +static int intr_reason; + +int irq_handler_jpeg_codec(int irqn, void *priv) +{ + int curr_int = 0; + +#ifdef PROFILE_PERFORMANCE + int ms; + + ms = timer_meter_get_ms(); + BM_DBG_PERF("time = %d ms\n", ms); +#endif + + curr_int = jdi_read_register(MJPEG_PIC_STATUS_REG); + + intr_reason |= curr_int; + BM_DBG_TRACE("curr_int = 0x%X, intr_reason = 0x%X\n", curr_int, intr_reason); + + JpuWriteReg(MJPEG_PIC_STATUS_REG, curr_int); + + return 0; +} + +int jdi_wait_interrupt(int timeout) +{ +#ifdef SUPPORT_INTERRUPT + int out_reason = 0; + + while (1) { + BM_DBG_TRACE("intr_reason = 0x%X\n", intr_reason); + + out_reason = intr_reason; + if (out_reason) { + int int_en = jdi_read_register(MJPEG_INTR_MASK_REG); + + JpuWriteReg(MJPEG_INTR_MASK_REG, 0); + + intr_reason &= (~out_reason); + BM_DBG_TRACE("out_reason = 0x%X\n", out_reason); + + JpuWriteReg(MJPEG_INTR_MASK_REG, int_en); + break; + } + } + + return out_reason; +#else + + while (1) { + if (jdi_read_register(MJPEG_PIC_STATUS_REG)) + break; + + //Sleep(1); // 1ms sec + //if (count++ > timeout) + // return -1; + } + + return 0; +#endif +} + +void jdi_log(int cmd, int step) +{ + int i; + + switch (cmd) { + case JDI_LOG_CMD_PICRUN: + if (step == 1) { + JLOG(INFO, "\n**PIC_RUN start\n"); + } else { + JLOG(INFO, "\n**PIC_RUN end\n"); + } + break; + } + + for (i = 0; i <= 0x238; i = i + 16) { + JLOG(INFO, "0x%04xh: 0x%08x 0x%08x 0x%08x 0x%08x\n", i, + jdi_read_register(i), jdi_read_register(i + 4), + jdi_read_register(i + 8), jdi_read_register(i + 0xc)); + } +} + +int jpu_swap_endian(unsigned char *data, int len, int endian) +{ + unsigned long *p; + unsigned long v1, v2, v3; + int i; + int swap = 0; + + p = (unsigned long *)data; + + if (endian == JDI_SYSTEM_ENDIAN) + swap = 0; + else + swap = 1; + + if (swap) { + if (endian == JDI_LITTLE_ENDIAN || endian == JDI_BIG_ENDIAN) { + for (i = 0; i < len / 4; i += 2) { + v1 = p[i]; + v2 = (v1 >> 24) & 0xFF; + v2 |= ((v1 >> 16) & 0xFF) << 8; + v2 |= ((v1 >> 8) & 0xFF) << 16; + v2 |= ((v1 >> 0) & 0xFF) << 24; + v3 = v2; + v1 = p[i + 1]; + v2 = (v1 >> 24) & 0xFF; + v2 |= ((v1 >> 16) & 0xFF) << 8; + v2 |= ((v1 >> 8) & 0xFF) << 16; + v2 |= ((v1 >> 0) & 0xFF) << 24; + p[i] = v2; + p[i + 1] = v3; + } + } else { + int sys_endian = JDI_SYSTEM_ENDIAN; + int swap4byte = 0; + + swap = 0; + + if (endian == JDI_32BIT_LITTLE_ENDIAN) { + if (sys_endian == JDI_BIG_ENDIAN) { + swap = 1; + } + } else { + if (sys_endian == JDI_BIG_ENDIAN) { + swap4byte = 1; + } else if (sys_endian == JDI_LITTLE_ENDIAN) { + swap4byte = 1; + swap = 1; + } else { + swap = 1; + } + } + if (swap) { + for (i = 0; i < len / 4; i++) { + v1 = p[i]; + v2 = (v1 >> 24) & 0xFF; + v2 |= ((v1 >> 16) & 0xFF) << 8; + v2 |= ((v1 >> 8) & 0xFF) << 16; + v2 |= ((v1 >> 0) & 0xFF) << 24; + p[i] = v2; + } + } + if (swap4byte) { + for (i = 0; i < len / 4; i += 2) { + v1 = p[i]; + v2 = p[i + 1]; + p[i] = v2; + p[i + 1] = v1; + } + } + } + } + return swap; +} + +#endif diff --git a/u-boot-2021.10/drivers/jpeg/jdi.h b/u-boot-2021.10/drivers/jpeg/jdi.h new file mode 100644 index 000000000..6a89d0400 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jdi.h @@ -0,0 +1,118 @@ + +#ifndef _JDI_HPI_H_ +#define _JDI_HPI_H_ + +#include +//#include +#include "jpuconfig.h" +#include "regdefine.h" +#include "mm.h" +#include "jdi_osal.h" + +#define MAX_JPU_BUFFER_POOL 32 + +#define JpuWriteReg(ADDR, DATA) jdi_write_register(ADDR, DATA) // system register write +#define JpuReadReg(ADDR) jdi_read_register(ADDR) // system register write +#define JpuWriteMem(ADDR, DATA, LEN, ENDIAN) jdi_write_memory(ADDR, DATA, LEN, ENDIAN) // system memory write +#define JpuReadMem(ADDR, DATA, LEN, ENDIAN) jdi_read_memory(ADDR, DATA, LEN, ENDIAN) // system memory write + +typedef struct jpu_buffer_t { + unsigned int size; + unsigned long phys_addr; + unsigned long base; + unsigned long virt_addr; +} jpu_buffer_t; + +typedef struct jpu_instance_pool_t { + unsigned char jpgInstPool[MAX_NUM_INSTANCE][MAX_INST_HANDLE_SIZE]; + void *jpu_mutex; + int jpu_instance_num; + int instance_pool_inited; + void *pendingInst; + jpeg_mm_t vmem; +} jpu_instance_pool_t; + +#ifdef SUPPORT_128BIT_BUS + +typedef enum { + JDI_128BIT_LITTLE_64BIT_LITTLE_ENDIAN = ((0 << 2) + (0 << 1) + (0 << 0)), //128 bit little, 64 bit little + JDI_128BIT_BIG_64BIT_LITTLE_ENDIAN = ((1 << 2) + (0 << 1) + (0 << 0)), //128 bit big , 64 bit little + JDI_128BIT_LITTLE_64BIT_BIG_ENDIAN = ((0 << 2) + (0 << 1) + (1 << 0)), //128 bit little, 64 bit big + JDI_128BIT_BIG_64BIT_BIG_ENDIAN = ((1 << 2) + (0 << 1) + (1 << 0)), //128 bit big, 64 bit big + JDI_128BIT_LITTLE_32BIT_LITTLE_ENDIAN = ((0 << 2) + (1 << 1) + (0 << 0)), //128 bit little, 32 bit little + JDI_128BIT_BIG_32BIT_LITTLE_ENDIAN = ((1 << 2) + (1 << 1) + (0 << 0)), //128 bit big , 32 bit little + JDI_128BIT_LITTLE_32BIT_BIG_ENDIAN = ((0 << 2) + (1 << 1) + (1 << 0)), //128 bit little, 32 bit big + JDI_128BIT_BIG_32BIT_BIG_ENDIAN = ((1 << 2) + (1 << 1) + (1 << 0)), //128 bit big, 32 bit big +} EndianMode; + +#define JDI_LITTLE_ENDIAN JDI_128BIT_LITTLE_64BIT_LITTLE_ENDIAN +#define JDI_BIG_ENDIAN JDI_128BIT_BIG_64BIT_BIG_ENDIAN +#ifndef BIT(x) +#define BIT(x) (1 << (x)) +#endif +#define JDI_128BIT_ENDIAN_MASK BIT(2) +#define JDI_64BIT_ENDIAN_MASK BIT(1) +#define JDI_ENDIAN_MASK BIT(0) + +#define JDI_32BIT_LITTLE_ENDIAN JDI_128BIT_LITTLE_32BIT_LITTLE_ENDIAN +#define JDI_32BIT_BIG_ENDIAN JDI_128BIT_LITTLE_32BIT_BIG_ENDIAN + +#else + +typedef enum { + JDI_LITTLE_ENDIAN = 0, + JDI_BIG_ENDIAN, + JDI_32BIT_LITTLE_ENDIAN, + JDI_32BIT_BIG_ENDIAN, +} EndianMode; +#endif + +typedef enum { + JDI_LOG_CMD_PICRUN = 0, + JDI_LOG_CMD_MAX +} jdi_log_cmd; + +#if defined(__cplusplus) +extern "C" { +#endif + int jdi_probe(void); + int jdi_init(void); + int jdi_release(void); //this function may be called only at system off. + jpu_instance_pool_t *jdi_get_instance_pool(void); + int jdi_allocate_dma_memory(jpu_buffer_t *vb); + void jdi_free_dma_memory(jpu_buffer_t *vb); + + int jdi_wait_interrupt(int timeout); + int jdi_hw_reset(void); + + int jdi_set_clock_gate(int enable); + int jdi_get_clock_gate(void); + + int jdi_open_instance(unsigned long instIdx); + int jdi_close_instance(unsigned long instIdx); + int jdi_get_instance_num(void); + + void jdi_write_register(unsigned int addr, unsigned int data); + unsigned int jdi_read_register(unsigned int addr); + + int jdi_write_memory(unsigned long addr, unsigned char *data, int len, int endian); + int jdi_read_memory(unsigned long addr, unsigned char *data, int len, int endian); + + int jdi_lock(void); + void jdi_unlock(void); + void jdi_log(int cmd, int step); + +#ifdef JPU_FPGA_PLATFORM +#define HPI_SET_TIMING_MAX 1000 + int jdi_set_timing_opt(void); + int jdi_set_clock_freg(int Device, int OutFreqMHz, int InFreqMHz); +#endif + + int getch(void); + int kbhit(void); + +#if defined(__cplusplus) +} +#endif + +#endif //#ifndef _JDI_HPI_H_ diff --git a/u-boot-2021.10/drivers/jpeg/jdi_osal.c b/u-boot-2021.10/drivers/jpeg/jdi_osal.c new file mode 100644 index 000000000..01e9b6496 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jdi_osal.c @@ -0,0 +1,717 @@ +//------------------------------------------------------------------------------ +// File: vdi_osal.c +// +// Copyright (c) 2006, Chips & Media. All rights reserved. +//------------------------------------------------------------------------------ +//#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WIN32) || defined(__MINGW32__) +//#elif defined(linux) || defined(__linux) || defined(ANDROID) +//#else + +#include +#include +#include + +#include "jdi.h" +#include "jdi_osal.h" +#include "asm/cache.h" +#include "jpulog.h" + +#if defined(JPEG_FVP) +#define FILE_BUFFER_BASE 0xE0000000 +#elif defined(JPEG_FPGA) +#define FILE_BUFFER_BASE 0x116000000 +#endif + +#define FILE_BUFFER_BASE 0x138000000 + +#define MAX_LIST_NUM 1 +#define DEC_BS_FILE_BUFFER_BASE FILE_BUFFER_BASE +#define DEC_BS_FILE_BUFFER_SIZE (0x400000 * MAX_LIST_NUM) +#define DEC_YUV_FILE_BUFFER_BASE (DEC_BS_FILE_BUFFER_BASE + DEC_BS_FILE_BUFFER_SIZE) +#define DEC_YUV_FILE_BUFFER_SIZE (0x800000 * MAX_LIST_NUM) + +#define ENC_YUV_FILE_BUFFER_BASE (DEC_YUV_FILE_BUFFER_BASE + DEC_YUV_FILE_BUFFER_SIZE) +#define ENC_YUV_FILE_BUFFER_SIZE (0x800000 * MAX_LIST_NUM) +#define ENC_BS_FILE_BUFFER_BASE (ENC_YUV_FILE_BUFFER_BASE + ENC_YUV_FILE_BUFFER_SIZE) +#define ENC_BS_FILE_BUFFER_SIZE (0x400000 * MAX_LIST_NUM) +#define ENC_HUFF_FILE_BUFFER_BASE (ENC_BS_FILE_BUFFER_BASE + ENC_BS_FILE_BUFFER_SIZE) +#define ENC_HUFF_FILE_BUFFER_SIZE (0x100000 * MAX_LIST_NUM) +#define ENC_QMAT_FILE_BUFFER_BASE (ENC_HUFF_FILE_BUFFER_BASE + ENC_HUFF_FILE_BUFFER_BASE) +#define ENC_QMAT_FILE_BUFFER_SIZE (0x100000 * MAX_LIST_NUM) +#define ENC_QP_FILE_BUFFER_BASE (ENC_QMAT_FILE_BUFFER_BASE + ENC_QMAT_FILE_BUFFER_SIZE) +#define ENC_QP_FILE_BUFFER_SIZE (0x100000 * MAX_LIST_NUM) +#define ENC_CFG_FILE_BUFFER_BASE (ENC_QP_FILE_BUFFER_BASE + ENC_QP_FILE_BUFFER_SIZE) +#define ENC_CFG_FILE_BUFFER_SIZE (0x10000 * MAX_LIST_NUM) + +#define MULTI_FILE_BUFFER_BASE (ENC_CFG_FILE_BUFFER_BASE + ENC_CFG_FILE_BUFFER_SIZE) +#define MULTI_FILE_BUFFER_SIZE (0x10000) +#define MULTI_YUV_FILE_BUFFER_BASE (MULTI_FILE_BUFFER_BASE + MULTI_FILE_BUFFER_SIZE) +#define MULTI_YUV_FILE_BUFFER_SIZE (0x400000) + +#if defined(JPEG_FVP) +#define LOG_MSG_BUF_BASE 0xD0000000 +#elif defined(JPEG_FPGA) +#define LOG_MSG_BUF_BASE 0x120500000 +#endif + +#define LOG_MSG_BUF_BASE 0x120500000 // fixme fix me + +#define LOG_MSG_BUF_SIZE 0x100000 +static char *LOG_MSG_BUF = (char *)LOG_MSG_BUF_BASE; + +#define MAX_MALLOC_BLOCK_SIZE 0x50000//0x200000 +#define MAX_MALLOC_BLOCK_NUM 7 + +int jpu_level = BM_MASK_ERR; + +//To +#define FILE_BUFFER_SIZE 0x1000000 * (MAX_FD_NUM - 1) +#define CMP_FILE_BUFFER_SIZE 0x1000000 +unsigned char osal_malloc_heap[MAX_MALLOC_BLOCK_NUM][MAX_MALLOC_BLOCK_SIZE]; // allocate 64 4M-block for malloc +unsigned char osal_malloc_used[MAX_MALLOC_BLOCK_NUM] = {0}; + +typedef struct fileio_buf_t { + char *_ptr; + int _cnt; + char *_base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char *_tmpfname; +} fileio_buf_t; + +#define MAX_FD_NUM 5 // 0-bitstream file 1-yuv cmp file 2- +static fileio_buf_t s_file[MAX_FD_NUM] = {0}; + +static void myprintf(char *MsgBuf) +{ + int size = strlen(MsgBuf); + + if (size == 0) + return; + + if (LOG_MSG_BUF + size >= (char *)(LOG_MSG_BUF_BASE + LOG_MSG_BUF_SIZE)) + return; + + josal_memcpy(LOG_MSG_BUF, MsgBuf, size); + + LOG_MSG_BUF += size; +} + +void *josal_memcpy(void *dst, const void *src, int count) +{ + void *ret; + + ret = memcpy(dst, src, count); + flush_dcache_range((unsigned long)dst, count); + return ret; +} + +void *josal_memset(void *dst, int val, int count) +{ + return memset(dst, val, count); +} + +int josal_memcmp(const void *src, const void *dst, int size) +{ + return memcmp(src, dst, size); +} + +void *josal_malloc(int size) +{ + int i; + + if (size > MAX_MALLOC_BLOCK_SIZE || size == 0) + return NULL; + + for (i = 0; i < MAX_MALLOC_BLOCK_NUM; i++) + if (osal_malloc_used[i] == 0) + break; + + if (i < MAX_MALLOC_BLOCK_NUM) { + osal_malloc_used[i] = 1; +// JLOG(INFO, "malloc: %d, addr: 0x%p, size: %d\n", i, osal_malloc_heap[i], size); + return (void *)osal_malloc_heap[i]; + } + + return NULL; + +} + +void *josal_realloc(void *ptr, int size) +{ + if (!ptr) + return josal_malloc(size); + + if (size == 0 || size > MAX_MALLOC_BLOCK_SIZE) { + josal_free(ptr); + return NULL; + } + + if (size <= MAX_MALLOC_BLOCK_SIZE) + return ptr; + + return NULL; +} + +void josal_free(void *p) +{ + //free(p); + int i; + + for (i = 0; i < MAX_MALLOC_BLOCK_NUM; i++) + if ((void *)osal_malloc_heap[i] == p) + break; + + osal_malloc_used[i] = 0; +} + +int josal_fflush(osal_file_t fp) +{ + return 1; +} + +int josal_feof(osal_file_t fp) +{ + fileio_buf_t *p_fp = (fileio_buf_t *)fp; + + if ((uint64_t)p_fp->_ptr >= p_fp->_bufsiz) + return 1; + else + return 0; +} + +osal_file_t josal_fopen(const char *osal_file_tname, const char *mode) +{ + int i; + + for (i = 0; i < MAX_FD_NUM; i++) + if (s_file[i]._bufsiz == 0) // not used + break; + + if (i == MAX_FD_NUM) + return NULL; + + if (i != 1) // 1 - cmp file + s_file[i]._bufsiz = FILE_BUFFER_SIZE / (MAX_FD_NUM - 1); + else + s_file[i]._bufsiz = CMP_FILE_BUFFER_SIZE; // 256M for YUV compare file + + if (i == 0) + s_file[i]._base = (char *)FILE_BUFFER_BASE; + else + s_file[i]._base = s_file[i - 1]._base + s_file[i - 1]._bufsiz; + + s_file[i]._ptr = (char *)0; + + for (i = 0; i < MAX_FD_NUM; i++) { + JLOG(INFO, "file = %d, base = 0x%lX, size = 0x%lX\n", i, + (unsigned long)s_file[i]._base, + (unsigned long)s_file[i]._bufsiz); + } + + return &s_file[i]; +} + +size_t josal_fwrite(const void *p, int size, int count, osal_file_t fp) +{ + long addr; + long real_size; + fileio_buf_t *p_fp = (fileio_buf_t *)fp; + + if (!p_fp) + return 0; + + if ((unsigned long)(size * count + p_fp->_ptr) > p_fp->_bufsiz) + real_size = p_fp->_bufsiz - (unsigned long)p_fp->_ptr; + else + real_size = size * count; + + addr = (long)((long)p_fp->_base + (long)p_fp->_ptr); + josal_memcpy((void *)addr, (void *)p, real_size); + p_fp->_ptr += real_size; + + JLOG(INFO, "fp: 0x%lx, size: %ld\n", addr, real_size); + return real_size; +} + +size_t josal_fread(void *p, int size, int count, osal_file_t fp) +{ + long addr; + long real_size; + fileio_buf_t *p_fp = (fileio_buf_t *)fp; + + if (!p_fp) + return 0; + + if ((unsigned long)(size * count + p_fp->_ptr) > p_fp->_bufsiz) + real_size = p_fp->_bufsiz - (unsigned long)p_fp->_ptr; + else + real_size = size * count; + + addr = (long)((long)p_fp->_base + (long)p_fp->_ptr); + josal_memcpy((void *)p, (void *)addr, real_size); + p_fp->_ptr += real_size; + + //printf("p_fp: _ptr = 0x%016llx _base = 0x%016llx _bufsiz = 0x%08x\n", + // (uint64_t)p_fp->_ptr, (uint64_t)p_fp->_base, p_fp->_bufsiz); + + return real_size; +} + +char *josal_fgets(void *p, int size, osal_file_t fp) +{ + int s = josal_fread(p, 1, size, fp); + + if (s == size) + return p; + else + return NULL; +} + +char josal_fgetc(osal_file_t fp) +{ + char *ptr; + fileio_buf_t *p_fp = (fileio_buf_t *)fp; + + if (!p_fp) + return -1; + + if ((unsigned long)p_fp->_ptr + sizeof(char) == p_fp->_bufsiz) + return -1; + + ptr = p_fp->_base + (unsigned long)p_fp->_ptr; + p_fp->_ptr++; + + return *ptr; +} + +size_t josal_fputs(const char *s, osal_file_t fp) +{ + return josal_fwrite(s, sizeof(char), strlen(s), fp); +} + +long josal_ftell(osal_file_t fp) +{ + fileio_buf_t *p_fp = (fileio_buf_t *)fp; + + return p_fp->_bufsiz; +} + +int josal_fseek(osal_file_t fp, long offset, int origin) +{ + char *curr_p; + fileio_buf_t *p_fp = (fileio_buf_t *)fp; + + if (!fp) + return -1; + + switch (origin) { + case SEEK_CUR: + curr_p = (char *)p_fp->_ptr; + break; + case SEEK_END: + curr_p = (char *)(uint64_t)p_fp->_bufsiz; + break; + case SEEK_SET: + curr_p = (char *)0; + break; + default: + return -1; + } + + p_fp->_ptr = curr_p + offset; + if (p_fp->_ptr > p_fp->_base + p_fp->_bufsiz) + p_fp->_ptr = p_fp->_base + p_fp->_bufsiz; + + return 0; +} + +int josal_fclose(osal_file_t fp) +{ + fileio_buf_t *p_fp = (fileio_buf_t *)fp; + + if (!p_fp) + return -1; + + p_fp->_base = (char *)0; + p_fp->_bufsiz = 0; + p_fp->_ptr = (char *)0; + + return 1; +} + +int josal_fscanf(osal_file_t fp, const char *_Format, ...) +{ + return 1; +} + +int josal_fprintf(osal_file_t fp, const char *_Format, ...) +{ + va_list ptr; + char logBuf[MAX_PRINT_LENGTH] = {0}; + + va_start(ptr, _Format); + + vsnprintf(logBuf, MAX_PRINT_LENGTH, _Format, ptr); + + va_end(ptr); + + myprintf(logBuf); + + return 1; + +} + +int josal_kbhit(void) +{ + return 0; +} + +int josal_getch(void) +{ + return -1; +} + +int josal_flush_ch(void) +{ + return -1; +} + +int josal_srand(int seed) +{ + return 0; +} + +/* to return a integer between 0~FEEDING_MAX_SIZE(4M) */ +int josal_rand(void) +{ + return 0x10000; +} + +/* to conver c to upper case */ +int josal_toupper(int c) +{ + int ret = c; + char *ptr = (char *)&ret; + int i; + + for (i = 0; i < sizeof(int); i++) { + if (ptr[i] > 96 && ptr[i] < 123) + ptr[i++] -= 32; + } + return ret; +} + +void jinv_dcache_range(unsigned long start, unsigned long size) +{ + invalidate_dcache_range(start, size); +} + +#ifdef LIB_C_STUB + +/* + * newlib_stubs.c + * the bellow code is just to build ref-code. + * customers will removed the bellow code bacuase they need a library which is related to the + * system library such as newlibc + */ +#include +#include +#include +#include + +#ifndef STDOUT_USART +#define STDOUT_USART 0 +#endif + +#ifndef STDERR_USART +#define STDERR_USART 0 +#endif + +#ifndef STDIN_USART +#define STDIN_USART 0 +#endif + +#undef errno +int errno; +extern int errno; + +/* + * environ + * A pointer to a list of environment variables and their values. + * For a minimal environment, this empty list is adequate: + */ +char *__env[1] = { 0 }; +char **environ = __env; + +//int _write(int file, char *ptr, int len); + +void _exit(int status) +{ + _write(1, "exit", 4); + while (1) { + ; + } +} + +int _close(int file) +{ + return -1; +} + +/* + * execve + * Transfer control to a new process. Minimal implementation (for a system without processes): + */ +int _execve(char *name, char **argv, char **env) +{ + errno = ENOMEM; + return -1; +} + +/* + * fork + * Create a new process. Minimal implementation (for a system without processes): + */ +int _fork(void) +{ + errno = EAGAIN; + return -1; +} + +/* + * fstat + * Status of an open file. For consistency with other minimal implementations in these examples, + * all files are regarded as character special devices. + * The `sys/stat.h' header file required is distributed in the `include' subdirectory for this C library. + */ +int _fstat(int file, struct stat *st) +{ + st->st_mode = S_IFCHR; + return 0; +} + +/* + * getpid + * Process-ID; this is sometimes used to generate strings unlikely to conflict with other processes. + * Minimal implementation, + * for a system without processes: + */ +int _getpid(void) +{ + return 1; +} + +/* + * isatty + * Query whether output stream is a terminal. For consistency with the other minimal implementations, + */ +int _isatty(int file) +{ + switch (file) { + case STDOUT_FILENO: + case STDERR_FILENO: + case STDIN_FILENO: + return 1; + default: + //errno = ENOTTY; + errno = EBADF; + return 0; + } +} + +/* + * kill + * Send a signal. Minimal implementation: + */ +int _kill(int pid, int sig) +{ + errno = EINVAL; + return (-1); +} + +/* + * link + * Establish a new name for an existing file. Minimal implementation: + */ + +int _link(char *old, char *new) +{ + errno = EMLINK; + return -1; +} + +/* + * lseek + * Set position in a file. Minimal implementation: + */ +int _lseek(int file, int ptr, int dir) +{ + return 0; +} + +/* + * sbrk + * Increase program data space. + * Malloc and related functions depend on this + */ +caddr_t _sbrk(int incr) +{ + + // extern char _ebss; // Defined by the linker + char _ebss; + static char *heap_end; + char *prev_heap_end; + + if (heap_end == 0) { + heap_end = &_ebss; + } + prev_heap_end = heap_end; + + heap_end += incr; + return (caddr_t)prev_heap_end; +} + +/* + * read + * Read a character to a file. `libc' subroutines will use this system routine for input from all files, + * including stdin + * Returns -1 on error or blocks until the number of characters have been read. + */ + +int _read(int file, char *ptr, int len) +{ + int n; + int num = 0; + + switch (file) { + case STDIN_FILENO: + for (n = 0; n < len; n++) { + char c = 0; +#if STDIN_USART == 1 + while ((USART1->SR & USART_FLAG_RXNE) == (u16)RESET) { + } + c = (char)(USART1->DR & (u16)0x01FF); +#elif STDIN_USART == 2 + while ((USART2->SR & USART_FLAG_RXNE) == (u16)RESET) { + } + c = (char)(USART2->DR & (u16)0x01FF); +#elif STDIN_USART == 3 + while ((USART3->SR & USART_FLAG_RXNE) == (u16)RESET) { + } + c = (char)(USART3->DR & (u16)0x01FF); +#endif + *ptr++ = c; + num++; + } + break; + default: + errno = EBADF; + return -1; + } + return num; +} + +/* + * stat + * Status of a file (by name). Minimal implementation: + * int _EXFUN(stat,( const char *__path, struct stat *__sbuf )); + */ +int stat(const char *filepath, struct stat *st) +{ + return _stat(filepath, st); +} + +int _stat(const char *filepath, struct stat *st) +{ + st->st_mode = S_IFCHR; + st->st_size = CMP_FILE_BUFFER_SIZE; + return 0; +} + +/* + * times + * Timing information for current process. Minimal implementation: + */ +clock_t _times(struct tms *buf) +{ + return -1; +} + +/* + * unlink + * Remove a file's directory entry. Minimal implementation: + */ +int _unlink(char *name) +{ + errno = ENOENT; + return -1; +} + +/* + * wait + * Wait for a child process. Minimal implementation: + */ +int _wait(int *status) +{ + errno = ECHILD; + return -1; +} + +/* + * write + * Write a character to a file. `libc' subroutines will use this system routine for output to all files, + * including stdout + * Returns -1 on error or number of bytes sent + */ +int _write(int file, char *ptr, int len) +{ + int n; + + switch (file) { + case STDOUT_FILENO: /*stdout*/ + for (n = 0; n < len; n++) { +#if STDOUT_USART == 1 + while ((USART1->SR & USART_FLAG_TC) == (u16)RESET) { + } + USART1->DR = (*ptr++ & (u16)0x01FF); +#elif STDOUT_USART == 2 + while ((USART2->SR & USART_FLAG_TC) == (u16)RESET) { + } + USART2->DR = (*ptr++ & (u16)0x01FF); +#elif STDOUT_USART == 3 + while ((USART3->SR & USART_FLAG_TC) == (u16)RESET) { + } + USART3->DR = (*ptr++ & (u16)0x01FF); +#endif + } + break; + case STDERR_FILENO: /* stderr */ + for (n = 0; n < len; n++) { +#if STDERR_USART == 1 + while ((USART1->SR & USART_FLAG_TC) == (u16)RESET) { + } + USART1->DR = (*ptr++ & (u16)0x01FF); +#elif STDERR_USART == 2 + while ((USART2->SR & USART_FLAG_TC) == (u16)RESET) { + } + USART2->DR = (*ptr++ & (u16)0x01FF); +#elif STDERR_USART == 3 + while ((USART3->SR & USART_FLAG_TC) == (u16)RESET) { + } + USART3->DR = (*ptr++ & (u16)0x01FF); +#endif + } + break; + default: + errno = EBADF; + return -1; + } + return len; +} + +#endif +//#endif + diff --git a/u-boot-2021.10/drivers/jpeg/jdi_osal.h b/u-boot-2021.10/drivers/jpeg/jdi_osal.h new file mode 100644 index 000000000..abd0e4743 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jdi_osal.h @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +// File: log.h +// +// Copyright (c) 2006, Chips & Media. All rights reserved. +//------------------------------------------------------------------------------ + +#ifndef _VDI_OSAL_H_ +#define _VDI_OSAL_H_ + +//#include +#include +//#include +#include "cvi_jpeg_cfg.h" + +#define MAX_PRINT_LENGTH 512 + +typedef void *osal_file_t; +# ifndef SEEK_SET +# define SEEK_SET 0 +# endif + +# ifndef SEEK_CUR +# define SEEK_CUR 1 +# endif + +# ifndef SEEK_END +# define SEEK_END 2 +# endif + +#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WIN32) || defined(__MINGW32__) +#elif defined(linux) || defined(__linux) || defined(ANDROID) + +//#ifndef stdout +//# define stdout (void * )1 +//#endif +//#ifndef stderr +//# define stderr (void * )1 +//#endif + +#define OSAL_MEMCPY josal_memcpy +#define OSAL_MEMCMP josal_memcmp +#define OSAL_MALLOC josal_malloc +#define OSAL_FREE josal_free +#define OSAL_FOPEN josal_fopen +#define OSAL_FWRITE josal_fwrite +#define OSAL_FREAD josal_fread +#define OSAL_FSEEK josal_fseek +#define OSAL_FCLOSE josal_fclose +#define OSAL_FFLUSH josal_fflush +#define OSAL_FEOF josal_feof +#define OSAL_FGETS josal_fgets +#define INV_DCACHE_RANGE jinv_dcache_range + +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +//memory +void *josal_memcpy(void *dst, const void *src, int count); +void *josal_memset(void *dst, int val, int count); +int josal_memcmp(const void *src, const void *dst, int size); +void *josal_malloc(int size); +void *josal_realloc(void *ptr, int size); +void josal_free(void *p); + +osal_file_t josal_fopen(const char *osal_file_tname, const char *mode); +size_t josal_fwrite(const void *p, int size, int count, osal_file_t fp); +size_t josal_fread(void *p, int size, int count, osal_file_t fp); +long josal_ftell(osal_file_t fp); +int josal_fseek(osal_file_t fp, long offset, int origin); +int josal_fclose(osal_file_t fp); +int josal_fflush(osal_file_t fp); +int josal_fprintf(osal_file_t fp, const char *_Format, ...); +int josal_fscanf(osal_file_t fp, const char *_Format, ...); +int josal_kbhit(void); +int josal_getch(void); +int josal_flush_ch(void); +int josal_feof(osal_file_t fp); +void *josal_create_mutex(const char *name); +void josal_close_mutex(void *handle); +int josal_mutex_lock(void *handle); +int josal_mutex_unlock(void *handle); +char josal_fgetc(osal_file_t fp); +char *josal_fgets(void *p, int size, osal_file_t fp); +int josal_srand(int seed); +int josal_rand(void); +int josal_toupper(int c); +size_t josal_fputs(const char *s, osal_file_t fp); +void jinv_dcache_range(unsigned long start, unsigned long size); + +#if defined(__cplusplus) +} +#endif + +#endif //#ifndef _VDI_OSAL_H diff --git a/u-boot-2021.10/drivers/jpeg/jpeg.c b/u-boot-2021.10/drivers/jpeg/jpeg.c new file mode 100644 index 000000000..577dbd040 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpeg.c @@ -0,0 +1,155 @@ +#include "jpuconfig.h" +#include "regdefine.h" +#include "jpulog.h" +#include "jpurun.h" +#include "jpuhelper.h" +#include "jdi_osal.h" +#include + +typedef struct v { + int mode; // 1 = dec, 2 = enc + int comparatorFlag; + int packedFormat; + int chroma_interleave; + int usePartialMode; + int partialBufNum; + int rot_angle; + int mirDir; + int outNum; + int roiEnable; + int roiWidth; + int roiHeight; + int mjpgChromaFormat; + int roiOffsetX; + int roiOffsetY; + int iHorScaleMode; + int iVerScaleMode; + int fileSize; + void *bs_addr; + void *yuv_addr; +} dec_cfg_t; + +#define mmio_write_32(a, v) writel(v, a) +#define mmio_read_32(a) readl(a) + +enum _mode_ { + MODE_DEC = 1, + MODE_ENC, +}; + +enum _packFormat_ { + PACK_PLANAR = 0, + PACK_YUYV, + PACK_UYVY, + PACK_YVYU, + PACK_VYUY, + PACK_YUV_444_PACKED, +} packFormat; + +enum _partialMode_ { + PARTIAL_MODE_DISABLE = 0, + PARTIAL_MODE_ENABLE, +}; + +enum _rorateAngle_ { + ROTATE_0 = 0, + ROTATE_90 = 90, + ROTATE_180 = 180, + ROTATE_270 = 270, +}; + +enum _mirror_dir_ { + MIRROR_NO = 0, + MIRROR_VERTICAL, + MIRROR_HORIZONTAL, + MIRROR_BOTH, +}; + +int jpeg_dec(dec_cfg_t *cfg, void *bs_addr, void *yuv_addr, int size) +{ + int ret = 0; + DecConfigParam decConfig; + + memset(&decConfig, 0x00, sizeof(DecConfigParam)); + + decConfig.bitstreamFileName = NULL; + decConfig.StreamEndian = JPU_STREAM_ENDIAN; + decConfig.FrameEndian = JPU_FRAME_ENDIAN; + decConfig.yuvFileName = NULL; + decConfig.comparatorFlag = cfg->comparatorFlag; + decConfig.packedFormat = cfg->packedFormat; + decConfig.chroma_interleave = cfg->chroma_interleave; + decConfig.usePartialMode = cfg->usePartialMode; + decConfig.partialBufNum = cfg->partialBufNum; + decConfig.rot_angle = cfg->rot_angle; + decConfig.mirDir = cfg->mirDir; + decConfig.outNum = cfg->outNum; + decConfig.roiEnable = cfg->roiEnable; + decConfig.roiWidth = cfg->roiWidth; + decConfig.roiHeight = cfg->roiHeight; + decConfig.roiOffsetX = cfg->roiOffsetX; + decConfig.roiOffsetY = cfg->roiOffsetY; + decConfig.iHorScaleMode = cfg->iHorScaleMode; + decConfig.iVerScaleMode = cfg->iVerScaleMode; + decConfig.bs_addr = bs_addr; + decConfig.yuv_addr = yuv_addr; + decConfig.size = size; + + if (!decConfig.usePartialMode) { + if (decConfig.rot_angle != 0 && decConfig.rot_angle != 90 && + decConfig.rot_angle != 180 && decConfig.rot_angle != 270) { + JLOG(ERR, "Invalid rotation angle.\n"); + return 1; + } + + if (decConfig.mirDir != 0 && decConfig.mirDir != 1 && + decConfig.mirDir != 2 && decConfig.mirDir != 3) { + JLOG(ERR, "Invalid mirror direction.\n"); + return 1; + } + + if (decConfig.rot_angle != 0 || decConfig.mirDir != 0) + decConfig.useRot = 1; + } + + ret = jpeg_decode_helper(&decConfig); + + return 1 - ret; +} + +int jpeg_decoder(void *bs_addr, void *yuv_addr, int size) +{ + dec_cfg_t allCfgs[] = { + // comp + // {MODE_ENC, 1, PACK_PLANAR, 0, PARTIAL_MODE_DISABLE, 2, ROTATE_0, MIRROR_NO, 1, + // 0, 3840, 2160, PACK_PLANAR, 0, 0, 0, 0, 40681 }, + {MODE_DEC, 1, PACK_PLANAR, 0, PARTIAL_MODE_DISABLE, 4, ROTATE_0, MIRROR_NO, 1, + 0, 300, 300, 0, 50, 50, 0, 0, 0x23431}, + }; + + int idx, ret = 0, all = 0; + + mmio_write_32((void *)TOP_DDR_ADDR_MODE_REG, (1 << DAMR_REG_VD_REMAP_ADDR_39_32_OFFSET)); + mmio_write_32((void *)VC_REG_BASE, (mmio_read_32((void *)VC_REG_BASE) | (0x1f))); + +#ifdef SUPPORT_INTERRUPT + request_irq(JPEG_CODEC_INTR_NUM, irq_handler_jpeg_codec, 0, "jpeg int", NULL); + BM_DBG_TRACE("irq num = %d\n", JPEG_INTRPT_REQ); +#endif + + for (idx = 0; idx < sizeof(allCfgs) / sizeof(dec_cfg_t); idx++) { + if (allCfgs[idx].mode == MODE_DEC) + ret = jpeg_dec(&allCfgs[idx], bs_addr, yuv_addr, size); +// else +// ret = jpeg_enc_slt_test(&allCfgs[idx]); + + if (ret) { + JLOG(NONE, "case %d, error\n", idx); + all = 1; + } else + JLOG(NONE, "case %d, success\n", idx); + } + + JLOG(NONE, "jpeg decode %s\n", all ? "failed" : "passed"); + return all; +} diff --git a/u-boot-2021.10/drivers/jpeg/jpeg.h b/u-boot-2021.10/drivers/jpeg/jpeg.h new file mode 100644 index 000000000..dd6e6a14c --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpeg.h @@ -0,0 +1,6 @@ +#ifndef _JPEG_H_ +#define _JPEG_H_ + +int jpeg_decoder(void *bs_addr, void *yuv_addr, int size); + +#endif diff --git a/u-boot-2021.10/drivers/jpeg/jpuapi.c b/u-boot-2021.10/drivers/jpeg/jpuapi.c new file mode 100644 index 000000000..22cc5dcdf --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpuapi.c @@ -0,0 +1,1834 @@ + +#include "jpuapi.h" +#include "jpuapifunc.h" + +#include "jpulog.h" +#include "dm/device.h" +#include "timer.h" + +static unsigned char sJpuCompInfoTable[5][24] = { + {00, 02, 02, 00, 00, 00, 01, 01, 01, 01, 01, 01, + 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00}, // 420 + {00, 02, 01, 00, 00, 00, 01, 01, 01, 01, 01, 01, + 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00}, // 422H + {00, 01, 02, 00, 00, 00, 01, 01, 01, 01, 01, 01, + 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00}, // 422V + {00, 01, 01, 00, 00, 00, 01, 01, 01, 01, 01, 01, + 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00}, // 444 + {00, 01, 01, 00, 00, 00, 01, 00, 00, 00, 00, 00, + 02, 00, 00, 00, 00, 00, 03, 00, 00, 00, 00, 00}, // 400 +}; + +int JPU_IsBusy(void) +{ + Uint32 val; + + val = JpuReadReg(MJPEG_PIC_STATUS_REG); + + if ((val & (1 << INT_JPU_DONE)) || (val & (1 << INT_JPU_ERROR))) + return 0; + + return 1; +} + +void JPU_ClrStatus(Uint32 val) +{ + if (val != 0) + JpuWriteReg(MJPEG_PIC_STATUS_REG, val); +} + +Uint32 JPU_GetStatus(void) +{ + return JpuReadReg(MJPEG_PIC_STATUS_REG); +} + +Uint32 JPU_IsInit(void) +{ + jpu_instance_pool_t *pjip; + + pjip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + + if (!pjip) + return 0; + + return 1; +} + +Uint32 JPU_WaitInterrupt(int timeout) +{ + Uint32 reason = 0; +#ifdef SUPPORT_INTERRUPT + reason = jdi_wait_interrupt(timeout); + BM_DBG_TRACE("reason = 0x%X\n", reason); +#else + + reason = jdi_wait_interrupt(timeout); + BM_DBG_TRACE("reason = 0x%X\n", reason); + + JpgSetClockGate(1); + + if (reason != (Uint32)-1) + reason = JpuReadReg(MJPEG_PIC_STATUS_REG); + + JpgSetClockGate(0); +#endif + return reason; +} + +int JPU_GetOpenInstanceNum(void) +{ + jpu_instance_pool_t *pjip; + + pjip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + if (!pjip) + return -1; + + return pjip->jpu_instance_num; +} + +JpgRet JPU_Init(void) +{ + jpu_instance_pool_t *pjip; + + if (jdi_init() < 0) + return JPG_RET_FAILURE; + + pjip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + if (!pjip) + return JPG_RET_FAILURE; + + InitJpgInstancePool(); + JPU_SWReset(); + return JPG_RET_SUCCESS; +} + +void JPU_DeInit(void) +{ + jdi_release(); +} + +JpgRet JPU_GetVersionInfo(Uint32 *versionInfo) +{ + + if (JPU_IsInit() == 0) { + return JPG_RET_NOT_INITIALIZED; + } + + *versionInfo = API_VERSION; + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecOpen(JpgDecHandle *pHandle, JpgDecOpenParam *pop) +{ + JpgInst *pJpgInst; + JpgDecInfo *pDecInfo; + JpgRet ret; + + ret = CheckJpgDecOpenParam(pop); + if (ret != JPG_RET_SUCCESS) { + return ret; + } + + ret = GetJpgInstance(&pJpgInst); + if (ret == JPG_RET_FAILURE) { + *pHandle = 0; + JpgLeaveLock(); + return JPG_RET_FAILURE; + } + + *pHandle = pJpgInst; + + pDecInfo = &pJpgInst->JpgInfo.decInfo; + memset(pDecInfo, 0x00, sizeof(JpgDecInfo)); + + pDecInfo->streamWrPtr = pop->bitstreamBuffer; + pDecInfo->streamRdPtr = pop->bitstreamBuffer; + + pDecInfo->streamBufStartAddr = pop->bitstreamBuffer; + pDecInfo->streamBufSize = pop->bitstreamBufferSize; + pDecInfo->streamBufEndAddr = + pop->bitstreamBuffer + pop->bitstreamBufferSize; + JpuWriteReg(MJPEG_BBC_BAS_ADDR_REG, pDecInfo->streamBufStartAddr); + JpuWriteReg(MJPEG_BBC_END_ADDR_REG, pDecInfo->streamBufEndAddr); + JpuWriteReg(MJPEG_BBC_RD_PTR_REG, pDecInfo->streamRdPtr); + JpuWriteReg(MJPEG_BBC_WR_PTR_REG, pDecInfo->streamWrPtr); + JpuWriteReg(MJPEG_BBC_STRM_CTRL_REG, 0); + + pDecInfo->pBitStream = pop->pBitStream; + pDecInfo->streamEndian = pop->streamEndian; + pDecInfo->frameEndian = pop->frameEndian; + pDecInfo->chroma_interleave = pop->chroma_interleave; + pDecInfo->packedFormat = pop->packedFormat; + pDecInfo->roiEnable = pop->roiEnable; + pDecInfo->roiWidth = pop->roiWidth; + pDecInfo->roiHeight = pop->roiHeight; + pDecInfo->roiOffsetX = pop->roiOffsetX; + pDecInfo->roiOffsetY = pop->roiOffsetY; + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecClose(JpgDecHandle handle) +{ + JpgInst *pJpgInst; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + + JpgEnterLock(); + FreeJpgInstance(pJpgInst); + JpgLeaveLock(); + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecGetInitialInfo(JpgDecHandle handle, JpgDecInitialInfo *info) +{ + JpgInst *pJpgInst; + JpgDecInfo *pDecInfo; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) { + BM_DBG_ERR("CheckJpgInstValidity\n"); + return ret; + } + + if (info == 0) { + return JPG_RET_INVALID_PARAM; + } + pJpgInst = handle; + pDecInfo = &pJpgInst->JpgInfo.decInfo; + + if (JpegDecodeHeader(pDecInfo) <= 0) { + BM_DBG_ERR("JpegDecodeHeader\n"); + return JPG_RET_FAILURE; + } + + info->picWidth = pDecInfo->picWidth; + info->picHeight = pDecInfo->picHeight; + info->minFrameBufferCount = 1; + info->sourceFormat = pDecInfo->format; + info->ecsPtr = pDecInfo->ecsPtr; + + JLOG(ERR, "pDecInfo->format %d\n", pDecInfo->format); + + pDecInfo->initialInfoObtained = 1; + pDecInfo->minFrameBufferNum = 1; + +#ifdef MJPEG_ERROR_CONCEAL + pDecInfo->curRstIdx = 0; + pDecInfo->nextRstIdx = -1; +#endif + + if (pDecInfo->packedFormat == PACKED_FORMAT_444 && + pDecInfo->format != FORMAT_444) { + return JPG_RET_INVALID_PARAM; + } + + if (pDecInfo->roiEnable) { + pDecInfo->roiMcuWidth = pDecInfo->roiWidth / pDecInfo->mcuWidth; + pDecInfo->roiMcuHeight = pDecInfo->roiHeight / pDecInfo->mcuHeight; + pDecInfo->roiMcuOffsetX = pDecInfo->roiOffsetX / pDecInfo->mcuWidth; + pDecInfo->roiMcuOffsetY = pDecInfo->roiOffsetY / pDecInfo->mcuHeight; + + if (pDecInfo->roiOffsetX > pDecInfo->alignedWidth || + pDecInfo->roiOffsetY > pDecInfo->alignedHeight || + pDecInfo->roiOffsetX + pDecInfo->roiWidth > pDecInfo->alignedWidth || + pDecInfo->roiOffsetY + pDecInfo->roiHeight > pDecInfo->alignedHeight) + return JPG_RET_INVALID_PARAM; + + if (((pDecInfo->roiOffsetX + pDecInfo->roiWidth) < pDecInfo->mcuWidth) || + ((pDecInfo->roiOffsetY + pDecInfo->roiHeight) < pDecInfo->mcuHeight)) + return JPG_RET_INVALID_PARAM; + + info->roiFrameWidth = pDecInfo->roiMcuWidth * pDecInfo->mcuWidth; + info->roiFrameHeight = pDecInfo->roiMcuHeight * pDecInfo->mcuHeight; + info->roiFrameOffsetX = pDecInfo->roiMcuOffsetX * pDecInfo->mcuWidth; + info->roiFrameOffsetY = pDecInfo->roiMcuOffsetY * pDecInfo->mcuHeight; + info->roiMCUSize = pDecInfo->mcuWidth; + } + info->colorComponents = pDecInfo->compNum; + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecRegisterFrameBuffer(JpgDecHandle handle, FrameBuffer *bufArray, + int num, int strideY, int strideC) +{ + JpgInst *pJpgInst; + JpgDecInfo *pDecInfo; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + pDecInfo = &pJpgInst->JpgInfo.decInfo; + + if (!pDecInfo->initialInfoObtained) { + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + if (bufArray == 0) { + return JPG_RET_INVALID_FRAME_BUFFER; + } + + if (num < pDecInfo->minFrameBufferNum) { + return JPG_RET_INSUFFICIENT_FRAME_BUFFERS; + } + if (pDecInfo->usePartial && pDecInfo->bufNum == 0) { + return JPG_RET_INSUFFICIENT_FRAME_BUFFERS; + } + if (pDecInfo->usePartial && num < pDecInfo->bufNum) { + return JPG_RET_INSUFFICIENT_FRAME_BUFFERS; + } + + if (!pDecInfo->roiEnable) { + if (strideY < pDecInfo->picWidth >> 3 || strideY % 8 != 0) + return JPG_RET_INVALID_STRIDE; + } + + pDecInfo->frameBufPool = bufArray; + pDecInfo->numFrameBuffers = num; + pDecInfo->stride = strideY; + pDecInfo->strideY = strideY; + pDecInfo->strideC = strideC; + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecGetBitstreamBuffer(JpgDecHandle handle, PhysicalAddress *prdPrt, + PhysicalAddress *pwrPtr, int *size) +{ + JpgInst *pJpgInst; + JpgDecInfo *pDecInfo; + JpgRet ret; + PhysicalAddress rdPtr; + PhysicalAddress wrPtr; + int room; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + if (prdPrt == 0 || pwrPtr == 0 || size == 0) { + return JPG_RET_INVALID_PARAM; + } + + pJpgInst = handle; + pDecInfo = &pJpgInst->JpgInfo.decInfo; + + if (GetJpgPendingInst() == pJpgInst) { + rdPtr = JpuReadReg(MJPEG_BBC_RD_PTR_REG); + } else { + rdPtr = pDecInfo->streamRdPtr; + } + + wrPtr = pDecInfo->streamWrPtr; + + if (wrPtr == pDecInfo->streamBufStartAddr) { + if (pDecInfo->frameOffset == 0) { + room = (pDecInfo->streamBufEndAddr -= pDecInfo->streamBufStartAddr); + } else { + room = (pDecInfo->frameOffset); + } + } else { + room = (pDecInfo->streamBufEndAddr - wrPtr); + } + + room = ((room >> 9) << 9); // multiple of 512 + + *prdPrt = rdPtr; + *pwrPtr = wrPtr; + + *size = room; + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecUpdateBitstreamBuffer(JpgDecHandle handle, int size) +{ + JpgInst *pJpgInst; + JpgDecInfo *pDecInfo; + PhysicalAddress wrPtr; + PhysicalAddress rdPtr; + JpgRet ret; + int val = 0; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + pDecInfo = &pJpgInst->JpgInfo.decInfo; + wrPtr = pDecInfo->streamWrPtr; + + if (size == 0) { + val = (wrPtr - pDecInfo->streamBufStartAddr) / 256; + if ((wrPtr - pDecInfo->streamBufStartAddr) % 256) + val = val + 1; + if (GetJpgPendingInst() == pJpgInst) + JpuWriteReg(MJPEG_BBC_STRM_CTRL_REG, (1 << 31 | val)); + pDecInfo->streamEndflag = 1; + return JPG_RET_SUCCESS; + } + + JpgSetClockGate(1); + + wrPtr = pDecInfo->streamWrPtr; + wrPtr += size; + + if (wrPtr == pDecInfo->streamBufEndAddr) { + wrPtr = pDecInfo->streamBufStartAddr; + } + + pDecInfo->streamWrPtr = wrPtr; + + if (GetJpgPendingInst() == pJpgInst) { + rdPtr = JpuReadReg(MJPEG_BBC_RD_PTR_REG); + + if (rdPtr == (pDecInfo->streamBufEndAddr & 0xffffffff)) { + JpuWriteReg(MJPEG_BBC_CUR_POS_REG, 0); + JpuWriteReg(MJPEG_GBU_TT_CNT_REG, 0); + JpuWriteReg(MJPEG_GBU_TT_CNT_REG + 4, 0); + } + + JpuWriteReg(MJPEG_BBC_WR_PTR_REG, wrPtr); + if (wrPtr == pDecInfo->streamBufStartAddr) { + JpuWriteReg(MJPEG_BBC_END_ADDR_REG, pDecInfo->streamBufEndAddr); + } else { + JpuWriteReg(MJPEG_BBC_END_ADDR_REG, wrPtr); + } + } else { + rdPtr = pDecInfo->streamRdPtr; + } + + pDecInfo->streamRdPtr = rdPtr; + + JpgSetClockGate(0); + return JPG_RET_SUCCESS; +} + +JpgRet JPU_SWReset(void) +{ + Uint32 val; + PhysicalAddress streamBufStartAddr; + PhysicalAddress streamBufEndAddr; + PhysicalAddress streamWrPtr; + PhysicalAddress streamRdPtr; + + JpgEnterLock(); + + streamBufStartAddr = JpuReadReg(MJPEG_BBC_BAS_ADDR_REG); + streamBufEndAddr = JpuReadReg(MJPEG_BBC_END_ADDR_REG); + streamWrPtr = JpuReadReg(MJPEG_BBC_RD_PTR_REG); + streamRdPtr = JpuReadReg(MJPEG_BBC_WR_PTR_REG); + + JpuWriteReg(MJPEG_PIC_START_REG, (1 << JPG_START_INIT)); + + do { + val = JpuReadReg(MJPEG_PIC_START_REG); + } while ((val & (1 << JPG_START_INIT)) == (1 << JPG_START_INIT)); + + JpuWriteReg(MJPEG_BBC_BAS_ADDR_REG, streamBufStartAddr); + JpuWriteReg(MJPEG_BBC_END_ADDR_REG, streamBufEndAddr); + JpuWriteReg(MJPEG_BBC_RD_PTR_REG, streamRdPtr); + JpuWriteReg(MJPEG_BBC_WR_PTR_REG, streamWrPtr); + + JpgLeaveLock(); + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_HWReset(void) +{ + if (jdi_hw_reset() < 0) + return JPG_RET_FAILURE; + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecIssueStop(JpgDecHandle handle) +{ + JpgInst *pJpgInst; + // JpgDecInfo * pDecInfo; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + // pDecInfo = &pJpgInst->JpgInfo.decInfo; + + if (pJpgInst != GetJpgPendingInst()) { + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + JpgSetClockGate(1); + JpuWriteReg(MJPEG_PIC_START_REG, 1 << JPG_START_STOP); + JpgSetClockGate(0); + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecCompleteStop(JpgDecHandle handle) +{ + JpgInst *pJpgInst; + // JpgDecInfo * pDecInfo; + JpgRet ret; + Uint32 val; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + // pDecInfo = &pJpgInst->JpgInfo.decInfo; + + if (pJpgInst != GetJpgPendingInst()) { + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + JpgSetClockGate(1); + val = JpuReadReg(MJPEG_PIC_STATUS_REG); + + if (val & (1 << INT_JPU_BIT_BUF_STOP)) { + SetJpgPendingInst(0); + JpgSetClockGate(0); + } else { + JpgSetClockGate(0); + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecSetRdPtr(JpgDecHandle handle, PhysicalAddress addr, int updateWrPtr) +{ + JpgInst *pJpgInst; + JpgDecInfo *pDecInfo; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + pDecInfo = &pJpgInst->JpgInfo.decInfo; + + JpgEnterLock(); + + if (GetJpgPendingInst()) { + JpgLeaveLock(); + return JPG_RET_FRAME_NOT_COMPLETE; + } + + pDecInfo->streamRdPtr = addr; + if (updateWrPtr) + pDecInfo->streamWrPtr = addr; + + pDecInfo->frameOffset = addr - pDecInfo->streamBufStartAddr; + pDecInfo->consumeByte = 0; + + JpuWriteReg(MJPEG_BBC_RD_PTR_REG, pDecInfo->streamRdPtr); + + JpgLeaveLock(); + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecStartOneFrame(JpgDecHandle handle, JpgDecParam *param) +{ + JpgInst *pJpgInst; + JpgDecInfo *pDecInfo; + Uint32 rotMir; + JpgRet ret; + Uint32 val; + int i; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + pDecInfo = &pJpgInst->JpgInfo.decInfo; + + if (pDecInfo->frameBufPool == 0) { // This means frame buffers have not been registered. + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + rotMir = 0; + if (pDecInfo->rotationEnable) { + rotMir |= 0x10; // Enable rotator + switch (pDecInfo->rotationAngle) { + case 0: + rotMir |= 0x0; + break; + + case 90: + rotMir |= 0x1; + break; + + case 180: + rotMir |= 0x2; + break; + + case 270: + rotMir |= 0x3; + break; + } + } + + if (pDecInfo->mirrorEnable) { + rotMir |= 0x10; // Enable rotator + switch (pDecInfo->mirrorDirection) { + case MIRDIR_NONE: + rotMir |= 0x0; + break; + + case MIRDIR_VER: + rotMir |= 0x4; + break; + + case MIRDIR_HOR: + rotMir |= 0x8; + break; + + case MIRDIR_HOR_VER: + rotMir |= 0xc; + break; + } + } + JpgEnterLock(); + + if (GetJpgPendingInst()) { + JpgLeaveLock(); + return JPG_RET_FRAME_NOT_COMPLETE; + } + +#ifdef MJPEG_ERROR_CONCEAL + // Error Concealment + if (pDecInfo->errInfo.bError) { + // error conceal main function + val = JpegDecodeConcealError(pDecInfo); + if (val == -1) { + // stream buffer wrap around in error cases. + pDecInfo->frameOffset = 0; + pDecInfo->nextOffset = 0; + + // end of stream + if (pDecInfo->streamEndflag == 1) { + pDecInfo->frameOffset = -1; + SetJpgPendingInst(pJpgInst); + return JPG_RET_EOS; + } + // request data + JpgLeaveLock(); + return JPG_RET_BIT_EMPTY; + } + + // init GBU + JpuWriteReg(MJPEG_GBU_TT_CNT_REG, 0); + JpuWriteReg(MJPEG_GBU_TT_CNT_REG + 4, 0); + + val = pDecInfo->huffAcIdx << 10 | pDecInfo->huffDcIdx << 7 | pDecInfo->userHuffTab << 6; + val |= (JPU_CHECK_WRITE_RESPONSE_BVALID_SIGNAL << 2) | 0; + JpuWriteReg(MJPEG_PIC_CTRL_REG, val); + val = pDecInfo->mcuBlockNum << 16 | pDecInfo->compNum << 12; + val |= pDecInfo->compInfo[0] << 8 | pDecInfo->compInfo[1] << 4 | pDecInfo->compInfo[2]; + JpuWriteReg(MJPEG_MCU_INFO_REG, val); + JpuWriteReg(MJPEG_RST_INTVAL_REG, pDecInfo->rstIntval); + + JpgDecGramSetup(pDecInfo); + + JpuWriteReg(MJPEG_DPCM_DIFF_Y_REG, 0); + JpuWriteReg(MJPEG_DPCM_DIFF_CB_REG, 0); + JpuWriteReg(MJPEG_DPCM_DIFF_CR_REG, 0); + + JpuWriteReg(MJPEG_GBU_FF_RPTR_REG, pDecInfo->bitPtr); + JpuWriteReg(MJPEG_GBU_CTRL_REG, 3); + + val = (pDecInfo->setPosX << 16) | (pDecInfo->setPosY); + JpuWriteReg(MJPEG_PIC_SETMB_REG, val); + JpuWriteReg(MJPEG_PIC_START_REG, (1 << JPG_START_PIC)); + + SetJpgPendingInst(pJpgInst); + return JPG_RET_SUCCESS; + } +#endif + + if (pDecInfo->frameOffset < 0) { + SetJpgPendingInst(pJpgInst); + return JPG_RET_EOS; + } + + val = JpegDecodeHeader(pDecInfo); + if (val == 0) { + JpgLeaveLock(); + return JPG_RET_FAILURE; + } + + if (val == -2) { // wrap around case + pDecInfo->frameOffset = 0; + pDecInfo->ecsPtr = 0; +#ifdef MJPEG_ERROR_CONCEAL + pDecInfo->nextOffset = 0; +#endif + val = JpegDecodeHeader(pDecInfo); + if (val == 0) { + JpgLeaveLock(); + return JPG_RET_FAILURE; + } + } + + if (val == -1) { // stream empty case + if (pDecInfo->streamEndflag == 1) { + SetJpgPendingInst(pJpgInst); + pDecInfo->frameOffset = -1; + return JPG_RET_EOS; + } + JpgLeaveLock(); + return JPG_RET_BIT_EMPTY; + } + + if (pDecInfo->streamRdPtr == pDecInfo->streamBufEndAddr) { + JpuWriteReg(MJPEG_BBC_CUR_POS_REG, 0); + JpuWriteReg(MJPEG_GBU_TT_CNT_REG, 0); + JpuWriteReg(MJPEG_GBU_TT_CNT_REG + 4, 0); + } + + JpuWriteReg(MJPEG_BBC_WR_PTR_REG, pDecInfo->streamWrPtr); + if (pDecInfo->streamWrPtr == pDecInfo->streamBufStartAddr) { + JpuWriteReg(MJPEG_BBC_END_ADDR_REG, pDecInfo->streamBufEndAddr); + } else { + JpuWriteReg(MJPEG_BBC_END_ADDR_REG, pDecInfo->streamWrPtr); + } + + JLOG(INFO, "pDecInfo->streamBufStartAddr %p\n", + (void *)pDecInfo->streamBufStartAddr); + + JpuWriteReg(MJPEG_BBC_BAS_ADDR_REG, pDecInfo->streamBufStartAddr); + + if (pDecInfo->streamEndflag == 1) { + val = JpuReadReg(MJPEG_BBC_STRM_CTRL_REG); + if ((val & (1 << 31)) == 0) { + val = (pDecInfo->streamWrPtr - + pDecInfo->streamBufStartAddr) / + 256; + if ((pDecInfo->streamWrPtr - + pDecInfo->streamBufStartAddr) % + 256) + val = val + 1; + + JpuWriteReg(MJPEG_BBC_STRM_CTRL_REG, (1 << 31 | val)); + } + } else { + JpuWriteReg(MJPEG_BBC_STRM_CTRL_REG, 0); + } + + JpuWriteReg(MJPEG_GBU_TT_CNT_REG, 0); + JpuWriteReg(MJPEG_GBU_TT_CNT_REG + 4, 0); + JpuWriteReg(MJPEG_PIC_ERRMB_REG, 0); + val = pDecInfo->huffAcIdx << 10 | pDecInfo->huffDcIdx << 7 | pDecInfo->userHuffTab << 6; + val |= ((JPU_CHECK_WRITE_RESPONSE_BVALID_SIGNAL << 2) | pDecInfo->usePartial); + JpuWriteReg(MJPEG_PIC_CTRL_REG, val); + + JpuWriteReg(MJPEG_PIC_SIZE_REG, (pDecInfo->alignedWidth << 16) | pDecInfo->alignedHeight); + JpuWriteReg(MJPEG_ROT_INFO_REG, 0); + JpuWriteReg(MJPEG_OP_INFO_REG, pDecInfo->lineNum << 16 | pDecInfo->bufNum << 3 | pDecInfo->busReqNum); + val = pDecInfo->mcuBlockNum << 16 | pDecInfo->compNum << 12; + val |= pDecInfo->compInfo[0] << 8 | pDecInfo->compInfo[1] << 4 | pDecInfo->compInfo[2]; + JpuWriteReg(MJPEG_MCU_INFO_REG, val); + + if (pDecInfo->chroma_interleave == 0) + val = 0; + else if (pDecInfo->chroma_interleave == 1) + val = 2; + else + val = 3; + if (pDecInfo->packedFormat == PACKED_FORMAT_NONE) { + val |= (pDecInfo->frameEndian << 6) | (0 << 5) | (0 << 4); + JpuWriteReg(MJPEG_DPB_CONFIG_REG, val); + } else if (pDecInfo->packedFormat == PACKED_FORMAT_444) { + val |= (pDecInfo->frameEndian << 6) | (1 << 5) | (0 << 4) | (0 << 2); + JpuWriteReg(MJPEG_DPB_CONFIG_REG, val); + } else { + val |= (pDecInfo->frameEndian << 6) | (0 << 5) | (1 << 4) | ((pDecInfo->packedFormat - 1) << 2); + JpuWriteReg(MJPEG_DPB_CONFIG_REG, val); + } + JpuWriteReg(MJPEG_RST_INTVAL_REG, pDecInfo->rstIntval); + if (param) { + if (param->scaleDownRatioWidth > 0) + pDecInfo->iHorScaleMode = param->scaleDownRatioWidth; + if (param->scaleDownRatioHeight > 0) + pDecInfo->iVerScaleMode = param->scaleDownRatioHeight; + } + if (pDecInfo->iHorScaleMode | pDecInfo->iVerScaleMode) + val = ((pDecInfo->iHorScaleMode & 0x3) << 2) | + ((pDecInfo->iVerScaleMode & 0x3)) | 0x10; + else { + val = 0; + } + JpuWriteReg(MJPEG_SCL_INFO_REG, val); + + if (pDecInfo->userHuffTab) { + if (!JpgDecHuffTabSetUp(pDecInfo)) { + JpgLeaveLock(); + return JPG_RET_INVALID_PARAM; + } + } + + if (!JpgDecQMatTabSetUp(pDecInfo)) { + JpgLeaveLock(); + return JPG_RET_INVALID_PARAM; + } + + JpgDecGramSetup(pDecInfo); + + JpuWriteReg(MJPEG_RST_INDEX_REG, 0); // RST index at the beginning. + JpuWriteReg(MJPEG_RST_COUNT_REG, 0); + + JpuWriteReg(MJPEG_DPCM_DIFF_Y_REG, 0); + JpuWriteReg(MJPEG_DPCM_DIFF_CB_REG, 0); + JpuWriteReg(MJPEG_DPCM_DIFF_CR_REG, 0); + + JpuWriteReg(MJPEG_GBU_FF_RPTR_REG, pDecInfo->bitPtr); + JpuWriteReg(MJPEG_GBU_CTRL_REG, 3); + + JpuWriteReg(MJPEG_ROT_INFO_REG, rotMir); + + if (rotMir & 1) { + pDecInfo->format = (pDecInfo->format == FORMAT_422) + ? FORMAT_224 + : (pDecInfo->format == FORMAT_224) + ? FORMAT_422 + : pDecInfo->format; + } + + if (rotMir & 0x10) { + JpuWriteReg(MJPEG_DPB_BASE00_REG, pDecInfo->rotatorOutput.bufY); + JpuWriteReg(MJPEG_DPB_BASE01_REG, + pDecInfo->rotatorOutput.bufCb); + JpuWriteReg(MJPEG_DPB_BASE02_REG, + pDecInfo->rotatorOutput.bufCr); + } else if (pDecInfo->usePartial) { + PhysicalAddress addr; + + val = (pDecInfo->frameIdx % (pDecInfo->numFrameBuffers / pDecInfo->bufNum)); + for (i = 0; i < pDecInfo->bufNum; i++) { + addr = pDecInfo->frameBufPool[(val * pDecInfo->bufNum) + i].bufY; + JpuWriteReg(MJPEG_DPB_BASE00_REG + (i * 12), addr); + addr = pDecInfo->frameBufPool[(val * pDecInfo->bufNum) + i].bufCb; + JpuWriteReg(MJPEG_DPB_BASE01_REG + (i * 12), addr); + addr = pDecInfo->frameBufPool[(val * pDecInfo->bufNum) + i].bufCr; + JpuWriteReg(MJPEG_DPB_BASE02_REG + (i * 12), addr); + } + } else { + val = (pDecInfo->frameIdx % pDecInfo->numFrameBuffers); + JpuWriteReg(MJPEG_DPB_BASE00_REG, pDecInfo->frameBufPool[val].bufY); + JpuWriteReg(MJPEG_DPB_BASE01_REG, pDecInfo->frameBufPool[val].bufCb); + JpuWriteReg(MJPEG_DPB_BASE02_REG, pDecInfo->frameBufPool[val].bufCr); + } + + if (pDecInfo->rotationEnable) { + JpuWriteReg(MJPEG_DPB_YSTRIDE_REG, pDecInfo->rotatorStride); + val = (pDecInfo->format == FORMAT_420 || + pDecInfo->format == FORMAT_422 || + pDecInfo->format == FORMAT_400) + ? 2 + : 1; + if (pDecInfo->chroma_interleave) + JpuWriteReg(MJPEG_DPB_CSTRIDE_REG, (pDecInfo->rotatorStride / (int)val) * 2); + else + JpuWriteReg(MJPEG_DPB_CSTRIDE_REG, pDecInfo->rotatorStride / (int)val); + } else { + + CVI_JPG_DBG("packedFormat = %d\n", pDecInfo->packedFormat); + if (pDecInfo->packedFormat == PACKED_FORMAT_NONE && pDecInfo->format == FORMAT_420) { + CVI_JPG_DBG("strideY = %d, strideC = %d\n", pDecInfo->strideY, pDecInfo->strideC); + JpuWriteReg(MJPEG_DPB_YSTRIDE_REG, pDecInfo->strideY); + JpuWriteReg(MJPEG_DPB_CSTRIDE_REG, pDecInfo->strideC); + } else { + JpuWriteReg(MJPEG_DPB_YSTRIDE_REG, pDecInfo->stride); + if (pDecInfo->chroma_interleave) + JpuWriteReg(MJPEG_DPB_CSTRIDE_REG, (pDecInfo->stride / (int)val) * 2); + else + JpuWriteReg(MJPEG_DPB_CSTRIDE_REG, pDecInfo->stride / (int)val); + } + } + if (pDecInfo->roiEnable) { + JpuWriteReg(MJPEG_CLP_INFO_REG, 1); + JpuWriteReg(MJPEG_CLP_BASE_REG, pDecInfo->roiOffsetX << 16 | pDecInfo->roiOffsetY); // pixel unit + val = (pDecInfo->roiMcuWidth * pDecInfo->mcuWidth) << 16; + val |= pDecInfo->roiMcuHeight * pDecInfo->mcuHeight; + JpuWriteReg(MJPEG_CLP_SIZE_REG, val); // pixel Unit + } else { + JpuWriteReg(MJPEG_CLP_INFO_REG, 0); + } + + if (pJpgInst->loggingEnable) + jdi_log(JDI_LOG_CMD_PICRUN, 1); + + BM_DBG_FLOW("JPG_START_PIC\n"); + +#ifdef PROFILE_PERFORMANCE + timer_meter_start(); +#endif + + JpuWriteReg(MJPEG_PIC_STATUS_REG, JpuReadReg(MJPEG_PIC_STATUS_REG)); + + JpuWriteReg(MJPEG_PIC_START_REG, (1 << JPG_START_PIC)); + + SetJpgPendingInst(pJpgInst); + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecGetOutputInfo(JpgDecHandle handle, JpgDecOutputInfo *info) +{ + JpgInst *pJpgInst; + JpgDecInfo *pDecInfo; + JpgRet ret; + Uint32 val = 0; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) { + SetJpgPendingInst(0); + JpgLeaveLock(); + return ret; + } + + if (info == 0) { + SetJpgPendingInst(0); + JpgLeaveLock(); + return JPG_RET_INVALID_PARAM; + } + + pJpgInst = handle; + pDecInfo = &pJpgInst->JpgInfo.decInfo; + + val = JpuReadReg(MJPEG_PIC_STATUS_REG); + + if (pJpgInst != GetJpgPendingInst()) { + SetJpgPendingInst(0); + JpgLeaveLock(); + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + if (pDecInfo->frameOffset < 0) { + info->numOfErrMBs = 0; + info->decodingSuccess = 1; + info->indexFrameDisplay = -1; + SetJpgPendingInst(0); + JpgLeaveLock(); + return JPG_RET_SUCCESS; + } + + if (pDecInfo->roiEnable) { + info->decPicWidth = pDecInfo->roiMcuWidth * pDecInfo->mcuWidth; + info->decPicHeight = + pDecInfo->roiMcuHeight * pDecInfo->mcuHeight; + } else { + info->decPicWidth = pDecInfo->alignedWidth; + info->decPicHeight = pDecInfo->alignedHeight; + } + + info->decPicWidth >>= pDecInfo->iHorScaleMode; + info->decPicHeight >>= pDecInfo->iVerScaleMode; + + info->indexFrameDisplay = + (pDecInfo->frameIdx % pDecInfo->numFrameBuffers); +#ifdef MJPEG_ERROR_CONCEAL + info->consumedByte = + pDecInfo->gbuStartPtr + (JpuReadReg(MJPEG_GBU_TT_CNT_REG)) / 8; +#else + info->consumedByte = (JpuReadReg(MJPEG_GBU_TT_CNT_REG)) / 8; +#endif + pDecInfo->streamRdPtr = JpuReadReg(MJPEG_BBC_RD_PTR_REG); + pDecInfo->consumeByte = info->consumedByte - 16 - pDecInfo->ecsPtr; + info->bytePosFrameStart = pDecInfo->frameOffset; + info->ecsPtr = pDecInfo->ecsPtr; + + pDecInfo->ecsPtr = 0; + pDecInfo->frameIdx++; + + val = JpuReadReg(MJPEG_PIC_STATUS_REG); + + if (val & (1 << INT_JPU_DONE)) { + info->decodingSuccess = 1; + info->numOfErrMBs = 0; + +#ifdef MJPEG_ERROR_CONCEAL + pDecInfo->errInfo.bError = 0; + pDecInfo->nextOffset = 0; + pDecInfo->gbuStartPtr = 0; +#endif + } else if (val & (1 << INT_JPU_ERROR)) { + + info->numOfErrMBs = JpuReadReg(MJPEG_PIC_ERRMB_REG); + info->decodingSuccess = 0; + +#ifdef MJPEG_ERROR_CONCEAL + // info->numOfErrMBs = + // JpuReadReg(MJPEG_PIC_ERRMB_REG); + pDecInfo->errInfo.bError = 1; + pDecInfo->errInfo.errPosY = info->numOfErrMBs & 0xFFF; + pDecInfo->errInfo.errPosX = (info->numOfErrMBs >> 12) & 0xFFF; + + // set search point to find next rstMarker from origin of frame + // buffer by host + pDecInfo->nextOffset = (info->consumedByte) & (~7); + + // prevent to find same position. + if (pDecInfo->currOffset == pDecInfo->nextOffset) + pDecInfo->nextOffset += JPU_GBU_SIZE; +#endif + } + + if (val != 0) + JpuWriteReg(MJPEG_PIC_STATUS_REG, val); + + if (pJpgInst->loggingEnable) { + jdi_log(JDI_LOG_CMD_PICRUN, 0); + } + + SetJpgPendingInst(0); + JpgLeaveLock(); + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_DecGiveCommand(JpgDecHandle handle, JpgCommand cmd, void *param) +{ + JpgInst *pJpgInst; + JpgDecInfo *pDecInfo; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + pDecInfo = &pJpgInst->JpgInfo.decInfo; + switch (cmd) { + case ENABLE_JPG_ROTATION: { + if (pDecInfo->roiEnable) { + return JPG_RET_INVALID_PARAM; + } + + if (pDecInfo->rotatorStride == 0) { + return JPG_RET_ROTATOR_STRIDE_NOT_SET; + } + pDecInfo->rotationEnable = 1; + break; + } + + case DISABLE_JPG_ROTATION: { + pDecInfo->rotationEnable = 0; + break; + } + + case ENABLE_JPG_MIRRORING: { + if (pDecInfo->rotatorStride == 0) { + return JPG_RET_ROTATOR_STRIDE_NOT_SET; + } + pDecInfo->mirrorEnable = 1; + break; + } + case DISABLE_JPG_MIRRORING: { + pDecInfo->mirrorEnable = 0; + break; + } + case SET_JPG_MIRROR_DIRECTION: { + + JpgMirrorDirection mirDir; + + if (param == 0) { + return JPG_RET_INVALID_PARAM; + } + mirDir = *(JpgMirrorDirection *)param; + if (!(mirDir >= MIRDIR_NONE && mirDir <= MIRDIR_HOR_VER)) { + return JPG_RET_INVALID_PARAM; + } + pDecInfo->mirrorDirection = mirDir; + + break; + } + case SET_JPG_ROTATION_ANGLE: { + int angle; + + if (param == 0) { + return JPG_RET_INVALID_PARAM; + } + + angle = *(int *)param; + if (angle != 0 && angle != 90 && angle != 180 && angle != 270) { + return JPG_RET_INVALID_PARAM; + } + + pDecInfo->rotationAngle = angle; + break; + } + + case SET_JPG_ROTATOR_OUTPUT: { + FrameBuffer *frame; + + if (param == 0) { + return JPG_RET_INVALID_PARAM; + } + frame = (FrameBuffer *)param; + pDecInfo->rotatorOutput = *frame; + pDecInfo->rotatorOutputValid = 1; + break; + } + + case SET_JPG_ROTATOR_STRIDE: { + int stride; + + if (param == 0) { + return JPG_RET_INVALID_PARAM; + } + stride = *(int *)param; + if (stride % 8 != 0 || stride == 0) { + return JPG_RET_INVALID_STRIDE; + } + + if (pDecInfo->rotationAngle == 90 || + pDecInfo->rotationAngle == 270) { + if (pDecInfo->alignedHeight > stride) { + return JPG_RET_INVALID_STRIDE; + } + } else { + if (pDecInfo->alignedWidth > stride) { + return JPG_RET_INVALID_STRIDE; + } + } + + pDecInfo->rotatorStride = stride; + break; + } + case SET_JPG_SCALE_HOR: { + int scale; + + scale = *(int *)param; + if (pDecInfo->alignedWidth < 128 || + pDecInfo->alignedHeight < 128) { + if (scale) { + return JPG_RET_INVALID_PARAM; + } + } + + pDecInfo->iHorScaleMode = scale; + break; + } + case SET_JPG_SCALE_VER: { + int scale; + + scale = *(int *)param; + if (pDecInfo->alignedWidth < 128 || + pDecInfo->alignedHeight < 128) { + if (scale) { + return JPG_RET_INVALID_PARAM; + } + } + pDecInfo->iVerScaleMode = scale; + break; + } + case SET_JPG_USE_PARTIAL_MODE: { + int enable; + + enable = *(int *)param; + pDecInfo->usePartial = enable; + + break; + } + case SET_JPG_PARTIAL_FRAME_NUM: { + int frame; + + if (pDecInfo->stride != 0) { + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + frame = *(int *)param; + pDecInfo->bufNum = frame; + + break; + } + case SET_JPG_PARTIAL_LINE_NUM: { + int line; + + if (pDecInfo->stride != 0) { + return JPG_RET_WRONG_CALL_SEQUENCE; + } + line = *(int *)param; + pDecInfo->lineNum = line; + + break; + } + case ENABLE_LOGGING: { + pJpgInst->loggingEnable = 1; + } break; + case DISABLE_LOGGING: { + pJpgInst->loggingEnable = 0; + } break; + default: + return JPG_RET_INVALID_COMMAND; + } + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncOpen(JpgEncHandle *pHandle, JpgEncOpenParam *pop) +{ + JpgInst *pJpgInst; + JpgEncInfo *pEncInfo; + JpgRet ret; + int i; + + ret = CheckJpgEncOpenParam(pop); + if (ret != JPG_RET_SUCCESS) { + BM_DBG_ERR("CheckJpgEncOpenParam\n"); + return ret; + } + + JpgEnterLock(); + ret = GetJpgInstance(&pJpgInst); + if (ret == JPG_RET_FAILURE) { + BM_DBG_ERR("GetJpgInstance\n"); + *pHandle = 0; + JpgLeaveLock(); + return JPG_RET_FAILURE; + } + + *pHandle = pJpgInst; + pEncInfo = &pJpgInst->JpgInfo.encInfo; + memset(pEncInfo, 0x00, sizeof(JpgEncInfo)); + pEncInfo->openParam = *pop; + pEncInfo->streamRdPtr = pop->bitstreamBuffer; + pEncInfo->streamWrPtr = pop->bitstreamBuffer; + + JpuWriteReg(MJPEG_BBC_WR_PTR_REG, pEncInfo->streamWrPtr); + pEncInfo->streamBufStartAddr = pop->bitstreamBuffer; + pEncInfo->streamBufSize = pop->bitstreamBufferSize; + pEncInfo->streamBufEndAddr = + pop->bitstreamBuffer + pop->bitstreamBufferSize; + pEncInfo->streamEndian = pop->streamEndian; + pEncInfo->frameEndian = pop->frameEndian; + pEncInfo->chroma_interleave = pop->chroma_interleave; + + pEncInfo->format = pEncInfo->openParam.sourceFormat; + pEncInfo->picWidth = pEncInfo->openParam.picWidth; + pEncInfo->picHeight = pEncInfo->openParam.picHeight; + // Picture size alignment + if (pEncInfo->format == FORMAT_420 || pEncInfo->format == FORMAT_422) + pEncInfo->alignedWidth = ((pEncInfo->picWidth + 15) / 16) * 16; + else + pEncInfo->alignedWidth = ((pEncInfo->picWidth + 7) / 8) * 8; + + if (pEncInfo->format == FORMAT_420 || pEncInfo->format == FORMAT_224) + pEncInfo->alignedHeight = + ((pEncInfo->picHeight + 15) / 16) * 16; + else + pEncInfo->alignedHeight = ((pEncInfo->picHeight + 7) / 8) * 8; + pEncInfo->rstIntval = pEncInfo->openParam.restartInterval; + + for (i = 0; i < 4; i++) + pEncInfo->pHuffVal[i] = pEncInfo->openParam.huffVal[i]; + for (i = 0; i < 4; i++) + pEncInfo->pHuffBits[i] = pEncInfo->openParam.huffBits[i]; + for (i = 0; i < 4; i++) + pEncInfo->pQMatTab[i] = pEncInfo->openParam.qMatTab[i]; + + pEncInfo->pCInfoTab[0] = sJpuCompInfoTable[/*2*/ pEncInfo->format]; + pEncInfo->pCInfoTab[1] = pEncInfo->pCInfoTab[0] + 6; + pEncInfo->pCInfoTab[2] = pEncInfo->pCInfoTab[1] + 6; + pEncInfo->pCInfoTab[3] = pEncInfo->pCInfoTab[2] + 6; + + if (pop->packedFormat == PACKED_FORMAT_444 && + pEncInfo->format != FORMAT_444) { + BM_DBG_ERR("PACKED_FORMAT_444\n"); + return JPG_RET_INVALID_PARAM; + } + pEncInfo->packedFormat = pop->packedFormat; + + JpgLeaveLock(); + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncClose(JpgEncHandle handle) +{ + JpgInst *pJpgInst; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + JpgEnterLock(); + + if (GetJpgPendingInst()) { + JpgLeaveLock(); + return JPG_RET_FRAME_NOT_COMPLETE; + } + + pJpgInst = handle; + JpuWriteReg(MJPEG_BBC_FLUSH_CMD_REG, 0); + FreeJpgInstance(pJpgInst); + JpgLeaveLock(); + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncGetInitialInfo(JpgEncHandle handle, JpgEncInitialInfo *info) +{ + JpgInst *pJpgInst; + JpgEncInfo *pEncInfo; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + if (info == 0) { + return JPG_RET_INVALID_PARAM; + } + + pJpgInst = handle; + pEncInfo = &pJpgInst->JpgInfo.encInfo; + + if (pEncInfo->initialInfoObtained) { + return JPG_RET_CALLED_BEFORE; + } + + JpgEnterLock(); + + if (GetJpgPendingInst()) { + JpgLeaveLock(); + return JPG_RET_FRAME_NOT_COMPLETE; + } + + if (pEncInfo->format == FORMAT_400) { + pEncInfo->compInfo[1] = 0; + pEncInfo->compInfo[2] = 0; + } else { + pEncInfo->compInfo[1] = 5; + pEncInfo->compInfo[2] = 5; + } + + if (pEncInfo->format == FORMAT_400) + pEncInfo->compNum = 1; + else + pEncInfo->compNum = 3; + + if (pEncInfo->format == FORMAT_420) { + pEncInfo->mcuBlockNum = 6; + pEncInfo->compInfo[0] = 10; + pEncInfo->busReqNum = 2; + } else if (pEncInfo->format == FORMAT_422) { + pEncInfo->mcuBlockNum = 4; + pEncInfo->busReqNum = 3; + pEncInfo->compInfo[0] = 9; + } else if (pEncInfo->format == FORMAT_224) { + pEncInfo->mcuBlockNum = 4; + pEncInfo->busReqNum = 3; + pEncInfo->compInfo[0] = 6; + } else if (pEncInfo->format == FORMAT_444) { + pEncInfo->mcuBlockNum = 3; + pEncInfo->compInfo[0] = 5; + pEncInfo->busReqNum = 4; + } else if (pEncInfo->format == FORMAT_400) { + pEncInfo->mcuBlockNum = 1; + pEncInfo->busReqNum = 4; + pEncInfo->compInfo[0] = 5; + } + + info->minFrameBufferCount = 0; + info->colorComponents = pEncInfo->compNum; + + pEncInfo->initialInfo = *info; + pEncInfo->initialInfoObtained = 1; + + JpgLeaveLock(); + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncGetBitstreamBuffer(JpgEncHandle handle, PhysicalAddress *prdPrt, + PhysicalAddress *pwrPtr, int *size) +{ + JpgInst *pJpgInst; + JpgEncInfo *pEncInfo; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + if (prdPrt == 0 || pwrPtr == 0 || size == 0) { + return JPG_RET_INVALID_PARAM; + } + + pJpgInst = handle; + pEncInfo = &pJpgInst->JpgInfo.encInfo; + + JpgSetClockGate(1); + *prdPrt = pEncInfo->streamRdPtr; + + if (GetJpgPendingInst() == pJpgInst) { + *pwrPtr = JpuReadReg(MJPEG_BBC_WR_PTR_REG); + } else { + *pwrPtr = pEncInfo->streamWrPtr; + } + *size = *pwrPtr - *prdPrt; + JpgSetClockGate(0); + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncUpdateBitstreamBuffer(JpgEncHandle handle, int size) +{ + JpgInst *pJpgInst; + JpgEncInfo *pEncInfo; + PhysicalAddress rdPtr; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + pEncInfo = &pJpgInst->JpgInfo.encInfo; + + JpgSetClockGate(1); + rdPtr = pEncInfo->streamRdPtr; + rdPtr += size; + + if (rdPtr == pEncInfo->streamBufEndAddr) { + rdPtr = pEncInfo->streamBufStartAddr; + } + + pEncInfo->streamRdPtr = pEncInfo->streamBufStartAddr; + + if (GetJpgPendingInst() == pJpgInst) { + pEncInfo->streamWrPtr = JpuReadReg(MJPEG_BBC_WR_PTR_REG); + JpuWriteReg(MJPEG_BBC_CUR_POS_REG, 0); + JpuWriteReg(MJPEG_BBC_EXT_ADDR_REG, + pEncInfo->streamBufStartAddr); + JpuWriteReg(MJPEG_BBC_RD_PTR_REG, pEncInfo->streamBufStartAddr); + JpuWriteReg(MJPEG_BBC_WR_PTR_REG, pEncInfo->streamBufStartAddr); + } + JpgSetClockGate(0); + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncIssueStop(JpgEncHandle handle) +{ + JpgInst *pJpgInst; + // JpgEncInfo *pEncInfo; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + // pEncInfo = &pJpgInst->JpgInfo.encInfo; + + if (pJpgInst != GetJpgPendingInst()) { + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + JpgSetClockGate(1); + JpuWriteReg(MJPEG_PIC_START_REG, 1 << JPG_START_STOP); + JpgSetClockGate(0); + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncCompleteStop(JpgEncHandle handle) +{ + JpgInst *pJpgInst; + // JpgEncInfo *pEncInfo; + JpgRet ret; + Uint32 val; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + // pEncInfo = &pJpgInst->JpgInfo.encInfo; + + if (pJpgInst != GetJpgPendingInst()) { + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + JpgSetClockGate(1); + val = JpuReadReg(MJPEG_PIC_STATUS_REG); + + if (val & (1 << INT_JPU_BIT_BUF_STOP)) { + SetJpgPendingInst(0); + JpgSetClockGate(0); + } else { + JpgSetClockGate(0); + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncStartOneFrame(JpgEncHandle handle, JpgEncParam *param) +{ + JpgInst *pJpgInst; + JpgEncInfo *pEncInfo; + FrameBuffer *pBasFrame; + Uint32 rotMirEnable; + Uint32 rotMirMode; + JpgRet ret; + Uint32 val; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + pEncInfo = &pJpgInst->JpgInfo.encInfo; + + ret = CheckJpgEncParam(handle, param); + if (ret != JPG_RET_SUCCESS) { + return ret; + } + + pBasFrame = param->sourceFrame; + rotMirEnable = 0; + rotMirMode = 0; + if (pEncInfo->rotationEnable) { + rotMirEnable = 0x10; // Enable rotator + switch (pEncInfo->rotationAngle) { + case 0: + rotMirMode |= 0x0; + break; + + case 90: + rotMirMode |= 0x1; + break; + + case 180: + rotMirMode |= 0x2; + break; + + case 270: + rotMirMode |= 0x3; + break; + } + } + if (pEncInfo->mirrorEnable) { + rotMirEnable = 0x10; // Enable rotator + + switch (pEncInfo->mirrorDirection) { + case MIRDIR_NONE: + rotMirMode |= 0x0; + break; + + case MIRDIR_VER: + rotMirMode |= 0x4; + break; + + case MIRDIR_HOR: + rotMirMode |= 0x8; + break; + + case MIRDIR_HOR_VER: + rotMirMode |= 0xc; + break; + } + } + + JpgEnterLock(); + + if (GetJpgPendingInst()) { + JpgLeaveLock(); + return JPG_RET_FRAME_NOT_COMPLETE; + } + + // off ROI enable due to not supported feature for encoder. + JpuWriteReg(MJPEG_CLP_INFO_REG, 0); + + JpuWriteReg(MJPEG_BBC_BAS_ADDR_REG, pEncInfo->streamBufStartAddr); + JpuWriteReg(MJPEG_BBC_END_ADDR_REG, pEncInfo->streamBufEndAddr); + JpuWriteReg(MJPEG_BBC_WR_PTR_REG, pEncInfo->streamBufStartAddr); + JpuWriteReg(MJPEG_BBC_RD_PTR_REG, pEncInfo->streamBufStartAddr); + JpuWriteReg(MJPEG_BBC_CUR_POS_REG, 0); + JpuWriteReg(MJPEG_BBC_DATA_CNT_REG, 256 / 4); // 64 * 4 byte == 32 * 8 byte + JpuWriteReg(MJPEG_BBC_EXT_ADDR_REG, pEncInfo->streamBufStartAddr); + JpuWriteReg(MJPEG_BBC_INT_ADDR_REG, 0); + + JpuWriteReg(MJPEG_GBU_BT_PTR_REG, 0); + JpuWriteReg(MJPEG_GBU_WD_PTR_REG, 0); + JpuWriteReg(MJPEG_GBU_BBSR_REG, 0); + JpuWriteReg(MJPEG_GBU_CTRL_REG, 0); + + JpuWriteReg(MJPEG_GBU_BBER_REG, ((256 / 4) * 2) - 1); + JpuWriteReg(MJPEG_GBU_BBIR_REG, 256 / 4); // 64 * 4 byte == 32 * 8 byte + JpuWriteReg(MJPEG_GBU_BBHR_REG, 256 / 4); // 64 * 4 byte == 32 * 8 byte + val = 0x18 | pEncInfo->usePartial | (JPU_CHECK_WRITE_RESPONSE_BVALID_SIGNAL << 2); + JpuWriteReg(MJPEG_PIC_CTRL_REG, val); + JpuWriteReg(MJPEG_SCL_INFO_REG, 0); + if (pEncInfo->chroma_interleave == 0) + val = 0; + else if (pEncInfo->chroma_interleave == 1) + val = 2; + else + val = 3; + if (pEncInfo->packedFormat == PACKED_FORMAT_NONE) { + val |= (pEncInfo->frameEndian << 6) | (0 << 5) | (0 << 4) | (0 << 2); + JpuWriteReg(MJPEG_DPB_CONFIG_REG, val); + } else if (pEncInfo->packedFormat == PACKED_FORMAT_444) { + val |= (pEncInfo->frameEndian << 6) | (1 << 5) | (0 << 4) | (0 << 2); + JpuWriteReg(MJPEG_DPB_CONFIG_REG, val); + } else { + val |= (pEncInfo->frameEndian << 6) | (0 << 5) | (1 << 4) | ((pEncInfo->packedFormat - 1) << 2); + JpuWriteReg(MJPEG_DPB_CONFIG_REG, val); + } + + JpuWriteReg(MJPEG_RST_INTVAL_REG, pEncInfo->rstIntval); + JpuWriteReg(MJPEG_BBC_CTRL_REG, (pEncInfo->streamEndian << 1) | 1); + val = pEncInfo->partiallineNum << 16 | pEncInfo->partialBufNum << 3 | pEncInfo->busReqNum; + JpuWriteReg(MJPEG_OP_INFO_REG, val); + + // Load HUFFTab + if (!JpgEncLoadHuffTab(pEncInfo)) { + JpgLeaveLock(); + return JPG_RET_INVALID_PARAM; + } + + // Load QMATTab + if (!JpgEncLoadQMatTab(pEncInfo)) { + JpgLeaveLock(); + return JPG_RET_INVALID_PARAM; + } + JpgEncEncodeHeader(handle, pEncInfo->paraSet); + // although rotator is enable, this picture size must not be changed + // from widh to height. + JpuWriteReg(MJPEG_PIC_SIZE_REG, pEncInfo->alignedWidth << 16 | pEncInfo->alignedHeight); + JpuWriteReg(MJPEG_ROT_INFO_REG, (rotMirEnable | rotMirMode)); + + val = pEncInfo->mcuBlockNum << 16 | pEncInfo->compNum << 12; + val |= pEncInfo->compInfo[0] << 8 | pEncInfo->compInfo[1] << 4 | pEncInfo->compInfo[2]; + JpuWriteReg(MJPEG_MCU_INFO_REG, val); + + // JpgEncGbuResetReg + JpuWriteReg(MJPEG_GBU_CTRL_REG, pEncInfo->stuffByteEnable << 3); // stuffing "FF" data where frame end + + if (pEncInfo->usePartial) { + int i; + + for (i = 0; i < pEncInfo->partialBufNum; i++) { + JpuWriteReg(MJPEG_DPB_BASE00_REG + (i * 12), pBasFrame[i].bufY); + JpuWriteReg(MJPEG_DPB_BASE01_REG + (i * 12), pBasFrame[i].bufCb); + JpuWriteReg(MJPEG_DPB_BASE02_REG + (i * 12), pBasFrame[i].bufCr); + } + + } else { + JpuWriteReg(MJPEG_DPB_BASE00_REG, pBasFrame->bufY); + JpuWriteReg(MJPEG_DPB_BASE01_REG, pBasFrame->bufCb); + JpuWriteReg(MJPEG_DPB_BASE02_REG, pBasFrame->bufCr); + } + + JpuWriteReg(MJPEG_DPB_YSTRIDE_REG, pBasFrame->stride); + + if (pEncInfo->format == FORMAT_420 || pEncInfo->format == FORMAT_422 || pEncInfo->format == FORMAT_400) + val = 2; + else + val = 1; + + if (pEncInfo->chroma_interleave) + JpuWriteReg(MJPEG_DPB_CSTRIDE_REG, (pBasFrame->stride / (int)val) * 2); + else + JpuWriteReg(MJPEG_DPB_CSTRIDE_REG, pBasFrame->stride / (int)val); + + if (pJpgInst->loggingEnable) + jdi_log(JDI_LOG_CMD_PICRUN, 1); + +#ifdef PROFILE_PERFORMANCE + timer_meter_start(); +#endif + + JpuWriteReg(MJPEG_PIC_STATUS_REG, JpuReadReg(MJPEG_PIC_STATUS_REG)); + if (pEncInfo->usePartial) + JpuWriteReg(MJPEG_PIC_START_REG, (1 << JPG_START_PIC) | (1 << JPG_START_PARTIAL)); + else + JpuWriteReg(MJPEG_PIC_START_REG, (1 << JPG_START_PIC)); + + SetJpgPendingInst(pJpgInst); + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncGetOutputInfo(JpgEncHandle handle, JpgEncOutputInfo *info) +{ + JpgInst *pJpgInst; + JpgEncInfo *pEncInfo; + Uint32 val; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) { + SetJpgPendingInst(0); + JpgLeaveLock(); + return ret; + } + + if (info == 0) { + SetJpgPendingInst(0); + JpgLeaveLock(); + return JPG_RET_INVALID_PARAM; + } + + pJpgInst = handle; + pEncInfo = &pJpgInst->JpgInfo.encInfo; + + if (pJpgInst != GetJpgPendingInst()) { + SetJpgPendingInst(0); + JpgLeaveLock(); + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + val = JpuReadReg(MJPEG_PIC_STATUS_REG); + + if ((val & 0x4) >> 2) { + SetJpgPendingInst(0); + JpgLeaveLock(); + return JPG_RET_WRONG_CALL_SEQUENCE; + } + + if (val != 0) + JpuWriteReg(MJPEG_PIC_STATUS_REG, val); + + info->bitstreamBuffer = pEncInfo->streamBufStartAddr; + info->bitstreamSize = JpuReadReg(MJPEG_BBC_WR_PTR_REG) - pEncInfo->streamBufStartAddr; + pEncInfo->streamWrPtr = JpuReadReg(MJPEG_BBC_WR_PTR_REG); + + JpuWriteReg(MJPEG_BBC_FLUSH_CMD_REG, 0); + + if (pJpgInst->loggingEnable) + jdi_log(JDI_LOG_CMD_PICRUN, 0); + + SetJpgPendingInst(0); + JpgLeaveLock(); + return JPG_RET_SUCCESS; +} + +JpgRet JPU_EncGiveCommand(JpgEncHandle handle, JpgCommand cmd, void *param) +{ + JpgInst *pJpgInst; + JpgEncInfo *pEncInfo; + JpgRet ret; + + ret = CheckJpgInstValidity(handle); + if (ret != JPG_RET_SUCCESS) + return ret; + + pJpgInst = handle; + pEncInfo = &pJpgInst->JpgInfo.encInfo; + switch (cmd) { + case ENABLE_JPG_ROTATION: { + pEncInfo->rotationEnable = 1; + } break; + case DISABLE_JPG_ROTATION: { + pEncInfo->rotationEnable = 0; + } break; + case ENABLE_JPG_MIRRORING: { + pEncInfo->mirrorEnable = 1; + } break; + case DISABLE_JPG_MIRRORING: { + pEncInfo->mirrorEnable = 0; + } break; + case SET_JPG_MIRROR_DIRECTION: { + JpgMirrorDirection mirDir; + + if (param == 0) { + return JPG_RET_INVALID_PARAM; + } + mirDir = *(JpgMirrorDirection *)param; + if (!(mirDir >= MIRDIR_NONE && mirDir <= MIRDIR_HOR_VER)) { + return JPG_RET_INVALID_PARAM; + } + pEncInfo->mirrorDirection = mirDir; + } break; + case SET_JPG_ROTATION_ANGLE: { + int angle; + + if (param == 0) { + return JPG_RET_INVALID_PARAM; + } + angle = *(int *)param; + if (angle != 0 && angle != 90 && angle != 180 && angle != 270) { + return JPG_RET_INVALID_PARAM; + } + if (pEncInfo->initialInfoObtained && (angle == 90 || angle == 270)) { + return JPG_RET_INVALID_PARAM; + } + pEncInfo->rotationAngle = angle; + } break; + case ENC_JPG_GET_HEADER: { + if (param == 0) { + return JPG_RET_INVALID_PARAM; + } + + pEncInfo->paraSet = (JpgEncParamSet *)param; + break; + } + case SET_JPG_USE_PARTIAL_MODE: { + int enable; + + enable = *(int *)param; + pEncInfo->usePartial = enable; + + break; + } + case SET_JPG_PARTIAL_FRAME_NUM: { + int frame; + + frame = *(int *)param; + pEncInfo->partialBufNum = frame; + + break; + } + case SET_JPG_PARTIAL_LINE_NUM: { + int line; + + line = *(int *)param; + pEncInfo->partiallineNum = line; + + break; + } + case SET_JPG_ENCODE_NEXT_LINE: { + JpuWriteReg(MJPEG_PIC_START_REG, (1 << JPG_START_PARTIAL)); + break; + } + case SET_JPG_USE_STUFFING_BYTE_FF: { + int enable; + + enable = *(int *)param; + pEncInfo->stuffByteEnable = enable; + break; + } + case ENABLE_LOGGING: { + pJpgInst->loggingEnable = 1; + break; + } + case DISABLE_LOGGING: { + pJpgInst->loggingEnable = 0; + break; + } + default: + return JPG_RET_INVALID_COMMAND; + } + + return JPG_RET_SUCCESS; +} diff --git a/u-boot-2021.10/drivers/jpeg/jpuapi.h b/u-boot-2021.10/drivers/jpeg/jpuapi.h new file mode 100644 index 000000000..4f47c5a6b --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpuapi.h @@ -0,0 +1,270 @@ +#ifndef _JPU_API_H_ +#define _JPU_API_H_ + +#include "jpuconfig.h" +#include "jdi.h" + +#define CVI_JPG_DBG(msg, ...) \ + do {\ + if (1) {\ + printf("[DBG] %s = %d, " msg, __func__, __LINE__, ##__VA_ARGS__);\ + } \ + } while (0) + +#define ALIGN_X(IN, ALIGN) (((IN) + (ALIGN) - 1) / (ALIGN) * (ALIGN)) +#define ALIGN_32 + +//------------------------------------------------------------------------------ +// common struct and definition +//------------------------------------------------------------------------------ + +typedef enum { + ENABLE_JPG_ROTATION, + DISABLE_JPG_ROTATION, + ENABLE_JPG_MIRRORING, + DISABLE_JPG_MIRRORING, + SET_JPG_MIRROR_DIRECTION, + SET_JPG_ROTATION_ANGLE, + SET_JPG_ROTATOR_OUTPUT, + SET_JPG_ROTATOR_STRIDE, + SET_JPG_SCALE_HOR, + SET_JPG_SCALE_VER, + SET_JPG_USE_PARTIAL_MODE, + SET_JPG_PARTIAL_FRAME_NUM, + SET_JPG_PARTIAL_LINE_NUM, + SET_JPG_ENCODE_NEXT_LINE, + SET_JPG_USE_STUFFING_BYTE_FF, + ENC_JPG_GET_HEADER, + ENABLE_LOGGING, + DISABLE_LOGGING, + JPG_CMD_END +} JpgCommand; + +typedef enum { + JPG_RET_SUCCESS, + JPG_RET_FAILURE, + JPG_RET_BIT_EMPTY, + JPG_RET_EOS, + JPG_RET_INVALID_HANDLE, + JPG_RET_INVALID_PARAM, + JPG_RET_INVALID_COMMAND, + JPG_RET_ROTATOR_OUTPUT_NOT_SET, + JPG_RET_ROTATOR_STRIDE_NOT_SET, + JPG_RET_FRAME_NOT_COMPLETE, + JPG_RET_INVALID_FRAME_BUFFER, + JPG_RET_INSUFFICIENT_FRAME_BUFFERS, + JPG_RET_INVALID_STRIDE, + JPG_RET_WRONG_CALL_SEQUENCE, + JPG_RET_CALLED_BEFORE, + JPG_RET_NOT_INITIALIZED +} JpgRet; + +typedef enum { + MIRDIR_NONE, + MIRDIR_VER, + MIRDIR_HOR, + MIRDIR_HOR_VER +} JpgMirrorDirection; + +typedef enum { + FORMAT_420 = 0, + FORMAT_422 = 1, + FORMAT_224 = 2, + FORMAT_444 = 3, + FORMAT_400 = 4 +} FrameFormat; + +typedef enum { + CBCR_ORDER_NORMAL, + CBCR_ORDER_REVERSED +} CbCrOrder; + +typedef enum { + CBCR_SEPARATED = 0, + CBCR_INTERLEAVE + , + CRCB_INTERLEAVE +} CbCrInterLeave; + +typedef enum { + PACKED_FORMAT_NONE, + PACKED_FORMAT_422_YUYV, + PACKED_FORMAT_422_UYVY, + PACKED_FORMAT_422_YVYU, + PACKED_FORMAT_422_VYUY, + PACKED_FORMAT_444 +} PackedOutputFormat; + +typedef enum { + INT_JPU_DONE = 0, + INT_JPU_ERROR = 1, + INT_JPU_BIT_BUF_EMPTY = 2, + INT_JPU_BIT_BUF_FULL = 2, + INT_JPU_PARIAL_OVERFLOW = 3, + INT_JPU_PARIAL_BUF0_EMPTY = 4, + INT_JPU_PARIAL_BUF1_EMPTY, + INT_JPU_PARIAL_BUF2_EMPTY, + INT_JPU_PARIAL_BUF3_EMPTY, + INT_JPU_BIT_BUF_STOP +} InterruptJpu; + +typedef enum { + JPG_TBL_NORMAL, + JPG_TBL_MERGE +} JpgTableMode; + +typedef enum { + ENC_HEADER_MODE_NORMAL, + ENC_HEADER_MODE_SOS_ONLY +} JpgEncHeaderMode; + +typedef struct { + PhysicalAddress bufY; + PhysicalAddress bufCb; + PhysicalAddress bufCr; + int stride; +} FrameBuffer; + +struct JpgInst; + +//------------------------------------------------------------------------------ +// decode struct and definition +//------------------------------------------------------------------------------ + +typedef struct JpgInst JpgDecInst; +typedef JpgDecInst * JpgDecHandle; + +typedef struct { + PhysicalAddress bitstreamBuffer; + int bitstreamBufferSize; + BYTE *pBitStream; + int streamEndian; + int frameEndian; + CbCrInterLeave chroma_interleave; + int thumbNailEn; + PackedOutputFormat packedFormat; + int roiEnable; + int roiOffsetX; + int roiOffsetY; + int roiWidth; + int roiHeight; + +} JpgDecOpenParam; + +typedef struct { + int picWidth; + int picHeight; + int minFrameBufferCount; + int sourceFormat; + int ecsPtr; + int roiFrameWidth; + int roiFrameHeight; + int roiFrameOffsetX; + int roiFrameOffsetY; + int roiMCUSize; + int colorComponents; +} JpgDecInitialInfo; + +typedef struct { + int scaleDownRatioWidth; + int scaleDownRatioHeight; +} JpgDecParam; + +typedef struct { + int indexFrameDisplay; + int numOfErrMBs; + int decodingSuccess; + int decPicHeight; + int decPicWidth; + int consumedByte; + int bytePosFrameStart; + int ecsPtr; +} JpgDecOutputInfo; + +//------------------------------------------------------------------------------ +// encode struct and definition +//------------------------------------------------------------------------------ + +typedef struct JpgInst JpgEncInst; +typedef JpgEncInst * JpgEncHandle; + +typedef struct { + PhysicalAddress bitstreamBuffer; + Uint32 bitstreamBufferSize; + int picWidth; + int picHeight; + int sourceFormat; + int restartInterval; + int streamEndian; + int frameEndian; + CbCrInterLeave chroma_interleave; + BYTE huffVal[4][162]; + BYTE huffBits[4][256]; + BYTE qMatTab[4][64]; + PackedOutputFormat packedFormat; +} JpgEncOpenParam; + +typedef struct { + int minFrameBufferCount; + int colorComponents; +} JpgEncInitialInfo; + +typedef struct { + FrameBuffer *sourceFrame; +} JpgEncParam; + +typedef struct { + PhysicalAddress bitstreamBuffer; + Uint32 bitstreamSize; +} JpgEncOutputInfo; + +typedef struct { + PhysicalAddress paraSet; + BYTE *pParaSet; + int size; + int headerMode; + int quantMode; + int huffMode; + int disableAPPMarker; +} JpgEncParamSet; + +#ifdef __cplusplus +extern "C" { +#endif + +int JPU_IsBusy(void); +Uint32 JPU_GetStatus(void); +void JPU_ClrStatus(Uint32 val); +Uint32 JPU_IsInit(void); +Uint32 JPU_WaitInterrupt(int timeout); + +JpgRet JPU_Init(void); +void JPU_DeInit(void); +int JPU_GetOpenInstanceNum(void); +JpgRet JPU_GetVersionInfo(Uint32 *versionInfo); + +// function for decode +JpgRet JPU_DecOpen(JpgDecHandle *pHandle, JpgDecOpenParam *pop); +JpgRet JPU_DecClose(JpgDecHandle handle); +JpgRet JPU_DecGetInitialInfo(JpgDecHandle handle, JpgDecInitialInfo *info); + +JpgRet JPU_DecSetRdPtr(JpgDecHandle handle, PhysicalAddress addr, int updateWrPtr); + +JpgRet JPU_DecRegisterFrameBuffer(JpgDecHandle handle, FrameBuffer *bufArray, int num, int strideY, int strideC); +JpgRet JPU_DecGetBitstreamBuffer(JpgDecHandle handle, PhysicalAddress *prdPrt, PhysicalAddress *pwrPtr, int *size); +JpgRet JPU_DecUpdateBitstreamBuffer(JpgDecHandle handle, int size); +JpgRet JPU_HWReset(void); +JpgRet JPU_SWReset(void); +JpgRet JPU_DecStartOneFrame(JpgDecHandle handle, JpgDecParam *param); +JpgRet JPU_DecGetOutputInfo(JpgDecHandle handle, JpgDecOutputInfo *info); +JpgRet JPU_DecIssueStop(JpgDecHandle handle); +JpgRet JPU_DecCompleteStop(JpgDecHandle handle); +JpgRet JPU_DecGiveCommand(JpgDecHandle handle, JpgCommand cmd, void *parameter); +JpgRet JPU_EncGetBitstreamBuffer(JpgEncHandle handle, PhysicalAddress *prdPrt, PhysicalAddress *pwrPtr, int *size); +JpgRet JPU_EncUpdateBitstreamBuffer(JpgEncHandle handle, int size); + +#ifdef __cplusplus +} +#endif + +#endif //_JPU_API_H_ diff --git a/u-boot-2021.10/drivers/jpeg/jpuapifunc.c b/u-boot-2021.10/drivers/jpeg/jpuapifunc.c new file mode 100644 index 000000000..ac5caf1d8 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpuapifunc.c @@ -0,0 +1,2112 @@ +#include "jdi.h" +#include "jpuapifunc.h" +#include "jpulog.h" +#include "regdefine.h" + +/****************************************************************************** + * Codec Instance Slot Management + ******************************************************************************/ + +// static UINT tGetBits(JpgDecInfo *jpg, int endian, int byteCnt); + +const char lendian[4] = {0x49, 0x49, 0x2A, 0x00}; +const char bendian[4] = {0x4D, 0x4D, 0x00, 0x2A}; + +const char *jfif = "JFIF"; +const char *jfxx = "JFXX"; +const char *exif = "Exif"; + +static unsigned char sJpuCompInfoTable[5][24] = { + {00, 02, 02, 00, 00, 00, 01, 01, 01, 01, 01, 01, + 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00}, // 420 + {00, 02, 01, 00, 00, 00, 01, 01, 01, 01, 01, 01, + 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00}, // 422H + {00, 01, 02, 00, 00, 00, 01, 01, 01, 01, 01, 01, + 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00}, // 422V + {00, 01, 01, 00, 00, 00, 01, 01, 01, 01, 01, 01, + 02, 01, 01, 01, 01, 01, 03, 00, 00, 00, 00, 00}, // 444 + {00, 01, 01, 00, 00, 00, 01, 00, 00, 00, 00, 00, + 02, 00, 00, 00, 00, 00, 03, 00, 00, 00, 00, 00}, // 400 +}; + +JpgRet InitJpgInstancePool(void) +{ + int i; + JpgInst *pJpgInst; + jpu_instance_pool_t *jip; + + jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + if (!jip) + return JPG_RET_INVALID_HANDLE; + + if (jip->instance_pool_inited == 0) { + for (i = 0; i < MAX_NUM_INSTANCE; i++) { + pJpgInst = (JpgInst *)jip->jpgInstPool[i]; + pJpgInst->instIndex = i; + pJpgInst->inUse = 0; + } + jip->instance_pool_inited = 1; + } + + return JPG_RET_SUCCESS; +} + +/* + * GetJpgInstance() obtains a instance. + * It stores a pointer to the allocated instance in *ppInst + * and returns JPG_RET_SUCCESS on success. + * Failure results in 0(null pointer) in *ppInst and JPG_RET_FAILURE. + */ + +JpgRet GetJpgInstance(JpgInst **ppInst) +{ + int i; + JpgInst *pJpgInst = 0; + jpu_instance_pool_t *jip; + + jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + if (!jip) + return JPG_RET_INVALID_HANDLE; + + for (i = 0; i < MAX_NUM_INSTANCE; ++i, ++pJpgInst) { + pJpgInst = (JpgInst *)jip->jpgInstPool[i]; + + if (!pJpgInst) { + return JPG_RET_FAILURE; + } + if (!pJpgInst->inUse) + break; + } + + if (i == MAX_NUM_INSTANCE) { + *ppInst = 0; + return JPG_RET_FAILURE; + } + + pJpgInst->inUse = 1; + *ppInst = pJpgInst; + + if (jdi_open_instance(pJpgInst->instIndex) < 0) + return JPG_RET_FAILURE; + + return JPG_RET_SUCCESS; +} + +void FreeJpgInstance(JpgInst *pJpgInst) +{ + pJpgInst->inUse = 0; + + jdi_close_instance(pJpgInst->instIndex); +} + +JpgRet CheckJpgInstValidity(JpgInst *pci) +{ + JpgInst *pJpgInst = 0; + int i; + jpu_instance_pool_t *jip; + + jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + + if (!jip) { + BM_DBG_ERR("jdi_get_instance_pool\n"); + return JPG_RET_FAILURE; + } + + for (i = 0; i < MAX_NUM_INSTANCE; ++i, ++pJpgInst) { + if ((JpgInst *)jip->jpgInstPool[i] == pci) + return JPG_RET_SUCCESS; + } + return JPG_RET_INVALID_HANDLE; +} + +/****************************************************************************** + * API Subroutines + ******************************************************************************/ + +JpgRet CheckJpgDecOpenParam(JpgDecOpenParam *pop) +{ + if (pop == 0) { + return JPG_RET_INVALID_PARAM; + } + if (pop->bitstreamBuffer % 8) { + return JPG_RET_INVALID_PARAM; + } + if (pop->bitstreamBufferSize % 1024 || + pop->bitstreamBufferSize < 1024) { + return JPG_RET_INVALID_PARAM; + } + + if (pop->chroma_interleave != CBCR_SEPARATED && + pop->chroma_interleave != CBCR_INTERLEAVE && + pop->chroma_interleave != CRCB_INTERLEAVE) { + return JPG_RET_INVALID_PARAM; + } + + if (pop->packedFormat > PACKED_FORMAT_444) { + return JPG_RET_INVALID_PARAM; + } + + if (pop->packedFormat != PACKED_FORMAT_NONE) { + if (pop->chroma_interleave != CBCR_SEPARATED) { + return JPG_RET_INVALID_PARAM; + } + } + + return JPG_RET_SUCCESS; +} + +int JpgDecHuffTabSetUp(JpgDecInfo *jpg) +{ + int i, j; + int HuffData; // 16BITS + int HuffLength; + int temp; + + // MIN Tables + JpuWriteReg(MJPEG_HUFF_CTRL_REG, 0x003); + + // DC Luma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffMin[0][j]; + temp = (HuffData & 0x8000) >> 15; + temp = (temp << 15) | (temp << 14) | (temp << 13) | + (temp << 12) | (temp << 11) | (temp << 10) | + (temp << 9) | (temp << 8) | (temp << 7) | (temp << 6) | + (temp << 5) | (temp << 4) | (temp << 3) | (temp << 2) | + (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, + (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit + } + + // DC Chroma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffMin[2][j]; + temp = (HuffData & 0x8000) >> 15; + temp = (temp << 15) | (temp << 14) | (temp << 13) | + (temp << 12) | (temp << 11) | (temp << 10) | + (temp << 9) | (temp << 8) | (temp << 7) | (temp << 6) | + (temp << 5) | (temp << 4) | (temp << 3) | (temp << 2) | + (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit + } + + // AC Luma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffMin[1][j]; + temp = (HuffData & 0x8000) >> 15; + temp = (temp << 15) | (temp << 14) | (temp << 13) | + (temp << 12) | (temp << 11) | (temp << 10) | + (temp << 9) | (temp << 8) | (temp << 7) | (temp << 6) | + (temp << 5) | (temp << 4) | (temp << 3) | (temp << 2) | + (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit + } + + // AC Chroma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffMin[3][j]; + temp = (HuffData & 0x8000) >> 15; + temp = (temp << 15) | (temp << 14) | (temp << 13) | + (temp << 12) | (temp << 11) | (temp << 10) | + (temp << 9) | (temp << 8) | (temp << 7) | (temp << 6) | + (temp << 5) | (temp << 4) | (temp << 3) | (temp << 2) | + (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); // 32-bit + } + // MAX Tables + JpuWriteReg(MJPEG_HUFF_CTRL_REG, 0x403); + JpuWriteReg(MJPEG_HUFF_ADDR_REG, 0x440); + + // DC Luma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffMax[0][j]; + temp = (HuffData & 0x8000) >> 15; + temp = (temp << 15) | (temp << 14) | (temp << 13) | + (temp << 12) | (temp << 11) | (temp << 10) | + (temp << 9) | (temp << 8) | (temp << 7) | (temp << 6) | + (temp << 5) | (temp << 4) | (temp << 3) | (temp << 2) | + (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); + } + // DC Chroma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffMax[2][j]; + temp = (HuffData & 0x8000) >> 15; + temp = (temp << 15) | (temp << 14) | (temp << 13) | + (temp << 12) | (temp << 11) | (temp << 10) | + (temp << 9) | (temp << 8) | (temp << 7) | (temp << 6) | + (temp << 5) | (temp << 4) | (temp << 3) | (temp << 2) | + (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); + } + // AC Luma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffMax[1][j]; + temp = (HuffData & 0x8000) >> 15; + temp = (temp << 15) | (temp << 14) | (temp << 13) | + (temp << 12) | (temp << 11) | (temp << 10) | + (temp << 9) | (temp << 8) | (temp << 7) | (temp << 6) | + (temp << 5) | (temp << 4) | (temp << 3) | (temp << 2) | + (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); + } + // AC Chroma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffMax[3][j]; + temp = (HuffData & 0x8000) >> 15; + temp = (temp << 15) | (temp << 14) | (temp << 13) | + (temp << 12) | (temp << 11) | (temp << 10) | + (temp << 9) | (temp << 8) | (temp << 7) | (temp << 6) | + (temp << 5) | (temp << 4) | (temp << 3) | (temp << 2) | + (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFF) << 16) | HuffData)); + } + + // PTR Tables + JpuWriteReg(MJPEG_HUFF_CTRL_REG, 0x803); + JpuWriteReg(MJPEG_HUFF_ADDR_REG, 0x880); + + // DC Luma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffPtr[0][j]; + temp = (HuffData & 0x80) >> 7; + temp = (temp << 23) | (temp << 22) | (temp << 21) | + (temp << 20) | (temp << 19) | (temp << 18) | + (temp << 17) | (temp << 16) | (temp << 15) | + (temp << 14) | (temp << 13) | (temp << 12) | + (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | + (temp << 7) | (temp << 6) | (temp << 5) | (temp << 4) | + (temp << 3) | (temp << 2) | (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); + } + // DC Chroma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffPtr[2][j]; + temp = (HuffData & 0x80) >> 7; + temp = (temp << 23) | (temp << 22) | (temp << 21) | + (temp << 20) | (temp << 19) | (temp << 18) | + (temp << 17) | (temp << 16) | (temp << 15) | + (temp << 14) | (temp << 13) | (temp << 12) | + (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | + (temp << 7) | (temp << 6) | (temp << 5) | (temp << 4) | + (temp << 3) | (temp << 2) | (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); + } + // AC Luma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffPtr[1][j]; + temp = (HuffData & 0x80) >> 7; + temp = (temp << 23) | (temp << 22) | (temp << 21) | + (temp << 20) | (temp << 19) | (temp << 18) | + (temp << 17) | (temp << 16) | (temp << 15) | + (temp << 14) | (temp << 13) | (temp << 12) | + (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | + (temp << 7) | (temp << 6) | (temp << 5) | (temp << 4) | + (temp << 3) | (temp << 2) | (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); + } + // AC Chroma + for (j = 0; j < 16; j++) { + HuffData = jpg->huffPtr[3][j]; + temp = (HuffData & 0x80) >> 7; + temp = (temp << 23) | (temp << 22) | (temp << 21) | + (temp << 20) | (temp << 19) | (temp << 18) | + (temp << 17) | (temp << 16) | (temp << 15) | + (temp << 14) | (temp << 13) | (temp << 12) | + (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | + (temp << 7) | (temp << 6) | (temp << 5) | (temp << 4) | + (temp << 3) | (temp << 2) | (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); + } + + // VAL Tables + JpuWriteReg(MJPEG_HUFF_CTRL_REG, 0xC03); + + // VAL DC Luma + HuffLength = 0; + for (i = 0; i < 12; i++) + HuffLength += jpg->huffBits[0][i]; + + for (i = 0; i < HuffLength; + i++) { // 8-bit, 12 row, 1 category (DC Luma) + HuffData = jpg->huffVal[0][i]; + temp = (HuffData & 0x80) >> 7; + temp = (temp << 23) | (temp << 22) | (temp << 21) | + (temp << 20) | (temp << 19) | (temp << 18) | + (temp << 17) | (temp << 16) | (temp << 15) | + (temp << 14) | (temp << 13) | (temp << 12) | + (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | + (temp << 7) | (temp << 6) | (temp << 5) | (temp << 4) | + (temp << 3) | (temp << 2) | (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); + } + + for (i = 0; i < 12 - HuffLength; i++) { + JpuWriteReg(MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); + } + + // VAL DC Chroma + HuffLength = 0; + for (i = 0; i < 12; i++) + HuffLength += jpg->huffBits[2][i]; + for (i = 0; i < HuffLength; i++) { // 8-bit, 12 row, 1 category (DC Chroma) + HuffData = jpg->huffVal[2][i]; + temp = (HuffData & 0x80) >> 7; + temp = (temp << 23) | (temp << 22) | (temp << 21) | + (temp << 20) | (temp << 19) | (temp << 18) | + (temp << 17) | (temp << 16) | (temp << 15) | + (temp << 14) | (temp << 13) | (temp << 12) | + (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | + (temp << 7) | (temp << 6) | (temp << 5) | (temp << 4) | + (temp << 3) | (temp << 2) | (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); + } + for (i = 0; i < 12 - HuffLength; i++) { + JpuWriteReg(MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); + } + + // VAL AC Luma + HuffLength = 0; + for (i = 0; i < 162; i++) + HuffLength += jpg->huffBits[1][i]; + for (i = 0; i < HuffLength; i++) { // 8-bit, 162 row, 1 category (AC Luma) + HuffData = jpg->huffVal[1][i]; + temp = (HuffData & 0x80) >> 7; + temp = (temp << 23) | (temp << 22) | (temp << 21) | + (temp << 20) | (temp << 19) | (temp << 18) | + (temp << 17) | (temp << 16) | (temp << 15) | + (temp << 14) | (temp << 13) | (temp << 12) | + (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | + (temp << 7) | (temp << 6) | (temp << 5) | (temp << 4) | + (temp << 3) | (temp << 2) | (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); + } + for (i = 0; i < 162 - HuffLength; i++) { + JpuWriteReg(MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); + } + + // VAL AC Chroma + HuffLength = 0; + for (i = 0; i < 162; i++) + HuffLength += jpg->huffBits[3][i]; + for (i = 0; i < HuffLength; i++) { // 8-bit, 162 row, 1 category (AC Chroma) + HuffData = jpg->huffVal[3][i]; + temp = (HuffData & 0x80) >> 7; + temp = (temp << 23) | (temp << 22) | (temp << 21) | + (temp << 20) | (temp << 19) | (temp << 18) | + (temp << 17) | (temp << 16) | (temp << 15) | + (temp << 14) | (temp << 13) | (temp << 12) | + (temp << 11) | (temp << 10) | (temp << 9) | (temp << 8) | + (temp << 7) | (temp << 6) | (temp << 5) | (temp << 4) | + (temp << 3) | (temp << 2) | (temp << 1) | (temp); + JpuWriteReg(MJPEG_HUFF_DATA_REG, (((temp & 0xFFFFFF) << 8) | HuffData)); + } + + for (i = 0; i < 162 - HuffLength; i++) { + JpuWriteReg(MJPEG_HUFF_DATA_REG, 0xFFFFFFFF); + } + + // end SerPeriHuffTab + JpuWriteReg(MJPEG_HUFF_CTRL_REG, 0x000); + + return 1; +} + +int JpgDecQMatTabSetUp(JpgDecInfo *jpg) +{ + + int i; + int table; + int val; + + // SetPeriQMatTab + // Comp 0 + JpuWriteReg(MJPEG_QMAT_CTRL_REG, 0x03); + table = jpg->cInfoTab[0][3]; + for (i = 0; i < 64; i++) { + val = jpg->qMatTab[table][i]; + JpuWriteReg(MJPEG_QMAT_DATA_REG, val); + } + JpuWriteReg(MJPEG_QMAT_CTRL_REG, 0x00); + + // Comp 1 + JpuWriteReg(MJPEG_QMAT_CTRL_REG, 0x43); + table = jpg->cInfoTab[1][3]; + for (i = 0; i < 64; i++) { + val = jpg->qMatTab[table][i]; + JpuWriteReg(MJPEG_QMAT_DATA_REG, val); + } + JpuWriteReg(MJPEG_QMAT_CTRL_REG, 0x00); + + // Comp 2 + JpuWriteReg(MJPEG_QMAT_CTRL_REG, 0x83); + table = jpg->cInfoTab[2][3]; + for (i = 0; i < 64; i++) { + val = jpg->qMatTab[table][i]; + JpuWriteReg(MJPEG_QMAT_DATA_REG, val); + } + JpuWriteReg(MJPEG_QMAT_CTRL_REG, 0x00); + return 1; +} + +void JpgDecGramSetup(JpgDecInfo *jpg) +{ + int dExtBitBufCurPos; + int dExtBitBufBaseAddr; + int dMibStatus; + + dMibStatus = 1; + dExtBitBufCurPos = jpg->pagePtr; + dExtBitBufBaseAddr = jpg->streamBufStartAddr; + + JpuWriteReg(MJPEG_BBC_CUR_POS_REG, dExtBitBufCurPos); + JpuWriteReg(MJPEG_BBC_EXT_ADDR_REG, dExtBitBufBaseAddr + (dExtBitBufCurPos << 8)); + JpuWriteReg(MJPEG_BBC_INT_ADDR_REG, (dExtBitBufCurPos & 1) << 6); + JpuWriteReg(MJPEG_BBC_DATA_CNT_REG, 256 / 4); // 64 * 4 byte == 32 * 8 byte + JpuWriteReg(MJPEG_BBC_COMMAND_REG, (jpg->streamEndian << 1) | 0); + + while (dMibStatus == 1) { + dMibStatus = JpuReadReg(MJPEG_BBC_BUSY_REG); + } + + dMibStatus = 1; + dExtBitBufCurPos = dExtBitBufCurPos + 1; + + JpuWriteReg(MJPEG_BBC_CUR_POS_REG, dExtBitBufCurPos); + JpuWriteReg(MJPEG_BBC_EXT_ADDR_REG, dExtBitBufBaseAddr + (dExtBitBufCurPos << 8)); + JpuWriteReg(MJPEG_BBC_INT_ADDR_REG, (dExtBitBufCurPos & 1) << 6); + JpuWriteReg(MJPEG_BBC_DATA_CNT_REG, 256 / 4); // 64 * 4 byte == 32 * 8 byte + JpuWriteReg(MJPEG_BBC_COMMAND_REG, (jpg->streamEndian << 1) | 0); + + while (dMibStatus == 1) { + dMibStatus = JpuReadReg(MJPEG_BBC_BUSY_REG); + } + + dMibStatus = 1; + dExtBitBufCurPos = dExtBitBufCurPos + 1; + + JpuWriteReg(MJPEG_BBC_CUR_POS_REG, dExtBitBufCurPos); // next unit page pointer + + JpuWriteReg(MJPEG_BBC_CTRL_REG, (jpg->streamEndian << 1) | 1); + + JpuWriteReg(MJPEG_GBU_WD_PTR_REG, jpg->wordPtr); + + JpuWriteReg(MJPEG_GBU_BBSR_REG, 0); + JpuWriteReg(MJPEG_GBU_BBER_REG, ((256 / 4) * 2) - 1); + + if (jpg->pagePtr & 1) { + JpuWriteReg(MJPEG_GBU_BBIR_REG, 0); + JpuWriteReg(MJPEG_GBU_BBHR_REG, 0); + } else { + JpuWriteReg(MJPEG_GBU_BBIR_REG, 256 / 4); // 64 * 4 byte == 32 * 8 byte + JpuWriteReg(MJPEG_GBU_BBHR_REG, 256 / 4); // 64 * 4 byte == 32 * 8 byte + } + + JpuWriteReg(MJPEG_GBU_CTRL_REG, 4); + JpuWriteReg(MJPEG_GBU_FF_RPTR_REG, jpg->bitPtr); +} + +enum { + SAMPLE_420 = 0xA, + SAMPLE_H422 = 0x9, + SAMPLE_V422 = 0x6, + SAMPLE_444 = 0x5, + SAMPLE_400 = 0x1 +}; + +const BYTE cDefHuffBits[4][16] = { + {// DC index 0 (Luminance DC) + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {// AC index 0 (Luminance AC) + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, + 0x00, 0x00, 0x01, 0x7D}, + {// DC index 1 (Chrominance DC) + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {// AC index 1 (Chrominance AC) + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, + 0x00, 0x01, 0x02, 0x77} +}; + +const BYTE cDefHuffVal[4][162] = { + {// DC index 0 (Luminance DC) + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B}, + {// AC index 0 (Luminance AC) + 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}, + {// DC index 1 (Chrominance DC) + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B}, + {// AC index 1 (Chrominance AC) + 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} +}; + +enum { + Marker = 0xFF, + FF_Marker = 0x00, + + SOI_Marker = 0xFFD8, // Start of image + EOI_Marker = 0xFFD9, // End of image + + JFIF_CODE = 0xFFE0, // Application + EXIF_CODE = 0xFFE1, + + DRI_Marker = 0xFFDD, // Define restart interval + RST_Marker = 0xD, // 0xD0 ~0xD7 + + DQT_Marker = 0xFFDB, // Define quantization table(s) + DHT_Marker = 0xFFC4, // Define Huffman table(s) + + SOF_Marker = 0xFFC0, // Start of frame : Baseline DCT + SOS_Marker = 0xFFDA, // Start of scan +}; + +int check_start_code(JpgDecInfo *jpg) +{ + if (show_bits(&jpg->gbc, 8) == 0xFF) + return 1; + else + return 0; +} + +int find_start_code(JpgDecInfo *jpg) +{ + int word; + + for (;;) { + if (get_bits_left(&jpg->gbc) <= 16) { + ////printf("hit end of stream\n"); + return 0; + } + + word = show_bits(&jpg->gbc, 16); + if (word > 0xFF00 && word < 0xFFFF) + break; + + get_bits(&jpg->gbc, 8); + } + + return word; +} + +int find_start_soi_code(JpgDecInfo *jpg) +{ + int word; + + for (;;) { + if (get_bits_left(&jpg->gbc) <= 16) { + ////printf("hit end of stream\n"); + return 0; + } + + word = show_bits(&jpg->gbc, 16); + if (word > 0xFF00 && word < 0xFFFF) { + if (word != SOI_Marker) + get_bits(&jpg->gbc, 8); + break; + } + + get_bits(&jpg->gbc, 8); + } + + return word; +} + +#ifdef MJPEG_ERROR_CONCEAL +int find_restart_marker(JpgDecInfo *jpg) +{ + int word; + + for (;;) { + if (get_bits_left(&jpg->gbc) <= 16) { + ////printf("hit end of stream\n"); + return -1; + } + + word = show_bits(&jpg->gbc, 16); + if ((word >= 0xFFD0 && word <= 0xFFD7) || word == 0xFFD8 || word == 0xFFD9) + break; + + get_bits(&jpg->gbc, 8); + } + + return word; +} +#endif + +int decode_app_header(JpgDecInfo *jpg) +{ + int length; + + if (get_bits_left(&jpg->gbc) < 16) + return 0; + length = get_bits(&jpg->gbc, 16); + length -= 2; + + while (length-- > 0) { + if (get_bits_left(&jpg->gbc) < 8) + return 0; + get_bits(&jpg->gbc, 8); + } + + return 1; +} + +int decode_dri_header(JpgDecInfo *jpg) +{ + // Length, Lr + if (get_bits_left(&jpg->gbc) < 16 * 2) + return 0; + get_bits(&jpg->gbc, 16); + + jpg->rstIntval = get_bits(&jpg->gbc, 16); + + return 1; +} + +int decode_dqt_header(JpgDecInfo *jpg) +{ + int Pq; + int Tq; + int i; + int tmp; + + if (get_bits_left(&jpg->gbc) < 16) + return 0; + + // Lq, Length of DQT + get_bits(&jpg->gbc, 16); + + do { + + if (get_bits_left(&jpg->gbc) < 4 + 4 + 8 * 64) + return 0; + + // Pq, Quantization Precision + tmp = get_bits(&jpg->gbc, 8); + // Tq, Quantization table destination identifier + Pq = (tmp >> 4) & 0xf; + Tq = tmp & 0xf; + + for (i = 0; i < 64; i++) + jpg->qMatTab[Tq][i] = (BYTE)get_bits(&jpg->gbc, 8); + } while (!check_start_code(jpg)); + + if (Pq != 0) {// not 8-bit + ////printf("pq is not set to zero\n"); + return 0; + } + return 1; +} + +int decode_dth_header(JpgDecInfo *jpg) +{ + int Tc; + int Th; + int ThTc; + int bitCnt; + int i; + int tmp; + // Length, Lh + if (get_bits_left(&jpg->gbc) < 16) + return 0; + + get_bits(&jpg->gbc, 16); + + do { + + if (get_bits_left(&jpg->gbc) < 8 + 8 * 16) + return 0; + + // Table class - DC, AC + tmp = get_bits(&jpg->gbc, 8); + // Table destination identifier + Tc = (tmp >> 4) & 0xf; + Th = tmp & 0xf; + + // DC_ID0 (0x00) -> 0 + // AC_ID0 (0x10) -> 1 + // DC_ID1 (0x01) -> 2 + // AC_ID1 (0x11) -> 3 + ThTc = ((Th & 1) << 1) | (Tc & 1); + + // Get Huff Bits list + bitCnt = 0; + for (i = 0; i < 16; i++) { + jpg->huffBits[ThTc][i] = (BYTE)get_bits(&jpg->gbc, 8); + bitCnt += jpg->huffBits[ThTc][i]; + + if (cDefHuffBits[ThTc][i] != jpg->huffBits[ThTc][i]) + jpg->userHuffTab = 1; + } + + if (get_bits_left(&jpg->gbc) < 8 * bitCnt) + return 0; + + // Get Huff Val list + for (i = 0; i < bitCnt; i++) { + jpg->huffVal[ThTc][i] = (BYTE)get_bits(&jpg->gbc, 8); + if (cDefHuffVal[ThTc][i] != jpg->huffVal[ThTc][i]) + jpg->userHuffTab = 1; + } + } while (!check_start_code(jpg)); + + return 1; +} + +int decode_sof_header(JpgDecInfo *jpg) +{ + int samplePrecision; + int sampleFactor; + int i; + int Tqi; + BYTE compID; + int hSampFact[3] = { + 0, + }; + int vSampFact[3] = { + 0, + }; + int picX, picY; + int numComp; + int tmp; + + if (get_bits_left(&jpg->gbc) < 16 + 8 + 16 + 16 + 8) + return 0; + // LF, Length of SOF + get_bits(&jpg->gbc, 16); + + // Sample Precision: Baseline(8), P + samplePrecision = get_bits(&jpg->gbc, 8); + + if (samplePrecision != 8) { + // printf("Sample Precision is not 8\n"); + return 0; + } + + picY = get_bits(&jpg->gbc, 16); + if (picY > MAX_MJPG_PIC_WIDTH) { + // printf("Picture Vertical Size limits Maximum size\n"); + return 0; + } + + picX = get_bits(&jpg->gbc, 16); + if (picX > MAX_MJPG_PIC_HEIGHT) { + // printf("Picture Horizontal Size limits Maximum size\n"); + return 0; + } + + // Number of Components in Frame: Nf + numComp = get_bits(&jpg->gbc, 8); + if (numComp > 3) { + // printf("Picture Horizontal Size limits Maximum size\n"); + } + + if (get_bits_left(&jpg->gbc) < numComp * (8 + 4 + 4 + 8)) + return 0; + for (i = 0; i < numComp; i++) { + // Component ID, Ci 0 ~ 255 + compID = (BYTE)get_bits(&jpg->gbc, 8); + tmp = get_bits(&jpg->gbc, 8); + // Horizontal Sampling Factor, Hi + hSampFact[i] = (tmp >> 4) & 0xf; + // Vertical Sampling Factor, Vi + vSampFact[i] = tmp & 0xf; + // Quantization Table Selector, Tqi + Tqi = get_bits(&jpg->gbc, 8); + + jpg->cInfoTab[i][0] = compID; + jpg->cInfoTab[i][1] = (BYTE)hSampFact[i]; + jpg->cInfoTab[i][2] = (BYTE)vSampFact[i]; + jpg->cInfoTab[i][3] = (BYTE)Tqi; + } + + // if ( hSampFact[0]>2 || vSampFact[0]>2 || ( numComp == 3 && ( + // hSampFact[1]!=1 || hSampFact[2]!=1 || vSampFact[1]!=1 || + // vSampFact[2]!=1) ) ) printf("Not Supported Sampling Factor\n"); + + if (numComp == 1) + sampleFactor = SAMPLE_400; + else + sampleFactor = ((hSampFact[0] & 3) << 2) | (vSampFact[0] & 3); + + switch (sampleFactor) { + case SAMPLE_420: + jpg->format = FORMAT_420; + break; + case SAMPLE_H422: + jpg->format = FORMAT_422; + break; + case SAMPLE_V422: + jpg->format = FORMAT_224; + break; + case SAMPLE_444: + jpg->format = FORMAT_444; + break; + default: // 4:0:0 + jpg->format = FORMAT_400; + } + + jpg->picWidth = picX; + jpg->picHeight = picY; + + return 1; +} + +int decode_sos_header(JpgDecInfo *jpg) +{ + int i, j; + int len; + int numComp; + int compID; + int ecsPtr; + int ss, se, ah, al; + int dcHufTblIdx[3] = { + 0, + }; + int acHufTblIdx[3] = { + 0, + }; + int tmp; + + if (get_bits_left(&jpg->gbc) < 8) + return 0; + // Length, Ls + len = get_bits(&jpg->gbc, 16); + + jpg->ecsPtr = get_bits_count(&jpg->gbc) / 8 + len - 2; + + ecsPtr = jpg->ecsPtr + jpg->frameOffset; + + // printf("ecsPtr=0x%x frameOffset=0x%x, ecsOffset=0x%x, wrPtr=0x%x, + // rdPtr0x%x\n", jpg->ecsPtr, jpg->frameOffset, ecsPtr, + // jpg->streamWrPtr, jpg->streamRdPtr); + + jpg->pagePtr = ecsPtr >> 8; // page unit ecsPtr/256; + jpg->wordPtr = (ecsPtr & 0xF0) >> 2; // word unit ((ecsPtr % 256) & 0xF0) / 4; + + if (jpg->pagePtr & 1) + jpg->wordPtr += 64; + if (jpg->wordPtr & 1) + jpg->wordPtr -= 1; // to make even. + + jpg->bitPtr = (ecsPtr & 0xF) << 3; // bit unit (ecsPtr & 0xF) * 8; + + if (get_bits_left(&jpg->gbc) < 8) + return 0; + // Number of Components in Scan: Ns + numComp = get_bits(&jpg->gbc, 8); + + if (get_bits_left(&jpg->gbc) < numComp * (8 + 4 + 4)) + return 0; + for (i = 0; i < numComp; i++) { + // Component ID, Csj 0 ~ 255 + compID = get_bits(&jpg->gbc, 8); + tmp = get_bits(&jpg->gbc, 8); + // dc entropy coding table selector, Tdj + dcHufTblIdx[i] = (tmp >> 4) & 0xf; + // ac entropy coding table selector, Taj + acHufTblIdx[i] = tmp & 0xf; + + for (j = 0; j < numComp; j++) { + if (compID == jpg->cInfoTab[j][0]) { + jpg->cInfoTab[j][4] = (BYTE)dcHufTblIdx[i]; + jpg->cInfoTab[j][5] = (BYTE)acHufTblIdx[i]; + } + } + } + + if (get_bits_left(&jpg->gbc) < 8 + 8 + 4 + 4) + return 0; + // Ss 0 + ss = get_bits(&jpg->gbc, 8); + // Se 3F + se = get_bits(&jpg->gbc, 8); + tmp = get_bits(&jpg->gbc, 8); + // Ah 0 + ah = (i >> 4) & 0xf; + // Al 0 + al = tmp & 0xf; + + if (ss != 0 || se != 0x3F || ah != 0 || al != 0) { + // printf("The Jpeg Image must be another profile\n"); + return 0; + } + + return 1; +} + +static void genDecHuffTab(JpgDecInfo *jpg, int tabNum) +{ + unsigned char *huffPtr, *huffBits; + unsigned int *huffMax, *huffMin; + + int ptrCnt = 0; + int huffCode = 0; + int zeroFlag = 0; + int dataFlag = 0; + int i; + + huffBits = jpg->huffBits[tabNum]; + huffPtr = jpg->huffPtr[tabNum]; + huffMax = jpg->huffMax[tabNum]; + huffMin = jpg->huffMin[tabNum]; + + for (i = 0; i < 16; i++) { + if (huffBits[i]) { // if there is bit cnt value + huffPtr[i] = (BYTE)ptrCnt; + ptrCnt += huffBits[i]; + huffMin[i] = huffCode; + huffMax[i] = huffCode + (huffBits[i] - 1); + dataFlag = 1; + zeroFlag = 0; + } else { + huffPtr[i] = 0xFF; + huffMin[i] = 0xFFFF; + huffMax[i] = 0xFFFF; + zeroFlag = 1; + } + + if (dataFlag == 1) { + if (zeroFlag == 1) + huffCode <<= 1; + else + huffCode = (huffMax[i] + 1) << 1; + } + } +} + +int JpuGbuInit(vpu_getbit_context_t *ctx, BYTE *buffer, int size) +{ + + ctx->buffer = buffer; + ctx->index = 0; + ctx->size = size / 8; + + return 1; +} + +int JpuGbuGetUsedBitCount(vpu_getbit_context_t *ctx) { return ctx->index * 8; } + +int JpuGbuGetLeftBitCount(vpu_getbit_context_t *ctx) +{ + return (ctx->size * 8) - JpuGbuGetUsedBitCount(ctx); +} + +unsigned int JpuGbuGetBit(vpu_getbit_context_t *ctx, int bit_num) +{ + BYTE *p; + unsigned int b = 0x0; + + if (bit_num > JpuGbuGetLeftBitCount(ctx)) + return (unsigned int)-1; + + p = ctx->buffer + ctx->index; + + if (bit_num == 8) { + b = *p; + ctx->index++; + } else if (bit_num == 16) { + b = *p++ << 8; + b |= *p++; + ctx->index += 2; + } else if (bit_num == 32) { + b = *p++ << 24; + b |= (*p++ << 16); + b |= (*p++ << 8); + b |= (*p++ << 0); + ctx->index += 4; + } + + return b; +} + +unsigned int JpuGguShowBit(vpu_getbit_context_t *ctx, int bit_num) +{ + BYTE *p; + unsigned int b = 0x0; + + if (bit_num > JpuGbuGetLeftBitCount(ctx)) + return (unsigned int)-1; + + p = ctx->buffer + ctx->index; + + if (bit_num == 8) { + b = *p; + } else if (bit_num == 16) { + b = *p++ << 8; + b |= *p++; + } else if (bit_num == 32) { + b = *p++ << 24; + b |= (*p++ << 16); + b |= (*p++ << 8); + b |= (*p++ << 0); + } + + return b; +} + +static int wraparound_bistream_data(JpgDecInfo *jpg, int return_type) +{ + BYTE *dst; + BYTE *src; + BYTE *data; + int data_size; + int src_size; + int dst_size; + + data_size = jpg->streamWrPtr - jpg->streamBufStartAddr; + data = (BYTE *)OSAL_MALLOC(data_size); + + if (data_size && data) + JpuReadMem(jpg->streamBufStartAddr, data, data_size, + jpg->streamEndian); + + src_size = jpg->streamBufSize - jpg->frameOffset; + src = (BYTE *)OSAL_MALLOC(src_size); + dst_size = ((src_size + (JPU_GBU_SIZE - 1)) & ~(JPU_GBU_SIZE - 1)); + dst = (BYTE *)OSAL_MALLOC(dst_size); + if (dst && src) { + memset(dst, 0x00, dst_size); + JpuReadMem(jpg->streamBufStartAddr + jpg->frameOffset, src, src_size, jpg->streamEndian); + memcpy(dst + (dst_size - src_size), src, src_size); + JpuWriteMem(jpg->streamBufStartAddr, dst, dst_size, jpg->streamEndian); + if (data_size && data) + JpuWriteMem(jpg->streamBufStartAddr + dst_size, data, data_size, jpg->streamEndian); + OSAL_FREE(src); + OSAL_FREE(dst); + } + + if (data_size && data) + OSAL_FREE(data); + + if (return_type == -2) { // header wraparound + jpg->streamWrPtr = jpg->streamBufStartAddr + dst_size + data_size; + jpg->consumeByte = 0; + return -2; + } else if (return_type == -1) { // ecsPtr wraparound + jpg->streamWrPtr = jpg->streamBufStartAddr + dst_size + data_size; + jpg->frameOffset = 0; + return -1; + } + + return 0; // error +} + +#ifdef MJPEG_ERROR_CONCEAL +int JpegDecodeConcealError(JpgDecInfo *jpg) +{ + unsigned int code; + int ret, foced_stop = 0; + BYTE *b; + Uint32 ecsPtr = 0; + Uint32 size, wrOffset; + Uint32 nextMarkerPtr; + Uint32 iRstIdx; + int numMcu = 0, numMcuCol = 0; + + // "nextOffset" is distance between frameOffset and next_restart_index + // that exist. + nextMarkerPtr = jpg->nextOffset + jpg->frameOffset; + + if (jpg->streamWrPtr == jpg->streamBufStartAddr) { + size = jpg->streamBufSize - nextMarkerPtr; + wrOffset = jpg->streamBufSize; + } else { + size = jpg->streamWrPtr - nextMarkerPtr; + wrOffset = (jpg->streamWrPtr - jpg->streamBufStartAddr); + } + + // pointing to find next_restart_marker + b = jpg->pBitStream + nextMarkerPtr; + init_get_bits(&jpg->gbc, b, size * 8); + + for (;;) { + + ret = find_restart_marker(jpg); + if (ret < 0) { + break; + } + + code = get_bits(&jpg->gbc, 16); + if (code == 0xFFD8 || code == 0xFFD9) { + // if next_start_maker meet EOI(end of picture) or next + // SOI(start of image) but decoding is not completed + // yet, To prevent over picture boundary in ringbuffer + // mode, finding previous maker and make decoding forced + // to stop. + b = jpg->pBitStream + jpg->currOffset + jpg->frameOffset; + init_get_bits(&jpg->gbc, b, size * 8); + + nextMarkerPtr = jpg->currOffset + jpg->frameOffset; + foced_stop = 1; + continue; + } + + iRstIdx = (code & 0xF); + // you can find next restart marker which will be. + if (iRstIdx >= 0 && iRstIdx <= 7) { + int numMcuRow; + + if (get_bits_left(&jpg->gbc) < 8) + return (-1); + + jpg->ecsPtr = get_bits_count(&jpg->gbc) / 8; + // set ecsPtr that restart marker is founded. + ecsPtr = jpg->ecsPtr + nextMarkerPtr; + + jpg->pagePtr = ecsPtr >> 8; + jpg->wordPtr = (ecsPtr & 0xF0) >> 2; // word unit + if (jpg->pagePtr & 1) + jpg->wordPtr += 64; + if (jpg->wordPtr & 1) + jpg->wordPtr -= 1; // to make even. + + jpg->bitPtr = (ecsPtr & 0xF) << 3; // bit unit + + numMcuRow = (jpg->alignedWidth / jpg->mcuWidth); + numMcuCol = (jpg->alignedHeight / jpg->mcuHeight); + + // num of restart marker that is rounded can be + // calculated from error position. + // numRstMakerRounding = + // ((jpg->errInfo.errPosY*numMcuRow + + // jpg->errInfo.errPosX) / (jpg->rstIntval*8)); + jpg->curRstIdx = iRstIdx; + if (jpg->curRstIdx < jpg->nextRstIdx) + jpg->numRstMakerRounding++; + + // find mcu position to restart. + numMcu = + (jpg->numRstMakerRounding * jpg->rstIntval * 8) + + (jpg->curRstIdx + 1) * jpg->rstIntval; + // numMcu = jpg->rstIntval; + jpg->setPosX = (numMcu % numMcuRow); + jpg->setPosY = (numMcu / numMcuRow); + jpg->gbuStartPtr = ((ecsPtr - jpg->frameOffset) / 256) * 256; + + // if setPosY is greater than Picture Height, set mcu + // position to last mcu of picture to finish decoding. + if (jpg->setPosY > numMcuCol || foced_stop) { + jpg->setPosX = numMcuRow - 1; + jpg->setPosY = numMcuCol - 1; + } + + // update restart_index to find next. + jpg->nextRstIdx = iRstIdx++; + + ret = 0; + break; + } + } + + // prevent to find same position. + jpg->currOffset = jpg->nextOffset; + + // if the distance between ecsPtr and streamBufEndAddr is less than + // 512byte, that rdPtr run over than streamBufEndAddr without interrupt. + // bellow is workaround to avoid this case. + if (jpg->streamBufSize - (jpg->frameOffset + ecsPtr) < JPU_GBU_SIZE) + // if((jpg->streamBufEndAddr - ecsPtr < JPU_GBU_SIZE) ) + { + ret = wraparound_bistream_data(jpg, -1); + } + + if (wrOffset - (jpg->frameOffset + jpg->ecsPtr) < JPU_GBU_SIZE && jpg->streamEndflag == 0) { + return -1; + } + return ret; +} +#endif + +int JpegDecodeHeader(JpgDecInfo *jpg) +{ + + unsigned int code; + int ret; + int i; + int temp; + int wrOffset; + BYTE *b = jpg->pBitStream + jpg->frameOffset; + int size; + + ret = 1; + if (jpg->streamWrPtr == jpg->streamBufStartAddr) { + size = jpg->streamBufSize - jpg->frameOffset; + wrOffset = jpg->streamBufSize; + } else { + if (jpg->frameOffset >= (int)(jpg->streamWrPtr - jpg->streamBufStartAddr)) + size = jpg->streamBufSize - jpg->frameOffset; + else + size = (jpg->streamWrPtr - jpg->streamBufStartAddr) - jpg->frameOffset; + wrOffset = (jpg->streamWrPtr - jpg->streamBufStartAddr); + } + + if (!b || !size) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + + // find start code of next frame + if (!jpg->ecsPtr) { + int nextOffset = 0; + int soiOffset = 0; + + if (jpg->consumeByte != 0) { // meaning is frameIdx > 0 + nextOffset = jpg->consumeByte; + if (nextOffset <= 0) + nextOffset = 2; // in order to consume start code. + } + + // consume to find the start code of next frame. + b += nextOffset; + size -= nextOffset; + + if (size < 0) { + jpg->consumeByte -= (b - (jpg->pBitStream + jpg->streamBufSize)); + if (jpg->consumeByte < 0) { + ret = 0; + goto DONE_DEC_HEADER; + } + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + + init_get_bits(&jpg->gbc, b, size * 8); + for (;;) { + code = find_start_soi_code(jpg); + if (code == 0) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + + if (code == SOI_Marker) + break; + } + + soiOffset = get_bits_count(&jpg->gbc) / 8; + + b += soiOffset; + size -= soiOffset; + jpg->frameOffset += (soiOffset + nextOffset); + } + + if (jpg->headerSize > 0 && (jpg->headerSize > (jpg->streamBufSize - jpg->frameOffset))) { + // if header size is smaller than room of stream end. copy the buffer to bistream start. + BM_DBG_ERR("\n"); + return wraparound_bistream_data(jpg, -2); + } + + init_get_bits(&jpg->gbc, b, size * 8); + // Initialize component information table + for (i = 0; i < 4; i++) { + jpg->cInfoTab[i][0] = 0; + jpg->cInfoTab[i][1] = 0; + jpg->cInfoTab[i][2] = 0; + jpg->cInfoTab[i][3] = 0; + jpg->cInfoTab[i][4] = 0; + jpg->cInfoTab[i][5] = 0; + } + + for (;;) { + if (find_start_code(jpg) == 0) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + + code = get_bits(&jpg->gbc, 16); // getbit 2byte + + switch (code) { + case SOI_Marker: + break; + case JFIF_CODE: + case EXIF_CODE: { + if (!decode_app_header(jpg)) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + } + + break; + case DRI_Marker: + if (!decode_dri_header(jpg)) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + break; + case DQT_Marker: + if (!decode_dqt_header(jpg)) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + break; + case DHT_Marker: + if (!decode_dth_header(jpg)) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + break; + case SOF_Marker: + if (!decode_sof_header(jpg)) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + break; + case SOS_Marker: + if (!decode_sos_header(jpg)) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + // we assume header size of all frame is same for mjpeg case + if (!jpg->headerSize) + jpg->headerSize = jpg->ecsPtr; + goto DONE_DEC_HEADER; +// break; + case EOI_Marker: + goto DONE_DEC_HEADER; + default: + switch (code & 0xFFF0) { + case 0xFFE0: // 0xFFEX + case 0xFFF0: // 0xFFFX + if (get_bits_left(&jpg->gbc) <= 0) { + { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + } else { + if (!decode_app_header(jpg)) { + ret = -1; + BM_DBG_ERR("DONE_DEC_HEADER\n"); + goto DONE_DEC_HEADER; + } + break; + } + default: + // in case, restart marker is founded. + if ((code & 0xFFF0) >= 0xFFD0 && (code & 0xFFF0) <= 0xFFD7) + break; + + return 0; + } + break; + } + } + +DONE_DEC_HEADER: + + if (ret == -1) { + if (wrOffset < jpg->frameOffset) { + BM_DBG_ERR("fail\n"); + return -2; + } + + BM_DBG_ERR("fail\n"); + return -1; + } + + if (!jpg->ecsPtr) { + BM_DBG_ERR("fail\n"); + return 0; + } + + if (wrOffset - (jpg->frameOffset + jpg->ecsPtr) < JPU_GBU_SIZE && jpg->streamEndflag == 0) { + BM_DBG_ERR("fail\n"); + return -1; + } + + // this bellow is workaround to avoid the case that JPU is run over + // without interrupt. + if (jpg->streamBufSize - (jpg->frameOffset + jpg->ecsPtr) < JPU_GBU_SIZE) { + BM_DBG_ERR("fail\n"); + return wraparound_bistream_data(jpg, -1); + } + + // Generate Huffman table information + for (i = 0; i < 4; i++) + genDecHuffTab(jpg, i); + + // Q Idx + temp = jpg->cInfoTab[0][3]; + temp = temp << 1 | jpg->cInfoTab[1][3]; + temp = temp << 1 | jpg->cInfoTab[2][3]; + jpg->Qidx = temp; + + // Huff Idx[DC, AC] + temp = jpg->cInfoTab[0][4]; + temp = temp << 1 | jpg->cInfoTab[1][4]; + temp = temp << 1 | jpg->cInfoTab[2][4]; + jpg->huffDcIdx = temp; + + temp = jpg->cInfoTab[0][5]; + temp = temp << 1 | jpg->cInfoTab[1][5]; + temp = temp << 1 | jpg->cInfoTab[2][5]; + jpg->huffAcIdx = temp; + + switch (jpg->format) { + case FORMAT_420: + jpg->busReqNum = 2; + jpg->mcuBlockNum = 6; + jpg->compNum = 3; + jpg->compInfo[0] = 10; + jpg->compInfo[1] = 5; + jpg->compInfo[2] = 5; + jpg->alignedWidth = ((jpg->picWidth + 15) & ~15); + jpg->alignedHeight = ((jpg->picHeight + 15) & ~15); + jpg->mcuWidth = 16; + jpg->mcuHeight = 16; + break; + case FORMAT_422: + jpg->busReqNum = 3; + jpg->mcuBlockNum = 4; + jpg->compNum = 3; + jpg->compInfo[0] = 9; + jpg->compInfo[1] = 5; + jpg->compInfo[2] = 5; + jpg->alignedWidth = ((jpg->picWidth + 15) & ~15); + jpg->alignedHeight = ((jpg->picHeight + 7) & ~7); + jpg->mcuWidth = 16; + jpg->mcuHeight = 8; + break; + case FORMAT_224: + jpg->busReqNum = 3; + jpg->mcuBlockNum = 4; + jpg->compNum = 3; + jpg->compInfo[0] = 6; + jpg->compInfo[1] = 5; + jpg->compInfo[2] = 5; + jpg->alignedWidth = ((jpg->picWidth + 7) & ~7); + jpg->alignedHeight = ((jpg->picHeight + 15) & ~15); + jpg->mcuWidth = 8; + jpg->mcuHeight = 16; + break; + case FORMAT_444: + jpg->busReqNum = 4; + jpg->mcuBlockNum = 3; + jpg->compNum = 3; + jpg->compInfo[0] = 5; + jpg->compInfo[1] = 5; + jpg->compInfo[2] = 5; + jpg->alignedWidth = ((jpg->picWidth + 7) & ~7); + jpg->alignedHeight = ((jpg->picHeight + 7) & ~7); + jpg->mcuWidth = 8; + jpg->mcuHeight = 8; + break; + case FORMAT_400: + jpg->busReqNum = 4; + jpg->mcuBlockNum = 1; + jpg->compNum = 1; + jpg->compInfo[0] = 5; + jpg->compInfo[1] = 0; + jpg->compInfo[2] = 0; + jpg->alignedWidth = ((jpg->picWidth + 7) & ~7); + jpg->alignedHeight = ((jpg->picHeight + 7) & ~7); + jpg->mcuWidth = 8; + jpg->mcuHeight = 8; + break; + } + + return 1; +} + +JpgRet CheckJpgEncOpenParam(JpgEncOpenParam *pop) +{ + int picWidth; + int picHeight; + + if (pop == 0) { + BM_DBG_ERR("JPG_RET_INVALID_PARAM\n"); + return JPG_RET_INVALID_PARAM; + } + + picWidth = pop->picWidth; + picHeight = pop->picHeight; + + if (pop->bitstreamBuffer % 8) { + BM_DBG_ERR("bitstreamBuffer, JPG_RET_INVALID_PARAM\n"); + return JPG_RET_INVALID_PARAM; + } + if (pop->bitstreamBufferSize % 1024 || + pop->bitstreamBufferSize < 1024 || + pop->bitstreamBufferSize > 16383 * 1024) { + BM_DBG_ERR("JPG_RET_INVALID_PARAM\n"); + return JPG_RET_INVALID_PARAM; + } + + if (picWidth < 16 || picWidth > MAX_MJPG_PIC_WIDTH) { + BM_DBG_ERR("JPG_RET_INVALID_PARAM, picWidth = %d\n", picWidth); + return JPG_RET_INVALID_PARAM; + } + if (picHeight < 16 || picHeight > MAX_MJPG_PIC_HEIGHT) { + BM_DBG_ERR("JPG_RET_INVALID_PARAM, picHeight = %d\n", + picHeight); + return JPG_RET_INVALID_PARAM; + } + + return JPG_RET_SUCCESS; +} + +JpgRet CheckJpgEncParam(JpgEncHandle handle, JpgEncParam *param) +{ + JpgInst *pJpgInst; + JpgEncInfo *pEncInfo; + + pJpgInst = handle; + pEncInfo = &pJpgInst->JpgInfo.encInfo; + + if (param == 0) { + return JPG_RET_INVALID_PARAM; + } + + if (pEncInfo->packedFormat != PACKED_FORMAT_NONE) { + if (pEncInfo->packedFormat == PACKED_FORMAT_444) { + if (param->sourceFrame->stride < pEncInfo->openParam.picWidth * 2) { + return JPG_RET_INVALID_PARAM; + } + } + if (pEncInfo->packedFormat == PACKED_FORMAT_444) { + if (param->sourceFrame->stride < pEncInfo->openParam.picWidth * 3) { + return JPG_RET_INVALID_PARAM; + } + } + } + + return JPG_RET_SUCCESS; +} + +int JpgEncGenHuffTab(JpgEncInfo *pEncInfo, int tabNum) +{ + int p, i, l, lastp, si, maxsymbol; + + int huffsize[256] = { + 0, + }; + int huffcode[256] = { + 0, + }; + int code; + + BYTE *bitleng, *huffval; + unsigned int *ehufco, *ehufsi; + + bitleng = pEncInfo->pHuffBits[tabNum]; + huffval = pEncInfo->pHuffVal[tabNum]; + ehufco = pEncInfo->huffCode[tabNum]; + ehufsi = pEncInfo->huffSize[tabNum]; + + maxsymbol = tabNum & 1 ? 256 : 16; + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = bitleng[l - 1]; + if (i < 0 || p + i > maxsymbol) + return 0; + while (i--) + huffsize[p++] = l; + } + lastp = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. + */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p] != 0) { + while (huffsize[p] == si) { + huffcode[p++] = code; + code++; + } + if (code >= (1 << si)) + return 0; + code <<= 1; + si++; + } + + /* Figure C.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + for (i = 0; i < 256; i++) + ehufsi[i] = 0x00; + + for (i = 0; i < 256; i++) + ehufco[i] = 0x00; + + for (p = 0; p < lastp; p++) { + i = huffval[p]; + if (i < 0 || i >= maxsymbol || ehufsi[i]) + return 0; + ehufco[i] = huffcode[p]; + ehufsi[i] = huffsize[p]; + } + + return 1; +} + +int JpgEncLoadHuffTab(JpgEncInfo *pEncInfo) +{ + int i, j, t; + int huffData; + + for (i = 0; i < 4; i++) + JpgEncGenHuffTab(pEncInfo, i); + + JpuWriteReg(MJPEG_HUFF_CTRL_REG, 0x3); + + for (j = 0; j < 4; j++) { + + t = (j == 0) ? AC_TABLE_INDEX0 + : (j == 1) ? AC_TABLE_INDEX1 + : (j == 2) ? DC_TABLE_INDEX0 + : DC_TABLE_INDEX1; + + for (i = 0; i < 256; i++) { + if ((t == DC_TABLE_INDEX0 || t == DC_TABLE_INDEX1) && i > 15) // DC + break; + + if (pEncInfo->huffSize[t][i] == 0 && pEncInfo->huffCode[t][i] == 0) + huffData = 0; + else { + huffData = (pEncInfo->huffSize[t][i] - 1); // Code length (1 ~ 16), 4-bit + huffData = (huffData << 16) | (pEncInfo->huffCode[t][i]); // Code word, 16-bit + } + JpuWriteReg(MJPEG_HUFF_DATA_REG, huffData); + } + } + JpuWriteReg(MJPEG_HUFF_CTRL_REG, 0x0); + return 1; +} + +int JpgEncLoadQMatTab(JpgEncInfo *pEncInfo) +{ + +#ifdef WIN32 + __int64 dividend = 0x80000; + __int64 quotient; +#else + long long dividend = 0x80000; + long long quotient; +#endif + int quantID; + int divisor; + int comp; + int i, t; + + for (comp = 0; comp < 3; comp++) { + quantID = pEncInfo->pCInfoTab[comp][3]; + if (quantID >= 4) + return 0; + t = (comp == 0) ? Q_COMPONENT0 + : (comp == 1) ? Q_COMPONENT1 : Q_COMPONENT2; + JpuWriteReg(MJPEG_QMAT_CTRL_REG, 0x3 + t); + for (i = 0; i < 64; i++) { + divisor = pEncInfo->pQMatTab[quantID][i]; + quotient = dividend / divisor; + // enhace bit precision & rounding Q + JpuWriteReg(MJPEG_QMAT_DATA_REG, (int)(divisor << 20) | (int)(quotient & 0xFFFFF)); + } + JpuWriteReg(MJPEG_QMAT_CTRL_REG, t); + } + + return 1; +} + +int JpgEncEncodeHeader(JpgEncHandle handle, JpgEncParamSet *para) +{ + JpgInst *pJpgInst; + JpgEncInfo *pEncInfo; + // BYTE *p; + int i; + BYTE *pCInfoTab[4]; + int frameFormat; + Uint32 val; + + pJpgInst = handle; + pEncInfo = &pJpgInst->JpgInfo.encInfo; + + if (!para) + return 0; + + // p = para->pParaSet; + // len = para->size; + + // SOI Header + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, 0xFFD8); + + if (!para->disableAPPMarker) { + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, 0xFFE90004); + // APP9 Header + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, pEncInfo->frameIdx); + } + + // DRI header + if (pEncInfo->rstIntval) { + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, 0xFFDD0004); + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, pEncInfo->rstIntval); + } + + // DQT Header + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, 0xFFDB); + + if (para->quantMode == JPG_TBL_NORMAL) { + JpuWriteReg(MJPEG_GBU_PBIT_24_REG, 0x004300); + + for (i = 0; i < 64; i += 4) { + val = pEncInfo->pQMatTab[0][i] << 24; + val |= pEncInfo->pQMatTab[0][i + 1] << 16; + val |= pEncInfo->pQMatTab[0][i + 2] << 8; + val |= pEncInfo->pQMatTab[0][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + if (pEncInfo->format != FORMAT_400) { + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, 0xFFDB0043); + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, 0x01); + + for (i = 0; i < 64; i += 4) { + val = pEncInfo->pQMatTab[1][i] << 24; + val |= pEncInfo->pQMatTab[1][i + 1] << 16; + val |= pEncInfo->pQMatTab[1][i + 2] << 8; + val |= pEncInfo->pQMatTab[1][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + } + } else { // if (para->quantMode == JPG_TBL_MERGE) + if (pEncInfo->format != FORMAT_400) { + JpuWriteReg(MJPEG_GBU_PBIT_24_REG, 0x008400); + } else { + JpuWriteReg(MJPEG_GBU_PBIT_24_REG, 0x004300); + } + + for (i = 0; i < 64; i += 4) { + val = pEncInfo->pQMatTab[0][i] << 24; + val |= pEncInfo->pQMatTab[0][i + 1] << 16; + val |= pEncInfo->pQMatTab[0][i + 2] << 8; + val |= pEncInfo->pQMatTab[0][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + if (pEncInfo->format != FORMAT_400) { + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, 0x01); + for (i = 0; i < 64; i += 4) { + val = pEncInfo->pQMatTab[0][i] << 24; + val |= pEncInfo->pQMatTab[0][i + 1] << 16; + val |= pEncInfo->pQMatTab[0][i + 2] << 8; + val |= pEncInfo->pQMatTab[0][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + } + } + + // DHT Header + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, 0xFFC4); + + if (para->huffMode == JPG_TBL_NORMAL) { + JpuWriteReg(MJPEG_GBU_PBIT_24_REG, 0x001F00); + + for (i = 0; i < 16; i += 4) { + val = pEncInfo->pHuffBits[0][i] << 24; + val |= pEncInfo->pHuffBits[0][i + 1] << 16; + val |= pEncInfo->pHuffBits[0][i + 2] << 8; + val |= pEncInfo->pHuffBits[0][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + for (i = 0; i < 12; i += 4) { + val = pEncInfo->pHuffVal[0][i] << 24; + val |= pEncInfo->pHuffVal[0][i + 1] << 16; + val |= pEncInfo->pHuffVal[0][i + 2] << 8; + val |= pEncInfo->pHuffVal[0][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, 0xFFC400B5); + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, 0x10); + + for (i = 0; i < 16; i += 4) { + val = pEncInfo->pHuffBits[1][i] << 24; + val |= pEncInfo->pHuffBits[1][i + 1] << 16; + val |= pEncInfo->pHuffBits[1][i + 2] << 8; + val |= pEncInfo->pHuffBits[1][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + for (i = 0; i < 160; i += 4) { + val = pEncInfo->pHuffVal[1][i] << 24; + val |= pEncInfo->pHuffVal[1][i + 1] << 16; + val |= pEncInfo->pHuffVal[1][i + 2] << 8; + val |= pEncInfo->pHuffVal[1][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, pEncInfo->pHuffVal[1][160] << 8 | pEncInfo->pHuffVal[1][161]); + + if (pEncInfo->format != FORMAT_400) { + + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, 0xFFC4001F); + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, 0x01); + + for (i = 0; i < 16; i += 4) { + val = pEncInfo->pHuffBits[2][i] << 24; + val |= pEncInfo->pHuffBits[2][i + 1] << 16; + val |= pEncInfo->pHuffBits[2][i + 2] << 8; + val |= pEncInfo->pHuffBits[2][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + for (i = 0; i < 12; i += 4) { + val = pEncInfo->pHuffVal[2][i] << 24; + val |= pEncInfo->pHuffVal[2][i + 1] << 16; + val |= pEncInfo->pHuffVal[2][i + 2] << 8; + val |= pEncInfo->pHuffVal[2][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, 0xFFC400B5); + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, 0x11); + + for (i = 0; i < 16; i += 4) { + val = pEncInfo->pHuffBits[3][i] << 24; + val |= pEncInfo->pHuffBits[3][i + 1] << 16; + val |= pEncInfo->pHuffBits[3][i + 2] << 8; + val |= pEncInfo->pHuffBits[3][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + for (i = 0; i < 160; i += 4) { + val = pEncInfo->pHuffVal[3][i] << 24; + val |= pEncInfo->pHuffVal[3][i + 1] << 16; + val |= pEncInfo->pHuffVal[3][i + 2] << 8; + val |= pEncInfo->pHuffVal[3][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + val = pEncInfo->pHuffVal[3][160] << 8 | pEncInfo->pHuffVal[3][161]; + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, val); + } + } else { // if (para->huffMode == JPG_TBL_MERGE) + if (pEncInfo->format != FORMAT_400) { + JpuWriteReg(MJPEG_GBU_PBIT_24_REG, 0x01A200); + } else { + JpuWriteReg(MJPEG_GBU_PBIT_24_REG, 0x00D400); + } + + for (i = 0; i < 16; i += 4) { + val = pEncInfo->pHuffBits[0][i] << 24; + val |= pEncInfo->pHuffBits[0][i + 1] << 16; + val |= pEncInfo->pHuffBits[0][i + 2] << 8; + val |= pEncInfo->pHuffBits[0][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + for (i = 0; i < 12; i += 4) { + val = pEncInfo->pHuffVal[0][i] << 24; + val |= pEncInfo->pHuffVal[0][i + 1] << 16; + val |= pEncInfo->pHuffVal[0][i + 2] << 8; + val |= pEncInfo->pHuffVal[0][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, 0x10); + + for (i = 0; i < 16; i += 4) { + val = pEncInfo->pHuffBits[1][i] << 24; + val |= pEncInfo->pHuffBits[1][i + 1] << 16; + val |= pEncInfo->pHuffBits[1][i + 2] << 8; + val |= pEncInfo->pHuffBits[1][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + for (i = 0; i < 160; i += 4) { + val = pEncInfo->pHuffVal[1][i] << 24; + val |= pEncInfo->pHuffVal[1][i + 1] << 16; + val |= pEncInfo->pHuffVal[1][i + 2] << 8; + val |= pEncInfo->pHuffVal[1][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, pEncInfo->pHuffVal[1][160] << 8 | pEncInfo->pHuffVal[1][161]); + + if (pEncInfo->format != FORMAT_400) { + + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, 0x01); + + for (i = 0; i < 16; i += 4) { + val = pEncInfo->pHuffBits[2][i] << 24; + val |= pEncInfo->pHuffBits[2][i + 1] << 16; + val |= pEncInfo->pHuffBits[2][i + 2] << 8; + val |= pEncInfo->pHuffBits[2][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + for (i = 0; i < 12; i += 4) { + val = pEncInfo->pHuffVal[2][i] << 24; + val |= pEncInfo->pHuffVal[2][i + 1] << 16; + val |= pEncInfo->pHuffVal[2][i + 2] << 8; + val |= pEncInfo->pHuffVal[2][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, 0x11); + + for (i = 0; i < 16; i += 4) { + val = pEncInfo->pHuffBits[3][i] << 24; + val |= pEncInfo->pHuffBits[3][i + 1] << 16; + val |= pEncInfo->pHuffBits[3][i + 2] << 8; + val |= pEncInfo->pHuffBits[3][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + for (i = 0; i < 160; i += 4) { + val = pEncInfo->pHuffVal[3][i] << 24; + val |= pEncInfo->pHuffVal[3][i + 1] << 16; + val |= pEncInfo->pHuffVal[3][i + 2] << 8; + val |= pEncInfo->pHuffVal[3][i + 3]; + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, val); + } + + val = pEncInfo->pHuffVal[3][160] << 8 | pEncInfo->pHuffVal[3][161]; + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, val); + } + } + + // SOF header + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, 0xFFC0); + JpuWriteReg(MJPEG_GBU_PBIT_16_REG, (8 + (pEncInfo->compNum * 3))); + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, 0x08); + + if (pEncInfo->rotationAngle == 90 || pEncInfo->rotationAngle == 270) { + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, pEncInfo->picWidth << 16 | pEncInfo->picHeight); + } else { + JpuWriteReg(MJPEG_GBU_PBIT_32_REG, pEncInfo->picHeight << 16 | pEncInfo->picWidth); + } + + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, pEncInfo->compNum); + + frameFormat = pEncInfo->format; + if (pEncInfo->rotationEnable && + (pEncInfo->rotationAngle == 90 || pEncInfo->rotationAngle == 270)) { + frameFormat = (frameFormat == FORMAT_422) + ? FORMAT_224 + : (frameFormat == FORMAT_224) ? FORMAT_422 + : frameFormat; + } + + pCInfoTab[0] = sJpuCompInfoTable[frameFormat]; + pCInfoTab[1] = pCInfoTab[0] + 6; + pCInfoTab[2] = pCInfoTab[1] + 6; + pCInfoTab[3] = pCInfoTab[2] + 6; + + for (i = 0; i < pEncInfo->compNum; i++) { + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, (i + 1)); + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, ((pCInfoTab[i][1] << 4) & 0xF0) + (pCInfoTab[i][2] & 0x0F)); + JpuWriteReg(MJPEG_GBU_PBIT_08_REG, pCInfoTab[i][3]); + } + + pEncInfo->frameIdx++; + + return 1; +} + +JpgRet JpgEnterLock(void) +{ + jdi_lock(); + JpgSetClockGate(1); + return JPG_RET_SUCCESS; +} + +JpgRet JpgLeaveLock(void) +{ + JpgSetClockGate(0); + jdi_unlock(); + return JPG_RET_SUCCESS; +} + +JpgRet JpgSetClockGate(Uint32 on) +{ + JpgInst *inst; + jpu_instance_pool_t *jip; + + jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + if (!jip) + return JPG_RET_FAILURE; + + inst = jip->pendingInst; + if (inst && !on) + return JPG_RET_SUCCESS; + + jdi_set_clock_gate(on); + + return JPG_RET_SUCCESS; +} + +void SetJpgPendingInst(JpgInst *inst) +{ + jpu_instance_pool_t *jip; + + jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + if (!jip) + return; + + jip->pendingInst = inst; +} + +void ClearJpgPendingInst(void) +{ + jpu_instance_pool_t *jip; + + jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + if (!jip) + return; + + if (jip->pendingInst) + jip->pendingInst = 0; +} + +JpgInst *GetJpgPendingInst(void) +{ + jpu_instance_pool_t *jip; + + jip = (jpu_instance_pool_t *)jdi_get_instance_pool(); + if (!jip) + return NULL; + + return jip->pendingInst; +} diff --git a/u-boot-2021.10/drivers/jpeg/jpuapifunc.h b/u-boot-2021.10/drivers/jpeg/jpuapifunc.h new file mode 100644 index 000000000..a065ad410 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpuapifunc.h @@ -0,0 +1,280 @@ +#ifndef _JPUAPI_UTIL_H_ +#define _JPUAPI_UTIL_H_ + +#include "jpuapi.h" +#include "regdefine.h" + +#define DC_TABLE_INDEX0 0 +#define AC_TABLE_INDEX0 1 +#define DC_TABLE_INDEX1 2 +#define AC_TABLE_INDEX1 3 + +#define Q_COMPONENT0 0 +#define Q_COMPONENT1 0x40 +#define Q_COMPONENT2 0x80 + +typedef enum { + JPG_START_PIC = 0, + JPG_START_INIT, + JPG_START_STOP, + JPG_START_PARTIAL +} JpgStartCmd; + +typedef struct{ + UINT tag; + UINT type; + int count; + int offset; +} TAG; + +enum { + JFIF = 0, + JFXX_JPG = 1, + JFXX_PAL = 2, + JFXX_RAW = 3, + EXIF_JPG = 4 +}; + +typedef struct { + int PicX; + int PicY; + int BitPerSample[3]; + int Compression; // 1 for uncompressed / 6 for compressed(jpeg) + int PixelComposition; // 2 for RGB / 6 for YCbCr + int SamplePerPixel; + int PlanrConfig; // 1 for chunky / 2 for planar + int YCbCrSubSample; // 00020002 for YCbCr 4:2:0 / 00020001 for YCbCr 4:2:2 + UINT JpegOffset; + UINT JpegThumbSize; +} EXIF_INFO; + +typedef struct { + BYTE *buffer; + int index; + int size; +} vpu_getbit_context_t; + +#define init_get_bits(CTX, BUFFER, SIZE) JpuGbuInit(CTX, BUFFER, SIZE) +#define show_bits(CTX, NUM) JpuGguShowBit(CTX, NUM) +#define get_bits(CTX, NUM) JpuGbuGetBit(CTX, NUM) +#define get_bits_left(CTX) JpuGbuGetLeftBitCount(CTX) +#define get_bits_count(CTX) JpuGbuGetUsedBitCount(CTX) + +typedef struct { + PhysicalAddress streamWrPtr; + PhysicalAddress streamRdPtr; + int streamEndflag; + PhysicalAddress streamBufStartAddr; + PhysicalAddress streamBufEndAddr; + int streamBufSize; + BYTE *pBitStream; + + int frameOffset; + int consumeByte; + int nextOffset; + int currOffset; + + FrameBuffer *frameBufPool; + int numFrameBuffers; + int stride; + int strideY; + int strideC; + int rotationEnable; + int mirrorEnable; + int mirrorDirection; + int rotationAngle; + FrameBuffer rotatorOutput; + int rotatorStride; + int rotatorOutputValid; + int initialInfoObtained; + int minFrameBufferNum; + int streamEndian; + int frameEndian; + int chroma_interleave; + + int picWidth; + int picHeight; + int alignedWidth; + int alignedHeight; + int headerSize; + int ecsPtr; + int pagePtr; + int wordPtr; + int bitPtr; + int format; + int rstIntval; + + int userHuffTab; + + int huffDcIdx; + int huffAcIdx; + int Qidx; + + BYTE huffVal[4][162]; + BYTE huffBits[4][256]; + BYTE cInfoTab[4][6]; + BYTE qMatTab[4][64]; + + Uint32 huffMin[4][16]; + Uint32 huffMax[4][16]; + BYTE huffPtr[4][16]; + + // partial + int usePartial; + int lineNum; + int bufNum; + + int busReqNum; + int compNum; + int mcuBlockNum; + int compInfo[3]; + int frameIdx; + int bitEmpty; + int iHorScaleMode; + int iVerScaleMode; + int mcuWidth; + int mcuHeight; + vpu_getbit_context_t gbc; + +#ifdef MJPEG_ERROR_CONCEAL + //error conceal + struct{ + int bError; + int rstMarker; + int errPosX; + int errPosY; + } errInfo; + + int curRstIdx; + int nextRstIdx; + int setPosX; + int setPosY; + int gbuStartPtr; // entry point in stream buffer before pic_run + + int numRstMakerRounding; +#endif + + //ROI + int roiEnable; + int roiOffsetX; + int roiOffsetY; + int roiWidth; + int roiHeight; + int roiMcuOffsetX; + int roiMcuOffsetY; + int roiMcuWidth; + int roiMcuHeight; + int packedFormat; +} JpgDecInfo; + +typedef struct { + JpgEncOpenParam openParam; + JpgEncInitialInfo initialInfo; + PhysicalAddress streamRdPtr; + PhysicalAddress streamWrPtr; + PhysicalAddress streamBufStartAddr; + PhysicalAddress streamBufEndAddr; + int streamBufSize; + + FrameBuffer *frameBufPool; + int numFrameBuffers; + int stride; + int rotationEnable; + int mirrorEnable; + int mirrorDirection; + int rotationAngle; + int initialInfoObtained; + + int picWidth; + int picHeight; + int alignedWidth; + int alignedHeight; + int seqInited; + int frameIdx; + int format; + + int streamEndian; + int frameEndian; + int chroma_interleave; + + int rstIntval; + int busReqNum; + int mcuBlockNum; + int compNum; + int compInfo[3]; + + // give command + int disableAPPMarker; + int quantMode; + int stuffByteEnable; + + Uint32 huffCode[4][256]; + Uint32 huffSize[4][256]; + BYTE *pHuffVal[4]; + BYTE *pHuffBits[4]; + BYTE *pCInfoTab[4]; + BYTE *pQMatTab[4]; + // partial + int usePartial; + int partiallineNum; + int partialBufNum; + int packedFormat; + + JpgEncParamSet *paraSet; + +} JpgEncInfo; + +typedef struct JpgInst { + int inUse; + int instIndex; + int loggingEnable; + union { + JpgEncInfo encInfo; + JpgDecInfo decInfo; + } JpgInfo; +} JpgInst; + +#ifdef __cplusplus +extern "C" { +#endif + + JpgRet InitJpgInstancePool(void); + JpgRet GetJpgInstance(JpgInst **ppInst); + void FreeJpgInstance(JpgInst *pJpgInst); + JpgRet CheckJpgInstValidity(JpgInst *pci); + JpgRet CheckJpgDecOpenParam(JpgDecOpenParam *pop); + + int JpuGbuInit(vpu_getbit_context_t *ctx, BYTE *buffer, int size); + int JpuGbuGetUsedBitCount(vpu_getbit_context_t *ctx); + int JpuGbuGetLeftBitCount(vpu_getbit_context_t *ctx); + unsigned int JpuGbuGetBit(vpu_getbit_context_t *ctx, int bit_num); + unsigned int JpuGguShowBit(vpu_getbit_context_t *ctx, int bit_num); + + int JpegDecodeHeader(JpgDecInfo *jpg); + int JpgDecQMatTabSetUp(JpgDecInfo *jpg); + int JpgDecHuffTabSetUp(JpgDecInfo *jpg); + void JpgDecGramSetup(JpgDecInfo *jpg); + + JpgRet CheckJpgEncOpenParam(JpgEncOpenParam *pop); + JpgRet CheckJpgEncParam(JpgEncHandle handle, JpgEncParam *param); + int JpgEncLoadHuffTab(JpgEncInfo *pJpgEncInfo); + int JpgEncLoadQMatTab(JpgEncInfo *pJpgEncInfo); + int JpgEncEncodeHeader(JpgEncHandle handle, JpgEncParamSet *para); + + JpgRet JpgEnterLock(void); + JpgRet JpgLeaveLock(void); + JpgRet JpgSetClockGate(Uint32 on); + + void SetJpgPendingInst(JpgInst *inst); + void ClearJpgPendingInst(void); + JpgInst *GetJpgPendingInst(void); + +#ifdef MJPEG_ERROR_CONCEAL + int JpegDecodeConcealError(JpgDecInfo *jpg); +#endif + +#ifdef __cplusplus +} +#endif + +#endif //_JPUAPI_UTIL_H_ diff --git a/u-boot-2021.10/drivers/jpeg/jpuconfig.h b/u-boot-2021.10/drivers/jpeg/jpuconfig.h new file mode 100644 index 000000000..cc4638fb3 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpuconfig.h @@ -0,0 +1,36 @@ +#ifndef _JPU_CONFIG_H_ +#define _JPU_CONFIG_H_ + +#include "config.h" +#include "jputypes.h" + +#define MAX_NUM_INSTANCE 8 +#define MAX_INST_HANDLE_SIZE (12 * 1024) + +#ifdef JPU_FPGA_PLATFORM +#define JPU_FRAME_ENDIAN JDI_BIG_ENDIAN +#define JPU_STREAM_ENDIAN JDI_BIG_ENDIAN +#else +#define JPU_FRAME_ENDIAN JDI_LITTLE_ENDIAN +#define JPU_STREAM_ENDIAN JDI_LITTLE_ENDIAN +#endif + +// 0 (chroma separate mode), 1 (cbcr interleave mode), 2 (crcb interleave mode) +#define JPU_CHROMA_INTERLEAVE 1 +#define JPU_INTERRUPT_TIMEOUT_MS 5000 +#define JPU_STUFFING_BYTE_FF 0 // 0 : ON ("0xFF"), 1 : OFF ("0x00") for stuffing +#define JPU_PARTIAL_DECODE 1 // 0 : OFF, 1 : ON + +#define MAX_MJPG_PIC_WIDTH 32768 +#define MAX_MJPG_PIC_HEIGHT 32768 + +// For AVC decoder, 16(reference) + 2(current) + 1(rotator) +#define MAX_FRAME (19 * MAX_NUM_INSTANCE) +#define STREAM_FILL_SIZE 0x10000 +#define STREAM_END_SIZE 0 +#define JPU_GBU_SIZE 512 +#define STREAM_BUF_SIZE 0x100000 + +#define JPU_CHECK_WRITE_RESPONSE_BVALID_SIGNAL 0 + +#endif /* _JPU_CONFIG_H_ */ diff --git a/u-boot-2021.10/drivers/jpeg/jpuhelper.c b/u-boot-2021.10/drivers/jpeg/jpuhelper.c new file mode 100644 index 000000000..b0a4c1c95 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpuhelper.c @@ -0,0 +1,2017 @@ + +#include +#include +#include + +#include "jpuapi.h" +#include "jpuapifunc.h" +#include "jpuhelper.h" +#include "jpulog.h" +#include "jputable.h" +#include "regdefine.h" + +extern int sscanf(const char *str, const char *format, ...); + +extern int __must_check kstrtoint(const char *s, unsigned int base, int *res); + +static int FillSdramBurst(BufInfo *pBufInfo, Uint64 targetAddr, + PhysicalAddress bsBufStartAddr, + PhysicalAddress bsBufEndAddr, Uint32 size, + int checkeos, int *streameos, int endian); +static int StoreYuvImageBurstFormat(Uint8 *dst, int picWidth, int picHeight, + unsigned long addrY, unsigned long addrCb, + unsigned long addrCr, int stride, + int interLeave, int format, int endian, + int packed); +static void ProcessEncodedBitstreamBurst(osal_file_t *fp, + unsigned long targetAddr, + PhysicalAddress bsBufStartAddr, + PhysicalAddress bsBufEndAddr, int size, + int endian); +static int LoadYuvImageBurstFormat(unsigned char *src, int picWidth, + int picHeight, unsigned long addrY, + unsigned long addrCb, unsigned long addrCr, + int stride, int interLeave, int format, + int endian, int packed); + +// Figure A.6 - Zig-zag sequence of quantized DCT coefficients +const int InvScanTable[64] = { + 0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63 +}; + +const int ScanTable[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, + 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, + 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, + 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, + 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + +JpgRet WriteJpgBsBufHelperStream(JpgDecHandle handle, BufInfo *pBufInfo, + PhysicalAddress paBsBufStart, + PhysicalAddress paBsBufEnd, int defaultsize, + int checkeos, int *pstreameos, int endian) +{ + JpgRet ret = JPG_RET_SUCCESS; + int size = 0; + int fillSize = 0; + PhysicalAddress paRdPtr, paWrPtr; + + ret = JPU_DecGetBitstreamBuffer(handle, &paRdPtr, &paWrPtr, &size); + JLOG(INFO, "rdPtr: 0x%lx, wrPtr: 0x%lx, size: %d\n", paRdPtr, paWrPtr, size); + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "VPU_DecGetBitstreamBuffer failed Error code is 0x%x\n", ret); + goto FILL_BS_ERROR; + } + + if (size <= 0) + return JPG_RET_SUCCESS; + + if (defaultsize) { + if (size < defaultsize) + fillSize = size; + else + fillSize = defaultsize; + } else { + fillSize = size; + } + + JLOG(INFO, "Before fillSize: %d\n", fillSize); + + fillSize = FillSdramBurst(pBufInfo, paWrPtr, paBsBufStart, paBsBufEnd, + fillSize, checkeos, pstreameos, endian); + + if (fillSize == 0 && pBufInfo->fillendbs != 1) + return ret; + JLOG(INFO, "After fillSize :%d\n", fillSize); + if (*pstreameos == 0) { + ret = JPU_DecUpdateBitstreamBuffer(handle, fillSize); + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "VPU_DecUpdateBitstreamBuffer failed Error code is 0x%x\n", ret); + goto FILL_BS_ERROR; + } + + if (pBufInfo->fillendbs == 1) { + ret = JPU_DecUpdateBitstreamBuffer(handle, STREAM_END_SIZE); + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "VPU_DecUpdateBitstreamBuffer failed Error code is 0x%x\n", ret); + goto FILL_BS_ERROR; + } + + // pBufInfo->fillendbs = 1; + } + } else { + if (!pBufInfo->fillendbs) { + ret = JPU_DecUpdateBitstreamBuffer(handle, STREAM_END_SIZE); + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "VPU_DecUpdateBitstreamBuffer failed Error code is 0x%x\n", ret); + goto FILL_BS_ERROR; + } + pBufInfo->fillendbs = 1; + } + } + +FILL_BS_ERROR: + + return ret; +} + +JpgRet WriteJpgBsBufHelper(JpgDecHandle handle, BufInfo *pBufInfo, + PhysicalAddress paBsBufStart, + PhysicalAddress paBsBufEnd, int defaultsize, + int checkeos, int *pstreameos, int endian) +{ + JpgRet ret = JPG_RET_SUCCESS; + int size = 0; + int fillSize = 0; + PhysicalAddress paRdPtr, paWrPtr; + + ret = JPU_DecGetBitstreamBuffer(handle, &paRdPtr, &paWrPtr, &size); + + JLOG(INFO, "rdPtr: 0x%lx, wrPtr: 0x%lx, size: %d\n", paRdPtr, paWrPtr, size); + + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "VPU_DecGetBitstreamBuffer failed Error code is 0x%x\n", ret); + goto FILL_BS_ERROR; + } + + if (size <= 0) + return JPG_RET_SUCCESS; + + if (defaultsize) { + if (size < defaultsize) + fillSize = size; + else + fillSize = defaultsize; + } else { + fillSize = size; + } + + fillSize = FillSdramBurst(pBufInfo, paWrPtr, paBsBufStart, paBsBufEnd, + fillSize, checkeos, pstreameos, endian); + + JLOG(INFO, "fillSize :%d\n", fillSize); + + if (*pstreameos == 0) { + ret = JPU_DecUpdateBitstreamBuffer(handle, fillSize); + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "VPU_DecUpdateBitstreamBuffer failed Error code is 0x%x\n", ret); + goto FILL_BS_ERROR; + } + + if ((pBufInfo->size - pBufInfo->point) <= 0) { + ret = JPU_DecUpdateBitstreamBuffer(handle, STREAM_END_SIZE); + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "VPU_DecUpdateBitstreamBuffer failed Error code is 0x%x\n", ret); + goto FILL_BS_ERROR; + } + + pBufInfo->fillendbs = 1; + } + } else { + if (!pBufInfo->fillendbs) { + ret = JPU_DecUpdateBitstreamBuffer(handle, STREAM_END_SIZE); + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "VPU_DecUpdateBitstreamBuffer failed Error code is 0x%x\n", ret); + goto FILL_BS_ERROR; + } + pBufInfo->fillendbs = 1; + } + } + +FILL_BS_ERROR: + + return ret; +} + +/** + * Bitstream Read for encoders + */ +JpgRet ReadJpgBsBufHelper(JpgEncHandle handle, osal_file_t *bsFp, + PhysicalAddress paBsBufStart, + PhysicalAddress paBsBufEnd, int encHeaderSize, + int endian) +{ + JpgRet ret = JPG_RET_SUCCESS; + int loadSize = 0; + int stuffSize; + PhysicalAddress paRdPtr, paWrPtr; + int size = 0; + + ret = JPU_EncGetBitstreamBuffer(handle, &paRdPtr, &paWrPtr, &size); + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "JPU_EncGetBitstreamBuffer failed Error code is 0x%x\n", ret); + goto LOAD_BS_ERROR; + } + + if (size > 0) { + stuffSize = 0; + if (encHeaderSize && (size + encHeaderSize) % 8) { + stuffSize = (size + encHeaderSize) - ((size + encHeaderSize) / 8) * 8; + stuffSize = 8 - stuffSize; + } + + loadSize = size; + + if (loadSize > 0) { + ProcessEncodedBitstreamBurst(bsFp, paRdPtr, paBsBufStart, paBsBufEnd, loadSize, endian); + + ret = JPU_EncUpdateBitstreamBuffer(handle, loadSize); + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "VPU_EncUpdateBitstreamBuffer failed Error code is 0x%x\n", ret); + goto LOAD_BS_ERROR; + } + } + } + +LOAD_BS_ERROR: + + return ret; +} + +/****************************************************************************** + * DPB Image Data Control + ******************************************************************************/ +int LoadYuvImageHelperFormat(osal_file_t *yuvFp, Uint8 *pYuv, + PhysicalAddress addrY, PhysicalAddress addrCb, + PhysicalAddress addrCr, int picWidth, + int picHeight, int stride, int interleave, + int format, int endian, int packed) +{ + int frameSize = 0; + + switch (format) { + case FORMAT_420: + frameSize = picWidth * picHeight * 3 / 2; + break; + case FORMAT_224: + frameSize = picWidth * picHeight * 4 / 2; + break; + case FORMAT_422: + frameSize = picWidth * picHeight * 4 / 2; + break; + case FORMAT_444: + frameSize = picWidth * picHeight * 6 / 2; + break; + case FORMAT_400: + frameSize = picWidth * picHeight; + break; + } + + if (packed == PACKED_FORMAT_NONE) { + frameSize = frameSize; + } else if (packed == PACKED_FORMAT_444) { + frameSize = picWidth * 3 * picHeight; + } else { // PACKED_FORMAT_422_XXXX + frameSize = picWidth * 2 * picHeight; + } + + // Load source one picture image to encode to SDRAM frame buffer. + if (!OSAL_FREAD(pYuv, 1, frameSize, yuvFp)) { + if (!OSAL_FEOF(yuvFp)) + JLOG(ERR, "Yuv Data fread failed file handle is 0x%p\n", yuvFp); + return 0; + } + + LoadYuvImageBurstFormat(pYuv, picWidth, picHeight, addrY, addrCb, + addrCr, stride, interleave, format, endian, + packed); + + return 1; +} + +int LoadYuvPartialImageHelperFormat(osal_file_t *yuvFp, Uint8 *pYuv, PhysicalAddress addrY, + PhysicalAddress addrCb, PhysicalAddress addrCr, int picWidth, int picHeight, + int picHeightPartial, int stride, int interleave, int format, int endian, + int partPosIdx, int frameIdx, int packed) +{ + int LumaPicSize; + int ChromaPicSize; + int LumaPartialSize; + int ChromaPartialSize; + int pos; + int divX, divY; + int frameSize = 0; + + divX = format == FORMAT_420 || format == FORMAT_422 ? 2 : 1; + divY = format == FORMAT_420 || format == FORMAT_224 ? 2 : 1; + + LumaPicSize = picWidth * picHeight; + ChromaPicSize = LumaPicSize / divX / divY; + + LumaPartialSize = picWidth * picHeightPartial; + ChromaPartialSize = LumaPartialSize / divX / divY; + + if (format == FORMAT_400) + frameSize = LumaPicSize; + else + frameSize = LumaPicSize + ChromaPicSize * 2; + // Load source one picture image to encode to SDRAM frame buffer. + + if (packed) { + if (packed == PACKED_FORMAT_444) { + LumaPicSize = picWidth * 3 * picHeight; + LumaPartialSize = picWidth * 3 * picHeightPartial; + } else { + LumaPicSize = picWidth * 2 * picHeight; + LumaPartialSize = picWidth * 2 * picHeightPartial; + } + frameSize = LumaPicSize; + ChromaPicSize = 0; + ChromaPartialSize = 0; + } + + // Y + OSAL_FSEEK(yuvFp, (frameIdx * frameSize), SEEK_SET); + pos = LumaPartialSize * partPosIdx; + OSAL_FSEEK(yuvFp, pos, SEEK_CUR); + + if (!OSAL_FREAD(pYuv, 1, LumaPartialSize, yuvFp)) { + if (!OSAL_FEOF(yuvFp)) + JLOG(ERR, "Yuv Data fread failed file handle is 0x%p\n", yuvFp); + return 0; + } + + if (format != FORMAT_400 && packed == 0) { + // Cb + OSAL_FSEEK(yuvFp, (frameIdx * frameSize), SEEK_SET); + pos = LumaPicSize + ChromaPartialSize * partPosIdx; + OSAL_FSEEK(yuvFp, pos, SEEK_CUR); + + if (!OSAL_FREAD(pYuv + LumaPartialSize, 1, ChromaPartialSize, + yuvFp)) { + if (!OSAL_FEOF(yuvFp)) + JLOG(ERR, "Yuv Data fread failed file handle is 0x%p\n", yuvFp); + return 0; + } + + // Cr + OSAL_FSEEK(yuvFp, (frameIdx * frameSize), SEEK_SET); + pos = LumaPicSize + ChromaPicSize + ChromaPartialSize * partPosIdx; + OSAL_FSEEK(yuvFp, pos, SEEK_CUR); + + if (!OSAL_FREAD(pYuv + LumaPartialSize + ChromaPartialSize, 1, ChromaPartialSize, yuvFp)) { + if (!OSAL_FEOF(yuvFp)) + JLOG(ERR, "Yuv Data fread failed file handle is 0x%p\n", yuvFp); + return 0; + } + } + + LoadYuvImageBurstFormat(pYuv, picWidth, picHeightPartial, addrY, addrCb, + addrCr, stride, interleave, format, endian, + packed); + + return 1; +} + +int SaveYuvImageHelperFormat(osal_file_t *yuvFp, Uint8 *pYuv, + PhysicalAddress addrY, PhysicalAddress addrCb, + PhysicalAddress addrCr, int picWidth, + int picHeight, int stride, int interLeave, + int format, int endian, int packed) +{ + int frameSize; + + frameSize = StoreYuvImageBurstFormat(pYuv, picWidth, picHeight, addrY, + addrCb, addrCr, stride, interLeave, + format, endian, packed); + + if (yuvFp) { + if (!OSAL_FWRITE(pYuv, sizeof(Uint8), frameSize, yuvFp)) { + JLOG(ERR, "Frame Data fwrite failed file handle is 0x%p\n", yuvFp); + return 0; + } + OSAL_FFLUSH(yuvFp); + } + return 1; +} + +int SaveYuvPartialImageHelperFormat(osal_file_t *yuvFp, Uint8 *pYuv, PhysicalAddress addrY, + PhysicalAddress addrCb, PhysicalAddress addrCr, int picWidth, int picHeight, + int picHeightPartial, int stride, int interLeave, int format, int endian, + int partPosIdx, int frameIdx, int packed) +{ + int LumaPicSize = 0; + int ChromaPicSize = 0; + int frameSize = 0; + + int LumaPartialSize = 0; + int ChromaPartialSize = 0; + + int pos = 0; + // int divX, divY; + + // divX = format == FORMAT_420 || format == FORMAT_422 ? 2 : 1; + // divY = format == FORMAT_420 || format == FORMAT_224 ? 2 : 1; + + switch (format) { + case FORMAT_420: + LumaPicSize = picWidth * ((picHeight + 1) / 2 * 2); + ChromaPicSize = ((picWidth + 1) / 2) * ((picHeight + 1) / 2); + frameSize = LumaPicSize + ChromaPicSize * 2; + + LumaPartialSize = picWidth * ((picHeightPartial + 1) / 2 * 2); + ChromaPartialSize = ((picWidth + 1) / 2) * ((picHeightPartial + 1) / 2); + if (interLeave) + ChromaPartialSize = (((picWidth + 1) / 2) * 2) * ((picHeightPartial + 1) / 2); + break; + case FORMAT_224: + LumaPicSize = picWidth * ((picHeight + 1) / 2 * 2); + ChromaPicSize = picWidth * ((picHeight + 1) / 2); + frameSize = LumaPicSize + ChromaPicSize * 2; + + LumaPartialSize = picWidth * ((picHeightPartial + 1) / 2 * 2); + ChromaPartialSize = picWidth * ((picHeightPartial + 1) / 2); + if (interLeave) + ChromaPartialSize = picWidth * 2 * ((picHeightPartial + 1) / 2); + break; + case FORMAT_422: + LumaPicSize = picWidth * picHeight; + ChromaPicSize = ((picWidth + 1) / 2) * picHeight; + frameSize = LumaPicSize + ChromaPicSize * 2; + + LumaPartialSize = picWidth * picHeightPartial; + ChromaPartialSize = ((picWidth + 1) / 2) * picHeightPartial; + if (interLeave) + ChromaPartialSize = (((picWidth + 1) / 2) * 2) * picHeightPartial; + break; + case FORMAT_444: + LumaPicSize = picWidth * picHeight; + ChromaPicSize = picWidth * picHeight; + frameSize = LumaPicSize + ChromaPicSize * 2; + + LumaPartialSize = picWidth * picHeightPartial; + ChromaPartialSize = picWidth * picHeightPartial; + if (interLeave) + ChromaPartialSize = picWidth * 2 * picHeightPartial; + break; + case FORMAT_400: + LumaPicSize = picWidth * picHeight; + ChromaPicSize = 0; + frameSize = LumaPicSize + ChromaPicSize * 2; + + LumaPartialSize = picWidth * picHeightPartial; + ChromaPartialSize = 0; + break; + } + + if (packed) { + if (packed == PACKED_FORMAT_444) + picWidth *= 3; + else + picWidth *= 2; + + LumaPicSize = picWidth * picHeight; + ChromaPicSize = 0; + frameSize = LumaPicSize; + LumaPartialSize = picWidth * picHeightPartial; + ChromaPartialSize = 0; + } + + StoreYuvImageBurstFormat(pYuv, picWidth, picHeightPartial, addrY, + addrCb, addrCr, stride, interLeave, format, + endian, packed); + + if (yuvFp) { + // Y + OSAL_FSEEK(yuvFp, (frameIdx * frameSize), SEEK_SET); + pos = LumaPartialSize * partPosIdx; + OSAL_FSEEK(yuvFp, pos, SEEK_CUR); + if (!OSAL_FWRITE(pYuv, sizeof(Uint8), LumaPartialSize, yuvFp)) { + JLOG(ERR, "Frame Data fwrite failed file handle is 0x%p\n", yuvFp); + return 0; + } + + if (packed) { + OSAL_FFLUSH(yuvFp); + return 1; + } + + if (format != FORMAT_400) { + // Cb + OSAL_FSEEK(yuvFp, (frameIdx * frameSize), SEEK_SET); + pos = LumaPicSize + ChromaPartialSize * partPosIdx; + OSAL_FSEEK(yuvFp, pos, SEEK_CUR); + if (!OSAL_FWRITE(pYuv + LumaPartialSize, sizeof(Uint8), ChromaPartialSize, yuvFp)) { + JLOG(ERR, "Frame Data fwrite failed file handle is 0x%p\n", yuvFp); + return 0; + } + + if (interLeave) { + OSAL_FFLUSH(yuvFp); + return 1; + } + + // Cr + OSAL_FSEEK(yuvFp, (frameIdx * frameSize), SEEK_SET); + pos = LumaPicSize + ChromaPicSize + ChromaPartialSize * partPosIdx; + OSAL_FSEEK(yuvFp, pos, SEEK_CUR); + if (!OSAL_FWRITE(pYuv + LumaPartialSize + ChromaPartialSize, sizeof(Uint8), + ChromaPartialSize, yuvFp)) { + JLOG(ERR, "Frame Data fwrite failed file handle is 0x%p\n", yuvFp); + return 0; + } + } + OSAL_FFLUSH(yuvFp); + } + return 1; +} + +/****************************************************************************** + * JPEG specific Helper + ******************************************************************************/ +static int getTblElement(osal_file_t *fp, char *str) +{ + static int LineNum = 1; + + while (1) { + if (!OSAL_FGETS(str, 256, fp)) + return 0; + if ((str[0] != ';') && (str[0] != '/')) + break; + LineNum++; + } + return 1; +} + +static int parseHuffmanTable(osal_file_t *fp, EncMjpgParam *param) +{ + int ret = 0; + char sLine[256] = { + 0, + }; + unsigned int h[8] = { + 0, + }; + BYTE *huffBit; + BYTE *huffVal; + int i, j; + + huffBit = param->huffBits[DC_TABLE_INDEX0]; + huffVal = param->huffVal[DC_TABLE_INDEX0]; + + for (i = 0; i < 2; i++) { // Luma DC BitLength + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + + for (j = 0; j < 8; j++) + *huffBit++ = (BYTE)h[j]; + } + + for (i = 0; i < (16 / 8); i++) { // Luma DC HuffValue + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + + for (j = 0; j < 8; j++) + *huffVal++ = (BYTE)h[j]; + } + + huffBit = param->huffBits[AC_TABLE_INDEX0]; + huffVal = param->huffVal[AC_TABLE_INDEX0]; + + for (i = 0; i < (16 / 8); i++) { // Luma AC BitLength + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + for (j = 0; j < 8; j++) + *huffBit++ = (BYTE)h[j]; + } + + for (i = 0; i < (162 / 8); i++) { // Luma DC HuffValue + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + for (j = 0; j < 8; j++) + *huffVal++ = (BYTE)h[j]; + } + + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], &h[3], + &h[4], &h[5], &h[6], &h[7]); + for (j = 0; j < 2; j++) + *huffVal++ = (BYTE)h[j]; + + huffBit = param->huffBits[DC_TABLE_INDEX1]; + huffVal = param->huffVal[DC_TABLE_INDEX1]; + + for (i = 0; i < (16 / 8); i++) { // Chroma DC BitLength + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + for (j = 0; j < 8; j++) + *huffBit++ = (BYTE)h[j]; + } + + for (i = 0; i < (16 / 8); i++) { // Chroma DC HuffValue + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + for (j = 0; j < 8; j++) + *huffVal++ = (BYTE)h[j]; + } + + huffBit = param->huffBits[AC_TABLE_INDEX1]; + huffVal = param->huffVal[AC_TABLE_INDEX1]; + + for (i = 0; i < (16 / 8); i++) { // Chroma DC BitLength + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + for (j = 0; j < 8; j++) + *huffBit++ = (BYTE)h[j]; + } + + for (i = 0; i < (162 / 8); i++) {// Luma DC HuffValue + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + for (j = 0; j < 8; j++) + *huffVal++ = (BYTE)h[j]; + } + + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], &h[3], + &h[4], &h[5], &h[6], &h[7]); + for (j = 0; j < 2; j++) + *huffVal++ = (BYTE)h[j]; + + (void)ret; + return 1; +} + +static int parseQMatrix(osal_file_t *fp, EncMjpgParam *param) +{ + int ret = 0; + char sLine[256] = { + 0, + }; + int i, j; + unsigned int h[8] = { + 0, + }; + BYTE temp_dc[64], temp_ac[64]; + BYTE *qTable_dc, *qTable_ac, *qTable; + + qTable = temp_dc; + for (i = 0; i < (64 / 8); i++) { + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + + for (j = 0; j < 8; j++) + *qTable++ = (BYTE)h[j]; + } + + qTable = temp_ac; + for (i = 0; i < (64 / 8); i++) { + if (getTblElement(fp, sLine) == 0) + return 0; + + memset(h, 0x00, 8 * sizeof(unsigned int)); + ret = sscanf(sLine, "%x %x %x %x %x %x %x %x", &h[0], &h[1], &h[2], + &h[3], &h[4], &h[5], &h[6], &h[7]); + + for (j = 0; j < 8; j++) + *qTable++ = (BYTE)h[j]; + } + + qTable_dc = param->qMatTab[DC_TABLE_INDEX0]; + qTable_ac = param->qMatTab[AC_TABLE_INDEX0]; + + for (i = 0; i < 64; i++) { + qTable_dc[InvScanTable[i]] = temp_dc[i]; + qTable_ac[InvScanTable[i]] = temp_ac[i]; + } + + memcpy(param->qMatTab[DC_TABLE_INDEX1], param->qMatTab[DC_TABLE_INDEX0], 64); + memcpy(param->qMatTab[AC_TABLE_INDEX1], param->qMatTab[AC_TABLE_INDEX0], 64); + + (void)ret; + return 1; +} + +int jpgGetHuffTable(char *huffFileName, EncMjpgParam *param) +{ + char huffFilePath[256]; + osal_file_t *huffFp = NULL; + + if (huffFileName && huffFileName[0] != 0) { + // strcpy(huffFilePath, huffFileName); + huffFp = OSAL_FOPEN(huffFilePath, "rt"); + if (!huffFp) { + JLOG(ERR, "Can't open Huffman Table file %s\n", huffFilePath); + return 0; + } + parseHuffmanTable(huffFp, param); + OSAL_FCLOSE(huffFp); + } else { + // Rearrange and insert pre-defined Huffman table to deticated + // variable. + memcpy(param->huffBits[DC_TABLE_INDEX0], lumaDcBits, 16); // Luma DC BitLength + memcpy(param->huffVal[DC_TABLE_INDEX0], lumaDcValue, 16); // Luma DC HuffValue + + memcpy(param->huffBits[AC_TABLE_INDEX0], lumaAcBits, 16); // Luma DC BitLength + memcpy(param->huffVal[AC_TABLE_INDEX0], lumaAcValue, 162); // Luma DC HuffValue + + memcpy(param->huffBits[DC_TABLE_INDEX1], chromaDcBits, 16); // Chroma DC BitLength + memcpy(param->huffVal[DC_TABLE_INDEX1], chromaDcValue, 16); // Chroma DC HuffValue + + memcpy(param->huffBits[AC_TABLE_INDEX1], chromaAcBits, 16); // Chroma AC BitLength + memcpy(param->huffVal[AC_TABLE_INDEX1], chromaAcValue, 162); // Chorma AC HuffValue + } + + return 1; +} + +int jpgGetQMatrix(char *qMatFileName, EncMjpgParam *param) +{ + char qMatFilePath[256]; + osal_file_t *qMatFp = NULL; + + if (qMatFileName && qMatFileName[0] != 0) { + // strcpy(qMatFilePath, qMatFileName); + qMatFp = OSAL_FOPEN(qMatFilePath, "rt"); + if (!qMatFp) { + JLOG(ERR, "Can't open Q Matrix file %s\n", qMatFilePath); + return 0; + } + parseQMatrix(qMatFp, param); + OSAL_FCLOSE(qMatFp); + } else { + // Rearrange and insert pre-defined Q-matrix to deticated + // variable. + memcpy(param->qMatTab[DC_TABLE_INDEX0], lumaQ2, 64); + memcpy(param->qMatTab[AC_TABLE_INDEX0], chromaBQ2, 64); + + memcpy(param->qMatTab[DC_TABLE_INDEX1], param->qMatTab[DC_TABLE_INDEX0], 64); + memcpy(param->qMatTab[AC_TABLE_INDEX1], param->qMatTab[AC_TABLE_INDEX0], 64); + } + + return 1; +} + +/****************************************************************************** + * EncOpenParam Initialization + ******************************************************************************/ +int getJpgEncOpenParamDefault(JpgEncOpenParam *pEncOP, + EncConfigParam *pEncConfig) +{ + int ret; + EncMjpgParam mjpgParam; + + memset(&mjpgParam, 0x00, sizeof(EncMjpgParam)); + + pEncOP->picWidth = pEncConfig->picWidth; + pEncOP->picHeight = pEncConfig->picHeight; + pEncOP->sourceFormat = pEncConfig->mjpgChromaFormat; + pEncOP->restartInterval = 0; + pEncOP->chroma_interleave = pEncConfig->chroma_interleave; + pEncOP->packedFormat = pEncConfig->packedFormat; + mjpgParam.sourceFormat = pEncConfig->mjpgChromaFormat; + ret = jpgGetHuffTable(pEncConfig->huffFileName, &mjpgParam); + if (ret == 0) + return ret; + ret = jpgGetQMatrix(pEncConfig->qMatFileName, &mjpgParam); + if (ret == 0) + return ret; + + memcpy(pEncOP->huffVal, mjpgParam.huffVal, 4 * 162); + memcpy(pEncOP->huffBits, mjpgParam.huffBits, 4 * 256); + memcpy(pEncOP->qMatTab, mjpgParam.qMatTab, 4 * 64); + + return 1; +} + +/** + * To init EncOpenParam by CFG file + * IN + * EncConfigParam *pEncConfig + * OUT + * EncOpenParam *pEncOP + * char *srcYuvFileName + */ + +int getJpgEncOpenParam(JpgEncOpenParam *pEncOP, EncConfigParam *pEncConfig, char *srcYuvFileName) +{ + ENC_CFG encCfg; + int ret; + EncMjpgParam mjpgParam; + char cfgFileName[MAX_FILE_PATH]; + + // Source YUV Image File to load + // strcpy(srcYuvFileName, encCfg.SrcFileName); + memset(&encCfg, 0x00, sizeof(ENC_CFG)); + memset(&mjpgParam, 0x00, sizeof(EncMjpgParam)); + + if (strlen(pEncConfig->strCfgDir)) + sprintf(cfgFileName, "%s%s", pEncConfig->strCfgDir, pEncConfig->cfgFileName); + // else + // strcpy(cfgFileName, pEncConfig->cfgFileName); + + parseJpgCfgFile(&encCfg, cfgFileName); + + if (srcYuvFileName) { + if (strlen(pEncConfig->strStmDir)) + sprintf(srcYuvFileName, "%s%s", pEncConfig->strStmDir, encCfg.SrcFileName); + // else + // strcpy(srcYuvFileName, encCfg.SrcFileName); + } + + if (encCfg.FrmFormat == 0) + pEncConfig->chroma_interleave = CBCR_SEPARATED; + else if (encCfg.FrmFormat == 1) + pEncConfig->chroma_interleave = CBCR_INTERLEAVE; + else if (encCfg.FrmFormat == 2) + pEncConfig->chroma_interleave = CRCB_INTERLEAVE; + else + pEncConfig->chroma_interleave = CBCR_SEPARATED; + + pEncConfig->packedFormat = (encCfg.FrmFormat - 2); + if (pEncConfig->packedFormat < 0) + pEncConfig->packedFormat = 0; + + pEncConfig->outNum = encCfg.NumFrame; + + if (pEncOP) { + pEncOP->picWidth = encCfg.PicX; + pEncOP->picHeight = encCfg.PicY; + pEncOP->chroma_interleave = pEncConfig->chroma_interleave; + pEncOP->packedFormat = pEncConfig->packedFormat; + pEncOP->sourceFormat = encCfg.SrcFormat; + pEncOP->restartInterval = encCfg.RstIntval; + + mjpgParam.sourceFormat = encCfg.SrcFormat; + ret = jpgGetHuffTable(encCfg.HuffTabName, &mjpgParam); + if (ret == 0) + return ret; + ret = jpgGetQMatrix(encCfg.QMatTabName, &mjpgParam); + if (ret == 0) + return ret; + + memcpy(pEncOP->huffVal, mjpgParam.huffVal, 4 * 162); + memcpy(pEncOP->huffBits, mjpgParam.huffBits, 4 * 256); + memcpy(pEncOP->qMatTab, mjpgParam.qMatTab, 4 * 64); + } + + return 1; +} + +//------------------------------------------------------------------------------ +// ENCODE PARAMETER PARSE FUNCSIONS +//------------------------------------------------------------------------------ +// Parameter parsing helper +static int GetValue(osal_file_t *fp, char *para, char *value) +{ + static int LineNum = 1; + char lineStr[256]; + char paraStr[256]; + int ret = 0; + + OSAL_FSEEK(fp, 0, SEEK_SET); + + while (1) { + if (!OSAL_FGETS(lineStr, 256, fp)) + return 0; + ret = sscanf(lineStr, "%s %s", paraStr, value); + if (paraStr[0] != ';') { + if (strcmp(para, paraStr) == 0) + return 1; + } + LineNum++; + } + + (void)ret; + return 1; +} + +int parseJpgCfgFile(ENC_CFG *pEncCfg, char *FileName) +{ + osal_file_t *Fp; + int ret = 0; + + char sLine[256] = { + 0, + }; + + Fp = OSAL_FOPEN(FileName, "rt"); + + if (!Fp) { + BM_DBG_ERR(" > ERROR: File not exist <%s>\n", FileName); + return 0; + } + + // source file name + if (GetValue(Fp, "YUV_SRC_IMG", sLine) == 0) + return 0; + ret = sscanf(sLine, "%s", (char *)&pEncCfg->SrcFileName); + + // frame format + // ; 0-planar, 1-NV12,NV16(CbCr interleave) 2-NV21,NV61(CbCr + // alternative) ; 3-YUYV, 4-UYVY, 5-YVYU, 6-VYUY, 7-YUV packed + // (444 only) + if (GetValue(Fp, "FRAME_FORMAT", sLine) == 0) + return 0; + pEncCfg->FrmFormat = (int)simple_strtol(sLine, NULL, 10);//sscanf(sLine, "%d", &pEncCfg->FrmFormat); + + // width + if (GetValue(Fp, "PICTURE_WIDTH", sLine) == 0) + return 0; + pEncCfg->PicX = (int)simple_strtol(sLine, NULL, 10);//sscanf(sLine, "%d", &pEncCfg->PicX); + + // height + if (GetValue(Fp, "PICTURE_HEIGHT", sLine) == 0) + return 0; + pEncCfg->PicY = (int)simple_strtol(sLine, NULL, 10);//sscanf(sLine, "%d", &pEncCfg->PicY); + + // frame_rate + if (GetValue(Fp, "FRAME_RATE", sLine) == 0) + return 0; + { + double frameRate = 0.0; + int timeRes, timeInc; + + // frameRate = (double)(int)atoi(sLine); + + timeInc = 1; + while ((int)frameRate != frameRate) { + timeInc *= 10; + frameRate *= 10; + } + timeRes = (int)frameRate; + // divide 2 or 5 + if (timeInc % 2 == 0 && timeRes % 2 == 0) + timeInc /= 2, timeRes /= 2; + if (timeInc % 5 == 0 && timeRes % 5 == 0) + timeInc /= 5, timeRes /= 5; + + if (timeRes == 2997 && timeInc == 100) + timeRes = 30000, timeInc = 1001; + pEncCfg->FrameRate = (timeInc - 1) << 16; + pEncCfg->FrameRate |= timeRes; + } + + // frame count + if (GetValue(Fp, "FRAME_NUMBER_ENCODED", sLine) == 0) + return 0; + + pEncCfg->NumFrame = (int)simple_strtol(sLine, NULL, 10);//sscanf(sLine, "%d", &pEncCfg->NumFrame); + + if (GetValue(Fp, "VERSION_ID", sLine) == 0) + return 0; + + pEncCfg->VersionID = (int)simple_strtol(sLine, NULL, 10);//sscanf(sLine, "%d", &pEncCfg->VersionID); + + if (GetValue(Fp, "RESTART_INTERVAL", sLine) == 0) + return 0; + + pEncCfg->RstIntval = (int)simple_strtol(sLine, NULL, 10);//sscanf(sLine, "%d", &pEncCfg->RstIntval); + + if (GetValue(Fp, "IMG_FORMAT", sLine) == 0) + return 0; + + pEncCfg->SrcFormat = (int)simple_strtol(sLine, NULL, 10);//sscanf(sLine, "%d", &pEncCfg->SrcFormat); + + if (GetValue(Fp, "QMATRIX_TABLE", sLine) == 0) + return 0; + + ret = sscanf(sLine, "%s", (char *)&pEncCfg->QMatTabName); + + if (GetValue(Fp, "HUFFMAN_TABLE", sLine) == 0) + return 0; + + ret = sscanf(sLine, "%s", (char *)&pEncCfg->HuffTabName); + + (void)ret; + OSAL_FCLOSE(Fp); + return 1; +} + +int FillSdramBurst(BufInfo *pBufInfo, Uint64 targetAddr, + PhysicalAddress bsBufStartAddr, PhysicalAddress bsBufEndAddr, + Uint32 size, int checkeos, int *streameos, int endian) +{ + Uint8 *pBuf; + int room; + + pBufInfo->count = 0; + + if (checkeos == 1 && pBufInfo->point >= pBufInfo->size) { + *streameos = 1; + return 0; + } + + if ((pBufInfo->size - pBufInfo->point) < (int)size) + pBufInfo->count = (pBufInfo->size - pBufInfo->point); + else + pBufInfo->count = size; + + pBuf = pBufInfo->buf + pBufInfo->point; + + if ((targetAddr + pBufInfo->count) > bsBufEndAddr) { + room = bsBufEndAddr - targetAddr; + JpuWriteMem(targetAddr, pBuf, room, endian); + JpuWriteMem(bsBufStartAddr, pBuf + room, (pBufInfo->count - room), endian); + } else { + JpuWriteMem(targetAddr, pBuf, pBufInfo->count, endian); + } + + pBufInfo->point += pBufInfo->count; + return pBufInfo->count; +} + +int StoreYuvImageBurstFormat(Uint8 *dst, int picWidth, int picHeight, + unsigned long addrY, unsigned long addrCb, + unsigned long addrCr, int stride, int interLeave, + int format, int endian, int packed) +{ + int size = 0; + int y = 0, nY = 0, nCb = 0, nCr = 0; + unsigned long addr = 0; + int lumaSize = 0, chromaSize = 0, chromaStride = 0, chromaWidth = 0, chromaHeight = 0; + + Uint8 *puc; + + switch (format) { + case FORMAT_420: + nY = (picHeight + 1) / 2 * 2; + nCb = (picHeight + 1) / 2; + nCr = (picHeight + 1) / 2; + chromaSize = ((picWidth + 1) / 2) * ((picHeight + 1) / 2); + chromaStride = stride / 2; + chromaWidth = (picWidth + 1) / 2; + chromaHeight = nY; + break; + case FORMAT_224: + nY = (picHeight + 1) / 2 * 2; + nCb = (picHeight + 1) / 2; + nCr = (picHeight + 1) / 2; + chromaSize = (picWidth) * ((picHeight + 1) / 2); + chromaStride = stride; + chromaWidth = picWidth; + chromaHeight = nY; + break; + case FORMAT_422: + nY = picHeight; + nCb = picHeight; + nCr = picHeight; + chromaSize = ((picWidth + 1) / 2) * picHeight; + chromaStride = stride / 2; + chromaWidth = (picWidth + 1) / 2; + chromaHeight = nY * 2; + break; + case FORMAT_444: + nY = picHeight; + nCb = picHeight; + nCr = picHeight; + chromaSize = picWidth * picHeight; + chromaStride = stride; + chromaWidth = picWidth; + chromaHeight = nY * 2; + break; + case FORMAT_400: + nY = picHeight; + nCb = 0; + nCr = 0; + chromaSize = 0; + chromaStride = 0; + chromaWidth = 0; + chromaHeight = 0; + break; + } + + puc = dst; + addr = addrY; + + if (packed) { + if (packed == PACKED_FORMAT_444) + picWidth *= 3; + else + picWidth *= 2; + + chromaSize = 0; + } + + lumaSize = picWidth * nY; + + size = lumaSize + chromaSize * 2; + + if (picWidth == stride) { + JpuReadMem(addr, (Uint8 *)(puc), lumaSize, endian); + + if (packed) + return size; + + if (interLeave) { + puc = dst + lumaSize; + addr = addrCb; + JpuReadMem(addr, (Uint8 *)(puc), chromaSize * 2, + endian); + } else { + puc = dst + lumaSize; + addr = addrCb; + JpuReadMem(addr, (Uint8 *)(puc), chromaSize, endian); + + puc = dst + lumaSize + chromaSize; + addr = addrCr; + JpuReadMem(addr, (Uint8 *)(puc), chromaSize, endian); + } + } else { + for (y = 0; y < nY; ++y) { + JpuReadMem(addr + stride * y, (Uint8 *)(puc + y * picWidth), picWidth, endian); + } + + if (packed) + return size; + + if (interLeave) { + puc = dst + lumaSize; + addr = addrCb; + for (y = 0; y < (chromaHeight / 2); ++y) { + JpuReadMem(addr + (chromaStride * 2) * y, + (Uint8 *)(puc + y * (chromaWidth * 2)), + (chromaWidth * 2), endian); + } + } else { + puc = dst + lumaSize; + addr = addrCb; + for (y = 0; y < nCb; ++y) { + JpuReadMem(addr + chromaStride * y, + (Uint8 *)(puc + y * chromaWidth), + chromaWidth, endian); + } + + puc = dst + lumaSize + chromaSize; + addr = addrCr; + for (y = 0; y < nCr; ++y) { + JpuReadMem(addr + chromaStride * y, + (Uint8 *)(puc + y * chromaWidth), + chromaWidth, endian); + } + } + } + + return size; +} + +void ProcessEncodedBitstreamBurst(osal_file_t *fp, unsigned long targetAddr, + PhysicalAddress bsBufStartAddr, + PhysicalAddress bsBufEndAddr, int size, + int endian) +{ + Uint8 *val = 0; + int room = 0; + + BM_DBG_TRACE("target addr :%lx\n", targetAddr); + BM_DBG_TRACE("start :%lx, end:%lx, size:%d\n", bsBufStartAddr, bsBufEndAddr, size); + + val = (Uint8 *)OSAL_MALLOC(size); + if ((targetAddr + size) > (unsigned long)bsBufEndAddr) { + room = bsBufEndAddr - targetAddr; + JpuReadMem(targetAddr, val, room, endian); + JpuReadMem(bsBufStartAddr, val + room, (size - room), endian); + } else { + BM_DBG_TRACE("read target addr :%lx\n", targetAddr); + JpuReadMem(targetAddr, val, size, endian); + } + + if (fp) { + OSAL_FWRITE(val, sizeof(Uint8), size, fp); + OSAL_FFLUSH(fp); + } + + OSAL_FREE(val); +} + +int LoadYuvImageBurstFormat(Uint8 *src, int picWidth, int picHeight, + unsigned long addrY, unsigned long addrCb, + unsigned long addrCr, int stride, int interLeave, + int format, int endian, int packed) +{ + int y = 0, nY = 0, nCb = 0, nCr = 0; + unsigned long addr = 0; + int size = 0; + int lumaSize = 0, chromaSize = 0, chromaStride = 0, chromaWidth = 0; + Uint8 *puc = NULL; + + switch (format) { + case FORMAT_420: + nY = picHeight; + nCb = picHeight / 2; + nCr = picHeight / 2; + chromaSize = picWidth * picHeight / 4; + chromaStride = stride / 2; + chromaWidth = picWidth / 2; + break; + case FORMAT_224: + nY = picHeight; + nCb = picHeight / 2; + nCr = picHeight / 2; + chromaSize = picWidth * picHeight / 2; + chromaStride = stride; + chromaWidth = picWidth; + break; + case FORMAT_422: + nY = picHeight; + nCb = picHeight; + nCr = picHeight; + chromaSize = picWidth * picHeight / 2; + chromaStride = stride / 2; + chromaWidth = picWidth / 2; + break; + case FORMAT_444: + nY = picHeight; + nCb = picHeight; + nCr = picHeight; + chromaSize = picWidth * picHeight; + chromaStride = stride; + chromaWidth = picWidth; + break; + case FORMAT_400: + nY = picHeight; + nCb = 0; + nCr = 0; + chromaSize = picWidth * picHeight / 4; + chromaStride = stride / 2; + chromaWidth = picWidth / 2; + break; + } + + puc = src; + addr = addrY; + + if (packed) { + if (packed == PACKED_FORMAT_444) + picWidth *= 3; + else + picWidth *= 2; + + chromaSize = 0; + } + + lumaSize = picWidth * nY; + + size = lumaSize + chromaSize * 2; + + if (picWidth == stride) { // for fast write + JpuWriteMem(addr, (Uint8 *)(puc), lumaSize, endian); + + if (format == FORMAT_400) + return size; + + if (packed) + return size; + + if (interLeave) { + Uint8 t0, t1, t2, t3, t4, t5, t6, t7; + int i, height, width; + int stride; + Uint8 *pTemp; + Uint8 *dstAddrCb; + Uint8 *dstAddrCr; + + addr = addrCb; + stride = chromaStride * 2; + height = nCb; + width = chromaWidth * 2; + + dstAddrCb = (Uint8 *)(puc + picWidth * nY); + dstAddrCr = (Uint8 *)(dstAddrCb + chromaSize); + + pTemp = OSAL_MALLOC(width); + if (!pTemp) { + return 0; + } + + for (y = 0; y < height; ++y) { + for (i = 0; i < width; i += 8) { + t0 = *dstAddrCb++; + t2 = *dstAddrCb++; + t4 = *dstAddrCb++; + t6 = *dstAddrCb++; + t1 = *dstAddrCr++; + t3 = *dstAddrCr++; + t5 = *dstAddrCr++; + t7 = *dstAddrCr++; + if (interLeave == CBCR_INTERLEAVE) { + pTemp[i] = t0; + pTemp[i + 1] = t1; + pTemp[i + 2] = t2; + pTemp[i + 3] = t3; + pTemp[i + 4] = t4; + pTemp[i + 5] = t5; + pTemp[i + 6] = t6; + pTemp[i + 7] = t7; + } else { // CRCB_INTERLEAVE + pTemp[i] = t1; + pTemp[i + 1] = t0; + pTemp[i + 2] = t3; + pTemp[i + 3] = t2; + pTemp[i + 4] = t5; + pTemp[i + 5] = t4; + pTemp[i + 6] = t7; + pTemp[i + 7] = t6; + } + } + JpuWriteMem(addr + stride * y, (unsigned char *)pTemp, width, endian); + } + + OSAL_FREE(pTemp); + } else { + puc = src + lumaSize; + addr = addrCb; + JpuWriteMem(addr, (Uint8 *)puc, chromaSize, endian); + + puc = src + lumaSize + chromaSize; + addr = addrCr; + JpuWriteMem(addr, (Uint8 *)puc, chromaSize, endian); + } + } else { + for (y = 0; y < nY; ++y) { + JpuWriteMem(addr + stride * y, (Uint8 *)(puc + y * picWidth), picWidth, endian); + } + + if (format == FORMAT_400) + return size; + + if (packed) + return size; + + if (interLeave == 1) { + Uint8 t0, t1, t2, t3, t4, t5, t6, t7; + int i, width, height, stride; + Uint8 *pTemp; + Uint8 *dstAddrCb; + Uint8 *dstAddrCr; + + addr = addrCb; + stride = chromaStride * 2; + height = nCb / 2; + width = chromaWidth * 2; + + dstAddrCb = (Uint8 *)(puc + picWidth * nY); + dstAddrCr = (Uint8 *)(dstAddrCb + chromaSize); + + pTemp = OSAL_MALLOC((width + 7) & ~7); + if (!pTemp) { + return 0; + } + + // it may be not occur that pic_width in not 8byte + // alined. + for (y = 0; y < height; ++y) { + for (i = 0; i < width; i += 8) { + t0 = *dstAddrCb++; + t2 = *dstAddrCb++; + t4 = *dstAddrCb++; + t6 = *dstAddrCb++; + t1 = *dstAddrCr++; + t3 = *dstAddrCr++; + t5 = *dstAddrCr++; + t7 = *dstAddrCr++; + + if (interLeave == CBCR_INTERLEAVE) { + pTemp[i] = t0; + pTemp[i + 1] = t1; + pTemp[i + 2] = t2; + pTemp[i + 3] = t3; + pTemp[i + 4] = t4; + pTemp[i + 5] = t5; + pTemp[i + 6] = t6; + pTemp[i + 7] = t7; + } else { // CRCB_INTERLEAVE + pTemp[i] = t1; + pTemp[i + 1] = t0; + pTemp[i + 2] = t3; + pTemp[i + 3] = t2; + pTemp[i + 4] = t5; + pTemp[i + 5] = t3; + pTemp[i + 6] = t7; + pTemp[i + 7] = t6; + } + + JpuWriteMem(addr + stride * y, (unsigned char *)pTemp, stride, endian); + } + } + + } else { + puc = src + lumaSize; + addr = addrCb; + for (y = 0; y < nCb; ++y) { + JpuWriteMem(addr + chromaStride * y, + (Uint8 *)(puc + y * chromaWidth), + chromaWidth, endian); + } + + puc = src + lumaSize + chromaSize; + addr = addrCr; + for (y = 0; y < nCr; ++y) { + JpuWriteMem(addr + chromaStride * y, + (Uint8 *)(puc + y * chromaWidth), + chromaWidth, endian); + } + } + } + + return size; +} + +void GetMcuUnitSize(int format, int *mcuWidth, int *mcuHeight) +{ + switch (format) { + case FORMAT_420: + *mcuWidth = 16; + *mcuHeight = 16; + break; + case FORMAT_422: + *mcuWidth = 16; + *mcuHeight = 8; + break; + case FORMAT_224: + *mcuWidth = 8; + *mcuHeight = 16; + break; + default: // FORMAT_444,400 + *mcuWidth = 8; + *mcuHeight = 8; + break; + } +} + +unsigned int GetFrameBufSize(int framebufFormat, int picWidth, int picHeight) +{ + unsigned int framebufSize = 0; + unsigned int framebufWidth, framebufHeight; + + if (framebufFormat == FORMAT_420 || framebufFormat == FORMAT_422) + framebufWidth = ((picWidth + 15) / 16) * 16; + else + framebufWidth = ((picWidth + 7) / 8) * 8; + + if (framebufFormat == FORMAT_420 || framebufFormat == FORMAT_224) + framebufHeight = ((picHeight + 15) / 16) * 16; + else + framebufHeight = ((picHeight + 7) / 8) * 8; + + switch (framebufFormat) { + case FORMAT_420: + framebufSize = + framebufWidth * ((framebufHeight + 1) / 2 * 2) + + ((framebufWidth + 1) / 2) * ((framebufHeight + 1) / 2) * 2; + break; + case FORMAT_224: + framebufSize = framebufWidth * ((framebufHeight + 1) / 2 * 2) + + framebufWidth * ((framebufHeight + 1) / 2) * 2; + break; + case FORMAT_422: + framebufSize = framebufWidth * framebufHeight + + ((framebufWidth + 1) / 2) * framebufHeight * 2; + break; + case FORMAT_444: + framebufSize = framebufWidth * framebufHeight * 3; + break; + case FORMAT_400: + framebufSize = framebufWidth * framebufHeight; + break; + } + + framebufSize = ((framebufSize + 7) & ~7); + + return framebufSize; +} + +// inteleave : 0 (chroma separate mode), 1 (cbcr interleave mode), 2 (crcb +// interleave mode) +yuv2rgb_color_format +convert_jpuapi_format_to_yuv2rgb_color_format(int planar_format, + int pack_format, int interleave) +{ + yuv2rgb_color_format format = 0; + + if (!pack_format) { + switch (planar_format) { + case FORMAT_400: + format = YUV400; + break; + case FORMAT_444: + format = YUV444; + break; + case FORMAT_224: + case FORMAT_422: + format = YUV422; + break; + case FORMAT_420: + if (interleave == 0) + format = YUV420; + else if (interleave == 1) + format = NV12; + else + format = NV21; + break; + } + } else { + switch (pack_format) { + case PACKED_FORMAT_422_YUYV: + format = YUYV; + break; + case PACKED_FORMAT_422_UYVY: + format = UYVY; + break; + case PACKED_FORMAT_422_YVYU: + format = YVYU; + break; + case PACKED_FORMAT_422_VYUY: + format = VYUY; + break; + case PACKED_FORMAT_444: + format = YYY; + break; + } + } + + return format; +} + +void jpu_yuv2rgb(int width, int height, yuv2rgb_color_format format, + unsigned char *src, unsigned char *rgba, int cbcr_reverse) +{ +#define jpu_clip(var) (((var) >= 255) ? 255 : ((var) <= 0) ? 0 : (var)) + int j, i; + int c, d, e; + + unsigned char *line = rgba; + unsigned char *cur = NULL; + unsigned char *y = NULL; + unsigned char *u = NULL; + unsigned char *v = NULL; + unsigned char *misc = NULL; + + int frame_size_y; + int frame_size_uv; + int t_width; + + frame_size_y = width * height; + + if (format == YUV444 || format == RGB_PLANAR) + frame_size_uv = width * height; + else if (format == YUV422) + frame_size_uv = (width * height) >> 1; + else if (format == YUV420 || format == NV12 || format == NV21) + frame_size_uv = (width * height) >> 2; + else + frame_size_uv = 0; + + t_width = width; + + if (format == YUYV || format == YVYU || format == UYVY || format == VYUY) { + misc = src; + } else if (format == NV12 || format == NV21) { + y = src; + misc = src + frame_size_y; + } else if (format == RGB32 || format == RGB24 || format == RGB16) { + misc = src; + } else { + y = src; + u = src + frame_size_y; + v = src + frame_size_y + frame_size_uv; + } + + if (format == YUV444) { + for (j = 0; j < height; j++) { + cur = line; + for (i = 0; i < width; i++) { + c = y[j * width + i] - 16; + d = u[j * width + i] - 128; + e = v[j * width + i] - 128; + + if (!cbcr_reverse) { + d = u[j * width + i] - 128; + e = v[j * width + i] - 128; + } else { + e = u[j * width + i] - 128; + e = v[j * width + i] - 128; + } + (*cur) = jpu_clip((298 * c + 409 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c - 100 * d - 208 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c + 516 * d + 128) >> 8); + cur++; + (*cur) = 0; + cur++; + } + line += t_width << 2; + } + } else if (format == YUV422) { + for (j = 0; j < height; j++) { + cur = line; + for (i = 0; i < width; i++) { + c = y[j * width + i] - 16; + d = u[j * (width >> 1) + (i >> 1)] - 128; + e = v[j * (width >> 1) + (i >> 1)] - 128; + + if (!cbcr_reverse) { + d = u[j * (width >> 1) + (i >> 1)] - 128; + e = v[j * (width >> 1) + (i >> 1)] - 128; + } else { + e = u[j * (width >> 1) + (i >> 1)] - 128; + d = v[j * (width >> 1) + (i >> 1)] - 128; + } + + (*cur) = jpu_clip((298 * c + 409 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c - 100 * d - 208 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c + 516 * d + 128) >> 8); + cur++; + (*cur) = 0; + cur++; + } + line += t_width << 2; + } + } else if (format == YUYV || format == YVYU || format == UYVY || format == VYUY) { + unsigned char *t = misc; + + for (j = 0; j < height; j++) { + cur = line; + for (i = 0; i < width; i += 2) { + switch (format) { + case YUYV: + c = *(t) - 16; + if (!cbcr_reverse) { + d = *(t + 1) - 128; + e = *(t + 3) - 128; + } else { + e = *(t + 1) - 128; + d = *(t + 3) - 128; + } + break; + case YVYU: + c = *(t) - 16; + if (!cbcr_reverse) { + d = *(t + 3) - 128; + e = *(t + 1) - 128; + } else { + e = *(t + 3) - 128; + d = *(t + 1) - 128; + } + break; + case UYVY: + c = *(t + 1) - 16; + if (!cbcr_reverse) { + d = *(t) - 128; + e = *(t + 2) - 128; + } else { + e = *(t) - 128; + d = *(t + 2) - 128; + } + break; + case VYUY: + c = *(t + 1) - 16; + if (!cbcr_reverse) { + d = *(t + 2) - 128; + e = *(t) - 128; + } else { + e = *(t + 2) - 128; + d = *(t) - 128; + } + break; + default: // like YUYV + c = *(t) - 16; + if (!cbcr_reverse) { + d = *(t + 1) - 128; + e = *(t + 3) - 128; + } else { + e = *(t + 1) - 128; + d = *(t + 3) - 128; + } + break; + } + + (*cur) = jpu_clip((298 * c + 409 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c - 100 * d - 208 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c + 516 * d + 128) >> 8); + cur++; + (*cur) = 0; + cur++; + + switch (format) { + case YUYV: + case YVYU: + c = *(t + 2) - 16; + break; + + case VYUY: + case UYVY: + c = *(t + 3) - 16; + break; + default: // like YUYV + c = *(t + 2) - 16; + break; + } + + (*cur) = jpu_clip((298 * c + 409 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c - 100 * d - 208 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c + 516 * d + 128) >> 8); + cur++; + (*cur) = 0; + cur++; + + t += 4; + } + line += t_width << 2; + } + } else if (format == YUV420 || format == NV12 || format == NV21) { + for (j = 0; j < height; j++) { + cur = line; + for (i = 0; i < width; i++) { + c = y[j * width + i] - 16; + if (format == YUV420) { + if (!cbcr_reverse) { + d = u[(j >> 1) * (width >> 1) + (i >> 1)] - 128; + e = v[(j >> 1) * (width >> 1) + (i >> 1)] - 128; + } else { + e = u[(j >> 1) * (width >> 1) + (i >> 1)] - 128; + d = v[(j >> 1) * (width >> 1) + (i >> 1)] - 128; + } + } else if (format == NV12) { + if (!cbcr_reverse) { + d = misc[(j >> 1) * width + (i >> 1 << 1)] - 128; + e = misc[(j >> 1) * width + (i >> 1 << 1) + 1] - 128; + } else { + e = misc[(j >> 1) * width + (i >> 1 << 1)] - 128; + d = misc[(j >> 1) * width + (i >> 1 << 1) + 1] - 128; + } + } else { // if (m_color == NV21) + if (!cbcr_reverse) { + d = misc[(j >> 1) * width + (i >> 1 << 1) + 1] - 128; + e = misc[(j >> 1) * width + (i >> 1 << 1)] - 128; + } else { + e = misc[(j >> 1) * width + (i >> 1 << 1) + 1] - 128; + d = misc[(j >> 1) * width + (i >> 1 << 1)] - 128; + } + } + (*cur) = jpu_clip((298 * c + 409 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c - 100 * d - 208 * e + 128) >> 8); + cur++; + (*cur) = jpu_clip((298 * c + 516 * d + 128) >> 8); + cur++; + (*cur) = 0; + cur++; + } + line += t_width << 2; + } + } else if (format == RGB_PLANAR) { + for (j = 0; j < height; j++) { + cur = line; + for (i = 0; i < width; i++) { + (*cur) = y[j * width + i]; + cur++; + (*cur) = u[j * width + i]; + cur++; + (*cur) = v[j * width + i]; + cur++; + (*cur) = 0; + cur++; + } + line += t_width << 2; + } + } else if (format == RGB32) { + for (j = 0; j < height; j++) { + cur = line; + for (i = 0; i < width; i++) { + (*cur) = misc[j * width * 4 + i]; + cur++; // R + (*cur) = misc[j * width * 4 + i + 1]; + cur++; // G + (*cur) = misc[j * width * 4 + i + 2]; + cur++; // B + (*cur) = misc[j * width * 4 + i + 3]; + cur++; // A + } + line += t_width << 2; + } + } else if (format == RGB24) { + for (j = 0; j < height; j++) { + cur = line; + for (i = 0; i < width; i++) { + (*cur) = misc[j * width * 3 + i]; + cur++; // R + (*cur) = misc[j * width * 3 + i + 1]; + cur++; // G + (*cur) = misc[j * width * 3 + i + 2]; + cur++; // B + (*cur) = 0; + cur++; + } + line += t_width << 2; + } + } else if (format == RGB16) { + for (j = 0; j < height; j++) { + cur = line; + for (i = 0; i < width; i++) { + int tmp = misc[j * width * 2 + i] << 8 | misc[j * width * 2 + i + 1]; + (*cur) = ((tmp >> 11) & 0x1F << 3); + cur++; // R(5bit) + (*cur) = ((tmp >> 5) & 0x3F << 2); + cur++; // G(6bit) + (*cur) = ((tmp) & 0x1F << 3); + cur++; // B(5bit) + (*cur) = 0; + cur++; + } + line += t_width << 2; + } + } else { // YYY + for (j = 0; j < height; j++) { + cur = line; + for (i = 0; i < width; i++) { + (*cur) = y[j * width + i]; + cur++; + (*cur) = y[j * width + i]; + cur++; + (*cur) = y[j * width + i]; + cur++; + (*cur) = 0; + cur++; + } + line += t_width << 2; + } + } +} + +int comparateYuv(Uint8 *pYuv, Uint8 *pRefYuv, int picWidth, int picHeight, + int stride, int interleave, int format, int endian, int packed) +{ + int size = 0; + int y = 0, nY = 0, nCb = 0, nCr = 0; + Uint8 *pRef = NULL; + int lumaSize = 0, chromaSize = 0, chromaStride = 0, chromaWidth = 0, chromaHeight = 0; + + Uint8 *pOrg = NULL; + + switch (format) { + case FORMAT_420: + nY = (picHeight + 1) / 2 * 2; + nCb = (picHeight + 1) / 2; + nCr = (picHeight + 1) / 2; + chromaSize = ((picWidth + 1) / 2) * ((picHeight + 1) / 2); + chromaStride = stride / 2; + chromaWidth = (picWidth + 1) / 2; + chromaHeight = nY; + break; + case FORMAT_224: + nY = (picHeight + 1) / 2 * 2; + nCb = (picHeight + 1) / 2; + nCr = (picHeight + 1) / 2; + chromaSize = (picWidth) * ((picHeight + 1) / 2); + chromaStride = stride; + chromaWidth = picWidth; + chromaHeight = nY; + break; + case FORMAT_422: + nY = picHeight; + nCb = picHeight; + nCr = picHeight; + chromaSize = ((picWidth + 1) / 2) * picHeight; + chromaStride = stride / 2; + chromaWidth = (picWidth + 1) / 2; + chromaHeight = nY * 2; + break; + case FORMAT_444: + nY = picHeight; + nCb = picHeight; + nCr = picHeight; + chromaSize = picWidth * picHeight; + chromaStride = stride; + chromaWidth = picWidth; + chromaHeight = nY * 2; + break; + case FORMAT_400: + nY = picHeight; + nCb = 0; + nCr = 0; + chromaSize = 0; + chromaStride = 0; + chromaWidth = 0; + chromaHeight = 0; + break; + } + + pRef = pRefYuv; + pOrg = pYuv; + + if (packed) { + if (packed == PACKED_FORMAT_444) + picWidth *= 3; + else + picWidth *= 2; + + chromaSize = 0; + } + + lumaSize = picWidth * nY; + + size = lumaSize + chromaSize * 2; + + if (picWidth == stride) { + if (OSAL_MEMCMP(pRef, pOrg, size)) { + JLOG(INFO, "pRef = 0x%lx, pOrg = 0x%lx, size:%d\n", + (unsigned long)pRef, (unsigned long)pOrg, size); + return 1; + } else + return 0; + } else { + for (y = 0; y < nY; ++y) { + if (OSAL_MEMCMP(pOrg + stride * y, pRef + y * picWidth, picWidth)) { + JLOG(INFO, "pRef1 = 0x%lx, pOrg1 = 0x%lx\n", + (unsigned long)(pRef + y * picWidth), + (unsigned long)(pOrg + stride * y)); + return 1; + } + } + + if (packed) + return 0; + + pRef = pRef + lumaSize; + pOrg = pOrg + nY * stride; + if (interleave) { + for (y = 0; y < (chromaHeight / 2); ++y) { + if (OSAL_MEMCMP(pOrg + (chromaStride * 2) * y, + pRef + y * (chromaWidth * 2), + (chromaWidth * 2))) { + JLOG(INFO, "pRef1 = 0x%lx\n", (unsigned long)(pOrg + (chromaStride * 2) * y)); + JLOG(INFO, "pOrg2 = 0x%lx\n", (unsigned long)(pRef + y * (chromaWidth * 2))); + return 1; + } + } + } else { + for (y = 0; y < nCb; ++y) { + if (OSAL_MEMCMP(pOrg + chromaStride * y, pRef + y * chromaWidth, chromaWidth)) { + JLOG(INFO, + "pRef3 = 0x%lx, pOrg3 = 0x%lx\n", + (unsigned long)(pOrg + chromaStride * y), + (unsigned long)(pRef + y * chromaWidth)); + return 1; + } + } + + pRef = pRef + chromaSize; + pOrg = pOrg + nCb * chromaStride; + for (y = 0; y < nCr; ++y) { + if (OSAL_MEMCMP(pOrg + chromaStride * y, pRef + y * chromaWidth, chromaWidth)) { + JLOG(INFO, + "pRef4 = 0x%lx, pOrg4 = 0x%lx\n", + (unsigned long)(pOrg + chromaStride * y), + (unsigned long)(pRef + y * chromaWidth)); + return 1; + } + } + } + } + + return 0; +} diff --git a/u-boot-2021.10/drivers/jpeg/jpuhelper.h b/u-boot-2021.10/drivers/jpeg/jpuhelper.h new file mode 100644 index 000000000..f000b5b9d --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpuhelper.h @@ -0,0 +1,165 @@ +#ifndef _JPU_HELPER_H_ +#define _JPU_HELPER_H_ + +#include "jpuapi.h" +#include "jpurun.h" + +typedef struct { + char SrcFileName[256]; + int NumFrame; + int PicX; + int PicY; + int FrameRate; + + // MPEG4 ONLY + int VerId; + int DataPartEn; + int RevVlcEn; + int ShortVideoHeader; + int AnnexI; + int AnnexJ; + int AnnexK; + int AnnexT; + int IntraDcVlcThr; + int VopQuant; + + // H.264 ONLY + int ConstIntraPredFlag; + int DisableDeblk; + int DeblkOffsetA; + int DeblkOffsetB; + int ChromaQpOffset; + int PicQpY; + + // MJPEG ONLY + char HuffTabName[256]; + char QMatTabName[256]; + int VersionID; + int FrmFormat; + int SrcFormat; + int RstIntval; + int ThumbEnable; + int ThumbSizeX; + int ThumbSizeY; + + // COMMON + int GopPicNum; + int SliceMode; + int SliceSizeMode; + int SliceSizeNum; + + int IntraRefreshNum; + + int ConstantIntraQPEnable; + int RCIntraQP; + int MaxQpSetEnable; + int MaxQp; + int GammaSetEnable; + int Gamma; + int HecEnable; + + // RC + int RcEnable; + int RcBitRate; + int RcInitDelay; + int RcBufSize; + + // NEW RC Scheme + int RcIntervalMode; + int RcMBInterval; + int IntraCostWeight; + int SearchRange; + int MeUseZeroPmv; + int MeBlkModeEnable; + +} ENC_CFG; + +typedef struct { + int sourceFormat; + int restartInterval; + BYTE huffVal[4][162]; + BYTE huffBits[4][256]; + BYTE qMatTab[4][64]; +} EncMjpgParam; + +#if defined(__cplusplus) +extern "C" { +#endif + +int jpgGetHuffTable(char *huffFileName, EncMjpgParam *param); +int jpgGetQMatrix(char *qMatFileName, EncMjpgParam *param); + +int getJpgEncOpenParamDefault(JpgEncOpenParam *pEncOP, EncConfigParam *pEncConfig); +int getJpgEncOpenParam(JpgEncOpenParam *pEncOP, EncConfigParam *pEncConfig, char *srcYuvFileName); +int parseJpgCfgFile(ENC_CFG *pEncCfg, char *FileName); + +JpgRet WriteJpgBsBufHelper(JpgDecHandle handle, BufInfo *pBufInfo, + PhysicalAddress paBsBufStart, + PhysicalAddress paBsBufEnd, int defaultsize, + int checkeos, int *pstreameos, int endian); + +int WriteBsBufFromBufHelper(JpgDecHandle handle, jpu_buffer_t *pJbStream, + BYTE *pChunk, int chunkSize, int endian); + +JpgRet ReadJpgBsBufHelper(JpgEncHandle handle, osal_file_t *bsFp, + PhysicalAddress paBsBufStart, + PhysicalAddress paBsBufEnd, int encHeaderSize, + int endian); + +int LoadYuvImageHelperFormat(osal_file_t *yuvFp, Uint8 *pYuv, + PhysicalAddress addrY, PhysicalAddress addrCb, + PhysicalAddress addrCr, int picWidth, + int picHeight, int stride, int interleave, + int format, int endian, int packed); + +int LoadYuvPartialImageHelperFormat(osal_file_t *yuvFp, Uint8 *pYuv, PhysicalAddress addrY, + PhysicalAddress addrCb, PhysicalAddress addrCr, int picWidth, int picHeight, + int picHeightPartial, int stride, int interleave, int format, int endian, + int partPosIdx, int frameIdx, int packed); + +int SaveYuvImageHelperFormat(osal_file_t *yuvFp, Uint8 *pYuv, + PhysicalAddress addrY, PhysicalAddress addrCb, + PhysicalAddress addrCr, int picWidth, + int picHeight, int stride, int interLeave, + int format, int endian, int packed); + +int SaveYuvPartialImageHelperFormat(osal_file_t *yuvFp, Uint8 *pYuv, PhysicalAddress addrY, + PhysicalAddress addrCb, PhysicalAddress addrCr, int picWidth, int picHeight, + int picHeightPartial, int stride, int interLeave, int format, int endian, + int partPosIdx, int frameIdx, int packed); + +unsigned int GetFrameBufSize(int framebufFormat, int picWidth, int picHeight); +void GetMcuUnitSize(int format, int *mcuWidth, int *mcuHeight); + +typedef enum { + YUV444, + YUV422, + YUV420, + NV12, + NV21, + YUV400, + YUYV, + YVYU, + UYVY, + VYUY, + YYY, + RGB_PLANAR, + RGB32, + RGB24, + RGB16 +} yuv2rgb_color_format; + +void jpu_yuv2rgb(int width, int height, yuv2rgb_color_format format, + unsigned char *src, unsigned char *rgba, int chroma_reverse); +yuv2rgb_color_format +convert_jpuapi_format_to_yuv2rgb_color_format(int planar_format, + int pack_format, int interleave); + +int comparateYuv(Uint8 *pYuv, Uint8 *pRefYuv, int picWidth, int picHeight, + int stride, int interleave, int format, int endian, + int packed); +#if defined(__cplusplus) +} +#endif + +#endif //#ifndef _JPU_HELPER_H_ diff --git a/u-boot-2021.10/drivers/jpeg/jpulog.h b/u-boot-2021.10/drivers/jpeg/jpulog.h new file mode 100644 index 000000000..70e7e1973 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpulog.h @@ -0,0 +1,79 @@ +#ifndef _JPU_LOG_H_ +#define _JPU_LOG_H_ + +#include +#include +#include +#include +#include + +enum { NONE = 0, INFO, WARN, ERR, TRACE, MAX_LOG_LEVEL }; + +enum { + LOG_HAS_DAY_NAME = 1, /**< Include day name [default: no] */ + LOG_HAS_YEAR = 2, /**< Include year digit [no] */ + LOG_HAS_MONTH = 4, /**< Include month [no] */ + LOG_HAS_DAY_OF_MON = 8, /**< Include day of month [no] */ + LOG_HAS_TIME = 16, /**< Include time [yes] */ + LOG_HAS_MICRO_SEC = 32, /**< Include microseconds [yes] ......*/ + LOG_HAS_FILE = 64, /**< Include sender in the log [yes] */ + LOG_HAS_NEWLINE = 128, /**< Terminate each call with newline [yes] .*/ + LOG_HAS_CR = 256, /**< Include carriage return [no] */ + LOG_HAS_SPACE = 512, /**< Include two spaces before log[yes] ..*/ + LOG_HAS_COLOR = 1024, /**< Colorize logs [yes on win32] */ + LOG_HAS_LEVEL_TEXT = 2048 /**< Include level text string [no] */ +}; + +enum { + TERM_COLOR_R = 2, /**< Red */ + TERM_COLOR_G = 4, /**< Green */ + TERM_COLOR_B = 1, /**< Blue. */ + TERM_COLOR_BRIGHT = 8 /**< Bright mask. */ +}; + +#define MAX_PRINT_LENGTH 512 +#ifdef ANDROID +#include +#undef LOG_NDEBUG +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "JPUAPI" +#endif + +#define JLOG LogMsg + +#define LOG_ENABLE_FILE SetLogDecor(GetLogDecor() | LOG_HAS_FILE) + +#if defined(__cplusplus) +extern "C" { +#endif + +int InitLog(void); +void DeInitLog(void); + +void SetMaxLogLevel(int level); +int GetMaxLogLevel(void); + +void SetLogColor(int level, int color); +int GetLogColor(int level); + +void SetLogDecor(int decor); +int GetLogDecor(void); + +#define JLOG_LEVEL ERR + +#define LogMsg(level, msg, ...) \ + if (JLOG_LEVEL <= (level)) \ + printf("%s = %d, " msg, __func__, __LINE__, ##__VA_ARGS__) + +void timer_stop(void); +double timer_elapsed_us(void); +double timer_elapsed_ms(void); +int timer_is_valid(void); +double timer_frequency(void); + +#if defined(__cplusplus) +} +#endif + +#endif //#ifndef _JPU_LOG_H_ \ No newline at end of file diff --git a/u-boot-2021.10/drivers/jpeg/jpurun.c b/u-boot-2021.10/drivers/jpeg/jpurun.c new file mode 100644 index 000000000..d7b07c6b2 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpurun.c @@ -0,0 +1,704 @@ +#include "jpuapi.h" +#include "jpuapifunc.h" +#include "jpuhelper.h" +#include "jpulog.h" +#include "jpurun.h" +#include "mixer.h" +#include "regdefine.h" +#include +#include "asm/cache.h" + +#ifdef JPU_FPGA_PLATFORM +//#define ENC_SOURCE_FRAME_DISPLAY +#endif + +#define NUM_FRAME_BUF MAX_FRAME +#define MAX_ROT_BUF_NUM 1 +#define EXTRA_FRAME_BUFFER_NUM 0 +#define ENC_SRC_BUF_NUM 1 +//#define ROI_RANDOM_TEST +//#define TEST_JPEG_PERFORMANCE + +#ifdef TEST_JPEG_PERFORMANCE +#undef __CONFIG_H__ + +#include "fw_config.h" +#include "system_common.h" +#include "dm/device.h" +#include "timer.h" +#endif + +#define ALIGN_N_BIT(ADDR, BITS) ((((ADDR) + ((1 << (BITS)) - 1)) >> (BITS)) << (BITS)) + +int img_width, img_height; + +int copy_to_dest_addr(Uint8 *pYuv, Uint8 *pRefYuv, + int picWidth, int picHeight, int strideY, int strideC, + int interleave, int format, int endian, int packed) +{ + int size = 0; + int nY = 0; + Uint8 *pRef = NULL; + int lumaSize = 0, chromaSize = 0; + + Uint8 *pOrg = NULL; + + switch (format) { + case FORMAT_420: + nY = (picHeight + 1) / 2 * 2; + chromaSize = ((picWidth + 1) / 2) * ((picHeight + 1) / 2); + break; + case FORMAT_224: + nY = (picHeight + 1) / 2 * 2; + chromaSize = (picWidth) * ((picHeight + 1) / 2); + break; + case FORMAT_422: + nY = picHeight; + chromaSize = ((picWidth + 1) / 2) * picHeight; + break; + case FORMAT_444: + nY = picHeight; + chromaSize = picWidth * picHeight; + break; + case FORMAT_400: + nY = picHeight; + chromaSize = 0; + break; + } + + pRef = pRefYuv; + pOrg = pYuv; + + if (packed) { + if (packed == PACKED_FORMAT_444) + picWidth *= 3; + else + picWidth *= 2; + + lumaSize = picWidth * nY; + chromaSize = 0; + } else { + if (format == FORMAT_420) { + lumaSize = strideY * nY; + chromaSize = strideC * ((picHeight + 1) / 2); + } else { + lumaSize = picWidth * nY; + } + } + + CVI_JPG_DBG("nY = %d, picHeight = %d\n", nY, picHeight); + CVI_JPG_DBG("strideY = %d, lumaSize = 0x%X\n", strideY, lumaSize); + CVI_JPG_DBG("strideC = %d, chromaSize = 0x%X\n", strideC, chromaSize); + + size = lumaSize + chromaSize * 2; + + CVI_JPG_DBG("size = 0x%X, lumaSize = 0x%X, chromaSize = 0x%X\n", size, lumaSize, chromaSize); + + CVI_JPG_DBG("y, pRef = %p, pOrg = %p\n", pRef, pOrg); + OSAL_MEMCPY(pRef, pOrg, lumaSize); + + pOrg += lumaSize; + pRef += lumaSize; + pRef = (Uint8 *)ALIGN_N_BIT((unsigned long long)pRef, 12); + CVI_JPG_DBG("u, pRef = %p, pOrg = %p\n", pRef, pOrg); + OSAL_MEMCPY(pRef, pOrg, chromaSize); + + pOrg += chromaSize; + pRef += chromaSize; + pRef = (Uint8 *)ALIGN_N_BIT((unsigned long long)pRef, 12); + CVI_JPG_DBG("v, pRef = %p, pOrg = %p\n", pRef, pOrg); + OSAL_MEMCPY(pRef, pOrg, chromaSize); + + //flush_dcache_all(); + flush_dcache_range((unsigned long)pRefYuv, (unsigned long)pRefYuv + lumaSize + chromaSize + chromaSize); + + return 0; +} + +int jpeg_decode_helper(DecConfigParam *param) +{ + JpgDecHandle handle = {0}; + JpgDecOpenParam decOP = {0}; + JpgDecInitialInfo initialInfo = {0}; + JpgDecOutputInfo outputInfo = {0}; + JpgDecParam decParam = {0}; + JpgRet ret = JPG_RET_SUCCESS; + FrameBuffer frameBuf[NUM_FRAME_BUF]; + jpu_buffer_t vbStream = {0}; + BufInfo bufInfo = {0}; + FRAME_BUF * pFrame[NUM_FRAME_BUF]; + Uint32 framebufWidth = 0, framebufHeight = 0; + Uint32 framebufStrideY = 0, framebufStrideC = 0; + Uint32 framebufFormat = FORMAT_420; + int dispWidth = 0, dispHeight = 0; + int i = 0, frameIdx = 0, ppIdx = 0, saveIdx = 0, totalNumofErrMbs = 0, streameos = 0, dispImage = 0; + int suc = 1; + Uint8 *pRefYuvBuf = NULL; + int needFrameBufCount = 0, regFrameBufCount = 0; + int rotEnable = 0; + int int_reason = 0; + int instIdx; + int partPosIdx = 0; + int partBufIdx = 0; + int partMaxIdx = 0; + int partialHeight = 0; + int jpeg_done = 0; + + DecConfigParam decConfig; + + memcpy(&decConfig, param, sizeof(DecConfigParam)); + memset(&pFrame, 0x00, sizeof(FRAME_BUF *) * NUM_FRAME_BUF); + memset(&frameBuf, 0x00, sizeof(FrameBuffer) * NUM_FRAME_BUF); + + instIdx = decConfig.instNum; + if (decConfig.usePartialMode && decConfig.roiEnable) { + JLOG(ERR, "Invalid operation mode : partial and ROI mode can not be worked\n"); + goto ERR_DEC_INIT; + } + + if (decConfig.packedFormat && decConfig.roiEnable) { + JLOG(ERR, "Invalid operation mode : packed mode and ROI mode can not be worked\n"); + goto ERR_DEC_INIT; + } + + if ((decConfig.iHorScaleMode || decConfig.iVerScaleMode) && decConfig.roiEnable) { + JLOG(ERR, "Invalid operation mode : Scaler mode and ROI mode can not be worked\n"); + goto ERR_DEC_INIT; + } + + if (decConfig.useRot && decConfig.roiEnable) { + JLOG(ERR, "Invalid operation mode : Rotator mode and ROI mode can not be worked\n"); + goto ERR_DEC_INIT; + } + + if (!decConfig.yuvFileName) + dispImage = 0; + else + dispImage = 1; + + decConfig.comparatorFlag = param->comparatorFlag; + + pRefYuvBuf = (Uint8 *)decConfig.yuv_addr; + bufInfo.buf = (Uint8 *)decConfig.bs_addr; + bufInfo.size = decConfig.size; + bufInfo.point = 0; + + ret = JPU_Init(); + + if (ret != JPG_RET_SUCCESS && ret != JPG_RET_CALLED_BEFORE) { + suc = 0; + JLOG(ERR, "JPU_Init failed Error code is 0x%x\n", ret); + goto ERR_DEC_INIT; + } + + // Open an instance and get initial information for decoding. + + vbStream.size = STREAM_BUF_SIZE; + if (jdi_allocate_dma_memory(&vbStream) < 0) { + JLOG(ERR, "fail to allocate bitstream buffer\n"); + goto ERR_DEC_INIT; + } + + decOP.streamEndian = decConfig.StreamEndian; + decOP.frameEndian = decConfig.FrameEndian; + decOP.chroma_interleave = (CbCrInterLeave)decConfig.chroma_interleave; + decOP.bitstreamBuffer = vbStream.phys_addr; + decOP.bitstreamBufferSize = vbStream.size; + decOP.pBitStream = (BYTE *)vbStream.virt_addr; // set virtual address mapped of physical address + decOP.packedFormat = decConfig.packedFormat; + decOP.roiEnable = decConfig.roiEnable; + decOP.roiOffsetX = decConfig.roiOffsetX; + decOP.roiOffsetY = decConfig.roiOffsetY; + decOP.roiWidth = decConfig.roiWidth; + decOP.roiHeight = decConfig.roiHeight; + + decParam.scaleDownRatioWidth = decConfig.iHorScaleMode; + decParam.scaleDownRatioHeight = decConfig.iVerScaleMode; + + JLOG(INFO, "scale ratio:%d, %d\n", decParam.scaleDownRatioWidth, decParam.scaleDownRatioHeight); + + ret = JPU_DecOpen(&handle, &decOP); + + if (ret != JPG_RET_SUCCESS) { + JLOG(ERR, "JPU_DecOpen failed Error code is 0x%x\n", ret); + goto ERR_DEC_INIT; + } + + // JPU_DecGiveCommand(handle, ENABLE_LOGGING, NULL); + + if (decConfig.useRot) + rotEnable = 1; + else + rotEnable = 0; + + ret = WriteJpgBsBufHelper(handle, &bufInfo, decOP.bitstreamBuffer, + decOP.bitstreamBuffer + decOP.bitstreamBufferSize, + 0, 0, &streameos, decOP.streamEndian); + + //flush_dcache_all(); + flush_dcache_range(decOP.bitstreamBuffer, decOP.bitstreamBuffer + decOP.bitstreamBufferSize); + + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, "WriteBsBufHelper failed Error code is 0x%x\n", ret); + goto ERR_DEC_OPEN; + } + + ret = JPU_DecGetInitialInfo(handle, &initialInfo); + + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, "JPU_DecGetInitialInfo failed Error code is 0x%x, inst=%d\n", ret, instIdx); + goto ERR_DEC_OPEN; + } + + if (decConfig.usePartialMode) { + // disable Rotator, Scaler + rotEnable = 0; + decConfig.iHorScaleMode = 0; + decConfig.iVerScaleMode = 0; + partialHeight = (initialInfo.sourceFormat == FORMAT_420 || initialInfo.sourceFormat == FORMAT_224) ? + 16 : 8; + + partMaxIdx = ((initialInfo.picHeight + 15) & ~15) / partialHeight; + + if (partMaxIdx < decConfig.partialBufNum) + decConfig.partialBufNum = partMaxIdx; + } + img_width = initialInfo.picWidth; + img_height = initialInfo.picHeight; + + JLOG(INFO, "init info width: %d, height = %d\n", initialInfo.picWidth, initialInfo.picHeight); + + if (initialInfo.sourceFormat == FORMAT_420 || initialInfo.sourceFormat == FORMAT_422) + framebufWidth = ((initialInfo.picWidth + 15) / 16) * 16; + else + framebufWidth = ((initialInfo.picWidth + 7) / 8) * 8; + + if (initialInfo.sourceFormat == FORMAT_420 || initialInfo.sourceFormat == FORMAT_224) + framebufHeight = ((initialInfo.picHeight + 15) / 16) * 16; + else + framebufHeight = ((initialInfo.picHeight + 7) / 8) * 8; + + if (decConfig.roiEnable) { + framebufWidth = initialInfo.roiFrameWidth; + framebufHeight = initialInfo.roiFrameHeight; + } + + // scaler constraint when conformance test is disable + if (framebufWidth < 128 || framebufHeight < 128) { + if (decConfig.iHorScaleMode || decConfig.iVerScaleMode) + JLOG(WARN, + "Invalid operation mode : Not supported resolution with Scaler, width=%d, height=%d\n", + framebufWidth, framebufHeight); + decConfig.iHorScaleMode = 0; + decConfig.iVerScaleMode = 0; + } + + JLOG(INFO, "* Dec InitialInfo =>\n instance #%d,\n minframeBuffercount: %u\n", + instIdx, initialInfo.minFrameBufferCount); + JLOG(INFO, "picWidth: %u\n picHeight: %u\n roiWidth: %u\n rouHeight: %u\n", + initialInfo.picWidth, initialInfo.picHeight, initialInfo.roiFrameWidth, initialInfo.roiFrameHeight); + + if (decConfig.usePartialMode) { + JLOG(INFO, "Partial Mode Enable\n "); + JLOG(INFO, "Num of Buffer for Partial : %d\n ", decConfig.partialBufNum); + JLOG(INFO, "Num of Line for Partial : %d\n ", partialHeight); + } + + framebufFormat = initialInfo.sourceFormat; + framebufWidth >>= decConfig.iHorScaleMode; + framebufHeight >>= decConfig.iVerScaleMode; + + if (decConfig.iHorScaleMode || decConfig.iVerScaleMode) { + framebufHeight = ((framebufHeight + 1) / 2) * 2; + framebufWidth = ((framebufWidth + 1) / 2) * 2; + } + + dispWidth = (decConfig.rot_angle == 90 || decConfig.rot_angle == 270) ? framebufHeight : framebufWidth; + dispHeight = (decConfig.rot_angle == 90 || decConfig.rot_angle == 270) ? framebufWidth : framebufHeight; + + if (decConfig.rot_angle == 90 || decConfig.rot_angle == 270) { + framebufStrideY = framebufHeight; + framebufHeight = framebufWidth; + framebufFormat = (framebufFormat == FORMAT_422) ? FORMAT_224 : + (framebufFormat == FORMAT_224) ? FORMAT_422 : framebufFormat; + } else { + framebufStrideY = framebufWidth; + } + + framebufStrideC = framebufStrideY / 2; + printf("framebufStrideY = %d, framebufStrideC = %d\n", framebufStrideY, framebufStrideC); + + if (decConfig.iHorScaleMode || decConfig.iVerScaleMode) + framebufStrideY = ((framebufStrideY + 15) / 16) * 16; + + if (decOP.packedFormat >= PACKED_FORMAT_422_YUYV && decOP.packedFormat <= PACKED_FORMAT_422_VYUY) { + framebufStrideY = framebufStrideY * 2; + framebufFormat = FORMAT_422; + if (decConfig.rot_angle == 90 || decConfig.rot_angle == 270) + framebufFormat = FORMAT_224; + + } else if (decOP.packedFormat == PACKED_FORMAT_444) { + framebufStrideY = framebufStrideY * 3; + framebufFormat = FORMAT_444; + } else if (decOP.packedFormat == PACKED_FORMAT_NONE) { +#ifdef ALIGN_32 + if (framebufFormat == FORMAT_420) { + framebufStrideY = ALIGN_X(framebufStrideY, 32); + framebufStrideC = ALIGN_X(framebufStrideY / 2, 32); + } +#endif + } + + JLOG(INFO, "framebufStrideY = %d, framebufHeight = %d\n", framebufStrideY, framebufHeight); + JLOG(INFO, "framebufFormat = %d, packedFormat = %d\n", framebufFormat, decOP.packedFormat); + JLOG(INFO, "display width: %d, height = %d\n", dispWidth, dispHeight); + + // Allocate frame buffer + regFrameBufCount = initialInfo.minFrameBufferCount + EXTRA_FRAME_BUFFER_NUM; + + if (decConfig.usePartialMode) { + if (decConfig.partialBufNum > 4) + decConfig.partialBufNum = 4; + + regFrameBufCount *= decConfig.partialBufNum; + } + + needFrameBufCount = regFrameBufCount; + + AllocateFrameBuffer(instIdx, framebufFormat, framebufStrideY, + framebufHeight, needFrameBufCount, 0, framebufStrideC); + + JpgEnterLock(); + + for (i = 0; i < needFrameBufCount; ++i) { + pFrame[i] = GetFrameBuffer(instIdx, i); + frameBuf[i].bufY = pFrame[i]->vb_y.phys_addr; + JLOG(INFO, "frame buffer Y addr: 0x%lx\n", frameBuf[i].bufY); + frameBuf[i].bufCb = pFrame[i]->vb_cb.phys_addr; + JLOG(INFO, "frame buffer Cb addr: 0x%lx\n", frameBuf[i].bufCb); + + if (decOP.chroma_interleave == CBCR_SEPARATED) { + frameBuf[i].bufCr = pFrame[i]->vb_cr.phys_addr; + JLOG(INFO, "frame buffer Cr addr: 0x%lx\n", frameBuf[i].bufCr); + } + + if (dispImage) { + clear_frame_buffer(instIdx, i); + JLOG(INFO, "."); + } + } + + JpgLeaveLock(); + + ret = JPU_DecGiveCommand(handle, SET_JPG_USE_PARTIAL_MODE, &decConfig.usePartialMode); + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, "JPU_DecGiveCommand[SET_JPG_USE_PARTIAL_MODE] failed Error code is 0x%x\n", ret); + goto ERR_DEC_OPEN; + } + + ret = JPU_DecGiveCommand(handle, SET_JPG_PARTIAL_FRAME_NUM, &decConfig.partialBufNum); + + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, "JPU_DecGiveCommand[SET_JPG_PARTIAL_FRAME_NUM] failed Error code is 0x%x\n", ret); + goto ERR_DEC_OPEN; + } + + ret = JPU_DecGiveCommand(handle, SET_JPG_PARTIAL_LINE_NUM, &partialHeight); + + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, "JPU_DecGiveCommand[SET_JPG_PARTIAL_LINE_NUM] failed Error code is 0x%x\n", ret); + goto ERR_DEC_OPEN; + } + + // Register frame buffers requested by the decoder. + ret = JPU_DecRegisterFrameBuffer(handle, frameBuf, regFrameBufCount, framebufStrideY, framebufStrideC); + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, "JPU_DecRegisterFrameBuffer failed Error code is 0x%x\n", ret); + goto ERR_DEC_OPEN; + } + + ppIdx = 0; + + while (1) { +#ifdef TEST_JPEG_PERFORMANCE + u64 now = timer_get_tick(); // get_timer(0); + u64 time_consume = 0; +#endif + if (rotEnable) { + JPU_DecGiveCommand(handle, SET_JPG_ROTATION_ANGLE, &decConfig.rot_angle); + JPU_DecGiveCommand(handle, SET_JPG_MIRROR_DIRECTION, &decConfig.mirDir); + JPU_DecGiveCommand(handle, SET_JPG_ROTATOR_OUTPUT, &frameBuf[ppIdx]); + JPU_DecGiveCommand(handle, SET_JPG_ROTATOR_STRIDE, &framebufStrideY); + JPU_DecGiveCommand(handle, ENABLE_JPG_ROTATION, 0); + JPU_DecGiveCommand(handle, ENABLE_JPG_MIRRORING, 0); + } + + JPU_DecGiveCommand(handle, SET_JPG_SCALE_HOR, &decConfig.iHorScaleMode); + JPU_DecGiveCommand(handle, SET_JPG_SCALE_VER, &decConfig.iVerScaleMode); + + if (decConfig.usePartialMode) { + partPosIdx = 0; + partBufIdx = 0; + outputInfo.decodingSuccess = 0; + JPU_SWReset(); + } + + // Start decoding a frame. + ret = JPU_DecStartOneFrame(handle, &decParam); + + if (ret != JPG_RET_SUCCESS && ret != JPG_RET_EOS) { + if (ret == JPG_RET_BIT_EMPTY) { + ret = WriteJpgBsBufHelper(handle, &bufInfo, decOP.bitstreamBuffer, + decOP.bitstreamBuffer + decOP.bitstreamBufferSize, + STREAM_FILL_SIZE, 0, &streameos, decOP.streamEndian); + + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, "WriteBsBufHelper failed Error code is 0x%x\n", ret); + goto ERR_DEC_OPEN; + } + continue; + } + + suc = 0; + JLOG(ERR, "JPU_DecStartOneFrame failed Error code is 0x%x\n", ret); + goto ERR_DEC_OPEN; + } + + if (ret == JPG_RET_EOS) + goto JPU_END_OF_STREAM; + + while (1) { + int_reason = JPU_WaitInterrupt(JPU_INTERRUPT_TIMEOUT_MS); + + if (int_reason == -1) { + JLOG(ERR, "Error : timeout happened\n"); + JPU_SWReset(); + break; + } + + if (decConfig.usePartialMode && (int_reason & 0xf0)) { + partBufIdx = ((partPosIdx) % decConfig.partialBufNum); + + if ((1 << partBufIdx) & ((int_reason & 0xf0) >> 4)) { + printf("DECODED : PARTIAL BUFFER IDX %d / POS %d / MAX POS %d / INT_REASON=0x%x\n", + partBufIdx, partPosIdx + 1, partMaxIdx, int_reason); + + if (dispImage) { +// p_disp_frame = FindFrameBuffer(instIdx, +// frameBuf[partBufIdx].bufY); +#ifdef JPU_FPGA_PLATFORM + set_mixer_dec_out_frame(p_disp_frame, framebufStrideY, partialHeight); +#endif + } + + partPosIdx++; + JPU_ClrStatus((1 << (INT_JPU_PARIAL_BUF0_EMPTY + partBufIdx))); + + continue; + } else { + suc = 0; + JLOG(ERR, + "Invalid partial interrupt : expected reason =0x%x, actual reason=0x%x\n", + (1 << partBufIdx), ((int_reason & 0xF0) >> 4)); + goto ERR_DEC_OPEN; + } + } + + if (int_reason & (1 << INT_JPU_DONE)) { + // Must catch PIC_DONE interrupt before catching EMPTY interrupt + // Do no clear INT_JPU_DONE and INT_JPU_ERROR interrupt. + // these will be cleared in JPU_DecGetOutputInfo. + JLOG(INFO, "jpeg done\n"); + jpeg_done = 1; + break; + } + + if (int_reason & (1 << INT_JPU_ERROR)) { + // Must catch PIC_DONE interrupt before catching EMPTY interrupt + // Do no clear INT_JPU_DONE and INT_JPU_ERROR interrupt. + // these will be cleared in JPU_DecGetOutputInfo. + break; + } + + if (int_reason & (1 << INT_JPU_BIT_BUF_EMPTY)) { + ret = WriteJpgBsBufHelper(handle, &bufInfo, decOP.bitstreamBuffer, + decOP.bitstreamBuffer + decOP.bitstreamBufferSize, + STREAM_FILL_SIZE, 0, &streameos, decOP.streamEndian); + printf("write buffer in empty intterupt!\n\n"); + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, + "WriteBsBufHelper failed Error code is 0x%x\n", + ret); + goto ERR_DEC_OPEN; + } + JPU_ClrStatus((1 << INT_JPU_BIT_BUF_EMPTY)); + } + + if (int_reason & (1 << INT_JPU_BIT_BUF_STOP)) { + ret = JPU_DecCompleteStop(handle); + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, "JPU_DecCompleteStop failed Error code is 0x%x\n", ret); + goto ERR_DEC_OPEN; + } + JPU_ClrStatus((1 << INT_JPU_BIT_BUF_STOP)); + break; + } + + if (int_reason & (1 << INT_JPU_PARIAL_OVERFLOW)) + JPU_ClrStatus((1 << INT_JPU_PARIAL_OVERFLOW)); + } + +JPU_END_OF_STREAM: + ret = JPU_DecGetOutputInfo(handle, &outputInfo); + + if (ret != JPG_RET_SUCCESS) { + suc = 0; + JLOG(ERR, "JPU_DecGetOutputInfo failed Error code is 0x%x\n", ret); + goto ERR_DEC_OPEN; + } + +#ifdef TEST_JPEG_PERFORMANCE + time_consume = timer_get_tick(); + JLOG(INFO, "time_consume: %ld\n", (time_consume - now) / TIMER_CNT_US); +#endif + +#ifdef MJPEG_ERROR_CONCEAL + if (outputInfo.numOfErrMBs) { + int err_rst_idx, errPosX, errPosY; + + err_rst_idx = (outputInfo.numOfErrMBs & 0x0F000000) >> 24; + errPosX = (outputInfo.numOfErrMBs & 0x00FFF000) >> 12; + errPosY = (outputInfo.numOfErrMBs & 0x00000FFF); + JLOG(ERR, + "Error restart Idx : %d, MCU x:%d, y:%d, in Frame : %d\n", + err_rst_idx, errPosX, errPosY, frameIdx); + continue; + } +#endif + + if (outputInfo.decodingSuccess == 0) + JLOG(ERR, "JPU_DecGetOutputInfo decode fail framdIdx %d\n", frameIdx); + + JLOG(INFO, + "#%d:%d, indexFrameDisplay %d || consumedByte %d || ppIdx %d || frameStart=0x%x || ecsStart=0x%x\n", + instIdx, frameIdx, outputInfo.indexFrameDisplay, outputInfo.consumedByte, + ppIdx, outputInfo.bytePosFrameStart, outputInfo.bytePosFrameStart + outputInfo.ecsPtr); + + JLOG(INFO, "rdPtr=0x%x || wrPtr=0x%x || pos=%d\n", + JpuReadReg(MJPEG_BBC_RD_PTR_REG), + JpuReadReg(MJPEG_BBC_WR_PTR_REG), + JpuReadReg(MJPEG_BBC_CUR_POS_REG)); + + if (outputInfo.indexFrameDisplay == -1) + break; + + // YUV Dump Done when partial buffer is all displayed. + int_reason = JPU_GetStatus(); + + if (decConfig.usePartialMode && !(int_reason & 0xF0)) + goto SKIP_BUF_DUMP; + + // indexFrameDisplay points to the frame buffer, among ones + // registered, which holds the output of the decoder. + if (dispImage) { +#ifdef JPU_FPGA_PLATFORM + if (frameIdx) + wait_mixer_int(); +#endif + if (!rotEnable) { +#ifdef JPU_FPGA_PLATFORM + set_mixer_dec_out_frame(p_disp_frame, outputInfo.decPicWidth, outputInfo.decPicHeight); +#endif + } else { +#ifdef JPU_FPGA_PLATFORM + set_mixer_dec_out_frame(p_disp_frame, + (decConfig.rot_angle == 90 || decConfig.rot_angle == 270) + ? outputInfo.decPicHeight : outputInfo.decPicWidth, + (decConfig.rot_angle == 90 || decConfig.rot_angle == 270) + ? outputInfo.decPicWidth : outputInfo.decPicHeight); +#endif + + ppIdx = (ppIdx - regFrameBufCount + 1) % MAX_ROT_BUF_NUM; + } + } else if (decConfig.comparatorFlag != 0) { + JLOG(INFO, "compare yuv, frameBuf[%d].bufY = 0x%lx\n", saveIdx, frameBuf[saveIdx].bufY); + JLOG(INFO, "width:%d, height:%d\n", dispWidth, dispHeight); + + saveIdx = ppIdx; + if (comparateYuv((Uint8 *)frameBuf[saveIdx].bufY, pRefYuvBuf, + dispWidth, dispHeight, framebufStrideY, (int)decOP.chroma_interleave, + framebufFormat, 0, decOP.packedFormat) != 0) { + suc = 0; + } + + JLOG(INFO, "compare result: %d\n", 1 - suc); + + if (suc) + JLOG(ERR, "compare pass\n"); + + ppIdx = (ppIdx - regFrameBufCount + 1) % MAX_ROT_BUF_NUM; + } + + copy_to_dest_addr((Uint8 *)frameBuf[saveIdx].bufY, pRefYuvBuf, + dispWidth, dispHeight, framebufStrideY, framebufStrideC, + (int)decOP.chroma_interleave, framebufFormat, 0, decOP.packedFormat); + +SKIP_BUF_DUMP: + if (outputInfo.numOfErrMBs) { + int err_rst_idx, errPosX, errPosY; + + err_rst_idx = (outputInfo.numOfErrMBs & 0x0F000000) >> 24; + errPosX = (outputInfo.numOfErrMBs & 0x00FFF000) >> 12; + errPosY = (outputInfo.numOfErrMBs & 0x00000FFF); + JLOG(ERR, + "Error restart Idx : %d, MCU x:%d, y:%d, in Frame : %d\n", + err_rst_idx, errPosX, errPosY, frameIdx); + } + frameIdx++; + + if (decConfig.outNum && frameIdx == decConfig.outNum) + break; + } + + if (totalNumofErrMbs) { + suc = 0; + JLOG(ERR, "Total Num of Error MBs : %d\n", totalNumofErrMbs); + } + +ERR_DEC_OPEN: + // Now that we are done with decoding, close the open instance. + ret = JPU_DecClose(handle); + + JLOG(INFO, "Dec End. Tot Frame %d\n", frameIdx); + +ERR_DEC_INIT: + free_frame_buffer(instIdx); + + jdi_free_dma_memory(&vbStream); + + JPU_DeInit(); + + if (jpeg_done == 1) { + JLOG(INFO, "decode test done\n"); + } + + return suc; +} + +int get_jpeg_size(int *width_addr, int *height_addr) +{ + *width_addr = img_width; + *height_addr = img_height; + + return 0; +} + diff --git a/u-boot-2021.10/drivers/jpeg/jpurun.h b/u-boot-2021.10/drivers/jpeg/jpurun.h new file mode 100644 index 000000000..247276a4d --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jpurun.h @@ -0,0 +1,114 @@ +#ifndef _JPU_RUN_H_ +#define _JPU_RUN_H_ +#include "jpuconfig.h" + +#define MAX_FILE_PATH 256 + +typedef struct { + unsigned char *buf; + int size; + int point; + int count; + int fillendbs; +} BufInfo; + +typedef struct { + char *yuvFileName; + char *bitstreamFileName; + char *huffFileName; + char *qMatFileName; + char *qpFileName; + char *cfgFileName; + int picWidth; + int picHeight; + int rot_angle; + int mirDir; + int useRot; + int mjpgChromaFormat; + int outNum; + int instNum; + int roiEnable; + + int StreamEndian; + int FrameEndian; + int chroma_interleave; + int bEnStuffByte; + + // altek requirement + int encHeaderMode; + + char *strStmDir; + char *strCfgDir; + int usePartialMode; + int partialBufNum; + int partialHeight; + int packedFormat; + int RandRotMode; + int compareJpg; +} EncConfigParam; + +typedef struct { + char *yuvFileName; + char *bitstreamFileName; + int comparatorFlag; + int rot_angle; + int mirDir; + int useRot; + int outNum; + int checkeos; + int instNum; + int StreamEndian; + int FrameEndian; + int chroma_interleave; + int iHorScaleMode; + int iVerScaleMode; + + // ROI + int roiEnable; + int roiWidth; + int roiHeight; + int roiOffsetX; + int roiOffsetY; + int roiWidthInMcu; + int roiHeightInMcu; + int roiOffsetXInMcu; + int roiOffsetYInMcu; + + // packed + int packedFormat; + + int usePartialMode; + int partialBufNum; + + int partialHeight; + int filePlay; + + int size; + void *bs_addr; + void *yuv_addr; +} DecConfigParam; + +enum { STD_JPG_ENC }; + +typedef struct { + int codecMode; + int numMulti; + int saveYuv; + int multiMode[MAX_NUM_INSTANCE]; + char *multiFileName[MAX_NUM_INSTANCE]; + char *multiYuvFileName[MAX_NUM_INSTANCE]; + EncConfigParam encConfig[MAX_NUM_INSTANCE]; + DecConfigParam decConfig[MAX_NUM_INSTANCE]; +} MultiConfigParam; + +#if defined(__cplusplus) +extern "C" { +#endif +int jpeg_decode_helper(DecConfigParam *param); +int EncodeTest(EncConfigParam *param); +int MultiInstanceTest(MultiConfigParam *param); +int get_jpeg_size(int *width_addr, int *height_addr); +#if defined(__cplusplus) +} +#endif +#endif /* _JPU_RUN_H_ */ diff --git a/u-boot-2021.10/drivers/jpeg/jputable.h b/u-boot-2021.10/drivers/jpeg/jputable.h new file mode 100644 index 000000000..cb174093c --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jputable.h @@ -0,0 +1,125 @@ +#ifndef _JPU_TABLE_H_ +#define _JPU_TABLE_H_ + +static unsigned char lumaDcBits[16] = { + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static unsigned char lumaDcValue[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x00, 0x00, 0x00, 0x00, +}; + +static unsigned char lumaAcBits[16] = { + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, +}; + +static unsigned char lumaAcValue[168] = { + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static unsigned char chromaDcBits[16] = { + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static unsigned char chromaDcValue[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x00, 0x00, 0x00, 0x00, +}; + +static unsigned char chromaAcBits[16] = { + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, +}; + +static unsigned char chromaAcValue[168] = { + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#ifdef NOT_USED +static unsigned char lumaQ[64] = { + 0x0C, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0C, 0x09, 0x09, 0x0C, 0x11, + 0x0B, 0x0A, 0x0B, 0x11, 0x15, 0x0F, 0x0C, 0x0C, 0x0F, 0x15, 0x18, + 0x13, 0x13, 0x15, 0x13, 0x13, 0x18, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, +}; + +static unsigned char chromaBQ[64] = { + 0x0D, 0x0B, 0x0B, 0x0D, 0x0E, 0x0D, 0x10, 0x0E, 0x0E, 0x10, 0x14, + 0x0E, 0x0E, 0x0E, 0x14, 0x14, 0x0E, 0x0E, 0x0E, 0x0E, 0x14, 0x11, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, +}; + +static unsigned char chromaRQ[64] = { + 0x0D, 0x0B, 0x0B, 0x0D, 0x0E, 0x0D, 0x10, 0x0E, 0x0E, 0x10, 0x14, + 0x0E, 0x0E, 0x0E, 0x14, 0x14, 0x0E, 0x0E, 0x0E, 0x0E, 0x14, 0x11, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, +}; +#endif +static unsigned char lumaQ2[64] = { + 0x06, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x05, 0x05, 0x06, 0x09, + 0x06, 0x05, 0x06, 0x09, 0x0B, 0x08, 0x06, 0x06, 0x08, 0x0B, 0x0C, + 0x0A, 0x0A, 0x0B, 0x0A, 0x0A, 0x0C, 0x10, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x10, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, +}; + +static unsigned char chromaBQ2[64] = { + 0x07, 0x07, 0x07, 0x0D, 0x0C, 0x0D, 0x18, 0x10, 0x10, 0x18, 0x14, + 0x0E, 0x0E, 0x0E, 0x14, 0x14, 0x0E, 0x0E, 0x0E, 0x0E, 0x14, 0x11, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, +}; + +#ifdef NOT_USED +static unsigned char chromaRQ2[64] = { + 0x07, 0x07, 0x07, 0x0D, 0x0C, 0x0D, 0x18, 0x10, 0x10, 0x18, 0x14, + 0x0E, 0x0E, 0x0E, 0x14, 0x14, 0x0E, 0x0E, 0x0E, 0x0E, 0x14, 0x11, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x11, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x11, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, +}; +#endif + +#endif //_JPU_TABLE_H_ \ No newline at end of file diff --git a/u-boot-2021.10/drivers/jpeg/jputypes.h b/u-boot-2021.10/drivers/jpeg/jputypes.h new file mode 100644 index 000000000..bdcf8fb0d --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/jputypes.h @@ -0,0 +1,62 @@ + +#ifndef _JPU_TYPES_H_ +#define _JPU_TYPES_H_ + +typedef unsigned int UINT; +typedef unsigned char Uint8; +typedef unsigned int Uint32; +typedef unsigned short Uint16; +typedef char Int8; +typedef int Int32; +typedef short Int16; +#if defined(_MSC_VER) +typedef unsigned _int64 Uint64; +typedef _int64 Int64; +#else +typedef unsigned long Uint64; +typedef long Int64; +#endif +typedef Uint64 PhysicalAddress; +typedef unsigned char BYTE; +typedef int BOOL; + +#ifndef HAVE_STDIN_H + +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned short uint16_t; +typedef short int16_t; +#if defined(_MSC_VER) +typedef unsigned _int64 uint64_t; +typedef _int64 int64_t; +#else +#endif + +#ifndef __int8_t_defined +typedef signed char int8_t; +#endif + +typedef int int32_t; +typedef short int16_t; + +#ifndef BYTE +typedef unsigned char BYTE; +#endif + +#ifndef BOOL +typedef int BOOL; +#endif + +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#if defined(linux) || defined(__linux) || defined(ANDROID) +#define TRUE 1 +#define FALSE 0 +#endif + +#endif /* _JPU_TYPES_H_ */ diff --git a/u-boot-2021.10/drivers/jpeg/mixer.c b/u-boot-2021.10/drivers/jpeg/mixer.c new file mode 100644 index 000000000..d1a91ee17 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/mixer.c @@ -0,0 +1,373 @@ +//#include +#include "jpuapi.h" +#include "jpuhelper.h" +#include "jpulog.h" +#include "mixer.h" +#include "regdefine.h" +#include +#include + +typedef struct { + FRAME_BUF frameBuf[MAX_FRAME]; + jpu_buffer_t vb_base; + int instIndex; + int last_num; + unsigned long last_addr; +} fb_context; + +static fb_context s_fb[MAX_NUM_INSTANCE]; + +int AllocateFrameBuffer(int instIdx, int format, int strideY, int height, + int frameBufNum, int pack, int strideC) +{ + unsigned int divX, divY; + int i; + unsigned int lum_size, chr_size; + fb_context *fb; + + fb = &s_fb[instIdx]; + + divX = format == FORMAT_420 || format == FORMAT_422 ? 2 : 1; + divY = format == FORMAT_420 || format == FORMAT_224 ? 2 : 1; + + switch (format) { + case FORMAT_420: + height = (height + 1) / 2 * 2; + strideY = (strideY + 1) / 2 * 2; + break; + case FORMAT_224: + height = (height + 1) / 2 * 2; + break; + case FORMAT_422: + strideY = (strideY + 1) / 2 * 2; + break; + case FORMAT_444: + height = (height + 1) / 2 * 2; + strideY = (strideY + 1) / 2 * 2; + break; + case FORMAT_400: + height = (height + 1) / 2 * 2; + strideY = (strideY + 1) / 2 * 2; + break; + } + + lum_size = (unsigned int)strideY * (unsigned int)height; + + if (pack) + chr_size = 0; + else { + if (format == FORMAT_420) + chr_size = strideC * height / divY; + else + chr_size = lum_size / divX / divY; + } + + fb->vb_base.size = lum_size + chr_size * 2; + fb->vb_base.size *= frameBufNum; + + if (jdi_allocate_dma_memory(&fb->vb_base) < 0) { + JLOG(ERR, "Fail to allocate frame buffer size=%d\n", fb->vb_base.size); + return 0; + } + + fb->last_addr = fb->vb_base.phys_addr; + + for (i = fb->last_num; i < fb->last_num + frameBufNum; i++) { + fb->frameBuf[i].Format = format; + fb->frameBuf[i].Index = i; + + fb->frameBuf[i].vb_y.phys_addr = fb->last_addr; + fb->frameBuf[i].vb_y.size = lum_size; + + fb->last_addr += fb->frameBuf[i].vb_y.size; + fb->last_addr = ((fb->last_addr + 7) & ~7); + + if (chr_size) { + fb->frameBuf[i].vb_cb.phys_addr = fb->last_addr; + fb->frameBuf[i].vb_cb.size = chr_size; + + fb->last_addr += fb->frameBuf[i].vb_cb.size; + fb->last_addr = ((fb->last_addr + 7) & ~7); + + fb->frameBuf[i].vb_cr.phys_addr = fb->last_addr; + fb->frameBuf[i].vb_cr.size = chr_size; + + fb->last_addr += fb->frameBuf[i].vb_cr.size; + fb->last_addr = ((fb->last_addr + 7) & ~7); + } + + fb->frameBuf[i].strideY = strideY; + if (format == FORMAT_420) + fb->frameBuf[i].strideC = strideC; + else + fb->frameBuf[i].strideC = strideY / divX; + } + + fb->last_num += frameBufNum; + + return 1; +} + +int GetFrameBufBase(int instIdx) +{ + fb_context *fb; + + fb = &s_fb[instIdx]; + + return fb->vb_base.phys_addr; +} + +int GetFrameBufAllocSize(int instIdx) +{ + fb_context *fb; + + fb = &s_fb[instIdx]; + + return (fb->last_addr - fb->vb_base.phys_addr); +} + +FRAME_BUF *GetFrameBuffer(int instIdx, int index) +{ + fb_context *fb; + + fb = &s_fb[instIdx]; + return &fb->frameBuf[index]; +} + +FRAME_BUF *find_frame_buffer(int instIdx, PhysicalAddress addrY) +{ + int i; + fb_context *fb; + + fb = &s_fb[instIdx]; + + for (i = 0; i < MAX_FRAME; i++) { + if (fb->frameBuf[i].vb_y.phys_addr == addrY) { + return &fb->frameBuf[i]; + } + } + + return NULL; +} + +void clear_frame_buffer(int instIdx, int index) +{ +} + +void free_frame_buffer(int instIdx) +{ + fb_context *fb; + + fb = &s_fb[instIdx]; + + fb->last_num = 0; + fb->last_addr = -1; + + jdi_free_dma_memory(&fb->vb_base); + fb->vb_base.base = 0; + fb->vb_base.size = 0; +} + +#ifdef JPU_FPGA_PLATFORM +//------------------------------------------------------------------------------ +// MIXER REGISTER ADDRESS +//------------------------------------------------------------------------------ +#define MIX_BASE 0x1000000 +#define DISP_MIX 0x2000000 + +#define MIX_INT (MIX_BASE + 0x044) + +#define MIX_STRIDE_Y (MIX_BASE + 0x144) +#define MIX_STRIDE_CB (MIX_BASE + 0x148) +#define MIX_STRIDE_CR (MIX_BASE + 0x14c) + +#define MIX_ADDR_Y (MIX_BASE + 0x138) +#define MIX_ADDR_CB (MIX_BASE + 0x13C) +#define MIX_ADDR_CR (MIX_BASE + 0x140) + +#define MIX_RUN (MIX_BASE + 0x120) + +#define DISP_TOTAL_SAMPLE (DISP_MIX + 0x00C) +#define DISP_ACTIVE_SAMPLE (DISP_MIX + 0x010) +#define DISP_HSYNC_START_END (DISP_MIX + 0x014) +#define DISP_VSYNC_TOP_START (DISP_MIX + 0x018) +#define DISP_VSYNC_TOP_END (DISP_MIX + 0x01C) +#define DISP_VSYNC_BOT_START (DISP_MIX + 0x020) +#define DISP_VSYNC_BOT_END (DISP_MIX + 0x024) +#define DISP_ACTIVE_REGION_TOP (DISP_MIX + 0x02C) +#define DISP_ACTIVE_REGION_BOT (DISP_MIX + 0x030) + +#define MIX_MIX_INTRPT (MIX_BASE + 0x0000) +#define MIX_SYNC_STATE (MIX_BASE + 0x0004) +#define MIX_SYNC_CTRL (MIX_BASE + 0x0008) +#define MIX_TOTAL_SAMPLE (MIX_BASE + 0x000c) +#define MIX_ACTIVE_SAMPLE (MIX_BASE + 0x0010) +#define MIX_HSYNC_START_END (MIX_BASE + 0x0014) +#define MIX_VSYNC_TOP_START (MIX_BASE + 0x0018) +#define MIX_VSYNC_TOP_END (MIX_BASE + 0x001c) +#define MIX_VSYNC_BOT_START (MIX_BASE + 0x0020) +#define MIX_VSYNC_BOT_END (MIX_BASE + 0x0024) +#define MIX_ACT_REGION_SAMPLE (MIX_BASE + 0x0028) +#define MIX_ACT_REGION_TOP (MIX_BASE + 0x002c) +#define MIX_ACT_REGION_BOT (MIX_BASE + 0x0030) +#define MIX_TOP_START (MIX_BASE + 0x0034) +#define MIX_BOT_START (MIX_BASE + 0x0038) +#define MIX_LINE_INC (MIX_BASE + 0x003c) +#define MIX_LATCH_PARAM_CTRL (MIX_BASE + 0x0040) +#define MIX_INTERRUPT (MIX_BASE + 0x0044) + +#define MIX_LAYER_CTRL (MIX_BASE + 0x0100) +#define MIX_LAYER_ORDER (MIX_BASE + 0x0104) +#define MIX_BIG_ENDIAN (MIX_BASE + 0x0108) +#define MIX_L0_BG_COLOR (MIX_BASE + 0x0110) +#define MIX_L1_CTRL (MIX_BASE + 0x0120) +#define MIX_L1_LSIZE (MIX_BASE + 0x0124) +#define MIX_L1_SSIZE (MIX_BASE + 0x0128) +#define MIX_L1_LPOS (MIX_BASE + 0x012c) +#define MIX_L1_SPOS (MIX_BASE + 0x0130) +#define MIX_L1_BG_COLOR (MIX_BASE + 0x0134) +#define MIX_L1_Y_SADDR (MIX_BASE + 0x0138) +#define MIX_L1_CB_SADDR (MIX_BASE + 0x013c) +#define MIX_L1_CR_SADDR (MIX_BASE + 0x0140) +#define MIX_L1_Y_STRIDE (MIX_BASE + 0x0144) +#define MIX_L1_CB_STRIDE (MIX_BASE + 0x0148) +#define MIX_L1_CR_STRIDE (MIX_BASE + 0x014c) + +int SetMixerDecOutFrame(FRAME_BUF *pFrame, int width, int height) +{ + int staX, staY; + int div; + + staX = (MAX_DISPLAY_WIDTH - width) / 2; + if (height > MAX_DISPLAY_HEIGHT) + staY = 0; + else + staY = (MAX_DISPLAY_HEIGHT - height) / 2; + if (staX % 16) + staX = (staX + 15) / 16 * 16; + + JpuWriteReg(MIX_L0_BG_COLOR, (0 << 16) | (0x80 << 8) | 0x80); + + JpuWriteReg(MIX_L1_LSIZE, (height << 12) | width); + JpuWriteReg(MIX_L1_SSIZE, (height << 12) | width); + JpuWriteReg(MIX_L1_LPOS, (staY << 12) | staX); + + div = (pFrame->Format == FORMAT_420 || pFrame->Format == FORMAT_422 || + pFrame->Format == FORMAT_400) + ? 2 + : 1; + + JpuWriteReg(MIX_STRIDE_Y, width); + JpuWriteReg(MIX_STRIDE_CB, width / div); + JpuWriteReg(MIX_STRIDE_CR, width / div); + + JpuWriteReg(MIX_ADDR_Y, pFrame->vb_y.phys_addr); + JpuWriteReg(MIX_ADDR_CB, pFrame->vb_cb.phys_addr); + JpuWriteReg(MIX_ADDR_CR, pFrame->vb_cr.phys_addr); + + JpuWriteReg(DISP_HSYNC_START_END, + ((0x7d7 - 40) << 12) | (0x82f - 40)); // horizontal center + JpuWriteReg(DISP_ACTIVE_REGION_TOP, ((0x014 - 2) << 12) | (0x230 - 2)); + JpuWriteReg(DISP_ACTIVE_REGION_BOT, ((0x247 - 2) << 12) | (0x463 - 2)); + + JpuWriteReg(MIX_LAYER_CTRL, 0x3); // backgroup on + JpuWriteReg(MIX_RUN, 0x92); // on, vdec, from sdram + + return 1; +} + +int SetMixerDecOutLayer(int instIdx, int index, int width, int height) +{ + FRAME_BUF *pFrame; + int staX, staY; + int div; + + pFrame = GetFrameBuffer(instIdx, index); + + staX = (MAX_DISPLAY_WIDTH - width) / 2; + if (height > MAX_DISPLAY_HEIGHT) + staY = 0; + else + staY = (MAX_DISPLAY_HEIGHT - height) / 2; + if (staX % 16) + staX = (staX + 15) / 16 * 16; + + JpuWriteReg(MIX_L0_BG_COLOR, (0 << 16) | (0x80 << 8) | 0x80); + + JpuWriteReg(MIX_L1_LSIZE, (height << 12) | width); + JpuWriteReg(MIX_L1_SSIZE, (height << 12) | width); + JpuWriteReg(MIX_L1_LPOS, (staY << 12) | staX); + + div = (pFrame->Format == FORMAT_420 || pFrame->Format == FORMAT_422 || + pFrame->Format == FORMAT_400) + ? 2 + : 1; + + JpuWriteReg(MIX_STRIDE_Y, width); + JpuWriteReg(MIX_STRIDE_CB, width / div); + JpuWriteReg(MIX_STRIDE_CR, width / div); + + JpuWriteReg(MIX_ADDR_Y, pFrame->vb_y.phys_addr); + JpuWriteReg(MIX_ADDR_CB, pFrame->vb_cb.phys_addr); + JpuWriteReg(MIX_ADDR_CR, pFrame->vb_cr.phys_addr); + + JpuWriteReg(DISP_HSYNC_START_END, ((0x7d7 - 40) << 12) | (0x82f - 40)); // horizontal center + JpuWriteReg(DISP_ACTIVE_REGION_TOP, ((0x014 - 2) << 12) | (0x230 - 2)); + JpuWriteReg(DISP_ACTIVE_REGION_BOT, ((0x247 - 2) << 12) | (0x463 - 2)); + + JpuWriteReg(MIX_LAYER_CTRL, 0x3); // backgroup on + JpuWriteReg(MIX_RUN, 0x92); // on, vdec, from sdram + + return 1; +} + +void wait_mixer_int(void) +{ + int data; + + return; + + if (JpuReadReg(MIX_INT) == 1) + JpuWriteReg(MIX_INT, 0); + + while (1) { + data = JpuReadReg(MIX_INT); + if (data & 1) + break; + } + JpuWriteReg(MIX_INT, 0); +} + +#endif + +#ifdef PLATFORM_LINUX +#include +#define FBDEV_FILENAME "/dev/fb0" + +typedef struct { + int s_fd; + unsigned char *s_scr_ptr; + unsigned char *s_rgb_ptr; + unsigned long s_product; + int s_fb_stride; + int s_fb_height; + int s_fb_width; + int s_fb_bpp; +} sw_mixer_context_t; +#endif // PLATFORM_LINUX + +int sw_mixer_open(int instIdx, int width, int height) +{ + return 0; +} + +int sw_mixer_draw(int instIdx, int x, int y, int width, int height, + int planar_format, int pack_format, int interleave, + unsigned char *pbImage) +{ + return 0; +} + +void sw_mixer_close(int instIdx) +{ +} diff --git a/u-boot-2021.10/drivers/jpeg/mixer.h b/u-boot-2021.10/drivers/jpeg/mixer.h new file mode 100644 index 000000000..96663aacd --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/mixer.h @@ -0,0 +1,47 @@ + +#ifndef _MIXER_H_ +#define _MIXER_H_ + +#include "jpuconfig.h" + +typedef struct { + int Format; + int Index; + jpu_buffer_t vb_y; + jpu_buffer_t vb_cb; + jpu_buffer_t vb_cr; + int strideY; + int strideC; +} FRAME_BUF; + +#define MAX_DISPLAY_WIDTH 1920 +#define MAX_DISPLAY_HEIGHT 1088 + +#if defined(__cplusplus) +extern "C" { +#endif + +int AllocateFrameBuffer(int instIdx, int format, int strideY, int height, + int frameBufNum, int pack, int strideC); +void free_frame_buffer(int instIdx); +FRAME_BUF *GetFrameBuffer(int instIdx, int index); +int GetFrameBufBase(int instIdx); +int GetFrameBufAllocSize(int instIdx); +void clear_frame_buffer(int instIdx, int index); +FRAME_BUF *find_frame_buffer(int instIdx, PhysicalAddress addrY); +#ifdef JPU_FPGA_PLATFORM +int SetMixerDecOutLayer(int instIdx, int index, int picX, int picY); +int SetMixerDecOutFrame(FRAME_BUF *pFrame, int width, int height); +void wait_mixer_int(void); +#endif +int sw_mixer_open(int instIdx, int width, int height); +int sw_mixer_draw(int instIdx, int x, int y, int width, int height, + int planar_format, int pack_format, int inteleave, + unsigned char *pbImage); +void sw_mixer_close(int instIdx); + +#if defined(__cplusplus) +} +#endif + +#endif //#ifndef _MIXER_H_ diff --git a/u-boot-2021.10/drivers/jpeg/mm.c b/u-boot-2021.10/drivers/jpeg/mm.c new file mode 100644 index 000000000..ed3c34e5f --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/mm.c @@ -0,0 +1,582 @@ + +#include +#include "mm.h" +#include "jdi_osal.h" +#include +#include "jpulog.h" + +#define P_ALLOC(_x) OSAL_MALLOC(_x) +#define P_FREE(_x) OSAL_FREE(_x) +//#define assert(_exp) // if (!(_exp)) { osal_printf("assert at %s:%d\n", __FILE__, __LINE__); while(1); } +#define HEIGHT(_tree) (!(_tree) ? -1 : _tree->height) + +/* + * doubly linked list + */ +#define MAX(_a, _b) ((_a) >= (_b) ? (_a) : (_b)) + +enum { + LEFT, + RIGHT +} rotation_dir_t; + +struct avl_node_data { + int key; + page_t *page; +} avl_node_data_t; + +static avl_node_t *make_avl_node(vmem_key_t key, page_t *page) +{ + avl_node_t *node = (avl_node_t *) + + josal_malloc(sizeof(avl_node_t)); + + node->key = key; + node->page = page; + node->height = 0; + node->left = NULL; + node->right = NULL; + + return node; +} + +static int get_balance_factor(avl_node_t *tree) +{ + int factor = 0; + + if (tree) { + factor = HEIGHT(tree->right) - HEIGHT(tree->left); + } + + return factor; +} + +/* + * Left Rotation + * + * A B + * \ / \ + * B => A C + * / \ \ + * D C D + * + */ +static avl_node_t *rotation_left(avl_node_t *tree) +{ + avl_node_t *rchild; + avl_node_t *lchild; + + if (!tree) + return NULL; + + rchild = tree->right; + + if (!rchild) { + return tree; + } + + lchild = rchild->left; + rchild->left = tree; + tree->right = lchild; + + tree->height = MAX(HEIGHT(tree->left), HEIGHT(tree->right)) + 1; + rchild->height = MAX(HEIGHT(rchild->left), HEIGHT(rchild->right)) + 1; + + return rchild; +} + +/* + * Reft Rotation + * + * A B + * \ / \ + * B => D A + * / \ / + * D C C + * + */ +static avl_node_t *rotation_right(avl_node_t *tree) +{ + avl_node_t *rchild; + avl_node_t *lchild; + + if (!tree) + return NULL; + + lchild = tree->left; + + if (!lchild) + return NULL; + + rchild = lchild->right; + lchild->right = tree; + tree->left = rchild; + + tree->height = MAX(HEIGHT(tree->left), HEIGHT(tree->right)) + 1; + lchild->height = MAX(HEIGHT(lchild->left), HEIGHT(lchild->right)) + 1; + + return lchild; +} + +static avl_node_t *do_balance(avl_node_t *tree) +{ + int bfactor = 0, child_bfactor; /* balancing factor */ + + bfactor = get_balance_factor(tree); + + if (bfactor >= 2) { + child_bfactor = get_balance_factor(tree->right); + + if (child_bfactor == 1 || child_bfactor == 0) { + tree = rotation_left(tree); + } else if (child_bfactor == -1) { + tree->right = rotation_right(tree->right); + tree = rotation_left(tree); + } else { + //fprintf(stderr, "invalid balancing factor: %d\n", child_bfactor); + assert(0); + return NULL; + } + } else if (bfactor <= -2) { + child_bfactor = get_balance_factor(tree->left); + + if (child_bfactor == -1 || child_bfactor == 0) { + tree = rotation_right(tree); + } else if (child_bfactor == 1) { + tree->left = rotation_left(tree->left); + tree = rotation_right(tree); + } else { + //fprintf(stderr, "invalid balancing factor: %d\n", child_bfactor); + assert(0); + return NULL; + } + } + + return tree; +} + +static avl_node_t *unlink_end_node(avl_node_t *tree, int dir, avl_node_t **found_node) +{ + // avl_node_t* node; + *found_node = NULL; + + if (!tree) + return NULL; + + if (dir == LEFT) { + if (!tree->left) { + *found_node = tree; + return NULL; + } + } else { + if (!tree->right) { + *found_node = tree; + return NULL; + } + } + + if (dir == LEFT) { + // node = tree->left; + tree->left = unlink_end_node(tree->left, LEFT, found_node); + + if (!tree->left) { + tree->left = (*found_node)->right; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } else { + // node = tree->right; + tree->right = unlink_end_node(tree->right, RIGHT, found_node); + + if (!tree->right) { + tree->right = (*found_node)->left; + (*found_node)->left = NULL; + (*found_node)->right = NULL; + } + } + + tree->height = MAX(HEIGHT(tree->left), HEIGHT(tree->right)) + 1; + + return do_balance(tree); +} + +static avl_node_t *avltree_insert(avl_node_t *tree, vmem_key_t key, page_t *page) +{ + if (!tree) { + tree = make_avl_node(key, page); + } else { + if (key >= tree->key) { + tree->right = avltree_insert(tree->right, key, page); + } else { + tree->left = avltree_insert(tree->left, key, page); + } + } + + tree = do_balance(tree); + tree->height = MAX(HEIGHT(tree->left), HEIGHT(tree->right)) + 1; + + return tree; +} + +static avl_node_t *do_unlink(avl_node_t *tree) +{ + avl_node_t *node; + avl_node_t *end_node; + + node = unlink_end_node(tree->right, LEFT, &end_node); + + if (node) { + tree->right = node; + } else { + node = unlink_end_node(tree->left, RIGHT, &end_node); + + if (node) + tree->left = node; + } + + if (!node) { + node = tree->right ? tree->right : tree->left; + end_node = node; + } + + if (end_node) { + end_node->left = (tree->left != end_node) ? tree->left : end_node->left; + end_node->right = (tree->right != end_node) ? tree->right : end_node->right; + end_node->height = MAX(HEIGHT(end_node->left), HEIGHT(end_node->right)) + 1; + } + + tree = end_node; + + return tree; +} + +static avl_node_t *avltree_remove(avl_node_t *tree, avl_node_t **found_node, vmem_key_t key) +{ + *found_node = NULL; + + if (!tree) { + // DPRINT("failed to find key %d\n", key); + return NULL; + } + + if (key == tree->key) { + *found_node = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = avltree_remove(tree->right, found_node, key); + } else { + tree->left = avltree_remove(tree->left, found_node, key); + } + + if (tree) + tree->height = MAX(HEIGHT(tree->left), HEIGHT(tree->right)) + 1; + + tree = do_balance(tree); + + return tree; + +} + +void jpu_avltree_free(avl_node_t *tree) +{ + if (!tree) + return; + + if (!tree->left && !tree->right) { + P_FREE(tree); + return; + } + + jpu_avltree_free(tree->left); + tree->left = NULL; + jpu_avltree_free(tree->right); + tree->right = NULL; +} + +static avl_node_t *remove_approx_value(avl_node_t *tree, avl_node_t **found, vmem_key_t key) +{ + *found = NULL; + + if (!tree) { + return NULL; + } + + if (key == tree->key) { + *found = tree; + tree = do_unlink(tree); + } else if (key > tree->key) { + tree->right = remove_approx_value(tree->right, found, key); + } else { + tree->left = remove_approx_value(tree->left, found, key); + + if (!*found) { + *found = tree; + tree = do_unlink(tree); + } + } + + if (tree) + tree->height = MAX(HEIGHT(tree->left), HEIGHT(tree->right)) + 1; + + tree = do_balance(tree); + + return tree; +} + +static void set_blocks_free(jpeg_mm_t *mm, int pageno, int npages) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t *page; + page_t *last_page; + + assert(npages); + + if (last_pageno >= mm->num_pages) { + // DPRINT("set_blocks_free: invalid last page number: %d\n", last_pageno); + assert(0); + return; + } + + for (i = pageno; i <= last_pageno; i++) { + mm->page_list[i].used = 0; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->free_tree = avltree_insert(mm->free_tree, MAKE_KEY(npages, pageno), page); +} + +static void set_blocks_alloc(jpeg_mm_t *mm, int pageno, int npages) +{ + int last_pageno = pageno + npages - 1; + int i; + page_t *page; + page_t *last_page; + + if (last_pageno >= mm->num_pages) { + // DPRINT("set_blocks_free: invalid last page number: %d\n", last_pageno); + assert(0); + return; + } + + for (i = pageno; i <= last_pageno; i++) { + mm->page_list[i].used = 1; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].first_pageno = -1; + } + + page = &mm->page_list[pageno]; + page->alloc_pages = npages; + + last_page = &mm->page_list[last_pageno]; + last_page->first_pageno = pageno; + + mm->alloc_tree = avltree_insert(mm->alloc_tree, MAKE_KEY(page->addr, 0), page); +} + +int jmem_init(jpeg_mm_t *mm, unsigned long addr, unsigned long size) +{ + int i; + + mm->base_addr = (addr + (VMEM_PAGE_SIZE - 1)) & ~(VMEM_PAGE_SIZE - 1); + mm->mem_size = size & ~VMEM_PAGE_SIZE; + mm->num_pages = mm->mem_size / VMEM_PAGE_SIZE; + mm->page_list = (page_t *) + P_ALLOC(mm->num_pages * sizeof(page_t)); + mm->free_tree = NULL; + mm->alloc_tree = NULL; + mm->free_page_count = mm->num_pages; + mm->alloc_page_count = 0; + + // printf("page list addr: 0x%llx\n", mm->page_list); + for (i = 0; i < mm->num_pages; i++) { + mm->page_list[i].pageno = i; + mm->page_list[i].addr = mm->base_addr + i * VMEM_PAGE_SIZE; + mm->page_list[i].alloc_pages = 0; + mm->page_list[i].used = 0; + mm->page_list[i].first_pageno = -1; + } + + set_blocks_free(mm, 0, mm->num_pages); + return 0; +} + +int jmem_exit(jpeg_mm_t *mm) +{ + if (!mm) { + // DPRINT("vmem_exit: invalid handle\n"); + return -1; + } + + if (mm->free_tree) { + jpu_avltree_free(mm->free_tree); + } + + if (mm->alloc_tree) { + jpu_avltree_free(mm->alloc_tree); + } + + P_FREE(mm->page_list); + + return 0; +} + +unsigned long jmem_alloc(jpeg_mm_t *mm, unsigned int size, unsigned long pid) +{ + avl_node_t *node; + page_t *free_page; + int npages, free_size; + int alloc_pageno; + unsigned long ptr; + + if (!mm) { +// DPRINT("vmem_alloc: invalid handle\n"); + return -1; + } + + if (size <= 0) + return -1; + + npages = (size + VMEM_PAGE_SIZE - 1) / VMEM_PAGE_SIZE; + + mm->free_tree = remove_approx_value(mm->free_tree, &node, MAKE_KEY(npages, 0)); + + if (!node) { + return -1; + } + + free_page = node->page; + free_size = KEY_TO_VALUE(node->key); + + alloc_pageno = free_page->pageno; + set_blocks_alloc(mm, alloc_pageno, npages); + + if (npages != free_size) { + int free_pageno = alloc_pageno + npages; + + set_blocks_free(mm, free_pageno, (free_size - npages)); + } + + P_FREE(node); + + ptr = mm->page_list[alloc_pageno].addr; + mm->alloc_page_count += npages; + mm->free_page_count -= npages; + + return ptr; +} + +int jmem_free(jpeg_mm_t *mm, unsigned long ptr, unsigned long pid) +{ + unsigned long addr; + avl_node_t *found; + page_t *page; + int pageno, prev_free_pageno, next_free_pageno; + int prev_size, next_size; + int merge_page_no, merge_page_size, free_page_size; + + if (!mm) { + // DPRINT("vmem_free: invalid handle\n"); + return -1; + } + + addr = ptr; + + mm->alloc_tree = avltree_remove(mm->alloc_tree, &found, MAKE_KEY(addr, 0)); + + if (!found) { + // DPRINT("vmem_free: 0x%08x not found\n", addr); + return -1; + } + + /* find previous free block */ + page = found->page; + pageno = page->pageno; + free_page_size = page->alloc_pages; + prev_free_pageno = pageno - 1; + prev_size = -1; + + if (prev_free_pageno >= 0) { + if (mm->page_list[prev_free_pageno].used == 0) { + prev_free_pageno = mm->page_list[prev_free_pageno].first_pageno; + prev_size = mm->page_list[prev_free_pageno].alloc_pages; + } + } + + /* find next free block */ + next_free_pageno = pageno + page->alloc_pages; + next_free_pageno = (next_free_pageno == mm->num_pages) ? -1 : next_free_pageno; + next_size = -1; + + if (next_free_pageno >= 0) { + if (mm->page_list[next_free_pageno].used == 0) { + next_size = mm->page_list[next_free_pageno].alloc_pages; + } + } + + P_FREE(found); + + /* merge */ + merge_page_no = page->pageno; + merge_page_size = page->alloc_pages; + + if (prev_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(prev_size, prev_free_pageno)); + + if (!found) { + assert(0); + return -1; + } + + merge_page_no = found->page->pageno; + merge_page_size += found->page->alloc_pages; + P_FREE(found); + } + + if (next_size >= 0) { + mm->free_tree = avltree_remove(mm->free_tree, &found, MAKE_KEY(next_size, next_free_pageno)); + + if (!found) { + assert(0); + return -1; + } + + merge_page_size += found->page->alloc_pages; + P_FREE(found); + } + + page->alloc_pages = 0; + page->first_pageno = -1; + + set_blocks_free(mm, merge_page_no, merge_page_size); + + mm->alloc_page_count -= free_page_size; + mm->free_page_count += free_page_size; + + return 0; +} + +int jmem_get_info(jpeg_mm_t *mm, jmem_info_t *info) +{ + if (!mm) { + // DPRINT("vmem_get_info: invalid handle\n"); + return -1; + } + + if (!info) { + return -1; + } + + info->total_pages = mm->num_pages; + info->alloc_pages = mm->alloc_page_count; + info->free_pages = mm->free_page_count; + info->page_size = VMEM_PAGE_SIZE; + + return 0; +} diff --git a/u-boot-2021.10/drivers/jpeg/mm.h b/u-boot-2021.10/drivers/jpeg/mm.h new file mode 100644 index 000000000..461b9100f --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/mm.h @@ -0,0 +1,71 @@ +#ifndef __JPU_VIDEO_MEMORY_MANAGEMENT_H__ +#define __JPU_VIDEO_MEMORY_MANAGEMENT_H__ + +typedef struct _jmem_info_struct { + unsigned long total_pages; + unsigned long alloc_pages; + unsigned long free_pages; + unsigned long page_size; +} jmem_info_t; + +#if defined(WIN32) || defined(WIN64) +#if (_MSC_VER == 1200) +typedef _int64 vmem_key_t; +#else +typedef unsigned long long vmem_key_t; +#endif +#else +typedef unsigned long long vmem_key_t; +#endif + +#define VMEM_PAGE_SIZE (16 * 1024) + +#define MAKE_KEY(_a, _b) (((vmem_key_t)(_a)) << 32 | (_b)) +#define KEY_TO_VALUE(_key) ((_key) >> 32) + +typedef struct page_struct { + int pageno; + unsigned long addr; + int used; + int alloc_pages; + int first_pageno; +} page_t; + +typedef struct avl_node_struct { + vmem_key_t key; + int height; + page_t *page; + struct avl_node_struct *left; + struct avl_node_struct *right; +} avl_node_t; + +typedef struct _jpeg_mm_struct { + avl_node_t *free_tree; + avl_node_t *alloc_tree; + page_t *page_list; + int num_pages; + unsigned long base_addr; + unsigned long mem_size; + void *mutex; + int free_page_count; + int alloc_page_count; +} jpeg_mm_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +extern int jmem_init(jpeg_mm_t *mm, unsigned long addr, unsigned long size); + +extern int jmem_exit(jpeg_mm_t *mm); + +extern unsigned long jmem_alloc(jpeg_mm_t *mm, unsigned int size, unsigned long pid); + +extern int jmem_free(jpeg_mm_t *mm, unsigned long ptr, unsigned long pid); + +extern int jmem_get_info(jpeg_mm_t *mm, jmem_info_t *info); + +#if defined(__cplusplus) +} +#endif +#endif /* __JPU_VIDEO_MEMORY_MANAGEMENT_H__ */ \ No newline at end of file diff --git a/u-boot-2021.10/drivers/jpeg/regdefine.h b/u-boot-2021.10/drivers/jpeg/regdefine.h new file mode 100644 index 000000000..c51e15eb6 --- /dev/null +++ b/u-boot-2021.10/drivers/jpeg/regdefine.h @@ -0,0 +1,162 @@ +#include "config.h" + +#ifndef NPT_REGDEFINE_H_INCLUDED +#define NPT_REGDEFINE_H_INCLUDED + +//------------------------------------------------------------------------------ +// REGISTER BASE +//------------------------------------------------------------------------------ +#define TOP_BASE 0x03000000 +#define TOP_USB_PHY_CTRSTS_REG (TOP_BASE + 0x48) +#define UPCR_EXTERNAL_VBUS_VALID_OFFSET 0 + +#define TOP_DDR_ADDR_MODE_REG (TOP_BASE + 0x64) +#define DAMR_REG_USB_REMAP_ADDR_39_32_OFFSET 16 +#define DAMR_REG_USB_REMAP_ADDR_39_32_MSK (0xff) + +#define DAMR_REG_VD_REMAP_ADDR_39_32_OFFSET 24 +#define DAMR_REG_VD_REMAP_ADDR_39_32_MSK (0xff) + +#define JPEG_INTRPT_REQ 75 + +#define NPT_REG_SIZE 0x300 +#define NPT_REG_BASE (void *)(0x10000000 + 0x3000) +#define VC_REG_BASE (void *)(0x0B000000 + 0x30000) + +#define NPT_BASE 0x00 + +/*-------------------------------------------------------------------- + * NIEUPORT REGISTERS + *------------------------------------------------------------------ + */ +// MAIN CONTROL REGISTER +// [3] - start partial encoding [2] - pic stop en/decoding[1] - pic init +// en/decoding [0] - pic start en/decoding +#define MJPEG_PIC_START_REG (NPT_BASE + 0x000) + +// [8] - stop [7:4] - partial buffer interrupt [3] - overflow, [2] - bbc +// interrupt, [1] - error, [0] - done +#define MJPEG_PIC_STATUS_REG (NPT_BASE + 0x004) + +// [27:24] - error restart idx, [23:12] - error MCU pos X, [11:0] - error MCU +// pos Y +#define MJPEG_PIC_ERRMB_REG (NPT_BASE + 0x008) + +// [27:16] - MCU pos X, [11:0] - MCU pos Y +#define MJPEG_PIC_SETMB_REG (NPT_BASE + 0x00C) + +// [12:7] huffman table index [6] - user huffman en, [4] - TC direction, [3] - +// encoder enable, [1:0] - operation mode +#define MJPEG_PIC_CTRL_REG (NPT_BASE + 0x010) +#define MJPEG_PIC_SIZE_REG (NPT_BASE + 0x014) +#define MJPEG_MCU_INFO_REG (NPT_BASE + 0x018) + +// [4] - rot-mir enable, [3:0] - rot-mir mode +#define MJPEG_ROT_INFO_REG (NPT_BASE + 0x01C) +#define MJPEG_SCL_INFO_REG (NPT_BASE + 0x020) + +// [1] - sensor interface clear, [0] - display interface clear +#define MJPEG_IF_INFO_REG (NPT_BASE + 0x024) +#define MJPEG_CLP_INFO_REG (NPT_BASE + 0x028) + +// [31:16] - # of line in 1 partial buffer, [5:3] - # of partial buffers [2:0] - +// # of request +#define MJPEG_OP_INFO_REG (NPT_BASE + 0x02C) + +#define MJPEG_DPB_CONFIG_REG (NPT_BASE + 0x030) +#define MJPEG_DPB_BASE00_REG (NPT_BASE + 0x034) +#define MJPEG_DPB_BASE01_REG (NPT_BASE + 0x038) +#define MJPEG_DPB_BASE02_REG (NPT_BASE + 0x03C) + +#define MJPEG_DPB_BASE10_REG (NPT_BASE + 0x040) +#define MJPEG_DPB_BASE11_REG (NPT_BASE + 0x044) +#define MJPEG_DPB_BASE12_REG (NPT_BASE + 0x048) +#define MJPEG_DPB_BASE20_REG (NPT_BASE + 0x04C) + +#define MJPEG_DPB_BASE21_REG (NPT_BASE + 0x050) +#define MJPEG_DPB_BASE22_REG (NPT_BASE + 0x054) +#define MJPEG_DPB_BASE30_REG (NPT_BASE + 0x058) +#define MJPEG_DPB_BASE31_REG (NPT_BASE + 0x05C) + +#define MJPEG_DPB_BASE32_REG (NPT_BASE + 0x060) +#define MJPEG_DPB_YSTRIDE_REG (NPT_BASE + 0x064) +#define MJPEG_DPB_CSTRIDE_REG (NPT_BASE + 0x068) +#define MJPEG_WRESP_CHECK_REG (NPT_BASE + 0x06C) + +#define MJPEG_CLP_BASE_REG (NPT_BASE + 0x070) +#define MJPEG_CLP_SIZE_REG (NPT_BASE + 0x074) + +#define MJPEG_HUFF_CTRL_REG (NPT_BASE + 0x080) +#define MJPEG_HUFF_ADDR_REG (NPT_BASE + 0x084) +#define MJPEG_HUFF_DATA_REG (NPT_BASE + 0x088) + +#define MJPEG_QMAT_CTRL_REG (NPT_BASE + 0x090) +#define MJPEG_QMAT_ADDR_REG (NPT_BASE + 0x094) +#define MJPEG_QMAT_DATA_REG (NPT_BASE + 0x098) + +#define MJPEG_COEF_CTRL_REG (NPT_BASE + 0x0A0) +#define MJPEG_COEF_ADDR_REG (NPT_BASE + 0x0A4) +#define MJPEG_COEF_DATA_REG (NPT_BASE + 0x0A8) + +#define MJPEG_RST_INTVAL_REG (NPT_BASE + 0x0B0) +#define MJPEG_RST_INDEX_REG (NPT_BASE + 0x0B4) +#define MJPEG_RST_COUNT_REG (NPT_BASE + 0x0B8) + +#define MJPEG_INTR_MASK_REG (NPT_BASE + 0x0C0) +#define MJPEG_CYCLE_INFO_REG (NPT_BASE + 0x0C8) + +#define MJPEG_DPCM_DIFF_Y_REG (NPT_BASE + 0x0F0) +#define MJPEG_DPCM_DIFF_CB_REG (NPT_BASE + 0x0F4) +#define MJPEG_DPCM_DIFF_CR_REG (NPT_BASE + 0x0F8) + +// GBU CONTROL REGISTER +#define MJPEG_GBU_CTRL_REG \ + (NPT_BASE + \ + 0x100) // [3] - GBU flush for encoding [2] - init GBU for decoding [1] + // - init GBU ff emulation for decoding [0] - reserved +#define MJPEG_GBU_PBIT_BUSY_REG (NPT_BASE + 0x104) + +#define MJPEG_GBU_BT_PTR_REG (NPT_BASE + 0x110) +#define MJPEG_GBU_WD_PTR_REG (NPT_BASE + 0x114) +#define MJPEG_GBU_TT_CNT_REG (NPT_BASE + 0x118) +//#define MJPEG_GBU_TT_CNT_REG+4 (NPT_BASE + 0x11C) + +#define MJPEG_GBU_PBIT_08_REG (NPT_BASE + 0x120) +#define MJPEG_GBU_PBIT_16_REG (NPT_BASE + 0x124) +#define MJPEG_GBU_PBIT_24_REG (NPT_BASE + 0x128) +#define MJPEG_GBU_PBIT_32_REG (NPT_BASE + 0x12C) + +#define MJPEG_GBU_BBSR_REG (NPT_BASE + 0x140) +#define MJPEG_GBU_BBER_REG (NPT_BASE + 0x144) +#define MJPEG_GBU_BBIR_REG (NPT_BASE + 0x148) +#define MJPEG_GBU_BBHR_REG (NPT_BASE + 0x14C) + +#define MJPEG_GBU_BCNT_REG (NPT_BASE + 0x158) + +#define MJPEG_GBU_FF_RPTR_REG (NPT_BASE + 0x160) +#define MJPEG_GBU_FF_WPTR_REG (NPT_BASE + 0x164) + +// BBC CONTROL REGISTER +#define MJPEG_BBC_END_ADDR_REG (NPT_BASE + 0x208) +#define MJPEG_BBC_WR_PTR_REG (NPT_BASE + 0x20C) +#define MJPEG_BBC_RD_PTR_REG (NPT_BASE + 0x210) + +#define MJPEG_BBC_EXT_ADDR_REG (NPT_BASE + 0x214) +#define MJPEG_BBC_INT_ADDR_REG (NPT_BASE + 0x218) +#define MJPEG_BBC_DATA_CNT_REG (NPT_BASE + 0x21C) +#define MJPEG_BBC_COMMAND_REG \ + (NPT_BASE + 0x220) // [2:1] - endianness [0] - load/save +#define MJPEG_BBC_BUSY_REG (NPT_BASE + 0x224) + +#define MJPEG_BBC_CTRL_REG \ + (NPT_BASE + 0x228) // [2:1] - endianness [0] - BBC auto run +#define MJPEG_BBC_CUR_POS_REG (NPT_BASE + 0x22C) + +#define MJPEG_BBC_BAS_ADDR_REG (NPT_BASE + 0x230) +#define MJPEG_BBC_STRM_CTRL_REG \ + (NPT_BASE + \ + 0x234) // [31] - end of bitstream file [23:0] - stream counter + +#define MJPEG_BBC_FLUSH_CMD_REG (NPT_BASE + 0x238) + +#endif