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