rt-thread/bsp/nuvoton/libraries/n9h30/rtt_port/drv_jpegcodec.c

1413 lines
42 KiB
C

/**************************************************************************//**
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-4-16 Wayne First version
*
******************************************************************************/
#include "rtthread.h"
#include "NuMicro.h"
#include "nu_jpeg.h"
#include "drv_sys.h"
struct nu_jpeg
{
struct rt_device dev;
char *name;
IRQn_Type irqn;
E_SYS_IPRST rstidx;
E_SYS_IPCLK clkidx;
struct rt_mutex lock;
};
typedef struct nu_jpeg *nu_jpeg_t;
static BOOL volatile g_bWait = FALSE, g_jpegError = FALSE, g_bScale = FALSE, g_OutputWait = FALSE, g_InputWait = FALSE, g_u32WindowDec = FALSE, g_bEncThumbnailDownScale = FALSE, g_bEncPrimaryDownScale = FALSE;
static UINT32 volatile g_u32Stride, g_u32ScaleWidth, g_u32ScaleHeight, g_u32OpMode, g_u32EncRotate = 0;
static UINT32 volatile g_u32BufferCount, g_u32DecInputWaitAddr;
static UINT16 volatile g_u16BufferSize, g_u16ReserveSize;
static UINT32 volatile g_u32OutputFormat, g_u32windowSizeX, g_u32windowSizeY;
static PFN_JPEG_CALLBACK pfnJpegDecodeComplete = NULL;
static PFN_JPEG_CALLBACK pfnJpegDecodeError = NULL;
static PFN_JPEG_CALLBACK pfnJpegEncodeComplete = NULL;
static PFN_JPEG_HEADERDECODE_CALLBACK pfnJpegHeaderDecode = NULL;
static PFN_JPEG_DECWAIT_CALLBACK pfnJpegDecInputWait = NULL;
static PFN_JPEG_DECWAIT_CALLBACK pfnJpegDecOutputWait = NULL;
static JPEG_INFO_T jpegInfo;
/* Default Quantization-Table 0 ~ 2 */
static UINT8 g_au8QTable0[64] = { 0x06, 0x04, 0x04, 0x05, 0x04, 0x04, 0x06, 0x05,
0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x08, 0x0E,
0x09, 0x08, 0x08, 0x08, 0x08, 0x11, 0x0C, 0x0D,
0x0A, 0x0E, 0x14, 0x11, 0x15, 0x14, 0x13, 0x11,
0x13, 0x13, 0x16, 0x18, 0x1F, 0x1A, 0x16, 0x17,
0x1D, 0x17, 0x13, 0x13, 0x1B, 0x25, 0x1B, 0x1D,
0x20, 0x21, 0x23, 0x23, 0x23, 0x15, 0x1A, 0x26,
0x29, 0x26, 0x22, 0x28, 0x1F, 0x22, 0x23, 0x21
},
g_au8QTable1[64] = { 0x06, 0x06, 0x06, 0x08, 0x07, 0x08, 0x10, 0x09,
0x09, 0x10, 0x21, 0x16, 0x13, 0x16, 0x21, 0x21,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21
};
static struct nu_jpeg g_sNuJpeg =
{
.name = "jpegcodec",
.irqn = JPEG_IRQn,
.rstidx = JPEGRST,
.clkidx = JPEGCKEN
};
/* Interrupt Service Routine for H/W JPEG CODEC */
static void nu_jpeg_isr(int vector, void *param)
{
UINT32 u32interruptStatus;
/* Get the interrupt status */
u32interruptStatus = JPEG_GET_INT_STATUS();
/* It's Header Decode Complete Interrupt */
if (u32interruptStatus & DHE_INTS)
{
UINT32 u32YuvFormat;
UINT16 u16Height, u16Width, UVHeight, UVWidth;
UINT16 u16WidthTmp, u16HeightTmp;
/* Get the JPEG format */
u32YuvFormat = JPEG_DEC_GET_DECODED_IMAGE_FORMAT();
/* Get the decoded image dimension */
jpegGetDecodedDimension(&u16Height, &u16Width);
jpegInfo.jpeg_width = u16Width;
jpegInfo.jpeg_height = u16Height;
jpegInfo.yuvformat = u32YuvFormat;
if (pfnJpegHeaderDecode != NULL)
{
if (!pfnJpegHeaderDecode())
{
jpegInit();
g_bWait = FALSE;
return;
}
}
if (g_bScale)
{
UINT16 u16RatioH, u16RatioW;
if (jpegCalScalingFactor(
g_u32OpMode, //Up / Down Scaling
u16Height, //Original Height
u16Width, //Original Width
g_u32ScaleHeight, //Scaled Height
g_u32ScaleWidth, //Scaled Width
&u16RatioH, //Horizontal Ratio
&u16RatioW //Vertical Ratio
) != E_SUCCESS)
{
g_bWait = FALSE;
g_jpegError = TRUE;
}
else
{
jpegSetScalingFactor(g_u32OpMode, u16RatioH, u16RatioW);
u16Width = g_u32ScaleWidth;
u16Height = g_u32ScaleHeight;
}
}
else
{
if (u32YuvFormat == JPEG_DEC_YUV411)
{
/* 32-pixel alignment for YUV411 raw data */
if (u16Width % 32)
u16Width = (u16Width & 0xFFFFFFE0) + 32;
}
else if ((u32YuvFormat == JPEG_DEC_YUV444) || (u32YuvFormat == JPEG_DEC_YUV422T))
{
/* 8-pixel alignment for YUV444 raw data */
if (u16Width % 8)
u16Width = (u16Width & 0xFFFFFFF8) + 8;
}
else
{
/* 16-pixel alignment for YUV422 or YUV420 raw data */
if (u16Width % 16)
u16Width = (u16Width & 0xFFFFFFF0) + 16;
}
}
if (g_u32Stride >= u16Width)
{
jpegInfo.stride = g_u32Stride;
g_u32Stride = g_u32Stride - u16Width;
JPEG_SET_YSTRIDE(g_u32Stride);
u16Width = jpegInfo.stride;
}
else
{
g_u32Stride = 0;
JPEG_SET_YSTRIDE(0);
jpegInfo.stride = 0;
}
if (g_u32OutputFormat == JPEG_DEC_PRIMARY_PLANAR_YUV || g_u32OutputFormat == JPEG_DEC_THUMBNAIL_PLANAR_YUV)
{
if (g_u32WindowDec)
{
u16WidthTmp = u16Width;
u16HeightTmp = u16Height;
u16Width = g_u32windowSizeX;
u16Height = g_u32windowSizeY;
}
if (u32YuvFormat == JPEG_DEC_YUV411)
{
/* For YUV411 raw data */
UVWidth = u16Width / 4;
}
else if ((u32YuvFormat == JPEG_DEC_YUV444) || (u32YuvFormat == JPEG_DEC_YUV422T))
{
/* For YUV444 raw data */
UVWidth = u16Width;
}
/* Set the U-component and V-componente width for YUV422 or YUV420 raw data */
else if (u16Width % 2)
UVWidth = u16Width / 2 + 1;
else
UVWidth = u16Width / 2;
/* Sets the height of U and V for YUV420 image */
if (u32YuvFormat == JPEG_DEC_YUV420)
{
/* 16-pixel alignment for YUV422 or YUV420 raw data */
if (u16Height % 16)
u16Height = (u16Height & 0xFFFFFFF0) + 16;
UVHeight = u16Height / 2;
}
else if (u32YuvFormat == JPEG_DEC_YUV422)
{
/* 8-pixel alignment for YUV444 raw data */
if (u16Height % 8)
u16Height = (u16Height & 0xFFFFFFF8) + 8;
UVHeight = u16Height;
}
else if (u32YuvFormat == JPEG_DEC_YUV444)
{
/* 8-pixel alignment for YUV444 raw data */
if (u16Height % 8)
u16Height = (u16Height & 0xFFFFFFF8) + 8;
UVHeight = u16Height;
}
else if (u32YuvFormat == JPEG_DEC_YUV411)
{
/* 8-pixel alignment for YUV411 raw data */
if (u16Height % 8)
u16Height = (u16Height & 0xFFFFFFF8) + 8;
UVHeight = u16Height;
}
else if (u32YuvFormat == JPEG_DEC_YUV422T)
{
/* 16-pixel alignment for YUV422 or YUV420 raw data */
if (u16Height % 16)
u16Height = (u16Height & 0xFFFFFFF0) + 16;
UVHeight = u16Height / 2;
}
else
{
/* 8-pixel alignment for raw data */
if (u16Height % 8)
u16Height = (u16Height & 0xFFFFFFF8) + 8;
UVHeight = u16Height;
}
JPEG_SET_UADDR(JPEG_GET_YADDR() + u16Width * u16Height);
JPEG_SET_VADDR(JPEG_GET_UADDR() + UVWidth * UVHeight);
if (u32YuvFormat == JPEG_DEC_GRAY)
jpegInfo.image_size[0] = u16Width * u16Height;
else
jpegInfo.image_size[0] = u16Width * u16Height + 2 * UVWidth * UVHeight;
if (g_u32WindowDec)
{
u16Width = u16WidthTmp;
u16Height = u16HeightTmp;
}
}
else
{
if (g_u32WindowDec)
{
u16WidthTmp = u16Width;
u16HeightTmp = u16Height;
u16Width = g_u32windowSizeX;
u16Height = g_u32windowSizeY;
}
if (jpegInfo.stride)
jpegInfo.image_size[0] = jpegInfo.stride * u16Height;
else
jpegInfo.image_size[0] = u16Width * u16Height;
if (g_u32OutputFormat == JPEG_DEC_PRIMARY_PACKET_RGB888)
jpegInfo.image_size[0] = 4 * jpegInfo.image_size[0];
else
jpegInfo.image_size[0] = 2 * jpegInfo.image_size[0];
if (g_u32WindowDec)
{
u16Width = u16WidthTmp;
u16Height = u16HeightTmp;
}
}
/* Set the image dimension */
jpegSetDimension(u16Height, u16Width);
outp32(JITCR, inp32(JITCR) | Dec_Scatter_Gather);
/* Clear interrupt status */
JPEG_CLEAR_INT(DHE_INTS);
}
/* It's Decode Output Wait Interrupt */
else if (u32interruptStatus & JPG_DOW_INTS)
{
if (pfnJpegDecOutputWait != NULL)
{
pfnJpegDecOutputWait(inp32(JYADDR0), inp32(JDOWFBS));
}
JPEG_CLEAR_INT(JPG_DOW_INTS);
outp32(JITCR, inp32(JITCR) | Dec_Scatter_Gather);
}
/* It's Encode Complete Interrupt */
else if (u32interruptStatus & ENC_INTS)
{
/* Get the Encode Bit stream length */
jpegInfo.image_size[0] = JPEG_GET_ENC_PRIMARY_BITSTREAM_SIZE();
jpegInfo.image_size[1] = JPEG_GET_ENC_THUMBNAIL_BITSTREAM_SIZE();
/* Clear interrupt status */
JPEG_CLEAR_INT(ENC_INTS);
g_bWait = FALSE;
if (pfnJpegEncodeComplete != NULL)
pfnJpegEncodeComplete();
}
/* It's Decode Complete Interrupt */
else if (u32interruptStatus & DEC_INTS)
{
UINT16 imageWidth, imageHeight;
/* Get the image dimension */
jpegGetDimension(&imageHeight, &imageWidth);
if (g_u32Stride != 0)
{
imageWidth = imageWidth - g_u32Stride;
}
jpegInfo.width = imageWidth;
jpegInfo.height = imageHeight;
/* Clear interrupt status */
JPEG_CLEAR_INT(DEC_INTS);
JPEG_CLEAR_INT(JPG_DOW_INTS);
g_bWait = FALSE;
if (pfnJpegDecodeComplete != NULL)
pfnJpegDecodeComplete();
}
/* It's Decode Error Interrupt */
else if (u32interruptStatus & DER_INTS)
{
/* Clear interrupt status */
JPEG_CLEAR_INT(DER_INTS);
g_bWait = FALSE;
g_jpegError = TRUE;
if (pfnJpegDecodeError != NULL)
pfnJpegDecodeError();
}
else if (u32interruptStatus & IPW_INTS)
{
/* Clear interrupt status */
JPEG_CLEAR_INT(IPW_INTS);
JPEG_DEC_RESUME_INPUT_WAIT();
if (pfnJpegDecInputWait != NULL)
{
if (!pfnJpegDecInputWait((g_u32DecInputWaitAddr + (g_u32BufferCount % 2) * g_u16BufferSize), g_u16BufferSize))
{
jpegInit();
g_bWait = FALSE;
return;
}
g_u32BufferCount++;
}
else
while (1);
}
}
static INT jpegAdjustQTAB(UINT8 u8Mode, UINT8 u8Qadjust, UINT8 u8Qscaling)
{
UINT32 u32Addr;
if (u8Mode == JPEG_ENC_PRIMARY)
u32Addr = REG_JPRIQC;
else if (u8Mode == JPEG_ENC_THUMBNAIL)
u32Addr = REG_JTHBQC;
else
return E_JPEG_INVALID_PARAM;
outp32(u32Addr, ((u8Qadjust & 0xF) << 4) | (u8Qscaling & 0xF));
return E_SUCCESS;
}
#if 0
//Poll the interrupt status and get if the interrupt is generated
static BOOL jpegPollInt(UINT32 u32Intflag)
{
if (JPEG_GET_INT_STATUS() & u32Intflag)
return 1;
else
return 0;
}
static UINT32 jpegPower(UINT32 u32Index, UINT32 u32Exp)
{
if (u32Exp == 0)
return 1;
else
{
UINT32 u32Idx;
for (u32Idx = 1; u32Idx < u32Exp; u32Idx = u32Idx + 1)
{
u32Index = 2 * u32Index;
}
}
return u32Index;
}
static VOID jpegGetScalingFactor(
UINT8 u8Mode, //Up / Down Scaling
PUINT16 pu16FactorH, //Vertical Scaling Factor
PUINT16 pu16FactorW //Horizontal Scaling Factor
)
{
if (u8Mode == JPEG_DEC_PLANAR_DOWNSCALE_MODE)
{
*pu16FactorH = inp32(REG_JPSCALD) & 0x3F;
*pu16FactorW = (inp32(REG_JPSCALD) >> 8) & 0x1F;
}
else
{
*pu16FactorH = (inp32(REG_JUPRAT) >> 16) & 0x3FFF;
*pu16FactorW = inp32(REG_JUPRAT) & 0x3FFF;
}
}
#endif
static INT jpegSetEncodeMode(UINT8 u8SourceFormat, UINT16 u16JpegFormat)
{
UINT8 u8Gray = 0;
switch (u16JpegFormat)
{
case JPEG_ENC_PRIMARY_YUV420:
case JPEG_ENC_PRIMARY_YUV422:
case JPEG_ENC_THUMBNAIL_YUV420:
case JPEG_ENC_THUMBNAIL_YUV422:
case (JPEG_ENC_PRIMARY_YUV420 | JPEG_ENC_THUMBNAIL_YUV420):
case (JPEG_ENC_PRIMARY_YUV422 | JPEG_ENC_THUMBNAIL_YUV422):
outp32(REG_JMCR, (inp32(REG_JMCR) & WIN_DEC) | u16JpegFormat);
u8Gray = 0;
break;
case JPEG_ENC_PRIMARY_GRAY:
case JPEG_ENC_THUMBNAIL_GRAY:
case (JPEG_ENC_PRIMARY_GRAY | JPEG_ENC_THUMBNAIL_GRAY):
if (u8SourceFormat == JPEG_ENC_SOURCE_PACKET)
return E_JPEG_INVALID_PARAM;
else
{
if (u16JpegFormat == (JPEG_ENC_PRIMARY_GRAY | JPEG_ENC_THUMBNAIL_GRAY))
outp32(REG_JMCR, 0xB0);
else
outp32(REG_JMCR, 0xA0);
}
u8Gray = EY_ONLY;
break;
default:
return E_JPEG_INVALID_PARAM;
}
g_u32OpMode = JPEG_ENC_UPSCALE_MODE;
if (g_bEncPrimaryDownScale)
g_u32OpMode = JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE;
if (g_bEncThumbnailDownScale)
g_u32OpMode = JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE;
if (u8SourceFormat == JPEG_ENC_SOURCE_PLANAR)
outp32(REG_JITCR, (inp32(REG_JITCR) & (0x8 | ROTATE)) | PLANAR_ON | u8Gray);
else if (u8SourceFormat == JPEG_ENC_SOURCE_PACKET)
outp32(REG_JITCR, inp32(REG_JITCR) & ~(PLANAR_ON | ROTATE));
else
return E_JPEG_INVALID_PARAM;
return E_SUCCESS;
}
static INT jpegSetDecodeMode(UINT32 u32OutputFormat)
{
switch (u32OutputFormat)
{
case JPEG_DEC_PRIMARY_PLANAR_YUV:
case JPEG_DEC_PRIMARY_PACKET_YUV422:
case JPEG_DEC_PRIMARY_PACKET_RGB555:
case JPEG_DEC_PRIMARY_PACKET_RGB555R1:
case JPEG_DEC_PRIMARY_PACKET_RGB555R2:
case JPEG_DEC_THUMBNAIL_PLANAR_YUV:
case JPEG_DEC_THUMBNAIL_PACKET_YUV422:
case JPEG_DEC_THUMBNAIL_PACKET_RGB555:
case JPEG_DEC_PRIMARY_PACKET_RGB565:
case JPEG_DEC_PRIMARY_PACKET_RGB565R1:
case JPEG_DEC_PRIMARY_PACKET_RGB565R2:
case JPEG_DEC_PRIMARY_PACKET_RGB888:
outp32(REG_JITCR, u32OutputFormat);
outp32(REG_JMCR, inp32(REG_JMCR) & ~ENC_DEC);
g_u32OpMode = JPEG_DEC_PACKET_DOWNSCALE_MODE;
g_u32OutputFormat = u32OutputFormat;
if (u32OutputFormat == JPEG_DEC_PRIMARY_PLANAR_YUV || u32OutputFormat == JPEG_DEC_THUMBNAIL_PLANAR_YUV)
g_u32OpMode = JPEG_DEC_PLANAR_DOWNSCALE_MODE;
break;
default:
return E_JPEG_INVALID_PARAM;
}
return E_SUCCESS;
}
static VOID jpegDecodeTrigger(void)
{
g_bWait = TRUE;
g_jpegError = FALSE;
rt_memset(&jpegInfo, 0, sizeof(jpegInfo));
/* Decode Complete /Decode Header End/Decode Error Interrupt Enable and clear the Decode Complete /Decode Header End/Decode Error Interrupt */
if (g_InputWait)
{
g_u32BufferCount = 0;
g_u32DecInputWaitAddr = JPEG_GET_BITSTREAM_ADDR();
if (g_OutputWait)
JPEG_INT_ENABLE(DEC_INTE | DER_INTE | DHE_INTE | IPW_INTE | JPG_DOW_INTE);
else
JPEG_INT_ENABLE(DEC_INTE | DER_INTE | DHE_INTE | IPW_INTE);
}
else if (g_OutputWait)
{
JPEG_INT_ENABLE(DEC_INTE | DER_INTE | DHE_INTE | JPG_DOW_INTE);
}
else
JPEG_INT_ENABLE(DEC_INTE | DER_INTE | DHE_INTE);
JPEG_CLEAR_INT(DEC_INTS | JPEG_DER_INTS | JPEG_DHE_INTS | JPEG_IPW_INTS | JPG_DOW_INTS);
outp32(REG_JMCR, JPG_EN | inp32(REG_JMCR));
outp32(REG_JMCR, ~JPG_EN & inp32(REG_JMCR));
}
static VOID jpegEncodeTrigger(void)
{
g_bWait = TRUE;
g_jpegError = FALSE;
g_u32OpMode = JPEG_ENC_UPSCALE_MODE;
if (g_bEncPrimaryDownScale)
g_u32OpMode = JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE;
if (g_bEncThumbnailDownScale)
g_u32OpMode = JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE;
rt_memset(&jpegInfo, 0, sizeof(jpegInfo));
if (g_u32EncRotate != 0)
{
UINT16 u16Height, u16Width;
if (((inp32(REG_JITCR) & (PLANAR_ON | EY_ONLY)) != (PLANAR_ON)) && ((inp32(REG_JMCR) & EY422) != 0))
{
g_jpegError = TRUE;
g_bWait = FALSE;
return;
}
jpegGetDimension(&u16Width, &u16Height);
if (g_u32EncRotate == JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_LEFT)
{
JPEG_SET_YADDR((JPEG_GET_YADDR() + (u16Width - 1)));
JPEG_SET_UADDR((JPEG_GET_UADDR() + (u16Width / 2 - 1)));
JPEG_SET_VADDR((JPEG_GET_VADDR() + (u16Width / 2 - 1)));
}
else
{
JPEG_SET_YADDR((JPEG_GET_YADDR() + ((u16Height - 1) * u16Width)));
u16Width = JPEG_GET_USTRIDE();
JPEG_SET_UADDR((JPEG_GET_UADDR() + ((u16Height - 2) * u16Width / 2)));
JPEG_SET_VADDR((JPEG_GET_VADDR() + ((u16Height - 2) * u16Width / 2)));
}
}
if (g_bScale)
{
UINT16 u16Height, u16Width, u16ratioH, u16ratioW;
if (g_u32EncRotate != 0)
jpegGetDimension(&u16Width, &u16Height);
else
jpegGetDimension(&u16Height, &u16Width);
if (jpegCalScalingFactor(
g_u32OpMode, //Up / Down Scaling
u16Height, //Original Height
u16Width, //Original Width
g_u32ScaleHeight, //Scaled Height
g_u32ScaleWidth, //Scaled Width
&u16ratioH, //Horizontal Ratio
&u16ratioW //Vertical Ratio
) != E_SUCCESS)
{
g_jpegError = TRUE;
g_bWait = FALSE;
return;
}
else
{
jpegSetScalingFactor(g_u32OpMode, u16ratioH, u16ratioW);
if (g_bEncThumbnailDownScale)
outp32(REG_JTHBWH, ((g_u32ScaleHeight & 0x1FFF) << 16) | (g_u32ScaleWidth & 0x1FFF));
else
{
if (g_u32EncRotate != 0)
jpegSetDimension(g_u32ScaleWidth, g_u32ScaleHeight);
else
jpegSetDimension(g_u32ScaleHeight, g_u32ScaleWidth);
}
}
}
/* Encode Complete Interrupt Enable and clear the Encode Complete Interrupt */
JPEG_INT_ENABLE(ENC_INTE);
JPEG_CLEAR_INT(ENC_INTS);
outp32(REG_JMCR, JPG_EN | inp32(REG_JMCR));
outp32(REG_JMCR, ~JPG_EN & inp32(REG_JMCR));
}
static INT jpegCalScalingFactor(
UINT8 u8Mode, //Up / Down Scaling
UINT16 u16Height, //Original Height
UINT16 u16Width, //Original Width
UINT16 u16ScalingHeight, //Scaled Height
UINT16 u16ScalingWidth, //Scaled Width
PUINT16 pu16RatioH, //Horizontal Ratio
PUINT16 pu16RatioW //Vertical Ratio
)
{
if (u8Mode == JPEG_ENC_UPSCALE_MODE)
{
if (u16ScalingHeight < u16Height || u16ScalingWidth < u16Width)
return E_JPEG_INVALID_PARAM;
*pu16RatioW = (UINT32)((float)(u16ScalingWidth - 1) / (float)(u16Width - 2) * 1024);
*pu16RatioH = (UINT32)((float)(u16ScalingHeight - 1) / (float)(u16Height - 2) * 1024);
}
else if (u8Mode == JPEG_DEC_PACKET_DOWNSCALE_MODE)
{
if (u16ScalingHeight > u16Height || u16ScalingWidth > u16Width)
return E_JPEG_INVALID_PARAM;
*pu16RatioW = (UINT32)(((float)(u16ScalingWidth) / (u16Width - 1) * 8192));
if (*pu16RatioW > 8192)
*pu16RatioW = 8192;
*pu16RatioH = (UINT32)((float)(u16ScalingHeight) / (u16Height - 1) * 8192);
if (*pu16RatioH > 8192)
*pu16RatioH = 8192;
}
else if (u8Mode == JPEG_DEC_PLANAR_DOWNSCALE_MODE || u8Mode == JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE || u8Mode == JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE)
{
UINT16 u16RatioW, u16RatioH;
if (u16ScalingHeight > u16Height || u16ScalingWidth > u16Width)
return E_JPEG_INVALID_PARAM;
if (u16Height % u16ScalingHeight)
return E_JPEG_INVALID_PARAM;
if (u16Width % u16ScalingWidth)
return E_JPEG_INVALID_PARAM;
u16RatioW = u16Width / u16ScalingWidth;
u16RatioW = u16RatioW / 2 - 1;
if ((u16RatioW != 0) && (u16RatioW != 1) && (u16RatioW != 3))
return E_JPEG_INVALID_PARAM;
u16RatioH = u16Height / u16ScalingHeight - 1;
if ((u16RatioH != 0) && (u16RatioH != 1) && (u16RatioH != 3) && (u16RatioH != 7))
return E_JPEG_INVALID_PARAM;
*pu16RatioW = u16RatioW;
*pu16RatioH = u16RatioH;
}
else
return E_JPEG_INVALID_PARAM;
return E_SUCCESS;
}
static INT jpegSetScalingFactor(
UINT8 u8Mode, //Up / Down Scaling
UINT16 u16FactorH, //Vertical Scaling Factor
UINT16 u16FactorW //Horizontal Scaling Factor
)
{
if (u8Mode == JPEG_ENC_UPSCALE_MODE)
{
JPEG_DEC_DISABLE_DOWNSCALING();
JPEG_ENC_ENABLE_UPSCALING();
}
else if (u8Mode == JPEG_DEC_PACKET_DOWNSCALE_MODE || u8Mode == JPEG_DEC_PLANAR_DOWNSCALE_MODE || u8Mode == JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE)
{
JPEG_DEC_ENABLE_DOWNSCALING();
JPEG_ENC_DISABLE_UPSCALING();
}
else if (u8Mode == JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE)
{
outp32(REG_JTSCALD, TSX_ON);
}
if (u8Mode == JPEG_DEC_PLANAR_DOWNSCALE_MODE || u8Mode == JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE)
outp32(REG_JPSCALD, (inp32(REG_JPSCALD) & ~(PSCALX_F | PSCALY_F)) | ((u16FactorW & 0x1F) << 8) | (u16FactorH & 0x1F));
else if (u8Mode == JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE)
outp32(REG_JTSCALD, (inp32(REG_JTSCALD) & ~(TSCALX_F | TSCALY_F)) | ((u16FactorW & 0x1F) << 8) | (u16FactorH & 0x1F));
else
{
outp32(REG_JPSCALD, inp32(REG_JPSCALD) & ~(PSCALX_F | PSCALY_F));
outp32(REG_JUPRAT, ((u16FactorH & 0x3FFF) << 16) | (u16FactorW & 0x3FFF));
}
return E_SUCCESS;
}
static VOID jpegGetDecodedDimension(
PUINT16 pu16Height, //Decode/Encode Height
PUINT16 pu16Width //Decode/Encode Width
)
{
*pu16Width = inp32(REG_JDECWH) & 0x0000FFFF;
*pu16Height = inp32(REG_JDECWH) >> 16;
}
static VOID jpegSetDimension(
UINT16 u16Height, //Decode/Encode Height
UINT16 u16Width //Decode/Encode Width
)
{
outp32(REG_JPRIWH, ((u16Height & 0x1FFF) << 16) | (u16Width & 0x1FFF));
}
static VOID jpegGetDimension(
PUINT16 pu16Height, //Decoded Height from bit stream
PUINT16 pu16Width //Decoded Width from bit stream
)
{
*pu16Height = inp32(REG_JPRIWH) >> 16;
*pu16Width = inp32(REG_JPRIWH) & 0x1FFF;
}
static INT jpegSetWindowDecode(
UINT16 u16StartMCUX, //Start X MCU
UINT16 u16StartMCUY, //Horizontal Scaling Factor
UINT16 u16EndMCUX, //Vertical Scaling Factor
UINT16 u16EndMCUY, //Horizontal Scaling Factor
UINT32 u32Stride //Decode Output Stride
)
{
if (u16StartMCUX >= u16EndMCUX || u16StartMCUY >= u16EndMCUY)
return E_JPEG_INVALID_PARAM;
outp32(REG_JWINDEC0, u16StartMCUY << 16 | u16StartMCUX);
outp32(REG_JWINDEC1, u16EndMCUY << 16 | u16EndMCUX);
outp32(REG_JWINDEC2, u32Stride);
outp32(REG_JMCR, WIN_DEC);
//sysprintf("\tJWINDEC0 0x%X\n", inp32(REG_JWINDEC0));
//sysprintf("\tJWINDEC1 0x%X\n", inp32(REG_JWINDEC1));
//sysprintf("\tJWINDEC2 0x%X\n", inp32(REG_JWINDEC2));
return E_SUCCESS;
}
/**
* @brief The function is used to set JPEG Q Table.
*
* @param[in] puQTable0: Q Table 0
* @param[in] puQTable1: Q Table 1
* @param[in] puQTable2: Q Table 2
* @param[in] u8num: Q Table number
*
* @return E_JPEG_TIMEOUT: Time-out \n
* E_SUCCESS: success
*/
static INT _jpegSetQTAB(PUINT8 puQTable0, PUINT8 puQTable1, PUINT8 puQTable2, UINT8 u8num)
{
UINT32 u32value;
UINT32 u32TimeOut;
int i;
u32TimeOut = 0xFFFFFF;
for (i = 0; i < 64; i = i + 4)
{
while ((inp32(REG_JMCR) & QT_BUSY) & u32TimeOut)
u32TimeOut--;
if (!u32TimeOut)
return E_JPEG_TIMEOUT;
u32value = puQTable0[i] | (puQTable0[i + 1] << 8) | (puQTable0[i + 2] << 16) | (puQTable0[i + 3] << 24);
outp32((REG_JQTAB0 + i), u32value);
}
u32TimeOut = 0xFFFFFF;
for (i = 0; i < 64; i = i + 4)
{
while ((inp32(REG_JMCR) & QT_BUSY) & u32TimeOut)
u32TimeOut--;
if (!u32TimeOut)
return E_JPEG_TIMEOUT;
u32value = puQTable1[i] | (puQTable1[i + 1] << 8) | (puQTable1[i + 2] << 16) | (puQTable1[i + 3] << 24);
outp32((REG_JQTAB1 + i), u32value);
}
if (u8num < 3)
return E_SUCCESS;
outp32(JITCR, inp32(JITCR) | 0x8);
u32TimeOut = 0xFFFFFF;
for (i = 0; i < 64; i = i + 4)
{
while ((inp32(REG_JMCR) & QT_BUSY) & u32TimeOut)
u32TimeOut--;
if (!u32TimeOut)
return E_JPEG_TIMEOUT;
u32value = puQTable2[i] | (puQTable2[i + 1] << 8) | (puQTable2[i + 2] << 16) | (puQTable2[i + 3] << 24);
outp32((REG_JQTAB2 + i), u32value);
}
u32TimeOut = 0xFFFFFF;
while ((inp32(REG_JMCR) & QT_BUSY) & u32TimeOut)
u32TimeOut--;
if (!u32TimeOut)
return E_JPEG_TIMEOUT;
else
return E_SUCCESS;
}
INT jpegSetQTAB(PUINT8 puQTable0, PUINT8 puQTable1, PUINT8 puQTable2, UINT8 u8num)
{
INT ret = 0;
struct nu_jpeg_ioctl sNuJpegIoctl = {0};
struct nu_jpeg_qtab sNuJpegQTab = {0};
sNuJpegQTab.puQTable0 = puQTable0;
sNuJpegQTab.puQTable1 = puQTable1;
sNuJpegQTab.puQTable2 = puQTable2;
sNuJpegQTab.u8num = u8num;
sNuJpegIoctl.arg0 = (UINT32)&sNuJpegQTab;
sNuJpegIoctl.arg1 = (UINT32)&ret;
rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_SET_QTAB, (void *)&sNuJpegIoctl);
return ret;
}
/// @endcond HIDDEN_SYMBOLS
/** @addtogroup N9H30_JPEG_EXPORTED_FUNCTIONS JPEG Exported Functions
@{
*/
/**
* @brief The function is used to initial device parameters and register.
*
* @return 0
*/
static VOID _jpegInit(void)
{
/* Set the default values of the JPEG registers */
g_bScale = FALSE;
g_u32Stride = 0;
g_u32BufferCount = 0;
g_u16ReserveSize = 0;
g_u32WindowDec = FALSE;
g_u32windowSizeX = 0;
g_u32windowSizeY = 0;
g_InputWait = FALSE;
g_bEncThumbnailDownScale = FALSE;
g_bEncPrimaryDownScale = FALSE;
g_OutputWait = FALSE;
g_u32EncRotate = 0;
pfnJpegHeaderDecode = NULL;
pfnJpegDecInputWait = NULL;
pfnJpegDecOutputWait = NULL;
outp32(REG_JPRIQC, 0x000000F4);
outp32(REG_JTHBQC, 0x000000F4);
outp32(REG_JPRST, 0x00000004);
outp32(REG_JTRST, 0x00000004);
outp32(REG_JITCR, 0x00000000);
outp32(REG_JINTCR, 0x00000000);
outp32(JDOWFBS, 0xFFFFFFFF);
// Disable the Primary Up-scaling & Scaling-down
outp32(REG_JPSCALU, 0x00000000);
outp32(REG_JPSCALD, 0x00000000);
// Reset JUPRAT and JSRCH
outp32(REG_JUPRAT, 0x00000000);
outp32(REG_JSRCH, 0x00000FFF);
//-------------------------------------------
/* Reset JPEG (JMCR [1]) */
outp32(REG_JMCR, 0x00000002);
outp32(REG_JMCR, 0x00000000);
outp32(REG_JMACR, 0x00400000); //Can't use single buffer
}
VOID jpegInit(void)
{
rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_INITIAL_CODEC, (void *)RT_NULL);
}
/**
* @brief The function is used to check JPEG engine not busy.
*
* @return TRUE: JPEG engine busy \n
* FALSE: JPEG engine not busy
*/
static BOOL _jpegIsReady(void)
{
if (g_bWait == FALSE)
return TRUE;
else
return FALSE;
}
BOOL jpegIsReady(void)
{
UINT32 u32IsReady = 0;
struct nu_jpeg_ioctl sNuJpegIoctl = {0};
sNuJpegIoctl.arg0 = (UINT32)&u32IsReady;
rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_IS_READY, (void *)&sNuJpegIoctl);
return (BOOL)u32IsReady;
}
/**
* @brief The function is used to get JPEG information.
*
* @param[out] *info: JPEG encode/decode information.
*
* @return 0
*/
static VOID _jpegGetInfo(JPEG_INFO_T *info)
{
rt_memcpy(info, &jpegInfo, sizeof(JPEG_INFO_T));
}
VOID jpegGetInfo(JPEG_INFO_T *info)
{
struct nu_jpeg_ioctl sNuJpegIoctl = {0};
sNuJpegIoctl.arg0 = (UINT32)info;
rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_GET_INFO, (void *)&sNuJpegIoctl);
}
/**
* @brief The function is used to wait JPEG engine, until JPEG engine not busy.
*
* @return E_SUCCESS: JPEG engine encode/decode complete \n
* FALSE: JPEG engine error
*/
static INT _jpegWait(void)
{
while (1)
{
if (g_bWait == FALSE)
break;
}
if (g_jpegError)
return E_FAIL;
return E_SUCCESS;
}
INT jpegWait(void)
{
INT ret = 0;
struct nu_jpeg_ioctl sNuJpegIoctl;
sNuJpegIoctl.arg0 = (UINT32)&ret;
sNuJpegIoctl.arg1 = 0;
rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_WAITDONE, (void *)&sNuJpegIoctl);
return ret;
}
/**
* @brief The function is used to config and reset JPEG IP.
*
* @return E_SUCCESS: success
*/
INT jpegOpen(void)
{
return (rt_device_open(&g_sNuJpeg.dev, RT_DEVICE_FLAG_RDWR) == RT_EOK) ? E_SUCCESS : E_FAIL;
}
/**
* @brief Support some JPEG driver commands for application.
*
* @param[in] cmd: Command.
*
* @param[in] arg0: Arguments for the command.
*
* @param[in] arg1: Arguments for the command.
*
* @return 0
*
*/
VOID jpegIoctl(UINT32 cmd, UINT32 arg0, UINT32 arg1)
{
struct nu_jpeg_ioctl sNuJpegIoctl;
sNuJpegIoctl.arg0 = arg0;
sNuJpegIoctl.arg1 = arg1;
rt_device_control(&g_sNuJpeg.dev, cmd, (void *)&sNuJpegIoctl);
}
/**
* @brief JPEG function close.
*
* @return 0
*
*/
VOID jpegClose(void)
{
rt_device_close(&g_sNuJpeg.dev);
}
static rt_err_t nu_jpeg_init(rt_device_t dev)
{
UINT32 u32JPGDiv = 0;
UINT32 u32JPGSource;
UINT32 u32HclkHz;
nu_jpeg_t psNuJpeg = (nu_jpeg_t)dev;
RT_ASSERT(dev != RT_NULL);
/* Set JPEG engine clock */
u32HclkHz = sysGetClock(SYS_HCLK234) * 1000000;
u32JPGSource = u32HclkHz / (((inp32(REG_CLK_DIVCTL3) & 0xf0000000) >> 28) + 1);
if (u32JPGSource > 75000000)
{
if (u32JPGSource % 75000000)
{
u32JPGDiv = (u32JPGSource / 75000000);
}
else
u32JPGDiv = (u32JPGSource / 75000000) - 1;
}
outp32(REG_CLK_DIVCTL3, (inp32(REG_CLK_DIVCTL3) & ~(0xf0000000)) | ((u32JPGDiv & 0xf) << 28));
rt_kprintf("JPEG Engine clock frequency is %d MHz\n", u32JPGSource / (u32JPGDiv + 1) / 1000000);
/* Register ISR and Response JPEG Interrupt. */
rt_hw_interrupt_install(psNuJpeg->irqn, nu_jpeg_isr, (void *)psNuJpeg, psNuJpeg->name);
rt_hw_interrupt_umask(psNuJpeg->irqn);
return RT_EOK;
}
static rt_err_t nu_jpeg_open(rt_device_t dev, rt_uint16_t oflag)
{
rt_err_t result;
nu_jpeg_t psNuJpeg = (nu_jpeg_t)dev;
result = rt_mutex_take(&psNuJpeg->lock, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Enable JPEG engine clock */
nu_sys_ipclk_enable(psNuJpeg->clkidx);
/* Reset JPEG codec and internal variables. */
nu_sys_ip_reset(psNuJpeg->rstidx);
jpegInit();
result = rt_mutex_release(&psNuJpeg->lock);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}
static rt_err_t nu_jpeg_close(rt_device_t dev)
{
rt_err_t result;
nu_jpeg_t psNuJpeg = (nu_jpeg_t)dev;
RT_ASSERT(dev != RT_NULL);
result = rt_mutex_take(&psNuJpeg->lock, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Reset JPEG (JMCR [1]) */
outp32(REG_JMCR, 0x00000002);
outp32(REG_JMCR, 0x00000000);
/* Disable JPEG engine clock */
nu_sys_ipclk_disable(psNuJpeg->clkidx);
result = rt_mutex_release(&psNuJpeg->lock);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}
static rt_err_t nu_jpeg_control(rt_device_t dev, int cmd, void *args)
{
JPEG_WINDOW_DECODE_T *winDecode;
PUINT32 pu32Tmp;
UINT32 arg0 = 0, arg1 = 0;
rt_err_t result;
nu_jpeg_t psNuJpeg = (nu_jpeg_t)dev;
nu_jpeg_ioctl_t psNuJpegIoctl = (nu_jpeg_ioctl_t)args;
RT_ASSERT(dev != RT_NULL);
result = rt_mutex_take(&psNuJpeg->lock, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
if (psNuJpegIoctl != RT_NULL)
{
arg0 = psNuJpegIoctl->arg0;
arg1 = psNuJpegIoctl->arg1;
}
switch (cmd)
{
case JPEG_IOCTL_SET_YADDR:
JPEG_SET_YADDR(arg0);
break;
case JPEG_IOCTL_SET_UADDR:
JPEG_SET_UADDR(arg0);
break;
case JPEG_IOCTL_SET_VADDR:
JPEG_SET_VADDR(arg0);
break;
case JPEG_IOCTL_SET_YSTRIDE:
JPEG_SET_YSTRIDE(arg0);
break;
case JPEG_IOCTL_SET_USTRIDE:
JPEG_SET_USTRIDE(arg0);
break;
case JPEG_IOCTL_SET_VSTRIDE:
JPEG_SET_VSTRIDE(arg0);
break;
case JPEG_IOCTL_SET_BITSTREAM_ADDR:
JPEG_SET_BITSTREAM_ADDR(arg0);
break;
case JPEG_IOCTL_SET_SOURCE_IMAGE_HEIGHT:
JPEG_SET_SOURCE_IMAGE_HEIGHT(arg0);
break;
case JPEG_IOCTL_ENC_SET_HEADER_CONTROL:
JPEG_ENC_SET_HEADER_CONTROL(arg0);
break;
case JPEG_IOCTL_SET_DEFAULT_QTAB:
jpegSetQTAB(g_au8QTable0, g_au8QTable1, 0, 2);
break;
case JPEG_IOCTL_SET_DECODE_MODE:
jpegSetDecodeMode(arg0);
break;
case JPEG_IOCTL_SET_ENCODE_MODE:
jpegSetEncodeMode(arg0, arg1);
break;
case JPEG_IOCTL_SET_DIMENSION:
jpegSetDimension(arg0, arg1);
break;
case JPEG_IOCTL_ENCODE_TRIGGER:
jpegEncodeTrigger();
if (g_u16ReserveSize != 0)
{
UINT32 u32Addr = JPEG_GET_BITSTREAM_ADDR();
outp8(u32Addr + 2, 0xFF);
outp8(u32Addr + 3, 0xE0);
outp8(u32Addr + 4, ((g_u16ReserveSize - 4) & 0xFF00) >> 8);
outp8(u32Addr + 5, (g_u16ReserveSize - 4) & 0xFF);
}
break;
case JPEG_IOCTL_DECODE_TRIGGER:
jpegDecodeTrigger();
break;
case JPEG_IOCTL_WINDOW_DECODE:
winDecode = (JPEG_WINDOW_DECODE_T *)arg0;
jpegSetWindowDecode(winDecode->u16StartMCUX, winDecode->u16StartMCUY,
winDecode->u16EndMCUX, winDecode->u16EndMCUY, winDecode->u32Stride);
g_u32WindowDec = TRUE;
g_u32windowSizeX = winDecode->u32Stride;
g_u32windowSizeY = 16 * (winDecode->u16EndMCUY - winDecode->u16StartMCUY + 1);
break;
case JPEG_IOCTL_SET_DECODE_STRIDE:
g_u32Stride = arg0;
break;
case JPEG_IOCTL_SET_DECODE_DOWNSCALE:
g_bScale = TRUE;
g_u32ScaleWidth = arg1;
g_u32ScaleHeight = arg0;
break;
case JPEG_IOCTL_SET_ENCODE_UPSCALE:
g_bScale = TRUE;
g_u32ScaleWidth = arg1;
g_u32ScaleHeight = arg0;
break;
case JPEG_IOCTL_SET_HEADERDECODE_CALBACKFUN:
pfnJpegHeaderDecode = (PFN_JPEG_HEADERDECODE_CALLBACK) arg0;
break;
case JPEG_IOCTL_SET_DECINPUTWAIT_CALBACKFUN:
g_InputWait = TRUE;
pfnJpegDecInputWait = (PFN_JPEG_DECWAIT_CALLBACK) arg0;
JPEG_DEC_SET_INPUT_WAIT(((UINT16) arg1 / 2048));
g_u16BufferSize = arg1 / 2;
break;
case JPEG_IOCTL_ADJUST_QTAB:
jpegAdjustQTAB(arg0, ((arg1 & 0xFF00) >> 4), (arg1 & 0xFF));
break;
case JPEG_IOCTL_ENC_RESERVED_FOR_SOFTWARE:
if (arg0 > 0)
{
UINT32 u32Tmp;
u32Tmp = arg0 + 4;
if (u32Tmp % 2)
u32Tmp++;
if ((u32Tmp % 4) == 0)
u32Tmp += 2;
if (u32Tmp >= 0xFFFF)
u32Tmp = 65534;
outp32(REG_JPSCALU, inp32(REG_JPSCALU) | A_JUMP);
outp32(JRESERVE, u32Tmp);
g_u16ReserveSize = u32Tmp;
}
break;
case JPEG_IOCTL_SET_ENCODE_PRIMARY_RESTART_INTERVAL:
outp32(REG_JPRST, arg0);
break;
case JPEG_IOCTL_SET_ENCODE_THUMBNAIL_RESTART_INTERVAL:
outp32(REG_JTRST, arg0);
break;
case JPEG_IOCTL_GET_ENCODE_PRIMARY_RESTART_INTERVAL:
pu32Tmp = (PUINT32) arg0;
*pu32Tmp = inp32(REG_JPRST);
break;
case JPEG_IOCTL_GET_ENCODE_THUMBNAIL_RESTART_INTERVAL:
pu32Tmp = (PUINT32) arg0;
*pu32Tmp = inp32(REG_JTRST);
break;
case JPEG_IOCTL_SET_THUMBNAIL_DIMENSION:
outp32(REG_JTHBWH, ((arg0 & 0x1FFF) << 16) | (arg1 & 0x1FFF));
break;
case JPEG_IOCTL_SET_ENCODE_SW_OFFSET:
outp32(REG_JOFFSET, arg0);
break;
case JPEG_IOCTL_GET_THUMBNAIL_DIMENSION:
pu32Tmp = (PUINT32) arg0;
*pu32Tmp = inp32(REG_JTHBWH) >> 16;
pu32Tmp = (PUINT32) arg1;
*pu32Tmp = inp32(REG_JTHBWH) & 0x1FFF;
break;
case JPEG_IOCTL_GET_ENCODE_SW_OFFSET:
pu32Tmp = (PUINT32) arg0;
*pu32Tmp = inp32(REG_JOFFSET);
break;
case JPEG_IOCTL_SET_ENCODE_PRIMARY_DOWNSCALE:
g_bScale = TRUE;
g_bEncPrimaryDownScale = TRUE;
g_u32ScaleWidth = arg1;
g_u32ScaleHeight = arg0;
break;
case JPEG_IOCTL_SET_ENCODE_THUMBNAIL_DOWNSCALE:
g_bScale = TRUE;
g_bEncThumbnailDownScale = TRUE;
g_u32ScaleWidth = arg1;
g_u32ScaleHeight = arg0;
break;
case JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_RIGHT:
g_u32EncRotate = JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_RIGHT;
outp32(REG_JITCR, (inp32(REG_JITCR) & ~ROTATE) | ROTATE);
break;
case JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_LEFT:
g_u32EncRotate = JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_LEFT;
outp32(REG_JITCR, (inp32(REG_JITCR) & ~ROTATE) | 0x1000);
break;
case JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_NORMAL:
g_u32EncRotate = 0;
outp32(REG_JITCR, (inp32(REG_JITCR) & ~ROTATE));
break;
case JPEG_IOCTL_SET_DECOUTPUTWAIT_CALBACKFUN:
pfnJpegDecOutputWait = (PFN_JPEG_DECWAIT_CALLBACK) arg0;
break;
case JPEG_IOCTL_SET_DECOUTPUTWAIT:
outp32(JYADDR0, arg0);
outp32(JDOWFBS, arg1);
g_OutputWait = TRUE;
break;
case JPEG_IOCTL_GET_DECOUTPUTWAIT_ADDR:
pu32Tmp = (PUINT32) arg0;
*pu32Tmp = inp32(JYADDR0);
break;
case JPEG_IOCTL_GET_DECOUTPUTWAIT_SIZE:
pu32Tmp = (PUINT32) arg0;
*pu32Tmp = inp32(JDOWFBS);
break;
case JPEG_IOCTL_SET_DECODE_COMPLETE_CALBACKFUN:
pfnJpegDecodeComplete = (PFN_JPEG_CALLBACK) arg0;
break;
case JPEG_IOCTL_SET_ENCODE_COMPLETE_CALBACKFUN:
pfnJpegEncodeComplete = (PFN_JPEG_CALLBACK) arg0;
break;
case JPEG_IOCTL_SET_DECODE_ERROR_CALBACKFUN:
pfnJpegDecodeError = (PFN_JPEG_CALLBACK) arg0;
break;
/* Extended IOCTL command */
case JPEG_IOCTL_SET_QTAB:
{
nu_jpeg_qtab_t psJpegQtab = (nu_jpeg_qtab_t)arg0;
INT *pi32ret = (INT *)arg1;
*pi32ret = _jpegSetQTAB(psJpegQtab->puQTable0, psJpegQtab->puQTable1, psJpegQtab->puQTable2, psJpegQtab->u8num);
}
break;
case JPEG_IOCTL_INITIAL_CODEC:
_jpegInit();
break;
case JPEG_IOCTL_GET_INFO:
_jpegGetInfo((JPEG_INFO_T *)arg0);
break;
case JPEG_IOCTL_IS_READY:
{
UINT32 *pu32ret = (UINT32 *)arg0;
*pu32ret = _jpegIsReady();
}
break;
case JPEG_IOCTL_WAITDONE:
{
INT *pi32ret = (INT *)arg0;
*pi32ret = _jpegWait();
}
break;
default:
break;
}
result = rt_mutex_release(&psNuJpeg->lock);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}
/* Hardward JPEG codec init */
static int rt_hw_jpeg_init(void)
{
rt_err_t ret = RT_EOK;
/* Register sdcard device */
g_sNuJpeg.dev.type = RT_Device_Class_Miscellaneous;
g_sNuJpeg.dev.init = nu_jpeg_init;
g_sNuJpeg.dev.open = nu_jpeg_open;
g_sNuJpeg.dev.close = nu_jpeg_close;
g_sNuJpeg.dev.read = RT_NULL;
g_sNuJpeg.dev.write = RT_NULL;
g_sNuJpeg.dev.control = nu_jpeg_control;
/* Private */
g_sNuJpeg.dev.user_data = (void *)&g_sNuJpeg;
ret = rt_mutex_init(&g_sNuJpeg.lock, "jpeg_lock", RT_IPC_FLAG_PRIO);
RT_ASSERT(ret == RT_EOK);
/* Only support single opening. */
ret = rt_device_register(&g_sNuJpeg.dev, g_sNuJpeg.name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
RT_ASSERT(ret == RT_EOK);
return (int)ret;
}
INIT_DEVICE_EXPORT(rt_hw_jpeg_init);