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