[ARM] S3C: Merge next-s3c64xx-dma2 into for-rmk-devel

Merge branch 'next-s3c64xx-dma2' into for-rmk-devel

Conflicts:

	arch/arm/plat-s3c64xx/Makefile
This commit is contained in:
Ben Dooks 2009-05-18 16:32:29 +01:00
commit bcb8a0d6f5
22 changed files with 1476 additions and 378 deletions

View file

@ -0,0 +1,138 @@
/* arch/arm/include/asm/hardware/pl080.h
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* ARM PrimeCell PL080 DMA controller
*
* 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.
*/
/* Note, there are some Samsung updates to this controller block which
* make it not entierly compatible with the PL080 specification from
* ARM. When in doubt, check the Samsung documentation first.
*
* The Samsung defines are PL080S, and add an extra controll register,
* the ability to move more than 2^11 counts of data and some extra
* OneNAND features.
*/
#define PL080_INT_STATUS (0x00)
#define PL080_TC_STATUS (0x04)
#define PL080_TC_CLEAR (0x08)
#define PL080_ERR_STATUS (0x0C)
#define PL080_ERR_CLEAR (0x10)
#define PL080_RAW_TC_STATUS (0x14)
#define PL080_RAW_ERR_STATUS (0x18)
#define PL080_EN_CHAN (0x1c)
#define PL080_SOFT_BREQ (0x20)
#define PL080_SOFT_SREQ (0x24)
#define PL080_SOFT_LBREQ (0x28)
#define PL080_SOFT_LSREQ (0x2C)
#define PL080_CONFIG (0x30)
#define PL080_CONFIG_M2_BE (1 << 2)
#define PL080_CONFIG_M1_BE (1 << 1)
#define PL080_CONFIG_ENABLE (1 << 0)
#define PL080_SYNC (0x34)
/* Per channel configuration registers */
#define PL008_Cx_STRIDE (0x20)
#define PL080_Cx_BASE(x) ((0x100 + (x * 0x20)))
#define PL080_Cx_SRC_ADDR(x) ((0x100 + (x * 0x20)))
#define PL080_Cx_DST_ADDR(x) ((0x104 + (x * 0x20)))
#define PL080_Cx_LLI(x) ((0x108 + (x * 0x20)))
#define PL080_Cx_CONTROL(x) ((0x10C + (x * 0x20)))
#define PL080_Cx_CONFIG(x) ((0x110 + (x * 0x20)))
#define PL080S_Cx_CONTROL2(x) ((0x110 + (x * 0x20)))
#define PL080S_Cx_CONFIG(x) ((0x114 + (x * 0x20)))
#define PL080_CH_SRC_ADDR (0x00)
#define PL080_CH_DST_ADDR (0x04)
#define PL080_CH_LLI (0x08)
#define PL080_CH_CONTROL (0x0C)
#define PL080_CH_CONFIG (0x10)
#define PL080S_CH_CONTROL2 (0x10)
#define PL080S_CH_CONFIG (0x14)
#define PL080_LLI_ADDR_MASK (0x3fffffff << 2)
#define PL080_LLI_ADDR_SHIFT (2)
#define PL080_LLI_LM_AHB2 (1 << 0)
#define PL080_CONTROL_TC_IRQ_EN (1 << 31)
#define PL080_CONTROL_PROT_MASK (0x7 << 28)
#define PL080_CONTROL_PROT_SHIFT (28)
#define PL080_CONTROL_PROT_SYS (1 << 28)
#define PL080_CONTROL_DST_INCR (1 << 27)
#define PL080_CONTROL_SRC_INCR (1 << 26)
#define PL080_CONTROL_DST_AHB2 (1 << 25)
#define PL080_CONTROL_SRC_AHB2 (1 << 24)
#define PL080_CONTROL_DWIDTH_MASK (0x7 << 21)
#define PL080_CONTROL_DWIDTH_SHIFT (21)
#define PL080_CONTROL_SWIDTH_MASK (0x7 << 18)
#define PL080_CONTROL_SWIDTH_SHIFT (18)
#define PL080_CONTROL_DB_SIZE_MASK (0x7 << 15)
#define PL080_CONTROL_DB_SIZE_SHIFT (15)
#define PL080_CONTROL_SB_SIZE_MASK (0x7 << 12)
#define PL080_CONTROL_SB_SIZE_SHIFT (12)
#define PL080_CONTROL_TRANSFER_SIZE_MASK (0xfff << 0)
#define PL080_CONTROL_TRANSFER_SIZE_SHIFT (0)
#define PL080_BSIZE_1 (0x0)
#define PL080_BSIZE_4 (0x1)
#define PL080_BSIZE_8 (0x2)
#define PL080_BSIZE_16 (0x3)
#define PL080_BSIZE_32 (0x4)
#define PL080_BSIZE_64 (0x5)
#define PL080_BSIZE_128 (0x6)
#define PL080_BSIZE_256 (0x7)
#define PL080_WIDTH_8BIT (0x0)
#define PL080_WIDTH_16BIT (0x1)
#define PL080_WIDTH_32BIT (0x2)
#define PL080_CONFIG_HALT (1 << 18)
#define PL080_CONFIG_ACTIVE (1 << 17) /* RO */
#define PL080_CONFIG_LOCK (1 << 16)
#define PL080_CONFIG_TC_IRQ_MASK (1 << 15)
#define PL080_CONFIG_ERR_IRQ_MASK (1 << 14)
#define PL080_CONFIG_FLOW_CONTROL_MASK (0x7 << 11)
#define PL080_CONFIG_FLOW_CONTROL_SHIFT (11)
#define PL080_CONFIG_DST_SEL_MASK (0xf << 6)
#define PL080_CONFIG_DST_SEL_SHIFT (6)
#define PL080_CONFIG_SRC_SEL_MASK (0xf << 1)
#define PL080_CONFIG_SRC_SEL_SHIFT (1)
#define PL080_CONFIG_ENABLE (1 << 0)
#define PL080_FLOW_MEM2MEM (0x0)
#define PL080_FLOW_MEM2PER (0x1)
#define PL080_FLOW_PER2MEM (0x2)
#define PL080_FLOW_SRC2DST (0x3)
#define PL080_FLOW_SRC2DST_DST (0x4)
#define PL080_FLOW_MEM2PER_PER (0x5)
#define PL080_FLOW_PER2MEM_PER (0x6)
#define PL080_FLOW_SRC2DST_SRC (0x7)
/* DMA linked list chain structure */
struct pl080_lli {
u32 src_addr;
u32 dst_addr;
u32 next_lli;
u32 control0;
};
struct pl080s_lli {
u32 src_addr;
u32 dst_addr;
u32 next_lli;
u32 control0;
u32 control1;
};

View file

@ -17,14 +17,16 @@
#include <linux/sysdev.h>
#include <linux/serial_core.h>
#include <mach/map.h>
#include <mach/dma.h>
#include <plat/cpu.h>
#include <plat/dma.h>
#include <plat/dma-plat.h>
#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
#include <plat/regs-ac97.h>
#include <plat/regs-dma.h>
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>

View file

@ -3,7 +3,7 @@
* Copyright (C) 2003,2004,2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Samsung S3C241XX DMA support
* Samsung S3C24XX DMA support
*
* 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
@ -13,8 +13,8 @@
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H __FILE__
#include <plat/dma.h>
#include <linux/sysdev.h>
#include <mach/hardware.h>
#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */
@ -55,9 +55,9 @@ enum dma_ch {
/* we have 4 dma channels */
#ifndef CONFIG_CPU_S3C2443
#define S3C2410_DMA_CHANNELS (4)
#define S3C_DMA_CHANNELS (4)
#else
#define S3C2410_DMA_CHANNELS (6)
#define S3C_DMA_CHANNELS (6)
#endif
/* types */
@ -68,7 +68,6 @@ enum s3c2410_dma_state {
S3C2410_DMA_PAUSED
};
/* enum s3c2410_dma_loadst
*
* This represents the state of the DMA engine, wrt to the loaded / running
@ -104,32 +103,6 @@ enum s3c2410_dma_loadst {
S3C2410_DMALOAD_1LOADED_1RUNNING,
};
enum s3c2410_dma_buffresult {
S3C2410_RES_OK,
S3C2410_RES_ERR,
S3C2410_RES_ABORT
};
enum s3c2410_dmasrc {
S3C2410_DMASRC_HW, /* source is memory */
S3C2410_DMASRC_MEM /* source is hardware */
};
/* enum s3c2410_chan_op
*
* operation codes passed to the DMA code by the user, and also used
* to inform the current channel owner of any changes to the system state
*/
enum s3c2410_chan_op {
S3C2410_DMAOP_START,
S3C2410_DMAOP_STOP,
S3C2410_DMAOP_PAUSE,
S3C2410_DMAOP_RESUME,
S3C2410_DMAOP_FLUSH,
S3C2410_DMAOP_TIMEOUT, /* internal signal to handler */
S3C2410_DMAOP_STARTED, /* indicate channel started */
};
/* flags */
@ -139,17 +112,14 @@ enum s3c2410_chan_op {
/* dma buffer */
struct s3c2410_dma_client {
char *name;
};
struct s3c2410_dma_buf;
/* s3c2410_dma_buf_s
/* s3c2410_dma_buf
*
* internally used buffer structure to describe a queued or running
* buffer.
*/
struct s3c2410_dma_buf;
struct s3c2410_dma_buf {
struct s3c2410_dma_buf *next;
int magic; /* magic */
@ -161,20 +131,6 @@ struct s3c2410_dma_buf {
/* [1] is this updated for both recv/send modes? */
struct s3c2410_dma_chan;
/* s3c2410_dma_cbfn_t
*
* buffer callback routine type
*/
typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
void *buf, int size,
enum s3c2410_dma_buffresult result);
typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
enum s3c2410_chan_op );
struct s3c2410_dma_stats {
unsigned long loads;
unsigned long timeout_longest;
@ -206,10 +162,10 @@ struct s3c2410_dma_chan {
/* channel configuration */
enum s3c2410_dmasrc source;
enum dma_ch req_ch;
unsigned long dev_addr;
unsigned long load_timeout;
unsigned int flags; /* channel flags */
unsigned int hw_cfg; /* last hw config */
struct s3c24xx_dma_map *map; /* channel hw maps */
@ -236,213 +192,6 @@ struct s3c2410_dma_chan {
struct sys_device dev;
};
/* the currently allocated channel information */
extern struct s3c2410_dma_chan s3c2410_chans[];
/* note, we don't really use dma_device_t at the moment */
typedef unsigned long dma_device_t;
/* functions --------------------------------------------------------------- */
/* s3c2410_dma_request
*
* request a dma channel exclusivley
*/
extern int s3c2410_dma_request(unsigned int channel,
struct s3c2410_dma_client *, void *dev);
/* s3c2410_dma_ctrl
*
* change the state of the dma channel
*/
extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
/* s3c2410_dma_setflags
*
* set the channel's flags to a given state
*/
extern int s3c2410_dma_setflags(unsigned int channel,
unsigned int flags);
/* s3c2410_dma_free
*
* free the dma channel (will also abort any outstanding operations)
*/
extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
/* s3c2410_dma_enqueue
*
* place the given buffer onto the queue of operations for the channel.
* The buffer must be allocated from dma coherent memory, or the Dcache/WB
* drained before the buffer is given to the DMA system.
*/
extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
dma_addr_t data, int size);
/* s3c2410_dma_config
*
* configure the dma channel
*/
extern int s3c2410_dma_config(unsigned int channel, int xferunit, int dcon);
/* s3c2410_dma_devconfig
*
* configure the device we're talking to
*/
extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
int hwcfg, unsigned long devaddr);
/* s3c2410_dma_getposition
*
* get the position that the dma transfer is currently at
*/
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);
/* DMA Register definitions */
#define S3C2410_DMA_DISRC (0x00)
#define S3C2410_DMA_DISRCC (0x04)
#define S3C2410_DMA_DIDST (0x08)
#define S3C2410_DMA_DIDSTC (0x0C)
#define S3C2410_DMA_DCON (0x10)
#define S3C2410_DMA_DSTAT (0x14)
#define S3C2410_DMA_DCSRC (0x18)
#define S3C2410_DMA_DCDST (0x1C)
#define S3C2410_DMA_DMASKTRIG (0x20)
#define S3C2412_DMA_DMAREQSEL (0x24)
#define S3C2443_DMA_DMAREQSEL (0x24)
#define S3C2410_DISRCC_INC (1<<0)
#define S3C2410_DISRCC_APB (1<<1)
#define S3C2410_DMASKTRIG_STOP (1<<2)
#define S3C2410_DMASKTRIG_ON (1<<1)
#define S3C2410_DMASKTRIG_SWTRIG (1<<0)
#define S3C2410_DCON_DEMAND (0<<31)
#define S3C2410_DCON_HANDSHAKE (1<<31)
#define S3C2410_DCON_SYNC_PCLK (0<<30)
#define S3C2410_DCON_SYNC_HCLK (1<<30)
#define S3C2410_DCON_INTREQ (1<<29)
#define S3C2410_DCON_CH0_XDREQ0 (0<<24)
#define S3C2410_DCON_CH0_UART0 (1<<24)
#define S3C2410_DCON_CH0_SDI (2<<24)
#define S3C2410_DCON_CH0_TIMER (3<<24)
#define S3C2410_DCON_CH0_USBEP1 (4<<24)
#define S3C2410_DCON_CH1_XDREQ1 (0<<24)
#define S3C2410_DCON_CH1_UART1 (1<<24)
#define S3C2410_DCON_CH1_I2SSDI (2<<24)
#define S3C2410_DCON_CH1_SPI (3<<24)
#define S3C2410_DCON_CH1_USBEP2 (4<<24)
#define S3C2410_DCON_CH2_I2SSDO (0<<24)
#define S3C2410_DCON_CH2_I2SSDI (1<<24)
#define S3C2410_DCON_CH2_SDI (2<<24)
#define S3C2410_DCON_CH2_TIMER (3<<24)
#define S3C2410_DCON_CH2_USBEP3 (4<<24)
#define S3C2410_DCON_CH3_UART2 (0<<24)
#define S3C2410_DCON_CH3_SDI (1<<24)
#define S3C2410_DCON_CH3_SPI (2<<24)
#define S3C2410_DCON_CH3_TIMER (3<<24)
#define S3C2410_DCON_CH3_USBEP4 (4<<24)
#define S3C2410_DCON_SRCSHIFT (24)
#define S3C2410_DCON_SRCMASK (7<<24)
#define S3C2410_DCON_BYTE (0<<20)
#define S3C2410_DCON_HALFWORD (1<<20)
#define S3C2410_DCON_WORD (2<<20)
#define S3C2410_DCON_AUTORELOAD (0<<22)
#define S3C2410_DCON_NORELOAD (1<<22)
#define S3C2410_DCON_HWTRIG (1<<23)
#ifdef CONFIG_CPU_S3C2440
#define S3C2440_DIDSTC_CHKINT (1<<2)
#define S3C2440_DCON_CH0_I2SSDO (5<<24)
#define S3C2440_DCON_CH0_PCMIN (6<<24)
#define S3C2440_DCON_CH1_PCMOUT (5<<24)
#define S3C2440_DCON_CH1_SDI (6<<24)
#define S3C2440_DCON_CH2_PCMIN (5<<24)
#define S3C2440_DCON_CH2_MICIN (6<<24)
#define S3C2440_DCON_CH3_MICIN (5<<24)
#define S3C2440_DCON_CH3_PCMOUT (6<<24)
#endif
#ifdef CONFIG_CPU_S3C2412
#define S3C2412_DMAREQSEL_SRC(x) ((x)<<1)
#define S3C2412_DMAREQSEL_HW (1)
#define S3C2412_DMAREQSEL_SPI0TX S3C2412_DMAREQSEL_SRC(0)
#define S3C2412_DMAREQSEL_SPI0RX S3C2412_DMAREQSEL_SRC(1)
#define S3C2412_DMAREQSEL_SPI1TX S3C2412_DMAREQSEL_SRC(2)
#define S3C2412_DMAREQSEL_SPI1RX S3C2412_DMAREQSEL_SRC(3)
#define S3C2412_DMAREQSEL_I2STX S3C2412_DMAREQSEL_SRC(4)
#define S3C2412_DMAREQSEL_I2SRX S3C2412_DMAREQSEL_SRC(5)
#define S3C2412_DMAREQSEL_TIMER S3C2412_DMAREQSEL_SRC(9)
#define S3C2412_DMAREQSEL_SDI S3C2412_DMAREQSEL_SRC(10)
#define S3C2412_DMAREQSEL_USBEP1 S3C2412_DMAREQSEL_SRC(13)
#define S3C2412_DMAREQSEL_USBEP2 S3C2412_DMAREQSEL_SRC(14)
#define S3C2412_DMAREQSEL_USBEP3 S3C2412_DMAREQSEL_SRC(15)
#define S3C2412_DMAREQSEL_USBEP4 S3C2412_DMAREQSEL_SRC(16)
#define S3C2412_DMAREQSEL_XDREQ0 S3C2412_DMAREQSEL_SRC(17)
#define S3C2412_DMAREQSEL_XDREQ1 S3C2412_DMAREQSEL_SRC(18)
#define S3C2412_DMAREQSEL_UART0_0 S3C2412_DMAREQSEL_SRC(19)
#define S3C2412_DMAREQSEL_UART0_1 S3C2412_DMAREQSEL_SRC(20)
#define S3C2412_DMAREQSEL_UART1_0 S3C2412_DMAREQSEL_SRC(21)
#define S3C2412_DMAREQSEL_UART1_1 S3C2412_DMAREQSEL_SRC(22)
#define S3C2412_DMAREQSEL_UART2_0 S3C2412_DMAREQSEL_SRC(23)
#define S3C2412_DMAREQSEL_UART2_1 S3C2412_DMAREQSEL_SRC(24)
#endif
#define S3C2443_DMAREQSEL_SRC(x) ((x)<<1)
#define S3C2443_DMAREQSEL_HW (1)
#define S3C2443_DMAREQSEL_SPI0TX S3C2443_DMAREQSEL_SRC(0)
#define S3C2443_DMAREQSEL_SPI0RX S3C2443_DMAREQSEL_SRC(1)
#define S3C2443_DMAREQSEL_SPI1TX S3C2443_DMAREQSEL_SRC(2)
#define S3C2443_DMAREQSEL_SPI1RX S3C2443_DMAREQSEL_SRC(3)
#define S3C2443_DMAREQSEL_I2STX S3C2443_DMAREQSEL_SRC(4)
#define S3C2443_DMAREQSEL_I2SRX S3C2443_DMAREQSEL_SRC(5)
#define S3C2443_DMAREQSEL_TIMER S3C2443_DMAREQSEL_SRC(9)
#define S3C2443_DMAREQSEL_SDI S3C2443_DMAREQSEL_SRC(10)
#define S3C2443_DMAREQSEL_XDREQ0 S3C2443_DMAREQSEL_SRC(17)
#define S3C2443_DMAREQSEL_XDREQ1 S3C2443_DMAREQSEL_SRC(18)
#define S3C2443_DMAREQSEL_UART0_0 S3C2443_DMAREQSEL_SRC(19)
#define S3C2443_DMAREQSEL_UART0_1 S3C2443_DMAREQSEL_SRC(20)
#define S3C2443_DMAREQSEL_UART1_0 S3C2443_DMAREQSEL_SRC(21)
#define S3C2443_DMAREQSEL_UART1_1 S3C2443_DMAREQSEL_SRC(22)
#define S3C2443_DMAREQSEL_UART2_0 S3C2443_DMAREQSEL_SRC(23)
#define S3C2443_DMAREQSEL_UART2_1 S3C2443_DMAREQSEL_SRC(24)
#define S3C2443_DMAREQSEL_UART3_0 S3C2443_DMAREQSEL_SRC(25)
#define S3C2443_DMAREQSEL_UART3_1 S3C2443_DMAREQSEL_SRC(26)
#define S3C2443_DMAREQSEL_PCMOUT S3C2443_DMAREQSEL_SRC(27)
#define S3C2443_DMAREQSEL_PCMIN S3C2443_DMAREQSEL_SRC(28)
#define S3C2443_DMAREQSEL_MICIN S3C2443_DMAREQSEL_SRC(29)
#endif /* __ASM_ARCH_DMA_H */

View file

@ -20,12 +20,13 @@
#include <mach/dma.h>
#include <plat/dma.h>
#include <plat/dma-plat.h>
#include <plat/cpu.h>
#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
#include <plat/regs-ac97.h>
#include <plat/regs-dma.h>
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>

View file

@ -17,14 +17,16 @@
#include <linux/sysdev.h>
#include <linux/serial_core.h>
#include <mach/map.h>
#include <mach/dma.h>
#include <plat/dma.h>
#include <plat/dma-plat.h>
#include <plat/cpu.h>
#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
#include <plat/regs-ac97.h>
#include <plat/regs-dma.h>
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>

View file

@ -20,12 +20,13 @@
#include <mach/dma.h>
#include <plat/dma.h>
#include <plat/dma-plat.h>
#include <plat/cpu.h>
#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
#include <plat/regs-ac97.h>
#include <plat/regs-dma.h>
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>

View file

@ -11,6 +11,63 @@
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H __FILE__
/* currently nothing here, placeholder */
#define S3C_DMA_CHANNELS (16)
/* see mach-s3c2410/dma.h for notes on dma channel numbers */
/* Note, for the S3C64XX architecture we keep the DMACH_
* defines in the order they are allocated to [S]DMA0/[S]DMA1
* so that is easy to do DHACH_ -> DMA controller conversion
*/
enum dma_ch {
/* DMA0/SDMA0 */
DMACH_UART0 = 0,
DMACH_UART0_SRC2,
DMACH_UART1,
DMACH_UART1_SRC2,
DMACH_UART2,
DMACH_UART2_SRC2,
DMACH_UART3,
DMACH_UART3_SRC2,
DMACH_PCM0_TX,
DMACH_PCM0_RX,
DMACH_I2S0_OUT,
DMACH_I2S0_IN,
DMACH_SPI0_TX,
DMACH_SPI0_RX,
DMACH_HSI_I2SV40_TX,
DMACH_HSI_I2SV40_RX,
/* DMA1/SDMA1 */
DMACH_PCM1_TX = 16,
DMACH_PCM1_RX,
DMACH_I2S1_OUT,
DMACH_I2S1_IN,
DMACH_SPI1_TX,
DMACH_SPI1_RX,
DMACH_AC97_PCMOUT,
DMACH_AC97_PCMIN,
DMACH_AC97_MICIN,
DMACH_PWM,
DMACH_IRDA,
DMACH_EXTERNAL,
DMACH_RES1,
DMACH_RES2,
DMACH_SECURITY_RX, /* SDMA1 only */
DMACH_SECURITY_TX, /* SDMA1 only */
DMACH_MAX /* the end */
};
static __inline__ int s3c_dma_has_circular(void)
{
/* we will be supporting ciruclar buffers as soon as we have DMA
* engine support.
*/
return 1;
}
#define S3C2410_DMAF_CIRCULAR (1 << 0)
#include <plat/dma.h>
#endif /* __ASM_ARCH_IRQ_H */

View file

@ -159,6 +159,13 @@ config S3C_GPIO_CFG_S3C64XX
Internal configuration to enable S3C64XX style GPIO configuration
functions.
# DMA
config S3C_DMA
bool
help
Internal configuration for S3C DMA core
# device definitions to compile in
config S3C_DEV_HSMMC

View file

@ -18,6 +18,10 @@ obj-y += pwm-clock.o
obj-y += gpio.o
obj-y += gpio-config.o
# DMA support
obj-$(CONFIG_S3C_DMA) += dma.o
# PM support
obj-$(CONFIG_PM) += pm.o

86
arch/arm/plat-s3c/dma.c Normal file
View file

@ -0,0 +1,86 @@
/* linux/arch/arm/plat-s3c/dma.c
*
* Copyright (c) 2003-2005,2006,2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* S3C DMA core
*
* 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.
*/
struct s3c2410_dma_buf;
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <mach/dma.h>
#include <mach/irqs.h>
#include <plat/dma-plat.h>
/* dma channel state information */
struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
struct s3c2410_dma_chan *s3c_dma_chan_map[DMACH_MAX];
/* s3c_dma_lookup_channel
*
* change the dma channel number given into a real dma channel id
*/
struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel)
{
if (channel & DMACH_LOW_LEVEL)
return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
else
return s3c_dma_chan_map[channel];
}
/* do we need to protect the settings of the fields from
* irq?
*/
int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
if (chan == NULL)
return -EINVAL;
pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn);
chan->op_fn = rtn;
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_set_opfn);
int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
if (chan == NULL)
return -EINVAL;
pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
chan->callback_fn = rtn;
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
if (chan == NULL)
return -EINVAL;
chan->flags = flags;
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_setflags);

View file

@ -0,0 +1,22 @@
/* arch/arm/plat-s3c/include/plat/dma.h
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* Samsung S3C DMA core support
*
* 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.
*/
extern struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel);
extern struct s3c2410_dma_chan *s3c_dma_chan_map[];
/* the currently allocated channel information */
extern struct s3c2410_dma_chan s3c2410_chans[];

View file

@ -0,0 +1,127 @@
/* arch/arm/plat-s3c/include/plat/dma.h
*
* Copyright (C) 2003,2004,2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Samsung S3C DMA support
*
* 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.
*/
enum s3c2410_dma_buffresult {
S3C2410_RES_OK,
S3C2410_RES_ERR,
S3C2410_RES_ABORT
};
enum s3c2410_dmasrc {
S3C2410_DMASRC_HW, /* source is memory */
S3C2410_DMASRC_MEM /* source is hardware */
};
/* enum s3c2410_chan_op
*
* operation codes passed to the DMA code by the user, and also used
* to inform the current channel owner of any changes to the system state
*/
enum s3c2410_chan_op {
S3C2410_DMAOP_START,
S3C2410_DMAOP_STOP,
S3C2410_DMAOP_PAUSE,
S3C2410_DMAOP_RESUME,
S3C2410_DMAOP_FLUSH,
S3C2410_DMAOP_TIMEOUT, /* internal signal to handler */
S3C2410_DMAOP_STARTED, /* indicate channel started */
};
struct s3c2410_dma_client {
char *name;
};
struct s3c2410_dma_chan;
/* s3c2410_dma_cbfn_t
*
* buffer callback routine type
*/
typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
void *buf, int size,
enum s3c2410_dma_buffresult result);
typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
enum s3c2410_chan_op );
/* s3c2410_dma_request
*
* request a dma channel exclusivley
*/
extern int s3c2410_dma_request(unsigned int channel,
struct s3c2410_dma_client *, void *dev);
/* s3c2410_dma_ctrl
*
* change the state of the dma channel
*/
extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
/* s3c2410_dma_setflags
*
* set the channel's flags to a given state
*/
extern int s3c2410_dma_setflags(unsigned int channel,
unsigned int flags);
/* s3c2410_dma_free
*
* free the dma channel (will also abort any outstanding operations)
*/
extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
/* s3c2410_dma_enqueue
*
* place the given buffer onto the queue of operations for the channel.
* The buffer must be allocated from dma coherent memory, or the Dcache/WB
* drained before the buffer is given to the DMA system.
*/
extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
dma_addr_t data, int size);
/* s3c2410_dma_config
*
* configure the dma channel
*/
extern int s3c2410_dma_config(unsigned int channel, int xferunit);
/* s3c2410_dma_devconfig
*
* configure the device we're talking to
*/
extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
unsigned long devaddr);
/* s3c2410_dma_getposition
*
* get the position that the dma transfer is currently at
*/
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);

View file

@ -71,6 +71,7 @@ config PM_SIMTEC
config S3C2410_DMA
bool "S3C2410 DMA support"
depends on ARCH_S3C2410
select S3C_DMA
help
S3C2410 DMA support. This is needed for drivers like sound which
use the S3C2410's DMA system to move data to and from the

View file

@ -31,10 +31,10 @@
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/dma.h>
#include <mach/map.h>
#include <plat/dma.h>
#include <plat/dma-plat.h>
#include <plat/regs-dma.h>
/* io map for dma */
static void __iomem *dma_base;
@ -44,8 +44,6 @@ static int dma_channels;
static struct s3c24xx_dma_selection dma_sel;
/* dma channel state information */
struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
/* debugging functions */
@ -135,21 +133,6 @@ dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
#define dbg_showchan(chan) do { } while(0)
#endif /* CONFIG_S3C2410_DMA_DEBUG */
static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
/* lookup_dma_channel
*
* change the dma channel number given into a real dma channel id
*/
static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
{
if (channel & DMACH_LOW_LEVEL)
return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
else
return dma_chan_map[channel];
}
/* s3c2410_dma_stats_timeout
*
* Update DMA stats from timeout info
@ -214,8 +197,6 @@ s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
return 0;
}
/* s3c2410_dma_loadbuffer
*
* load a buffer, and update the channel state
@ -453,7 +434,7 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
int s3c2410_dma_enqueue(unsigned int channel, void *id,
dma_addr_t data, int size)
{
struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
struct s3c2410_dma_buf *buf;
unsigned long flags;
@ -804,7 +785,7 @@ EXPORT_SYMBOL(s3c2410_dma_request);
int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
{
struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
unsigned long flags;
if (chan == NULL)
@ -836,7 +817,7 @@ int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
chan->irq_claimed = 0;
if (!(channel & DMACH_LOW_LEVEL))
dma_chan_map[channel] = NULL;
s3c_dma_chan_map[channel] = NULL;
local_irq_restore(flags);
@ -995,7 +976,7 @@ static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
int
s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
{
struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
if (chan == NULL)
return -EINVAL;
@ -1038,14 +1019,13 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl);
/* s3c2410_dma_config
*
* xfersize: size of unit in bytes (1,2,4)
* dcon: base value of the DCONx register
*/
int s3c2410_dma_config(unsigned int channel,
int xferunit,
int dcon)
int xferunit)
{
struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
unsigned int dcon;
pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
__func__, channel, xferunit, dcon);
@ -1055,10 +1035,33 @@ int s3c2410_dma_config(unsigned int channel,
pr_debug("%s: Initial dcon is %08x\n", __func__, dcon);
dcon |= chan->dcon & dma_sel.dcon_mask;
dcon = chan->dcon & dma_sel.dcon_mask;
pr_debug("%s: New dcon is %08x\n", __func__, dcon);
switch (chan->req_ch) {
case DMACH_I2S_IN:
case DMACH_I2S_OUT:
case DMACH_PCM_IN:
case DMACH_PCM_OUT:
case DMACH_MIC_IN:
default:
dcon |= S3C2410_DCON_HANDSHAKE;
dcon |= S3C2410_DCON_SYNC_PCLK;
break;
case DMACH_SDI:
/* note, ensure if need HANDSHAKE or not */
dcon |= S3C2410_DCON_SYNC_PCLK;
break;
case DMACH_XD0:
case DMACH_XD1:
dcon |= S3C2410_DCON_HANDSHAKE;
dcon |= S3C2410_DCON_SYNC_HCLK;
break;
}
switch (xferunit) {
case 1:
dcon |= S3C2410_DCON_BYTE;
@ -1090,58 +1093,6 @@ int s3c2410_dma_config(unsigned int channel,
EXPORT_SYMBOL(s3c2410_dma_config);
int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
{
struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
if (chan == NULL)
return -EINVAL;
pr_debug("%s: chan=%p, flags=%08x\n", __func__, chan, flags);
chan->flags = flags;
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_setflags);
/* do we need to protect the settings of the fields from
* irq?
*/
int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
{
struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
if (chan == NULL)
return -EINVAL;
pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn);
chan->op_fn = rtn;
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_set_opfn);
int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
{
struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
if (chan == NULL)
return -EINVAL;
pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
chan->callback_fn = rtn;
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
/* s3c2410_dma_devconfig
*
@ -1150,29 +1101,38 @@ EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
* source: S3C2410_DMASRC_HW: source is hardware
* S3C2410_DMASRC_MEM: source is memory
*
* hwcfg: the value for xxxSTCn register,
* bit 0: 0=increment pointer, 1=leave pointer
* bit 1: 0=source is AHB, 1=source is APB
*
* devaddr: physical address of the source
*/
int s3c2410_dma_devconfig(int channel,
enum s3c2410_dmasrc source,
int hwcfg,
unsigned long devaddr)
{
struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
unsigned int hwcfg;
if (chan == NULL)
return -EINVAL;
pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
__func__, (int)source, hwcfg, devaddr);
pr_debug("%s: source=%d, devaddr=%08lx\n",
__func__, (int)source, devaddr);
chan->source = source;
chan->dev_addr = devaddr;
chan->hw_cfg = hwcfg;
switch (chan->req_ch) {
case DMACH_XD0:
case DMACH_XD1:
hwcfg = 0; /* AHB */
break;
default:
hwcfg = S3C2410_DISRCC_APB;
}
/* always assume our peripheral desintation is a fixed
* address in memory. */
hwcfg |= S3C2410_DISRCC_INC;
switch (source) {
case S3C2410_DMASRC_HW:
@ -1219,7 +1179,7 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig);
int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *dst)
{
struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
if (chan == NULL)
return -EINVAL;
@ -1278,8 +1238,8 @@ static int s3c2410_dma_resume(struct sys_device *dev)
printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
s3c2410_dma_config(no, cp->xfer_unit, cp->dcon);
s3c2410_dma_devconfig(no, cp->source, cp->hw_cfg, cp->dev_addr);
s3c2410_dma_config(no, cp->xfer_unit);
s3c2410_dma_devconfig(no, cp->source, cp->dev_addr);
/* re-select the dma source for this channel */
@ -1476,7 +1436,8 @@ static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
found:
dmach = &s3c2410_chans[ch];
dmach->map = ch_map;
dma_chan_map[channel] = dmach;
dmach->req_ch = channel;
s3c_dma_chan_map[channel] = dmach;
/* select the channel */

View file

@ -1,4 +1,4 @@
/* linux/include/asm-arm/plat-s3c24xx/dma.h
/* linux/arch/arm/plat-s3c24xx/include/plat/dma-plat.h
*
* Copyright (C) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@ -10,8 +10,10 @@
* published by the Free Software Foundation.
*/
#include <plat/dma-core.h>
extern struct sysdev_class dma_sysclass;
extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
extern struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
#define DMA_CH_VALID (1<<31)
#define DMA_CH_NEVER (1<<30)
@ -31,8 +33,8 @@ struct s3c24xx_dma_map {
const char *name;
struct s3c24xx_dma_addr hw_addr;
unsigned long channels[S3C2410_DMA_CHANNELS];
unsigned long channels_rx[S3C2410_DMA_CHANNELS];
unsigned long channels[S3C_DMA_CHANNELS];
unsigned long channels_rx[S3C_DMA_CHANNELS];
};
struct s3c24xx_dma_selection {
@ -58,7 +60,7 @@ extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
*/
struct s3c24xx_dma_order_ch {
unsigned int list[S3C2410_DMA_CHANNELS]; /* list of channels */
unsigned int list[S3C_DMA_CHANNELS]; /* list of channels */
unsigned int flags; /* flags */
};

View file

@ -0,0 +1,145 @@
/* arch/arm/mach-s3c2410/include/mach/dma.h
*
* Copyright (C) 2003,2004,2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Samsung S3C24XX DMA support
*
* 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.
*/
/* DMA Register definitions */
#define S3C2410_DMA_DISRC (0x00)
#define S3C2410_DMA_DISRCC (0x04)
#define S3C2410_DMA_DIDST (0x08)
#define S3C2410_DMA_DIDSTC (0x0C)
#define S3C2410_DMA_DCON (0x10)
#define S3C2410_DMA_DSTAT (0x14)
#define S3C2410_DMA_DCSRC (0x18)
#define S3C2410_DMA_DCDST (0x1C)
#define S3C2410_DMA_DMASKTRIG (0x20)
#define S3C2412_DMA_DMAREQSEL (0x24)
#define S3C2443_DMA_DMAREQSEL (0x24)
#define S3C2410_DISRCC_INC (1<<0)
#define S3C2410_DISRCC_APB (1<<1)
#define S3C2410_DMASKTRIG_STOP (1<<2)
#define S3C2410_DMASKTRIG_ON (1<<1)
#define S3C2410_DMASKTRIG_SWTRIG (1<<0)
#define S3C2410_DCON_DEMAND (0<<31)
#define S3C2410_DCON_HANDSHAKE (1<<31)
#define S3C2410_DCON_SYNC_PCLK (0<<30)
#define S3C2410_DCON_SYNC_HCLK (1<<30)
#define S3C2410_DCON_INTREQ (1<<29)
#define S3C2410_DCON_CH0_XDREQ0 (0<<24)
#define S3C2410_DCON_CH0_UART0 (1<<24)
#define S3C2410_DCON_CH0_SDI (2<<24)
#define S3C2410_DCON_CH0_TIMER (3<<24)
#define S3C2410_DCON_CH0_USBEP1 (4<<24)
#define S3C2410_DCON_CH1_XDREQ1 (0<<24)
#define S3C2410_DCON_CH1_UART1 (1<<24)
#define S3C2410_DCON_CH1_I2SSDI (2<<24)
#define S3C2410_DCON_CH1_SPI (3<<24)
#define S3C2410_DCON_CH1_USBEP2 (4<<24)
#define S3C2410_DCON_CH2_I2SSDO (0<<24)
#define S3C2410_DCON_CH2_I2SSDI (1<<24)
#define S3C2410_DCON_CH2_SDI (2<<24)
#define S3C2410_DCON_CH2_TIMER (3<<24)
#define S3C2410_DCON_CH2_USBEP3 (4<<24)
#define S3C2410_DCON_CH3_UART2 (0<<24)
#define S3C2410_DCON_CH3_SDI (1<<24)
#define S3C2410_DCON_CH3_SPI (2<<24)
#define S3C2410_DCON_CH3_TIMER (3<<24)
#define S3C2410_DCON_CH3_USBEP4 (4<<24)
#define S3C2410_DCON_SRCSHIFT (24)
#define S3C2410_DCON_SRCMASK (7<<24)
#define S3C2410_DCON_BYTE (0<<20)
#define S3C2410_DCON_HALFWORD (1<<20)
#define S3C2410_DCON_WORD (2<<20)
#define S3C2410_DCON_AUTORELOAD (0<<22)
#define S3C2410_DCON_NORELOAD (1<<22)
#define S3C2410_DCON_HWTRIG (1<<23)
#ifdef CONFIG_CPU_S3C2440
#define S3C2440_DIDSTC_CHKINT (1<<2)
#define S3C2440_DCON_CH0_I2SSDO (5<<24)
#define S3C2440_DCON_CH0_PCMIN (6<<24)
#define S3C2440_DCON_CH1_PCMOUT (5<<24)
#define S3C2440_DCON_CH1_SDI (6<<24)
#define S3C2440_DCON_CH2_PCMIN (5<<24)
#define S3C2440_DCON_CH2_MICIN (6<<24)
#define S3C2440_DCON_CH3_MICIN (5<<24)
#define S3C2440_DCON_CH3_PCMOUT (6<<24)
#endif
#ifdef CONFIG_CPU_S3C2412
#define S3C2412_DMAREQSEL_SRC(x) ((x)<<1)
#define S3C2412_DMAREQSEL_HW (1)
#define S3C2412_DMAREQSEL_SPI0TX S3C2412_DMAREQSEL_SRC(0)
#define S3C2412_DMAREQSEL_SPI0RX S3C2412_DMAREQSEL_SRC(1)
#define S3C2412_DMAREQSEL_SPI1TX S3C2412_DMAREQSEL_SRC(2)
#define S3C2412_DMAREQSEL_SPI1RX S3C2412_DMAREQSEL_SRC(3)
#define S3C2412_DMAREQSEL_I2STX S3C2412_DMAREQSEL_SRC(4)
#define S3C2412_DMAREQSEL_I2SRX S3C2412_DMAREQSEL_SRC(5)
#define S3C2412_DMAREQSEL_TIMER S3C2412_DMAREQSEL_SRC(9)
#define S3C2412_DMAREQSEL_SDI S3C2412_DMAREQSEL_SRC(10)
#define S3C2412_DMAREQSEL_USBEP1 S3C2412_DMAREQSEL_SRC(13)
#define S3C2412_DMAREQSEL_USBEP2 S3C2412_DMAREQSEL_SRC(14)
#define S3C2412_DMAREQSEL_USBEP3 S3C2412_DMAREQSEL_SRC(15)
#define S3C2412_DMAREQSEL_USBEP4 S3C2412_DMAREQSEL_SRC(16)
#define S3C2412_DMAREQSEL_XDREQ0 S3C2412_DMAREQSEL_SRC(17)
#define S3C2412_DMAREQSEL_XDREQ1 S3C2412_DMAREQSEL_SRC(18)
#define S3C2412_DMAREQSEL_UART0_0 S3C2412_DMAREQSEL_SRC(19)
#define S3C2412_DMAREQSEL_UART0_1 S3C2412_DMAREQSEL_SRC(20)
#define S3C2412_DMAREQSEL_UART1_0 S3C2412_DMAREQSEL_SRC(21)
#define S3C2412_DMAREQSEL_UART1_1 S3C2412_DMAREQSEL_SRC(22)
#define S3C2412_DMAREQSEL_UART2_0 S3C2412_DMAREQSEL_SRC(23)
#define S3C2412_DMAREQSEL_UART2_1 S3C2412_DMAREQSEL_SRC(24)
#endif
#define S3C2443_DMAREQSEL_SRC(x) ((x)<<1)
#define S3C2443_DMAREQSEL_HW (1)
#define S3C2443_DMAREQSEL_SPI0TX S3C2443_DMAREQSEL_SRC(0)
#define S3C2443_DMAREQSEL_SPI0RX S3C2443_DMAREQSEL_SRC(1)
#define S3C2443_DMAREQSEL_SPI1TX S3C2443_DMAREQSEL_SRC(2)
#define S3C2443_DMAREQSEL_SPI1RX S3C2443_DMAREQSEL_SRC(3)
#define S3C2443_DMAREQSEL_I2STX S3C2443_DMAREQSEL_SRC(4)
#define S3C2443_DMAREQSEL_I2SRX S3C2443_DMAREQSEL_SRC(5)
#define S3C2443_DMAREQSEL_TIMER S3C2443_DMAREQSEL_SRC(9)
#define S3C2443_DMAREQSEL_SDI S3C2443_DMAREQSEL_SRC(10)
#define S3C2443_DMAREQSEL_XDREQ0 S3C2443_DMAREQSEL_SRC(17)
#define S3C2443_DMAREQSEL_XDREQ1 S3C2443_DMAREQSEL_SRC(18)
#define S3C2443_DMAREQSEL_UART0_0 S3C2443_DMAREQSEL_SRC(19)
#define S3C2443_DMAREQSEL_UART0_1 S3C2443_DMAREQSEL_SRC(20)
#define S3C2443_DMAREQSEL_UART1_0 S3C2443_DMAREQSEL_SRC(21)
#define S3C2443_DMAREQSEL_UART1_1 S3C2443_DMAREQSEL_SRC(22)
#define S3C2443_DMAREQSEL_UART2_0 S3C2443_DMAREQSEL_SRC(23)
#define S3C2443_DMAREQSEL_UART2_1 S3C2443_DMAREQSEL_SRC(24)
#define S3C2443_DMAREQSEL_UART3_0 S3C2443_DMAREQSEL_SRC(25)
#define S3C2443_DMAREQSEL_UART3_1 S3C2443_DMAREQSEL_SRC(26)
#define S3C2443_DMAREQSEL_PCMOUT S3C2443_DMAREQSEL_SRC(27)
#define S3C2443_DMAREQSEL_PCMIN S3C2443_DMAREQSEL_SRC(28)
#define S3C2443_DMAREQSEL_MICIN S3C2443_DMAREQSEL_SRC(29)

View file

@ -39,6 +39,10 @@ config CPU_S3C6400_CLOCK
Common clock support code for the S3C6400 that is shared
by other CPUs in the series, such as the S3C6410.
config S3C64XX_DMA
bool "S3C64XX DMA"
select S3C_DMA
# platform specific device setup
config S3C64XX_SETUP_I2C0

View file

@ -30,6 +30,10 @@ obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_PM) += sleep.o
obj-$(CONFIG_PM) += irq-pm.o
# DMA support
obj-$(CONFIG_S3C64XX_DMA) += dma.o
# Device setup
obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o

722
arch/arm/plat-s3c64xx/dma.c Normal file
View file

@ -0,0 +1,722 @@
/* linux/arch/arm/plat-s3c64xx/dma.c
*
* Copyright 2009 Openmoko, Inc.
* Copyright 2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* S3C64XX DMA core
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/dmapool.h>
#include <linux/sysdev.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <mach/dma.h>
#include <mach/map.h>
#include <mach/irqs.h>
#include <plat/dma-plat.h>
#include <plat/regs-sys.h>
#include <asm/hardware/pl080.h>
/* dma channel state information */
struct s3c64xx_dmac {
struct sys_device sysdev;
struct clk *clk;
void __iomem *regs;
struct s3c2410_dma_chan *channels;
enum dma_ch chanbase;
};
/* pool to provide LLI buffers */
static struct dma_pool *dma_pool;
/* Debug configuration and code */
static unsigned char debug_show_buffs = 0;
static void dbg_showchan(struct s3c2410_dma_chan *chan)
{
pr_debug("DMA%d: %08x->%08x L %08x C %08x,%08x S %08x\n",
chan->number,
readl(chan->regs + PL080_CH_SRC_ADDR),
readl(chan->regs + PL080_CH_DST_ADDR),
readl(chan->regs + PL080_CH_LLI),
readl(chan->regs + PL080_CH_CONTROL),
readl(chan->regs + PL080S_CH_CONTROL2),
readl(chan->regs + PL080S_CH_CONFIG));
}
static void show_lli(struct pl080s_lli *lli)
{
pr_debug("LLI[%p] %08x->%08x, NL %08x C %08x,%08x\n",
lli, lli->src_addr, lli->dst_addr, lli->next_lli,
lli->control0, lli->control1);
}
static void dbg_showbuffs(struct s3c2410_dma_chan *chan)
{
struct s3c64xx_dma_buff *ptr;
struct s3c64xx_dma_buff *end;
pr_debug("DMA%d: buffs next %p, curr %p, end %p\n",
chan->number, chan->next, chan->curr, chan->end);
ptr = chan->next;
end = chan->end;
if (debug_show_buffs) {
for (; ptr != NULL; ptr = ptr->next) {
pr_debug("DMA%d: %08x ",
chan->number, ptr->lli_dma);
show_lli(ptr->lli);
}
}
}
/* End of Debug */
static struct s3c2410_dma_chan *s3c64xx_dma_map_channel(unsigned int channel)
{
struct s3c2410_dma_chan *chan;
unsigned int start, offs;
start = 0;
if (channel >= DMACH_PCM1_TX)
start = 8;
for (offs = 0; offs < 8; offs++) {
chan = &s3c2410_chans[start + offs];
if (!chan->in_use)
goto found;
}
return NULL;
found:
s3c_dma_chan_map[channel] = chan;
return chan;
}
int s3c2410_dma_config(unsigned int channel, int xferunit)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
if (chan == NULL)
return -EINVAL;
switch (xferunit) {
case 1:
chan->hw_width = 0;
break;
case 2:
chan->hw_width = 1;
break;
case 4:
chan->hw_width = 2;
break;
default:
printk(KERN_ERR "%s: illegal width %d\n", __func__, xferunit);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_config);
static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
struct pl080s_lli *lli,
dma_addr_t data, int size)
{
dma_addr_t src, dst;
u32 control0, control1;
switch (chan->source) {
case S3C2410_DMASRC_HW:
src = chan->dev_addr;
dst = data;
control0 = PL080_CONTROL_SRC_AHB2;
control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT;
control0 |= 2 << PL080_CONTROL_DWIDTH_SHIFT;
control0 |= PL080_CONTROL_DST_INCR;
break;
case S3C2410_DMASRC_MEM:
src = data;
dst = chan->dev_addr;
control0 = PL080_CONTROL_DST_AHB2;
control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT;
control0 |= 2 << PL080_CONTROL_SWIDTH_SHIFT;
control0 |= PL080_CONTROL_SRC_INCR;
break;
default:
BUG();
}
/* note, we do not currently setup any of the burst controls */
control1 = size >> chan->hw_width; /* size in no of xfers */
control0 |= PL080_CONTROL_PROT_SYS; /* always in priv. mode */
control0 |= PL080_CONTROL_TC_IRQ_EN; /* always fire IRQ */
lli->src_addr = src;
lli->dst_addr = dst;
lli->next_lli = 0;
lli->control0 = control0;
lli->control1 = control1;
}
static void s3c64xx_lli_to_regs(struct s3c2410_dma_chan *chan,
struct pl080s_lli *lli)
{
void __iomem *regs = chan->regs;
pr_debug("%s: LLI %p => regs\n", __func__, lli);
show_lli(lli);
writel(lli->src_addr, regs + PL080_CH_SRC_ADDR);
writel(lli->dst_addr, regs + PL080_CH_DST_ADDR);
writel(lli->next_lli, regs + PL080_CH_LLI);
writel(lli->control0, regs + PL080_CH_CONTROL);
writel(lli->control1, regs + PL080S_CH_CONTROL2);
}
static int s3c64xx_dma_start(struct s3c2410_dma_chan *chan)
{
struct s3c64xx_dmac *dmac = chan->dmac;
u32 config;
u32 bit = chan->bit;
dbg_showchan(chan);
pr_debug("%s: clearing interrupts\n", __func__);
/* clear interrupts */
writel(bit, dmac->regs + PL080_TC_CLEAR);
writel(bit, dmac->regs + PL080_ERR_CLEAR);
pr_debug("%s: starting channel\n", __func__);
config = readl(chan->regs + PL080S_CH_CONFIG);
config |= PL080_CONFIG_ENABLE;
pr_debug("%s: writing config %08x\n", __func__, config);
writel(config, chan->regs + PL080S_CH_CONFIG);
return 0;
}
static int s3c64xx_dma_stop(struct s3c2410_dma_chan *chan)
{
u32 config;
int timeout;
pr_debug("%s: stopping channel\n", __func__);
dbg_showchan(chan);
config = readl(chan->regs + PL080S_CH_CONFIG);
config |= PL080_CONFIG_HALT;
writel(config, chan->regs + PL080S_CH_CONFIG);
timeout = 1000;
do {
config = readl(chan->regs + PL080S_CH_CONFIG);
pr_debug("%s: %d - config %08x\n", __func__, timeout, config);
if (config & PL080_CONFIG_ACTIVE)
udelay(10);
else
break;
} while (--timeout > 0);
if (config & PL080_CONFIG_ACTIVE) {
printk(KERN_ERR "%s: channel still active\n", __func__);
return -EFAULT;
}
config = readl(chan->regs + PL080S_CH_CONFIG);
config &= ~PL080_CONFIG_ENABLE;
writel(config, chan->regs + PL080S_CH_CONFIG);
return 0;
}
static inline void s3c64xx_dma_bufffdone(struct s3c2410_dma_chan *chan,
struct s3c64xx_dma_buff *buf,
enum s3c2410_dma_buffresult result)
{
if (chan->callback_fn != NULL)
(chan->callback_fn)(chan, buf->pw, 0, result);
}
static void s3c64xx_dma_freebuff(struct s3c64xx_dma_buff *buff)
{
dma_pool_free(dma_pool, buff->lli, buff->lli_dma);
kfree(buff);
}
static int s3c64xx_dma_flush(struct s3c2410_dma_chan *chan)
{
struct s3c64xx_dma_buff *buff, *next;
u32 config;
dbg_showchan(chan);
pr_debug("%s: flushing channel\n", __func__);
config = readl(chan->regs + PL080S_CH_CONFIG);
config &= ~PL080_CONFIG_ENABLE;
writel(config, chan->regs + PL080S_CH_CONFIG);
/* dump all the buffers associated with this channel */
for (buff = chan->curr; buff != NULL; buff = next) {
next = buff->next;
pr_debug("%s: buff %p (next %p)\n", __func__, buff, buff->next);
s3c64xx_dma_bufffdone(chan, buff, S3C2410_RES_ABORT);
s3c64xx_dma_freebuff(buff);
}
chan->curr = chan->next = chan->end = NULL;
return 0;
}
int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
WARN_ON(!chan);
if (!chan)
return -EINVAL;
switch (op) {
case S3C2410_DMAOP_START:
return s3c64xx_dma_start(chan);
case S3C2410_DMAOP_STOP:
return s3c64xx_dma_stop(chan);
case S3C2410_DMAOP_FLUSH:
return s3c64xx_dma_flush(chan);
/* belive PAUSE/RESUME are no-ops */
case S3C2410_DMAOP_PAUSE:
case S3C2410_DMAOP_RESUME:
case S3C2410_DMAOP_STARTED:
case S3C2410_DMAOP_TIMEOUT:
return 0;
}
return -ENOENT;
}
EXPORT_SYMBOL(s3c2410_dma_ctrl);
/* s3c2410_dma_enque
*
*/
int s3c2410_dma_enqueue(unsigned int channel, void *id,
dma_addr_t data, int size)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
struct s3c64xx_dma_buff *next;
struct s3c64xx_dma_buff *buff;
struct pl080s_lli *lli;
int ret;
WARN_ON(!chan);
if (!chan)
return -EINVAL;
buff = kzalloc(sizeof(struct s3c64xx_dma_buff), GFP_KERNEL);
if (!buff) {
printk(KERN_ERR "%s: no memory for buffer\n", __func__);
return -ENOMEM;
}
lli = dma_pool_alloc(dma_pool, GFP_KERNEL, &buff->lli_dma);
if (!lli) {
printk(KERN_ERR "%s: no memory for lli\n", __func__);
ret = -ENOMEM;
goto err_buff;
}
pr_debug("%s: buff %p, dp %08x lli (%p, %08x) %d\n",
__func__, buff, data, lli, (u32)buff->lli_dma, size);
buff->lli = lli;
buff->pw = id;
s3c64xx_dma_fill_lli(chan, lli, data, size);
if ((next = chan->next) != NULL) {
struct s3c64xx_dma_buff *end = chan->end;
struct pl080s_lli *endlli = end->lli;
pr_debug("enquing onto channel\n");
end->next = buff;
endlli->next_lli = buff->lli_dma;
if (chan->flags & S3C2410_DMAF_CIRCULAR) {
struct s3c64xx_dma_buff *curr = chan->curr;
lli->next_lli = curr->lli_dma;
}
if (next == chan->curr) {
writel(buff->lli_dma, chan->regs + PL080_CH_LLI);
chan->next = buff;
}
show_lli(endlli);
chan->end = buff;
} else {
pr_debug("enquing onto empty channel\n");
chan->curr = buff;
chan->next = buff;
chan->end = buff;
s3c64xx_lli_to_regs(chan, lli);
}
show_lli(lli);
dbg_showchan(chan);
dbg_showbuffs(chan);
return 0;
err_buff:
kfree(buff);
return ret;
}
EXPORT_SYMBOL(s3c2410_dma_enqueue);
int s3c2410_dma_devconfig(int channel,
enum s3c2410_dmasrc source,
unsigned long devaddr)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
u32 peripheral;
u32 config = 0;
pr_debug("%s: channel %d, source %d, dev %08lx, chan %p\n",
__func__, channel, source, devaddr, chan);
WARN_ON(!chan);
if (!chan)
return -EINVAL;
peripheral = (chan->peripheral & 0xf);
chan->source = source;
chan->dev_addr = devaddr;
pr_debug("%s: peripheral %d\n", __func__, peripheral);
switch (source) {
case S3C2410_DMASRC_HW:
config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT;
break;
case S3C2410_DMASRC_MEM:
config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT;
break;
default:
printk(KERN_ERR "%s: bad source\n", __func__);
return -EINVAL;
}
/* allow TC and ERR interrupts */
config |= PL080_CONFIG_TC_IRQ_MASK;
config |= PL080_CONFIG_ERR_IRQ_MASK;
pr_debug("%s: config %08x\n", __func__, config);
writel(config, chan->regs + PL080S_CH_CONFIG);
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_devconfig);
int s3c2410_dma_getposition(unsigned int channel,
dma_addr_t *src, dma_addr_t *dst)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
WARN_ON(!chan);
if (!chan)
return -EINVAL;
if (src != NULL)
*src = readl(chan->regs + PL080_CH_SRC_ADDR);
if (dst != NULL)
*dst = readl(chan->regs + PL080_CH_DST_ADDR);
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_getposition);
/* s3c2410_request_dma
*
* get control of an dma channel
*/
int s3c2410_dma_request(unsigned int channel,
struct s3c2410_dma_client *client,
void *dev)
{
struct s3c2410_dma_chan *chan;
unsigned long flags;
pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
channel, client->name, dev);
local_irq_save(flags);
chan = s3c64xx_dma_map_channel(channel);
if (chan == NULL) {
local_irq_restore(flags);
return -EBUSY;
}
dbg_showchan(chan);
chan->client = client;
chan->in_use = 1;
chan->peripheral = channel;
local_irq_restore(flags);
/* need to setup */
pr_debug("%s: channel initialised, %p\n", __func__, chan);
return chan->number | DMACH_LOW_LEVEL;
}
EXPORT_SYMBOL(s3c2410_dma_request);
/* s3c2410_dma_free
*
* release the given channel back to the system, will stop and flush
* any outstanding transfers, and ensure the channel is ready for the
* next claimant.
*
* Note, although a warning is currently printed if the freeing client
* info is not the same as the registrant's client info, the free is still
* allowed to go through.
*/
int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
{
struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
unsigned long flags;
if (chan == NULL)
return -EINVAL;
local_irq_save(flags);
if (chan->client != client) {
printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
channel, chan->client, client);
}
/* sort out stopping and freeing the channel */
chan->client = NULL;
chan->in_use = 0;
if (!(channel & DMACH_LOW_LEVEL))
s3c_dma_chan_map[channel] = NULL;
local_irq_restore(flags);
return 0;
}
EXPORT_SYMBOL(s3c2410_dma_free);
static void s3c64xx_dma_tcirq(struct s3c64xx_dmac *dmac, int offs)
{
struct s3c2410_dma_chan *chan = dmac->channels + offs;
/* note, we currently do not bother to work out which buffer
* or buffers have been completed since the last tc-irq. */
if (chan->callback_fn)
(chan->callback_fn)(chan, chan->curr->pw, 0, S3C2410_RES_OK);
}
static void s3c64xx_dma_errirq(struct s3c64xx_dmac *dmac, int offs)
{
printk(KERN_DEBUG "%s: offs %d\n", __func__, offs);
}
static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
{
struct s3c64xx_dmac *dmac = pw;
u32 tcstat, errstat;
u32 bit;
int offs;
tcstat = readl(dmac->regs + PL080_TC_STATUS);
errstat = readl(dmac->regs + PL080_ERR_STATUS);
for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) {
if (tcstat & bit) {
writel(bit, dmac->regs + PL080_TC_CLEAR);
s3c64xx_dma_tcirq(dmac, offs);
}
if (errstat & bit) {
s3c64xx_dma_errirq(dmac, offs);
writel(bit, dmac->regs + PL080_ERR_CLEAR);
}
}
return IRQ_HANDLED;
}
static struct sysdev_class dma_sysclass = {
.name = "s3c64xx-dma",
};
static int s3c64xx_dma_init1(int chno, enum dma_ch chbase,
int irq, unsigned int base)
{
struct s3c2410_dma_chan *chptr = &s3c2410_chans[chno];
struct s3c64xx_dmac *dmac;
char clkname[16];
void __iomem *regs;
void __iomem *regptr;
int err, ch;
dmac = kzalloc(sizeof(struct s3c64xx_dmac), GFP_KERNEL);
if (!dmac) {
printk(KERN_ERR "%s: failed to alloc mem\n", __func__);
return -ENOMEM;
}
dmac->sysdev.id = chno / 8;
dmac->sysdev.cls = &dma_sysclass;
err = sysdev_register(&dmac->sysdev);
if (err) {
printk(KERN_ERR "%s: failed to register sysdevice\n", __func__);
goto err_alloc;
}
regs = ioremap(base, 0x200);
if (!regs) {
printk(KERN_ERR "%s: failed to ioremap()\n", __func__);
err = -ENXIO;
goto err_dev;
}
snprintf(clkname, sizeof(clkname), "dma%d", dmac->sysdev.id);
dmac->clk = clk_get(NULL, clkname);
if (IS_ERR(dmac->clk)) {
printk(KERN_ERR "%s: failed to get clock %s\n", __func__, clkname);
err = PTR_ERR(dmac->clk);
goto err_map;
}
clk_enable(dmac->clk);
dmac->regs = regs;
dmac->chanbase = chbase;
dmac->channels = chptr;
err = request_irq(irq, s3c64xx_dma_irq, 0, "DMA", dmac);
if (err < 0) {
printk(KERN_ERR "%s: failed to get irq\n", __func__);
goto err_clk;
}
regptr = regs + PL080_Cx_BASE(0);
for (ch = 0; ch < 8; ch++, chno++, chptr++) {
printk(KERN_INFO "%s: registering DMA %d (%p)\n",
__func__, chno, regptr);
chptr->bit = 1 << ch;
chptr->number = chno;
chptr->dmac = dmac;
chptr->regs = regptr;
regptr += PL008_Cx_STRIDE;
}
/* for the moment, permanently enable the controller */
writel(PL080_CONFIG_ENABLE, regs + PL080_CONFIG);
printk(KERN_INFO "PL080: IRQ %d, at %p\n", irq, regs);
return 0;
err_clk:
clk_disable(dmac->clk);
clk_put(dmac->clk);
err_map:
iounmap(regs);
err_dev:
sysdev_unregister(&dmac->sysdev);
err_alloc:
kfree(dmac);
return err;
}
static int __init s3c64xx_dma_init(void)
{
int ret;
printk(KERN_INFO "%s: Registering DMA channels\n", __func__);
dma_pool = dma_pool_create("DMA-LLI", NULL, 32, 16, 0);
if (!dma_pool) {
printk(KERN_ERR "%s: failed to create pool\n", __func__);
return -ENOMEM;
}
ret = sysdev_class_register(&dma_sysclass);
if (ret) {
printk(KERN_ERR "%s: failed to create sysclass\n", __func__);
return -ENOMEM;
}
/* Set all DMA configuration to be DMA, not SDMA */
writel(0xffffff, S3C_SYSREG(0x110));
/* Register standard DMA controlers */
s3c64xx_dma_init1(0, DMACH_UART0, IRQ_DMA0, 0x75000000);
s3c64xx_dma_init1(8, DMACH_PCM1_TX, IRQ_DMA1, 0x75100000);
return 0;
}
arch_initcall(s3c64xx_dma_init);

View file

@ -0,0 +1,70 @@
/* linux/arch/arm/plat-s3c64xx/include/plat/dma-plat.h
*
* Copyright 2009 Openmoko, Inc.
* Copyright 2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* S3C64XX DMA core
*
* 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.
*/
#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
struct s3c64xx_dma_buff;
/** s3c64xx_dma_buff - S3C64XX DMA buffer descriptor
* @next: Pointer to next buffer in queue or ring.
* @pw: Client provided identifier
* @lli: Pointer to hardware descriptor this buffer is associated with.
* @lli_dma: Hardare address of the descriptor.
*/
struct s3c64xx_dma_buff {
struct s3c64xx_dma_buff *next;
void *pw;
struct pl080_lli *lli;
dma_addr_t lli_dma;
};
struct s3c64xx_dmac;
struct s3c2410_dma_chan {
unsigned char number; /* number of this dma channel */
unsigned char in_use; /* channel allocated */
unsigned char bit; /* bit for enable/disable/etc */
unsigned char hw_width;
unsigned char peripheral;
unsigned int flags;
enum s3c2410_dmasrc source;
dma_addr_t dev_addr;
struct s3c2410_dma_client *client;
struct s3c64xx_dmac *dmac; /* pointer to controller */
void __iomem *regs;
/* cdriver callbacks */
s3c2410_dma_cbfn_t callback_fn; /* buffer done callback */
s3c2410_dma_opfn_t op_fn; /* channel op callback */
/* buffer list and information */
struct s3c64xx_dma_buff *curr; /* current dma buffer */
struct s3c64xx_dma_buff *next; /* next buffer to load */
struct s3c64xx_dma_buff *end; /* end of queue */
/* note, when channel is running in circular mode, curr is the
* first buffer enqueued, end is the last and curr is where the
* last buffer-done event is set-at. The buffers are not freed
* and the last buffer hardware descriptor points back to the
* first.
*/
};
#include <plat/dma-core.h>

View file

@ -789,7 +789,7 @@ static void s3cmci_dma_setup(struct s3cmci_host *host,
last_source = source;
s3c2410_dma_devconfig(host->dma, source, 3,
s3c2410_dma_devconfig(host->dma, source,
host->mem->start + host->sdidata);
if (!setup_ok) {

View file

@ -218,24 +218,17 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
* sync to pclk, half-word transfers to the IIS-FIFO. */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
s3c2410_dma_devconfig(prtd->params->channel,
S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC |
S3C2410_DISRCC_APB, prtd->params->dma_addr);
s3c2410_dma_config(prtd->params->channel,
prtd->params->dma_size,
S3C2410_DCON_SYNC_PCLK |
S3C2410_DCON_HANDSHAKE);
S3C2410_DMASRC_MEM,
prtd->params->dma_addr);
} else {
s3c2410_dma_config(prtd->params->channel,
prtd->params->dma_size,
S3C2410_DCON_HANDSHAKE |
S3C2410_DCON_SYNC_PCLK);
s3c2410_dma_devconfig(prtd->params->channel,
S3C2410_DMASRC_HW, 0x3,
prtd->params->dma_addr);
S3C2410_DMASRC_HW,
prtd->params->dma_addr);
}
s3c2410_dma_config(prtd->params->channel,
prtd->params->dma_size);
/* flush the DMA channel */
s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
prtd->dma_loaded = 0;