Subject: [@num@/@total@] i.MX2 family: Add basic mach support (sources)
From: Juergen Beisert <j.beisert@pengutronix.de>

This patch adds basic mach support for the mx2 processor family, based
on the original freescale code and adapted to mainline kernel coding
style.

Things happend since last review:
 - this part adds the C sources and local build support to keep the
   patch small.
 - ran checkpatch.pl on it

TODO:

 - split into i.MX21/i.MX27 specific parts
 - how to include board specific header files everywhere instead in hardware.h
 - get a sign from freescale for the patch

Signed-off-by: Juergen Beisert <j.beisert@pengutronix.de>

---

 arch/arm/mach-mx2/Kconfig       |   11 +
 arch/arm/mach-mx2/Makefile      |    9 +
 arch/arm/mach-mx2/Makefile.boot |    3 
 arch/arm/mach-mx2/cpu_imx27.c   |   65 +++++++++
 arch/arm/mach-mx2/generic.c     |   74 ++++++++++
 arch/arm/mach-mx2/serial.c      |  284 ++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-mx2/system.c      |   62 ++++++++
 arch/arm/plat-mxc/Kconfig       |    1 
 8 files changed, 509 insertions(+)

Index: arch/arm/mach-mx2/cpu_imx27.c
===================================================================
--- /dev/null
+++ arch/arm/mach-mx2/cpu_imx27.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/*
+ * i.MX27 specific CPU detection code
+ */
+#include <linux/module.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include "crm_regs.h"
+
+static int cpu_silicon_rev = -1;
+static int cpu_partnumber;
+
+static void query_silicon_parameter(void)
+{
+	u32 val;
+	/*
+	 * now we have access to the IO registers. As we need
+	 * the silicon revision very early we read it here to
+	 * avoid any further hooks
+	*/
+	val = __raw_readl(IO_ADDRESS(SYSCTRL_BASE_ADDR) + SYS_CHIP_ID);
+
+	cpu_silicon_rev = (int)(val >> 28);
+	cpu_partnumber = (int)((val >> 12) & 0xFFFF);
+}
+
+/*
+ * Create inline functions to test for cpu revision
+ * Function name is cpu_is_<cpu name>_rev(rev)
+ *
+ * Returns:
+ *	 0 - not the cpu queried
+ *	 1 - cpu and revision match
+ *	 2 - cpu matches, but cpu revision is greater than queried rev
+ *	-1 - cpu matches, but cpu revision is less than queried rev
+ */
+int cpu_is_mx27_rev(int test_rev)
+{
+	if (cpu_silicon_rev == -1)
+		query_silicon_parameter();
+
+	if (cpu_partnumber != 0x8821)
+		return 0;
+
+	return test_rev == cpu_silicon_rev ?
+			1 : test_rev < cpu_silicon_rev ? -1 : 2;
+}
+EXPORT_SYMBOL(cpu_is_mx27_rev);
Index: arch/arm/mach-mx2/Kconfig
===================================================================
--- /dev/null
+++ arch/arm/mach-mx2/Kconfig
@@ -0,0 +1,11 @@
+comment "MX2 family CPU support"
+	depends on ARCH_MX2
+
+config MACH_MX27
+	bool "i.MX27 support"
+	depends on ARCH_MX2
+	help
+	  This enables support for Freescale's MX2 based i.MX27 processor.
+
+comment "MX2 Platforms"
+	depends on ARCH_MX2
Index: arch/arm/mach-mx2/Makefile
===================================================================
--- /dev/null
+++ arch/arm/mach-mx2/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y	:=  gpio_mux.o devices.o serial.o system.o generic.o
+
+obj-$(CONFIG_MACH_MX27) += cpu_imx27.o
Index: arch/arm/mach-mx2/Makefile.boot
===================================================================
--- /dev/null
+++ arch/arm/mach-mx2/Makefile.boot
@@ -0,0 +1,3 @@
+   zreladdr-y	:= 0xA0008000
+params_phys-y	:= 0xA0000100
+initrd_phys-y	:= 0xA0800000
Index: arch/arm/mach-mx2/system.c
===================================================================
--- /dev/null
+++ arch/arm/mach-mx2/system.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 1999 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/proc-fns.h>
+#include <asm/system.h>
+
+/*
+ * Put the CPU into idle mode. It is called by default_idle()
+ * in process.c file.
+ */
+void arch_idle(void)
+{
+	/*
+	 * This should do all the clock switching
+	 * and wait for interrupt tricks.
+	 */
+	cpu_do_idle();
+}
+
+#define WDOG_WCR_REG                    IO_ADDRESS(WDOG_BASE_ADDR)
+#define WDOG_WCR_SRS                    (1 << 4)
+
+/*
+ * Reset the system. It is called by machine_restart().
+ */
+void arch_reset(char mode)
+{
+	struct clk *clk;
+
+	clk = clk_get(NULL, "wdog_clk");
+	if (!clk) {
+		printk(KERN_ERR"Cannot activate the watchdog. Giving up\n");
+		return;
+	}
+
+	clk_enable(clk);
+
+	/* Assert SRS signal */
+	__raw_writew(__raw_readw(WDOG_WCR_REG) & ~WDOG_WCR_SRS, WDOG_WCR_REG);
+}
Index: arch/arm/mach-mx2/serial.c
===================================================================
--- /dev/null
+++ arch/arm/mach-mx2/serial.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <asm/hardware.h>
+#include <asm/arch/imx_uart.h>
+#include "serial.h"
+#include "devices.h"
+
+/*
+ * This is an array where each element holds information about a UART port,
+ * like base address of the UART, interrupt numbers etc. This structure is
+ * passed to the serial_core.c file. Based on which UART is used, the core file
+ * passes back the appropriate port structure as an argument to the control
+ * functions.
+ */
+static struct uart_mxc_port mxc_ports[6] = {
+	[0] = {
+	       .port = {
+			.membase = (void *)IO_ADDRESS(UART1_BASE_ADDR),
+			.mapbase = UART1_BASE_ADDR,
+			.iotype = SERIAL_IO_MEM,
+			.irq = UART1_INT1,
+			.fifosize = 32,
+			.flags = ASYNC_BOOT_AUTOCONF,
+			.line = 0,
+		},
+	       .ints_muxed = UART1_MUX_INTS,
+	       .irqs = {UART1_INT2, UART1_INT3},
+	       .hardware_flow = UART1_HW_FLOW,
+	       .cts_threshold = UART1_UCR4_CTSTL,
+	       .rx_threshold = UART1_UFCR_RXTL,
+	       .tx_threshold = UART1_UFCR_TXTL,
+	       .shared = UART1_SHARED_PERI,
+	       .rxd_mux = MXC_UART_RXDMUX,
+	       },
+	[1] = {
+	       .port = {
+			.membase = (void *)IO_ADDRESS(UART2_BASE_ADDR),
+			.mapbase = UART2_BASE_ADDR,
+			.iotype = SERIAL_IO_MEM,
+			.irq = UART2_INT1,
+			.fifosize = 32,
+			.flags = ASYNC_BOOT_AUTOCONF,
+			.line = 1,
+		},
+	       .ints_muxed = UART2_MUX_INTS,
+	       .irqs = {UART2_INT2, UART2_INT3},
+	       .hardware_flow = UART2_HW_FLOW,
+	       .cts_threshold = UART2_UCR4_CTSTL,
+	       .rx_threshold = UART2_UFCR_RXTL,
+	       .tx_threshold = UART2_UFCR_TXTL,
+	       .shared = UART2_SHARED_PERI,
+	       .rxd_mux = MXC_UART_RXDMUX,
+	       },
+	[2] = {
+	       .port = {
+			.membase = (void *)IO_ADDRESS(UART3_BASE_ADDR),
+			.mapbase = UART3_BASE_ADDR,
+			.iotype = SERIAL_IO_MEM,
+			.irq = UART3_INT1,
+			.fifosize = 32,
+			.flags = ASYNC_BOOT_AUTOCONF,
+			.line = 2,
+		},
+	       .ints_muxed = UART3_MUX_INTS,
+	       .irqs = {UART3_INT2, UART3_INT3},
+	       .hardware_flow = UART3_HW_FLOW,
+	       .cts_threshold = UART3_UCR4_CTSTL,
+	       .rx_threshold = UART3_UFCR_RXTL,
+	       .tx_threshold = UART3_UFCR_TXTL,
+	       .shared = UART3_SHARED_PERI,
+	       .rxd_mux = MXC_UART_IR_RXDMUX,
+	       },
+	[3] = {
+	       .port = {
+			.membase = (void *)IO_ADDRESS(UART4_BASE_ADDR),
+			.mapbase = UART4_BASE_ADDR,
+			.iotype = SERIAL_IO_MEM,
+			.irq = UART4_INT1,
+			.fifosize = 32,
+			.flags = ASYNC_BOOT_AUTOCONF,
+			.line = 3,
+		},
+	       .ints_muxed = UART4_MUX_INTS,
+	       .irqs = {UART4_INT2, UART4_INT3},
+	       .hardware_flow = UART4_HW_FLOW,
+	       .cts_threshold = UART4_UCR4_CTSTL,
+	       .rx_threshold = UART4_UFCR_RXTL,
+	       .tx_threshold = UART4_UFCR_TXTL,
+	       .shared = UART4_SHARED_PERI,
+	       .rxd_mux = MXC_UART_RXDMUX,
+	       },
+	[4] = {
+	       .port = {
+			.membase = (void *)IO_ADDRESS(UART5_BASE_ADDR),
+			.mapbase = UART5_BASE_ADDR,
+			.iotype = SERIAL_IO_MEM,
+			.irq = UART5_INT1,
+			.fifosize = 32,
+			.flags = ASYNC_BOOT_AUTOCONF,
+			.line = 4,
+		},
+	       .ints_muxed = UART5_MUX_INTS,
+	       .irqs = {UART5_INT2, UART5_INT3},
+	       .hardware_flow = UART5_HW_FLOW,
+	       .cts_threshold = UART5_UCR4_CTSTL,
+	       .rx_threshold = UART5_UFCR_RXTL,
+	       .tx_threshold = UART5_UFCR_TXTL,
+	       .shared = UART5_SHARED_PERI,
+	       .rxd_mux = MXC_UART_RXDMUX,
+	       },
+	[5] = {
+	       .port = {
+			.membase = (void *)IO_ADDRESS(UART6_BASE_ADDR),
+			.mapbase = UART6_BASE_ADDR,
+			.iotype = SERIAL_IO_MEM,
+			.irq = UART6_INT1,
+			.fifosize = 32,
+			.flags = ASYNC_BOOT_AUTOCONF,
+			.line = 5,
+		},
+	       .ints_muxed = UART6_MUX_INTS,
+	       .irqs = {UART6_INT2, UART6_INT3},
+	       .hardware_flow = UART6_HW_FLOW,
+	       .cts_threshold = UART6_UCR4_CTSTL,
+	       .rx_threshold = UART6_UFCR_RXTL,
+	       .tx_threshold = UART6_UFCR_TXTL,
+	       .shared = UART6_SHARED_PERI,
+	       .rxd_mux = MXC_UART_RXDMUX,
+	       },
+};
+
+static struct resource uart0 = {
+	.start = UART1_BASE_ADDR,
+	.end = UART1_BASE_ADDR + 0x0B5,
+	.flags = IORESOURCE_MEM
+};
+
+static struct platform_device mxc_uart_device0 = {
+	.name = "mxcintuart",
+	.id = 0,
+	.resource = &uart0,
+	.num_resources = 1,
+	.dev = {
+		.platform_data = &mxc_ports[0],
+	},
+};
+
+static struct resource uart1 = {
+	.start = UART2_BASE_ADDR,
+	.end = UART2_BASE_ADDR + 0x0B5,
+	.flags = IORESOURCE_MEM
+};
+
+static struct platform_device mxc_uart_device1 = {
+	.name = "mxcintuart",
+	.id = 1,
+	.resource = &uart1,
+	.num_resources = 1,
+	.dev = {
+		.platform_data = &mxc_ports[1],
+	},
+};
+
+static struct resource uart2 = {
+	.start = UART3_BASE_ADDR,
+	.end = UART3_BASE_ADDR + 0x0B5,
+	.flags = IORESOURCE_MEM
+};
+
+static struct platform_device mxc_uart_device2 = {
+	.name = "mxcintuart",
+	.id = 2,
+	.resource = &uart2,
+	.num_resources = 1,
+	.dev = {
+		.platform_data = &mxc_ports[2],
+	},
+};
+
+static struct resource uart3 = {
+	.start = UART4_BASE_ADDR,
+	.end = UART4_BASE_ADDR + 0x0B5,
+	.flags = IORESOURCE_MEM
+};
+
+static struct platform_device mxc_uart_device3 = {
+	.name = "mxcintuart",
+	.id = 3,
+	.resource = &uart3,
+	.num_resources = 1,
+	.dev = {
+		.platform_data = &mxc_ports[3],
+	},
+};
+
+static struct resource uart4 = {
+	.start = UART5_BASE_ADDR,
+	.end = UART5_BASE_ADDR + 0x0B5,
+	.flags = IORESOURCE_MEM
+};
+
+static struct platform_device mxc_uart_device4 = {
+	.name = "mxcintuart",
+	.id = 4,
+	.resource = &uart4,
+	.num_resources = 1,
+	.dev = {
+		.platform_data = &mxc_ports[4],
+	},
+};
+
+static struct resource uart5 = {
+	.start = UART6_BASE_ADDR,
+	.end = UART6_BASE_ADDR + 0x0B5,
+	.flags = IORESOURCE_MEM
+};
+
+static struct platform_device mxc_uart_device5 = {
+	.name = "mxcintuart",
+	.id = 5,
+	.resource = &uart5,
+	.num_resources = 1,
+	.dev = {
+		.platform_data = &mxc_ports[5],
+	},
+};
+
+/*
+ * Register only those UARTs that physically exists
+ */
+int __init mxc_init_uart(int uart_no, unsigned int flags,
+	int (*init)(struct platform_device *pdev),
+	int (*exit)(struct platform_device *pdev))
+{
+	mxc_ports[uart_no].flags = flags;
+	mxc_ports[uart_no].init = init;
+	mxc_ports[uart_no].exit = exit;
+
+	switch (uart_no) {
+	case 0:
+		platform_device_register(&mxc_uart_device0);
+		break;
+	case 1:
+		platform_device_register(&mxc_uart_device1);
+		break;
+#ifndef CONFIG_MXC_IRDA
+	case 2:
+		platform_device_register(&mxc_uart_device2);
+		break;
+#endif
+	case 3:
+		platform_device_register(&mxc_uart_device3);
+		break;
+	case 4:
+		platform_device_register(&mxc_uart_device4);
+		break;
+	case 5:
+		platform_device_register(&mxc_uart_device5);
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	return 0;
+}
Index: arch/arm/plat-mxc/Kconfig
===================================================================
--- arch/arm/plat-mxc/Kconfig.orig
+++ arch/arm/plat-mxc/Kconfig
@@ -18,6 +18,7 @@ config ARCH_MX3
 
 endchoice
 
+source "arch/arm/mach-mx2/Kconfig"
 source "arch/arm/mach-mx3/Kconfig"
 
 endmenu
Index: arch/arm/mach-mx2/generic.c
===================================================================
--- /dev/null
+++ arch/arm/mach-mx2/generic.c
@@ -0,0 +1,74 @@
+/*
+ * generic.c
+ *
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <asm/hardware.h>
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+
+/* MX27 memory map definition */
+static struct map_desc mxc_io_desc[] __initdata = {
+	/*
+	 * this fixed mapping covers:
+	 * - AIPI1
+	 * - AIPI2
+	 * - AITC
+	 * - ROM Patch
+	 * - and some reserved space
+	 */
+	{
+		.virtual = AIPI_BASE_ADDR_VIRT,
+		.pfn = __phys_to_pfn(AIPI_BASE_ADDR),
+		.length = AIPI_SIZE,
+		.type = MT_DEVICE
+	},
+	/*
+	 * this fixed mapping covers:
+	 * - CSI
+	 * - ATA
+	 */
+	{
+		.virtual = SAHB1_BASE_ADDR_VIRT,
+		.pfn = __phys_to_pfn(SAHB1_BASE_ADDR),
+		.length = SAHB1_SIZE,
+		.type = MT_DEVICE
+	},
+	/*
+	 * this fixed mapping covers:
+	 * - EMI
+	 */
+	{
+		.virtual = X_MEMC_BASE_ADDR_VIRT,
+		.pfn = __phys_to_pfn(X_MEMC_BASE_ADDR),
+		.length = X_MEMC_SIZE,
+		.type = MT_DEVICE
+	}
+};
+
+/*
+ * Initialize the memory map. It is called during the
+ * system startup to create static physical to virtual
+ * memory map for the IO modules.
+ */
+void __init imx_map_io(void)
+{
+	iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
+
+}
