From 823ad3e6e88353226ec28f48183a467181887a1b Mon Sep 17 00:00:00 2001
From: Kurt Mahan <kmahan@freescale.com>
Date: Wed, 31 Oct 2007 16:56:09 -0600
Subject: [PATCH] Core Coldfire/MCF54455 kernel changes.

LTIBName: mcfv4e-kernel-mods
Signed-off-by: Kurt Mahan <kmahan@freescale.com>
---
 arch/m68k/Kconfig              |   65 ++++++++++++++++++++++++++++++++++++++-
 arch/m68k/Kconfig.debug        |    9 +++++
 arch/m68k/Makefile             |   14 ++++++++
 arch/m68k/kernel/Makefile      |   15 ++++++---
 arch/m68k/kernel/asm-offsets.c |    7 ++++
 arch/m68k/kernel/dma.c         |   17 ++++++++++
 arch/m68k/kernel/process.c     |   57 +++++++++++++++++++++++++++++++++++
 arch/m68k/kernel/setup.c       |   49 ++++++++++++++++++++++++++----
 arch/m68k/kernel/time.c        |    5 +++
 arch/m68k/kernel/vmlinux.lds.S |    2 +
 10 files changed, 227 insertions(+), 13 deletions(-)

--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -119,6 +119,20 @@ config SUN3
 
 	  If you don't want to compile a kernel exclusively for a Sun 3, say N.
 
+config COLDFIRE
+	bool "ColdFire V4e support"
+	default y
+	select CFV4E
+	help
+	  Say Y if you want to build a kernel to run on one of the ColdFire
+	  V4e boards.
+
+config CFV4E
+	bool
+	depends on COLDFIRE
+	select MMU_CFV4E if MMU
+	default y
+
 config AMIGA
 	bool "Amiga support"
 	depends on !MMU_SUN3
@@ -294,14 +308,53 @@ config M68060
 	  If you anticipate running this kernel on a computer with a MC68060
 	  processor, say Y. Otherwise, say N.
 
+config M54455
+	bool "MCF54455 support"
+	depends on COLDFIRE
+	default y
+	help
+          This option will add support for the MCF54455 processor with mmu.
+
+config MCFCLK
+	int "M54455EVB System Clock"
+	depends on M54455
+	default 266666666
+	help
+	  System clock for EVB.  Usually 266MHz for u-boot and 200MHz for dBUG.
+
+config MCF_USER_HALT
+	bool "Coldfire User Halt Enable"
+	depends on M54455
+	default n
+	help
+	  Enables the HALT instruction in User Mode.
+
 config MMU_MOTOROLA
 	bool
-	depends on MMU && !MMU_SUN3
+	depends on MMU && !MMU_SUN3 && !COLDFIRE
 	default y
 
 config MMU_SUN3
 	bool
 
+config MMU_CFV4E
+	bool
+
+config SDRAM_BASE
+	hex
+	depends on M54455
+	default 0x40000000
+
+config SDRAM_SIZE
+	hex
+	depends on M54455
+	default 0x0FFFFFFF
+
+config NOR_FLASH_BASE
+	hex "NOR Flash Base Address"
+	depends on M54455
+	default 0x00000000
+
 config M68KFPU_EMU
 	bool "Math emulation support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
@@ -468,6 +521,14 @@ config ZONE_DMA
 source "drivers/pci/Kconfig"
 
 source "drivers/zorro/Kconfig"
+endmenu
+
+menu "Power management options"
+
+config PM
+	bool "Power Management support"
+	help
+	  Support processor power management modes
 
 endmenu
 
@@ -647,7 +708,7 @@ config DN_SERIAL
 
 config SERIAL_CONSOLE
 	bool "Support for serial port console"
-	depends on (AMIGA || ATARI || MAC || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL)
+	depends on (AMIGA || ATARI || MAC || SUN3 || SUN3X || VME || APOLLO || COLDFIRE) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL || SERIAL_COLDFIRE)
 	---help---
 	  If you say Y here, it will be possible to use a serial port as the
 	  system console (the system console is the device which receives all
--- a/arch/m68k/Kconfig.debug
+++ b/arch/m68k/Kconfig.debug
@@ -2,4 +2,13 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config BOOTPARAM
+	bool 'Compiled-in Kernel Boot Parameter'
+	depends on COLDFIRE
+
+config BOOTPARAM_STRING
+	string 'Kernel Boot Parameter'
+	default 'console=ttyS0,115200'
+	depends on BOOTPARAM
+
 endmenu
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -16,7 +16,9 @@
 KBUILD_DEFCONFIG := amiga_defconfig
 
 # override top level makefile
+ifndef CONFIG_COLDFIRE
 AS += -m68020
+endif
 LDFLAGS := -m m68kelf
 LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
 ifneq ($(SUBARCH),$(ARCH))
@@ -36,6 +38,7 @@ CHECKFLAGS += -D__mc68000__
 KBUILD_CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
 
 # enable processor switch if compiled only for a single cpu
+ifndef CONFIG_COLDFIRE
 ifndef CONFIG_M68020
 ifndef CONFIG_M68030
 
@@ -49,6 +52,12 @@ endif
 
 endif
 endif
+endif
+
+ifdef CONFIG_M54455
+CFLAGS := $(CFLAGS) -march=isac -mcpu=54455 -msoft-float -g 
+AFLAGS := $(AFLAGS) -march=isac -mcpu=54455 -msoft-float  
+endif
 
 ifdef CONFIG_KGDB
 # If configured for kgdb support, include debugging infos and keep the
@@ -57,8 +66,12 @@ KBUILD_CFLAGS := $(subst -fomit-frame-po
 endif
 
 ifndef CONFIG_SUN3
+ifndef CONFIG_COLDFIRE
 head-y := arch/m68k/kernel/head.o
 else
+head-y := arch/m68k/coldfire/head.o
+endif
+else
 head-y := arch/m68k/kernel/sun3-head.o
 endif
 
@@ -79,6 +92,7 @@ core-$(CONFIG_SUN3)		+= arch/m68k/sun3/	
 core-$(CONFIG_M68040)		+= arch/m68k/fpsp040/
 core-$(CONFIG_M68060)		+= arch/m68k/ifpsp060/
 core-$(CONFIG_M68KFPU_EMU)	+= arch/m68k/math-emu/
+core-$(CONFIG_COLDFIRE)		+= arch/m68k/coldfire/
 
 all:	zImage
 
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -2,14 +2,19 @@
 # Makefile for the linux kernel.
 #
 
-ifndef CONFIG_SUN3
-  extra-y := head.o
+ifdef CONFIG_SUN3
+  extra-y := sun3-head.o vmlinux.lds
+  obj-y := entry.o signal.o ints.o
 else
-  extra-y := sun3-head.o
+ifndef CONFIG_COLDFIRE
+  extra-y := head.o vmlinux.lds
+  obj-y := entry.o signal.o traps.o ints.o
+else   # CONFIG_COLDFIRE
+  extra-y := ../coldfire/head.o vmlinux.lds
+endif
 endif
-extra-y	+= vmlinux.lds
 
-obj-y	:= entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
+obj-y	+= process.o ptrace.o module.o \
 	   sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o devres.o
 
 devres-y = ../../../kernel/irq/devres.o
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -58,8 +58,15 @@ int main(void)
 	DEFINE(PT_A2, offsetof(struct pt_regs, a2));
 	DEFINE(PT_PC, offsetof(struct pt_regs, pc));
 	DEFINE(PT_SR, offsetof(struct pt_regs, sr));
+#ifdef CONFIG_COLDFIRE
+	/* Need to get the context out of struct mm for ASID setting */
+	DEFINE(MM_CONTEXT, offsetof(struct mm_struct, context));
+	/* Coldfire exception frame has vector *before* pc */
+	DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) - 4);
+#else
 	/* bitfields are a bit difficult */
 	DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
+#endif
 
 	/* offsets into the irq_handler struct */
 	DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
--- a/arch/m68k/kernel/dma.c
+++ b/arch/m68k/kernel/dma.c
@@ -17,6 +17,7 @@
 void *dma_alloc_coherent(struct device *dev, size_t size,
 			 dma_addr_t *handle, gfp_t flag)
 {
+#ifndef CONFIG_M54455
 	struct page *page, **map;
 	pgprot_t pgprot;
 	void *addr;
@@ -55,6 +56,18 @@ void *dma_alloc_coherent(struct device *
 	kfree(map);
 
 	return addr;
+#else
+	/*
+	 * On the M5445x platform the memory allocated with GFP_DMA
+	 * is guaranteed to be DMA'able.
+	 */
+	void *addr;
+
+	size = PAGE_ALIGN(size);
+	addr = kmalloc(size, GFP_DMA);
+	*handle = virt_to_phys(addr);
+	return addr;
+#endif
 }
 EXPORT_SYMBOL(dma_alloc_coherent);
 
@@ -62,7 +75,11 @@ void dma_free_coherent(struct device *de
 		       void *addr, dma_addr_t handle)
 {
 	pr_debug("dma_free_coherent: %p, %x\n", addr, handle);
+#ifndef CONFIG_M54455
 	vfree(addr);
+#else
+	kfree(addr);
+#endif
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -191,6 +191,7 @@ EXPORT_SYMBOL(kernel_thread);
 
 void flush_thread(void)
 {
+#if !defined(CONFIG_COLDFIRE)
 	unsigned long zero = 0;
 	set_fs(USER_DS);
 	current->thread.fs = __USER_DS;
@@ -198,6 +199,14 @@ void flush_thread(void)
 		asm volatile (".chip 68k/68881\n\t"
 			      "frestore %0@\n\t"
 			      ".chip 68k" : : "a" (&zero));
+#else
+	set_fs(USER_DS);
+	current->thread.fs = USER_DS;
+#if defined(CONFIG_FPU)
+	if (!FPU_IS_EMU)
+		asm volatile ("frestore %0@\n\t" : : "a" (&zero));
+#endif
+#endif
 }
 
 /*
@@ -261,6 +270,7 @@ int copy_thread(int nr, unsigned long cl
 	 * Must save the current SFC/DFC value, NOT the value when
 	 * the parent was last descheduled - RGH  10-08-96
 	 */
+#if !defined(CONFIG_COLDFIRE)
 	p->thread.fs = get_fs().seg;
 
 	if (!FPU_IS_EMU) {
@@ -272,9 +282,34 @@ int copy_thread(int nr, unsigned long cl
 				"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
 				: : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
 				: "memory");
+#else
+	p->thread.fs = get_fs();
+
+#if defined(CONFIG_FPU)
+	if (!FPU_IS_EMU) {
+		/* Copy the current fpu state */
+		asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0])
+			      : "memory");
+
+		if (p->thread.fpstate[0]) {
+			asm volatile ("fmovemd %/fp0-%/fp7,%0"
+				      : : "m" (p->thread.fp[0])
+				      : "memory");
+			asm volatile ("fmovel %/fpiar,%0"
+				      : : "m" (p->thread.fpcntl[0])
+				      : "memory");
+			asm volatile ("fmovel %/fpcr,%0"
+				      : : "m" (p->thread.fpcntl[1])
+				      : "memory");
+			asm volatile ("fmovel %/fpsr,%0"
+				      : : "m" (p->thread.fpcntl[2])
+				      : "memory");
+		}
 		/* Restore the state in case the fpu was busy */
 		asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
 	}
+#endif
+#endif
 
 	return 0;
 }
@@ -283,7 +318,9 @@ int copy_thread(int nr, unsigned long cl
 
 int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
 {
+#if !defined(CONFIG_COLDFIRE) || defined(CONFIG_FPU)
 	char fpustate[216];
+#endif
 
 	if (FPU_IS_EMU) {
 		int i;
@@ -300,6 +337,7 @@ int dump_fpu (struct pt_regs *regs, stru
 	}
 
 	/* First dump the fpu context to avoid protocol violation.  */
+#if !defined(CONFIG_COLDFIRE)
 	asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
 	if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
 		return 0;
@@ -310,6 +348,25 @@ int dump_fpu (struct pt_regs *regs, stru
 	asm volatile ("fmovemx %/fp0-%/fp7,%0"
 		:: "m" (fpu->fpregs[0])
 		: "memory");
+#elif defined(CONFIG_FPU)
+	asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
+	if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
+		return 0;
+
+	asm volatile ("fmovel %/fpiar,%0"
+		      : : "m" (fpu->fpcntl[0])
+		      : "memory");
+	asm volatile ("fmovel %/fpcr,%0"
+		      : : "m" (fpu->fpcntl[1])
+		      : "memory");
+	asm volatile ("fmovel %/fpsr,%0"
+		      : : "m" (fpu->fpcntl[2])
+		      : "memory");
+	asm volatile ("fmovemd %/fp0-%/fp7,%0"
+		      : : "m" (fpu->fpregs[0])
+		      : "memory");
+#endif
+
 	return 1;
 }
 EXPORT_SYMBOL(dump_fpu);
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -67,13 +67,22 @@ EXPORT_SYMBOL(m68k_memory);
 
 struct mem_info m68k_ramdisk;
 
+#if !defined(CONFIG_COLDFIRE)
 static char m68k_command_line[CL_SIZE];
+#else
+char m68k_command_line[CL_SIZE];
+unsigned long uboot_info_stk;
+EXPORT_SYMBOL(uboot_info_stk);
+#endif
 
 void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL;
 /* machine dependent irq functions */
 void (*mach_init_IRQ) (void) __initdata = NULL;
 void (*mach_get_model) (char *model);
 int (*mach_get_hardware_list) (char *buffer);
+#ifdef CONFIG_COLDFIRE
+void (*mach_tick)(void);
+#endif
 /* machine dependent timer functions */
 unsigned long (*mach_gettimeoffset) (void);
 int (*mach_hwclk) (int, struct rtc_time*);
@@ -128,13 +137,17 @@ extern void config_hp300(void);
 extern void config_q40(void);
 extern void config_sun3x(void);
 
+#ifdef CONFIG_COLDFIRE
+void coldfire_sort_memrec(void);
+#endif
+
 #define MASK_256K 0xfffc0000
 
 extern void paging_init(void);
 
 static void __init m68k_parse_bootinfo(const struct bi_record *record)
 {
-	while (record->tag != BI_LAST) {
+	while ((record->tag != BI_LAST) && !(CONFIG_COLDFIRE)) {
 		int unknown = 0;
 		const unsigned long *data = record->data;
 
@@ -192,7 +205,11 @@ static void __init m68k_parse_bootinfo(c
 					      record->size);
 	}
 
-	m68k_realnum_memory = m68k_num_memory;
+#ifdef CONFIG_COLDFIRE
+    coldfire_sort_memrec();
+#endif
+
+    m68k_realnum_memory = m68k_num_memory;
 #ifdef CONFIG_SINGLE_MEMORY_CHUNK
 	if (m68k_num_memory > 1) {
 		printk("Ignoring last %i chunks of physical memory\n",
@@ -205,7 +222,9 @@ static void __init m68k_parse_bootinfo(c
 void __init setup_arch(char **cmdline_p)
 {
 	extern int _etext, _edata, _end;
+#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE)
 	int i;
+#endif
 
 	/* The bootinfo is located right after the kernel bss */
 	m68k_parse_bootinfo((const struct bi_record *)&_end);
@@ -220,9 +239,10 @@ void __init setup_arch(char **cmdline_p)
 	 * We should really do our own FPU check at startup.
 	 * [what do we do with buggy 68LC040s? if we have problems
 	 *  with them, we should add a test to check_bugs() below] */
-#ifndef CONFIG_M68KFPU_EMU_ONLY
+#if !defined(CONFIG_M68KFPU_EMU_ONLY) && defined(CONFIG_FPU)
 	/* clear the fpu if we have one */
-	if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
+	if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060|
+			    FPU_CFV4E)) {
 		volatile int zero = 0;
 		asm volatile ("frestore %0" : : "m" (zero));
 	}
@@ -310,13 +330,18 @@ void __init setup_arch(char **cmdline_p)
 		config_sun3x();
 		break;
 #endif
+#ifdef CONFIG_COLDFIRE
+	case MACH_CFMMU:
+		config_coldfire();
+		break;
+#endif
 	default:
 		panic("No configuration setup");
 	}
 
 	paging_init();
 
-#ifndef CONFIG_SUN3
+#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE)
 	for (i = 1; i < m68k_num_memory; i++)
 		free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr,
 				  m68k_memory[i].size);
@@ -343,6 +368,10 @@ void __init setup_arch(char **cmdline_p)
 
 #endif /* !CONFIG_SUN3 */
 
+#ifdef CONFIG_COLDFIRE
+	mmu_context_init();
+#endif
+
 /* set ISA defs early as possible */
 #if defined(CONFIG_ISA) && defined(MULTI_ISA)
 #if defined(CONFIG_Q40)
@@ -373,6 +402,7 @@ static int show_cpuinfo(struct seq_file 
 #define LOOP_CYCLES_68030	(8)
 #define LOOP_CYCLES_68040	(3)
 #define LOOP_CYCLES_68060	(1)
+#define LOOP_CYCLES_COLDFIRE	(2)
 
 	if (CPU_IS_020) {
 		cpu = "68020";
@@ -386,6 +416,9 @@ static int show_cpuinfo(struct seq_file 
 	} else if (CPU_IS_060) {
 		cpu = "68060";
 		clockfactor = LOOP_CYCLES_68060;
+	} else if (CPU_IS_CFV4E) {
+		cpu = "ColdFire V4e";
+		clockfactor = LOOP_CYCLES_COLDFIRE;
 	} else {
 		cpu = "680x0";
 		clockfactor = 0;
@@ -404,6 +437,8 @@ static int show_cpuinfo(struct seq_file 
 		fpu = "68060";
 	else if (m68k_fputype & FPU_SUNFPA)
 		fpu = "Sun FPA";
+	else if (m68k_fputype & FPU_CFV4E)
+		fpu = "ColdFire V4e";
 	else
 		fpu = "none";
 #endif
@@ -420,6 +455,8 @@ static int show_cpuinfo(struct seq_file 
 		mmu = "Sun-3";
 	else if (m68k_mmutype & MMU_APOLLO)
 		mmu = "Apollo";
+	else if (m68k_mmutype & MMU_CFV4E)
+		mmu = "ColdFire";
 	else
 		mmu = "unknown";
 
@@ -482,7 +519,7 @@ int get_hardware_list(char *buffer)
 
 void check_bugs(void)
 {
-#ifndef CONFIG_M68KFPU_EMU
+#if !defined(CONFIG_M68KFPU_EMU) && !defined(CONFIG_M54455)
 	if (m68k_fputype == 0) {
 		printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
 			"WHICH IS REQUIRED BY LINUX/M68K ***\n");
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -40,6 +40,11 @@ static inline int set_rtc_mmss(unsigned 
  */
 static irqreturn_t timer_interrupt(int irq, void *dummy)
 {
+#ifdef CONFIG_COLDFIRE
+	/* kick hardware timer if necessary */
+	if (mach_tick)
+		mach_tick();
+#endif
 	do_timer(1);
 #ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
--- a/arch/m68k/kernel/vmlinux.lds.S
+++ b/arch/m68k/kernel/vmlinux.lds.S
@@ -5,6 +5,8 @@ PHDRS
 }
 #ifdef CONFIG_SUN3
 #include "vmlinux-sun3.lds"
+#elif CONFIG_COLDFIRE
+#include "../coldfire/vmlinux-cf.lds"
 #else
 #include "vmlinux-std.lds"
 #endif