Merge tag 'u-boot-amlogic-20181207' of git://git.denx.de/u-boot-amlogic
[oweals/u-boot.git] / drivers / dma / sandbox-dma-test.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Direct Memory Access U-Class Simulation driver
4  *
5  * Copyright (C) 2018 Texas Instruments Incorporated <www.ti.com>
6  *
7  * Author: Grygorii Strashko <grygorii.strashko@ti.com>
8  */
9
10 #include <common.h>
11 #include <dm.h>
12 #include <dm/read.h>
13 #include <dma-uclass.h>
14 #include <dt-structs.h>
15 #include <errno.h>
16
17 #define SANDBOX_DMA_CH_CNT 3
18 #define SANDBOX_DMA_BUF_SIZE 1024
19
20 struct sandbox_dma_chan {
21         struct sandbox_dma_dev *ud;
22         char name[20];
23         u32 id;
24         enum dma_direction dir;
25         bool in_use;
26         bool enabled;
27 };
28
29 struct sandbox_dma_dev {
30         struct device *dev;
31         u32 ch_count;
32         struct sandbox_dma_chan channels[SANDBOX_DMA_CH_CNT];
33         uchar   buf[SANDBOX_DMA_BUF_SIZE];
34         uchar   *buf_rx;
35         size_t  data_len;
36         u32     meta;
37 };
38
39 static int sandbox_dma_transfer(struct udevice *dev, int direction,
40                                 void *dst, void *src, size_t len)
41 {
42         memcpy(dst, src, len);
43
44         return 0;
45 }
46
47 static int sandbox_dma_of_xlate(struct dma *dma,
48                                 struct ofnode_phandle_args *args)
49 {
50         struct sandbox_dma_dev *ud = dev_get_priv(dma->dev);
51         struct sandbox_dma_chan *uc;
52
53         debug("%s(dma id=%u)\n", __func__, args->args[0]);
54
55         if (args->args[0] >= SANDBOX_DMA_CH_CNT)
56                 return -EINVAL;
57
58         dma->id = args->args[0];
59
60         uc = &ud->channels[dma->id];
61
62         if (dma->id == 1)
63                 uc->dir = DMA_MEM_TO_DEV;
64         else if (dma->id == 2)
65                 uc->dir = DMA_DEV_TO_MEM;
66         else
67                 uc->dir = DMA_MEM_TO_MEM;
68         debug("%s(dma id=%lu dir=%d)\n", __func__, dma->id, uc->dir);
69
70         return 0;
71 }
72
73 static int sandbox_dma_request(struct dma *dma)
74 {
75         struct sandbox_dma_dev *ud = dev_get_priv(dma->dev);
76         struct sandbox_dma_chan *uc;
77
78         if (dma->id >= SANDBOX_DMA_CH_CNT)
79                 return -EINVAL;
80
81         uc = &ud->channels[dma->id];
82         if (uc->in_use)
83                 return -EBUSY;
84
85         uc->in_use = true;
86         debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use);
87
88         return 0;
89 }
90
91 static int sandbox_dma_free(struct dma *dma)
92 {
93         struct sandbox_dma_dev *ud = dev_get_priv(dma->dev);
94         struct sandbox_dma_chan *uc;
95
96         if (dma->id >= SANDBOX_DMA_CH_CNT)
97                 return -EINVAL;
98
99         uc = &ud->channels[dma->id];
100         if (!uc->in_use)
101                 return -EINVAL;
102
103         uc->in_use = false;
104         ud->buf_rx = NULL;
105         ud->data_len = 0;
106         debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use);
107
108         return 0;
109 }
110
111 static int sandbox_dma_enable(struct dma *dma)
112 {
113         struct sandbox_dma_dev *ud = dev_get_priv(dma->dev);
114         struct sandbox_dma_chan *uc;
115
116         if (dma->id >= SANDBOX_DMA_CH_CNT)
117                 return -EINVAL;
118
119         uc = &ud->channels[dma->id];
120         if (!uc->in_use)
121                 return -EINVAL;
122         if (uc->enabled)
123                 return -EINVAL;
124
125         uc->enabled = true;
126         debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled);
127
128         return 0;
129 }
130
131 static int sandbox_dma_disable(struct dma *dma)
132 {
133         struct sandbox_dma_dev *ud = dev_get_priv(dma->dev);
134         struct sandbox_dma_chan *uc;
135
136         if (dma->id >= SANDBOX_DMA_CH_CNT)
137                 return -EINVAL;
138
139         uc = &ud->channels[dma->id];
140         if (!uc->in_use)
141                 return -EINVAL;
142         if (!uc->enabled)
143                 return -EINVAL;
144
145         uc->enabled = false;
146         debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled);
147
148         return 0;
149 }
150
151 static int sandbox_dma_send(struct dma *dma,
152                             void *src, size_t len, void *metadata)
153 {
154         struct sandbox_dma_dev *ud = dev_get_priv(dma->dev);
155         struct sandbox_dma_chan *uc;
156
157         if (dma->id >= SANDBOX_DMA_CH_CNT)
158                 return -EINVAL;
159         if (!src || !metadata)
160                 return -EINVAL;
161
162         debug("%s(dma id=%lu)\n", __func__, dma->id);
163
164         uc = &ud->channels[dma->id];
165         if (uc->dir != DMA_MEM_TO_DEV)
166                 return -EINVAL;
167         if (!uc->in_use)
168                 return -EINVAL;
169         if (!uc->enabled)
170                 return -EINVAL;
171         if (len >= SANDBOX_DMA_BUF_SIZE)
172                 return -EINVAL;
173
174         memcpy(ud->buf, src, len);
175         ud->data_len = len;
176         ud->meta = *((u32 *)metadata);
177
178         debug("%s(dma id=%lu len=%zu meta=%08x)\n",
179               __func__, dma->id, len, ud->meta);
180
181         return 0;
182 }
183
184 static int sandbox_dma_receive(struct dma *dma, void **dst, void *metadata)
185 {
186         struct sandbox_dma_dev *ud = dev_get_priv(dma->dev);
187         struct sandbox_dma_chan *uc;
188
189         if (dma->id >= SANDBOX_DMA_CH_CNT)
190                 return -EINVAL;
191         if (!dst || !metadata)
192                 return -EINVAL;
193
194         uc = &ud->channels[dma->id];
195         if (uc->dir != DMA_DEV_TO_MEM)
196                 return -EINVAL;
197         if (!uc->in_use)
198                 return -EINVAL;
199         if (!uc->enabled)
200                 return -EINVAL;
201         if (!ud->data_len)
202                 return 0;
203
204         if (ud->buf_rx) {
205                 memcpy(ud->buf_rx, ud->buf, ud->data_len);
206                 *dst = ud->buf_rx;
207         } else {
208                 memcpy(*dst, ud->buf, ud->data_len);
209         }
210
211         *((u32 *)metadata) = ud->meta;
212
213         debug("%s(dma id=%lu len=%zu meta=%08x %p)\n",
214               __func__, dma->id, ud->data_len, ud->meta, *dst);
215
216         return ud->data_len;
217 }
218
219 static int sandbox_dma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size)
220 {
221         struct sandbox_dma_dev *ud = dev_get_priv(dma->dev);
222
223         ud->buf_rx = dst;
224
225         return 0;
226 }
227
228 static const struct dma_ops sandbox_dma_ops = {
229         .transfer       = sandbox_dma_transfer,
230         .of_xlate       = sandbox_dma_of_xlate,
231         .request        = sandbox_dma_request,
232         .free           = sandbox_dma_free,
233         .enable         = sandbox_dma_enable,
234         .disable        = sandbox_dma_disable,
235         .send           = sandbox_dma_send,
236         .receive        = sandbox_dma_receive,
237         .prepare_rcv_buf = sandbox_dma_prepare_rcv_buf,
238 };
239
240 static int sandbox_dma_probe(struct udevice *dev)
241 {
242         struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
243         struct sandbox_dma_dev *ud = dev_get_priv(dev);
244         int i, ret = 0;
245
246         uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM |
247                              DMA_SUPPORTS_MEM_TO_DEV |
248                              DMA_SUPPORTS_DEV_TO_MEM;
249
250         ud->ch_count = SANDBOX_DMA_CH_CNT;
251         ud->buf_rx = NULL;
252         ud->meta = 0;
253         ud->data_len = 0;
254
255         pr_err("Number of channels: %u\n", ud->ch_count);
256
257         for (i = 0; i < ud->ch_count; i++) {
258                 struct sandbox_dma_chan *uc = &ud->channels[i];
259
260                 uc->ud = ud;
261                 uc->id = i;
262                 sprintf(uc->name, "DMA chan%d\n", i);
263                 uc->in_use = false;
264                 uc->enabled = false;
265         }
266
267         return ret;
268 }
269
270 static const struct udevice_id sandbox_dma_ids[] = {
271         { .compatible = "sandbox,dma" },
272         { }
273 };
274
275 U_BOOT_DRIVER(sandbox_dma) = {
276         .name   = "sandbox-dma",
277         .id     = UCLASS_DMA,
278         .of_match = sandbox_dma_ids,
279         .ops    = &sandbox_dma_ops,
280         .probe = sandbox_dma_probe,
281         .priv_auto_alloc_size = sizeof(struct sandbox_dma_dev),
282 };