| /* | 
 |  * Copyright (C) 1996 Paul Mackerras. | 
 |  */ | 
 | #include "nonstdio.h" | 
 | #include "privinst.h" | 
 |  | 
 | #define scanhex	xmon_scanhex | 
 | #define skipbl	xmon_skipbl | 
 |  | 
 | #define ADB_B		(*(volatile unsigned char *)0xf3016000) | 
 | #define ADB_SR		(*(volatile unsigned char *)0xf3017400) | 
 | #define ADB_ACR		(*(volatile unsigned char *)0xf3017600) | 
 | #define ADB_IFR		(*(volatile unsigned char *)0xf3017a00) | 
 |  | 
 | static inline void eieio(void) { asm volatile ("eieio" : :); } | 
 |  | 
 | #define N_ADB_LOG	1000 | 
 | struct adb_log { | 
 |     unsigned char b; | 
 |     unsigned char ifr; | 
 |     unsigned char acr; | 
 |     unsigned int time; | 
 | } adb_log[N_ADB_LOG]; | 
 | int n_adb_log; | 
 |  | 
 | void | 
 | init_adb_log(void) | 
 | { | 
 |     adb_log[0].b = ADB_B; | 
 |     adb_log[0].ifr = ADB_IFR; | 
 |     adb_log[0].acr = ADB_ACR; | 
 |     adb_log[0].time = get_dec(); | 
 |     n_adb_log = 0; | 
 | } | 
 |  | 
 | void | 
 | dump_adb_log(void) | 
 | { | 
 |     unsigned t, t0; | 
 |     struct adb_log *ap; | 
 |     int i; | 
 |  | 
 |     ap = adb_log; | 
 |     t0 = ap->time; | 
 |     for (i = 0; i <= n_adb_log; ++i, ++ap) { | 
 | 	t = t0 - ap->time; | 
 | 	printf("b=%x ifr=%x acr=%x at %d.%.7d\n", ap->b, ap->ifr, ap->acr, | 
 | 	       t / 1000000000, (t % 1000000000) / 100); | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | adb_chklog(void) | 
 | { | 
 |     struct adb_log *ap = &adb_log[n_adb_log + 1]; | 
 |  | 
 |     ap->b = ADB_B; | 
 |     ap->ifr = ADB_IFR; | 
 |     ap->acr = ADB_ACR; | 
 |     if (ap->b != ap[-1].b || (ap->ifr & 4) != (ap[-1].ifr & 4) | 
 | 	|| ap->acr != ap[-1].acr) { | 
 | 	ap->time = get_dec(); | 
 | 	++n_adb_log; | 
 |     } | 
 | } | 
 |  | 
 | int | 
 | adb_bitwait(int bmask, int bval, int fmask, int fval) | 
 | { | 
 |     int i; | 
 |     struct adb_log *ap; | 
 |  | 
 |     for (i = 10000; i > 0; --i) { | 
 | 	adb_chklog(); | 
 | 	ap = &adb_log[n_adb_log]; | 
 | 	if ((ap->b & bmask) == bval && (ap->ifr & fmask) == fval) | 
 | 	    return 0; | 
 |     } | 
 |     return -1; | 
 | } | 
 |  | 
 | int | 
 | adb_wait(void) | 
 | { | 
 |     if (adb_bitwait(0, 0, 4, 4) < 0) { | 
 | 	printf("adb: ready wait timeout\n"); | 
 | 	return -1; | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | void | 
 | adb_readin(void) | 
 | { | 
 |     int i, j; | 
 |     unsigned char d[64]; | 
 |  | 
 |     if (ADB_B & 8) { | 
 | 	printf("ADB_B: %x\n", ADB_B); | 
 | 	return; | 
 |     } | 
 |     i = 0; | 
 |     adb_wait(); | 
 |     j = ADB_SR; | 
 |     eieio(); | 
 |     ADB_B &= ~0x20; | 
 |     eieio(); | 
 |     for (;;) { | 
 | 	if (adb_wait() < 0) | 
 | 	    break; | 
 | 	d[i++] = ADB_SR; | 
 | 	eieio(); | 
 | 	if (ADB_B & 8) | 
 | 	    break; | 
 | 	ADB_B ^= 0x10; | 
 | 	eieio(); | 
 |     } | 
 |     ADB_B |= 0x30; | 
 |     if (adb_wait() == 0) | 
 | 	j = ADB_SR; | 
 |     for (j = 0; j < i; ++j) | 
 | 	printf("%.2x ", d[j]); | 
 |     printf("\n"); | 
 | } | 
 |  | 
 | int | 
 | adb_write(unsigned char *d, int i) | 
 | { | 
 |     int j; | 
 |     unsigned x; | 
 |  | 
 |     if ((ADB_B & 8) == 0) { | 
 | 	printf("r: "); | 
 | 	adb_readin(); | 
 |     } | 
 |     for (;;) { | 
 | 	ADB_ACR = 0x1c; | 
 | 	eieio(); | 
 | 	ADB_SR = d[0]; | 
 | 	eieio(); | 
 | 	ADB_B &= ~0x20; | 
 | 	eieio(); | 
 | 	if (ADB_B & 8) | 
 | 	    break; | 
 | 	ADB_ACR = 0xc; | 
 | 	eieio(); | 
 | 	ADB_B |= 0x20; | 
 | 	eieio(); | 
 | 	adb_readin(); | 
 |     } | 
 |     adb_wait(); | 
 |     for (j = 1; j < i; ++j) { | 
 | 	ADB_SR = d[j]; | 
 | 	eieio(); | 
 | 	ADB_B ^= 0x10; | 
 | 	eieio(); | 
 | 	if (adb_wait() < 0) | 
 | 	    break; | 
 |     } | 
 |     ADB_ACR = 0xc; | 
 |     eieio(); | 
 |     x = ADB_SR; | 
 |     eieio(); | 
 |     ADB_B |= 0x30; | 
 |     return j; | 
 | } | 
 |  | 
 | void | 
 | adbcmds(void) | 
 | { | 
 |     char cmd; | 
 |     unsigned rtcu, rtcl, dec, pdec, x; | 
 |     int i, j; | 
 |     unsigned char d[64]; | 
 |  | 
 |     cmd = skipbl(); | 
 |     switch (cmd) { | 
 |     case 't': | 
 | 	for (;;) { | 
 | 	    rtcl = get_rtcl(); | 
 | 	    rtcu = get_rtcu(); | 
 | 	    dec = get_dec(); | 
 | 	    printf("rtc u=%u l=%u dec=%x (%d = %d.%.7d)\n", | 
 | 		   rtcu, rtcl, dec, pdec - dec, (pdec - dec) / 1000000000, | 
 | 		   ((pdec - dec) % 1000000000) / 100); | 
 | 	    pdec = dec; | 
 | 	    if (cmd == 'x') | 
 | 		break; | 
 | 	    while (xmon_read(stdin, &cmd, 1) != 1) | 
 | 		; | 
 | 	} | 
 | 	break; | 
 |     case 'r': | 
 | 	init_adb_log(); | 
 | 	while (adb_bitwait(8, 0, 0, 0) == 0) | 
 | 	    adb_readin(); | 
 | 	break; | 
 |     case 'w': | 
 | 	i = 0; | 
 | 	while (scanhex(&x)) | 
 | 	    d[i++] = x; | 
 | 	init_adb_log(); | 
 | 	j = adb_write(d, i); | 
 | 	printf("sent %d bytes\n", j); | 
 | 	while (adb_bitwait(8, 0, 0, 0) == 0) | 
 | 	    adb_readin(); | 
 | 	break; | 
 |     case 'l': | 
 | 	dump_adb_log(); | 
 | 	break; | 
 |     } | 
 | } |