| /* |
| * 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; |
| } |
| } |