aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/mac
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/mac')
-rw-r--r--arch/m68k/mac/Makefile6
-rw-r--r--arch/m68k/mac/baboon.c126
-rw-r--r--arch/m68k/mac/bootparse.c122
-rw-r--r--arch/m68k/mac/config.c902
-rw-r--r--arch/m68k/mac/debug.c398
-rw-r--r--arch/m68k/mac/iop.c714
-rw-r--r--arch/m68k/mac/mac_ksyms.c8
-rw-r--r--arch/m68k/mac/mac_penguin.S75
-rw-r--r--arch/m68k/mac/macboing.c309
-rw-r--r--arch/m68k/mac/macints.c760
-rw-r--r--arch/m68k/mac/misc.c651
-rw-r--r--arch/m68k/mac/oss.c301
-rw-r--r--arch/m68k/mac/psc.c197
-rw-r--r--arch/m68k/mac/via.c619
14 files changed, 5188 insertions, 0 deletions
diff --git a/arch/m68k/mac/Makefile b/arch/m68k/mac/Makefile
new file mode 100644
index 000000000000..995a09d912f5
--- /dev/null
+++ b/arch/m68k/mac/Makefile
@@ -0,0 +1,6 @@
1#
2# Makefile for Linux arch/m68k/mac source directory
3#
4
5obj-y := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \
6 baboon.o macboing.o debug.o misc.o mac_ksyms.o
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
new file mode 100644
index 000000000000..b19b7dd9bd21
--- /dev/null
+++ b/arch/m68k/mac/baboon.c
@@ -0,0 +1,126 @@
1/*
2 * Baboon Custom IC Management
3 *
4 * The Baboon custom IC controls the IDE, PCMCIA and media bay on the
5 * PowerBook 190. It multiplexes multiple interrupt sources onto the
6 * Nubus slot $C interrupt.
7 */
8
9#include <linux/types.h>
10#include <linux/kernel.h>
11#include <linux/mm.h>
12#include <linux/delay.h>
13#include <linux/init.h>
14#include <linux/ide.h>
15
16#include <asm/traps.h>
17#include <asm/bootinfo.h>
18#include <asm/macintosh.h>
19#include <asm/macints.h>
20#include <asm/mac_baboon.h>
21
22/* #define DEBUG_BABOON */
23/* #define DEBUG_IRQS */
24
25int baboon_present,baboon_active;
26volatile struct baboon *baboon;
27
28irqreturn_t baboon_irq(int, void *, struct pt_regs *);
29
30#if 0
31extern int macide_ack_intr(struct ata_channel *);
32#endif
33
34/*
35 * Baboon initialization.
36 */
37
38void __init baboon_init(void)
39{
40 if (macintosh_config->ident != MAC_MODEL_PB190) {
41 baboon = NULL;
42 baboon_present = 0;
43 return;
44 }
45
46 baboon = (struct baboon *) BABOON_BASE;
47 baboon_present = 1;
48 baboon_active = 0;
49
50 printk("Baboon detected at %p\n", baboon);
51}
52
53/*
54 * Register the Baboon interrupt dispatcher on nubus slot $C.
55 */
56
57void __init baboon_register_interrupts(void)
58{
59 request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
60 "baboon", (void *) baboon);
61}
62
63/*
64 * Baboon interrupt handler. This works a lot like a VIA.
65 */
66
67irqreturn_t baboon_irq(int irq, void *dev_id, struct pt_regs *regs)
68{
69 int irq_bit,i;
70 unsigned char events;
71
72#ifdef DEBUG_IRQS
73 printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n",
74 (uint) baboon->mb_control, (uint) baboon->mb_ifr,
75 (uint) baboon->mb_status, baboon_active);
76#endif
77
78 if (!(events = baboon->mb_ifr & 0x07))
79 return IRQ_NONE;
80
81 for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
82 if (events & irq_bit/* & baboon_active*/) {
83 baboon_active &= ~irq_bit;
84 mac_do_irq_list(IRQ_BABOON_0 + i, regs);
85 baboon_active |= irq_bit;
86 baboon->mb_ifr &= ~irq_bit;
87 }
88 }
89#if 0
90 if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL);
91 /* for now we need to smash all interrupts */
92 baboon->mb_ifr &= ~events;
93#endif
94 return IRQ_HANDLED;
95}
96
97void baboon_irq_enable(int irq) {
98 int irq_idx = IRQ_IDX(irq);
99
100#ifdef DEBUG_IRQUSE
101 printk("baboon_irq_enable(%d)\n", irq);
102#endif
103 baboon_active |= (1 << irq_idx);
104}
105
106void baboon_irq_disable(int irq) {
107 int irq_idx = IRQ_IDX(irq);
108
109#ifdef DEBUG_IRQUSE
110 printk("baboon_irq_disable(%d)\n", irq);
111#endif
112 baboon_active &= ~(1 << irq_idx);
113}
114
115void baboon_irq_clear(int irq) {
116 int irq_idx = IRQ_IDX(irq);
117
118 baboon->mb_ifr &= ~(1 << irq_idx);
119}
120
121int baboon_irq_pending(int irq)
122{
123 int irq_idx = IRQ_IDX(irq);
124
125 return baboon->mb_ifr & (1 << irq_idx);
126}
diff --git a/arch/m68k/mac/bootparse.c b/arch/m68k/mac/bootparse.c
new file mode 100644
index 000000000000..36d223609823
--- /dev/null
+++ b/arch/m68k/mac/bootparse.c
@@ -0,0 +1,122 @@
1#include <linux/string.h>
2#include <linux/kernel.h>
3#include <linux/sched.h>
4#include <asm/irq.h>
5#include <asm/setup.h>
6#include <asm/bootinfo.h>
7#include <asm/macintosh.h>
8
9/*
10 * Booter vars
11 */
12
13int boothowto;
14int _boothowto;
15
16/*
17 * Called early to parse the environment (passed to us from the booter)
18 * into a bootinfo struct. Will die as soon as we have our own booter
19 */
20
21#define atol(x) simple_strtoul(x,NULL,0)
22
23void parse_booter(char *env)
24{
25 char *name;
26 char *value;
27#if 0
28 while(0 && *env)
29#else
30 while(*env)
31#endif
32 {
33 name=env;
34 value=name;
35 while(*value!='='&&*value)
36 value++;
37 if(*value=='=')
38 *value++=0;
39 env=value;
40 while(*env)
41 env++;
42 env++;
43#if 0
44 if(strcmp(name,"VIDEO_ADDR")==0)
45 mac_mch.videoaddr=atol(value);
46 if(strcmp(name,"ROW_BYTES")==0)
47 mac_mch.videorow=atol(value);
48 if(strcmp(name,"SCREEN_DEPTH")==0)
49 mac_mch.videodepth=atol(value);
50 if(strcmp(name,"DIMENSIONS")==0)
51 mac_mch.dimensions=atol(value);
52#endif
53 if(strcmp(name,"BOOTTIME")==0)
54 mac_bi_data.boottime=atol(value);
55 if(strcmp(name,"GMTBIAS")==0)
56 mac_bi_data.gmtbias=atol(value);
57 if(strcmp(name,"BOOTERVER")==0)
58 mac_bi_data.bootver=atol(value);
59 if(strcmp(name,"MACOS_VIDEO")==0)
60 mac_bi_data.videological=atol(value);
61 if(strcmp(name,"MACOS_SCC")==0)
62 mac_bi_data.sccbase=atol(value);
63 if(strcmp(name,"MACHINEID")==0)
64 mac_bi_data.id=atol(value);
65 if(strcmp(name,"MEMSIZE")==0)
66 mac_bi_data.memsize=atol(value);
67 if(strcmp(name,"SERIAL_MODEM_FLAGS")==0)
68 mac_bi_data.serialmf=atol(value);
69 if(strcmp(name,"SERIAL_MODEM_HSKICLK")==0)
70 mac_bi_data.serialhsk=atol(value);
71 if(strcmp(name,"SERIAL_MODEM_GPICLK")==0)
72 mac_bi_data.serialgpi=atol(value);
73 if(strcmp(name,"SERIAL_PRINT_FLAGS")==0)
74 mac_bi_data.printmf=atol(value);
75 if(strcmp(name,"SERIAL_PRINT_HSKICLK")==0)
76 mac_bi_data.printhsk=atol(value);
77 if(strcmp(name,"SERIAL_PRINT_GPICLK")==0)
78 mac_bi_data.printgpi=atol(value);
79 if(strcmp(name,"PROCESSOR")==0)
80 mac_bi_data.cpuid=atol(value);
81 if(strcmp(name,"ROMBASE")==0)
82 mac_bi_data.rombase=atol(value);
83 if(strcmp(name,"TIMEDBRA")==0)
84 mac_bi_data.timedbra=atol(value);
85 if(strcmp(name,"ADBDELAY")==0)
86 mac_bi_data.adbdelay=atol(value);
87 }
88#if 0 /* XXX: TODO with m68k_mach_* */
89 /* Fill in the base stuff */
90 boot_info.machtype=MACH_MAC;
91 /* Read this from the macinfo we got ! */
92/* boot_info.cputype=CPU_68020|FPUB_68881;*/
93/* boot_info.memory[0].addr=0;*/
94/* boot_info.memory[0].size=((mac_bi_data.id>>7)&31)<<20;*/
95 boot_info.num_memory=1; /* On a MacII */
96 boot_info.ramdisk_size=0; /* For now */
97 *boot_info.command_line=0;
98#endif
99 }
100
101
102void print_booter(char *env)
103{
104 char *name;
105 char *value;
106 while(*env)
107 {
108 name=env;
109 value=name;
110 while(*value!='='&&*value)
111 value++;
112 if(*value=='=')
113 *value++=0;
114 env=value;
115 while(*env)
116 env++;
117 env++;
118 printk("%s=%s\n", name,value);
119 }
120 }
121
122
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
new file mode 100644
index 000000000000..cd19cbb213e8
--- /dev/null
+++ b/arch/m68k/mac/config.c
@@ -0,0 +1,902 @@
1/*
2 * linux/arch/m68k/mac/config.c
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file COPYING in the main directory of this archive
6 * for more details.
7 */
8
9/*
10 * Miscellaneous linux stuff
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/types.h>
16#include <linux/mm.h>
17#include <linux/tty.h>
18#include <linux/console.h>
19#include <linux/interrupt.h>
20/* keyb */
21#include <linux/random.h>
22#include <linux/delay.h>
23/* keyb */
24#include <linux/init.h>
25#include <linux/vt_kern.h>
26
27#define BOOTINFO_COMPAT_1_0
28#include <asm/setup.h>
29#include <asm/bootinfo.h>
30
31#include <asm/system.h>
32#include <asm/io.h>
33#include <asm/irq.h>
34#include <asm/pgtable.h>
35#include <asm/rtc.h>
36#include <asm/machdep.h>
37
38#include <asm/macintosh.h>
39#include <asm/macints.h>
40#include <asm/machw.h>
41
42#include <asm/mac_iop.h>
43#include <asm/mac_via.h>
44#include <asm/mac_oss.h>
45#include <asm/mac_psc.h>
46
47/* Mac bootinfo struct */
48
49struct mac_booter_data mac_bi_data;
50int mac_bisize = sizeof mac_bi_data;
51
52struct mac_hw_present mac_hw_present;
53
54/* New m68k bootinfo stuff and videobase */
55
56extern int m68k_num_memory;
57extern struct mem_info m68k_memory[NUM_MEMINFO];
58
59extern struct mem_info m68k_ramdisk;
60
61extern char m68k_command_line[CL_SIZE];
62
63void *mac_env; /* Loaded by the boot asm */
64
65/* The phys. video addr. - might be bogus on some machines */
66unsigned long mac_orig_videoaddr;
67
68/* Mac specific timer functions */
69extern unsigned long mac_gettimeoffset (void);
70extern int mac_hwclk (int, struct rtc_time *);
71extern int mac_set_clock_mmss (unsigned long);
72extern int show_mac_interrupts(struct seq_file *, void *);
73extern void iop_preinit(void);
74extern void iop_init(void);
75extern void via_init(void);
76extern void via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *));
77extern void via_flush_cache(void);
78extern void oss_init(void);
79extern void psc_init(void);
80extern void baboon_init(void);
81
82extern void mac_mksound(unsigned int, unsigned int);
83
84extern void nubus_sweep_video(void);
85
86/* Mac specific debug functions (in debug.c) */
87extern void mac_debug_init(void);
88extern void mac_debugging_long(int, long);
89
90static void mac_get_model(char *str);
91
92void mac_bang(int irq, void *vector, struct pt_regs *p)
93{
94 printk(KERN_INFO "Resetting ...\n");
95 mac_reset();
96}
97
98static void mac_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *))
99{
100 via_init_clock(vector);
101}
102
103#if 0
104void mac_waitbut (void)
105{
106 ;
107}
108#endif
109
110extern irqreturn_t mac_default_handler(int, void *, struct pt_regs *);
111
112irqreturn_t (*mac_handlers[8])(int, void *, struct pt_regs *)=
113{
114 mac_default_handler,
115 mac_default_handler,
116 mac_default_handler,
117 mac_default_handler,
118 mac_default_handler,
119 mac_default_handler,
120 mac_default_handler,
121 mac_default_handler
122};
123
124/*
125 * Parse a Macintosh-specific record in the bootinfo
126 */
127
128int __init mac_parse_bootinfo(const struct bi_record *record)
129{
130 int unknown = 0;
131 const u_long *data = record->data;
132
133 switch (record->tag) {
134 case BI_MAC_MODEL:
135 mac_bi_data.id = *data;
136 break;
137 case BI_MAC_VADDR:
138 mac_bi_data.videoaddr = *data;
139 break;
140 case BI_MAC_VDEPTH:
141 mac_bi_data.videodepth = *data;
142 break;
143 case BI_MAC_VROW:
144 mac_bi_data.videorow = *data;
145 break;
146 case BI_MAC_VDIM:
147 mac_bi_data.dimensions = *data;
148 break;
149 case BI_MAC_VLOGICAL:
150 mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
151 mac_orig_videoaddr = *data;
152 break;
153 case BI_MAC_SCCBASE:
154 mac_bi_data.sccbase = *data;
155 break;
156 case BI_MAC_BTIME:
157 mac_bi_data.boottime = *data;
158 break;
159 case BI_MAC_GMTBIAS:
160 mac_bi_data.gmtbias = *data;
161 break;
162 case BI_MAC_MEMSIZE:
163 mac_bi_data.memsize = *data;
164 break;
165 case BI_MAC_CPUID:
166 mac_bi_data.cpuid = *data;
167 break;
168 case BI_MAC_ROMBASE:
169 mac_bi_data.rombase = *data;
170 break;
171 default:
172 unknown = 1;
173 }
174 return(unknown);
175}
176
177/*
178 * Flip into 24bit mode for an instant - flushes the L2 cache card. We
179 * have to disable interrupts for this. Our IRQ handlers will crap
180 * themselves if they take an IRQ in 24bit mode!
181 */
182
183static void mac_cache_card_flush(int writeback)
184{
185 unsigned long flags;
186 local_irq_save(flags);
187 via_flush_cache();
188 local_irq_restore(flags);
189}
190
191void __init config_mac(void)
192{
193 if (!MACH_IS_MAC) {
194 printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
195 }
196
197 mach_sched_init = mac_sched_init;
198 mach_init_IRQ = mac_init_IRQ;
199 mach_request_irq = mac_request_irq;
200 mach_free_irq = mac_free_irq;
201 enable_irq = mac_enable_irq;
202 disable_irq = mac_disable_irq;
203 mach_get_model = mac_get_model;
204 mach_default_handler = &mac_handlers;
205 mach_get_irq_list = show_mac_interrupts;
206 mach_gettimeoffset = mac_gettimeoffset;
207#warning move to adb/via init
208#if 0
209 mach_hwclk = mac_hwclk;
210#endif
211 mach_set_clock_mmss = mac_set_clock_mmss;
212 mach_reset = mac_reset;
213 mach_halt = mac_poweroff;
214 mach_power_off = mac_poweroff;
215#ifdef CONFIG_DUMMY_CONSOLE
216 conswitchp = &dummy_con;
217#endif
218 mach_max_dma_address = 0xffffffff;
219#if 0
220 mach_debug_init = mac_debug_init;
221#endif
222#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
223 mach_beep = mac_mksound;
224#endif
225#ifdef CONFIG_HEARTBEAT
226#if 0
227 mach_heartbeat = mac_heartbeat;
228 mach_heartbeat_irq = IRQ_MAC_TIMER;
229#endif
230#endif
231
232 /*
233 * Determine hardware present
234 */
235
236 mac_identify();
237 mac_report_hardware();
238
239 /* AFAIK only the IIci takes a cache card. The IIfx has onboard
240 cache ... someone needs to figure out how to tell if it's on or
241 not. */
242
243 if (macintosh_config->ident == MAC_MODEL_IICI
244 || macintosh_config->ident == MAC_MODEL_IIFX) {
245 mach_l2_flush = mac_cache_card_flush;
246 }
247
248 /*
249 * Check for machine specific fixups.
250 */
251
252#ifdef OLD_NUBUS_CODE
253 nubus_sweep_video();
254#endif
255}
256
257
258/*
259 * Macintosh Table: hardcoded model configuration data.
260 *
261 * Much of this was defined by Alan, based on who knows what docs.
262 * I've added a lot more, and some of that was pure guesswork based
263 * on hardware pages present on the Mac web site. Possibly wildly
264 * inaccurate, so look here if a new Mac model won't run. Example: if
265 * a Mac crashes immediately after the VIA1 registers have been dumped
266 * to the screen, it probably died attempting to read DirB on a RBV.
267 * Meaning it should have MAC_VIA_IIci here :-)
268 */
269
270struct mac_model *macintosh_config;
271EXPORT_SYMBOL(macintosh_config);
272
273static struct mac_model mac_data_table[]=
274{
275 /*
276 * We'll pretend to be a Macintosh II, that's pretty safe.
277 */
278
279 {
280 .ident = MAC_MODEL_II,
281 .name = "Unknown",
282 .adb_type = MAC_ADB_II,
283 .via_type = MAC_VIA_II,
284 .scsi_type = MAC_SCSI_OLD,
285 .scc_type = MAC_SCC_II,
286 .nubus_type = MAC_NUBUS
287 },
288
289 /*
290 * Original MacII hardware
291 *
292 */
293
294 {
295 .ident = MAC_MODEL_II,
296 .name = "II",
297 .adb_type = MAC_ADB_II,
298 .via_type = MAC_VIA_II,
299 .scsi_type = MAC_SCSI_OLD,
300 .scc_type = MAC_SCC_II,
301 .nubus_type = MAC_NUBUS
302 }, {
303 .ident = MAC_MODEL_IIX,
304 .name = "IIx",
305 .adb_type = MAC_ADB_II,
306 .via_type = MAC_VIA_II,
307 .scsi_type = MAC_SCSI_OLD,
308 .scc_type = MAC_SCC_II,
309 .nubus_type = MAC_NUBUS
310 }, {
311 .ident = MAC_MODEL_IICX,
312 .name = "IIcx",
313 .adb_type = MAC_ADB_II,
314 .via_type = MAC_VIA_II,
315 .scsi_type = MAC_SCSI_OLD,
316 .scc_type = MAC_SCC_II,
317 .nubus_type = MAC_NUBUS
318 }, {
319 .ident = MAC_MODEL_SE30,
320 .name = "SE/30",
321 .adb_type = MAC_ADB_II,
322 .via_type = MAC_VIA_II,
323 .scsi_type = MAC_SCSI_OLD,
324 .scc_type = MAC_SCC_II,
325 .nubus_type = MAC_NUBUS
326 },
327
328 /*
329 * Weirdified MacII hardware - all subtley different. Gee thanks
330 * Apple. All these boxes seem to have VIA2 in a different place to
331 * the MacII (+1A000 rather than +4000)
332 * CSA: see http://developer.apple.com/technotes/hw/hw_09.html
333 */
334
335 {
336 .ident = MAC_MODEL_IICI,
337 .name = "IIci",
338 .adb_type = MAC_ADB_II,
339 .via_type = MAC_VIA_IIci,
340 .scsi_type = MAC_SCSI_OLD,
341 .scc_type = MAC_SCC_II,
342 .nubus_type = MAC_NUBUS
343 }, {
344 .ident = MAC_MODEL_IIFX,
345 .name = "IIfx",
346 .adb_type = MAC_ADB_IOP,
347 .via_type = MAC_VIA_IIci,
348 .scsi_type = MAC_SCSI_OLD,
349 .scc_type = MAC_SCC_IOP,
350 .nubus_type = MAC_NUBUS
351 }, {
352 .ident = MAC_MODEL_IISI,
353 .name = "IIsi",
354 .adb_type = MAC_ADB_IISI,
355 .via_type = MAC_VIA_IIci,
356 .scsi_type = MAC_SCSI_OLD,
357 .scc_type = MAC_SCC_II,
358 .nubus_type = MAC_NUBUS
359 }, {
360 .ident = MAC_MODEL_IIVI,
361 .name = "IIvi",
362 .adb_type = MAC_ADB_IISI,
363 .via_type = MAC_VIA_IIci,
364 .scsi_type = MAC_SCSI_OLD,
365 .scc_type = MAC_SCC_II,
366 .nubus_type = MAC_NUBUS
367 }, {
368 .ident = MAC_MODEL_IIVX,
369 .name = "IIvx",
370 .adb_type = MAC_ADB_IISI,
371 .via_type = MAC_VIA_IIci,
372 .scsi_type = MAC_SCSI_OLD,
373 .scc_type = MAC_SCC_II,
374 .nubus_type = MAC_NUBUS
375 },
376
377 /*
378 * Classic models (guessing: similar to SE/30 ?? Nope, similar to LC ...)
379 */
380
381 {
382 .ident = MAC_MODEL_CLII,
383 .name = "Classic II",
384 .adb_type = MAC_ADB_IISI,
385 .via_type = MAC_VIA_IIci,
386 .scsi_type = MAC_SCSI_OLD,
387 .scc_type = MAC_SCC_II,
388 .nubus_type = MAC_NUBUS
389 }, {
390 .ident = MAC_MODEL_CCL,
391 .name = "Color Classic",
392 .adb_type = MAC_ADB_CUDA,
393 .via_type = MAC_VIA_IIci,
394 .scsi_type = MAC_SCSI_OLD,
395 .scc_type = MAC_SCC_II,
396 .nubus_type = MAC_NUBUS},
397
398 /*
399 * Some Mac LC machines. Basically the same as the IIci, ADB like IIsi
400 */
401
402 {
403 .ident = MAC_MODEL_LC,
404 .name = "LC",
405 .adb_type = MAC_ADB_IISI,
406 .via_type = MAC_VIA_IIci,
407 .scsi_type = MAC_SCSI_OLD,
408 .scc_type = MAC_SCC_II,
409 .nubus_type = MAC_NUBUS
410 }, {
411 .ident = MAC_MODEL_LCII,
412 .name = "LC II",
413 .adb_type = MAC_ADB_IISI,
414 .via_type = MAC_VIA_IIci,
415 .scsi_type = MAC_SCSI_OLD,
416 .scc_type = MAC_SCC_II,
417 .nubus_type = MAC_NUBUS
418 }, {
419 .ident = MAC_MODEL_LCIII,
420 .name = "LC III",
421 .adb_type = MAC_ADB_IISI,
422 .via_type = MAC_VIA_IIci,
423 .scsi_type = MAC_SCSI_OLD,
424 .scc_type = MAC_SCC_II,
425 .nubus_type = MAC_NUBUS
426 },
427
428 /*
429 * Quadra. Video is at 0xF9000000, via is like a MacII. We label it differently
430 * as some of the stuff connected to VIA2 seems different. Better SCSI chip and
431 * onboard ethernet using a NatSemi SONIC except the 660AV and 840AV which use an
432 * AMD 79C940 (MACE).
433 * The 700, 900 and 950 have some I/O chips in the wrong place to
434 * confuse us. The 840AV has a SCSI location of its own (same as
435 * the 660AV).
436 */
437
438 {
439 .ident = MAC_MODEL_Q605,
440 .name = "Quadra 605",
441 .adb_type = MAC_ADB_CUDA,
442 .via_type = MAC_VIA_QUADRA,
443 .scsi_type = MAC_SCSI_QUADRA,
444 .scc_type = MAC_SCC_QUADRA,
445 .nubus_type = MAC_NUBUS
446 }, {
447 .ident = MAC_MODEL_Q605_ACC,
448 .name = "Quadra 605",
449 .adb_type = MAC_ADB_CUDA,
450 .via_type = MAC_VIA_QUADRA,
451 .scsi_type = MAC_SCSI_QUADRA,
452 .scc_type = MAC_SCC_QUADRA,
453 .nubus_type = MAC_NUBUS
454 }, {
455 .ident = MAC_MODEL_Q610,
456 .name = "Quadra 610",
457 .adb_type = MAC_ADB_II,
458 .via_type = MAC_VIA_QUADRA,
459 .scsi_type = MAC_SCSI_QUADRA,
460 .scc_type = MAC_SCC_QUADRA,
461 .ether_type = MAC_ETHER_SONIC,
462 .nubus_type = MAC_NUBUS
463 }, {
464 .ident = MAC_MODEL_Q630,
465 .name = "Quadra 630",
466 .adb_type = MAC_ADB_CUDA,
467 .via_type = MAC_VIA_QUADRA,
468 .scsi_type = MAC_SCSI_QUADRA,
469 .ide_type = MAC_IDE_QUADRA,
470 .scc_type = MAC_SCC_QUADRA,
471 .ether_type = MAC_ETHER_SONIC,
472 .nubus_type = MAC_NUBUS
473 }, {
474 .ident = MAC_MODEL_Q650,
475 .name = "Quadra 650",
476 .adb_type = MAC_ADB_II,
477 .via_type = MAC_VIA_QUADRA,
478 .scsi_type = MAC_SCSI_QUADRA,
479 .scc_type = MAC_SCC_QUADRA,
480 .ether_type = MAC_ETHER_SONIC,
481 .nubus_type = MAC_NUBUS
482 },
483 /* The Q700 does have a NS Sonic */
484 {
485 .ident = MAC_MODEL_Q700,
486 .name = "Quadra 700",
487 .adb_type = MAC_ADB_II,
488 .via_type = MAC_VIA_QUADRA,
489 .scsi_type = MAC_SCSI_QUADRA2,
490 .scc_type = MAC_SCC_QUADRA,
491 .ether_type = MAC_ETHER_SONIC,
492 .nubus_type = MAC_NUBUS
493 }, {
494 .ident = MAC_MODEL_Q800,
495 .name = "Quadra 800",
496 .adb_type = MAC_ADB_II,
497 .via_type = MAC_VIA_QUADRA,
498 .scsi_type = MAC_SCSI_QUADRA,
499 .scc_type = MAC_SCC_QUADRA,
500 .ether_type = MAC_ETHER_SONIC,
501 .nubus_type = MAC_NUBUS
502 }, {
503 .ident = MAC_MODEL_Q840,
504 .name = "Quadra 840AV",
505 .adb_type = MAC_ADB_CUDA,
506 .via_type = MAC_VIA_QUADRA,
507 .scsi_type = MAC_SCSI_QUADRA3,
508 .scc_type = MAC_SCC_PSC,
509 .ether_type = MAC_ETHER_MACE,
510 .nubus_type = MAC_NUBUS
511 }, {
512 .ident = MAC_MODEL_Q900,
513 .name = "Quadra 900",
514 .adb_type = MAC_ADB_IOP,
515 .via_type = MAC_VIA_QUADRA,
516 .scsi_type = MAC_SCSI_QUADRA2,
517 .scc_type = MAC_SCC_IOP,
518 .ether_type = MAC_ETHER_SONIC,
519 .nubus_type = MAC_NUBUS
520 }, {
521 .ident = MAC_MODEL_Q950,
522 .name = "Quadra 950",
523 .adb_type = MAC_ADB_IOP,
524 .via_type = MAC_VIA_QUADRA,
525 .scsi_type = MAC_SCSI_QUADRA2,
526 .scc_type = MAC_SCC_IOP,
527 .ether_type = MAC_ETHER_SONIC,
528 .nubus_type = MAC_NUBUS
529 },
530
531 /*
532 * Performa - more LC type machines
533 */
534
535 {
536 .ident = MAC_MODEL_P460,
537 .name = "Performa 460",
538 .adb_type = MAC_ADB_IISI,
539 .via_type = MAC_VIA_IIci,
540 .scsi_type = MAC_SCSI_OLD,
541 .scc_type = MAC_SCC_II,
542 .nubus_type = MAC_NUBUS
543 }, {
544 .ident = MAC_MODEL_P475,
545 .name = "Performa 475",
546 .adb_type = MAC_ADB_CUDA,
547 .via_type = MAC_VIA_QUADRA,
548 .scsi_type = MAC_SCSI_QUADRA,
549 .scc_type = MAC_SCC_II,
550 .nubus_type = MAC_NUBUS
551 }, {
552 .ident = MAC_MODEL_P475F,
553 .name = "Performa 475",
554 .adb_type = MAC_ADB_CUDA,
555 .via_type = MAC_VIA_QUADRA,
556 .scsi_type = MAC_SCSI_QUADRA,
557 .scc_type = MAC_SCC_II,
558 .nubus_type = MAC_NUBUS
559 }, {
560 .ident = MAC_MODEL_P520,
561 .name = "Performa 520",
562 .adb_type = MAC_ADB_CUDA,
563 .via_type = MAC_VIA_IIci,
564 .scsi_type = MAC_SCSI_OLD,
565 .scc_type = MAC_SCC_II,
566 .nubus_type = MAC_NUBUS
567 }, {
568 .ident = MAC_MODEL_P550,
569 .name = "Performa 550",
570 .adb_type = MAC_ADB_CUDA,
571 .via_type = MAC_VIA_IIci,
572 .scsi_type = MAC_SCSI_OLD,
573 .scc_type = MAC_SCC_II,
574 .nubus_type = MAC_NUBUS
575 },
576 /* These have the comm slot, and therefore the possibility of SONIC ethernet */
577 {
578 .ident = MAC_MODEL_P575,
579 .name = "Performa 575",
580 .adb_type = MAC_ADB_CUDA,
581 .via_type = MAC_VIA_QUADRA,
582 .scsi_type = MAC_SCSI_QUADRA,
583 .scc_type = MAC_SCC_II,
584 .ether_type = MAC_ETHER_SONIC,
585 .nubus_type = MAC_NUBUS
586 }, {
587 .ident = MAC_MODEL_P588,
588 .name = "Performa 588",
589 .adb_type = MAC_ADB_CUDA,
590 .via_type = MAC_VIA_QUADRA,
591 .scsi_type = MAC_SCSI_QUADRA,
592 .ide_type = MAC_IDE_QUADRA,
593 .scc_type = MAC_SCC_II,
594 .ether_type = MAC_ETHER_SONIC,
595 .nubus_type = MAC_NUBUS
596 }, {
597 .ident = MAC_MODEL_TV,
598 .name = "TV",
599 .adb_type = MAC_ADB_CUDA,
600 .via_type = MAC_VIA_QUADRA,
601 .scsi_type = MAC_SCSI_OLD,
602 .scc_type = MAC_SCC_II,
603 .nubus_type = MAC_NUBUS
604 }, {
605 .ident = MAC_MODEL_P600,
606 .name = "Performa 600",
607 .adb_type = MAC_ADB_IISI,
608 .via_type = MAC_VIA_IIci,
609 .scsi_type = MAC_SCSI_OLD,
610 .scc_type = MAC_SCC_II,
611 .nubus_type = MAC_NUBUS
612 },
613
614 /*
615 * Centris - just guessing again; maybe like Quadra
616 */
617
618 /* The C610 may or may not have SONIC. We probe to make sure */
619 {
620 .ident = MAC_MODEL_C610,
621 .name = "Centris 610",
622 .adb_type = MAC_ADB_II,
623 .via_type = MAC_VIA_QUADRA,
624 .scsi_type = MAC_SCSI_QUADRA,
625 .scc_type = MAC_SCC_QUADRA,
626 .ether_type = MAC_ETHER_SONIC,
627 .nubus_type = MAC_NUBUS
628 }, {
629 .ident = MAC_MODEL_C650,
630 .name = "Centris 650",
631 .adb_type = MAC_ADB_II,
632 .via_type = MAC_VIA_QUADRA,
633 .scsi_type = MAC_SCSI_QUADRA,
634 .scc_type = MAC_SCC_QUADRA,
635 .ether_type = MAC_ETHER_SONIC,
636 .nubus_type = MAC_NUBUS
637 }, {
638 .ident = MAC_MODEL_C660,
639 .name = "Centris 660AV",
640 .adb_type = MAC_ADB_CUDA,
641 .via_type = MAC_VIA_QUADRA,
642 .scsi_type = MAC_SCSI_QUADRA3,
643 .scc_type = MAC_SCC_PSC,
644 .ether_type = MAC_ETHER_MACE,
645 .nubus_type = MAC_NUBUS
646 },
647
648 /*
649 * The PowerBooks all the same "Combo" custom IC for SCSI and SCC
650 * and a PMU (in two variations?) for ADB. Most of them use the
651 * Quadra-style VIAs. A few models also have IDE from hell.
652 */
653
654 {
655 .ident = MAC_MODEL_PB140,
656 .name = "PowerBook 140",
657 .adb_type = MAC_ADB_PB1,
658 .via_type = MAC_VIA_QUADRA,
659 .scsi_type = MAC_SCSI_OLD,
660 .scc_type = MAC_SCC_QUADRA,
661 .nubus_type = MAC_NUBUS
662 }, {
663 .ident = MAC_MODEL_PB145,
664 .name = "PowerBook 145",
665 .adb_type = MAC_ADB_PB1,
666 .via_type = MAC_VIA_QUADRA,
667 .scsi_type = MAC_SCSI_OLD,
668 .scc_type = MAC_SCC_QUADRA,
669 .nubus_type = MAC_NUBUS
670 }, {
671 .ident = MAC_MODEL_PB150,
672 .name = "PowerBook 150",
673 .adb_type = MAC_ADB_PB1,
674 .via_type = MAC_VIA_IIci,
675 .scsi_type = MAC_SCSI_OLD,
676 .ide_type = MAC_IDE_PB,
677 .scc_type = MAC_SCC_QUADRA,
678 .nubus_type = MAC_NUBUS
679 }, {
680 .ident = MAC_MODEL_PB160,
681 .name = "PowerBook 160",
682 .adb_type = MAC_ADB_PB1,
683 .via_type = MAC_VIA_QUADRA,
684 .scsi_type = MAC_SCSI_OLD,
685 .scc_type = MAC_SCC_QUADRA,
686 .nubus_type = MAC_NUBUS
687 }, {
688 .ident = MAC_MODEL_PB165,
689 .name = "PowerBook 165",
690 .adb_type = MAC_ADB_PB1,
691 .via_type = MAC_VIA_QUADRA,
692 .scsi_type = MAC_SCSI_OLD,
693 .scc_type = MAC_SCC_QUADRA,
694 .nubus_type = MAC_NUBUS
695 }, {
696 .ident = MAC_MODEL_PB165C,
697 .name = "PowerBook 165c",
698 .adb_type = MAC_ADB_PB1,
699 .via_type = MAC_VIA_QUADRA,
700 .scsi_type = MAC_SCSI_OLD,
701 .scc_type = MAC_SCC_QUADRA,
702 .nubus_type = MAC_NUBUS
703 }, {
704 .ident = MAC_MODEL_PB170,
705 .name = "PowerBook 170",
706 .adb_type = MAC_ADB_PB1,
707 .via_type = MAC_VIA_QUADRA,
708 .scsi_type = MAC_SCSI_OLD,
709 .scc_type = MAC_SCC_QUADRA,
710 .nubus_type = MAC_NUBUS
711 }, {
712 .ident = MAC_MODEL_PB180,
713 .name = "PowerBook 180",
714 .adb_type = MAC_ADB_PB1,
715 .via_type = MAC_VIA_QUADRA,
716 .scsi_type = MAC_SCSI_OLD,
717 .scc_type = MAC_SCC_QUADRA,
718 .nubus_type = MAC_NUBUS
719 }, {
720 .ident = MAC_MODEL_PB180C,
721 .name = "PowerBook 180c",
722 .adb_type = MAC_ADB_PB1,
723 .via_type = MAC_VIA_QUADRA,
724 .scsi_type = MAC_SCSI_OLD,
725 .scc_type = MAC_SCC_QUADRA,
726 .nubus_type = MAC_NUBUS
727 }, {
728 .ident = MAC_MODEL_PB190,
729 .name = "PowerBook 190",
730 .adb_type = MAC_ADB_PB2,
731 .via_type = MAC_VIA_QUADRA,
732 .scsi_type = MAC_SCSI_OLD,
733 .ide_type = MAC_IDE_BABOON,
734 .scc_type = MAC_SCC_QUADRA,
735 .nubus_type = MAC_NUBUS
736 }, {
737 .ident = MAC_MODEL_PB520,
738 .name = "PowerBook 520",
739 .adb_type = MAC_ADB_PB2,
740 .via_type = MAC_VIA_QUADRA,
741 .scsi_type = MAC_SCSI_OLD,
742 .scc_type = MAC_SCC_QUADRA,
743 .ether_type = MAC_ETHER_SONIC,
744 .nubus_type = MAC_NUBUS
745 },
746
747 /*
748 * PowerBook Duos are pretty much like normal PowerBooks
749 * All of these probably have onboard SONIC in the Dock which
750 * means we'll have to probe for it eventually.
751 *
752 * Are these reallly MAC_VIA_IIci? The developer notes for the
753 * Duos show pretty much the same custom parts as in most of
754 * the other PowerBooks which would imply MAC_VIA_QUADRA.
755 */
756
757 {
758 .ident = MAC_MODEL_PB210,
759 .name = "PowerBook Duo 210",
760 .adb_type = MAC_ADB_PB2,
761 .via_type = MAC_VIA_IIci,
762 .scsi_type = MAC_SCSI_OLD,
763 .scc_type = MAC_SCC_QUADRA,
764 .nubus_type = MAC_NUBUS
765 }, {
766 .ident = MAC_MODEL_PB230,
767 .name = "PowerBook Duo 230",
768 .adb_type = MAC_ADB_PB2,
769 .via_type = MAC_VIA_IIci,
770 .scsi_type = MAC_SCSI_OLD,
771 .scc_type = MAC_SCC_QUADRA,
772 .nubus_type = MAC_NUBUS
773 }, {
774 .ident = MAC_MODEL_PB250,
775 .name = "PowerBook Duo 250",
776 .adb_type = MAC_ADB_PB2,
777 .via_type = MAC_VIA_IIci,
778 .scsi_type = MAC_SCSI_OLD,
779 .scc_type = MAC_SCC_QUADRA,
780 .nubus_type = MAC_NUBUS
781 }, {
782 .ident = MAC_MODEL_PB270C,
783 .name = "PowerBook Duo 270c",
784 .adb_type = MAC_ADB_PB2,
785 .via_type = MAC_VIA_IIci,
786 .scsi_type = MAC_SCSI_OLD,
787 .scc_type = MAC_SCC_QUADRA,
788 .nubus_type = MAC_NUBUS
789 }, {
790 .ident = MAC_MODEL_PB280,
791 .name = "PowerBook Duo 280",
792 .adb_type = MAC_ADB_PB2,
793 .via_type = MAC_VIA_IIci,
794 .scsi_type = MAC_SCSI_OLD,
795 .scc_type = MAC_SCC_QUADRA,
796 .nubus_type = MAC_NUBUS
797 }, {
798 .ident = MAC_MODEL_PB280C,
799 .name = "PowerBook Duo 280c",
800 .adb_type = MAC_ADB_PB2,
801 .via_type = MAC_VIA_IIci,
802 .scsi_type = MAC_SCSI_OLD,
803 .scc_type = MAC_SCC_QUADRA,
804 .nubus_type = MAC_NUBUS
805 },
806
807 /*
808 * Other stuff ??
809 */
810 {
811 .ident = -1
812 }
813};
814
815void mac_identify(void)
816{
817 struct mac_model *m;
818
819 /* Penguin data useful? */
820 int model = mac_bi_data.id;
821 if (!model) {
822 /* no bootinfo model id -> NetBSD booter was used! */
823 /* XXX FIXME: breaks for model > 31 */
824 model=(mac_bi_data.cpuid>>2)&63;
825 printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
826 }
827
828 macintosh_config = mac_data_table;
829 for (m = macintosh_config ; m->ident != -1 ; m++) {
830 if (m->ident == model) {
831 macintosh_config = m;
832 break;
833 }
834 }
835
836 /* We need to pre-init the IOPs, if any. Otherwise */
837 /* the serial console won't work if the user had */
838 /* the serial ports set to "Faster" mode in MacOS. */
839
840 iop_preinit();
841 mac_debug_init();
842
843 printk (KERN_INFO "Detected Macintosh model: %d \n", model);
844
845 /*
846 * Report booter data:
847 */
848 printk (KERN_DEBUG " Penguin bootinfo data:\n");
849 printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n",
850 mac_bi_data.videoaddr, mac_bi_data.videorow,
851 mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF,
852 mac_bi_data.dimensions >> 16);
853 printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
854 mac_bi_data.videological, mac_orig_videoaddr,
855 mac_bi_data.sccbase);
856 printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
857 mac_bi_data.boottime, mac_bi_data.gmtbias);
858 printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
859 mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize);
860#if 0
861 printk ("Ramdisk: addr 0x%lx size 0x%lx\n",
862 m68k_ramdisk.addr, m68k_ramdisk.size);
863#endif
864
865 /*
866 * TODO: set the various fields in macintosh_config->hw_present here!
867 */
868 switch (macintosh_config->scsi_type) {
869 case MAC_SCSI_OLD:
870 MACHW_SET(MAC_SCSI_80);
871 break;
872 case MAC_SCSI_QUADRA:
873 case MAC_SCSI_QUADRA2:
874 case MAC_SCSI_QUADRA3:
875 MACHW_SET(MAC_SCSI_96);
876 if ((macintosh_config->ident == MAC_MODEL_Q900) ||
877 (macintosh_config->ident == MAC_MODEL_Q950))
878 MACHW_SET(MAC_SCSI_96_2);
879 break;
880 default:
881 printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
882 MACHW_SET(MAC_SCSI_80);
883 break;
884
885 }
886 iop_init();
887 via_init();
888 oss_init();
889 psc_init();
890 baboon_init();
891}
892
893void mac_report_hardware(void)
894{
895 printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
896}
897
898static void mac_get_model(char *str)
899{
900 strcpy(str,"Macintosh ");
901 strcat(str, macintosh_config->name);
902}
diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c
new file mode 100644
index 000000000000..cc62ed61cda2
--- /dev/null
+++ b/arch/m68k/mac/debug.c
@@ -0,0 +1,398 @@
1/*
2 * linux/arch/m68k/mac/debug.c
3 *
4 * Shamelessly stolen (SCC code and general framework) from:
5 *
6 * linux/arch/m68k/atari/debug.c
7 *
8 * Atari debugging and serial console stuff
9 *
10 * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
11 *
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file COPYING in the main directory of this archive
14 * for more details.
15 */
16
17#include <linux/config.h>
18#include <linux/types.h>
19#include <linux/sched.h>
20#include <linux/tty.h>
21#include <linux/console.h>
22#include <linux/init.h>
23#include <linux/delay.h>
24
25#define BOOTINFO_COMPAT_1_0
26#include <asm/setup.h>
27#include <asm/bootinfo.h>
28#include <asm/machw.h>
29#include <asm/macints.h>
30
31extern char m68k_debug_device[];
32
33extern struct compat_bootinfo compat_boot_info;
34
35extern unsigned long mac_videobase;
36extern unsigned long mac_videodepth;
37extern unsigned long mac_rowbytes;
38
39extern void mac_serial_print(const char *);
40
41#define DEBUG_HEADS
42#undef DEBUG_SCREEN
43#define DEBUG_SERIAL
44
45/*
46 * These two auxiliary debug functions should go away ASAP. Only usage:
47 * before the console output is up (after head.S come some other crucial
48 * setup routines :-) it permits writing 'data' to the screen as bit patterns
49 * (good luck reading those). Helped to figure that the bootinfo contained
50 * garbage data on the amount and size of memory chunks ...
51 *
52 * The 'pos' argument now simply means 'linefeed after print' ...
53 */
54
55#ifdef DEBUG_SCREEN
56static int peng=0, line=0;
57#endif
58
59void mac_debugging_short(int pos, short num)
60{
61#ifdef DEBUG_SCREEN
62 unsigned char *pengoffset;
63 unsigned char *pptr;
64 int i;
65#endif
66
67#ifdef DEBUG_SERIAL
68 printk("debug: %d !\n", num);
69#endif
70
71#ifdef DEBUG_SCREEN
72 if (!MACH_IS_MAC) {
73 /* printk("debug: %d !\n", num); */
74 return;
75 }
76
77 /* calculate current offset */
78 pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
79 +80*peng;
80
81 pptr=pengoffset;
82
83 for(i=0;i<8*sizeof(short);i++) /* # of bits */
84 {
85 /* value mask for bit i, reverse order */
86 *pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00);
87 }
88
89 peng++;
90
91 if (pos) {
92 line++;
93 peng = 0;
94 }
95#endif
96}
97
98void mac_debugging_long(int pos, long addr)
99{
100#ifdef DEBUG_SCREEN
101 unsigned char *pengoffset;
102 unsigned char *pptr;
103 int i;
104#endif
105
106#ifdef DEBUG_SERIAL
107 printk("debug: #%ld !\n", addr);
108#endif
109
110#ifdef DEBUG_SCREEN
111 if (!MACH_IS_MAC) {
112 /* printk("debug: #%ld !\n", addr); */
113 return;
114 }
115
116 pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
117 +80*peng;
118
119 pptr=pengoffset;
120
121 for(i=0;i<8*sizeof(long);i++) /* # of bits */
122 {
123 *pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00);
124 }
125
126 peng++;
127
128 if (pos) {
129 line++;
130 peng = 0;
131 }
132#endif
133}
134
135#ifdef DEBUG_SERIAL
136/*
137 * TODO: serial debug code
138 */
139
140struct mac_SCC
141 {
142 u_char cha_b_ctrl;
143 u_char char_dummy1;
144 u_char cha_a_ctrl;
145 u_char char_dummy2;
146 u_char cha_b_data;
147 u_char char_dummy3;
148 u_char cha_a_data;
149 };
150
151# define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase))
152
153/* Flag that serial port is already initialized and used */
154int mac_SCC_init_done;
155/* Can be set somewhere, if a SCC master reset has already be done and should
156 * not be repeated; used by kgdb */
157int mac_SCC_reset_done;
158
159static int scc_port = -1;
160
161static struct console mac_console_driver = {
162 .name = "debug",
163 .flags = CON_PRINTBUFFER,
164 .index = -1,
165};
166
167/*
168 * Crude hack to get console output to the screen before the framebuffer
169 * is initialized (happens a lot later in 2.1!).
170 * We just use the console routines declared in head.S, this will interfere
171 * with regular framebuffer console output and should be used exclusively
172 * to debug kernel problems manifesting before framebuffer init (aka WSOD)
173 *
174 * To keep this hack from interfering with the regular console driver, either
175 * deregister this driver before/on framebuffer console init, or silence this
176 * function after the fbcon driver is running (will lose console messages!?).
177 * To debug real early bugs, need to write a 'mac_register_console_hack()'
178 * that is called from start_kernel() before setup_arch() and just registers
179 * this driver if Mac.
180 */
181
182void mac_debug_console_write (struct console *co, const char *str,
183 unsigned int count)
184{
185 mac_serial_print(str);
186}
187
188
189
190/* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/
191
192#define uSEC 1
193
194static inline void mac_sccb_out (char c)
195{
196 int i;
197 do {
198 for( i = uSEC; i > 0; --i )
199 barrier();
200 } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
201 for( i = uSEC; i > 0; --i )
202 barrier();
203 scc.cha_b_data = c;
204}
205
206static inline void mac_scca_out (char c)
207{
208 int i;
209 do {
210 for( i = uSEC; i > 0; --i )
211 barrier();
212 } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
213 for( i = uSEC; i > 0; --i )
214 barrier();
215 scc.cha_a_data = c;
216}
217
218void mac_sccb_console_write (struct console *co, const char *str,
219 unsigned int count)
220{
221 while (count--) {
222 if (*str == '\n')
223 mac_sccb_out( '\r' );
224 mac_sccb_out( *str++ );
225 }
226}
227
228void mac_scca_console_write (struct console *co, const char *str,
229 unsigned int count)
230{
231 while (count--) {
232 if (*str == '\n')
233 mac_scca_out( '\r' );
234 mac_scca_out( *str++ );
235 }
236}
237
238
239/* The following two functions do a quick'n'dirty initialization of the MFP or
240 * SCC serial ports. They're used by the debugging interface, kgdb, and the
241 * serial console code. */
242#define SCCB_WRITE(reg,val) \
243 do { \
244 int i; \
245 scc.cha_b_ctrl = (reg); \
246 for( i = uSEC; i > 0; --i ) \
247 barrier(); \
248 scc.cha_b_ctrl = (val); \
249 for( i = uSEC; i > 0; --i ) \
250 barrier(); \
251 } while(0)
252
253#define SCCA_WRITE(reg,val) \
254 do { \
255 int i; \
256 scc.cha_a_ctrl = (reg); \
257 for( i = uSEC; i > 0; --i ) \
258 barrier(); \
259 scc.cha_a_ctrl = (val); \
260 for( i = uSEC; i > 0; --i ) \
261 barrier(); \
262 } while(0)
263
264/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
265 * delay of ~ 60us. */
266/* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/
267#define LONG_DELAY() \
268 do { \
269 int i; \
270 for( i = 60*uSEC; i > 0; --i ) \
271 barrier(); \
272 } while(0)
273
274#ifndef CONFIG_SERIAL_CONSOLE
275static void __init mac_init_scc_port( int cflag, int port )
276#else
277void mac_init_scc_port( int cflag, int port )
278#endif
279{
280 extern int mac_SCC_reset_done;
281
282 /*
283 * baud rates: 1200, 1800, 2400, 4800, 9600, 19.2k, 38.4k, 57.6k, 115.2k
284 */
285
286 static int clksrc_table[9] =
287 /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
288 { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
289 static int clkmode_table[9] =
290 /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
291 { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
292 static int div_table[9] =
293 /* reg12 (BRG low) */
294 { 94, 62, 46, 22, 10, 4, 1, 0, 0 };
295
296 int baud = cflag & CBAUD;
297 int clksrc, clkmode, div, reg3, reg5;
298
299 if (cflag & CBAUDEX)
300 baud += B38400;
301 if (baud < B1200 || baud > B38400+2)
302 baud = B9600; /* use default 9600bps for non-implemented rates */
303 baud -= B1200; /* tables starts at 1200bps */
304
305 clksrc = clksrc_table[baud];
306 clkmode = clkmode_table[baud];
307 div = div_table[baud];
308
309 reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40);
310 reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */;
311
312 if (port == 1) {
313 (void)scc.cha_b_ctrl; /* reset reg pointer */
314 SCCB_WRITE( 9, 0xc0 ); /* reset */
315 LONG_DELAY(); /* extra delay after WR9 access */
316 SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
317 0x04 /* 1 stopbit */ |
318 clkmode );
319 SCCB_WRITE( 3, reg3 );
320 SCCB_WRITE( 5, reg5 );
321 SCCB_WRITE( 9, 0 ); /* no interrupts */
322 LONG_DELAY(); /* extra delay after WR9 access */
323 SCCB_WRITE( 10, 0 ); /* NRZ mode */
324 SCCB_WRITE( 11, clksrc ); /* main clock source */
325 SCCB_WRITE( 12, div ); /* BRG value */
326 SCCB_WRITE( 13, 0 ); /* BRG high byte */
327 SCCB_WRITE( 14, 1 );
328 SCCB_WRITE( 3, reg3 | 1 );
329 SCCB_WRITE( 5, reg5 | 8 );
330 } else if (port == 0) {
331 (void)scc.cha_a_ctrl; /* reset reg pointer */
332 SCCA_WRITE( 9, 0xc0 ); /* reset */
333 LONG_DELAY(); /* extra delay after WR9 access */
334 SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
335 0x04 /* 1 stopbit */ |
336 clkmode );
337 SCCA_WRITE( 3, reg3 );
338 SCCA_WRITE( 5, reg5 );
339 SCCA_WRITE( 9, 0 ); /* no interrupts */
340 LONG_DELAY(); /* extra delay after WR9 access */
341 SCCA_WRITE( 10, 0 ); /* NRZ mode */
342 SCCA_WRITE( 11, clksrc ); /* main clock source */
343 SCCA_WRITE( 12, div ); /* BRG value */
344 SCCA_WRITE( 13, 0 ); /* BRG high byte */
345 SCCA_WRITE( 14, 1 );
346 SCCA_WRITE( 3, reg3 | 1 );
347 SCCA_WRITE( 5, reg5 | 8 );
348 }
349
350 mac_SCC_reset_done = 1;
351 mac_SCC_init_done = 1;
352}
353#endif /* DEBUG_SERIAL */
354
355void mac_init_scca_port( int cflag )
356{
357 mac_init_scc_port(cflag, 0);
358}
359
360void mac_init_sccb_port( int cflag )
361{
362 mac_init_scc_port(cflag, 1);
363}
364
365void __init mac_debug_init(void)
366{
367#ifdef DEBUG_SERIAL
368 if ( !strcmp( m68k_debug_device, "ser" )
369 || !strcmp( m68k_debug_device, "ser1" )) {
370 /* Mac modem port */
371 mac_init_scc_port( B9600|CS8, 0 );
372 mac_console_driver.write = mac_scca_console_write;
373 scc_port = 0;
374 }
375 else if (!strcmp( m68k_debug_device, "ser2" )) {
376 /* Mac printer port */
377 mac_init_scc_port( B9600|CS8, 1 );
378 mac_console_driver.write = mac_sccb_console_write;
379 scc_port = 1;
380 }
381#endif
382#ifdef DEBUG_HEADS
383 if ( !strcmp( m68k_debug_device, "scn" )
384 || !strcmp( m68k_debug_device, "con" )) {
385 /* display, using head.S console routines */
386 mac_console_driver.write = mac_debug_console_write;
387 }
388#endif
389 if (mac_console_driver.write)
390 register_console(&mac_console_driver);
391}
392
393/*
394 * Local variables:
395 * c-indent-level: 4
396 * tab-width: 8
397 * End:
398 */
diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
new file mode 100644
index 000000000000..d889ba80ccdc
--- /dev/null
+++ b/arch/m68k/mac/iop.c
@@ -0,0 +1,714 @@
1/*
2 * I/O Processor (IOP) management
3 * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice and this list of conditions.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice and this list of conditions in the documentation and/or other
12 * materials provided with the distribution.
13 */
14
15/*
16 * The IOP chips are used in the IIfx and some Quadras (900, 950) to manage
17 * serial and ADB. They are actually a 6502 processor and some glue logic.
18 *
19 * 990429 (jmt) - Initial implementation, just enough to knock the SCC IOP
20 * into compatible mode so nobody has to fiddle with the
21 * Serial Switch control panel anymore.
22 * 990603 (jmt) - Added code to grab the correct ISM IOP interrupt for OSS
23 * and non-OSS machines (at least I hope it's correct on a
24 * non-OSS machine -- someone with a Q900 or Q950 needs to
25 * check this.)
26 * 990605 (jmt) - Rearranged things a bit wrt IOP detection; iop_present is
27 * gone, IOP base addresses are now in an array and the
28 * globally-visible functions take an IOP number instead of an
29 * an actual base address.
30 * 990610 (jmt) - Finished the message passing framework and it seems to work.
31 * Sending _definitely_ works; my adb-bus.c mods can send
32 * messages and receive the MSG_COMPLETED status back from the
33 * IOP. The trick now is figuring out the message formats.
34 * 990611 (jmt) - More cleanups. Fixed problem where unclaimed messages on a
35 * receive channel were never properly acknowledged. Bracketed
36 * the remaining debug printk's with #ifdef's and disabled
37 * debugging. I can now type on the console.
38 * 990612 (jmt) - Copyright notice added. Reworked the way replies are handled.
39 * It turns out that replies are placed back in the send buffer
40 * for that channel; messages on the receive channels are always
41 * unsolicited messages from the IOP (and our replies to them
42 * should go back in the receive channel.) Also added tracking
43 * of device names to the listener functions ala the interrupt
44 * handlers.
45 * 990729 (jmt) - Added passing of pt_regs structure to IOP handlers. This is
46 * used by the new unified ADB driver.
47 *
48 * TODO:
49 *
50 * o Something should be periodically checking iop_alive() to make sure the
51 * IOP hasn't died.
52 * o Some of the IOP manager routines need better error checking and
53 * return codes. Nothing major, just prettying up.
54 */
55
56/*
57 * -----------------------
58 * IOP Message Passing 101
59 * -----------------------
60 *
61 * The host talks to the IOPs using a rather simple message-passing scheme via
62 * a shared memory area in the IOP RAM. Each IOP has seven "channels"; each
63 * channel is conneced to a specific software driver on the IOP. For example
64 * on the SCC IOP there is one channel for each serial port. Each channel has
65 * an incoming and and outgoing message queue with a depth of one.
66 *
67 * A message is 32 bytes plus a state byte for the channel (MSG_IDLE, MSG_NEW,
68 * MSG_RCVD, MSG_COMPLETE). To send a message you copy the message into the
69 * buffer, set the state to MSG_NEW and signal the IOP by setting the IRQ flag
70 * in the IOP control to 1. The IOP will move the state to MSG_RCVD when it
71 * receives the message and then to MSG_COMPLETE when the message processing
72 * has completed. It is the host's responsibility at that point to read the
73 * reply back out of the send channel buffer and reset the channel state back
74 * to MSG_IDLE.
75 *
76 * To receive message from the IOP the same procedure is used except the roles
77 * are reversed. That is, the IOP puts message in the channel with a state of
78 * MSG_NEW, and the host receives the message and move its state to MSG_RCVD
79 * and then to MSG_COMPLETE when processing is completed and the reply (if any)
80 * has been placed back in the receive channel. The IOP will then reset the
81 * channel state to MSG_IDLE.
82 *
83 * Two sets of host interrupts are provided, INT0 and INT1. Both appear on one
84 * interrupt level; they are distinguished by a pair of bits in the IOP status
85 * register. The IOP will raise INT0 when one or more messages in the send
86 * channels have gone to the MSG_COMPLETE state and it will raise INT1 when one
87 * or more messages on the receive channels have gone to the MSG_NEW state.
88 *
89 * Since each channel handles only one message we have to implement a small
90 * interrupt-driven queue on our end. Messages to be sent are placed on the
91 * queue for sending and contain a pointer to an optional callback function.
92 * The handler for a message is called when the message state goes to
93 * MSG_COMPLETE.
94 *
95 * For receiving message we maintain a list of handler functions to call when
96 * a message is received on that IOP/channel combination. The handlers are
97 * called much like an interrupt handler and are passed a copy of the message
98 * from the IOP. The message state will be in MSG_RCVD while the handler runs;
99 * it is the handler's responsibility to call iop_complete_message() when
100 * finished; this function moves the message state to MSG_COMPLETE and signals
101 * the IOP. This two-step process is provided to allow the handler to defer
102 * message processing to a bottom-half handler if the processing will take
103 * a signifigant amount of time (handlers are called at interrupt time so they
104 * should execute quickly.)
105 */
106
107#include <linux/config.h>
108#include <linux/types.h>
109#include <linux/kernel.h>
110#include <linux/mm.h>
111#include <linux/delay.h>
112#include <linux/init.h>
113#include <linux/proc_fs.h>
114#include <linux/interrupt.h>
115
116#include <asm/bootinfo.h>
117#include <asm/macintosh.h>
118#include <asm/macints.h>
119#include <asm/mac_iop.h>
120#include <asm/mac_oss.h>
121
122/*#define DEBUG_IOP*/
123
124/* Set to nonezero if the IOPs are present. Set by iop_init() */
125
126int iop_scc_present,iop_ism_present;
127
128#ifdef CONFIG_PROC_FS
129static int iop_get_proc_info(char *, char **, off_t, int);
130#endif /* CONFIG_PROC_FS */
131
132/* structure for tracking channel listeners */
133
134struct listener {
135 const char *devname;
136 void (*handler)(struct iop_msg *, struct pt_regs *);
137};
138
139/*
140 * IOP structures for the two IOPs
141 *
142 * The SCC IOP controls both serial ports (A and B) as its two functions.
143 * The ISM IOP controls the SWIM (floppy drive) and ADB.
144 */
145
146static volatile struct mac_iop *iop_base[NUM_IOPS];
147
148/*
149 * IOP message queues
150 */
151
152static struct iop_msg iop_msg_pool[NUM_IOP_MSGS];
153static struct iop_msg *iop_send_queue[NUM_IOPS][NUM_IOP_CHAN];
154static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN];
155
156irqreturn_t iop_ism_irq(int, void *, struct pt_regs *);
157
158extern void oss_irq_enable(int);
159
160/*
161 * Private access functions
162 */
163
164static __inline__ void iop_loadaddr(volatile struct mac_iop *iop, __u16 addr)
165{
166 iop->ram_addr_lo = addr;
167 iop->ram_addr_hi = addr >> 8;
168}
169
170static __inline__ __u8 iop_readb(volatile struct mac_iop *iop, __u16 addr)
171{
172 iop->ram_addr_lo = addr;
173 iop->ram_addr_hi = addr >> 8;
174 return iop->ram_data;
175}
176
177static __inline__ void iop_writeb(volatile struct mac_iop *iop, __u16 addr, __u8 data)
178{
179 iop->ram_addr_lo = addr;
180 iop->ram_addr_hi = addr >> 8;
181 iop->ram_data = data;
182}
183
184static __inline__ void iop_stop(volatile struct mac_iop *iop)
185{
186 iop->status_ctrl &= ~IOP_RUN;
187}
188
189static __inline__ void iop_start(volatile struct mac_iop *iop)
190{
191 iop->status_ctrl = IOP_RUN | IOP_AUTOINC;
192}
193
194static __inline__ void iop_bypass(volatile struct mac_iop *iop)
195{
196 iop->status_ctrl |= IOP_BYPASS;
197}
198
199static __inline__ void iop_interrupt(volatile struct mac_iop *iop)
200{
201 iop->status_ctrl |= IOP_IRQ;
202}
203
204static int iop_alive(volatile struct mac_iop *iop)
205{
206 int retval;
207
208 retval = (iop_readb(iop, IOP_ADDR_ALIVE) == 0xFF);
209 iop_writeb(iop, IOP_ADDR_ALIVE, 0);
210 return retval;
211}
212
213static struct iop_msg *iop_alloc_msg(void)
214{
215 int i;
216 unsigned long flags;
217
218 local_irq_save(flags);
219
220 for (i = 0 ; i < NUM_IOP_MSGS ; i++) {
221 if (iop_msg_pool[i].status == IOP_MSGSTATUS_UNUSED) {
222 iop_msg_pool[i].status = IOP_MSGSTATUS_WAITING;
223 local_irq_restore(flags);
224 return &iop_msg_pool[i];
225 }
226 }
227
228 local_irq_restore(flags);
229 return NULL;
230}
231
232static void iop_free_msg(struct iop_msg *msg)
233{
234 msg->status = IOP_MSGSTATUS_UNUSED;
235}
236
237/*
238 * This is called by the startup code before anything else. Its purpose
239 * is to find and initialize the IOPs early in the boot sequence, so that
240 * the serial IOP can be placed into bypass mode _before_ we try to
241 * initialize the serial console.
242 */
243
244void __init iop_preinit(void)
245{
246 if (macintosh_config->scc_type == MAC_SCC_IOP) {
247 if (macintosh_config->ident == MAC_MODEL_IIFX) {
248 iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_IIFX;
249 } else {
250 iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_QUADRA;
251 }
252 iop_base[IOP_NUM_SCC]->status_ctrl = 0x87;
253 iop_scc_present = 1;
254 } else {
255 iop_base[IOP_NUM_SCC] = NULL;
256 iop_scc_present = 0;
257 }
258 if (macintosh_config->adb_type == MAC_ADB_IOP) {
259 if (macintosh_config->ident == MAC_MODEL_IIFX) {
260 iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_IIFX;
261 } else {
262 iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_QUADRA;
263 }
264 iop_base[IOP_NUM_ISM]->status_ctrl = 0;
265 iop_ism_present = 1;
266 } else {
267 iop_base[IOP_NUM_ISM] = NULL;
268 iop_ism_present = 0;
269 }
270}
271
272/*
273 * Initialize the IOPs, if present.
274 */
275
276void __init iop_init(void)
277{
278 int i;
279
280 if (iop_scc_present) {
281 printk("IOP: detected SCC IOP at %p\n", iop_base[IOP_NUM_SCC]);
282 }
283 if (iop_ism_present) {
284 printk("IOP: detected ISM IOP at %p\n", iop_base[IOP_NUM_ISM]);
285 iop_start(iop_base[IOP_NUM_ISM]);
286 iop_alive(iop_base[IOP_NUM_ISM]); /* clears the alive flag */
287 }
288
289 /* Make the whole pool available and empty the queues */
290
291 for (i = 0 ; i < NUM_IOP_MSGS ; i++) {
292 iop_msg_pool[i].status = IOP_MSGSTATUS_UNUSED;
293 }
294
295 for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
296 iop_send_queue[IOP_NUM_SCC][i] = 0;
297 iop_send_queue[IOP_NUM_ISM][i] = 0;
298 iop_listeners[IOP_NUM_SCC][i].devname = NULL;
299 iop_listeners[IOP_NUM_SCC][i].handler = NULL;
300 iop_listeners[IOP_NUM_ISM][i].devname = NULL;
301 iop_listeners[IOP_NUM_ISM][i].handler = NULL;
302 }
303
304#if 0 /* Crashing in 2.4 now, not yet sure why. --jmt */
305#ifdef CONFIG_PROC_FS
306 create_proc_info_entry("mac_iop", 0, &proc_root, iop_get_proc_info);
307#endif
308#endif
309}
310
311/*
312 * Register the interrupt handler for the IOPs.
313 * TODO: might be wrong for non-OSS machines. Anyone?
314 */
315
316void __init iop_register_interrupts(void)
317{
318 if (iop_ism_present) {
319 if (oss_present) {
320 cpu_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
321 IRQ_FLG_LOCK, "ISM IOP",
322 (void *) IOP_NUM_ISM);
323 oss_irq_enable(IRQ_MAC_ADB);
324 } else {
325 request_irq(IRQ_VIA2_0, iop_ism_irq,
326 IRQ_FLG_LOCK|IRQ_FLG_FAST, "ISM IOP",
327 (void *) IOP_NUM_ISM);
328 }
329 if (!iop_alive(iop_base[IOP_NUM_ISM])) {
330 printk("IOP: oh my god, they killed the ISM IOP!\n");
331 } else {
332 printk("IOP: the ISM IOP seems to be alive.\n");
333 }
334 }
335}
336
337/*
338 * Register or unregister a listener for a specific IOP and channel
339 *
340 * If the handler pointer is NULL the current listener (if any) is
341 * unregistered. Otherwise the new listener is registered provided
342 * there is no existing listener registered.
343 */
344
345int iop_listen(uint iop_num, uint chan,
346 void (*handler)(struct iop_msg *, struct pt_regs *),
347 const char *devname)
348{
349 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL;
350 if (chan >= NUM_IOP_CHAN) return -EINVAL;
351 if (iop_listeners[iop_num][chan].handler && handler) return -EINVAL;
352 iop_listeners[iop_num][chan].devname = devname;
353 iop_listeners[iop_num][chan].handler = handler;
354 return 0;
355}
356
357/*
358 * Complete reception of a message, which just means copying the reply
359 * into the buffer, setting the channel state to MSG_COMPLETE and
360 * notifying the IOP.
361 */
362
363void iop_complete_message(struct iop_msg *msg)
364{
365 int iop_num = msg->iop_num;
366 int chan = msg->channel;
367 int i,offset;
368
369#ifdef DEBUG_IOP
370 printk("iop_complete(%p): iop %d chan %d\n", msg, msg->iop_num, msg->channel);
371#endif
372
373 offset = IOP_ADDR_RECV_MSG + (msg->channel * IOP_MSG_LEN);
374
375 for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
376 iop_writeb(iop_base[iop_num], offset, msg->reply[i]);
377 }
378
379 iop_writeb(iop_base[iop_num],
380 IOP_ADDR_RECV_STATE + chan, IOP_MSG_COMPLETE);
381 iop_interrupt(iop_base[msg->iop_num]);
382
383 iop_free_msg(msg);
384}
385
386/*
387 * Actually put a message into a send channel buffer
388 */
389
390static void iop_do_send(struct iop_msg *msg)
391{
392 volatile struct mac_iop *iop = iop_base[msg->iop_num];
393 int i,offset;
394
395 offset = IOP_ADDR_SEND_MSG + (msg->channel * IOP_MSG_LEN);
396
397 for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
398 iop_writeb(iop, offset, msg->message[i]);
399 }
400
401 iop_writeb(iop, IOP_ADDR_SEND_STATE + msg->channel, IOP_MSG_NEW);
402
403 iop_interrupt(iop);
404}
405
406/*
407 * Handle sending a message on a channel that
408 * has gone into the IOP_MSG_COMPLETE state.
409 */
410
411static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs)
412{
413 volatile struct mac_iop *iop = iop_base[iop_num];
414 struct iop_msg *msg,*msg2;
415 int i,offset;
416
417#ifdef DEBUG_IOP
418 printk("iop_handle_send: iop %d channel %d\n", iop_num, chan);
419#endif
420
421 iop_writeb(iop, IOP_ADDR_SEND_STATE + chan, IOP_MSG_IDLE);
422
423 if (!(msg = iop_send_queue[iop_num][chan])) return;
424
425 msg->status = IOP_MSGSTATUS_COMPLETE;
426 offset = IOP_ADDR_SEND_MSG + (chan * IOP_MSG_LEN);
427 for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
428 msg->reply[i] = iop_readb(iop, offset);
429 }
430 if (msg->handler) (*msg->handler)(msg, regs);
431 msg2 = msg;
432 msg = msg->next;
433 iop_free_msg(msg2);
434
435 iop_send_queue[iop_num][chan] = msg;
436 if (msg) iop_do_send(msg);
437}
438
439/*
440 * Handle reception of a message on a channel that has
441 * gone into the IOP_MSG_NEW state.
442 */
443
444static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs)
445{
446 volatile struct mac_iop *iop = iop_base[iop_num];
447 int i,offset;
448 struct iop_msg *msg;
449
450#ifdef DEBUG_IOP
451 printk("iop_handle_recv: iop %d channel %d\n", iop_num, chan);
452#endif
453
454 msg = iop_alloc_msg();
455 msg->iop_num = iop_num;
456 msg->channel = chan;
457 msg->status = IOP_MSGSTATUS_UNSOL;
458 msg->handler = iop_listeners[iop_num][chan].handler;
459
460 offset = IOP_ADDR_RECV_MSG + (chan * IOP_MSG_LEN);
461
462 for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
463 msg->message[i] = iop_readb(iop, offset);
464 }
465
466 iop_writeb(iop, IOP_ADDR_RECV_STATE + chan, IOP_MSG_RCVD);
467
468 /* If there is a listener, call it now. Otherwise complete */
469 /* the message ourselves to avoid possible stalls. */
470
471 if (msg->handler) {
472 (*msg->handler)(msg, regs);
473 } else {
474#ifdef DEBUG_IOP
475 printk("iop_handle_recv: unclaimed message on iop %d channel %d\n", iop_num, chan);
476 printk("iop_handle_recv:");
477 for (i = 0 ; i < IOP_MSG_LEN ; i++) {
478 printk(" %02X", (uint) msg->message[i]);
479 }
480 printk("\n");
481#endif
482 iop_complete_message(msg);
483 }
484}
485
486/*
487 * Send a message
488 *
489 * The message is placed at the end of the send queue. Afterwards if the
490 * channel is idle we force an immediate send of the next message in the
491 * queue.
492 */
493
494int iop_send_message(uint iop_num, uint chan, void *privdata,
495 uint msg_len, __u8 *msg_data,
496 void (*handler)(struct iop_msg *, struct pt_regs *))
497{
498 struct iop_msg *msg, *q;
499
500 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL;
501 if (chan >= NUM_IOP_CHAN) return -EINVAL;
502 if (msg_len > IOP_MSG_LEN) return -EINVAL;
503
504 msg = iop_alloc_msg();
505 if (!msg) return -ENOMEM;
506
507 msg->next = NULL;
508 msg->status = IOP_MSGSTATUS_WAITING;
509 msg->iop_num = iop_num;
510 msg->channel = chan;
511 msg->caller_priv = privdata;
512 memcpy(msg->message, msg_data, msg_len);
513 msg->handler = handler;
514
515 if (!(q = iop_send_queue[iop_num][chan])) {
516 iop_send_queue[iop_num][chan] = msg;
517 } else {
518 while (q->next) q = q->next;
519 q->next = msg;
520 }
521
522 if (iop_readb(iop_base[iop_num],
523 IOP_ADDR_SEND_STATE + chan) == IOP_MSG_IDLE) {
524 iop_do_send(msg);
525 }
526
527 return 0;
528}
529
530/*
531 * Upload code to the shared RAM of an IOP.
532 */
533
534void iop_upload_code(uint iop_num, __u8 *code_start,
535 uint code_len, __u16 shared_ram_start)
536{
537 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return;
538
539 iop_loadaddr(iop_base[iop_num], shared_ram_start);
540
541 while (code_len--) {
542 iop_base[iop_num]->ram_data = *code_start++;
543 }
544}
545
546/*
547 * Download code from the shared RAM of an IOP.
548 */
549
550void iop_download_code(uint iop_num, __u8 *code_start,
551 uint code_len, __u16 shared_ram_start)
552{
553 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return;
554
555 iop_loadaddr(iop_base[iop_num], shared_ram_start);
556
557 while (code_len--) {
558 *code_start++ = iop_base[iop_num]->ram_data;
559 }
560}
561
562/*
563 * Compare the code in the shared RAM of an IOP with a copy in system memory
564 * and return 0 on match or the first nonmatching system memory address on
565 * failure.
566 */
567
568__u8 *iop_compare_code(uint iop_num, __u8 *code_start,
569 uint code_len, __u16 shared_ram_start)
570{
571 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return code_start;
572
573 iop_loadaddr(iop_base[iop_num], shared_ram_start);
574
575 while (code_len--) {
576 if (*code_start != iop_base[iop_num]->ram_data) {
577 return code_start;
578 }
579 code_start++;
580 }
581 return (__u8 *) 0;
582}
583
584/*
585 * Handle an ISM IOP interrupt
586 */
587
588irqreturn_t iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs)
589{
590 uint iop_num = (uint) dev_id;
591 volatile struct mac_iop *iop = iop_base[iop_num];
592 int i,state;
593
594#ifdef DEBUG_IOP
595 printk("iop_ism_irq: status = %02X\n", (uint) iop->status_ctrl);
596#endif
597
598 /* INT0 indicates a state change on an outgoing message channel */
599
600 if (iop->status_ctrl & IOP_INT0) {
601 iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC;
602#ifdef DEBUG_IOP
603 printk("iop_ism_irq: new status = %02X, send states",
604 (uint) iop->status_ctrl);
605#endif
606 for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
607 state = iop_readb(iop, IOP_ADDR_SEND_STATE + i);
608#ifdef DEBUG_IOP
609 printk(" %02X", state);
610#endif
611 if (state == IOP_MSG_COMPLETE) {
612 iop_handle_send(iop_num, i, regs);
613 }
614 }
615#ifdef DEBUG_IOP
616 printk("\n");
617#endif
618 }
619
620 if (iop->status_ctrl & IOP_INT1) { /* INT1 for incoming msgs */
621 iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC;
622#ifdef DEBUG_IOP
623 printk("iop_ism_irq: new status = %02X, recv states",
624 (uint) iop->status_ctrl);
625#endif
626 for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
627 state = iop_readb(iop, IOP_ADDR_RECV_STATE + i);
628#ifdef DEBUG_IOP
629 printk(" %02X", state);
630#endif
631 if (state == IOP_MSG_NEW) {
632 iop_handle_recv(iop_num, i, regs);
633 }
634 }
635#ifdef DEBUG_IOP
636 printk("\n");
637#endif
638 }
639 return IRQ_HANDLED;
640}
641
642#ifdef CONFIG_PROC_FS
643
644char *iop_chan_state(int state)
645{
646 switch(state) {
647 case IOP_MSG_IDLE : return "idle ";
648 case IOP_MSG_NEW : return "new ";
649 case IOP_MSG_RCVD : return "received ";
650 case IOP_MSG_COMPLETE : return "completed ";
651 default : return "unknown ";
652 }
653}
654
655int iop_dump_one_iop(char *buf, int iop_num, char *iop_name)
656{
657 int i,len = 0;
658 volatile struct mac_iop *iop = iop_base[iop_num];
659
660 len += sprintf(buf+len, "%s IOP channel states:\n\n", iop_name);
661 len += sprintf(buf+len, "## send_state recv_state device\n");
662 len += sprintf(buf+len, "------------------------------------------------\n");
663 for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
664 len += sprintf(buf+len, "%2d %10s %10s %s\n", i,
665 iop_chan_state(iop_readb(iop, IOP_ADDR_SEND_STATE+i)),
666 iop_chan_state(iop_readb(iop, IOP_ADDR_RECV_STATE+i)),
667 iop_listeners[iop_num][i].handler?
668 iop_listeners[iop_num][i].devname : "");
669
670 }
671 len += sprintf(buf+len, "\n");
672 return len;
673}
674
675static int iop_get_proc_info(char *buf, char **start, off_t pos, int count)
676{
677 int len, cnt;
678
679 cnt = 0;
680 len = sprintf(buf, "IOPs detected:\n\n");
681
682 if (iop_scc_present) {
683 len += sprintf(buf+len, "SCC IOP (%p): status %02X\n",
684 iop_base[IOP_NUM_SCC],
685 (uint) iop_base[IOP_NUM_SCC]->status_ctrl);
686 }
687 if (iop_ism_present) {
688 len += sprintf(buf+len, "ISM IOP (%p): status %02X\n\n",
689 iop_base[IOP_NUM_ISM],
690 (uint) iop_base[IOP_NUM_ISM]->status_ctrl);
691 }
692
693 if (iop_scc_present) {
694 len += iop_dump_one_iop(buf+len, IOP_NUM_SCC, "SCC");
695
696 }
697
698 if (iop_ism_present) {
699 len += iop_dump_one_iop(buf+len, IOP_NUM_ISM, "ISM");
700
701 }
702
703 if (len >= pos) {
704 if (!*start) {
705 *start = buf + pos;
706 cnt = len - pos;
707 } else {
708 cnt += len;
709 }
710 }
711 return (count > cnt) ? cnt : count;
712}
713
714#endif /* CONFIG_PROC_FS */
diff --git a/arch/m68k/mac/mac_ksyms.c b/arch/m68k/mac/mac_ksyms.c
new file mode 100644
index 000000000000..6e37ceb0f3b5
--- /dev/null
+++ b/arch/m68k/mac/mac_ksyms.c
@@ -0,0 +1,8 @@
1#include <linux/module.h>
2#include <asm/ptrace.h>
3#include <asm/traps.h>
4
5/* Says whether we're using A/UX interrupts or not */
6extern int via_alt_mapping;
7
8EXPORT_SYMBOL(via_alt_mapping);
diff --git a/arch/m68k/mac/mac_penguin.S b/arch/m68k/mac/mac_penguin.S
new file mode 100644
index 000000000000..b3ce30b6071d
--- /dev/null
+++ b/arch/m68k/mac/mac_penguin.S
@@ -0,0 +1,75 @@
1.byte \
20x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
30x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
40x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
50x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
60x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
70x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
80x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
90x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
100x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
110x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
120x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
130x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
140x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
150x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
160x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0xFF,0xFF,0x0F,0xF0,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
170x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0x00,0xFF,0xFF,0x0F,0xFF,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
180x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0x0F,0xFF,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
190x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x0F,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
200x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
210x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
220x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
230x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
240x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
250x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x0F,0xF0,0x00,0x00,0xFF,0xF0,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
260x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x0F,0xF0,0xFF,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
270x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
280x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
290x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
300x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
310x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
320x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
330x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,\
340x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\
350x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\
360x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\
370x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,\
380x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\
390x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\
400x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
410x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
420x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,\
430x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\
440x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\
450x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\
460x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
470x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
480x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
490x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
500x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
510x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
520x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
530x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
540x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
550x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
560x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\
570x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0xF0,0x00,0x00,\
580x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0xF0,0x00,0x00,\
590x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,\
600x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\
610x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\
620x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,\
630x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,\
640x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,\
650x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
660x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
670x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,\
680x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,\
690xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,\
700x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,\
710x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,\
720x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,\
730x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,\
740x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\
750x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
new file mode 100644
index 000000000000..44c5cd2ad6a8
--- /dev/null
+++ b/arch/m68k/mac/macboing.c
@@ -0,0 +1,309 @@
1/*
2 * Mac bong noise generator. Note - we ought to put a boingy noise
3 * here 8)
4 *
5 * ----------------------------------------------------------------------
6 * 16.11.98:
7 * rewrote some functions, added support for Enhanced ASC (Quadras)
8 * after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck
9 * Juergen Mellinger (juergen.mellinger@t-online.de)
10 */
11
12#include <linux/sched.h>
13#include <linux/timer.h>
14
15#include <asm/macintosh.h>
16#include <asm/mac_asc.h>
17
18static int mac_asc_inited;
19/*
20 * dumb triangular wave table
21 */
22static __u8 mac_asc_wave_tab[ 0x800 ];
23
24/*
25 * Alan's original sine table; needs interpolating to 0x800
26 * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric)
27 */
28static const signed char sine_data[] = {
29 0, 39, 75, 103, 121, 127, 121, 103, 75, 39,
30 0, -39, -75, -103, -121, -127, -121, -103, -75, -39
31};
32
33/*
34 * where the ASC hides ...
35 */
36static volatile __u8* mac_asc_regs = ( void* )0x50F14000;
37
38/*
39 * sample rate; is this a good default value?
40 */
41static unsigned long mac_asc_samplespersec = 11050;
42static int mac_bell_duration;
43static unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */
44static unsigned long mac_bell_phasepersample;
45
46/*
47 * some function protos
48 */
49static void mac_init_asc( void );
50static void mac_nosound( unsigned long );
51static void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int );
52static void mac_quadra_ring_bell( unsigned long );
53static void mac_av_start_bell( unsigned int, unsigned int, unsigned int );
54static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int );
55
56/*
57 * our timer to start/continue/stop the bell
58 */
59static struct timer_list mac_sound_timer =
60 TIMER_INITIALIZER(mac_nosound, 0, 0);
61
62/*
63 * Sort of initialize the sound chip (called from mac_mksound on the first
64 * beep).
65 */
66static void mac_init_asc( void )
67{
68 int i;
69
70 /*
71 * do some machine specific initialization
72 * BTW:
73 * the NetBSD Quadra patch identifies the Enhanced Apple Sound Chip via
74 * mac_asc_regs[ 0x800 ] & 0xF0 != 0
75 * this makes no sense here, because we have to set the default sample
76 * rate anyway if we want correct frequencies
77 */
78 switch ( macintosh_config->ident )
79 {
80 case MAC_MODEL_IIFX:
81 /*
82 * The IIfx is always special ...
83 */
84 mac_asc_regs = ( void* )0x50010000;
85 break;
86 /*
87 * not sure about how correct this list is
88 * machines with the EASC enhanced apple sound chip
89 */
90 case MAC_MODEL_Q630:
91 case MAC_MODEL_P475:
92 mac_special_bell = mac_quadra_start_bell;
93 mac_asc_samplespersec = 22150;
94 break;
95 case MAC_MODEL_C660:
96 case MAC_MODEL_Q840:
97 /*
98 * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O.
99 * It appears to be similar to the "AWACS" custom ASIC in the Power Mac
100 * [678]100. Because Singer and AWACS may have a similar hardware
101 * interface, this would imply that the code in drivers/sound/dmasound.c
102 * for AWACS could be used as a basis for Singer support. All we have to
103 * do is figure out how to do DMA on the 660AV/840AV through the PSC and
104 * figure out where the Singer hardware sits in memory. (I'd look in the
105 * vicinity of the AWACS location in a Power Mac [678]100 first, or the
106 * current location of the Apple Sound Chip--ASC--in other Macs.) The
107 * Power Mac [678]100 info can be found in MkLinux Mach kernel sources.
108 *
109 * Quoted from Apple's Tech Info Library, article number 16405:
110 * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power
111 * Macintosh models have 16-bit audio input and output capability
112 * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer
113 * codec circuitry in the AVs. The Audio Waveform Amplifier and
114 * Converter (AWAC) chip in the Power Macintosh performs the same
115 * 16-bit I/O functionality. The PowerBook 500 series computers
116 * support 16-bit stereo output, but only mono input."
117 *
118 * http://til.info.apple.com/techinfo.nsf/artnum/n16405
119 *
120 * --David Kilzer
121 */
122 mac_special_bell = mac_av_start_bell;
123 break;
124 case MAC_MODEL_Q650:
125 case MAC_MODEL_Q700:
126 case MAC_MODEL_Q800:
127 case MAC_MODEL_Q900:
128 case MAC_MODEL_Q950:
129 /*
130 * Currently not implemented!
131 */
132 mac_special_bell = NULL;
133 break;
134 default:
135 /*
136 * Every switch needs a default
137 */
138 mac_special_bell = NULL;
139 break;
140 }
141
142 /*
143 * init the wave table with a simple triangular wave
144 * A sine wave would sure be nicer here ...
145 */
146 for ( i = 0; i < 0x400; i++ )
147 {
148 mac_asc_wave_tab[ i ] = i / 4;
149 mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4;
150 }
151 mac_asc_inited = 1;
152}
153
154/*
155 * Called to make noise; current single entry to the boing driver.
156 * Does the job for simple ASC, calls other routines else.
157 * XXX Fixme:
158 * Should be split into asc_mksound, easc_mksound, av_mksound and
159 * function pointer set in mac_init_asc which would be called at
160 * init time.
161 * _This_ is rather ugly ...
162 */
163void mac_mksound( unsigned int freq, unsigned int length )
164{
165 __u32 cfreq = ( freq << 5 ) / 468;
166 __u32 flags;
167 int i;
168
169 if ( mac_special_bell == NULL )
170 {
171 /* Do nothing */
172 return;
173 }
174
175 if ( !mac_asc_inited )
176 mac_init_asc();
177
178 if ( mac_special_bell )
179 {
180 mac_special_bell( freq, length, 128 );
181 return;
182 }
183
184 if ( freq < 20 || freq > 20000 || length == 0 )
185 {
186 mac_nosound( 0 );
187 return;
188 }
189
190 local_irq_save(flags);
191
192 del_timer( &mac_sound_timer );
193
194 for ( i = 0; i < 0x800; i++ )
195 mac_asc_regs[ i ] = 0;
196 for ( i = 0; i < 0x800; i++ )
197 mac_asc_regs[ i ] = mac_asc_wave_tab[ i ];
198
199 for ( i = 0; i < 8; i++ )
200 *( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq;
201
202 mac_asc_regs[ 0x807 ] = 0;
203 mac_asc_regs[ ASC_VOLUME ] = 128;
204 mac_asc_regs[ 0x805 ] = 0;
205 mac_asc_regs[ 0x80F ] = 0;
206 mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE;
207 mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE;
208
209 mac_sound_timer.expires = jiffies + length;
210 add_timer( &mac_sound_timer );
211
212 local_irq_restore(flags);
213}
214
215/*
216 * regular ASC: stop whining ..
217 */
218static void mac_nosound( unsigned long ignored )
219{
220 mac_asc_regs[ ASC_ENABLE ] = 0;
221}
222
223/*
224 * EASC entry; init EASC, don't load wavetable, schedule 'start whining'.
225 */
226static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
227{
228 __u32 flags;
229
230 /* if the bell is already ringing, ring longer */
231 if ( mac_bell_duration > 0 )
232 {
233 mac_bell_duration += length;
234 return;
235 }
236
237 mac_bell_duration = length;
238 mac_bell_phase = 0;
239 mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec;
240 /* this is reasonably big for small frequencies */
241
242 local_irq_save(flags);
243
244 /* set the volume */
245 mac_asc_regs[ 0x806 ] = volume;
246
247 /* set up the ASC registers */
248 if ( mac_asc_regs[ 0x801 ] != 1 )
249 {
250 /* select mono mode */
251 mac_asc_regs[ 0x807 ] = 0;
252 /* select sampled sound mode */
253 mac_asc_regs[ 0x802 ] = 0;
254 /* ??? */
255 mac_asc_regs[ 0x801 ] = 1;
256 mac_asc_regs[ 0x803 ] |= 0x80;
257 mac_asc_regs[ 0x803 ] &= 0x7F;
258 }
259
260 mac_sound_timer.function = mac_quadra_ring_bell;
261 mac_sound_timer.expires = jiffies + 1;
262 add_timer( &mac_sound_timer );
263
264 local_irq_restore(flags);
265}
266
267/*
268 * EASC 'start/continue whining'; I'm not sure why the above function didn't
269 * already load the wave table, or at least call this one...
270 * This piece keeps reloading the wave table until done.
271 */
272static void mac_quadra_ring_bell( unsigned long ignored )
273{
274 int i, count = mac_asc_samplespersec / HZ;
275 __u32 flags;
276
277 /*
278 * we neither want a sound buffer overflow nor underflow, so we need to match
279 * the number of samples per timer interrupt as exactly as possible.
280 * using the asc interrupt will give better results in the future
281 * ...and the possibility to use a real sample (a boingy noise, maybe...)
282 */
283
284 local_irq_save(flags);
285
286 del_timer( &mac_sound_timer );
287
288 if ( mac_bell_duration-- > 0 )
289 {
290 for ( i = 0; i < count; i++ )
291 {
292 mac_bell_phase += mac_bell_phasepersample;
293 mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ];
294 }
295 mac_sound_timer.expires = jiffies + 1;
296 add_timer( &mac_sound_timer );
297 }
298 else
299 mac_asc_regs[ 0x801 ] = 0;
300
301 local_irq_restore(flags);
302}
303
304/*
305 * AV code - please fill in.
306 */
307static void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
308{
309}
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
new file mode 100644
index 000000000000..1809601ad903
--- /dev/null
+++ b/arch/m68k/mac/macints.c
@@ -0,0 +1,760 @@
1/*
2 * Macintosh interrupts
3 *
4 * General design:
5 * In contrary to the Amiga and Atari platforms, the Mac hardware seems to
6 * exclusively use the autovector interrupts (the 'generic level0-level7'
7 * interrupts with exception vectors 0x19-0x1f). The following interrupt levels
8 * are used:
9 * 1 - VIA1
10 * - slot 0: one second interrupt (CA2)
11 * - slot 1: VBlank (CA1)
12 * - slot 2: ADB data ready (SR full)
13 * - slot 3: ADB data (CB2)
14 * - slot 4: ADB clock (CB1)
15 * - slot 5: timer 2
16 * - slot 6: timer 1
17 * - slot 7: status of IRQ; signals 'any enabled int.'
18 *
19 * 2 - VIA2 or RBV
20 * - slot 0: SCSI DRQ (CA2)
21 * - slot 1: NUBUS IRQ (CA1) need to read port A to find which
22 * - slot 2: /EXP IRQ (only on IIci)
23 * - slot 3: SCSI IRQ (CB2)
24 * - slot 4: ASC IRQ (CB1)
25 * - slot 5: timer 2 (not on IIci)
26 * - slot 6: timer 1 (not on IIci)
27 * - slot 7: status of IRQ; signals 'any enabled int.'
28 *
29 * 2 - OSS (IIfx only?)
30 * - slot 0: SCSI interrupt
31 * - slot 1: Sound interrupt
32 *
33 * Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:
34 *
35 * 3 - unused (?)
36 *
37 * 4 - SCC (slot number determined by reading RR3 on the SSC itself)
38 * - slot 1: SCC channel A
39 * - slot 2: SCC channel B
40 *
41 * 5 - unused (?)
42 * [serial errors or special conditions seem to raise level 6
43 * interrupts on some models (LC4xx?)]
44 *
45 * 6 - off switch (?)
46 *
47 * For OSS Macintoshes (IIfx only at this point):
48 *
49 * 3 - Nubus interrupt
50 * - slot 0: Slot $9
51 * - slot 1: Slot $A
52 * - slot 2: Slot $B
53 * - slot 3: Slot $C
54 * - slot 4: Slot $D
55 * - slot 5: Slot $E
56 *
57 * 4 - SCC IOP
58 * - slot 1: SCC channel A
59 * - slot 2: SCC channel B
60 *
61 * 5 - ISM IOP (ADB?)
62 *
63 * 6 - unused
64 *
65 * For PSC Macintoshes (660AV, 840AV):
66 *
67 * 3 - PSC level 3
68 * - slot 0: MACE
69 *
70 * 4 - PSC level 4
71 * - slot 1: SCC channel A interrupt
72 * - slot 2: SCC channel B interrupt
73 * - slot 3: MACE DMA
74 *
75 * 5 - PSC level 5
76 *
77 * 6 - PSC level 6
78 *
79 * Finally we have good 'ole level 7, the non-maskable interrupt:
80 *
81 * 7 - NMI (programmer's switch on the back of some Macs)
82 * Also RAM parity error on models which support it (IIc, IIfx?)
83 *
84 * The current interrupt logic looks something like this:
85 *
86 * - We install dispatchers for the autovector interrupts (1-7). These
87 * dispatchers are responsible for querying the hardware (the
88 * VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using
89 * this information a machspec interrupt number is generated by placing the
90 * index of the interrupt hardware into the low three bits and the original
91 * autovector interrupt number in the upper 5 bits. The handlers for the
92 * resulting machspec interrupt are then called.
93 *
94 * - Nubus is a special case because its interrupts are hidden behind two
95 * layers of hardware. Nubus interrupts come in as index 1 on VIA #2,
96 * which translates to IRQ number 17. In this spot we install _another_
97 * dispatcher. This dispatcher finds the interrupting slot number (9-F) and
98 * then forms a new machspec interrupt number as above with the slot number
99 * minus 9 in the low three bits and the pseudo-level 7 in the upper five
100 * bits. The handlers for this new machspec interrupt number are then
101 * called. This puts Nubus interrupts into the range 56-62.
102 *
103 * - The Baboon interrupts (used on some PowerBooks) are an even more special
104 * case. They're hidden behind the Nubus slot $C interrupt thus adding a
105 * third layer of indirection. Why oh why did the Apple engineers do that?
106 *
107 * - We support "fast" and "slow" handlers, just like the Amiga port. The
108 * fast handlers are called first and with all interrupts disabled. They
109 * are expected to execute quickly (hence the name). The slow handlers are
110 * called last with interrupts enabled and the interrupt level restored.
111 * They must therefore be reentrant.
112 *
113 * TODO:
114 *
115 */
116
117#include <linux/types.h>
118#include <linux/kernel.h>
119#include <linux/sched.h>
120#include <linux/kernel_stat.h>
121#include <linux/interrupt.h> /* for intr_count */
122#include <linux/delay.h>
123#include <linux/seq_file.h>
124
125#include <asm/system.h>
126#include <asm/irq.h>
127#include <asm/traps.h>
128#include <asm/bootinfo.h>
129#include <asm/machw.h>
130#include <asm/macintosh.h>
131#include <asm/mac_via.h>
132#include <asm/mac_psc.h>
133#include <asm/hwtest.h>
134#include <asm/errno.h>
135#include <asm/macints.h>
136
137#define DEBUG_SPURIOUS
138#define SHUTUP_SONIC
139
140/*
141 * The mac_irq_list array is an array of linked lists of irq_node_t nodes.
142 * Each node contains one handler to be called whenever the interrupt
143 * occurs, with fast handlers listed before slow handlers.
144 */
145
146irq_node_t *mac_irq_list[NUM_MAC_SOURCES];
147
148/* SCC interrupt mask */
149
150static int scc_mask;
151
152/*
153 * VIA/RBV hooks
154 */
155
156extern void via_init(void);
157extern void via_register_interrupts(void);
158extern void via_irq_enable(int);
159extern void via_irq_disable(int);
160extern void via_irq_clear(int);
161extern int via_irq_pending(int);
162
163/*
164 * OSS hooks
165 */
166
167extern int oss_present;
168
169extern void oss_init(void);
170extern void oss_register_interrupts(void);
171extern void oss_irq_enable(int);
172extern void oss_irq_disable(int);
173extern void oss_irq_clear(int);
174extern int oss_irq_pending(int);
175
176/*
177 * PSC hooks
178 */
179
180extern int psc_present;
181
182extern void psc_init(void);
183extern void psc_register_interrupts(void);
184extern void psc_irq_enable(int);
185extern void psc_irq_disable(int);
186extern void psc_irq_clear(int);
187extern int psc_irq_pending(int);
188
189/*
190 * IOP hooks
191 */
192
193extern void iop_register_interrupts(void);
194
195/*
196 * Baboon hooks
197 */
198
199extern int baboon_present;
200
201extern void baboon_init(void);
202extern void baboon_register_interrupts(void);
203extern void baboon_irq_enable(int);
204extern void baboon_irq_disable(int);
205extern void baboon_irq_clear(int);
206extern int baboon_irq_pending(int);
207
208/*
209 * SCC interrupt routines
210 */
211
212static void scc_irq_enable(int);
213static void scc_irq_disable(int);
214
215/*
216 * console_loglevel determines NMI handler function
217 */
218
219extern irqreturn_t mac_bang(int, void *, struct pt_regs *);
220irqreturn_t mac_nmi_handler(int, void *, struct pt_regs *);
221irqreturn_t mac_debug_handler(int, void *, struct pt_regs *);
222
223/* #define DEBUG_MACINTS */
224
225void mac_init_IRQ(void)
226{
227 int i;
228
229#ifdef DEBUG_MACINTS
230 printk("mac_init_IRQ(): Setting things up...\n");
231#endif
232 /* Initialize the IRQ handler lists. Initially each list is empty, */
233
234 for (i = 0; i < NUM_MAC_SOURCES; i++) {
235 mac_irq_list[i] = NULL;
236 }
237
238 scc_mask = 0;
239
240 /* Make sure the SONIC interrupt is cleared or things get ugly */
241#ifdef SHUTUP_SONIC
242 printk("Killing onboard sonic... ");
243 /* This address should hopefully be mapped already */
244 if (hwreg_present((void*)(0x50f0a000))) {
245 *(long *)(0x50f0a014) = 0x7fffL;
246 *(long *)(0x50f0a010) = 0L;
247 }
248 printk("Done.\n");
249#endif /* SHUTUP_SONIC */
250
251 /*
252 * Now register the handlers for the master IRQ handlers
253 * at levels 1-7. Most of the work is done elsewhere.
254 */
255
256 if (oss_present) {
257 oss_register_interrupts();
258 } else {
259 via_register_interrupts();
260 }
261 if (psc_present) psc_register_interrupts();
262 if (baboon_present) baboon_register_interrupts();
263 iop_register_interrupts();
264 cpu_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI",
265 mac_nmi_handler);
266#ifdef DEBUG_MACINTS
267 printk("mac_init_IRQ(): Done!\n");
268#endif
269}
270
271/*
272 * Routines to work with irq_node_t's on linked lists lifted from
273 * the Amiga code written by Roman Zippel.
274 */
275
276static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node)
277{
278 unsigned long flags;
279 irq_node_t *cur;
280
281 if (!node->dev_id)
282 printk("%s: Warning: dev_id of %s is zero\n",
283 __FUNCTION__, node->devname);
284
285 local_irq_save(flags);
286
287 cur = *list;
288
289 if (node->flags & IRQ_FLG_FAST) {
290 node->flags &= ~IRQ_FLG_SLOW;
291 while (cur && cur->flags & IRQ_FLG_FAST) {
292 list = &cur->next;
293 cur = cur->next;
294 }
295 } else if (node->flags & IRQ_FLG_SLOW) {
296 while (cur) {
297 list = &cur->next;
298 cur = cur->next;
299 }
300 } else {
301 while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
302 list = &cur->next;
303 cur = cur->next;
304 }
305 }
306
307 node->next = cur;
308 *list = node;
309
310 local_irq_restore(flags);
311}
312
313static inline void mac_delete_irq(irq_node_t **list, void *dev_id)
314{
315 unsigned long flags;
316 irq_node_t *node;
317
318 local_irq_save(flags);
319
320 for (node = *list; node; list = &node->next, node = *list) {
321 if (node->dev_id == dev_id) {
322 *list = node->next;
323 /* Mark it as free. */
324 node->handler = NULL;
325 local_irq_restore(flags);
326 return;
327 }
328 }
329 local_irq_restore(flags);
330 printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
331}
332
333/*
334 * Call all the handlers for a given interrupt. Fast handlers are called
335 * first followed by slow handlers.
336 *
337 * This code taken from the original Amiga code written by Roman Zippel.
338 */
339
340void mac_do_irq_list(int irq, struct pt_regs *fp)
341{
342 irq_node_t *node, *slow_nodes;
343 unsigned long flags;
344
345 kstat_cpu(0).irqs[irq]++;
346
347#ifdef DEBUG_SPURIOUS
348 if (!mac_irq_list[irq] && (console_loglevel > 7)) {
349 printk("mac_do_irq_list: spurious interrupt %d!\n", irq);
350 return;
351 }
352#endif
353
354 /* serve first fast and normal handlers */
355 for (node = mac_irq_list[irq];
356 node && (!(node->flags & IRQ_FLG_SLOW));
357 node = node->next)
358 node->handler(irq, node->dev_id, fp);
359 if (!node) return;
360 local_save_flags(flags);
361 local_irq_restore((flags & ~0x0700) | (fp->sr & 0x0700));
362 /* if slow handlers exists, serve them now */
363 slow_nodes = node;
364 for (; node; node = node->next) {
365 node->handler(irq, node->dev_id, fp);
366 }
367}
368
369/*
370 * mac_enable_irq - enable an interrupt source
371 * mac_disable_irq - disable an interrupt source
372 * mac_clear_irq - clears a pending interrupt
373 * mac_pending_irq - Returns the pending status of an IRQ (nonzero = pending)
374 *
375 * These routines are just dispatchers to the VIA/OSS/PSC routines.
376 */
377
378void mac_enable_irq (unsigned int irq)
379{
380 int irq_src = IRQ_SRC(irq);
381
382 switch(irq_src) {
383 case 1: via_irq_enable(irq);
384 break;
385 case 2:
386 case 7: if (oss_present) {
387 oss_irq_enable(irq);
388 } else {
389 via_irq_enable(irq);
390 }
391 break;
392 case 3:
393 case 4:
394 case 5:
395 case 6: if (psc_present) {
396 psc_irq_enable(irq);
397 } else if (oss_present) {
398 oss_irq_enable(irq);
399 } else if (irq_src == 4) {
400 scc_irq_enable(irq);
401 }
402 break;
403 case 8: if (baboon_present) {
404 baboon_irq_enable(irq);
405 }
406 break;
407 }
408}
409
410void mac_disable_irq (unsigned int irq)
411{
412 int irq_src = IRQ_SRC(irq);
413
414 switch(irq_src) {
415 case 1: via_irq_disable(irq);
416 break;
417 case 2:
418 case 7: if (oss_present) {
419 oss_irq_disable(irq);
420 } else {
421 via_irq_disable(irq);
422 }
423 break;
424 case 3:
425 case 4:
426 case 5:
427 case 6: if (psc_present) {
428 psc_irq_disable(irq);
429 } else if (oss_present) {
430 oss_irq_disable(irq);
431 } else if (irq_src == 4) {
432 scc_irq_disable(irq);
433 }
434 break;
435 case 8: if (baboon_present) {
436 baboon_irq_disable(irq);
437 }
438 break;
439 }
440}
441
442void mac_clear_irq( unsigned int irq )
443{
444 switch(IRQ_SRC(irq)) {
445 case 1: via_irq_clear(irq);
446 break;
447 case 2:
448 case 7: if (oss_present) {
449 oss_irq_clear(irq);
450 } else {
451 via_irq_clear(irq);
452 }
453 break;
454 case 3:
455 case 4:
456 case 5:
457 case 6: if (psc_present) {
458 psc_irq_clear(irq);
459 } else if (oss_present) {
460 oss_irq_clear(irq);
461 }
462 break;
463 case 8: if (baboon_present) {
464 baboon_irq_clear(irq);
465 }
466 break;
467 }
468}
469
470int mac_irq_pending( unsigned int irq )
471{
472 switch(IRQ_SRC(irq)) {
473 case 1: return via_irq_pending(irq);
474 case 2:
475 case 7: if (oss_present) {
476 return oss_irq_pending(irq);
477 } else {
478 return via_irq_pending(irq);
479 }
480 case 3:
481 case 4:
482 case 5:
483 case 6: if (psc_present) {
484 return psc_irq_pending(irq);
485 } else if (oss_present) {
486 return oss_irq_pending(irq);
487 }
488 }
489 return 0;
490}
491
492/*
493 * Add an interrupt service routine to an interrupt source.
494 * Returns 0 on success.
495 *
496 * FIXME: You can register interrupts on nonexistent source (ie PSC4 on a
497 * non-PSC machine). We should return -EINVAL in those cases.
498 */
499
500int mac_request_irq(unsigned int irq,
501 irqreturn_t (*handler)(int, void *, struct pt_regs *),
502 unsigned long flags, const char *devname, void *dev_id)
503{
504 irq_node_t *node;
505
506#ifdef DEBUG_MACINTS
507 printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname);
508#endif
509
510 if (irq < VIA1_SOURCE_BASE) {
511 return cpu_request_irq(irq, handler, flags, devname, dev_id);
512 }
513
514 if (irq >= NUM_MAC_SOURCES) {
515 printk ("%s: unknown irq %d requested by %s\n",
516 __FUNCTION__, irq, devname);
517 }
518
519 /* Get a node and stick it onto the right list */
520
521 if (!(node = new_irq_node())) return -ENOMEM;
522
523 node->handler = handler;
524 node->flags = flags;
525 node->dev_id = dev_id;
526 node->devname = devname;
527 node->next = NULL;
528 mac_insert_irq(&mac_irq_list[irq], node);
529
530 /* Now enable the IRQ source */
531
532 mac_enable_irq(irq);
533
534 return 0;
535}
536
537/*
538 * Removes an interrupt service routine from an interrupt source.
539 */
540
541void mac_free_irq(unsigned int irq, void *dev_id)
542{
543#ifdef DEBUG_MACINTS
544 printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id);
545#endif
546
547 if (irq < VIA1_SOURCE_BASE) {
548 cpu_free_irq(irq, dev_id);
549 return;
550 }
551
552 if (irq >= NUM_MAC_SOURCES) {
553 printk ("%s: unknown irq %d freed\n",
554 __FUNCTION__, irq);
555 return;
556 }
557
558 mac_delete_irq(&mac_irq_list[irq], dev_id);
559
560 /* If the list for this interrupt is */
561 /* empty then disable the source. */
562
563 if (!mac_irq_list[irq]) {
564 mac_disable_irq(irq);
565 }
566}
567
568/*
569 * Generate a pretty listing for /proc/interrupts
570 *
571 * By the time we're called the autovector interrupt list has already been
572 * generated, so we just need to do the machspec interrupts.
573 *
574 * 990506 (jmt) - rewritten to handle chained machspec interrupt handlers.
575 * Also removed display of num_spurious it is already
576 * displayed for us as autovector irq 0.
577 */
578
579int show_mac_interrupts(struct seq_file *p, void *v)
580{
581 int i;
582 irq_node_t *node;
583 char *base;
584
585 /* Don't do Nubus interrupts in this loop; we do them separately */
586 /* below so that we can print slot numbers instead of IRQ numbers */
587
588 for (i = VIA1_SOURCE_BASE ; i < NUM_MAC_SOURCES ; ++i) {
589
590 /* Nonexistant interrupt or nothing registered; skip it. */
591
592 if ((node = mac_irq_list[i]) == NULL) continue;
593 if (node->flags & IRQ_FLG_STD) continue;
594
595 base = "";
596 switch(IRQ_SRC(i)) {
597 case 1: base = "via1";
598 break;
599 case 2: if (oss_present) {
600 base = "oss";
601 } else {
602 base = "via2";
603 }
604 break;
605 case 3:
606 case 4:
607 case 5:
608 case 6: if (psc_present) {
609 base = "psc";
610 } else if (oss_present) {
611 base = "oss";
612 } else {
613 if (IRQ_SRC(i) == 4) base = "scc";
614 }
615 break;
616 case 7: base = "nbus";
617 break;
618 case 8: base = "bbn";
619 break;
620 }
621 seq_printf(p, "%4s %2d: %10u ", base, i, kstat_cpu(0).irqs[i]);
622
623 do {
624 if (node->flags & IRQ_FLG_FAST) {
625 seq_puts(p, "F ");
626 } else if (node->flags & IRQ_FLG_SLOW) {
627 seq_puts(p, "S ");
628 } else {
629 seq_puts(p, " ");
630 }
631 seq_printf(p, "%s\n", node->devname);
632 if ((node = node->next)) {
633 seq_puts(p, " ");
634 }
635 } while(node);
636
637 }
638 return 0;
639}
640
641void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
642{
643#ifdef DEBUG_SPURIOUS
644 printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
645#endif
646}
647
648static int num_debug[8];
649
650irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
651{
652 if (num_debug[irq] < 10) {
653 printk("DEBUG: Unexpected IRQ %d\n", irq);
654 num_debug[irq]++;
655 }
656 return IRQ_HANDLED;
657}
658
659static int in_nmi;
660static volatile int nmi_hold;
661
662irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
663{
664 int i;
665 /*
666 * generate debug output on NMI switch if 'debug' kernel option given
667 * (only works with Penguin!)
668 */
669
670 in_nmi++;
671 for (i=0; i<100; i++)
672 udelay(1000);
673
674 if (in_nmi == 1) {
675 nmi_hold = 1;
676 printk("... pausing, press NMI to resume ...");
677 } else {
678 printk(" ok!\n");
679 nmi_hold = 0;
680 }
681
682 barrier();
683
684 while (nmi_hold == 1)
685 udelay(1000);
686
687 if ( console_loglevel >= 8 ) {
688#if 0
689 show_state();
690 printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
691 printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
692 fp->d0, fp->d1, fp->d2, fp->d3);
693 printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
694 fp->d4, fp->d5, fp->a0, fp->a1);
695
696 if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
697 printk("Corrupted stack page\n");
698 printk("Process %s (pid: %d, stackpage=%08lx)\n",
699 current->comm, current->pid, current->kernel_stack_page);
700 if (intr_count == 1)
701 dump_stack((struct frame *)fp);
702#else
703 /* printk("NMI "); */
704#endif
705 }
706 in_nmi--;
707 return IRQ_HANDLED;
708}
709
710/*
711 * Simple routines for masking and unmasking
712 * SCC interrupts in cases where this can't be
713 * done in hardware (only the PSC can do that.)
714 */
715
716static void scc_irq_enable(int irq) {
717 int irq_idx = IRQ_IDX(irq);
718
719 scc_mask |= (1 << irq_idx);
720}
721
722static void scc_irq_disable(int irq) {
723 int irq_idx = IRQ_IDX(irq);
724
725 scc_mask &= ~(1 << irq_idx);
726}
727
728/*
729 * SCC master interrupt handler. We have to do a bit of magic here
730 * to figure out what channel gave us the interrupt; putting this
731 * here is cleaner than hacking it into drivers/char/macserial.c.
732 */
733
734void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs)
735{
736 volatile unsigned char *scc = (unsigned char *) mac_bi_data.sccbase + 2;
737 unsigned char reg;
738 unsigned long flags;
739
740 /* Read RR3 from the chip. Always do this on channel A */
741 /* This must be an atomic operation so disable irqs. */
742
743 local_irq_save(flags);
744 *scc = 3;
745 reg = *scc;
746 local_irq_restore(flags);
747
748 /* Now dispatch. Bits 0-2 are for channel B and */
749 /* bits 3-5 are for channel A. We can safely */
750 /* ignore the remaining bits here. */
751 /* */
752 /* Note that we're ignoring scc_mask for now. */
753 /* If we actually mask the ints then we tend to */
754 /* get hammered by very persistent SCC irqs, */
755 /* and since they're autovector interrupts they */
756 /* pretty much kill the system. */
757
758 if (reg & 0x38) mac_do_irq_list(IRQ_SCCA, regs);
759 if (reg & 0x07) mac_do_irq_list(IRQ_SCCB, regs);
760}
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
new file mode 100644
index 000000000000..5b80d7cd954a
--- /dev/null
+++ b/arch/m68k/mac/misc.c
@@ -0,0 +1,651 @@
1/*
2 * Miscellaneous Mac68K-specific stuff
3 */
4
5#include <linux/config.h>
6#include <linux/types.h>
7#include <linux/errno.h>
8#include <linux/miscdevice.h>
9#include <linux/kernel.h>
10#include <linux/delay.h>
11#include <linux/sched.h>
12#include <linux/slab.h>
13#include <linux/time.h>
14#include <linux/rtc.h>
15#include <linux/mm.h>
16
17#include <linux/adb.h>
18#include <linux/cuda.h>
19#include <linux/pmu.h>
20
21#include <asm/uaccess.h>
22#include <asm/io.h>
23#include <asm/rtc.h>
24#include <asm/system.h>
25#include <asm/segment.h>
26#include <asm/setup.h>
27#include <asm/macintosh.h>
28#include <asm/mac_via.h>
29#include <asm/mac_oss.h>
30
31#define BOOTINFO_COMPAT_1_0
32#include <asm/bootinfo.h>
33#include <asm/machdep.h>
34
35/* Offset between Unix time (1970-based) and Mac time (1904-based) */
36
37#define RTC_OFFSET 2082844800
38
39extern struct mac_booter_data mac_bi_data;
40static void (*rom_reset)(void);
41
42#ifdef CONFIG_ADB
43/*
44 * Return the current time as the number of seconds since January 1, 1904.
45 */
46
47static long adb_read_time(void)
48{
49 volatile struct adb_request req;
50 long time;
51
52 adb_request((struct adb_request *) &req, NULL,
53 ADBREQ_RAW|ADBREQ_SYNC,
54 2, CUDA_PACKET, CUDA_GET_TIME);
55
56 time = (req.reply[3] << 24) | (req.reply[4] << 16)
57 | (req.reply[5] << 8) | req.reply[6];
58 return time - RTC_OFFSET;
59}
60
61/*
62 * Set the current system time
63 */
64
65static void adb_write_time(long data)
66{
67 volatile struct adb_request req;
68
69 data += RTC_OFFSET;
70
71 adb_request((struct adb_request *) &req, NULL,
72 ADBREQ_RAW|ADBREQ_SYNC,
73 6, CUDA_PACKET, CUDA_SET_TIME,
74 (data >> 24) & 0xFF, (data >> 16) & 0xFF,
75 (data >> 8) & 0xFF, data & 0xFF);
76}
77
78/*
79 * Get a byte from the NVRAM
80 */
81
82static __u8 adb_read_pram(int offset)
83{
84 volatile struct adb_request req;
85
86 adb_request((struct adb_request *) &req, NULL,
87 ADBREQ_RAW|ADBREQ_SYNC,
88 4, CUDA_PACKET, CUDA_GET_PRAM,
89 (offset >> 8) & 0xFF, offset & 0xFF);
90 return req.reply[3];
91}
92
93/*
94 * Write a byte to the NVRAM
95 */
96
97static void adb_write_pram(int offset, __u8 data)
98{
99 volatile struct adb_request req;
100
101 adb_request((struct adb_request *) &req, NULL,
102 ADBREQ_RAW|ADBREQ_SYNC,
103 5, CUDA_PACKET, CUDA_SET_PRAM,
104 (offset >> 8) & 0xFF, offset & 0xFF,
105 data);
106}
107#endif /* CONFIG_ADB */
108
109/*
110 * VIA PRAM/RTC access routines
111 *
112 * Must be called with interrupts disabled and
113 * the RTC should be enabled.
114 */
115
116static __u8 via_pram_readbyte(void)
117{
118 int i,reg;
119 __u8 data;
120
121 reg = via1[vBufB] & ~VIA1B_vRTCClk;
122
123 /* Set the RTC data line to be an input. */
124
125 via1[vDirB] &= ~VIA1B_vRTCData;
126
127 /* The bits of the byte come out in MSB order */
128
129 data = 0;
130 for (i = 0 ; i < 8 ; i++) {
131 via1[vBufB] = reg;
132 via1[vBufB] = reg | VIA1B_vRTCClk;
133 data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData);
134 }
135
136 /* Return RTC data line to output state */
137
138 via1[vDirB] |= VIA1B_vRTCData;
139
140 return data;
141}
142
143static void via_pram_writebyte(__u8 data)
144{
145 int i,reg,bit;
146
147 reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData);
148
149 /* The bits of the byte go in in MSB order */
150
151 for (i = 0 ; i < 8 ; i++) {
152 bit = data & 0x80? 1 : 0;
153 data <<= 1;
154 via1[vBufB] = reg | bit;
155 via1[vBufB] = reg | bit | VIA1B_vRTCClk;
156 }
157}
158
159/*
160 * Execute a VIA PRAM/RTC command. For read commands
161 * data should point to a one-byte buffer for the
162 * resulting data. For write commands it should point
163 * to the data byte to for the command.
164 *
165 * This function disables all interrupts while running.
166 */
167
168static void via_pram_command(int command, __u8 *data)
169{
170 unsigned long flags;
171 int is_read;
172
173 local_irq_save(flags);
174
175 /* Enable the RTC and make sure the strobe line is high */
176
177 via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb;
178
179 if (command & 0xFF00) { /* extended (two-byte) command */
180 via_pram_writebyte((command & 0xFF00) >> 8);
181 via_pram_writebyte(command & 0xFF);
182 is_read = command & 0x8000;
183 } else { /* one-byte command */
184 via_pram_writebyte(command);
185 is_read = command & 0x80;
186 }
187 if (is_read) {
188 *data = via_pram_readbyte();
189 } else {
190 via_pram_writebyte(*data);
191 }
192
193 /* All done, disable the RTC */
194
195 via1[vBufB] |= VIA1B_vRTCEnb;
196
197 local_irq_restore(flags);
198}
199
200static __u8 via_read_pram(int offset)
201{
202 return 0;
203}
204
205static void via_write_pram(int offset, __u8 data)
206{
207}
208
209/*
210 * Return the current time in seconds since January 1, 1904.
211 *
212 * This only works on machines with the VIA-based PRAM/RTC, which
213 * is basically any machine with Mac II-style ADB.
214 */
215
216static long via_read_time(void)
217{
218 union {
219 __u8 cdata[4];
220 long idata;
221 } result, last_result;
222 int ct;
223
224 /*
225 * The NetBSD guys say to loop until you get the same reading
226 * twice in a row.
227 */
228
229 ct = 0;
230 do {
231 if (++ct > 10) {
232 printk("via_read_time: couldn't get valid time, "
233 "last read = 0x%08lx and 0x%08lx\n",
234 last_result.idata, result.idata);
235 break;
236 }
237
238 last_result.idata = result.idata;
239 result.idata = 0;
240
241 via_pram_command(0x81, &result.cdata[3]);
242 via_pram_command(0x85, &result.cdata[2]);
243 via_pram_command(0x89, &result.cdata[1]);
244 via_pram_command(0x8D, &result.cdata[0]);
245 } while (result.idata != last_result.idata);
246
247 return result.idata - RTC_OFFSET;
248}
249
250/*
251 * Set the current time to a number of seconds since January 1, 1904.
252 *
253 * This only works on machines with the VIA-based PRAM/RTC, which
254 * is basically any machine with Mac II-style ADB.
255 */
256
257static void via_write_time(long time)
258{
259 union {
260 __u8 cdata[4];
261 long idata;
262 } data;
263 __u8 temp;
264
265 /* Clear the write protect bit */
266
267 temp = 0x55;
268 via_pram_command(0x35, &temp);
269
270 data.idata = time + RTC_OFFSET;
271 via_pram_command(0x01, &data.cdata[3]);
272 via_pram_command(0x05, &data.cdata[2]);
273 via_pram_command(0x09, &data.cdata[1]);
274 via_pram_command(0x0D, &data.cdata[0]);
275
276 /* Set the write protect bit */
277
278 temp = 0xD5;
279 via_pram_command(0x35, &temp);
280}
281
282static void via_shutdown(void)
283{
284 if (rbv_present) {
285 via2[rBufB] &= ~0x04;
286 } else {
287 /* Direction of vDirB is output */
288 via2[vDirB] |= 0x04;
289 /* Send a value of 0 on that line */
290 via2[vBufB] &= ~0x04;
291 mdelay(1000);
292 }
293}
294
295/*
296 * FIXME: not sure how this is supposed to work exactly...
297 */
298
299static void oss_shutdown(void)
300{
301 oss->rom_ctrl = OSS_POWEROFF;
302}
303
304#ifdef CONFIG_ADB_CUDA
305
306static void cuda_restart(void)
307{
308 adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
309 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
310}
311
312static void cuda_shutdown(void)
313{
314 adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
315 2, CUDA_PACKET, CUDA_POWERDOWN);
316}
317
318#endif /* CONFIG_ADB_CUDA */
319
320#ifdef CONFIG_ADB_PMU
321
322void pmu_restart(void)
323{
324 adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
325 3, PMU_PACKET, PMU_SET_INTR_MASK,
326 PMU_INT_ADB|PMU_INT_TICK);
327
328 adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
329 2, PMU_PACKET, PMU_RESET);
330}
331
332void pmu_shutdown(void)
333{
334 adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
335 3, PMU_PACKET, PMU_SET_INTR_MASK,
336 PMU_INT_ADB|PMU_INT_TICK);
337
338 adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
339 6, PMU_PACKET, PMU_SHUTDOWN,
340 'M', 'A', 'T', 'T');
341}
342
343#endif /* CONFIG_ADB_PMU */
344
345/*
346 *-------------------------------------------------------------------
347 * Below this point are the generic routines; they'll dispatch to the
348 * correct routine for the hardware on which we're running.
349 *-------------------------------------------------------------------
350 */
351
352void mac_pram_read(int offset, __u8 *buffer, int len)
353{
354 __u8 (*func)(int) = NULL;
355 int i;
356
357 if (macintosh_config->adb_type == MAC_ADB_IISI ||
358 macintosh_config->adb_type == MAC_ADB_PB1 ||
359 macintosh_config->adb_type == MAC_ADB_PB2 ||
360 macintosh_config->adb_type == MAC_ADB_CUDA) {
361#ifdef CONFIG_ADB
362 func = adb_read_pram;
363#else
364 return;
365#endif
366 } else {
367 func = via_read_pram;
368 }
369 for (i = 0 ; i < len ; i++) {
370 buffer[i] = (*func)(offset++);
371 }
372}
373
374void mac_pram_write(int offset, __u8 *buffer, int len)
375{
376 void (*func)(int, __u8) = NULL;
377 int i;
378
379 if (macintosh_config->adb_type == MAC_ADB_IISI ||
380 macintosh_config->adb_type == MAC_ADB_PB1 ||
381 macintosh_config->adb_type == MAC_ADB_PB2 ||
382 macintosh_config->adb_type == MAC_ADB_CUDA) {
383#ifdef CONFIG_ADB
384 func = adb_write_pram;
385#else
386 return;
387#endif
388 } else {
389 func = via_write_pram;
390 }
391 for (i = 0 ; i < len ; i++) {
392 (*func)(offset++, buffer[i]);
393 }
394}
395
396void mac_poweroff(void)
397{
398 /*
399 * MAC_ADB_IISI may need to be moved up here if it doesn't actually
400 * work using the ADB packet method. --David Kilzer
401 */
402
403 if (oss_present) {
404 oss_shutdown();
405 } else if (macintosh_config->adb_type == MAC_ADB_II) {
406 via_shutdown();
407#ifdef CONFIG_ADB_CUDA
408 } else if (macintosh_config->adb_type == MAC_ADB_CUDA) {
409 cuda_shutdown();
410#endif
411#ifdef CONFIG_ADB_PMU
412 } else if (macintosh_config->adb_type == MAC_ADB_PB1
413 || macintosh_config->adb_type == MAC_ADB_PB2) {
414 pmu_shutdown();
415#endif
416 }
417 local_irq_enable();
418 printk("It is now safe to turn off your Macintosh.\n");
419 while(1);
420}
421
422void mac_reset(void)
423{
424 if (macintosh_config->adb_type == MAC_ADB_II) {
425 unsigned long flags;
426
427 /* need ROMBASE in booter */
428 /* indeed, plus need to MAP THE ROM !! */
429
430 if (mac_bi_data.rombase == 0)
431 mac_bi_data.rombase = 0x40800000;
432
433 /* works on some */
434 rom_reset = (void *) (mac_bi_data.rombase + 0xa);
435
436 if (macintosh_config->ident == MAC_MODEL_SE30) {
437 /*
438 * MSch: Machines known to crash on ROM reset ...
439 */
440 } else {
441 local_irq_save(flags);
442
443 rom_reset();
444
445 local_irq_restore(flags);
446 }
447#ifdef CONFIG_ADB_CUDA
448 } else if (macintosh_config->adb_type == MAC_ADB_CUDA) {
449 cuda_restart();
450#endif
451#ifdef CONFIG_ADB_PMU
452 } else if (macintosh_config->adb_type == MAC_ADB_PB1
453 || macintosh_config->adb_type == MAC_ADB_PB2) {
454 pmu_restart();
455#endif
456 } else if (CPU_IS_030) {
457
458 /* 030-specific reset routine. The idea is general, but the
459 * specific registers to reset are '030-specific. Until I
460 * have a non-030 machine, I can't test anything else.
461 * -- C. Scott Ananian <cananian@alumni.princeton.edu>
462 */
463
464 unsigned long rombase = 0x40000000;
465
466 /* make a 1-to-1 mapping, using the transparent tran. reg. */
467 unsigned long virt = (unsigned long) mac_reset;
468 unsigned long phys = virt_to_phys(mac_reset);
469 unsigned long offset = phys-virt;
470 local_irq_disable(); /* lets not screw this up, ok? */
471 __asm__ __volatile__(".chip 68030\n\t"
472 "pmove %0,%/tt0\n\t"
473 ".chip 68k"
474 : : "m" ((phys&0xFF000000)|0x8777));
475 /* Now jump to physical address so we can disable MMU */
476 __asm__ __volatile__(
477 ".chip 68030\n\t"
478 "lea %/pc@(1f),%/a0\n\t"
479 "addl %0,%/a0\n\t"/* fixup target address and stack ptr */
480 "addl %0,%/sp\n\t"
481 "pflusha\n\t"
482 "jmp %/a0@\n\t" /* jump into physical memory */
483 "0:.long 0\n\t" /* a constant zero. */
484 /* OK. Now reset everything and jump to reset vector. */
485 "1:\n\t"
486 "lea %/pc@(0b),%/a0\n\t"
487 "pmove %/a0@, %/tc\n\t" /* disable mmu */
488 "pmove %/a0@, %/tt0\n\t" /* disable tt0 */
489 "pmove %/a0@, %/tt1\n\t" /* disable tt1 */
490 "movel #0, %/a0\n\t"
491 "movec %/a0, %/vbr\n\t" /* clear vector base register */
492 "movec %/a0, %/cacr\n\t" /* disable caches */
493 "movel #0x0808,%/a0\n\t"
494 "movec %/a0, %/cacr\n\t" /* flush i&d caches */
495 "movew #0x2700,%/sr\n\t" /* set up status register */
496 "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */
497 "movec %/a0, %/isp\n\t"
498 "movel %1@(0x4),%/a0\n\t" /* load reset vector */
499 "reset\n\t" /* reset external devices */
500 "jmp %/a0@\n\t" /* jump to the reset vector */
501 ".chip 68k"
502 : : "r" (offset), "a" (rombase) : "a0");
503 }
504
505 /* should never get here */
506 local_irq_enable();
507 printk ("Restart failed. Please restart manually.\n");
508 while(1);
509}
510
511/*
512 * This function translates seconds since 1970 into a proper date.
513 *
514 * Algorithm cribbed from glibc2.1, __offtime().
515 */
516#define SECS_PER_MINUTE (60)
517#define SECS_PER_HOUR (SECS_PER_MINUTE * 60)
518#define SECS_PER_DAY (SECS_PER_HOUR * 24)
519
520static void unmktime(unsigned long time, long offset,
521 int *yearp, int *monp, int *dayp,
522 int *hourp, int *minp, int *secp)
523{
524 /* How many days come before each month (0-12). */
525 static const unsigned short int __mon_yday[2][13] =
526 {
527 /* Normal years. */
528 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
529 /* Leap years. */
530 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
531 };
532 long int days, rem, y, wday, yday;
533 const unsigned short int *ip;
534
535 days = time / SECS_PER_DAY;
536 rem = time % SECS_PER_DAY;
537 rem += offset;
538 while (rem < 0) {
539 rem += SECS_PER_DAY;
540 --days;
541 }
542 while (rem >= SECS_PER_DAY) {
543 rem -= SECS_PER_DAY;
544 ++days;
545 }
546 *hourp = rem / SECS_PER_HOUR;
547 rem %= SECS_PER_HOUR;
548 *minp = rem / SECS_PER_MINUTE;
549 *secp = rem % SECS_PER_MINUTE;
550 /* January 1, 1970 was a Thursday. */
551 wday = (4 + days) % 7; /* Day in the week. Not currently used */
552 if (wday < 0) wday += 7;
553 y = 1970;
554
555#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
556#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
557#define __isleap(year) \
558 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
559
560 while (days < 0 || days >= (__isleap (y) ? 366 : 365))
561 {
562 /* Guess a corrected year, assuming 365 days per year. */
563 long int yg = y + days / 365 - (days % 365 < 0);
564
565 /* Adjust DAYS and Y to match the guessed year. */
566 days -= ((yg - y) * 365
567 + LEAPS_THRU_END_OF (yg - 1)
568 - LEAPS_THRU_END_OF (y - 1));
569 y = yg;
570 }
571 *yearp = y - 1900;
572 yday = days; /* day in the year. Not currently used. */
573 ip = __mon_yday[__isleap(y)];
574 for (y = 11; days < (long int) ip[y]; --y)
575 continue;
576 days -= ip[y];
577 *monp = y;
578 *dayp = days + 1; /* day in the month */
579 return;
580}
581
582/*
583 * Read/write the hardware clock.
584 */
585
586int mac_hwclk(int op, struct rtc_time *t)
587{
588 unsigned long now;
589
590 if (!op) { /* read */
591 if (macintosh_config->adb_type == MAC_ADB_II) {
592 now = via_read_time();
593 } else
594#ifdef CONFIG_ADB
595 if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
596 (macintosh_config->adb_type == MAC_ADB_PB1) ||
597 (macintosh_config->adb_type == MAC_ADB_PB2) ||
598 (macintosh_config->adb_type == MAC_ADB_CUDA)) {
599 now = adb_read_time();
600 } else
601#endif
602 if (macintosh_config->adb_type == MAC_ADB_IOP) {
603 now = via_read_time();
604 } else {
605 now = 0;
606 }
607
608 t->tm_wday = 0;
609 unmktime(now, 0,
610 &t->tm_year, &t->tm_mon, &t->tm_mday,
611 &t->tm_hour, &t->tm_min, &t->tm_sec);
612 printk("mac_hwclk: read %04d-%02d-%-2d %02d:%02d:%02d\n",
613 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
614 } else { /* write */
615 printk("mac_hwclk: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n",
616 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
617
618#if 0 /* it trashes my rtc */
619 now = mktime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
620 t->tm_hour, t->tm_min, t->tm_sec);
621
622 if (macintosh_config->adb_type == MAC_ADB_II) {
623 via_write_time(now);
624 } else if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
625 (macintosh_config->adb_type == MAC_ADB_PB1) ||
626 (macintosh_config->adb_type == MAC_ADB_PB2) ||
627 (macintosh_config->adb_type == MAC_ADB_CUDA)) {
628 adb_write_time(now);
629 } else if (macintosh_config->adb_type == MAC_ADB_IOP) {
630 via_write_time(now);
631 }
632#endif
633 }
634 return 0;
635}
636
637/*
638 * Set minutes/seconds in the hardware clock
639 */
640
641int mac_set_clock_mmss (unsigned long nowtime)
642{
643 struct rtc_time now;
644
645 mac_hwclk(0, &now);
646 now.tm_sec = nowtime % 60;
647 now.tm_min = (nowtime / 60) % 60;
648 mac_hwclk(1, &now);
649
650 return 0;
651}
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
new file mode 100644
index 000000000000..333547692724
--- /dev/null
+++ b/arch/m68k/mac/oss.c
@@ -0,0 +1,301 @@
1/*
2 * OSS handling
3 * Written by Joshua M. Thompson (funaho@jurai.org)
4 *
5 *
6 * This chip is used in the IIfx in place of VIA #2. It acts like a fancy
7 * VIA chip with prorammable interrupt levels.
8 *
9 * 990502 (jmt) - Major rewrite for new interrupt architecture as well as some
10 * recent insights into OSS operational details.
11 * 990610 (jmt) - Now taking fulll advantage of the OSS. Interrupts are mapped
12 * to mostly match the A/UX interrupt scheme supported on the
13 * VIA side. Also added support for enabling the ISM irq again
14 * since we now have a functional IOP manager.
15 */
16
17#include <linux/types.h>
18#include <linux/kernel.h>
19#include <linux/mm.h>
20#include <linux/delay.h>
21#include <linux/init.h>
22
23#include <asm/bootinfo.h>
24#include <asm/machw.h>
25#include <asm/macintosh.h>
26#include <asm/macints.h>
27#include <asm/mac_via.h>
28#include <asm/mac_oss.h>
29
30int oss_present;
31volatile struct mac_oss *oss;
32
33irqreturn_t oss_irq(int, void *, struct pt_regs *);
34irqreturn_t oss_nubus_irq(int, void *, struct pt_regs *);
35
36extern irqreturn_t via1_irq(int, void *, struct pt_regs *);
37extern irqreturn_t mac_scc_dispatch(int, void *, struct pt_regs *);
38
39/*
40 * Initialize the OSS
41 *
42 * The OSS "detection" code is actually in via_init() which is always called
43 * before us. Thus we can count on oss_present being valid on entry.
44 */
45
46void __init oss_init(void)
47{
48 int i;
49
50 if (!oss_present) return;
51
52 oss = (struct mac_oss *) OSS_BASE;
53
54 /* Disable all interrupts. Unlike a VIA it looks like we */
55 /* do this by setting the source's interrupt level to zero. */
56
57 for (i = 0; i <= OSS_NUM_SOURCES; i++) {
58 oss->irq_level[i] = OSS_IRQLEV_DISABLED;
59 }
60 /* If we disable VIA1 here, we never really handle it... */
61 oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1;
62}
63
64/*
65 * Register the OSS and NuBus interrupt dispatchers.
66 */
67
68void __init oss_register_interrupts(void)
69{
70 cpu_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
71 "scsi", (void *) oss);
72 cpu_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
73 "scc", mac_scc_dispatch);
74 cpu_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
75 "nubus", (void *) oss);
76 cpu_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
77 "sound", (void *) oss);
78 cpu_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
79 "via1", (void *) via1);
80}
81
82/*
83 * Initialize OSS for Nubus access
84 */
85
86void __init oss_nubus_init(void)
87{
88}
89
90/*
91 * Handle miscellaneous OSS interrupts. Right now that's just sound
92 * and SCSI; everything else is routed to its own autovector IRQ.
93 */
94
95irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs)
96{
97 int events;
98
99 events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI);
100 if (!events)
101 return IRQ_NONE;
102
103#ifdef DEBUG_IRQS
104 if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) {
105 printk("oss_irq: irq %d events = 0x%04X\n", irq,
106 (int) oss->irq_pending);
107 }
108#endif
109 /* FIXME: how do you clear a pending IRQ? */
110
111 if (events & OSS_IP_SOUND) {
112 /* FIXME: call sound handler */
113 oss->irq_pending &= ~OSS_IP_SOUND;
114 } else if (events & OSS_IP_SCSI) {
115 oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
116 mac_do_irq_list(IRQ_MAC_SCSI, regs);
117 oss->irq_pending &= ~OSS_IP_SCSI;
118 oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
119 } else {
120 /* FIXME: error check here? */
121 }
122 return IRQ_HANDLED;
123}
124
125/*
126 * Nubus IRQ handler, OSS style
127 *
128 * Unlike the VIA/RBV this is on its own autovector interrupt level.
129 */
130
131irqreturn_t oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
132{
133 int events, irq_bit, i;
134
135 events = oss->irq_pending & OSS_IP_NUBUS;
136 if (!events)
137 return IRQ_NONE;
138
139#ifdef DEBUG_NUBUS_INT
140 if (console_loglevel > 7) {
141 printk("oss_nubus_irq: events = 0x%04X\n", events);
142 }
143#endif
144 /* There are only six slots on the OSS, not seven */
145
146 for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
147 if (events & irq_bit) {
148 oss->irq_level[i] = OSS_IRQLEV_DISABLED;
149 mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
150 oss->irq_pending &= ~irq_bit;
151 oss->irq_level[i] = OSS_IRQLEV_NUBUS;
152 }
153 }
154 return IRQ_HANDLED;
155}
156
157/*
158 * Enable an OSS interrupt
159 *
160 * It looks messy but it's rather straightforward. The switch() statement
161 * just maps the machspec interrupt numbers to the right OSS interrupt
162 * source (if the OSS handles that interrupt) and then sets the interrupt
163 * level for that source to nonzero, thus enabling the interrupt.
164 */
165
166void oss_irq_enable(int irq) {
167#ifdef DEBUG_IRQUSE
168 printk("oss_irq_enable(%d)\n", irq);
169#endif
170 switch(irq) {
171 case IRQ_SCC:
172 case IRQ_SCCA:
173 case IRQ_SCCB:
174 oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_IOPSCC;
175 break;
176 case IRQ_MAC_ADB:
177 oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_IOPISM;
178 break;
179 case IRQ_MAC_SCSI:
180 oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
181 break;
182 case IRQ_NUBUS_9:
183 case IRQ_NUBUS_A:
184 case IRQ_NUBUS_B:
185 case IRQ_NUBUS_C:
186 case IRQ_NUBUS_D:
187 case IRQ_NUBUS_E:
188 irq -= NUBUS_SOURCE_BASE;
189 oss->irq_level[irq] = OSS_IRQLEV_NUBUS;
190 break;
191#ifdef DEBUG_IRQUSE
192 default:
193 printk("%s unknown irq %d\n",__FUNCTION__, irq);
194 break;
195#endif
196 }
197}
198
199/*
200 * Disable an OSS interrupt
201 *
202 * Same as above except we set the source's interrupt level to zero,
203 * to disable the interrupt.
204 */
205
206void oss_irq_disable(int irq) {
207#ifdef DEBUG_IRQUSE
208 printk("oss_irq_disable(%d)\n", irq);
209#endif
210 switch(irq) {
211 case IRQ_SCC:
212 case IRQ_SCCA:
213 case IRQ_SCCB:
214 oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_DISABLED;
215 break;
216 case IRQ_MAC_ADB:
217 oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_DISABLED;
218 break;
219 case IRQ_MAC_SCSI:
220 oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
221 break;
222 case IRQ_NUBUS_9:
223 case IRQ_NUBUS_A:
224 case IRQ_NUBUS_B:
225 case IRQ_NUBUS_C:
226 case IRQ_NUBUS_D:
227 case IRQ_NUBUS_E:
228 irq -= NUBUS_SOURCE_BASE;
229 oss->irq_level[irq] = OSS_IRQLEV_DISABLED;
230 break;
231#ifdef DEBUG_IRQUSE
232 default:
233 printk("%s unknown irq %d\n", __FUNCTION__, irq);
234 break;
235#endif
236 }
237}
238
239/*
240 * Clear an OSS interrupt
241 *
242 * Not sure if this works or not but it's the only method I could
243 * think of based on the contents of the mac_oss structure.
244 */
245
246void oss_irq_clear(int irq) {
247 /* FIXME: how to do this on OSS? */
248 switch(irq) {
249 case IRQ_SCC:
250 case IRQ_SCCA:
251 case IRQ_SCCB:
252 oss->irq_pending &= ~OSS_IP_IOPSCC;
253 break;
254 case IRQ_MAC_ADB:
255 oss->irq_pending &= ~OSS_IP_IOPISM;
256 break;
257 case IRQ_MAC_SCSI:
258 oss->irq_pending &= ~OSS_IP_SCSI;
259 break;
260 case IRQ_NUBUS_9:
261 case IRQ_NUBUS_A:
262 case IRQ_NUBUS_B:
263 case IRQ_NUBUS_C:
264 case IRQ_NUBUS_D:
265 case IRQ_NUBUS_E:
266 irq -= NUBUS_SOURCE_BASE;
267 oss->irq_pending &= ~(1 << irq);
268 break;
269 }
270}
271
272/*
273 * Check to see if a specific OSS interrupt is pending
274 */
275
276int oss_irq_pending(int irq)
277{
278 switch(irq) {
279 case IRQ_SCC:
280 case IRQ_SCCA:
281 case IRQ_SCCB:
282 return oss->irq_pending & OSS_IP_IOPSCC;
283 break;
284 case IRQ_MAC_ADB:
285 return oss->irq_pending & OSS_IP_IOPISM;
286 break;
287 case IRQ_MAC_SCSI:
288 return oss->irq_pending & OSS_IP_SCSI;
289 break;
290 case IRQ_NUBUS_9:
291 case IRQ_NUBUS_A:
292 case IRQ_NUBUS_B:
293 case IRQ_NUBUS_C:
294 case IRQ_NUBUS_D:
295 case IRQ_NUBUS_E:
296 irq -= NUBUS_SOURCE_BASE;
297 return oss->irq_pending & (1 << irq);
298 break;
299 }
300 return 0;
301}
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
new file mode 100644
index 000000000000..e72384e43a1e
--- /dev/null
+++ b/arch/m68k/mac/psc.c
@@ -0,0 +1,197 @@
1/*
2 * Apple Peripheral System Controller (PSC)
3 *
4 * The PSC is used on the AV Macs to control IO functions not handled
5 * by the VIAs (Ethernet, DSP, SCC).
6 *
7 * TO DO:
8 *
9 * Try to figure out what's going on in pIFR5 and pIFR6. There seem to be
10 * persisant interrupt conditions in those registers and I have no idea what
11 * they are. Granted it doesn't affect since we're not enabling any interrupts
12 * on those levels at the moment, but it would be nice to know. I have a feeling
13 * they aren't actually interrupt lines but data lines (to the DSP?)
14 */
15
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/mm.h>
19#include <linux/delay.h>
20#include <linux/init.h>
21
22#include <asm/traps.h>
23#include <asm/bootinfo.h>
24#include <asm/macintosh.h>
25#include <asm/macints.h>
26#include <asm/mac_psc.h>
27
28#define DEBUG_PSC
29
30int psc_present;
31volatile __u8 *psc;
32
33irqreturn_t psc_irq(int, void *, struct pt_regs *);
34
35/*
36 * Debugging dump, used in various places to see what's going on.
37 */
38
39void psc_debug_dump(void)
40{
41 int i;
42
43 if (!psc_present) return;
44 for (i = 0x30 ; i < 0x70 ; i += 0x10) {
45 printk("PSC #%d: IFR = 0x%02X IER = 0x%02X\n",
46 i >> 4,
47 (int) psc_read_byte(pIFRbase + i),
48 (int) psc_read_byte(pIERbase + i));
49 }
50}
51
52/*
53 * Try to kill all DMA channels on the PSC. Not sure how this his
54 * supposed to work; this is code lifted from macmace.c and then
55 * expanded to cover what I think are the other 7 channels.
56 */
57
58void psc_dma_die_die_die(void)
59{
60 int i;
61
62 printk("Killing all PSC DMA channels...");
63 for (i = 0 ; i < 9 ; i++) {
64 psc_write_word(PSC_CTL_BASE + (i << 4), 0x8800);
65 psc_write_word(PSC_CTL_BASE + (i << 4), 0x1000);
66 psc_write_word(PSC_CMD_BASE + (i << 5), 0x1100);
67 psc_write_word(PSC_CMD_BASE + (i << 5) + 0x10, 0x1100);
68 }
69 printk("done!\n");
70}
71
72/*
73 * Initialize the PSC. For now this just involves shutting down all
74 * interrupt sources using the IERs.
75 */
76
77void __init psc_init(void)
78{
79 int i;
80
81 if (macintosh_config->ident != MAC_MODEL_C660
82 && macintosh_config->ident != MAC_MODEL_Q840)
83 {
84 psc = NULL;
85 psc_present = 0;
86 return;
87 }
88
89 /*
90 * The PSC is always at the same spot, but using psc
91 * keeps things consisant with the psc_xxxx functions.
92 */
93
94 psc = (void *) PSC_BASE;
95 psc_present = 1;
96
97 printk("PSC detected at %p\n", psc);
98
99 psc_dma_die_die_die();
100
101#ifdef DEBUG_PSC
102 psc_debug_dump();
103#endif
104 /*
105 * Mask and clear all possible interrupts
106 */
107
108 for (i = 0x30 ; i < 0x70 ; i += 0x10) {
109 psc_write_byte(pIERbase + i, 0x0F);
110 psc_write_byte(pIFRbase + i, 0x0F);
111 }
112}
113
114/*
115 * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
116 */
117
118void __init psc_register_interrupts(void)
119{
120 cpu_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3", (void *) 0x30);
121 cpu_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4", (void *) 0x40);
122 cpu_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5", (void *) 0x50);
123 cpu_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6", (void *) 0x60);
124}
125
126/*
127 * PSC interrupt handler. It's a lot like the VIA interrupt handler.
128 */
129
130irqreturn_t psc_irq(int irq, void *dev_id, struct pt_regs *regs)
131{
132 int pIFR = pIFRbase + ((int) dev_id);
133 int pIER = pIERbase + ((int) dev_id);
134 int base_irq;
135 int irq_bit,i;
136 unsigned char events;
137
138 base_irq = irq << 3;
139
140#ifdef DEBUG_IRQS
141 printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n",
142 irq, (int) psc_read_byte(pIFR), (int) psc_read_byte(pIER));
143#endif
144
145 events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF;
146 if (!events)
147 return IRQ_NONE;
148
149 for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
150 if (events & irq_bit) {
151 psc_write_byte(pIER, irq_bit);
152 mac_do_irq_list(base_irq + i, regs);
153 psc_write_byte(pIFR, irq_bit);
154 psc_write_byte(pIER, irq_bit | 0x80);
155 }
156 }
157 return IRQ_HANDLED;
158}
159
160void psc_irq_enable(int irq) {
161 int irq_src = IRQ_SRC(irq);
162 int irq_idx = IRQ_IDX(irq);
163 int pIER = pIERbase + (irq_src << 4);
164
165#ifdef DEBUG_IRQUSE
166 printk("psc_irq_enable(%d)\n", irq);
167#endif
168 psc_write_byte(pIER, (1 << irq_idx) | 0x80);
169}
170
171void psc_irq_disable(int irq) {
172 int irq_src = IRQ_SRC(irq);
173 int irq_idx = IRQ_IDX(irq);
174 int pIER = pIERbase + (irq_src << 4);
175
176#ifdef DEBUG_IRQUSE
177 printk("psc_irq_disable(%d)\n", irq);
178#endif
179 psc_write_byte(pIER, 1 << irq_idx);
180}
181
182void psc_irq_clear(int irq) {
183 int irq_src = IRQ_SRC(irq);
184 int irq_idx = IRQ_IDX(irq);
185 int pIFR = pIERbase + (irq_src << 4);
186
187 psc_write_byte(pIFR, 1 << irq_idx);
188}
189
190int psc_irq_pending(int irq)
191{
192 int irq_src = IRQ_SRC(irq);
193 int irq_idx = IRQ_IDX(irq);
194 int pIFR = pIERbase + (irq_src << 4);
195
196 return psc_read_byte(pIFR) & (1 << irq_idx);
197}
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
new file mode 100644
index 000000000000..cd528bf7b43f
--- /dev/null
+++ b/arch/m68k/mac/via.c
@@ -0,0 +1,619 @@
1/*
2 * 6522 Versatile Interface Adapter (VIA)
3 *
4 * There are two of these on the Mac II. Some IRQ's are vectored
5 * via them as are assorted bits and bobs - eg RTC, ADB.
6 *
7 * CSA: Motorola seems to have removed documentation on the 6522 from
8 * their web site; try
9 * http://nerini.drf.com/vectrex/other/text/chips/6522/
10 * http://www.zymurgy.net/classic/vic20/vicdet1.htm
11 * and
12 * http://193.23.168.87/mikro_laborversuche/via_iobaustein/via6522_1.html
13 * for info. A full-text web search on 6522 AND VIA will probably also
14 * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
15 *
16 * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
17 * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
18 *
19 */
20
21#include <linux/types.h>
22#include <linux/kernel.h>
23#include <linux/mm.h>
24#include <linux/delay.h>
25#include <linux/init.h>
26#include <linux/ide.h>
27
28#include <asm/traps.h>
29#include <asm/bootinfo.h>
30#include <asm/macintosh.h>
31#include <asm/macints.h>
32#include <asm/machw.h>
33#include <asm/mac_via.h>
34#include <asm/mac_psc.h>
35
36volatile __u8 *via1, *via2;
37#if 0
38/* See note in mac_via.h about how this is possibly not useful */
39volatile long *via_memory_bogon=(long *)&via_memory_bogon;
40#endif
41int rbv_present,via_alt_mapping;
42__u8 rbv_clear;
43
44/*
45 * Globals for accessing the VIA chip registers without having to
46 * check if we're hitting a real VIA or an RBV. Normally you could
47 * just hit the combined register (ie, vIER|rIER) but that seems to
48 * break on AV Macs...probably because they actually decode more than
49 * eight address bits. Why can't Apple engineers at least be
50 * _consistently_ lazy? - 1999-05-21 (jmt)
51 */
52
53static int gIER,gIFR,gBufA,gBufB;
54
55/*
56 * Timer defs.
57 */
58
59#define TICK_SIZE 10000
60#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */
61#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF)
62#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8)
63
64static int nubus_active;
65
66void via_debug_dump(void);
67irqreturn_t via1_irq(int, void *, struct pt_regs *);
68irqreturn_t via2_irq(int, void *, struct pt_regs *);
69irqreturn_t via_nubus_irq(int, void *, struct pt_regs *);
70void via_irq_enable(int irq);
71void via_irq_disable(int irq);
72void via_irq_clear(int irq);
73
74extern irqreturn_t mac_bang(int, void *, struct pt_regs *);
75extern irqreturn_t mac_scc_dispatch(int, void *, struct pt_regs *);
76extern int oss_present;
77
78/*
79 * Initialize the VIAs
80 *
81 * First we figure out where they actually _are_ as well as what type of
82 * VIA we have for VIA2 (it could be a real VIA or an RBV or even an OSS.)
83 * Then we pretty much clear them out and disable all IRQ sources.
84 *
85 * Note: the OSS is actually "detected" here and not in oss_init(). It just
86 * seems more logical to do it here since via_init() needs to know
87 * these things anyways.
88 */
89
90void __init via_init(void)
91{
92 switch(macintosh_config->via_type) {
93
94 /* IIci, IIsi, IIvx, IIvi (P6xx), LC series */
95
96 case MAC_VIA_IIci:
97 via1 = (void *) VIA1_BASE;
98 if (macintosh_config->ident == MAC_MODEL_IIFX) {
99 via2 = NULL;
100 rbv_present = 0;
101 oss_present = 1;
102 } else {
103 via2 = (void *) RBV_BASE;
104 rbv_present = 1;
105 oss_present = 0;
106 }
107 if (macintosh_config->ident == MAC_MODEL_LCIII) {
108 rbv_clear = 0x00;
109 } else {
110 /* on most RBVs (& unlike the VIAs), you */
111 /* need to set bit 7 when you write to IFR */
112 /* in order for your clear to occur. */
113 rbv_clear = 0x80;
114 }
115 gIER = rIER;
116 gIFR = rIFR;
117 gBufA = rSIFR;
118 gBufB = rBufB;
119 break;
120
121 /* Quadra and early MacIIs agree on the VIA locations */
122
123 case MAC_VIA_QUADRA:
124 case MAC_VIA_II:
125 via1 = (void *) VIA1_BASE;
126 via2 = (void *) VIA2_BASE;
127 rbv_present = 0;
128 oss_present = 0;
129 rbv_clear = 0x00;
130 gIER = vIER;
131 gIFR = vIFR;
132 gBufA = vBufA;
133 gBufB = vBufB;
134 break;
135 default:
136 panic("UNKNOWN VIA TYPE");
137 }
138
139 printk(KERN_INFO "VIA1 at %p is a 6522 or clone\n", via1);
140
141 printk(KERN_INFO "VIA2 at %p is ", via2);
142 if (rbv_present) {
143 printk(KERN_INFO "an RBV\n");
144 } else if (oss_present) {
145 printk(KERN_INFO "an OSS\n");
146 } else {
147 printk(KERN_INFO "a 6522 or clone\n");
148 }
149
150#ifdef DEBUG_VIA
151 via_debug_dump();
152#endif
153
154 /*
155 * Shut down all IRQ sources, reset the timers, and
156 * kill the timer latch on VIA1.
157 */
158
159 via1[vIER] = 0x7F;
160 via1[vIFR] = 0x7F;
161 via1[vT1LL] = 0;
162 via1[vT1LH] = 0;
163 via1[vT1CL] = 0;
164 via1[vT1CH] = 0;
165 via1[vT2CL] = 0;
166 via1[vT2CH] = 0;
167 via1[vACR] &= 0x3F;
168
169 /*
170 * SE/30: disable video IRQ
171 * XXX: testing for SE/30 VBL
172 */
173
174 if (macintosh_config->ident == MAC_MODEL_SE30) {
175 via1[vDirB] |= 0x40;
176 via1[vBufB] |= 0x40;
177 }
178
179 /*
180 * Set the RTC bits to a known state: all lines to outputs and
181 * RTC disabled (yes that's 0 to enable and 1 to disable).
182 */
183
184 via1[vDirB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk | VIA1B_vRTCData);
185 via1[vBufB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk);
186
187 /* Everything below this point is VIA2/RBV only... */
188
189 if (oss_present) return;
190
191#if 1
192 /* Some machines support an alternate IRQ mapping that spreads */
193 /* Ethernet and Sound out to their own autolevel IRQs and moves */
194 /* VIA1 to level 6. A/UX uses this mapping and we do too. Note */
195 /* that the IIfx emulates this alternate mapping using the OSS. */
196
197 switch(macintosh_config->ident) {
198 case MAC_MODEL_C610:
199 case MAC_MODEL_Q610:
200 case MAC_MODEL_C650:
201 case MAC_MODEL_Q650:
202 case MAC_MODEL_Q700:
203 case MAC_MODEL_Q800:
204 case MAC_MODEL_Q900:
205 case MAC_MODEL_Q950:
206 via_alt_mapping = 1;
207 via1[vDirB] |= 0x40;
208 via1[vBufB] &= ~0x40;
209 break;
210 default:
211 via_alt_mapping = 0;
212 break;
213 }
214#else
215 /* The alernate IRQ mapping seems to just not work. Anyone with a */
216 /* supported machine is welcome to take a stab at fixing it. It */
217 /* _should_ work on the following Quadras: 610,650,700,800,900,950 */
218 /* - 1999-06-12 (jmt) */
219
220 via_alt_mapping = 0;
221#endif
222
223 /*
224 * Now initialize VIA2. For RBV we just kill all interrupts;
225 * for a regular VIA we also reset the timers and stuff.
226 */
227
228 via2[gIER] = 0x7F;
229 via2[gIFR] = 0x7F | rbv_clear;
230 if (!rbv_present) {
231 via2[vT1LL] = 0;
232 via2[vT1LH] = 0;
233 via2[vT1CL] = 0;
234 via2[vT1CH] = 0;
235 via2[vT2CL] = 0;
236 via2[vT2CH] = 0;
237 via2[vACR] &= 0x3F;
238 }
239}
240
241/*
242 * Start the 100 Hz clock
243 */
244
245void __init via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *))
246{
247 via1[vACR] |= 0x40;
248 via1[vT1LL] = MAC_CLOCK_LOW;
249 via1[vT1LH] = MAC_CLOCK_HIGH;
250 via1[vT1CL] = MAC_CLOCK_LOW;
251 via1[vT1CH] = MAC_CLOCK_HIGH;
252
253 request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func);
254}
255
256/*
257 * Register the interrupt dispatchers for VIA or RBV machines only.
258 */
259
260void __init via_register_interrupts(void)
261{
262 if (via_alt_mapping) {
263 cpu_request_irq(IRQ_AUTO_1, via1_irq,
264 IRQ_FLG_LOCK|IRQ_FLG_FAST, "software",
265 (void *) via1);
266 cpu_request_irq(IRQ_AUTO_6, via1_irq,
267 IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
268 (void *) via1);
269 } else {
270 cpu_request_irq(IRQ_AUTO_1, via1_irq,
271 IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1",
272 (void *) via1);
273#if 0 /* interferes with serial on some machines */
274 if (!psc_present) {
275 cpu_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK,
276 "Off Switch", mac_bang);
277 }
278#endif
279 }
280 cpu_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
281 "via2", (void *) via2);
282 if (!psc_present) {
283 cpu_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
284 "scc", mac_scc_dispatch);
285 }
286 request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
287 "nubus", (void *) via2);
288}
289
290/*
291 * Debugging dump, used in various places to see what's going on.
292 */
293
294void via_debug_dump(void)
295{
296 printk(KERN_DEBUG "VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
297 (uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
298 printk(KERN_DEBUG " PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n",
299 (uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
300 if (oss_present) {
301 printk(KERN_DEBUG "VIA2: <OSS>\n");
302 } else if (rbv_present) {
303 printk(KERN_DEBUG "VIA2: IFR = 0x%02X IER = 0x%02X\n",
304 (uint) via2[rIFR], (uint) via2[rIER]);
305 printk(KERN_DEBUG " SIFR = 0x%02X SIER = 0x%02X\n",
306 (uint) via2[rSIFR], (uint) via2[rSIER]);
307 } else {
308 printk(KERN_DEBUG "VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
309 (uint) via2[vDirA], (uint) via2[vDirB],
310 (uint) via2[vACR]);
311 printk(KERN_DEBUG " PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n",
312 (uint) via2[vPCR],
313 (uint) via2[vIFR], (uint) via2[vIER]);
314 }
315}
316
317/*
318 * This is always executed with interrupts disabled.
319 *
320 * TBI: get time offset between scheduling timer ticks
321 */
322
323unsigned long mac_gettimeoffset (void)
324{
325 unsigned long ticks, offset = 0;
326
327 /* read VIA1 timer 2 current value */
328 ticks = via1[vT1CL] | (via1[vT1CH] << 8);
329 /* The probability of underflow is less than 2% */
330 if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50)
331 /* Check for pending timer interrupt in VIA1 IFR */
332 if (via1[vIFR] & 0x40) offset = TICK_SIZE;
333
334 ticks = MAC_CLOCK_TICK - ticks;
335 ticks = ticks * 10000L / MAC_CLOCK_TICK;
336
337 return ticks + offset;
338}
339
340/*
341 * Flush the L2 cache on Macs that have it by flipping
342 * the system into 24-bit mode for an instant.
343 */
344
345void via_flush_cache(void)
346{
347 via2[gBufB] &= ~VIA2B_vMode32;
348 via2[gBufB] |= VIA2B_vMode32;
349}
350
351/*
352 * Return the status of the L2 cache on a IIci
353 */
354
355int via_get_cache_disable(void)
356{
357 /* Safeguard against being called accidentally */
358 if (!via2) {
359 printk(KERN_ERR "via_get_cache_disable called on a non-VIA machine!\n");
360 return 1;
361 }
362
363 return (int) via2[gBufB] & VIA2B_vCDis;
364}
365
366/*
367 * Initialize VIA2 for Nubus access
368 */
369
370void __init via_nubus_init(void)
371{
372 /* don't set nubus_active = 0 here, it kills the Baboon */
373 /* interrupt that we've already registered. */
374
375 /* unlock nubus transactions */
376
377 if (!rbv_present) {
378 /* set the line to be an output on non-RBV machines */
379 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
380 (macintosh_config->adb_type != MAC_ADB_PB2)) {
381 via2[vDirB] |= 0x02;
382 }
383 }
384
385 /* this seems to be an ADB bit on PMU machines */
386 /* according to MkLinux. -- jmt */
387
388 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
389 (macintosh_config->adb_type != MAC_ADB_PB2)) {
390 via2[gBufB] |= 0x02;
391 }
392
393 /* disable nubus slot interrupts. */
394 if (rbv_present) {
395 via2[rSIER] = 0x7F;
396 via2[rSIER] = nubus_active | 0x80;
397 } else {
398 /* These are ADB bits on PMU */
399 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
400 (macintosh_config->adb_type != MAC_ADB_PB2)) {
401 switch(macintosh_config->ident)
402 {
403 case MAC_MODEL_II:
404 case MAC_MODEL_IIX:
405 case MAC_MODEL_IICX:
406 case MAC_MODEL_SE30:
407 via2[vBufA] |= 0x3F;
408 via2[vDirA] = ~nubus_active | 0xc0;
409 break;
410 default:
411 via2[vBufA] = 0xFF;
412 via2[vDirA] = ~nubus_active;
413 }
414 }
415 }
416}
417
418/*
419 * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
420 * via6522.c :-), disable/pending masks added.
421 *
422 * The new interrupt architecture in macints.c takes care of a lot of the
423 * gruntwork for us, including tallying the interrupts and calling the
424 * handlers on the linked list. All we need to do here is basically generate
425 * the machspec interrupt number after clearing the interrupt.
426 */
427
428irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs)
429{
430 int irq_bit, i;
431 unsigned char events, mask;
432
433 mask = via1[vIER] & 0x7F;
434 if (!(events = via1[vIFR] & mask))
435 return IRQ_NONE;
436
437 for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
438 if (events & irq_bit) {
439 via1[vIER] = irq_bit;
440 mac_do_irq_list(VIA1_SOURCE_BASE + i, regs);
441 via1[vIFR] = irq_bit;
442 via1[vIER] = irq_bit | 0x80;
443 }
444
445#if 0 /* freakin' pmu is doing weird stuff */
446 if (!oss_present) {
447 /* This (still) seems to be necessary to get IDE
448 working. However, if you enable VBL interrupts,
449 you're screwed... */
450 /* FIXME: should we check the SLOTIRQ bit before
451 pulling this stunt? */
452 /* No, it won't be set. that's why we're doing this. */
453 via_irq_disable(IRQ_MAC_NUBUS);
454 via_irq_clear(IRQ_MAC_NUBUS);
455 mac_do_irq_list(IRQ_MAC_NUBUS, regs);
456 via_irq_enable(IRQ_MAC_NUBUS);
457 }
458#endif
459 return IRQ_HANDLED;
460}
461
462irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs)
463{
464 int irq_bit, i;
465 unsigned char events, mask;
466
467 mask = via2[gIER] & 0x7F;
468 if (!(events = via2[gIFR] & mask))
469 return IRQ_NONE;
470
471 for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
472 if (events & irq_bit) {
473 via2[gIER] = irq_bit;
474 mac_do_irq_list(VIA2_SOURCE_BASE + i, regs);
475 via2[gIFR] = irq_bit | rbv_clear;
476 via2[gIER] = irq_bit | 0x80;
477 }
478 return IRQ_HANDLED;
479}
480
481/*
482 * Dispatch Nubus interrupts. We are called as a secondary dispatch by the
483 * VIA2 dispatcher as a fast interrupt handler.
484 */
485
486irqreturn_t via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
487{
488 int irq_bit, i;
489 unsigned char events;
490
491 if (!(events = ~via2[gBufA] & nubus_active))
492 return IRQ_NONE;
493
494 for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
495 if (events & irq_bit) {
496 via_irq_disable(NUBUS_SOURCE_BASE + i);
497 mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
498 via_irq_enable(NUBUS_SOURCE_BASE + i);
499 }
500 }
501 return IRQ_HANDLED;
502}
503
504void via_irq_enable(int irq) {
505 int irq_src = IRQ_SRC(irq);
506 int irq_idx = IRQ_IDX(irq);
507 int irq_bit = 1 << irq_idx;
508
509#ifdef DEBUG_IRQUSE
510 printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
511#endif
512
513 if (irq_src == 1) {
514 via1[vIER] = irq_bit | 0x80;
515 } else if (irq_src == 2) {
516 /*
517 * Set vPCR for SCSI interrupts (but not on RBV)
518 */
519 if ((irq_idx == 0) && !rbv_present) {
520 if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
521 /* CB2 (IRQ) indep. input, positive edge */
522 /* CA2 (DRQ) indep. input, positive edge */
523 via2[vPCR] = 0x66;
524 } else {
525 /* CB2 (IRQ) indep. input, negative edge */
526 /* CA2 (DRQ) indep. input, negative edge */
527 via2[vPCR] = 0x22;
528 }
529 }
530 via2[gIER] = irq_bit | 0x80;
531 } else if (irq_src == 7) {
532 if (rbv_present) {
533 /* enable the slot interrupt. SIER works like IER. */
534 via2[rSIER] = IER_SET_BIT(irq_idx);
535 } else {
536 /* Make sure the bit is an input, to enable the irq */
537 /* But not on PowerBooks, that's ADB... */
538 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
539 (macintosh_config->adb_type != MAC_ADB_PB2)) {
540 switch(macintosh_config->ident)
541 {
542 case MAC_MODEL_II:
543 case MAC_MODEL_IIX:
544 case MAC_MODEL_IICX:
545 case MAC_MODEL_SE30:
546 via2[vDirA] &= (~irq_bit | 0xc0);
547 break;
548 default:
549 via2[vDirA] &= ~irq_bit;
550 }
551 }
552 }
553 nubus_active |= irq_bit;
554 }
555}
556
557void via_irq_disable(int irq) {
558 int irq_src = IRQ_SRC(irq);
559 int irq_idx = IRQ_IDX(irq);
560 int irq_bit = 1 << irq_idx;
561
562#ifdef DEBUG_IRQUSE
563 printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
564#endif
565
566 if (irq_src == 1) {
567 via1[vIER] = irq_bit;
568 } else if (irq_src == 2) {
569 via2[gIER] = irq_bit;
570 } else if (irq_src == 7) {
571 if (rbv_present) {
572 /* disable the slot interrupt. SIER works like IER. */
573 via2[rSIER] = IER_CLR_BIT(irq_idx);
574 } else {
575 /* disable the nubus irq by changing dir to output */
576 /* except on PMU */
577 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
578 (macintosh_config->adb_type != MAC_ADB_PB2)) {
579 via2[vDirA] |= irq_bit;
580 }
581 }
582 nubus_active &= ~irq_bit;
583 }
584}
585
586void via_irq_clear(int irq) {
587 int irq_src = IRQ_SRC(irq);
588 int irq_idx = IRQ_IDX(irq);
589 int irq_bit = 1 << irq_idx;
590
591 if (irq_src == 1) {
592 via1[vIFR] = irq_bit;
593 } else if (irq_src == 2) {
594 via2[gIFR] = irq_bit | rbv_clear;
595 } else if (irq_src == 7) {
596 /* FIXME: hmm.. */
597 }
598}
599
600/*
601 * Returns nonzero if an interrupt is pending on the given
602 * VIA/IRQ combination.
603 */
604
605int via_irq_pending(int irq)
606{
607 int irq_src = IRQ_SRC(irq);
608 int irq_idx = IRQ_IDX(irq);
609 int irq_bit = 1 << irq_idx;
610
611 if (irq_src == 1) {
612 return via1[vIFR] & irq_bit;
613 } else if (irq_src == 2) {
614 return via2[gIFR] & irq_bit;
615 } else if (irq_src == 7) {
616 return ~via2[gBufA] & irq_bit;
617 }
618 return 0;
619}