From: Philippe Langlais on
Signed-off-by: Philippe Langlais <philippe.langlais(a)stericsson.com>
---
arch/arm/Kconfig | 11 +
arch/arm/Makefile | 2 +
arch/arm/mach-u67xx/Kconfig | 12 +
arch/arm/mach-u67xx/Makefile | 11 +
arch/arm/mach-u67xx/Makefile.boot | 4 +
arch/arm/mach-u67xx/board_u67xx_wavex.c | 47 +++
arch/arm/mach-u67xx/devices.c | 28 ++
arch/arm/plat-u6xxx/Kconfig | 22 ++
arch/arm/plat-u6xxx/Makefile | 8 +
arch/arm/plat-u6xxx/include/mach/cpu.h | 36 ++
arch/arm/plat-u6xxx/include/mach/debug-macro.S | 38 ++
arch/arm/plat-u6xxx/include/mach/entry-macro.S | 32 ++
arch/arm/plat-u6xxx/include/mach/hardware.h | 41 +++
arch/arm/plat-u6xxx/include/mach/io.h | 30 ++
arch/arm/plat-u6xxx/include/mach/irqs.h | 102 ++++++
arch/arm/plat-u6xxx/include/mach/memory.h | 17 +
arch/arm/plat-u6xxx/include/mach/regs-u6.h | 121 +++++++
arch/arm/plat-u6xxx/include/mach/system.h | 42 +++
arch/arm/plat-u6xxx/include/mach/timer.h | 16 +
arch/arm/plat-u6xxx/include/mach/timex.h | 23 ++
arch/arm/plat-u6xxx/include/mach/uncompress.h | 47 +++
arch/arm/plat-u6xxx/include/mach/vmalloc.h | 10 +
arch/arm/plat-u6xxx/io.c | 34 ++
arch/arm/plat-u6xxx/irq.c | 254 ++++++++++++++
arch/arm/plat-u6xxx/timer.c | 442 ++++++++++++++++++++++++
25 files changed, 1430 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-u67xx/Kconfig
create mode 100644 arch/arm/mach-u67xx/Makefile
create mode 100644 arch/arm/mach-u67xx/Makefile.boot
create mode 100644 arch/arm/mach-u67xx/board_u67xx_wavex.c
create mode 100644 arch/arm/mach-u67xx/devices.c
create mode 100644 arch/arm/plat-u6xxx/Kconfig
create mode 100644 arch/arm/plat-u6xxx/Makefile
create mode 100644 arch/arm/plat-u6xxx/include/mach/cpu.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/debug-macro.S
create mode 100644 arch/arm/plat-u6xxx/include/mach/entry-macro.S
create mode 100644 arch/arm/plat-u6xxx/include/mach/hardware.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/io.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/irqs.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/memory.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/regs-u6.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/system.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/timer.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/timex.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/uncompress.h
create mode 100644 arch/arm/plat-u6xxx/include/mach/vmalloc.h
create mode 100644 arch/arm/plat-u6xxx/io.c
create mode 100644 arch/arm/plat-u6xxx/irq.c
create mode 100644 arch/arm/plat-u6xxx/timer.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index cf30fc9..1ae089c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -739,6 +739,14 @@ config ARCH_U300
help
Support for ST-Ericsson U300 series mobile platforms.

+config PLAT_U6XXX
+ bool "ST-Ericsson U6XXX Series"
+ select CPU_ARM926T
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Support for ST-Ericsson's U6XXX architecture
+
config ARCH_U8500
bool "ST-Ericsson U8500 Series"
select CPU_V7
@@ -910,6 +918,9 @@ source "arch/arm/mach-tegra/Kconfig"

source "arch/arm/mach-u300/Kconfig"

+source "arch/arm/plat-u6xxx/Kconfig"
+source "arch/arm/mach-u67xx/Kconfig"
+
source "arch/arm/mach-ux500/Kconfig"

source "arch/arm/mach-versatile/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2de67c9..c510a64 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -176,6 +176,7 @@ machine-$(CONFIG_ARCH_STMP378X) := stmp378x
machine-$(CONFIG_ARCH_STMP37XX) := stmp37xx
machine-$(CONFIG_ARCH_TEGRA) := tegra
machine-$(CONFIG_ARCH_U300) := u300
+machine-$(CONFIG_ARCH_U67XX) := u67xx
machine-$(CONFIG_ARCH_U8500) := ux500
machine-$(CONFIG_ARCH_VERSATILE) := versatile
machine-$(CONFIG_ARCH_VEXPRESS) := vexpress
@@ -200,6 +201,7 @@ plat-$(CONFIG_PLAT_PXA) := pxa
plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx samsung
plat-$(CONFIG_PLAT_S5P) := s5p samsung
plat-$(CONFIG_PLAT_SPEAR) := spear
+plat-$(CONFIG_PLAT_U6XXX) := u6xxx
plat-$(CONFIG_PLAT_VERSATILE) := versatile

ifeq ($(CONFIG_ARCH_EBSA110),y)
diff --git a/arch/arm/mach-u67xx/Kconfig b/arch/arm/mach-u67xx/Kconfig
new file mode 100644
index 0000000..f02f6e2
--- /dev/null
+++ b/arch/arm/mach-u67xx/Kconfig
@@ -0,0 +1,12 @@
+comment "U67XX Board Type"
+ depends on ARCH_U67XX
+
+choice
+ depends on ARCH_U67XX
+ prompt "Choose the U67XX Board type"
+ default MACH_U67XX_WAVEC_2GB
+ help
+ Choose the ST-Ericsson Reference Design Board
+config MACH_U67XX_WAVEC_2GB
+ bool "U67XX WaveC Board with 2Gb Micron combo"
+endchoice
diff --git a/arch/arm/mach-u67xx/Makefile b/arch/arm/mach-u67xx/Makefile
new file mode 100644
index 0000000..38cf624
--- /dev/null
+++ b/arch/arm/mach-u67xx/Makefile
@@ -0,0 +1,11 @@
+#
+## Makefile for the linux kernel, hardware dependent part of ST-Ericsson U67xx
+#
+#
+## Object file lists.
+
+# Common support
+obj-y := devices.o
+
+# Specific board support
+obj-$(CONFIG_MACH_U67XX_WAVEC_2GB) += board_u67xx_wavex.o
diff --git a/arch/arm/mach-u67xx/Makefile.boot b/arch/arm/mach-u67xx/Makefile.boot
new file mode 100644
index 0000000..c4e8c02
--- /dev/null
+++ b/arch/arm/mach-u67xx/Makefile.boot
@@ -0,0 +1,4 @@
+ zreladdr-y := 0x20008000
+params_phys-y := 0x20000100
+initrd_phys-y := 0x26000000
+
diff --git a/arch/arm/mach-u67xx/board_u67xx_wavex.c b/arch/arm/mach-u67xx/board_u67xx_wavex.c
new file mode 100644
index 0000000..633989f
--- /dev/null
+++ b/arch/arm/mach-u67xx/board_u67xx_wavex.c
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/mach-u67xx/board_u67xx_wavex.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Platform machine definition for U6XXX WAVEx Board.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/timer.h>
+
+/* List of board specific devices */
+static struct platform_device *devices[] __initdata = {
+};
+
+void __init u67xx_init(void)
+{
+ /* Add specific board devices */
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+MACHINE_START(U6715, "STE_U67xx_refd")
+ /* Maintainer: Philippe Langlais <philippe.langlais(a)stericsson.com> */
+ .phys_io = UART1_BASE,
+ .io_pg_offst = (IO_ADDRESS(UART1_BASE) >> 18) & 0xfffc,
+ .boot_params = PHYS_OFFSET + 0x100,
+ .map_io = u6xxx_map_io,
+ .init_irq = u6_init_irq,
+ .init_machine = u67xx_init,
+ .timer = &u6_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-u67xx/devices.c b/arch/arm/mach-u67xx/devices.c
new file mode 100644
index 0000000..1d00b35
--- /dev/null
+++ b/arch/arm/mach-u67xx/devices.c
@@ -0,0 +1,28 @@
+/*
+ * linux/arch/arm/mach-u67xx/devices.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Device specification for the U67XX
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+/* list of devices */
+static struct platform_device *platform_devs[] __initdata = {
+};
+
+/* register generic devices */
+
+static int __init u67xx_devices_init(void)
+{
+ platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+ return 0;
+}
+
+arch_initcall(u67xx_devices_init);
diff --git a/arch/arm/plat-u6xxx/Kconfig b/arch/arm/plat-u6xxx/Kconfig
new file mode 100644
index 0000000..10929ea
--- /dev/null
+++ b/arch/arm/plat-u6xxx/Kconfig
@@ -0,0 +1,22 @@
+if PLAT_U6XXX
+
+menu "STE U6XXX Implementations"
+
+choice
+ prompt "U67XX System Type"
+ default ARCH_U67XX
+
+config ARCH_U67XX
+ bool "U67XX"
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
+ select U6_MTU_TIMER
+endchoice
+
+endmenu
+
+config U6_MTU_TIMER
+ bool
+ default y
+
+endif
diff --git a/arch/arm/plat-u6xxx/Makefile b/arch/arm/plat-u6xxx/Makefile
new file mode 100644
index 0000000..12c832c
--- /dev/null
+++ b/arch/arm/plat-u6xxx/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux kernel hardware independant part of STE U6XXX.
+#
+
+# Common support
+obj-y := io.o irq.o
+
+obj-$(CONFIG_U6_MTU_TIMER) += timer.o
diff --git a/arch/arm/plat-u6xxx/include/mach/cpu.h b/arch/arm/plat-u6xxx/include/mach/cpu.h
new file mode 100644
index 0000000..4f1f57f
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/cpu.h
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/cpu.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ * U6 cpu type detection
+ */
+
+#ifndef __ASM_PLAT_CPU_H
+#define __ASM_PLAT_CPU_H
+
+/*
+ * Macros to group U6xxx into cpu classes.
+ * These can be used in most places.
+ * cpu_is_u67xx(): True for U67XX
+ */
+
+#define GET_U6XXX_CLASS ((readl(SCON_SYSVER_REG)&0x0F00)>>8)
+#define GET_U6XXX_SUBCLASS ((readl(SCON_SYSVER_REG)&0x0FF0)>>4)
+
+#define cpu_is_u67xx() 0
+#define cpu_is_u67xx_v2() 0
+#define cpu_is_u67xx_v3() 0
+
+#if defined(CONFIG_ARCH_U67XX)
+# undef cpu_is_u67xx
+# undef cpu_is_u67xx_v2
+# undef cpu_is_u67xx_v3
+# define cpu_is_u67xx() (GET_U6XXX_CLASS == 0x6)
+# define cpu_is_u67xx_v2() (GET_U6XXX_SUBCLASS == 0x62)
+# define cpu_is_u67xx_v3() (GET_U6XXX_SUBCLASS == 0x63)
+#endif
+
+#endif /* __ASM_PLAT_CPU_H */
+
diff --git a/arch/arm/plat-u6xxx/include/mach/debug-macro.S b/arch/arm/plat-u6xxx/include/mach/debug-macro.S
new file mode 100644
index 0000000..039c810
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/debug-macro.S
@@ -0,0 +1,38 @@
+/* linux/arch/arm/plat-u6xxx/include/mach/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ * Copyright (C) 2010 ST-Ericsson
+ *
+ * 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, = UART1_BASE @ physical base address
+ ldrne \rx, = IO_ADDRESS(UART1_BASE) @ virtual base
+ .endm
+
+ .macro senduart,rd,rx
+ strb \rd, [\rx]
+ .endm
+
+ .macro waituart,rd,rx
+1001:
+ ldr \rd, [\rx, #20]
+ tst \rd, #1 << 5 @ LSR_THRE - 0 when full
+ beq 1001b
+ .endm
+
+ .macro busyuart,rd,rx
+1001:
+ ldr \rd, [\rx, #20]
+ tst \rd, #1 << 6 @ LSR_TEMT - 0 when busy
+ beq 1001b
+ .endm
diff --git a/arch/arm/plat-u6xxx/include/mach/entry-macro.S b/arch/arm/plat-u6xxx/include/mach/entry-macro.S
new file mode 100644
index 0000000..cae8824
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/entry-macro.S
@@ -0,0 +1,32 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for U6-based platforms
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * 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>
+#include <mach/irqs.h>
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_preamble, base, tmp
+ ldr \base, =IO_ADDRESS(INTC_BASE)
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ ldr \irqnr, [\base, #INTC_VECTOR_IRQ_OFFSET] @ load intc vector reg
+ mov \irqnr, \irqnr, lsr #3 @ Bits[0..2] are reserved
+ ands \irqnr, \irqnr, #0x00FF @ mask Bits[11..31]
+ .endm
+
+ .macro irq_prio_table
+ .endm
+
diff --git a/arch/arm/plat-u6xxx/include/mach/hardware.h b/arch/arm/plat-u6xxx/include/mach/hardware.h
new file mode 100644
index 0000000..79199ec
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/hardware.h
@@ -0,0 +1,41 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/hardware.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+#ifndef __ASSEMBLER__
+#include <mach/cpu.h>
+#endif
+
+/*
+ * Processor specific registers defines
+ */
+#include "regs-u6.h"
+
+/*
+ * Where in virtual memory the IO devices (timers, system controllers
+ * and so on)
+ */
+
+#define IO_BASE_VIRT 0xE8000000 /* VA of IO */
+
+/* macro to get at IO space when running virtually */
+/* this version gives more IO address range to map*/
+#define IO_ADDRESS(x) ((x) - IO_BASE_PHYS + IO_BASE_VIRT)
+
+/* typesafe io address */
+#define __io_address(n) __io(IO_ADDRESS(n))
+
+/*
+ * Board specific defines
+ */
+
+#endif
+
diff --git a/arch/arm/plat-u6xxx/include/mach/io.h b/arch/arm/plat-u6xxx/include/mach/io.h
new file mode 100644
index 0000000..e8a93b4
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/io.h
@@ -0,0 +1,30 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/io.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Dummy IO map & IO definitions
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a) __typesafe_io(a)
+#define __mem_pci(a) (a)
+
+/*
+ * I/O mapping
+ */
+#ifdef __ASSEMBLER__
+#define IOMEM(x) (x)
+#else
+#define IOMEM(x) ((void __force __iomem *)(x))
+#endif
+#define U6_IO_ADDRESS(pa) IOMEM(IO_ADDRESS(pa))
+
+void u6xxx_map_io(void);
+
+#endif /* __ASM_ARM_ARCH_IO_H */
diff --git a/arch/arm/plat-u6xxx/include/mach/irqs.h b/arch/arm/plat-u6xxx/include/mach/irqs.h
new file mode 100644
index 0000000..2943882
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/irqs.h
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/irqs.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_PLAT_U6_IRQS_H
+#define __ASM_PLAT_U6_IRQS_H
+
+#define IRQ_COUNT 65
+
+/* external IRQ definition EXTINT */
+#define IRQ_EXTINT(num) (IRQ_COUNT+(num))
+#define EXTINT_NUM(irq) ((irq)-IRQ_COUNT)
+
+#define NR_EXTINT 24
+#define NR_IRQS (IRQ_COUNT+NR_EXTINT)
+
+#ifndef __ASSEMBLY__
+extern unsigned char extint_to_gpio[NR_EXTINT];
+
+#define EXTINT_TO_GPIO(gpio_irq) extint_to_gpio[gpio_irq-IRQ_COUNT]
+
+void /*__init */ u6_init_irq(void);
+void u6_monitor_irq_enter(unsigned int irq);
+void u6_monitor_irq_exit(unsigned int irq);
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Interrupt numbers
+ */
+#define IRQ_GHOST 0
+#define IRQ_EXTINT1 1
+#define IRQ_EXTINT2 2
+#define IRQ_EXTINT3 3
+#define IRQ_RFRD 4
+#define IRQ_MMTU 5
+#define IRQ_IIS 6
+#define IRQ_USB 7
+#define IRQ_I2C2 8
+#define IRQ_TVO 9
+#define IRQ_3G_WUP 10
+#define IRQ_3G_CALINT 11
+#define IRQ_3G_FRAME_IT 12
+#define IRQ_GPADCINT 13
+#define IRQ_ARM9_COMMTX 14
+#define IRQ_ARM9_COMMRX 15
+#define IRQ_KBS 16
+#define IRQ_SCTU2 17
+#define IRQ_SCTU1 18
+#define IRQ_PIO1 19
+#define IRQ_PIO2 20
+#define IRQ_FINT0 21
+#define IRQ_FINT1 22
+#define IRQ_UART2 23
+#define IRQ_UART1 24
+#define IRQ_SPI2 25
+#define IRQ_SPI1 26
+#define IRQ_FCI 27
+#define IRQ_I2C1 28
+#define IRQ_DMAU 29
+#define IRQ_USIM 30
+#define IRQ_HSDPA 31 /* reserved */
+#define IRQ_MSI 32
+#define IRQ_JDI 33
+#define IRQ_JDU 34
+#define IRQ_NFI 35
+#define IRQ_IPP 36
+#define IRQ_VDC 37
+#define IRQ_VEC 38
+#define IRQ_VDE 39
+#define IRQ_CAM 40
+#define IRQ_ETB_ACQ 41
+#define IRQ_ETB_FULL 42
+#define IRQ_RESERVED43 43
+#define IRQ_RESERVED44 44
+#define IRQ_RESERVED45 45 /* reserved */
+#define IRQ_RESERVED46 46
+#define IRQ_RESERVED47 47
+#define IRQ_PDCU 48
+#define IRQ_MC2SC0 49
+#define IRQ_MC2SC1 50
+#define IRQ_MC2SC2 51
+#define IRQ_MC2SC3 52
+#define IRQ_MC2SC4 53
+#define IRQ_MC2SC5 54
+#define IRQ_MC2SC6 55
+#define IRQ_MC2SC7 56
+
+/* INTC VECTOR_IRQ Register (32 bits) */
+#define INTC_VECTOR_IRQ_OFFSET 0x100
+
+/* INTC REQUEST 64 Registers (32 bits) */
+#define INTC_REQUEST1_OFFSET 0x404
+#define INTC_REQUEST64_OFFSET 0x500
+
+/* interrupt x [1..64] request configuration */
+#define INTC_REQUESTx(x) U6_IO_ADDRESS(INTC_BASE+INTC_REQUEST1_OFFSET+(x-1)*4)
+
+#endif /* __ASM_PLAT_U6_IRQS_H */
diff --git a/arch/arm/plat-u6xxx/include/mach/memory.h b/arch/arm/plat-u6xxx/include/mach/memory.h
new file mode 100644
index 0000000..71a5c60
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/memory.h
@@ -0,0 +1,17 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/memory.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET UL(0x20000000)
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/regs-u6.h b/arch/arm/plat-u6xxx/include/mach/regs-u6.h
new file mode 100644
index 0000000..aa2fbb0
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/regs-u6.h
@@ -0,0 +1,121 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/regs-u6.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ * Basic register address definitions in physical memory
+ */
+
+#if !defined(__REGS_U6_H__)
+#define __REGS_U6_H__
+
+#define IO_BASE_PHYS 0xC1000000 /* phys base address of reg */
+#define IO_SIZE 0x03400000 /* How much */
+
+/*
+ * System Controller Core devices base address table
+ */
+
+/* DMA Controller */
+#define DMAU_BASE (IO_BASE_PHYS + 0x0000000)
+
+/* Interrupt Controller */
+#define INTC_BASE (IO_BASE_PHYS + 0x0100000)
+
+/* SDRam controller */
+#define SDI_BASE (IO_BASE_PHYS + 0x0200000)
+
+/* Nand Flash Inteface controller */
+#define NFI_BASE (IO_BASE_PHYS + 0x0300000)
+
+/* USB controller */
+#define USB_BASE (IO_BASE_PHYS + 0x0400000)
+
+/* Video Display Engine */
+#define VDE_BASE (IO_BASE_PHYS + 0x0500000)
+
+/* Video Decoder */
+#define VDC_BASE (IO_BASE_PHYS + 0x1000000)
+
+/* Viedo Encoder */
+#define VEC_BASE (IO_BASE_PHYS + 0x1100000)
+
+/* Texture Codec, MPEG4 encoder sub module */
+#define TC_BASE (IO_BASE_PHYS + 0x1102000)
+
+/* Image Post-Processor */
+#define IPP2_BASE (IO_BASE_PHYS + 0x1200000)
+
+/* JPEG Decoder Unit */
+#define JDU_BASE (IO_BASE_PHYS + 0x1300000)
+
+/* TV output controller */
+#define TVO_BASE (IO_BASE_PHYS + 0x1400000)
+
+/* Camera controller */
+#define CAM_BASE (IO_BASE_PHYS + 0x1800000)
+
+/* External Bus Interfaces */
+#define EBI_BASE (IO_BASE_PHYS + 0x2001000)
+
+/* SPI controllers */
+#define SPI1_BASE (IO_BASE_PHYS + 0x2002000)
+#define SPI2_BASE (IO_BASE_PHYS + 0x2003000)
+
+/* SD/MMC controller */
+#define FCI_BASE (IO_BASE_PHYS + 0x2008000)
+
+/* Crypto Acceleration Engine */
+#define CAE_BASE (IO_BASE_PHYS + 0x2009000)
+
+/* Multimedia Timer Unit, aka MTU in Datasheet */
+#define MMTU_BASE (IO_BASE_PHYS + 0x2101000)
+
+/* System controller timer units */
+#define SCTU1_BASE (IO_BASE_PHYS + 0x2102000)
+#define SCTU2_BASE (IO_BASE_PHYS + 0x2103000)
+
+/* General Purpose I/O units */
+#define GPIOA_BASE (IO_BASE_PHYS + 0x2104000)
+#define GPIOB_BASE (IO_BASE_PHYS + 0x2104200)
+#define GPIOC_BASE (IO_BASE_PHYS + 0x2104400)
+#define GPIOD_BASE (IO_BASE_PHYS + 0x2104600)
+#define GPIOE_BASE (IO_BASE_PHYS + 0x2104800)
+#define GPIOF_BASE (IO_BASE_PHYS + 0x2104A00)
+
+/* External Interrupt controller */
+#define EXTINT_BASE (IO_BASE_PHYS + 0x2105000)
+
+/* Keyboard Scanner */
+#define KBS_BASE (IO_BASE_PHYS + 0x2106000)
+
+/* Pulse Width Modulators */
+#define PWM1_BASE (IO_BASE_PHYS + 0x2108000)
+#define PWM2_BASE (IO_BASE_PHYS + 0x2109000)
+#define PWM3_BASE (IO_BASE_PHYS + 0x210A000)
+
+/* I2C controllers */
+#define I2C1_BASE (IO_BASE_PHYS + 0x210C000)
+#define I2C2_BASE (IO_BASE_PHYS + 0x210D000)
+
+/* UARTs */
+#define UART1_BASE (IO_BASE_PHYS + 0x210E000)
+#define UART2_BASE (IO_BASE_PHYS + 0x210F000)
+
+/* Clock Generation Unit */
+#define CGU_BASE (IO_BASE_PHYS + 0x2200000)
+
+/* Time base Unit */
+#define TBU_BASE (IO_BASE_PHYS + 0x2201000)
+
+/* Power Down Control Unit */
+#define PDCU_BASE (IO_BASE_PHYS + 0x2202000)
+
+/* Watchdog & Reset Unit */
+#define WDRU_BASE (IO_BASE_PHYS + 0x2203000)
+
+/* System Configuration */
+#define SCON_BASE (IO_BASE_PHYS + 0x2204000)
+
+#endif /* __REGS_U6_H__ */
diff --git a/arch/arm/plat-u6xxx/include/mach/system.h b/arch/arm/plat-u6xxx/include/mach/system.h
new file mode 100644
index 0000000..8799e57
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/system.h
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/system.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <mach/hardware.h>
+
+/* Watchdog & Reset Unit TIMER Register (16 bits) */
+#define WDRU_TIM_OFFSET 0x4
+
+static inline void arch_idle(void)
+{
+ /*
+ * This should do all the clock switching
+ * and wait for interrupt tricks
+ */
+ cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+ unsigned long flags;
+ /*
+ * To reset, we hit the on-board reset register
+ * in the system FPGA
+ */
+ /* diasble HW interruption */
+ raw_local_irq_save(flags);
+ /* load watchdog with reset value */
+ writel(0x5, IO_ADDRESS(WDRU_BASE + WDRU_TIM_OFFSET));
+ /* wait for wachdog expiration */
+ while (1)
+ ;
+}
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/timer.h b/arch/arm/plat-u6xxx/include/mach/timer.h
new file mode 100644
index 0000000..614d6cf
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/timer.h
@@ -0,0 +1,16 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/timer.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef __PLAT_TIMER_H
+#define __PLAT_TIMER_H
+
+struct sys_timer;
+
+extern struct sys_timer u6_timer;
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/timex.h b/arch/arm/plat-u6xxx/include/mach/timex.h
new file mode 100644
index 0000000..1e71241
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/timex.h
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/timex.h
+ *
+ * Integrator architecture timex specifications
+ *
+ * Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define CLOCK_TICK_RATE (50000000 / 16)
diff --git a/arch/arm/plat-u6xxx/include/mach/uncompress.h b/arch/arm/plat-u6xxx/include/mach/uncompress.h
new file mode 100644
index 0000000..e37f0b4
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/uncompress.h
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/uncompress.h
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2003 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/io.h>
+#include "mach/hardware.h"
+
+/* UART THR Register (8 bits) */
+#define UART1_THR_OFFSET 0x0
+#define UART1_THR_REG IO_ADDRESS(UART1_BASE + UART1_THR_OFFSET)
+
+/* UART LSR Register (8 bits) */
+#define UART1_LSR_OFFSET 0x14
+#define UART1_LSR_REG IO_ADDRESS(UART1_BASE + UART1_LSR_OFFSET)
+
+static void putc(int c)
+{
+ while (!(readb(UART1_LSR_REG) & (1<<5)))
+ barrier();
+ writeb(c, UART1_THR_REG);
+}
+
+static inline void flush(void)
+{
+}
+
+/* nothing to do */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
diff --git a/arch/arm/plat-u6xxx/include/mach/vmalloc.h b/arch/arm/plat-u6xxx/include/mach/vmalloc.h
new file mode 100644
index 0000000..cb89107
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/vmalloc.h
@@ -0,0 +1,10 @@
+/*
+ * linux/arch/arm/plat-u6/include/mach/vmalloc.h
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Virtual memory allocations
+ * End must be above the I/O registers and on an even 2MiB boundary.
+ */
+#define VMALLOC_END 0xe8000000UL
diff --git a/arch/arm/plat-u6xxx/io.c b/arch/arm/plat-u6xxx/io.c
new file mode 100644
index 0000000..01d447c
--- /dev/null
+++ b/arch/arm/plat-u6xxx/io.c
@@ -0,0 +1,34 @@
+/*
+ * linux/arch/arm/plat-u6xxx/io.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+
+
+static struct map_desc u6xxx_io_desc[] __initdata = {
+ {
+ .virtual = IO_BASE_VIRT, /* only peripherals */
+ .pfn = __phys_to_pfn(IO_BASE_PHYS),
+ .length = IO_SIZE,
+ .type = MT_DEVICE,
+ }
+};
+
+void __init u6xxx_map_io(void)
+{
+ iotable_init(u6xxx_io_desc, ARRAY_SIZE(u6xxx_io_desc));
+}
+
diff --git a/arch/arm/plat-u6xxx/irq.c b/arch/arm/plat-u6xxx/irq.c
new file mode 100644
index 0000000..2ede5f0
--- /dev/null
+++ b/arch/arm/plat-u6xxx/irq.c
@@ -0,0 +1,254 @@
+/*
+ * linux/arch/arm/plat-u6xxx/irq.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <mach/irqs.h> /* U6 specific constants, types */
+
+/* INTC PRIOMASK_IRQ Register (32 bits) */
+#define INTC_PRIOMASK_IRQ_OFFSET 0x0
+#define INTC_PRIOMASK_IRQ_REG IO_ADDRESS(INTC_BASE + INTC_PRIOMASK_IRQ_OFFSET)
+
+/* INTC PRIOMASK_FIQ Register (32 bits) */
+#define INTC_PRIOMASK_FIQ_OFFSET 0x4
+#define INTC_PRIOMASK_FIQ_REG IO_ADDRESS(INTC_BASE + INTC_PRIOMASK_FIQ_OFFSET)
+
+/* INTC VECTOR_IRQ Register (32 bits) */
+#define INTC_VECTOR_IRQ_REG IO_ADDRESS(INTC_BASE + INTC_VECTOR_IRQ_OFFSET)
+
+/* INTC VECTOR_FIQ Register (32 bits) */
+#define INTC_VECTOR_FIQ_OFFSET 0x104
+#define INTC_VECTOR_FIQ_REG IO_ADDRESS(INTC_BASE + INTC_VECTOR_FIQ_OFFSET)
+
+/* INTC PENDING_* Registers (32 bits) */
+#define INTC_PENDING_1_OFFSET 0x200
+#define INTC_PENDING_2_OFFSET 0x204
+#define INTC_PENDING_3_OFFSET 0x208
+#define INTC_FEATURES_OFFSET 0x300
+
+#define INTC_REQUESTx_PENDING_MASK (1 << 31)
+#define INTC_REQUESTx_SET_SWINT_MASK (1 << 30)
+#define INTC_REQUESTx_CLR_SWINT_MASK (1 << 29)
+#define INTC_REQUESTx_WE_PRIORITY_MASK (1 << 28)
+#define INTC_REQUESTx_WE_TARGET_MASK (1 << 27)
+#define INTC_REQUESTx_WE_ENABLE_MASK (1 << 26)
+#define INTC_REQUESTx_WE_ACTIVE_LOW_MASK (1 << 25)
+#define INTC_REQUESTx_ACTIVE_LOW_MASK (1 << 17)
+#define INTC_REQUESTx_ENABLE_MASK (1 << 16)
+#define INTC_REQUESTx_TARGET_MASK (1 << 8)
+
+#define INTC_IID_USB_LP_INT 13
+
+static void u6_irq_mask(uint32_t irqno)
+{
+ if (irqno > 0 || irqno < IRQ_COUNT) {
+ unsigned long flags;
+ void __iomem *a;
+ uint32_t v;
+
+ raw_local_irq_save(flags);
+
+ a = INTC_REQUESTx(irqno);
+ v = readl(a);
+ v &= ~INTC_REQUESTx_ENABLE_MASK;
+ v |= INTC_REQUESTx_WE_ENABLE_MASK;
+ v |= INTC_REQUESTx_CLR_SWINT_MASK;
+ writel(v, a);
+
+ raw_local_irq_restore(flags);
+ }
+}
+
+static void u6_irq_unmask(uint32_t irqno)
+{
+ if (irqno > 0 || irqno < IRQ_COUNT) {
+ unsigned long flags;
+ void __iomem *a;
+ uint32_t v;
+
+ raw_local_irq_save(flags);
+
+ a = INTC_REQUESTx(irqno);
+ v = readl(a);
+ v |= INTC_REQUESTx_ENABLE_MASK;
+ v |= INTC_REQUESTx_WE_ENABLE_MASK;
+ v |= INTC_REQUESTx_CLR_SWINT_MASK;
+ writel(v, a);
+
+ raw_local_irq_restore(flags);
+ }
+}
+
+static int u6_irq_type(unsigned irqno, unsigned type)
+{
+ int l;
+ void __iomem *reg = INTC_REQUESTx(irqno);
+
+ if (irqno > 0 || irqno < IRQ_COUNT) {
+ if (type == IRQF_TRIGGER_LOW) {
+ l = (INTC_REQUESTx_ACTIVE_LOW_MASK
+ | INTC_REQUESTx_WE_ACTIVE_LOW_MASK);
+ } else if (type == IRQF_TRIGGER_HIGH) {
+ l = (INTC_REQUESTx_WE_ACTIVE_LOW_MASK);
+ } else {
+ goto bad;
+ }
+
+ writel(l, reg);
+ return 0;
+
+ }
+
+bad:
+ return -EINVAL;
+}
+
+int u6_irq_enabled(uint32_t irqno)
+{
+ if (irqno > 0 || irqno < IRQ_COUNT) {
+ void __iomem *a = INTC_REQUESTx(irqno);
+ uint32_t v = readl(a);
+
+ return v & INTC_REQUESTx_ENABLE_MASK;
+ } else
+ return 0;
+}
+
+static struct irq_chip u6_irq_chip = {
+ .ack = u6_irq_mask,
+ .mask = u6_irq_mask, /* disable irqs */
+ .unmask = u6_irq_unmask, /* enable irqs */
+ .set_type = u6_irq_type,
+};
+
+
+#if defined(CONFIG_ARCH_U67XX)
+
+static const uint32_t u6_irq_config[] = {
+ 0, /* GHOST 0 */
+ INTC_REQUESTx_ACTIVE_LOW_MASK, /* EXTINT1 1 */
+ INTC_REQUESTx_ACTIVE_LOW_MASK, /* EXTINT2 2 */
+ INTC_REQUESTx_ACTIVE_LOW_MASK, /* EXTINT3 3 */
+ 0, /* RFRD 4 */
+ 0, /* MTU 5 */
+ 0, /* IIS 6 */
+ 0, /* USB 7 */
+ INTC_REQUESTx_ACTIVE_LOW_MASK, /* I2C2 8 */
+ 0, /* TVO 9 */
+ 0, /* 3G_WUP 10 */
+ 0, /* 3G_CALINT 11 */
+ 0, /* 3G_FRAME_IT 12 */
+ 0, /* GPADCINT 13 */
+ 0, /* ARM9_COMMTX 14 */
+ 0, /* ARM9_COMMRX 15 */
+ 0, /* KBS 16 */
+ 0, /* SCTU2 17 */
+ 0, /* SCTU1 18 */
+ 0, /* PIO1 19 */
+ 0, /* PIO2 20 */
+ 0, /* FINT0 21 */
+ 0, /* FINT1 22 */
+ 0, /* UART2 23 */
+ 0, /* UART1 24 */
+ 0, /* SPI2 25 */
+ 0, /* SPI1 26 */
+ 0, /* FCI 27 */
+ INTC_REQUESTx_ACTIVE_LOW_MASK, /* I2C1 28 */
+ 0, /* DMAU 29 */
+ 0, /* USIM 30 */
+ 0, /* RESERVED31 31 */
+ INTC_REQUESTx_ACTIVE_LOW_MASK, /* MSI 32 */
+ 0, /* JDI 33 */
+ 0, /* JDU 34 */
+ 0, /* NFI 35 */
+ 0, /* IPP 36 */
+ 0, /* VDC 37 */
+ 0, /* VEC 38 */
+ 0, /* VDE 39 */
+ INTC_REQUESTx_ACTIVE_LOW_MASK, /* CAM 40 */
+ 0, /* ETB_ACQ 41 */
+ 0, /* ETB_FULL 42 */
+ 0, /* DIGRF_TX 43 */
+ 0, /* DIGRF_RX 44 */
+ 0, /* RESERVED45 45 */
+ 0, /* FIR_FI 46 */
+ 0, /* FIR 47 */
+ 0, /* PDCU 48 */
+ 0, /* MC2SC0 49 */
+ 0, /* MC2SC1 50 */
+ 0, /* MC2SC2 51 */
+ 0, /* MC2SC3 52 */
+ 0, /* MC2SC4 53 */
+ 0, /* MC2SC5 54 */
+ 0, /* MC2SC6 55 */
+ 0, /* MC2SC7 56 */
+ 0, /* Reserved 57 */
+ 0, /* Reserved 58 */
+ 0, /* Reserved 59 */
+ 0, /* Reserved 60 */
+ 0, /* Reserved 61 */
+ 0, /* Reserved 62 */
+ 0, /* Reserved 63 */
+ 0, /* Reserved 64 */
+};
+
+#endif
+
+static const uint32_t u6_irq_irq_priority;
+static const uint32_t u6_irq_fiq_priority;
+
+void __init u6_init_irq(void)
+{
+ unsigned int irqno;
+
+ /* Clock interrupt controller.
+ */
+ struct clk *clk = clk_get(NULL, "INTC");
+ clk_enable(clk);
+ clk_put(clk);
+
+ /* The address of the vector table INTCdata.asm is assumed to be aligned
+ * to a 2KB boundary. Thus the register access value will be padded with
+ * zeroes, which is conforming to the 'READ_ONLY' attributes of the LS
+ * 11 bits. We are using the same table for both IRQ and FIQ.
+ */
+ writel(0, INTC_VECTOR_FIQ_REG); /* no vector IRQ */
+ writel(0, INTC_VECTOR_IRQ_REG); /* no vector FIQ */
+
+ writel(u6_irq_irq_priority, INTC_PRIOMASK_IRQ_REG);
+ writel(u6_irq_fiq_priority, INTC_PRIOMASK_FIQ_REG);
+
+ /* Initialize the individual interrupt sources.
+ */
+ for (irqno = 1; irqno < IRQ_COUNT; irqno += 1) {
+ void __iomem *a = INTC_REQUESTx(irqno);
+ uint32_t v = u6_irq_config[irqno];
+
+ v |= 4;
+ v |= INTC_REQUESTx_WE_ACTIVE_LOW_MASK;
+ v |= INTC_REQUESTx_WE_TARGET_MASK;
+ v |= INTC_REQUESTx_WE_PRIORITY_MASK;
+ v |= INTC_REQUESTx_WE_ENABLE_MASK;
+ v |= INTC_REQUESTx_CLR_SWINT_MASK;
+
+ writel(v, a);
+
+ set_irq_chip(irqno, &u6_irq_chip);
+ set_irq_handler(irqno, handle_level_irq);
+ set_irq_flags(irqno, IRQF_VALID | IRQF_PROBE);
+ }
+}
diff --git a/arch/arm/plat-u6xxx/timer.c b/arch/arm/plat-u6xxx/timer.c
new file mode 100644
index 0000000..b72e8cf
--- /dev/null
+++ b/arch/arm/plat-u6xxx/timer.c
@@ -0,0 +1,442 @@
+/*
+ * linux/arch/arm/plat-u6xxx/timer.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Vincent Guittot <vincent.guittot(a)stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/clock.h>
+
+/*** System timer variable ***/
+struct sys_timer u6_timer;
+
+/*** Module definition ***/
+/*************************/
+
+#define MODULE_NAME "U6_TIMER"
+#define PKMOD MODULE_NAME ": "
+
+/*#define DEBUG*/
+#define U6_MMTU_CLOCK_SOURCE
+
+/*** MMTU clock devices ***/
+/*************************/
+
+/*** MMTU HW ip register index definition ***/
+#define MMTU_CON_IDX 0
+#define MMTU_TCVAL_IDX 0x4
+#define MMTU_PRESCALER_IDX 0x8
+#define MMTU_MATCH_CON_IDX 0xC
+#define MMTU_MATCH0_IDX 0x14
+#define MMTU_MATCH1_IDX 0x18
+
+#define MMTU_INT_OFFSET 0xFD0
+#define MMTU_MOD_CONF_IDX 0x4
+#define MMTU_INT_CLR_ENA_IDX 0x8
+#define MMTU_INT_SET_ENA_IDX 0xC
+#define MMTU_INT_STATUS_IDX 0x10
+#define MMTU_INT_ENABLE_IDX 0x14
+#define MMTU_INT_CLR_STAT_IDX 0x18
+#define MMTU_INT_SET_STAT_IDX 0x1C
+
+#define MMTU_IRQ_MASK 0x1
+#define MMTU_USED_MATCH_IDX MMTU_MATCH0_IDX
+
+/* MMTU sys clock definition */
+#define MMTU_SYS_FRQ 13000000
+
+/*** MMTU Clock event device ***/
+#define MMTU_ROOT_FRQ 8000
+static int u6_mmtu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt);
+static void u6_mmtu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt);
+
+static struct clock_event_device clockevent_mmtu = {
+ .name = "mmtu_timer",
+ .rating = 360,
+ .shift = 30,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .set_next_event = u6_mmtu_set_next_event,
+ .set_mode = u6_mmtu_set_mode,
+};
+
+/*** MMTU Clock source device ***/
+#ifdef U6_MMTU_CLOCK_SOURCE
+static cycle_t u6_mmtu_read(struct clocksource *);
+
+static struct clocksource clocksource_mmtu = {
+ .name = "mmtu_timer",
+ .rating = 360,
+ .read = u6_mmtu_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 8,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+#endif
+
+/*** MMTU driver ***/
+#define RELOAD_COUNTER_POWER_MMTU 32
+#define RELOAD_COUNTER_MMTU (1 << RELOAD_COUNTER_POWER_MMTU)
+
+struct mmtu_ctxt {
+ void __iomem *base;
+ uint32_t compvalue;
+ uint32_t endvalue;
+ struct clk *clk;
+ int mode;
+};
+
+struct mmtu_ctxt mmtu_table[1] = {
+ {
+ .base = U6_IO_ADDRESS(MMTU_BASE),
+ },
+};
+
+static inline struct mmtu_ctxt *u6_mmtu_get_context(int id)
+{
+ return &(mmtu_table[id]);
+}
+
+static inline int u6_mmtu_timer_start(unsigned long cycles, int id);
+static inline void u6_mmtu_clk_enable(int id);
+static inline void u6_mmtu_clk_disable(int id);
+
+static irqreturn_t
+u6_mmtu_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ uint8_t status, enable;
+ struct mmtu_ctxt *mmtu;
+
+ mmtu = u6_mmtu_get_context(0);
+
+ status = readl((mmtu->base + MMTU_INT_OFFSET + MMTU_INT_STATUS_IDX));
+ enable = readl((mmtu->base + MMTU_INT_OFFSET + MMTU_INT_ENABLE_IDX));
+
+ pr_debug(PKMOD "mmtu_timer_interrupt %d\n", status);
+
+ if (status & enable & MMTU_IRQ_MASK) {
+ struct clock_event_device *evt = &clockevent_mmtu;
+
+ writel(MMTU_IRQ_MASK, (mmtu->base + MMTU_INT_OFFSET
+ + MMTU_INT_CLR_STAT_IDX));
+ writel(MMTU_IRQ_MASK,
+ (mmtu->base + MMTU_INT_OFFSET +
+ MMTU_INT_CLR_ENA_IDX));
+
+ if (evt->event_handler)
+ evt->event_handler(evt);
+ }
+ return IRQ_HANDLED;
+}
+
+static struct irqaction u6_mmtu_timer_irq = {
+ .name = "U6 MMTU timer Tick",
+ .flags = IRQF_DISABLED,
+ .handler = (irq_handler_t) u6_mmtu_timer_interrupt,
+};
+
+static inline void u6_mmtu_clk_enable(int id)
+{
+ struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+ /* Clock Multimedia Timer Unit.
+ */
+ if ((mmtu->clk != NULL) && (mmtu->mode == 0)) {
+ pr_debug(PKMOD "mmtu_clk_enable\n");
+ mmtu->mode = 1;
+ clk_enable(mmtu->clk);
+ }
+}
+
+static inline void u6_mmtu_clk_disable(int id)
+{
+ struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+ /* Clock Multimedia Timer Unit.
+ */
+ if ((mmtu->clk != NULL) && (mmtu->mode == 1)) {
+ pr_debug(PKMOD "mmtu_clk_disable\n");
+ clk_disable(mmtu->clk);
+ mmtu->mode = 0;
+ }
+}
+
+static inline int u6_mmtu_timer_start(unsigned long cycles, int id)
+{
+ struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+ pr_debug(PKMOD "mmtu_timer_start %ld\n", cycles);
+ u6_mmtu_clk_enable(id);
+
+ /* MMTU limitation : can't set a value smaller or equal to tcval + 1 */
+ cycles = cycles < 2 ? 2 : cycles;
+
+ mmtu->compvalue = cycles;
+
+ mmtu->endvalue = mmtu->compvalue
+ + readl((mmtu->base + MMTU_TCVAL_IDX));
+
+ writel(MMTU_IRQ_MASK,
+ (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+ writel(mmtu->endvalue, (mmtu->base + MMTU_USED_MATCH_IDX));
+
+ writel(MMTU_IRQ_MASK,
+ (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
+
+ /* the value has already expired */
+ if ((mmtu->endvalue <= readl((mmtu->base + MMTU_TCVAL_IDX)))
+ && (mmtu->endvalue > mmtu->compvalue)
+ && !(readl((mmtu->base + MMTU_INT_OFFSET
+ + MMTU_INT_STATUS_IDX)) & MMTU_IRQ_MASK))
+ writel(MMTU_IRQ_MASK, (mmtu->base + MMTU_INT_OFFSET
+ + MMTU_INT_SET_STAT_IDX));
+
+ return 0;
+}
+
+static int u6_mmtu_timer_init(int id, unsigned long reload,
+ unsigned long prescale, int over_it)
+{
+
+ struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+ pr_debug(PKMOD "mmtu_timer_init %d\n", id);
+
+ /* Enable clock */
+/*
+ u6_mmtu_clk_enable(id);
+ clk mngt not available yet
+ directly enable it
+*/
+ {
+ unsigned long flags;
+ unsigned long reg;
+ local_irq_save(flags);
+ reg = readl(CGU_GATESC2_REG);
+ reg |= 0x1 << 2;
+ writel(reg, CGU_GATESC2_REG);
+ local_irq_restore(flags);
+ }
+
+ /* Reset timer */
+ /* reset control register */
+ writel(0x0000, (mmtu->base + MMTU_CON_IDX));
+ writel(0x0002, (mmtu->base + MMTU_CON_IDX));
+ /* reset control register */
+ writel(0x0000, (mmtu->base + MMTU_CON_IDX));
+
+ /* clear whole enable irq register */
+ writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_ENA_IDX));
+ /* clear whole status register */
+ writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+ /* reset pre-scaler reload register */
+ writel(0x00000000, (mmtu->base + MMTU_PRESCALER_IDX));
+
+ /* reset match control register */
+ writel(0x0000, (mmtu->base + MMTU_MATCH_CON_IDX));
+ /* reset match 0 register */
+ writel(0x00000000, (mmtu->base + MMTU_MATCH0_IDX));
+ /* reset match 1 register */
+ writel(0x00000000, (mmtu->base + MMTU_MATCH1_IDX));
+
+ /* Initialize timer */
+ writel(prescale - 1, (mmtu->base + MMTU_PRESCALER_IDX));
+ /* power of 2 system clock */
+ writel(reload, (mmtu->base + MMTU_MATCH0_IDX));
+
+ /* enable counter register */
+ writel(0x0001, (mmtu->base + MMTU_CON_IDX));
+
+ /* clear whole status register */
+ writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+ if (id == 0)
+ setup_irq(IRQ_MMTU, &u6_mmtu_timer_irq);
+
+ /* Disable clock */
+#ifndef U6_MMTU_CLOCK_SOURCE
+ u6_mmtu_clk_disable(id);
+#endif
+ return 0;
+}
+
+/*** MMTU Clock event device ***/
+
+static int u6_mmtu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ pr_debug(PKMOD "mmtu_set_next_event %ld\n", cycles);
+ u6_mmtu_timer_start(cycles, 0);
+
+ return 0;
+}
+
+static void u6_mmtu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ struct mmtu_ctxt *mmtu = u6_mmtu_get_context(0);
+ unsigned long reg;
+
+ pr_debug(PKMOD "mmtu_set_mode %d\n", mode);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_UNUSED:
+ writel(MMTU_IRQ_MASK,
+ (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_ENA_IDX));
+ writel(MMTU_IRQ_MASK,
+ (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+ reg = readl((mmtu->base + MMTU_TCVAL_IDX));
+ writel(reg - 1, (mmtu->base + MMTU_USED_MATCH_IDX));
+
+#ifndef U6_MMTU_CLOCK_SOURCE
+ u6_mmtu_clk_disable(0);
+
+ if (mmtu->clk != NULL)
+ clk_put(mmtu->clk);
+#endif
+ break;
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ if (mmtu->clk == NULL) {
+ mmtu->clk = clk_get(NULL, "MMTU");
+ if (IS_ERR(mmtu->clk))
+ mmtu->clk = NULL;
+ }
+
+ writel(MMTU_IRQ_MASK,
+ (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+ writel(MMTU_IRQ_MASK,
+ (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ writel(MMTU_IRQ_MASK,
+ (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
+ break;
+ }
+}
+
+static void u6_clockevent_init_mmtu(void)
+{
+ printk(PKMOD "clockevent_init_mmtu\n");
+
+ /* prescale 13Mhz -> 1Mhz */
+#ifndef U6_MMTU_CLOCK_SOURCE
+ u6_mmtu_timer_init(0, 0, (MMTU_SYS_FRQ / MMTU_ROOT_FRQ), 0);
+#endif
+
+ /* issue it is shorter than reality and generates spurious irq */
+ /* clockevent_mmtu.mult = div_sc(MMTU_ROOT_FRQ, NSEC_PER_SEC,
+ * clockevent_mmtu.shift) + 1;*/
+ clockevent_mmtu.mult =
+ div_sc(MMTU_ROOT_FRQ, NSEC_PER_SEC, clockevent_mmtu.shift);
+
+ /* clockevent_mmtu.max_delta_ns = div_sc(RELOAD_COUNTER_MMTU,
+ * clockevent_mmtu.mult, clockevent_mmtu.shift);*/
+ /* In fact it is wider than the 32bits variable !!! */
+ clockevent_mmtu.max_delta_ns = 0xFFFFFFFF;
+
+ /* MMTU HW limitation: match register can't be set w/ tcval+1 */
+ /* clockevent_mmtu.min_delta_ns = div_sc(1, clockevent_mmtu.mult,
+ * clockevent_mmtu.shift)+1;*/
+ clockevent_mmtu.min_delta_ns =
+ div_sc(2, clockevent_mmtu.mult, clockevent_mmtu.shift) + 1;
+ /* avoid to much timer interrupt with 10us min between 2 irq */
+ if (clockevent_mmtu.min_delta_ns < 10000)
+ clockevent_mmtu.min_delta_ns = 10000;
+ else if (clockevent_mmtu.max_delta_ns < 10000)
+ clockevent_mmtu.min_delta_ns = clockevent_mmtu.max_delta_ns>>1;
+
+ clockevent_mmtu.cpumask = get_cpu_mask(0);
+ clockevents_register_device(&clockevent_mmtu);
+
+ u6_mmtu_set_next_event(MMTU_ROOT_FRQ / HZ, &clockevent_mmtu);
+}
+
+/*** MMTU Clock source device ***/
+#ifdef U6_MMTU_CLOCK_SOURCE
+
+static cycle_t u6_mmtu_read(struct clocksource *source)
+{
+ struct mmtu_ctxt *mmtu = u6_mmtu_get_context(0);
+
+ return readl(mmtu->base + MMTU_TCVAL_IDX);
+}
+
+static void u6_clocksource_init_mmtu(void)
+{
+ printk(PKMOD "clocksource_init_mmtu\n");
+
+ if (MMTU_ROOT_FRQ >= 1000000)
+ clocksource_mmtu.mult =
+ clocksource_khz2mult((MMTU_ROOT_FRQ / 1000),
+ clocksource_mmtu.shift);
+ else
+ clocksource_mmtu.mult = clocksource_hz2mult((MMTU_ROOT_FRQ),
+ clocksource_mmtu.shift);
+
+ u6_mmtu_timer_init(0, 0, (MMTU_SYS_FRQ / MMTU_ROOT_FRQ), 0);
+
+ clocksource_register(&clocksource_mmtu);
+}
+
+#endif
+
+/*** System timer init ***/
+/*************************/
+
+void __init u6_timer_init(void)
+{
+ printk(PKMOD "mmtu_timer_init\n");
+
+#ifdef U6_MMTU_CLOCK_SOURCE
+ u6_clocksource_init_mmtu();
+#endif
+
+ u6_clockevent_init_mmtu();
+}
+
+struct sys_timer u6_timer = {
+ .init = u6_timer_init,
+};
+
+#ifdef CONFIG_U6_POWER_SYSFS
+static int __init u6_mmtu_init_sysfs(void)
+{
+ printk(PKMOD "mmtu_init_sysfs\n");
+
+#ifdef U6_MMTU_CLOCK_SOURCE
+ if (sysfs_create_group(&u6_power_kobj, &dbs_attr_srce_group))
+ printk(PKMOD "Unable to register %s in sysfs\n",
+ dbs_attr_srce_group.name);
+#endif
+
+ if (sysfs_create_group(&u6_power_kobj, &dbs_attr_event_group))
+ printk(PKMOD "Unable to register %s in sysfs\n",
+ dbs_attr_event_group.name);
+
+ return 0;
+}
+
+module_init(u6_mmtu_init_sysfs);
+#endif
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/