add dsp dir
author杜坤明 <dkm@rock-chips.com>
Wed, 19 May 2010 02:38:46 +0000 (02:38 +0000)
committer黄涛 <huangtao@rock-chips.com>
Mon, 21 Jun 2010 05:35:13 +0000 (13:35 +0800)
drivers/staging/rk2818/rk2818_dsp/Kconfig [new file with mode: 0644]
drivers/staging/rk2818/rk2818_dsp/Makefile [new file with mode: 0644]
drivers/staging/rk2818/rk2818_dsp/queue.c [new file with mode: 0644]
drivers/staging/rk2818/rk2818_dsp/queue.h [new file with mode: 0644]
drivers/staging/rk2818/rk2818_dsp/rk2818_dsp.c [new file with mode: 0644]
drivers/staging/rk2818/rk2818_dsp/rk2818_dsp.h [new file with mode: 0644]

diff --git a/drivers/staging/rk2818/rk2818_dsp/Kconfig b/drivers/staging/rk2818/rk2818_dsp/Kconfig
new file mode 100644 (file)
index 0000000..fe5d684
--- /dev/null
@@ -0,0 +1,7 @@
+menu "DSP"
+config RK2818_DSP
+       tristate "ROCKCHIP RK2818 DSP"
+       default y
+       help
+          rk28 dsp module.
+endmenu
diff --git a/drivers/staging/rk2818/rk2818_dsp/Makefile b/drivers/staging/rk2818/rk2818_dsp/Makefile
new file mode 100644 (file)
index 0000000..efd55bf
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for the dsp core.
+#
+
+obj-$(CONFIG_RK2818_DSP)       += rk2818dsp.o
+rk2818dsp-objs := rk2818_dsp.o queue.o
\ No newline at end of file
diff --git a/drivers/staging/rk2818/rk2818_dsp/queue.c b/drivers/staging/rk2818/rk2818_dsp/queue.c
new file mode 100644 (file)
index 0000000..533b409
--- /dev/null
@@ -0,0 +1,180 @@
+/******************************************************************************
+ * queue.c
+ *
+ * Copyright (c) 2009 Fuzhou Rockchip Co.,Ltd.
+ *
+ * DESCRIPTION: -
+ *     Functions used to manage a FIFO queue .
+ *
+ * modification history
+ * --------------------
+ * Keith Lin, Feb 27, 2009,  Initial version
+ * --------------------
+ ******************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "queue.h"
+
+DEFINE_SPINLOCK(lock);
+unsigned long flag;
+
+/**
+ * queue initialize,
+ * return Queue pointer on success and NULL on error.
+ */
+Queue *queue_init(int32_t max_nb_item, void (*destruct)(void *, void *), void *param)
+{
+       Queue *q = NULL;
+       spin_lock_irqsave(&lock, flag);
+
+       q = kmalloc(sizeof(*q), GFP_DMA);
+       if(NULL == q) {
+           spin_unlock_irqrestore(&lock, flag);
+               return NULL;
+    }
+
+       q->items = kmalloc(max_nb_item * sizeof(*q->items), GFP_DMA);
+
+       if(NULL == q->items)
+       {
+               kfree(q);
+               spin_unlock_irqrestore(&lock, flag);
+               return NULL;
+       }
+
+       q->first = q->last = 0;
+       q->nb_item = 0;
+       q->max_nb_item = max_nb_item;
+       q->size = 0;
+    q->destruct = (void (*)(void *, void *))destruct;
+    q->param = param;
+    spin_unlock_irqrestore(&lock, flag);
+       return q;
+}
+
+/**
+ * put an element to the queue,
+ * return 0 on success and -1 on error.
+ */
+int32_t queue_put(Queue *q, void *elem, int32_t size)
+{
+    spin_lock_irqsave(&lock, flag);
+       if(q->nb_item >= q->max_nb_item) {
+        spin_unlock_irqrestore(&lock, flag);
+               return -1;
+    }
+
+       q->items[q->last].elem = elem;
+       q->items[q->last].size = size;
+       q->last = (q->last + 1) % q->max_nb_item;
+       q->size += size;
+       q->nb_item++;
+
+    spin_unlock_irqrestore(&lock, flag);
+       return 0;
+}
+
+/**
+ * get an element from the queue.
+ * return element pointer on success and NULL on error.
+ */
+void *queue_get(Queue *q)
+{
+       Item *item;
+
+    spin_lock_irqsave(&lock, flag);
+       if(q->nb_item <= 0) {
+           spin_unlock_irqrestore(&lock, flag);
+               return NULL;
+    }
+
+       item = &(q->items[q->first]);
+       q->first = (q->first + 1) % q->max_nb_item;
+       q->size -= item->size;
+       q->nb_item--;
+
+    spin_unlock_irqrestore(&lock, flag);
+       return item->elem;
+}
+
+/**
+ * Flush the queue.
+ */
+void queue_flush(Queue *q)
+{
+    spin_lock_irqsave(&lock, flag);
+    /* destruct all elements in the queue */
+    if (NULL != q->destruct)
+    {
+        for(; q->nb_item > 0; q->nb_item --)
+        {
+            q->destruct(q->param, q->items[q->first].elem);
+            q->first = (q->first + 1) % q->max_nb_item;
+        }
+    }
+
+       q->first = q->last = 0;
+       q->nb_item = 0;
+       q->size = 0;
+       spin_unlock_irqrestore(&lock, flag);
+}
+
+/**
+ * Destroy the queue.
+ */
+void queue_destroy(Queue *q)
+{
+    spin_lock_irqsave(&lock, flag);
+    /* destruct all elements first */
+    if (NULL != q->destruct)
+    {
+        for(; q->nb_item > 0; q->nb_item--)
+        {
+            q->destruct(q->param, q->items[q->first].elem);
+            q->first = (q->first + 1) % q->max_nb_item;
+        }
+    }
+
+       if(NULL != q)
+       {
+               if(NULL != q->items)
+        {
+                       kfree(q->items);
+            q->items = NULL;
+        }
+               kfree(q);
+               q = NULL;
+       }
+       spin_unlock_irqrestore(&lock, flag);
+}
+
+int32_t queue_is_full(Queue *q)
+{
+    int32_t ret = 0;
+    spin_lock_irqsave(&lock, flag);
+    ret = (q->nb_item >= q->max_nb_item) ? 1 : 0;
+    spin_unlock_irqrestore(&lock, flag);
+       return ret;
+}
+
+int32_t queue_is_empty(Queue *q)
+{
+    int32_t ret = 0;
+    spin_lock_irqsave(&lock, flag);
+    ret = (q->nb_item == 0);
+    spin_unlock_irqrestore(&lock, flag);
+       return ret;
+}
+
+int32_t queue_size(Queue *q)
+{
+    int32_t ret = 0;
+    spin_lock_irqsave(&lock, flag);
+    ret = q->size;
+    spin_unlock_irqrestore(&lock, flag);
+    return ret;
+}
+
diff --git a/drivers/staging/rk2818/rk2818_dsp/queue.h b/drivers/staging/rk2818/rk2818_dsp/queue.h
new file mode 100644 (file)
index 0000000..33d691c
--- /dev/null
@@ -0,0 +1,62 @@
+/******************************************************************************
+ * queue.h
+ *
+ * Copyright (c) 2009 Fuzhou Rockchip Co.,Ltd.
+ *
+ * DESCRIPTION: -
+ *     Functions used to manage a FIFO queue.
+ *
+ * modification history
+ * --------------------
+ * Keith Lin, Feb 27, 2009,  Initial version
+ * --------------------
+ ******************************************************************************/
+
+#ifndef QUEUE_H
+#define QUEUE_H
+
+
+typedef struct Item
+{
+       void *elem;
+
+       /* data size of the element */
+       int32_t size;
+}Item;
+
+typedef struct Queue
+{
+       Item *items;
+
+       /**
+        * first - the first item of the queue,
+        * last - the last item of the queue.
+        */
+       int32_t first, last;
+
+       /* the number of items in the queue */
+       int32_t nb_item;
+
+       /* max item number */
+       int32_t max_nb_item;
+
+       /* total data size in the queue */
+       int32_t size;
+
+    /* parameter for destruct function */
+    void *param;
+
+    /* call this call back to destruct elements before flush */
+    void  (*destruct)(void *, void *);
+} Queue;
+
+Queue *queue_init(int32_t max_nb_item, void (*destruct)(void *, void *), void *param);
+int32_t queue_put(Queue *q, void *elem, int32_t size);
+void *queue_get(Queue *q);
+void queue_flush(Queue *q);
+void queue_destroy(Queue *q);
+int32_t queue_is_full(Queue *q);
+int32_t queue_is_empty(Queue *q);
+int32_t queue_size(Queue *q);
+
+#endif /* QUEUE_H */
diff --git a/drivers/staging/rk2818/rk2818_dsp/rk2818_dsp.c b/drivers/staging/rk2818/rk2818_dsp/rk2818_dsp.c
new file mode 100644 (file)
index 0000000..1fb8bf4
--- /dev/null
@@ -0,0 +1,949 @@
+/* drivers/staging/rk2818/rk2818_dsp/rk2818_dsp.c
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <asm/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <mach/scu.h>
+#include <mach/rk2818_iomap.h>
+#include <mach/irqs.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <linux/firmware.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/syscalls.h>
+#include <linux/timer.h>
+#include "rk2818_dsp.h"
+#include "queue.h"
+
+
+#if 0
+       #define dspprintk(msg...)       printk(msg);
+#else
+       #define dspprintk(msg...)
+#endif
+
+struct rk28dsp_inf {
+    struct miscdevice miscdev;
+    struct device dev;
+
+       void *pmu_base;
+       void *l1_dbase;
+       void *l2_idbase;
+
+       int irq0;
+       int irq1;
+
+       void *bootaddress;
+    void *codeprogramaddress;
+       void *codetableaddress;
+       void *codedataaddress;
+
+       struct rk28dsp_msg rcvmsg;
+       Queue *rcvmsg_q;
+
+       int cur_req;
+       pid_t cur_pid;
+       int cur_freq;
+       int req_waited;
+
+       char req1fwname[20];
+
+       struct timer_list dsp_timer;
+       int dsp_status;
+
+       struct clk *clk;
+};
+
+
+#define SET_BOOT_VECTOR(v)  __raw_writel(v,RK2818_REGFILE_BASE + 0x18);
+#define DSP_BOOT_CTRL() __raw_writel(__raw_readl(RK2818_REGFILE_BASE + 0x14) | (1<<4),RK2818_REGFILE_BASE + 0x14);
+#define DSP_BOOT_CLR()  __raw_writel(__raw_readl(RK2818_REGFILE_BASE + 0x14) & (~(1<<4)),RK2818_REGFILE_BASE + 0x14);
+
+
+#define CODEC_SECTION_NO 0x5
+#define DSP_MAJOR              232
+
+
+/* CEVA memory map base address for ARM */
+#define DSP_L2_IMEM_BASE   (RK2818_DSP_PHYS + 0x200000)
+#define DSP_L2_DMEM_BASE   (RK2818_DSP_PHYS + 0x400000)
+#define PIU_BASE_ADDR      (RK2818_DSP_PHYS + 0x132000)
+#define PMU_BASE_ADDR      (RK2818_DSP_PHYS + 0x130000)
+
+
+
+#define PIU_PUT_IMASK(port,v) __raw_writel(v,inf->pmu_base+PIU_IMASK_OFFSET);
+
+#define PIU_GET_STATUS_REPX(channel) \
+        (__raw_readl(inf->pmu_base + PIU_STATUS_OFFSET) & (1 << ((channel) + PIU_STATUS_R0WRS)))
+
+#define PIU_READ_REPX_VAL(channel) \
+        __raw_readl(inf->pmu_base + PIU_REPLY0_OFFSET + ((channel) << 2))
+
+#define PIU_CLR_STATUS_REPX(channel) \
+        __raw_writel(__raw_readl(inf->pmu_base + PIU_STATUS_OFFSET) | (1 << ((channel) + PIU_STATUS_R0WRS)), \
+        inf->pmu_base+PIU_STATUS_OFFSET)
+
+#define PIU_SEND_CMD(channel, cmd) \
+        __raw_writel(cmd,inf->pmu_base+PIU_CMD0_OFFSET + (channel << 2))
+
+
+typedef enum _DSP_STATUS {
+    DS_NORMAL = 0,
+    DS_TOSLOW,
+    DS_SLOW,
+    DS_SLEEP,
+} DSP_STATUS;
+
+typedef enum _DSP_PWR_CTL {
+    DPC_NORMAL = 0,
+    DPC_SLOW,
+    DPC_SLEEP,
+} DSP_PWR_CTL;
+
+
+static struct rk28dsp_inf *g_inf = NULL;
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+static int wq_condition = 1;
+
+static DECLARE_WAIT_QUEUE_HEAD(wq2);
+static int wq2_condition = 0;
+
+static DECLARE_MUTEX(sem);
+
+static int rcv_quit = 0;
+
+static int CheckDSPLIBHead(char *buff)
+{
+    if ((buff[0] != 'r')
+               || (buff[1] != 'k')
+               || (buff[2] != 'd')
+               || (buff[3] != 's')
+               || (buff[4] != 'p')
+               || (buff[5] != ' ')
+               || (buff[6] != 'X')
+               || (buff[7] != 'X'))
+       {
+        return -1;
+       }
+    else
+    {
+        return 0;
+    }
+}
+
+void dsp_set_clk(int clkrate)
+{
+#if 1
+       struct rk28dsp_inf *inf = g_inf;
+    if(!inf)      return;
+    if(clkrate > 24 && clkrate < 600) {
+               if(inf->clk)    clk_set_rate(inf->clk, clkrate*1000000);
+    } else {
+        if(inf->clk)   clk_set_rate(inf->clk, 300*1000000);
+    }
+#else
+       unsigned int freqreg = 0;
+    switch(clkrate) {
+    case 300:   freqreg = 0x01830310;   break;
+    case 400:   freqreg = 0x01820310;   break;
+    case 560:   freqreg = 0x01982300;   break;
+    case 600:   freqreg = 0x01982580;   break;
+    case 500:
+    default:    freqreg = 0x01810290;   break;
+    }
+    __raw_writel(freqreg, RK2818_SCU_BASE+0x04); //0x01830310 300mhz  0x01820310 400mhz  0x01810290 500mhz  0x01982300 560mhz  0x01982580 600mhz
+    mdelay(15);
+#endif
+}
+
+
+void dsp_powerctl(int ctl, int arg)
+{
+    struct rk28dsp_inf *inf = g_inf;
+    if(!inf)      return;
+
+    switch(ctl)
+    {
+    case DPC_SLOW:
+        {
+            /* dsp work mode :slow mode*/
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x0c) & (~0x03)) , RK2818_SCU_BASE+0x0c);
+        }
+        break;
+    case DPC_NORMAL:
+        {
+            /* dsp clock enable 0x12*/
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x1c) & (~0x02)) , RK2818_SCU_BASE+0x1c);
+            /* dsp ahb bus clock enable*/
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x24) & (~0x04)) , RK2818_SCU_BASE+0x24);
+            /* sram arm clock enable */
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x1c) & (~0x08)) , RK2818_SCU_BASE+0x1c);
+            /* sram dsp clock enable */
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x1c) & (~0x10)) , RK2818_SCU_BASE+0x1c);
+            /* dsp core peripheral rest then not rest */
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x28) | 0x02000030) , RK2818_SCU_BASE+0x28);
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x28) & (~0x02000020)) , RK2818_SCU_BASE+0x28);
+            mdelay(15);
+            /* dsp work mode :slow mode*/
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x0c) & (~0x03)) , RK2818_SCU_BASE+0x0c);
+            mdelay(15);
+
+                       /* dsp set clk */
+                       dsp_set_clk(arg);
+
+            /* dsp subsys power on 0x21*/
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x10) & (~0x21)) , RK2818_SCU_BASE+0x10);
+            mdelay(15);
+            /* change dsp & arm to normal mode */
+            __raw_writel(0x5, RK2818_SCU_BASE+0x0c);
+        }
+        break;
+    case DPC_SLEEP:
+        {
+            /* dsp work mode :slow mode*/
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x0c) & (~0x03)) , RK2818_SCU_BASE+0x0c);
+            /* dsp core/peripheral rest*/
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x28) | 0x02000030) , RK2818_SCU_BASE+0x28);
+            /* dsp clock disable */
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x1c) | (0x02)) , RK2818_SCU_BASE+0x1c);
+            /* dsp ahb bus clock disable */
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x24) | (0x04)) , RK2818_SCU_BASE+0x24);
+            /* sram arm clock disable */
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x1c) | (0x08)) , RK2818_SCU_BASE+0x1c);
+            /* sram dsp clock disable */
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x1c) | (0x10)) , RK2818_SCU_BASE+0x1c);
+            udelay(10);
+            /* dsp pll disable */
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x04) | (0x01u<<22)) , RK2818_SCU_BASE+0x04);
+            udelay(10);
+            /* dsp subsys power off 0x21*/
+            __raw_writel((__raw_readl(RK2818_SCU_BASE+0x10) | (0x21)) , RK2818_SCU_BASE+0x10);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+
+static int _down_firmware(char *fwname, struct rk28dsp_inf *inf)
+{
+       static char lst_fwname[20] = {0};
+       int ret = 0;
+
+       if(NULL==fwname)                return -EINVAL;
+       if(0==strcmp(fwname, ""))       return -EINVAL;
+       if((0==strcmp(lst_fwname, fwname)) && (DS_SLEEP!=inf->dsp_status)) {
+           if(1==inf->cur_req) {
+               dspprintk("%s already down, not redown! \n", fwname);
+
+               /* change dsp & arm to normal mode */
+               if(DS_SLOW==inf->dsp_status)    printk("dsp work mode : slow -> normal mode \n");
+               inf->dsp_status = DS_NORMAL;
+               __raw_writel(0x5, RK2818_SCU_BASE+0x0c);
+            return 0;
+           }
+    }
+
+    if(DS_SLEEP==inf->dsp_status)    printk("dsp work mode : sleep -> normal mode \n");
+    inf->dsp_status = DS_NORMAL;
+
+    dspprintk("down firmware (%s) ... \n", fwname);
+       {
+               const struct firmware *fw;
+               char *buf,*code_buf;
+               int *pfile,*pboot;
+               int indexoffset,dataOffset;
+               int *pcodeprograml1,*pcodedatal1,*pcodetable;
+               int address,length,indexNo,loadNo,i,j;
+               int *fpIndexFile,*fpDataFile;
+
+        __raw_writel((__raw_readl(RK2818_REGFILE_BASE + 0x10) | (0x6d8)), RK2818_REGFILE_BASE + 0x10);  // 0x6d8
+        dsp_powerctl(DPC_NORMAL, inf->cur_freq);
+        dspprintk("\nrequest_firmware ... \n");
+
+               /* down dsp boot */
+               ret = request_firmware(&fw, "DspBoot.rkl", &inf->dev);
+           if (ret) {
+               printk(KERN_ERR "Failed to load boot image \"DspBoot.rkl\" err %d\n",ret);
+               return -ENOMEM;
+           }
+               buf = (char*)fw->data;
+               if(CheckDSPLIBHead(buf) != 0){
+               printk("dsp boot head failed ! \n");
+            return -ENOMEM;
+        }
+               pboot = (int*)inf->bootaddress;
+           indexoffset = *(buf+8+32);
+           dataOffset = *(buf+8+32+4);
+           pfile = (int *)(buf+dataOffset);
+               memcpy((char *)(pboot+16),(char *)(pfile),2000); /*copy boot to *pboot point*/
+           SET_BOOT_VECTOR(__pa(pboot+16));  /*set dsp boot program address*/
+           dspprintk("%s [%d]--%x\n",__FUNCTION__,__LINE__,__raw_readl(RK2818_REGFILE_BASE + 0x18));
+           release_firmware(fw);
+
+               /* down dsp codec */
+               pcodeprograml1 = (int*)inf->codeprogramaddress;
+               pcodedatal1 = (int*)inf->codedataaddress;
+               pcodetable = (int*)inf->codetableaddress;
+               *(pboot+13) = __pa(pcodetable); /*set decode table address */
+               *(pboot+14) = __pa(pcodeprograml1); /*set decode program address */
+               *(pboot+15) = __pa(pcodedatal1); /*set decode data address */
+               ret = request_firmware(&fw, fwname, &inf->dev);
+               if (ret) {
+                       printk(KERN_ERR "Failed to load image \"%s\" err %d\n",fwname, ret);
+                       return ret;
+               }
+               code_buf = (char*)fw->data;
+               if(CheckDSPLIBHead(code_buf) != 0){
+                       printk("dsp code head failed ! \n");
+               return -ENOMEM;
+               }
+
+               loadNo = CODEC_SECTION_NO;
+               i=8+16;
+               while ((loadNo--) != 0x0)
+       {
+               indexoffset = *((int *)(code_buf + i));
+               dataOffset = *((int *)(code_buf + i + 4));
+               //dspprintk("%s [%d]-- indexoffset=0x%x  dataOffset=0x%x  loadNo=%d \n",__FUNCTION__,__LINE__,indexoffset,dataOffset,loadNo);
+               i = i + 8;
+               if ((indexoffset != 0x0) && (dataOffset != 0x0))
+               {
+                       fpIndexFile = (int *)(code_buf + indexoffset);
+                       fpDataFile = (int *)(code_buf + dataOffset);
+                       indexNo = *(fpIndexFile + 1);
+                       j = 0;
+                while ((indexNo--) != 0x0)
+                {
+                    if(indexNo<0)   break;
+                    address = *(fpIndexFile + 2 + j*2);
+                    length = *(fpIndexFile + 2 + 1 + j*2);
+                    j = j + 1;
+                    //dspprintk("%s [%d]-- address=0x%x  length =0x%x  indexNo=0x%x\n",__FUNCTION__,__LINE__,address,length,indexNo);
+                    if(loadNo == (CODEC_SECTION_NO - 0x1)){
+                        /* Èç¹ûΪL1 data MEMµÄ´úÂë¶Î£¬¿½±´µ½¹Ì¼þµÄλÖà*/
+                        memcpy((char *)(pcodeprograml1),(char *)(fpDataFile),length);
+                    } else {
+                        if (loadNo == (CODEC_SECTION_NO - 0x2)) {
+                             /* Èç¹ûΪL1 data MEMµÄÊý¾Ý¶Î£¬¿½±´µ½¹Ì¼þµÄλÖà*/
+                            memcpy((char *)(pcodedatal1),(char *)(fpDataFile),length);
+                        } else {
+                            /* Èç¹ûΪCEVAµÄÄÚ´æÇøÓò£¬ÐèÒª½øÐеØÖ·×ª»» */
+                            if (address < RK2818_SDRAM_PHYS) {
+#if 1
+                                int     k;
+                                int    *buffL2;
+                                address = (unsigned int)inf->l2_idbase + (address - 0x200000);
+                                buffL2 = (int *)address;
+                                for (k=0; k<(length >> 2); k++)
+                                {
+                                    buffL2[k] = fpDataFile[k];
+                                }
+                                fpDataFile = (int *)((int)fpDataFile + length);
+#else
+                                address = (unsigned int)inf->l2_idbase + (address - 0x200000);
+                                memcpy((char *)(address), (char *)fpDataFile, length);
+#endif
+                            } else {
+                                /* Èç¹ûΪsdramÖУ¬ÔòÖ»ÄÜÂë±í£¬ÇÒµØÖ·Î޹أ¬
+                                       ²¢ÇÒÖ»ÄÜÓÐÒ»¶Î(¼´µØÖ·Á¬Ðø), ·ñÔòÒýÆðϵͳ±ÀÀ£
+                                       ÔÚÍ˳öÊÓÆµ»òÕß¼ÓÔØ²»³É¹¦ºó£¬¼ÇµÃ°Ñ´ËBuffÊͷŵô */
+                                memcpy((char *)pcodetable, (char *)fpDataFile, length);
+                            }
+                        }
+                    }
+
+                }
+               }
+       }
+               release_firmware(fw);
+       }
+
+       DSP_BOOT_CTRL();
+    mdelay(10);
+    __raw_writel((__raw_readl(RK2818_SCU_BASE+0x28) & (~0x00000010)) , RK2818_SCU_BASE+0x28); /* dsp core peripheral not rest*/
+
+       strcpy(lst_fwname, fwname);
+
+       return 0;
+}
+
+
+void dsptimer_callback(unsigned long arg)
+{
+    struct rk28dsp_inf *inf = g_inf;
+    static int sec_cnt = 0;
+    if(!inf)      return;
+
+    mod_timer(&inf->dsp_timer, jiffies + HZ);
+
+    switch(inf->dsp_status)
+    {
+    case DS_TOSLOW:
+        dsp_powerctl(DPC_SLOW, 0);
+        inf->dsp_status = DS_SLOW;
+        printk("dsp work mode : slow mode \n");
+        sec_cnt = 0;
+        break;
+    case DS_SLOW:
+        if(++sec_cnt>=5) {
+            dsp_powerctl(DPC_SLEEP, 0);
+            inf->dsp_status = DS_SLEEP;
+            printk("dsp work mode : sleep mode \n");
+        }
+        break;
+    case DS_SLEEP:
+        break;
+    case DS_NORMAL:
+    default:
+        inf->dsp_status = DS_NORMAL;
+        sec_cnt = 0;
+        break;
+    }
+
+
+}
+
+
+static int dsp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct rk28dsp_inf *inf;
+    unsigned long vma_size =  vma->vm_end - vma->vm_start;
+       unsigned long pageFrameNo = 0;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+    if(!g_inf)   return -EAGAIN;
+    inf = g_inf;
+
+       switch(vma_size)
+       {
+       case 0x10000:   //l1_dbase
+           offset += RK2818_DSP_PHYS;
+               pageFrameNo = (offset >> PAGE_SHIFT);
+               //dspprintk("dsp_mmap l1_dbase \n");
+               break;
+       case 0x400000:  //l2_idbase
+           offset += DSP_L2_IMEM_BASE;
+               pageFrameNo = (offset >> PAGE_SHIFT);
+               //dspprintk("dsp_mmap l2_idbase \n");
+               break;
+    case 0x600000:  //dsp_base
+        offset += RK2818_DSP_PHYS;
+        pageFrameNo = (offset >> PAGE_SHIFT);
+               //dspprintk("dsp_mmap dsp_base \n");
+               break;
+       default:        //pmu_base (0x3000)
+           offset += PMU_BASE_ADDR;
+           pageFrameNo = (offset >> PAGE_SHIFT);
+               //dspprintk("dsp_mmap pmu_base \n");
+               break;
+       }
+       vma->vm_pgoff = pageFrameNo;
+       vma->vm_flags |= VM_IO|VM_RESERVED|VM_LOCKED;
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+               printk("remap_pfn_range fail(vma_size=0x%08x)\n", (unsigned int)vma_size);
+               return -EAGAIN;
+       }
+    return 0;
+}
+
+
+static long dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int ret = 0;
+       struct rk28dsp_req req;
+       struct rk28dsp_inf *inf;
+
+       if(!g_inf)   return -EAGAIN;
+    inf = g_inf;
+
+       if(DSP_IOCTL_RES_REQUEST!=cmd && DSP_IOCTL_GET_TABLE_PHY!=cmd) {
+               if(inf->cur_pid!=current->tgid) {
+                   dspprintk("res is obtain by pid %d, refuse this req(pid=%d cmd=0x%08x) \n",
+                       inf->cur_pid, current->tgid, cmd);
+                   return -EBUSY;
+               }
+       }
+
+       switch(cmd)
+       {
+       case DSP_IOCTL_RES_REQUEST:
+               if(copy_from_user(&req, (void *)arg, sizeof(struct rk28dsp_req)))
+                       return -EFAULT;
+               dspprintk("DSP_IOCTL_RES_REQUEST reqno=%d(%d->%d)  cur_req=%d(%d) \n",
+                       req.reqno, current->tgid, current->pid, inf->cur_req, inf->cur_pid);
+
+               if(0==req.reqno)        return -EINVAL;
+               if(0==strcmp(req.fwname, ""))   return -EINVAL;
+
+               down(&sem);
+               if(0==inf->cur_req && !inf->req_waited)
+               {
+                       inf->cur_req = req.reqno;
+                       inf->cur_pid = current->tgid;
+                       inf->cur_freq = req.freq;
+                       if(1==req.reqno)        strcpy(inf->req1fwname, req.fwname);
+               }
+               else if(1==inf->cur_req && !inf->req_waited && inf->cur_req!=req.reqno)
+               {
+                       inf->req_waited = 1;
+                       wq_condition = 0;
+                       up(&sem);
+                       dspprintk("wait_event \n");
+                       wait_event(wq, wq_condition);
+                       down(&sem);
+                       inf->req_waited = 0;
+                       inf->cur_req = req.reqno;
+                       inf->cur_pid = current->tgid;
+                       inf->cur_freq = req.freq;
+               } else {
+                   ret = -EBUSY;
+               }
+
+               if(0==ret) {
+                   _down_firmware(req.fwname, inf);
+                   queue_flush(inf->rcvmsg_q);
+                   rcv_quit = 0;
+                       wq2_condition = 0;
+               }
+               up(&sem);
+               break;
+
+       case DSP_IOCTL_RES_RELEASE:
+           dspprintk("DSP_IOCTL_RES_RELEASE cur_req = %d \n",inf->cur_req);
+           down(&sem);
+               if(inf->cur_req) {
+                       if(1==inf->cur_req) {
+                               if(1==arg)      strcpy(inf->req1fwname, "");
+                               wq_condition = 1;
+                               wake_up(&wq);
+                       } else {
+                               if(strcmp(inf->req1fwname, "")) {
+                                       _down_firmware(inf->req1fwname, inf);
+                               }
+                       }
+                       inf->cur_req = 0;
+                       inf->cur_pid = 0;
+
+            mod_timer(&inf->dsp_timer, jiffies + HZ);
+            inf->dsp_status = DS_TOSLOW;
+               }
+
+        /* force DSP_IOCTL_RECV_MSG return */
+           rcv_quit = 1;
+        wq2_condition = 1;
+        wake_up(&wq2);
+
+        up(&sem);
+               break;
+
+    case DSP_IOCTL_SEND_MSG:
+        //dspprintk("DSP_IOCTL_SEND_MSG \n");
+        {
+            struct rk28dsp_msg msg;
+            if(copy_from_user(&msg, (void *)arg, sizeof(struct rk28dsp_msg)))
+                return -EFAULT;
+
+            if(CODEC_MSG_ICU_CHANNEL==msg.channel) {
+               __raw_writel((__raw_readl(inf->pmu_base+0x043C) | 0x100), inf->pmu_base+0x043C);
+            } else {
+                PIU_SEND_CMD(msg.channel, msg.cmd);
+            }
+        }
+        break;
+
+    case DSP_IOCTL_RECV_MSG:
+        {
+            struct rk28dsp_msg *pmsg = NULL;
+            struct rk28dsp_msg msg;
+            if(NULL==inf->rcvmsg_q)     return -EFAULT;
+
+            while(NULL==pmsg)
+            {
+                pmsg = queue_get(inf->rcvmsg_q);
+                if(pmsg)    break;
+
+                if(copy_from_user(&msg, (void *)arg, sizeof(struct rk28dsp_msg)))   return -EFAULT;
+                if(0==msg.rcv_timeout)      return -EAGAIN;
+
+                if(-1==msg.rcv_timeout) {
+                    if(rcv_quit)    return -EAGAIN;
+                    wait_event(wq2, wq2_condition);
+                    wq2_condition = 0;
+                    if(rcv_quit)    return -EAGAIN;
+                } else {
+                    if(rcv_quit)    return -EAGAIN;
+                    if(!wait_event_timeout(wq2, wq2_condition, msg.rcv_timeout))   { wq2_condition = 0; return -EAGAIN; }
+                    wq2_condition = 0;
+                    if(rcv_quit)    return -EAGAIN;
+                }
+            }
+
+            if(pmsg) {
+                if(copy_to_user((void __user *)arg, pmsg, sizeof(struct rk28dsp_msg)))  ret = -EFAULT;
+                kfree(pmsg);
+            } else {
+                ret = -EFAULT;
+            }
+        }
+        break;
+
+       case DSP_IOCTL_SET_FREQ:
+               dspprintk("DSP_IOCTL_SET_FREQ: %dM!\n", (int)arg);
+               {
+                       dsp_set_clk((int)arg);
+                       inf->cur_freq = (int)arg;
+        }
+        break;
+
+    case DSP_IOCTL_GET_TABLE_PHY:
+        {
+            unsigned int table_phy = __pa(inf->codetableaddress);
+            if(copy_to_user((void __user *)arg, (void*)&table_phy, 4))  ret = -EFAULT;
+        }
+        break;
+
+       default:
+               break;
+       }
+
+    return ret;
+}
+
+
+static int dsp_open(struct inode *inode, struct file *file)
+{
+    return 0;
+}
+
+
+static int dsp_release(struct inode *inode, struct file *file)
+{
+    return 0;
+    //return dsp_ioctl(file, DSP_IOCTL_RES_RELEASE, 1);
+}
+
+static irqreturn_t rk28_dsp_irq(int irq, void *dev_id)
+{
+       struct platform_device *pdev = (struct platform_device*)dev_id;
+    struct rk28dsp_inf *inf = platform_get_drvdata(pdev);
+    struct rk28dsp_msg *pmsg = NULL;
+    unsigned int cmd = 0;
+
+       if(NULL==inf || NULL==inf->rcvmsg_q)            return IRQ_HANDLED;
+
+    if(IRQ_NR_PIUCMD == irq)
+    {
+        if (PIU_GET_STATUS_REPX(CODEC_OUTPUT_PIU_CHANNEL)) {
+            cmd = PIU_READ_REPX_VAL(CODEC_OUTPUT_PIU_CHANNEL);
+            if(inf->cur_pid && !queue_is_full(inf->rcvmsg_q)) {
+                pmsg = kmalloc(sizeof(struct rk28dsp_msg), GFP_ATOMIC);
+                if(pmsg) {
+                    pmsg->channel = CODEC_OUTPUT_PIU_CHANNEL;
+                    pmsg->cmd = cmd;
+                    pmsg->rcv_timeout = 0;
+                    if(!queue_put(inf->rcvmsg_q, pmsg, sizeof(struct rk28dsp_msg))) {
+                        wq2_condition = 1;
+                        wake_up(&wq2);
+                    } else {
+                        printk("queue_put fail! \n");
+                    }
+                } else {
+                    printk("kmalloc fail! \n");
+                }
+            }
+            PIU_CLR_STATUS_REPX(CODEC_OUTPUT_PIU_CHANNEL);  // clear status.
+        }
+
+        if (PIU_GET_STATUS_REPX(CODEC_MSG_PIU_CHANNEL)) {
+            cmd = PIU_READ_REPX_VAL(CODEC_MSG_PIU_CHANNEL);
+            if(inf->cur_pid && !queue_is_full(inf->rcvmsg_q)) {
+                pmsg = kmalloc(sizeof(struct rk28dsp_msg), GFP_ATOMIC);
+                if(pmsg) {
+                    pmsg->channel = CODEC_MSG_PIU_CHANNEL;
+                    pmsg->cmd = cmd;
+                    pmsg->rcv_timeout = 0;
+                    if(!queue_put(inf->rcvmsg_q, pmsg, sizeof(struct rk28dsp_msg))) {
+                        wq2_condition = 1;
+                        wake_up(&wq2);
+                    } else {
+                        printk("queue_put fail! \n");
+                    }
+                } else {
+                    printk("kmalloc fail! \n");
+                }
+            }
+            PIU_CLR_STATUS_REPX(CODEC_MSG_PIU_CHANNEL);  // clear status.
+        }
+
+        if (PIU_GET_STATUS_REPX(CODEC_MSG_PIU_NEXT_CHANNEL)) {
+            cmd = PIU_READ_REPX_VAL(CODEC_MSG_PIU_NEXT_CHANNEL);
+            if(inf->cur_pid && !queue_is_full(inf->rcvmsg_q)) {
+                pmsg = kmalloc(sizeof(struct rk28dsp_msg), GFP_ATOMIC);
+                if(pmsg) {
+                    pmsg->channel = CODEC_MSG_PIU_NEXT_CHANNEL;
+                    pmsg->cmd = cmd;
+                    pmsg->rcv_timeout = 0;
+                    if(!queue_put(inf->rcvmsg_q, pmsg, sizeof(struct rk28dsp_msg))) {
+                        wq2_condition = 1;
+                        wake_up(&wq2);
+                    } else {
+                        printk("queue_put fail! \n");
+                    }
+                } else {
+                    printk("kmalloc fail! \n");
+                }
+            }
+            PIU_CLR_STATUS_REPX(CODEC_MSG_PIU_NEXT_CHANNEL);    // clear status.
+        }
+    }
+
+
+    if(IRQ_NR_DSPSWI == irq)
+    {
+        __raw_writel((__raw_readl(inf->pmu_base+0x2c10) & (~0x40)), inf->pmu_base+0x2c10);    // clear status.
+        if(inf->cur_pid && !queue_is_full(inf->rcvmsg_q)) {
+            pmsg = kmalloc(sizeof(struct rk28dsp_msg), GFP_ATOMIC);
+            if(pmsg) {
+                pmsg->channel = CODEC_MSG_ICU_CHANNEL;
+                pmsg->cmd = 0;
+                pmsg->rcv_timeout = 0;
+                if(!queue_put(inf->rcvmsg_q, pmsg, sizeof(struct rk28dsp_msg))) {
+                    wq2_condition = 1;
+                    wake_up(&wq2);
+                } else {
+                    printk("queue_put fail! \n");
+                }
+            } else {
+                printk("kmalloc fail! \n");
+            }
+        }
+    }
+
+    return IRQ_HANDLED;
+}
+
+
+struct file_operations dsp_fops = {
+    .open           = dsp_open,
+       .release        = dsp_release,
+       .mmap           = dsp_mmap,
+       .unlocked_ioctl = dsp_ioctl,
+};
+
+static struct miscdevice dsp_dev ={
+    .minor = DSP_MAJOR,
+    .name = "rk28-dsp",
+    .fops = &dsp_fops,
+};
+
+void destruct(void *param, void *elem)
+{
+    if(elem)    kfree(elem);
+}
+
+
+static int __init dsp_drv_probe(struct platform_device *pdev)
+{
+       struct rk28dsp_inf *inf;
+       int ret = 0;
+
+       inf = kmalloc(sizeof(struct rk28dsp_inf), GFP_KERNEL);
+       if(NULL==inf) { ret = -ENOMEM;  goto alloc_fail; }
+       memset(inf, 0, sizeof(struct rk28dsp_inf));
+
+       inf->clk = clk_get(NULL, "dsp");
+       if(inf->clk)    clk_enable(inf->clk);
+
+       inf->pmu_base = (void*)ioremap(PMU_BASE_ADDR, 0x3000);
+       inf->l1_dbase = (void*)ioremap(RK2818_DSP_PHYS, 0x10000);
+       inf->l2_idbase = (void*)ioremap(DSP_L2_IMEM_BASE, 0x400000);
+
+       inf->irq0 = pdev->resource[1].start;
+       inf->irq1 = pdev->resource[2].start;
+
+       inf->bootaddress = (void*)__get_free_page(GFP_DMA);
+       inf->codeprogramaddress = (void*)__get_free_pages(GFP_DMA,4);
+       inf->codedataaddress = (void*)__get_free_pages(GFP_DMA,4);
+       inf->codetableaddress = (void*)__get_free_pages(GFP_DMA,6);
+       if(0==inf->bootaddress)                 { ret = -ENOMEM; printk("alloc bootaddress fail!\n"); goto alloc2_fail; }
+       if(0==inf->codeprogramaddress)  { ret = -ENOMEM; printk("alloc codeprogramaddress fail!\n");   goto alloc2_fail; }
+       if(0==inf->codedataaddress)             { ret = -ENOMEM; printk("alloc codedataaddress fail!\n");   goto alloc2_fail; }
+       if(0==inf->codetableaddress)    { ret = -ENOMEM; printk("alloc codetableaddress fail!\n");   goto alloc2_fail; }
+
+       platform_set_drvdata(pdev, inf);
+       inf->dev = pdev->dev;
+
+       inf->rcvmsg_q = queue_init(256, destruct, NULL);
+
+       ret = request_irq(inf->irq0, rk28_dsp_irq, IRQF_SHARED, "rk28-dsp", pdev);
+    if (ret < 0) {
+               goto irq0_fail;
+       }
+
+       ret = request_irq(inf->irq1, rk28_dsp_irq, IRQF_SHARED, "rk28-dsp", pdev);
+    if (ret < 0) {
+               goto irq1_fail;
+       }
+
+       init_MUTEX(&sem);
+
+    init_timer(&inf->dsp_timer);
+    inf->dsp_timer.function = dsptimer_callback;
+    inf->dsp_timer.expires = jiffies + HZ;
+    add_timer(&inf->dsp_timer);
+
+       inf->miscdev = dsp_dev;
+       ret = misc_register(&(inf->miscdev));
+       if(ret) {
+               goto reg_fail;
+       }
+
+       g_inf = inf;
+
+    return 0;
+
+reg_fail:
+       if(inf->irq1)   free_irq(inf->irq1, &inf->miscdev);
+irq1_fail:
+       if(inf->irq0)   free_irq(inf->irq0, &inf->miscdev);
+irq0_fail:
+alloc2_fail:
+       if(inf->bootaddress)        free_page((unsigned int)inf->bootaddress);
+       if(inf->codeprogramaddress) free_pages((unsigned int)inf->codeprogramaddress,4);
+       if(inf->codedataaddress)    free_pages((unsigned int)inf->codedataaddress,4);
+       if(inf->codetableaddress)   free_pages((unsigned int)inf->codetableaddress,6);
+       if(inf)    kfree(inf);
+alloc_fail:
+       return ret;
+}
+
+static int dsp_drv_remove(struct platform_device *pdev)
+{
+       struct rk28dsp_inf *inf = platform_get_drvdata(pdev);
+    dspprintk("%s [%d]\n",__FUNCTION__,__LINE__);
+
+    misc_deregister(&(inf->miscdev));
+       if(inf->irq0)       free_irq(inf->irq0, &inf->miscdev);
+    if(inf->irq1)       free_irq(inf->irq1, &inf->miscdev);
+
+    if(inf->bootaddress)        free_page((unsigned int)inf->bootaddress);
+       if(inf->codeprogramaddress) free_pages((unsigned int)inf->codeprogramaddress,4);
+       if(inf->codedataaddress)    free_pages((unsigned int)inf->codedataaddress,4);
+       if(inf->codetableaddress)   free_pages((unsigned int)inf->codetableaddress,6);
+
+       iounmap((void __iomem *)(inf->pmu_base));
+    iounmap((void __iomem *)(inf->l1_dbase));
+    iounmap((void __iomem *)(inf->l2_idbase));
+
+       if(inf->clk) {
+               clk_disable(inf->clk);
+               clk_put(inf->clk);
+       }
+
+    kfree(inf);
+    return 0;
+}
+
+
+#if defined(CONFIG_PM)
+static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+    struct rk28dsp_inf *inf = platform_get_drvdata(pdev);
+
+    dspprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+    if(!inf) {
+        printk("inf==0, dsp_drv_suspend fail! \n");
+        return -EINVAL;
+    }
+
+    if(DS_NORMAL==inf->dsp_status)  return -EPERM;
+
+    dsp_powerctl(DPC_SLEEP, 0);
+    inf->dsp_status = DS_SLEEP;
+    printk("dsp work mode : sleep mode \n");
+    return 0;
+}
+
+static int dsp_drv_resume(struct platform_device *pdev)
+{
+    struct rk28dsp_inf *inf = platform_get_drvdata(pdev);
+
+    dspprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+    if(!inf) {
+        printk("inf==0, dsp_drv_resume fail! \n");
+        return -EINVAL;
+    }
+
+    return 0;
+}
+#else
+#define dsp_drv_suspend                NULL
+#define dsp_drv_resume         NULL
+#endif /* CONFIG_PM */
+
+
+static struct platform_driver dsp_driver = {
+       .probe          = dsp_drv_probe,
+       .remove         = dsp_drv_remove,
+       .suspend        = dsp_drv_suspend,
+       .resume         = dsp_drv_resume,
+       .driver         = {
+               .name   = "rk28-dsp",
+       },
+};
+
+static int __init rk2818_dsp_init(void)
+{
+       return platform_driver_register(&dsp_driver);
+}
+
+static void __exit rk2818_dsp_exit(void)
+{
+       platform_driver_unregister(&dsp_driver);
+}
+
+
+//module_init(rk2818_dsp_init);
+subsys_initcall(rk2818_dsp_init);
+module_exit(rk2818_dsp_exit);
+
+MODULE_AUTHOR(" dukunming  dkm@rock-chips.com");
+MODULE_DESCRIPTION("Driver for rk2818 dsp device");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/staging/rk2818/rk2818_dsp/rk2818_dsp.h b/drivers/staging/rk2818/rk2818_dsp/rk2818_dsp.h
new file mode 100644 (file)
index 0000000..4f54ccf
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * drivers/staging/rk2818/rk2818_dsp/rk2818_dsp.h
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRIVERS_STAGING_RK2818_DSP_H
+#define __DRIVERS_STAGING_RK2818_DSP_H
+
+
+#define PIU_CMD0_OFFSET         (0x2030)
+#define PIU_REPLY0_OFFSET       (0x203c)
+#define PIU_STATUS_OFFSET       (0x204c)
+#define PIU_IMASK_OFFSET        (0x2048)
+#define PIU_STATUS_R0WRS        3
+
+
+#define CODEC_OUTPUT_PIU_CHANNEL        0
+#define CODEC_MSG_PIU_CHANNEL           1
+#define CODEC_MSG_PIU_NEXT_CHANNEL      2
+#define CODEC_MSG_ICU_CHANNEL           3
+
+
+#define DSP_IOCTL_RES_REQUEST           (0x00800000)
+#define DSP_IOCTL_RES_RELEASE           (0x00800001)
+#define DSP_IOCTL_SEND_MSG              (0x00800002)
+#define DSP_IOCTL_RECV_MSG              (0x00800003)
+#define DSP_IOCTL_SET_FREQ              (0x00800004)
+#define DSP_IOCTL_GET_TABLE_PHY         (0x00800005)
+
+
+struct rk28dsp_req {
+       int reqno;
+       char fwname[20];
+       int freq;
+};
+
+struct rk28dsp_msg {
+       int channel;
+       unsigned int cmd;
+       int rcv_timeout;    // 0:no block   -1:block   >0:block with timeout
+};
+
+extern void rockchip_add_device_dsp(void);
+
+#endif /* __DRIVERS_STAGING_RK2818_DSP_H */
+