From 1dcced23a5ed21220d42540a1e897db61cda66ba Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Mon, 10 Feb 2014 11:14:48 +0800 Subject: [PATCH] dma pl330: add device tree mode support, memcpy function ok, but clock is not used now. --- arch/arm/boot/dts/rk3188.dtsi | 28 +++ arch/arm/configs/rockchip_defconfig | 3 + arch/arm/mach-rockchip/Kconfig | 9 + arch/arm/mach-rockchip/Makefile | 1 + arch/arm/mach-rockchip/dma_memcpy_test.c | 277 +++++++++++++++++++++++ drivers/amba/bus.c | 14 +- drivers/dma/pl330.c | 20 +- 7 files changed, 340 insertions(+), 12 deletions(-) mode change 100755 => 100644 arch/arm/boot/dts/rk3188.dtsi create mode 100644 arch/arm/mach-rockchip/dma_memcpy_test.c diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi old mode 100755 new mode 100644 index 7ea34b9af08a..1fcd4300a4c8 --- a/arch/arm/boot/dts/rk3188.dtsi +++ b/arch/arm/boot/dts/rk3188.dtsi @@ -200,6 +200,34 @@ 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 = , + ; + #dma-cells = <1>; + #dma-channels = <9>; + #dma-requests = <10>; + }; + + pdma1: pdma@20078000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x20078000 0x4000>; + interrupts = , + ; + #dma-cells = <1>; + #dma-channels = <7>; + #dma-requests = <14>; + }; + }; + uart0: serial@10124000 { compatible = "rockchip,serial"; reg = <0x10124000 0x100>; diff --git a/arch/arm/configs/rockchip_defconfig b/arch/arm/configs/rockchip_defconfig index b623cdd23bc6..413d06ad502f 100644 --- a/arch/arm/configs/rockchip_defconfig +++ b/arch/arm/configs/rockchip_defconfig @@ -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 diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index 51518a24b95a..ed5afe409beb 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -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 diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile index e0eb29e72cd9..46d03c096e3f 100644 --- a/arch/arm/mach-rockchip/Makefile +++ b/arch/arm/mach-rockchip/Makefile @@ -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 index 000000000000..0bb48fce1dd1 --- /dev/null +++ b/arch/arm/mach-rockchip/dma_memcpy_test.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 "); +MODULE_AUTHOR("Hong Huibin"); diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index cdbad3a454a0..54ef6951d946 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -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; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 4c2f465be339..1244c8f780b3 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -27,6 +27,7 @@ #include #include #include +#include #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, -- 2.34.1