summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig8
-rw-r--r--arch/arm/Makefile1
-rw-r--r--arch/arm/mach-gemini/Kconfig12
-rw-r--r--arch/arm/mach-gemini/Makefile7
-rw-r--r--arch/arm/mach-gemini/Makefile.boot9
-rw-r--r--arch/arm/mach-gemini/common.h27
-rw-r--r--arch/arm/mach-gemini/devices.c92
-rw-r--r--arch/arm/mach-gemini/include/mach/debug-macro.S23
-rw-r--r--arch/arm/mach-gemini/include/mach/entry-macro.S39
-rw-r--r--arch/arm/mach-gemini/include/mach/global_reg.h278
-rw-r--r--arch/arm/mach-gemini/include/mach/hardware.h75
-rw-r--r--arch/arm/mach-gemini/include/mach/io.h18
-rw-r--r--arch/arm/mach-gemini/include/mach/irqs.h50
-rw-r--r--arch/arm/mach-gemini/include/mach/memory.h19
-rw-r--r--arch/arm/mach-gemini/include/mach/system.h37
-rw-r--r--arch/arm/mach-gemini/include/mach/timex.h13
-rw-r--r--arch/arm/mach-gemini/include/mach/uncompress.h42
-rw-r--r--arch/arm/mach-gemini/include/mach/vmalloc.h10
-rw-r--r--arch/arm/mach-gemini/irq.c102
-rw-r--r--arch/arm/mach-gemini/mm.c82
-rw-r--r--arch/arm/mach-gemini/time.c89
21 files changed, 1033 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index dbfdf87f993..5686f4074dd 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -275,6 +275,12 @@ config ARCH_EP93XX
help
This enables support for the Cirrus EP93xx series of CPUs.
+config ARCH_GEMINI
+ bool "Cortina Systems Gemini"
+ select CPU_FA526
+ help
+ Support for the Cortina Systems Gemini family SoCs
+
config ARCH_FOOTBRIDGE
bool "FootBridge"
select CPU_SA110
@@ -598,6 +604,8 @@ source "arch/arm/mach-ep93xx/Kconfig"
source "arch/arm/mach-footbridge/Kconfig"
+source "arch/arm/mach-gemini/Kconfig"
+
source "arch/arm/mach-integrator/Kconfig"
source "arch/arm/mach-iop32x/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index d29f9260fb1..56e13bf2202 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -108,6 +108,7 @@ endif
machine-$(CONFIG_ARCH_PXA) := pxa
machine-$(CONFIG_ARCH_L7200) := l7200
machine-$(CONFIG_ARCH_INTEGRATOR) := integrator
+ machine-$(CONFIG_ARCH_GEMINI) := gemini
textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000
machine-$(CONFIG_ARCH_CLPS711X) := clps711x
machine-$(CONFIG_ARCH_IOP32X) := iop32x
diff --git a/arch/arm/mach-gemini/Kconfig b/arch/arm/mach-gemini/Kconfig
new file mode 100644
index 00000000000..3aff39abb18
--- /dev/null
+++ b/arch/arm/mach-gemini/Kconfig
@@ -0,0 +1,12 @@
+if ARCH_GEMINI
+
+menu "Cortina Systems Gemini Implementations"
+
+endmenu
+
+config GEMINI_MEM_SWAP
+ bool "Gemini memory is swapped"
+ help
+ Say Y here if Gemini memory is swapped by bootloader.
+
+endif
diff --git a/arch/arm/mach-gemini/Makefile b/arch/arm/mach-gemini/Makefile
new file mode 100644
index 00000000000..133e2050685
--- /dev/null
+++ b/arch/arm/mach-gemini/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y := irq.o mm.o time.o devices.o
diff --git a/arch/arm/mach-gemini/Makefile.boot b/arch/arm/mach-gemini/Makefile.boot
new file mode 100644
index 00000000000..22a52c228d9
--- /dev/null
+++ b/arch/arm/mach-gemini/Makefile.boot
@@ -0,0 +1,9 @@
+ifeq ($(CONFIG_GEMINI_MEM_SWAP),y)
+ zreladdr-y := 0x00008000
+params_phys-y := 0x00000100
+initrd_phys-y := 0x00800000
+else
+ zreladdr-y := 0x10008000
+params_phys-y := 0x10000100
+initrd_phys-y := 0x10800000
+endif
diff --git a/arch/arm/mach-gemini/common.h b/arch/arm/mach-gemini/common.h
new file mode 100644
index 00000000000..9c1afa1c580
--- /dev/null
+++ b/arch/arm/mach-gemini/common.h
@@ -0,0 +1,27 @@
+/*
+ * Common Gemini architecture functions
+ *
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+
+#ifndef __GEMINI_COMMON_H__
+#define __GEMINI_COMMON_H__
+
+struct mtd_partition;
+
+extern void gemini_map_io(void);
+extern void gemini_init_irq(void);
+extern void gemini_timer_init(void);
+
+/* Common platform devices registration functions */
+extern int platform_register_uart(void);
+extern int platform_register_pflash(unsigned int size,
+ struct mtd_partition *parts,
+ unsigned int nr_parts);
+
+#endif /* __GEMINI_COMMON_H__ */
diff --git a/arch/arm/mach-gemini/devices.c b/arch/arm/mach-gemini/devices.c
new file mode 100644
index 00000000000..6b525253d02
--- /dev/null
+++ b/arch/arm/mach-gemini/devices.c
@@ -0,0 +1,92 @@
+/*
+ * Common devices definition for Gemini
+ *
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/mtd/physmap.h>
+
+#include <mach/irqs.h>
+#include <mach/hardware.h>
+#include <mach/global_reg.h>
+
+static struct plat_serial8250_port serial_platform_data[] = {
+ {
+ .membase = (void *)IO_ADDRESS(GEMINI_UART_BASE),
+ .mapbase = GEMINI_UART_BASE,
+ .irq = IRQ_UART,
+ .uartclk = UART_CLK,
+ .regshift = 2,
+ .iotype = UPIO_MEM,
+ .type = PORT_16550A,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_FIXED_TYPE,
+ },
+ {},
+};
+
+static struct platform_device serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = serial_platform_data,
+ },
+};
+
+int platform_register_uart(void)
+{
+ return platform_device_register(&serial_device);
+}
+
+static struct resource flash_resource = {
+ .start = GEMINI_FLASH_BASE,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct physmap_flash_data pflash_platform_data = {};
+
+static struct platform_device pflash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &pflash_platform_data,
+ },
+ .resource = &flash_resource,
+ .num_resources = 1,
+};
+
+int platform_register_pflash(unsigned int size, struct mtd_partition *parts,
+ unsigned int nr_parts)
+{
+ unsigned int reg;
+
+ reg = __raw_readl(IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_STATUS);
+
+ if ((reg & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL)
+ return -ENXIO;
+
+ if (reg & FLASH_WIDTH_16BIT)
+ pflash_platform_data.width = 2;
+ else
+ pflash_platform_data.width = 1;
+
+ /* enable parallel flash pins and disable others */
+ reg = __raw_readl(IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_MISC_CTRL);
+ reg &= ~PFLASH_PADS_DISABLE;
+ reg |= SFLASH_PADS_DISABLE | NAND_PADS_DISABLE;
+ __raw_writel(reg, IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_MISC_CTRL);
+
+ flash_resource.end = flash_resource.start + size - 1;
+
+ pflash_platform_data.parts = parts;
+ pflash_platform_data.nr_parts = nr_parts;
+
+ return platform_device_register(&pflash_device);
+}
diff --git a/arch/arm/mach-gemini/include/mach/debug-macro.S b/arch/arm/mach-gemini/include/mach/debug-macro.S
new file mode 100644
index 00000000000..d04a6eaeae1
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/debug-macro.S
@@ -0,0 +1,23 @@
+/*
+ * Debugging macro include header
+ *
+ * Copyright (C) 1994-1999 Russell King
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <mach/hardware.h>
+
+ .macro addruart,rx
+ mrc p15, 0, \rx, c1, c0
+ tst \rx, #1 @ MMU enabled?
+ ldreq \rx, =GEMINI_UART_BASE @ physical
+ ldrne \rx, =IO_ADDRESS(GEMINI_UART_BASE) @ virtual
+ .endm
+
+#define UART_SHIFT 2
+#define FLOW_CONTROL
+#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-gemini/include/mach/entry-macro.S b/arch/arm/mach-gemini/include/mach/entry-macro.S
new file mode 100644
index 00000000000..1624f91a2b8
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/entry-macro.S
@@ -0,0 +1,39 @@
+/*
+ * Low-level IRQ helper macros for Gemini platform.
+ *
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <mach/hardware.h>
+
+#define IRQ_STATUS 0x14
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_preamble, base, tmp
+ .endm
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ ldr \irqstat, =IO_ADDRESS(GEMINI_INTERRUPT_BASE + IRQ_STATUS)
+ ldr \irqnr, [\irqstat]
+ cmp \irqnr, #0
+ beq 2313f
+ mov \tmp, \irqnr
+ mov \irqnr, #0
+2312:
+ tst \tmp, #1
+ bne 2313f
+ add \irqnr, \irqnr, #1
+ mov \tmp, \tmp, lsr #1
+ cmp \irqnr, #31
+ bcc 2312b
+2313:
+ .endm
diff --git a/arch/arm/mach-gemini/include/mach/global_reg.h b/arch/arm/mach-gemini/include/mach/global_reg.h
new file mode 100644
index 00000000000..de7ff7e849f
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/global_reg.h
@@ -0,0 +1,278 @@
+/*
+ * This file contains the hardware definitions for Gemini.
+ *
+ * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+#ifndef __MACH_GLOBAL_REG_H
+#define __MACH_GLOBAL_REG_H
+
+/* Global Word ID Register*/
+#define GLOBAL_ID 0x00
+
+#define CHIP_ID(reg) ((reg) >> 8)
+#define CHIP_REVISION(reg) ((reg) & 0xFF)
+
+/* Global Status Register */
+#define GLOBAL_STATUS 0x04
+
+#define CPU_BIG_ENDIAN (1 << 31)
+#define PLL_OSC_30M (1 << 30) /* else 60MHz */
+
+#define OPERATION_MODE_MASK (0xF << 26)
+#define OPM_IDDQ (0xF << 26)
+#define OPM_NAND (0xE << 26)
+#define OPM_RING (0xD << 26)
+#define OPM_DIRECT_BOOT (0xC << 26)
+#define OPM_USB1_PHY_TEST (0xB << 26)
+#define OPM_USB0_PHY_TEST (0xA << 26)
+#define OPM_SATA1_PHY_TEST (0x9 << 26)
+#define OPM_SATA0_PHY_TEST (0x8 << 26)
+#define OPM_ICE_ARM (0x7 << 26)
+#define OPM_ICE_FARADAY (0x6 << 26)
+#define OPM_PLL_BYPASS (0x5 << 26)
+#define OPM_DEBUG (0x4 << 26)
+#define OPM_BURN_IN (0x3 << 26)
+#define OPM_MBIST (0x2 << 26)
+#define OPM_SCAN (0x1 << 26)
+#define OPM_REAL (0x0 << 26)
+
+#define FLASH_TYPE_MASK (0x3 << 24)
+#define FLASH_TYPE_NAND_2K (0x3 << 24)
+#define FLASH_TYPE_NAND_512 (0x2 << 24)
+#define FLASH_TYPE_PARALLEL (0x1 << 24)
+#define FLASH_TYPE_SERIAL (0x0 << 24)
+/* if parallel */
+#define FLASH_WIDTH_16BIT (1 << 23) /* else 8 bit */
+/* if serial */
+#define FLASH_ATMEL (1 << 23) /* else STM */
+
+#define FLASH_SIZE_MASK (0x3 << 21)
+#define NAND_256M (0x3 << 21) /* and more */
+#define NAND_128M (0x2 << 21)
+#define NAND_64M (0x1 << 21)
+#define NAND_32M (0x0 << 21)
+#define ATMEL_16M (0x3 << 21) /* and more */
+#define ATMEL_8M (0x2 << 21)
+#define ATMEL_4M_2M (0x1 << 21)
+#define ATMEL_1M (0x0 << 21) /* and less */
+#define STM_32M (1 << 22) /* and more */
+#define STM_16M (0 << 22) /* and less */
+
+#define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */
+
+#define CPU_AHB_RATIO_MASK (0x3 << 18)
+#define CPU_AHB_1_1 (0x0 << 18)
+#define CPU_AHB_3_2 (0x1 << 18)
+#define CPU_AHB_24_13 (0x2 << 18)
+#define CPU_AHB_2_1 (0x3 << 18)
+
+#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130)
+#define AHB_SPEED_TO_REG(x) ((((x - 130)) / 10) << 15)
+
+/* it is posible to override some settings, use >> OVERRIDE_xxxx_SHIFT */
+#define OVERRIDE_FLASH_TYPE_SHIFT 16
+#define OVERRIDE_FLASH_WIDTH_SHIFT 16
+#define OVERRIDE_FLASH_SIZE_SHIFT 16
+#define OVERRIDE_CPU_AHB_RATIO_SHIFT 15
+#define OVERRIDE_AHB_SPEED_SHIFT 15
+
+/* Global PLL Control Register */
+#define GLOBAL_PLL_CTRL 0x08
+
+#define PLL_BYPASS (1 << 31)
+#define PLL_POWER_DOWN (1 << 8)
+#define PLL_CONTROL_Q (0x1F << 0)
+
+/* Global Soft Reset Control Register */
+#define GLOBAL_RESET 0x0C
+
+#define RESET_GLOBAL (1 << 31)
+#define RESET_CPU1 (1 << 30)
+#define RESET_TVE (1 << 28)
+#define RESET_SATA1 (1 << 27)
+#define RESET_SATA0 (1 << 26)
+#define RESET_CIR (1 << 25)
+#define RESET_EXT_DEV (1 << 24)
+#define RESET_WD (1 << 23)
+#define RESET_GPIO2 (1 << 22)
+#define RESET_GPIO1 (1 << 21)
+#define RESET_GPIO0 (1 << 20)
+#define RESET_SSP (1 << 19)
+#define RESET_UART (1 << 18)
+#define RESET_TIMER (1 << 17)
+#define RESET_RTC (1 << 16)
+#define RESET_INT1 (1 << 15)
+#define RESET_INT0 (1 << 14)
+#define RESET_LCD (1 << 13)
+#define RESET_LPC (1 << 12)
+#define RESET_APB (1 << 11)
+#define RESET_DMA (1 << 10)
+#define RESET_USB1 (1 << 9)
+#define RESET_USB0 (1 << 8)
+#define RESET_PCI (1 << 7)
+#define RESET_GMAC1 (1 << 6)
+#define RESET_GMAC0 (1 << 5)
+#define RESET_SECURITY (1 << 4)
+#define RESET_RAID (1 << 3)
+#define RESET_IDE (1 << 2)
+#define RESET_FLASH (1 << 1)
+#define RESET_DRAM (1 << 0)
+
+/* Global IO Pad Driving Capability Control Register */
+#define GLOBAL_IO_DRIVING_CTRL 0x10
+
+#define DRIVING_CURRENT_MASK 0x3
+
+/* here 00-4mA, 01-8mA, 10-12mA, 11-16mA */
+#define GPIO1_PADS_31_28_SHIFT 28
+#define GPIO0_PADS_31_16_SHIFT 26
+#define GPIO0_PADS_15_0_SHIFT 24
+#define PCI_AND_EXT_RESET_PADS_SHIFT 22
+#define IDE_PADS_SHIFT 20
+#define GMAC1_PADS_SHIFT 18
+#define GMAC0_PADS_SHIFT 16
+/* DRAM is not in mA and poorly documented */
+#define DRAM_CLOCK_PADS_SHIFT 8
+#define DRAM_DATA_PADS_SHIFT 4
+#define DRAM_CONTROL_PADS_SHIFT 0
+
+/* Global IO Pad Slew Rate Control Register */
+#define GLOBAL_IO_SLEW_RATE_CTRL 0x14
+
+#define GPIO1_PADS_31_28_SLOW (1 << 10)
+#define GPIO0_PADS_31_16_SLOW (1 << 9)
+#define GPIO0_PADS_15_0_SLOW (1 << 8)
+#define PCI_PADS_SLOW (1 << 7)
+#define IDE_PADS_SLOW (1 << 6)
+#define GMAC1_PADS_SLOW (1 << 5)
+#define GMAC0_PADS_SLOW (1 << 4)
+#define DRAM_CLOCK_PADS_SLOW (1 << 1)
+#define DRAM_IO_PADS_SLOW (1 << 0)
+
+/*
+ * General skew control defines
+ * 16 steps, each step is around 0.2ns
+ */
+#define SKEW_MASK 0xF
+
+/* Global IDE PAD Skew Control Register */
+#define GLOBAL_IDE_SKEW_CTRL 0x18
+
+#define IDE1_HOST_STROBE_DELAY_SHIFT 28
+#define IDE1_DEVICE_STROBE_DELAY_SHIFT 24
+#define IDE1_OUTPUT_IO_SKEW_SHIFT 20
+#define IDE1_INPUT_IO_SKEW_SHIFT 16
+#define IDE0_HOST_STROBE_DELAY_SHIFT 12
+#define IDE0_DEVICE_STROBE_DELAY_SHIFT 8
+#define IDE0_OUTPUT_IO_SKEW_SHIFT 4
+#define IDE0_INPUT_IO_SKEW_SHIFT 0
+
+/* Global GMAC Control Pad Skew Control Register */
+#define GLOBAL_GMAC_CTRL_SKEW_CTRL 0x1C
+
+#define GMAC1_TXC_SKEW_SHIFT 28
+#define GMAC1_TXEN_SKEW_SHIFT 24
+#define GMAC1_RXC_SKEW_SHIFT 20
+#define GMAC1_RXDV_SKEW_SHIFT 16
+#define GMAC0_TXC_SKEW_SHIFT 12
+#define GMAC0_TXEN_SKEW_SHIFT 8
+#define GMAC0_RXC_SKEW_SHIFT 4
+#define GMAC0_RXDV_SKEW_SHIFT 0
+
+/* Global GMAC0 Data PAD Skew Control Register */
+#define GLOBAL_GMAC0_DATA_SKEW_CTRL 0x20
+/* Global GMAC1 Data PAD Skew Control Register */
+#define GLOBAL_GMAC1_DATA_SKEW_CTRL 0x24
+
+#define GMAC_TXD_SKEW_SHIFT(x) (((x) * 4) + 16)
+#define GMAC_RXD_SKEW_SHIFT(x) ((x) * 4)
+
+/* CPU has two AHB busses. */
+
+/* Global Arbitration0 Control Register */
+#define GLOBAL_ARBITRATION0_CTRL 0x28
+
+#define BOOT_CONTROLLER_HIGH_PRIO (1 << 3)
+#define DMA_BUS1_HIGH_PRIO (1 << 2)
+#define CPU0_HIGH_PRIO (1 << 0)
+
+/* Global Arbitration1 Control Register */
+#define GLOBAL_ARBITRATION1_CTRL 0x2C
+
+#define TVE_HIGH_PRIO (1 << 9)
+#define PCI_HIGH_PRIO (1 << 8)
+#define USB1_HIGH_PRIO (1 << 7)
+#define USB0_HIGH_PRIO (1 << 6)
+#define GMAC1_HIGH_PRIO (1 << 5)
+#define GMAC0_HIGH_PRIO (1 << 4)
+#define SECURITY_HIGH_PRIO (1 << 3)
+#define RAID_HIGH_PRIO (1 << 2)
+#define IDE_HIGH_PRIO (1 << 1)
+#define DMA_BUS2_HIGH_PRIO (1 << 0)
+
+/* Common bits for both arbitration registers */
+#define BURST_LENGTH_SHIFT 16
+#define BURST_LENGTH_MASK (0x3F << 16)
+
+/* Miscellaneous Control Register */
+#define GLOBAL_MISC_CTRL 0x30
+
+#define MEMORY_SPACE_SWAP (1 << 31)
+#define USB1_PLUG_MINIB (1 << 30) /* else plug is mini-A */
+#define USB0_PLUG_MINIB (1 << 29)
+#define GMAC_GMII (1 << 28)
+#define GMAC_1_ENABLE (1 << 27)
+/* TODO: define ATA/SATA bits */
+#define USB1_VBUS_ON (1 << 23)
+#define USB0_VBUS_ON (1 << 22)
+#define APB_CLKOUT_ENABLE (1 << 21)
+#define TVC_CLKOUT_ENABLE (1 << 20)
+#define EXT_CLKIN_ENABLE (1 << 19)
+#define PCI_66MHZ (1 << 18) /* else 33 MHz */
+#define PCI_CLKOUT_ENABLE (1 << 17)
+#define LPC_CLKOUT_ENABLE (1 << 16)
+#define USB1_WAKEUP_ON (1 << 15)
+#define USB0_WAKEUP_ON (1 << 14)
+/* TODO: define PCI idle detect bits */
+#define TVC_PADS_ENABLE (1 << 9)
+#define SSP_PADS_ENABLE (1 << 8)
+#define LCD_PADS_ENABLE (1 << 7)
+#define LPC_PADS_ENABLE (1 << 6)
+#define PCI_PADS_ENABLE (1 << 5)
+#define IDE_PADS_ENABLE (1 << 4)
+#define DRAM_PADS_POWER_DOWN (1 << 3)
+#define NAND_PADS_DISABLE (1 << 2)
+#define PFLASH_PADS_DISABLE (1 << 1)
+#define SFLASH_PADS_DISABLE (1 << 0)
+
+/* Global Clock Control Register */
+#define GLOBAL_CLOCK_CTRL 0x34
+
+#define POWER_STATE_G0 (1 << 31)
+#define POWER_STATE_S1 (1 << 30) /* else it is S3/S4 state */
+#define SECURITY_APB_AHB (1 << 29)
+/* else Security APB clk will be 0.75xAHB */
+/* TODO: TVC clock divider */
+#define PCI_CLKRUN_ENABLE (1 << 16)
+#define BOOT_CLK_DISABLE (1 << 13)
+#define TVC_CLK_DISABLE (1 << 12)
+#define FLASH_CLK_DISABLE (1 << 11)
+#define DDR_CLK_DISABLE (1 << 10)
+#define PCI_CLK_DISABLE (1 << 9)
+#define IDE_CLK_DISABLE (1 << 8)
+#define USB1_CLK_DISABLE (1 << 7)
+#define USB0_CLK_DISABLE (1 << 6)
+#define SATA1_CLK_DISABLE (1 << 5)
+#define SATA0_CLK_DISABLE (1 << 4)
+#define GMAC1_CLK_DISABLE (1 << 3)
+#define GMAC0_CLK_DISABLE (1 << 2)
+#define SECURITY_CLK_DISABLE (1 << 1)
+
+/* TODO: other registers definitions if needed */
+
+#endif /* __MACH_GLOBAL_REG_H */
diff --git a/arch/arm/mach-gemini/include/mach/hardware.h b/arch/arm/mach-gemini/include/mach/hardware.h
new file mode 100644
index 00000000000..de6752674c0
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/hardware.h
@@ -0,0 +1,75 @@
+/*
+ * This file contains the hardware definitions for Gemini.
+ *
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+#ifndef __MACH_HARDWARE_H
+#define __MACH_HARDWARE_H
+
+/*
+ * Memory Map definitions
+ */
+/* FIXME: Does it really swap SRAM like this? */
+#ifdef CONFIG_GEMINI_MEM_SWAP
+# define GEMINI_DRAM_BASE 0x00000000
+# define GEMINI_SRAM_BASE 0x20000000
+#else
+# define GEMINI_SRAM_BASE 0x00000000
+# define GEMINI_DRAM_BASE 0x10000000
+#endif
+#define GEMINI_FLASH_BASE 0x30000000
+#define GEMINI_GLOBAL_BASE 0x40000000
+#define GEMINI_WAQTCHDOG_BASE 0x41000000
+#define GEMINI_UART_BASE 0x42000000
+#define GEMINI_TIMER_BASE 0x43000000
+#define GEMINI_LCD_BASE 0x44000000
+#define GEMINI_RTC_BASE 0x45000000
+#define GEMINI_SATA_BASE 0x46000000
+#define GEMINI_LPC_HOST_BASE 0x47000000
+#define GEMINI_LPC_IO_BASE 0x47800000
+#define GEMINI_INTERRUPT_BASE 0x48000000
+/* TODO: Different interrupt controlers when SMP
+ * #define GEMINI_INTERRUPT0_BASE 0x48000000
+ * #define GEMINI_INTERRUPT1_BASE 0x49000000
+ */
+#define GEMINI_SSP_CTRL_BASE 0x4A000000
+#define GEMINI_POWER_CTRL_BASE 0x4B000000
+#define GEMINI_CIR_BASE 0x4C000000
+#define GEMINI_GPIO_BASE(x) (0x4D000000 + (x) * 0x1000000)
+#define GEMINI_PCI_IO_BASE 0x50000000
+#define GEMINI_PCI_MEM_BASE 0x58000000
+#define GEMINI_TOE_BASE 0x60000000
+#define GEMINI_GMAC0_BASE 0x6000A000
+#define GEMINI_GMAC1_BASE 0x6000E000
+#define GEMINI_SECURITY_BASE 0x62000000
+#define GEMINI_IDE0_BASE 0x63000000
+#define GEMINI_IDE1_BASE 0x63400000
+#define GEMINI_RAID_BASE 0x64000000
+#define GEMINI_FLASH_CTRL_BASE 0x65000000
+#define GEMINI_DRAM_CTRL_BASE 0x66000000
+#define GEMINI_GENERAL_DMA_BASE 0x67000000
+#define GEMINI_USB0_BASE 0x68000000
+#define GEMINI_USB1_BASE 0x69000000
+#define GEMINI_BIG_ENDIAN_BASE 0x80000000
+
+#define GEMINI_TIMER1_BASE GEMINI_TIMER_BASE
+#define GEMINI_TIMER2_BASE (GEMINI_TIMER_BASE + 0x10)
+#define GEMINI_TIMER3_BASE (GEMINI_TIMER_BASE + 0x20)
+
+/*
+ * UART Clock when System clk is 150MHz
+ */
+#define UART_CLK 48000000
+
+/*
+ * macro to get at IO space when running virtually
+ */
+#define IO_ADDRESS(x) ((((x) & 0xFFF00000) >> 4) | ((x) & 0x000FFFFF) | 0xF0000000)
+
+#endif
diff --git a/arch/arm/mach-gemini/include/mach/io.h b/arch/arm/mach-gemini/include/mach/io.h
new file mode 100644
index 00000000000..c548056b98b
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/io.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+#ifndef __MACH_IO_H
+#define __MACH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a) __typesafe_io(a)
+#define __mem_pci(a) (a)
+
+#endif /* __MACH_IO_H */
diff --git a/arch/arm/mach-gemini/include/mach/irqs.h b/arch/arm/mach-gemini/include/mach/irqs.h
new file mode 100644
index 00000000000..c7728ac458f
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/irqs.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+
+#ifndef __MACH_IRQS_H__
+#define __MACH_IRQS_H__
+
+#define IRQ_SERIRQ1 31
+#define IRQ_SERIRQ0 30
+#define IRQ_PCID 29
+#define IRQ_PCIC 28
+#define IRQ_PCIB 27
+#define IRQ_PWR 26
+#define IRQ_CIR 25
+#define IRQ_GPIO(x) (22 + (x))
+#define IRQ_SSP 21
+#define IRQ_LPC 20
+#define IRQ_LCD 19
+#define IRQ_UART 18
+#define IRQ_RTC 17
+#define IRQ_TIMER3 16
+#define IRQ_TIMER2 15
+#define IRQ_TIMER1 14
+#define IRQ_FLASH 12
+#define IRQ_USB1 11
+#define IRQ_USB0 10
+#define IRQ_DMA 9
+#define IRQ_PCI 8
+#define IRQ_IPSEC 7
+#define IRQ_RAID 6
+#define IRQ_IDE1 5
+#define IRQ_IDE0 4
+#define IRQ_WATCHDOG 3
+#define IRQ_GMAC1 2
+#define IRQ_GMAC0 1
+#define IRQ_IPI 0
+
+#define NORMAL_IRQ_NUM 32
+
+#define ARCH_TIMER_IRQ IRQ_TIMER2
+
+#define NR_IRQS NORMAL_IRQ_NUM
+
+#endif /* __MACH_IRQS_H__ */
diff --git a/arch/arm/mach-gemini/include/mach/memory.h b/arch/arm/mach-gemini/include/mach/memory.h
new file mode 100644
index 00000000000..2d14d5bf1f9
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/memory.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+#ifndef __MACH_MEMORY_H
+#define __MACH_MEMORY_H
+
+#ifdef CONFIG_GEMINI_MEM_SWAP
+# define PHYS_OFFSET UL(0x00000000)
+#else
+# define PHYS_OFFSET UL(0x10000000)
+#endif
+
+#endif /* __MACH_MEMORY_H */
diff --git a/arch/arm/mach-gemini/include/mach/system.h b/arch/arm/mach-gemini/include/mach/system.h
new file mode 100644
index 00000000000..bbbd72767a0
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/system.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+#ifndef __MACH_SYSTEM_H
+#define __MACH_SYSTEM_H
+
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/global_reg.h>
+
+static inline void arch_idle(void)
+{
+ /*
+ * Because of broken hardware we have to enable interrupts or the CPU
+ * will never wakeup... Acctualy it is not very good to enable
+ * interrupts here since scheduler can miss a tick, but there is
+ * no other way around this. Platforms that needs it for power saving
+ * should call enable_hlt() in init code, since by default it is
+ * disabled.
+ */
+ local_irq_enable();
+ cpu_do_idle();
+}
+
+static inline void arch_reset(char mode)
+{
+ __raw_writel(RESET_GLOBAL | RESET_CPU1,
+ IO_ADDRESS(GEMINI_GLOBAL_BASE) + GLOBAL_RESET);
+}
+
+#endif /* __MACH_SYSTEM_H */
diff --git a/arch/arm/mach-gemini/include/mach/timex.h b/arch/arm/mach-gemini/include/mach/timex.h
new file mode 100644
index 00000000000..dc5690ba975
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/timex.h
@@ -0,0 +1,13 @@
+/*
+ * Gemini timex specifications
+ *
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+
+/* When AHB bus frequency is 150MHz */
+#define CLOCK_TICK_RATE 38000000
diff --git a/arch/arm/mach-gemini/include/mach/uncompress.h b/arch/arm/mach-gemini/include/mach/uncompress.h
new file mode 100644
index 00000000000..59c5df7e716
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/uncompress.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on mach-pxa/include/mach/uncompress.h:
+ * Copyright: (C) 2001 MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+#ifndef __MACH_UNCOMPRESS_H
+#define __MACH_UNCOMPRESS_H
+
+#include <linux/serial_reg.h>
+#include <mach/hardware.h>
+
+static volatile unsigned long *UART = (unsigned long *)GEMINI_UART_BASE;
+
+/*
+ * The following code assumes the serial port has already been
+ * initialized by the bootloader. If you didn't setup a port in
+ * your bootloader then nothing will appear (which might be desired).
+ */
+static inline void putc(char c)
+{
+ while (!(UART[UART_LSR] & UART_LSR_THRE))
+ barrier();
+ UART[UART_TX] = c;
+}
+
+#define flush() do { } while (0)
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
+
+#endif /* __MACH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-gemini/include/mach/vmalloc.h b/arch/arm/mach-gemini/include/mach/vmalloc.h
new file mode 100644
index 00000000000..83e536d9436
--- /dev/null
+++ b/arch/arm/mach-gemini/include/mach/vmalloc.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+
+#define VMALLOC_END 0xF0000000
diff --git a/arch/arm/mach-gemini/irq.c b/arch/arm/mach-gemini/irq.c
new file mode 100644
index 00000000000..9e613ca8120
--- /dev/null
+++ b/arch/arm/mach-gemini/irq.c
@@ -0,0 +1,102 @@
+/*
+ * Interrupt routines for Gemini
+ *
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/stddef.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <mach/hardware.h>
+
+#define IRQ_SOURCE(base_addr) (base_addr + 0x00)
+#define IRQ_MASK(base_addr) (base_addr + 0x04)
+#define IRQ_CLEAR(base_addr) (base_addr + 0x08)
+#define IRQ_TMODE(base_addr) (base_addr + 0x0C)
+#define IRQ_TLEVEL(base_addr) (base_addr + 0x10)
+#define IRQ_STATUS(base_addr) (base_addr + 0x14)
+#define FIQ_SOURCE(base_addr) (base_addr + 0x20)
+#define FIQ_MASK(base_addr) (base_addr + 0x24)
+#define FIQ_CLEAR(base_addr) (base_addr + 0x28)
+#define FIQ_TMODE(base_addr) (base_addr + 0x2C)
+#define FIQ_LEVEL(base_addr) (base_addr + 0x30)
+#define FIQ_STATUS(base_addr) (base_addr + 0x34)
+
+static void gemini_ack_irq(unsigned int irq)
+{
+ __raw_writel(1 << irq, IRQ_CLEAR(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+}
+
+static void gemini_mask_irq(unsigned int irq)
+{
+ unsigned int mask;
+
+ mask = __raw_readl(IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+ mask &= ~(1 << irq);
+ __raw_writel(mask, IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+}
+
+static void gemini_unmask_irq(unsigned int irq)
+{
+ unsigned int mask;
+
+ mask = __raw_readl(IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+ mask |= (1 << irq);
+ __raw_writel(mask, IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+}
+
+static struct irq_chip gemini_irq_chip = {
+ .name = "INTC",
+ .ack = gemini_ack_irq,
+ .mask = gemini_mask_irq,
+ .unmask = gemini_unmask_irq,
+};
+
+static struct resource irq_resource = {
+ .name = "irq_handler",
+ .start = IO_ADDRESS(GEMINI_INTERRUPT_BASE),
+ .end = IO_ADDRESS(FIQ_STATUS(GEMINI_INTERRUPT_BASE)) + 4,
+};
+
+void __init gemini_init_irq(void)
+{
+ unsigned int i, mode = 0, level = 0;
+
+ /*
+ * Disable arch_idle() by default since it is buggy
+ * For more info see arch/arm/mach-gemini/include/mach/system.h
+ */
+ disable_hlt();
+
+ request_resource(&iomem_resource, &irq_resource);
+
+ for (i = 0; i < NR_IRQS; i++) {
+ set_irq_chip(i, &gemini_irq_chip);
+ if((i >= IRQ_TIMER1 && i <= IRQ_TIMER3) || (i >= IRQ_SERIRQ0 && i <= IRQ_SERIRQ1)) {
+ set_irq_handler(i, handle_edge_irq);
+ mode |= 1 << i;
+ level |= 1 << i;
+ } else {
+ set_irq_handler(i, handle_level_irq);
+ }
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+
+ /* Disable all interrupts */
+ __raw_writel(0, IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+ __raw_writel(0, FIQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+
+ /* Set interrupt mode */
+ __raw_writel(mode, IRQ_TMODE(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+ __raw_writel(level, IRQ_TLEVEL(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+}
diff --git a/arch/arm/mach-gemini/mm.c b/arch/arm/mach-gemini/mm.c
new file mode 100644
index 00000000000..51948242ec0
--- /dev/null
+++ b/arch/arm/mach-gemini/mm.c
@@ -0,0 +1,82 @@
+/*
+ * Static mappings for Gemini
+ *
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+
+/* Page table mapping for I/O region */
+static struct map_desc gemini_io_desc[] __initdata = {
+ {
+ .virtual = IO_ADDRESS(GEMINI_GLOBAL_BASE),
+ .pfn =__phys_to_pfn(GEMINI_GLOBAL_BASE),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_UART_BASE),
+ .pfn = __phys_to_pfn(GEMINI_UART_BASE),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_TIMER_BASE),
+ .pfn = __phys_to_pfn(GEMINI_TIMER_BASE),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_INTERRUPT_BASE),
+ .pfn = __phys_to_pfn(GEMINI_INTERRUPT_BASE),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_POWER_CTRL_BASE),
+ .pfn = __phys_to_pfn(GEMINI_POWER_CTRL_BASE),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_GPIO_BASE(0)),
+ .pfn = __phys_to_pfn(GEMINI_GPIO_BASE(0)),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_GPIO_BASE(1)),
+ .pfn = __phys_to_pfn(GEMINI_GPIO_BASE(1)),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_GPIO_BASE(2)),
+ .pfn = __phys_to_pfn(GEMINI_GPIO_BASE(2)),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_FLASH_CTRL_BASE),
+ .pfn = __phys_to_pfn(GEMINI_FLASH_CTRL_BASE),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_DRAM_CTRL_BASE),
+ .pfn = __phys_to_pfn(GEMINI_DRAM_CTRL_BASE),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(GEMINI_GENERAL_DMA_BASE),
+ .pfn = __phys_to_pfn(GEMINI_GENERAL_DMA_BASE),
+ .length = SZ_512K,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init gemini_map_io(void)
+{
+ iotable_init(gemini_io_desc, ARRAY_SIZE(gemini_io_desc));
+}
diff --git a/arch/arm/mach-gemini/time.c b/arch/arm/mach-gemini/time.c
new file mode 100644
index 00000000000..21dc5a89d1c
--- /dev/null
+++ b/arch/arm/mach-gemini/time.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2001-2006 Storlink, Corp.
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * 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.
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/global_reg.h>
+#include <asm/mach/time.h>
+
+/*
+ * Register definitions for the timers
+ */
+#define TIMER_COUNT(BASE_ADDR) (BASE_ADDR + 0x00)
+#define TIMER_LOAD(BASE_ADDR) (BASE_ADDR + 0x04)
+#define TIMER_MATCH1(BASE_ADDR) (BASE_ADDR + 0x08)
+#define TIMER_MATCH2(BASE_ADDR) (BASE_ADDR + 0x0C)
+#define TIMER_CR(BASE_ADDR) (BASE_ADDR + 0x30)
+
+#define TIMER_1_CR_ENABLE (1 << 0)
+#define TIMER_1_CR_CLOCK (1 << 1)
+#define TIMER_1_CR_INT (1 << 2)
+#define TIMER_2_CR_ENABLE (1 << 3)
+#define TIMER_2_CR_CLOCK (1 << 4)
+#define TIMER_2_CR_INT (1 << 5)
+#define TIMER_3_CR_ENABLE (1 << 6)
+#define TIMER_3_CR_CLOCK (1 << 7)
+#define TIMER_3_CR_INT (1 << 8)
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t gemini_timer_interrupt(int irq, void *dev_id)
+{
+ timer_tick();
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction gemini_timer_irq = {
+ .name = "Gemini Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = gemini_timer_interrupt,
+};
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+void __init gemini_timer_init(void)
+{
+ unsigned int tick_rate, reg_v;
+
+ reg_v = __raw_readl(IO_ADDRESS(GEMINI_GLOBAL_BASE + GLOBAL_STATUS));
+ tick_rate = REG_TO_AHB_SPEED(reg_v) * 1000000;
+
+ printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000);
+
+ tick_rate /= 6; /* APB bus run AHB*(1/6) */
+
+ switch(reg_v & CPU_AHB_RATIO_MASK) {
+ case CPU_AHB_1_1:
+ printk(KERN_CONT "(1/1)\n");
+ break;
+ case CPU_AHB_3_2:
+ printk(KERN_CONT "(3/2)\n");
+ break;
+ case CPU_AHB_24_13:
+ printk(KERN_CONT "(24/13)\n");
+ break;
+ case CPU_AHB_2_1:
+ printk(KERN_CONT "(2/1)\n");
+ break;
+ }
+
+ /*
+ * Make irqs happen for the system timer
+ */
+ setup_irq(IRQ_TIMER2, &gemini_timer_irq);
+ /* Start the timer */
+ __raw_writel(tick_rate / HZ, TIMER_COUNT(IO_ADDRESS(GEMINI_TIMER2_BASE)));
+ __raw_writel(tick_rate / HZ, TIMER_LOAD(IO_ADDRESS(GEMINI_TIMER2_BASE)));
+ __raw_writel(TIMER_2_CR_ENABLE | TIMER_2_CR_INT, TIMER_CR(IO_ADDRESS(GEMINI_TIMER_BASE)));
+}