xref: /plan9-contrib/sys/src/cmd/jtagfs/mpsse.c (revision dedb130315e7b691e306ee069395ee1f0b18e4d4)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "debug.h"
5 #include "lebo.h"
6 #include "tap.h"
7 #include "chain.h"
8 #include "jtag.h"
9 #include "icert.h"
10 #include "mpsse.h"
11 
12 /*
13 	See schematics, openocd code.
14 	Guessing for the GuruDisp...
15  */
16 
17 static uchar cablingH[][4] = {
18 	[Sheeva]		{[TRST] 0x2, [SRST] 0x0, [TRSTnOE]0x0, [SRSTnOE] 0x04,},
19 	[GuruDisp]	{[TRST] 0x2, [SRST] 0x0, [TRSTnOE]0x0, [SRSTnOE] 0x04,},
20 };
21 
22 static uchar cablingL[][5] = {
23 	[Sheeva]		{[TCK] 0x01, [TDI] 0x02, [TDO]0x04, [TMS] 0x08, [nOE] 0x10,},
24 	[GuruDisp]	{[TCK] 0x01, [TDI] 0x02, [TDO]0x04, [TMS] 0x08, [nOE] 0x10,},
25 };
26 
27 static uchar valcabling[][2] = {
28 	[Sheeva]		{isPushPull, isOpenDrain},
29 	[GuruDisp]	{isPushPull, isPushPull},
30 };
31 
32 static u32int cpuids[] = {
33 	[Sheeva]		FeroceonId,
34 	[GuruDisp]	ArmadaId,
35 };
36 
37 static uchar
hinitvalH(int motherb,int trst,int srst)38 hinitvalH(int motherb, int trst, int srst)
39 {
40 	uchar hout;
41 
42 	hout = 0;
43 
44 	if(trst){
45 		hout |= cablingH[motherb][TRSTnOE];
46 		hout &= ~cablingH[motherb][TRST];
47 	}
48 	else{
49 		hout &= ~cablingH[motherb][TRSTnOE];
50 		hout |= cablingH[motherb][TRST];
51 	}
52 	if(srst){
53 		hout &= ~cablingH[motherb][SRSTnOE];
54 		hout |= cablingH[motherb][SRST];
55 	}
56 	else{
57 		hout |= cablingH[motherb][SRSTnOE];
58 		hout &= ~cablingH[motherb][SRST];
59 	}
60 
61 	return hout;
62 }
63 
64 static uchar
hinitdirH(int motherb)65 hinitdirH(int motherb)
66 {
67 	USED(motherb);
68 	//int i;
69 	//uchar dir;
70 	//dir = 0;
71 	//for(i = 0; i < 4; i++)
72 	//	dir |= cablingH[motherb][i];	/* BUG: TODO */
73 	return 0xf;
74 }
75 
76 int
mpsseflush(void * mdata)77 mpsseflush(void *mdata)
78 {
79 	int r, nb;
80 	ushort s;
81 	Mpsse *mpsse;
82 
83 	mpsse = mdata;
84 	s = 0xbebe;
85 
86 	r = 0;
87 
88 	nb = Bbuffered(&mpsse->bout);
89 	if(debug[DFile] || debug[DAll])
90 		fprint(2, "Flush %d\n", nb);
91 
92 	if(debug[DXFlush])
93 		Bwrite(&mpsse->bout, &s, sizeof s);
94 	if(nb && Bflush(&mpsse->bout) == Beof)
95 		r = -1;
96 
97 	return r;
98 }
99 
100 static int
mpsseresets(void * mdata,int trst,int srst)101 mpsseresets(void *mdata, int trst, int srst)
102 {
103 	char cmd[128];
104 	uchar hout, hdir;
105 	int motherb;
106 	Mpsse *mpsse;
107 
108 	mpsse = mdata;
109 	motherb = mpsse->motherb;
110 
111 	hdir = hinitdirH(motherb);
112 	hout = hinitvalH(motherb, trst, srst);
113 
114 	snprint(cmd, sizeof(cmd), "SetBitsH %#2.2ux %#2.2ux", hout, hdir);
115 	if(pushcmd(mpsse, cmd) < 0)
116 		return -1;
117 	if(mpsseflush(mpsse) < 0)
118 		return -1;
119 	return 0;
120 }
121 
122 
123 static int
initpins(Mpsse * mpsse)124 initpins(Mpsse *mpsse)
125 {
126 	char cmd[128];
127 	uchar hout, hdir;
128 	int motherb;
129 	Biobufhdr *bout;
130 
131 	motherb = mpsse->motherb;
132 	bout = &mpsse->bout;
133 
134 	/* value of this also depends on opendrain etc?, seems it does not */
135 	hout = cablingL[motherb][TMS];
136 	hdir =  cablingL[motherb][TCK]|cablingL[motherb][TDI];
137 	hdir |= cablingL[motherb][TMS]|cablingL[motherb][nOE];
138 	snprint(cmd, sizeof(cmd), "SetBitsL %#2.2ux %#2.2ux", hout, hdir);
139 	if(pushcmd(mpsse, cmd) < 0){
140 		Bterm(bout);
141 		return -1;
142 	}
143 	if(mpsseflush(mpsse) < 0)
144 		return -1;
145 
146 	/* is this Board dependant? */
147 	if(mpsseresets(mpsse, 0, 0) < 0)
148 		return -1;
149 
150 	return 0;
151 }
152 
153 static int
mpsseterm(void * mdata)154 mpsseterm(void *mdata)
155 {
156 	Mpsse *mpsse;
157 	int r;
158 
159 	mpsse = mdata;
160 	r =  Bterm(&mpsse->bout);
161 	free(mpsse);
162 
163 	return r;
164 }
165 
166 /* I always work with bits on the lsb side, nbits count the
167  * n less significant bits, no matter msb or lsb order
168  * I know that mpsse works with lsb on the lsb side and
169  * msb I am not sure how it is codified msb on lsb side would be
170  * 00001234, instead of lsb on msb side 12340000
171  * In any case I never use msb on the mpsse,
172  * just on the paths for convenience and they are lsb side
173  * like 000001234
174  * in other words, nbits always counts from lsb bit
175  */
176 static ulong
msb2lsb(ulong msbl,int nbits)177 msb2lsb(ulong msbl, int nbits)
178 {
179 	int i;
180 	ulong lsbl, bit;
181 
182 	lsbl = 0;
183 	for(i = 0; i < nbits; i++){
184 		bit = (msbl >> (nbits - i - 1))&1;
185 		lsbl |= bit << i;
186 	}
187 	return lsbl;
188 }
189 
190 /* how many clk bits takes to clock out a data bit */
191 static int
tmsdata2clk(int nbits)192 tmsdata2clk(int nbits)
193 {
194 	return ((nbits + 6)/7) * 3;
195 }
196 
197 #define takebits(byte, nbits, offset) (((byte) >> (offset)) & ((1U << (nbits))-1))
198 
199 static void
dropbits(Mpsse * mpsse,int nbits)200 dropbits(Mpsse *mpsse, int nbits)
201 {
202 	int nby, nbi;
203 
204 	nby = nbits / 8;
205 	nbi = nbits % 8;
206 
207 	assert(mpsse->nbits >= nbits);
208 
209 	mpsse->nbits -= 8*nby;
210 	mpsse->rb += nby;
211 
212 	mpsse->rbits = (mpsse->rbits + nbi) %8;
213 
214 	mpsse->nbits -= nbi;
215 }
216 
217 static int
runpath(JMedium * jmed,SmPath * pth,int isrd,int issend)218 runpath(JMedium *jmed, SmPath *pth, int isrd, int issend)
219 {
220 	SmPath pref;
221 	uchar tmslsb, lastbit;
222 	int nclkbits;
223 	char cmd[128];
224 	Mpsse *mpsse;
225 
226 	mpsse = jmed->mdata;
227 	lastbit = 0;
228 	nclkbits = 0;
229 	if(issend && mpsse->nbits != 0){
230 		lastbit = mpsse->lastbit;
231 		mpsse->nbits--;
232 		nclkbits = 1;
233 	}
234 
235 	while(pth->ptmslen != 0){
236 		pref = takepathpref(pth, MaxNbitsT);
237 		tmslsb = msb2lsb(pref.ptms, pref.ptmslen);
238 
239 		if(issend && nclkbits--){
240 			tmslsb |= lastbit<<7;
241 		}
242 		if(isrd)
243 			snprint(cmd, sizeof(cmd), "TmsCsOutIn EdgeDown EdgeUp LSB B%#2.2ux %#2.2ux",
244 				(uchar)pref.ptmslen, tmslsb);
245 		else
246 			snprint(cmd, sizeof(cmd), "TmsCsOut EdgeDown LSB B%#2.2ux %#2.2ux",
247 				(uchar)pref.ptmslen, tmslsb);
248 
249 		if(pushcmd(mpsse, cmd) < 0)
250 			return -1;
251 	}
252 
253 	moveto(jmed, pth->st);
254 	return 0;
255 }
256 
257 static int
sendbytes(Mpsse * mpsse,int nbytes,int op)258 sendbytes(Mpsse *mpsse, int nbytes, int op)
259 {
260 	char cmd[128];
261 	int totbytes, nwbytes;
262 	uchar *buf;
263 
264 	buf = mpsse->rb;
265 	totbytes = mpsse->nbits/8;
266 	nwbytes = nbytes;
267 	if(totbytes < nbytes){
268 		werrstr("sendbytes: not enough %d<%d", totbytes, nbytes);
269 		return -1;
270 	}
271 	if( (op&ShiftIn ) && !(op&ShiftOut) ){
272 		snprint(cmd, sizeof(cmd), "DataIn EdgeUp LSB %#2.2ux",
273 				nbytes);
274 		nwbytes = 0;
275 	}
276 	else if( !(op&ShiftIn) && (op&ShiftOut) )
277 		snprint(cmd, sizeof(cmd), "DataOut EdgeDown LSB %#2.2ux @",
278 				nbytes);
279 	else if( (op&ShiftIn) && (op&ShiftOut) )
280 
281 		snprint(cmd, sizeof(cmd), "DataOutIn EdgeDown EdgeUp LSB %#2.2ux @",
282 				nbytes);
283 	else
284 		return -1;
285 
286 
287 	if(pushcmdwdata(mpsse, cmd, buf, nwbytes) < 0)
288 		return -1;
289 
290 	dropbits(mpsse, 8*nbytes);
291 	return 0;
292 }
293 
294 
295 static int
sendbits(Mpsse * mpsse,int nbits,int op)296 sendbits(Mpsse *mpsse, int nbits, int op)
297 {
298 	char cmd[128];
299 	uchar lastbyte, obyte;
300 
301 	lastbyte = *mpsse->rb;
302 	if(nbits > 8){
303 		werrstr("too many bits %d>%d", nbits, MaxNbitsS);
304 		return -1;
305 	}
306 
307 
308 	obyte = takebits(lastbyte, nbits, mpsse->rbits);
309 
310 	if( (op&ShiftIn ) && !(op&ShiftOut) )
311 		snprint(cmd, sizeof(cmd), "DataIn EdgeUp LSB B%#2.2ux",
312 				nbits);
313 	else  if( !(op&ShiftIn) && (op&ShiftOut) )
314 		snprint(cmd, sizeof(cmd), "DataOut EdgeDown LSB B%#2.2ux %#2.2ux",
315 				nbits, obyte);
316 	else if( (op&ShiftIn) && (op&ShiftOut) )
317 
318 		snprint(cmd, sizeof(cmd), "DataOutIn EdgeDown EdgeUp LSB B%#2.2ux %#2.2ux",
319 				nbits, obyte);
320 	else
321 		return -1;
322 
323 
324 	if(pushcmd(mpsse, cmd) < 0)
325 		return -1;
326 
327 	dropbits(mpsse, nbits);
328 	return 0;
329 }
330 
331 static int
movetost(JMedium * jmed,int dst,int isrd,int issend)332 movetost(JMedium *jmed, int dst, int isrd, int issend)
333 {
334 	SmPath pth;
335 	int len;
336 
337 	pth = pathto(jmed, dst);
338 	len = pth.ptmslen;
339 	if(runpath(jmed, &pth, isrd, issend) < 0)
340 		return -1;
341 	return len;
342 }
343 
344 static int
stayinst(JMedium * jmed,int nclock)345 stayinst(JMedium *jmed, int nclock)
346 {
347 	SmPath pth;
348 
349 	pth.ptms = 0;
350 	pth.ptmslen = nclock;
351 	if(runpath(jmed, &pth, 0, 0) < 0)
352 		return -1;
353 	return nclock;
354 }
355 
356 static int
mpsserdshiftrep(JMedium * jmed,uchar * buf,ShiftRDesc * rep)357 mpsserdshiftrep(JMedium *jmed, uchar *buf, ShiftRDesc *rep)
358 {
359 	int nr, npartial, nby;
360 	uchar msk;
361 
362 	Mpsse *mpsse;
363 
364 	mpsse = jmed->mdata;
365 	dprint(DFile, "Reading %d\n", rep->nbyread);
366 
367 	nr = readn(mpsse->jtagfd, buf, rep->nbyread);
368 
369 	npartial = 0;
370 
371 	dprint(DFile, "Read %d\n", nr);
372 	dumpbuf(DFile, buf, nr);
373 	if(nr <= 0)
374 		return -1;
375 	if(rep->nbiprelast != 0){
376 		npartial++;
377 	}
378 	if(rep->nbilast != 0){
379 		npartial++;
380 	}
381 	nby = rep->nbyread - npartial;
382 	if(rep->nbiprelast != 0){
383 		buf[nby] = buf[nby] >> (8 - rep->nbiprelast);
384 	}
385 	if(rep->nbilast != 0){
386 		msk = MSK(rep->nbilast);
387 		buf[nby] |= (buf[nby+1] & msk) << (8 - rep->nbilast);
388 	}
389 	return (7 + nby + npartial) / 8;	/* readjust after compacting */
390 }
391 
392 /*
393  * May need a couple of two or three bytes of margin for reading,
394  * do not call it with just enough bytes
395 */
396 
397 static int
mpsseregshift(JMedium * jmed,ShiftTDesc * req,ShiftRDesc * rep)398 mpsseregshift(JMedium *jmed, ShiftTDesc *req, ShiftRDesc *rep)
399 {
400 	int npsend, nr, nl, isrd, nback, nby, ntrail, reg, nbits, op;
401 	ShiftRDesc rr;
402 	uchar *buf;
403 	Mpsse *mpsse;
404 
405 	reg = req->reg;
406 	buf = req->buf;
407 	nbits = req->nbits;
408 	op = req->op;
409 
410 	mpsse = jmed->mdata;
411 	if(rep == nil)
412 		rep = &rr;
413 
414 	nr = 0;
415 	nby = 0;
416 	nback = 0;
417 	npsend = 0;
418 
419 
420 	if(reg != TapDR && reg != TapIR)
421 		sysfatal("unknown register");
422 
423 	isrd = op&ShiftIn;
424 
425 	/*
426 	 *	May need to go to Pause to cross capture before starting
427 	 *	May still have a trailing bit from last shifting
428 	 */
429 
430 	if(op&ShiftPauseIn){
431 		nl = movetost(jmed, TapPauseDR+reg, 0, mpsse->nbits != 0);
432 		if(nl < 0){
433 			werrstr("regshift: going to pause in");
434 			return -1;
435 		}
436 	}
437 
438 	if(movetost(jmed, TapShiftDR+reg, 0, mpsse->nbits != 0) < 0){
439 		werrstr("regshift: going to shift");
440 		return -1;
441 	}
442 
443 	mpsse->nbits = nbits;
444 	mpsse->rb = buf;
445 	mpsse->rbits = 0;
446 
447 	if((mpsse->nbits / 8)  > 1){
448 		nby = mpsse->nbits / 8;
449 		if(mpsse->nbits % 8 == 0)
450 			nby--;
451 		if(sendbytes(mpsse, nby, op) < 0){
452 			werrstr("regshift: shifting bytes");
453 			return -1;
454 		}
455 		nback = nby;
456 	}
457 
458 
459 	if(mpsse->nbits > 1){
460 		nback++;				/* each op gives a partial byte */
461 		npsend = mpsse->nbits;
462 		if(mpsse->nbits > 7)		/* apparently hw does not like 8 bytes */
463 			npsend = MaxNbitsS;
464 		npsend -= 1;	/* one is for the way */
465 		if(sendbits(mpsse, npsend, op) < 0){
466 			werrstr("regshift: shifting bits");
467 			return -1;
468 		}
469 		mpsse->lastbit = takebits(*mpsse->rb, 1, mpsse->rbits);
470 	}
471 
472 
473 	/* 	I only go through pause if I need extra time to shift
474 	 *	for example, I need a command to read or if I am told
475 	*/
476 
477 	if(isrd || (op&ShiftPauseOut)){
478 		nback++;
479 		nl = movetost(jmed, TapPauseDR+reg, isrd, mpsse->nbits != 0);
480 		if(nl < 0){
481 			werrstr("regshift: going to pause out");
482 			return -1;
483 		}
484 	}
485 
486 	if(! (op&ShiftNoCommit)){
487 		nl = movetost(jmed, TapIdle, 0, mpsse->nbits != 0);
488 		if(nl < 0){
489 			werrstr("regshift: going to idle out");
490 			return -1;
491 		}
492 	}
493 	if(isrd){
494 		if(mpsseflush(mpsse) < 0){
495 			werrstr("regshift: flushing");
496 			return -1;
497 		}
498 
499 		ntrail = nbits - npsend - 8*nby;
500 		rep->nbyread = nback;
501 		rep->nbiprelast = npsend;
502 		rep->nbilast = ntrail;
503 		if( !(op&ShiftAsync) )
504 			nr = mpsserdshiftrep(jmed, buf, rep);
505 	}
506 	return nr;
507 }
508 
509 JMedium *
newmpsse(int fd,int motherb)510 newmpsse(int fd, int motherb)
511 {
512 	Mpsse *mpsse;
513 	Biobufhdr *bout;
514 	JMedium *jmed;
515 	int i;
516 
517 	jmed = mallocz(sizeof(JMedium), 1);
518 	if(jmed == nil)
519 		return nil;
520 
521 	mpsse = malloc(sizeof(Mpsse));
522 	if(mpsse == nil)
523 		return nil;
524 
525 	jmed->motherb = motherb;
526 	jmed->mdata = mpsse;
527 	jmed->regshift = mpsseregshift;
528 	jmed->rdshiftrep = mpsserdshiftrep;
529 	jmed->flush = mpsseflush;
530 	jmed->term = mpsseterm;
531 	jmed->resets = mpsseresets;
532 
533 	/* BUG: configuration file? */
534 	if(motherb == Sheeva){
535 		jmed->ntaps = 1;
536 		jmed->tapcpu = 0;
537 		jmed->taps[0].hwid = FeroceonId;
538 		jmed->taps[0].irlen = InLen;
539 	}
540 	else if(motherb == GuruDisp){
541 		/* BUG: set concatenating mode */
542 		jmed->ntaps = 3;
543 		jmed->taps[0].hwid = 0;
544 		jmed->taps[0].irlen = 1;
545 		jmed->tapcpu = 1;
546 		jmed->taps[1].hwid = ArmadaId;
547 		jmed->taps[1].irlen = InLen;
548 		jmed->taps[2].hwid = 0;
549 		jmed->taps[2].irlen = 9;
550 	}
551 	else
552 		sysfatal("Unkwown motherboard");
553 
554 	for(i = 0; i < jmed->ntaps; i++)
555 		jmed->taps[i].state = TapUnknown;
556 	jmed->state = TapUnknown;
557 
558 	mpsse->jtagfd = fd;
559 	mpsse->motherb = motherb;
560 
561 
562 	bout = &mpsse->bout;
563 
564 	if(Binits(bout, fd, OWRITE, mpsse->bp, MpsseBufSz) == Beof){
565 		free(mpsse);
566 		return nil;
567 	}
568 	return jmed;
569 }
570 
571 JMedium *
initmpsse(int fd,int motherb)572 initmpsse(int fd, int motherb)
573 {
574 	Mpsse *mpsse;
575 	JMedium *jmed;
576 	uchar buf[32];
577 	ShiftTDesc req;
578 
579 
580 	jmed = newmpsse(fd, motherb);
581 	if(jmed == nil){
582 		free(jmed);
583 		return nil;
584 	}
585 	mpsse = jmed->mdata;
586 
587 	if(initpins(mpsse) < 0)
588 		goto Err;
589 
590 	if(pushcmd(mpsse, "TckSkDiv 0x0200") < 0)
591 		goto Err;
592 	if(mpsseflush(mpsse) < 0)
593 		goto Err;
594 
595 	if(pushcmd(mpsse, "BreakLoop") < 0)
596 		goto Err;
597 	if(mpsseflush(mpsse) < 0)
598 		goto Err;
599 
600 	/* Board dependant ? */
601 	if(mpsseresets(mpsse, 0, 0) < 0)
602 		goto Err;
603 
604 	if(motherb == GuruDisp){	/* set concat mode */
605 		req.reg = TapIR;
606 		hleputs(buf, InGuruTapctl);
607 		req.buf = buf;
608 		req.nbits = InGuruLen;
609 		req.op = ShiftOut;
610 
611 		jmed->regshift(jmed, &req, nil);
612 		req.reg = TapDR;
613 		hleputs(buf, DrGuruTapctl);
614 		req.buf = buf;
615 		req.nbits = 16;
616 		req.op = ShiftOut;
617 		jmed->regshift(jmed, &req, nil);
618 		jmed->taps[2].TapSm = jmed->TapSm;
619 	}
620 	return jmed;
621 Err:
622 	mpsseterm(mpsse);
623 	free(jmed);
624 	return nil;
625 }
626 
627 static void
termmpsse(JMedium * jmed)628 termmpsse(JMedium *jmed)
629 {
630 	mpsseterm(jmed->mdata);
631 	free(jmed);
632 }
633 
634 
635 JMedium *
resetmpsse(JMedium * jmed)636 resetmpsse(JMedium *jmed)
637 {
638 	Mpsse mpsse;
639 	JMedium *jmnew;
640 
641 	mpsse = *(Mpsse *)jmed->mdata;
642 	mpsseflush((Mpsse *)jmed->mdata);
643 	free(jmed->mdata);
644 
645 	jmnew = initmpsse(mpsse.jtagfd, mpsse.motherb);
646 	return jmnew;
647 }
648 
649