[Feature]Upload Modem source code

Change-Id: Id4294f30faced84d3e6fd6d5e61e1111bf287a37
diff --git a/mcu/driver/devdrv/soe/src/drv_soe.c b/mcu/driver/devdrv/soe/src/drv_soe.c
new file mode 100644
index 0000000..910fcd6
--- /dev/null
+++ b/mcu/driver/devdrv/soe/src/drv_soe.c
@@ -0,0 +1,937 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2013
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+/*****************************************************************************
+ *
+ * Filename:
+ * ---------
+ *  drv_soe.c
+ *
+ * Description:
+ * ------------
+ *   SOE Driver
+ *
+ * Author:
+ * -------
+ * -------
+ *
+ *============================================================================
+ *             HISTORY
+ * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *------------------------------------------------------------------------------
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ *
+ *------------------------------------------------------------------------------
+ * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *============================================================================
+ *****************************************************************************/
+
+
+/*******************************************************************************
+ * Include header files
+ *******************************************************************************/
+#include "kal_general_types.h"
+#include "sleepdrv_interface.h"
+#include "drvpdn.h"
+#include "ex_public.h"
+
+#include "drv_soe_reg.h"
+#include "drv_soe_key.h"
+#include "drv_soe_bm.h"
+#include "drv_soe_engine.h"
+
+#ifdef SOE_CHB_MODE
+  #define SOE_GPD_CHK SOE_CHK_32
+#else
+  #define SOE_GPD_CHK SOE_CHK_28
+#endif
+#define SOE_BD_CHK SOE_CHK_16
+
+#if 0 //defined(ATEST_ENABLE)
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+#else
+#define DRV_MSG(level, fmt...)
+#endif
+
+#if defined(ATEST_ENABLE)
+kal_uint32 drv_soe_dbg_frc[5];
+kal_uint32 drv_soe_frc_start[5], drv_soe_frc_end[5];
+extern kal_uint32 drv_sm_getCurFRC(void);
+
+#define DRV_DBG_FRC_INIT(t)  drv_soe_dbg_frc[t]=0
+#define DRV_DBG_FRC_START(t) do{  drv_soe_frc_start[t] = drv_sm_getCurFRC(); \
+                               }while(0)
+
+#define DRV_DBG_FRC_END(t) do{  drv_soe_frc_end[t] = drv_sm_getCurFRC(); \
+                                drv_soe_dbg_frc[t] += (drv_soe_frc_end[t] - drv_soe_frc_start[t]); \
+                               }while(0)
+#else
+#define DRV_DBG_FRC_INIT(t)
+#define DRV_DBG_FRC_START(t)
+#define DRV_DBG_FRC_END(t)
+#endif
+
+//#define DRV_DISABLE_IRQ
+
+/*******************************************************************************
+ * global variable definitions
+ *******************************************************************************/
+static kal_bool drv_inited = KAL_FALSE;
+static kal_enhmutexid drv_soe_locker;
+static kal_eventgrpid  drv_soe_egid;
+#ifdef ATEST_ENABLE
+static void (*drv_soe_lisr_handler_cb)(kal_uint32 vector) = NULL;
+#endif
+
+kal_bool drv_soe_irq_en = KAL_TRUE;
+
+/*******************************************************************************
+ * SOE register dump
+ *******************************************************************************/
+EX_BBREG_DUMP soe_reg_dump;
+const kal_uint32 soe_reg_dump_regions[] = {
+	SOE_BASE,        0xC0, 4,
+	SOE_BASE+0x200,  0xB0, 4,
+	SOE_BASE+0x8000, 0x10, 4,
+};
+
+static void drv_soe_register_bbreg_dump(void)
+{
+    soe_reg_dump.regions = (kal_uint32*)soe_reg_dump_regions;
+    soe_reg_dump.num = sizeof(soe_reg_dump_regions) / (sizeof(kal_uint32) * 3);
+    soe_reg_dump.bbreg_dump_callback = NULL;
+    EX_REGISTER_BBREG_DUMP(&soe_reg_dump);
+}
+ 
+/*******************************************************************************
+ * Function definitions
+ *******************************************************************************/
+static kal_uint8 drv_soe_calc_chksum(kal_uint8 *data, kal_uint16 len)
+{
+    kal_uint8 *uDataPtr, ckSum;
+    kal_uint16 i;
+
+    *(data + 1) = 0x0;
+    uDataPtr = data;
+    ckSum = 0;
+    for (i = 0; i < len; i++)
+        ckSum += *(uDataPtr + i);
+    return 0xFF - ckSum;
+}
+
+static void drv_soe_set_reg(kal_uint32 reg, kal_uint32 mask, kal_uint32 val, kal_uint32 offset)
+{
+    kal_uint32 tmp;
+    tmp = SOE_REG(reg);
+    tmp &= (~mask);
+    tmp |= (val << offset);
+    SOE_REG(SOE_CR) = tmp;
+}
+
+void drv_soe_lisr(kal_uint32 irq_id)
+{
+    kal_uint32 intr_status;
+
+#ifdef ATEST_ENABLE
+    if(drv_soe_lisr_handler_cb != NULL) {
+        drv_soe_lisr_handler_cb(irq_id);
+        return;
+    }
+#endif
+    intr_status = SOE_REG(SOE_L2ISAR);
+    SOE_REG(SOE_L2ISAR) = intr_status;
+#if defined(MT6297)
+    intr_status |= (SOE_REG(SOE_ASYM_STATUS_REG7) << 8);
+#endif
+    Data_Sync_Barrier();
+    IRQClearInt(SOE_IRQ);
+    Data_Sync_Barrier();
+
+    kal_set_eg_events(drv_soe_egid, intr_status, KAL_OR);
+}
+
+#ifdef ATEST_ENABLE
+void drv_soe_reg_interrupt(void (*handler)(kal_uint32 vector))
+{
+    drv_soe_lisr_handler_cb = handler;
+}
+#endif
+
+void drv_soe_init(void)
+{
+    if(drv_inited) {
+        return;
+    }
+
+    drv_soe_locker = kal_create_enh_mutex("SOEMtx");
+    if(!drv_soe_locker) ASSERT(0);
+
+    drv_soe_egid = kal_create_event_group("SOEEvt");
+    if(!drv_soe_egid) ASSERT(0);
+
+    //move to interface/service/config/kal_config/xxx_isr_config.h
+    //IRQ_Register_LISR(SOE_IRQ, drv_soe_lisr, "SOE handler");
+    //IRQSensitivity(SOE_IRQ, KAL_TRUE);
+    IRQClearInt(SOE_IRQ);
+    IRQUnmask(SOE_IRQ);
+    
+    drv_inited = KAL_TRUE;
+    DRV_DBG_FRC_INIT(0);
+    DRV_DBG_FRC_INIT(1);
+	drv_soe_register_bbreg_dump();
+}
+
+static kal_uint32 drv_soe_gen_key_attr(drv_soe_key_attr_t *key_attr, sec_key_t *key_table)
+{
+#ifdef SOE_CHB_MODE
+    kal_uint32 kindex2;
+#endif
+    kal_uint32 i, kindex = 0;
+    kal_bool extKey = KAL_TRUE;
+
+    //Get valid key index
+    for(i=0; i < SOE_DRV_KEY_ENTRY_MAX; i++) {
+        if(!SECK_GET_VALID(key_table[i])) {
+            kindex = i;
+#ifdef SOE_CHB_MODE
+            kindex2 = (i + 1);
+#endif
+            break;
+        }
+    }
+    if(i == (SOE_KEY_ENTRY_MAX + 1)) {
+        return 1;
+    }
+
+    if (key_attr->mode == SECK_CHB) {
+        key_attr->en = SECK_DEC;
+    }
+
+    if((kal_uint32)key_attr->key >= (kal_uint32)key_table && 
+        (kal_uint32)key_attr->key < ((kal_uint32)key_table + sizeof(sec_key_t))) {
+        extKey = KAL_FALSE;
+    }
+    else {
+        memset(&key_table[kindex], 0, sizeof(sec_key_t));
+    }
+    SECK_SET_VALID(key_table[kindex]);
+    key_attr->idx = (kindex + 1);
+
+    if (key_attr->en == SECK_ENC) {
+        SECK_SET_ENC(key_table[kindex]);
+    }
+    else {
+        SECK_SET_DEC(key_table[kindex]);
+    }
+    
+    if (key_attr->mode == SECK_CHB) {
+        SECK_SET_MODE(key_table[kindex], SECK_AES);
+    }
+    else {
+        SECK_SET_MODE(key_table[kindex], key_attr->mode);
+    }
+    SECK_SET_OPT(key_table[kindex], key_attr->opt);
+    SECK_SET_ALG(key_table[kindex], key_attr->alg);
+
+    if (key_attr->mode == SECK_DES && key_attr->opt == SECK_OPT_3DES) {
+        SECK_SET_3DES(key_table[kindex], key_attr->desmode);
+    }
+#if defined(SOE_MD97_HW)
+    if (key_attr->mode == SECK_RC5) {
+        rc5_para_t rc5_para;
+        rc5_para.pack.keylen = key_attr->var_key.rc5_len;
+        rc5_para.pack.block = key_attr->ops_para.rc5_attr.word_size / SECK_RC5_WORD_SIZE_BIT_INC;
+        rc5_para.pack.round = key_attr->ops_para.rc5_attr.rounds / SECK_RC5_ROUND_INC ;
+        SECK_SET_RC5_ATTR(key_table[kindex], rc5_para.p);
+    }
+
+    if (key_attr->mode == SECK_IDEA && key_attr->opt == SECK_OPT_3IDEA) {
+        SECK_SET_3IDEA(key_table[kindex], key_attr->ideamode);
+    }
+
+    if (key_attr->mode == SECK_CAST5 || key_attr->mode == SECK_CAST6 || key_attr->mode == SECK_BLOWFISH) {
+        SECK_SET_VAR_KEYLEN(key_table[kindex], key_attr->keylen);
+    }
+    if ((key_attr->mode == SECK_HASH || key_attr->mode == SECK_HMAC) && (key_attr->alg == SECK_ALG_TIGER))
+    {
+        tiger_para_t tiger_para;
+        tiger_para.pack.bits = key_attr->ops_para.tiger_attr.bits;
+        tiger_para.pack.rounds = key_attr->ops_para.tiger_attr.rounds;
+        SECK_SET_TIGER_ATTR(key_table[kindex], tiger_para.p);
+    }
+#endif
+    /*MSG(MSG_INFO, "%s mod = %d\r\n", __FUNCTION__, attr->mode);*/
+
+    if (key_attr->key && extKey) {
+        SECK_SET_KEY(key_table[kindex], key_attr->key, key_attr->keylen);
+    }
+    SOE_CACHE_STORE(&key_table[kindex], sizeof(sec_key_t));
+#ifdef SOE_CHB_MODE
+    if (key_attr->mode == SECK_CHB) {
+        if(extKey) {
+            memset(&key_table[kindex2], 0, sizeof(sec_key_t));
+        }
+        SECK_SET_VALID(key_table[kindex2]);
+        key_attr->idx2 = (kindex2 + 1);
+
+        if (key_attr->en == SECK_ENC) {
+            SECK_SET_ENC(key_table[kindex2]);
+        }
+        else {
+            SECK_SET_DEC(key_table[kindex2]);
+        }
+
+        SECK_SET_MODE(key_table[kindex2], SECK_HMAC);
+        SECK_SET_OPT(key_table[kindex2], key_attr->opt2);
+        SECK_SET_ALG(key_table[kindex2], key_attr->alg2);
+
+        if (key_attr->key2 && extKey) {
+            SECK_SET_KEY(key_table[kindex2], key_attr->key2, key_attr->keylen2);
+        }
+        SOE_CACHE_STORE(&key_table[kindex2], sizeof(sec_key_t));
+    }
+#endif
+    return 0;
+}
+
+static kal_uint32 drv_soe_list_init(drv_soe_list_attr_t *attr)
+{
+    kal_uint16 i, type;
+    gpd_t *gpd_now = NULL, *gpd_new;
+    bd_t *bd_now = NULL, *bd_new;
+    drv_soe_gpd_attr_t *gpd_attr;
+    drv_soe_key_attr_t *key_attr;
+    kal_uint32 len;
+    kal_uint8 *buf;
+
+    for (i = 0; i < attr->gpdnum; i++) {
+        /* reset variable */
+        gpd_attr = &attr->gpd[i];
+        key_attr = &attr->key[i];
+        bd_now = NULL;
+        gpd_new = gpd_attr->gpd;      
+        if (gpd_now != NULL) {
+            SOE_SET_NEXT(gpd_now, virt_to_phys(gpd_new));
+            SOE_SET_CHKSUM(gpd_now, SOE_GPD_CHK);
+        }
+        memset(gpd_new, 0, GPD_SIZE);
+        SOE_SET_FLAGS_HWO(gpd_new);
+        if (gpd_attr->bd == NULL) {
+            SOE_CLR_FLAGS_BDP(gpd_new);
+        } else {
+            SOE_SET_FLAGS_BDP(gpd_new);
+        }
+        SOE_CLR_FORMAT_VR(gpd_new);
+
+        if(!SOE_IS_DYNA_DRAM((kal_uint32)gpd_attr->outbuf, gpd_attr->outlen)) {
+            return DRV_SOE_ERR_INVALID_PTR;
+        }
+        if(query_is_cached_ram((kal_uint32)gpd_attr->outbuf, gpd_attr->outlen)) {
+            SOE_CACHE_STORE(gpd_attr->outbuf, gpd_attr->outlen);
+            SOE_CACHE_INVALIDATE(gpd_attr->outbuf, gpd_attr->outlen);
+            gpd_attr->outbuf = (kal_uint8*)virt_to_phys(gpd_attr->outbuf);
+        }
+        SOE_SET_BUF_LEN(gpd_new, gpd_attr->buflen);
+        SOE_SET_OUTPTR(gpd_new, gpd_attr->outbuf);
+
+        if(gpd_attr->icblen) {
+            if(!SOE_IS_DYNA_DRAM((kal_uint32)gpd_attr->icb, gpd_attr->icblen)) {
+                return DRV_SOE_ERR_INVALID_PTR;
+            }
+            if(query_is_cached_ram((kal_uint32)gpd_attr->icb, gpd_attr->icblen)) {
+                SOE_CACHE_STORE(gpd_attr->icb, gpd_attr->icblen);
+                gpd_attr->icb = (kal_uint8*)virt_to_phys(gpd_attr->icb);
+            }
+            SOE_SET_ICBPTR(gpd_new, gpd_attr->icb);
+            if(key_attr->alg == SECK_ALG_CBC) {
+#if defined(SOE_MD97_HW) && !defined(MT6297)
+                SOE_SET_FORMAT_UI(gpd_new);
+#else
+                /* Apollo is not ready for using UI with new algorithms */
+                do {
+                if(key_attr->mode == SECK_DES || key_attr->mode == SECK_AES)
+                    SOE_SET_FORMAT_UI(gpd_new);        
+                }while(0);
+#endif
+            }
+        }
+        else {
+            SOE_SET_ICBPTR(gpd_new, gpd_attr->outbuf); //dummy ptr
+        }
+        
+        if(gpd_attr->icvlen) {
+            if(!SOE_IS_DYNA_DRAM((kal_uint32)gpd_attr->icv, gpd_attr->icvlen)) {
+                return DRV_SOE_ERR_INVALID_PTR;
+            }
+            if(query_is_cached_ram((kal_uint32)gpd_attr->icv, gpd_attr->icvlen)) {
+                SOE_CACHE_STORE(gpd_attr->icv, gpd_attr->icvlen);
+                SOE_CACHE_INVALIDATE(gpd_attr->icv, gpd_attr->icvlen);
+                gpd_attr->icv = (kal_uint8*)virt_to_phys(gpd_attr->icv);
+            }
+            SOE_SET_ICVPTR(gpd_new, gpd_attr->icv);
+        }
+        else {
+            SOE_SET_ICVPTR(gpd_new, gpd_attr->outbuf); //dummy ptr
+        }
+        SOE_SET_KEY_IDX(gpd_new, gpd_attr->keyidx);
+#ifdef SOE_CHB_MODE
+        SOE_SET_KEY_IDX2(gpd_new, gpd_attr->keyidx2);
+        SOE_SET_CIPHER_OFFSET(gpd_new, gpd_attr->cipher_offset);
+        if (key_attr->mode == SECK_CHB) {
+            SOE_SET_FORMAT_CHB(gpd_new);
+        }
+        else {
+            SOE_CLR_FORMAT_CHB(gpd_new);
+        }
+#endif
+
+        if (gpd_attr->bd == NULL) {
+            /* No BD, set data ptr */
+            if(!SOE_IS_DYNA_DRAM((kal_uint32)gpd_attr->inbuf, gpd_attr->inlen)) {
+                return DRV_SOE_ERR_INVALID_PTR;
+            }
+            if(query_is_cached_ram((kal_uint32)gpd_attr->inbuf, gpd_attr->inlen)) {
+                SOE_CACHE_STORE(gpd_attr->inbuf, gpd_attr->inlen);
+                gpd_attr->inbuf = (kal_uint8*)virt_to_phys(gpd_attr->inbuf);
+            }            
+            SOE_SET_DATA(gpd_new, gpd_attr->inbuf);
+        } else {
+            /* Generate BDs */
+            for (type = 0; type < 2; type++) {
+                if(key_attr->alg == SECK_ALG_XCBC) {
+                    // XCBC
+                    buf = type ? gpd_attr->inbuf : gpd_attr->icb;
+                    len = type ? gpd_attr->inlen : gpd_attr->icblen;
+                }
+                else {
+                    // CCM/GCM
+                    buf = type ? gpd_attr->inbuf : gpd_attr->abuf;
+                    len = type ? gpd_attr->inlen : gpd_attr->alen;
+                }
+                
+                if(!SOE_IS_DYNA_DRAM((kal_uint32)buf, len)) {
+                    return DRV_SOE_ERR_INVALID_PTR;
+                }
+                if(query_is_cached_ram((kal_uint32)buf, len)) {
+                    SOE_CACHE_STORE(buf, len);
+                    buf = (kal_uint8*)virt_to_phys(buf);
+                }
+                bd_new = &gpd_attr->bd[type];
+
+                /* set data ptr */
+                memset(bd_new, 0, BD_SIZE);
+                BD_SET_DATA(bd_new, buf);
+                BD_SET_BUF_LEN(bd_new, len);
+                /* set list */
+                if (bd_now == NULL) {
+                    SOE_SET_BD(gpd_new, virt_to_phys(bd_new));
+                } else {
+                    if(!len)
+                        BD_SET_FLAGS_EOL(bd_now);
+                    BD_SET_NEXT(bd_now, virt_to_phys(bd_new));
+                    BD_SET_CHKSUM(bd_now, SOE_BD_CHK);
+                    SOE_CACHE_STORE(bd_now, BD_SIZE);
+                }
+                if (type == 1) { /* last BD */
+                    BD_SET_FLAGS_EOL(bd_new);
+                }
+                bd_now = bd_new;
+            }
+            BD_SET_CHKSUM(bd_now, SOE_BD_CHK);
+            SOE_CACHE_STORE(bd_now, BD_SIZE);            
+        }
+        SOE_SET_CHKSUM(gpd_new, SOE_GPD_CHK);
+        SOE_CACHE_STORE(gpd_new, GPD_SIZE);
+        gpd_now = gpd_new;
+    }
+    /* link last GPD */
+    gpd_new = (gpd_t *)&gpd_now[1];
+    SOE_SET_NEXT(gpd_now, virt_to_phys(gpd_new));
+    SOE_SET_FLAGS_INT(gpd_now);
+    SOE_SET_CHKSUM(gpd_now, SOE_GPD_CHK);
+    SOE_CACHE_STORE(gpd_now, GPD_SIZE);
+    memset(gpd_new, 0, GPD_SIZE);
+    SOE_CACHE_STORE(gpd_new, GPD_SIZE);
+    return 0;
+}
+
+static kal_uint32 drv_soe_gen_gpd_attr(drv_soe_gpd_attr_t *attr, drv_soe_key_attr_t *key)
+{
+    kal_uint32 err = 0;
+
+    // check keylen and datalen
+    switch(key->mode) {
+        case SECK_NULL:
+            err = 0;
+            break;
+        case SECK_HMAC:
+            switch(key->alg) {
+                case SECK_ALG_MD5:
+                case SECK_ALG_SHA1:
+                case SECK_ALG_SHA256:
+#if defined(SOE_MD97_HW)				
+                case SECK_ALG_TIGER:
+#endif
+                    if(key->keylen != 64) err = DRV_SOE_ERR_KEYLEN;
+                    break;
+                case SECK_ALG_SHA384:
+                case SECK_ALG_SHA512:
+                    if(key->keylen != 128) err = DRV_SOE_ERR_KEYLEN;
+                    break;
+                default:
+                    err = DRV_SOE_ERR_ALG;
+                    break;
+            }            
+            //following check as HASH
+        case SECK_HASH:
+            if(attr->inlen > 65535) err = DRV_SOE_ERR_INLEN;
+#if defined(SOE_MD97_HW)
+            if(key->alg > SECK_ALG_TIGER) err = DRV_SOE_ERR_ALG;
+#else
+            if(key->alg > SECK_ALG_SHA512) err = DRV_SOE_ERR_ALG;
+#endif
+            switch(key->alg) {
+                case SECK_ALG_MD5:
+                    if(attr->outlen != 16) err = DRV_SOE_ERR_OUTLEN;
+                    break;
+                case SECK_ALG_SHA1:
+                    if(attr->outlen != 20) err = DRV_SOE_ERR_OUTLEN;
+                    break;
+                case SECK_ALG_SHA256:
+                    if(attr->outlen != 32) err = DRV_SOE_ERR_OUTLEN;
+                    break;
+                case SECK_ALG_SHA384:
+                    if(attr->outlen != 48) err = DRV_SOE_ERR_OUTLEN;
+                    break;
+                case SECK_ALG_SHA512:
+                    if(attr->outlen != 64) err = DRV_SOE_ERR_OUTLEN;
+                    break;
+#if defined(SOE_MD97_HW)
+                case SECK_ALG_TIGER:
+                    if(attr->outlen != 16 && attr->outlen != 24 && attr->outlen != 32) err = DRV_SOE_ERR_OUTLEN;
+                    break;
+#endif
+                default:
+                    err = DRV_SOE_ERR_ALG;
+                    break;
+            }
+            break;
+        case SECK_DES:
+            if(key->opt > SECK_OPT_3DES) err = DRV_SOE_ERR_OPT;
+            if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
+            if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
+            if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
+            if(key->opt == SECK_OPT_DES && key->keylen != 8) err = DRV_SOE_ERR_KEYLEN;
+            if(key->opt == SECK_OPT_3DES && key->keylen != 24) err = DRV_SOE_ERR_KEYLEN;
+            if(key->alg == SECK_ALG_CBC && attr->icblen != 8) err = DRV_SOE_ERR_ICBLEN;
+            break;
+        case SECK_AES:
+            if(key->alg != SECK_ALG_XCBC && key->alg != SECK_ALG_CMAC) {
+                if(key->opt > SECK_AES_256) err = DRV_SOE_ERR_OPT;
+                if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
+            }
+            else {
+                if(key->opt > SECK_AES_128) err = DRV_SOE_ERR_OPT;
+                if(attr->inlen > 65535) err = DRV_SOE_ERR_INLEN;
+                if(key->en == SECK_DEC && attr->icvlen != 16) err = DRV_SOE_ERR_ICVLEN;
+            }
+            switch(key->alg) {
+                case SECK_ALG_CBC:
+                    if(attr->icblen != 16) err = DRV_SOE_ERR_ICBLEN;
+                    //following check as ECB
+                case SECK_ALG_ECB:
+                    if(!(attr->inlen == 16 || (attr->inlen >= 32 && attr->inlen <= 65520))) err = DRV_SOE_ERR_INLEN;
+                    break;
+                case SECK_ALG_CTR:
+                    if(attr->inlen == 0 || attr->inlen > 65535) {
+                        err = DRV_SOE_ERR_INLEN;
+                    }
+                    if(attr->icblen != 16) err = DRV_SOE_ERR_ICBLEN;
+                    break;
+                case SECK_ALG_CCM:
+                case SECK_ALG_GCM:
+                    //check in next stage
+                default:
+                    break;
+            }            
+            break;
+#if defined(SOE_MD97_HW)			
+        case SECK_RC5:
+            if(key->opt != 0) err = DRV_SOE_ERR_OPT;
+            if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
+            if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
+            if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
+            if(key->alg == SECK_ALG_CBC && (attr->icblen != 4 && attr->icblen != 8 && attr->icblen != 16)) err = DRV_SOE_ERR_ICBLEN;
+            if(key->keylen == 0 /*|| key->keylen > 255 */) err = DRV_SOE_ERR_KEYLEN;
+            break;
+        case SECK_IDEA:
+            if(key->opt > SECK_OPT_3IDEA) err = DRV_SOE_ERR_OPT;
+            if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
+            if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
+            if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
+            if(key->opt == SECK_OPT_IDEA && key->keylen != 16) err = DRV_SOE_ERR_KEYLEN;
+            if(key->opt == SECK_OPT_3IDEA && key->keylen != 48) err = DRV_SOE_ERR_KEYLEN;
+            if(key->alg == SECK_ALG_CBC && attr->icblen != 8) err = DRV_SOE_ERR_ICBLEN;
+            break;
+        case SECK_CAST5:
+            if(key->opt != 0) err = DRV_SOE_ERR_OPT;
+            if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
+            if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
+            if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
+            if(key->alg == SECK_ALG_CBC && attr->icblen != 8) err = DRV_SOE_ERR_ICBLEN;
+            if(key->keylen < 5 || key->keylen > 16) err = DRV_SOE_ERR_KEYLEN;
+            break;
+        case SECK_CAST6:
+            if(key->opt != 0) err = DRV_SOE_ERR_OPT;
+            if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
+            if(!(attr->inlen == 16 || (attr->inlen >= 32 && attr->inlen <= 65520))) err = DRV_SOE_ERR_INLEN;
+            if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
+            if(key->alg == SECK_ALG_CBC && attr->icblen != 16) err = DRV_SOE_ERR_ICBLEN;
+            if(key->keylen < 16 || key->keylen > 32 || (key->keylen & 3) != 0) err = DRV_SOE_ERR_KEYLEN;
+            break;
+        case SECK_BLOWFISH:
+            if(key->opt != 0) err = DRV_SOE_ERR_OPT;
+            if(key->alg > SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
+            if(!(attr->inlen == 8 || (attr->inlen >= 16 && attr->inlen <= 65528))) err = DRV_SOE_ERR_INLEN;
+            if(attr->inlen != attr->outlen) err = DRV_SOE_ERR_OUTLEN;
+            if(key->alg == SECK_ALG_CBC && attr->icblen != 8) err = DRV_SOE_ERR_ICBLEN;
+            if(key->keylen < 4 || key->keylen > 56) err = DRV_SOE_ERR_KEYLEN;
+            break;
+        case SECK_CHB:
+            if (key->opt != SECK_AES_128) err = DRV_SOE_ERR_OPT;
+            if (key->alg != SECK_ALG_CBC) err = DRV_SOE_ERR_ALG;
+            if (key->alg2 > SECK_ALG_SHA256) err = 3;
+            break;
+        case SECK_RSADH:
+            if (key->opt != 0) err = DRV_SOE_ERR_OPT;
+            if (key->alg > SECK_ALG_MODEXP) err = DRV_SOE_ERR_ALG;
+            break;
+        case SECK_ECC:
+            if (key->opt != 0) err = DRV_SOE_ERR_OPT;
+            if (key->alg > SECK_ALG_PADD) err = DRV_SOE_ERR_ALG;
+            break;
+#endif			
+        default:
+            err = DRV_SOE_ERR_MODE;
+    }
+
+    //check CHB mode
+    if (key->mode != SECK_CHB) {
+        if ((key->mode == SECK_AES) && (key->alg == SECK_ALG_CCM || key->alg == SECK_ALG_GCM)) {
+            attr->buflen = attr->inlen;
+            if((attr->inlen + attr->alen) > 65535) {
+                err = DRV_SOE_ERR_CHBLEN;
+            }
+        }
+        else {
+            attr->alen = 0;
+        }
+    }
+    else {
+        attr->alen = 0;
+    }
+    if(err) {
+        DRV_MSG(MSG_INFO, "%s err: %x\r\n", __FUNCTION__, err);
+        return err;
+    }
+    
+    //assign keyidx
+    attr->keyidx = key->idx;
+    if (key->mode == SECK_CHB) {
+        attr->keyidx2 = key->idx2;
+    }
+    DRV_MSG(MSG_INFO, "%s keyidx:%d keyidx2:%d\r\n", __FUNCTION__, attr->keyidx, attr->keyidx2);
+    
+    return 0;
+}
+
+kal_uint32 drv_soe_gen_attr(drv_soe_ctrl_struct_t *ctrl)
+{
+    drv_soe_list_attr_t *attr = &ctrl->list_attr;
+    kal_uint32 i, idx, ret;
+
+    DRV_DBG_FRC_START(0);
+
+    // check ptr
+    if(ctrl->gpd == NULL || ctrl->key == NULL) {
+        return DRV_SOE_ERR_INVALID_PTR;
+    }
+    if(!SOE_IS_DYNA_DRAM((kal_uint32)ctrl->gpd, sizeof(gpd_t))) {
+        return DRV_SOE_ERR_INVALID_PTR;
+    }
+    if(!SOE_IS_DYNA_DRAM((kal_uint32)ctrl->key, sizeof(sec_key_t))) {
+        return DRV_SOE_ERR_INVALID_PTR;
+    }
+
+    // set key table
+    for(i = 0, idx = 0; i < attr->gpdnum; i++) {
+        if(idx == (SOE_DRV_GPD_MAX + 1)) {
+            return DRV_SOE_ERR_GPD_OVERFLOW;
+        }
+        
+        ret = drv_soe_gen_key_attr(&attr->key[i], ctrl->key);
+        if(ret) {
+            DRV_MSG(MSG_INFO, "%s gen_key err: %x\r\n", __FUNCTION__, ret);
+            return ret;
+        }
+
+        if(attr->gpd[i].alen > 0) {
+            ret = attr->key[i].idx - 1;
+            SECK_SET_ADATA(ctrl->key[ret], attr->gpd[i].alen);
+            SOE_CACHE_STORE(&ctrl->key[ret], sizeof(sec_key_t));
+        }
+        
+        memset(&ctrl->gpd[idx], 0, sizeof(gpd_t));
+        attr->gpd[i].gpd = &ctrl->gpd[idx++];
+        ret = drv_soe_gen_gpd_attr(&attr->gpd[i], &attr->key[i]);
+        if(ret) {
+            DRV_MSG(MSG_INFO, "%s gen_gpd err: %x\r\n", __FUNCTION__, ret);
+            return ret;
+        }
+        if(attr->gpd[i].alen || (attr->key[i].mode == SECK_AES && attr->key[i].alg == SECK_ALG_XCBC && attr->gpd[i].icblen) ) {
+            memset(&ctrl->gpd[idx], 0, sizeof(gpd_t));
+            attr->gpd[i].bd = (bd_t*)&ctrl->gpd[attr->gpdnum + idx];
+        }
+    }
+    ret = drv_soe_list_init(attr);
+
+#ifdef ATEST_ENABLE
+    if(!ret) 
+        ctrl->r_gpd_cnt += attr->gpdnum;
+#endif
+    DRV_DBG_FRC_END(0);
+    return ret;
+}
+
+kal_uint32 drv_soe_update_attr(drv_soe_ctrl_struct_t *ctrl)
+{
+    drv_soe_list_attr_t *attr = &ctrl->list_attr;
+    kal_uint32 ret;
+
+    DRV_DBG_FRC_START(0);
+
+    // check ctrl
+    if(!SOE_GET_NEXT(ctrl->gpd)) {
+        return DRV_SOE_ERR_INVALID_GPD;
+    }
+    
+    // update GPD
+    ret = drv_soe_list_init(attr);
+
+#ifdef ATEST_ENABLE
+    if(!ret) 
+        ctrl->r_gpd_cnt += attr->gpdnum;
+#endif
+    DRV_DBG_FRC_END(0);
+    return ret;
+}
+
+kal_uint32 drv_soe_trigger(gpd_t *pGpd, sec_key_t *pKey)
+{
+    kal_uint32 err = 0;
+    kal_uint32 event_group = 0;
+    kal_uint32 soe_timeout_ticks;
+    gpd_t *last_gpd = pGpd;
+
+    //check GPD/KEY
+    if(last_gpd == NULL || pKey == NULL) return DRV_SOE_ERR_INVALID_PTR;
+    if((kal_uint32)last_gpd & 0x3) return DRV_SOE_ERR_INVALID_PTR;
+    if((kal_uint32)pKey & 0x3) return DRV_SOE_ERR_INVALID_PTR;
+    if(!SOE_IS_DYNA_DRAM((kal_uint32)pGpd, sizeof(gpd_t))) return DRV_SOE_ERR_INVALID_PTR;
+
+    pKey = (sec_key_t*)((kal_uint32)pKey - sizeof(sec_key_t));
+    if(!SOE_IS_DYNA_DRAM((kal_uint32)pKey, sizeof(sec_key_t))) return DRV_SOE_ERR_INVALID_PTR;
+    while(SOE_IS_FLAGS_HWO(last_gpd)) {
+        if(!SECK_GET_VALID(pKey[last_gpd->keyidx])) return DRV_SOE_ERR_INVALID_KEY;
+        if(last_gpd->pnext == NULL) return DRV_SOE_ERR_INVALID_PNEXT;
+        if(last_gpd->icbptr == NULL) return DRV_SOE_ERR_INVALID_ICB;
+        if(last_gpd->icvptr == NULL) return DRV_SOE_ERR_INVALID_ICV;
+        last_gpd = last_gpd->pnext;
+    }
+    if(last_gpd == pGpd) return DRV_SOE_ERR_INVALID_GPD;
+
+    DRV_DBG_FRC_START(0);
+
+    //check drv init
+    if(!drv_inited) {
+        drv_soe_init();
+    }
+
+    //mutex lock
+    kal_take_enh_mutex(drv_soe_locker);
+    SleepDrv_LockSleep(SLEEP_CTL_SOE, SMP);
+    PDN_CLR(PDN_SOE);
+
+    //check SOE status
+    Data_Mem_Barrier();
+    if(SOE_REG(SOE_QCSR) & SOQ_STAT) {
+        err = DRV_SOE_ERR_STAT_BUSY;
+        goto EngineError;
+    }
+
+    //unmask irq
+#ifndef DRV_DISABLE_IRQ
+    if(drv_soe_irq_en) {
+        SOE_REG(SOE_L2ISAR) = 0xFFFFFFFF;
+        SOE_REG(SOE_L2IMCR) = 0xFFFFFFFF;
+        IRQClearInt(SOE_IRQ);
+        IRQUnmask(SOE_IRQ);
+    }
+#endif
+
+    //config SOE
+#if defined(MT6297)
+    SOE_REG(SOE_ASYM_STATUS_REG7) = 0xFFFFFFFF;
+#endif
+    SOE_REG(SOE_CR) = (SOE_CS_EN | SOE_CSALL_EN);
+    drv_soe_set_reg(SOE_CR, SOE_DMA_MODE, SOE_DMA_MODE, SOE_DMA_MODE_BITS);
+    if(query_is_cached_ram((kal_uint32)pKey, sizeof(sec_key_t))) {
+        SOE_REG(SOE_KTSAR) = virt_to_phys(pKey);
+    }
+    else {
+        SOE_REG(SOE_KTSAR) = (kal_uint32)pKey;
+    }
+    if(query_is_cached_ram((kal_uint32)pGpd, sizeof(gpd_t))) {
+        SOE_REG(SOE_QSAR) = virt_to_phys(pGpd);
+    }
+    else {
+        SOE_REG(SOE_QSAR) = (kal_uint32)pGpd;
+    }
+
+    //start queue
+    Data_Mem_Barrier();
+    DRV_DBG_FRC_START(1);
+    SOE_REG(SOE_QCSR) = SOQ_START;
+    Data_Sync_Barrier();
+    
+    //wait done
+#ifndef DRV_DISABLE_IRQ
+    if(drv_soe_irq_en) {
+        kal_retrieve_eg_events(drv_soe_egid, (SO_ERROR_MASK | SO_DONE), KAL_OR_CONSUME, &event_group, KAL_SUSPEND);
+    }
+    else
+#endif
+    {
+        soe_timeout_ticks = drv_get_current_time();
+        while(SOE_REG(SOE_QCSR) & SOQ_STAT) {
+            if(drv_get_duration_ms(soe_timeout_ticks) > 8000) {
+                DRV_DBG_FRC_END(1);
+                err = DRV_SOE_ERR_STAT_BUSY;
+                goto EngineError;
+            }
+        }
+        event_group = SOE_REG(SOE_L2ISAR);
+        #if defined(MT6297)
+        event_group |= (SOE_REG(SOE_ASYM_STATUS_REG7) << 8);
+        #endif
+    }
+    DRV_DBG_FRC_END(1);
+    if(event_group & SO_GPD_CSERR) err = DRV_SOE_ERR_GPD_CSERR;
+    if(event_group & SO_BD_CSERR) err = DRV_SOE_ERR_BD_CSERR;
+    if(event_group & SO_LENERR) err = DRV_SOE_ERR_LENERR;
+    if(event_group & SO_KTERR) err = DRV_SOE_ERR_KTERR;
+    if(SOE_IS_FORMAT_VR(pGpd)) err = DRV_SOE_ERR_VRERR;
+    if(event_group & SO_ASYM_ERROR_MASK) err = DRV_SOE_ERR_ASYMERR;
+    if(err) goto EngineError;
+
+    SOE_REG(SOE_L2IMSR) = 0xFFFFFFFF;
+    Data_Sync_Barrier();
+EngineError:
+    PDN_SET(PDN_SOE);
+    SleepDrv_UnlockSleep(SLEEP_CTL_SOE, SMP);
+    kal_give_enh_mutex(drv_soe_locker);
+    DRV_DBG_FRC_END(0);
+    return err;    
+}
+
+void drv_soe_cache_ctrl(kal_bool clean, kal_bool invalidate, kal_uint32 addr, kal_uint32 ln)
+{
+    if(clean)
+        SOE_CACHE_STORE(addr, ln);
+    if(invalidate)
+        SOE_CACHE_INVALIDATE(addr, ln);
+}
+
+void* drv_soe_memcpy(kal_uint8 *dst, kal_uint8 *src, kal_uint32 ln)
+{
+    return memcpy((kal_uint8*)virt_to_phys(dst), \
+                  (kal_uint8*)virt_to_phys(src), \
+                  ln);
+}
+
+//Call from devdrv_common.c Drv_Init_Phase2()
+void SOE_Drv_Init(void)
+{
+    drv_soe_init();
+    PDN_SET(PDN_SOE);
+}