]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/devqspi.c
devether: mux bridges, portable netconsole
[plan9front.git] / sys / src / 9 / zynq / devqspi.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 #include "../port/error.h"
9
10 enum {
11         QSPIDIV = 1,
12         QSPISIZ = 1<<24,
13 };
14
15 enum {
16         CONF,
17         INTSTAT,
18         INTEN,
19         INTDIS,
20         INTMASK,
21         SPIEN,
22         DELAY,
23         TXD0,
24         RXD,
25         IDLE,
26         TXTHRES,
27         RXTHRES,
28         TXD1 = 0x80/4,
29         TXD2,
30         TXD3,
31         LQSPICFG = 0xA0/4,
32 };
33
34 enum {
35         TXFULL = 1<<3,
36         TXNFULL = 1<<2,
37         RXNEMPTY = 1<<4,
38         STARTCOM = 1<<16,
39 };
40
41 enum {
42         Qdir = 0,
43         Qboot,
44         Qbase,
45
46         Qmax = 16,
47 };
48
49 static ulong *qspi;
50 static QLock qspil;
51
52 static Dirtab qspidir[Qmax] = {
53         ".",            { Qdir, 0, QTDIR },     0,      0555,
54         "boot",         { Qboot, 0},            65536,  0640,
55 };
56 static int nqspidir = Qbase;
57
58 static ulong
59 qspicmd(int n, ulong d)
60 {
61         while((qspi[INTSTAT] & TXNFULL) == 0)
62                 ;
63         if(n == 4)
64                 qspi[TXD0] = d;
65         else
66                 qspi[TXD1 - 1 + n] = d;
67         qspi[CONF] |= STARTCOM;
68         while((qspi[INTSTAT] & (TXNFULL|RXNEMPTY)) != (TXNFULL|RXNEMPTY))
69                 ;
70         return qspi[RXD];
71 }
72
73 static void
74 qspiinit(void)
75 {
76         static int done;
77         
78         if(done)
79                 return;
80         qspi = vmap(QSPI_BASE, 0x100);
81         qspi[LQSPICFG] &= ~(1<<31);
82         qspi[CONF] = 1<<31 | 1<<19 | 1<<15 | 1<<14 | 1<<10 | 3<<6 | QSPIDIV<<3 | 1;
83         qspi[SPIEN] = 1;        
84 }
85
86 static void
87 qspisel(int sel)
88 {
89         if(sel)
90                 qspi[CONF] &= ~(1<<10);
91         else
92                 qspi[CONF] |= 1<<10;
93 }
94
95 static void
96 waitbusy(void)
97 {
98         ulong d;
99
100         for(;;){
101                 qspisel(1);
102                 d = qspicmd(2, 0x05);
103                 qspisel(0);
104                 if((d & 1<<24) == 0)
105                         break;
106                 tsleep(&up->sleep, return0, nil, 1);
107         }
108 }
109
110 static ulong
111 doread(uvlong addr, void *a, ulong n)
112 {
113         ulong d, *aa, ret;
114
115         if(addr >= QSPISIZ)
116                 return 0;
117         if(addr + n > QSPISIZ)
118                 n = QSPISIZ - addr;
119         evenaddr((uintptr) a);
120         qspisel(1);
121         qspicmd(4, 0x6B | addr << 8);
122         qspicmd(1, 0);
123         ret = n;
124         aa = a;
125         while(n > 0){
126                 d = qspicmd(4, 0);
127                 if(n >= 4){
128                         *aa++ = d;
129                         n -= 4;
130                 }else{
131                         memmove(aa, (char*) &d + 4 - n, n);
132                         break;
133                 }
134         }
135         qspisel(0);
136         return ret;
137 }
138
139 static ulong
140 dowrite(uvlong addr, void *a, ulong n)
141 {
142         ulong *aa, ret, nn;
143
144         if(addr >= QSPISIZ)
145                 return 0;
146         if(addr + n > QSPISIZ)
147                 n = QSPISIZ - addr;
148         evenaddr((uintptr) a);
149         ret = n;
150         aa = a;
151         while(n > 0){
152                 qspisel(1);
153                 qspicmd(1, 6);
154                 qspisel(0);
155                 qspisel(1);
156                 qspicmd(4, 0x32 | addr << 8);
157                 if(n > 256)
158                         nn = 256;
159                 else
160                         nn = n;
161                 n -= nn;
162                 addr += nn;
163                 while(nn > 0)
164                         if(nn >= 4){
165                                 qspicmd(4, *aa++);
166                                 nn -= 4;
167                         }else{
168                                 qspicmd(n, *aa);
169                                 break;
170                         }
171                 qspisel(0);
172                 waitbusy();
173         }
174         return ret;
175 }
176
177 static void
178 doerase(ulong addr)
179 {
180         qspisel(1);
181         qspicmd(1, 6);
182         qspisel(0);
183         qspisel(1);
184         qspicmd(4, 0xD8 | addr << 8);
185         qspisel(0);
186         waitbusy();
187 }
188
189 static Walkqid*
190 qspiwalk(Chan* c, Chan *nc, char** name, int nname)
191 {
192         return devwalk(c, nc, name, nname, qspidir, nqspidir, devgen);
193 }
194
195 static int
196 qspistat(Chan* c, uchar* dp, int n)
197 {
198         return devstat(c, dp, n, qspidir, nqspidir, devgen);
199 }
200
201 static Chan*
202 qspiopen(Chan* c, int omode)
203 {
204         devopen(c, omode, qspidir, nqspidir, devgen);
205         if(c->qid.path == Qboot){
206                 qlock(&qspil);
207                 if((omode & OTRUNC) != 0)
208                         doerase(0);
209         }
210         return c;
211 }
212
213 static void
214 qspiclose(Chan* c)
215 {
216         if(c->qid.path == Qboot && (c->flag & COPEN) != 0)
217                 qunlock(&qspil);
218 }
219
220 static long
221 qspiread(Chan *c, void *a, long n, vlong offset)
222 {
223         switch((ulong)c->qid.path){
224         case Qdir:
225                 return devdirread(c, a, n, qspidir, nqspidir, devgen);
226         case Qboot:
227                 return doread(offset, a, n);
228         default:
229                 error(Egreg);
230                 return -1;
231         }
232 }
233
234 static long
235 qspiwrite(Chan *c, void *a, long n, vlong offset)
236 {
237         switch((ulong)c->qid.path){
238         case Qboot:
239                 return dowrite(offset, a, n);
240         default:
241                 error(Egreg);
242                 return -1;
243         }
244 }
245
246 static Chan*
247 qspiattach(char* spec)
248 {
249         qspiinit();
250         return devattach('Q', spec);
251 }
252
253 Dev qspidevtab = {
254         'Q',
255         "qspi",
256         
257         devreset,
258         devinit,
259         devshutdown,
260         qspiattach,
261         qspiwalk,
262         qspistat,
263         qspiopen,
264         devcreate,
265         qspiclose,
266         qspiread,
267         devbread,
268         qspiwrite,
269         devbwrite,
270         devremove,
271         devwstat,
272 };
273