]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/devgpio.c
pc kernel: fix wrong simd exception mask (fixes go bootstrap)
[plan9front.git] / sys / src / 9 / bcm / devgpio.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 #include "io.h"
8
9 // path:
10 // 3 bits - generic file type (Qinctl, Qindata)
11 // 3 bits - parent type
12 // 3 bits - chosen scheme type (Qgeneric, Qbcm, Qboard, Qwpi)
13 // 6 bits - input number
14
15 #define PIN_TABLE_SIZE  32
16
17 #define PIN_OFFSET              SCHEME_OFFSET + SCHEME_BITS
18 #define PIN_BITS                6
19 #define PIN_MASK                ((1 << PIN_BITS) - 1)
20 #define PIN_NUMBER(q)   (((q).path >> PIN_OFFSET) & PIN_MASK)
21
22 #define SCHEME_OFFSET   PARENT_OFFSET + PARENT_BITS
23 #define SCHEME_BITS     3
24 #define SCHEME_MASK     ((1 << SCHEME_BITS) - 1)
25 #define SCHEME_TYPE(q)  (((q).path >> SCHEME_OFFSET) & SCHEME_MASK)
26
27 #define PARENT_OFFSET   FILE_OFFSET + FILE_BITS
28 #define PARENT_BITS     3
29 #define PARENT_MASK     ((1 << PARENT_BITS) - 1)
30 #define PARENT_TYPE(q)  (((q).path >> PARENT_OFFSET) & PARENT_MASK)
31
32 #define FILE_OFFSET     0
33 #define FILE_BITS               3
34 #define FILE_MASK               ((1 << FILE_BITS) - 1)
35 #define FILE_TYPE(q)    (((q).path >> FILE_OFFSET) & FILE_MASK)
36
37 // pin is valid only when file is Qdata otherwise 0 is used
38 #define PATH(pin, scheme, parent, file) \
39                                                 ((pin & PIN_MASK) << PIN_OFFSET) \
40                                                 | ((scheme & SCHEME_MASK) << SCHEME_OFFSET) \
41                                                 | ((parent & PARENT_MASK) << PARENT_OFFSET) \
42                                                 | ((file & FILE_MASK) << FILE_OFFSET)
43
44 #define SET_BIT(f, offset, value) \
45         (*f = ((*f & ~(1 << (offset % 32))) | (value << (offset % 32))))
46
47 static int dflag = 0;
48 #define D(...)  if(dflag) print(__VA_ARGS__)
49
50 enum {
51         // parent types
52         Qtopdir = 0,
53         Qgpiodir,
54         // file types
55         Qdir,
56         Qdata,
57         Qctl,
58         Qevent,
59 };
60 enum {
61         // naming schemes
62         Qbcm,
63         Qboard,
64         Qwpi,
65         Qgeneric
66 };
67
68
69 // commands
70 enum {
71         CMzero,
72         CMone,
73         CMscheme,
74         CMfunc,
75         CMpull,
76         CMevent,
77 };
78
79 // dev entries
80 Dirtab topdir = { "#G", {PATH(0, Qgeneric, Qtopdir, Qdir), 0, QTDIR}, 0, 0555 };
81 Dirtab gpiodir = { "gpio", {PATH(0, Qgeneric, Qgpiodir, Qdir), 0, QTDIR}, 0, 0555 };
82
83 Dirtab typedir[] = {
84         "OK",   { PATH(16, Qgeneric, Qgpiodir, Qdata), 0, QTFILE }, 0, 0666,
85         "ctl",  { PATH(0, Qgeneric, Qgpiodir, Qctl), 0, QTFILE }, 0, 0666,
86         "event",        { PATH(0, Qgeneric, Qgpiodir, Qevent), 0, QTFILE }, 0, 0444,
87 };
88
89 // commands definition
90 static
91 Cmdtab gpiocmd[] = {
92         CMzero,         "0",            1,
93         CMone,          "1",            1,
94         CMscheme,       "scheme",       2,
95         CMfunc,         "function",     3,
96         CMpull,         "pull",         3,
97         CMevent,        "event",        4,
98 };
99
100 static int pinscheme;
101 static int boardrev;
102
103 static Rendez rend;
104 static u32int eventvalue;
105 static long eventinuse;
106 static Lock eventlock;
107
108 //
109 // BCM
110 //
111 enum {
112         Fin = 0,
113         Fout,
114         Ffunc5,
115         Ffunc4,
116         Ffunc0,
117         Ffunc1,
118         Ffunc2,
119         Ffunc3,
120 };
121
122 static char *funcname[] = {
123         "in", "out", "5", "4", "0", "1", "2", "3",
124 };
125
126 enum {
127         Poff = 0,
128         Pdown,
129         Pup,
130 };
131
132 static char *pudname[] = {
133         "off", "down", "up",
134 };
135
136 static char *evstatename[] = {
137         "disable", "enable",
138 };
139
140 enum {
141         Erising,
142         Efalling,
143 };
144
145 static char *evtypename[] = {
146         "edge-rising", "edge-falling",
147 };
148
149 static char *bcmtableR1[PIN_TABLE_SIZE] = {
150         "1", "2", 0, 0,                 // 0-3
151         "4", 0, 0, "7",                 // 4-7
152         "8", "9", "10", "11",   // 8-11
153         0, 0, "14", "15",               // 12-15
154         0, "17", "18", 0,               // 16-19
155         0, "21", "22", "23",    // 20-23
156         "24", "25", 0, 0,               // 24-27
157         0, 0, 0, 0,                             // 28-31
158 };
159
160 static char *bcmtableR2[PIN_TABLE_SIZE] = {
161         0, 0, "2", "3",                 // 0-3
162         "4", 0, 0, "7",                 // 4-7
163         "8", "9", "10", "11",   // 8-11
164         0, 0, "14", "15",               // 12-15
165         0, "17", "18", 0,               // 16-19
166         0, 0, "22", "23",               // 20-23
167         "24", "25", 0, "27",    // 24-27
168         "28", "29", "30", "31", // 28-31
169 };
170
171 static char *boardtableR1[PIN_TABLE_SIZE] = {
172         "SDA", "SCL", 0, 0,                             // 0-3
173         "GPIO7", 0, 0, "CE1",                   // 4-7
174         "CE0", "MISO", "MOSI", "SCLK",  // 8-11
175         0, 0, "TxD", "RxD",                             // 12-15
176         0, "GPIO0", "GPIO1", 0,                 // 16-19
177         0, "GPIO2", "GPIO3", "GPIO4",   // 20-23
178         "GPIO5", "GPIO6", 0, 0,                 // 24-27
179         0, 0, 0, 0,                                             // 28-31
180 };
181
182 static char *boardtableR2[PIN_TABLE_SIZE] = {
183         0, 0, "SDA", "SCL",                                             // 0-3
184         "GPIO7", 0, 0, "CE1",                                   // 4-7
185         "CE0", "MISO", "MOSI", "SCLK",                  // 8-11
186         0, 0, "TxD", "RxD",                                             // 12-15
187         0, "GPIO0", "GPIO1", 0,                                 // 16-19
188         0, 0, "GPIO3", "GPIO4",                                 // 20-23
189         "GPIO5", "GPIO6", 0, "GPIO2",                   // 24-27
190         "GPIO8", "GPIO9", "GPIO10", "GPIO11",   // 28-31
191 };
192
193 static char *wpitableR1[PIN_TABLE_SIZE] = {
194         "8", "9", 0, 0,                 // 0-3
195         "7", 0, 0, "11",                // 4-7
196         "10", "13", "12", "14", // 8-11
197         0, 0, "15", "16",               // 12-15
198         0, "0", "1", 0,                 // 16-19
199         0, "2", "3", "4",               // 20-23
200         "5", "6", 0, 0,                 // 24-27
201         0, 0, 0, 0,                             // 28-31
202 };
203
204 static char *wpitableR2[PIN_TABLE_SIZE] = {
205         0, 0, "8", "9",                 // 0-3
206         "7", 0, 0, "11",                // 4-7
207         "10", "13", "12", "14", // 8-11
208         0, 0, "15", "16",               // 12-15
209         0, "0", "1", 0,                 // 16-19
210         0, 0, "3", "4",                 // 20-23
211         "5", "6", 0, "2",               // 24-27
212         "17", "18", "19", "20", // 28-31
213 };
214
215 static char *schemename[] = {
216         "bcm", "board", "wpi",
217 };
218
219 static char**
220 getpintable(void)
221 {
222         switch(pinscheme)
223         {
224         case Qbcm:
225                 return (boardrev>3)?bcmtableR2:bcmtableR1;
226         case Qboard:
227                 return (boardrev>3)?boardtableR2:boardtableR1;
228         case Qwpi:
229                 return (boardrev>3)?wpitableR2:wpitableR1;
230         default:
231                 return nil;
232         }
233 }
234
235 // stolen from uartmini.c
236 #define GPIOREGS        (VIRTIO+0x200000)
237 /* GPIO regs */
238 enum {
239         Fsel0   = 0x00>>2,
240                 FuncMask= 0x7,
241         Set0    = 0x1c>>2,
242         Clr0    = 0x28>>2,
243         Lev0    = 0x34>>2,
244         Evds0   = 0x40>>2,
245         Redge0  = 0x4C>>2,
246         Fedge0  = 0x58>>2,
247         Hpin0   = 0x64>>2,
248         Lpin0   = 0x70>>2,
249         ARedge0 = 0x7C>>2,
250         AFedge0 = 0x88>2,
251         PUD     = 0x94>>2,
252         PUDclk0 = 0x98>>2,
253         PUDclk1 = 0x9c>>2,
254 };
255
256 static void
257 gpiofuncset(uint pin, int func)
258 {       
259         u32int *gp, *fsel;
260         int off;
261
262         gp = (u32int*)GPIOREGS;
263         fsel = &gp[Fsel0 + pin/10];
264         off = (pin % 10) * 3;
265         *fsel = (*fsel & ~(FuncMask<<off)) | func<<off;
266 }
267
268 static int
269 gpiofuncget(uint pin)
270 {       
271         u32int *gp, *fsel;
272         int off;
273
274         gp = (u32int*)GPIOREGS;
275         fsel = &gp[Fsel0 + pin/10];
276         off = (pin % 10) * 3;
277         return ((*fsel >> off) & FuncMask);
278 }
279
280 static void
281 gpiopullset(uint pin, int state)
282 {
283         u32int *gp, *reg;
284         u32int mask;
285
286         gp = (u32int*)GPIOREGS;
287         reg = &gp[PUDclk0 + pin/32];
288         mask = 1 << (pin % 32);
289         gp[PUD] = state;
290         microdelay(1);
291         *reg = mask;
292         microdelay(1);
293         *reg = 0;
294 }
295
296 static void
297 gpioout(uint pin, int set)
298 {
299         u32int *gp;
300         int v;
301
302         gp = (u32int*)GPIOREGS;
303         v = set? Set0 : Clr0;
304         gp[v + pin/32] = 1 << (pin % 32);
305 }
306
307 static int
308 gpioin(uint pin)
309 {
310         u32int *gp;
311
312         gp = (u32int*)GPIOREGS;
313         return (gp[Lev0 + pin/32] & (1 << (pin % 32))) != 0;
314 }
315
316 static void
317 gpioevent(uint pin, int event, int enable)
318 {
319         u32int *gp, *field;
320         int reg = 0;
321         
322         switch(event)
323         {
324                 case Erising:
325                         reg = Redge0;
326                         break;
327                 case Efalling:
328                         reg = Fedge0;
329                         break;
330                 default:
331                         panic("gpio: unknown event type");
332         }
333         gp = (u32int*)GPIOREGS;
334         field = &gp[reg + pin/32];
335         SET_BIT(field, pin, enable);
336 }
337
338 static void
339 mkdeventry(Chan *c, Qid qid, Dirtab *tab, Dir *db)
340 {
341         mkqid(&qid, tab->qid.path, tab->qid.vers, tab->qid.type);
342         devdir(c, qid, tab->name, tab->length, eve, tab->perm, db);
343 }
344
345 static int
346 gpiogen(Chan *c, char *, Dirtab *, int , int s, Dir *db)
347 {
348         Qid qid;
349         int parent, scheme, l;
350         char **pintable = getpintable();
351         
352         qid.vers = 0;
353         parent = PARENT_TYPE(c->qid);
354         scheme = SCHEME_TYPE(c->qid);
355         
356         if(s == DEVDOTDOT)
357         {
358                 switch(parent)
359                 {
360                 case Qtopdir:
361                 case Qgpiodir:
362                         mkdeventry(c, qid, &topdir, db);
363                         break;
364                 default:
365                         return -1;
366                 }
367                 return 1;
368         }
369
370         if(parent == Qtopdir)
371         {
372                 switch(s)
373                 {
374                 case 0:
375                         mkdeventry(c, qid, &gpiodir, db);
376                         break;
377                 default:
378                         return -1;
379                 }
380         return 1;
381         }
382
383         if(scheme != Qgeneric && scheme != pinscheme)
384         {
385                 error(nil);
386         }
387
388         if(parent == Qgpiodir)
389         {
390                 l = nelem(typedir);
391                 if(s < l)
392                 {
393                         mkdeventry(c, qid, &typedir[s], db);
394                 } else if (s < l + PIN_TABLE_SIZE)
395                 {
396                         s -= l;
397                         
398                         if(pintable[s] == 0)
399                         {
400                                 return 0;
401                         }
402                         mkqid(&qid, PATH(s, pinscheme, Qgpiodir, Qdata), 0, QTFILE);
403                         snprint(up->genbuf, sizeof up->genbuf, "%s", pintable[s]);
404                         devdir(c, qid, up->genbuf, 0, eve, 0666, db);
405                 }
406                 else
407                 {
408                         return -1;
409                 }
410                 return 1;
411         }
412
413         return 1;
414 }
415
416 static void
417 interrupt(Ureg*, void *)
418 {
419         
420         u32int *gp, *field;
421         char pin;
422         
423         gp = (u32int*)GPIOREGS;
424
425         int set;
426
427         coherence();
428         
429         eventvalue = 0;
430         
431         for(pin = 0; pin < PIN_TABLE_SIZE; pin++)
432         {
433                 set = (gp[Evds0 + pin/32] & (1 << (pin % 32))) != 0;
434
435                 if(set)
436                 {
437                         field = &gp[Evds0 + pin/32];
438                         SET_BIT(field, pin, 1);
439                         SET_BIT(&eventvalue, pin, 1);
440                 }
441         }
442         coherence();
443
444         wakeup(&rend);
445 }
446
447 static void
448 gpioinit(void)
449 {
450         boardrev = getrevision() & 0xff;
451         pinscheme = Qboard;
452         intrenable(49, interrupt, nil, 0, "gpio1");
453 }
454
455 static void
456 gpioshutdown(void)
457 { }
458
459 static Chan*
460 gpioattach(char *spec)
461 {
462         return devattach('G', spec);
463 }
464
465 static Walkqid*
466 gpiowalk(Chan *c, Chan *nc, char** name, int nname)
467 {
468         return devwalk(c, nc, name, nname, 0, 0, gpiogen);
469 }
470
471 static int
472 gpiostat(Chan *c, uchar *db, int n)
473 {
474         return devstat(c, db, n, 0, 0, gpiogen);
475 }
476
477 static Chan*
478 gpioopen(Chan *c, int omode)
479 {
480         int type;
481         
482         c = devopen(c, omode, 0, 0, gpiogen);
483         
484         type = FILE_TYPE(c->qid);
485         
486         switch(type)
487         {
488         case Qdata:
489                 c->iounit = 1;
490                 break;
491         case Qctl:
492                 break;
493         case Qevent:
494                 lock(&eventlock);
495                 if(eventinuse != 0){
496                         c->flag &= ~COPEN;
497                         unlock(&eventlock);
498                         error(Einuse);
499                 }
500                 eventinuse = 1;
501                 unlock(&eventlock);
502                 eventvalue = 0;
503                 c->iounit = 4;
504         }
505
506         return c;
507 }
508
509 static void
510 gpioclose(Chan *c)
511 {
512         int type;
513         type = FILE_TYPE(c->qid);
514         
515         switch(type)
516         {
517         case Qevent:
518                 if(c->flag & COPEN)
519                 {
520                         if(c->flag & COPEN){
521                                 eventinuse = 0;
522                         }
523                 }
524                 break;
525         }
526 }
527
528 static int
529 isset(void *)
530 {
531         return eventvalue;
532 }
533
534 static long
535 gpioread(Chan *c, void *va, long n, vlong off)
536 {
537         int type, scheme;
538         uint pin;
539         char *a;
540         
541         a = va;
542         
543         if(c->qid.type & QTDIR)
544         {
545                 return devdirread(c, va, n, 0, 0, gpiogen);
546         }
547
548         type = FILE_TYPE(c->qid);
549         scheme = SCHEME_TYPE(c->qid);
550         
551         if(scheme != Qgeneric && scheme != pinscheme)
552         {
553                 error(nil);
554         }
555
556         switch(type)
557         {
558         case Qdata:
559                 pin = PIN_NUMBER(c->qid);
560                 a[0] = (gpioin(pin))?'1':'0';
561                 n = 1;
562                 break;
563         case Qctl:
564                 break;
565         case Qevent:
566                 if(off >= 4)
567                 {
568                         off %= 4;
569                         eventvalue = 0;
570                 }
571                 sleep(&rend, isset, 0);
572                         
573                 if(off + n > 4)
574                 {
575                         n = 4 - off;
576                 }
577                 memmove(a, &eventvalue + off, n);
578         }
579
580         return n;
581 }
582
583 static int
584 getpin(char *pinname)
585 {
586         int i;
587         char **pintable = getpintable();
588         for(i = 0; i < PIN_TABLE_SIZE; i++)
589         {
590                 if(!pintable[i])
591                 {
592                         continue;
593                 }
594                 if(strncmp(pintable[i], pinname, strlen(pintable[i])) == 0)
595                 {
596                         return i;
597                 }
598         }
599         return -1;
600 }
601
602 static long
603 gpiowrite(Chan *c, void *va, long n, vlong)
604 {
605         int type, i, scheme;
606         uint pin;
607         char *arg;
608
609         Cmdbuf *cb;
610         Cmdtab *ct;
611
612         if(c->qid.type & QTDIR)
613         {
614                 error(Eisdir);
615         }
616
617         type = FILE_TYPE(c->qid);
618
619         scheme = SCHEME_TYPE(c->qid);
620         
621         if(scheme != Qgeneric && scheme != pinscheme)
622         {
623                 error(nil);
624         }
625
626         cb = parsecmd(va, n);
627         if(waserror())
628         {
629                 free(cb);
630                 nexterror();
631         }
632         ct = lookupcmd(cb, gpiocmd,  nelem(gpiocmd));
633         if(ct == nil)
634         {
635                 error(Ebadctl);
636         }
637         
638         switch(type)
639         {
640         case Qdata:
641                 pin = PIN_NUMBER(c->qid);
642
643                 switch(ct->index)
644                 {
645                 case CMzero:
646                         gpioout(pin, 0);
647                         break;
648                 case CMone:
649                         gpioout(pin, 1);
650                         break;
651                 default:
652                         error(Ebadctl);
653                 }
654                 break;
655         case Qctl:
656                 switch(ct->index)
657                 {
658                 case CMscheme:
659                         arg = cb->f[1];
660                         for(i = 0; i < nelem(schemename); i++)
661                         {
662                                 if(strncmp(schemename[i], arg, strlen(schemename[i])) == 0)
663                                 {
664                                         pinscheme = i;
665                                         break;
666                                 }
667                         }
668                         break;
669                 case CMfunc:
670                         pin = getpin(cb->f[2]);
671                         arg = cb->f[1];
672                         if(pin == -1) {
673                                 error(Ebadctl);
674                         }
675                         for(i = 0; i < nelem(funcname); i++)
676                         {
677                                 if(strncmp(funcname[i], arg, strlen(funcname[i])) == 0)
678                                 {
679                                         gpiofuncset(pin, i);
680                                         break;
681                                 }
682                         }
683                         break;
684                 case CMpull:
685                         pin = getpin(cb->f[2]);
686                         if(pin == -1) {
687                                 error(Ebadctl);
688                         }
689                         arg = cb->f[1];
690                         for(i = 0; i < nelem(pudname); i++)
691                         {
692                                 if(strncmp(pudname[i], arg, strlen(pudname[i])) == 0)
693                                 {
694                                         gpiopullset(pin, i);
695                                         break;
696                                 }
697                         }
698                         break;
699                 case CMevent:
700                         pin = getpin(cb->f[3]);
701                         if(pin == -1) {
702                                 error(Ebadctl);
703                         }
704                                 
705                         arg = cb->f[1];
706                         for(i = 0; i < nelem(evtypename); i++)
707                         {
708                                 if(strncmp(evtypename[i], arg, strlen(evtypename[i])) == 0)
709                                 {
710                                         gpioevent(pin, i, (cb->f[2][0] == 'e'));
711                                         break;
712                                 }
713                         }
714                         break;
715                 default:
716                         error(Ebadctl);
717                 }
718                 break;
719         }
720         
721         free(cb);
722
723         poperror();
724         return n;
725 }
726
727 Dev gpiodevtab = {
728         'G',
729         "gpio",
730
731         devreset,
732         gpioinit,
733         gpioshutdown,
734         gpioattach,
735         gpiowalk,
736         gpiostat,
737         gpioopen,
738         devcreate,
739         gpioclose,
740         gpioread,
741         devbread,
742         gpiowrite,
743         devbwrite,
744         devremove,
745         devwstat,
746 };