aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2007-02-13 07:02:52 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-02-14 10:04:22 -0500
commit0c6022d453ecebdace0ce15434c7108e158149ca (patch)
tree153ce6dd661059601fa8591d36e0b81c6663566a
parentd2a76020e3a52c6370a7d603082b4cdb3db0703e (diff)
[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>
-rw-r--r--Documentation/arm/Samsung-S3C24XX/DMA.txt46
-rw-r--r--arch/arm/plat-s3c24xx/dma.c49
-rw-r--r--include/asm-arm/plat-s3c24xx/dma.h25
3 files changed, 117 insertions, 3 deletions
diff --git a/Documentation/arm/Samsung-S3C24XX/DMA.txt b/Documentation/arm/Samsung-S3C24XX/DMA.txt
new file mode 100644
index 000000000000..37f4edcc5d87
--- /dev/null
+++ b/Documentation/arm/Samsung-S3C24XX/DMA.txt
@@ -0,0 +1,46 @@
1 S3C2410 DMA
2 ===========
3
4Introduction
5------------
6
7 The kernel provides an interface to manage DMA transfers
8 using the DMA channels in the cpu, so that the central
9 duty of managing channel mappings, and programming the
10 channel generators is in one place.
11
12
13DMA Channel Ordering
14--------------------
15
16 Many of the range do not have connections for the DMA
17 channels to all sources, which means that some devices
18 have a restricted number of channels that can be used.
19
20 To allow flexibilty for each cpu type and board, the
21 dma code can be given an dma ordering structure which
22 allows the order of channel search to be specified, as
23 well as allowing the prohibition of certain claims.
24
25 struct s3c24xx_dma_order has a list of channels, and
26 each channel within has a slot for a list of dma
27 channel numbers. The slots are searched in order, for
28 the presence of a dma channel number with DMA_CH_VALID
29 orred in.
30
31 If the order has the flag DMA_CH_NEVER set, then after
32 checking the channel list, the system will return no
33 found channel, thus denying the request.
34
35 A board support file can call s3c24xx_dma_order_set()
36 to register an complete ordering set. The routine will
37 copy the data, so the original can be discared with
38 __initdata.
39
40
41Authour
42-------
43
44Ben Dooks,
45Copyright (c) 2007 Ben Dooks, Simtec Electronics
46Licensed under the GPL v2
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index c784e1f816bb..44e39438b9d8 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -1354,18 +1354,22 @@ static inline int is_channel_valid(unsigned int channel)
1354 return (channel & DMA_CH_VALID); 1354 return (channel & DMA_CH_VALID);
1355} 1355}
1356 1356
1357static struct s3c24xx_dma_order *dma_order;
1358
1359
1357/* s3c2410_dma_map_channel() 1360/* s3c2410_dma_map_channel()
1358 * 1361 *
1359 * turn the virtual channel number into a real, and un-used hardware 1362 * turn the virtual channel number into a real, and un-used hardware
1360 * channel. 1363 * channel.
1361 * 1364 *
1362 * currently this code uses first-free channel from the specified harware 1365 * first, try the dma ordering given to us by either the relevant
1363 * map, not taking into account anything that the board setup code may 1366 * dma code, or the board. Then just find the first usable free
1364 * have to say about the likely peripheral set to be in use. 1367 * channel
1365*/ 1368*/
1366 1369
1367struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) 1370struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
1368{ 1371{
1372 struct s3c24xx_dma_order_ch *ord = NULL;
1369 struct s3c24xx_dma_map *ch_map; 1373 struct s3c24xx_dma_map *ch_map;
1370 struct s3c2410_dma_chan *dmach; 1374 struct s3c2410_dma_chan *dmach;
1371 int ch; 1375 int ch;
@@ -1375,6 +1379,27 @@ struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
1375 1379
1376 ch_map = dma_sel.map + channel; 1380 ch_map = dma_sel.map + channel;
1377 1381
1382 /* first, try the board mapping */
1383
1384 if (dma_order) {
1385 ord = &dma_order->channels[channel];
1386
1387 for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
1388 if (!is_channel_valid(ord->list[ch]))
1389 continue;
1390
1391 if (s3c2410_chans[ord->list[ch]].in_use == 0) {
1392 ch = ord->list[ch] & ~DMA_CH_VALID;
1393 goto found;
1394 }
1395 }
1396
1397 if (ord->flags & DMA_CH_NEVER)
1398 return NULL;
1399 }
1400
1401 /* second, search the channel map for first free */
1402
1378 for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) { 1403 for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
1379 if (!is_channel_valid(ch_map->channels[ch])) 1404 if (!is_channel_valid(ch_map->channels[ch]))
1380 continue; 1405 continue;
@@ -1390,6 +1415,7 @@ struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
1390 1415
1391 /* update our channel mapping */ 1416 /* update our channel mapping */
1392 1417
1418 found:
1393 dmach = &s3c2410_chans[ch]; 1419 dmach = &s3c2410_chans[ch];
1394 dma_chan_map[channel] = dmach; 1420 dma_chan_map[channel] = dmach;
1395 1421
@@ -1439,3 +1465,20 @@ int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
1439 1465
1440 return 0; 1466 return 0;
1441} 1467}
1468
1469int __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord)
1470{
1471 struct s3c24xx_dma_order *nord = dma_order;
1472
1473 if (nord == NULL)
1474 nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL);
1475
1476 if (nord == NULL) {
1477 printk(KERN_ERR "no memory to store dma channel order\n");
1478 return -ENOMEM;
1479 }
1480
1481 dma_order = nord;
1482 memcpy(nord, ord, sizeof(struct s3c24xx_dma_order));
1483 return 0;
1484}
diff --git a/include/asm-arm/plat-s3c24xx/dma.h b/include/asm-arm/plat-s3c24xx/dma.h
index 421b567fa019..15e140c2d4fc 100644
--- a/include/asm-arm/plat-s3c24xx/dma.h
+++ b/include/asm-arm/plat-s3c24xx/dma.h
@@ -14,6 +14,7 @@ extern struct sysdev_class dma_sysclass;
14extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; 14extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
15 15
16#define DMA_CH_VALID (1<<31) 16#define DMA_CH_VALID (1<<31)
17#define DMA_CH_NEVER (1<<30)
17 18
18struct s3c24xx_dma_addr { 19struct s3c24xx_dma_addr {
19 unsigned long from; 20 unsigned long from;
@@ -43,3 +44,27 @@ struct s3c24xx_dma_selection {
43}; 44};
44 45
45extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel); 46extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
47
48/* struct s3c24xx_dma_order_ch
49 *
50 * channel map for one of the `enum dma_ch` dma channels. the list
51 * entry contains a set of low-level channel numbers, orred with
52 * DMA_CH_VALID, which are checked in the order in the array.
53*/
54
55struct s3c24xx_dma_order_ch {
56 unsigned int list[S3C2410_DMA_CHANNELS]; /* list of channels */
57 unsigned int flags; /* flags */
58};
59
60/* struct s3c24xx_dma_order
61 *
62 * information provided by either the core or the board to give the
63 * dma system a hint on how to allocate channels
64*/
65
66struct s3c24xx_dma_order {
67 struct s3c24xx_dma_order_ch channels[DMACH_MAX];
68};
69
70extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);