1/*
2 *  Copyright (C) 1998, 1999  Jesper Skov
3 *
4 *  Basically what is needed to replace functionality found in
5 *  arch/m68k allowing Amiga drivers to work under APUS.
6 *  Bits of code and/or ideas from arch/m68k and arch/ppc files.
7 *
8 * TODO:
9 *  This file needs a *really* good cleanup. Restructure and optimize.
10 *  Make sure it can be compiled for non-APUS configs. Begin to move
11 *  Amiga specific stuff into mach/amiga.
12 */
13
14#include <linux/kernel.h>
15#include <linux/sched.h>
16#include <linux/init.h>
17#include <linux/initrd.h>
18#include <linux/seq_file.h>
19
20/* Needs INITSERIAL call in head.S! */
21#undef APUS_DEBUG
22
23#include <asm/bootinfo.h>
24#include <asm/setup.h>
25#include <asm/amigahw.h>
26#include <asm/amigaints.h>
27#include <asm/amigappc.h>
28#include <asm/pgtable.h>
29#include <asm/dma.h>
30#include <asm/machdep.h>
31#include <asm/time.h>
32
33unsigned long m68k_machtype;
34char debug_device[6] = "";
35
36extern void amiga_init_IRQ(void);
37
38extern void apus_setup_pci_ptrs(void);
39
40void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
41/* machine dependent irq functions */
42void (*mach_init_IRQ) (void) __initdata = NULL;
43void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
44void (*mach_get_model) (char *model) = NULL;
45int (*mach_get_hardware_list) (char *buffer) = NULL;
46int (*mach_get_irq_list) (struct seq_file *, void *) = NULL;
47void (*mach_process_int) (int, struct pt_regs *) = NULL;
48/* machine dependent timer functions */
49unsigned long (*mach_gettimeoffset) (void);
50void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
51int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
52int (*mach_set_clock_mmss) (unsigned long) = NULL;
53void (*mach_reset)( void );
54long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
55#ifdef CONFIG_HEARTBEAT
56void (*mach_heartbeat) (int) = NULL;
57extern void apus_heartbeat (void);
58#endif
59
60extern unsigned long amiga_model;
61extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */
62extern unsigned count_period_num; /* 1 decrementer count equals */
63extern unsigned count_period_den; /* count_period_num / count_period_den us */
64
65int num_memory = 0;
66struct mem_info memory[NUM_MEMINFO];/* memory description */
67int m68k_realnum_memory = 0;
68struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
69
70struct mem_info ramdisk;
71
72extern void config_amiga(void);
73
74static int __60nsram = 0;
75
76/* for cpuinfo */
77static int __bus_speed = 0;
78static int __speed_test_failed = 0;
79
80/********************************************** COMPILE PROTECTION */
81/* Provide some stubs that links to Amiga specific functions.
82 * This allows CONFIG_APUS to be removed from generic PPC files while
83 * preventing link errors for other PPC targets.
84 */
85unsigned long apus_get_rtc_time(void)
86{
87#ifdef CONFIG_APUS
88	extern unsigned long m68k_get_rtc_time(void);
89
90	return m68k_get_rtc_time ();
91#else
92	return 0;
93#endif
94}
95
96int apus_set_rtc_time(unsigned long nowtime)
97{
98#ifdef CONFIG_APUS
99	extern int m68k_set_rtc_time(unsigned long nowtime);
100
101	return m68k_set_rtc_time (nowtime);
102#else
103	return 0;
104#endif
105}
106
107/*********************************************************** SETUP */
108/* From arch/m68k/kernel/setup.c. */
109void __init apus_setup_arch(void)
110{
111#ifdef CONFIG_APUS
112	extern char cmd_line[];
113	int i;
114	char *p, *q;
115
116	/* Let m68k-shared code know it should do the Amiga thing. */
117	m68k_machtype = MACH_AMIGA;
118
119	for( p = cmd_line; p && *p; ) {
120	    i = 0;
121	    if (!strncmp( p, "debug=", 6 )) {
122		    strlcpy( debug_device, p+6, sizeof(debug_device) );
123		    if ((q = strchr( debug_device, ' ' ))) *q = 0;
124		    i = 1;
125	    } else if (!strncmp( p, "60nsram", 7 )) {
126		    APUS_WRITE (APUS_REG_WAITSTATE,
127				REGWAITSTATE_SETRESET
128				|REGWAITSTATE_PPCR
129				|REGWAITSTATE_PPCW);
130		    __60nsram = 1;
131		    i = 1;
132	    }
133
134	    if (i) {
135		/* option processed, delete it */
136		if ((q = strchr( p, ' ' )))
137		    strcpy( p, q+1 );
138		else
139		    *p = 0;
140	    } else {
141		if ((p = strchr( p, ' ' ))) ++p;
142	    }
143	}
144
145	config_amiga();
146
147#endif
148}
149
150int
151apus_show_cpuinfo(struct seq_file *m)
152{
153	extern int __map_without_bats;
154	extern unsigned long powerup_PCI_present;
155
156	seq_printf(m, "machine\t\t: Amiga\n");
157	seq_printf(m, "bus speed\t: %d%s", __bus_speed,
158		   (__speed_test_failed) ? " [failed]\n" : "\n");
159	seq_printf(m, "using BATs\t: %s\n",
160		   (__map_without_bats) ? "No" : "Yes");
161	seq_printf(m, "ram speed\t: %dns\n", (__60nsram) ? 60 : 70);
162	seq_printf(m, "PCI bridge\t: %s\n",
163		   (powerup_PCI_present) ? "Yes" : "No");
164	return 0;
165}
166
167static void get_current_tb(unsigned long long *time)
168{
169	__asm __volatile ("1:mftbu 4      \n\t"
170			  "  mftb  5      \n\t"
171			  "  mftbu 6      \n\t"
172			  "  cmpw  4,6    \n\t"
173			  "  bne   1b     \n\t"
174			  "  stw   4,0(%0)\n\t"
175			  "  stw   5,4(%0)\n\t"
176			  :
177			  : "r" (time)
178			  : "r4", "r5", "r6");
179}
180
181
182void apus_calibrate_decr(void)
183{
184#ifdef CONFIG_APUS
185	unsigned long freq;
186
187	/* This algorithm for determining the bus speed was
188           contributed by Ralph Schmidt. */
189	unsigned long long start, stop;
190	int bus_speed;
191	int speed_test_failed = 0;
192
193	{
194		unsigned long loop = amiga_eclock / 10;
195
196		get_current_tb (&start);
197		while (loop--) {
198			unsigned char tmp;
199
200			tmp = ciaa.pra;
201		}
202		get_current_tb (&stop);
203	}
204
205	bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000;
206	if (AMI_1200 == amiga_model)
207		bus_speed /= 2;
208
209	if ((bus_speed >= 47) && (bus_speed < 53)) {
210		bus_speed = 50;
211		freq = 12500000;
212	} else if ((bus_speed >= 57) && (bus_speed < 63)) {
213		bus_speed = 60;
214		freq = 15000000;
215	} else if ((bus_speed >= 63) && (bus_speed < 69)) {
216		bus_speed = 67;
217		freq = 16666667;
218	} else {
219		printk ("APUS: Unable to determine bus speed (%d). "
220			"Defaulting to 50MHz", bus_speed);
221		bus_speed = 50;
222		freq = 12500000;
223		speed_test_failed = 1;
224	}
225
226	/* Ease diagnostics... */
227	{
228		extern int __map_without_bats;
229		extern unsigned long powerup_PCI_present;
230
231		printk ("APUS: BATs=%d, BUS=%dMHz",
232			(__map_without_bats) ? 0 : 1,
233			bus_speed);
234		if (speed_test_failed)
235			printk ("[FAILED - please report]");
236
237		printk (", RAM=%dns, PCI bridge=%d\n",
238			(__60nsram) ? 60 : 70,
239			(powerup_PCI_present) ? 1 : 0);
240
241		/* print a bit more if asked politely... */
242		if (!(ciaa.pra & 0x40)){
243			extern unsigned int bat_addrs[4][3];
244			int b;
245			for (b = 0; b < 4; ++b) {
246				printk ("APUS: BAT%d ", b);
247				printk ("%08x-%08x -> %08x\n",
248					bat_addrs[b][0],
249					bat_addrs[b][1],
250					bat_addrs[b][2]);
251			}
252		}
253
254	}
255
256        printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
257	       freq/1000000, freq%1000000);
258	tb_ticks_per_jiffy = freq / HZ;
259	tb_to_us = mulhwu_scale_factor(freq, 1000000);
260
261	__bus_speed = bus_speed;
262	__speed_test_failed = speed_test_failed;
263#endif
264}
265
266void arch_gettod(int *year, int *mon, int *day, int *hour,
267		 int *min, int *sec)
268{
269#ifdef CONFIG_APUS
270	if (mach_gettod)
271		mach_gettod(year, mon, day, hour, min, sec);
272	else
273		*year = *mon = *day = *hour = *min = *sec = 0;
274#endif
275}
276
277/* for "kbd-reset" cmdline param */
278__init
279void kbd_reset_setup(char *str, int *ints)
280{
281}
282
283/*********************************************************** MEMORY */
284#define KMAP_MAX 32
285unsigned long kmap_chunks[KMAP_MAX*3];
286int kmap_chunk_count = 0;
287
288/* From pgtable.h */
289static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va)
290{
291	pgd_t *dir = 0;
292	pmd_t *pmd = 0;
293	pte_t *pte = 0;
294
295	va &= PAGE_MASK;
296
297	dir = pgd_offset( mm, va );
298	if (dir)
299	{
300		pmd = pmd_offset(dir, va & PAGE_MASK);
301		if (pmd && pmd_present(*pmd))
302		{
303			pte = pte_offset(pmd, va);
304		}
305	}
306	return pte;
307}
308
309
310/* Again simulating an m68k/mm/kmap.c function. */
311void kernel_set_cachemode( unsigned long address, unsigned long size,
312			   unsigned int cmode )
313{
314	unsigned long mask, flags;
315
316	switch (cmode)
317	{
318	case IOMAP_FULL_CACHING:
319		mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
320		flags = 0;
321		break;
322	case IOMAP_NOCACHE_SER:
323		mask = ~0;
324		flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);
325		break;
326	default:
327		panic ("kernel_set_cachemode() doesn't support mode %d\n",
328		       cmode);
329		break;
330	}
331
332	size /= PAGE_SIZE;
333	address &= PAGE_MASK;
334	while (size--)
335	{
336		pte_t *pte;
337
338		pte = my_find_pte(&init_mm, address);
339		if ( !pte )
340		{
341			printk("pte NULL in kernel_set_cachemode()\n");
342			return;
343		}
344
345                pte_val (*pte) &= mask;
346                pte_val (*pte) |= flags;
347                flush_tlb_page(find_vma(&init_mm,address),address);
348
349		address += PAGE_SIZE;
350	}
351}
352
353unsigned long mm_ptov (unsigned long paddr)
354{
355	unsigned long ret;
356	if (paddr < 16*1024*1024)
357		ret = ZTWO_VADDR(paddr);
358	else {
359		int i;
360
361		for (i = 0; i < kmap_chunk_count;){
362			unsigned long phys = kmap_chunks[i++];
363			unsigned long size = kmap_chunks[i++];
364			unsigned long virt = kmap_chunks[i++];
365			if (paddr >= phys
366			    && paddr < (phys + size)){
367				ret = virt + paddr - phys;
368				goto exit;
369			}
370		}
371
372		ret = (unsigned long) __va(paddr);
373	}
374exit:
375#ifdef DEBUGPV
376	printk ("PTOV(%lx)=%lx\n", paddr, ret);
377#endif
378	return ret;
379}
380
381int mm_end_of_chunk (unsigned long addr, int len)
382{
383	if (memory[0].addr + memory[0].size == addr + len)
384		return 1;
385	return 0;
386}
387
388/*********************************************************** CACHE */
389
390#define L1_CACHE_BYTES 32
391#define MAX_CACHE_SIZE 8192
392void cache_push(__u32 addr, int length)
393{
394	addr = mm_ptov(addr);
395
396	if (MAX_CACHE_SIZE < length)
397		length = MAX_CACHE_SIZE;
398
399	while(length > 0){
400		__asm ("dcbf 0,%0\n\t"
401		       : : "r" (addr));
402		addr += L1_CACHE_BYTES;
403		length -= L1_CACHE_BYTES;
404	}
405	/* Also flush trailing block */
406	__asm ("dcbf 0,%0\n\t"
407	       "sync \n\t"
408	       : : "r" (addr));
409}
410
411void cache_clear(__u32 addr, int length)
412{
413	if (MAX_CACHE_SIZE < length)
414		length = MAX_CACHE_SIZE;
415
416	addr = mm_ptov(addr);
417
418	__asm ("dcbf 0,%0\n\t"
419	       "sync \n\t"
420	       "icbi 0,%0 \n\t"
421	       "isync \n\t"
422	       : : "r" (addr));
423
424	addr += L1_CACHE_BYTES;
425	length -= L1_CACHE_BYTES;
426
427	while(length > 0){
428		__asm ("dcbf 0,%0\n\t"
429		       "sync \n\t"
430		       "icbi 0,%0 \n\t"
431		       "isync \n\t"
432		       : : "r" (addr));
433		addr += L1_CACHE_BYTES;
434		length -= L1_CACHE_BYTES;
435	}
436
437	__asm ("dcbf 0,%0\n\t"
438	       "sync \n\t"
439	       "icbi 0,%0 \n\t"
440	       "isync \n\t"
441	       : : "r" (addr));
442}
443
444/****************************************************** from setup.c */
445void
446apus_restart(char *cmd)
447{
448	local_irq_disable();
449
450	APUS_WRITE(APUS_REG_LOCK,
451		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
452	APUS_WRITE(APUS_REG_LOCK,
453		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
454	APUS_WRITE(APUS_REG_LOCK,
455		   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
456	APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
457	APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
458	for(;;);
459}
460
461void
462apus_power_off(void)
463{
464	for (;;);
465}
466
467void
468apus_halt(void)
469{
470   apus_restart(NULL);
471}
472
473/****************************************************** IRQ stuff */
474
475static unsigned char last_ipl[8];
476
477int apus_get_irq(void)
478{
479	unsigned char ipl_emu, mask;
480	unsigned int level;
481
482	APUS_READ(APUS_IPL_EMU, ipl_emu);
483	level = (ipl_emu >> 3) & IPLEMU_IPLMASK;
484	mask = IPLEMU_SETRESET|IPLEMU_DISABLEINT|level;
485	level ^= 7;
486
487	/* Save previous IPL value */
488	if (last_ipl[level])
489		return -2;
490	last_ipl[level] = ipl_emu;
491
492	/* Set to current IPL value */
493	APUS_WRITE(APUS_IPL_EMU, mask);
494	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|level);
495
496
497#ifdef __INTERRUPT_DEBUG
498	printk("<%d:%d>", level, ~ipl_emu & IPLEMU_IPLMASK);
499#endif
500	return level + IRQ_AMIGA_AUTO;
501}
502
503void apus_end_irq(unsigned int irq)
504{
505	unsigned char ipl_emu;
506	unsigned int level = irq - IRQ_AMIGA_AUTO;
507#ifdef __INTERRUPT_DEBUG
508	printk("{%d}", ~last_ipl[level] & IPLEMU_IPLMASK);
509#endif
510	/* Restore IPL to the previous value */
511	ipl_emu = last_ipl[level] & IPLEMU_IPLMASK;
512	APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET|IPLEMU_DISABLEINT|ipl_emu);
513	last_ipl[level] = 0;
514	ipl_emu ^= 7;
515	APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT|ipl_emu);
516}
517
518/****************************************************** debugging */
519
520/* some serial hardware definitions */
521#define SDR_OVRUN   (1<<15)
522#define SDR_RBF     (1<<14)
523#define SDR_TBE     (1<<13)
524#define SDR_TSRE    (1<<12)
525
526#define AC_SETCLR   (1<<15)
527#define AC_UARTBRK  (1<<11)
528
529#define SER_DTR     (1<<7)
530#define SER_RTS     (1<<6)
531#define SER_DCD     (1<<5)
532#define SER_CTS     (1<<4)
533#define SER_DSR     (1<<3)
534
535static __inline__ void ser_RTSon(void)
536{
537    ciab.pra &= ~SER_RTS; /* active low */
538}
539
540int __debug_ser_out( unsigned char c )
541{
542	amiga_custom.serdat = c | 0x100;
543	mb();
544	while (!(amiga_custom.serdatr & 0x2000))
545		barrier();
546	return 1;
547}
548
549unsigned char __debug_ser_in( void )
550{
551	unsigned char c;
552
553	while( !(amiga_custom.intreqr & IF_RBF) )
554		barrier();
555	c = amiga_custom.serdatr;
556	/* clear the interrupt, so that another character can be read */
557	amiga_custom.intreq = IF_RBF;
558	return c;
559}
560
561int __debug_serinit( void )
562{
563	unsigned long flags;
564
565	local_irq_save(flags);
566
567	/* turn off Rx and Tx interrupts */
568	amiga_custom.intena = IF_RBF | IF_TBE;
569
570	/* clear any pending interrupt */
571	amiga_custom.intreq = IF_RBF | IF_TBE;
572
573	local_irq_restore(flags);
574
575	/*
576	 * set the appropriate directions for the modem control flags,
577	 * and clear RTS and DTR
578	 */
579	ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
580	ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
581
582#ifdef CONFIG_KGDB
583	/* turn Rx interrupts on for GDB */
584	amiga_custom.intena = IF_SETCLR | IF_RBF;
585	ser_RTSon();
586#endif
587
588	return 0;
589}
590
591void __debug_print_hex(unsigned long x)
592{
593	int i;
594	char hexchars[] = "0123456789ABCDEF";
595
596	for (i = 0; i < 8; i++) {
597		__debug_ser_out(hexchars[(x >> 28) & 15]);
598		x <<= 4;
599	}
600	__debug_ser_out('\n');
601	__debug_ser_out('\r');
602}
603
604void __debug_print_string(char* s)
605{
606	unsigned char c;
607	while((c = *s++))
608		__debug_ser_out(c);
609	__debug_ser_out('\n');
610	__debug_ser_out('\r');
611}
612
613static void apus_progress(char *s, unsigned short value)
614{
615	__debug_print_string(s);
616}
617
618/****************************************************** init */
619
620/* The number of spurious interrupts */
621volatile unsigned int num_spurious;
622
623extern struct irqaction amiga_sys_irqaction[AUTO_IRQS];
624
625
626extern void amiga_enable_irq(unsigned int irq);
627extern void amiga_disable_irq(unsigned int irq);
628
629struct hw_interrupt_type amiga_sys_irqctrl = {
630	.typename = "Amiga IPL",
631	.end = apus_end_irq,
632};
633
634struct hw_interrupt_type amiga_irqctrl = {
635	.typename = "Amiga    ",
636	.enable = amiga_enable_irq,
637	.disable = amiga_disable_irq,
638};
639
640#define HARDWARE_MAPPED_SIZE (512*1024)
641unsigned long __init apus_find_end_of_memory(void)
642{
643	int shadow = 0;
644	unsigned long total;
645
646	/* The memory size reported by ADOS excludes the 512KB
647	   reserved for PPC exception registers and possibly 512KB
648	   containing a shadow of the ADOS ROM. */
649	{
650		unsigned long size = memory[0].size;
651
652		/* If 2MB aligned, size was probably user
653                   specified. We can't tell anything about shadowing
654                   in this case so skip shadow assignment. */
655		if (0 != (size & 0x1fffff)){
656			/* Align to 512KB to ensure correct handling
657			   of both memfile and system specified
658			   sizes. */
659			size = ((size+0x0007ffff) & 0xfff80000);
660			/* If memory is 1MB aligned, assume
661                           shadowing. */
662			shadow = !(size & 0x80000);
663		}
664
665		/* Add the chunk that ADOS does not see. by aligning
666                   the size to the nearest 2MB limit upwards.  */
667		memory[0].size = ((size+0x001fffff) & 0xffe00000);
668	}
669
670	ppc_memstart = memory[0].addr;
671	ppc_memoffset = PAGE_OFFSET - PPC_MEMSTART;
672	total = memory[0].size;
673
674	/* Remove the memory chunks that are controlled by special
675           Phase5 hardware. */
676
677	if (shadow)
678		total -= HARDWARE_MAPPED_SIZE;
679
680	/* Remove the upper 512KB where the PPC exception
681	   vectors are mapped. */
682	total -= HARDWARE_MAPPED_SIZE;
683
684	/* Linux/APUS only handles one block of memory -- the one on
685	   the PowerUP board. Other system memory is horrible slow in
686	   comparison. The user can use other memory for swapping
687	   using the z2ram device. */
688	return total;
689}
690
691static void __init
692apus_map_io(void)
693{
694	/* Map PPC exception vectors. */
695	io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL);
696	/* Map chip and ZorroII memory */
697	io_block_mapping(zTwoBase,   0x00000000, 0x01000000, _PAGE_IO);
698}
699
700__init
701void apus_init_IRQ(void)
702{
703	struct irqaction *action;
704	int i;
705
706#ifdef CONFIG_PCI
707        apus_setup_pci_ptrs();
708#endif
709
710	for ( i = 0 ; i < AMI_IRQS; i++ ) {
711		irq_desc[i].status = IRQ_LEVEL;
712		if (i < IRQ_AMIGA_AUTO) {
713			irq_desc[i].chip = &amiga_irqctrl;
714		} else {
715			irq_desc[i].chip = &amiga_sys_irqctrl;
716			action = &amiga_sys_irqaction[i-IRQ_AMIGA_AUTO];
717			if (action->name)
718				setup_irq(i, action);
719		}
720	}
721
722	amiga_init_IRQ();
723
724}
725
726__init
727void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
728		   unsigned long r6, unsigned long r7)
729{
730	extern int parse_bootinfo(const struct bi_record *);
731	extern char _end[];
732
733	/* Parse bootinfo. The bootinfo is located right after
734           the kernel bss */
735	parse_bootinfo((const struct bi_record *)&_end);
736#ifdef CONFIG_BLK_DEV_INITRD
737	/* Take care of initrd if we have one. Use data from
738	   bootinfo to avoid the need to initialize PPC
739	   registers when kernel is booted via a PPC reset. */
740	if ( ramdisk.addr ) {
741		initrd_start = (unsigned long) __va(ramdisk.addr);
742		initrd_end = (unsigned long)
743			__va(ramdisk.size + ramdisk.addr);
744	}
745#endif /* CONFIG_BLK_DEV_INITRD */
746
747	ISA_DMA_THRESHOLD = 0x00ffffff;
748
749	ppc_md.setup_arch     = apus_setup_arch;
750	ppc_md.show_cpuinfo   = apus_show_cpuinfo;
751	ppc_md.init_IRQ       = apus_init_IRQ;
752	ppc_md.get_irq        = apus_get_irq;
753
754#ifdef CONFIG_HEARTBEAT
755	ppc_md.heartbeat      = apus_heartbeat;
756	ppc_md.heartbeat_count = 1;
757#endif
758#ifdef APUS_DEBUG
759	__debug_serinit();
760	ppc_md.progress       = apus_progress;
761#endif
762	ppc_md.init           = NULL;
763
764	ppc_md.restart        = apus_restart;
765	ppc_md.power_off      = apus_power_off;
766	ppc_md.halt           = apus_halt;
767
768	ppc_md.time_init      = NULL;
769	ppc_md.set_rtc_time   = apus_set_rtc_time;
770	ppc_md.get_rtc_time   = apus_get_rtc_time;
771	ppc_md.calibrate_decr = apus_calibrate_decr;
772
773	ppc_md.find_end_of_memory = apus_find_end_of_memory;
774	ppc_md.setup_io_mappings = apus_map_io;
775}
776