1/* $NetBSD: pramasm.s,v 1.8 2001/11/20 03:19:43 chs Exp $ */ 2 3/* 4 * RTC toolkit version 1.08b, copyright 1995, erik vogan 5 * 6 * All rights and privledges to this code hereby donated 7 * to the ALICE group for use in NetBSD. see the copyright 8 * below for more info... 9 */ 10/* 11 * Copyright (c) 1995 Erik Vogan 12 * All rights reserved. 13 * 14 * This code is derived from software contributed to the Alice Group 15 * by Erik Vogan. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. All advertising materials mentioning features or use of this software 26 * must display the following acknowledgement: 27 * This product includes software developed by the Alice Group. 28 * 4. The names of the Alice Group or any of its members may not be used 29 * to endorse or promote products derived from this software without 30 * specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 35 * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, 36 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 37 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44/* 45 * The following are the C interface functions to RTC access functions 46 * that are defined later in this file. 47 */ 48 49#include "opt_adb.h" 50 51#include <m68k/asm.h> 52 53#ifdef MRG_ADB 54/* 55 * These functions are NOT defined at all if we are not using 56 * the MRG method of accessing the ADB/PRAM/RTC. 57 */ 58 59 .text 60 61 .even 62ENTRY(readPram) 63 link %a6,#-4 | create a little home for ourselves 64 .word 0xa03f | _InitUtil to read PRam 65 moveml %d1/%a1,%sp@- 66 moveq #0,%d0 | zero out length register 67 moveb %a6@(19),%d0 | move the length byte in 68 moveq #0,%d1 | zero out location 69 moveb %a6@(15),%d1 | now get out PRam location 70 lea _C_LABEL(SysParam),%a1 | start of PRam data 71 movel %a6@(8),%a0 | get our data address 72_readPramAgain: 73 subql #1,%d0 74 bcs _readPramDone | see if we are through 75 moveb %a1@(%d1),%a0@+ | transfer byte 76 addql #1,%d1 | next byte 77 jmp _readPramAgain | do it again 78_readPramDone: 79 clrw %d0 80 moveml %sp@+,%d1/%a1 81 unlk %a6 | clean up after ourselves 82 rts | and return to caller 83 84 85ENTRY(writePram) 86 link %a6,#-4 | create a little home for ourselves 87 .word 0xa03f | _InitUtil to read PRam in the case it hasn't been read yet 88 moveml %d1/%a1,%sp@- 89 moveq #0,%d0 | zero out length register 90 moveb %a6@(19),%d0 | move the length byte in 91 moveq #0,%d1 | zero out location 92 moveb %a6@(15),%d1 | now get out PRam location 93 lea _C_LABEL(SysParam),%a1 | start of PRam data 94 movel %a6@(8),%a0 | get our data address 95_writePramAgain: 96 subql #1,%d0 97 bcs _writePramDone | see if we are through 98 cmpil #0x14,%d1 | check for end of _SysParam 99 bcc _writePramDone | do not write if beyond end 100 moveb %a0@+,%a1@(%d1) | transfer byte 101 addql #1,%d1 | next byte 102 jmp _writePramAgain | do it again 103_writePramDone: 104 .word 0xa038 | writeParam 105 moveml %sp@+,%d1/%a1 106 unlk %a6 | clean up after ourselves 107 rts | and return to caller 108 109 110ENTRY(readExtPram) 111 link %a6,#-4 | create a little home for ourselves 112 moveq #0,%d0 | zero out our future command register 113 moveb %a6@(19),%d0 | move the length byte in 114 swap %d0 | and make that the MSW 115 moveb %a6@(15),%d0 | now get out PRAM location 116 movel %a6@(8),%a0 | get our data address 117 .word 0xa051 | and go read the data 118 unlk %a6 | clean up after ourselves 119 rts | and return to caller 120 121ENTRY(writeExtPram) 122 link %a6,#-4 | create a little home for ourselves 123 moveq #0,%d0 | zero out our future command register 124 moveb %a6@(19),%d0 | move the length byte in 125 swap %d0 | and make that the MSW 126 moveb %a6@(15),%d0 | now get out PRAM location 127 movel %a6@(8),%a0 | get our data address 128 .word 0xa052 | and go write the data 129 unlk %a6 | clean up after ourselves 130 rts | and return to caller 131 132ENTRY(getPramTime) 133 link %a6,#-4 | create a little home for ourselves 134 .word 0xa03f | call the routine to read the time (InitUtil) 135 movel _C_LABEL(Time),%d0 136 unlk %a6 | clean up after ourselves 137 rts | and return to caller 138 139ENTRY(setPramTime) 140 link %a6,#-4 | create a little home for ourselves 141 movel %a6@(8),%d0 | get the passed in long (seconds since 1904) 142 .word 0xa03a | call the routine to write the time 143 unlk %a6 | clean up after ourselves 144 rts | and return to caller 145 146#else 147/* The following routines are the hardware specific routines for the 148 * machines that use the II-like method to access the PRAM, and are only 149 * defined when the MRG method is not used to access the PRAM. 150 */ 151 152/* 153 * The following are the C interface functions to RTC access functions 154 * that are defined later in this file. 155 */ 156 157 .text 158 159 .even 160ENTRY(readPramII) 161 link %a6,#-4 | create a little home for ourselves 162 moveq #0,%d0 | zero out our future command register 163 moveb %a6@(19),%d0 | move the length byte in 164 swap %d0 | and make that the MSW 165 moveb %a6@(15),%d0 | now get out PRAM location 166 oriw #0x0100,%d0 | and set up for non-extended read 167 movel %a6@(8),%a0 | get our data address 168 jbsr _C_LABEL(PRAMacc) | and go read the data 169 unlk %a6 | clean up after ourselves 170 rts | and return to caller 171 172ENTRY(writePramII) 173 link %a6,#-4 | create a little home for ourselves 174 moveq #0,%d0 | zero out our future command register 175 moveb %a6@(19),%d0 | move the length byte in 176 swap %d0 | and make that the MSW 177 moveb %a6@(15),%d0 | now get out PRAM location 178 nop | and set up for non-extended write 179 movel %a6@(8),%a0 | get our data address 180 jbsr _C_LABEL(PRAMacc) | and go write the data 181 unlk %a6 | clean up after ourselves 182 rts | and return to caller 183 184ENTRY(readExtPramII) 185 link %a6,#-4 | create a little home for ourselves 186 moveq #0,%d0 | zero out our future command register 187 moveb %a6@(19),%d0 | move the length byte in 188 swap %d0 | and make that the MSW 189 moveb %a6@(15),%d0 | now get out PRAM location 190 oriw #0x0300,%d0 | and set up for extended read 191 movel %a6@(8),%a0 | get our data address 192 jbsr _C_LABEL(PRAMacc) | and go read the data 193 unlk %a6 | clean up after ourselves 194 rts | and return to caller 195 196ENTRY(writeExtPramII) 197 link %a6,#-4 | create a little home for ourselves 198 moveq #0,%d0 | zero out our future command register 199 moveb %a6@(19),%d0 | move the length byte in 200 swap %d0 | and make that the MSW 201 moveb %a6@(15),%d0 | now get out PRAM location 202 oriw #0x0200,%d0 | and set up for extended write 203 movel %a6@(8),%a0 | get our data address 204 jbsr _C_LABEL(PRAMacc) | and go write the data 205 unlk %a6 | clean up after ourselves 206 rts | and return to caller 207 208ENTRY(getPramTimeII) 209 link %a6,#-4 | create a little home for ourselves 210 jbsr _C_LABEL(readClock) | call the routine to read the time 211 unlk %a6 | clean up after ourselves 212 rts | and return to caller 213 214ENTRY(setPramTimeII) 215 link %a6,#-4 | create a little home for ourselves 216 movel %a6@(8),%d0 | get the passed in long (seconds since 1904) 217 jbsr _C_LABEL(writeClock) | call the routine to write the time 218 unlk %a6 | clean up after ourselves 219 rts | and return to caller 220 221/* 222 * The following are the RTC access functions used by the interface 223 * routines, above. 224 */ 225 226ENTRY(readClock) 227 moveml #0x7cc0,%sp@- | store off the regs we need 228 moveq #00,%d0 | zero out our result reg 229readagan: 230 moveq #00,%d5 | and our temp result reg 231 moveq #03,%d4 | set our count down reg to 4 232 movel #0x00000081,%d1 | read sec byte 0 first 233getSecb: 234 bsr _C_LABEL(Transfer) | get that byte 235 rorl #8,%d5 | shift our time to the right 236 swap %d1 | we want to access our new data 237 moveb %d1,%d5 | move that byte to the spot we vacated 238 swap %d1 | return our PRAM command to orig. config 239 addqb #4,%d1 | increment to the next sec byte 240 dbf %d4,getSecb | any more bytes to get ? 241 cmpl %d5,%d0 | same secs value we as we just got ? 242 beq gotTime | we got a good time value 243 movel %d5,%d0 | copy our current time to the compare reg 244 bra readagan | read the time again 245gotTime: 246 rorl #8,%d0 | make that last shift to correctly order 247 | time bytes!!! 248 movel #0x00d50035,%d1 | we have to set the write protect bit 249 | so the clock doesn't run down ! 250 bsr _C_LABEL(Transfer) | (so sezs Apple...) 251 moveml %sp@+,#0x033e | restore our regs 252 rts | and return to caller 253 254ENTRY(writeClock) 255 moveml #0x78c0,%sp@- | store off the regs we need 256 moveq #03,%d4 | set our count down reg to 4 257 movel #0x00550035,%d1 | de-write-protect the PRAM 258 bsr _C_LABEL(Transfer) | so we can set our value 259 moveq #1,%d1 | write sec byte 0 first 260putSecb: 261 swap %d1 | we want access to data byte of command 262 moveb %d0,%d1 | set our first secs byte 263 swap %d1 | and return command to orig. config 264 bsr _C_LABEL(Transfer) | write that byte 265 rorl #8,%d0 | shift our time to the right 266 addqb #4,%d1 | increment to the next sec byte 267 dbf %d4,putSecb | any more bytes to put ? 268 movel #0x00d50035,%d1 | we have to set the write protect bit 269 | so the clock doesn't run down ! 270 bsr _C_LABEL(Transfer) | (so sezs Apple...) 271 moveml %sp@+,#0x031e | restore our regs 272 rts | and return to caller 273 274ENTRY(PRAMacc) 275 moveml #0xf8c0,%sp@- | store off the regs we'll use 276 moveq #00,%d3 | zero out our command reg 277 moveq #00,%d4 | zero out our count reg too 278 swap %d0 | we want the length byte 279 movew %d0,%d4 | copy length byte to our counter reg 280 swap %d0 | and return command reg to prior state 281 subqb #1,%d4 | predecrement counter for use w/ DBF 282 movew %d0,%d2 | copy command to %d2 283 rorw #8,%d2 | rotate copy to examine flags 284 roxrw #1,%d2 | read/write bit out of param. 285 roxlb #1,%d3 | and into command reg 286 tstb %d3 | was it read (1) or write (0) ? 287 bne NoWrit | go around de-write protect logic 288 movel #0x00550035,%d1 | clear write protect bit of PRAM 289 | (we really only need to zero the high 290 | bit, but other patterns don't work! ) 291 moveml #0x3000,%sp@- | store off the regs that'll change 292 bsr _C_LABEL(Transfer) | and go de-write protect RTC 293 moveml %sp@+,#0x000c | reclaim our reg values 294NoWrit: 295 andib #1,%d2 | isolate the extended command bit 296 beq oldPRAM | it's zero, so do old PRAM style access 297NuPRAM: 298 moveb %d0,%d2 | reget our PRAM location 299 lslw #4,%d3 | insert our template blanks 300 moveq #2,%d1 | set bit counter for 3 cycles 301threebit: 302 roxlb #1,%d2 | rotate address bit from %d2 303 roxlw #1,%d3 | and into command in %d3 304 dbf %d1,threebit | until we've done bits 7-5 305 lslw #1,%d3 | and add a bit spacer 306 moveq #4,%d1 | ok, 5 bits to go... 307fivebit: 308 roxlb #1,%d2 | another addr bit out of %d2 309 roxlw #1,%d3 | and into command template in %d3 310 dbf %d1,fivebit | til we've done bit 4-0 311 lslw #2,%d3 | more bit magic 312 oriw #0x3880,%d3 | set extended command bits 313 bra Loaddata | go load the rest of command for xfer rtn 314oldPRAM: 315 moveb %d0,%d2 | reget our PRAM location 316 lslb #1,%d3 | add a template blank (bit) 317 rolb #4,%d2 | get low nibble of PRAM loc ready 318 moveq #3,%d1 | set our bit counter for 4 cycles 319fourbit: 320 roxlb #1,%d2 | bit out of PRAM loc 321 roxlb #1,%d3 | and bit into PRAM command 322 dbf %d1,fourbit | until we've done the low nibble 323 lslb #2,%d3 | bump bits to type of command byte 324 orib #0x41,%d3 | set command bits (for access to $0-F!) 325 btst #4,%d2 | change to access $10-13 ? 326 beq Loaddata | nope, should stay the way it is 327 andib #0x8F,%d3 | clear bits 4-6 of current command 328 orib #0x20,%d3 | and set bit 5 (now accesses $10-13) 329Loaddata: 330 moveb %a0@,%d1 | get our (data/dummy) byte into %d1 331 swap %d1 | move (data/dummy) byte to MSW 332 movew %d3,%d1 | now move command into %d1 333tagain: 334 bsr _C_LABEL(Transfer) | now execute that command 335 swap %d1 | we want access to (data/dummy) byte 336 moveb %d1,%a0@+ | move (data/dummy) byte back to %a0, 337 moveb %a0@,%d1 | NEXT VICTIM!! 338 swap %d1 | now we want to tweak the command 339 addqw #4,%d1 | increment our memory addr by 1 (this even 340 | works if we want to dump across 32 byte 341 | boundries for an extended command!!! 342 | thanks to the oriw #$3880 above !!!) 343 dbf %d4,tagain | repeat until we've got all we want 344 movel #0x00d50035,%d1 | remember that command to write the wp byte ? 345 | set the high bit in the wp reg (Apple sezs 346 | this way the battery won't wear down !! ) 347 bsr _C_LABEL(Transfer) | so we'll play by the rules 348 moveml %sp@+,#0x031f | restore all our registers 349 rts | and return to our gracious caller 350 351ENTRY(Transfer) 352 movew %sr,%sp@- | store the SR (we'll change it!) 353 oriw #0x0700,%sr | disable all interrupts 354 moveal _C_LABEL(Via1Base),%a1 | move VIA1 addr in reference reg 355 moveq #0,%d2 | zero out %d2 (it'll hold VIA1 reg B contents) 356 moveb %a1@,%d2 | and get VIA1 reg B contents 357 andib #0xF8,%d2 | don't touch any but RTC bits 358 | (and zero all those) 359 movew %d1,%d3 | we want to manipulate our command 360 andiw #0xFF00,%d3 | zero the LSB 361 beq oldPRAMc | do an old PRAM style command 362xPRAMc: 363 rorw #8,%d1 | swap the command bytes (1st byte of 2) 364 bsr writebyte | and write the command byte 365 rorw #8,%d1 | swap the command bytes again (2nd byte of 2) 366 bsr writebyte | write that byte to RTC too 367 moveq #0x1F,%d3 | r/w bit is $F for an extended command 368 | (but command is swapped to MSW!! so add $10) 369 bra Rwbrnch | go figure out if it's a read or a write cmd 370oldPRAMc: 371 bsr writebyte | only one byte for an old PRAM command 372 moveq #0x17,%d3 | r/w bit is $7 for and old PRAM command 373 | ( command is swapped to MSW, add $10) 374Rwbrnch: 375 swap %d1 | better get that (data/dummy) byte ready 376 btst %d3,%d1 | test bit no. %d3 of reg %d1 (read or write ?) 377 beq Wtrue | 0 = write, 1 = read (branch on write) 378Rtrue: 379 bsr readbyte | read a byte from the RTC 380 bra Cleanup | and call mom to clean up after us 381Wtrue: 382 bsr writebyte | write the data to the RTC 383Cleanup: 384 swap %d1 | move command to LSW again 385 bset #2,%a1@ | bring the RTC enable line high (end of xfer) 386 movew %sp@+,%sr | restore prior interrupt status 387 rts | and return to caller 388 389writebyte: 390 moveq #7,%d3 | set our bit counter to 8 391wagain: 392 lsrb #1,%d2 | ditch the old data channel value 393 roxlb #1,%d1 | and move a new value to X 394 roxlb #1,%d2 | now move value from X to data channel 395 moveb %d2,%a1@ | set our VIA1 reg B contents to match 396 bset #1,%a1@ | and finish strobing the clock line 397 dbf %d3,wagain | do this until we've sent a whole byte 398 lsrb #1,%d2 | ditch the data channel value one last time 399 roxlb #1,%d1 | get rid of the extra X bit we've carried 400 lslb #1,%d2 | and restore %d2 to prior status 401 rts | return to caller 402 403readbyte: 404 moveq #7,%d3 | set our bit counter to 8 405 bclr #0,%a1@(0x0400) | set VIA1 reg B data line to input 406ragain: 407 bclr #1,%a1@ | strobe the clock line to make 408 bset #1,%a1@ | the data valid 409 moveb %a1@,%d2 | and get out data byte 410 lsrb #1,%d2 | get the data channel value to X 411 roxlb #1,%d1 | and move X to data byte 412 dbf %d3,ragain | do this until we've received a whole byte 413 bset #0,%a1@(0x0400) | and return RTC data line to output 414 rts | return to caller 415 416#endif /* MRG_ADB */ 417 418