dma pl330: add device tree mode support, memcpy function ok,
author宋秀杰 <sxj@rock-chips.com>
Mon, 10 Feb 2014 03:14:48 +0000 (11:14 +0800)
committer宋秀杰 <sxj@rock-chips.com>
Mon, 10 Feb 2014 03:21:00 +0000 (11:21 +0800)
but clock is not used now.

arch/arm/boot/dts/rk3188.dtsi [changed mode: 0755->0644]
arch/arm/configs/rockchip_defconfig
arch/arm/mach-rockchip/Kconfig
arch/arm/mach-rockchip/Makefile
arch/arm/mach-rockchip/dma_memcpy_test.c [new file with mode: 0644]
drivers/amba/bus.c
drivers/dma/pl330.c

old mode 100755 (executable)
new mode 100644 (file)
index 7ea34b9..1fcd430
                rockchip,clocksource = <1>;
        };
 
+    amba {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "arm,amba-bus";
+               interrupt-parent = <&gic>;
+               ranges;
+
+        pdma0: pdma@20018000 {
+            compatible = "arm,pl330", "arm,primecell";
+            reg = <0x20018000 0x4000>;
+            interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+            #dma-cells = <1>;
+                       #dma-channels = <9>;
+                       #dma-requests = <10>;
+        };
+
+        pdma1: pdma@20078000 {
+            compatible = "arm,pl330", "arm,primecell";
+            reg = <0x20078000 0x4000>;
+            interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+            #dma-cells = <1>;
+                       #dma-channels = <7>;
+                       #dma-requests = <14>;
+        };
+    };
+
        uart0: serial@10124000 {
                compatible = "rockchip,serial";
                reg = <0x10124000 0x100>;
index b623cdd23bc6c631f707b56a4806b1c4e66a8fb2..413d06ad502f9ff06d1e245d7a78cf86fe44e85d 100644 (file)
@@ -32,6 +32,7 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_ROCKCHIP=y
+CONFIG_RK_PL330_DMA_TEST=y
 # CONFIG_SWP_EMULATE is not set
 CONFIG_ARM_ERRATA_720789=y
 CONFIG_PL310_ERRATA_753970=y
@@ -409,6 +410,8 @@ CONFIG_SWITCH=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_PCF8563=y
 CONFIG_RK808_RTC=y
+CONFIG_DMADEVICES=y
+CONFIG_PL330_DMA=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
index 51518a24b95ae27e7060ec198efb1288cfcd7ea5..ed5afe409beb2496843624c528f6b22fbe7b0aa1 100644 (file)
@@ -16,6 +16,11 @@ config ARCH_ROCKCHIP
        select CLKSRC_OF if OF
        select ARCH_HAS_CPUFREQ
        select ARCH_HAS_OPP
+       select ARM_AMBA
+    select ROCKCHIP_DEV_DMA
+       help
+         Support for Rockchip's Cortex-A9 Single-to-Quad-Core-SoCs
+         containing the RK2928, RK30xx and RK31xx series.
 
 if ARCH_ROCKCHIP
 
@@ -33,4 +38,8 @@ config DVFS
        default y
        select PM_OPP
        select CPU_FREQ
+
+config RK_PL330_DMA_TEST
+       bool "pl330 DMA memcpy test"
+       depends on PL330_DMA
 endif
index e0eb29e72cd9ddee7ab3667445aff99e1a1b7e4e..46d03c096e3fa3c0cb0a8005ec338d0549f5037c 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_SMP) += platsmp.o
 obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o
 obj-$(CONFIG_CPU_FREQ) += rk3188-cpufreq.o
 obj-$(CONFIG_DVFS) += dvfs.o
+obj-$(CONFIG_RK_PL330_DMA_TEST) += dma_memcpy_test.o
diff --git a/arch/arm/mach-rockchip/dma_memcpy_test.c b/arch/arm/mach-rockchip/dma_memcpy_test.c
new file mode 100644 (file)
index 0000000..0bb48fc
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ *
+ * arch/arm/plat-rk/dma_memcpy_test.c
+ *
+ * Copyright (C) 2012 Rochchip.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: hhb@rock-chips.com
+ * Create Date: 2012.03.26
+ * 
+ * HOW TO USE IT?
+ * enter the follow command at command line
+ * echo 1 > sys/module/dma_memcpy_test/parameters/debug   enable log output,default is enable
+ * echo 1000 > sys/module/dma_memcpy_test/parameters/interval   set dma transfer interval, default is 1000ms
+ * echo 1 > /sys/devices/platform/dma_memcpy.0/dmamemcpy  to start the dma test
+ *
+ */
+
+/*
+*              Driver Version Note
+*
+*v1.0 : 1. add dam thread number from 2 to 8;
+*              
+*              
+*/
+#define VERSION_AND_TIME  "dma_memcpy_test.c v1.0 2012-08-13"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/current.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl330.h>
+#include <linux/slab.h>
+
+
+#define DMA_TEST_BUFFER_SIZE 512
+#define DMA_THREAD  6
+
+struct Dma_MemToMem {
+       const char *name;
+       unsigned char* src;                     //virtual address
+       unsigned char* dst;
+       int MenSize;
+    dma_cap_mask_t  cap_mask;
+       struct dma_chan *dma_chan;
+       struct dma_slave_config *config;
+       struct dma_async_tx_descriptor *tx;
+};
+
+//enable log output
+static int debug = 8;
+module_param(debug,int,S_IRUGO|S_IWUSR);
+#define MEMCPY_DMA_DBG(fmt...)  {if(debug > 0) printk(fmt);}
+
+static struct Dma_MemToMem DmaMemInfo[DMA_THREAD];
+
+static void dma_memtest_transfer(struct Dma_MemToMem *DmaMemInfo)
+{
+       dma_async_tx_descriptor_init(DmaMemInfo->tx, DmaMemInfo->dma_chan);
+       
+       dma_async_memcpy_buf_to_buf(DmaMemInfo->dma_chan, DmaMemInfo->dst,
+                       DmaMemInfo->src, DMA_TEST_BUFFER_SIZE);
+
+       dma_wait_for_async_tx(DmaMemInfo->tx);
+
+       dmaengine_terminate_all(DmaMemInfo->dma_chan);
+}
+
+//int slecount = 0;
+static ssize_t memcpy_dma_read(struct device *device,struct device_attribute *attr, char *argv)
+{
+
+     return 0;
+}
+
+static ssize_t memcpy_dma_write(struct device *device, struct device_attribute *attr, const char *argv, size_t count)
+{
+    int i,j;
+    printk("memcpy_dma_write\n");
+
+       for(j = DMA_THREAD; j > 0; j--)
+       {
+        memset(DmaMemInfo[j-1].src, ((j-1)<<4|(j-1)), DMA_TEST_BUFFER_SIZE);                   
+               memset(DmaMemInfo[j-1].dst, 0x0, DMA_TEST_BUFFER_SIZE);
+       }
+
+       switch(DMA_THREAD) {            
+               case 8:                 
+                       dma_memtest_transfer(&DmaMemInfo[7]);           
+               case 7:                 
+                       dma_memtest_transfer(&DmaMemInfo[6]);   
+               case 6:                 
+                       dma_memtest_transfer(&DmaMemInfo[5]);
+               case 5:                 
+                       dma_memtest_transfer(&DmaMemInfo[4]);   
+               case 4:                 
+                       dma_memtest_transfer(&DmaMemInfo[3]);   
+               case 3:                 
+                       dma_memtest_transfer(&DmaMemInfo[2]);   
+               case 2:                 
+                       dma_memtest_transfer(&DmaMemInfo[1]);   
+               case 1:                 
+                       dma_memtest_transfer(&DmaMemInfo[0]);
+                       break;          
+               default:                        
+                       printk("%s no channel\n", __func__);                    
+               break;          
+       }
+       
+
+       for(i = 0; i < 16; i++) {       
+               for(j = DMA_THREAD; j > 0; j--)
+               {
+                       printk("src%d:%2x",j,*(DmaMemInfo[j-1].src + i*(DMA_TEST_BUFFER_SIZE/16)));                             
+                       printk(" -> dst%d:%2x\n",j,*(DmaMemInfo[j-1].dst + i*(DMA_TEST_BUFFER_SIZE/16)));       
+               }
+       }       
+
+    return count;
+}
+
+static DEVICE_ATTR(dmamemcpy,  S_IRUGO|S_IALLUGO, memcpy_dma_read, memcpy_dma_write);
+
+
+static int dma_memtest_channel_setup_and_init(struct Dma_MemToMem *DmaMemInfo, const char *name,
+               u32 direction, u32 addr_width, u32 maxburst)
+{
+       DmaMemInfo->name = name;
+       dma_cap_set(DMA_MEMCPY, DmaMemInfo->cap_mask);
+       DmaMemInfo->dma_chan = dma_request_channel(DmaMemInfo->cap_mask,NULL,NULL);
+
+       if(DmaMemInfo->dma_chan==NULL)
+       {
+               printk("request dma_chan %s fail\n",DmaMemInfo->name);
+               return -1;
+       }else
+       {
+               printk("request dma_chan %s success\n",DmaMemInfo->name);
+       }
+
+       DmaMemInfo->config = kmalloc(sizeof(struct dma_slave_config *),GFP_KERNEL);
+       DmaMemInfo->tx = kmalloc(sizeof(struct dma_async_tx_descriptor *),GFP_KERNEL);
+       if(DmaMemInfo->config == NULL)
+       {
+               printk("struct config kmalloc memory %s fail\n",DmaMemInfo->name);
+               return -1;
+       }
+       else    
+       {
+               printk("struct config kmalloc memory %s sucess\n",DmaMemInfo->name);
+       }
+       
+
+       DmaMemInfo->src = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo->config->src_addr, GFP_KERNEL); 
+       DmaMemInfo->dst = dma_alloc_coherent(NULL, DMA_TEST_BUFFER_SIZE, &DmaMemInfo->config->dst_addr, GFP_KERNEL);
+       if(DmaMemInfo->src == NULL || DmaMemInfo->dst == NULL)
+       {
+               printk("dma_alloc_coherent %s fail\n",DmaMemInfo->name);
+               return -1;
+       }
+       else                                            
+       {
+               printk("dma_alloc_coherent %s success\n",DmaMemInfo->name);
+       }
+       
+       DmaMemInfo->MenSize = DMA_TEST_BUFFER_SIZE;
+       DmaMemInfo->config->direction = direction;
+       DmaMemInfo->config->src_addr_width = addr_width;
+       DmaMemInfo->config->dst_addr_width = addr_width;
+       DmaMemInfo->config->src_maxburst = maxburst;
+       DmaMemInfo->config->dst_maxburst = maxburst;
+       
+       dmaengine_slave_config(DmaMemInfo->dma_chan,DmaMemInfo->config);
+
+       return 0;
+
+}
+
+
+static int dma_memcpy_probe(struct platform_device *pdev)
+{
+    int ret;
+
+    ret = device_create_file(&pdev->dev, &dev_attr_dmamemcpy);
+       printk(">>>>>>>>>>>>>>>>>>>>> dam_test_probe <<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+
+    switch(DMA_THREAD) {               
+               case 8:                 
+                       dma_memtest_channel_setup_and_init(&DmaMemInfo[7], "DmaMemInfo[7]",
+                DMA_MEM_TO_MEM, DMA_SLAVE_BUSWIDTH_8_BYTES, 16);                       
+               case 7:                 
+                       dma_memtest_channel_setup_and_init(&DmaMemInfo[6], "DmaMemInfo[6]",
+                DMA_MEM_TO_MEM, DMA_SLAVE_BUSWIDTH_8_BYTES, 16);       
+               case 6:                 
+                       dma_memtest_channel_setup_and_init(&DmaMemInfo[5], "DmaMemInfo[5]",
+                DMA_MEM_TO_MEM, DMA_SLAVE_BUSWIDTH_8_BYTES, 16);       
+               case 5:                 
+                       dma_memtest_channel_setup_and_init(&DmaMemInfo[4], "DmaMemInfo[4]",
+                DMA_MEM_TO_MEM, DMA_SLAVE_BUSWIDTH_8_BYTES, 16);               
+               case 4:                 
+                       dma_memtest_channel_setup_and_init(&DmaMemInfo[3], "DmaMemInfo[3]",
+                DMA_MEM_TO_MEM, DMA_SLAVE_BUSWIDTH_8_BYTES, 16);               
+               case 3:                 
+                       dma_memtest_channel_setup_and_init(&DmaMemInfo[2], "DmaMemInfo[2]",
+                DMA_MEM_TO_MEM, DMA_SLAVE_BUSWIDTH_8_BYTES, 16);       
+               case 2:                 
+                       dma_memtest_channel_setup_and_init(&DmaMemInfo[1], "DmaMemInfo[1]",
+                DMA_MEM_TO_MEM, DMA_SLAVE_BUSWIDTH_8_BYTES, 16);       
+               case 1:                 
+                       dma_memtest_channel_setup_and_init(&DmaMemInfo[0], "DmaMemInfo[0]",
+                DMA_MEM_TO_MEM, DMA_SLAVE_BUSWIDTH_8_BYTES, 16);
+                       break;          
+               default:                        
+                       printk("%s no channel\n", __func__);                    
+               break;          
+       }
+       
+       printk("dma_memcpy_probe sucess\n");
+    return 0;
+}
+
+static int dma_memcpy_remove(struct platform_device *pdev)
+{
+    device_remove_file(&pdev->dev, &dev_attr_dmamemcpy);
+
+    return 0;
+}
+
+static struct platform_driver dma_mempcy_driver = {
+        .driver = {
+                .name   = "dma_memcpy",
+                .owner  = THIS_MODULE,
+        },
+        .probe          = dma_memcpy_probe,
+        .remove         = dma_memcpy_remove,
+};
+
+struct platform_device rk29_device_dma_cpy = {
+       .name             = "dma_memcpy",
+       .id               = 0,
+
+};
+
+
+static int __init dma_test_init(void)
+{
+               platform_device_register(&rk29_device_dma_cpy);
+               return platform_driver_register(&dma_mempcy_driver);
+}
+
+static void __exit dma_test_exit(void)
+{
+               dma_release_channel(DmaMemInfo[0].dma_chan);
+               platform_driver_unregister(&dma_mempcy_driver);
+}
+
+late_initcall(dma_test_init);
+module_exit(dma_test_exit);
+
+MODULE_DESCRIPTION("RK29 PL330 Dma Test Deiver");
+MODULE_LICENSE("GPL V2");
+MODULE_AUTHOR("ZhenFu Fang <fzf@rock-chips.com>");
+MODULE_AUTHOR("Hong Huibin<hhb@rock-chips.com>");
index cdbad3a454a085a7aa17bf1ae29e4a22b73c5c37..54ef6951d946094bf9b43430274f5ad957e5aec9 100644 (file)
@@ -361,9 +361,9 @@ static int amba_probe(struct device *dev)
        int ret;
 
        do {
-               ret = amba_get_enable_pclk(pcdev);
-               if (ret)
-                       break;
+               //ret = amba_get_enable_pclk(pcdev);
+               //if (ret)
+               //      break;
 
                pm_runtime_get_noresume(dev);
                pm_runtime_set_active(dev);
@@ -377,7 +377,7 @@ static int amba_probe(struct device *dev)
                pm_runtime_set_suspended(dev);
                pm_runtime_put_noidle(dev);
 
-               amba_put_disable_pclk(pcdev);
+               //amba_put_disable_pclk(pcdev);
        } while (0);
 
        return ret;
@@ -421,6 +421,7 @@ int amba_driver_register(struct amba_driver *drv)
 {
        drv->drv.bus = &amba_bustype;
 
+
 #define SETFN(fn)      if (drv->fn) drv->drv.fn = amba_##fn
        SETFN(probe);
        SETFN(remove);
@@ -489,7 +490,8 @@ int amba_device_add(struct amba_device *dev, struct resource *parent)
                goto err_release;
        }
 
-       ret = amba_get_enable_pclk(dev);
+//     ret = amba_get_enable_pclk(dev);
+       ret = 0;
        if (ret == 0) {
                u32 pid, cid;
 
@@ -504,7 +506,7 @@ int amba_device_add(struct amba_device *dev, struct resource *parent)
                        cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
                                (i * 8);
 
-               amba_put_disable_pclk(dev);
+//             amba_put_disable_pclk(dev);
 
                if (cid == AMBA_CID)
                        dev->periphid = pid;
index 4c2f465be3399b3c2f0dba993220978b08b6694b..1244c8f780b3e22b77d4724a6f27dd636089e54f 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/of.h>
 #include <linux/of_dma.h>
 #include <linux/err.h>
+#include <asm/unaligned.h>
 
 #include "dmaengine.h"
 #define PL330_MAX_CHAN         8
@@ -655,10 +656,17 @@ static inline u32 get_id(struct pl330_info *pi, u32 off)
        void __iomem *regs = pi->base;
        u32 id = 0;
 
+#ifdef CONFIG_ARCH_ROCKCHIP
+       id |= ((readl(regs + off + 0x0) & 0xff) << 0);
+       id |= ((readl(regs + off + 0x4) & 0xff) << 8);
+       id |= ((readl(regs + off + 0x8) & 0xff) << 16);
+       id |= ((readl(regs + off + 0xc) & 0xff) << 24);
+#else
        id |= (readb(regs + off + 0x0) << 0);
        id |= (readb(regs + off + 0x4) << 8);
        id |= (readb(regs + off + 0x8) << 16);
        id |= (readb(regs + off + 0xc) << 24);
+#endif
 
        return id;
 }
@@ -676,7 +684,7 @@ static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[],
 
        buf[0] = CMD_DMAADDH;
        buf[0] |= (da << 1);
-       *((u16 *)&buf[1]) = val;
+       put_unaligned(val, (u16 *)&buf[1]);     //*((u16 *)&buf[1]) = val;
 
        PL330_DBGCMD_DUMP(SZ_DMAADDH, "\tDMAADDH %s %u\n",
                da == 1 ? "DA" : "SA", val);
@@ -830,7 +838,7 @@ static inline u32 _emit_MOV(unsigned dry_run, u8 buf[],
 
        buf[0] = CMD_DMAMOV;
        buf[1] = dst;
-       *((u32 *)&buf[2]) = val;
+       put_unaligned(val, (u32 *)&buf[2]);     //*((u32 *)&buf[2]) = val;
 
        PL330_DBGCMD_DUMP(SZ_DMAMOV, "\tDMAMOV %s 0x%x\n",
                dst == SAR ? "SAR" : (dst == DAR ? "DAR" : "CCR"), val);
@@ -1008,7 +1016,7 @@ static inline u32 _emit_GO(unsigned dry_run, u8 buf[],
 
        buf[1] = chan & 0x7;
 
-       *((u32 *)&buf[2]) = addr;
+       put_unaligned(addr, (u32 *)&buf[2]);    //*((u32 *)&buf[2]) = addr;
 
        return SZ_DMAGO;
 }
@@ -1283,7 +1291,7 @@ static inline int _ldst_devtomem(unsigned dry_run, u8 buf[],
                off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri);
                off += _emit_LDP(dry_run, &buf[off], SINGLE, pxs->r->peri);
                off += _emit_ST(dry_run, &buf[off], ALWAYS);
-               off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);
+               //off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);    //for sdmmc sdio
        }
 
        return off;
@@ -1298,7 +1306,7 @@ static inline int _ldst_memtodev(unsigned dry_run, u8 buf[],
                off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri);
                off += _emit_LD(dry_run, &buf[off], ALWAYS);
                off += _emit_STP(dry_run, &buf[off], SINGLE, pxs->r->peri);
-               off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);
+               //off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri);
        }
 
        return off;
@@ -3038,7 +3046,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        }
 
        dev_info(&adev->dev,
-               "Loaded driver for PL330 DMAC-%d\n", adev->periphid);
+               "Loaded driver for PL330 DMAC-%x\n", adev->periphid);
        dev_info(&adev->dev,
                "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n",
                pi->pcfg.data_buf_dep,