]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/devqspi.c
kernel: reduce Page structure size by changing Page.cachectl[]
[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, nn, 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)
217                 qunlock(&qspil);
218 }
219
220 static long
221 qspiread(Chan *c, void *a, long n, vlong offset)
222 {
223         char buf[64];
224
225         switch((ulong)c->qid.path){
226         case Qdir:
227                 return devdirread(c, a, n, qspidir, nqspidir, devgen);
228         case Qboot:
229                 return doread(offset, a, n);
230         default:
231                 error(Egreg);
232                 return -1;
233         }
234 }
235
236 static long
237 qspiwrite(Chan *c, void *a, long n, vlong offset)
238 {
239         switch((ulong)c->qid.path){
240         case Qboot:
241                 return dowrite(offset, a, n);
242         default:
243                 error(Egreg);
244                 return -1;
245         }
246 }
247
248 static Chan*
249 qspiattach(char* spec)
250 {
251         qspiinit();
252         return devattach('Q', spec);
253 }
254
255 Dev qspidevtab = {
256         'Q',
257         "qspi",
258         
259         devreset,
260         devinit,
261         devshutdown,
262         qspiattach,
263         qspiwalk,
264         qspistat,
265         qspiopen,
266         devcreate,
267         qspiclose,
268         qspiread,
269         devbread,
270         qspiwrite,
271         devbwrite,
272         devremove,
273         devwstat,
274 };
275