diff options
Diffstat (limited to 'configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0004-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch')
-rw-r--r-- | configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0004-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch | 843 |
1 files changed, 0 insertions, 843 deletions
diff --git a/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0004-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch b/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0004-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch deleted file mode 100644 index 3e161f6..0000000 --- a/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.11-rc1/0004-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch +++ /dev/null @@ -1,843 +0,0 @@ -From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> -Date: Thu, 17 Nov 2011 14:36:23 +0100 -Subject: [PATCH] ARM: new platform for Energy Micro's EFM32 Cortex-M3 SoCs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> ---- - arch/arm/Kconfig | 15 +- - arch/arm/Kconfig.debug | 16 ++ - arch/arm/Makefile | 1 + - arch/arm/boot/dts/efm32gg-dk3750.dts | 126 +++++++++++ - arch/arm/mach-efm32/Makefile | 1 + - arch/arm/mach-efm32/Makefile.boot | 1 + - arch/arm/mach-efm32/clk.c | 88 ++++++++ - arch/arm/mach-efm32/cmu.h | 15 ++ - arch/arm/mach-efm32/common.h | 3 + - arch/arm/mach-efm32/dtmachine.c | 28 +++ - arch/arm/mach-efm32/include/mach/debug-macro.S | 48 ++++ - arch/arm/mach-efm32/include/mach/entry-macro.S | 9 + - arch/arm/mach-efm32/include/mach/io.h | 6 + - arch/arm/mach-efm32/include/mach/irqs.h | 6 + - arch/arm/mach-efm32/include/mach/system.h | 18 ++ - arch/arm/mach-efm32/include/mach/timex.h | 7 + - arch/arm/mach-efm32/time.c | 289 +++++++++++++++++++++++++ - 17 files changed, 676 insertions(+), 1 deletion(-) - create mode 100644 arch/arm/boot/dts/efm32gg-dk3750.dts - create mode 100644 arch/arm/mach-efm32/Makefile - create mode 100644 arch/arm/mach-efm32/Makefile.boot - create mode 100644 arch/arm/mach-efm32/clk.c - create mode 100644 arch/arm/mach-efm32/cmu.h - create mode 100644 arch/arm/mach-efm32/common.h - create mode 100644 arch/arm/mach-efm32/dtmachine.c - create mode 100644 arch/arm/mach-efm32/include/mach/debug-macro.S - create mode 100644 arch/arm/mach-efm32/include/mach/entry-macro.S - create mode 100644 arch/arm/mach-efm32/include/mach/io.h - create mode 100644 arch/arm/mach-efm32/include/mach/irqs.h - create mode 100644 arch/arm/mach-efm32/include/mach/system.h - create mode 100644 arch/arm/mach-efm32/include/mach/timex.h - create mode 100644 arch/arm/mach-efm32/time.c - -diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index ba412e0..b8196cc 100644 ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -404,6 +404,19 @@ config ARCH_EBSA110 - Ethernet interface, two PCMCIA sockets, two serial ports and a - parallel port. - -+config ARCH_EFM32 -+ bool "Energy Micro Cortex M3 Platform" -+ depends on !MMU -+ select ARM_NVIC -+ select CLKSRC_MMIO -+ select COMMON_CLK -+ select CPU_V7M -+ select GENERIC_CLOCKEVENTS -+ select HAVE_CLK -+ select NO_DMA -+ select NO_IOPORT -+ select USE_OF -+ - config ARCH_EP93XX - bool "EP93xx-based" - select ARCH_HAS_HOLES_MEMORYMODEL -@@ -1763,7 +1776,7 @@ config FORCE_MAX_ZONEORDER - int "Maximum zone order" if ARCH_SHMOBILE - range 11 64 if ARCH_SHMOBILE - default "12" if SOC_AM33XX -- default "9" if SA1111 -+ default "9" if SA1111 || ARCH_EFM32 - default "11" - help - The kernel memory allocator divides physically contiguous memory -diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index e401a76..9f1b304 100644 ---- a/arch/arm/Kconfig.debug -+++ b/arch/arm/Kconfig.debug -@@ -167,6 +167,22 @@ choice - Say Y here if you want the debug print routines to direct - their output to the serial port in the DC21285 (Footbridge). - -+ config DEBUG_EFM32_USART1 -+ bool "Kernel low-level debugging messages via USART1" -+ depends on ARCH_EFM32 -+ help -+ Say Y here if you want the debug print routines to direct -+ their output to the second USART port on efm32 based -+ machines. -+ -+ config DEBUG_EFM32_UART1 -+ bool "Kernel low-level debugging messages via UART1" -+ depends on ARCH_EFM32 -+ help -+ Say Y here if you want the debug print routines to direct -+ their output to the second UART port on efm32 based -+ machines. -+ - config DEBUG_FOOTBRIDGE_COM1 - bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1" - depends on FOOTBRIDGE -diff --git a/arch/arm/Makefile b/arch/arm/Makefile -index c0ac0f5..c632e2a 100644 ---- a/arch/arm/Makefile -+++ b/arch/arm/Makefile -@@ -152,6 +152,7 @@ machine-$(CONFIG_ARCH_CNS3XXX) += cns3xxx - machine-$(CONFIG_ARCH_DAVINCI) += davinci - machine-$(CONFIG_ARCH_DOVE) += dove - machine-$(CONFIG_ARCH_EBSA110) += ebsa110 -+machine-$(CONFIG_ARCH_EFM32) += efm32 - machine-$(CONFIG_ARCH_EP93XX) += ep93xx - machine-$(CONFIG_ARCH_GEMINI) += gemini - machine-$(CONFIG_ARCH_HIGHBANK) += highbank -diff --git a/arch/arm/boot/dts/efm32gg-dk3750.dts b/arch/arm/boot/dts/efm32gg-dk3750.dts -new file mode 100644 -index 0000000..10e8d94 ---- /dev/null -+++ b/arch/arm/boot/dts/efm32gg-dk3750.dts -@@ -0,0 +1,126 @@ -+/dts-v1/; -+/include/ "skeleton.dtsi" -+ -+/ { -+ model = "Energy Micro Giant Gecko Development Kit"; -+ compatible = "efm32,dk3750"; -+ -+ aliases { -+ serial4 = &uart4; -+ }; -+ -+ nvic: nv-interrupt-controller@0xe0000000 { -+ compatible = "arm,armv7m-nvic"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ reg = <0xe000e100 0xc00>; -+ }; -+ -+ chosen { -+ bootargs = "console=ttyefm4,115200 init=/linuxrc ignore_loglevel ihash_entries=64 dhash_entries=64 earlyprintk uclinux.physaddr=0x8c400000 root=/dev/mtdblock0"; -+ }; -+ -+ memory { -+ reg = <0x88000000 0x400000>; -+ }; -+ -+ soc { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ compatible = "simple-bus"; -+ interrupt-parent = <&nvic>; -+ ranges; -+ -+ adc@0x40002000 { -+ compatible = "efm32,adc"; -+ reg = <0x40002000 0x400>; -+ interrupts = <7>; -+ status = "ok"; -+ }; -+ -+ gpio: gpio@0x40006000 { -+ compatible = "efm32,gpio"; -+ reg = <0x40006000 0x1000>; -+ interrupts = <1 11>; -+ gpio-controller; -+ #gpio-cells = <2>; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ clocks = <&cmu 32>; -+ status = "ok"; -+ }; -+ -+ spi@0x4000c400 { /* USART1 */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "efm32,spi"; -+ reg = <0x4000c400 0x400>; -+ interrupts = <15 16>; -+ clocks = <&cmu 20>; -+ cs-gpios = <&gpio 51 1>; // D3 -+ status = "ok"; -+ -+ ks8851@0 { -+ compatible = "ks8851"; -+ spi-max-frequency = <6000000>; -+ reg = <0>; -+ interrupt-parent = <&boardfpga>; -+ interrupts = <4>; -+ status = "ok"; -+ }; -+ }; -+ -+ uart4: uart@0x4000e400 { /* UART1 */ -+ compatible = "efm32,uart"; -+ reg = <0x4000e400 0x400>; -+ interrupts = <22 23>; -+ clocks = <&cmu 23>; -+ location = <2>; -+ status = "ok"; -+ }; -+ -+ timer0: timer@40010000 { -+ compatible = "efm32,timer"; -+ reg = <0x40010000 0x400>; -+ interrupts = <2>; -+ clocks = <&cmu 24>; -+ }; -+ -+ timer1: timer@40010400 { -+ compatible = "efm32,timer"; -+ reg = <0x40010400 0x400>; -+ interrupts = <12>; -+ clocks = <&cmu 25>; -+ }; -+ -+ timer2: timer@40010800 { -+ compatible = "efm32,timer"; -+ reg = <0x40010800 0x400>; -+ interrupts = <13>; -+ clocks = <&cmu 26>; -+ }; -+ -+ timer3: timer@40010c00 { -+ compatible = "efm32,timer"; -+ reg = <0x40010c00 0x400>; -+ interrupts = <14>; -+ clocks = <&cmu 27>; -+ }; -+ -+ cmu: cmu@400c8000 { -+ compatible = "efm32,cmu"; -+ reg = <0x400c8000 0x400>; -+ interrupts = <32>; -+ #clock-cells = <1>; -+ }; -+ -+ boardfpga: boardfpga@0x80000000 { -+ compatible = "efm32board"; -+ reg = <0x80000000 0x400>; -+ irq-gpios = <&gpio 64 1>; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ status = "ok"; -+ }; -+ }; -+}; -diff --git a/arch/arm/mach-efm32/Makefile b/arch/arm/mach-efm32/Makefile -new file mode 100644 -index 0000000..c6786a0 ---- /dev/null -+++ b/arch/arm/mach-efm32/Makefile -@@ -0,0 +1 @@ -+obj-y += clk.o dtmachine.o time.o -diff --git a/arch/arm/mach-efm32/Makefile.boot b/arch/arm/mach-efm32/Makefile.boot -new file mode 100644 -index 0000000..385e93a ---- /dev/null -+++ b/arch/arm/mach-efm32/Makefile.boot -@@ -0,0 +1 @@ -+dtb-$(CONFIG_MACH_EFM32GG_DK3750) += efm32gg-dk3750.dtb -diff --git a/arch/arm/mach-efm32/clk.c b/arch/arm/mach-efm32/clk.c -new file mode 100644 -index 0000000..f99719a ---- /dev/null -+++ b/arch/arm/mach-efm32/clk.c -@@ -0,0 +1,88 @@ -+#include <linux/clk.h> -+#include <linux/io.h> -+#include <linux/clk-provider.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+ -+#include "cmu.h" -+ -+enum efm32_clks { -+ /* 0 */ hfxo, hfrco, lfxo, lfrco, ulfrco, auxhfrco, hfclknodiv, hfclk, -+ /* 8 */ hfperclk, hfcoreclk, lfaclk, lfbclk, wdogclk, hfcoreclkdma, -+ /* 14 */ hfcoreclkaes, hfcoreclkusbc, hfcoreclkusb, hfcoreclkle, -+ /* 18 */ hfcoreclkebi, hfperclkusart0, hfperclkusart1, hfperclkusart2, -+ /* 22 */ hfperclkuart0, hfperclkuart1, hfperclktimer0, hfperclktimer1, -+ /* 26 */ hfperclktimer2, hfperclktimer3, hfperclkacmp0, hfperclkacmp1, -+ /* 30 */ hfperclki2c0, hfperclki2c1, hfperclkgpio, hfperclkvcmp, -+ /* 34 */ hfperclkprs, hfperclkadc0, hfperclkdac0, clk_max -+}; -+ -+static struct clk *clk[clk_max]; -+static struct clk_onecell_data clk_data = { -+ .clks = clk, -+ .clk_num = ARRAY_SIZE(clk), -+}; -+ -+void __init efm32_clk_init(void) -+{ -+ int i; -+ struct device_node *np; -+ void __iomem *base; -+ -+ for (i = 0; i < clk_max; ++i) -+ clk[i] = ERR_PTR(-ENOENT); -+ -+ np = of_find_compatible_node(NULL, NULL, "efm32,cmu"); -+ if (!np) { -+ pr_warn("failed to find cmu node in device tree\n"); -+ return; -+ } -+ -+ base = of_iomap(np, 0); -+ if (!base) { -+ pr_warn("failed to map cmu\n"); -+ return; -+ } -+ -+ clk[hfxo] = clk_register_fixed_rate(NULL, "HFXO", NULL, -+ CLK_IS_ROOT, 48000000); -+ -+ clk[hfperclkusart0] = clk_register_gate(NULL, "HFPERCLK.USART0", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 0, 0, NULL); -+ clk[hfperclkusart1] = clk_register_gate(NULL, "HFPERCLK.USART1", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 1, 0, NULL); -+ clk[hfperclkusart2] = clk_register_gate(NULL, "HFPERCLK.USART2", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 2, 0, NULL); -+ clk[hfperclkuart0] = clk_register_gate(NULL, "HFPERCLK.UART0", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 3, 0, NULL); -+ clk[hfperclkuart1] = clk_register_gate(NULL, "HFPERCLK.UART1", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 4, 0, NULL); -+ clk[hfperclktimer0] = clk_register_gate(NULL, "HFPERCLK.TIMER0", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 5, 0, NULL); -+ clk[hfperclktimer1] = clk_register_gate(NULL, "HFPERCLK.TIMER1", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 6, 0, NULL); -+ clk[hfperclktimer2] = clk_register_gate(NULL, "HFPERCLK.TIMER2", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 7, 0, NULL); -+ clk[hfperclktimer3] = clk_register_gate(NULL, "HFPERCLK.TIMER3", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 8, 0, NULL); -+ clk[hfperclkacmp0] = clk_register_gate(NULL, "HFPERCLK.ACMP0", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 9, 0, NULL); -+ clk[hfperclkacmp1] = clk_register_gate(NULL, "HFPERCLK.ACMP1", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 10, 0, NULL); -+ clk[hfperclki2c0] = clk_register_gate(NULL, "HFPERCLK.I2C0", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 11, 0, NULL); -+ clk[hfperclki2c1] = clk_register_gate(NULL, "HFPERCLK.I2C1", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 12, 0, NULL); -+ clk[hfperclkgpio] = clk_register_gate(NULL, "HFPERCLK.GPIO", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 13, 0, NULL); -+ clk[hfperclkvcmp] = clk_register_gate(NULL, "HFPERCLK.VCMP", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 14, 0, NULL); -+ clk[hfperclkprs] = clk_register_gate(NULL, "HFPERCLK.PRS", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 15, 0, NULL); -+ clk[hfperclkadc0] = clk_register_gate(NULL, "HFPERCLK.ADC0", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 16, 0, NULL); -+ clk[hfperclkdac0] = clk_register_gate(NULL, "HFPERCLK.DAC0", "HFXO", -+ 0, base + CMU_HFPERCLKEN0, 17, 0, NULL); -+ -+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); -+} -diff --git a/arch/arm/mach-efm32/cmu.h b/arch/arm/mach-efm32/cmu.h -new file mode 100644 -index 0000000..a7e5741 ---- /dev/null -+++ b/arch/arm/mach-efm32/cmu.h -@@ -0,0 +1,15 @@ -+/* -+ * Register definition for efm32's CMU component -+ */ -+ -+#define CMU_OSCENCMD 0x20 -+#define CMU_OSCENCMD_HFXOEN 0x00000004 -+ -+#define CMU_CMD 0x24 -+#define CMU_CMD_HFCLKSEL_HFXO 0x00000002 -+ -+#define CMU_STATUS 0x2c -+#define CMU_STATUS_HFRCOSEL 0x00000400 -+#define CMU_STATUS_HFXOSEL 0x00000800 -+ -+#define CMU_HFPERCLKEN0 0x44 -diff --git a/arch/arm/mach-efm32/common.h b/arch/arm/mach-efm32/common.h -new file mode 100644 -index 0000000..8b04c19 ---- /dev/null -+++ b/arch/arm/mach-efm32/common.h -@@ -0,0 +1,3 @@ -+void efm32_timer_init(void); -+ -+void efm32_clk_init(void); -diff --git a/arch/arm/mach-efm32/dtmachine.c b/arch/arm/mach-efm32/dtmachine.c -new file mode 100644 -index 0000000..30fce6d ---- /dev/null -+++ b/arch/arm/mach-efm32/dtmachine.c -@@ -0,0 +1,28 @@ -+#include <linux/kernel.h> -+#include <linux/pinctrl/machine.h> -+#include <linux/irqdomain.h> -+#include <linux/of_platform.h> -+#include <linux/of_irq.h> -+#include <linux/irqchip.h> -+ -+#include <asm/mach/arch.h> -+#include <asm/mach/time.h> -+ -+#include "common.h" -+ -+static void __init efm32_init(void) -+{ -+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); -+} -+ -+static const char *const efm32gg_compat[] __initconst = { -+ "efm32,dk3750", -+ NULL -+}; -+ -+DT_MACHINE_START(EFM32DT, "EFM32 (Device Tree Support)") -+ .init_irq = irqchip_init, -+ .init_time = efm32_timer_init, -+ .init_machine = efm32_init, -+ .dt_compat = efm32gg_compat, -+MACHINE_END -diff --git a/arch/arm/mach-efm32/include/mach/debug-macro.S b/arch/arm/mach-efm32/include/mach/debug-macro.S -new file mode 100644 -index 0000000..c58915c ---- /dev/null -+++ b/arch/arm/mach-efm32/include/mach/debug-macro.S -@@ -0,0 +1,48 @@ -+/* -+ * 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. -+ */ -+ -+#define UARTn_CMD 0x000c -+#define UARTn_CMD_TXEN 0x0004 -+ -+#define UARTn_STATUS 0x0010 -+#define UARTn_STATUS_TXC 0x0020 -+#define UARTn_STATUS_TXBL 0x0040 -+ -+#define UARTn_TXDATA 0x0034 -+ -+ .macro addruart, rx, tmp -+#if defined(CONFIG_DEBUG_EFM32_USART1) -+ ldr \rx, =(0x4000c400) /* USART1 */ -+#elif defined(CONFIG_DEBUG_EFM32_UART1) -+ ldr \rx, =(0x4000e400) /* UART1 */ -+#else -+#error "No debug port configured" -+#endif -+ /* -+ * enable TX. The driver might disable that to save energy. We -+ * don't care about disabling at the end as during debug power -+ * consumption isn't that important. -+ */ -+ ldr \tmp, =(UARTn_CMD_TXEN) -+ str \tmp, [\rx, #UARTn_CMD] -+ .endm -+ -+ -+ .macro senduart,rd,rx -+ strb \rd, [\rx, #UARTn_TXDATA] -+ .endm -+ -+ .macro waituart,rd,rx -+1001: ldr \rd, [\rx, #UARTn_STATUS] -+ tst \rd, #UARTn_STATUS_TXBL -+ beq 1001b -+ .endm -+ -+ .macro busyuart,rd,rx -+1001: ldr \rd, [\rx, UARTn_STATUS] -+ tst \rd, #UARTn_STATUS_TXC -+ bne 1001b -+ .endm -diff --git a/arch/arm/mach-efm32/include/mach/entry-macro.S b/arch/arm/mach-efm32/include/mach/entry-macro.S -new file mode 100644 -index 0000000..547f7b1 ---- /dev/null -+++ b/arch/arm/mach-efm32/include/mach/entry-macro.S -@@ -0,0 +1,9 @@ -+/* -+ * -+ */ -+ -+ .macro get_irqnr_preamble, base, tmp -+ .endm -+ -+ .macro arch_ret_to_user, tmp1, tmp2 -+ .endm -diff --git a/arch/arm/mach-efm32/include/mach/io.h b/arch/arm/mach-efm32/include/mach/io.h -new file mode 100644 -index 0000000..bc3519b ---- /dev/null -+++ b/arch/arm/mach-efm32/include/mach/io.h -@@ -0,0 +1,6 @@ -+#ifndef __MACH_IO_H__ -+#define __MACH_IO_H__ -+ -+#define __mem_pci(a) (a) -+ -+#endif /* __MACH_IO_H__ */ -diff --git a/arch/arm/mach-efm32/include/mach/irqs.h b/arch/arm/mach-efm32/include/mach/irqs.h -new file mode 100644 -index 0000000..e33ed12 ---- /dev/null -+++ b/arch/arm/mach-efm32/include/mach/irqs.h -@@ -0,0 +1,6 @@ -+#ifndef __MACH_IRQS_H__ -+#define __MACH_IRQS_H__ -+ -+#define NR_IRQS 82 -+ -+#endif /* __MACH_IRQS_H__ */ -diff --git a/arch/arm/mach-efm32/include/mach/system.h b/arch/arm/mach-efm32/include/mach/system.h -new file mode 100644 -index 0000000..619222c ---- /dev/null -+++ b/arch/arm/mach-efm32/include/mach/system.h -@@ -0,0 +1,18 @@ -+#ifndef __MACH_SYSTEM_H__ -+#define __MACH_SYSTEM_H__ -+ -+#include <asm/io.h> -+ -+static inline void arch_idle(void) -+{ -+ cpu_do_idle(); -+} -+ -+static inline void arch_reset(char mode, const char *cmd) -+{ -+ /* XXX: move this to (say) cpuv7m_reset */ -+ dsb(); -+ __raw_writel(0x05fa0004, (void __iomem *)0xe000ed0c); -+ dsb(); -+} -+#endif /* __MACH_SYSTEM_H__ */ -diff --git a/arch/arm/mach-efm32/include/mach/timex.h b/arch/arm/mach-efm32/include/mach/timex.h -new file mode 100644 -index 0000000..b408dce ---- /dev/null -+++ b/arch/arm/mach-efm32/include/mach/timex.h -@@ -0,0 +1,7 @@ -+#ifndef __MACH_TIMEX_H__ -+#define __MACH_TIMEX_H__ -+ -+/* just a bogus value */ -+#define CLOCK_TICK_RATE 12345678 -+ -+#endif /* __MACH_TIMEX_H__ */ -diff --git a/arch/arm/mach-efm32/time.c b/arch/arm/mach-efm32/time.c -new file mode 100644 -index 0000000..1181bf2 ---- /dev/null -+++ b/arch/arm/mach-efm32/time.c -@@ -0,0 +1,289 @@ -+#define DEBUG -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include <linux/kernel.h> -+#include <linux/clocksource.h> -+#include <linux/clockchips.h> -+#include <linux/irq.h> -+#include <linux/interrupt.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/of_irq.h> -+#include <linux/clk.h> -+ -+#include <asm/mach/time.h> -+ -+#include "common.h" -+ -+#define BASEADDR_TIMER(n) IOMEM(0x40010000 + (n) * 0x400) -+ -+#define TIMERn_CTRL 0x00 -+#define TIMERn_CTRL_PRESC(val) (((val) & 0xf) << 24) -+#define TIMERn_CTRL_PRESC_1024 TIMERn_CTRL_PRESC(10) -+#define TIMERn_CTRL_CLKSEL(val) (((val) & 0x3) << 16) -+#define TIMERn_CTRL_CLKSEL_PRESCHFPERCLK TIMERn_CTRL_CLKSEL(0) -+#define TIMERn_CTRL_OSMEN 0x00000010 -+#define TIMERn_CTRL_MODE(val) (((val) & 0x3) << 0) -+#define TIMERn_CTRL_MODE_UP TIMERn_CTRL_MODE(0) -+#define TIMERn_CTRL_MODE_DOWN TIMERn_CTRL_MODE(1) -+ -+#define TIMERn_CMD 0x04 -+#define TIMERn_CMD_START 0x1 -+#define TIMERn_CMD_STOP 0x2 -+ -+#define TIMERn_IEN 0x0c -+#define TIMERn_IF 0x10 -+#define TIMERn_IFS 0x14 -+#define TIMERn_IFC 0x18 -+#define TIMERn_IRQ_UF 0x2 -+#define TIMERn_IRQ_OF 0x1 -+ -+#define TIMERn_TOP 0x1c -+#define TIMERn_CNT 0x24 -+ -+#define TIMER_CLOCKSOURCE 0 -+#define TIMER_CLOCKEVENT 1 -+ -+struct efm32_clock_event_ddata { -+ struct clock_event_device evtdev; -+ void __iomem *base; -+}; -+ -+static void efm32_clock_event_set_mode(enum clock_event_mode mode, -+ struct clock_event_device *evtdev) -+{ -+ struct efm32_clock_event_ddata *ddata = -+ container_of(evtdev, struct efm32_clock_event_ddata, evtdev); -+ -+ switch (mode) { -+ case CLOCK_EVT_MODE_PERIODIC: -+ writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); -+ writel_relaxed(137 /* XXX: magic constant */, ddata->base + TIMERn_TOP); -+ writel_relaxed(TIMERn_CTRL_PRESC_1024 | -+ TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | -+ TIMERn_CTRL_MODE_DOWN, -+ ddata->base + TIMERn_CTRL); -+ writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD); -+ break; -+ -+ case CLOCK_EVT_MODE_ONESHOT: -+ writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); -+ writel_relaxed(TIMERn_CTRL_PRESC_1024 | -+ TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | -+ TIMERn_CTRL_OSMEN | -+ TIMERn_CTRL_MODE_DOWN, -+ ddata->base + TIMERn_CTRL); -+ break; -+ -+ case CLOCK_EVT_MODE_UNUSED: -+ case CLOCK_EVT_MODE_SHUTDOWN: -+ writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); -+ break; -+ -+ case CLOCK_EVT_MODE_RESUME: -+ break; -+ } -+} -+ -+static int efm32_clock_event_set_next_event(unsigned long evt, -+ struct clock_event_device *evtdev) -+{ -+ struct efm32_clock_event_ddata *ddata = -+ container_of(evtdev, struct efm32_clock_event_ddata, evtdev); -+ -+ writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); -+ writel_relaxed(evt, ddata->base + TIMERn_CNT); -+ writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD); -+ -+ return 0; -+} -+ -+static irqreturn_t efm32_clock_event_handler(int irq, void *dev_id) -+{ -+ struct efm32_clock_event_ddata *ddata = dev_id; -+ -+ writel_relaxed(TIMERn_IRQ_UF, ddata->base + TIMERn_IFC); -+ -+ ddata->evtdev.event_handler(&ddata->evtdev); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct efm32_clock_event_ddata clock_event_ddata = { -+ .evtdev = { -+ .name = "efm32 clockevent", -+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_MODE_PERIODIC, -+ .set_mode = efm32_clock_event_set_mode, -+ .set_next_event = efm32_clock_event_set_next_event, -+ .rating = 200, -+ }, -+}; -+ -+static struct irqaction efm32_clock_event_irq = { -+ .name = "efm32 clockevent", -+ .flags = IRQF_TIMER, -+ .handler = efm32_clock_event_handler, -+ .dev_id = &clock_event_ddata, -+}; -+ -+/* -+ * XXX: use clk_ API to get frequency and enabling of the clocks used. -+ * Here the reset defaults are used: -+ * - freq_{HFPERCLK} = freq_{HFCLK} -+ * (CMU_HFPERCLKDIV_HFPERCLKDIV = 0x0) -+ * - freq_{HFCLK} = freq_{HFRCO} -+ * (CMU_CTRL_HFCLKDIV = 0x0, CMU_STATUS_HFRCOSEL = 0x1) -+ * - freq_{HFRCO} = 14MHz -+ * (CMU_HFRCOCTRL_BAND = 0x3) -+ * -+ * So the HFPERCLK runs at 14MHz. The timer has an additional prescaler -+ * programmed to /1024. This make the timer run at -+ * -+ * 14 MHz / 1024 = 13671.875 Hz -+ * -+ * When HFXO is used HFPERCLK runs at 48 MHz, so the timer runs at -+ * -+ * 48 MHz / 1024 = 46875 Hz -+ * -+ */ -+ -+static int efm32_timer_clocksource_init(struct device_node *np) -+{ -+ struct clk *clk; -+ void __iomem *base; -+ unsigned long rate; -+ int ret; -+ -+ clk = of_clk_get(np, 0); -+ if (IS_ERR(clk)) { -+ pr_err("failed to get clock for clocksource\n"); -+ ret = PTR_ERR(clk); -+ goto err_clk_get; -+ } -+ -+ ret = clk_prepare_enable(clk); -+ if (ret) { -+ pr_err("failed to enable timer clock for clocksource\n"); -+ goto err_clk_enable; -+ } -+ rate = clk_get_rate(clk); -+ -+ base = of_iomap(np, 0); -+ if (!base) { -+ pr_err("failed to map registers for clocksource\n"); -+ goto err_iomap; -+ } -+ -+ writel_relaxed(TIMERn_CTRL_PRESC_1024 | -+ TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | -+ TIMERn_CTRL_MODE_UP, base + TIMERn_CTRL); -+ writel_relaxed(TIMERn_CMD_START, base + TIMERn_CMD); -+ -+ return clocksource_mmio_init(base + TIMERn_CNT, -+ "efm32 timer", rate / 1024, 200, 16, -+ clocksource_mmio_readl_up); -+ -+ iounmap(base); -+err_iomap: -+ -+ clk_disable_unprepare(clk); -+err_clk_enable: -+ -+ clk_put(clk); -+err_clk_get: -+ -+ return ret; -+} -+ -+int __init efm32_clockevent_init(struct device_node *np) -+{ -+ struct clk *clk; -+ void __iomem *base; -+ unsigned long rate; -+ int irq; -+ int ret; -+ -+ clk = of_clk_get(np, 0); -+ if (IS_ERR(clk)) { -+ pr_err("failed to get clock for clocksource\n"); -+ ret = PTR_ERR(clk); -+ goto err_clk_get; -+ } -+ -+ ret = clk_prepare_enable(clk); -+ if (ret) { -+ pr_err("failed to enable timer clock for clocksource\n"); -+ goto err_clk_enable; -+ } -+ rate = clk_get_rate(clk); -+ -+ base = of_iomap(np, 0); -+ if (!base) { -+ pr_err("failed to map registers for clocksource\n"); -+ goto err_iomap; -+ } -+ -+ irq = irq_of_parse_and_map(np, 0); -+ if (!irq) { -+ pr_err("failed to get irq\n"); -+ goto err_get_irq; -+ } -+ -+ writel_relaxed(TIMERn_IRQ_UF, base + TIMERn_IEN); -+ -+ clock_event_ddata.base = base; -+ -+ setup_irq(irq, &efm32_clock_event_irq); -+ -+ /* XXX: tune min_delta */ -+ clockevents_config_and_register(&clock_event_ddata.evtdev, -+ rate / 1024, 0xf, 0xffff); -+ -+ return 0; -+ -+err_get_irq: -+ -+ iounmap(base); -+err_iomap: -+ -+ clk_disable_unprepare(clk); -+err_clk_enable: -+ -+ clk_put(clk); -+err_clk_get: -+ -+ return ret; -+} -+ -+void __init efm32_timer_init(void) -+{ -+ struct device_node *np; -+ -+ efm32_clk_init(); -+ -+ /* -+ * enable CMU_HFPERCLKEN0_TIMERn for clocksource via bit-band; -+ * XXX: drop this when clock framework is not a stub anymore. -+ */ -+ __raw_writel(1, IOMEM(0x43900894 + 4 * TIMER_CLOCKSOURCE)); -+ /* enable CMU_HFPERCLKEN0_TIMERn for clockevent via bit-band */ -+ __raw_writel(1, IOMEM(0x43900894 + 4 * TIMER_CLOCKEVENT)); -+ -+ np = of_find_compatible_node(NULL, NULL, "efm32,timer"); -+ if (!np) { -+ pr_err("failed to find timer node for clocksource\n"); -+ return; -+ } -+ -+ efm32_timer_clocksource_init(np); -+ -+ np = of_find_compatible_node(np, NULL, "efm32,timer"); -+ if (!np) { -+ pr_err("failed to find timer node for clock events\n"); -+ return; -+ } -+ -+ efm32_clockevent_init(np); -+ -+ of_node_put(np); -+} |