/**************************************************************************//** * @file jpegcodec.c * @version V3.00 * @brief N9H20 series JPEG driver source file * * SPDX-License-Identifier: Apache-2.0 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. *****************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "wbio.h" #include "wblib.h" #include "wbtypes.h" #include "N9H20_JPEG.h" #include "jpeg.h" BOOL volatile g_bWait = FALSE, g_jpegError = FALSE, g_bScale = FALSE, g_InputWait = FALSE,g_u32WindowDec = FALSE,g_bEncThumbnailDownScale = FALSE,g_bEncPrimaryDownScale =FALSE; UINT32 volatile g_u32Stride, g_u32ScaleWidth, g_u32ScaleHeight, g_u32OpMode,g_u32EncRotate = 0; UINT32 volatile g_u32BufferCount,g_u32DecInputWaitAddr; UINT16 volatile g_u16BufferSize, g_u16ReserveSize; UINT32 volatile g_u32OutputFormat,g_u32windowSizeX,g_u32windowSizeY; PFN_JPEG_HEADERDECODE_CALLBACK pfnJpegHeaderDecode = NULL; PFN_JPEG_DECINPUTWAIT_CALLBACK pfnJpegDecInputWait = NULL; static JPEG_INFO_T jpegInfo; /* Default Quantization-Table 0 ~ 2 */ 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 }, g_au8QTable2[64] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; /* Interrupt Service Routine for H/W JPEG CODEC */ void jpegISR(void) { 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 = 0, u16HeightTmp = 0; /* 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_JPEG_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); /* Clear interrupt status */ JPEG_CLEAR_INT(DHE_INTS); } /* 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; } /* 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); g_bWait = FALSE; } /* It's Decode Error Interrupt */ else if(u32interruptStatus & DER_INTS) { /* Clear interrupt status */ JPEG_CLEAR_INT(DER_INTS); g_bWait = FALSE; g_jpegError = TRUE; } 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); } } INT jpegWait(VOID) { while(1) { if(g_bWait == FALSE) break; } if(g_jpegError) return E_JPEG_FAIL; return E_JPEG_SUCCESS; } BOOL jpegIsReady(VOID) { if (g_bWait == FALSE) return TRUE; else return FALSE; } VOID jpegGetInfo(JPEG_INFO_T *info) { memcpy(info, &jpegInfo, sizeof(JPEG_INFO_T)); } 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; } INT jpegOpen(VOID) { UINT32 u32JPGDiv; UINT32 u32JPGSource; E_SYS_SRC_CLK eSrcClk; UINT32 u32PllKHz, u32SysKHz, u32CpuKHz, u32HclkKHz, u32ApbKHz; /* 1.Check I/O pins. If I/O pins are used by other IPs, return error code (check PINFUN) */ /* 2.Enable IP��s clock */ outp32(REG_AHBCLK, (inp32(REG_AHBCLK) | JPG_CKE)); // 3.Reset IP */ outp32(REG_AHBIPRST, JPGRST); outp32(REG_AHBIPRST, 0); /* 4.Configure IP according to inputted arguments (check CLKSEL) */ /* 5.Enable IP I/O pins */ /* 6.Return E_JPEG_SUCCESS to present success */ sysGetSystemClock(&eSrcClk, &u32PllKHz, &u32SysKHz, &u32CpuKHz, &u32HclkKHz, &u32ApbKHz); u32JPGSource = u32HclkKHz / (((inp32(REG_CLKDIV4) & HCLK234_N) >> 4) + 1); u32JPGDiv = 0; if(u32JPGSource > 100000) { if(u32JPGSource % 100000) { u32JPGDiv = (u32JPGSource / 100000); } else u32JPGDiv = (u32JPGSource / 100000) - 1; } outp32(REG_CLKDIV4, (inp32(REG_CLKDIV4) & ~JPG_N) | ((u32JPGDiv & 0x7) << 24)); sysInstallISR(IRQ_LEVEL_1, IRQ_JPG, (PVOID)jpegISR); sysSetLocalInterrupt(ENABLE_IRQ); sysEnableInterrupt(IRQ_JPG); return E_JPEG_SUCCESS; } 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_u32EncRotate = 0; pfnJpegHeaderDecode = NULL; pfnJpegDecInputWait = NULL; outp32(REG_JPRIQC, 0x000000F4); outp32(REG_JTHBQC, 0x000000F4); outp32(REG_JPRST, 0x00000004); outp32(REG_JTRST, 0x00000004); outp32(REG_JITCR, 0x00000000); /* 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 */ } 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_JPEG_SUCCESS; } 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_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_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_JPEG_SUCCESS; } VOID jpegDecodeTrigger(VOID) { g_bWait = TRUE; g_jpegError = FALSE; 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(); JPEG_INT_ENABLE( DEC_INTE | DER_INTE | DHE_INTE | IPW_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); outp32(REG_JMCR, JPG_EN | inp32(REG_JMCR)); outp32(REG_JMCR, ~JPG_EN & inp32(REG_JMCR)); } 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; 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_JPEG_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)); } 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_JPEG_SUCCESS; } 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_JPEG_SUCCESS; } VOID jpegGetDecodedDimension( PUINT16 pu16Height, /* Decode/Encode Height */ PUINT16 pu16Width /* Decode/Encode Width */ ) { *pu16Width = inp32(REG_JDECWH) & 0x0000FFFF; *pu16Height = inp32(REG_JDECWH) >> 16; } VOID jpegSetDimension( UINT16 u16Height, /* Decode/Encode Height */ UINT16 u16Width /* Decode/Encode Width */ ) { outp32(REG_JPRIWH,((u16Height & 0x1FFF)<<16) | (u16Width & 0x1FFF) ); } 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; } 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; } } 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); return E_JPEG_SUCCESS; } 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_JPEG_SUCCESS; } 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_JPEG_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_JPEG_SUCCESS; } VOID jpegIoctl(UINT32 cmd, UINT32 arg0, UINT32 arg1) { JPEG_WINDOW_DECODE_T *winDecode; PUINT32 pu32Tmp; 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_DECINPUTWAIT_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; default: break; } } VOID jpegClose(VOID) { /* Reset JPEG (JMCR [1]) */ outp32(REG_JMCR,0x00000002); outp32(REG_JMCR,0x00000000); outp32(REG_AHBCLK, (inp32(REG_AHBCLK) & ~JPG_CKE)); sysDisableInterrupt(IRQ_JPG); } /* Poll the interrupt status and get if the interrupt is generated */ BOOL jpegPollInt(UINT32 u32Intflag) { if(JPEG_GET_INT_STATUS() & u32Intflag) return 1; else return 0; }