]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/dma.c
kernel: expose no execute bit to portable mmu code as SG_NOEXEC / PTENOEXEC, add...
[plan9front.git] / sys / src / 9 / omap / dma.c
1 /*
2  * omap3530 system dma controller
3  *
4  * terminology: a block consist of frame(s), a frame consist of elements
5  * (uchar, ushort, or ulong sized).
6  */
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "mem.h"
10 #include "dat.h"
11 #include "fns.h"
12 #include "io.h"
13 #include "../port/error.h"
14 #include "../port/netif.h"
15
16 enum {
17         Nirq    = 4,
18         Baseirq = 12,
19
20         Nchan   = 32,
21 };
22
23 /*
24  * has a sw reset bit
25  * dma req lines 1, 2, 6, 63 are available for `system expansion'
26  */
27
28 typedef struct Regs Regs;
29 typedef struct Dchan Dchan;
30 struct Regs {
31         uchar   _pad0[8];
32         /* bitfield of intrs pending, by Dchan; write 1s to clear */
33         ulong   irqsts[Nirq];
34         ulong   irqen[Nirq];    /* bitfield of intrs enabled, by Dchan */
35         ulong   syssts;         /* 1<<0 is Resetdone */
36         ulong   syscfg;         /* 1<<1 is Softreset */
37         uchar   _pad1[0x64 - 0x30];
38
39         ulong   caps[5];        /* caps[1] not defined */
40         ulong   gcr;            /* knobs */
41         ulong   _pad2;
42
43         struct Dchan {
44                 ulong   ccr;    /* chan ctrl: incr, etc. */
45                 ulong   clnkctrl; /* link ctrl */
46                 ulong   cicr;   /* intr ctrl */
47                 ulong   csr;    /* status */
48                 ulong   csdp;   /* src & dest params */
49                 ulong   cen;    /* element # */
50                 ulong   cfn;    /* frame # */
51                 ulong   cssa;   /* src start addr */
52                 ulong   cdsa;   /* dest start addr */
53                 ulong   csei;   /* src element index */
54                 ulong   csfi;   /* src frame index | pkt size */
55                 ulong   cdei;   /* dest element index */
56                 ulong   cdfi;   /* dest frame index | pkt size */
57                 ulong   csac;   /* src addr value (read-only?) */
58                 ulong   cdac;   /* dest addr value */
59                 ulong   ccen;   /* curr transferred element # (in frame) */
60                 ulong   ccfn;   /* curr transferred frame # (in xfer) */
61                 ulong   color;
62                 uchar   _pad3[24];
63         } chan[Nchan];
64 };
65
66 enum {
67         /* cicr/csr bits */
68         Blocki  = 1 << 5,
69
70         /* ccr bits */
71         Enable  = 1 << 7,
72 };
73
74 typedef struct Xfer Xfer;
75 static struct Xfer {
76         Rendez  *rend;
77         int     *done;          /* flag to set on intr */
78 } xfer[Nirq];
79
80 int
81 isdmadone(int irq)
82 {
83         Dchan *cp;
84         Regs *regs = (Regs *)PHYSSDMA;
85
86         cp = regs->chan + irq;
87         return cp->csr & Blocki;
88 }
89
90 static void
91 dmaintr(Ureg *, void *a)
92 {
93         int i = (int)a;                 /* dma request & chan # */
94         Dchan *cp;
95         Regs *regs = (Regs *)PHYSSDMA;
96
97         assert(i >= 0 && i < Nirq);
98
99         *xfer[i].done = 1;
100         assert(xfer[i].rend != nil);
101         wakeup(xfer[i].rend);
102
103         cp = regs->chan + i;
104         if(!(cp->csr & Blocki))
105                 iprint("dmaintr: req %d: Blocki not set; csr %#lux\n",
106                         i, cp->csr);
107         cp->csr |= cp->csr;                     /* extinguish intr source */
108         coherence();
109         regs->irqsts[i] = regs->irqsts[i];      /* extinguish intr source */
110         coherence();
111         regs->irqen[i] &= ~(1 << i);
112         coherence();
113
114         xfer[i].rend = nil;
115         coherence();
116 }
117
118 void
119 zerowds(ulong *wdp, int cnt)
120 {
121         while (cnt-- > 0)
122                 *wdp++ = 0;
123 }
124
125 static int
126 istestdmadone(void *arg)
127 {
128         return *(int *)arg;
129 }
130
131 void
132 dmainit(void)
133 {
134         int n;
135         char name[16];
136         Dchan *cp;
137         Regs *regs = (Regs *)PHYSSDMA;
138
139         if (probeaddr((uintptr)&regs->syssts) < 0)
140                 panic("dmainit: no syssts reg");
141         regs->syssts = 0;
142         coherence();
143         regs->syscfg |= 1<<1;           /* Softreset */
144         coherence();
145         while(!(regs->syssts & (1<<0))) /* Resetdone? */
146                 ;
147
148         for (n = 0; n < Nchan; n++) {
149                 cp = regs->chan + n;
150                 cp->ccr = 0;
151                 cp->clnkctrl = 0;
152                 cp->cicr = 0;
153                 cp->csr = 0;
154                 cp->csdp = 0;
155                 cp->cen = cp->cfn = 0;
156                 cp->cssa = cp->cdsa = 0;
157                 cp->csei = cp->csfi = 0;
158                 cp->cdei = cp->cdfi = 0;
159 //              cp->csac = cp->cdac = 0;                // ro
160                 cp->ccen = cp->ccfn = 0;
161                 cp->color = 0;
162         }
163         zerowds((void *)regs->irqsts, sizeof regs->irqsts / sizeof(ulong));
164         zerowds((void *)regs->irqen,  sizeof regs->irqen / sizeof(ulong));
165         coherence();
166
167         regs->gcr = 65;                 /* burst size + 1 */
168         coherence();
169
170         for (n = 0; n < Nirq; n++) {
171                 snprint(name, sizeof name, "dma%d", n);
172                 intrenable(Baseirq + n, dmaintr, (void *)n, nil, name);
173         }
174 }
175
176 enum {
177         Testbyte        = 0252,
178         Testsize        = 256,
179         Scratch         = MB,
180 };
181
182 /*
183  * try to confirm sane operation
184  */
185 void
186 dmatest(void)
187 {
188         int n, done;
189         uchar *bp;
190         static ulong pat = 0x87654321;
191         static Rendez trendez;
192
193         if (up == nil)
194                 panic("dmatest: up not set yet");
195         bp = (uchar *)KADDR(PHYSDRAM + 128*MB);
196         memset(bp, Testbyte, Scratch);
197         done = 0;
198         dmastart((void *)PADDR(bp), Postincr, (void *)PADDR(&pat), Const,
199                 Testsize, &trendez, &done);
200         sleep(&trendez, istestdmadone, &done);
201         cachedinvse(bp, Scratch);
202
203         if (((ulong *)bp)[0] != pat)
204                 panic("dmainit: copied incorrect data %#lux != %#lux",
205                         ((ulong *)bp)[0], pat);
206         for (n = Testsize; n < Scratch && bp[n] != Testbyte; n++)
207                 ;
208         if (n >= Scratch)
209                 panic("dmainit: ran wild over memory, clobbered ≥%,d bytes", n);
210         if (bp[n] == Testbyte && n != Testsize)
211                 iprint("dma: %d-byte dma stopped after %d bytes!\n",
212                         Testsize, n);
213 }
214
215 /* addresses are physical */
216 int
217 dmastart(void *to, int tmode, void *from, int fmode, uint len, Rendez *rend,
218         int *done)
219 {
220         int irq, chan;
221         uint ruplen;
222         Dchan *cp;
223         Regs *regs = (Regs *)PHYSSDMA;
224         static Lock alloclck;
225
226         /* allocate free irq (and chan) */
227         ilock(&alloclck);
228         for (irq = 0; irq < Nirq && xfer[irq].rend != nil; irq++)
229                 ;
230         if (irq >= Nirq)
231                 panic("dmastart: no available irqs; too many concurrent dmas");
232         chan = irq;
233         xfer[irq].rend = rend;                  /* for wakeup at intr time */
234         xfer[irq].done = done;
235         *done = 0;
236         iunlock(&alloclck);
237
238         ruplen = ROUND(len, sizeof(ulong));
239         assert(to != from);
240
241         cp = regs->chan + chan;
242         cp->ccr &= ~Enable;                     /* paranoia */
243         cp->cicr = 0;
244         regs->irqen[irq] &= ~(1 << chan);
245         coherence();
246
247         cp->csdp = 2;                           /* 2 = log2(sizeof(ulong)) */
248         cp->cssa = (uintptr)from;
249         cp->cdsa = (uintptr)to;
250         cp->ccr = tmode << 14 | fmode << 12;
251         cp->csei = cp->csfi = cp->cdei = cp->cdfi = 1;
252         cp->cen = ruplen / sizeof(ulong);       /* ulongs / frame */
253         cp->cfn = 1;                            /* 1 frame / xfer */
254         cp->cicr = Blocki;                      /* intr at end of block */
255
256         regs->irqen[irq] |= 1 << chan;
257         coherence();
258
259         cp->ccr |= Enable;                      /* fire! */
260         coherence();
261
262         return irq;
263 }