[PATCH 1/3] ARM: S5P6440: Added PL330 support in plat-samsung for samsung S5P6440 soc.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds DMA pl330 mico code for S5P series in plat-samsung.This patch also
moves some common code from s3c2410 to plat-samsung which can also be used by pl330.

Signed-off-by: Atul Dahiya <atul.dahiya@xxxxxxxxxxx>
---
 arch/arm/mach-s3c2410/include/mach/dma.h           |   12 +-
 arch/arm/plat-samsung/Kconfig                      |    5 +
 arch/arm/plat-samsung/Makefile                     |    2 +-
 arch/arm/plat-samsung/dma-pl330-mcode.c            |  671 ++++++++++++++++++++
 arch/arm/plat-samsung/include/plat/cpu.h           |    1 +
 .../plat-samsung/include/plat/dma-pl330-mcode.h    |  103 +++
 arch/arm/plat-samsung/include/plat/dma.h           |   59 ++-
 7 files changed, 843 insertions(+), 10 deletions(-)
 create mode 100644 arch/arm/plat-samsung/dma-pl330-mcode.c
 create mode 100644 arch/arm/plat-samsung/include/plat/dma-pl330-mcode.h

diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h
index 08ac5f9..316e0cc 100644
--- a/arch/arm/mach-s3c2410/include/mach/dma.h
+++ b/arch/arm/mach-s3c2410/include/mach/dma.h
@@ -61,13 +61,13 @@ enum dma_ch {
 #endif
 
 /* types */
-
+/*
 enum s3c2410_dma_state {
 	S3C2410_DMA_IDLE,
 	S3C2410_DMA_RUNNING,
 	S3C2410_DMA_PAUSED
 };
-
+*/
 /* enum s3c2410_dma_loadst
  *
  * This represents the state of the DMA engine, wrt to the loaded / running
@@ -95,14 +95,14 @@ enum s3c2410_dma_state {
  * There is a buffer waiting to be loaded by the DMA engine, and one
  * currently running.
 */
-
+/*
 enum s3c2410_dma_loadst {
 	S3C2410_DMALOAD_NONE,
 	S3C2410_DMALOAD_1LOADED,
 	S3C2410_DMALOAD_1RUNNING,
 	S3C2410_DMALOAD_1LOADED_1RUNNING,
 };
-
+*/
 
 /* flags */
 
@@ -132,7 +132,7 @@ struct s3c2410_dma_buf {
 };
 
 /* [1] is this updated for both recv/send modes? */
-
+/*
 struct s3c2410_dma_stats {
 	unsigned long		loads;
 	unsigned long		timeout_longest;
@@ -140,7 +140,7 @@ struct s3c2410_dma_stats {
 	unsigned long		timeout_avg;
 	unsigned long		timeout_failed;
 };
-
+*/
 struct s3c2410_dma_map;
 
 /* struct s3c2410_dma_chan
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index d552c65..39b42eb 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -69,6 +69,11 @@ config SAMSUNG_IRQ_UART
        help
          Internal configuration to build the IRQ UART demux code.
 
+config SAMSUNG_PL_330
+	bool
+	help
+	Select pl-330 code for all SAMSUNG S5P SOCs.
+
 # options for gpio configuration support
 
 config SAMSUNG_GPIOLIB_4BIT
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 22c89d0..32c57b0 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -44,7 +44,7 @@ obj-$(CONFIG_S3C_DEV_NAND)	+= dev-nand.o
 # DMA support
 
 obj-$(CONFIG_S3C_DMA)		+= dma.o
-
+obj-$(CONFIG_SAMSUNG_PL_330)	+= dma-pl330-mcode.o
 # PM support
 
 obj-$(CONFIG_PM)		+= pm.o
diff --git a/arch/arm/plat-samsung/dma-pl330-mcode.c b/arch/arm/plat-samsung/dma-pl330-mcode.c
new file mode 100644
index 0000000..ec6e8e7
--- /dev/null
+++ b/arch/arm/plat-samsung/dma-pl330-mcode.c
@@ -0,0 +1,671 @@
+/* linux/arch/arm/plat-s5p/dma-pl330-mcode.c
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ * 		http://www.samsung.com/
+ *
+ * DMA PL330 microcode
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/io.h>
+#include "plat/dma-pl330-mcode.h"
+
+/* DMAMOV CCR, ...  */
+int encode_dma_move_ch_ctrl(u8 *mcode_ptr, u32 dmacon)
+{
+	writeb(DMAMOV, mcode_ptr++);
+	writeb(0x1, mcode_ptr++);
+	writel(dmacon, mcode_ptr);
+	return 6;
+}
+
+/* DMAMOV SAR, uStAddr
+ * DMAMOV DAR, uStAddr
+ * DMAMOV CCR,  */
+int encode_dma_move(u8 *mcode_ptr, u8 uDir, u32 uStAddr)
+{
+	writeb(DMAMOV, mcode_ptr++);
+	writeb(uDir, mcode_ptr++);
+	writel(uStAddr, mcode_ptr);
+	return 6;
+}
+
+/* DMALD */
+int encode_dma_load(u8 *mcode_ptr)
+{
+	writeb(DMALD, mcode_ptr);
+	return 1;
+
+}
+
+/* DMALDS */
+int encode_dma_load_s(u8 *mcode_ptr)
+{
+	writeb(DMALDS, mcode_ptr);
+	return 1;
+
+}
+
+/* DMALDB  */
+int encode_dma_load_b(u8 *mcode_ptr)
+{
+	 writeb(DMALDB, mcode_ptr);
+	return 1;
+
+}
+
+/* DMALDPS, DMALDPB (Load Peripheral)  */
+int encode_dma_load_peri(u8 *mcode_ptr, u8 mPeriNum, u8 m_uBurstSz)
+{
+	u8 bs;
+	if (mPeriNum > PL330_MAX_PERIPHERAL_NUM) {
+		print_warning("[%s] The peripheral number is"
+				"too big ! : %d\n", __func__, mPeriNum);
+		return 0;
+	}
+	bs = (m_uBurstSz == 1) ? 0 : 1; /* single -> 0, burst -> 1 */
+	writeb((DMALDPS|(bs<<1)), mcode_ptr++);
+	writeb(mPeriNum << 3, mcode_ptr);
+
+	return 2;
+}
+
+/* DMAST  */
+static int encode_dma_store(u8 *mcode_ptr)
+{
+	u8 opcode = DMAST;
+	writeb(opcode, mcode_ptr);
+	return 1;
+}
+
+/* DMASTS */
+static int encode_dma_store_single(u8 *mcode_ptr)
+{
+	u8 opcode = DMASTS;
+	writeb(opcode, mcode_ptr);
+	return 1;
+}
+
+/*DMASTB  */
+static int encode_dma_store_brust(u8 *mcode_ptr)
+{
+	u8 opcode = DMASTB;
+	writeb(opcode, mcode_ptr);
+	return 1;
+}
+
+/* DMASTPS, DMASTPB (Store and notify Peripheral)  */
+int encode_dma_store_peri(u8 *mcode_ptr, u8 mPeriNum, u8 m_uBurstSz)
+{
+	u8 bs;
+	if (mPeriNum > PL330_MAX_PERIPHERAL_NUM) {
+		print_warning("[%s] The peripheral number is too"
+					"big ! : %d\n", __func__, mPeriNum);
+		return 0;
+	}
+	bs = (m_uBurstSz == 1) ? 0 : 1; /* single:0, burst:1 */
+	writeb((DMASTPS|(bs<<1)), mcode_ptr++);
+	writeb(mPeriNum << 3, mcode_ptr);
+	return 2;
+}
+
+/* DMASTZ  */
+int encode_dma_store_zero(u8 *mcode_ptr)
+{
+	writeb(DMASTZ , mcode_ptr);
+	return 1;
+}
+
+/* DMALP  */
+static int encode_dma_loop(u8 *mcode_ptr, u8 uLoopCnt, u8 uIteration)
+{
+	u8 opcode = DMALP | (uLoopCnt << 1);
+	writeb(opcode, mcode_ptr++);
+	writeb(uIteration, mcode_ptr);
+	return 2;
+}
+
+/* DMALPFE  */
+static int encode_dma_loop_forever(u8 *mcode_ptr, u8 uBwJump)
+{
+	writeb(DMALPFE, mcode_ptr++);
+	writeb(uBwJump, mcode_ptr);
+	return 2;
+}
+
+/* DMALPEND */
+static int encode_dma_loop_end(u8 *mcode_ptr, u8 uLoopCnt, u8 uBwJump)
+{
+	u8 opcode = DMALPEND | (uLoopCnt << 2);
+	writeb(opcode, mcode_ptr++);
+	writeb(uBwJump, mcode_ptr);
+	return 2;
+}
+
+/* DMALPENDS */
+static int encode_dma_loop_ends(u8 *mcode_ptr, u8 uLoopCnt, u8 uBwJump)
+{
+	u8 opcode = DMALPENDS | (uLoopCnt << 2);
+	writeb(opcode, mcode_ptr++);
+	writeb(uBwJump, mcode_ptr);
+	return 2;
+}
+
+/* DMALPENDB  */
+static int encode_dma_loop_endb(u8 *mcode_ptr, u8 uLoopCnt, u8 uBwJump)
+{
+	u8 opcode = DMALPENDB | (uLoopCnt << 2);
+	writeb(opcode, mcode_ptr++);
+	writeb(uBwJump, mcode_ptr);
+	return 2;
+}
+
+/*  DMAWFPS (Wait For Peripheral) */
+static int encode_dma_wait_for_peri(u8 *mcode_ptr, u8 mPeriNum)
+{
+	u8 opcode = DMAWFPS;
+	writeb(opcode, mcode_ptr++);
+	writeb(mPeriNum << 3, mcode_ptr);
+	return 2;
+}
+
+/*  DMAWFPB (Wait For Peripheral)
+static int encode_dma_wait_for_peri(u8 *mcode_ptr, u8 mPeriNum)
+{
+	u8 opcode = DMAWFPB;
+	writeb(opcode, mcode_ptr++);
+	writeb(mPeriNum << 3, mcode_ptr);
+	return 2;
+}
+
+/  DMAWFP (Wait For Peripheral) /
+static int encode_dma_wait_for_peri(u8 *mcode_ptr, u8 mPeriNum)
+{
+	u8 opcode = DMAWFP;
+	writeb(opcode, mcode_ptr++);
+	writeb(mPeriNum << 3, mcode_ptr);
+	return 2;
+}
+
+  DMAFLUSHP (Flush and notify Peripheral) */
+static int encode_dma_flush_peri(u8 *mcode_ptr, u8 mPeriNum)
+{
+	u8 opcode = DMAFLUSHP;
+	writeb(opcode, mcode_ptr++);
+	writeb(mPeriNum << 3, mcode_ptr);
+	return 2;
+}
+
+/* DMAEND */
+static int encode_dma_end(u8 *mcode_ptr)
+{
+	u8 opcode = DMAEND;
+	writeb(opcode, mcode_ptr);
+	return 1;
+}
+
+/* DMARMB (Read Memory Barrier) */
+static int encode_dma_read_mem_barrier(u8 *mcode_ptr)
+{
+	u8 opcode = DMARMB;
+	writeb(opcode, mcode_ptr);
+	return 1;
+}
+
+/* DMASEV (Send Event) : 0 ~ 31 */
+static int encode_dma_send_event(u8 *mcode_ptr, u8 uEventNum)
+{
+	u8 opcode = DMASEV;
+	writeb(opcode, mcode_ptr++);
+	writeb(uEventNum << 3, mcode_ptr);
+	return 2;
+}
+
+/* DMAGO over DBGINST[0:1] registers */
+static void encode_dma_go_over_dbginst(u32 *mcode_ptr, u8 chanNum,
+					u32 mbufAddr, u8 m_secureBit)
+{
+	u32 x;
+	u8 uDmaGo;		/* DMAGO instruction */
+	if (chanNum > PL330_MAX_CHANNEL_NUM) {
+		print_warning("[%s] Channel num big: %d\n", __func__, chanNum);
+		return;
+	}
+	do {
+		x = Inp32(mcode_ptr+DMA_DBGSTATUS);
+	} while ((x&0x1) == 0x1);
+	uDmaGo = (m_secureBit == 0) ?
+		(0xa0|(0<<1)) : 	/* secure mode : M2M DMA only   */
+		(0xa0|(1<<1));  	/* non-secure mode : M2P/P2M DMA only */
+	Outp32(mcode_ptr+DMA_DBGINST0,
+		(chanNum<<24)|(uDmaGo<<16)|(chanNum<<8)|(0<<0));
+	Outp32(mcode_ptr+DMA_DBGINST1, mbufAddr);
+	Outp32(mcode_ptr+DMA_DBGCMD, 0);
+
+}
+
+/* DMAKILL over DBGINST[0:1] registers - Stop a DMA channel */
+static void encode_dma_kill_channel_over_dbginst(u32 *mcode_ptr, u8 chanNum)
+{
+	u32 x;
+	if (chanNum > PL330_MAX_CHANNEL_NUM) {
+		print_warning("[%s] Channel num big: %d\n", __func__, chanNum);
+		return;
+	}
+	do {
+		x = Inp32(mcode_ptr+DMA_DBGSTATUS);
+	} while ((x&0x1) == 0x1);
+	Outp32(mcode_ptr+DMA_DBGINST0, (0<<24)|(1<<16)|(chanNum<<8)|(1<<0));
+	Outp32(mcode_ptr+DMA_DBGINST1, 0);
+	Outp32(mcode_ptr+DMA_DBGCMD, 0);
+	do {
+		x = Inp32(mcode_ptr+DMA_DBGSTATUS);
+	} while ((x&0x1) == 0x1);
+}
+
+/* DMAKILL over DBGINST[0:1] registers - Stop a DMA controlle*/
+static void encode_dma_kill_dmac_over_dbginst(u32 *mcode_ptr)
+{
+	u32 x;
+	do {
+		x = Inp32(mcode_ptr+DMA_DBGSTATUS);
+	} while ((x&0x1) == 0x1);
+
+	Outp32(mcode_ptr+DMA_DBGINST0, (0<<24)|(1<<16)|(0<<8)|(0<<0));
+	Outp32(mcode_ptr+DMA_DBGINST1, 0);
+	Outp32(mcode_ptr+DMA_DBGCMD, 0); 	/* 0 : execute the instruction*/
+
+	do {
+		x = Inp32(mcode_ptr+DMA_DBGSTATUS);
+	} while ((x&0x1) == 0x1);
+}
+
+/* config_dma_start_address
+ * - set the DMA start address
+ *
+ *	mcode_ptr	the pointer to the buffer for PL330 DMAMOVE micro code
+ *			to be stored into
+ *	uStAddr		the DMA start address
+ */
+static int config_dma_start_address(u8 *mcode_ptr, int uStAddr)
+{
+	return encode_dma_move(mcode_ptr, 0, (u32)uStAddr);
+}
+
+/* config_dma_destination_address
+ * - set the DMA destination address
+ *	mcode_ptr	the pointer to the buffer for PL330 DMAMOVE micro
+ *			code to be stored into
+ *	uStAddr		the DMA destination address
+ */
+static int config_dma_destination_address(u8 *mcode_ptr, int uStAddr)
+{
+	return encode_dma_move(mcode_ptr, 2, (u32)uStAddr);
+}
+
+/* config_dma_control
+ * - set the burst length, burst size, source and destination increment/fixed
+ *   field
+ *	mcode_ptr	the pointer to the buffer for PL330 DMAMOVE micro
+ *			code to be stored into
+ *	dmacon		the value for the DMA channel control register
+ */
+static int config_dma_control(u8 *mcode_ptr,  struct DMA_control dmacon)
+{
+	return encode_dma_move(mcode_ptr, 1, *(u32 *)&dmacon);
+}
+
+/* config_dma_transfer_remainder
+ * - set the transfer size of the remainder
+ *	mcode_ptr	the pointer to the buffer for PL330 DMADMA micro code
+ *			to be stored into
+ *	lcRemainder	the remainder except for the LC-aligned transfers
+ *	dma_param	the parameter set for a DMA operation
+ */
+static int config_dma_transfer_remainder(u8 *mcode_ptr, int lcRemainder,
+					struct DMA_parameters dma_param)
+{
+	int mcode_size = 0, msize = 0;
+	int lc0 = 0, lcSize = 0, mLoopStart0 = 0, dmaSent = 0;
+	dmaSent = dma_param.mTrSize - lcRemainder;
+	msize = config_dma_start_address(mcode_ptr+mcode_size,
+					dma_param.mSrcAddr+dmaSent);
+	mcode_size += msize;
+	msize = config_dma_destination_address(mcode_ptr+mcode_size,
+					dma_param.mDstAddr+dmaSent);
+	mcode_size += msize;
+	dma_param.mControl.uSBSize = 0x2;	/* 4 bytes    */
+	dma_param.mControl.uSBLength = 0x0;	/* 1 transfer */
+	dma_param.mControl.uDBSize = 0x2;	/* 4 bytes    */
+	dma_param.mControl.uDBLength = 0x0;	/* 1 transfer */
+	msize = config_dma_control(mcode_ptr+mcode_size,
+					dma_param.mControl);
+	mcode_size += msize;
+	lcSize = (dma_param.mControl.uSBLength+1)*
+			(1<<dma_param.mControl.uSBSize);
+	lc0 = lcRemainder/lcSize;
+	msize = encode_dma_loop(mcode_ptr+mcode_size, 0, lc0-1);
+	mcode_size += msize;
+	mLoopStart0 = mcode_size;
+	switch (dma_param.mDirection) {
+	case PL330_M2M_DMA:
+		msize = encode_dma_load(mcode_ptr+mcode_size);
+		mcode_size += msize;
+		msize = encode_dma_store(mcode_ptr+mcode_size);
+		mcode_size += msize;
+		break;
+	case PL330_M2P_DMA:
+		msize = encode_dma_wait_for_peri(mcode_ptr+mcode_size,
+						(u8)dma_param.mPeriNum);
+		mcode_size += msize;
+		msize = encode_dma_load(mcode_ptr+mcode_size);
+		mcode_size += msize;
+		msize = encode_dma_store_peri(mcode_ptr+mcode_size,
+					(u8)dma_param.mPeriNum, 1);
+		mcode_size += msize;
+		msize = encode_dma_flush_peri(mcode_ptr+mcode_size,
+						(u8)dma_param.mPeriNum);
+		mcode_size += msize;
+		break;
+	case PL330_P2M_DMA:
+		msize = encode_dma_wait_for_peri(mcode_ptr+mcode_size,
+						(u8)dma_param.mPeriNum);
+		mcode_size += msize;
+		msize = encode_dma_load_peri(mcode_ptr+mcode_size,
+						(u8)dma_param.mPeriNum, 1);
+		mcode_size += msize;
+		msize = encode_dma_store(mcode_ptr+mcode_size);
+		mcode_size += msize;
+		msize = encode_dma_flush_peri(mcode_ptr+mcode_size,
+					(u8)dma_param.mPeriNum);
+		mcode_size += msize;
+		break;
+	case PL330_P2P_DMA:
+		print_warning("[%s] P2P DMA selected !\n", __func__);
+		break;
+	default:
+		print_warning("[%s] Invaild DMA direction"
+					"selected !\n", __func__);
+		break;
+	}
+	msize = encode_dma_loop_end(mcode_ptr+mcode_size, 0,
+				(u8)(mcode_size-mLoopStart0));
+	mcode_size += msize;
+	return mcode_size;
+}
+
+/* config_dma_transfer_size
+ * - set the transfer size
+ *	mcode_ptr	the pointer to the buffer for PL330 DMA micro code into
+ *	dma_param	the parameter set for a DMA operation
+ */
+static int config_dma_transfer_size(u8 *mcode_ptr,
+			struct DMA_parameters dma_param)
+{
+	int mcode_size = 0, msize = 0;
+	int lc0 = 0, lc1 = 0, lcRemainder = 0, lcSize = 0;
+	int mLoopStart0 = 0, mLoopStart1 = 0;
+	switch (dma_param.mDirection) {
+	case PL330_M2M_DMA:
+		if (dma_param.mTrSize > (8*1024*1024)) {
+			print_warning("[%s] The chunk size is too big"
+					"%lu\n", __func__, dma_param.mTrSize);
+			return 0;
+		}
+		break;
+	case PL330_M2P_DMA:
+	case PL330_P2M_DMA:
+		if (dma_param.mTrSize > (2*1024*1024)) {
+			print_warning("[%s] The chunk size is too"
+				"big !: %lu\n", __func__, dma_param.mTrSize);
+			return 0;
+		}
+		break;
+	case PL330_P2P_DMA:
+		print_warning("[%s] P2P DMA selected !\n", __func__);
+		break;
+	default:
+		print_warning("[%s] Invaild DMA direction entered\n", __func__);
+		break;
+	}
+	lcSize = (dma_param.mControl.uSBLength+1)*
+			(1<<dma_param.mControl.uSBSize);
+	lc0 = dma_param.mTrSize/lcSize;
+	lcRemainder = dma_param.mTrSize - (lc0*lcSize);
+	if (lc0 > PL330_MAX_ITERATION_NUM) {
+		lc1 = lc0/PL330_MAX_ITERATION_NUM;
+		if (lc1 <= PL330_MAX_ITERATION_NUM) {
+			msize = encode_dma_loop(mcode_ptr+mcode_size, 1, lc1-1);
+			mcode_size += msize;
+			mLoopStart1 = mcode_size;
+			msize = encode_dma_loop(mcode_ptr+mcode_size, 0,
+						PL330_MAX_ITERATION_NUM-1);
+			mcode_size += msize;
+			mLoopStart0 = mcode_size;
+			switch (dma_param.mDirection) {
+			case PL330_M2M_DMA:
+				msize = encode_dma_load(mcode_ptr+mcode_size);
+				mcode_size += msize;
+				msize = encode_dma_read_mem_barrier(mcode_ptr+
+								mcode_size);
+				mcode_size += msize;
+				msize = encode_dma_store(mcode_ptr+mcode_size);
+				mcode_size += msize;
+				break;
+			case PL330_M2P_DMA:
+				msize = encode_dma_wait_for_peri(mcode_ptr +
+					mcode_size, (u8)dma_param.mPeriNum);
+				mcode_size += msize;
+				msize = encode_dma_load(mcode_ptr+mcode_size);
+				mcode_size += msize;
+				msize = encode_dma_store_peri(mcode_ptr +
+					mcode_size, (u8)dma_param.mPeriNum, 1);
+				mcode_size += msize;
+				msize = encode_dma_flush_peri(mcode_ptr +
+					mcode_size, (u8)dma_param.mPeriNum);
+				mcode_size += msize;
+				break;
+			case PL330_P2M_DMA:
+			msize = encode_dma_wait_for_peri(mcode_ptr + mcode_size,
+						(u8)dma_param.mPeriNum);
+				mcode_size += msize;
+				msize = encode_dma_load_peri(mcode_ptr +
+					mcode_size, (u8)dma_param.mPeriNum, 1);
+				mcode_size += msize;
+				msize = encode_dma_store(mcode_ptr +
+								mcode_size);
+				mcode_size += msize;
+				msize = encode_dma_flush_peri(mcode_ptr +
+					mcode_size, (u8)dma_param.mPeriNum);
+				mcode_size += msize;
+				break;
+			case PL330_P2P_DMA:
+				print_warning("[%s] P2P DMA!\n", __func__);
+				break;
+			default:
+				print_warning("[%s] Invaild DMA direction"
+						"selected !\n", __func__);
+				break;
+			}
+			msize = encode_dma_loop_end(mcode_ptr + mcode_size, 0,
+						(u8)(mcode_size-mLoopStart0));
+			mcode_size += msize;
+			msize = encode_dma_loop_end(mcode_ptr + mcode_size, 1,
+						(u8)(mcode_size-mLoopStart1));
+			mcode_size += msize;
+			lc0 = lc0 - (lc1*PL330_MAX_ITERATION_NUM);
+		} else {
+			print_warning("[%s] The transfer size is over the"
+					"limit (lc1=%d)\n", __func__, lc1);
+		}
+	}
+
+	if (lc0 > 0) {
+		msize = encode_dma_loop(mcode_ptr+mcode_size, 0, lc0-1);
+		mcode_size += msize;
+		mLoopStart0 = mcode_size;
+		switch (dma_param.mDirection) {
+		case PL330_M2M_DMA:
+			msize = encode_dma_load(mcode_ptr + mcode_size);
+			mcode_size += msize;
+			msize = encode_dma_store(mcode_ptr + mcode_size);
+			mcode_size += msize;
+			break;
+		case PL330_M2P_DMA:
+			msize = encode_dma_wait_for_peri(mcode_ptr + mcode_size,
+							(u8)dma_param.mPeriNum);
+			mcode_size += msize;
+			msize = encode_dma_load(mcode_ptr + mcode_size);
+			mcode_size += msize;
+			msize = encode_dma_store_peri(mcode_ptr + mcode_size,
+						(u8)dma_param.mPeriNum, 1);
+			mcode_size += msize;
+			msize = encode_dma_flush_peri(mcode_ptr+mcode_size,
+						(u8)dma_param.mPeriNum);
+			mcode_size += msize;
+			break;
+		case PL330_P2M_DMA:
+			msize = encode_dma_wait_for_peri(mcode_ptr + mcode_size,
+							(u8)dma_param.mPeriNum);
+			mcode_size += msize;
+			msize = encode_dma_load_peri(mcode_ptr + mcode_size,
+						(u8)dma_param.mPeriNum, 1);
+			mcode_size += msize;
+			msize = encode_dma_store(mcode_ptr+mcode_size);
+			mcode_size += msize;
+			msize = encode_dma_flush_peri(mcode_ptr+mcode_size,
+						(u8)dma_param.mPeriNum);
+			mcode_size += msize;
+			break;
+		case PL330_P2P_DMA:
+			print_warning("[%s] P2P DMA selected !\n", __func__);
+			break;
+		default:
+			break;
+		}
+		msize = encode_dma_loop_end(mcode_ptr+mcode_size, 0,
+					(u8)(mcode_size-mLoopStart0));
+		mcode_size += msize;
+	}
+	if (lcRemainder != 0) {
+		msize = config_dma_transfer_remainder(mcode_ptr+mcode_size,
+							lcRemainder, dma_param);
+		mcode_size += msize;
+	}
+	return mcode_size;
+}
+
+/* register_irq_to_dma_channel
+ * - register an event with the DMA channel
+ *	mcode_ptr	the pointer to the buffer for PL330 DMASEV micro code
+ *			to be stored into
+ *	uEventNum	the event number to be assigned to this DMA channel
+ */
+static int register_irq_to_dma_channel(u8 *mcode_ptr, int uEventNum)
+{
+	return encode_dma_send_event(mcode_ptr, (u8)uEventNum);
+}
+
+/* config_dma_set_infinite_loop
+ * - set an infinite loop
+ *	mcode_ptr	the pointer to the buffer for PL330 DMAPLPEND micro
+ *			code to be stored into
+ *	bBwJump		the relative location of the first instruction in the
+ *			the program loop
+ */
+static int config_dma_set_infinite_loop(u8 *mcode_ptr, int uBwJump)
+{
+	return encode_dma_loop_forever(mcode_ptr, (u8)uBwJump);
+}
+
+/* config_dma_mark_end
+ * - mark the end of the DMA request
+ *	mcode_ptr	the pointer to the buffer for PL330 DMAEND micro code
+ *			to be stored into
+ */
+static int config_dma_mark_end(u8 *mcode_ptr)
+{
+	return encode_dma_end(mcode_ptr);
+}
+
+/* start_dma_controller
+ * - start the DMA controller
+ */
+void start_dma_controller(u32 *mbuf)
+{
+	return;
+}
+
+/* stop_dma_controller
+ * - stop the DMA controller
+ *
+ *	mbuf	the address of the buffer for DMAKILL micro code to be stored
+ */
+void stop_dma_controller(u32 *mbuf)
+{
+	encode_dma_kill_dmac_over_dbginst(mbuf);
+}
+
+/* setup_dma_channel
+ * - set up a DMA channel for the DMA operation
+ *
+ *	mbuf		the address of the buffer that will contain PL330
+ *			D MA micro codes
+ *	dma_param	the parameter set for a DMA operation
+ *	chanNum		the DMA channel number to be started
+ */
+int setup_dma_channel(u8 *mbuf, struct DMA_parameters dma_param, int chanNum)
+{
+	int mcode_size = 0, msize = 0;
+	msize = config_dma_start_address(mbuf, dma_param.mSrcAddr);
+	mcode_size += msize;
+	msize = config_dma_destination_address(mbuf + mcode_size,
+						dma_param.mDstAddr);
+	mcode_size += msize;
+	msize = config_dma_control(mbuf+mcode_size, dma_param.mControl);
+	mcode_size += msize;
+	msize = config_dma_transfer_size(mbuf+mcode_size, dma_param);
+	mcode_size += msize;
+	if (dma_param.mIrqEnable) {
+		msize = register_irq_to_dma_channel(mbuf+mcode_size, chanNum);
+		mcode_size += msize;
+	}
+	if (dma_param.mLoop) {
+		msize = config_dma_set_infinite_loop(mbuf+mcode_size,
+					dma_param.mBwJump+mcode_size);
+		mcode_size += msize;
+	}
+	if (dma_param.mLastReq) {
+		msize = config_dma_mark_end(mbuf+mcode_size);
+		mcode_size += msize;
+	}
+	return mcode_size;
+}
+
+/* start_dma_channel
+ * - get the DMA channel started
+ * mbuf		the address of the buffer for DMAGO micro
+ *		code to be stored at
+ * chanNum	the DMA channel number to be started
+ * mbufAddr	the start address of the buffer containing
+ *		PL330 DMA micro codes
+*/
+void start_dma_channel(u32 *mbuf, int chanNum, u32 mbufAddr, int secureMode)
+{
+	encode_dma_go_over_dbginst(mbuf, (u8)chanNum, mbufAddr,
+							(u8)secureMode);
+}
+
+/* stop_dma_channel
+ * - get the DMA channel stopped
+ * mbuf		the address of the buffer for DMAKILL micro code to be stored
+ * chanNum 	the DMA channel number to be stopped
+*/
+
+void stop_dma_channel(u32 *mbuf, int chanNum)
+{
+	 encode_dma_kill_channel_over_dbginst(mbuf, (u8)chanNum);
+
+}
diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index d316b4a..1f8af60 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -78,6 +78,7 @@ extern struct sysdev_class s3c2442_sysclass;
 extern struct sysdev_class s3c2443_sysclass;
 extern struct sysdev_class s3c6410_sysclass;
 extern struct sysdev_class s3c64xx_sysclass;
+extern struct sysdev_class s5p6440_sysclass;
 
 extern void (*s5pc1xx_idle)(void);
 
diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330-mcode.h b/arch/arm/plat-samsung/include/plat/dma-pl330-mcode.h
new file mode 100644
index 0000000..1b21477
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/dma-pl330-mcode.h
@@ -0,0 +1,103 @@
+/* linux/arch/arm/plat-s5p/dma-pl330-mcode.h
+ *
+ *  Copyright (c) 2010 Samsung Electronics
+ *             http://www.samsung.com/
+ *
+ * DMA PL330 microcode
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARM_PLAT_DMA_PL330_MCODE_H
+#define __ARM_PLAT_DMA_PL330_MCODE_H __FILE__
+
+#include <linux/sysdev.h>
+
+#define print_warning(fmt...)		printk(fmt)
+
+#define PL330_P2M_DMA			0
+#define PL330_M2P_DMA			1
+#define PL330_M2M_DMA			2
+#define PL330_P2P_DMA			3
+
+#define	PL330_MAX_ITERATION_NUM		256
+#define	PL330_MAX_JUMPBACK_NUM		256
+#define	PL330_MAX_EVENT_NUM		32
+#define	PL330_MAX_PERIPHERAL_NUM	32
+#define	PL330_MAX_CHANNEL_NUM		8
+
+#define DMA_DBGSTATUS			0x0
+#define DMA_DBGCMD			0x1
+#define DMA_DBGINST0			0x2
+#define DMA_DBGINST1			0x3
+
+#define DMAMOV 		(0xbc)
+#define DMALD 		(0x04)
+#define DMALDS 		(0x05)
+#define DMALDB 		(0x07)
+#define DMALDPS 	(0x25)
+#define DMAST 		(0x08)
+#define DMASTS 		(0x09)
+#define DMASTB 		(0x0b)
+#define DMASTPS 	(0x29)
+#define DMASTZ 		(0x0c)
+#define DMALP 		(0x20)
+#define DMALPFE 	(0x28)
+#define DMALPEND 	(0x38)
+#define DMALPENDS 	(0x39)
+#define DMALPENDB 	(0x3b)
+#define DMAWFPS 	(0x30)
+#define DMAWFPB 	(0x32)
+#define DMAWFP 		(0x31)
+#define DMAFLUSHP 	(0x35)
+#define DMAEND 		(0x00)
+#define DMARMB 		(0x12)
+#define DMASEV 		(0x34)
+
+#define Outp32(addr, data)		(*(u32 *)(addr) = (data))
+#define Inp32(addr)			(*(u32 *)(addr))
+
+/* Parameter set for Channel Control Register */
+struct DMA_control{
+	unsigned 	uSI;/* [0] Transfer size not count*/
+	unsigned 	uSBSize;/* [3:1] Source 1 transfer size*/
+	unsigned 	uSBLength;/* [7:4] Sourse burst len*/
+	unsigned 	uSProt;/* [10:8] Source Protection set 101b=5*/
+	unsigned 	uSCache;/* [13:11] Source Cache control*/
+	unsigned 	uDI;/* [14] Destination increment*/
+	unsigned 	uDBSize;/* [17:15] Destination 1 transfer size*/
+	unsigned 	uDBLength;/* [21:18] Destination burst len*/
+	unsigned	 uDProt;/* [24:22] Source Protection set 101b=5*/
+	unsigned 	uDCache;/* [27:25] Source Cache control*/
+	unsigned 	uESSize;/* [31:28] endian_swap_size	*/
+};
+
+/* Parameter list for a DMA operation */
+struct DMA_parameters{
+	unsigned long		mDirection;/* DMA direction */
+	unsigned long		mPeriNum;/* DMA Peripheral number */
+	unsigned long		mSrcAddr;/* DMA source address */
+	unsigned long		mDstAddr;/* DMA destination address */
+	unsigned long		mTrSize;/* DMA Transfer size */
+	struct DMA_control	mControl;
+	unsigned long		mIrqEnable;/* DMA Send IRQ */
+	unsigned long		mLoop;	/* DMA Infinite Loop - 0(off) */
+	unsigned long		mBwJump;/* DMA backward relative offset */
+	unsigned long		mLastReq;/* The last DMA Req.  */
+};
+
+extern void start_dma_controller(u32 *mbuf);
+
+extern void stop_dma_controller(u32 *mbuf);
+
+extern int setup_dma_channel(u8 *mbuf,
+		struct DMA_parameters dma_param, int chanNum);
+
+extern void start_dma_channel(u32 *mbuf, int chanNum,
+					u32 mbufAddr, int secureMode);
+
+extern void stop_dma_channel(u32 *mbuf, int chanNum);
+
+#endif
diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h
index 7584d75..a71897d 100644
--- a/arch/arm/plat-samsung/include/plat/dma.h
+++ b/arch/arm/plat-samsung/include/plat/dma.h
@@ -10,6 +10,61 @@
  * published by the Free Software Foundation.
 */
 
+
+/* types */
+#ifndef __ARM_PLAT_SAMSUNG_DMA_H
+#define __ARM_PLAT_SAMSUNG_DMA_H
+
+enum s3c2410_dma_state {
+	S3C2410_DMA_IDLE,
+	S3C2410_DMA_RUNNING,
+	S3C2410_DMA_PAUSED
+};
+
+/* enum s3c2410_dma_loadst
+ *
+ * This represents the state of the DMA engine, wrt to the loaded / running
+ * transfers. Since we don't have any way of knowing exactly the state of
+ * the DMA transfers, we need to know the state to make decisions on wether
+ * we can
+ *
+ * S3C2410_DMA_NONE
+ *
+ * There are no buffers loaded (the channel should be inactive)
+ *
+ * S3C2410_DMA_1LOADED
+ *
+ * There is one buffer loaded, however it has not been confirmed to be
+ * loaded by the DMA engine. This may be because the channel is not
+ * yet running, or the DMA driver decided that it was too costly to
+ * sit and wait for it to happen.
+ *
+ * S3C2410_DMA_1RUNNING
+ *
+ * The buffer has been confirmed running, and not finisged
+ *
+ * S3C2410_DMA_1LOADED_1RUNNING
+ *
+ * There is a buffer waiting to be loaded by the DMA engine, and one
+ * currently running.
+*/
+
+
+enum s3c2410_dma_loadst {
+	S3C2410_DMALOAD_NONE,
+	S3C2410_DMALOAD_1LOADED,
+	S3C2410_DMALOAD_1RUNNING,
+	S3C2410_DMALOAD_1LOADED_1RUNNING,
+};
+
+struct s3c2410_dma_stats {
+	unsigned long		loads;
+	unsigned long		timeout_longest;
+	unsigned long		timeout_shortest;
+	unsigned long		timeout_avg;
+	unsigned long		timeout_failed;
+};
+
 enum s3c2410_dma_buffresult {
 	S3C2410_RES_OK,
 	S3C2410_RES_ERR,
@@ -56,7 +111,6 @@ typedef int  (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
 				   enum s3c2410_chan_op );
 
 
-
 /* s3c2410_dma_request
  *
  * request a dma channel exclusivley
@@ -120,8 +174,7 @@ extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
 
 extern int s3c2410_dma_getposition(unsigned int channel,
 				   dma_addr_t *src, dma_addr_t *dest);
-
 extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
 extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
 
-
+#endif
-- 
1.6.6

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux SoC Development]     [Linux Rockchip Development]     [Linux USB Development]     [Video for Linux]     [Linux Audio Users]     [Linux SCSI]     [Yosemite News]

  Powered by Linux