/*
 * Project Name JPEG DRIVER IN WINCE
 * Copyright  2007 Samsung Electronics Co, Ltd. All Rights Reserved.
 *
 * This software is the confidential and proprietary information
 * of Samsung Electronics  ("Confidential Information").
 * you shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Samsung Electronics
 *
 * This file implements JPEG driver.
 *
 * @name JPEG DRIVER MODULE Module (JPGOpr.c)
 * @author Jiyoung Shin (idon.shin@samsung.com)
 * @date 28-03-07
 */

#include "JPGMem.h"
#include "JPGMisc.h"
#include "JPGOpr.h"
#include "JPGConf.h"
#include "jpg_reg.h"
#include "JPGIntr.h"
#include "bsp_args.h"

#define INT_JPG_CLOCK_ON    1
#define INT_JPG_CLOCK_OFF   0

enum
{
    UNKNOWN,
    BASELINE = 0xC0,
    EXTENDED_SEQ = 0xC1,
    PROGRESSIVE = 0xC2
} JPG_SOF_MARKER;



/*----------------------------------------------------------------------------
*Function: resetJPG

*Parameters:    jCTX:
*Return Value:
*Implementation Notes:
-----------------------------------------------------------------------------*/
void resetJPG()
{
    volatile JPG_SFR *JpgSfr;
    int count = 0;
    
    DBGMSG(JPG_FUNC,(_T("[JPGDRV] %s++\r\n"), _T(__FUNCTION__)));
    JpgSfr = GetJPGSfrVirAddr();

    JpgSfr->JPGSW_RESET = 1;
    do
    {
        JPGDelay(1);
        if(count++ > 1000){
            ERRMSG((_T("[JPGDRV] %s :: JPG Reset failed(timeout)\r\n"), _T(__FUNCTION__)));
            break;
        }
    } while (JpgSfr->JPGSW_RESET != 0);
    
     DBGMSG(JPG_FUNC,(_T("[JPGAPI] %s--\r\n"), _T(__FUNCTION__)));   
}


/*----------------------------------------------------------------------------
*Function: resetJPG

*Parameters:    jCTX:
*Return Value:
*Implementation Notes:
-----------------------------------------------------------------------------*/
void setInternalClock(int on_off)
{
    volatile JPG_SFR *JpgSfr;

    JpgSfr = GetJPGSfrVirAddr();

    JpgSfr->JPGCLKCON = on_off;
}

/*----------------------------------------------------------------------------
*Function:    getSampleType

*Parameters:    jCTX:
*Return Value:
*Implementation Notes:
-----------------------------------------------------------------------------*/
SAMPLE_MODE_T getSampleType()
{
    volatile JPG_SFR *JpgSfr;
    SAMPLE_MODE_T sampleMode;

    DBGMSG(JPG_FUNC,(_T("[JPGDRV] %s++\r\n"), _T(__FUNCTION__)));
    JpgSfr = GetJPGSfrVirAddr();

    sampleMode =
        ((JpgSfr->JPGMOD & JPG_SMPL_MODE_MASK) == JPG_444) ? JPG_444 :
        ((JpgSfr->JPGMOD & JPG_SMPL_MODE_MASK) == JPG_422) ? JPG_422 :
        ((JpgSfr->JPGMOD & JPG_SMPL_MODE_MASK) == JPG_420) ? JPG_420 :
        ((JpgSfr->JPGMOD & JPG_SMPL_MODE_MASK) == JPG_400) ? JPG_400 : JPG_SAMPLE_UNKNOWN;

    DBGMSG(JPG_FUNC,(_T("[JPGAPI] %s--\r\n"), _T(__FUNCTION__)));
    return(sampleMode);
}


/*----------------------------------------------------------------------------
*Function: getYUVSize

*Parameters:    sampleMode:
                width:
                height:
*Return Value:
*Implementation Notes:
-----------------------------------------------------------------------------*/
UINT32 getYUVSize(SAMPLE_MODE_T sampleMode, OUT_MODE_T outFormat, UINT32 width, UINT32 height, UINT32 *yuvwidth, UINT32 *yuvheight)
{
    *yuvwidth = width;
    *yuvheight = height;

    DBGMSG(JPG_FUNC,(_T("[JPGDRV] %s++\r\n"), _T(__FUNCTION__)));
    switch(sampleMode)
    {
        case JPG_400 :
        case JPG_444 :
            if((*yuvwidth % 8 == 0) && (*yuvheight % 8 == 0))
                break;
            if(*yuvwidth % 8 != 0)
                *yuvwidth += 8 - (*yuvwidth % 8);
            if(*yuvheight % 8 != 0)
                *yuvheight += 8 - (*yuvheight % 8);
            break;
	
        case JPG_422 :
            if((*yuvwidth % 16 == 0) && (*yuvheight % 8 == 0))
                break;
            if(*yuvwidth % 16 != 0)
                *yuvwidth += 16 - (*yuvwidth % 16);
            if(*yuvheight % 8 != 0)
                *yuvheight += 8 - (*yuvheight % 8);
            break;

        case JPG_420 :
            if((*yuvwidth % 16 == 0) && (*yuvheight % 16 == 0))
                break;;
            if(*yuvwidth % 16 != 0)
                *yuvwidth += 16 - (*yuvwidth % 16);
            if(*yuvheight % 16 != 0)
                *yuvheight += 16 - (*yuvheight % 16);
            break;
        default : 
            ERRMSG((_T("[JPGDRV] %s :: invalid samplemode\r\n"), _T(__FUNCTION__)));
            return(0);
    }

    DBGMSG(JPG_DBG,(_T("[JPGDRV] GetYUVSize : width(%d)xheight(%d) --> yuvwidth(%d)xyuvheight(%d)\r\n"), width, height, *yuvwidth, *yuvheight));
    switch(outFormat)
    {
        case YCBCR_422 : return((*yuvwidth)*(*yuvheight)*2);
        case YCBCR_420 : return(((*yuvwidth)*(*yuvheight)) + ((*yuvwidth)*(*yuvheight)>>1));
        default : 
            ERRMSG((_T("[JPGDRV] %s :: invalid outFormat\r\n"), _T(__FUNCTION__)));
            return(0);
    }

    DBGMSG(JPG_FUNC,(_T("[JPGAPI] %s--\r\n"), _T(__FUNCTION__)));
}


/*----------------------------------------------------------------------------
*Function: decodeJPG

*Parameters:    jCTX:
                input_buff:
                input_size:
                output_buff:
                output_size
*Return Value:
*Implementation Notes:
-----------------------------------------------------------------------------*/
JPG_RETURN_STATUS decodeJPG(JPG_CTX *jCTX, JPG_DEC_PROC_PARAM *decParam)
{
    int        ret;
    UINT32    width, height;
    UINT32    yuvwidth, yuvheight;
    BOOL    headerFixed = FALSE;
    volatile JPG_SFR *JpgSfr;

    DBGMSG(JPG_FUNC,(_T("[JPGDRV] %s++\r\n"), _T(__FUNCTION__)));

    ////////////////////////////////////////
    // Initialization                     //
    ////////////////////////////////////////
    if (jCTX)
        resetJPG();
    else
    {
        ERRMSG((_T("[JPGDRV] %s :: JPG CTX is NULL\r\n"), _T(__FUNCTION__)));
        return JPG_FAIL;
    }
    setInternalClock(INT_JPG_CLOCK_ON);

    ////////////////////////////////////////
    // Start Decoding                     //
    ////////////////////////////////////////

    JpgSfr = GetJPGSfrVirAddr();
    JpgSfr->JPGMOD = (0x1 << 3);
    JpgSfr->JPGINTSE = 0xe0; // enable interrupt
    JpgSfr->JPGOUTFORM = (decParam->outFormat == YCBCR_422)?0x0:0x1;
    JpgSfr->JPGIMGADR = jCTX->IMGDataAddr;
    JpgSfr->JPGADR = jCTX->JPGDataAddr;
    JpgSfr->JPGJSTART = 1;


    ret = waitForJPGIRQ();
    if(ret != OK_ENC_OR_DEC)
    {
        ERRMSG((_T("[JPGDRV] %s :: JPG Decoding Error(%d)\r\n"), _T(__FUNCTION__), ret));
        return JPG_FAIL;
    }

    ////////////////////////////////////////
    // Make return vale                   //
    ////////////////////////////////////////
    width = ((JpgSfr->JPGX_U << 8)|JpgSfr->JPGX_L);
    height =((JpgSfr->JPGY_U << 8)|JpgSfr->JPGY_L);
    decParam->sampleMode = getSampleType();
    decParam->dataSize = getYUVSize(decParam->sampleMode, decParam->outFormat, width, height, &yuvwidth, &yuvheight);
    decParam->width = width;
    decParam->height = height;
    decParam->yuvwidth = yuvwidth;
    decParam->yuvheight = yuvheight;
    DBGMSG(JPG_DBG,(_T("[JPGDRV] decodeJPG() - width:%d height:%d sampleMode : %d\r\n"), width, height, decParam->sampleMode));
    DBGMSG(JPG_DBG,(_T("[JPGDRV] decodeJPG() - yuvwidth:%d yuvheight:%d dataSize : %d\r\n"), yuvwidth, yuvheight, decParam->dataSize));

    setInternalClock(INT_JPG_CLOCK_OFF);

    DBGMSG(JPG_FUNC,(_T("[JPGAPI] %s--\r\n"), _T(__FUNCTION__)));
    return JPG_SUCCESS;
}



/*----------------------------------------------------------------------------
*Function: encodeJPG

*Parameters:    jCTX:
*Return Value:
*Implementation Notes:
-----------------------------------------------------------------------------*/
JPG_RETURN_STATUS encodeJPG(JPG_CTX*jCTX, JPG_ENC_PROC_PARAM    *EncParam)
{
    UINT    i, ret;
    volatile JPG_SFR *JpgSfr;
    unsigned int colorMode;


    DBGMSG(JPG_FUNC,(_T("[JPGDRV] %s++\r\n"), _T(__FUNCTION__)));

    if(	EncParam->width <= 0 || EncParam->width > MAX_JPG_WIDTH
        || EncParam->height <=0 || EncParam->height > MAX_JPG_HEIGHT)
    {
        ERRMSG((_T("[JPGDRV] %s :: Invalid width/height\r\n"), _T(__FUNCTION__)));
        return JPG_FAIL;
    }
    if (jCTX)
        resetJPG();
    else
    {
        ERRMSG((_T("[JPGDRV] %s :: JPG CTX is NULL\r\n"), _T(__FUNCTION__)));
        return JPG_FAIL;
    }
    setInternalClock(INT_JPG_CLOCK_ON);

    JpgSfr = GetJPGSfrVirAddr();
    colorMode = (EncParam->inFormat == JPG_MODESEL_RGB)? (0x2&0x7) : (0x1&0x7);
    JpgSfr->JPGCMOD = (colorMode<<5)|(EncParam->mode_Y16<<1);
    JpgSfr->JPGMOD = (0<<3) |((EncParam->sampleMode == JPG_422)? 0x1 : 0x2);
    JpgSfr->JPGDRI_L = JPG_RESTART_INTRAVEL;
    JpgSfr->JPGDRI_U = 0;

    JpgSfr->JPGQTBL = 0;
    JpgSfr->JPGHTBL = 0;

    JpgSfr->JPGY_U = (EncParam->height>>8);
    JpgSfr->JPGY_L = EncParam->height;
    JpgSfr->JPGX_U = (EncParam->width>>8);
    JpgSfr->JPGX_L = EncParam->width;

    if(EncParam->encType == JPG_MAIN){
        JpgSfr->JPGIMGADR = jCTX->IMGDataAddr;
        JpgSfr->JPGADR = jCTX->JPGDataAddr;
    }
    else{
        JpgSfr->JPGIMGADR = jCTX->IMGThumbDataAddr;
        JpgSfr->JPGADR = jCTX->JPGThumbDataAddr;
    }
    
    JpgSfr->JPGCOEF1 = COEF1_RGB_2_YUV;
    JpgSfr->JPGCOEF2 = COEF2_RGB_2_YUV;
    JpgSfr->JPGCOEF3 = COEF3_RGB_2_YUV;

    JpgSfr->JPGINTSE = 0xe0;

    // Quantiazation and Huffman Table setting
    for (i=0; i<64; i++)
        JpgSfr->JPGQTBL0[i] = (UINT32)QTBL_Luminance[EncParam->quality][i];

    for (i=0; i<64; i++)
        JpgSfr->JPGQTBL1[i] = (UINT32)QTBL_Chrominance[EncParam->quality][i];

    for (i=0; i<16; i++)
        JpgSfr->JPGHDCTBL0[i] = (UINT32)HDCTBL0[i];

    for (i=0; i<12; i++)
        JpgSfr->JPGHDCTBLG0[i] = (UINT32)HDCTBLG0[i];

    for (i=0; i<16; i++)
        JpgSfr->JPGHACTBL0[i] = (UINT32)HACTBL0[i];

    for (i=0; i<162; i++)
        JpgSfr->JPGHACTBLG0[i] = (UINT32)HACTBLG0[i];

    JpgSfr->JPGJSTART = 1;


    ret = waitForJPGIRQ();
    if(ret != OK_ENC_OR_DEC)
    {
        ERRMSG((_T("[JPGDRV] %s :: Encoding Error(%d)\r\n"), _T(__FUNCTION__), ret));
        return JPG_FAIL;
    }

    EncParam->fileSize = ((JpgSfr->JPGCNT_U<<16)|(JpgSfr->JPGCNT_M<<8)|(JpgSfr->JPGCNT_L<<0));
    setInternalClock(INT_JPG_CLOCK_OFF);

    DBGMSG(JPG_FUNC,(_T("[JPGAPI] %s--\r\n"), _T(__FUNCTION__)));
    return JPG_SUCCESS;
}


