Merge branch 'for-rmk' of git://gitorious.org/linux-gemini/mainline into devel
Russell King [Thu, 26 Mar 2009 23:10:11 +0000 (23:10 +0000)]
Conflicts:
arch/arm/mm/Kconfig

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

37 files changed:
MAINTAINERS
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/head.S
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/page.h
arch/arm/include/asm/proc-fns.h
arch/arm/include/asm/system.h
arch/arm/include/asm/tlbflush.h
arch/arm/mach-gemini/Kconfig [new file with mode: 0644]
arch/arm/mach-gemini/Makefile [new file with mode: 0644]
arch/arm/mach-gemini/Makefile.boot [new file with mode: 0644]
arch/arm/mach-gemini/board-rut1xx.c [new file with mode: 0644]
arch/arm/mach-gemini/common.h [new file with mode: 0644]
arch/arm/mach-gemini/devices.c [new file with mode: 0644]
arch/arm/mach-gemini/gpio.c [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/global_reg.h [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/mach-gemini/irq.c [new file with mode: 0644]
arch/arm/mach-gemini/mm.c [new file with mode: 0644]
arch/arm/mach-gemini/time.c [new file with mode: 0644]
arch/arm/mm/Kconfig
arch/arm/mm/Makefile
arch/arm/mm/cache-fa.S [new file with mode: 0644]
arch/arm/mm/copypage-fa.c [new file with mode: 0644]
arch/arm/mm/proc-fa526.S [new file with mode: 0644]
arch/arm/mm/tlb-fa.S [new file with mode: 0644]

index 50725d0..03b9fb9 100644 (file)
@@ -502,6 +502,13 @@ P: Richard Purdie
 M:     rpurdie@rpsys.net
 S:     Maintained
 
+ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
+P:     Paulius Zaleckas
+M:     paulius.zaleckas@teltonika.lt
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+T:     git gitorious.org/linux-gemini/mainline.git
+S:     Maintained
+
 ARM/EZX SMARTPHONES (A780, A910, A1200, E680, ROKR E2 and ROKR E6)
 P:     Daniel Ribeiro
 M:     drwyrm@gmail.com
@@ -513,6 +520,12 @@ L: openezx-devel@lists.openezx.org (subscribers-only)
 W:     http://www.openezx.org/
 S:     Maintained
 
+ARM/FARADAY FA526 PORT
+P:     Paulius Zaleckas
+M:     paulius.zaleckas@teltonika.lt
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S:     Maintained
+
 ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
 P:     Sascha Hauer
 M:     kernel@pengutronix.de
index e62b37a..e02b893 100644 (file)
@@ -276,6 +276,14 @@ config ARCH_EP93XX
        help
          This enables support for the Cirrus EP93xx series of CPUs.
 
+config ARCH_GEMINI
+       bool "Cortina Systems Gemini"
+       select CPU_FA526
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       help
+         Support for the Cortina Systems Gemini family SoCs
+
 config ARCH_FOOTBRIDGE
        bool "FootBridge"
        select CPU_SA110
@@ -616,6 +624,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"
index 95186ef..e84729b 100644 (file)
@@ -72,6 +72,7 @@ tune-$(CONFIG_CPU_ARM920T)    :=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_ARM922T)     :=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_ARM925T)     :=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_ARM926T)     :=-mtune=arm9tdmi
+tune-$(CONFIG_CPU_FA526)       :=-mtune=arm9tdmi
 tune-$(CONFIG_CPU_SA110)       :=-mtune=strongarm110
 tune-$(CONFIG_CPU_SA1100)      :=-mtune=strongarm1100
 tune-$(CONFIG_CPU_XSCALE)      :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
@@ -113,6 +114,7 @@ endif
     plat-$(CONFIG_PLAT_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
index d14b827..b371fba 100644 (file)
@@ -465,6 +465,20 @@ __armv7_mmu_cache_on:
                mcr     p15, 0, r0, c7, c5, 4   @ ISB
                mov     pc, r12
 
+__fa526_cache_on:
+               mov     r12, lr
+               bl      __setup_mmu
+               mov     r0, #0
+               mcr     p15, 0, r0, c7, c7, 0   @ Invalidate whole cache
+               mcr     p15, 0, r0, c7, c10, 4  @ drain write buffer
+               mcr     p15, 0, r0, c8, c7, 0   @ flush UTLB
+               mrc     p15, 0, r0, c1, c0, 0   @ read control reg
+               orr     r0, r0, #0x1000         @ I-cache enable
+               bl      __common_mmu_cache_on
+               mov     r0, #0
+               mcr     p15, 0, r0, c8, c7, 0   @ flush UTLB
+               mov     pc, r12
+
 __arm6_mmu_cache_on:
                mov     r12, lr
                bl      __setup_mmu
@@ -654,6 +668,12 @@ proc_types:
                b       __armv4_mmu_cache_off
                b       __armv5tej_mmu_cache_flush
 
+               .word   0x66015261              @ FA526
+               .word   0xff01fff1
+               b       __fa526_cache_on
+               b       __armv4_mmu_cache_off
+               b       __fa526_cache_flush
+
                @ These match on the architecture ID
 
                .word   0x00020000              @ ARMv4T
@@ -793,6 +813,12 @@ __armv4_mpu_cache_flush:
                mcr     p15, 0, ip, c7, c10, 4  @ drain WB
                mov     pc, lr
                
+__fa526_cache_flush:
+               mov     r1, #0
+               mcr     p15, 0, r1, c7, c14, 0  @ clean and invalidate D cache
+               mcr     p15, 0, r1, c7, c5, 0   @ flush I cache
+               mcr     p15, 0, r1, c7, c10, 4  @ drain WB
+               mov     pc, lr
 
 __armv6_mmu_cache_flush:
                mov     r1, #0
index bfb0cb9..bb7d695 100644 (file)
 # define MULTI_CACHE 1
 #endif
 
+#if defined(CONFIG_CPU_FA526)
+# ifdef _CACHE
+#  define MULTI_CACHE 1
+# else
+#  define _CACHE fa
+# endif
+#endif
+
 #if defined(CONFIG_CPU_ARM926T)
 # ifdef _CACHE
 #  define MULTI_CACHE 1
index f341c9d..e6eb8a6 100644 (file)
 # endif
 #endif
 
+#ifdef CONFIG_CPU_COPY_FA
+# ifdef _USER
+#  define MULTI_USER 1
+# else
+#  define _USER fa
+# endif
+#endif
+
 #ifdef CONFIG_CPU_SA1100
 # ifdef _USER
 #  define MULTI_USER 1
index c625031..3976412 100644 (file)
 #   define CPU_NAME cpu_arm922
 #  endif
 # endif
+# ifdef CONFIG_CPU_FA526
+#  ifdef CPU_NAME
+#   undef  MULTI_CPU
+#   define MULTI_CPU
+#  else
+#   define CPU_NAME cpu_fa526
+#  endif
+# endif
 # ifdef CONFIG_CPU_ARM925T
 #  ifdef CPU_NAME
 #   undef  MULTI_CPU
index 0a0d49a..bd4dc8e 100644 (file)
@@ -125,6 +125,12 @@ extern unsigned int user_debug;
                                    : : "r" (0) : "memory")
 #define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
                                    : : "r" (0) : "memory")
+#elif defined(CONFIG_CPU_FA526)
+#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
+                                   : : "r" (0) : "memory")
+#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+                                   : : "r" (0) : "memory")
+#define dmb() __asm__ __volatile__ ("" : : : "memory")
 #else
 #define isb() __asm__ __volatile__ ("" : : : "memory")
 #define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
index b543a05..a622180 100644 (file)
@@ -39,6 +39,7 @@
 #define TLB_V6_D_ASID  (1 << 17)
 #define TLB_V6_I_ASID  (1 << 18)
 
+#define TLB_BTB                (1 << 28)
 #define TLB_L2CLEAN_FR (1 << 29)               /* Feroceon */
 #define TLB_DCLEAN     (1 << 30)
 #define TLB_WB         (1 << 31)
@@ -53,6 +54,7 @@
  *       v4wb  - ARMv4 with write buffer without I TLB flush entry instruction
  *       v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
  *       fr    - Feroceon (v4wbi with non-outer-cacheable page table walks)
+ *       fa    - Faraday (v4 with write buffer with UTLB and branch target buffer (BTB))
  *       v6wbi - ARMv6 with write buffer with I TLB flush entry instruction
  *       v7wbi - identical to v6wbi
  */
 # define v4_always_flags       (-1UL)
 #endif
 
+#define fa_tlb_flags   (TLB_WB | TLB_BTB | TLB_DCLEAN | \
+                        TLB_V4_U_FULL | TLB_V4_U_PAGE)
+
+#ifdef CONFIG_CPU_TLB_FA
+# define fa_possible_flags     fa_tlb_flags
+# define fa_always_flags       fa_tlb_flags
+# ifdef _TLB
+#  define MULTI_TLB 1
+# else
+#  define _TLB fa
+# endif
+#else
+# define fa_possible_flags     0
+# define fa_always_flags       (-1UL)
+#endif
+
 #define v4wbi_tlb_flags        (TLB_WB | TLB_DCLEAN | \
                         TLB_V4_I_FULL | TLB_V4_D_FULL | \
                         TLB_V4_I_PAGE | TLB_V4_D_PAGE)
 # define v4wb_always_flags     (-1UL)
 #endif
 
-#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | \
+#define v6wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
                         TLB_V6_I_FULL | TLB_V6_D_FULL | \
                         TLB_V6_I_PAGE | TLB_V6_D_PAGE | \
                         TLB_V6_I_ASID | TLB_V6_D_ASID)
@@ -267,6 +285,7 @@ extern struct cpu_tlb_fns cpu_tlb;
                                 v4wbi_possible_flags | \
                                 fr_possible_flags | \
                                 v4wb_possible_flags | \
+                                fa_possible_flags | \
                                 v6wbi_possible_flags | \
                                 v7wbi_possible_flags)
 
@@ -275,6 +294,7 @@ extern struct cpu_tlb_fns cpu_tlb;
                                 v4wbi_always_flags & \
                                 fr_always_flags & \
                                 v4wb_always_flags & \
+                                fa_always_flags & \
                                 v6wbi_always_flags & \
                                 v7wbi_always_flags)
 
@@ -297,9 +317,7 @@ static inline void local_flush_tlb_all(void)
        if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
                asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
 
-       if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
-                    TLB_V6_I_PAGE | TLB_V6_D_PAGE |
-                    TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+       if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */
                asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
                dsb();
@@ -334,9 +352,7 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
        if (tlb_flag(TLB_V6_I_ASID))
                asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
 
-       if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
-                    TLB_V6_I_PAGE | TLB_V6_D_PAGE |
-                    TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+       if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */
                asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
                dsb();
@@ -374,9 +390,7 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
        if (tlb_flag(TLB_V6_I_PAGE))
                asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
 
-       if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
-                    TLB_V6_I_PAGE | TLB_V6_D_PAGE |
-                    TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+       if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */
                asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
                dsb();
@@ -411,9 +425,7 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
        if (tlb_flag(TLB_V6_I_PAGE))
                asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
 
-       if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
-                    TLB_V6_I_PAGE | TLB_V6_D_PAGE |
-                    TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+       if (tlb_flag(TLB_BTB)) {
                /* flush the branch target cache */
                asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
                dsb();
diff --git a/arch/arm/mach-gemini/Kconfig b/arch/arm/mach-gemini/Kconfig
new file mode 100644 (file)
index 0000000..515b75c
--- /dev/null
@@ -0,0 +1,19 @@
+if ARCH_GEMINI
+
+menu "Cortina Systems Gemini Implementations"
+
+config MACH_RUT100
+       bool "Teltonika RUT100"
+       select GEMINI_MEM_SWAP
+       help
+         Say Y here if you intend to run this kernel on a
+         Teltonika 3G Router RUT100.
+
+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 (file)
index 0000000..719505b
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y                  := irq.o mm.o time.o devices.o gpio.o
+
+# Board-specific support
+obj-$(CONFIG_MACH_RUT100)      += board-rut1xx.o
diff --git a/arch/arm/mach-gemini/Makefile.boot b/arch/arm/mach-gemini/Makefile.boot
new file mode 100644 (file)
index 0000000..22a52c2
--- /dev/null
@@ -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/board-rut1xx.c b/arch/arm/mach-gemini/board-rut1xx.c
new file mode 100644 (file)
index 0000000..e0de968
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *  Support for Teltonika RUT1xx
+ *
+ *  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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include "common.h"
+
+static struct gpio_keys_button rut1xx_keys[] = {
+       {
+               .code           = KEY_SETUP,
+               .gpio           = 60,
+               .active_low     = 1,
+               .desc           = "Reset to defaults",
+               .type           = EV_KEY,
+       },
+};
+
+static struct gpio_keys_platform_data rut1xx_keys_data = {
+       .buttons        = rut1xx_keys,
+       .nbuttons       = ARRAY_SIZE(rut1xx_keys),
+};
+
+static struct platform_device rut1xx_keys_device = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &rut1xx_keys_data,
+       },
+};
+
+static struct gpio_led rut100_leds[] = {
+       {
+               .name                   = "Power",
+               .default_trigger        = "heartbeat",
+               .gpio                   = 17,
+       },
+       {
+               .name                   = "GSM",
+               .default_trigger        = "default-on",
+               .gpio                   = 7,
+               .active_low             = 1,
+       },
+};
+
+static struct gpio_led_platform_data rut100_leds_data = {
+       .num_leds       = ARRAY_SIZE(rut100_leds),
+       .leds           = rut100_leds,
+};
+
+static struct platform_device rut1xx_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &rut100_leds_data,
+       },
+};
+
+static struct sys_timer rut1xx_timer = {
+       .init   = gemini_timer_init,
+};
+
+static void __init rut1xx_init(void)
+{
+       gemini_gpio_init();
+       platform_register_uart();
+       platform_register_pflash(SZ_8M, NULL, 0);
+       platform_device_register(&rut1xx_leds);
+       platform_device_register(&rut1xx_keys_device);
+}
+
+MACHINE_START(RUT100, "Teltonika RUT100")
+       .phys_io        = 0x7fffc000,
+       .io_pg_offst    = ((0xffffc000) >> 18) & 0xfffc,
+       .boot_params    = 0x100,
+       .map_io         = gemini_map_io,
+       .init_irq       = gemini_init_irq,
+       .timer          = &rut1xx_timer,
+       .init_machine   = rut1xx_init,
+MACHINE_END
diff --git a/arch/arm/mach-gemini/common.h b/arch/arm/mach-gemini/common.h
new file mode 100644 (file)
index 0000000..9392834
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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);
+extern void gemini_gpio_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 (file)
index 0000000..6b52525
--- /dev/null
@@ -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/gpio.c b/arch/arm/mach-gemini/gpio.c
new file mode 100644 (file)
index 0000000..e726385
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Gemini gpiochip and interrupt routines
+ *
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on plat-mxc/gpio.c:
+ *  MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
+ *  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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+#define GPIO_BASE(x)           IO_ADDRESS(GEMINI_GPIO_BASE(x))
+
+/* GPIO registers definition */
+#define GPIO_DATA_OUT          0x0
+#define GPIO_DATA_IN           0x4
+#define GPIO_DIR               0x8
+#define GPIO_DATA_SET          0x10
+#define GPIO_DATA_CLR          0x14
+#define GPIO_PULL_EN           0x18
+#define GPIO_PULL_TYPE         0x1C
+#define GPIO_INT_EN            0x20
+#define GPIO_INT_STAT          0x24
+#define GPIO_INT_MASK          0x2C
+#define GPIO_INT_CLR           0x30
+#define GPIO_INT_TYPE          0x34
+#define GPIO_INT_BOTH_EDGE     0x38
+#define GPIO_INT_LEVEL         0x3C
+#define GPIO_DEBOUNCE_EN       0x40
+#define GPIO_DEBOUNCE_PRESCALE 0x44
+
+#define GPIO_PORT_NUM          3
+
+static void _set_gpio_irqenable(unsigned int base, unsigned int index,
+                               int enable)
+{
+       unsigned int reg;
+
+       reg = __raw_readl(base + GPIO_INT_EN);
+       reg = (reg & (~(1 << index))) | (!!enable << index);
+       __raw_writel(reg, base + GPIO_INT_EN);
+}
+
+static void gpio_ack_irq(unsigned int irq)
+{
+       unsigned int gpio = irq_to_gpio(irq);
+       unsigned int base = GPIO_BASE(gpio / 32);
+
+       __raw_writel(1 << (gpio % 32), base + GPIO_INT_CLR);
+}
+
+static void gpio_mask_irq(unsigned int irq)
+{
+       unsigned int gpio = irq_to_gpio(irq);
+       unsigned int base = GPIO_BASE(gpio / 32);
+
+       _set_gpio_irqenable(base, gpio % 32, 0);
+}
+
+static void gpio_unmask_irq(unsigned int irq)
+{
+       unsigned int gpio = irq_to_gpio(irq);
+       unsigned int base = GPIO_BASE(gpio / 32);
+
+       _set_gpio_irqenable(base, gpio % 32, 1);
+}
+
+static int gpio_set_irq_type(unsigned int irq, unsigned int type)
+{
+       unsigned int gpio = irq_to_gpio(irq);
+       unsigned int gpio_mask = 1 << (gpio % 32);
+       unsigned int base = GPIO_BASE(gpio / 32);
+       unsigned int reg_both, reg_level, reg_type;
+
+       reg_type = __raw_readl(base + GPIO_INT_TYPE);
+       reg_level = __raw_readl(base + GPIO_INT_BOTH_EDGE);
+       reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE);
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_BOTH:
+               reg_type &= ~gpio_mask;
+               reg_both |= gpio_mask;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               reg_type &= ~gpio_mask;
+               reg_both &= ~gpio_mask;
+               reg_level &= ~gpio_mask;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               reg_type &= ~gpio_mask;
+               reg_both &= ~gpio_mask;
+               reg_level |= gpio_mask;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               reg_type |= gpio_mask;
+               reg_level &= ~gpio_mask;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               reg_type |= gpio_mask;
+               reg_level |= gpio_mask;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       __raw_writel(reg_type, base + GPIO_INT_TYPE);
+       __raw_writel(reg_level, base + GPIO_INT_BOTH_EDGE);
+       __raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE);
+
+       gpio_ack_irq(irq);
+
+       return 0;
+}
+
+static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned int gpio_irq_no, irq_stat;
+       unsigned int port = (unsigned int)get_irq_data(irq);
+
+       irq_stat = __raw_readl(GPIO_BASE(port) + GPIO_INT_STAT);
+
+       gpio_irq_no = GPIO_IRQ_BASE + port * 32;
+       for (; irq_stat != 0; irq_stat >>= 1, gpio_irq_no++) {
+
+               if ((irq_stat & 1) == 0)
+                       continue;
+
+               BUG_ON(!(irq_desc[gpio_irq_no].handle_irq));
+               irq_desc[gpio_irq_no].handle_irq(gpio_irq_no,
+                               &irq_desc[gpio_irq_no]);
+       }
+}
+
+static struct irq_chip gpio_irq_chip = {
+       .name = "GPIO",
+       .ack = gpio_ack_irq,
+       .mask = gpio_mask_irq,
+       .unmask = gpio_unmask_irq,
+       .set_type = gpio_set_irq_type,
+};
+
+static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset,
+                               int dir)
+{
+       unsigned int base = GPIO_BASE(offset / 32);
+       unsigned int reg;
+
+       reg = __raw_readl(base + GPIO_DIR);
+       if (dir)
+               reg |= 1 << (offset % 32);
+       else
+               reg &= ~(1 << (offset % 32));
+       __raw_writel(reg, base + GPIO_DIR);
+}
+
+static void gemini_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       unsigned int base = GPIO_BASE(offset / 32);
+
+       if (value)
+               __raw_writel(1 << (offset % 32), base + GPIO_DATA_SET);
+       else
+               __raw_writel(1 << (offset % 32), base + GPIO_DATA_CLR);
+}
+
+static int gemini_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       unsigned int base = GPIO_BASE(offset / 32);
+
+       return (__raw_readl(base + GPIO_DATA_IN) >> (offset % 32)) & 1;
+}
+
+static int gemini_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       _set_gpio_direction(chip, offset, 0);
+       return 0;
+}
+
+static int gemini_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+                                       int value)
+{
+       _set_gpio_direction(chip, offset, 1);
+       gemini_gpio_set(chip, offset, value);
+       return 0;
+}
+
+static struct gpio_chip gemini_gpio_chip = {
+       .label                  = "Gemini",
+       .direction_input        = gemini_gpio_direction_input,
+       .get                    = gemini_gpio_get,
+       .direction_output       = gemini_gpio_direction_output,
+       .set                    = gemini_gpio_set,
+       .base                   = 0,
+       .ngpio                  = GPIO_PORT_NUM * 32,
+};
+
+void __init gemini_gpio_init(void)
+{
+       int i, j;
+
+       for (i = 0; i < GPIO_PORT_NUM; i++) {
+               /* disable, unmask and clear all interrupts */
+               __raw_writel(0x0, GPIO_BASE(i) + GPIO_INT_EN);
+               __raw_writel(0x0, GPIO_BASE(i) + GPIO_INT_MASK);
+               __raw_writel(~0x0, GPIO_BASE(i) + GPIO_INT_CLR);
+
+               for (j = GPIO_IRQ_BASE + i * 32;
+                    j < GPIO_IRQ_BASE + (i + 1) * 32; j++) {
+                       set_irq_chip(j, &gpio_irq_chip);
+                       set_irq_handler(j, handle_edge_irq);
+                       set_irq_flags(j, IRQF_VALID);
+               }
+
+               set_irq_chained_handler(IRQ_GPIO(i), gpio_irq_handler);
+               set_irq_data(IRQ_GPIO(i), (void *)i);
+       }
+
+       BUG_ON(gpiochip_add(&gemini_gpio_chip));
+}
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 (file)
index 0000000..d04a6ea
--- /dev/null
@@ -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 (file)
index 0000000..1624f91
--- /dev/null
@@ -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 (file)
index 0000000..de7ff7e
--- /dev/null
@@ -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/gpio.h b/arch/arm/mach-gemini/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..3bc2c70
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Gemini gpiolib specific defines
+ *
+ * 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_GPIO_H__
+#define __MACH_GPIO_H__
+
+#include <mach/irqs.h>
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep  __gpio_cansleep
+
+#define gpio_to_irq(x) ((x) + GPIO_IRQ_BASE)
+#define irq_to_gpio(x) ((x) - GPIO_IRQ_BASE)
+
+#endif /* __MACH_GPIO_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 (file)
index 0000000..de67526
--- /dev/null
@@ -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 (file)
index 0000000..c548056
--- /dev/null
@@ -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 (file)
index 0000000..06bc47e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  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 GPIO_IRQ_BASE  NORMAL_IRQ_NUM
+#define GPIO_IRQ_NUM   (3 * 32)
+
+#define ARCH_TIMER_IRQ IRQ_TIMER2
+
+#define NR_IRQS                (NORMAL_IRQ_NUM + GPIO_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 (file)
index 0000000..2d14d5b
--- /dev/null
@@ -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 (file)
index 0000000..bbbd727
--- /dev/null
@@ -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 (file)
index 0000000..dc5690b
--- /dev/null
@@ -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 (file)
index 0000000..59c5df7
--- /dev/null
@@ -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 (file)
index 0000000..83e536d
--- /dev/null
@@ -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 (file)
index 0000000..9e613ca
--- /dev/null
@@ -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 (file)
index 0000000..5194824
--- /dev/null
@@ -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 (file)
index 0000000..21dc5a8
--- /dev/null
@@ -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)));
+}
index a6230f7..2097956 100644 (file)
@@ -186,6 +186,24 @@ config CPU_ARM926T
          Say Y if you want support for the ARM926T processor.
          Otherwise, say N.
 
+# FA526
+config CPU_FA526
+       bool
+       select CPU_32v4
+       select CPU_ABRT_EV4
+       select CPU_PABRT_NOIFAR
+       select CPU_CACHE_VIVT
+       select CPU_CP15_MMU
+       select CPU_CACHE_FA
+       select CPU_COPY_FA if MMU
+       select CPU_TLB_FA if MMU
+       help
+         The FA526 is a version of the ARMv4 compatible processor with
+         Branch Target Buffer, Unified TLB and cache line size 16.
+
+         Say Y if you want support for the FA526 processor.
+         Otherwise, say N.
+
 # ARM940T
 config CPU_ARM940T
        bool "Support ARM940T processor" if ARCH_INTEGRATOR
@@ -495,6 +513,9 @@ config CPU_CACHE_VIVT
 config CPU_CACHE_VIPT
        bool
 
+config CPU_CACHE_FA
+       bool
+
 if MMU
 # The copy-page model
 config CPU_COPY_V3
@@ -509,6 +530,9 @@ config CPU_COPY_V4WB
 config CPU_COPY_FEROCEON
        bool
 
+config CPU_COPY_FA
+       bool
+
 config CPU_COPY_V6
        bool
 
@@ -539,6 +563,13 @@ config CPU_TLB_FEROCEON
        help
          Feroceon TLB (v4wbi with non-outer-cachable page table walks).
 
+config CPU_TLB_FA
+       bool
+       help
+         Faraday ARM FA526 architecture, unified TLB with writeback cache
+         and invalidate instruction cache entry. Branch target buffer is
+         also supported.
+
 config CPU_TLB_V6
        bool
 
@@ -649,7 +680,7 @@ config CPU_DCACHE_SIZE
 
 config CPU_DCACHE_WRITETHROUGH
        bool "Force write through D-cache"
-       depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020) && !CPU_DCACHE_DISABLE
+       depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FA526) && !CPU_DCACHE_DISABLE
        default y if CPU_ARM925T
        help
          Say Y here to use the data cache in writethrough mode. Unless you
@@ -664,7 +695,7 @@ config CPU_CACHE_ROUND_ROBIN
 
 config CPU_BPREDICT_DISABLE
        bool "Disable branch prediction"
-       depends on CPU_ARM1020 || CPU_V6 || CPU_MOHAWK || CPU_XSC3 || CPU_V7
+       depends on CPU_ARM1020 || CPU_V6 || CPU_MOHAWK || CPU_XSC3 || CPU_V7 || CPU_FA526
        help
          Say Y here to disable branch prediction.  If unsure, say N.
 
index c264683..63e3f6d 100644 (file)
@@ -33,6 +33,7 @@ obj-$(CONFIG_CPU_CACHE_V4WT)  += cache-v4wt.o
 obj-$(CONFIG_CPU_CACHE_V4WB)   += cache-v4wb.o
 obj-$(CONFIG_CPU_CACHE_V6)     += cache-v6.o
 obj-$(CONFIG_CPU_CACHE_V7)     += cache-v7.o
+obj-$(CONFIG_CPU_CACHE_FA)     += cache-fa.o
 
 obj-$(CONFIG_CPU_COPY_V3)      += copypage-v3.o
 obj-$(CONFIG_CPU_COPY_V4WT)    += copypage-v4wt.o
@@ -42,6 +43,7 @@ obj-$(CONFIG_CPU_COPY_V6)     += copypage-v6.o context.o
 obj-$(CONFIG_CPU_SA1100)       += copypage-v4mc.o
 obj-$(CONFIG_CPU_XSCALE)       += copypage-xscale.o
 obj-$(CONFIG_CPU_XSC3)         += copypage-xsc3.o
+obj-$(CONFIG_CPU_COPY_FA)      += copypage-fa.o
 
 obj-$(CONFIG_CPU_TLB_V3)       += tlb-v3.o
 obj-$(CONFIG_CPU_TLB_V4WT)     += tlb-v4.o
@@ -50,6 +52,7 @@ obj-$(CONFIG_CPU_TLB_V4WBI)   += tlb-v4wbi.o
 obj-$(CONFIG_CPU_TLB_FEROCEON) += tlb-v4wbi.o  # reuse v4wbi TLB functions
 obj-$(CONFIG_CPU_TLB_V6)       += tlb-v6.o
 obj-$(CONFIG_CPU_TLB_V7)       += tlb-v7.o
+obj-$(CONFIG_CPU_TLB_FA)       += tlb-fa.o
 
 obj-$(CONFIG_CPU_ARM610)       += proc-arm6_7.o
 obj-$(CONFIG_CPU_ARM710)       += proc-arm6_7.o
@@ -63,6 +66,7 @@ obj-$(CONFIG_CPU_ARM925T)     += proc-arm925.o
 obj-$(CONFIG_CPU_ARM926T)      += proc-arm926.o
 obj-$(CONFIG_CPU_ARM940T)      += proc-arm940.o
 obj-$(CONFIG_CPU_ARM946E)      += proc-arm946.o
+obj-$(CONFIG_CPU_FA526)                += proc-fa526.o
 obj-$(CONFIG_CPU_ARM1020)      += proc-arm1020.o
 obj-$(CONFIG_CPU_ARM1020E)     += proc-arm1020e.o
 obj-$(CONFIG_CPU_ARM1022)      += proc-arm1022.o
diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S
new file mode 100644 (file)
index 0000000..b63a8f7
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ *  linux/arch/arm/mm/cache-fa.S
+ *
+ *  Copyright (C) 2005 Faraday Corp.
+ *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on cache-v4wb.S:
+ *  Copyright (C) 1997-2002 Russell king
+ *
+ * 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.
+ *
+ *  Processors: FA520 FA526 FA626      
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/memory.h>
+#include <asm/page.h>
+
+#include "proc-macros.S"
+
+/*
+ * The size of one data cache line.
+ */
+#define CACHE_DLINESIZE        16
+
+/*
+ * The total size of the data cache.
+ */
+#ifdef CONFIG_ARCH_GEMINI
+#define CACHE_DSIZE    8192
+#else
+#define CACHE_DSIZE    16384 
+#endif 
+
+/* FIXME: put optimal value here. Current one is just estimation */
+#define CACHE_DLIMIT   (CACHE_DSIZE * 2)
+
+/*
+ *     flush_user_cache_all()
+ *
+ *     Clean and invalidate all cache entries in a particular address
+ *     space.
+ */
+ENTRY(fa_flush_user_cache_all)
+       /* FALLTHROUGH */
+/*
+ *     flush_kern_cache_all()
+ *
+ *     Clean and invalidate the entire cache.
+ */
+ENTRY(fa_flush_kern_cache_all)
+       mov     ip, #0
+       mov     r2, #VM_EXEC
+__flush_whole_cache:
+       mcr     p15, 0, ip, c7, c14, 0          @ clean/invalidate D cache
+       tst     r2, #VM_EXEC
+       mcrne   p15, 0, ip, c7, c5, 0           @ invalidate I cache
+       mcrne   p15, 0, ip, c7, c5, 6           @ invalidate BTB
+       mcrne   p15, 0, ip, c7, c10, 4          @ drain write buffer
+       mcrne   p15, 0, ip, c7, c5, 4           @ prefetch flush
+       mov     pc, lr
+
+/*
+ *     flush_user_cache_range(start, end, flags)
+ *
+ *     Invalidate a range of cache entries in the specified
+ *     address space.
+ *
+ *     - start - start address (inclusive, page aligned)
+ *     - end   - end address (exclusive, page aligned)
+ *     - flags - vma_area_struct flags describing address space
+ */
+ENTRY(fa_flush_user_cache_range)
+       mov     ip, #0
+       sub     r3, r1, r0                      @ calculate total size
+       cmp     r3, #CACHE_DLIMIT               @ total size >= limit?
+       bhs     __flush_whole_cache             @ flush whole D cache
+
+1:     tst     r2, #VM_EXEC
+       mcrne   p15, 0, r0, c7, c5, 1           @ invalidate I line
+       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D entry
+       add     r0, r0, #CACHE_DLINESIZE
+       cmp     r0, r1
+       blo     1b
+       tst     r2, #VM_EXEC
+       mcrne   p15, 0, ip, c7, c5, 6           @ invalidate BTB
+       mcrne   p15, 0, ip, c7, c10, 4          @ data write barrier
+       mcrne   p15, 0, ip, c7, c5, 4           @ prefetch flush
+       mov     pc, lr
+
+/*
+ *     coherent_kern_range(start, end)
+ *
+ *     Ensure coherency between the Icache and the Dcache in the
+ *     region described by start.  If you have non-snooping
+ *     Harvard caches, you need to implement this function.
+ *
+ *     - start  - virtual start address
+ *     - end    - virtual end address
+ */
+ENTRY(fa_coherent_kern_range)
+       /* fall through */
+
+/*
+ *     coherent_user_range(start, end)
+ *
+ *     Ensure coherency between the Icache and the Dcache in the
+ *     region described by start.  If you have non-snooping
+ *     Harvard caches, you need to implement this function.
+ *
+ *     - start  - virtual start address
+ *     - end    - virtual end address
+ */
+ENTRY(fa_coherent_user_range)
+       bic     r0, r0, #CACHE_DLINESIZE - 1
+1:     mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D entry
+       mcr     p15, 0, r0, c7, c5, 1           @ invalidate I entry
+       add     r0, r0, #CACHE_DLINESIZE
+       cmp     r0, r1
+       blo     1b
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 6           @ invalidate BTB
+       mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
+       mcr     p15, 0, r0, c7, c5, 4           @ prefetch flush
+       mov     pc, lr
+
+/*
+ *     flush_kern_dcache_page(kaddr)
+ *
+ *     Ensure that the data held in the page kaddr is written back
+ *     to the page in question.
+ *
+ *     - kaddr   - kernel address (guaranteed to be page aligned)
+ */
+ENTRY(fa_flush_kern_dcache_page)
+       add     r1, r0, #PAGE_SZ
+1:     mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line
+       add     r0, r0, #CACHE_DLINESIZE
+       cmp     r0, r1
+       blo     1b
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 0           @ invalidate I cache
+       mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
+       mov     pc, lr
+
+/*
+ *     dma_inv_range(start, end)
+ *
+ *     Invalidate (discard) the specified virtual address range.
+ *     May not write back any entries.  If 'start' or 'end'
+ *     are not cache line aligned, those lines must be written
+ *     back.
+ *
+ *     - start  - virtual start address
+ *     - end    - virtual end address
+ */
+ENTRY(fa_dma_inv_range)
+       tst     r0, #CACHE_DLINESIZE - 1
+       bic     r0, r0, #CACHE_DLINESIZE - 1
+       mcrne   p15, 0, r0, c7, c14, 1          @ clean & invalidate D entry
+       tst     r1, #CACHE_DLINESIZE - 1
+       bic     r1, r1, #CACHE_DLINESIZE - 1
+       mcrne   p15, 0, r1, c7, c14, 1          @ clean & invalidate D entry
+1:     mcr     p15, 0, r0, c7, c6, 1           @ invalidate D entry
+       add     r0, r0, #CACHE_DLINESIZE
+       cmp     r0, r1
+       blo     1b
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
+       mov     pc, lr
+
+/*
+ *     dma_clean_range(start, end)
+ *
+ *     Clean (write back) the specified virtual address range.
+ *
+ *     - start  - virtual start address
+ *     - end    - virtual end address
+ */
+ENTRY(fa_dma_clean_range)
+       bic     r0, r0, #CACHE_DLINESIZE - 1
+1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       add     r0, r0, #CACHE_DLINESIZE
+       cmp     r0, r1
+       blo     1b
+       mov     r0, #0  
+       mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
+       mov     pc, lr
+
+/*
+ *     dma_flush_range(start,end)
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ */
+ENTRY(fa_dma_flush_range)
+       bic     r0, r0, #CACHE_DLINESIZE - 1
+1:     mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D entry
+       add     r0, r0, #CACHE_DLINESIZE
+       cmp     r0, r1
+       blo     1b
+       mov     r0, #0  
+       mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
+       mov     pc, lr
+
+       __INITDATA
+
+       .type   fa_cache_fns, #object
+ENTRY(fa_cache_fns)
+       .long   fa_flush_kern_cache_all
+       .long   fa_flush_user_cache_all
+       .long   fa_flush_user_cache_range
+       .long   fa_coherent_kern_range
+       .long   fa_coherent_user_range
+       .long   fa_flush_kern_dcache_page
+       .long   fa_dma_inv_range
+       .long   fa_dma_clean_range
+       .long   fa_dma_flush_range
+       .size   fa_cache_fns, . - fa_cache_fns
diff --git a/arch/arm/mm/copypage-fa.c b/arch/arm/mm/copypage-fa.c
new file mode 100644 (file)
index 0000000..b2a6008
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  linux/arch/arm/lib/copypage-fa.S
+ *
+ *  Copyright (C) 2005 Faraday Corp.
+ *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on copypage-v4wb.S:
+ *  Copyright (C) 1995-1999 Russell King
+ *
+ * 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/init.h>
+#include <linux/highmem.h>
+
+/*
+ * Faraday optimised copy_user_page
+ */
+static void __naked
+fa_copy_user_page(void *kto, const void *kfrom)
+{
+       asm("\
+       stmfd   sp!, {r4, lr}                   @ 2\n\
+       mov     r2, %0                          @ 1\n\
+1:     ldmia   r1!, {r3, r4, ip, lr}           @ 4\n\
+       stmia   r0, {r3, r4, ip, lr}            @ 4\n\
+       mcr     p15, 0, r0, c7, c14, 1          @ 1   clean and invalidate D line\n\
+       add     r0, r0, #16                     @ 1\n\
+       ldmia   r1!, {r3, r4, ip, lr}           @ 4\n\
+       stmia   r0, {r3, r4, ip, lr}            @ 4\n\
+       mcr     p15, 0, r0, c7, c14, 1          @ 1   clean and invalidate D line\n\
+       add     r0, r0, #16                     @ 1\n\
+       subs    r2, r2, #1                      @ 1\n\
+       bne     1b                              @ 1\n\
+       mcr     p15, 0, r2, c7, c10, 4          @ 1   drain WB\n\
+       ldmfd   sp!, {r4, pc}                   @ 3"
+       :
+       : "I" (PAGE_SIZE / 32));
+}
+
+void fa_copy_user_highpage(struct page *to, struct page *from,
+       unsigned long vaddr)
+{
+       void *kto, *kfrom;
+
+       kto = kmap_atomic(to, KM_USER0);
+       kfrom = kmap_atomic(from, KM_USER1);
+       fa_copy_user_page(kto, kfrom);
+       kunmap_atomic(kfrom, KM_USER1);
+       kunmap_atomic(kto, KM_USER0);
+}
+
+/*
+ * Faraday optimised clear_user_page
+ *
+ * Same story as above.
+ */
+void fa_clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+       void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
+       asm volatile("\
+       mov     r1, %2                          @ 1\n\
+       mov     r2, #0                          @ 1\n\
+       mov     r3, #0                          @ 1\n\
+       mov     ip, #0                          @ 1\n\
+       mov     lr, #0                          @ 1\n\
+1:     stmia   %0, {r2, r3, ip, lr}            @ 4\n\
+       mcr     p15, 0, %0, c7, c14, 1          @ 1   clean and invalidate D line\n\
+       add     %0, %0, #16                     @ 1\n\
+       stmia   %0, {r2, r3, ip, lr}            @ 4\n\
+       mcr     p15, 0, %0, c7, c14, 1          @ 1   clean and invalidate D line\n\
+       add     %0, %0, #16                     @ 1\n\
+       subs    r1, r1, #1                      @ 1\n\
+       bne     1b                              @ 1\n\
+       mcr     p15, 0, r1, c7, c10, 4          @ 1   drain WB"
+       : "=r" (ptr)
+       : "0" (kaddr), "I" (PAGE_SIZE / 32)
+       : "r1", "r2", "r3", "ip", "lr");
+       kunmap_atomic(kaddr, KM_USER0);
+}
+
+struct cpu_user_fns fa_user_fns __initdata = {
+       .cpu_clear_user_highpage = fa_clear_user_highpage,
+       .cpu_copy_user_highpage = fa_copy_user_highpage,
+};
diff --git a/arch/arm/mm/proc-fa526.S b/arch/arm/mm/proc-fa526.S
new file mode 100644 (file)
index 0000000..08b8a95
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ *  linux/arch/arm/mm/proc-fa526.S: MMU functions for FA526
+ *
+ *  Written by : Luke Lee
+ *  Copyright (C) 2005 Faraday 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.
+ *
+ *
+ * These are the low level assembler for performing cache and TLB
+ * functions on the fa526.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+#include <asm/hwcap.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+
+#include "proc-macros.S"
+
+#define CACHE_DLINESIZE        16
+
+       .text
+/*
+ * cpu_fa526_proc_init()
+ */
+ENTRY(cpu_fa526_proc_init)
+       mov     pc, lr
+
+/*
+ * cpu_fa526_proc_fin()
+ */
+ENTRY(cpu_fa526_proc_fin)
+       stmfd   sp!, {lr}
+       mov     ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
+       msr     cpsr_c, ip
+       bl      fa_flush_kern_cache_all
+       mrc     p15, 0, r0, c1, c0, 0           @ ctrl register
+       bic     r0, r0, #0x1000                 @ ...i............
+       bic     r0, r0, #0x000e                 @ ............wca.
+       mcr     p15, 0, r0, c1, c0, 0           @ disable caches
+       nop
+       nop
+       ldmfd   sp!, {pc}
+
+/*
+ * cpu_fa526_reset(loc)
+ *
+ * Perform a soft reset of the system.  Put the CPU into the
+ * same state as it would be if it had been reset, and branch
+ * to what would be the reset vector.
+ *
+ * loc: location to jump to for soft reset
+ */
+       .align  4
+ENTRY(cpu_fa526_reset)
+/* TODO: Use CP8 if possible... */
+       mov     ip, #0
+       mcr     p15, 0, ip, c7, c7, 0           @ invalidate I,D caches
+       mcr     p15, 0, ip, c7, c10, 4          @ drain WB
+#ifdef CONFIG_MMU
+       mcr     p15, 0, ip, c8, c7, 0           @ invalidate I & D TLBs
+#endif
+       mrc     p15, 0, ip, c1, c0, 0           @ ctrl register
+       bic     ip, ip, #0x000f                 @ ............wcam
+       bic     ip, ip, #0x1100                 @ ...i...s........
+       bic     ip, ip, #0x0800                 @ BTB off
+       mcr     p15, 0, ip, c1, c0, 0           @ ctrl register
+       nop
+       nop
+       mov     pc, r0
+
+/*
+ * cpu_fa526_do_idle()
+ */
+       .align  4
+ENTRY(cpu_fa526_do_idle)
+       mcr     p15, 0, r0, c7, c0, 4           @ Wait for interrupt
+       mov     pc, lr
+
+
+ENTRY(cpu_fa526_dcache_clean_area)
+1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       add     r0, r0, #CACHE_DLINESIZE
+       subs    r1, r1, #CACHE_DLINESIZE
+       bhi     1b
+       mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+       mov     pc, lr
+
+/* =============================== PageTable ============================== */
+
+/*
+ * cpu_fa526_switch_mm(pgd)
+ *
+ * Set the translation base pointer to be as described by pgd.
+ *
+ * pgd: new page tables
+ */
+       .align  4
+ENTRY(cpu_fa526_switch_mm)
+#ifdef CONFIG_MMU
+       mov     ip, #0
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+       mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
+#else
+       mcr     p15, 0, ip, c7, c14, 0          @ clean and invalidate whole D cache
+#endif
+       mcr     p15, 0, ip, c7, c5, 0           @ invalidate I cache
+       mcr     p15, 0, ip, c7, c5, 6           @ invalidate BTB since mm changed
+       mcr     p15, 0, ip, c7, c10, 4          @ data write barrier
+       mcr     p15, 0, ip, c7, c5, 4           @ prefetch flush
+       mcr     p15, 0, r0, c2, c0, 0           @ load page table pointer
+       mcr     p15, 0, ip, c8, c7, 0           @ invalidate UTLB
+#endif
+       mov     pc, lr
+
+/*
+ * cpu_fa526_set_pte_ext(ptep, pte, ext)
+ *
+ * Set a PTE and flush it out
+ */
+       .align  4
+ENTRY(cpu_fa526_set_pte_ext)
+#ifdef CONFIG_MMU
+       armv3_set_pte_ext
+       mov     r0, r0
+       mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c10, 4          @ drain WB
+#endif
+       mov     pc, lr
+
+       __INIT
+
+       .type   __fa526_setup, #function
+__fa526_setup:
+       /* On return of this routine, r0 must carry correct flags for CFG register */
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c7              @ invalidate I,D caches on v4
+       mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer on v4
+#ifdef CONFIG_MMU
+       mcr     p15, 0, r0, c8, c7              @ invalidate I,D TLBs on v4
+#endif
+       mcr     p15, 0, r0, c7, c5, 5           @ invalidate IScratchpad RAM
+
+       mov     r0, #1
+       mcr     p15, 0, r0, c1, c1, 0           @ turn-on ECR
+
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 6           @ invalidate BTB All
+       mcr     p15, 0, r0, c7, c10, 4          @ data write barrier
+       mcr     p15, 0, r0, c7, c5, 4           @ prefetch flush
+
+       mov     r0, #0x1f                       @ Domains 0, 1 = manager, 2 = client
+       mcr     p15, 0, r0, c3, c0              @ load domain access register
+
+       mrc     p15, 0, r0, c1, c0              @ get control register v4
+       ldr     r5, fa526_cr1_clear
+       bic     r0, r0, r5
+       ldr     r5, fa526_cr1_set
+       orr     r0, r0, r5
+       mov     pc, lr
+       .size   __fa526_setup, . - __fa526_setup
+
+       /*
+        * .RVI ZFRS BLDP WCAM
+        * ..11 1001 .111 1101
+        *
+        */
+       .type   fa526_cr1_clear, #object
+       .type   fa526_cr1_set, #object
+fa526_cr1_clear:
+       .word   0x3f3f
+fa526_cr1_set:
+       .word   0x397D
+
+       __INITDATA
+
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ *          come through these
+ */
+       .type   fa526_processor_functions, #object
+fa526_processor_functions:
+       .word   v4_early_abort
+       .word   pabort_noifar
+       .word   cpu_fa526_proc_init
+       .word   cpu_fa526_proc_fin
+       .word   cpu_fa526_reset
+       .word   cpu_fa526_do_idle
+       .word   cpu_fa526_dcache_clean_area
+       .word   cpu_fa526_switch_mm
+       .word   cpu_fa526_set_pte_ext
+       .size   fa526_processor_functions, . - fa526_processor_functions
+
+       .section ".rodata"
+
+       .type   cpu_arch_name, #object
+cpu_arch_name:
+       .asciz  "armv4"
+       .size   cpu_arch_name, . - cpu_arch_name
+
+       .type   cpu_elf_name, #object
+cpu_elf_name:
+       .asciz  "v4"
+       .size   cpu_elf_name, . - cpu_elf_name
+
+       .type   cpu_fa526_name, #object
+cpu_fa526_name:
+       .asciz  "FA526"
+       .size   cpu_fa526_name, . - cpu_fa526_name
+
+       .align
+
+       .section ".proc.info.init", #alloc, #execinstr
+
+       .type   __fa526_proc_info,#object
+__fa526_proc_info:
+       .long   0x66015261
+       .long   0xff01fff1
+       .long   PMD_TYPE_SECT | \
+               PMD_SECT_BUFFERABLE | \
+               PMD_SECT_CACHEABLE | \
+               PMD_BIT4 | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ
+       .long   PMD_TYPE_SECT | \
+               PMD_BIT4 | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ
+       b       __fa526_setup
+       .long   cpu_arch_name
+       .long   cpu_elf_name
+       .long   HWCAP_SWP | HWCAP_HALF
+       .long   cpu_fa526_name
+       .long   fa526_processor_functions
+       .long   fa_tlb_fns
+       .long   fa_user_fns
+       .long   fa_cache_fns
+       .size   __fa526_proc_info, . - __fa526_proc_info
diff --git a/arch/arm/mm/tlb-fa.S b/arch/arm/mm/tlb-fa.S
new file mode 100644 (file)
index 0000000..9694f1f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *  linux/arch/arm/mm/tlb-fa.S
+ *
+ *  Copyright (C) 2005 Faraday Corp.
+ *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on tlb-v4wbi.S:
+ *  Copyright (C) 1997-2002 Russell King
+ *
+ * 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.
+ *
+ *  ARM architecture version 4, Faraday variation.
+ *  This assume an unified TLBs, with a write buffer, and branch target buffer (BTB)
+ *
+ *  Processors: FA520 FA526 FA626
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/asm-offsets.h>
+#include <asm/tlbflush.h>
+#include "proc-macros.S"
+
+
+/*
+ *     flush_user_tlb_range(start, end, mm)
+ *
+ *     Invalidate a range of TLB entries in the specified address space.
+ *
+ *     - start - range start address
+ *     - end   - range end address
+ *     - mm    - mm_struct describing address space
+ */
+       .align  4
+ENTRY(fa_flush_user_tlb_range)
+       vma_vm_mm ip, r2
+       act_mm  r3                              @ get current->active_mm
+       eors    r3, ip, r3                      @ == mm ?
+       movne   pc, lr                          @ no, we dont do anything
+       mov     r3, #0
+       mcr     p15, 0, r3, c7, c10, 4          @ drain WB
+       bic     r0, r0, #0x0ff
+       bic     r0, r0, #0xf00
+1:     mcr     p15, 0, r0, c8, c7, 1           @ invalidate UTLB entry
+       add     r0, r0, #PAGE_SZ
+       cmp     r0, r1
+       blo     1b
+       mcr     p15, 0, r3, c7, c5, 6           @ invalidate BTB
+       mcr     p15, 0, r3, c7, c10, 4          @ data write barrier
+       mov     pc, lr
+
+
+ENTRY(fa_flush_kern_tlb_range)
+       mov     r3, #0
+       mcr     p15, 0, r3, c7, c10, 4          @ drain WB
+       bic     r0, r0, #0x0ff
+       bic     r0, r0, #0xf00
+1:     mcr     p15, 0, r0, c8, c7, 1           @ invalidate UTLB entry
+       add     r0, r0, #PAGE_SZ
+       cmp     r0, r1
+       blo     1b
+       mcr     p15, 0, r3, c7, c5, 6           @ invalidate BTB
+       mcr     p15, 0, r3, c7, c10, 4          @ data write barrier
+       mcr     p15, 0, r3, c7, c5, 4           @ prefetch flush
+       mov     pc, lr
+
+       __INITDATA
+
+       .type   fa_tlb_fns, #object
+ENTRY(fa_tlb_fns)
+       .long   fa_flush_user_tlb_range
+       .long   fa_flush_kern_tlb_range
+       .long   fa_tlb_flags
+       .size   fa_tlb_fns, . - fa_tlb_fns