diff options
Diffstat (limited to 'c/src/lib/libbsp/m68k/efi68k/startup/efi68k_tcp.c')
-rw-r--r-- | c/src/lib/libbsp/m68k/efi68k/startup/efi68k_tcp.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/m68k/efi68k/startup/efi68k_tcp.c b/c/src/lib/libbsp/m68k/efi68k/startup/efi68k_tcp.c new file mode 100644 index 0000000000..9dd4836b25 --- /dev/null +++ b/c/src/lib/libbsp/m68k/efi68k/startup/efi68k_tcp.c @@ -0,0 +1,248 @@ +/* + *------------------------------------------------------------------- + * + * This file contains the subroutines necessary to initalize + * the DP8750A TCP on the efi68k board. + * + * This file has been created by John S. Gwynne for the efi68k + * project. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. Redistribution of source code and documentation must retain + * the above authorship, this list of conditions and the + * following disclaimer. + * 2. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * This software is provided "AS IS" without warranty of any kind, + * either expressed or implied, including, but not limited to, the + * implied warranties of merchantability, title and fitness for a + * particular purpose. + * + *------------------------------------------------------------------ + * + * $Id$ + */ + +#include <bsp.h> + +/* define tcp struct pointers */ +struct clock_ram * const tcp_power_up = + (struct clock_ram * const)(0x16*2+TCP_BASE_ADDRESS); + +struct clock_ram * const tcp_power_down = + (struct clock_ram * const)(0x1b*2+TCP_BASE_ADDRESS); + +struct clock_counters * const tcp_clock = + (struct clock_counters * const)(0x05*2+TCP_BASE_ADDRESS); + +struct clock_ram * const tcp_save_ram = + (struct clock_ram * const)(0x19*2+TCP_BASE_ADDRESS); + +#define X_DELAY 300 /* time-out delay for crystal start */ +#define X1_DELAY 100000 + +void tcp_delay(int count) +{ + int i; + /* change latter to use a counter !!! */ + for (i=0;i<count/4;i++); +} + +void tcp_init() +{ + unsigned char low_bat, osc_fail, power_up; + unsigned char mon, dom, hrs, min, sec; + int i, count; + + /* delay about 60us to ensure TCP is not locked-out */ + tcp_delay(80); + + /* set normal supply mode and reset test mode bit */ + *MSR = 0; + *PFR = 0; + + /* save oscillator failure condition */ + *MSR = 0; /* set RS and PS to zero */ + osc_fail = (*PFR & OSF ? 1 : 0); + *MSR = PS; + *RAM_OSC_FAIL = *RAM_OSC_FAIL || osc_fail; + + *MSR = PS; + if (*RAM_OSC_FAIL) { + power_up = 1; + *MSR = PS; + *RAM_POWERUP = power_up; + /* clear time counters and power up & down ram */ + *MSR = 0; + tcp_clock->hofs = 0; + tcp_clock->sec = 0; + tcp_clock->min = 0; + tcp_clock->hrs = 0; + tcp_clock->dom = 1; + tcp_clock->mon = 1; + tcp_clock->yr = 0x95; + tcp_clock->jd0 = 0x01; + tcp_clock->jd1 = 0; + tcp_clock->dow = 1; + *MSR = PS; + tcp_power_up->sec = 0; + tcp_power_up->min = 0; + tcp_power_up->hrs = 0; + tcp_power_up->dom = 0; + tcp_power_up->mon = 0; + tcp_power_down->sec = 0; + tcp_power_down->min = 0; + tcp_power_down->hrs = 0; + tcp_power_down->dom = 0; + tcp_power_down->mon = 0; + } else { + /* save for power-up test */ + *MSR = 0; + power_up = (*IRR & TMSE ? 0 : 1); + *MSR = PS; + *RAM_POWERUP = power_up; + + /* update tcp_power_up and tcp_power_down on power up */ + if (power_up) { + *MSR = 0; + do { + *PFR; + sec = tcp_clock->sec; + min = tcp_clock->min; + hrs = tcp_clock->hrs; + dom = tcp_clock->dom; + mon = tcp_clock->mon; + } while (*PFR & R_1S); + *MSR = PS; + tcp_power_up->sec = sec; + tcp_power_up->min = min; + tcp_power_up->hrs = hrs; + tcp_power_up->dom = dom; + tcp_power_up->mon = ( (((mon>>4)*10)+(mon&0xf))>12 ? 0 : mon ); + *MSR = 0; /* save ram is not running */ + sec = tcp_save_ram->sec; + min = tcp_save_ram->min; + hrs = tcp_save_ram->hrs; + dom = tcp_save_ram->dom; + mon = tcp_save_ram->mon; + *MSR = PS; + tcp_power_down->sec = sec; + tcp_power_down->min = min; + tcp_power_down->hrs = hrs; + tcp_power_down->dom = dom; + tcp_power_down->mon = ( (((mon>>4)*10)+(mon&0xf))>12 ? 0 : mon ); + } + } + + /* load interrupt routing reg. PF must be enabled to test + for low battery, but I route it to MFO to avoid any + potential problems */ + *MSR = 0; + *IRR = PF_R | TMSE; + + /* initialize the output mode register */ + *MSR = RS; + *OMR = IP | MP | MO; /* INTR active low and push/pull */ + + /* initialize interrupt control reg 0 */ + *MSR = RS; + *ICR0 = 0; /* disable all interrupts */ + + /* initialize interrupt control reg 1 */ + *MSR = RS; + *ICR1 = PFE; /* this also enables the low battery + detection circuit. */ + + /* I had trouble getting the tcp to be completely + flexabale to supply modes (i.e., automatically + selecting single or normal battery backup modes based + on inputs at power-up. If single supply mode is + selected, the low battery detect is disabled and the + low battery detect in normal mode does not seem to + detect when no battery is present at all. If normal + mode is selected and no battery is present, the + crystal will stop, but only if reset after + power-up. It would seem that after a power-up reset, + with no battery, the chip may automaticlly switch to + single supply mode which disables the low battery + detection circuit.) The following software tests + works for all permiatations of low batt, reset, + power-on reset, battery, no battery, battery on after + Vcc,.... *except* for battery switched on for the + first time before power up in which case the chip + will still be in single suppy mode till restarted (a + second call to tcp_init such as when the time is set + or a reboot.) The timer/clock itself should always + be completely functional regardless of the supply + mode. */ + + + /* initialize the real time mode register */ + /* note: write mode bits *before* CSS, then set CSS */ + *MSR = 0; /* clear roll-over */ + *PFR; + count=1; + for (i=0;i<X_DELAY;i++) { /* loop till xtal starts */ + *MSR = RS; + *RTMR = (*RTMR & (LY0 | LY1 )) | CSS; + *MSR = 0; + if (*PFR & R_1MS) + if (!(count--)) break; + } + if (i>=X_DELAY) { + { + /* xtal didn't start; try single supply mode */ + *MSR = 0; /* single supply */ + *PFR = OSF; + *MSR = 0; /* clear roll-over */ + *PFR; + count=1; + for (i=0;i<X1_DELAY;i++) { /* loop till xtal starts */ + *MSR = RS; + *RTMR = (*RTMR & (LY0 | LY1 )) | CSS; + *MSR = 0; + if (*PFR & R_1MS) + if (!(count--)) break; + } + if (i>=X1_DELAY) { + /* xtal didn't start; fail tcp */ + *MSR = PS; + *RAM_TCP_FAILURE = 1; + *MSR = PS; + *RAM_SINGLE_SUP=1; + } else { + *MSR = PS; + *RAM_TCP_FAILURE = 0; + *MSR = PS; + *RAM_SINGLE_SUP=1; + } + } + } else { + *MSR = PS; + *RAM_TCP_FAILURE = 0; + *MSR = PS; + *RAM_SINGLE_SUP=0; + } + + /* wait for low battery detection circuit to stabalize */ + tcp_delay(1000); + + /* battery test */ + *MSR = 0; + low_bat = (*IRR & LBF ? 1 : 0 ); + *MSR = PS; + *RAM_LOWBAT = low_bat & !(*RAM_SINGLE_SUP); + + /* reset pending interrupts */ + *MSR = ( PER | AL | T0 | T1 ); + + /* resync the time save ram with the clock */ + tcp_save_ram->sec = 0; + tcp_save_ram->min = 0; + tcp_save_ram->hrs = 0; + tcp_save_ram->dom = 0; + tcp_save_ram->mon = 0; +} |