/**************************************************************************//**
* @file     jpegcodec.c
* @brief    N9H30 JPEG driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "N9H30.h"
#include "sys.h"
#include "jpegcodec.h"
#include "jpeg.h"

/** @addtogroup N9H30_Device_Driver N9H30 Device Driver
  @{
*/

/** @addtogroup N9H30_JPEG_Driver JPEG Driver
  @{
*/

/// @cond HIDDEN_SYMBOLS

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;
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_CALLBACK pfnJpegDecodeComplete = NULL;
PFN_JPEG_CALLBACK pfnJpegDecodeError = NULL;
PFN_JPEG_CALLBACK pfnJpegEncodeComplete = NULL;
PFN_JPEG_HEADERDECODE_CALLBACK pfnJpegHeaderDecode = NULL;
PFN_JPEG_DECWAIT_CALLBACK pfnJpegDecInputWait = NULL;
PFN_JPEG_DECWAIT_CALLBACK pfnJpegDecOutputWait = 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, 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);

    }

}

//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;
}

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;
}


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 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;
}

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;
}

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();
        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));
}

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_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_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_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);
    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;
}

/// @endcond HIDDEN_SYMBOLS


/** @addtogroup N9H30_JPEG_EXPORTED_FUNCTIONS JPEG Exported Functions
  @{
*/

/**
  * @brief    The function is used to config and reset JPEG IP.
  *
  * @return   E_SUCCESS: success
  */
INT jpegOpen(void)
{
    UINT32 u32JPGDiv;
    UINT32 u32JPGSource;
    UINT32  u32HclkHz;

    // 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_CLK_HCLKEN, (inp32(REG_CLK_HCLKEN) | (1 << 29))); // Enable JPEG clock

    //u32HclkHz =   sysGetHCLK1Clock();
    u32HclkHz = sysGetClock(SYS_HCLK234) * 1000000;
    u32JPGSource = u32HclkHz / (((inp32(REG_CLK_DIVCTL3) & 0xf0000000) >> 28) + 1);

    u32JPGDiv = 0;

    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));

    //sysprintf("jpeg engine is %dHz\n",u32JPGSource / (u32JPGDiv+1));

    // 3.Reset IP
    outp32(REG_SYS_AHBIPRST, (1 << 22));  // JPEG IP Reset
    outp32(REG_SYS_AHBIPRST, 0);
    // 4.Configure IP according to inputted arguments (check CLKSEL)
    sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), JPEG_IRQn, (PVOID)jpegISR);
    sysSetLocalInterrupt(ENABLE_IRQ);
    sysEnableInterrupt(JPEG_IRQn);
    // 5.Enable IP I/O pins
    // 6.Return E_SUCCESS to present success
    return E_SUCCESS;
}

/**
  * @brief    The function is used to initial device parameters and register.
  *
  * @return   0
  */
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
}

/**
  * @brief    The function is used to check JPEG engine not busy.
  *
  * @return   TRUE: JPEG engine busy  \n
  *           FALSE: JPEG engine not busy
  */
BOOL jpegIsReady(void)
{
    if (g_bWait == FALSE)
        return TRUE;
    else
        return FALSE;
}

/**
  * @brief    The function is used to get JPEG information.
  *
  * @param[out]   *info: JPEG encode/decode information.
  *
  * @return   0
  */
VOID jpegGetInfo(JPEG_INFO_T *info)
{
    memcpy(info, &jpegInfo, sizeof(JPEG_INFO_T));
}

/**
  * @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
  */
INT jpegWait(void)
{
    while(1) {
        if(g_bWait == FALSE)
            break;
    }

    if(g_jpegError)
        return E_FAIL;

    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
  */
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;

}

/**
  * @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)
{
    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_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;
        default:
            break;
    }
}

/**
  * @brief    JPEG function close.
  *
  * @return   0
  *
  */
VOID jpegClose(void)
{

    /* Reset JPEG (JMCR [1]) */
    outp32(REG_JMCR,0x00000002);
    outp32(REG_JMCR,0x00000000);

    //outp32(REG_AHBCLK, (inp32(REG_AHBCLK) & ~JPG_CKE));

    sysDisableInterrupt(JPEG_IRQn);
}



/*@}*/ /* end of group N9H30_JPEG_EXPORTED_FUNCTIONS */

/*@}*/ /* end of group N9H30_JPEG_Driver */

/*@}*/ /* end of group N9H30_Device_Driver */


/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/


