diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-s3c2410/include/mach/dma.h | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c64xx/include/mach/dma.h | 4 | ||||
-rw-r--r-- | arch/arm/plat-samsung/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/plat-samsung/dma-ops.c | 131 | ||||
-rw-r--r-- | arch/arm/plat-samsung/include/plat/dma-ops.h | 63 | ||||
-rw-r--r-- | arch/arm/plat-samsung/include/plat/dma-pl330.h | 4 | ||||
-rw-r--r-- | arch/arm/plat-samsung/include/plat/dma.h | 1 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s3c-dma-ops.c | 133 |
8 files changed, 347 insertions, 3 deletions
diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h index b2b2a5bb275e..e61a91f88c52 100644 --- a/arch/arm/mach-s3c2410/include/mach/dma.h +++ b/arch/arm/mach-s3c2410/include/mach/dma.h | |||
@@ -13,7 +13,6 @@ | |||
13 | #ifndef __ASM_ARCH_DMA_H | 13 | #ifndef __ASM_ARCH_DMA_H |
14 | #define __ASM_ARCH_DMA_H __FILE__ | 14 | #define __ASM_ARCH_DMA_H __FILE__ |
15 | 15 | ||
16 | #include <plat/dma.h> | ||
17 | #include <linux/sysdev.h> | 16 | #include <linux/sysdev.h> |
18 | 17 | ||
19 | #define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ | 18 | #define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ |
@@ -51,6 +50,13 @@ enum dma_ch { | |||
51 | DMACH_MAX, /* the end entry */ | 50 | DMACH_MAX, /* the end entry */ |
52 | }; | 51 | }; |
53 | 52 | ||
53 | static inline bool samsung_dma_is_dmadev(void) | ||
54 | { | ||
55 | return false; | ||
56 | } | ||
57 | |||
58 | #include <plat/dma.h> | ||
59 | |||
54 | #define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */ | 60 | #define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */ |
55 | 61 | ||
56 | /* we have 4 dma channels */ | 62 | /* we have 4 dma channels */ |
diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index 0a5d9268a23e..49c3a53135d4 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h | |||
@@ -63,6 +63,10 @@ static __inline__ bool s3c_dma_has_circular(void) | |||
63 | return true; | 63 | return true; |
64 | } | 64 | } |
65 | 65 | ||
66 | static inline bool samsung_dma_is_dmadev(void) | ||
67 | { | ||
68 | return false; | ||
69 | } | ||
66 | #define S3C2410_DMAF_CIRCULAR (1 << 0) | 70 | #define S3C2410_DMAF_CIRCULAR (1 << 0) |
67 | 71 | ||
68 | #include <plat/dma.h> | 72 | #include <plat/dma.h> |
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index 853764ba8cc5..e2ee0b8a3763 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile | |||
@@ -63,9 +63,11 @@ obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o | |||
63 | 63 | ||
64 | # DMA support | 64 | # DMA support |
65 | 65 | ||
66 | obj-$(CONFIG_S3C_DMA) += dma.o | 66 | obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o |
67 | 67 | ||
68 | obj-$(CONFIG_S3C_PL330_DMA) += s3c-pl330.o | 68 | obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o |
69 | |||
70 | obj-$(CONFIG_S3C_PL330_DMA) += s3c-pl330.o s3c-dma-ops.o | ||
69 | 71 | ||
70 | # PM support | 72 | # PM support |
71 | 73 | ||
diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c new file mode 100644 index 000000000000..6e3d9abc9e2e --- /dev/null +++ b/arch/arm/plat-samsung/dma-ops.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* linux/arch/arm/plat-samsung/dma-ops.c | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * Samsung DMA Operations | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/amba/pl330.h> | ||
16 | #include <linux/scatterlist.h> | ||
17 | |||
18 | #include <mach/dma.h> | ||
19 | |||
20 | static inline bool pl330_filter(struct dma_chan *chan, void *param) | ||
21 | { | ||
22 | struct dma_pl330_peri *peri = chan->private; | ||
23 | return peri->peri_id == (unsigned)param; | ||
24 | } | ||
25 | |||
26 | static unsigned samsung_dmadev_request(enum dma_ch dma_ch, | ||
27 | struct samsung_dma_info *info) | ||
28 | { | ||
29 | struct dma_chan *chan; | ||
30 | dma_cap_mask_t mask; | ||
31 | struct dma_slave_config slave_config; | ||
32 | |||
33 | dma_cap_zero(mask); | ||
34 | dma_cap_set(info->cap, mask); | ||
35 | |||
36 | chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch); | ||
37 | |||
38 | if (info->direction == DMA_FROM_DEVICE) { | ||
39 | memset(&slave_config, 0, sizeof(struct dma_slave_config)); | ||
40 | slave_config.direction = info->direction; | ||
41 | slave_config.src_addr = info->fifo; | ||
42 | slave_config.src_addr_width = info->width; | ||
43 | slave_config.src_maxburst = 1; | ||
44 | dmaengine_slave_config(chan, &slave_config); | ||
45 | } else if (info->direction == DMA_TO_DEVICE) { | ||
46 | memset(&slave_config, 0, sizeof(struct dma_slave_config)); | ||
47 | slave_config.direction = info->direction; | ||
48 | slave_config.dst_addr = info->fifo; | ||
49 | slave_config.dst_addr_width = info->width; | ||
50 | slave_config.dst_maxburst = 1; | ||
51 | dmaengine_slave_config(chan, &slave_config); | ||
52 | } | ||
53 | |||
54 | return (unsigned)chan; | ||
55 | } | ||
56 | |||
57 | static int samsung_dmadev_release(unsigned ch, | ||
58 | struct s3c2410_dma_client *client) | ||
59 | { | ||
60 | dma_release_channel((struct dma_chan *)ch); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int samsung_dmadev_prepare(unsigned ch, | ||
66 | struct samsung_dma_prep_info *info) | ||
67 | { | ||
68 | struct scatterlist sg; | ||
69 | struct dma_chan *chan = (struct dma_chan *)ch; | ||
70 | struct dma_async_tx_descriptor *desc; | ||
71 | |||
72 | switch (info->cap) { | ||
73 | case DMA_SLAVE: | ||
74 | sg_init_table(&sg, 1); | ||
75 | sg_dma_len(&sg) = info->len; | ||
76 | sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)), | ||
77 | info->len, offset_in_page(info->buf)); | ||
78 | sg_dma_address(&sg) = info->buf; | ||
79 | |||
80 | desc = chan->device->device_prep_slave_sg(chan, | ||
81 | &sg, 1, info->direction, DMA_PREP_INTERRUPT); | ||
82 | break; | ||
83 | case DMA_CYCLIC: | ||
84 | desc = chan->device->device_prep_dma_cyclic(chan, | ||
85 | info->buf, info->len, info->period, info->direction); | ||
86 | break; | ||
87 | default: | ||
88 | dev_err(&chan->dev->device, "unsupported format\n"); | ||
89 | return -EFAULT; | ||
90 | } | ||
91 | |||
92 | if (!desc) { | ||
93 | dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); | ||
94 | return -EFAULT; | ||
95 | } | ||
96 | |||
97 | desc->callback = info->fp; | ||
98 | desc->callback_param = info->fp_param; | ||
99 | |||
100 | dmaengine_submit((struct dma_async_tx_descriptor *)desc); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static inline int samsung_dmadev_trigger(unsigned ch) | ||
106 | { | ||
107 | dma_async_issue_pending((struct dma_chan *)ch); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static inline int samsung_dmadev_flush(unsigned ch) | ||
113 | { | ||
114 | return dmaengine_terminate_all((struct dma_chan *)ch); | ||
115 | } | ||
116 | |||
117 | struct samsung_dma_ops dmadev_ops = { | ||
118 | .request = samsung_dmadev_request, | ||
119 | .release = samsung_dmadev_release, | ||
120 | .prepare = samsung_dmadev_prepare, | ||
121 | .trigger = samsung_dmadev_trigger, | ||
122 | .started = NULL, | ||
123 | .flush = samsung_dmadev_flush, | ||
124 | .stop = samsung_dmadev_flush, | ||
125 | }; | ||
126 | |||
127 | void *samsung_dmadev_get_ops(void) | ||
128 | { | ||
129 | return &dmadev_ops; | ||
130 | } | ||
131 | EXPORT_SYMBOL(samsung_dmadev_get_ops); | ||
diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h new file mode 100644 index 000000000000..4c1a363526cf --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/dma-ops.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* arch/arm/plat-samsung/include/plat/dma-ops.h | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * Samsung DMA support | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __SAMSUNG_DMA_OPS_H_ | ||
14 | #define __SAMSUNG_DMA_OPS_H_ __FILE__ | ||
15 | |||
16 | #include <linux/dmaengine.h> | ||
17 | |||
18 | struct samsung_dma_prep_info { | ||
19 | enum dma_transaction_type cap; | ||
20 | enum dma_data_direction direction; | ||
21 | dma_addr_t buf; | ||
22 | unsigned long period; | ||
23 | unsigned long len; | ||
24 | void (*fp)(void *data); | ||
25 | void *fp_param; | ||
26 | }; | ||
27 | |||
28 | struct samsung_dma_info { | ||
29 | enum dma_transaction_type cap; | ||
30 | enum dma_data_direction direction; | ||
31 | enum dma_slave_buswidth width; | ||
32 | dma_addr_t fifo; | ||
33 | struct s3c2410_dma_client *client; | ||
34 | }; | ||
35 | |||
36 | struct samsung_dma_ops { | ||
37 | unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info); | ||
38 | int (*release)(unsigned ch, struct s3c2410_dma_client *client); | ||
39 | int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info); | ||
40 | int (*trigger)(unsigned ch); | ||
41 | int (*started)(unsigned ch); | ||
42 | int (*flush)(unsigned ch); | ||
43 | int (*stop)(unsigned ch); | ||
44 | }; | ||
45 | |||
46 | extern void *samsung_dmadev_get_ops(void); | ||
47 | extern void *s3c_dma_get_ops(void); | ||
48 | |||
49 | static inline void *__samsung_dma_get_ops(void) | ||
50 | { | ||
51 | if (samsung_dma_is_dmadev()) | ||
52 | return samsung_dmadev_get_ops(); | ||
53 | else | ||
54 | return s3c_dma_get_ops(); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * samsung_dma_get_ops | ||
59 | * get the set of samsung dma operations | ||
60 | */ | ||
61 | #define samsung_dma_get_ops() __samsung_dma_get_ops() | ||
62 | |||
63 | #endif /* __SAMSUNG_DMA_OPS_H_ */ | ||
diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h index 0a5dade0e85c..2916920034f0 100644 --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h | |||
@@ -93,6 +93,10 @@ static inline bool s3c_dma_has_circular(void) | |||
93 | return true; | 93 | return true; |
94 | } | 94 | } |
95 | 95 | ||
96 | static inline bool samsung_dma_is_dmadev(void) | ||
97 | { | ||
98 | return true; | ||
99 | } | ||
96 | #include <plat/dma.h> | 100 | #include <plat/dma.h> |
97 | 101 | ||
98 | #endif /* __DMA_PL330_H_ */ | 102 | #endif /* __DMA_PL330_H_ */ |
diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h index 8c273b7a6f56..361076060744 100644 --- a/arch/arm/plat-samsung/include/plat/dma.h +++ b/arch/arm/plat-samsung/include/plat/dma.h | |||
@@ -126,3 +126,4 @@ extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn); | |||
126 | extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn); | 126 | extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn); |
127 | 127 | ||
128 | 128 | ||
129 | #include <plat/dma-ops.h> | ||
diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c new file mode 100644 index 000000000000..33ab3241268d --- /dev/null +++ b/arch/arm/plat-samsung/s3c-dma-ops.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* linux/arch/arm/plat-samsung/s3c-dma-ops.c | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * Samsung S3C-DMA Operations | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/types.h> | ||
17 | |||
18 | #include <mach/dma.h> | ||
19 | |||
20 | struct cb_data { | ||
21 | void (*fp) (void *); | ||
22 | void *fp_param; | ||
23 | unsigned ch; | ||
24 | struct list_head node; | ||
25 | }; | ||
26 | |||
27 | static LIST_HEAD(dma_list); | ||
28 | |||
29 | static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param, | ||
30 | int size, enum s3c2410_dma_buffresult res) | ||
31 | { | ||
32 | struct cb_data *data = param; | ||
33 | |||
34 | data->fp(data->fp_param); | ||
35 | } | ||
36 | |||
37 | static unsigned s3c_dma_request(enum dma_ch dma_ch, | ||
38 | struct samsung_dma_info *info) | ||
39 | { | ||
40 | struct cb_data *data; | ||
41 | |||
42 | if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) { | ||
43 | s3c2410_dma_free(dma_ch, info->client); | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | data = kzalloc(sizeof(struct cb_data), GFP_KERNEL); | ||
48 | data->ch = dma_ch; | ||
49 | list_add_tail(&data->node, &dma_list); | ||
50 | |||
51 | if (info->direction == DMA_FROM_DEVICE) | ||
52 | s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_HW, info->fifo); | ||
53 | else | ||
54 | s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_MEM, info->fifo); | ||
55 | |||
56 | if (info->cap == DMA_CYCLIC) | ||
57 | s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR); | ||
58 | |||
59 | s3c2410_dma_config(dma_ch, info->width); | ||
60 | |||
61 | return (unsigned)dma_ch; | ||
62 | } | ||
63 | |||
64 | static int s3c_dma_release(unsigned ch, struct s3c2410_dma_client *client) | ||
65 | { | ||
66 | struct cb_data *data; | ||
67 | |||
68 | list_for_each_entry(data, &dma_list, node) | ||
69 | if (data->ch == ch) | ||
70 | break; | ||
71 | list_del(&data->node); | ||
72 | |||
73 | s3c2410_dma_free(ch, client); | ||
74 | kfree(data); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep_info *info) | ||
80 | { | ||
81 | struct cb_data *data; | ||
82 | int len = (info->cap == DMA_CYCLIC) ? info->period : info->len; | ||
83 | |||
84 | list_for_each_entry(data, &dma_list, node) | ||
85 | if (data->ch == ch) | ||
86 | break; | ||
87 | |||
88 | if (!data->fp) { | ||
89 | s3c2410_dma_set_buffdone_fn(ch, s3c_dma_cb); | ||
90 | data->fp = info->fp; | ||
91 | data->fp_param = info->fp_param; | ||
92 | } | ||
93 | |||
94 | s3c2410_dma_enqueue(ch, (void *)data, info->buf, len); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static inline int s3c_dma_trigger(unsigned ch) | ||
100 | { | ||
101 | return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START); | ||
102 | } | ||
103 | |||
104 | static inline int s3c_dma_started(unsigned ch) | ||
105 | { | ||
106 | return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED); | ||
107 | } | ||
108 | |||
109 | static inline int s3c_dma_flush(unsigned ch) | ||
110 | { | ||
111 | return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH); | ||
112 | } | ||
113 | |||
114 | static inline int s3c_dma_stop(unsigned ch) | ||
115 | { | ||
116 | return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP); | ||
117 | } | ||
118 | |||
119 | static struct samsung_dma_ops s3c_dma_ops = { | ||
120 | .request = s3c_dma_request, | ||
121 | .release = s3c_dma_release, | ||
122 | .prepare = s3c_dma_prepare, | ||
123 | .trigger = s3c_dma_trigger, | ||
124 | .started = s3c_dma_started, | ||
125 | .flush = s3c_dma_flush, | ||
126 | .stop = s3c_dma_stop, | ||
127 | }; | ||
128 | |||
129 | void *s3c_dma_get_ops(void) | ||
130 | { | ||
131 | return &s3c_dma_ops; | ||
132 | } | ||
133 | EXPORT_SYMBOL(s3c_dma_get_ops); | ||