add ipp driver.
authorroot <root@android.localdomain>
Thu, 16 Dec 2010 07:28:05 +0000 (15:28 +0800)
committerroot <root@android.localdomain>
Thu, 16 Dec 2010 07:28:05 +0000 (15:28 +0800)
arch/arm/mach-rk29/board-rk29sdk.c
arch/arm/mach-rk29/devices.c
arch/arm/mach-rk29/devices.h
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/rk29/ipp/Kconfig [new file with mode: 0644]
drivers/staging/rk29/ipp/Makefile [new file with mode: 0644]
drivers/staging/rk29/ipp/rk29-ipp.c [new file with mode: 0644]
drivers/staging/rk29/ipp/rk29-ipp.h [new file with mode: 0644]

index d26ee77df61e3ef1ddfee85782f76a230130ee38..2f1084213fe2104d1c1023cfde0cac8259761ea5 100755 (executable)
@@ -1142,6 +1142,9 @@ static struct platform_device *devices[] __initdata = {
        &android_usb_device,\r
        &usb_mass_storage_device,\r
 #endif\r
+#ifdef CONFIG_RK29_IPP\r
+       &rk29_device_ipp,\r
+#endif\r
 };\r
 \r
 /*****************************************************************************************\r
index a4d50aa90f81473ae5c59723b905cd356771fe40..3761431cd477ee2168e223f10ea619e0289b8180 100755 (executable)
@@ -437,6 +437,29 @@ struct platform_device rk29_device_camera = {
 };
 #endif
 
+#ifdef CONFIG_RK29_IPP
+/* rk29 ipp resource */
+static struct resource rk29_ipp_resource[] = {
+       [0] = {
+               .start = RK29_IPP_PHYS,
+               .end   = RK29_IPP_PHYS + RK29_IPP_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_IPP,
+               .end   = IRQ_IPP,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+/*platform_device*/
+struct platform_device rk29_device_ipp = {
+       .name             = "rk29-ipp",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(rk29_ipp_resource),
+       .resource         = rk29_ipp_resource,
+};
+#endif
 #if defined(CONFIG_MTD_NAND_RK29XX)  
 static struct resource rk29xxnand_resources[] = {
        {
index 2928b2d1c4fb4a678879a73ab9f34efcfa4c4c95..ed885aa0ce89535733b07b4b6e4d7660b281dd24 100755 (executable)
@@ -56,4 +56,5 @@ extern struct usb_mass_storage_platform_data mass_storage_pdata;
 extern struct platform_device usb_mass_storage_device;
 extern struct platform_device rk29_device_vmac;
 extern struct rk29_vmac_platform_data rk29_vmac_pdata;
+extern struct platform_device rk29_device_ipp;
 #endif
index 34ee095555abede24ab8eac60ce2917034554814..59eaa5ac9cdfddc25d358c0e44fa987c9c05ddc8 100755 (executable)
@@ -132,5 +132,6 @@ source "drivers/staging/rk2818/rk1000_control/Kconfig"
 source "drivers/staging/rk2818/rk2818_power/Kconfig"
 
 source "drivers/staging/rk29/vivante/Kconfig"
+source "drivers/staging/rk29/ipp/Kconfig"
 endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
index 5b2a508c7fcc7cfe37a866ffa2ab19f1a230dbef..a991d1f0055d163a680e49b5618f44b738b09c87 100755 (executable)
@@ -49,3 +49,4 @@ obj-$(CONFIG_RK1000_CONTROL)    += rk2818/rk1000_control/
 obj-$(CONFIG_RK1000_TVOUT)    += rk2818/rk1000_tv/
 obj-$(CONFIG_RK2818_POWER)                             += rk2818/rk2818_power/
 obj-$(CONFIG_VIVANTE)           += rk29/vivante/
+obj-$(CONFIG_RK29_IPP)           += rk29/ipp/
diff --git a/drivers/staging/rk29/ipp/Kconfig b/drivers/staging/rk29/ipp/Kconfig
new file mode 100644 (file)
index 0000000..f759916
--- /dev/null
@@ -0,0 +1,8 @@
+menu "IPP"
+config RK29_IPP
+       tristate "ROCKCHIP RK29 IPP"
+       default y
+       help
+          rk29 ipp module.
+endmenu
+
diff --git a/drivers/staging/rk29/ipp/Makefile b/drivers/staging/rk29/ipp/Makefile
new file mode 100644 (file)
index 0000000..674c218
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for the ipp.
+#
+
+obj-$(CONFIG_RK29_IPP) += rk29-ipp.o
+rk29ipp-objs := rk29-ipp.o 
\ No newline at end of file
diff --git a/drivers/staging/rk29/ipp/rk29-ipp.c b/drivers/staging/rk29/ipp/rk29-ipp.c
new file mode 100644 (file)
index 0000000..411be71
--- /dev/null
@@ -0,0 +1,939 @@
+/* drivers/staging/rk29/ipp/rk29-ipp.c\r
+ *\r
+ * Copyright (C) 2010 ROCKCHIP, Inc.\r
+ *\r
+ * This software is licensed under the terms of the GNU General Public\r
+ * License version 2, as published by the Free Software Foundation, and\r
+ * may be copied, distributed, and modified under those terms.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ */\r
+\r
+#include <linux/kernel.h>\r
+#include <linux/init.h>\r
+#include <linux/module.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/sched.h>\r
+#include <linux/mutex.h>\r
+#include <linux/err.h>\r
+#include <linux/clk.h>\r
+#include <asm/delay.h>\r
+#include <linux/dma-mapping.h>\r
+#include <linux/delay.h>\r
+#include <asm/io.h>\r
+#include <linux/irq.h>\r
+#include <linux/interrupt.h>\r
+#include <mach/rk29_iomap.h>\r
+#include <mach/irqs.h>\r
+#include <linux/fs.h>\r
+#include <asm/uaccess.h>\r
+#include <linux/firmware.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/poll.h>\r
+#include <linux/delay.h>\r
+#include <linux/wait.h>\r
+#include <linux/syscalls.h>\r
+#include <linux/timer.h>\r
+#include "rk29-ipp.h"\r
+\r
+\r
+struct ipp_drvdata {\r
+       struct miscdevice miscdev;\r
+       struct device dev;\r
+       void *ipp_base;\r
+       struct ipp_regs regs;\r
+       int irq0;\r
+       struct clk *axi_clk;\r
+       struct clk *ahb_clk;\r
+       struct mutex    mutex;  // mutex\r
+};\r
+\r
+static struct ipp_drvdata *drvdata = NULL;\r
+\r
+static DECLARE_WAIT_QUEUE_HEAD(wait_queue);\r
+static int wq_condition = 0;\r
+\r
+/* Context data (unique) */\r
+struct ipp_context\r
+{\r
+       struct ipp_drvdata      *data;  // driver data\r
+       struct rk29_ipp_req     *blit;  // blit request\r
+       uint32_t                        rot;    // rotation mode\r
+       struct file                     *srcf;  // source file (for PMEM)\r
+       struct file                     *dstf;  // destination file (for PMEM)\r
+};\r
+\r
+#define IPP_MAJOR              232\r
+#define RK_IPP_BLIT    0x5017\r
+#define RK_IPP_SYNC    0x5018\r
+\r
+#define RK29_IPP_PHYS  0x10110000\r
+#define RK29_IPP_SIZE  SZ_16K\r
+#define IPP_RESET_TIMEOUT      1000\r
+\r
+/* Driver information */\r
+#define DRIVER_DESC            "RK29 IPP Device Driver"\r
+#define DRIVER_NAME            "rk29-ipp"\r
+\r
+/* Logging */\r
+#define IPP_DEBUG 0\r
+#ifdef IPP_DEBUG\r
+#define DBG(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args)\r
+#define ERR(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args)\r
+#define WARNING(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args)\r
+#define INFO(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args)\r
+#else\r
+#define DBG(format, args...)\r
+#define ERR(format, args...)\r
+#define WARNING(format, args...)\r
+#define INFO(format, args...)\r
+#endif\r
+\r
+static inline void ipp_write( uint32_t b, uint32_t r)\r
+{\r
+       __raw_writel(b, drvdata->ipp_base + r);\r
+}\r
+\r
+static inline uint32_t ipp_read( uint32_t r)\r
+{\r
+       return __raw_readl(drvdata->ipp_base + r);\r
+}\r
+\r
+static void ipp_soft_reset(void)\r
+{\r
+       uint32_t i;\r
+       uint32_t reg;\r
+\r
+       ipp_write(1, IPP_SRESET);\r
+\r
+       for(i = 0; i < IPP_RESET_TIMEOUT; i++) {\r
+               reg = ipp_read( IPP_SRESET) & 1;\r
+\r
+               if(reg == 0)\r
+                       break;\r
+\r
+               udelay(1);\r
+       }\r
+\r
+       if(i == IPP_RESET_TIMEOUT)\r
+               ERR("soft reset timeout.\n");\r
+}\r
+\r
+static int ipp_do_blit(struct rk29_ipp_req *req)\r
+{\r
+       uint32_t rotate;\r
+       uint32_t pre_scale      = 0;\r
+       uint32_t post_scale = 0;\r
+       uint32_t pre_scale_w, pre_scale_h;\r
+       uint32_t post_scale_w = 0x1000;\r
+       uint32_t post_scale_h = 0x1000;\r
+       uint32_t pre_scale_target_w, pre_scale_target_h;\r
+       uint32_t post_scale_target_w, post_scale_target_h;\r
+       uint32_t dst0_YrgbMst,dst0_CbrMst;\r
+       uint32_t ret = 0;\r
+       rotate = req->flag;\r
+       switch (rotate) {\r
+       case IPP_ROT_90:\r
+               //for rotation 90 degree\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst  =  req->dst0.YrgbMst + req->dst0.w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst  =  req->dst0.YrgbMst +  req->dst0.w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst  =  req->dst0.YrgbMst + req->dst0.w;\r
+                       dst0_CbrMst   =  req->dst0.CbrMst + req->dst0.w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst + req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst + req->dst0.w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst = req->dst0.YrgbMst+ req->dst0.w;\r
+                       dst0_CbrMst  = req->dst0.CbrMst + req->dst0.w;\r
+                       break;\r
+\r
+               default:\r
+\r
+                       break;\r
+               }\r
+       break;\r
+\r
+       case IPP_ROT_180:\r
+               //for rotation 180 degree\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*4+req->dst0.w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*2+req->dst0.w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2+req->dst0.w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+((req->dst0.h/2)-1)*req->dst_vir_w+req->dst0.w;\r
+                       break;\r
+\r
+               default:\r
+                       break;\r
+               }\r
+                       break;\r
+\r
+       case IPP_ROT_270:\r
+               DBG("rotate %d, src0.fmt %d \n",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst +(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+((req->dst0.h/2)-1)*req->dst_vir_w;\r
+                       break;\r
+\r
+               default:\r
+                       break;\r
+               }\r
+               break;\r
+\r
+       case IPP_ROT_X_FLIP:\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+req->dst0.w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+req->dst0.w;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+req->dst0.w;\r
+                       break;\r
+\r
+               default:\r
+                       break;\r
+               }\r
+\r
+       break;\r
+\r
+       case IPP_ROT_Y_FLIP:\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst = req->dst0.CbrMst+((req->dst0.h/2)-1)*req->dst_vir_w;\r
+                       break;\r
+\r
+       default:\r
+               break;\r
+       }\r
+\r
+       break;\r
+       case IPP_ROT_0:\r
+               //for  0 degree\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               dst0_YrgbMst =  req->dst0.YrgbMst;\r
+               dst0_CbrMst  = req->dst0.CbrMst;\r
+       break;\r
+\r
+       default:\r
+               ERR("ipp is not surpport degree!!\n" );\r
+               break;\r
+       }\r
+\r
+       if(drvdata->axi_clk)\r
+       {\r
+               clk_enable(drvdata->axi_clk);\r
+       }\r
+       else\r
+       {\r
+               printk("axi_clk is null \n");\r
+               ret =  -EINVAL;\r
+               goto error_axi_clk;\r
+       }\r
+\r
+       if(drvdata->ahb_clk)\r
+       {\r
+               clk_enable(drvdata->ahb_clk);\r
+       }\r
+       else\r
+       {\r
+               printk("ahb_clk is null \n");\r
+               ret = -EINVAL;\r
+               goto error_ahb_clk;\r
+       }\r
+\r
+       /* Configure source image */\r
+       DBG("src YrgbMst 0x%x , CbrMst0x%x,  %dx%d, fmt = %d\n", req->src0.YrgbMst,req->src0.CbrMst,\r
+                                       req->src0.w, req->src0.h, req->src0.fmt);\r
+\r
+       ipp_write(req->src0.YrgbMst, IPP_SRC0_Y_MST);\r
+       if(IS_YCRCB(req->src0.fmt))\r
+       {\r
+               ipp_write(req->src0.CbrMst, IPP_SRC0_CBR_MST);\r
+       }\r
+       ipp_write(req->src0.h<<16|req->src0.w, IPP_SRC_IMG_INFO);\r
+       ipp_write(ipp_read(IPP_CONFIG)|req->src0.fmt, IPP_CONFIG);\r
+\r
+       /* Configure destination image */\r
+       DBG("dst YrgbMst 0x%x , CbrMst0x%x, %dx%d\n", dst0_YrgbMst,dst0_CbrMst,\r
+                                       req->dst0.w, req->dst0.h);\r
+\r
+       ipp_write(dst0_YrgbMst, IPP_DST0_Y_MST);\r
+\r
+       if(IS_YCRCB(req->src0.fmt))\r
+       {\r
+               ipp_write(dst0_CbrMst, IPP_DST0_CBR_MST);\r
+       }\r
+       ipp_write(req->dst0.h<<16|req->dst0.w, IPP_DST_IMG_INFO);\r
+\r
+       /*Configure Pre_scale*/\r
+       if((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate))\r
+       {\r
+               pre_scale = ((req->dst0.w < req->src0.h) ? 1 : 0)||((req->dst0.h < req->src0.w) ? 1 : 0);\r
+       }\r
+       else //other degree\r
+       {\r
+               pre_scale = ((req->dst0.w < req->src0.w) ? 1 : 0)||((req->dst0.h < req->src0.h) ? 1 : 0);\r
+       }\r
+\r
+       if(pre_scale)\r
+       {\r
+               if(((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate)))\r
+               {\r
+\r
+                       if((req->src0.w>req->dst0.h))\r
+                       {\r
+                               pre_scale_w = (uint32_t)( req->src0.w/req->dst0.h);//floor\r
+                       }\r
+                       else\r
+                       {\r
+                          pre_scale_w = 1;\r
+                       }\r
+                       if((req->src0.h>req->dst0.w))\r
+                       {\r
+                               pre_scale_h = (uint32_t)( req->src0.h/req->dst0.w);//floor\r
+                       }\r
+                       else\r
+                       {\r
+                               pre_scale_h = 1;\r
+                       }\r
+\r
+                       DBG("!!!!!pre_scale_h %d,pre_scale_w %d \n",pre_scale_h,pre_scale_w);\r
+\r
+                       ipp_write(ipp_read(IPP_CONFIG)|PRE_SCALE, IPP_CONFIG);          //enable pre_scale\r
+                       ipp_write(ipp_read(IPP_PRE_SCL_PARA)|(pre_scale_h-1)<<3|(pre_scale_w-1),IPP_PRE_SCL_PARA);\r
+\r
+                       if((req->src0.w%pre_scale_w)!=0) //ÏòÉÏÈ¡Õû ceil\r
+                       {\r
+                               pre_scale_target_w = req->src0.w/pre_scale_w+1;\r
+                       }\r
+                       else\r
+                       {\r
+                               pre_scale_target_w = req->src0.w/pre_scale_w;\r
+                       }\r
+\r
+                       if((req->src0.h%pre_scale_h)!=0)//ÏòÉÏÈ¡Õû ceil\r
+                       {\r
+                               pre_scale_target_h  = req->src0.h/pre_scale_h +1;\r
+                       }\r
+                       else\r
+                       {\r
+                               pre_scale_target_h = req->src0.h/pre_scale_h;\r
+                       }\r
+\r
+                       ipp_write(((pre_scale_target_h)<<16)|(pre_scale_target_w), IPP_PRE_IMG_INFO);\r
+\r
+               }\r
+               else//0 180 x ,y\r
+               {\r
+\r
+                       if((req->src0.w>req->dst0.w))\r
+                       {\r
+                               pre_scale_w = (uint32_t)( req->src0.w/req->dst0.w);//floor\r
+                       }\r
+                       else\r
+                       {\r
+                          pre_scale_w = 1;\r
+                       }\r
+\r
+                       if((req->src0.h>req->dst0.h))\r
+                       {\r
+                               pre_scale_h = (uint32_t)( req->src0.h/req->dst0.h);//floor\r
+                       }\r
+                       else\r
+                       {\r
+                               pre_scale_h = 1;\r
+                       }\r
+\r
+                       DBG("!!!!!pre_scale_h %d,pre_scale_w %d \n",pre_scale_h,pre_scale_w);\r
+\r
+                       ipp_write(ipp_read(IPP_CONFIG)|PRE_SCALE, IPP_CONFIG);          //enable pre_scale\r
+                       ipp_write(ipp_read(IPP_PRE_SCL_PARA)|(pre_scale_h-1)<<3|(pre_scale_w-1),IPP_PRE_SCL_PARA);\r
+\r
+                       if((req->src0.w%pre_scale_w)!=0) //ÏòÉÏÈ¡Õû ceil\r
+                       {\r
+                               pre_scale_target_w = req->src0.w/pre_scale_w+1;\r
+                       }\r
+                       else\r
+                       {\r
+                               pre_scale_target_w = req->src0.w/pre_scale_w;\r
+                       }\r
+\r
+                       if((req->src0.h%pre_scale_h)!=0)//ÏòÉÏÈ¡Õû ceil\r
+                       {\r
+                               pre_scale_target_h  = req->src0.h/pre_scale_h +1;\r
+                       }\r
+                       else\r
+                       {\r
+                               pre_scale_target_h = req->src0.h/pre_scale_h;\r
+                       }\r
+               }\r
+               ipp_write(((pre_scale_target_h)<<16)|(pre_scale_target_w), IPP_PRE_IMG_INFO);\r
+\r
+       }\r
+       else//no pre_scale\r
+       {\r
+               ipp_write(0,IPP_PRE_SCL_PARA);\r
+               ipp_write((req->src0.h<<16)|req->src0.w, IPP_PRE_IMG_INFO);\r
+       }\r
+\r
+       /*Configure Post_scale*/\r
+       if((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate))\r
+       {\r
+               if (( (req->src0.h%req->dst0.w)!=0)||( (req->src0.w%req->dst0.h)!= 0)//СÊý±¶ËõС\r
+                       ||(req->dst0.w > req->src0.h) ||(req->dst0.h > req->src0.w))\r
+               {\r
+                       post_scale = 1;\r
+               }\r
+               else\r
+               {\r
+                       post_scale = 0;\r
+               }\r
+       }\r
+       else  //0 180 x-flip y-flip\r
+       {\r
+               if (( (req->src0.w%req->dst0.w)!=0)||( (req->src0.h%req->dst0.h)!= 0)//СÊý±¶ËõС\r
+                       ||(req->dst0.w > req->src0.w) ||(req->dst0.h > req->src0.h))\r
+               {\r
+                       post_scale = 1;\r
+               }\r
+               else\r
+               {\r
+                       post_scale = 0;\r
+               }\r
+       }\r
+\r
+       if(post_scale)\r
+       {\r
+               if((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate))\r
+               {\r
+                       if(pre_scale)\r
+                       {\r
+                               post_scale_target_w = pre_scale_target_w;\r
+                               post_scale_target_h = pre_scale_target_h;\r
+                       }\r
+                       else\r
+                       {\r
+                               post_scale_target_w = req->src0.w;\r
+                               post_scale_target_h = req->src0.h;\r
+                       }\r
+\r
+                       DBG("post_scale_target_w %d ,post_scale_target_h %d !!!\n",post_scale_target_w,post_scale_target_h);\r
+\r
+                       switch(req->src0.fmt)\r
+                       {\r
+                       case IPP_XRGB_8888:\r
+                       case IPP_RGB_565:\r
+                       case IPP_Y_CBCR_H1V1:\r
+                                post_scale_w = (uint32_t)(4096*(post_scale_target_w-1)/(req->dst0.h-1));\r
+                    break;\r
+\r
+                       case IPP_Y_CBCR_H2V1:\r
+                       case IPP_Y_CBCR_H2V2:\r
+                                post_scale_w = (uint32_t)(4096*(post_scale_target_w/2-1)/(req->dst0.h/2-1));\r
+                        break;\r
+\r
+                       default:\r
+                               break;\r
+               }\r
+                       post_scale_h = (uint32_t)(4096*(post_scale_target_h -1)/(req->dst0.w-1));\r
+\r
+                       DBG("1111 post_scale_w %x,post_scale_h %x!!! \n",post_scale_w,post_scale_h);\r
+               }\r
+               else// 0 180 x-flip y-flip\r
+               {\r
+\r
+                       if(pre_scale)\r
+                       {\r
+                               post_scale_target_w = pre_scale_target_w;\r
+                               post_scale_target_h = pre_scale_target_h;\r
+                       }\r
+                       else\r
+                       {\r
+                               post_scale_target_w = req->src0.w;\r
+                               post_scale_target_h = req->src0.h;\r
+                       }\r
+\r
+                       switch(req->src0.fmt)\r
+                       {\r
+                       case IPP_XRGB_8888:\r
+                       case IPP_RGB_565:\r
+                       case IPP_Y_CBCR_H1V1:\r
+                                post_scale_w = (uint32_t)(4096*(post_scale_target_w-1)/(req->dst0.w-1));\r
+                    break;\r
+\r
+                       case IPP_Y_CBCR_H2V1:\r
+                       case IPP_Y_CBCR_H2V2:\r
+                                post_scale_w = (uint32_t)(4096*(post_scale_target_w/2-1)/(req->dst0.w/2-1));\r
+                        break;\r
+\r
+                       default:\r
+                               break;\r
+               }\r
+                       post_scale_h = (uint32_t)(4096*(post_scale_target_h -1)/(req->dst0.h-1));\r
+\r
+               }\r
+               ipp_write(ipp_read(IPP_CONFIG)|POST_SCALE, IPP_CONFIG); //enable post_scale\r
+               ipp_write((post_scale_h<<16)|post_scale_w, IPP_POST_SCL_PARA);\r
+       }\r
+       else //no post_scale\r
+       {\r
+               DBG("no post_scale !!!!!! \n");\r
+               ipp_write(ipp_read(IPP_CONFIG)&(~POST_SCALE), IPP_CONFIG); //disable post_scale\r
+               ipp_write((post_scale_h<<16)|post_scale_w, IPP_POST_SCL_PARA);\r
+       }\r
+\r
+       /* Configure rotation */\r
+\r
+       if(IPP_ROT_0 == req->flag)\r
+       {\r
+               ipp_write(ipp_read(IPP_CONFIG)&(~ROT_ENABLE), IPP_CONFIG);\r
+       }\r
+       else if(req->flag > IPP_ROT_LIMIT)\r
+       {\r
+           printk("rk29_ipp is not surpport rot degree!!!!\n");\r
+               ret = -1;\r
+               goto error_rot_limit;\r
+       }\r
+       else\r
+       {\r
+               ipp_write(ipp_read(IPP_CONFIG)|ROT_ENABLE, IPP_CONFIG);\r
+               ipp_write(ipp_read(IPP_CONFIG)|rotate<<5, IPP_CONFIG);\r
+       }\r
+\r
+       /*Configure other*/\r
+       ipp_write((req->dst_vir_w<<16)|req->src_vir_w, IPP_IMG_VIR);\r
+\r
+       if((req->src0.w%4) !=0)\r
+       ipp_write(ipp_read(IPP_CONFIG)|(1<<26), IPP_CONFIG);//store clip mode\r
+\r
+       /* Start the operation */\r
+\r
+       ipp_write(8, IPP_INT);//\r
+\r
+       //msleep(5000);//debug use\r
+\r
+       ipp_write(1, IPP_PROCESS_ST);\r
+\r
+       if(!wait_event_timeout(wait_queue, wq_condition, msecs_to_jiffies(req->timeout)))\r
+       {\r
+               printk("wait_event_timeout \n");\r
+               wq_condition = 0;\r
+               if(!drvdata)\r
+               {\r
+               printk("close clk 0! \n");\r
+               ret = -EINVAL;\r
+                       goto error_null;\r
+           }\r
+               ret =  -EAGAIN;\r
+               goto errot_timeout;\r
+       }\r
+\r
+       wq_condition = 0;\r
+\r
+       if(!drvdata)\r
+       {\r
+        printk("close clk! \n");\r
+        ret =  -EINVAL;\r
+               goto error_null;\r
+    }\r
+\r
+       if(((ipp_read(IPP_INT)>>6)&0x3) ==0)// idle\r
+       {\r
+               clk_disable(drvdata->axi_clk);\r
+               clk_disable(drvdata->ahb_clk);\r
+       }\r
+       else\r
+       {\r
+               printk("rk29 ipp status is error!!!\n");\r
+               ret =  -EINVAL;\r
+               goto errot_timeout;\r
+       }\r
+       return 0;\r
+\r
+error_null:\r
+errot_timeout:\r
+error_rot_limit:\r
+error_ahb_clk:\r
+       clk_disable(drvdata->ahb_clk);\r
+error_axi_clk:\r
+       clk_disable(drvdata->axi_clk);\r
+       return ret;\r
+}\r
+\r
+static int stretch_blit(struct ipp_context *ctx,  unsigned long arg )\r
+{\r
+       struct ipp_drvdata *data = ctx->data;\r
+       int ret = 0;\r
+       struct rk29_ipp_req req;\r
+\r
+       mutex_lock(&data->mutex);\r
+\r
+       if (unlikely(copy_from_user(&req, (struct rk29_ipp_req*)arg,\r
+                                       sizeof(struct rk29_ipp_req)))) {\r
+               ERR("copy_from_user failed\n");\r
+               ret = -EFAULT;\r
+               goto err_noput;\r
+       }\r
+\r
+       if (unlikely((req.src0.w <= 1) || (req.src0.h <= 1))) {\r
+               ERR("invalid source resolution\n");\r
+               ret = -EINVAL;\r
+               goto err_noput;\r
+       }\r
+\r
+       if (unlikely((req.dst0.w <= 1) || (req.dst0.h <= 1))) {\r
+               ERR("invalid destination resolution\n");\r
+               ret = -EINVAL;\r
+               goto err_noput;\r
+       }\r
+\r
+       if (unlikely(req.src0.YrgbMst== 0) )\r
+       {\r
+               ERR("could not retrieve src image from memory\n");\r
+               ret = -EINVAL;\r
+               goto err_noput;\r
+       }\r
+\r
+       if (unlikely(req.dst0.YrgbMst== 0) )\r
+       {\r
+               ERR("could not retrieve dst image from memory\n");\r
+               ret = -EINVAL;\r
+               goto err_noput;\r
+       }\r
+\r
+       ret = ipp_do_blit(&req);\r
+       if(ret != 0) {\r
+               ERR("Failed to start IPP operation (%d)\n", ret);\r
+               ipp_soft_reset();\r
+               goto err_noput;\r
+       }\r
+\r
+err_noput:\r
+\r
+       mutex_unlock(&data->mutex);\r
+\r
+       return ret;\r
+}\r
+\r
+static int ipp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+\r
+       struct ipp_context *ctx = (struct ipp_context *)file->private_data;\r
+       int ret = 0;\r
+       switch (cmd)\r
+       {\r
+               case RK_IPP_BLIT:\r
+                       ret = stretch_blit(ctx, arg);\r
+                       break;\r
+\r
+               default:\r
+                       ERR("unknown ioctl cmd!\n");\r
+                       ret = -EINVAL;\r
+                       break;\r
+       }\r
+       return ret;\r
+}\r
+\r
+static int rk29_ipp_open(struct inode *inode, struct file *file)\r
+{\r
+   struct ipp_context *ctx;\r
+\r
+    ctx = kmalloc(sizeof(struct ipp_context), GFP_KERNEL);\r
+       if (ctx == NULL) {\r
+               ERR("Context allocation failed\n");\r
+               return -ENOMEM;\r
+       }\r
+\r
+       memset(ctx, 0, sizeof(struct ipp_context));\r
+       ctx->data       = drvdata;\r
+       ctx->rot        = IPP_ROT_0;\r
+       file->private_data = ctx;\r
+\r
+       DBG("device opened\n");\r
+\r
+       return 0;\r
+}\r
+\r
+static int ipp_release(struct inode *inode, struct file *file)\r
+{\r
+    struct ipp_context *ctx = (struct ipp_context *)file->private_data;\r
+       kfree(ctx);\r
+\r
+       DBG("device released\n");\r
+       return 0;\r
+}\r
+\r
+static irqreturn_t rk29_ipp_irq(int irq,  void *dev_id)\r
+{\r
+       uint32_t stat;\r
+\r
+       DBG("rk29_ipp_irq %d \n",irq);\r
+       stat = ipp_read(IPP_INT);\r
+\r
+       while(!(stat & 0x1))\r
+       {\r
+               DBG("stat %d \n",stat);\r
+       }\r
+       wq_condition = 1;\r
+       wake_up(&wait_queue);\r
+\r
+       ipp_write(ipp_read(IPP_INT)|0xc, IPP_INT);\r
+       ipp_write(ipp_read(IPP_INT)|0x30, IPP_INT);\r
+       return IRQ_HANDLED;\r
+}\r
+\r
+struct file_operations ipp_fops = {\r
+       .owner          = THIS_MODULE,\r
+       .open           = rk29_ipp_open,\r
+       .release        = ipp_release,\r
+       .ioctl          = ipp_ioctl,\r
+};\r
+\r
+static struct miscdevice ipp_dev ={\r
+    .minor = IPP_MAJOR,\r
+    .name  = "rk29-ipp",\r
+    .fops  = &ipp_fops,\r
+};\r
+\r
+static int __init ipp_drv_probe(struct platform_device *pdev)\r
+{\r
+       struct ipp_drvdata *data;\r
+       int ret = 0;\r
+\r
+       data = kmalloc(sizeof(struct ipp_drvdata), GFP_KERNEL);\r
+       if(NULL==data)\r
+       {\r
+               ERR("failed to allocate driver data.\n");\r
+               return  -ENOMEM;\r
+       }\r
+\r
+       /* get the clock */\r
+       data->axi_clk = clk_get(&pdev->dev, "ipp_axi");\r
+       if(NULL == data->axi_clk)\r
+       {\r
+               ERR("failed to find ipp axi clock source\n");\r
+               ret = -ENOENT;\r
+               goto err_clock;\r
+       }\r
+\r
+       data->ahb_clk = clk_get(&pdev->dev, "ipp_ahb");\r
+       if(NULL == data->ahb_clk)\r
+       {\r
+               ERR("failed to find ipp ahb clock source\n");\r
+               ret = -ENOENT;\r
+               goto err_clock;\r
+       }\r
+\r
+       /* map the memory */\r
+       data->ipp_base = (void*)ioremap( RK29_IPP_PHYS, SZ_16K);//ipp size 16k\r
+       if (data->ipp_base == NULL)\r
+       {\r
+               ERR("ioremap failed\n");\r
+               ret = -ENOENT;\r
+               goto err_ioremap;\r
+       }\r
+\r
+       /* get the IRQ */\r
+       data->irq0 = pdev->resource[1].start;\r
+       printk("ipp irq %d\n",data->irq0);\r
+       if (data->irq0 <= 0)\r
+       {\r
+               ERR("failed to get irq resource (%d).\n", data->irq0);\r
+               ret = data->irq0;\r
+               goto err_irq;\r
+       }\r
+\r
+       /* request the IRQ */\r
+       ret = request_irq(data->irq0, rk29_ipp_irq, IRQF_SHARED, "rk29-ipp", pdev);\r
+       if (ret)\r
+       {\r
+               ERR("request_irq failed (%d).\n", ret);\r
+               goto err_irq;\r
+       }\r
+\r
+       mutex_init(&data->mutex);\r
+\r
+       platform_set_drvdata(pdev, data);\r
+       drvdata = data;\r
+\r
+       ret = misc_register(&ipp_dev);\r
+       if(ret)\r
+       {\r
+               ERR("cannot register miscdev (%d)\n", ret);\r
+               goto err_misc_register;\r
+       }\r
+       DBG("Driver loaded succesfully\n");\r
+\r
+       return 0;\r
+\r
+err_misc_register:\r
+       free_irq(data->irq0, pdev);\r
+err_irq:\r
+       iounmap(data->ipp_base);\r
+err_ioremap:\r
+err_clock:\r
+       kfree(data);\r
+\r
+       return ret;\r
+}\r
+\r
+static int ipp_drv_remove(struct platform_device *pdev)\r
+{\r
+       struct ipp_drvdata *data = platform_get_drvdata(pdev);\r
+    DBG("%s [%d]\n",__FUNCTION__,__LINE__);\r
+\r
+    misc_deregister(&(data->miscdev));\r
+       free_irq(data->irq0, &data->miscdev);\r
+    iounmap((void __iomem *)(data->ipp_base));\r
+\r
+       if(data->axi_clk) {\r
+               clk_put(data->axi_clk);\r
+       }\r
+       if(data->ahb_clk) {\r
+               clk_put(data->ahb_clk);\r
+       }\r
+\r
+    kfree(data);\r
+    return 0;\r
+}\r
+\r
+static struct platform_driver rk29_ipp_driver = {\r
+       .probe          = ipp_drv_probe,\r
+       .remove         = ipp_drv_remove,\r
+       .driver         = {\r
+               .owner  = THIS_MODULE,\r
+               .name   = "rk29-ipp",\r
+       },\r
+};\r
+\r
+static int __init rk29_ipp_init(void)\r
+{\r
+       int ret;\r
+\r
+       if ((ret = platform_driver_register(&rk29_ipp_driver)) != 0)\r
+               {\r
+                       ERR("Platform device register failed (%d).\n", ret);\r
+                       return ret;\r
+               }\r
+               INFO("Module initialized.\n");\r
+               return 0;\r
+}\r
+\r
+static void __exit rk29_ipp_exit(void)\r
+{\r
+       platform_driver_unregister(&rk29_ipp_driver);\r
+}\r
+\r
+module_init(rk29_ipp_init);\r
+module_exit(rk29_ipp_exit);\r
+\r
+/* Module information */\r
+MODULE_AUTHOR("wy@rock-chips.com");\r
+MODULE_DESCRIPTION("Driver for rk29 ipp device");\r
+MODULE_LICENSE("GPL");\r
+\r
+\r
diff --git a/drivers/staging/rk29/ipp/rk29-ipp.h b/drivers/staging/rk29/ipp/rk29-ipp.h
new file mode 100644 (file)
index 0000000..d9c5338
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _RK29_IPP_DRIVER_H_\r
+#define _RK29_IPP_DRIVER_H_\r
+\r
+/* Image data */\r
+struct rk29_ipp_image\r
+{\r
+       uint32_t        YrgbMst;        // image Y/rgb address\r
+       uint32_t    CbrMst;     // image CbCr address\r
+       uint32_t        w;      // image full width\r
+       uint32_t        h;      // image full height\r
+       uint32_t        fmt;    // color format\r
+};\r
+\r
+struct rk29_ipp_req {\r
+       struct rk29_ipp_image src0; // source0 image\r
+       struct rk29_ipp_image dst0; // destination0 image\r
+       struct rk29_ipp_image src1; // source1 image\r
+       struct rk29_ipp_image dst1; // destination1 image\r
+       uint32_t src_vir_w;\r
+       uint32_t dst_vir_w;\r
+       uint32_t timeout;\r
+       uint32_t flag; //rotate\r
+};\r
+\r
+//uint32_t format Ã¶¾ÙÀàÐÍ\r
+enum\r
+{\r
+       IPP_XRGB_8888 = 0,\r
+       IPP_RGB_565 =1 ,\r
+       IPP_Y_CBCR_H2V1 = 2,  //yuv 422sp\r
+       IPP_Y_CBCR_H2V2 = 3, //yuv 420sp\r
+       IPP_Y_CBCR_H1V1 =6, //yuv 444sp\r
+       IPP_IMGTYPE_LIMIT\r
+};\r
+\r
+typedef enum\r
+ {\r
+     IPP_ROT_90,\r
+     IPP_ROT_180,\r
+     IPP_ROT_270,\r
+     IPP_ROT_X_FLIP,\r
+     IPP_ROT_Y_FLIP,\r
+     IPP_ROT_0,\r
+     IPP_ROT_LIMIT\r
+ } ROT_DEG;\r
+\r
+ struct ipp_regs {\r
+       uint32_t ipp_config;\r
+       uint32_t ipp_src_img_info;\r
+       uint32_t ipp_dst_img_info;\r
+       uint32_t ipp_img_vir;\r
+       uint32_t ipp_int;\r
+       uint32_t ipp_src0_y_mst;\r
+       uint32_t ipp_src0_Cbr_mst;\r
+       uint32_t ipp_src1_y_mst;\r
+       uint32_t ipp_src1_Cbr_mst;\r
+       uint32_t ipp_dst0_y_mst;\r
+       uint32_t ipp_dst0_Cbr_mst;\r
+       uint32_t ipp_dst1_y_mst;\r
+       uint32_t ipp_dst1_Cbr_mst;\r
+       uint32_t ipp_pre_scl_para;\r
+       uint32_t ipp_post_scl_para;\r
+       uint32_t ipp_swap_ctrl;\r
+       uint32_t ipp_pre_img_info;\r
+       uint32_t ipp_axi_id;\r
+       uint32_t ipp_process_st;\r
+};\r
+\r
+#define IPP_CONFIG                             (0x00)\r
+#define IPP_SRC_IMG_INFO                       (0x04)\r
+#define IPP_DST_IMG_INFO                       (0x08)\r
+#define IPP_IMG_VIR                            (0x0c)\r
+#define IPP_INT                                        (0x10)\r
+#define IPP_SRC0_Y_MST                 (0x14)\r
+#define IPP_SRC0_CBR_MST                       (0x18)\r
+#define IPP_SRC1_Y_MST                 (0x1c)\r
+#define IPP_SRC1_CBR_MST                       (0x20)\r
+#define IPP_DST0_Y_MST                 (0x24)\r
+#define IPP_DST0_CBR_MST                       (0x28)\r
+#define IPP_DST1_Y_MST                 (0x2c)\r
+#define IPP_DST1_CBR_MST                       (0x30)\r
+#define IPP_PRE_SCL_PARA                       (0x34)\r
+#define IPP_POST_SCL_PARA                      (0x38)\r
+#define IPP_SWAP_CTRL                          (0x3c)\r
+#define IPP_PRE_IMG_INFO                       (0x40)\r
+#define IPP_AXI_ID                             (0x44)\r
+#define IPP_SRESET                             (0x48)\r
+#define IPP_PROCESS_ST                 (0x50)\r
+\r
+/*ipp config*/\r
+#define ROT_ENABLE                             (1<<8)\r
+#define PRE_SCALE                                      (1<<4)\r
+#define POST_SCALE                             (1<<3)\r
+\r
+\r
+#define IS_YCRCB(img) ((img == IPP_Y_CBCR_H2V1) | (img == IPP_Y_CBCR_H2V2) | \\r
+                      (img == IPP_Y_CBCR_H1V1) )\r
+#define IS_RGB(img) ((img == IPP_RGB_565) | (img == IPP_ARGB_8888) | \\r
+                    (img == IPP_XRGB_8888) ))\r
+#define HAS_ALPHA(img) (img == IPP_ARGB_8888)\r
+\r
+#endif /*_RK29_IPP_DRIVER_H_*/
\ No newline at end of file