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 8 #include "io.h" 9 #include "archipe.h" 10 11 enum { 12 FPGASIZE = 8*1024*1024, 13 FPGATMR = 2-1, /* BCLK timer number (mapped to origin 0) */ 14 TIMERSH = FPGATMR*4, /* timer field shift */ 15 16 COM3= IBIT(1)|IBIT(2), /* sccr: clock output disabled */ 17 18 ConfDone = 1<<1, 19 nStatus = 1<<0, 20 }; 21 22 /* 23 * provisional FPGA interface for simple development work; 24 * for more complex things, use this to load the device then have a 25 * purpose-built device driver or module 26 */ 27 28 enum{ 29 Qdir, 30 Qmemb, 31 Qmemw, 32 Qprog, 33 Qctl, 34 Qclk, 35 Qstatus, 36 }; 37 38 static struct { 39 QLock; 40 int clkspeed; 41 } fpga; 42 43 static void resetfpga(void); 44 static void startfpga(int); 45 static int endfpga(void); 46 static int fpgastatus(void); 47 static void powerfpga(int); 48 static void vclkenable(int); 49 static void vclkset(char*, char*, char*, char*); 50 static void memmovew(ushort*, ushort*, long); 51 52 static Dirtab fpgadir[]={ 53 ".", {Qdir, 0, QTDIR}, 0, 0555, 54 "fpgamemb", {Qmemb, 0}, FPGASIZE, 0666, 55 "fpgamemw", {Qmemw, 0}, FPGASIZE, 0666, 56 "fpgaprog", {Qprog, 0}, 0, 0222, 57 "fpgastatus", {Qstatus, 0}, 0, 0444, 58 "fpgactl", {Qctl, 0}, 0, 0666, 59 "fpgaclk", {Qclk, 0}, 0, 0666, 60 }; 61 62 static char Eodd[] = "odd count or offset"; 63 64 static void 65 fpgareset(void) 66 { 67 powerfpga(0); 68 } 69 70 static Chan* 71 fpgaattach(char *spec) 72 { 73 return devattach('G', spec); 74 } 75 76 static Walkqid* 77 fpgawalk(Chan *c, Chan *nc, char **name, int nname) 78 { 79 return devwalk(c, nc, name, nname, fpgadir, nelem(fpgadir), devgen); 80 } 81 82 static int 83 fpgastat(Chan *c, uchar *dp, int n) 84 { 85 return devstat(c, dp, n, fpgadir, nelem(fpgadir), devgen); 86 } 87 88 static Chan* 89 fpgaopen(Chan *c, int omode) 90 { 91 return devopen(c, omode, fpgadir, nelem(fpgadir), devgen); 92 } 93 94 static void 95 fpgaclose(Chan*) 96 { 97 } 98 99 static long 100 fpgaread(Chan *c, void *buf, long n, vlong offset) 101 { 102 int v; 103 char stat[32], *p; 104 105 if(c->qid.type & QTDIR) 106 return devdirread(c, buf, n, fpgadir, nelem(fpgadir), devgen); 107 108 switch((ulong)c->qid.path){ 109 case Qmemb: 110 if(offset >= FPGASIZE) 111 return 0; 112 if(offset+n >= FPGASIZE) 113 n = FPGASIZE-offset; 114 memmove(buf, KADDR(FPGAMEM+offset), n); 115 return n; 116 case Qmemw: 117 if((n | offset) & 1) 118 error(Eodd); 119 if(offset >= FPGASIZE) 120 return 0; 121 if(offset+n >= FPGASIZE) 122 n = FPGASIZE-offset; 123 memmovew((ushort*)buf, (ushort*)KADDR(FPGAMEM+offset), n); 124 return n; 125 case Qstatus: 126 v = fpgastatus(); 127 p = seprint(stat, stat+sizeof(stat), "%sconfig", v&ConfDone?"":"!"); 128 seprint(p, stat+sizeof(stat), " %sstatus\n", v&nStatus?"":"!"); 129 return readstr(offset, buf, n, stat); 130 case Qclk: 131 return readnum(offset, buf, n, fpga.clkspeed, NUMSIZE); 132 case Qctl: 133 case Qprog: 134 return 0; 135 } 136 error(Egreg); 137 return 0; /* not reached */ 138 } 139 140 static long 141 fpgawrite(Chan *c, void *buf, long n, vlong offset) 142 { 143 int i, j, v; 144 ulong w; 145 Cmdbuf *cb; 146 ulong *cfg; 147 uchar *cp; 148 149 switch((ulong)c->qid.path){ 150 case Qmemb: 151 if(offset >= FPGASIZE) 152 return 0; 153 if(offset+n >= FPGASIZE) 154 n = FPGASIZE-offset; 155 memmove(KADDR(FPGAMEM+offset), buf, n); 156 return n; 157 case Qmemw: 158 if((n | offset) & 1) 159 error(Eodd); 160 if(offset >= FPGASIZE) 161 return 0; 162 if(offset+n >= FPGASIZE) 163 n = FPGASIZE-offset; 164 memmovew((ushort*)KADDR(FPGAMEM+offset), (ushort*)buf, n); 165 return n; 166 case Qctl: 167 cb = parsecmd(buf, n); 168 if(waserror()){ 169 free(cb); 170 nexterror(); 171 } 172 if(cb->nf < 1) 173 error(Ebadarg); 174 if(strcmp(cb->f[0], "reset") == 0) 175 resetfpga(); 176 else if(strcmp(cb->f[0], "bclk") == 0){ 177 v = 48; 178 if(cb->nf > 1) 179 v = strtoul(cb->f[1], nil, 0); 180 if(v <= 0 || 48%v != 0) 181 error(Ebadarg); 182 startfpga(48/v-1); 183 }else if(strcmp(cb->f[0], "vclk") == 0){ 184 if(cb->nf == 5){ /* vclk n m v r */ 185 vclkenable(1); 186 vclkset(cb->f[1], cb->f[2], cb->f[3], cb->f[4]); 187 }else 188 vclkenable(cb->nf < 2 || strcmp(cb->f[1], "on") == 0); 189 }else if(strcmp(cb->f[0], "power") == 0) 190 powerfpga(cb->nf < 2 || strcmp(cb->f[1], "off") != 0); 191 else 192 error(Ebadarg); 193 poperror(); 194 free(cb); 195 return n; 196 case Qprog: 197 qlock(&fpga); 198 if(waserror()){ 199 qunlock(&fpga); 200 nexterror(); 201 } 202 powerfpga(1); 203 resetfpga(); 204 cfg = KADDR(FPGACR); 205 cp = buf; 206 for(i=0; i<n; i++){ 207 w = cp[i]; 208 for(j=0; j<8; j++){ 209 *cfg = w&1; 210 w >>= 1; 211 } 212 } 213 for(j=0; j<50; j++) /* Altera note says at least 10 clock cycles, but microblaster uses 50 */ 214 *cfg = 0; 215 v = fpgastatus(); 216 if(v != (nStatus|ConfDone)){ 217 snprint(up->genbuf, sizeof(up->genbuf), "error loading fpga: status %d", v); 218 error(up->genbuf); 219 } 220 poperror(); 221 qunlock(&fpga); 222 return n; 223 } 224 error(Egreg); 225 return 0; /* not reached */ 226 } 227 228 /* 229 * PDN seems to control power to the FPGA subsystem 230 * but it is not documented nor is its scope clear (PLL as well?). 231 * It will not run without it. 232 */ 233 static void 234 powerfpga(int on) 235 { 236 IMM *io; 237 238 io = ioplock(); 239 if(io->sccr & COM3){ 240 io->sccrk = KEEP_ALIVE_KEY; 241 io->sccr &= ~ COM3; /* FPGA designs can use the clock */ 242 io->sccrk = ~KEEP_ALIVE_KEY; 243 } 244 io->pcpar &= ~PDN; 245 io->pcdir |= PDN; 246 if(on) 247 io->pcdat &= ~PDN; 248 else 249 io->pcdat |= PDN; 250 iopunlock(); 251 } 252 253 static void 254 resetfpga(void) 255 { 256 IMM *io; 257 258 io = ioplock(); 259 io->pcpar &= ~nCONFIG; 260 io->pcdir |= nCONFIG; 261 io->pcdat &= ~nCONFIG; 262 microdelay(200); 263 io->pcdat |= nCONFIG; 264 iopunlock(); 265 } 266 267 static int 268 fpgastatus(void) 269 { 270 /* isolate status bits IP_B0 and IP_B1 */ 271 return (m->iomem->pipr>>14) & (ConfDone|nStatus); 272 } 273 274 static void 275 startfpga(int scale) 276 { 277 IMM *io; 278 279 io = ioplock(); 280 io->tgcr &= ~(0xF<<TIMERSH); 281 io->tmr2 = ((scale&0xFF)<<8) | 0x2A; 282 io->tcn2 = 0; 283 io->trr2 = 0; 284 io->ter2 = 0xFFFF; 285 io->tgcr |= 0x1<<TIMERSH; 286 io->padir |= BCLK; 287 io->papar |= BCLK; 288 iopunlock(); 289 } 290 291 static void 292 vclkenable(int i) 293 { 294 IMM *io; 295 296 io = ioplock(); 297 io->padir &= ~VCLK; 298 io->papar &= ~VCLK; 299 io->pbdir |= EnableVCLK; 300 io->pbpar &= ~EnableVCLK; 301 if(i) 302 io->pbdat |= EnableVCLK; 303 else 304 io->pbdat &= ~EnableVCLK; 305 iopunlock(); 306 } 307 308 static void 309 vclkin(ulong *clk, int v) 310 { 311 int i; 312 313 for(i=0; i<7; i++) 314 *clk = (v>>i) & 1; 315 } 316 317 static void 318 vclkset(char *ns, char *ms, char *vs, char *rs) 319 { 320 int n, m, v, r; 321 ulong *clk; 322 323 clk = KADDR(CLOCKCR); 324 n = strtol(ns, nil, 0); 325 m = strtol(ms, nil, 0); 326 v = strtol(vs, nil, 0); 327 r = strtol(rs, nil, 0); 328 if(n < 3 || n > 127 || m < 3 || m > 127 || v != 1 && v != 8 || 329 r != 1 && r != 2 && r != 4 && r != 8) 330 error(Ebadarg); 331 vclkenable(0); 332 vclkin(clk, n); 333 vclkin(clk, m); 334 *clk = (v==0) & 1; 335 *clk = 1; *clk = 1; 336 *clk = r == 2 || r == 8; 337 *clk = r == 4 || r == 8; 338 *clk = 1; /* clock out */ 339 *clk = 0; /* disable clk/x */ 340 *clk = 1; *clk = 0; *clk = 1; 341 *clk = 0; *clk = 0; *clk = 0; 342 vclkenable(1); 343 } 344 345 /* 346 * copy data aligned on 16-bit word boundaries. 347 */ 348 static void 349 memmovew(ushort *to, ushort *from, long count) 350 { 351 int n; 352 353 if(count <= 0) 354 return; 355 count >>= 1; 356 n = (count+7) >> 3; 357 switch(count&7) { /* Duff's device */ 358 case 0: do { *to++ = *from++; 359 case 7: *to++ = *from++; 360 case 6: *to++ = *from++; 361 case 5: *to++ = *from++; 362 case 4: *to++ = *from++; 363 case 3: *to++ = *from++; 364 case 2: *to++ = *from++; 365 case 1: *to++ = *from++; 366 } while(--n > 0); 367 } 368 } 369 370 Dev fpgadevtab = { 371 'G', 372 "fpga", 373 374 fpgareset, 375 devinit, 376 devshutdown, 377 fpgaattach, 378 fpgawalk, 379 fpgastat, 380 fpgaopen, 381 devcreate, 382 fpgaclose, 383 fpgaread, 384 devbread, 385 fpgawrite, 386 devbwrite, 387 devremove, 388 devwstat, 389 }; 390