mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
[ARM] 4177/1: S3C24XX: Add DMA channel allocation order
Allow the CPU code, and any board specific initialisation code to change the allocation order of the DMA channels, or stop a peripheral allocating any DMA at-all. This is due to the scarce mapping of DMA channels on some earlier S3C24XX cpus, where the selection changes depending on the channel in use. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
d2a76020e3
commit
0c6022d453
3 changed files with 117 additions and 3 deletions
46
Documentation/arm/Samsung-S3C24XX/DMA.txt
Normal file
46
Documentation/arm/Samsung-S3C24XX/DMA.txt
Normal file
|
@ -0,0 +1,46 @@
|
|||
S3C2410 DMA
|
||||
===========
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The kernel provides an interface to manage DMA transfers
|
||||
using the DMA channels in the cpu, so that the central
|
||||
duty of managing channel mappings, and programming the
|
||||
channel generators is in one place.
|
||||
|
||||
|
||||
DMA Channel Ordering
|
||||
--------------------
|
||||
|
||||
Many of the range do not have connections for the DMA
|
||||
channels to all sources, which means that some devices
|
||||
have a restricted number of channels that can be used.
|
||||
|
||||
To allow flexibilty for each cpu type and board, the
|
||||
dma code can be given an dma ordering structure which
|
||||
allows the order of channel search to be specified, as
|
||||
well as allowing the prohibition of certain claims.
|
||||
|
||||
struct s3c24xx_dma_order has a list of channels, and
|
||||
each channel within has a slot for a list of dma
|
||||
channel numbers. The slots are searched in order, for
|
||||
the presence of a dma channel number with DMA_CH_VALID
|
||||
orred in.
|
||||
|
||||
If the order has the flag DMA_CH_NEVER set, then after
|
||||
checking the channel list, the system will return no
|
||||
found channel, thus denying the request.
|
||||
|
||||
A board support file can call s3c24xx_dma_order_set()
|
||||
to register an complete ordering set. The routine will
|
||||
copy the data, so the original can be discared with
|
||||
__initdata.
|
||||
|
||||
|
||||
Authour
|
||||
-------
|
||||
|
||||
Ben Dooks,
|
||||
Copyright (c) 2007 Ben Dooks, Simtec Electronics
|
||||
Licensed under the GPL v2
|
|
@ -1354,18 +1354,22 @@ static inline int is_channel_valid(unsigned int channel)
|
|||
return (channel & DMA_CH_VALID);
|
||||
}
|
||||
|
||||
static struct s3c24xx_dma_order *dma_order;
|
||||
|
||||
|
||||
/* s3c2410_dma_map_channel()
|
||||
*
|
||||
* turn the virtual channel number into a real, and un-used hardware
|
||||
* channel.
|
||||
*
|
||||
* currently this code uses first-free channel from the specified harware
|
||||
* map, not taking into account anything that the board setup code may
|
||||
* have to say about the likely peripheral set to be in use.
|
||||
* first, try the dma ordering given to us by either the relevant
|
||||
* dma code, or the board. Then just find the first usable free
|
||||
* channel
|
||||
*/
|
||||
|
||||
struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
|
||||
{
|
||||
struct s3c24xx_dma_order_ch *ord = NULL;
|
||||
struct s3c24xx_dma_map *ch_map;
|
||||
struct s3c2410_dma_chan *dmach;
|
||||
int ch;
|
||||
|
@ -1375,6 +1379,27 @@ struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
|
|||
|
||||
ch_map = dma_sel.map + channel;
|
||||
|
||||
/* first, try the board mapping */
|
||||
|
||||
if (dma_order) {
|
||||
ord = &dma_order->channels[channel];
|
||||
|
||||
for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
|
||||
if (!is_channel_valid(ord->list[ch]))
|
||||
continue;
|
||||
|
||||
if (s3c2410_chans[ord->list[ch]].in_use == 0) {
|
||||
ch = ord->list[ch] & ~DMA_CH_VALID;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
if (ord->flags & DMA_CH_NEVER)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* second, search the channel map for first free */
|
||||
|
||||
for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
|
||||
if (!is_channel_valid(ch_map->channels[ch]))
|
||||
continue;
|
||||
|
@ -1390,6 +1415,7 @@ struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
|
|||
|
||||
/* update our channel mapping */
|
||||
|
||||
found:
|
||||
dmach = &s3c2410_chans[ch];
|
||||
dma_chan_map[channel] = dmach;
|
||||
|
||||
|
@ -1439,3 +1465,20 @@ int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord)
|
||||
{
|
||||
struct s3c24xx_dma_order *nord = dma_order;
|
||||
|
||||
if (nord == NULL)
|
||||
nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL);
|
||||
|
||||
if (nord == NULL) {
|
||||
printk(KERN_ERR "no memory to store dma channel order\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dma_order = nord;
|
||||
memcpy(nord, ord, sizeof(struct s3c24xx_dma_order));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ extern struct sysdev_class dma_sysclass;
|
|||
extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
|
||||
|
||||
#define DMA_CH_VALID (1<<31)
|
||||
#define DMA_CH_NEVER (1<<30)
|
||||
|
||||
struct s3c24xx_dma_addr {
|
||||
unsigned long from;
|
||||
|
@ -43,3 +44,27 @@ struct s3c24xx_dma_selection {
|
|||
};
|
||||
|
||||
extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
|
||||
|
||||
/* struct s3c24xx_dma_order_ch
|
||||
*
|
||||
* channel map for one of the `enum dma_ch` dma channels. the list
|
||||
* entry contains a set of low-level channel numbers, orred with
|
||||
* DMA_CH_VALID, which are checked in the order in the array.
|
||||
*/
|
||||
|
||||
struct s3c24xx_dma_order_ch {
|
||||
unsigned int list[S3C2410_DMA_CHANNELS]; /* list of channels */
|
||||
unsigned int flags; /* flags */
|
||||
};
|
||||
|
||||
/* struct s3c24xx_dma_order
|
||||
*
|
||||
* information provided by either the core or the board to give the
|
||||
* dma system a hint on how to allocate channels
|
||||
*/
|
||||
|
||||
struct s3c24xx_dma_order {
|
||||
struct s3c24xx_dma_order_ch channels[DMACH_MAX];
|
||||
};
|
||||
|
||||
extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
|
||||
|
|
Loading…
Reference in a new issue