xref: /netbsd/sys/arch/mac68k/mac68k/pramasm.s (revision bf9ec67e)
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