xref: /openbmc/linux/arch/m68k/mac/misc.c (revision b6dcefde)
1 /*
2  * Miscellaneous Mac68K-specific stuff
3  */
4 
5 #include <linux/types.h>
6 #include <linux/errno.h>
7 #include <linux/miscdevice.h>
8 #include <linux/kernel.h>
9 #include <linux/delay.h>
10 #include <linux/sched.h>
11 #include <linux/slab.h>
12 #include <linux/time.h>
13 #include <linux/rtc.h>
14 #include <linux/mm.h>
15 
16 #include <linux/adb.h>
17 #include <linux/cuda.h>
18 #include <linux/pmu.h>
19 
20 #include <asm/uaccess.h>
21 #include <asm/io.h>
22 #include <asm/rtc.h>
23 #include <asm/system.h>
24 #include <asm/segment.h>
25 #include <asm/setup.h>
26 #include <asm/macintosh.h>
27 #include <asm/mac_via.h>
28 #include <asm/mac_oss.h>
29 
30 #define BOOTINFO_COMPAT_1_0
31 #include <asm/bootinfo.h>
32 #include <asm/machdep.h>
33 
34 /* Offset between Unix time (1970-based) and Mac time (1904-based) */
35 
36 #define RTC_OFFSET 2082844800
37 
38 static void (*rom_reset)(void);
39 
40 #ifdef CONFIG_ADB_CUDA
41 static long cuda_read_time(void)
42 {
43 	struct adb_request req;
44 	long time;
45 
46 	if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
47 		return 0;
48 	while (!req.complete)
49 		cuda_poll();
50 
51 	time = (req.reply[3] << 24) | (req.reply[4] << 16)
52 		| (req.reply[5] << 8) | req.reply[6];
53 	return time - RTC_OFFSET;
54 }
55 
56 static void cuda_write_time(long data)
57 {
58 	struct adb_request req;
59 	data += RTC_OFFSET;
60 	if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
61 			(data >> 24) & 0xFF, (data >> 16) & 0xFF,
62 			(data >> 8) & 0xFF, data & 0xFF) < 0)
63 		return;
64 	while (!req.complete)
65 		cuda_poll();
66 }
67 
68 static __u8 cuda_read_pram(int offset)
69 {
70 	struct adb_request req;
71 	if (cuda_request(&req, NULL, 4, CUDA_PACKET, CUDA_GET_PRAM,
72 			(offset >> 8) & 0xFF, offset & 0xFF) < 0)
73 		return 0;
74 	while (!req.complete)
75 		cuda_poll();
76 	return req.reply[3];
77 }
78 
79 static void cuda_write_pram(int offset, __u8 data)
80 {
81 	struct adb_request req;
82 	if (cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_SET_PRAM,
83 			(offset >> 8) & 0xFF, offset & 0xFF, data) < 0)
84 		return;
85 	while (!req.complete)
86 		cuda_poll();
87 }
88 #else
89 #define cuda_read_time() 0
90 #define cuda_write_time(n)
91 #define cuda_read_pram NULL
92 #define cuda_write_pram NULL
93 #endif
94 
95 #if 0 /* def CONFIG_ADB_PMU68K */
96 static long pmu_read_time(void)
97 {
98 	struct adb_request req;
99 	long time;
100 
101 	if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
102 		return 0;
103 	while (!req.complete)
104 		pmu_poll();
105 
106 	time = (req.reply[0] << 24) | (req.reply[1] << 16)
107 		| (req.reply[2] << 8) | req.reply[3];
108 	return time - RTC_OFFSET;
109 }
110 
111 static void pmu_write_time(long data)
112 {
113 	struct adb_request req;
114 	data += RTC_OFFSET;
115 	if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
116 			(data >> 24) & 0xFF, (data >> 16) & 0xFF,
117 			(data >> 8) & 0xFF, data & 0xFF) < 0)
118 		return;
119 	while (!req.complete)
120 		pmu_poll();
121 }
122 
123 static __u8 pmu_read_pram(int offset)
124 {
125 	struct adb_request req;
126 	if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
127 			(offset >> 8) & 0xFF, offset & 0xFF) < 0)
128 		return 0;
129 	while (!req.complete)
130 		pmu_poll();
131 	return req.reply[3];
132 }
133 
134 static void pmu_write_pram(int offset, __u8 data)
135 {
136 	struct adb_request req;
137 	if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
138 			(offset >> 8) & 0xFF, offset & 0xFF, data) < 0)
139 		return;
140 	while (!req.complete)
141 		pmu_poll();
142 }
143 #else
144 #define pmu_read_time() 0
145 #define pmu_write_time(n)
146 #define pmu_read_pram NULL
147 #define pmu_write_pram NULL
148 #endif
149 
150 #if 0 /* def CONFIG_ADB_MACIISI */
151 extern int maciisi_request(struct adb_request *req,
152 			void (*done)(struct adb_request *), int nbytes, ...);
153 
154 static long maciisi_read_time(void)
155 {
156 	struct adb_request req;
157 	long time;
158 
159 	if (maciisi_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME))
160 		return 0;
161 
162 	time = (req.reply[3] << 24) | (req.reply[4] << 16)
163 		| (req.reply[5] << 8) | req.reply[6];
164 	return time - RTC_OFFSET;
165 }
166 
167 static void maciisi_write_time(long data)
168 {
169 	struct adb_request req;
170 	data += RTC_OFFSET;
171 	maciisi_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
172 			(data >> 24) & 0xFF, (data >> 16) & 0xFF,
173 			(data >> 8) & 0xFF, data & 0xFF);
174 }
175 
176 static __u8 maciisi_read_pram(int offset)
177 {
178 	struct adb_request req;
179 	if (maciisi_request(&req, NULL, 4, CUDA_PACKET, CUDA_GET_PRAM,
180 			(offset >> 8) & 0xFF, offset & 0xFF))
181 		return 0;
182 	return req.reply[3];
183 }
184 
185 static void maciisi_write_pram(int offset, __u8 data)
186 {
187 	struct adb_request req;
188 	maciisi_request(&req, NULL, 5, CUDA_PACKET, CUDA_SET_PRAM,
189 			(offset >> 8) & 0xFF, offset & 0xFF, data);
190 }
191 #else
192 #define maciisi_read_time() 0
193 #define maciisi_write_time(n)
194 #define maciisi_read_pram NULL
195 #define maciisi_write_pram NULL
196 #endif
197 
198 /*
199  * VIA PRAM/RTC access routines
200  *
201  * Must be called with interrupts disabled and
202  * the RTC should be enabled.
203  */
204 
205 static __u8 via_pram_readbyte(void)
206 {
207 	int	i,reg;
208 	__u8	data;
209 
210 	reg = via1[vBufB] & ~VIA1B_vRTCClk;
211 
212 	/* Set the RTC data line to be an input. */
213 
214 	via1[vDirB] &= ~VIA1B_vRTCData;
215 
216 	/* The bits of the byte come out in MSB order */
217 
218 	data = 0;
219 	for (i = 0 ; i < 8 ; i++) {
220 		via1[vBufB] = reg;
221 		via1[vBufB] = reg | VIA1B_vRTCClk;
222 		data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData);
223 	}
224 
225 	/* Return RTC data line to output state */
226 
227 	via1[vDirB] |= VIA1B_vRTCData;
228 
229 	return data;
230 }
231 
232 static void via_pram_writebyte(__u8 data)
233 {
234 	int	i,reg,bit;
235 
236 	reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData);
237 
238 	/* The bits of the byte go in in MSB order */
239 
240 	for (i = 0 ; i < 8 ; i++) {
241 		bit = data & 0x80? 1 : 0;
242 		data <<= 1;
243 		via1[vBufB] = reg | bit;
244 		via1[vBufB] = reg | bit | VIA1B_vRTCClk;
245 	}
246 }
247 
248 /*
249  * Execute a VIA PRAM/RTC command. For read commands
250  * data should point to a one-byte buffer for the
251  * resulting data. For write commands it should point
252  * to the data byte to for the command.
253  *
254  * This function disables all interrupts while running.
255  */
256 
257 static void via_pram_command(int command, __u8 *data)
258 {
259 	unsigned long flags;
260 	int	is_read;
261 
262 	local_irq_save(flags);
263 
264 	/* Enable the RTC and make sure the strobe line is high */
265 
266 	via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb;
267 
268 	if (command & 0xFF00) {		/* extended (two-byte) command */
269 		via_pram_writebyte((command & 0xFF00) >> 8);
270 		via_pram_writebyte(command & 0xFF);
271 		is_read = command & 0x8000;
272 	} else {			/* one-byte command */
273 		via_pram_writebyte(command);
274 		is_read = command & 0x80;
275 	}
276 	if (is_read) {
277 		*data = via_pram_readbyte();
278 	} else {
279 		via_pram_writebyte(*data);
280 	}
281 
282 	/* All done, disable the RTC */
283 
284 	via1[vBufB] |= VIA1B_vRTCEnb;
285 
286 	local_irq_restore(flags);
287 }
288 
289 static __u8 via_read_pram(int offset)
290 {
291 	return 0;
292 }
293 
294 static void via_write_pram(int offset, __u8 data)
295 {
296 }
297 
298 /*
299  * Return the current time in seconds since January 1, 1904.
300  *
301  * This only works on machines with the VIA-based PRAM/RTC, which
302  * is basically any machine with Mac II-style ADB.
303  */
304 
305 static long via_read_time(void)
306 {
307 	union {
308 		__u8  cdata[4];
309 		long  idata;
310 	} result, last_result;
311 	int	ct;
312 
313 	/*
314 	 * The NetBSD guys say to loop until you get the same reading
315 	 * twice in a row.
316 	 */
317 
318 	ct = 0;
319 	do {
320 		if (++ct > 10) {
321 			printk("via_read_time: couldn't get valid time, "
322 			       "last read = 0x%08lx and 0x%08lx\n",
323 			       last_result.idata, result.idata);
324 			break;
325 		}
326 
327 		last_result.idata = result.idata;
328 		result.idata = 0;
329 
330 		via_pram_command(0x81, &result.cdata[3]);
331 		via_pram_command(0x85, &result.cdata[2]);
332 		via_pram_command(0x89, &result.cdata[1]);
333 		via_pram_command(0x8D, &result.cdata[0]);
334 	} while (result.idata != last_result.idata);
335 
336 	return result.idata - RTC_OFFSET;
337 }
338 
339 /*
340  * Set the current time to a number of seconds since January 1, 1904.
341  *
342  * This only works on machines with the VIA-based PRAM/RTC, which
343  * is basically any machine with Mac II-style ADB.
344  */
345 
346 static void via_write_time(long time)
347 {
348 	union {
349 		__u8  cdata[4];
350 		long  idata;
351 	} data;
352 	__u8	temp;
353 
354 	/* Clear the write protect bit */
355 
356 	temp = 0x55;
357 	via_pram_command(0x35, &temp);
358 
359 	data.idata = time + RTC_OFFSET;
360 	via_pram_command(0x01, &data.cdata[3]);
361 	via_pram_command(0x05, &data.cdata[2]);
362 	via_pram_command(0x09, &data.cdata[1]);
363 	via_pram_command(0x0D, &data.cdata[0]);
364 
365 	/* Set the write protect bit */
366 
367 	temp = 0xD5;
368 	via_pram_command(0x35, &temp);
369 }
370 
371 static void via_shutdown(void)
372 {
373 	if (rbv_present) {
374 		via2[rBufB] &= ~0x04;
375 	} else {
376 		/* Direction of vDirB is output */
377 		via2[vDirB] |= 0x04;
378 		/* Send a value of 0 on that line */
379 		via2[vBufB] &= ~0x04;
380 		mdelay(1000);
381 	}
382 }
383 
384 /*
385  * FIXME: not sure how this is supposed to work exactly...
386  */
387 
388 static void oss_shutdown(void)
389 {
390 	oss->rom_ctrl = OSS_POWEROFF;
391 }
392 
393 #ifdef CONFIG_ADB_CUDA
394 
395 static void cuda_restart(void)
396 {
397 	struct adb_request req;
398 	if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM) < 0)
399 		return;
400 	while (!req.complete)
401 		cuda_poll();
402 }
403 
404 static void cuda_shutdown(void)
405 {
406 	struct adb_request req;
407 	if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN) < 0)
408 		return;
409 	while (!req.complete)
410 		cuda_poll();
411 }
412 
413 #endif /* CONFIG_ADB_CUDA */
414 
415 #ifdef CONFIG_ADB_PMU68K
416 
417 void pmu_restart(void)
418 {
419 	struct adb_request req;
420 	if (pmu_request(&req, NULL,
421 			2, PMU_SET_INTR_MASK, PMU_INT_ADB|PMU_INT_TICK) < 0)
422 		return;
423 	while (!req.complete)
424 		pmu_poll();
425 	if (pmu_request(&req, NULL, 1, PMU_RESET) < 0)
426 		return;
427 	while (!req.complete)
428 		pmu_poll();
429 }
430 
431 void pmu_shutdown(void)
432 {
433 	struct adb_request req;
434 	if (pmu_request(&req, NULL,
435 			2, PMU_SET_INTR_MASK, PMU_INT_ADB|PMU_INT_TICK) < 0)
436 		return;
437 	while (!req.complete)
438 		pmu_poll();
439 	if (pmu_request(&req, NULL, 5, PMU_SHUTDOWN, 'M', 'A', 'T', 'T') < 0)
440 		return;
441 	while (!req.complete)
442 		pmu_poll();
443 }
444 
445 #endif
446 
447 /*
448  *-------------------------------------------------------------------
449  * Below this point are the generic routines; they'll dispatch to the
450  * correct routine for the hardware on which we're running.
451  *-------------------------------------------------------------------
452  */
453 
454 void mac_pram_read(int offset, __u8 *buffer, int len)
455 {
456 	__u8 (*func)(int);
457 	int i;
458 
459 	switch(macintosh_config->adb_type) {
460 	case MAC_ADB_IISI:
461 		func = maciisi_read_pram; break;
462 	case MAC_ADB_PB1:
463 	case MAC_ADB_PB2:
464 		func = pmu_read_pram; break;
465 	case MAC_ADB_CUDA:
466 		func = cuda_read_pram; break;
467 	default:
468 		func = via_read_pram;
469 	}
470 	if (!func)
471 		return;
472 	for (i = 0 ; i < len ; i++) {
473 		buffer[i] = (*func)(offset++);
474 	}
475 }
476 
477 void mac_pram_write(int offset, __u8 *buffer, int len)
478 {
479 	void (*func)(int, __u8);
480 	int i;
481 
482 	switch(macintosh_config->adb_type) {
483 	case MAC_ADB_IISI:
484 		func = maciisi_write_pram; break;
485 	case MAC_ADB_PB1:
486 	case MAC_ADB_PB2:
487 		func = pmu_write_pram; break;
488 	case MAC_ADB_CUDA:
489 		func = cuda_write_pram; break;
490 	default:
491 		func = via_write_pram;
492 	}
493 	if (!func)
494 		return;
495 	for (i = 0 ; i < len ; i++) {
496 		(*func)(offset++, buffer[i]);
497 	}
498 }
499 
500 void mac_poweroff(void)
501 {
502 	/*
503 	 * MAC_ADB_IISI may need to be moved up here if it doesn't actually
504 	 * work using the ADB packet method.  --David Kilzer
505 	 */
506 
507 	if (oss_present) {
508 		oss_shutdown();
509 	} else if (macintosh_config->adb_type == MAC_ADB_II) {
510 		via_shutdown();
511 #ifdef CONFIG_ADB_CUDA
512 	} else if (macintosh_config->adb_type == MAC_ADB_CUDA) {
513 		cuda_shutdown();
514 #endif
515 #ifdef CONFIG_ADB_PMU68K
516 	} else if (macintosh_config->adb_type == MAC_ADB_PB1
517 		|| macintosh_config->adb_type == MAC_ADB_PB2) {
518 		pmu_shutdown();
519 #endif
520 	}
521 	local_irq_enable();
522 	printk("It is now safe to turn off your Macintosh.\n");
523 	while(1);
524 }
525 
526 void mac_reset(void)
527 {
528 	if (macintosh_config->adb_type == MAC_ADB_II) {
529 		unsigned long flags;
530 
531 		/* need ROMBASE in booter */
532 		/* indeed, plus need to MAP THE ROM !! */
533 
534 		if (mac_bi_data.rombase == 0)
535 			mac_bi_data.rombase = 0x40800000;
536 
537 		/* works on some */
538 		rom_reset = (void *) (mac_bi_data.rombase + 0xa);
539 
540 		if (macintosh_config->ident == MAC_MODEL_SE30) {
541 			/*
542 			 * MSch: Machines known to crash on ROM reset ...
543 			 */
544 		} else {
545 			local_irq_save(flags);
546 
547 			rom_reset();
548 
549 			local_irq_restore(flags);
550 		}
551 #ifdef CONFIG_ADB_CUDA
552 	} else if (macintosh_config->adb_type == MAC_ADB_CUDA) {
553 		cuda_restart();
554 #endif
555 #ifdef CONFIG_ADB_PMU68K
556 	} else if (macintosh_config->adb_type == MAC_ADB_PB1
557 		|| macintosh_config->adb_type == MAC_ADB_PB2) {
558 		pmu_restart();
559 #endif
560 	} else if (CPU_IS_030) {
561 
562 		/* 030-specific reset routine.  The idea is general, but the
563 		 * specific registers to reset are '030-specific.  Until I
564 		 * have a non-030 machine, I can't test anything else.
565 		 *  -- C. Scott Ananian <cananian@alumni.princeton.edu>
566 		 */
567 
568 		unsigned long rombase = 0x40000000;
569 
570 		/* make a 1-to-1 mapping, using the transparent tran. reg. */
571 		unsigned long virt = (unsigned long) mac_reset;
572 		unsigned long phys = virt_to_phys(mac_reset);
573 		unsigned long addr = (phys&0xFF000000)|0x8777;
574 		unsigned long offset = phys-virt;
575 		local_irq_disable(); /* lets not screw this up, ok? */
576 		__asm__ __volatile__(".chip 68030\n\t"
577 				     "pmove %0,%/tt0\n\t"
578 				     ".chip 68k"
579 				     : : "m" (addr));
580 		/* Now jump to physical address so we can disable MMU */
581 		__asm__ __volatile__(
582                     ".chip 68030\n\t"
583 		    "lea %/pc@(1f),%/a0\n\t"
584 		    "addl %0,%/a0\n\t"/* fixup target address and stack ptr */
585 		    "addl %0,%/sp\n\t"
586 		    "pflusha\n\t"
587 		    "jmp %/a0@\n\t" /* jump into physical memory */
588 		    "0:.long 0\n\t" /* a constant zero. */
589 		    /* OK.  Now reset everything and jump to reset vector. */
590 		    "1:\n\t"
591 		    "lea %/pc@(0b),%/a0\n\t"
592 		    "pmove %/a0@, %/tc\n\t" /* disable mmu */
593 		    "pmove %/a0@, %/tt0\n\t" /* disable tt0 */
594 		    "pmove %/a0@, %/tt1\n\t" /* disable tt1 */
595 		    "movel #0, %/a0\n\t"
596 		    "movec %/a0, %/vbr\n\t" /* clear vector base register */
597 		    "movec %/a0, %/cacr\n\t" /* disable caches */
598 		    "movel #0x0808,%/a0\n\t"
599 		    "movec %/a0, %/cacr\n\t" /* flush i&d caches */
600 		    "movew #0x2700,%/sr\n\t" /* set up status register */
601 		    "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */
602 		    "movec %/a0, %/isp\n\t"
603 		    "movel %1@(0x4),%/a0\n\t" /* load reset vector */
604 		    "reset\n\t" /* reset external devices */
605 		    "jmp %/a0@\n\t" /* jump to the reset vector */
606 		    ".chip 68k"
607 		    : : "r" (offset), "a" (rombase) : "a0");
608 	}
609 
610 	/* should never get here */
611 	local_irq_enable();
612 	printk ("Restart failed.  Please restart manually.\n");
613 	while(1);
614 }
615 
616 /*
617  * This function translates seconds since 1970 into a proper date.
618  *
619  * Algorithm cribbed from glibc2.1, __offtime().
620  */
621 #define SECS_PER_MINUTE (60)
622 #define SECS_PER_HOUR  (SECS_PER_MINUTE * 60)
623 #define SECS_PER_DAY   (SECS_PER_HOUR * 24)
624 
625 static void unmktime(unsigned long time, long offset,
626 		     int *yearp, int *monp, int *dayp,
627 		     int *hourp, int *minp, int *secp)
628 {
629         /* How many days come before each month (0-12).  */
630 	static const unsigned short int __mon_yday[2][13] =
631 	{
632 		/* Normal years.  */
633 		{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
634 		/* Leap years.  */
635 		{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
636 	};
637 	long int days, rem, y, wday, yday;
638 	const unsigned short int *ip;
639 
640 	days = time / SECS_PER_DAY;
641 	rem = time % SECS_PER_DAY;
642 	rem += offset;
643 	while (rem < 0) {
644 		rem += SECS_PER_DAY;
645 		--days;
646 	}
647 	while (rem >= SECS_PER_DAY) {
648 		rem -= SECS_PER_DAY;
649 		++days;
650 	}
651 	*hourp = rem / SECS_PER_HOUR;
652 	rem %= SECS_PER_HOUR;
653 	*minp = rem / SECS_PER_MINUTE;
654 	*secp = rem % SECS_PER_MINUTE;
655 	/* January 1, 1970 was a Thursday. */
656 	wday = (4 + days) % 7; /* Day in the week. Not currently used */
657 	if (wday < 0) wday += 7;
658 	y = 1970;
659 
660 #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
661 #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
662 #define __isleap(year)	\
663   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
664 
665 	while (days < 0 || days >= (__isleap (y) ? 366 : 365))
666 	{
667 		/* Guess a corrected year, assuming 365 days per year.  */
668 		long int yg = y + days / 365 - (days % 365 < 0);
669 
670 		/* Adjust DAYS and Y to match the guessed year.  */
671 		days -= ((yg - y) * 365
672 			 + LEAPS_THRU_END_OF (yg - 1)
673 			 - LEAPS_THRU_END_OF (y - 1));
674 		y = yg;
675 	}
676 	*yearp = y - 1900;
677 	yday = days; /* day in the year.  Not currently used. */
678 	ip = __mon_yday[__isleap(y)];
679 	for (y = 11; days < (long int) ip[y]; --y)
680 		continue;
681 	days -= ip[y];
682 	*monp = y;
683 	*dayp = days + 1; /* day in the month */
684 	return;
685 }
686 
687 /*
688  * Read/write the hardware clock.
689  */
690 
691 int mac_hwclk(int op, struct rtc_time *t)
692 {
693 	unsigned long now;
694 
695 	if (!op) { /* read */
696 		switch (macintosh_config->adb_type) {
697 		case MAC_ADB_II:
698 		case MAC_ADB_IOP:
699 			now = via_read_time();
700 			break;
701 		case MAC_ADB_IISI:
702 			now = maciisi_read_time();
703 			break;
704 		case MAC_ADB_PB1:
705 		case MAC_ADB_PB2:
706 			now = pmu_read_time();
707 			break;
708 		case MAC_ADB_CUDA:
709 			now = cuda_read_time();
710 			break;
711 		default:
712 			now = 0;
713 		}
714 
715 		t->tm_wday = 0;
716 		unmktime(now, 0,
717 			 &t->tm_year, &t->tm_mon, &t->tm_mday,
718 			 &t->tm_hour, &t->tm_min, &t->tm_sec);
719 #if 0
720 		printk("mac_hwclk: read %04d-%02d-%-2d %02d:%02d:%02d\n",
721 			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
722 			t->tm_hour, t->tm_min, t->tm_sec);
723 #endif
724 	} else { /* write */
725 #if 0
726 		printk("mac_hwclk: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n",
727 			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
728 			t->tm_hour, t->tm_min, t->tm_sec);
729 #endif
730 
731 		now = mktime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
732 			     t->tm_hour, t->tm_min, t->tm_sec);
733 
734 		switch (macintosh_config->adb_type) {
735 		case MAC_ADB_II:
736 		case MAC_ADB_IOP:
737 			via_write_time(now);
738 			break;
739 		case MAC_ADB_CUDA:
740 			cuda_write_time(now);
741 			break;
742 		case MAC_ADB_PB1:
743 		case MAC_ADB_PB2:
744 			pmu_write_time(now);
745 			break;
746 		case MAC_ADB_IISI:
747 			maciisi_write_time(now);
748 		}
749 	}
750 	return 0;
751 }
752 
753 /*
754  * Set minutes/seconds in the hardware clock
755  */
756 
757 int mac_set_clock_mmss (unsigned long nowtime)
758 {
759 	struct rtc_time now;
760 
761 	mac_hwclk(0, &now);
762 	now.tm_sec = nowtime % 60;
763 	now.tm_min = (nowtime / 60) % 60;
764 	mac_hwclk(1, &now);
765 
766 	return 0;
767 }
768