mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 17:01:14 +00:00
[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:
commit
bcb8a0d6f5
22 changed files with 1476 additions and 378 deletions
138
arch/arm/include/asm/hardware/pl080.h
Normal file
138
arch/arm/include/asm/hardware/pl080.h
Normal 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;
|
||||
};
|
||||
|
|
@ -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>
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
86
arch/arm/plat-s3c/dma.c
Normal 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);
|
22
arch/arm/plat-s3c/include/plat/dma-core.h
Normal file
22
arch/arm/plat-s3c/include/plat/dma-core.h
Normal 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[];
|
||||
|
||||
|
127
arch/arm/plat-s3c/include/plat/dma.h
Normal file
127
arch/arm/plat-s3c/include/plat/dma.h
Normal 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);
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
145
arch/arm/plat-s3c24xx/include/plat/regs-dma.h
Normal file
145
arch/arm/plat-s3c24xx/include/plat/regs-dma.h
Normal 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)
|
|
@ -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
|
||||
|
|
|
@ -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
722
arch/arm/plat-s3c64xx/dma.c
Normal 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);
|
70
arch/arm/plat-s3c64xx/include/plat/dma-plat.h
Normal file
70
arch/arm/plat-s3c64xx/include/plat/dma-plat.h
Normal 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>
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue