]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/gpio.c
kernel: expose no execute bit to portable mmu code as SG_NOEXEC / PTENOEXEC, add...
[plan9front.git] / sys / src / 9 / bcm / gpio.c
1 /*
2  * Raspberry Pi GPIO support
3  */
4
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "../port/error.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12
13 #define GPIOREGS        (VIRTIO+0x200000)
14
15 /* GPIO regs */
16 enum {
17         Fsel0   = 0x00>>2,
18                 FuncMask= 0x7,
19         Set0    = 0x1c>>2,
20         Clr0    = 0x28>>2,
21         Lev0    = 0x34>>2,
22         Evds0   = 0x40>>2,
23         Redge0  = 0x4C>>2,
24         Fedge0  = 0x58>>2,
25         Hpin0   = 0x64>>2,
26         Lpin0   = 0x70>>2,
27         ARedge0 = 0x7C>>2,
28         AFedge0 = 0x88>>2,
29         PUD     = 0x94>>2,
30                 Off     = 0x0,
31                 Pulldown= 0x1,
32                 Pullup  = 0x2,
33                 PudMask = 0x3,
34
35         PUDclk0 = 0x98>>2,
36         PUDclk1 = 0x9c>>2,
37
38         /* BCM2711 only */
39         PUPPDN0 = 0xe4>>2,
40         PUPPDN1 = 0xe8>>2,
41         PUPPDN2 = 0xec>>2,
42         PUPPDN3 = 0xf0>>2,
43 };
44
45 static u32int *regs = (u32int*)GPIOREGS;
46
47 void
48 gpiosel(uint pin, int func)
49 {       
50         int shift = (pin % 10) * 3;
51         u32int *reg = &regs[Fsel0 + pin/10];
52         func &= FuncMask;
53         *reg = (*reg & ~(FuncMask<<shift)) | (func<<shift);
54 }
55
56 void
57 gpiopull(uint pin, int func)
58 {
59         u32int *reg;
60         func &= PudMask;
61         if(regs[PUPPDN3] == 0x6770696f){
62                 /* BCM2835, BCM2836, BCM2837 */
63                 u32int mask = 1 << (pin % 32);
64                 reg = &regs[PUDclk0 + pin/32];
65                 regs[PUD] = func;
66                 microdelay(1);
67                 *reg = mask;
68                 microdelay(1);
69                 *reg = 0;
70         } else {
71                 /* BCM2711 */
72                 int shift = 2*(pin % 16);
73                 static u32int map[PudMask+1] = {0x00,0x02,0x01};
74                 reg = &regs[PUPPDN0 + pin/16];
75                 *reg = (*reg & ~(3<<shift)) | (map[func] << shift);
76         }
77 }
78
79 void
80 gpiopulloff(uint pin)
81 {
82         gpiopull(pin, Off);
83 }
84
85 void
86 gpiopullup(uint pin)
87 {
88         gpiopull(pin, Pullup);
89 }
90
91 void
92 gpiopulldown(uint pin)
93 {
94         gpiopull(pin, Pulldown);
95 }
96
97 void
98 gpioout(uint pin, int set)
99 {
100         regs[(set? Set0: Clr0) + pin/32] = 1 << (pin % 32);
101 }
102
103 int
104 gpioin(uint pin)
105 {
106         return (regs[Lev0 + pin/32] & (1 << (pin % 32))) != 0;
107 }
108
109 void
110 gpioselevent(uint pin, int falling, int enable)
111 {
112         u32int *reg = &regs[(falling? Fedge0: Redge0) + pin/32];
113         *reg = (*reg & ~(1<<pin)) | ((enable != 0)<<pin);
114 }
115
116 int
117 gpiogetevent(uint pin)
118 {
119         u32int *reg, val;
120
121         reg = &regs[Evds0 + pin/32];
122         val = *reg & (1 << (pin % 32));
123         *reg |= val;
124         return val != 0;
125 }
126
127 void
128 gpiomeminit(void)
129 {
130         Physseg seg;
131
132         memset(&seg, 0, sizeof seg);
133         seg.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
134         seg.name = "gpio";
135         seg.pa = (GPIOREGS - soc.virtio) + soc.physio;
136         seg.size = BY2PG;
137         addphysseg(&seg);
138 }