From e8689e63d4d2046079f2db9d494ac05c6885ac0c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 28 Sep 2010 15:57:37 +0200 Subject: dmaengine: driver for the ARM PL080/PL081 PrimeCells v5 This creates a DMAengine driver for the ARM PL080/PL081 PrimeCells based on the implementation earlier submitted by Peter Pearse. This is working like a charm for memcpy and slave DMA to the PL011 PrimeCell on the PB11MPCore. This DMA controller is used in mostly unmodified form in the ARM RealView and Versatile platforms, in the ST-Ericsson Nomadik, and in the ST SPEAr platform. It has been converted to use the header from the Samsung PL080 derivate instead of its own defintions. The Samsungs have a custom driver in their mach-* folders though, atleast we can share the register definitions. Cc: Peter Pearse Cc: Ben Dooks Cc: Kukjin Kim Cc: Alessandro Rubini Acked-by: Viresh Kumar Signed-off-by: Linus Walleij [GFP_KERNEL to GFP_NOWAIT in pl08x_prep_dma_memcpy] Signed-off-by: Dan Williams --- include/linux/amba/pl08x.h | 222 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 include/linux/amba/pl08x.h (limited to 'include') diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h new file mode 100644 index 000000000000..521a0f8974ac --- /dev/null +++ b/include/linux/amba/pl08x.h @@ -0,0 +1,222 @@ +/* + * linux/amba/pl08x.h - ARM PrimeCell DMA Controller driver + * + * Copyright (C) 2005 ARM Ltd + * Copyright (C) 2010 ST-Ericsson SA + * + * 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. + * + * pl08x information required by platform code + * + * Please credit ARM.com + * Documentation: ARM DDI 0196D + * + */ + +#ifndef AMBA_PL08X_H +#define AMBA_PL08X_H + +/* We need sizes of structs from this header */ +#include +#include + +/** + * struct pl08x_channel_data - data structure to pass info between + * platform and PL08x driver regarding channel configuration + * @bus_id: name of this device channel, not just a device name since + * devices may have more than one channel e.g. "foo_tx" + * @min_signal: the minimum DMA signal number to be muxed in for this + * channel (for platforms supporting muxed signals). If you have + * static assignments, make sure this is set to the assigned signal + * number, PL08x have 16 possible signals in number 0 thru 15 so + * when these are not enough they often get muxed (in hardware) + * disabling simultaneous use of the same channel for two devices. + * @max_signal: the maximum DMA signal number to be muxed in for + * the channel. Set to the same as min_signal for + * devices with static assignments + * @muxval: a number usually used to poke into some mux regiser to + * mux in the signal to this channel + * @cctl_opt: default options for the channel control register + * @addr: source/target address in physical memory for this DMA channel, + * can be the address of a FIFO register for burst requests for example. + * This can be left undefined if the PrimeCell API is used for configuring + * this. + * @circular_buffer: whether the buffer passed in is circular and + * shall simply be looped round round (like a record baby round + * round round round) + * @single: the device connected to this channel will request single + * DMA transfers, not bursts. (Bursts are default.) + */ +struct pl08x_channel_data { + char *bus_id; + int min_signal; + int max_signal; + u32 muxval; + u32 cctl; + u32 ccfg; + dma_addr_t addr; + bool circular_buffer; + bool single; +}; + +/** + * Struct pl08x_bus_data - information of source or destination + * busses for a transfer + * @addr: current address + * @maxwidth: the maximum width of a transfer on this bus + * @buswidth: the width of this bus in bytes: 1, 2 or 4 + * @fill_bytes: bytes required to fill to the next bus memory + * boundary + */ +struct pl08x_bus_data { + dma_addr_t addr; + u8 maxwidth; + u8 buswidth; + u32 fill_bytes; +}; + +/** + * struct pl08x_phy_chan - holder for the physical channels + * @id: physical index to this channel + * @lock: a lock to use when altering an instance of this struct + * @signal: the physical signal (aka channel) serving this + * physical channel right now + * @serving: the virtual channel currently being served by this + * physical channel + */ +struct pl08x_phy_chan { + unsigned int id; + void __iomem *base; + spinlock_t lock; + int signal; + struct pl08x_dma_chan *serving; + u32 csrc; + u32 cdst; + u32 clli; + u32 cctl; + u32 ccfg; +}; + +/** + * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor + * @llis_bus: DMA memory address (physical) start for the LLIs + * @llis_va: virtual memory address start for the LLIs + */ +struct pl08x_txd { + struct dma_async_tx_descriptor tx; + struct list_head node; + enum dma_data_direction direction; + struct pl08x_bus_data srcbus; + struct pl08x_bus_data dstbus; + int len; + dma_addr_t llis_bus; + void *llis_va; + struct pl08x_channel_data *cd; + bool active; + /* + * Settings to be put into the physical channel when we + * trigger this txd + */ + u32 csrc; + u32 cdst; + u32 clli; + u32 cctl; +}; + +/** + * struct pl08x_dma_chan_state - holds the PL08x specific virtual + * channel states + * @PL08X_CHAN_IDLE: the channel is idle + * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport + * channel and is running a transfer on it + * @PL08X_CHAN_PAUSED: the channel has allocated a physical transport + * channel, but the transfer is currently paused + * @PL08X_CHAN_WAITING: the channel is waiting for a physical transport + * channel to become available (only pertains to memcpy channels) + */ +enum pl08x_dma_chan_state { + PL08X_CHAN_IDLE, + PL08X_CHAN_RUNNING, + PL08X_CHAN_PAUSED, + PL08X_CHAN_WAITING, +}; + +/** + * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel + * @chan: wrappped abstract channel + * @phychan: the physical channel utilized by this channel, if there is one + * @tasklet: tasklet scheduled by the IRQ to handle actual work etc + * @name: name of channel + * @cd: channel platform data + * @runtime_addr: address for RX/TX according to the runtime config + * @runtime_direction: current direction of this channel according to + * runtime config + * @lc: last completed transaction on this channel + * @desc_list: queued transactions pending on this channel + * @at: active transaction on this channel + * @lockflags: sometimes we let a lock last between two function calls, + * especially prep/submit, and then we need to store the IRQ flags + * in the channel state, here + * @lock: a lock for this channel data + * @host: a pointer to the host (internal use) + * @state: whether the channel is idle, paused, running etc + * @slave: whether this channel is a device (slave) or for memcpy + * @waiting: a TX descriptor on this channel which is waiting for + * a physical channel to become available + */ +struct pl08x_dma_chan { + struct dma_chan chan; + struct pl08x_phy_chan *phychan; + struct tasklet_struct tasklet; + char *name; + struct pl08x_channel_data *cd; + dma_addr_t runtime_addr; + enum dma_data_direction runtime_direction; + atomic_t last_issued; + dma_cookie_t lc; + struct list_head desc_list; + struct pl08x_txd *at; + unsigned long lockflags; + spinlock_t lock; + void *host; + enum pl08x_dma_chan_state state; + bool slave; + struct pl08x_txd *waiting; +}; + +/** + * struct pl08x_platform_data - the platform configuration for the + * PL08x PrimeCells. + * @slave_channels: the channels defined for the different devices on the + * platform, all inclusive, including multiplexed channels. The available + * physical channels will be multiplexed around these signals as they + * are requested, just enumerate all possible channels. + * @get_signal: request a physical signal to be used for a DMA + * transfer immediately: if there is some multiplexing or similar blocking + * the use of the channel the transfer can be denied by returning + * less than zero, else it returns the allocated signal number + * @put_signal: indicate to the platform that this physical signal is not + * running any DMA transfer and multiplexing can be recycled + * @bus_bit_lli: Bit[0] of the address indicated which AHB bus master the + * LLI addresses are on 0/1 Master 1/2. + */ +struct pl08x_platform_data { + struct pl08x_channel_data *slave_channels; + unsigned int num_slave_channels; + struct pl08x_channel_data memcpy_channel; + int (*get_signal)(struct pl08x_dma_chan *); + void (*put_signal)(struct pl08x_dma_chan *); +}; + +#ifdef CONFIG_AMBA_PL08X +bool pl08x_filter_id(struct dma_chan *chan, void *chan_id); +#else +static inline bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) +{ + return false; +} +#endif + +#endif /* AMBA_PL08X_H */ -- cgit v1.2.3 From 782bc950d84e404422ba21008fd51ee894c8d231 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 30 Sep 2010 13:56:32 +0000 Subject: dmaengine: add possibility for cyclic transfers Cyclic transfers are useful for audio where a single buffer divided in periods has to be transfered endlessly until stopped. After being prepared the transfer is started using the dma_async_descriptor->tx_submit function. dma_async_descriptor->callback is called after each period. The transfer is stopped using the DMA_TERMINATE_ALL callback. While being used for cyclic transfers the channel cannot be used for other transfer types. Signed-off-by: Sascha Hauer Cc: Haavard Skinnemoen Signed-off-by: Dan Williams --- include/linux/dmaengine.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index c61d4ca27bcc..32cd84b47478 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -67,10 +67,11 @@ enum dma_transaction_type { DMA_PRIVATE, DMA_ASYNC_TX, DMA_SLAVE, + DMA_CYCLIC, }; /* last transaction type for creation of the capabilities mask */ -#define DMA_TX_TYPE_END (DMA_SLAVE + 1) +#define DMA_TX_TYPE_END (DMA_CYCLIC + 1) /** @@ -422,6 +423,9 @@ struct dma_tx_state { * @device_prep_dma_memset: prepares a memset operation * @device_prep_dma_interrupt: prepares an end of chain interrupt operation * @device_prep_slave_sg: prepares a slave dma operation + * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio. + * The function takes a buffer of size buf_len. The callback function will + * be called after period_len bytes have been transferred. * @device_control: manipulate all pending operations on a channel, returns * zero or error code * @device_tx_status: poll for transaction completion, the optional @@ -478,6 +482,9 @@ struct dma_device { struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_data_direction direction, unsigned long flags); + struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)( + struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_data_direction direction); int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg); -- cgit v1.2.3 From 6e3ecaf0ad49de0bed829d409a164e7107c02993 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 30 Sep 2010 13:56:33 +0000 Subject: dmaengine: add wrapper functions for device control functions Add wrapper functions around the dma_device->device_control function to bring back type safety. Also, add a wrapper function around dma_async_tx_descriptor->tx_submit. This is named dmaengine_submit instead of dmaengine_tx_submit to get rid of the confusing 'tx' in the function name Signed-off-by: Sascha Hauer Signed-off-by: Dan Williams --- include/linux/dmaengine.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 32cd84b47478..2218fdcbe8a9 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -494,6 +494,40 @@ struct dma_device { void (*device_issue_pending)(struct dma_chan *chan); }; +static inline int dmaengine_device_control(struct dma_chan *chan, + enum dma_ctrl_cmd cmd, + unsigned long arg) +{ + return chan->device->device_control(chan, cmd, arg); +} + +static inline int dmaengine_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + return dmaengine_device_control(chan, DMA_SLAVE_CONFIG, + (unsigned long)config); +} + +static inline int dmaengine_terminate_all(struct dma_chan *chan) +{ + return dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); +} + +static inline int dmaengine_pause(struct dma_chan *chan) +{ + return dmaengine_device_control(chan, DMA_PAUSE, 0); +} + +static inline int dmaengine_resume(struct dma_chan *chan) +{ + return dmaengine_device_control(chan, DMA_RESUME, 0); +} + +static inline int dmaengine_submit(struct dma_async_tx_descriptor *desc) +{ + return desc->tx_submit(desc); +} + static inline bool dmaengine_check_align(u8 align, size_t off1, size_t off2, size_t len) { size_t mask; -- cgit v1.2.3 From a86ee03ce6f279ebe581a7a8c0c4393eaeb789ee Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 30 Sep 2010 11:46:44 +0000 Subject: dma: add support for scatterlist to scatterlist copy This adds support for scatterlist to scatterlist DMA transfers. A similar interface is exposed by the fsldma driver (through the DMA_SLAVE API) and by the ste_dma40 driver (through an exported function). This patch paves the way for making this type of copy operation a part of the generic DMAEngine API. Futher patches will add support in individual drivers. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- include/linux/dmaengine.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index e2106495cc11..2c9ee98f6c77 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -64,6 +64,7 @@ enum dma_transaction_type { DMA_PQ_VAL, DMA_MEMSET, DMA_INTERRUPT, + DMA_SG, DMA_PRIVATE, DMA_ASYNC_TX, DMA_SLAVE, @@ -473,6 +474,11 @@ struct dma_device { unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( struct dma_chan *chan, unsigned long flags); + struct dma_async_tx_descriptor *(*device_prep_dma_sg)( + struct dma_chan *chan, + struct scatterlist *dst_sg, unsigned int dst_nents, + struct scatterlist *src_sg, unsigned int src_nents, + unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_slave_sg)( struct dma_chan *chan, struct scatterlist *sgl, -- cgit v1.2.3 From 968f19ae802fdc6b6b6b5af6fe79cf23d281be0f Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 30 Sep 2010 11:46:46 +0000 Subject: fsldma: improved DMA_SLAVE support Now that the generic DMAEngine API has support for scatterlist to scatterlist copying, the device_prep_slave_sg() portion of the DMA_SLAVE API is no longer necessary and has been removed. However, the device_control() portion of the DMA_SLAVE API is still useful to control device specific parameters, such as externally controlled DMA transfers and maximum burst length. A special dma_ctrl_cmd has been added to enable externally controlled DMA transfers. This is currently specific to the Freescale DMA controller, but can easily be made generic when another user is found. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- include/linux/dmaengine.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 2c9ee98f6c77..885f35211675 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -120,12 +120,15 @@ enum dma_ctrl_flags { * configuration data in statically from the platform). An additional * argument of struct dma_slave_config must be passed in with this * command. + * @FSLDMA_EXTERNAL_START: this command will put the Freescale DMA controller + * into external start mode. */ enum dma_ctrl_cmd { DMA_TERMINATE_ALL, DMA_PAUSE, DMA_RESUME, DMA_SLAVE_CONFIG, + FSLDMA_EXTERNAL_START, }; /** -- cgit v1.2.3 From 576e3c394a6c427c9a1378ec88ef7eb97e731992 Mon Sep 17 00:00:00 2001 From: Ramesh Babu K V Date: Mon, 4 Oct 2010 10:37:53 +0000 Subject: intel_mid_dma: Add sg list support to DMA driver For a very high speed DMA various periphral devices need scatter-gather list support. The DMA hardware support link list items. This list can be circular also (adding new flag DMA_PREP_CIRCULAR_LIST) Right now this flag is in driver header and should be moved to dmaengine header file eventually Signed-off-by: Ramesh Babu K V Signed-off-by: Vinod Koul Signed-off-by: Dan Williams --- include/linux/intel_mid_dma.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/intel_mid_dma.h b/include/linux/intel_mid_dma.h index d9d08b6269b6..befe3fbd9e28 100644 --- a/include/linux/intel_mid_dma.h +++ b/include/linux/intel_mid_dma.h @@ -27,6 +27,7 @@ #include +#define DMA_PREP_CIRCULAR_LIST (1 << 10) /*DMA transaction width, src and dstn width would be same The DMA length must be width aligned, for 32 bit width the length must be 32 bit (4bytes) aligned only*/ @@ -69,6 +70,7 @@ enum intel_mid_dma_msize { * @cfg_mode: DMA data transfer mode (per-per/mem-per/mem-mem) * @src_msize: Source DMA burst size * @dst_msize: Dst DMA burst size + * @per_addr: Periphral address * @device_instance: DMA peripheral device instance, we can have multiple * peripheral device connected to single DMAC */ @@ -80,6 +82,7 @@ struct intel_mid_dma_slave { enum intel_mid_dma_mode cfg_mode; /*mode configuration*/ enum intel_mid_dma_msize src_msize; /*size if src burst*/ enum intel_mid_dma_msize dst_msize; /*size of dst burst*/ + dma_addr_t per_addr; /*Peripheral address*/ unsigned int device_instance; /*0, 1 for periphral instance*/ }; -- cgit v1.2.3 From 20dd63900d238e17b122fe0c7376ff090867f528 Mon Sep 17 00:00:00 2001 From: "Koul, Vinod" Date: Mon, 4 Oct 2010 10:38:43 +0000 Subject: intel_mid_dma: change the slave interface In 2.6.36 kernel, dma slave control command was introduced, this patch changes the intel-mid-dma driver to this new kernel slave interface Signed-off-by: Vinod Koul Signed-off-by: Dan Williams --- include/linux/intel_mid_dma.h | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'include') diff --git a/include/linux/intel_mid_dma.h b/include/linux/intel_mid_dma.h index befe3fbd9e28..10496bd24c5c 100644 --- a/include/linux/intel_mid_dma.h +++ b/include/linux/intel_mid_dma.h @@ -28,14 +28,6 @@ #include #define DMA_PREP_CIRCULAR_LIST (1 << 10) -/*DMA transaction width, src and dstn width would be same -The DMA length must be width aligned, -for 32 bit width the length must be 32 bit (4bytes) aligned only*/ -enum intel_mid_dma_width { - LNW_DMA_WIDTH_8BIT = 0x0, - LNW_DMA_WIDTH_16BIT = 0x1, - LNW_DMA_WIDTH_32BIT = 0x2, -}; /*DMA mode configurations*/ enum intel_mid_dma_mode { @@ -75,15 +67,10 @@ enum intel_mid_dma_msize { * peripheral device connected to single DMAC */ struct intel_mid_dma_slave { - enum dma_data_direction dirn; - enum intel_mid_dma_width src_width; /*width of DMA src txn*/ - enum intel_mid_dma_width dst_width; /*width of DMA dst txn*/ enum intel_mid_dma_hs_mode hs_mode; /*handshaking*/ enum intel_mid_dma_mode cfg_mode; /*mode configuration*/ - enum intel_mid_dma_msize src_msize; /*size if src burst*/ - enum intel_mid_dma_msize dst_msize; /*size of dst burst*/ - dma_addr_t per_addr; /*Peripheral address*/ unsigned int device_instance; /*0, 1 for periphral instance*/ + struct dma_slave_config dma_slave; }; #endif /*__INTEL_MID_DMA_H__*/ -- cgit v1.2.3 From 5fc6d897fde352bad5db5767e7260741a8cdd9e9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 7 Oct 2010 16:44:50 -0700 Subject: async_tx: make async_tx channel switching opt-in The majority of drivers in drivers/dma/ will never establish cross channel operation chains and do not need the extra overhead in struct dma_async_tx_descriptor. Make channel switching opt-in by default. Cc: Anatolij Gustschin Cc: Ira Snyder Cc: Linus Walleij Cc: Saeed Bishara Signed-off-by: Dan Williams --- include/linux/dmaengine.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 3934ebdd85c2..9d8688b92d8b 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -321,14 +321,14 @@ struct dma_async_tx_descriptor { dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx); dma_async_tx_callback callback; void *callback_param; -#ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH +#ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH struct dma_async_tx_descriptor *next; struct dma_async_tx_descriptor *parent; spinlock_t lock; #endif }; -#ifdef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH +#ifndef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH static inline void txd_lock(struct dma_async_tx_descriptor *txd) { } @@ -656,11 +656,11 @@ static inline void net_dmaengine_put(void) #ifdef CONFIG_ASYNC_TX_DMA #define async_dmaengine_get() dmaengine_get() #define async_dmaengine_put() dmaengine_put() -#ifdef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH +#ifndef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH #define async_dma_find_channel(type) dma_find_channel(DMA_ASYNC_TX) #else #define async_dma_find_channel(type) dma_find_channel(type) -#endif /* CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH */ +#endif /* CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH */ #else static inline void async_dmaengine_get(void) { -- cgit v1.2.3