blob: d009bb216832c05bbf00ad39d25510196d9a43ea [file] [log] [blame]
Grygorii Strashkob3309912018-11-28 19:17:51 +01001// 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
20struct 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
29struct 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
39static 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
47static 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
73static 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
Simon Glassaae95882020-02-03 07:35:55 -070091static int sandbox_dma_rfree(struct dma *dma)
Grygorii Strashkob3309912018-11-28 19:17:51 +010092{
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
111static 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
131static 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
151static 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
184static 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
219static 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
228static const struct dma_ops sandbox_dma_ops = {
229 .transfer = sandbox_dma_transfer,
230 .of_xlate = sandbox_dma_of_xlate,
231 .request = sandbox_dma_request,
Simon Glassaae95882020-02-03 07:35:55 -0700232 .rfree = sandbox_dma_rfree,
Grygorii Strashkob3309912018-11-28 19:17:51 +0100233 .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
240static 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
270static const struct udevice_id sandbox_dma_ids[] = {
271 { .compatible = "sandbox,dma" },
272 { }
273};
274
275U_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};