ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/linux/drivers/mfd/adsp.c b/marvell/linux/drivers/mfd/adsp.c
new file mode 100644
index 0000000..c1859eb
--- /dev/null
+++ b/marvell/linux/drivers/mfd/adsp.c
@@ -0,0 +1,2143 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Audio DSP.
+ *
+ * Copyright (C) 2023 ASRMicro
+ *
+ * Author: Wang Yan <yjgwang@asrmicro.com>
+ */
+
+
+/******************************************************************************
+*               MODULE IMPLEMENTATION FILE
+*******************************************************************************
+* Title: Driver for ADSP in AP subsystem
+*
+* Filename: adsp.c
+*
+* Authors: Wang Yan
+*
+* Description: Driver file for ADSP.
+*
+* Last Updated:
+*
+* Notes:
+******************************************************************************/
+
+
+/******************************************************************************
+*   Include files
+******************************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <asm/io.h>
+#include <linux/interrupt.h>
+#include <linux/cputype.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/ioctl.h>
+#include <linux/vmalloc.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/kthread.h>
+#include <linux/dma-mapping.h>
+#include <linux/bug.h>
+#include <asm/cacheflush.h>
+#include "adsp.h"
+#include "adsp_ve.h"
+
+
+/******************************************************************************
+*   Macro definitions
+******************************************************************************/
+#define ADSP_PRINT_IPC 0
+
+#define IPC_MAX_CMD_LENGTH 128
+
+#define MIN(x, y) ((x < y) ? x : y)
+
+#define IPC_SUB_OPCODE( OPCODE ) ((OPCODE) & 0x3F)
+#define IPC_SET_ID( OPCODE )       ((UINT16)(((OPCODE) >> IPC_HEADER_SETID_BITNUM) & 0x3))
+#define IPC_DATA_BIT( OPCODE ) ((UINT16)(((OPCODE) >> IPC_HEADER_DATA_BITNUM) & 0x1))
+#define IPC_OPCODE(SET_ID, SUB_OPCODE)   ((SET_ID << IPC_HEADER_SETID_BITNUM) | SUB_OPCODE)
+
+#define IPC_COMPOSE_HEADER( SetID, SubSet, Urgent, Data, Long ) ((UINT16)( \
+                                                                     (((UINT16)(SetID)) << IPC_HEADER_SETID_BITNUM)  | \
+                                                                     (((UINT16)(SubSet)) << IPC_HEADER_SUBSET_BITNUM) | \
+                                                                     (((UINT16)(Data)) << IPC_HEADER_DATA_BITNUM)))
+
+#define IPC_COMPOSE_DATA_HEADER( ChID, CopyFlag, DataLen )  (((UINT32)(DataLen)) << 16)
+
+
+typedef struct AdspRingCtl {
+    /* TX ring buffer for CP , CP write , AP read */
+    unsigned int cp_wptr;
+    unsigned int ap_rptr;
+
+    /* RX ring buffer for CP , AP write , CP read */
+    unsigned int ap_wptr;
+    unsigned int cp_rptr;
+
+    /* physical address from AP's pespective*/
+    unsigned int rxring_base;
+    unsigned int txring_base;
+
+    unsigned int unitsz;
+    unsigned int unitnum;
+
+}AdspRingCtl;
+
+typedef struct AudioIpcHandle {
+    AdspRingCtl     *ring_ctl;
+    unsigned int    *tx_ring_buffer;
+    unsigned int    *rx_ring_buffer;
+
+    unsigned int iir;
+}AudioIpcHandle;
+
+//#define ADSP_VE_ADDR              (0xD6A01880)
+static void __iomem *rVe = NULL;
+
+//#define ADSP_RING_CTL_ADDR              (0xD6A01000)
+static void __iomem *rRingCtrl = NULL;
+
+#define ADSP_RING_BUFFER_SIZE    (1024)
+
+static unsigned int adsp_irq = 0;
+
+//platform_get_resource 0
+#define ADSP_DUMP_SQU_ADDR      (0xd101c000)
+#define ADSP_DUMP_SQU_LENGTH    (0x4000)
+static void __iomem *rDumpSQU = NULL;
+
+//platform_get_resource 1
+#define ADSP_DUMP_DTCM_ADDR     (0xd6000000)
+#define ADSP_DUMP_DTCM_LENGTH   (0x40000)
+static void __iomem *rDumpDTCM = NULL;
+
+//platform_get_resource 2
+#define ADSP_DUMP_SHM_ADDR      (0xd6a00000)
+#define ADSP_DUMP_SHM_LENGTH    (0x4000)
+static void __iomem *rDumpSHM = NULL;
+
+//platform_get_resource 3
+#define ITCM_ADDR               (0xd6200000)
+#define ITCM_LENGTH             (0x00010000)
+static void __iomem *rItcm =    NULL;
+
+//platform_get_resource 4
+//#define IPC_AP2AUD_BASE  0xd401d100
+//#define APB_H2_IPC_CPU_DWR_ADDR  (IPC_AP2AUD_BASE + 0x0)
+//#define APB_H2_IPC_CPU_WDR_ADDR  (IPC_AP2AUD_BASE + 0x4)
+//#define APB_H2_IPC_CPU_ISRW_ADDR (IPC_AP2AUD_BASE + 0x8)
+//#define APB_H2_IPC_CPU_ICR_ADDR  (IPC_AP2AUD_BASE + 0xc)
+//#define APB_H2_IPC_CPU_IIR_ADDR  (IPC_AP2AUD_BASE + 0x10)
+//#define APB_H2_IPC_CPU_RDR_ADDR  (IPC_AP2AUD_BASE + 0x14)
+static void __iomem *rIpcBASE = NULL;
+static void __iomem *rIpcDWR = NULL;
+static void __iomem *rIpcWDR = NULL;
+static void __iomem *rIpcISRW = NULL;
+static void __iomem *rIpcICR = NULL;
+static void __iomem *rIpcIIR = NULL;
+static void __iomem *rIpcRDR = NULL;
+
+//platform_get_resource 5
+static void __iomem *rSspaBase = NULL;
+//0xd401e178
+static void __iomem *rSspaClk = NULL;
+//0xd401e17c
+static void __iomem *rSspaFrm = NULL;
+//0xd401e180
+static void __iomem *rSspaTxd = NULL;
+//0xd401e184
+static void __iomem *rSspaRxd = NULL;
+
+//platform_get_resource 6
+//0xd6800014
+static void __iomem *rPc = NULL;
+
+//platform_get_resource 7
+//0xd6800048
+static void __iomem *rRls = NULL;
+
+//platform_get_resource 8
+//Can not platform_get_resource from dts
+//#define AP_IPC_CLK_RST         (0xd4015090)
+static void __iomem *rClkRst = NULL;
+
+//platform_get_resource 9
+//0xd42828f0
+static void __iomem *rPwr = NULL;
+
+//should be ioremap earlier before adsp driver init
+#define REG_PMU_AUDIO_CLK_RES_CTRL  (0xd428294c)
+static void __iomem *rClk = NULL;
+
+#define ADSP_DDR_LOAD_ADDR      (0x8d80000)
+#define ADSP_DDR_LOAD_LENGTH    (0x280000)
+
+#define ADSP_DDR_LOAD_ADDR_S      (0x5f80000)
+#define ADSP_DDR_LOAD_LENGTH_S    (0x80000)
+
+/* macro for register operation */
+#define reg_read(reg)       *(volatile unsigned int *)(reg)
+#define reg_write(reg, val) *(volatile unsigned int *)(reg) = (val)
+#define reg_bit_set(reg, val) *(volatile unsigned int *)(reg) |= (1 << (val))
+#define reg_bit_clr(reg, val) *(volatile unsigned int *)(reg) &= ~(1 << (val))
+
+
+/******************************************************************************
+*   Local variable definitions
+******************************************************************************/
+static AudioIpcHandle g_audio_ipc_handle = {
+    .ring_ctl = (AdspRingCtl *) 0,
+    .tx_ring_buffer = (unsigned int *)0,
+    .rx_ring_buffer = (unsigned int *)0,
+    .iir = 0
+};
+
+static struct mutex g_audio_ipc_sema;
+
+/******************************************************************************
+*   function definitions
+******************************************************************************/
+static void adsp_ipc_clk_enable(void)
+{
+    //unsigned int val = 0;
+
+    //val = reg_read(rClkRst);
+    //val |= (0x3);
+    reg_write(rClkRst, 0x3);
+    return;
+}
+
+static void print_adsp_ipc_clk(void)
+{
+    unsigned int val = 0;
+
+    val = reg_read(rClkRst);
+
+    printk(KERN_INFO "reg[0x%x] = 0x%x", (unsigned int)rClkRst, val);
+}
+
+static unsigned int adsp_ipc_read_iir(void)
+{
+    reg_write(rIpcDWR, 0);//dump write on demand
+    return reg_read(rIpcIIR);
+}
+
+static void adsp_ipc_set_wdr(void)
+{
+    reg_write(rIpcWDR, 0x55AA6688);
+    return;
+}
+
+static void adsp_ipc_set_isrw(void)
+{
+    reg_bit_set(rIpcISRW, 8);
+    //reg_write(rIpcISRW, ADSP_IPC_INT_CHANNEL);
+    return;
+}
+
+static void adsp_ipc_clear(unsigned int cls)
+{
+    reg_write(rIpcICR, cls);
+    return;
+}
+
+#if 0 //keep this for test
+static unsigned int adsp_ipc_tx_available(void)
+{
+    unsigned int delta = g_audio_ipc_handle.ring_ctl->cp_wptr - g_audio_ipc_handle.ring_ctl->ap_rptr;
+
+    return g_audio_ipc_handle.ring_ctl->unitnum - delta;
+}
+#endif
+
+static unsigned int adsp_ipc_rx_available(void)
+{
+    return g_audio_ipc_handle.ring_ctl->ap_wptr - g_audio_ipc_handle.ring_ctl->cp_rptr;
+}
+
+#if 0 //keep this for test
+static void print_AdspRingCtl(void)
+{
+    if (NULL == g_audio_ipc_handle.ring_ctl) {
+        printk("g_audio_ipc_handle.ring_ctl:0x%x\n", (unsigned int)g_audio_ipc_handle.ring_ctl);
+
+        return;
+    }
+
+    printk(KERN_INFO "p_adsp_ring_ctl(0x%x)," \
+           "tx_ring_buffer:(0x%x)," \
+           "rx_ring_buffer:(0x%x)," \
+           "ap_wptr:(0x%x)," \
+           "cp_rptr:(0x%x)," \
+           "cp_wptr:(0x%x)," \
+           "ap_rptr:(0x%x)," \
+           "unitsz:(0x%x)," \
+           "unitnum:(0x%x)\n", \
+           (unsigned int)g_audio_ipc_handle.ring_ctl, \
+           (unsigned int)g_audio_ipc_handle.tx_ring_buffer, \
+           (unsigned int)g_audio_ipc_handle.rx_ring_buffer, \
+           g_audio_ipc_handle.ring_ctl->ap_wptr, \
+           g_audio_ipc_handle.ring_ctl->cp_rptr, \
+           g_audio_ipc_handle.ring_ctl->cp_wptr, \
+           g_audio_ipc_handle.ring_ctl->ap_rptr, \
+           g_audio_ipc_handle.ring_ctl->unitsz, \
+           g_audio_ipc_handle.ring_ctl->unitnum);
+
+    printk(KERN_INFO "rxring_base:(0x%x),txring_base:(0x%x)\n", \
+           g_audio_ipc_handle.ring_ctl->rxring_base, \
+           g_audio_ipc_handle.ring_ctl->txring_base);
+
+    return;
+}
+#endif
+
+extern void handle_audio_playback_data(u16 len, u32 *addr, u16 id);
+extern void handle_audio_record_data(u16 len, u32 *addr, u16 id);
+extern void handle_adsp_exception(void);
+extern int audio_report_adsp_pwr_to_cp(u16 onoff);
+static int b_evs_set = 0;
+static int b_adsp_pwr_on = 0;
+static int b_adsp_pm_cp = 0;
+static unsigned char sAdspVer[42];
+
+#define ENABLE_ADSP_PM 0
+#if ENABLE_ADSP_PM
+static void pwr_off_hw(void);
+static struct task_struct *adsp_pwr_off_taskref = NULL;
+static DEFINE_MUTEX(pwr_lock);
+
+static int power_off_adsp_task(void *data)
+{
+    msleep(1000);
+    pwr_off_hw();
+    if (b_adsp_pm_cp) {
+        audio_report_adsp_pwr_to_cp(0);
+        b_adsp_pm_cp = 0;
+    }
+    adsp_pwr_off_taskref = NULL;
+    return 0;
+}
+
+void start_power_off_adsp(void)
+{
+    printk(KERN_INFO "%s/%d\n", __FUNCTION__, __LINE__);
+    if (adsp_pwr_off_taskref == NULL) {
+        adsp_pwr_off_taskref = (struct task_struct *)kthread_run(power_off_adsp_task, NULL, "pwr_off_adsp");
+    }
+}
+#endif
+
+static void pwr_on_hw(void);
+static struct task_struct *adsp_pwr_on_taskref = NULL;
+
+static int power_on_adsp_task(void *data)
+{
+    pwr_on_hw();
+    audio_report_adsp_pwr_to_cp(1);
+    b_adsp_pm_cp = 1;
+    adsp_pwr_on_taskref = NULL;
+    return 0;
+}
+
+void start_power_on_adsp_for_cp(void)
+{
+    printk(KERN_INFO "%s/%d: onoff=%d\n", __FUNCTION__, __LINE__, b_adsp_pwr_on);
+    if (b_adsp_pwr_on) {
+        audio_report_adsp_pwr_to_cp(1);
+        b_adsp_pm_cp = 1;
+        return;
+    }
+    if (adsp_pwr_on_taskref == NULL) {
+        adsp_pwr_on_taskref = (struct task_struct *)kthread_run(power_on_adsp_task, NULL, "pwr_on_adsp");
+    }
+}
+
+EXPORT_SYMBOL_GPL(start_power_on_adsp_for_cp);
+
+
+void AdspIPCCmdProcess(void)
+{
+    UINT32 LocalBuf[3 + IPC_MAX_CMD_LENGTH / 4];
+    IpcSetParamsType CmdParams;
+    //IpcDataParamsType DataParams;
+    IpcDataParamsType *DataParamsPtr = 0;
+    AdspRingCtl *IpcBuf = g_audio_ipc_handle.ring_ctl;
+    UINT32 IPCsizeMask = IpcBuf->unitnum - 1;
+    //UINT32 *IPCCmdBuf = (UINT32 *) IpcBuf->rxring_base;
+    UINT32 *IPCCmdBuf = g_audio_ipc_handle.rx_ring_buffer;
+    void __iomem *rData = NULL;
+
+    //printk("rxring_base= 0x%x,  cp_rptr  0x%x\n", IpcBuf->rxring_base, IpcBuf->cp_rptr);
+
+    while (IpcBuf->ap_wptr !=  IpcBuf->cp_rptr) {
+        UINT32 CopyLen;
+        int i, SetID;
+        UINT32 LocalOut = IpcBuf->cp_rptr;
+        union {
+            IpcCmdMsgHeaderType Cmd;
+            UINT32 Value;
+        } CmdHeader;
+
+        CmdHeader.Value =  IPCCmdBuf[IPCsizeMask & LocalOut];
+
+        CopyLen = (sizeof(CmdHeader) + CmdHeader.Cmd.UserLength + 3) >> 2;
+        for (i = 0; i < MIN(CopyLen, sizeof(LocalBuf) / 4); i++) {
+            LocalBuf[i] = IPCCmdBuf[IPCsizeMask & LocalOut];
+            LocalOut++;
+        }
+        IpcBuf->cp_rptr = LocalOut;
+
+        //Check Msg header
+        if (!CmdHeader.Cmd.Header) {
+            printk(KERN_INFO "%s/%d: ADSP IPC CMD Header is NULL\n", __FUNCTION__, __LINE__);
+            handle_adsp_exception();
+            return;
+        }
+
+        //Parser Msg header & DataParamsPtr
+        CmdParams.SubOpcode = CmdHeader.Cmd.Header;
+        CmdParams.CmdMsgLength = CmdHeader.Cmd.UserLength;
+        CmdParams.CmdMsgPtr = &LocalBuf[1];
+        DataParamsPtr = 0;
+        if (IPC_DATA_BIT( CmdParams.SubOpcode )) {
+            DataParamsPtr = (IpcDataParamsType *)&LocalBuf[1];
+
+            CmdParams.CmdMsgPtr += sizeof(IpcDataParamsType) / sizeof(UINT32);      //Msg skip IpcDataParamsType
+            CmdParams.CmdMsgLength -= sizeof(IpcDataParamsType);
+        }
+
+        //get SetID & subopcode
+        SetID = IPC_SET_ID( CmdParams.SubOpcode );
+        //CmdParams.SubOpcode = IPC_SUB_OPCODE( CmdParams.SubOpcode );
+
+#if ADSP_PRINT_IPC
+        printk("Receive: SetId:0x%x, SubOpcode:0x%x, CmdMsgLength:0x%x, CmdMsg:|%.8x|%.8x|%.8x|%.8x|\n",
+               SetID, CmdParams.SubOpcode, CmdParams.CmdMsgLength,
+               LocalBuf[1], LocalBuf[2], LocalBuf[3], LocalBuf[4]);
+#endif
+
+#if 0
+        //Process subopcode
+        if (DataParamsPtr) { //for data channel
+            UINT8 *p = NULL;
+            //printk(KERN_INFO "%s/%d: 0x%x|%d\n", __FUNCTION__, __LINE__, (unsigned int)DataParamsPtr->Ptr, DataParamsPtr->Length);
+            rData = ioremap_nocache((unsigned int)DataParamsPtr->Ptr, DataParamsPtr->Length);
+            if (!rData) {
+                printk(KERN_INFO "%s/%d: ioremap fail\n", __FUNCTION__, __LINE__);
+                return;
+            }
+            p = (UINT8 *)rData;
+            printk(KERN_INFO "Receive: SubOpcode:0x%.4x len:%d data:|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|\n", \
+                   CmdParams.SubOpcode, DataParamsPtr->Length, \
+                   *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++, \
+                   *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++);
+
+            //Process data
+        }
+#endif
+
+        switch (CmdParams.SubOpcode) {
+#if ENABLE_ADSP_PM
+            case POWER_OFF_REQ:
+            {
+                UINT16 *p = (UINT16 *)&LocalBuf[1];
+                printk("%s/%d: POWER_OFF_REQ: SubOpcode:0x%x\n", __FUNCTION__, __LINE__, CmdParams.SubOpcode);
+                if (b_adsp_pwr_on) {
+                    start_power_off_adsp();
+                }
+                break;
+            }
+#endif
+            case DATA_REQ:
+            {
+                UINT16 *p = (UINT16 *)&LocalBuf[1];
+                //printk("%s/%d: DATA_REQ: StreamID:%d, DataLen:0x%x, DataAddr:0x%x\n", __FUNCTION__, __LINE__, p[0], p[1], LocalBuf[2]);
+                handle_audio_playback_data(p[1], (u32 *)LocalBuf[2], p[0]);
+                break;
+            }
+
+            case RECORD_DATA:
+            {
+                UINT16 *p = (UINT16 *)&LocalBuf[1];
+                //printk("%s/%d: RECORD_DATA: Length:0x%x, Ptr:0x%x, StreamID:%d\n", __FUNCTION__, __LINE__, p[1], LocalBuf[2], p[4]);
+                handle_audio_record_data(p[1], (u32 *)LocalBuf[2], p[4]);
+                break;
+            }
+
+            case VOICE_DEBUG_CONTROL:
+            {
+                if (!b_evs_set) {
+                    memcpy(sAdspVer, CmdParams.CmdMsgPtr, 40);
+                    sAdspVer[40] = '\0';
+                    printk(KERN_INFO "ADSP Version: %s\n", sAdspVer);
+                    b_evs_set = 1;
+                }
+                break;
+            }
+
+            case ADSP_EXCEPTION:
+            {
+                UINT8 *p = NULL;
+                printk("%s/%d: ADSP report exception\n", __FUNCTION__, __LINE__);
+                if (DataParamsPtr) { //for data channel
+                    rData = ioremap_nocache((unsigned int)DataParamsPtr->Ptr, DataParamsPtr->Length);
+                    if (!rData) {
+                        printk(KERN_INFO "%s/%d: ioremap fail\n", __FUNCTION__, __LINE__);
+                        return;
+                    }
+                    p = (UINT8 *)rData;
+                    for (i = 0; i < (DataParamsPtr->Length + 15) / 16; i++) {
+#if 0
+                        printk(KERN_INFO "|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|\n", \
+                               *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++, \
+                               *p++, *p++, *p++, *p++, *p++, *p++, *p++, *p++);
+#else
+                        printk(KERN_INFO "|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|\n", \
+                               *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), \
+                               *(p+8), *(p+9), *(p+10), *(p+11), *(p+12), *(p+13), *(p+14), *(p+15));
+                        p += 16;
+#endif
+                    }
+                    handle_adsp_exception();
+                }
+                break;
+            }
+
+            default:
+                break;
+        }
+
+        if (DataParamsPtr) { //for data channel
+            if (rData) {
+                iounmap(rData);
+            }
+        }
+    }
+}
+
+//int gIpcIntDebug = 0;
+static irqreturn_t adsp_ipc_int_handler(int data, void *dev_id)
+{
+    //printk(KERN_INFO "%s:%d: \n", __FUNCTION__, __LINE__);
+    g_audio_ipc_handle.iir = adsp_ipc_read_iir();
+    adsp_ipc_clear(g_audio_ipc_handle.iir);
+    return IRQ_WAKE_THREAD;
+}
+
+static int b_phase2_inited = 0;
+static int adsp_ipc_init_phase2(void);
+irqreturn_t adsp_ipc_hisr(int irq, void *dev_id)
+{
+    unsigned int avail;
+
+    //print_AdspRingCtl();
+    //printk("adsp_ipc_hisr, g_audio_ipc_handle.iir:0x%x\n", g_audio_ipc_handle.iir);
+
+    if (!b_phase2_inited) {
+        b_phase2_inited = adsp_ipc_init_phase2();
+
+        if (!b_phase2_inited) {
+            return IRQ_HANDLED;
+        }
+    }
+
+    //unsigned int ipc_rdr = adsp_ipc_read_rdr();
+
+    avail = adsp_ipc_rx_available();
+
+    if (avail) {
+        AdspIPCCmdProcess();
+    }
+
+    //printk(KERN_INFO "%s/%d\n", __FUNCTION__, __LINE__);
+
+    //adsp_ipc_set_isrw();
+
+    return IRQ_HANDLED;
+}
+
+int adsp_ipc_init_phase1(void)
+{
+    int ret;
+
+    //AP ring_ctl addr is agreed in advance
+    if (!rRingCtrl) {
+        printk(KERN_INFO "%s/%d: ioremap fail\n", __FUNCTION__, __LINE__);
+        return 1;
+    }
+    g_audio_ipc_handle.ring_ctl = (AdspRingCtl *) rRingCtrl;
+
+    /*==================================================================*/
+    /*          in case that CP reset,rx clear buffer and INT           */
+    /*==================================================================*/
+    //adsp_ipc_clear(0xFFFFFFFF);
+
+    /*==================================================================*/
+    /*                  create semaphore for ring buffer                */
+    /*==================================================================*/
+    mutex_init(&g_audio_ipc_sema);
+    ret = request_threaded_irq(adsp_irq, adsp_ipc_int_handler, adsp_ipc_hisr, \
+                               IRQF_TRIGGER_HIGH | IRQF_ONESHOT, \
+                               "ipc_adsp2ap_int", NULL);
+    if (ret < 0) {
+        printk(KERN_INFO "%s/%d: request irq fail\n", __FUNCTION__, __LINE__);
+        return 3;
+    }
+    printk(KERN_INFO "%s/%d: ret=%d\n", __FUNCTION__, __LINE__, ret);
+
+    disable_irq(adsp_irq);
+    enable_irq(adsp_irq);
+
+    /*==================================================================*/
+    /*                          enable ipc clock in                     */
+    /*==================================================================*/
+    print_adsp_ipc_clk();
+    adsp_ipc_clk_enable();
+    print_adsp_ipc_clk();
+
+    mutex_lock(&g_audio_ipc_sema);
+
+    printk(KERN_INFO "%s/%d Done.\n", __FUNCTION__, __LINE__);
+
+    return 0;
+}
+
+static int adsp_ipc_init_phase2(void)
+{
+    //AP ring_ctl addr is from IPC reg
+    //g_audio_ipc_handle.ring_ctl = (AdspRingCtl *)adsp_ipc_read_rdr();
+    printk("%s/%d g_audio_ipc_handle.ring_ctl 0x%x\n", __FUNCTION__, __LINE__, (unsigned int)g_audio_ipc_handle.ring_ctl);
+
+    if (g_audio_ipc_handle.ring_ctl
+        && g_audio_ipc_handle.ring_ctl->rxring_base
+        && g_audio_ipc_handle.ring_ctl->txring_base) {
+
+        g_audio_ipc_handle.rx_ring_buffer = ioremap_nocache(g_audio_ipc_handle.ring_ctl->rxring_base, ADSP_RING_BUFFER_SIZE);
+        if (NULL == g_audio_ipc_handle.rx_ring_buffer) {
+            printk(KERN_INFO "%s/%d: ioremap fail\n", __FUNCTION__, __LINE__);
+            return 0;
+        }
+
+        g_audio_ipc_handle.tx_ring_buffer = ioremap_nocache(g_audio_ipc_handle.ring_ctl->txring_base, ADSP_RING_BUFFER_SIZE);
+        if (NULL == g_audio_ipc_handle.tx_ring_buffer) {
+            printk(KERN_INFO "%s/%d: ioremap fail\n", __FUNCTION__, __LINE__);
+            return 0;
+        }
+
+        mutex_unlock(&g_audio_ipc_sema); // after Adsp report the Version report, CP can send the IPC to Adsp
+        printk(KERN_INFO "%s/%d Done.\n", __FUNCTION__, __LINE__);
+        return 1;
+    }
+    else {
+        printk("adsp_ipc_init_phase1 Do Not Excute\n");
+    }
+
+    return 0;
+}
+
+static int PackIpcMsg(
+    UINT32 *Buf,
+    IpcSetIDType SetId,
+    IpcSetParamsType *IpcMsgParams,
+    IpcDataParamsType *IpcDataParams)
+{
+    Word32 CopyLen = 1;
+    Word32 MsgLen = (IpcMsgParams->CmdMsgLength + 1) >> 1;
+    {
+        union {
+            IpcCmdMsgHeaderType Msg;
+            UINT32 Value;
+        } IpcHeader;
+
+        IpcHeader.Msg.Header = IPC_COMPOSE_HEADER( SetId, IpcMsgParams->SubOpcode,  0,  (IpcDataParams ? 1 : 0),  0 );
+        IpcHeader.Msg.UserLength = IpcMsgParams->CmdMsgLength * 2 + (IpcDataParams ? sizeof(IpcDataParamsType) : 0);    //UserLength in bytes, without header size
+        *Buf++ = IpcHeader.Value;                                                                                       //32bit operation
+    }
+
+    if (IpcDataParams) {
+        *Buf++ = *((UINT32 *)(IpcDataParams));  // copy data header : ChId, CopyFlag and Length
+        *Buf++ = (UINT32)(IpcDataParams->Ptr);  // Copy Ptr
+        CopyLen += 2;
+    }
+
+    CopyLen += MsgLen;
+    memcpy((short *)Buf, (short *)IpcMsgParams->CmdMsgPtr,  MsgLen * 4);
+    return CopyLen;
+}
+
+IpcReturnCodeType IpcSendAdspMessageData(
+    IpcSetIDType SetId,
+    IpcSetParamsType *IpcMsgParams,
+    IpcDataParamsType *IpcDataParams)
+{
+    AdspRingCtl *IpcBuf = g_audio_ipc_handle.ring_ctl;
+    //  IPCRegType *IpcReg = (IPCRegType *)(BX2_CP_IPC_BASE)  ;
+    UINT32 LocalBuf[3 + IPC_MAX_CMD_LENGTH / 4];
+    //UINT32 currIMASK;
+    UINT32 CopyLen = PackIpcMsg(LocalBuf, SetId, IpcMsgParams, IpcDataParams);
+    IpcReturnCodeType ret = IPC_OK;
+
+    //UINT16 *p = (UINT16 *)LocalBuf;
+
+    //printk(KERN_INFO "%s/%d\n", __FUNCTION__, __LINE__);
+
+    if (!b_phase2_inited) {
+        printk(KERN_INFO "%s/%d: Adsp IPC is not ready\n", __FUNCTION__, __LINE__);
+        return IPC_ERROR;
+    }
+
+    //printk(KERN_INFO "CopyLen:%d, data:|%.4x %.4x|%.4x %.4x|%.4x %.4x|%.4x %.4x|%.4x %.4x|\n",
+    //CopyLen, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
+
+    //atom operation
+    mutex_lock(&g_audio_ipc_sema);
+
+    if ((IpcBuf->cp_wptr - IpcBuf->ap_rptr + CopyLen) <= IpcBuf->unitnum) {     //enough space to fill
+        UINT32 IPCsizeMask = IpcBuf->unitnum - 1;
+        UINT32 Windex = IpcBuf->cp_wptr & IPCsizeMask;
+        //UINT32 *IPCMsgMEM = (UINT32 *)IpcBuf->txring_base;
+        UINT32 *IPCMsgMEM = g_audio_ipc_handle.tx_ring_buffer;
+        int i;
+        for (i = 0; i < CopyLen; i++) {
+            IPCMsgMEM[Windex++] = LocalBuf[i];
+            Windex &= IPCsizeMask;
+        }
+        IpcBuf->cp_wptr += CopyLen;
+        //for ARM use DSB, ISB before trigger int to DSP !!!!!!!!!!!!.
+        //issue_sync_barrier
+        //NOP
+        //DSB
+        //ISB
+        //NOP
+        //BX LR
+        __asm__ __volatile__ ("ISB");
+        __asm__ __volatile__ ("DSB");     //make sure the data is ready before DSP is informed.
+
+        //send IPC INT to Adsp
+        adsp_ipc_set_wdr();
+        adsp_ipc_set_isrw();
+    }
+    else {
+        printk("Send Adsp IPC CMD Overflow\n");
+        ret = IPC_MSG_QUEUE_OVERFLOW;
+    }
+
+    mutex_unlock(&g_audio_ipc_sema);
+    //printk(KERN_INFO "%s/%d Done.\n\n", __FUNCTION__, __LINE__);
+    return ret;
+}
+
+
+/******************************************************************************
+*   Macro definitions
+******************************************************************************/
+//in short
+#define VOICE_START_COMMAND_LENGTH  7
+#define ADSP_SET_COMMAND_LENGTH  32
+
+
+/******************************************************************************
+*   Local variable definitions
+******************************************************************************/
+static int is_adsp_inited = 0;
+static int is_dump_full_ddr = 0;
+
+int ap_send_adsp(u16 *msg, int msglen, int sub_cmd )
+{
+    IpcSetIDType SetId = 0;
+    IpcSetParamsType CmdParams;
+    IpcDataParamsType DataParams;
+    UINT8 CmdMsg[128] = { 0 };
+
+    //printk(KERN_INFO "send cmd to adsp\n");
+
+    memset(&CmdParams, 0, sizeof(IpcSetParamsType));
+    memset(&DataParams, 0, sizeof(IpcDataParamsType));
+
+    if (!is_adsp_inited) {
+        printk(KERN_INFO "%s/%d: adsp is not ready\n", __FUNCTION__, __LINE__);
+        return -EFAULT;
+    }
+
+#if ENABLE_ADSP_PM
+    mutex_lock(&pwr_lock);
+
+    if (!b_adsp_pwr_on) {
+        pwr_on_hw();
+    }
+
+    mutex_unlock(&pwr_lock);
+#endif
+
+    CmdParams.SubOpcode = sub_cmd;
+    CmdParams.CmdMsgLength = msglen;
+    if (CmdParams.CmdMsgLength < ADSP_SET_COMMAND_LENGTH * 2 - 3) {
+        if (DATA_INDICATION == sub_cmd) {
+            memcpy(CmdMsg, msg + sizeof(IpcDataParamsType) / 2, 2);
+            CmdParams.CmdMsgPtr = (UINT32 *)CmdMsg;
+            CmdParams.SubOpcode |= (0x1 << IPC_HEADER_DATA_BITNUM);
+            memcpy(&DataParams, msg, sizeof(IpcDataParamsType));
+#if ADSP_PRINT_IPC
+            printk(KERN_INFO "SetId:0x%x, SubOpcode:0x%x, CmdMsgLength:%d, DataParams.Length:0x%.4x, DataParams.Ptr:0x%.8x, CmdMsgPtr:0x%x\n",
+                   SetId, CmdParams.SubOpcode, CmdParams.CmdMsgLength,
+                   DataParams.Length, DataParams.Ptr, ((UINT16 *)CmdParams.CmdMsgPtr)[0]);
+#endif
+            IpcSendAdspMessageData(SetId, &CmdParams, &DataParams);
+        }
+        else {
+            memcpy(CmdMsg, msg, msglen * 2);
+            CmdParams.CmdMsgPtr = (UINT32 *)CmdMsg;
+#if ADSP_PRINT_IPC
+            printk(KERN_INFO "SetId:0x%x, SubOpcode:0x%x, CmdMsgLength:0x%x, CmdMsg:|%.8x|%.8x|%.8x|%.8x|\n",
+                   SetId, CmdParams.SubOpcode, CmdParams.CmdMsgLength,
+                   CmdParams.CmdMsgPtr[0], CmdParams.CmdMsgPtr[1], CmdParams.CmdMsgPtr[2], CmdParams.CmdMsgPtr[3]);
+#endif
+            IpcSendAdspMessageData(SetId, &CmdParams, NULL);
+        }
+
+        return 0;
+    }
+    return -EFAULT;
+
+}
+
+EXPORT_SYMBOL_GPL(ap_send_adsp);
+
+
+/******************************************************************************
+*   Macro definitions
+******************************************************************************/
+//#define AUDIODEBUG_LOG
+
+typedef unsigned short ApplicationID;
+typedef unsigned int IPC_DataChannelNumber;
+
+typedef struct {
+    unsigned short opCode;
+    unsigned short length;
+    unsigned char *pipe;
+}IPC_CmdMsgParams;
+
+typedef struct {
+    unsigned short setID;
+    unsigned short subOpCode;
+    bool allSubOpCodes;
+}OpCodeParams;
+
+typedef struct {
+    unsigned short opCode;
+    unsigned short cmdLength;
+    unsigned short *cmdData;
+}IPC_Command;
+
+typedef struct {
+    unsigned int dataChannelID;
+    unsigned int copyMode;
+    unsigned short dataSize;
+    unsigned int *dataSrcPtr;
+    unsigned int *dataDestPtr;
+}IPC_DataStructToSend;
+
+typedef struct {
+    unsigned int *dataPtr;
+    unsigned short dataSize;
+    unsigned int dataChannelID;
+}IPC_DataStructReceived;
+
+
+/******************************************************************************
+*   Local variable definitions
+******************************************************************************/
+static int is_1901_E = 0;
+static int is_pmu_clk_inited = 0;
+
+
+/******************************************************************************
+*   functions for load adsp
+******************************************************************************/
+#define ADSP_BIN_NAME_1     "/data/adsp.bin"
+#define ADSP_BIN_NAME_E     "/lib/firmware/adsp.bin"
+#define ADSP_BIN_NAME_S     "/lib/firmware/adsp_s.bin"
+#define ADSP_READ_SIZE      (0x10000)
+
+#define ADSP_CHECK_IMAGE 1
+#if ADSP_CHECK_IMAGE
+#define ADSP_CHECK_SIZE (0x1000)
+#define ADSP_CHECK_COUNT 5
+#endif
+
+int enable_pmu_audio_clk(void)
+{
+    if (is_pmu_clk_inited) {
+        return 0;
+    }
+
+    if (!rClk) {
+        rClk = ioremap_nocache(REG_PMU_AUDIO_CLK_RES_CTRL, 4);
+        if (!rClk) {
+            printk(KERN_INFO "%s/%d: ioremap fail\n", __FUNCTION__, __LINE__);
+            return 1;
+        }
+    }
+
+    reg_write(rClk, reg_read(rClk) & ~8);   //put bx2 in reset
+    reg_bit_set(rClk, 19);                  //bypass repaire
+    reg_bit_set(rClk, 27);                  //enable  hw mode
+    reg_bit_set(rClk, 29);                  //trigger hw pwr on
+    printk(KERN_INFO "%s/%d: Done.\n", __FUNCTION__, __LINE__);
+
+    is_pmu_clk_inited = 1;
+
+    return 0;
+}
+
+static void pwr_on_hw(void)
+{
+    volatile unsigned int rdata;
+    int i;
+
+    if (b_adsp_pwr_on) {
+        return;
+    }
+
+    //Step 1 : Reset DSP
+    enable_pmu_audio_clk();
+
+    for (i = 0; i < 50; i++) {
+        printk(KERN_INFO "wait for audio power state (on) ...\n");
+        rdata = reg_read(rPwr);
+        //printk(KERN_INFO "pwr=0x%x\n", rdata);
+        if ((rdata & 0x800) != 0) {
+            break;
+        }
+        msleep(300);
+    }
+    printk(KERN_INFO "%s/%d: power on audio (hw mode) ok\n", __FUNCTION__, __LINE__);
+
+    // Step2 : AP Copy ITCM to   (0xD6200000)
+    if (is_1901_E) {
+        memcpy(rItcm, __va(ADSP_DDR_LOAD_ADDR), ITCM_LENGTH);
+    }
+    else {
+        memcpy(rItcm, __va(ADSP_DDR_LOAD_ADDR_S), ITCM_LENGTH);
+    }
+
+    // Step3 : AP Set DSP PC= 0x10
+    reg_write(rPc, 0x10);
+
+    // Step4 : AP Release DSP
+    reg_bit_set(rClk, 3);   //enable release audio aon reset
+    printk(KERN_INFO "%s/%d: release audio bx2 core\n", __FUNCTION__, __LINE__);
+    reg_write(rRls, 0xF);   // enable axi dyn ckg
+
+    printk(KERN_INFO "%s/%d Done.\n", __FUNCTION__, __LINE__);
+    b_adsp_pwr_on = 1;
+}
+
+static void pwr_off_hw(void)
+{
+    volatile unsigned int rdata;
+    int i;
+
+    if (!b_adsp_pwr_on) {
+        return;
+    }
+
+    reg_bit_set(rClk, 27);  //enable hw mode
+    printk(KERN_INFO "%s/%d: trigger power off audio (hw mode)\n", __FUNCTION__, __LINE__);
+    reg_bit_clr(rClk, 29);  //trigger hw pwr off
+
+    for (i = 0; i < 50; i++) {
+        printk(KERN_INFO "wait for audio power state (off) ...\n");
+        rdata = reg_read(rPwr);
+        //printk(KERN_INFO "pwr=0x%x\n", rdata);
+        if ((rdata & 0x40) == 0) {
+            break;
+        }
+        msleep(300);
+    }
+
+    printk(KERN_INFO "%s/%d Done.\n", __FUNCTION__, __LINE__);
+    is_pmu_clk_inited = 0;
+    b_adsp_pwr_on = 0;
+}
+
+extern int audio_request_cp_down(void);
+
+static int ap_boot_adsp(void)
+{
+    struct file *fp;
+    mm_segment_t fs;
+    loff_t pos;
+    ssize_t readret;
+    unsigned char *pread;
+    void *ptr;
+
+#if ADSP_CHECK_IMAGE
+    unsigned char *pddr;
+    int b_check_fail = 0;
+    int i = 0;
+#endif
+
+    //Step 0 : Copy bin from Flash to DDR
+    if (!rPc || !rRls || !rItcm) {
+        printk(KERN_INFO "%s/%d: registers not ready for boot bx2\n", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+#if ADSP_CHECK_IMAGE
+    for (i = 0; i < ADSP_CHECK_COUNT; i++) {
+        pread = is_1901_E ? __va(ADSP_DDR_LOAD_ADDR) : __va(ADSP_DDR_LOAD_ADDR_S);
+        printk(KERN_INFO "%s/%d: 0x%x\n", __FUNCTION__, __LINE__, (unsigned int)pread);
+        b_check_fail = 0;
+#endif
+    fp = filp_open(ADSP_BIN_NAME_1, O_RDONLY, 0);
+    if (IS_ERR(fp)) {
+        if (is_1901_E) {
+            fp = filp_open(ADSP_BIN_NAME_E, O_RDONLY, 0);
+        }
+        else {
+            fp = filp_open(ADSP_BIN_NAME_S, O_RDONLY, 0);
+        }
+        if (IS_ERR(fp)) {
+            printk(KERN_INFO "%s/%d: warning: open adsp bin fail, but can be ignored.\n", __FUNCTION__, __LINE__);
+            return -2;
+        }
+        printk(KERN_INFO "%s/%d: load %s\n", __FUNCTION__, __LINE__, is_1901_E ? ADSP_BIN_NAME_E : ADSP_BIN_NAME_S);
+    }
+    else {
+        printk(KERN_INFO "%s/%d: load %s\n", __FUNCTION__, __LINE__, ADSP_BIN_NAME_1);
+    }
+
+    fs = get_fs();
+    set_fs(KERNEL_DS);
+
+    pos = 0;
+    do {
+        readret = vfs_read(fp, pread, ADSP_READ_SIZE, &pos);
+        //printk(KERN_INFO "read: 0x%x|%x|%x|%x| read=0x%x pos=0x%llx \n", pread[0], pread[1], pread[2], pread[3], readret, pos);
+
+        for (ptr = pread;
+             (unsigned int)ptr < (unsigned int)(pread + readret);
+             ptr += PAGE_SIZE) {
+            flush_dcache_page(virt_to_page(ptr));
+        }
+
+        pread += readret;
+    }while (readret == ADSP_READ_SIZE);
+
+    printk(KERN_INFO "load adsp bin size: 0x%llx\n", pos);
+    if (is_1901_E) {
+        dma_sync_single_for_device(NULL, ADSP_DDR_LOAD_ADDR, ADSP_DDR_LOAD_LENGTH, DMA_FROM_DEVICE);
+    }
+    else {
+        dma_sync_single_for_device(NULL, ADSP_DDR_LOAD_ADDR_S, ADSP_DDR_LOAD_LENGTH_S, DMA_FROM_DEVICE);
+    }
+
+#if ADSP_CHECK_IMAGE
+    pddr = is_1901_E ? __va(ADSP_DDR_LOAD_ADDR) : __va(ADSP_DDR_LOAD_ADDR_S);
+
+    pread = (char *)vmalloc(ADSP_CHECK_SIZE);
+    if (!pread) {
+        printk(KERN_INFO "%s/%d: vmalloc for adsp check ddr fail\n", __FUNCTION__, __LINE__);
+        filp_close(fp, NULL);
+        set_fs(fs);
+        return -3;
+    }
+
+    pos = 0;
+    do {
+        readret = vfs_read(fp, pread, ADSP_CHECK_SIZE, &pos);
+
+        if (memcmp(pread, pddr, readret)) {
+            printk(KERN_INFO "adsp check ddr fail in 0x%llx, try %d more times\n", pos, ADSP_CHECK_COUNT - i - 1);
+            b_check_fail = 1;
+            break;
+        }
+
+        pddr += readret;
+    }while (readret == ADSP_CHECK_SIZE);
+
+    if (pread) {
+        vfree(pread);
+    }
+#endif
+
+    filp_close(fp, NULL);
+    set_fs(fs);
+
+#if ADSP_CHECK_IMAGE
+    if (!b_check_fail) {
+        printk(KERN_INFO "adsp check ddr: pass\n");
+        break;
+    }
+
+    msleep(3000);
+}
+
+if (b_check_fail) {
+    printk(KERN_INFO "adsp check ddr fail for %d times, the config of is_dump_full_ddr is %d, now forced to 1\n", i, is_dump_full_ddr);
+    is_dump_full_ddr = 1;
+    audio_request_cp_down();
+    return -4;
+}
+#endif
+
+    pwr_on_hw();
+    is_adsp_inited = 1;
+
+#if ENABLE_ADSP_PM
+    msleep(1000);
+    pwr_off_hw();
+#endif
+
+    return 0;
+}
+
+static int check_adsp_ddr(void)
+{
+    struct file *fp;
+    mm_segment_t fs;
+    loff_t pos;
+    ssize_t readret;
+    unsigned char *pread;
+    unsigned char *pddr;
+
+    pread = is_1901_E ? __va(ADSP_DDR_LOAD_ADDR) : __va(ADSP_DDR_LOAD_ADDR_S);
+    printk(KERN_INFO "%s/%d: 0x%x\n", __FUNCTION__, __LINE__, (unsigned int)pread);
+
+    fp = filp_open(ADSP_BIN_NAME_1, O_RDONLY, 0);
+    if (IS_ERR(fp)) {
+        if (is_1901_E) {
+            fp = filp_open(ADSP_BIN_NAME_E, O_RDONLY, 0);
+        }
+        else {
+            fp = filp_open(ADSP_BIN_NAME_S, O_RDONLY, 0);
+        }
+        if (IS_ERR(fp)) {
+            printk(KERN_INFO "%s/%d: warning: open adsp bin fail, but can be ignored.\n", __FUNCTION__, __LINE__);
+            return -2;
+        }
+        printk(KERN_INFO "%s/%d: check %s\n", __FUNCTION__, __LINE__, is_1901_E ? ADSP_BIN_NAME_E : ADSP_BIN_NAME_S);
+    }
+    else {
+        printk(KERN_INFO "%s/%d: check %s\n", __FUNCTION__, __LINE__, ADSP_BIN_NAME_1);
+    }
+
+    pddr = is_1901_E ? __va(ADSP_DDR_LOAD_ADDR) : __va(ADSP_DDR_LOAD_ADDR_S);
+
+    pread = (char *)vmalloc(ADSP_CHECK_SIZE);
+    if (!pread) {
+        printk(KERN_INFO "%s/%d: vmalloc for adsp check ddr fail\n", __FUNCTION__, __LINE__);
+        filp_close(fp, NULL);
+        return -3;
+    }
+
+    fs = get_fs();
+    set_fs(KERNEL_DS);
+
+    pos = 0;
+    do {
+        readret = vfs_read(fp, pread, ADSP_CHECK_SIZE, &pos);
+
+        if (memcmp(pread, pddr, readret)) {
+            printk(KERN_INFO "adsp check ddr fail in 0x%llx, the config of is_dump_full_ddr is %d, now forced to 1\n", pos, is_dump_full_ddr);
+            is_dump_full_ddr = 1;
+            //audio_request_cp_down(); //here cp already to be down
+            if (pread) {
+                vfree(pread);
+            }
+            filp_close(fp, NULL);
+            set_fs(fs);
+            return -4;
+        }
+
+        pddr += readret;
+    }while (readret == ADSP_CHECK_SIZE);
+
+    if (pread) {
+        vfree(pread);
+    }
+
+    filp_close(fp, NULL);
+    set_fs(fs);
+
+    printk(KERN_INFO "%s/%d: pass, the config of is_dump_full_ddr is %d\n", __FUNCTION__, __LINE__, is_dump_full_ddr);
+
+    return 0;
+}
+
+static void ap_reset_adsp(void)
+{
+    reg_write(rClk, reg_read(rClk) & ~8);   //put bx2 in reset
+
+    //is_adsp_inited = 1;
+    printk(KERN_INFO "%s/%d Done.\n", __FUNCTION__, __LINE__);
+}
+
+
+/******************************************************************************
+*   functions for task
+******************************************************************************/
+#define CONFIG_ASR1901S_MEM_SIZE    (256 * 1024 * 1024)
+static struct task_struct *adsp_taskref = NULL;
+extern bool cpu_is_asr190Xe(void);
+
+static int boot_adsp_task(void *data)
+{
+    //msleep(10000); //delay 10 seconds
+    printk(KERN_INFO "%s/%d: platform is 1901%c\n", __FUNCTION__, __LINE__, is_1901_E ? 'E' : 'S');
+
+    if (ap_boot_adsp()) {
+        //enable_pmu_audio_clk();
+        return 1;
+    }
+    return 0;
+}
+
+void start_boot_adsp(void)
+{
+    if (cpu_is_asr190Xe()) {
+        is_1901_E = 1;
+    }
+    if ((cpu_is_asr1901_a0_plus() || cpu_is_asr1906()) && adsp_taskref == NULL) {
+        adsp_taskref = (struct task_struct *)kthread_run(boot_adsp_task, NULL, "boot_adsp");
+    }
+}
+
+EXPORT_SYMBOL_GPL(start_boot_adsp);
+EXPORT_SYMBOL_GPL(enable_pmu_audio_clk);
+
+
+/******************************************************************************
+*   functions for task
+******************************************************************************/
+#define MFPR_SSPA_VALUE 0x1042
+#define MFPR_SSPA_SET_COUNT 10
+
+void audio_enable_mfpr_sspa(void)
+{
+    volatile unsigned int rdata;
+    int i;
+
+    for (i = 0; i < MFPR_SSPA_SET_COUNT; i++) {
+        reg_write(rSspaClk, MFPR_SSPA_VALUE);
+        rdata = reg_read(rSspaClk);
+        if (MFPR_SSPA_VALUE == rdata) {
+            break;
+        }
+        msleep(300);
+    }
+
+    for (i = 0; i < MFPR_SSPA_SET_COUNT; i++) {
+        reg_write(rSspaFrm, MFPR_SSPA_VALUE);
+        rdata = reg_read(rSspaFrm);
+        if (MFPR_SSPA_VALUE == rdata) {
+            break;
+        }
+        msleep(300);
+    }
+
+    for (i = 0; i < MFPR_SSPA_SET_COUNT; i++) {
+        reg_write(rSspaTxd, MFPR_SSPA_VALUE);
+        rdata = reg_read(rSspaTxd);
+        if (MFPR_SSPA_VALUE == rdata) {
+            break;
+        }
+        msleep(300);
+    }
+
+    for (i = 0; i < MFPR_SSPA_SET_COUNT; i++) {
+        reg_write(rSspaRxd, MFPR_SSPA_VALUE);
+        rdata = reg_read(rSspaRxd);
+        if (MFPR_SSPA_VALUE == rdata) {
+            break;
+        }
+        msleep(300);
+    }
+}
+
+EXPORT_SYMBOL_GPL(audio_enable_mfpr_sspa);
+
+
+/******************************************************************************
+*   functions for dump
+******************************************************************************/
+#define ADSP_DUMP_DDR_NAME  "/data/adsp_ddr.dat"
+#define ADSP_DUMP_SQU_NAME  "/data/adsp_squ.dat"
+#define ADSP_DUMP_DTCM_NAME "/data/adsp_dtcm.dat"
+#define ADSP_DUMP_SHM_NAME  "/data/adsp_shm.dat"
+#define ADSP_WRITE_SIZE      (0x4000)
+
+static void dump_memory(unsigned int type)
+{
+    struct file *fp;
+    mm_segment_t fs;
+    loff_t pos;
+    ssize_t ret;
+    unsigned char *pWrite;
+    unsigned int length;
+    int i;
+
+    switch (type) {
+        case 1:
+            printk(KERN_INFO "dump adsp ddr memory to %s\n", ADSP_DUMP_DDR_NAME);
+            if (is_1901_E) {
+                dma_sync_single_for_device(NULL, ADSP_DDR_LOAD_ADDR, ADSP_DDR_LOAD_LENGTH, DMA_FROM_DEVICE);
+                pWrite = (unsigned char *)__va(ADSP_DDR_LOAD_ADDR);
+                length = ADSP_DDR_LOAD_LENGTH;
+            }
+            else {
+                dma_sync_single_for_device(NULL, ADSP_DDR_LOAD_ADDR_S, ADSP_DDR_LOAD_LENGTH_S, DMA_FROM_DEVICE);
+                pWrite = (unsigned char *)__va(ADSP_DDR_LOAD_ADDR_S);
+                length = ADSP_DDR_LOAD_LENGTH_S;
+            }
+            fp = filp_open(ADSP_DUMP_DDR_NAME, O_RDWR | O_CREAT | O_SYNC, 0644);
+            break;
+
+        case 2:
+            printk(KERN_INFO "dump adsp squ memory to %s\n", ADSP_DUMP_SQU_NAME);
+            fp = filp_open(ADSP_DUMP_SQU_NAME, O_RDWR | O_CREAT | O_SYNC, 0644);
+            pWrite = (unsigned char *)rDumpSQU;
+            length = ADSP_DUMP_SQU_LENGTH;
+            break;
+
+        case 3:
+            printk(KERN_INFO "dump adsp dtcm memory to %s\n", ADSP_DUMP_DTCM_NAME);
+#if ENABLE_ADSP_PM
+            pwr_on_hw();
+#endif
+            fp = filp_open(ADSP_DUMP_DTCM_NAME, O_RDWR | O_CREAT | O_SYNC, 0644);
+            pWrite = (unsigned char *)rDumpDTCM;
+            length = ADSP_DUMP_DTCM_LENGTH;
+            break;
+
+        case 4:
+            printk(KERN_INFO "dump adsp shm memory to %s\n", ADSP_DUMP_SHM_NAME);
+#if ENABLE_ADSP_PM
+            pwr_on_hw();
+#endif
+            fp = filp_open(ADSP_DUMP_SHM_NAME, O_RDWR | O_CREAT | O_SYNC, 0644);
+            pWrite = (unsigned char *)rDumpSHM;
+            length = ADSP_DUMP_SHM_LENGTH;
+            break;
+
+        default:
+            printk(KERN_INFO "%s/%d: type invalid\n", __FUNCTION__, __LINE__);
+            break;
+    }
+
+    if (IS_ERR(fp)) {
+        printk(KERN_INFO "%s/%d: open adsp dump file fail\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    if (!pWrite) {
+        printk(KERN_INFO "%s/%d: ioremap fail\n", __FUNCTION__, __LINE__);
+        filp_close(fp, NULL);
+        return;
+    }
+
+    fs = get_fs();
+    set_fs(KERNEL_DS);
+
+    //pos = 0;
+    for (i = 0; i < length / ADSP_WRITE_SIZE; i++) {
+        pos = fp->f_pos;
+        ret = vfs_write(fp, pWrite, ADSP_WRITE_SIZE, &pos);
+        //printk(KERN_INFO "write: 0x%x|%x|%x|%x| write=0x%x pos=0x%llx \n", pWrite[0], pWrite[1], pWrite[2], pWrite[3], ret, pos);
+        fp->f_pos = pos;
+        pWrite += ret;
+    }
+
+    printk(KERN_INFO "dump adsp size: 0x%llx\n", pos);
+
+    set_fs(fs);
+    filp_close(fp, NULL);
+}
+
+static struct task_struct *adsp_exception_taskref = NULL;
+
+static int adsp_exception_task(void *data)
+{
+    msleep(300);  //300 ms, in case CP does not receive the ADSP exception report, which can trigger CP assert
+    ap_reset_adsp();
+    check_adsp_ddr();
+
+    if (!is_dump_full_ddr) {
+        if (is_1901_E) {
+            memcpy(__va(ADSP_DDR_LOAD_ADDR), rDumpDTCM, ADSP_DUMP_DTCM_LENGTH);
+            memcpy(__va(ADSP_DDR_LOAD_ADDR) + ADSP_DUMP_DTCM_LENGTH, rDumpSHM, ADSP_DUMP_SHM_LENGTH);
+        }
+        else {
+            memcpy(__va(ADSP_DDR_LOAD_ADDR_S), rDumpDTCM, ADSP_DUMP_DTCM_LENGTH);
+            memcpy(__va(ADSP_DDR_LOAD_ADDR_S) + ADSP_DUMP_DTCM_LENGTH, rDumpSHM, ADSP_DUMP_SHM_LENGTH);
+        }
+    }
+
+#if 0 //use ramp dump instead of write dump files to flash
+    dump_memory(1);
+    dump_memory(2);
+    dump_memory(3);
+    dump_memory(4);
+#endif
+
+    printk(KERN_INFO "%s/%d: ADSP Version: %s\n", __FUNCTION__, __LINE__, sAdspVer);
+
+    return 0;
+}
+
+void handle_adsp_exception(void)
+{
+    if ((cpu_is_asr1901_a0_plus() || cpu_is_asr1906()) && adsp_exception_taskref == NULL) {
+        adsp_exception_taskref = (struct task_struct *)kthread_run(adsp_exception_task, NULL, "adsp_exception");
+    }
+}
+
+EXPORT_SYMBOL_GPL(handle_adsp_exception);
+
+
+/******************************************************************************
+*   functions for debugfs
+******************************************************************************/
+#ifdef CONFIG_DEBUG_FS
+static void *adsp_map_ddr;
+static u32 adsp_map_len;
+
+static ssize_t adsp_rdp_squ_read(struct file *file, char __user *user_buf,
+                                 size_t size, loff_t *ppos)
+{
+    int ret;
+
+    ret = simple_read_from_buffer(user_buf, size, ppos,
+                                  rDumpSQU,
+                                  ADSP_DUMP_SQU_LENGTH);
+    return ret;
+}
+static const struct file_operations adsp_rdp_squ_fops = {
+    .owner = THIS_MODULE,
+    .open = simple_open,
+    .read = adsp_rdp_squ_read,
+};
+
+static ssize_t adsp_rdp_dtcm_read(struct file *file, char __user *user_buf,
+                                  size_t size, loff_t *ppos)
+{
+    int ret;
+
+    ret = simple_read_from_buffer(user_buf, size, ppos,
+                                  adsp_map_ddr,
+                                  ADSP_DUMP_DTCM_LENGTH);
+    return ret;
+}
+static const struct file_operations adsp_rdp_dtcm_fops = {
+    .owner = THIS_MODULE,
+    .open = simple_open,
+    .read = adsp_rdp_dtcm_read,
+};
+
+static ssize_t adsp_rdp_shm_read(struct file *file, char __user *user_buf,
+                                 size_t size, loff_t *ppos)
+{
+    int ret;
+
+    ret = simple_read_from_buffer(user_buf, size, ppos,
+                                  adsp_map_ddr + ADSP_DUMP_DTCM_LENGTH,
+                                  ADSP_DUMP_SHM_LENGTH);
+    return ret;
+}
+
+static const struct file_operations adsp_rdp_shm_fops = {
+    .owner = THIS_MODULE,
+    .open = simple_open,
+    .read = adsp_rdp_shm_read,
+};
+
+static ssize_t adsp_rdp_ddr_read(struct file *file, char __user *user_buf,
+                                 size_t size, loff_t *ppos)
+{
+    int ret;
+
+    ret = simple_read_from_buffer(user_buf, size, ppos,
+                                  adsp_map_ddr,
+                                  adsp_map_len);
+    return ret;
+}
+static const struct file_operations adsp_rdp_ddr_fops = {
+    .owner = THIS_MODULE,
+    .open = simple_open,
+    .read = adsp_rdp_ddr_read,
+};
+
+#endif
+
+static struct dentry *adsp_control = NULL;
+
+static ssize_t debugfs_read(struct file *file, char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+    printk(KERN_INFO "%s/%d.\n", __FUNCTION__, __LINE__);
+    return 0;
+}
+
+static ssize_t debugfs_write(struct file *file,
+                             const char __user *user_buf,
+                             size_t count, loff_t *ppos)
+{
+    char msg[10];
+    int ret = 0;
+    size_t tmp_count = 0;
+
+    memset(msg, 0x00, sizeof(msg));
+    tmp_count = count;
+
+    if (tmp_count >= sizeof(msg)) {
+        tmp_count = sizeof(msg) - 1;
+    }
+
+    /* copy the content from user space to kernel space */
+    ret = copy_from_user(msg, user_buf, tmp_count);
+    if (ret) {
+        printk(KERN_ALERT "copy from user fail \n");
+        return -EFAULT;
+    }
+
+    switch (msg[0]) {
+        case '1':    /* input command# echo 1 > /sys/kernel/debug/adsp */
+            printk(KERN_INFO "input %c to dump adsp DDR memory to %s\n", msg[0], ADSP_DUMP_DDR_NAME);
+            dump_memory(1);
+            break;
+
+        case '2':    /* input command# echo 2 > /sys/kernel/debug/adsp */
+            printk(KERN_INFO "input %c to dump adsp SQU memory to %s\n", msg[0], ADSP_DUMP_SQU_NAME);
+            dump_memory(2);
+            break;
+
+        case '3':    /* input command# echo 3 > /sys/kernel/debug/adsp */
+            printk(KERN_INFO "input %c to dump adsp DTCM memory to %s\n", msg[0], ADSP_DUMP_DTCM_NAME);
+            dump_memory(3);
+            break;
+
+        case '4':    /* input command# echo 4 > /sys/kernel/debug/adsp */
+            printk(KERN_INFO "input %c to dump adsp share memory to %s\n", msg[0], ADSP_DUMP_SHM_NAME);
+            dump_memory(4);
+            break;
+
+        case '5':    /* input command# echo 5 > /sys/kernel/debug/adsp */
+            printk(KERN_INFO "input %c to dump all the adsp memory\n", msg[0]);
+            dump_memory(1);
+            dump_memory(2);
+            dump_memory(3);
+            dump_memory(4);
+            break;
+
+        case '9':    /* input command# echo 9 > /sys/kernel/debug/adsp */
+            printk(KERN_INFO "input %c to power on adsp\n", msg[0]);
+            pwr_on_hw();
+            break;
+
+        case '0':    /* input command# echo 0 > /sys/kernel/debug/adsp */
+            printk(KERN_INFO "input %c to power off adsp\n", msg[0]);
+            pwr_off_hw();
+            break;
+
+        case 'h':    /* input command# echo ? > /sys/kernel/debug/adsp */
+            printk(KERN_INFO "\nUsage: echo <option> > /sys/kernel/debug/adsp\n");
+            printk(KERN_INFO "  1    dump adsp DDR memory to %s\n", ADSP_DUMP_DDR_NAME);
+            printk(KERN_INFO "  2    dump adsp SQU memory to %s\n", ADSP_DUMP_SHM_NAME);
+            printk(KERN_INFO "  3    dump adsp DTCM memory to %s\n", ADSP_DUMP_DTCM_NAME);
+            printk(KERN_INFO "  4    dump adsp share memory to %s\n", ADSP_DUMP_SHM_NAME);
+            printk(KERN_INFO "  5    dump all the adsp memory\n");
+            printk(KERN_INFO "  9    power on adsp\n");
+            printk(KERN_INFO "  0    power off adsp\n");
+            printk(KERN_INFO "  h    show help\n");
+            break;
+
+        default:    /* input command#  */
+            printk(KERN_INFO "input invalid.\n");
+            break;
+    }
+
+    return tmp_count;
+}
+
+static const struct file_operations debugfs_ops = {
+    .owner = THIS_MODULE,
+    .open = simple_open,
+    .read = debugfs_read,
+    .write = debugfs_write,
+};
+
+extern bool system_is_rdp_mode(void);
+extern void *shm_map(phys_addr_t start, size_t size);
+static inline int adsp_debugfs_init(void)
+{
+    if (cpu_is_asr190Xe()) {
+        is_1901_E = 1;
+    }
+    printk(KERN_INFO "%s/%d: platform is 1901%c\n", __FUNCTION__, __LINE__, is_1901_E ? 'E' : 'S');
+
+    if (system_is_rdp_mode()) {
+#ifdef CONFIG_DEBUG_FS
+        struct dentry *adsp_dir = NULL;
+        struct dentry *ads_buffer;
+
+        if (is_1901_E) {
+            adsp_map_ddr = shm_map(ADSP_DDR_LOAD_ADDR, ADSP_DDR_LOAD_LENGTH);
+            adsp_map_len = ADSP_DDR_LOAD_LENGTH;
+        }
+        else {
+            adsp_map_ddr = shm_map(ADSP_DDR_LOAD_ADDR_S, ADSP_DDR_LOAD_LENGTH_S);
+            adsp_map_len = ADSP_DDR_LOAD_LENGTH_S;
+        }
+
+        adsp_dir = debugfs_create_dir("adsp", NULL);
+        if (!adsp_dir || IS_ERR(adsp_dir)) {
+            pr_err("adsp debugfs create directory failed\n");
+            return -ENOENT;
+        }
+
+        ads_buffer = debugfs_create_file("adsp_squ", 0664, adsp_dir, NULL, &adsp_rdp_squ_fops);
+        if (!ads_buffer) {
+            pr_err("create adsp_squ debugfs error!\n");
+            return -ENOENT;
+        }
+
+        ads_buffer = debugfs_create_file("adsp_dtcm", 0664, adsp_dir, NULL, &adsp_rdp_dtcm_fops);
+        if (!ads_buffer) {
+            pr_err("create adsp_dtcm debugfs error!\n");
+            return -ENOENT;
+        }
+
+        ads_buffer = debugfs_create_file("adsp_shm", 0664, adsp_dir, NULL, &adsp_rdp_shm_fops);
+        if (!ads_buffer) {
+            pr_err("create adsp_shm debugfs error!\n");
+            return -ENOENT;
+        }
+
+        ads_buffer = debugfs_create_file("adsp_ddr", 0664, adsp_dir, NULL, &adsp_rdp_ddr_fops);
+        if (!ads_buffer) {
+            pr_err("create adsp_ddr debugfs error!\n");
+            return -ENOENT;
+        }
+#endif
+        return 0;
+    }
+
+    adsp_control = debugfs_create_file("adsp", S_IRUGO | S_IFREG, NULL, NULL, &debugfs_ops);
+    if (adsp_control == NULL) {
+        pr_err("create adsp debugfs error!\n");
+        return -ENOENT;
+    }
+    else if (adsp_control == ERR_PTR(-ENODEV)) {
+        pr_err("CONFIG_DEBUG_FS is not enabled!\n");
+        return -ENOENT;
+    }
+
+    return 0;
+}
+
+static void adsp_debugfs_remove(void)
+{
+    if (NULL != adsp_control) {
+        debugfs_remove_recursive(adsp_control);
+    }
+
+    return;
+}
+
+
+/******************************************************************************
+*   functions for cdev
+******************************************************************************/
+#define AUDIO_DSP_MAGIC 'y'
+#define ADSP_ENABLE _IO(AUDIO_DSP_MAGIC, 0x00)
+#define ADSP_DISABLE _IO(AUDIO_DSP_MAGIC, 0x01)
+#define ADSP_SET _IOW(AUDIO_DSP_MAGIC, 0x02, uint16_t[ADSP_SET_COMMAND_LENGTH])
+#define ADSP_SEND_VE _IOW(AUDIO_DSP_MAGIC, 0x03, EnhanceParmsT)
+#define ADSP_DUMP_FULL_DDR _IOR(AUDIO_DSP_MAGIC, 0x4, uint32_t)
+#define ADSP_START_AUDIO_PATH _IOW(AUDIO_DSP_MAGIC, 0x05, uint16_t[VOICE_START_COMMAND_LENGTH + 2])
+#define ADSP_END_AUDIO_PATH _IOW(AUDIO_DSP_MAGIC, 0x06, uint16_t[4])
+
+#define CTRL_BUFF_MAX_LEN 100
+
+static dev_t adsp_dev = 0;
+static struct class *adsp_class;
+static struct cdev adsp_cdev;
+
+
+static long cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+    u16 msg[CTRL_BUFF_MAX_LEN];
+    EnhanceParmsT *pVe;
+    IpcSetIDType SetId = 0;
+    IpcSetParamsType CmdParams;
+    IpcDataParamsType DataParams;
+    UINT8 CmdMsg[128];
+
+    //printk(KERN_INFO "%s/%d, cmd = %d", __FUNCTION__, __LINE__, cmd);
+
+    memset(&CmdParams, 0, sizeof(IpcSetParamsType));
+    memset(&DataParams, 0, sizeof(IpcDataParamsType));
+
+    switch (cmd) {
+        case ADSP_ENABLE:
+            printk(KERN_INFO "%s/%d: enable adsp\n", __FUNCTION__, __LINE__);
+            break;
+
+        case ADSP_DISABLE:
+            printk(KERN_INFO "%s/%d: disable adsp\n", __FUNCTION__, __LINE__);
+            break;
+
+        case ADSP_SET:
+            //printk(KERN_INFO "send cmd to adsp\n");
+            if (!is_adsp_inited) {
+                printk(KERN_INFO "%s/%d: adsp is not ready\n", __FUNCTION__, __LINE__);
+                return -EFAULT;
+            }
+            if (copy_from_user(msg, (void __user *)arg, ADSP_SET_COMMAND_LENGTH * 2)) {
+                return -EFAULT;
+            }
+            printk(KERN_INFO "|%.2x %.2x %.2x|%.4x %.4x|%.4x %.4x|%.4x %.4x|%.4x %.4x|\n",
+                   msg[0], msg[1], msg[2],
+                   msg[3], msg[4], msg[5], msg[6],
+                   msg[7], msg[8], msg[9], msg[10]);
+            SetId = msg[0];
+            CmdParams.SubOpcode = msg[1];
+            CmdParams.CmdMsgLength = msg[2];
+            if (CmdParams.CmdMsgLength < ADSP_SET_COMMAND_LENGTH * 2 - 3) {
+                memcpy(CmdMsg, &msg[3], CmdParams.CmdMsgLength * 2);
+                CmdParams.CmdMsgPtr = (UINT32 *)CmdMsg;
+                printk(KERN_INFO "SetId:0x%x, SubOpcode:0x%x, CmdMsgLength:0x%x, CmdMsg:|%.8x|%.8x|%.8x|%.8x|\n",
+                       SetId, CmdParams.SubOpcode, CmdParams.CmdMsgLength,
+                       CmdParams.CmdMsgPtr[0], CmdParams.CmdMsgPtr[1], CmdParams.CmdMsgPtr[2], CmdParams.CmdMsgPtr[3]);
+                IpcSendAdspMessageData(SetId, &CmdParams, NULL);
+            }
+            break;
+
+        case ADSP_SEND_VE:
+            printk(KERN_INFO "prepare ve for adsp\n");
+            //AP ring_ctl addr is agreed in advance, and ve should be prepared before release adsp
+            if (!rVe) {
+                printk(KERN_INFO "%s/%d: ioremap fail\n", __FUNCTION__, __LINE__);
+                return -EFAULT;
+            }
+            if (copy_from_user(rVe, (void __user *)arg, sizeof(EnhanceParmsT))) {
+                return -EFAULT;
+            }
+            pVe = rVe;
+            printk(KERN_INFO "%x|%x\n",
+                   pVe->VoiceParms.VoiceParmRX[1].NSRxConfig.NsParams.NoiseMatrix,
+                   pVe->VoiceParms.VoiceParmTX[0].NsTxConfig.NsParamsTx.NsParams.NoiseMatrix);
+            break;
+
+        case ADSP_DUMP_FULL_DDR:
+            printk(KERN_INFO "configure whether to dump full ddr\n");
+            if (!is_adsp_inited) {
+                printk(KERN_INFO "%s/%d: adsp is not ready\n", __FUNCTION__, __LINE__);
+                return -EFAULT;
+            }
+            if (copy_from_user(&is_dump_full_ddr, (void __user *)arg, sizeof(int))) {
+                return -EFAULT;
+            }
+            printk(KERN_INFO "is_dump_full_ddr = %x\n", is_dump_full_ddr);
+            break;
+
+        case ADSP_START_AUDIO_PATH:
+            printk(KERN_INFO "ADSP_START_VOICE_PATH\n");
+            if (!is_adsp_inited) {
+                printk(KERN_INFO "%s/%d: adsp is not ready\n", __FUNCTION__, __LINE__);
+                return -EFAULT;
+            }
+            if (copy_from_user(msg, (void __user *)arg, (2 + VOICE_START_COMMAND_LENGTH) * 2)) {
+                return -EFAULT;
+            }
+            //printk(KERN_INFO "0x%x|%x|%x|%x|%x|%x|%x|%x|%x|\n", msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6], msg[7], msg[8]);
+            SetId = 1;
+
+            CmdParams.SubOpcode = 0x05;
+            CmdParams.CmdMsgLength = 4;
+            memset(CmdMsg, 0, sizeof(CmdMsg));
+            CmdMsg[0] = 0x06;
+            CmdParams.CmdMsgPtr = (UINT32 *)CmdMsg;
+            printk(KERN_INFO "SubOpcode:0x%x, CmdMsgLength:0x%x, CmdMsg:|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|\n", \
+                   CmdParams.SubOpcode, CmdParams.CmdMsgLength, \
+                   CmdMsg[0], CmdMsg[1], CmdMsg[2], CmdMsg[3], CmdMsg[4], CmdMsg[5], CmdMsg[6], CmdMsg[7]);
+            IpcSendAdspMessageData(SetId, &CmdParams, NULL);
+
+            CmdParams.SubOpcode = 0x09;
+            CmdParams.CmdMsgLength = 2;
+            memset(CmdMsg, 0, sizeof(CmdMsg));
+            CmdMsg[0] = 0x01;
+            CmdParams.CmdMsgPtr = (UINT32 *)CmdMsg;
+            printk(KERN_INFO "SubOpcode:0x%x, CmdMsgLength:0x%x, CmdMsg:|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|\n", \
+                   CmdParams.SubOpcode, CmdParams.CmdMsgLength, \
+                   CmdMsg[0], CmdMsg[1], CmdMsg[2], CmdMsg[3], CmdMsg[4], CmdMsg[5], CmdMsg[6], CmdMsg[7]);
+            IpcSendAdspMessageData(SetId, &CmdParams, NULL);
+
+            CmdParams.SubOpcode = 0x06;
+            CmdParams.CmdMsgLength = 2;
+            memset(CmdMsg, 0, sizeof(CmdMsg));
+            CmdMsg[0] = 0x01;
+            CmdMsg[1] = 0x01;
+            CmdParams.CmdMsgPtr = (UINT32 *)CmdMsg;
+            printk(KERN_INFO "SubOpcode:0x%x, CmdMsgLength:0x%x, CmdMsg:|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|\n", \
+                   CmdParams.SubOpcode, CmdParams.CmdMsgLength, \
+                   CmdMsg[0], CmdMsg[1], CmdMsg[2], CmdMsg[3], CmdMsg[4], CmdMsg[5], CmdMsg[6], CmdMsg[7]);
+            IpcSendAdspMessageData(SetId, &CmdParams, NULL);
+
+            CmdParams.SubOpcode = 0x00;
+            CmdParams.CmdMsgLength = 0x0C;
+            memset(CmdMsg, 0, sizeof(CmdMsg));
+            CmdMsg[0] = 0x06;
+            CmdMsg[2] = 0x06;
+            CmdParams.CmdMsgPtr = (UINT32 *)CmdMsg;
+            printk(KERN_INFO "SubOpcode:0x%x, CmdMsgLength:0x%x, CmdMsg:|%.2x %.2x %.2x %.2x|%.2x %.2x %.2x %.2x|\n", \
+                   CmdParams.SubOpcode, CmdParams.CmdMsgLength, \
+                   CmdMsg[0], CmdMsg[1], CmdMsg[2], CmdMsg[3], CmdMsg[4], CmdMsg[5], CmdMsg[6], CmdMsg[7]);
+            IpcSendAdspMessageData(SetId, &CmdParams, NULL);
+            break;
+
+        case ADSP_END_AUDIO_PATH:
+            if (!is_adsp_inited) {
+                printk(KERN_INFO "%s/%d: adsp is not ready\n", __FUNCTION__, __LINE__);
+                return -EFAULT;
+            }
+            printk(KERN_INFO "ADSP_END_AUDIO_PATH\n");
+            if (copy_from_user(msg, (void __user *)arg, 4 * 2)) {
+                return -EFAULT;
+            }
+            printk(KERN_INFO "0x%x|%x|%x|%x|\n", msg[0], msg[1], msg[2], msg[3]);
+            CmdParams.SubOpcode = msg[0];
+            CmdParams.CmdMsgLength = msg[1];
+            memcpy(CmdMsg, &msg[2], CmdParams.CmdMsgLength * 2);
+            CmdParams.CmdMsgPtr = (UINT32 *)CmdMsg;
+            printk(KERN_INFO "SubOpcode:0x%x, CmdMsgLength:0x%x, CmdMsg:|%.2x %.2x|\n", CmdParams.SubOpcode, CmdParams.CmdMsgLength, CmdParams.CmdMsgPtr[0], CmdParams.CmdMsgPtr[1]);
+            IpcSendAdspMessageData(SetId, &CmdParams, NULL);
+            break;
+
+        default:
+            pr_info("Default\n");
+            break;
+    }
+    return 0;
+}
+
+static struct file_operations cdev_fops =
+{
+    .owner = THIS_MODULE,
+    .open = simple_open,
+    .unlocked_ioctl = cdev_ioctl,
+};
+
+static int adsp_cdev_init(void)
+{
+    /*Allocating Major number*/
+    if ((alloc_chrdev_region(&adsp_dev, 0, 1, "adsp_Dev")) < 0) {
+        pr_err("Cannot allocate major number\n");
+        return -1;
+    }
+    printk(KERN_INFO "%s/%d, Major = %d, Minor = %d\n", __FUNCTION__, __LINE__, MAJOR(adsp_dev), MINOR(adsp_dev));
+
+    /*Creating cdev structure*/
+    cdev_init(&adsp_cdev, &cdev_fops);
+
+    /*Adding character device to the system*/
+    if ((cdev_add(&adsp_cdev, adsp_dev, 1)) < 0) {
+        pr_err("Cannot add the device to the system\n");
+        unregister_chrdev_region(adsp_dev, 1);
+        return -1;
+    }
+
+    /*Creating struct class*/
+    if ((adsp_class = class_create(THIS_MODULE, "adsp_class")) == NULL) {
+        pr_err("Cannot create the struct class\n");
+        unregister_chrdev_region(adsp_dev, 1);
+        return -2;
+    }
+
+    /*Creating device*/
+    if ((device_create(adsp_class, NULL, adsp_dev, NULL, "audio_dsp")) == NULL) {
+        pr_err("Cannot create the Device 1\n");
+        class_destroy(adsp_class);
+        unregister_chrdev_region(adsp_dev, 1);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void adsp_cdev_exit(void)
+{
+    device_destroy(adsp_class, adsp_dev);
+    class_destroy(adsp_class);
+    cdev_del(&adsp_cdev);
+    unregister_chrdev_region(adsp_dev, 1);
+    printk(KERN_INFO "%s/%d Done.\n", __FUNCTION__, __LINE__);
+}
+
+
+/******************************************************************************
+*   functions for platform_device
+******************************************************************************/
+static int adsp_plat_probe(struct platform_device *pdev)
+{
+    struct resource *res = NULL;
+
+    if (NULL == pdev) {
+        printk(KERN_INFO "%s/%d: pdev is NULL.\n", __FUNCTION__, __LINE__);
+        return -ENOENT;
+    }
+
+    //MEM for dump SQU
+    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+    if (!res) {
+        printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+        return -ENXIO;
+    }
+    rDumpSQU = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+    if (!rDumpSQU) {
+        printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+        return -EIO;
+    }
+
+    //MEM for dump DTCM
+    res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+    if (!res) {
+        printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+        return -ENXIO;
+    }
+    rDumpDTCM = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+    if (!rDumpDTCM) {
+        printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+        return -EIO;
+    }
+
+    //MEM for share memory
+    res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+    if (!res) {
+        printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+        return -ENXIO;
+    }
+    rDumpSHM = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+    if (!rDumpSHM) {
+        printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+        return -EIO;
+    }
+    rRingCtrl = rDumpSHM + 0x1000;
+    rVe = rDumpSHM + 0x1880;
+
+    if (!system_is_rdp_mode()) {
+        //IRQ for IPC
+        adsp_irq = platform_get_irq(pdev, 0);
+        if (!adsp_irq) {
+            printk(KERN_INFO "%s/%d: platform_get_irq fail\n", __FUNCTION__, __LINE__);
+            return -ENXIO;
+        }
+        printk(KERN_INFO "%s/%d irq=0x%x.\n", __FUNCTION__, __LINE__, adsp_irq);
+
+        //MEM for ITCM
+        res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+        if (!res) {
+            printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+            return -ENXIO;
+        }
+        rItcm = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+        if (!rItcm) {
+            printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+            return -EIO;
+        }
+
+        //Register for IPC
+        res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+        if (!res) {
+            printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+            return -ENXIO;
+        }
+        rIpcBASE = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+        if (!rIpcBASE) {
+            printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+            return -EIO;
+        }
+        rIpcDWR = rIpcBASE;
+        rIpcWDR = rIpcBASE + 0x4;
+        rIpcISRW = rIpcBASE + 0x8;
+        rIpcICR = rIpcBASE + 0xc;
+        rIpcIIR = rIpcBASE + 0x10;
+        rIpcRDR = rIpcBASE + 0x14;
+
+        //Register for SSPA
+        res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
+        if (!res) {
+            printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+            return -ENXIO;
+        }
+        rSspaBase = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+        if (!rSspaBase) {
+            printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+            return -EIO;
+        }
+        rSspaClk = rSspaBase;
+        rSspaFrm = rSspaBase + 0x4;
+        rSspaTxd = rSspaBase + 0x8;
+        rSspaRxd = rSspaBase + 0xc;
+
+        //Register for BX2
+        res = platform_get_resource(pdev, IORESOURCE_MEM, 6);
+        if (!res) {
+            printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+            return -ENXIO;
+        }
+        rPc = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+        if (!rPc) {
+            printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+            return -EIO;
+        }
+
+        res = platform_get_resource(pdev, IORESOURCE_MEM, 7);
+        if (!res) {
+            printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+            return -ENXIO;
+        }
+        rRls = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+        if (!rRls) {
+            printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+            return -EIO;
+        }
+
+        res = platform_get_resource(pdev, IORESOURCE_MEM, 8);
+        if (!res) {
+            printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+            return -ENXIO;
+        }
+        rClkRst = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+        if (!rClkRst) {
+            printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+            return -EIO;
+        }
+
+        res = platform_get_resource(pdev, IORESOURCE_MEM, 9);
+        if (!res) {
+            printk(KERN_INFO "%s/%d: platform_get_resource fail\n", __FUNCTION__, __LINE__);
+            return -ENXIO;
+        }
+        rPwr = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+        if (!rPwr) {
+            printk(KERN_INFO "%s/%d: devm_ioremap_resource fail\n", __FUNCTION__, __LINE__);
+            return -EIO;
+        }
+
+        if (!rClk) {
+            rClk = ioremap_nocache(REG_PMU_AUDIO_CLK_RES_CTRL, 4);
+            if (!rClk) {
+                printk(KERN_INFO "%s/%d: ioremap fail\n", __FUNCTION__, __LINE__);
+                return -EIO;
+            }
+        }
+    }
+
+    printk(KERN_INFO "squ :[%x-%x]-->[%x-%x]\ndtcm:[%x-%x]-->[%x-%x]\nitcm:[%x-%x]-->[%x-%x]\nshm :[%x-%x]-->[%x-%x]\n",
+           ADSP_DUMP_SQU_ADDR, ADSP_DUMP_SQU_ADDR + ADSP_DUMP_SQU_LENGTH, (unsigned int)rDumpSQU, (unsigned int)rDumpSQU + ADSP_DUMP_SQU_LENGTH,
+           ADSP_DUMP_DTCM_ADDR, ADSP_DUMP_DTCM_ADDR + ADSP_DUMP_DTCM_LENGTH, (unsigned int)rDumpDTCM, (unsigned int)rDumpDTCM + ADSP_DUMP_DTCM_LENGTH,
+           ITCM_ADDR, ITCM_ADDR + ITCM_LENGTH, (unsigned int)rItcm, (unsigned int)rItcm + ITCM_LENGTH,
+           ADSP_DUMP_SHM_ADDR, ADSP_DUMP_SHM_ADDR + ADSP_DUMP_SHM_LENGTH, (unsigned int)rDumpSHM, (unsigned int)rDumpSHM + ADSP_DUMP_SHM_LENGTH);
+
+    printk(KERN_INFO "%s/%d Done.\n", __FUNCTION__, __LINE__);
+    return 0;
+}
+
+static int adsp_plat_remove(struct platform_device *pdev)
+{
+    iounmap(rClk);
+
+    printk(KERN_INFO "%s/%d.\n", __FUNCTION__, __LINE__);
+    return 0;
+}
+
+static const struct of_device_id adsp_dt_ids[] = {
+    { .compatible = "asr,adsp", },
+    {},
+};
+MODULE_DEVICE_TABLE(of, adsp_dt_ids);
+
+static struct platform_driver adsp_driver = {
+    .driver = {
+        .name = "adsp",
+        .owner = THIS_MODULE,
+        .of_match_table = of_match_ptr(adsp_dt_ids),
+    },
+    .probe = adsp_plat_probe,
+    .remove = adsp_plat_remove,
+};
+
+
+/******************************************************************************
+*   functions for module
+******************************************************************************/
+static int adspInit(void)
+{
+    printk(KERN_INFO "%s/%d.\n", __FUNCTION__, __LINE__);
+
+    if (cpu_is_asr1901_a0_plus() || cpu_is_asr1906()) {
+        platform_driver_register(&adsp_driver);
+        if (!system_is_rdp_mode()) {
+            adsp_cdev_init();
+        }
+        adsp_debugfs_init();
+        if (!system_is_rdp_mode()) {
+            adsp_ipc_init_phase1();
+            enable_pmu_audio_clk();
+        }
+        printk(KERN_INFO "%s/%d Done.\n", __FUNCTION__, __LINE__);
+    }
+
+    return 0;
+}
+
+static void adspUninit(void)
+{
+    printk(KERN_INFO "%s/%d.\n", __FUNCTION__, __LINE__);
+
+    if (cpu_is_asr1901_a0_plus() || cpu_is_asr1906()) {
+        if (g_audio_ipc_handle.rx_ring_buffer) {
+            iounmap(g_audio_ipc_handle.rx_ring_buffer);
+        }
+
+        if (g_audio_ipc_handle.tx_ring_buffer) {
+            iounmap(g_audio_ipc_handle.tx_ring_buffer);
+        }
+
+        if (adsp_irq) {
+            free_irq(adsp_irq, NULL);
+        }
+
+        adsp_cdev_exit();
+        adsp_debugfs_remove();
+    }
+}
+
+module_init(adspInit);
+module_exit(adspUninit);
+
+MODULE_DESCRIPTION("Driver for ADSP");
+MODULE_AUTHOR("yjgwang@asrmicro.com");
+MODULE_LICENSE("GPL v2");