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 
sandbox_dma_transfer(struct udevice * dev,int direction,void * dst,void * src,size_t len)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 
sandbox_dma_of_xlate(struct dma * dma,struct ofnode_phandle_args * args)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 
sandbox_dma_request(struct dma * dma)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 
sandbox_dma_free(struct dma * dma)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 
sandbox_dma_enable(struct dma * dma)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 
sandbox_dma_disable(struct dma * dma)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 
sandbox_dma_send(struct dma * dma,void * src,size_t len,void * metadata)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 
sandbox_dma_receive(struct dma * dma,void ** dst,void * metadata)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 
sandbox_dma_prepare_rcv_buf(struct dma * dma,void * dst,size_t size)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 
sandbox_dma_probe(struct udevice * dev)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 };
283