/* $NetBSD: pramasm.s,v 1.9 2013/09/07 19:06:29 chs Exp $ */ /* * RTC toolkit version 1.08b, copyright 1995, erik vogan * * All rights and privledges to this code hereby donated * to the ALICE group for use in NetBSD. see the copyright * below for more info... */ /* * Copyright (c) 1995 Erik Vogan * All rights reserved. * * This code is derived from software contributed to the Alice Group * by Erik Vogan. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Alice Group. * 4. The names of the Alice Group or any of its members may not be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * The following are the C interface functions to RTC access functions * that are defined later in this file. */ #include "opt_adb.h" #include #ifdef MRG_ADB /* * These functions are NOT defined at all if we are not using * the MRG method of accessing the ADB/PRAM/RTC. */ .text .even ENTRY(readPram) link %a6,#-4 | create a little home for ourselves .word 0xa03f | _InitUtil to read PRam moveml %d1/%a1,%sp@- moveq #0,%d0 | zero out length register moveb %a6@(19),%d0 | move the length byte in moveq #0,%d1 | zero out location moveb %a6@(15),%d1 | now get out PRam location lea _C_LABEL(SysParam),%a1 | start of PRam data movel %a6@(8),%a0 | get our data address _readPramAgain: subql #1,%d0 bcs _readPramDone | see if we are through moveb %a1@(%d1),%a0@+ | transfer byte addql #1,%d1 | next byte jmp _readPramAgain | do it again _readPramDone: clrw %d0 moveml %sp@+,%d1/%a1 unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(writePram) link %a6,#-4 | create a little home for ourselves .word 0xa03f | _InitUtil to read PRam in the case it hasn't been read yet moveml %d1/%a1,%sp@- moveq #0,%d0 | zero out length register moveb %a6@(19),%d0 | move the length byte in moveq #0,%d1 | zero out location moveb %a6@(15),%d1 | now get out PRam location lea _C_LABEL(SysParam),%a1 | start of PRam data movel %a6@(8),%a0 | get our data address _writePramAgain: subql #1,%d0 bcs _writePramDone | see if we are through cmpil #0x14,%d1 | check for end of _SysParam bcc _writePramDone | do not write if beyond end moveb %a0@+,%a1@(%d1) | transfer byte addql #1,%d1 | next byte jmp _writePramAgain | do it again _writePramDone: .word 0xa038 | writeParam moveml %sp@+,%d1/%a1 unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(readExtPram) link %a6,#-4 | create a little home for ourselves moveq #0,%d0 | zero out our future command register moveb %a6@(19),%d0 | move the length byte in swap %d0 | and make that the MSW moveb %a6@(15),%d0 | now get out PRAM location movel %a6@(8),%a0 | get our data address .word 0xa051 | and go read the data unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(writeExtPram) link %a6,#-4 | create a little home for ourselves moveq #0,%d0 | zero out our future command register moveb %a6@(19),%d0 | move the length byte in swap %d0 | and make that the MSW moveb %a6@(15),%d0 | now get out PRAM location movel %a6@(8),%a0 | get our data address .word 0xa052 | and go write the data unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(getPramTime) link %a6,#-4 | create a little home for ourselves .word 0xa03f | call the routine to read the time (InitUtil) movel _C_LABEL(Time),%d0 unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(setPramTime) link %a6,#-4 | create a little home for ourselves movel %a6@(8),%d0 | get the passed in long (seconds since 1904) .word 0xa03a | call the routine to write the time unlk %a6 | clean up after ourselves rts | and return to caller #else /* The following routines are the hardware specific routines for the * machines that use the II-like method to access the PRAM, and are only * defined when the MRG method is not used to access the PRAM. */ /* * The following are the C interface functions to RTC access functions * that are defined later in this file. */ .text .even ENTRY(readPramII) link %a6,#-4 | create a little home for ourselves moveq #0,%d0 | zero out our future command register moveb %a6@(19),%d0 | move the length byte in swap %d0 | and make that the MSW moveb %a6@(15),%d0 | now get out PRAM location oriw #0x0100,%d0 | and set up for non-extended read movel %a6@(8),%a0 | get our data address jbsr _C_LABEL(PRAMacc) | and go read the data unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(writePramII) link %a6,#-4 | create a little home for ourselves moveq #0,%d0 | zero out our future command register moveb %a6@(19),%d0 | move the length byte in swap %d0 | and make that the MSW moveb %a6@(15),%d0 | now get out PRAM location nop | and set up for non-extended write movel %a6@(8),%a0 | get our data address jbsr _C_LABEL(PRAMacc) | and go write the data unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(readExtPramII) link %a6,#-4 | create a little home for ourselves moveq #0,%d0 | zero out our future command register moveb %a6@(19),%d0 | move the length byte in swap %d0 | and make that the MSW moveb %a6@(15),%d0 | now get out PRAM location oriw #0x0300,%d0 | and set up for extended read movel %a6@(8),%a0 | get our data address jbsr _C_LABEL(PRAMacc) | and go read the data unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(writeExtPramII) link %a6,#-4 | create a little home for ourselves moveq #0,%d0 | zero out our future command register moveb %a6@(19),%d0 | move the length byte in swap %d0 | and make that the MSW moveb %a6@(15),%d0 | now get out PRAM location oriw #0x0200,%d0 | and set up for extended write movel %a6@(8),%a0 | get our data address jbsr _C_LABEL(PRAMacc) | and go write the data unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(getPramTimeII) link %a6,#-4 | create a little home for ourselves jbsr _C_LABEL(readClock) | call the routine to read the time unlk %a6 | clean up after ourselves rts | and return to caller ENTRY(setPramTimeII) link %a6,#-4 | create a little home for ourselves movel %a6@(8),%d0 | get the passed in long (seconds since 1904) jbsr _C_LABEL(writeClock) | call the routine to write the time unlk %a6 | clean up after ourselves rts | and return to caller /* * The following are the RTC access functions used by the interface * routines, above. */ ENTRY_NOPROFILE(readClock) moveml #0x7cc0,%sp@- | store off the regs we need moveq #00,%d0 | zero out our result reg readagan: moveq #00,%d5 | and our temp result reg moveq #03,%d4 | set our count down reg to 4 movel #0x00000081,%d1 | read sec byte 0 first getSecb: bsr _C_LABEL(Transfer) | get that byte rorl #8,%d5 | shift our time to the right swap %d1 | we want to access our new data moveb %d1,%d5 | move that byte to the spot we vacated swap %d1 | return our PRAM command to orig. config addqb #4,%d1 | increment to the next sec byte dbf %d4,getSecb | any more bytes to get ? cmpl %d5,%d0 | same secs value we as we just got ? beq gotTime | we got a good time value movel %d5,%d0 | copy our current time to the compare reg bra readagan | read the time again gotTime: rorl #8,%d0 | make that last shift to correctly order | time bytes!!! movel #0x00d50035,%d1 | we have to set the write protect bit | so the clock doesn't run down ! bsr _C_LABEL(Transfer) | (so sezs Apple...) moveml %sp@+,#0x033e | restore our regs rts | and return to caller ENTRY_NOPROFILE(writeClock) moveml #0x78c0,%sp@- | store off the regs we need moveq #03,%d4 | set our count down reg to 4 movel #0x00550035,%d1 | de-write-protect the PRAM bsr _C_LABEL(Transfer) | so we can set our value moveq #1,%d1 | write sec byte 0 first putSecb: swap %d1 | we want access to data byte of command moveb %d0,%d1 | set our first secs byte swap %d1 | and return command to orig. config bsr _C_LABEL(Transfer) | write that byte rorl #8,%d0 | shift our time to the right addqb #4,%d1 | increment to the next sec byte dbf %d4,putSecb | any more bytes to put ? movel #0x00d50035,%d1 | we have to set the write protect bit | so the clock doesn't run down ! bsr _C_LABEL(Transfer) | (so sezs Apple...) moveml %sp@+,#0x031e | restore our regs rts | and return to caller ENTRY_NOPROFILE(PRAMacc) moveml #0xf8c0,%sp@- | store off the regs we'll use moveq #00,%d3 | zero out our command reg moveq #00,%d4 | zero out our count reg too swap %d0 | we want the length byte movew %d0,%d4 | copy length byte to our counter reg swap %d0 | and return command reg to prior state subqb #1,%d4 | predecrement counter for use w/ DBF movew %d0,%d2 | copy command to %d2 rorw #8,%d2 | rotate copy to examine flags roxrw #1,%d2 | read/write bit out of param. roxlb #1,%d3 | and into command reg tstb %d3 | was it read (1) or write (0) ? bne NoWrit | go around de-write protect logic movel #0x00550035,%d1 | clear write protect bit of PRAM | (we really only need to zero the high | bit, but other patterns don't work! ) moveml #0x3000,%sp@- | store off the regs that'll change bsr _C_LABEL(Transfer) | and go de-write protect RTC moveml %sp@+,#0x000c | reclaim our reg values NoWrit: andib #1,%d2 | isolate the extended command bit beq oldPRAM | it's zero, so do old PRAM style access NuPRAM: moveb %d0,%d2 | reget our PRAM location lslw #4,%d3 | insert our template blanks moveq #2,%d1 | set bit counter for 3 cycles threebit: roxlb #1,%d2 | rotate address bit from %d2 roxlw #1,%d3 | and into command in %d3 dbf %d1,threebit | until we've done bits 7-5 lslw #1,%d3 | and add a bit spacer moveq #4,%d1 | ok, 5 bits to go... fivebit: roxlb #1,%d2 | another addr bit out of %d2 roxlw #1,%d3 | and into command template in %d3 dbf %d1,fivebit | til we've done bit 4-0 lslw #2,%d3 | more bit magic oriw #0x3880,%d3 | set extended command bits bra Loaddata | go load the rest of command for xfer rtn oldPRAM: moveb %d0,%d2 | reget our PRAM location lslb #1,%d3 | add a template blank (bit) rolb #4,%d2 | get low nibble of PRAM loc ready moveq #3,%d1 | set our bit counter for 4 cycles fourbit: roxlb #1,%d2 | bit out of PRAM loc roxlb #1,%d3 | and bit into PRAM command dbf %d1,fourbit | until we've done the low nibble lslb #2,%d3 | bump bits to type of command byte orib #0x41,%d3 | set command bits (for access to $0-F!) btst #4,%d2 | change to access $10-13 ? beq Loaddata | nope, should stay the way it is andib #0x8F,%d3 | clear bits 4-6 of current command orib #0x20,%d3 | and set bit 5 (now accesses $10-13) Loaddata: moveb %a0@,%d1 | get our (data/dummy) byte into %d1 swap %d1 | move (data/dummy) byte to MSW movew %d3,%d1 | now move command into %d1 tagain: bsr _C_LABEL(Transfer) | now execute that command swap %d1 | we want access to (data/dummy) byte moveb %d1,%a0@+ | move (data/dummy) byte back to %a0, moveb %a0@,%d1 | NEXT VICTIM!! swap %d1 | now we want to tweak the command addqw #4,%d1 | increment our memory addr by 1 (this even | works if we want to dump across 32 byte | boundries for an extended command!!! | thanks to the oriw #$3880 above !!!) dbf %d4,tagain | repeat until we've got all we want movel #0x00d50035,%d1 | remember that command to write the wp byte ? | set the high bit in the wp reg (Apple sezs | this way the battery won't wear down !! ) bsr _C_LABEL(Transfer) | so we'll play by the rules moveml %sp@+,#0x031f | restore all our registers rts | and return to our gracious caller ENTRY_NOPROFILE(Transfer) movew %sr,%sp@- | store the SR (we'll change it!) oriw #0x0700,%sr | disable all interrupts moveal _C_LABEL(Via1Base),%a1 | move VIA1 addr in reference reg moveq #0,%d2 | zero out %d2 (it'll hold VIA1 reg B contents) moveb %a1@,%d2 | and get VIA1 reg B contents andib #0xF8,%d2 | don't touch any but RTC bits | (and zero all those) movew %d1,%d3 | we want to manipulate our command andiw #0xFF00,%d3 | zero the LSB beq oldPRAMc | do an old PRAM style command xPRAMc: rorw #8,%d1 | swap the command bytes (1st byte of 2) bsr writebyte | and write the command byte rorw #8,%d1 | swap the command bytes again (2nd byte of 2) bsr writebyte | write that byte to RTC too moveq #0x1F,%d3 | r/w bit is $F for an extended command | (but command is swapped to MSW!! so add $10) bra Rwbrnch | go figure out if it's a read or a write cmd oldPRAMc: bsr writebyte | only one byte for an old PRAM command moveq #0x17,%d3 | r/w bit is $7 for and old PRAM command | ( command is swapped to MSW, add $10) Rwbrnch: swap %d1 | better get that (data/dummy) byte ready btst %d3,%d1 | test bit no. %d3 of reg %d1 (read or write ?) beq Wtrue | 0 = write, 1 = read (branch on write) Rtrue: bsr readbyte | read a byte from the RTC bra Cleanup | and call mom to clean up after us Wtrue: bsr writebyte | write the data to the RTC Cleanup: swap %d1 | move command to LSW again bset #2,%a1@ | bring the RTC enable line high (end of xfer) movew %sp@+,%sr | restore prior interrupt status rts | and return to caller writebyte: moveq #7,%d3 | set our bit counter to 8 wagain: lsrb #1,%d2 | ditch the old data channel value roxlb #1,%d1 | and move a new value to X roxlb #1,%d2 | now move value from X to data channel moveb %d2,%a1@ | set our VIA1 reg B contents to match bset #1,%a1@ | and finish strobing the clock line dbf %d3,wagain | do this until we've sent a whole byte lsrb #1,%d2 | ditch the data channel value one last time roxlb #1,%d1 | get rid of the extra X bit we've carried lslb #1,%d2 | and restore %d2 to prior status rts | return to caller readbyte: moveq #7,%d3 | set our bit counter to 8 bclr #0,%a1@(0x0400) | set VIA1 reg B data line to input ragain: bclr #1,%a1@ | strobe the clock line to make bset #1,%a1@ | the data valid moveb %a1@,%d2 | and get out data byte lsrb #1,%d2 | get the data channel value to X roxlb #1,%d1 | and move X to data byte dbf %d3,ragain | do this until we've received a whole byte bset #0,%a1@(0x0400) | and return RTC data line to output rts | return to caller #endif /* MRG_ADB */