v4.19.13 snapshot.
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile
new file mode 100644
index 0000000..0cac723
--- /dev/null
+++ b/arch/m68k/atari/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for Linux arch/m68k/atari source directory
+#
+
+obj-y		:= config.o time.o debug.o ataints.o stdma.o \
+			atasound.o stram.o
+
+obj-$(CONFIG_ATARI_KBD_CORE)	+= atakeyb.o
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
new file mode 100644
index 0000000..3d2b63b
--- /dev/null
+++ b/arch/m68k/atari/ataints.c
@@ -0,0 +1,391 @@
+/*
+ * arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code
+ *
+ * 5/2/94 Roman Hodek:
+ *  Added support for TT interrupts; setup for TT SCU (may someone has
+ *  twiddled there and we won't get the right interrupts :-()
+ *
+ *  Major change: The device-independent code in m68k/ints.c didn't know
+ *  about non-autovec ints yet. It hardcoded the number of possible ints to
+ *  7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the
+ *  number of possible ints a constant defined in interrupt.h, which is
+ *  47 for the Atari. So we can call request_irq() for all Atari interrupts
+ *  just the normal way. Additionally, all vectors >= 48 are initialized to
+ *  call trap() instead of inthandler(). This must be changed here, too.
+ *
+ * 1995-07-16 Lars Brinkhoff <f93labr@dd.chalmers.se>:
+ *  Corrected a bug in atari_add_isr() which rejected all SCC
+ *  interrupt sources if there were no TT MFP!
+ *
+ * 12/13/95: New interface functions atari_level_triggered_int() and
+ *  atari_register_vme_int() as support for level triggered VME interrupts.
+ *
+ * 02/12/96: (Roman)
+ *  Total rewrite of Atari interrupt handling, for new scheme see comments
+ *  below.
+ *
+ * 1996-09-03 lars brinkhoff <f93labr@dd.chalmers.se>:
+ *  Added new function atari_unregister_vme_int(), and
+ *  modified atari_register_vme_int() as well as IS_VALID_INTNO()
+ *  to work with it.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+
+#include <asm/traps.h>
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+#include <asm/irq.h>
+#include <asm/entry.h>
+#include <asm/io.h>
+
+
+/*
+ * Atari interrupt handling scheme:
+ * --------------------------------
+ *
+ * All interrupt source have an internal number (defined in
+ * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP,
+ * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can
+ * be allocated by atari_register_vme_int().
+ */
+
+/*
+ * Bitmap for free interrupt vector numbers
+ * (new vectors starting from 0x70 can be allocated by
+ * atari_register_vme_int())
+ */
+static int free_vme_vec_bitmap;
+
+/* GK:
+ * HBL IRQ handler for Falcon. Nobody needs it :-)
+ * ++andreas: raise ipl to disable further HBLANK interrupts.
+ */
+asmlinkage void falcon_hblhandler(void);
+asm(".text\n"
+__ALIGN_STR "\n\t"
+"falcon_hblhandler:\n\t"
+	"orw	#0x200,%sp@\n\t"	/* set saved ipl to 2 */
+	"rte");
+
+extern void atari_microwire_cmd(int cmd);
+
+static unsigned int atari_irq_startup(struct irq_data *data)
+{
+	unsigned int irq = data->irq;
+
+	m68k_irq_startup(data);
+	atari_turnon_irq(irq);
+	atari_enable_irq(irq);
+	return 0;
+}
+
+static void atari_irq_shutdown(struct irq_data *data)
+{
+	unsigned int irq = data->irq;
+
+	atari_disable_irq(irq);
+	atari_turnoff_irq(irq);
+	m68k_irq_shutdown(data);
+
+	if (irq == IRQ_AUTO_4)
+	    vectors[VEC_INT4] = falcon_hblhandler;
+}
+
+static void atari_irq_enable(struct irq_data *data)
+{
+	atari_enable_irq(data->irq);
+}
+
+static void atari_irq_disable(struct irq_data *data)
+{
+	atari_disable_irq(data->irq);
+}
+
+static struct irq_chip atari_irq_chip = {
+	.name		= "atari",
+	.irq_startup	= atari_irq_startup,
+	.irq_shutdown	= atari_irq_shutdown,
+	.irq_enable	= atari_irq_enable,
+	.irq_disable	= atari_irq_disable,
+};
+
+/*
+ * ST-MFP timer D chained interrupts - each driver gets its own timer
+ * interrupt instance.
+ */
+
+struct mfptimerbase {
+	volatile struct MFP *mfp;
+	unsigned char mfp_mask, mfp_data;
+	unsigned short int_mask;
+	int handler_irq, mfptimer_irq, server_irq;
+	char *name;
+} stmfp_base = {
+	.mfp		= &st_mfp,
+	.int_mask	= 0x0,
+	.handler_irq	= IRQ_MFP_TIMD,
+	.mfptimer_irq	= IRQ_MFP_TIMER1,
+	.name		= "MFP Timer D"
+};
+
+static irqreturn_t mfptimer_handler(int irq, void *dev_id)
+{
+	struct mfptimerbase *base = dev_id;
+	int mach_irq;
+	unsigned char ints;
+
+	mach_irq = base->mfptimer_irq;
+	ints = base->int_mask;
+	for (; ints; mach_irq++, ints >>= 1) {
+		if (ints & 1)
+			generic_handle_irq(mach_irq);
+	}
+	return IRQ_HANDLED;
+}
+
+
+static void atari_mfptimer_enable(struct irq_data *data)
+{
+	int mfp_num = data->irq - IRQ_MFP_TIMER1;
+	stmfp_base.int_mask |= 1 << mfp_num;
+	atari_enable_irq(IRQ_MFP_TIMD);
+}
+
+static void atari_mfptimer_disable(struct irq_data *data)
+{
+	int mfp_num = data->irq - IRQ_MFP_TIMER1;
+	stmfp_base.int_mask &= ~(1 << mfp_num);
+	if (!stmfp_base.int_mask)
+		atari_disable_irq(IRQ_MFP_TIMD);
+}
+
+static struct irq_chip atari_mfptimer_chip = {
+	.name		= "timer_d",
+	.irq_enable	= atari_mfptimer_enable,
+	.irq_disable	= atari_mfptimer_disable,
+};
+
+
+/*
+ * EtherNAT CPLD interrupt handling
+ * CPLD interrupt register is at phys. 0x80000023
+ * Need this mapped in at interrupt startup time
+ * Possibly need this mapped on demand anyway -
+ * EtherNAT USB driver needs to disable IRQ before
+ * startup!
+ */
+
+static unsigned char *enat_cpld;
+
+static unsigned int atari_ethernat_startup(struct irq_data *data)
+{
+	int enat_num = 140 - data->irq + 1;
+
+	m68k_irq_startup(data);
+	/*
+	* map CPLD interrupt register
+	*/
+	if (!enat_cpld)
+		enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
+	/*
+	 * do _not_ enable the USB chip interrupt here - causes interrupt storm
+	 * and triggers dead interrupt watchdog
+	 * Need to reset the USB chip to a sane state in early startup before
+	 * removing this hack
+	 */
+	if (enat_num == 1)
+		*enat_cpld |= 1 << enat_num;
+
+	return 0;
+}
+
+static void atari_ethernat_enable(struct irq_data *data)
+{
+	int enat_num = 140 - data->irq + 1;
+	/*
+	* map CPLD interrupt register
+	*/
+	if (!enat_cpld)
+		enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
+	*enat_cpld |= 1 << enat_num;
+}
+
+static void atari_ethernat_disable(struct irq_data *data)
+{
+	int enat_num = 140 - data->irq + 1;
+	/*
+	* map CPLD interrupt register
+	*/
+	if (!enat_cpld)
+		enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
+	*enat_cpld &= ~(1 << enat_num);
+}
+
+static void atari_ethernat_shutdown(struct irq_data *data)
+{
+	int enat_num = 140 - data->irq + 1;
+	if (enat_cpld) {
+		*enat_cpld &= ~(1 << enat_num);
+		iounmap(enat_cpld);
+		enat_cpld = NULL;
+	}
+}
+
+static struct irq_chip atari_ethernat_chip = {
+	.name		= "ethernat",
+	.irq_startup	= atari_ethernat_startup,
+	.irq_shutdown	= atari_ethernat_shutdown,
+	.irq_enable	= atari_ethernat_enable,
+	.irq_disable	= atari_ethernat_disable,
+};
+
+/*
+ * void atari_init_IRQ (void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function should be called during kernel startup to initialize
+ * the atari IRQ handling routines.
+ */
+
+void __init atari_init_IRQ(void)
+{
+	m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER);
+	m68k_setup_irq_controller(&atari_irq_chip, handle_simple_irq, 1,
+				  NUM_ATARI_SOURCES - 1);
+
+	/* Initialize the MFP(s) */
+
+#ifdef ATARI_USE_SOFTWARE_EOI
+	st_mfp.vec_adr  = 0x48;	/* Software EOI-Mode */
+#else
+	st_mfp.vec_adr  = 0x40;	/* Automatic EOI-Mode */
+#endif
+	st_mfp.int_en_a = 0x00;	/* turn off MFP-Ints */
+	st_mfp.int_en_b = 0x00;
+	st_mfp.int_mk_a = 0xff;	/* no Masking */
+	st_mfp.int_mk_b = 0xff;
+
+	if (ATARIHW_PRESENT(TT_MFP)) {
+#ifdef ATARI_USE_SOFTWARE_EOI
+		tt_mfp.vec_adr  = 0x58;		/* Software EOI-Mode */
+#else
+		tt_mfp.vec_adr  = 0x50;		/* Automatic EOI-Mode */
+#endif
+		tt_mfp.int_en_a = 0x00;		/* turn off MFP-Ints */
+		tt_mfp.int_en_b = 0x00;
+		tt_mfp.int_mk_a = 0xff;		/* no Masking */
+		tt_mfp.int_mk_b = 0xff;
+	}
+
+	if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) {
+		atari_scc.cha_a_ctrl = 9;
+		MFPDELAY();
+		atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
+	}
+
+	if (ATARIHW_PRESENT(SCU)) {
+		/* init the SCU if present */
+		tt_scu.sys_mask = 0x10;		/* enable VBL (for the cursor) and
+									 * disable HSYNC interrupts (who
+									 * needs them?)  MFP and SCC are
+									 * enabled in VME mask
+									 */
+		tt_scu.vme_mask = 0x60;		/* enable MFP and SCC ints */
+	} else {
+		/* If no SCU and no Hades, the HSYNC interrupt needs to be
+		 * disabled this way. (Else _inthandler in kernel/sys_call.S
+		 * gets overruns)
+		 */
+
+		vectors[VEC_INT2] = falcon_hblhandler;
+		vectors[VEC_INT4] = falcon_hblhandler;
+	}
+
+	if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
+		/* Initialize the LM1992 Sound Controller to enable
+		   the PSG sound.  This is misplaced here, it should
+		   be in an atasound_init(), that doesn't exist yet. */
+		atari_microwire_cmd(MW_LM1992_PSG_HIGH);
+	}
+
+	stdma_init();
+
+	/* Initialize the PSG: all sounds off, both ports output */
+	sound_ym.rd_data_reg_sel = 7;
+	sound_ym.wd_data = 0xff;
+
+	m68k_setup_irq_controller(&atari_mfptimer_chip, handle_simple_irq,
+				  IRQ_MFP_TIMER1, 8);
+
+	irq_set_status_flags(IRQ_MFP_TIMER1, IRQ_IS_POLLED);
+	irq_set_status_flags(IRQ_MFP_TIMER2, IRQ_IS_POLLED);
+
+	/* prepare timer D data for use as poll interrupt */
+	/* set Timer D data Register - needs to be > 0 */
+	st_mfp.tim_dt_d = 254;	/* < 100 Hz */
+	/* start timer D, div = 1:100 */
+	st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6;
+
+	/* request timer D dispatch handler */
+	if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED,
+			stmfp_base.name, &stmfp_base))
+		pr_err("Couldn't register %s interrupt\n", stmfp_base.name);
+
+	/*
+	 * EtherNAT ethernet / USB interrupt handlers
+	 */
+
+	m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq,
+				  139, 2);
+}
+
+
+/*
+ * atari_register_vme_int() returns the number of a free interrupt vector for
+ * hardware with a programmable int vector (probably a VME board).
+ */
+
+unsigned int atari_register_vme_int(void)
+{
+	int i;
+
+	for (i = 0; i < 32; i++)
+		if ((free_vme_vec_bitmap & (1 << i)) == 0)
+			break;
+
+	if (i == 16)
+		return 0;
+
+	free_vme_vec_bitmap |= 1 << i;
+	return VME_SOURCE_BASE + i;
+}
+EXPORT_SYMBOL(atari_register_vme_int);
+
+
+void atari_unregister_vme_int(unsigned int irq)
+{
+	if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
+		irq -= VME_SOURCE_BASE;
+		free_vme_vec_bitmap &= ~(1 << irq);
+	}
+}
+EXPORT_SYMBOL(atari_unregister_vme_int);
+
+
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
new file mode 100644
index 0000000..3709189
--- /dev/null
+++ b/arch/m68k/atari/atakeyb.c
@@ -0,0 +1,570 @@
+/*
+ * Atari Keyboard driver for 680x0 Linux
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Atari support by Robert de Vries
+ * enhanced by Bjoern Brauel and Roman Hodek
+ *
+ * 2.6 and input cleanup (removed autorepeat stuff) for 2.6.21
+ * 06/07 Michael Schmitz
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/keyboard.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/kd.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/kbd_kern.h>
+
+#include <asm/atariints.h>
+#include <asm/atarihw.h>
+#include <asm/atarikb.h>
+#include <asm/atari_joystick.h>
+#include <asm/irq.h>
+
+
+/* Hook for MIDI serial driver */
+void (*atari_MIDI_interrupt_hook) (void);
+/* Hook for keyboard inputdev  driver */
+void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
+/* Hook for mouse inputdev  driver */
+void (*atari_input_mouse_interrupt_hook) (char *);
+EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook);
+EXPORT_SYMBOL(atari_input_mouse_interrupt_hook);
+
+/* variables for IKBD self test: */
+
+/* state: 0: off; >0: in progress; >1: 0xf1 received */
+static volatile int ikbd_self_test;
+/* timestamp when last received a char */
+static volatile unsigned long self_test_last_rcv;
+/* bitmap of keys reported as broken */
+static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
+
+#define BREAK_MASK	(0x80)
+
+/*
+ * ++roman: The following changes were applied manually:
+ *
+ *  - The Alt (= Meta) key works in combination with Shift and
+ *    Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
+ *    Meta-Ctrl-A (0x81) ...
+ *
+ *  - The parentheses on the keypad send '(' and ')' with all
+ *    modifiers (as would do e.g. keypad '+'), but they cannot be used as
+ *    application keys (i.e. sending Esc O c).
+ *
+ *  - HELP and UNDO are mapped to be F21 and F24, resp, that send the
+ *    codes "\E[M" and "\E[P". (This is better than the old mapping to
+ *    F11 and F12, because these codes are on Shift+F1/2 anyway.) This
+ *    way, applications that allow their own keyboard mappings
+ *    (e.g. tcsh, X Windows) can be configured to use them in the way
+ *    the label suggests (providing help or undoing).
+ *
+ *  - Console switching is done with Alt+Fx (consoles 1..10) and
+ *    Shift+Alt+Fx (consoles 11..20).
+ *
+ *  - The misc. special function implemented in the kernel are mapped
+ *    to the following key combinations:
+ *
+ *      ClrHome          -> Home/Find
+ *      Shift + ClrHome  -> End/Select
+ *      Shift + Up       -> Page Up
+ *      Shift + Down     -> Page Down
+ *      Alt + Help       -> show system status
+ *      Shift + Help     -> show memory info
+ *      Ctrl + Help      -> show registers
+ *      Ctrl + Alt + Del -> Reboot
+ *      Alt + Undo       -> switch to last console
+ *      Shift + Undo     -> send interrupt
+ *      Alt + Insert     -> stop/start output (same as ^S/^Q)
+ *      Alt + Up         -> Scroll back console (if implemented)
+ *      Alt + Down       -> Scroll forward console (if implemented)
+ *      Alt + CapsLock   -> NumLock
+ *
+ * ++Andreas:
+ *
+ *  - Help mapped to K_HELP
+ *  - Undo mapped to K_UNDO (= K_F246)
+ *  - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
+ */
+
+typedef enum kb_state_t {
+	KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
+} KB_STATE_T;
+
+#define	IS_SYNC_CODE(sc)	((sc) >= 0x04 && (sc) <= 0xfb)
+
+typedef struct keyboard_state {
+	unsigned char buf[6];
+	int len;
+	KB_STATE_T state;
+} KEYBOARD_STATE;
+
+KEYBOARD_STATE kb_state;
+
+/* ++roman: If a keyboard overrun happened, we can't tell in general how much
+ * bytes have been lost and in which state of the packet structure we are now.
+ * This usually causes keyboards bytes to be interpreted as mouse movements
+ * and vice versa, which is very annoying. It seems better to throw away some
+ * bytes (that are usually mouse bytes) than to misinterpret them. Therefore I
+ * introduced the RESYNC state for IKBD data. In this state, the bytes up to
+ * one that really looks like a key event (0x04..0xf2) or the start of a mouse
+ * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
+ * speeds up the resynchronization of the event structure, even if maybe a
+ * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
+ * it's really hard to decide whether they're mouse or keyboard bytes. Since
+ * overruns usually occur when moving the Atari mouse rapidly, they're seen as
+ * mouse bytes here. If this is wrong, only a make code of the keyboard gets
+ * lost, which isn't too bad. Losing a break code would be disastrous,
+ * because then the keyboard repeat strikes...
+ */
+
+static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy)
+{
+	u_char acia_stat;
+	int scancode;
+	int break_flag;
+
+repeat:
+	if (acia.mid_ctrl & ACIA_IRQ)
+		if (atari_MIDI_interrupt_hook)
+			atari_MIDI_interrupt_hook();
+	acia_stat = acia.key_ctrl;
+	/* check out if the interrupt came from this ACIA */
+	if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
+		return IRQ_HANDLED;
+
+	if (acia_stat & ACIA_OVRN) {
+		/* a very fast typist or a slow system, give a warning */
+		/* ...happens often if interrupts were disabled for too long */
+		pr_debug("Keyboard overrun\n");
+		scancode = acia.key_data;
+		if (ikbd_self_test)
+			/* During self test, don't do resyncing, just process the code */
+			goto interpret_scancode;
+		else if (IS_SYNC_CODE(scancode)) {
+			/* This code seem already to be the start of a new packet or a
+			 * single scancode */
+			kb_state.state = KEYBOARD;
+			goto interpret_scancode;
+		} else {
+			/* Go to RESYNC state and skip this byte */
+			kb_state.state = RESYNC;
+			kb_state.len = 1;	/* skip max. 1 another byte */
+			goto repeat;
+		}
+	}
+
+	if (acia_stat & ACIA_RDRF) {
+		/* received a character */
+		scancode = acia.key_data;	/* get it or reset the ACIA, I'll get it! */
+	interpret_scancode:
+		switch (kb_state.state) {
+		case KEYBOARD:
+			switch (scancode) {
+			case 0xF7:
+				kb_state.state = AMOUSE;
+				kb_state.len = 0;
+				break;
+
+			case 0xF8:
+			case 0xF9:
+			case 0xFA:
+			case 0xFB:
+				kb_state.state = RMOUSE;
+				kb_state.len = 1;
+				kb_state.buf[0] = scancode;
+				break;
+
+			case 0xFC:
+				kb_state.state = CLOCK;
+				kb_state.len = 0;
+				break;
+
+			case 0xFE:
+			case 0xFF:
+				kb_state.state = JOYSTICK;
+				kb_state.len = 1;
+				kb_state.buf[0] = scancode;
+				break;
+
+			case 0xF1:
+				/* during self-test, note that 0xf1 received */
+				if (ikbd_self_test) {
+					++ikbd_self_test;
+					self_test_last_rcv = jiffies;
+					break;
+				}
+				/* FALL THROUGH */
+
+			default:
+				break_flag = scancode & BREAK_MASK;
+				scancode &= ~BREAK_MASK;
+				if (ikbd_self_test) {
+					/* Scancodes sent during the self-test stand for broken
+					 * keys (keys being down). The code *should* be a break
+					 * code, but nevertheless some AT keyboard interfaces send
+					 * make codes instead. Therefore, simply ignore
+					 * break_flag...
+					 */
+					int keyval, keytyp;
+
+					set_bit(scancode, broken_keys);
+					self_test_last_rcv = jiffies;
+					/* new Linux scancodes; approx. */
+					keyval = scancode;
+					keytyp = KTYP(keyval) - 0xf0;
+					keyval = KVAL(keyval);
+
+					pr_warn("Key with scancode %d ", scancode);
+					if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
+						if (keyval < ' ')
+							pr_cont("('^%c') ", keyval + '@');
+						else
+							pr_cont("('%c') ", keyval);
+					}
+					pr_cont("is broken -- will be ignored.\n");
+					break;
+				} else if (test_bit(scancode, broken_keys))
+					break;
+
+				if (atari_input_keyboard_interrupt_hook)
+					atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag);
+				break;
+			}
+			break;
+
+		case AMOUSE:
+			kb_state.buf[kb_state.len++] = scancode;
+			if (kb_state.len == 5) {
+				kb_state.state = KEYBOARD;
+				/* not yet used */
+				/* wake up someone waiting for this */
+			}
+			break;
+
+		case RMOUSE:
+			kb_state.buf[kb_state.len++] = scancode;
+			if (kb_state.len == 3) {
+				kb_state.state = KEYBOARD;
+				if (atari_input_mouse_interrupt_hook)
+					atari_input_mouse_interrupt_hook(kb_state.buf);
+			}
+			break;
+
+		case JOYSTICK:
+			kb_state.buf[1] = scancode;
+			kb_state.state = KEYBOARD;
+#ifdef FIXED_ATARI_JOYSTICK
+			atari_joystick_interrupt(kb_state.buf);
+#endif
+			break;
+
+		case CLOCK:
+			kb_state.buf[kb_state.len++] = scancode;
+			if (kb_state.len == 6) {
+				kb_state.state = KEYBOARD;
+				/* wake up someone waiting for this.
+				   But will this ever be used, as Linux keeps its own time.
+				   Perhaps for synchronization purposes? */
+				/* wake_up_interruptible(&clock_wait); */
+			}
+			break;
+
+		case RESYNC:
+			if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
+				kb_state.state = KEYBOARD;
+				goto interpret_scancode;
+			}
+			kb_state.len--;
+			break;
+		}
+	}
+
+#if 0
+	if (acia_stat & ACIA_CTS)
+		/* cannot happen */;
+#endif
+
+	if (acia_stat & (ACIA_FE | ACIA_PE)) {
+		pr_err("Error in keyboard communication\n");
+	}
+
+	/* handle_scancode() can take a lot of time, so check again if
+	 * some character arrived
+	 */
+	goto repeat;
+}
+
+/*
+ * I write to the keyboard without using interrupts, I poll instead.
+ * This takes for the maximum length string allowed (7) at 7812.5 baud
+ * 8 data 1 start 1 stop bit: 9.0 ms
+ * If this takes too long for normal operation, interrupt driven writing
+ * is the solution. (I made a feeble attempt in that direction but I
+ * kept it simple for now.)
+ */
+void ikbd_write(const char *str, int len)
+{
+	u_char acia_stat;
+
+	if ((len < 1) || (len > 7))
+		panic("ikbd: maximum string length exceeded");
+	while (len) {
+		acia_stat = acia.key_ctrl;
+		if (acia_stat & ACIA_TDRE) {
+			acia.key_data = *str++;
+			len--;
+		}
+	}
+}
+
+/* Reset (without touching the clock) */
+void ikbd_reset(void)
+{
+	static const char cmd[2] = { 0x80, 0x01 };
+
+	ikbd_write(cmd, 2);
+
+	/*
+	 * if all's well code 0xF1 is returned, else the break codes of
+	 * all keys making contact
+	 */
+}
+
+/* Set mouse button action */
+void ikbd_mouse_button_action(int mode)
+{
+	char cmd[2] = { 0x07, mode };
+
+	ikbd_write(cmd, 2);
+}
+
+/* Set relative mouse position reporting */
+void ikbd_mouse_rel_pos(void)
+{
+	static const char cmd[1] = { 0x08 };
+
+	ikbd_write(cmd, 1);
+}
+EXPORT_SYMBOL(ikbd_mouse_rel_pos);
+
+/* Set absolute mouse position reporting */
+void ikbd_mouse_abs_pos(int xmax, int ymax)
+{
+	char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
+
+	ikbd_write(cmd, 5);
+}
+
+/* Set mouse keycode mode */
+void ikbd_mouse_kbd_mode(int dx, int dy)
+{
+	char cmd[3] = { 0x0A, dx, dy };
+
+	ikbd_write(cmd, 3);
+}
+
+/* Set mouse threshold */
+void ikbd_mouse_thresh(int x, int y)
+{
+	char cmd[3] = { 0x0B, x, y };
+
+	ikbd_write(cmd, 3);
+}
+EXPORT_SYMBOL(ikbd_mouse_thresh);
+
+/* Set mouse scale */
+void ikbd_mouse_scale(int x, int y)
+{
+	char cmd[3] = { 0x0C, x, y };
+
+	ikbd_write(cmd, 3);
+}
+
+/* Interrogate mouse position */
+void ikbd_mouse_pos_get(int *x, int *y)
+{
+	static const char cmd[1] = { 0x0D };
+
+	ikbd_write(cmd, 1);
+
+	/* wait for returning bytes */
+}
+
+/* Load mouse position */
+void ikbd_mouse_pos_set(int x, int y)
+{
+	char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
+
+	ikbd_write(cmd, 6);
+}
+
+/* Set Y=0 at bottom */
+void ikbd_mouse_y0_bot(void)
+{
+	static const char cmd[1] = { 0x0F };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Set Y=0 at top */
+void ikbd_mouse_y0_top(void)
+{
+	static const char cmd[1] = { 0x10 };
+
+	ikbd_write(cmd, 1);
+}
+EXPORT_SYMBOL(ikbd_mouse_y0_top);
+
+/* Disable mouse */
+void ikbd_mouse_disable(void)
+{
+	static const char cmd[1] = { 0x12 };
+
+	ikbd_write(cmd, 1);
+}
+EXPORT_SYMBOL(ikbd_mouse_disable);
+
+/* Set joystick event reporting */
+void ikbd_joystick_event_on(void)
+{
+	static const char cmd[1] = { 0x14 };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Set joystick interrogation mode */
+void ikbd_joystick_event_off(void)
+{
+	static const char cmd[1] = { 0x15 };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Joystick interrogation */
+void ikbd_joystick_get_state(void)
+{
+	static const char cmd[1] = { 0x16 };
+
+	ikbd_write(cmd, 1);
+}
+
+#if 0
+/* This disables all other ikbd activities !!!! */
+/* Set joystick monitoring */
+void ikbd_joystick_monitor(int rate)
+{
+	static const char cmd[2] = { 0x17, rate };
+
+	ikbd_write(cmd, 2);
+
+	kb_state.state = JOYSTICK_MONITOR;
+}
+#endif
+
+/* some joystick routines not in yet (0x18-0x19) */
+
+/* Disable joysticks */
+void ikbd_joystick_disable(void)
+{
+	static const char cmd[1] = { 0x1A };
+
+	ikbd_write(cmd, 1);
+}
+
+/*
+ * The original code sometimes left the interrupt line of
+ * the ACIAs low forever. I hope, it is fixed now.
+ *
+ * Martin Rogge, 20 Aug 1995
+ */
+
+static int atari_keyb_done = 0;
+
+int atari_keyb_init(void)
+{
+	int error;
+
+	if (atari_keyb_done)
+		return 0;
+
+	kb_state.state = KEYBOARD;
+	kb_state.len = 0;
+
+	error = request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, 0,
+			    "keyboard,mouse,MIDI", atari_keyboard_interrupt);
+	if (error)
+		return error;
+
+	atari_turnoff_irq(IRQ_MFP_ACIA);
+	do {
+		/* reset IKBD ACIA */
+		acia.key_ctrl = ACIA_RESET |
+				((atari_switches & ATARI_SWITCH_IKBD) ?
+				 ACIA_RHTID : 0);
+		(void)acia.key_ctrl;
+		(void)acia.key_data;
+
+		/* reset MIDI ACIA */
+		acia.mid_ctrl = ACIA_RESET |
+				((atari_switches & ATARI_SWITCH_MIDI) ?
+				 ACIA_RHTID : 0);
+		(void)acia.mid_ctrl;
+		(void)acia.mid_data;
+
+		/* divide 500kHz by 64 gives 7812.5 baud */
+		/* 8 data no parity 1 start 1 stop bit */
+		/* receive interrupt enabled */
+		/* RTS low (except if switch selected), transmit interrupt disabled */
+		acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) |
+				((atari_switches & ATARI_SWITCH_IKBD) ?
+				 ACIA_RHTID : ACIA_RLTID);
+
+		acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S |
+				((atari_switches & ATARI_SWITCH_MIDI) ?
+				 ACIA_RHTID : 0);
+
+	/* make sure the interrupt line is up */
+	} while ((st_mfp.par_dt_reg & 0x10) == 0);
+
+	/* enable ACIA Interrupts */
+	st_mfp.active_edge &= ~0x10;
+	atari_turnon_irq(IRQ_MFP_ACIA);
+
+	ikbd_self_test = 1;
+	ikbd_reset();
+	/* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
+	 * self-test is finished */
+	self_test_last_rcv = jiffies;
+	while (time_before(jiffies, self_test_last_rcv + HZ/4))
+		barrier();
+	/* if not incremented: no 0xf1 received */
+	if (ikbd_self_test == 1)
+		pr_err("Keyboard self test failed!\n");
+	ikbd_self_test = 0;
+
+	ikbd_mouse_disable();
+	ikbd_joystick_disable();
+
+#ifdef FIXED_ATARI_JOYSTICK
+	atari_joystick_init();
+#endif
+
+	// flag init done
+	atari_keyb_done = 1;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(atari_keyb_init);
diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c
new file mode 100644
index 0000000..1c1181e
--- /dev/null
+++ b/arch/m68k/atari/atasound.c
@@ -0,0 +1,110 @@
+/*
+ * linux/arch/m68k/atari/atasound.c
+ *
+ * ++Geert: Moved almost all stuff to linux/drivers/sound/
+ *
+ * The author of atari_nosound, atari_mksound and atari_microwire_cmd is
+ * unknown. (++roman: That's me... :-)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * 1998-05-31 ++andreas: atari_mksound rewritten to always use the envelope,
+ *			 no timer, atari_nosound removed.
+ *
+ */
+
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <asm/atarihw.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/atariints.h>
+
+
+/*
+ * stuff from the old atasound.c
+ */
+
+void atari_microwire_cmd (int cmd)
+{
+	tt_microwire.mask = 0x7ff;
+	tt_microwire.data = MW_LM1992_ADDR | cmd;
+
+	/* Busy wait for data being completely sent :-( */
+	while( tt_microwire.mask != 0x7ff)
+		;
+}
+EXPORT_SYMBOL(atari_microwire_cmd);
+
+
+/* PSG base frequency */
+#define	PSG_FREQ	125000
+/* PSG envelope base frequency times 10 */
+#define PSG_ENV_FREQ_10	78125
+
+void atari_mksound (unsigned int hz, unsigned int ticks)
+{
+	/* Generates sound of some frequency for some number of clock
+	   ticks.  */
+	unsigned long flags;
+	unsigned char tmp;
+	int period;
+
+	local_irq_save(flags);
+
+
+	/* Disable generator A in mixer control.  */
+	sound_ym.rd_data_reg_sel = 7;
+	tmp = sound_ym.rd_data_reg_sel;
+	tmp |= 011;
+	sound_ym.wd_data = tmp;
+
+	if (hz) {
+	    /* Convert from frequency value to PSG period value (base
+	       frequency 125 kHz).  */
+
+	    period = PSG_FREQ / hz;
+
+	    if (period > 0xfff) period = 0xfff;
+
+	/* Set generator A frequency to hz.  */
+	sound_ym.rd_data_reg_sel = 0;
+	sound_ym.wd_data = period & 0xff;
+	sound_ym.rd_data_reg_sel = 1;
+	sound_ym.wd_data = (period >> 8) & 0xf;
+	if (ticks) {
+		/* Set length of envelope (max 8 sec).  */
+		int length = (ticks * PSG_ENV_FREQ_10) / HZ / 10;
+
+		if (length > 0xffff) length = 0xffff;
+		sound_ym.rd_data_reg_sel = 11;
+		sound_ym.wd_data = length & 0xff;
+		sound_ym.rd_data_reg_sel = 12;
+		sound_ym.wd_data = length >> 8;
+		/* Envelope form: max -> min single.  */
+		sound_ym.rd_data_reg_sel = 13;
+		sound_ym.wd_data = 0;
+		/* Use envelope for generator A.  */
+		sound_ym.rd_data_reg_sel = 8;
+		sound_ym.wd_data = 0x10;
+	} else {
+		/* Set generator A level to maximum, no envelope.  */
+		sound_ym.rd_data_reg_sel = 8;
+		sound_ym.wd_data = 15;
+	}
+	/* Turn on generator A in mixer control.  */
+	sound_ym.rd_data_reg_sel = 7;
+	tmp &= ~1;
+	sound_ym.wd_data = tmp;
+	}
+	local_irq_restore(flags);
+}
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
new file mode 100644
index 0000000..bd96702
--- /dev/null
+++ b/arch/m68k/atari/config.c
@@ -0,0 +1,920 @@
+/*
+ *  linux/arch/m68k/atari/config.c
+ *
+ *  Copyright (C) 1994 Bjoern Brauel
+ *
+ *  5/2/94 Roman Hodek:
+ *    Added setting of time_adj to get a better clock.
+ *
+ *  5/14/94 Roman Hodek:
+ *    gettod() for TT
+ *
+ *  5/15/94 Roman Hodek:
+ *    hard_reset_now() for Atari (and others?)
+ *
+ *  94/12/30 Andreas Schwab:
+ *    atari_sched_init fixed to get precise clock.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Miscellaneous atari stuff
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/usb/isp116x.h>
+#include <linux/vt_kern.h>
+#include <linux/module.h>
+
+#include <asm/bootinfo.h>
+#include <asm/bootinfo-atari.h>
+#include <asm/byteorder.h>
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stram.h>
+#include <asm/machdep.h>
+#include <asm/hwtest.h>
+#include <asm/io.h>
+
+u_long atari_mch_cookie;
+EXPORT_SYMBOL(atari_mch_cookie);
+
+u_long atari_mch_type;
+EXPORT_SYMBOL(atari_mch_type);
+
+struct atari_hw_present atari_hw_present;
+EXPORT_SYMBOL(atari_hw_present);
+
+u_long atari_switches;
+EXPORT_SYMBOL(atari_switches);
+
+int atari_dont_touch_floppy_select;
+EXPORT_SYMBOL(atari_dont_touch_floppy_select);
+
+int atari_rtc_year_offset;
+
+/* local function prototypes */
+static void atari_reset(void);
+static void atari_get_model(char *model);
+static void atari_get_hardware_list(struct seq_file *m);
+
+/* atari specific irq functions */
+extern void atari_init_IRQ (void);
+extern void atari_mksound(unsigned int count, unsigned int ticks);
+#ifdef CONFIG_HEARTBEAT
+static void atari_heartbeat(int on);
+#endif
+
+/* atari specific timer functions (in time.c) */
+extern void atari_sched_init(irq_handler_t);
+extern u32 atari_gettimeoffset(void);
+extern int atari_mste_hwclk (int, struct rtc_time *);
+extern int atari_tt_hwclk (int, struct rtc_time *);
+
+/* ++roman: This is a more elaborate test for an SCC chip, since the plain
+ * Medusa board generates DTACK at the SCC's standard addresses, but a SCC
+ * board in the Medusa is possible. Also, the addresses where the ST_ESCC
+ * resides generate DTACK without the chip, too.
+ * The method is to write values into the interrupt vector register, that
+ * should be readable without trouble (from channel A!).
+ */
+
+static int __init scc_test(volatile char *ctla)
+{
+	if (!hwreg_present(ctla))
+		return 0;
+	MFPDELAY();
+
+	*ctla = 2;
+	MFPDELAY();
+	*ctla = 0x40;
+	MFPDELAY();
+
+	*ctla = 2;
+	MFPDELAY();
+	if (*ctla != 0x40)
+		return 0;
+	MFPDELAY();
+
+	*ctla = 2;
+	MFPDELAY();
+	*ctla = 0x60;
+	MFPDELAY();
+
+	*ctla = 2;
+	MFPDELAY();
+	if (*ctla != 0x60)
+		return 0;
+
+	return 1;
+}
+
+
+    /*
+     *  Parse an Atari-specific record in the bootinfo
+     */
+
+int __init atari_parse_bootinfo(const struct bi_record *record)
+{
+	int unknown = 0;
+	const void *data = record->data;
+
+	switch (be16_to_cpu(record->tag)) {
+	case BI_ATARI_MCH_COOKIE:
+		atari_mch_cookie = be32_to_cpup(data);
+		break;
+	case BI_ATARI_MCH_TYPE:
+		atari_mch_type = be32_to_cpup(data);
+		break;
+	default:
+		unknown = 1;
+		break;
+	}
+	return unknown;
+}
+
+
+/* Parse the Atari-specific switches= option. */
+static int __init atari_switches_setup(char *str)
+{
+	char switches[strlen(str) + 1];
+	char *p;
+	int ovsc_shift;
+	char *args = switches;
+
+	if (!MACH_IS_ATARI)
+		return 0;
+
+	/* copy string to local array, strsep works destructively... */
+	strcpy(switches, str);
+	atari_switches = 0;
+
+	/* parse the options */
+	while ((p = strsep(&args, ",")) != NULL) {
+		if (!*p)
+			continue;
+		ovsc_shift = 0;
+		if (strncmp(p, "ov_", 3) == 0) {
+			p += 3;
+			ovsc_shift = ATARI_SWITCH_OVSC_SHIFT;
+		}
+
+		if (strcmp(p, "ikbd") == 0) {
+			/* RTS line of IKBD ACIA */
+			atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift;
+		} else if (strcmp(p, "midi") == 0) {
+			/* RTS line of MIDI ACIA */
+			atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift;
+		} else if (strcmp(p, "snd6") == 0) {
+			atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift;
+		} else if (strcmp(p, "snd7") == 0) {
+			atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
+		}
+	}
+	return 0;
+}
+
+early_param("switches", atari_switches_setup);
+
+
+    /*
+     *  Setup the Atari configuration info
+     */
+
+void __init config_atari(void)
+{
+	unsigned short tos_version;
+
+	memset(&atari_hw_present, 0, sizeof(atari_hw_present));
+
+	/* Change size of I/O space from 64KB to 4GB. */
+	ioport_resource.end  = 0xFFFFFFFF;
+
+	mach_sched_init      = atari_sched_init;
+	mach_init_IRQ        = atari_init_IRQ;
+	mach_get_model	 = atari_get_model;
+	mach_get_hardware_list = atari_get_hardware_list;
+	arch_gettimeoffset   = atari_gettimeoffset;
+	mach_reset           = atari_reset;
+	mach_max_dma_address = 0xffffff;
+#if IS_ENABLED(CONFIG_INPUT_M68K_BEEP)
+	mach_beep          = atari_mksound;
+#endif
+#ifdef CONFIG_HEARTBEAT
+	mach_heartbeat = atari_heartbeat;
+#endif
+
+	/* Set switches as requested by the user */
+	if (atari_switches & ATARI_SWITCH_IKBD)
+		acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID;
+	if (atari_switches & ATARI_SWITCH_MIDI)
+		acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+	if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) {
+		sound_ym.rd_data_reg_sel = 14;
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+				   ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) |
+				   ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0);
+	}
+
+	/* ++bjoern:
+	 * Determine hardware present
+	 */
+
+	pr_info("Atari hardware found:");
+	if (MACH_IS_MEDUSA) {
+		/* There's no Atari video hardware on the Medusa, but all the
+		 * addresses below generate a DTACK so no bus error occurs! */
+	} else if (hwreg_present(f030_xreg)) {
+		ATARIHW_SET(VIDEL_SHIFTER);
+		pr_cont(" VIDEL");
+		/* This is a temporary hack: If there is Falcon video
+		 * hardware, we assume that the ST-DMA serves SCSI instead of
+		 * ACSI. In the future, there should be a better method for
+		 * this...
+		 */
+		ATARIHW_SET(ST_SCSI);
+		pr_cont(" STDMA-SCSI");
+	} else if (hwreg_present(tt_palette)) {
+		ATARIHW_SET(TT_SHIFTER);
+		pr_cont(" TT_SHIFTER");
+	} else if (hwreg_present(&shifter.bas_hi)) {
+		if (hwreg_present(&shifter.bas_lo) &&
+		    (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
+			ATARIHW_SET(EXTD_SHIFTER);
+			pr_cont(" EXTD_SHIFTER");
+		} else {
+			ATARIHW_SET(STND_SHIFTER);
+			pr_cont(" STND_SHIFTER");
+		}
+	}
+	if (hwreg_present(&st_mfp.par_dt_reg)) {
+		ATARIHW_SET(ST_MFP);
+		pr_cont(" ST_MFP");
+	}
+	if (hwreg_present(&tt_mfp.par_dt_reg)) {
+		ATARIHW_SET(TT_MFP);
+		pr_cont(" TT_MFP");
+	}
+	if (hwreg_present(&tt_scsi_dma.dma_addr_hi)) {
+		ATARIHW_SET(SCSI_DMA);
+		pr_cont(" TT_SCSI_DMA");
+	}
+	/*
+	 * The ST-DMA address registers aren't readable
+	 * on all Medusas, so the test below may fail
+	 */
+	if (MACH_IS_MEDUSA ||
+	    (hwreg_present(&st_dma.dma_vhi) &&
+	     (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
+	     st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
+	     (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
+	     st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
+		ATARIHW_SET(EXTD_DMA);
+		pr_cont(" EXTD_DMA");
+	}
+	if (hwreg_present(&tt_scsi.scsi_data)) {
+		ATARIHW_SET(TT_SCSI);
+		pr_cont(" TT_SCSI");
+	}
+	if (hwreg_present(&sound_ym.rd_data_reg_sel)) {
+		ATARIHW_SET(YM_2149);
+		pr_cont(" YM2149");
+	}
+	if (!MACH_IS_MEDUSA && hwreg_present(&tt_dmasnd.ctrl)) {
+		ATARIHW_SET(PCM_8BIT);
+		pr_cont(" PCM");
+	}
+	if (hwreg_present(&falcon_codec.unused5)) {
+		ATARIHW_SET(CODEC);
+		pr_cont(" CODEC");
+	}
+	if (hwreg_present(&dsp56k_host_interface.icr)) {
+		ATARIHW_SET(DSP56K);
+		pr_cont(" DSP56K");
+	}
+	if (hwreg_present(&tt_scc_dma.dma_ctrl) &&
+#if 0
+	    /* This test sucks! Who knows some better? */
+	    (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
+	    (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
+#else
+	    !MACH_IS_MEDUSA
+#endif
+	    ) {
+		ATARIHW_SET(SCC_DMA);
+		pr_cont(" SCC_DMA");
+	}
+	if (scc_test(&atari_scc.cha_a_ctrl)) {
+		ATARIHW_SET(SCC);
+		pr_cont(" SCC");
+	}
+	if (scc_test(&st_escc.cha_b_ctrl)) {
+		ATARIHW_SET(ST_ESCC);
+		pr_cont(" ST_ESCC");
+	}
+	if (hwreg_present(&tt_scu.sys_mask)) {
+		ATARIHW_SET(SCU);
+		/* Assume a VME bus if there's a SCU */
+		ATARIHW_SET(VME);
+		pr_cont(" VME SCU");
+	}
+	if (hwreg_present((void *)(0xffff9210))) {
+		ATARIHW_SET(ANALOG_JOY);
+		pr_cont(" ANALOG_JOY");
+	}
+	if (hwreg_present(blitter.halftone)) {
+		ATARIHW_SET(BLITTER);
+		pr_cont(" BLITTER");
+	}
+	if (hwreg_present((void *)0xfff00039)) {
+		ATARIHW_SET(IDE);
+		pr_cont(" IDE");
+	}
+#if 1 /* This maybe wrong */
+	if (!MACH_IS_MEDUSA && hwreg_present(&tt_microwire.data) &&
+	    hwreg_present(&tt_microwire.mask) &&
+	    (tt_microwire.mask = 0x7ff,
+	     udelay(1),
+	     tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
+	     udelay(1),
+	     tt_microwire.data != 0)) {
+		ATARIHW_SET(MICROWIRE);
+		while (tt_microwire.mask != 0x7ff)
+			;
+		pr_cont(" MICROWIRE");
+	}
+#endif
+	if (hwreg_present(&tt_rtc.regsel)) {
+		ATARIHW_SET(TT_CLK);
+		pr_cont(" TT_CLK");
+		mach_hwclk = atari_tt_hwclk;
+	}
+	if (hwreg_present(&mste_rtc.sec_ones)) {
+		ATARIHW_SET(MSTE_CLK);
+		pr_cont(" MSTE_CLK");
+		mach_hwclk = atari_mste_hwclk;
+	}
+	if (!MACH_IS_MEDUSA && hwreg_present(&dma_wd.fdc_speed) &&
+	    hwreg_write(&dma_wd.fdc_speed, 0)) {
+		ATARIHW_SET(FDCSPEED);
+		pr_cont(" FDC_SPEED");
+	}
+	if (!ATARIHW_PRESENT(ST_SCSI)) {
+		ATARIHW_SET(ACSI);
+		pr_cont(" ACSI");
+	}
+	pr_cont("\n");
+
+	if (CPU_IS_040_OR_060)
+		/* Now it seems to be safe to turn of the tt0 transparent
+		 * translation (the one that must not be turned off in
+		 * head.S...)
+		 */
+		asm volatile ("\n"
+			"	moveq	#0,%%d0\n"
+			"	.chip	68040\n"
+			"	movec	%%d0,%%itt0\n"
+			"	movec	%%d0,%%dtt0\n"
+			"	.chip	68k"
+			: /* no outputs */
+			: /* no inputs */
+			: "d0");
+
+	/* allocator for memory that must reside in st-ram */
+	atari_stram_init();
+
+	/* Set up a mapping for the VMEbus address region:
+	 *
+	 * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
+	 * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
+	 * 0xfe000000 virt., because this can be done with a single
+	 * transparent translation. On the 68040, lots of often unused
+	 * page tables would be needed otherwise. On a MegaSTE or similar,
+	 * the highest byte is stripped off by hardware due to the 24 bit
+	 * design of the bus.
+	 */
+
+	if (CPU_IS_020_OR_030) {
+		unsigned long tt1_val;
+		tt1_val = 0xfe008543;	/* Translate 0xfexxxxxx, enable, cache
+					 * inhibit, read and write, FDC mask = 3,
+					 * FDC val = 4 -> Supervisor only */
+		asm volatile ("\n"
+			"	.chip	68030\n"
+			"	pmove	%0,%/tt1\n"
+			"	.chip	68k"
+			: : "m" (tt1_val));
+	} else {
+	        asm volatile ("\n"
+			"	.chip	68040\n"
+			"	movec	%0,%%itt1\n"
+			"	movec	%0,%%dtt1\n"
+			"	.chip	68k"
+			:
+			: "d" (0xfe00a040));	/* Translate 0xfexxxxxx, enable,
+						 * supervisor only, non-cacheable/
+						 * serialized, writable */
+
+	}
+
+	/* Fetch tos version at Physical 2 */
+	/*
+	 * We my not be able to access this address if the kernel is
+	 * loaded to st ram, since the first page is unmapped.  On the
+	 * Medusa this is always the case and there is nothing we can do
+	 * about this, so we just assume the smaller offset.  For the TT
+	 * we use the fact that in head.S we have set up a mapping
+	 * 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
+	 * in the last 16MB of the address space.
+	 */
+	tos_version = (MACH_IS_MEDUSA) ?
+			0xfff : *(unsigned short *)0xff000002;
+	atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
+}
+
+#ifdef CONFIG_HEARTBEAT
+static void atari_heartbeat(int on)
+{
+	unsigned char tmp;
+	unsigned long flags;
+
+	if (atari_dont_touch_floppy_select)
+		return;
+
+	local_irq_save(flags);
+	sound_ym.rd_data_reg_sel = 14;	/* Select PSG Port A */
+	tmp = sound_ym.rd_data_reg_sel;
+	sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
+	local_irq_restore(flags);
+}
+#endif
+
+/* ++roman:
+ *
+ * This function does a reset on machines that lack the ability to
+ * assert the processor's _RESET signal somehow via hardware. It is
+ * based on the fact that you can find the initial SP and PC values
+ * after a reset at physical addresses 0 and 4. This works pretty well
+ * for Atari machines, since the lowest 8 bytes of physical memory are
+ * really ROM (mapped by hardware). For other 680x0 machines: don't
+ * know if it works...
+ *
+ * To get the values at addresses 0 and 4, the MMU better is turned
+ * off first. After that, we have to jump into physical address space
+ * (the PC before the pmove statement points to the virtual address of
+ * the code). Getting that physical address is not hard, but the code
+ * becomes a bit complex since I've tried to ensure that the jump
+ * statement after the pmove is in the cache already (otherwise the
+ * processor can't fetch it!). For that, the code first jumps to the
+ * jump statement with the (virtual) address of the pmove section in
+ * an address register . The jump statement is surely in the cache
+ * now. After that, that physical address of the reset code is loaded
+ * into the same address register, pmove is done and the same jump
+ * statements goes to the reset code. Since there are not many
+ * statements between the two jumps, I hope it stays in the cache.
+ *
+ * The C code makes heavy use of the GCC features that you can get the
+ * address of a C label. No hope to compile this with another compiler
+ * than GCC!
+ */
+
+/* ++andreas: no need for complicated code, just depend on prefetch */
+
+static void atari_reset(void)
+{
+	long tc_val = 0;
+	long reset_addr;
+
+	/*
+	 * On the Medusa, phys. 0x4 may contain garbage because it's no
+	 * ROM.  See above for explanation why we cannot use PTOV(4).
+	 */
+	reset_addr = MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
+		     *(unsigned long *) 0xff000004;
+
+	/* reset ACIA for switch off OverScan, if it's active */
+	if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+		acia.key_ctrl = ACIA_RESET;
+	if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+		acia.mid_ctrl = ACIA_RESET;
+
+	/* processor independent: turn off interrupts and reset the VBR;
+	 * the caches must be left enabled, else prefetching the final jump
+	 * instruction doesn't work.
+	 */
+	local_irq_disable();
+	asm volatile ("movec	%0,%%vbr"
+			: : "d" (0));
+
+	if (CPU_IS_040_OR_060) {
+		unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
+		if (CPU_IS_060) {
+			/* 68060: clear PCR to turn off superscalar operation */
+			asm volatile ("\n"
+				"	.chip 68060\n"
+				"	movec %0,%%pcr\n"
+				"	.chip 68k"
+				: : "d" (0));
+		}
+
+		asm volatile ("\n"
+			"	move.l	%0,%%d0\n"
+			"	and.l	#0xff000000,%%d0\n"
+			"	or.w	#0xe020,%%d0\n"   /* map 16 MB, enable, cacheable */
+			"	.chip	68040\n"
+			"	movec	%%d0,%%itt0\n"
+			"	movec	%%d0,%%dtt0\n"
+			"	.chip	68k\n"
+			"	jmp	%0@"
+			: : "a" (jmp_addr040)
+			: "d0");
+	jmp_addr_label040:
+		asm volatile ("\n"
+			"	moveq	#0,%%d0\n"
+			"	nop\n"
+			"	.chip	68040\n"
+			"	cinva	%%bc\n"
+			"	nop\n"
+			"	pflusha\n"
+			"	nop\n"
+			"	movec	%%d0,%%tc\n"
+			"	nop\n"
+			/* the following setup of transparent translations is needed on the
+			 * Afterburner040 to successfully reboot. Other machines shouldn't
+			 * care about a different tt regs setup, they also didn't care in
+			 * the past that the regs weren't turned off. */
+			"	move.l	#0xffc000,%%d0\n" /* whole insn space cacheable */
+			"	movec	%%d0,%%itt0\n"
+			"	movec	%%d0,%%itt1\n"
+			"	or.w	#0x40,%/d0\n" /* whole data space non-cacheable/ser. */
+			"	movec	%%d0,%%dtt0\n"
+			"	movec	%%d0,%%dtt1\n"
+			"	.chip	68k\n"
+			"	jmp	%0@"
+			: /* no outputs */
+			: "a" (reset_addr)
+			: "d0");
+	} else
+		asm volatile ("\n"
+			"	pmove	%0,%%tc\n"
+			"	jmp	%1@"
+			: /* no outputs */
+			: "m" (tc_val), "a" (reset_addr));
+}
+
+
+static void atari_get_model(char *model)
+{
+	strcpy(model, "Atari ");
+	switch (atari_mch_cookie >> 16) {
+	case ATARI_MCH_ST:
+		if (ATARIHW_PRESENT(MSTE_CLK))
+			strcat(model, "Mega ST");
+		else
+			strcat(model, "ST");
+		break;
+	case ATARI_MCH_STE:
+		if (MACH_IS_MSTE)
+			strcat(model, "Mega STE");
+		else
+			strcat(model, "STE");
+		break;
+	case ATARI_MCH_TT:
+		if (MACH_IS_MEDUSA)
+			/* Medusa has TT _MCH cookie */
+			strcat(model, "Medusa");
+		else
+			strcat(model, "TT");
+		break;
+	case ATARI_MCH_FALCON:
+		strcat(model, "Falcon");
+		if (MACH_IS_AB40)
+			strcat(model, " (with Afterburner040)");
+		break;
+	default:
+		sprintf(model + strlen(model), "(unknown mach cookie 0x%lx)",
+			atari_mch_cookie);
+		break;
+	}
+}
+
+
+static void atari_get_hardware_list(struct seq_file *m)
+{
+	int i;
+
+	for (i = 0; i < m68k_num_memory; i++)
+		seq_printf(m, "\t%3ld MB at 0x%08lx (%s)\n",
+				m68k_memory[i].size >> 20, m68k_memory[i].addr,
+				(m68k_memory[i].addr & 0xff000000 ?
+				 "alternate RAM" : "ST-RAM"));
+
+#define ATARIHW_ANNOUNCE(name, str)			\
+	if (ATARIHW_PRESENT(name))			\
+		seq_printf(m, "\t%s\n", str)
+
+	seq_puts(m, "Detected hardware:\n");
+	ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
+	ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
+	ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
+	ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
+	ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
+	ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
+	ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
+	ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
+	ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
+	ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
+	ATARIHW_ANNOUNCE(IDE, "IDE Interface");
+	ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
+	ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
+	ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
+	ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
+	ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
+	ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
+	ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
+	ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
+	ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
+	ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
+	ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
+	ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
+	ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
+	ATARIHW_ANNOUNCE(SCU, "System Control Unit");
+	ATARIHW_ANNOUNCE(BLITTER, "Blitter");
+	ATARIHW_ANNOUNCE(VME, "VME Bus");
+	ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
+}
+
+/*
+ * MSch: initial platform device support for Atari,
+ * required for EtherNAT/EtherNEC/NetUSBee drivers
+ */
+
+#if defined(CONFIG_ATARI_ETHERNAT) || defined(CONFIG_ATARI_ETHERNEC)
+static void isp1160_delay(struct device *dev, int delay)
+{
+	ndelay(delay);
+}
+#endif
+
+#ifdef CONFIG_ATARI_ETHERNAT
+/*
+ * EtherNAT: SMC91C111 Ethernet chipset, handled by smc91x driver
+ */
+
+#define ATARI_ETHERNAT_IRQ		140
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.name	= "smc91x-regs",
+		.start	= ATARI_ETHERNAT_PHYS_ADDR,
+		.end	= ATARI_ETHERNAT_PHYS_ADDR + 0xfffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "smc91x-irq",
+		.start	= ATARI_ETHERNAT_IRQ,
+		.end	= ATARI_ETHERNAT_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+/*
+ * ISP 1160 - using the isp116x-hcd module
+ */
+
+#define ATARI_USB_PHYS_ADDR	0x80000012
+#define ATARI_USB_IRQ		139
+
+static struct resource isp1160_resources[] = {
+	[0] = {
+		.name	= "isp1160-data",
+		.start	= ATARI_USB_PHYS_ADDR,
+		.end	= ATARI_USB_PHYS_ADDR + 0x1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "isp1160-regs",
+		.start	= ATARI_USB_PHYS_ADDR + 0x4,
+		.end	= ATARI_USB_PHYS_ADDR + 0x5,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.name	= "isp1160-irq",
+		.start	= ATARI_USB_IRQ,
+		.end	= ATARI_USB_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+/* (DataBusWidth16|AnalogOCEnable|DREQOutputPolarity|DownstreamPort15KRSel ) */
+static struct isp116x_platform_data isp1160_platform_data = {
+	/* Enable internal resistors on downstream ports */
+	.sel15Kres		= 1,
+	/* On-chip overcurrent protection */
+	.oc_enable		= 1,
+	/* INT output polarity */
+	.int_act_high		= 1,
+	/* INT edge or level triggered */
+	.int_edge_triggered	= 0,
+
+	/* WAKEUP pin connected - NOT SUPPORTED  */
+	/* .remote_wakeup_connected = 0, */
+	/* Wakeup by devices on usb bus enabled */
+	.remote_wakeup_enable	= 0,
+	.delay			= isp1160_delay,
+};
+
+static struct platform_device isp1160_device = {
+	.name		= "isp116x-hcd",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(isp1160_resources),
+	.resource	= isp1160_resources,
+	.dev			= {
+		.platform_data	= &isp1160_platform_data,
+	},
+};
+
+static struct platform_device *atari_ethernat_devices[] __initdata = {
+	&smc91x_device,
+	&isp1160_device
+};
+#endif /* CONFIG_ATARI_ETHERNAT */
+
+#ifdef CONFIG_ATARI_ETHERNEC
+/*
+ * EtherNEC: RTL8019 (NE2000 compatible) Ethernet chipset,
+ * handled by ne.c driver
+ */
+
+#define ATARI_ETHERNEC_PHYS_ADDR	0xfffa0000
+#define ATARI_ETHERNEC_BASE		0x300
+#define ATARI_ETHERNEC_IRQ		IRQ_MFP_TIMER1
+
+static struct resource rtl8019_resources[] = {
+	[0] = {
+		.name	= "rtl8019-regs",
+		.start	= ATARI_ETHERNEC_BASE,
+		.end	= ATARI_ETHERNEC_BASE + 0x20 - 1,
+		.flags	= IORESOURCE_IO,
+	},
+	[1] = {
+		.name	= "rtl8019-irq",
+		.start	= ATARI_ETHERNEC_IRQ,
+		.end	= ATARI_ETHERNEC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device rtl8019_device = {
+	.name		= "ne",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(rtl8019_resources),
+	.resource	= rtl8019_resources,
+};
+
+/*
+ * NetUSBee: ISP1160 USB host adapter via ROM-port adapter
+ */
+
+#define ATARI_NETUSBEE_PHYS_ADDR	0xfffa8000
+#define ATARI_NETUSBEE_BASE		0x340
+#define ATARI_NETUSBEE_IRQ		IRQ_MFP_TIMER2
+
+static struct resource netusbee_resources[] = {
+	[0] = {
+		.name	= "isp1160-data",
+		.start	= ATARI_NETUSBEE_BASE,
+		.end	= ATARI_NETUSBEE_BASE + 0x1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "isp1160-regs",
+		.start	= ATARI_NETUSBEE_BASE + 0x20,
+		.end	= ATARI_NETUSBEE_BASE + 0x21,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.name	= "isp1160-irq",
+		.start	= ATARI_NETUSBEE_IRQ,
+		.end	= ATARI_NETUSBEE_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+/* (DataBusWidth16|AnalogOCEnable|DREQOutputPolarity|DownstreamPort15KRSel ) */
+static struct isp116x_platform_data netusbee_platform_data = {
+	/* Enable internal resistors on downstream ports */
+	.sel15Kres		= 1,
+	/* On-chip overcurrent protection */
+	.oc_enable		= 1,
+	/* INT output polarity */
+	.int_act_high		= 1,
+	/* INT edge or level triggered */
+	.int_edge_triggered	= 0,
+
+	/* WAKEUP pin connected - NOT SUPPORTED  */
+	/* .remote_wakeup_connected = 0, */
+	/* Wakeup by devices on usb bus enabled */
+	.remote_wakeup_enable	= 0,
+	.delay			= isp1160_delay,
+};
+
+static struct platform_device netusbee_device = {
+	.name		= "isp116x-hcd",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(netusbee_resources),
+	.resource	= netusbee_resources,
+	.dev			= {
+		.platform_data	= &netusbee_platform_data,
+	},
+};
+
+static struct platform_device *atari_netusbee_devices[] __initdata = {
+	&rtl8019_device,
+	&netusbee_device
+};
+#endif /* CONFIG_ATARI_ETHERNEC */
+
+#if IS_ENABLED(CONFIG_ATARI_SCSI)
+static const struct resource atari_scsi_st_rsrc[] __initconst = {
+	{
+		.flags = IORESOURCE_IRQ,
+		.start = IRQ_MFP_FSCSI,
+		.end   = IRQ_MFP_FSCSI,
+	},
+};
+
+static const struct resource atari_scsi_tt_rsrc[] __initconst = {
+	{
+		.flags = IORESOURCE_IRQ,
+		.start = IRQ_TT_MFP_SCSI,
+		.end   = IRQ_TT_MFP_SCSI,
+	},
+};
+#endif
+
+int __init atari_platform_init(void)
+{
+	int rv = 0;
+
+	if (!MACH_IS_ATARI)
+		return -ENODEV;
+
+#ifdef CONFIG_ATARI_ETHERNAT
+	{
+		unsigned char *enatc_virt;
+		enatc_virt = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0xf);
+		if (hwreg_present(enatc_virt)) {
+			rv = platform_add_devices(atari_ethernat_devices,
+						ARRAY_SIZE(atari_ethernat_devices));
+		}
+		iounmap(enatc_virt);
+	}
+#endif
+
+#ifdef CONFIG_ATARI_ETHERNEC
+	{
+		int error;
+		unsigned char *enec_virt;
+		enec_virt = (unsigned char *)ioremap((ATARI_ETHERNEC_PHYS_ADDR), 0xf);
+		if (hwreg_present(enec_virt)) {
+			error = platform_add_devices(atari_netusbee_devices,
+						ARRAY_SIZE(atari_netusbee_devices));
+			if (error && !rv)
+				rv = error;
+		}
+		iounmap(enec_virt);
+	}
+#endif
+
+#if IS_ENABLED(CONFIG_ATARI_SCSI)
+	if (ATARIHW_PRESENT(ST_SCSI))
+		platform_device_register_simple("atari_scsi", -1,
+			atari_scsi_st_rsrc, ARRAY_SIZE(atari_scsi_st_rsrc));
+	else if (ATARIHW_PRESENT(TT_SCSI))
+		platform_device_register_simple("atari_scsi", -1,
+			atari_scsi_tt_rsrc, ARRAY_SIZE(atari_scsi_tt_rsrc));
+#endif
+
+	return rv;
+}
+
+arch_initcall(atari_platform_init);
diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c
new file mode 100644
index 0000000..03cb5e0
--- /dev/null
+++ b/arch/m68k/atari/debug.c
@@ -0,0 +1,329 @@
+/*
+ * linux/arch/m68k/atari/debug.c
+ *
+ * Atari debugging and serial console stuff
+ *
+ * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+
+/* Can be set somewhere, if a SCC master reset has already be done and should
+ * not be repeated; used by kgdb */
+int atari_SCC_reset_done;
+EXPORT_SYMBOL(atari_SCC_reset_done);
+
+static struct console atari_console_driver = {
+	.name	= "debug",
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
+};
+
+
+static inline void ata_mfp_out(char c)
+{
+	while (!(st_mfp.trn_stat & 0x80))	/* wait for tx buf empty */
+		barrier();
+	st_mfp.usart_dta = c;
+}
+
+static void atari_mfp_console_write(struct console *co, const char *str,
+				    unsigned int count)
+{
+	while (count--) {
+		if (*str == '\n')
+			ata_mfp_out('\r');
+		ata_mfp_out(*str++);
+	}
+}
+
+static inline void ata_scc_out(char c)
+{
+	do {
+		MFPDELAY();
+	} while (!(atari_scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+	MFPDELAY();
+	atari_scc.cha_b_data = c;
+}
+
+static void atari_scc_console_write(struct console *co, const char *str,
+				    unsigned int count)
+{
+	while (count--) {
+		if (*str == '\n')
+			ata_scc_out('\r');
+		ata_scc_out(*str++);
+	}
+}
+
+static inline void ata_midi_out(char c)
+{
+	while (!(acia.mid_ctrl & ACIA_TDRE))	/* wait for tx buf empty */
+		barrier();
+	acia.mid_data = c;
+}
+
+static void atari_midi_console_write(struct console *co, const char *str,
+				     unsigned int count)
+{
+	while (count--) {
+		if (*str == '\n')
+			ata_midi_out('\r');
+		ata_midi_out(*str++);
+	}
+}
+
+static int ata_par_out(char c)
+{
+	unsigned char tmp;
+	/* This a some-seconds timeout in case no printer is connected */
+	unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
+
+	while ((st_mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */
+		;
+	if (!i)
+		return 0;
+
+	sound_ym.rd_data_reg_sel = 15;	/* select port B */
+	sound_ym.wd_data = c;		/* put char onto port */
+	sound_ym.rd_data_reg_sel = 14;	/* select port A */
+	tmp = sound_ym.rd_data_reg_sel;
+	sound_ym.wd_data = tmp & ~0x20;	/* set strobe L */
+	MFPDELAY();			/* wait a bit */
+	sound_ym.wd_data = tmp | 0x20;	/* set strobe H */
+	return 1;
+}
+
+static void atari_par_console_write(struct console *co, const char *str,
+				    unsigned int count)
+{
+	static int printer_present = 1;
+
+	if (!printer_present)
+		return;
+
+	while (count--) {
+		if (*str == '\n') {
+			if (!ata_par_out('\r')) {
+				printer_present = 0;
+				return;
+			}
+		}
+		if (!ata_par_out(*str++)) {
+			printer_present = 0;
+			return;
+		}
+	}
+}
+
+#if 0
+int atari_mfp_console_wait_key(struct console *co)
+{
+	while (!(st_mfp.rcv_stat & 0x80))	/* wait for rx buf filled */
+		barrier();
+	return st_mfp.usart_dta;
+}
+
+int atari_scc_console_wait_key(struct console *co)
+{
+	do {
+		MFPDELAY();
+	} while (!(atari_scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */
+	MFPDELAY();
+	return atari_scc.cha_b_data;
+}
+
+int atari_midi_console_wait_key(struct console *co)
+{
+	while (!(acia.mid_ctrl & ACIA_RDRF)) /* wait for rx buf filled */
+		barrier();
+	return acia.mid_data;
+}
+#endif
+
+/*
+ * The following two functions do a quick'n'dirty initialization of the MFP or
+ * SCC serial ports. They're used by the debugging interface, kgdb, and the
+ * serial console code.
+ */
+static void __init atari_init_mfp_port(int cflag)
+{
+	/*
+	 * timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
+	 * bps, resp., and work only correct if there's a RSVE or RSSPEED
+	 */
+	static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 };
+	int baud = cflag & CBAUD;
+	int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0;
+	int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00;
+
+	if (cflag & CBAUDEX)
+		baud += B38400;
+	if (baud < B1200 || baud > B38400+2)
+		baud = B9600;		/* use default 9600bps for non-implemented rates */
+	baud -= B1200;			/* baud_table[] starts at 1200bps */
+
+	st_mfp.trn_stat &= ~0x01;	/* disable TX */
+	st_mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
+	st_mfp.tim_ct_cd &= 0x70;	/* stop timer D */
+	st_mfp.tim_dt_d = baud_table[baud];
+	st_mfp.tim_ct_cd |= 0x01;	/* start timer D, 1:4 */
+	st_mfp.trn_stat |= 0x01;	/* enable TX */
+}
+
+#define SCC_WRITE(reg, val)				\
+	do {						\
+		atari_scc.cha_b_ctrl = (reg);		\
+		MFPDELAY();				\
+		atari_scc.cha_b_ctrl = (val);		\
+		MFPDELAY();				\
+	} while (0)
+
+/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
+ * delay of ~ 60us. */
+#define LONG_DELAY()					\
+	do {						\
+		int i;					\
+		for (i = 100; i > 0; --i)		\
+			MFPDELAY();			\
+	} while (0)
+
+static void __init atari_init_scc_port(int cflag)
+{
+	static int clksrc_table[9] =
+		/* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
+		{ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
+	static int brgsrc_table[9] =
+		/* reg 14: 0 = RTxC, 2 = PCLK */
+		{ 2, 2, 2, 2, 2, 2, 0, 2, 2 };
+	static int clkmode_table[9] =
+		/* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
+		{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
+	static int div_table[9] =
+		/* reg12 (BRG low) */
+		{ 208, 138, 103, 50, 24, 11, 1, 0, 0 };
+
+	int baud = cflag & CBAUD;
+	int clksrc, clkmode, div, reg3, reg5;
+
+	if (cflag & CBAUDEX)
+		baud += B38400;
+	if (baud < B1200 || baud > B38400+2)
+		baud = B9600;		/* use default 9600bps for non-implemented rates */
+	baud -= B1200;			/* tables starts at 1200bps */
+
+	clksrc  = clksrc_table[baud];
+	clkmode = clkmode_table[baud];
+	div     = div_table[baud];
+	if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
+		/* special treatment for TT, where rates >= 38400 are done via TRxC */
+		clksrc = 0x28;		/* TRxC */
+		clkmode = baud == 6 ? 0xc0 :
+			  baud == 7 ? 0x80 : /* really 76800bps */
+				      0x40;  /* really 153600bps */
+		div = 0;
+	}
+
+	reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
+	reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
+
+	(void)atari_scc.cha_b_ctrl;	/* reset reg pointer */
+	SCC_WRITE(9, 0xc0);		/* reset */
+	LONG_DELAY();			/* extra delay after WR9 access */
+	SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03)
+				      : 0 | 0x04 /* 1 stopbit */ | clkmode);
+	SCC_WRITE(3, reg3);
+	SCC_WRITE(5, reg5);
+	SCC_WRITE(9, 0);		/* no interrupts */
+	LONG_DELAY();			/* extra delay after WR9 access */
+	SCC_WRITE(10, 0);		/* NRZ mode */
+	SCC_WRITE(11, clksrc);		/* main clock source */
+	SCC_WRITE(12, div);		/* BRG value */
+	SCC_WRITE(13, 0);		/* BRG high byte */
+	SCC_WRITE(14, brgsrc_table[baud]);
+	SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0));
+	SCC_WRITE(3, reg3 | 1);
+	SCC_WRITE(5, reg5 | 8);
+
+	atari_SCC_reset_done = 1;
+}
+
+static void __init atari_init_midi_port(int cflag)
+{
+	int baud = cflag & CBAUD;
+	int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
+	/* warning 7N1 isn't possible! (instead 7O2 is used...) */
+	int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04;
+	int div;
+
+	/* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as
+	 * default) the standard MIDI speed 31250. */
+	if (cflag & CBAUDEX)
+		baud += B38400;
+	if (baud == B4800)
+		div = ACIA_DIV64;	/* really 7812.5 bps */
+	else if (baud == B38400+2 /* 115200 */)
+		div = ACIA_DIV1;	/* really 500 kbps (does that work??) */
+	else
+		div = ACIA_DIV16;	/* 31250 bps, standard for MIDI */
+
+	/* RTS low, ints disabled */
+	acia.mid_ctrl = div | csize | parity |
+		    ((atari_switches & ATARI_SWITCH_MIDI) ?
+		     ACIA_RHTID : ACIA_RLTID);
+}
+
+static int __init atari_debug_setup(char *arg)
+{
+	bool registered;
+
+	if (!MACH_IS_ATARI)
+		return 0;
+
+	if (!strcmp(arg, "ser"))
+		/* defaults to ser2 for a Falcon and ser1 otherwise */
+		arg = MACH_IS_FALCON ? "ser2" : "ser1";
+
+	registered = !!atari_console_driver.write;
+	if (!strcmp(arg, "ser1")) {
+		/* ST-MFP Modem1 serial port */
+		atari_init_mfp_port(B9600|CS8);
+		atari_console_driver.write = atari_mfp_console_write;
+	} else if (!strcmp(arg, "ser2")) {
+		/* SCC Modem2 serial port */
+		atari_init_scc_port(B9600|CS8);
+		atari_console_driver.write = atari_scc_console_write;
+	} else if (!strcmp(arg, "midi")) {
+		/* MIDI port */
+		atari_init_midi_port(B9600|CS8);
+		atari_console_driver.write = atari_midi_console_write;
+	} else if (!strcmp(arg, "par")) {
+		/* parallel printer */
+		atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */
+		sound_ym.rd_data_reg_sel = 7;	/* select mixer control */
+		sound_ym.wd_data = 0xff;	/* sound off, ports are output */
+		sound_ym.rd_data_reg_sel = 15;	/* select port B */
+		sound_ym.wd_data = 0;		/* no char */
+		sound_ym.rd_data_reg_sel = 14;	/* select port A */
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
+		atari_console_driver.write = atari_par_console_write;
+	}
+	if (atari_console_driver.write && !registered)
+		register_console(&atari_console_driver);
+
+	return 0;
+}
+
+early_param("debug", atari_debug_setup);
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
new file mode 100644
index 0000000..ba65f94
--- /dev/null
+++ b/arch/m68k/atari/stdma.c
@@ -0,0 +1,220 @@
+/*
+ *  linux/arch/m68k/atari/stmda.c
+ *
+ *  Copyright (C) 1994 Roman Hodek
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+
+/* This file contains some function for controlling the access to the  */
+/* ST-DMA chip that may be shared between devices. Currently we have:  */
+/*   TT:     Floppy and ACSI bus                                       */
+/*   Falcon: Floppy and SCSI                                           */
+/*                                                                     */
+/* The controlling functions set up a wait queue for access to the     */
+/* ST-DMA chip. Callers to stdma_lock() that cannot granted access are */
+/* put onto a queue and waked up later if the owner calls              */
+/* stdma_release(). Additionally, the caller gives his interrupt       */
+/* service routine to stdma_lock().                                    */
+/*                                                                     */
+/* On the Falcon, the IDE bus uses just the ACSI/Floppy interrupt, but */
+/* not the ST-DMA chip itself. So falhd.c needs not to lock the        */
+/* chip. The interrupt is routed to falhd.c if IDE is configured, the  */
+/* model is a Falcon and the interrupt was caused by the HD controller */
+/* (can be determined by looking at its status register).              */
+
+
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/genhd.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+
+#include <asm/atari_stdma.h>
+#include <asm/atariints.h>
+#include <asm/atarihw.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+static int stdma_locked;			/* the semaphore */
+						/* int func to be called */
+static irq_handler_t stdma_isr;
+static void *stdma_isr_data;			/* data passed to isr */
+static DECLARE_WAIT_QUEUE_HEAD(stdma_wait);	/* wait queue for ST-DMA */
+
+
+
+
+/***************************** Prototypes *****************************/
+
+static irqreturn_t stdma_int (int irq, void *dummy);
+
+/************************* End of Prototypes **************************/
+
+
+/**
+ * stdma_try_lock - attempt to acquire ST DMA interrupt "lock"
+ * @handler: interrupt handler to use after acquisition
+ *
+ * Returns !0 if lock was acquired; otherwise 0.
+ */
+
+int stdma_try_lock(irq_handler_t handler, void *data)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (stdma_locked) {
+		local_irq_restore(flags);
+		return 0;
+	}
+
+	stdma_locked   = 1;
+	stdma_isr      = handler;
+	stdma_isr_data = data;
+	local_irq_restore(flags);
+	return 1;
+}
+EXPORT_SYMBOL(stdma_try_lock);
+
+
+/*
+ * Function: void stdma_lock( isrfunc isr, void *data )
+ *
+ * Purpose: Tries to get a lock on the ST-DMA chip that is used by more
+ *   then one device driver. Waits on stdma_wait until lock is free.
+ *   stdma_lock() may not be called from an interrupt! You have to
+ *   get the lock in your main routine and release it when your
+ *   request is finished.
+ *
+ * Inputs: A interrupt function that is called until the lock is
+ *   released.
+ *
+ * Returns: nothing
+ *
+ */
+
+void stdma_lock(irq_handler_t handler, void *data)
+{
+	/* Since the DMA is used for file system purposes, we
+	 have to sleep uninterruptible (there may be locked
+	 buffers) */
+	wait_event(stdma_wait, stdma_try_lock(handler, data));
+}
+EXPORT_SYMBOL(stdma_lock);
+
+
+/*
+ * Function: void stdma_release( void )
+ *
+ * Purpose: Releases the lock on the ST-DMA chip.
+ *
+ * Inputs: none
+ *
+ * Returns: nothing
+ *
+ */
+
+void stdma_release(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	stdma_locked   = 0;
+	stdma_isr      = NULL;
+	stdma_isr_data = NULL;
+	wake_up(&stdma_wait);
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(stdma_release);
+
+
+/**
+ * stdma_is_locked_by - allow lock holder to check whether it needs to release.
+ * @handler: interrupt handler previously used to acquire lock.
+ *
+ * Returns !0 if locked for the given handler; 0 otherwise.
+ */
+
+int stdma_is_locked_by(irq_handler_t handler)
+{
+	unsigned long flags;
+	int result;
+
+	local_irq_save(flags);
+	result = stdma_locked && (stdma_isr == handler);
+	local_irq_restore(flags);
+
+	return result;
+}
+EXPORT_SYMBOL(stdma_is_locked_by);
+
+
+/*
+ * Function: int stdma_islocked( void )
+ *
+ * Purpose: Check if the ST-DMA is currently locked.
+ * Note: Returned status is only valid if ints are disabled while calling and
+ *       as long as they remain disabled.
+ *       If called with ints enabled, status can change only from locked to
+ *       unlocked, because ints may not lock the ST-DMA.
+ *
+ * Inputs: none
+ *
+ * Returns: != 0 if locked, 0 otherwise
+ *
+ */
+
+int stdma_islocked(void)
+{
+	return stdma_locked;
+}
+EXPORT_SYMBOL(stdma_islocked);
+
+
+/*
+ * Function: void stdma_init( void )
+ *
+ * Purpose: Initialize the ST-DMA chip access controlling.
+ *   It sets up the interrupt and its service routine. The int is registered
+ *   as slow int, client devices have to live with that (no problem
+ *   currently).
+ *
+ * Inputs: none
+ *
+ * Return: nothing
+ *
+ */
+
+void __init stdma_init(void)
+{
+	stdma_isr = NULL;
+	if (request_irq(IRQ_MFP_FDC, stdma_int, IRQF_SHARED,
+			"ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int))
+		pr_err("Couldn't register ST-DMA interrupt\n");
+}
+
+
+/*
+ * Function: void stdma_int()
+ *
+ * Purpose: The interrupt routine for the ST-DMA. It calls the isr
+ *   registered by stdma_lock().
+ *
+ */
+
+static irqreturn_t stdma_int(int irq, void *dummy)
+{
+  if (stdma_isr)
+      (*stdma_isr)(irq, stdma_isr_data);
+  return IRQ_HANDLED;
+}
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
new file mode 100644
index 0000000..c83d664
--- /dev/null
+++ b/arch/m68k/atari/stram.c
@@ -0,0 +1,198 @@
+/*
+ * Functions for ST-RAM allocations
+ *
+ * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+#include <linux/mount.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+
+#include <asm/setup.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/atarihw.h>
+#include <asm/atari_stram.h>
+#include <asm/io.h>
+
+
+/*
+ * The ST-RAM allocator allocates memory from a pool of reserved ST-RAM of
+ * configurable size, set aside on ST-RAM init.
+ * As long as this pool is not exhausted, allocation of real ST-RAM can be
+ * guaranteed.
+ */
+
+/* set if kernel is in ST-RAM */
+static int kernel_in_stram;
+
+static struct resource stram_pool = {
+	.name = "ST-RAM Pool"
+};
+
+static unsigned long pool_size = 1024*1024;
+
+static unsigned long stram_virt_offset;
+
+static int __init atari_stram_setup(char *arg)
+{
+	if (!MACH_IS_ATARI)
+		return 0;
+
+	pool_size = memparse(arg, NULL);
+	return 0;
+}
+
+early_param("stram_pool", atari_stram_setup);
+
+
+/*
+ * This init function is called very early by atari/config.c
+ * It initializes some internal variables needed for stram_alloc()
+ */
+void __init atari_stram_init(void)
+{
+	int i;
+
+	/*
+	 * determine whether kernel code resides in ST-RAM
+	 * (then ST-RAM is the first memory block at virtual 0x0)
+	 */
+	kernel_in_stram = (m68k_memory[0].addr == 0);
+
+	for (i = 0; i < m68k_num_memory; ++i) {
+		if (m68k_memory[i].addr == 0) {
+			return;
+		}
+	}
+
+	/* Should never come here! (There is always ST-Ram!) */
+	panic("atari_stram_init: no ST-RAM found!");
+}
+
+
+/*
+ * This function is called from setup_arch() to reserve the pages needed for
+ * ST-RAM management, if the kernel resides in ST-RAM.
+ */
+void __init atari_stram_reserve_pages(void *start_mem)
+{
+	if (kernel_in_stram) {
+		pr_debug("atari_stram pool: kernel in ST-RAM, using alloc_bootmem!\n");
+		stram_pool.start = (resource_size_t)alloc_bootmem_low_pages(pool_size);
+		stram_pool.end = stram_pool.start + pool_size - 1;
+		request_resource(&iomem_resource, &stram_pool);
+		stram_virt_offset = 0;
+		pr_debug("atari_stram pool: size = %lu bytes, resource = %pR\n",
+			pool_size, &stram_pool);
+		pr_debug("atari_stram pool: stram_virt_offset = %lx\n",
+			stram_virt_offset);
+	}
+}
+
+
+/*
+ * This function is called as arch initcall to reserve the pages needed for
+ * ST-RAM management, if the kernel does not reside in ST-RAM.
+ */
+int __init atari_stram_map_pages(void)
+{
+	if (!kernel_in_stram) {
+		/*
+		 * Skip page 0, as the fhe first 2 KiB are supervisor-only!
+		 */
+		pr_debug("atari_stram pool: kernel not in ST-RAM, using ioremap!\n");
+		stram_pool.start = PAGE_SIZE;
+		stram_pool.end = stram_pool.start + pool_size - 1;
+		request_resource(&iomem_resource, &stram_pool);
+		stram_virt_offset = (unsigned long) ioremap(stram_pool.start,
+				resource_size(&stram_pool)) - stram_pool.start;
+		pr_debug("atari_stram pool: size = %lu bytes, resource = %pR\n",
+			pool_size, &stram_pool);
+		pr_debug("atari_stram pool: stram_virt_offset = %lx\n",
+			stram_virt_offset);
+	}
+	return 0;
+}
+arch_initcall(atari_stram_map_pages);
+
+
+void *atari_stram_to_virt(unsigned long phys)
+{
+	return (void *)(phys + stram_virt_offset);
+}
+EXPORT_SYMBOL(atari_stram_to_virt);
+
+
+unsigned long atari_stram_to_phys(void *virt)
+{
+	return (unsigned long)(virt - stram_virt_offset);
+}
+EXPORT_SYMBOL(atari_stram_to_phys);
+
+
+void *atari_stram_alloc(unsigned long size, const char *owner)
+{
+	struct resource *res;
+	int error;
+
+	pr_debug("atari_stram_alloc: allocate %lu bytes\n", size);
+
+	/* round up */
+	size = PAGE_ALIGN(size);
+
+	res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+	if (!res)
+		return NULL;
+
+	res->name = owner;
+	error = allocate_resource(&stram_pool, res, size, 0, UINT_MAX,
+				  PAGE_SIZE, NULL, NULL);
+	if (error < 0) {
+		pr_err("atari_stram_alloc: allocate_resource() failed %d!\n",
+		       error);
+		kfree(res);
+		return NULL;
+	}
+
+	pr_debug("atari_stram_alloc: returning %pR\n", res);
+	return atari_stram_to_virt(res->start);
+}
+EXPORT_SYMBOL(atari_stram_alloc);
+
+
+void atari_stram_free(void *addr)
+{
+	unsigned long start = atari_stram_to_phys(addr);
+	struct resource *res;
+	unsigned long size;
+
+	res = lookup_resource(&stram_pool, start);
+	if (!res) {
+		pr_err("atari_stram_free: trying to free nonexistent region "
+		       "at %p\n", addr);
+		return;
+	}
+
+	size = resource_size(res);
+	pr_debug("atari_stram_free: free %lu bytes at %p\n", size, addr);
+	release_resource(res);
+	kfree(res);
+}
+EXPORT_SYMBOL(atari_stram_free);
diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
new file mode 100644
index 0000000..9cca642
--- /dev/null
+++ b/arch/m68k/atari/time.c
@@ -0,0 +1,293 @@
+/*
+ * linux/arch/m68k/atari/time.c
+ *
+ * Atari time and real time clock stuff
+ *
+ * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/mc146818rtc.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+
+#include <asm/atariints.h>
+
+DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL_GPL(rtc_lock);
+
+void __init
+atari_sched_init(irq_handler_t timer_routine)
+{
+    /* set Timer C data Register */
+    st_mfp.tim_dt_c = INT_TICKS;
+    /* start timer C, div = 1:100 */
+    st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
+    /* install interrupt service routine for MFP Timer C */
+    if (request_irq(IRQ_MFP_TIMC, timer_routine, 0, "timer", timer_routine))
+	pr_err("Couldn't register timer interrupt\n");
+}
+
+/* ++andreas: gettimeoffset fixed to check for pending interrupt */
+
+#define TICK_SIZE 10000
+
+/* This is always executed with interrupts disabled.  */
+u32 atari_gettimeoffset(void)
+{
+  u32 ticks, offset = 0;
+
+  /* read MFP timer C current value */
+  ticks = st_mfp.tim_dt_c;
+  /* The probability of underflow is less than 2% */
+  if (ticks > INT_TICKS - INT_TICKS / 50)
+    /* Check for pending timer interrupt */
+    if (st_mfp.int_pn_b & (1 << 5))
+      offset = TICK_SIZE;
+
+  ticks = INT_TICKS - ticks;
+  ticks = ticks * 10000L / INT_TICKS;
+
+  return (ticks + offset) * 1000;
+}
+
+
+static void mste_read(struct MSTE_RTC *val)
+{
+#define COPY(v) val->v=(mste_rtc.v & 0xf)
+	do {
+		COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
+		COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
+		COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
+		COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
+		COPY(year_tens) ;
+	/* prevent from reading the clock while it changed */
+	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
+#undef COPY
+}
+
+static void mste_write(struct MSTE_RTC *val)
+{
+#define COPY(v) mste_rtc.v=val->v
+	do {
+		COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
+		COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
+		COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
+		COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
+		COPY(year_tens) ;
+	/* prevent from writing the clock while it changed */
+	} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
+#undef COPY
+}
+
+#define	RTC_READ(reg)				\
+    ({	unsigned char	__val;			\
+		(void) atari_writeb(reg,&tt_rtc.regsel);	\
+		__val = tt_rtc.data;		\
+		__val;				\
+	})
+
+#define	RTC_WRITE(reg,val)			\
+    do {					\
+		atari_writeb(reg,&tt_rtc.regsel);	\
+		tt_rtc.data = (val);		\
+	} while(0)
+
+
+#define HWCLK_POLL_INTERVAL	5
+
+int atari_mste_hwclk( int op, struct rtc_time *t )
+{
+    int hour, year;
+    int hr24=0;
+    struct MSTE_RTC val;
+
+    mste_rtc.mode=(mste_rtc.mode | 1);
+    hr24=mste_rtc.mon_tens & 1;
+    mste_rtc.mode=(mste_rtc.mode & ~1);
+
+    if (op) {
+        /* write: prepare values */
+
+        val.sec_ones = t->tm_sec % 10;
+        val.sec_tens = t->tm_sec / 10;
+        val.min_ones = t->tm_min % 10;
+        val.min_tens = t->tm_min / 10;
+        hour = t->tm_hour;
+        if (!hr24) {
+	    if (hour > 11)
+		hour += 20 - 12;
+	    if (hour == 0 || hour == 20)
+		hour += 12;
+        }
+        val.hr_ones = hour % 10;
+        val.hr_tens = hour / 10;
+        val.day_ones = t->tm_mday % 10;
+        val.day_tens = t->tm_mday / 10;
+        val.mon_ones = (t->tm_mon+1) % 10;
+        val.mon_tens = (t->tm_mon+1) / 10;
+        year = t->tm_year - 80;
+        val.year_ones = year % 10;
+        val.year_tens = year / 10;
+        val.weekday = t->tm_wday;
+        mste_write(&val);
+        mste_rtc.mode=(mste_rtc.mode | 1);
+        val.year_ones = (year % 4);	/* leap year register */
+        mste_rtc.mode=(mste_rtc.mode & ~1);
+    }
+    else {
+        mste_read(&val);
+        t->tm_sec = val.sec_ones + val.sec_tens * 10;
+        t->tm_min = val.min_ones + val.min_tens * 10;
+        hour = val.hr_ones + val.hr_tens * 10;
+	if (!hr24) {
+	    if (hour == 12 || hour == 12 + 20)
+		hour -= 12;
+	    if (hour >= 20)
+                hour += 12 - 20;
+        }
+	t->tm_hour = hour;
+	t->tm_mday = val.day_ones + val.day_tens * 10;
+        t->tm_mon  = val.mon_ones + val.mon_tens * 10 - 1;
+        t->tm_year = val.year_ones + val.year_tens * 10 + 80;
+        t->tm_wday = val.weekday;
+    }
+    return 0;
+}
+
+int atari_tt_hwclk( int op, struct rtc_time *t )
+{
+    int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
+    unsigned long	flags;
+    unsigned char	ctrl;
+    int pm = 0;
+
+    ctrl = RTC_READ(RTC_CONTROL); /* control registers are
+                                   * independent from the UIP */
+
+    if (op) {
+        /* write: prepare values */
+
+        sec  = t->tm_sec;
+        min  = t->tm_min;
+        hour = t->tm_hour;
+        day  = t->tm_mday;
+        mon  = t->tm_mon + 1;
+        year = t->tm_year - atari_rtc_year_offset;
+        wday = t->tm_wday + (t->tm_wday >= 0);
+
+        if (!(ctrl & RTC_24H)) {
+	    if (hour > 11) {
+		pm = 0x80;
+		if (hour != 12)
+		    hour -= 12;
+	    }
+	    else if (hour == 0)
+		hour = 12;
+        }
+
+        if (!(ctrl & RTC_DM_BINARY)) {
+	    sec = bin2bcd(sec);
+	    min = bin2bcd(min);
+	    hour = bin2bcd(hour);
+	    day = bin2bcd(day);
+	    mon = bin2bcd(mon);
+	    year = bin2bcd(year);
+	    if (wday >= 0)
+		wday = bin2bcd(wday);
+        }
+    }
+
+    /* Reading/writing the clock registers is a bit critical due to
+     * the regular update cycle of the RTC. While an update is in
+     * progress, registers 0..9 shouldn't be touched.
+     * The problem is solved like that: If an update is currently in
+     * progress (the UIP bit is set), the process sleeps for a while
+     * (50ms). This really should be enough, since the update cycle
+     * normally needs 2 ms.
+     * If the UIP bit reads as 0, we have at least 244 usecs until the
+     * update starts. This should be enough... But to be sure,
+     * additionally the RTC_SET bit is set to prevent an update cycle.
+     */
+
+    while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
+	if (in_atomic() || irqs_disabled())
+	    mdelay(1);
+	else
+	    schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
+    }
+
+    local_irq_save(flags);
+    RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
+    if (!op) {
+        sec  = RTC_READ( RTC_SECONDS );
+        min  = RTC_READ( RTC_MINUTES );
+        hour = RTC_READ( RTC_HOURS );
+        day  = RTC_READ( RTC_DAY_OF_MONTH );
+        mon  = RTC_READ( RTC_MONTH );
+        year = RTC_READ( RTC_YEAR );
+        wday = RTC_READ( RTC_DAY_OF_WEEK );
+    }
+    else {
+        RTC_WRITE( RTC_SECONDS, sec );
+        RTC_WRITE( RTC_MINUTES, min );
+        RTC_WRITE( RTC_HOURS, hour + pm);
+        RTC_WRITE( RTC_DAY_OF_MONTH, day );
+        RTC_WRITE( RTC_MONTH, mon );
+        RTC_WRITE( RTC_YEAR, year );
+        if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
+    }
+    RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
+    local_irq_restore(flags);
+
+    if (!op) {
+        /* read: adjust values */
+
+        if (hour & 0x80) {
+	    hour &= ~0x80;
+	    pm = 1;
+	}
+
+	if (!(ctrl & RTC_DM_BINARY)) {
+	    sec = bcd2bin(sec);
+	    min = bcd2bin(min);
+	    hour = bcd2bin(hour);
+	    day = bcd2bin(day);
+	    mon = bcd2bin(mon);
+	    year = bcd2bin(year);
+	    wday = bcd2bin(wday);
+        }
+
+        if (!(ctrl & RTC_24H)) {
+	    if (!pm && hour == 12)
+		hour = 0;
+	    else if (pm && hour != 12)
+		hour += 12;
+        }
+
+        t->tm_sec  = sec;
+        t->tm_min  = min;
+        t->tm_hour = hour;
+        t->tm_mday = day;
+        t->tm_mon  = mon - 1;
+        t->tm_year = year + atari_rtc_year_offset;
+        t->tm_wday = wday - 1;
+    }
+
+    return( 0 );
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 8
+ * End:
+ */