[PATCH] [ARM] mmp: support marvell ARMADA610
Haojian Zhuang
haojian.zhuang at marvell.com
Fri Dec 4 09:41:28 EST 2009
Marvell ARMADA610 is a SoC based on PJ4 core. It's ARMv6 compatible.
Support basic interrupt handler and timer.
Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
---
arch/arm/Kconfig | 4 +-
arch/arm/mach-mmp/Kconfig | 20 +++-
arch/arm/mach-mmp/common.h | 2 +
arch/arm/mach-mmp/include/mach/cputype.h | 17 ++-
arch/arm/mach-mmp/include/mach/entry-macro.S | 34 ++++-
arch/arm/mach-mmp/include/mach/irqs.h | 107 ++++++++++++-
arch/arm/mach-mmp/include/mach/regs-apbc.h | 41 +++++
arch/arm/mach-mmp/include/mach/regs-icu.h | 32 ++++-
arch/arm/mach-mmp/include/mach/timex.h | 4 +
arch/arm/mach-mmp/irq.c | 225 ++++++++++++++++++++++++++
arch/arm/mach-mmp/time.c | 29 ++++-
11 files changed, 499 insertions(+), 16 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1c4119c..e4495ce 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -484,7 +484,7 @@ config ARCH_ORION5X
Orion-2 (5281), Orion-1-90 (6183).
config ARCH_MMP
- bool "Marvell PXA168/910"
+ bool "Marvell PXA168/910 & ARMADA610"
depends on MMU
select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB
@@ -495,7 +495,7 @@ config ARCH_MMP
select TICK_ONESHOT
select PLAT_PXA
help
- Support for Marvell's PXA168/910 processor line.
+ Support for Marvell's PXA168/910 & ARMADA610 processor line.
config ARCH_KS8695
bool "Micrel/Kendin KS8695"
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index c6a564f..2ed130d 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -1,6 +1,6 @@
if ARCH_MMP
-menu "Marvell PXA168/910 Implmentations"
+menu "Marvell PXA168/910 & ARMADA610 Implmentations"
config MACH_ASPENITE
bool "Marvell's PXA168 Aspenite Development Board"
@@ -30,6 +30,16 @@ config MACH_TTC_DKB
Say 'Y' here if you want to support the Marvell PXA910-based
TTC_DKB Development Board.
+config MACH_FLINT
+ bool "Marvell's Flint Development Platform"
+ select CPU_ARMADA610
+ help
+ Say 'Y' here if you want to support the Marvell ARMADA610-based
+ Flint Development Platform.
+ ARMADA610-based board can't be co-existed with PXA168-based &
+ PXA910-based development board. Since ARMADA610 is compatible to
+ ARMv6 architecture.
+
endmenu
config CPU_PXA168
@@ -44,4 +54,12 @@ config CPU_PXA910
help
Select code specific to PXA910
+config CPU_ARMADA610
+ bool
+ select CPU_V6
+ select CPU_32v6K
+ select PLAT_PXA
+ help
+ Select code specific to ARMADA610
+ ARMADA610 is ARMv6 compatible.
endif
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index c33fbbc..f929d61 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -6,8 +6,10 @@ extern void timer_init(int irq);
extern struct sys_timer pxa168_timer;
extern struct sys_timer pxa910_timer;
+extern struct sys_timer armada610_timer;
extern void __init pxa168_init_irq(void);
extern void __init pxa910_init_irq(void);
+extern void __init armada610_init_irq(void);
extern void __init icu_init_irq(void);
extern void __init pxa_map_io(void);
diff --git a/arch/arm/mach-mmp/include/mach/cputype.h
b/arch/arm/mach-mmp/include/mach/cputype.h
index 25e797b..3071ba9 100644
--- a/arch/arm/mach-mmp/include/mach/cputype.h
+++ b/arch/arm/mach-mmp/include/mach/cputype.h
@@ -8,23 +8,32 @@
*
* PXA168 A0 0x41159263 0x56158400 0x00A0A333
* PXA910 Y0 0x41159262 0x56158000 0x00F0C910
+ * ARMADA610 Z0 0x560f5811
*/
#ifdef CONFIG_CPU_PXA168
-# define __cpu_is_pxa168(id) \
+#define __cpu_is_pxa168(id) \
({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x84; })
#else
-# define __cpu_is_pxa168(id) (0)
+#define __cpu_is_pxa168(id) (0)
#endif
#ifdef CONFIG_CPU_PXA910
-# define __cpu_is_pxa910(id) \
+#define __cpu_is_pxa910(id) \
({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x80; })
#else
-# define __cpu_is_pxa910(id) (0)
+#define __cpu_is_pxa910(id) (0)
+#endif
+
+#ifdef CONFIG_CPU_ARMADA610
+#define __cpu_is_armada610(id) \
+ ({ unsigned int _id = ((id) >> 4) & 0xfff; _id == 0x581; })
+#else
+#define __cpu_is_armada610(id) (0)
#endif
#define cpu_is_pxa168() ({ __cpu_is_pxa168(read_cpuid_id()); })
#define cpu_is_pxa910() ({ __cpu_is_pxa910(read_cpuid_id()); })
+#define cpu_is_armada610() ({ __cpu_is_armada610(read_cpuid_id()); })
#endif /* __ASM_MACH_CPUTYPE_H */
diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S
b/arch/arm/mach-mmp/include/mach/entry-macro.S
index 6d3cd35..cfaa4b2 100644
--- a/arch/arm/mach-mmp/include/mach/entry-macro.S
+++ b/arch/arm/mach-mmp/include/mach/entry-macro.S
@@ -11,15 +11,39 @@
.macro disable_fiq
.endm
- .macro arch_ret_to_user, tmp1, tmp2
+ .macro get_irqnr_preamble, base, tmp
.endm
- .macro get_irqnr_preamble, base, tmp
- ldr \base, =ICU_AP_IRQ_SEL_INT_NUM
+ .macro arch_ret_to_user, tmp1, tmp2
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- ldr \tmp, [\base, #0]
+ ldr \base, =ICU_VIRT_BASE @ ICU register base
+ mrc p15, 0, \tmp, c0, c0, 0 @ CPUID
+ mov \tmp, \tmp, lsr #4
+ ldr \irqstat, =0xfff
+ and \irqstat, \tmp, \irqstat @ Core G
+
+ @ Core Sheeva PJ1 (PXA168/910)
+ ldr \tmp, =0x800 @ PXA910
+ cmp \irqstat, \tmp
+ beq 1001f
+ ldr \tmp, =0x840 @ PXA168
+ cmp \irqstat, \tmp
+ bne 1002f
+1001:
+ ldr \tmp, [\base, #0x10c] @ AP INT SEL register
+ tst \tmp, #0x40
+ and \irqnr, \tmp, #0x3f
+ b 1003f
+
+1002:
+ @ Core Sheeva PJ4 (PXA688)
+ ldr \tmp, =0x581
+ cmp \irqstat, \tmp
+ bne 1003f
+ ldr \tmp, [\base, #0x104] @ PJ4 IRQ SEL register
+ tst \tmp, #0x40
and \irqnr, \tmp, #0x3f
- tst \tmp, #(1 << 6)
+1003:
.endm
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h
b/arch/arm/mach-mmp/include/mach/irqs.h
index d68871b..3c246c6 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/include/mach/irqs.h
@@ -113,8 +113,111 @@
#define IRQ_PXA910_AP_PMU 60
#define IRQ_PXA910_SM_INT 63 /* from PinMux */
-#define IRQ_GPIO_START 64
-#define IRQ_GPIO_NUM 128
+/*
+ * Interrupt numbers for ARMADA610
+ */
+#define IRQ_ARMADA610_NONE (-1)
+#define IRQ_ARMADA610_SSP1 0
+#define IRQ_ARMADA610_SSP2 1
+#define IRQ_ARMADA610_SSPA1 2
+#define IRQ_ARMADA610_SSPA2 3
+#define IRQ_ARMADA610_PMIC_BASE 4 /* PMIC & Charger */
+#define IRQ_ARMADA610_RTC_BASE 5
+#define IRQ_ARMADA610_TWSI1 7
+#define IRQ_ARMADA610_GPU 8
+#define IRQ_ARMADA610_KEYPAD 9
+#define IRQ_ARMADA610_ROTARY 10
+#define IRQ_ARMADA610_TRACKBALL 11
+#define IRQ_ARMADA610_ONEWIRE 12
+#define IRQ_ARMADA610_TIMER1 13
+#define IRQ_ARMADA610_TIMER2 14
+#define IRQ_ARMADA610_TIMER3 15
+#define IRQ_ARMADA610_RIPC 16
+#define IRQ_ARMADA610_TWSI_BASE 17 /* TWSI2 ~ TWSI6 */
+#define IRQ_ARMADA610_HDMI 19
+#define IRQ_ARMADA610_SSP3 20
+#define IRQ_ARMADA610_SSP4 21
+#define IRQ_ARMADA610_USB_HS1 22
+#define IRQ_ARMADA610_USB_HS2 23
+#define IRQ_ARMADA610_UART3 24
+#define IRQ_ARMADA610_UART1 27
+#define IRQ_ARMADA610_UART2 28
+#define IRQ_ARMADA610_MIPI_DSI 29
+#define IRQ_ARMADA610_CI2 30
+#define IRQ_ARMADA610_PMU_TIMER1 31
+#define IRQ_ARMADA610_PMU_TIMER2 32
+#define IRQ_ARMADA610_PMU_TIMER3 33
+#define IRQ_ARMADA610_USB_FS 34
+#define IRQ_ARMADA610_MISC_BASE 35
+#define IRQ_ARMADA610_WDT1 36
+#define IRQ_ARMADA610_NAND_DMA 37
+#define IRQ_ARMADA610_USIM 38
+#define IRQ_ARMADA610_MMC 39
+#define IRQ_ARMADA610_WTM 40
+#define IRQ_ARMADA610_LCD 41
+#define IRQ_ARMADA610_CI 42
+#define IRQ_ARMADA610_IRE 43
+#define IRQ_ARMADA610_USB_OTG 44
+#define IRQ_ARMADA610_NAND 45
+#define IRQ_ARMADA610_UART4 46
+#define IRQ_ARMADA610_DMA_FIQ 47
+#define IRQ_ARMADA610_DMA_RIQ 48
+#define IRQ_ARMADA610_GPIO 49
+#define IRQ_ARMADA610_SSP_BASE 51
+#define IRQ_ARMADA610_MMC2 52
+#define IRQ_ARMADA610_MMC3 53
+#define IRQ_ARMADA610_MMC4 54
+#define IRQ_ARMADA610_MIPI_HSI 55
+#define IRQ_ARMADA610_MSP 58
+#define IRQ_ARMADA610_MIPI_SLIM_DMA 59
+#define IRQ_ARMADA610_PJ4_FREQ_CHG 60
+#define IRQ_ARMADA610_MIPI_SLIM 62
+#define IRQ_ARMADA610_SM 63
+
+/* secondary interrupt of INT #4 */
+#define ARMADA610_BASE_INT4 64
+#define IRQ_ARMADA610_CHARGER (ARMADA610_BASE_INT4)
+#define IRQ_ARMADA610_PMIC (ARMADA610_BASE_INT4 + 1)
+
+/* secondary interrupt of INT #5 */
+#define ARMADA610_BASE_INT5 66
+#define IRQ_ARMADA610_RTC_ALARM (ARMADA610_BASE_INT5)
+#define IRQ_ARMADA610_RTC (ARMADA610_BASE_INT5 + 1)
+
+/* secondary interrupt of INT #17 */
+#define ARMADA610_BASE_INT17 68
+#define IRQ_ARMADA610_TWSI2 (ARMADA610_BASE_INT17)
+#define IRQ_ARMADA610_TWSI3 (ARMADA610_BASE_INT17 + 1)
+#define IRQ_ARMADA610_TWSI4 (ARMADA610_BASE_INT17 + 2)
+#define IRQ_ARMADA610_TWSI5 (ARMADA610_BASE_INT17 + 3)
+#define IRQ_ARMADA610_TWSI6 (ARMADA610_BASE_INT17 + 4)
+
+/* secondary interrupt of INT #35 */
+#define ARMADA610_BASE_INT35 73
+#define IRQ_ARMADA610_PERF (ARMADA610_BASE_INT35)
+#define IRQ_ARMADA610_L2_PA_ECC (ARMADA610_BASE_INT35 + 1)
+#define IRQ_ARMADA610_L2_ECC (ARMADA610_BASE_INT35 + 2)
+#define IRQ_ARMADA610_L2_UECC (ARMADA610_BASE_INT35 + 3)
+#define IRQ_ARMADA610_DDR (ARMADA610_BASE_INT35 + 4)
+#define IRQ_ARMADA610_FAB0_TIMEOUT (ARMADA610_BASE_INT35 + 5)
+#define IRQ_ARMADA610_FAB1_TIMEOUT (ARMADA610_BASE_INT35 + 6)
+#define IRQ_ARMADA610_FAB2_TIMEOUT (ARMADA610_BASE_INT35 + 7)
+#define IRQ_ARMADA610_THERMAL (ARMADA610_BASE_INT35 + 9)
+#define IRQ_ARMADA610_MAIN_PMU (ARMADA610_BASE_INT35 + 10)
+#define IRQ_ARMADA610_WDT2 (ARMADA610_BASE_INT35 + 11)
+#define IRQ_ARMADA610_CORESIGHT (ARMADA610_BASE_INT35 + 12)
+#define IRQ_ARMADA610_COMMTX (ARMADA610_BASE_INT35 + 13)
+#define IRQ_ARMADA610_COMMRX (ARMADA610_BASE_INT35 + 14)
+
+/* secondary interrupt of INT #51 */
+#define ARMADA610_BASE_INT51 88
+#define IRQ_ARMADA610_SSP1_SRDY (ARMADA610_BASE_INT51)
+#define IRQ_ARMADA610_SSP3_SRDY (ARMADA610_BASE_INT51 + 1)
+
+#define ARMADA610_BASE_INT_END 90
+
+#define IRQ_GPIO_START 128
+#define IRQ_GPIO_NUM 192
#define IRQ_GPIO(x) (IRQ_GPIO_START + (x))
#define NR_IRQS (IRQ_GPIO_START + IRQ_GPIO_NUM)
diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h
b/arch/arm/mach-mmp/include/mach/regs-apbc.h
index 98ccbee..6ed1b9b 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apbc.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h
@@ -69,6 +69,47 @@
#define APBC_PXA910_ASFAR APBC_REG(0x050)
#define APBC_PXA910_ASSAR APBC_REG(0x054)
+/*
+ * APB Clock register offsets for ARMADA610
+ */
+#define APBC_ARMADA610_RTC APBC_REG(0x000)
+#define APBC_ARMADA610_TWSI1 APBC_REG(0x004)
+#define APBC_ARMADA610_TWSI2 APBC_REG(0x008)
+#define APBC_ARMADA610_TWSI3 APBC_REG(0x00c)
+#define APBC_ARMADA610_TWSI4 APBC_REG(0x010)
+#define APBC_ARMADA610_ONEWIRE APBC_REG(0x014)
+#define APBC_ARMADA610_KPC APBC_REG(0x018)
+#define APBC_ARMADA610_TB_ROTARY APBC_REG(0x01c)
+#define APBC_ARMADA610_SW_JTAG APBC_REG(0x020)
+#define APBC_ARMADA610_TIMERS APBC_REG(0x024)
+#define APBC_ARMADA610_UART1 APBC_REG(0x02c)
+#define APBC_ARMADA610_UART2 APBC_REG(0x030)
+#define APBC_ARMADA610_UART3 APBC_REG(0x034)
+#define APBC_ARMADA610_GPIO APBC_REG(0x038)
+#define APBC_ARMADA610_PWM0 APBC_REG(0x03c)
+#define APBC_ARMADA610_PWM1 APBC_REG(0x040)
+#define APBC_ARMADA610_PWM2 APBC_REG(0x044)
+#define APBC_ARMADA610_PWM3 APBC_REG(0x048)
+#define APBC_ARMADA610_SSP0 APBC_REG(0x04c)
+#define APBC_ARMADA610_SSP1 APBC_REG(0x050)
+#define APBC_ARMADA610_SSP2 APBC_REG(0x054)
+#define APBC_ARMADA610_SSP3 APBC_REG(0x058)
+#define APBC_ARMADA610_SSP4 APBC_REG(0x05c)
+#define APBC_ARMADA610_SSP5 APBC_REG(0x060)
+#define APBC_ARMADA610_AIB APBC_REG(0x064)
+#define APBC_ARMADA610_ASFAR APBC_REG(0x068)
+#define APBC_ARMADA610_ASSAR APBC_REG(0x06c)
+#define APBC_ARMADA610_USIM APBC_REG(0x070)
+#define APBC_ARMADA610_MPMU APBC_REG(0x074)
+#define APBC_ARMADA610_IPC APBC_REG(0x078)
+#define APBC_ARMADA610_TWSI5 APBC_REG(0x07c)
+#define APBC_ARMADA610_TWSI6 APBC_REG(0x080)
+#define APBC_ARMADA610_TWSI_INTSTS APBC_REG(0x084)
+#define APBC_ARMADA610_UART4 APBC_REG(0x088)
+#define APBC_ARMADA610_RIPC APBC_REG(0x08c)
+#define APBC_ARMADA610_THSENS1 APBC_REG(0x090) /* Thermal Sensor */
+#define APBC_ARMADA610_THSENS_INTSTS APBC_REG(0x0a4)
+
/* Common APB clock register bit definitions */
#define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */
#define APBC_FNCLK (1 << 1) /* Functional Clock Enable */
diff --git a/arch/arm/mach-mmp/include/mach/regs-icu.h
b/arch/arm/mach-mmp/include/mach/regs-icu.h
index e5f0872..ae7f97f 100644
--- a/arch/arm/mach-mmp/include/mach/regs-icu.h
+++ b/arch/arm/mach-mmp/include/mach/regs-icu.h
@@ -17,15 +17,45 @@
#define ICU_REG(x) (ICU_VIRT_BASE + (x))
#define ICU_INT_CONF(n) ICU_REG((n) << 2)
+#define ICU_INT_CONF_MASK (0xf)
+
+#if defined(CONFIG_CPU_PXA168) || defined(CONFIG_CPU_PXA910)
#define ICU_INT_CONF_AP_INT (1 << 6)
#define ICU_INT_CONF_CP_INT (1 << 5)
#define ICU_INT_CONF_IRQ (1 << 4)
-#define ICU_INT_CONF_MASK (0xf)
#define ICU_AP_FIQ_SEL_INT_NUM ICU_REG(0x108) /* AP FIQ Selected Interrupt */
#define ICU_AP_IRQ_SEL_INT_NUM ICU_REG(0x10C) /* AP IRQ Selected Interrupt */
#define ICU_AP_GBL_IRQ_MSK ICU_REG(0x114) /* AP Global Interrupt Mask */
#define ICU_INT_STATUS_0 ICU_REG(0x128) /* Interrupt Stuats 0 */
#define ICU_INT_STATUS_1 ICU_REG(0x12C) /* Interrupt Status 1 */
+#endif /* CONFIG_CPU_PXA168 || CONFIG_CPU_PXA910 */
+
+#ifdef CONFIG_CPU_ARMADA610
+/*
+ * IRQ0/FIQ0 is routed to SP IRQ/FIQ.
+ * IRQ1 is routed to PJ4 IRQ, and IRQ2 is routes to PJ4 FIQ.
+ */
+#define ICU_INT_ROUTE_SP_IRQ (1 << 4)
+#define ICU_INT_ROUTE_PJ4_IRQ (1 << 5)
+#define ICU_INT_ROUTE_PJ4_FIQ (1 << 6)
+
+#define ARMADA610_ICU_INT4_STATUS ICU_REG(0x150)
+#define ARMADA610_ICU_INT5_STATUS ICU_REG(0x154)
+#define ARMADA610_ICU_INT17_STATUS ICU_REG(0x158)
+#define ARMADA610_ICU_INT35_STATUS ICU_REG(0x15c)
+#define ARMADA610_ICU_INT51_STATUS ICU_REG(0x160)
+
+#define ARMADA610_ICU_INT4_MASK ICU_REG(0x168)
+#define ARMADA610_ICU_INT5_MASK ICU_REG(0x16C)
+#define ARMADA610_ICU_INT17_MASK ICU_REG(0x170)
+#define ARMADA610_ICU_INT35_MASK ICU_REG(0x174)
+#define ARMADA610_ICU_INT51_MASK ICU_REG(0x178)
+
+#define ARMADA610_ICU_SP_IRQ_SEL ICU_REG(0x100)
+#define ARMADA610_ICU_PJ4_IRQ_SEL ICU_REG(0x104)
+#define ARMADA610_ICU_PJ4_FIQ_SEL ICU_REG(0x108)
+
+#endif /* CONFIG_CPU_ARMADA610 */
#endif /* __ASM_MACH_ICU_H */
diff --git a/arch/arm/mach-mmp/include/mach/timex.h
b/arch/arm/mach-mmp/include/mach/timex.h
index 6cebbd0..9255e48 100644
--- a/arch/arm/mach-mmp/include/mach/timex.h
+++ b/arch/arm/mach-mmp/include/mach/timex.h
@@ -6,4 +6,8 @@
* published by the Free Software Foundation.
*/
+#ifdef CONFIG_CPU_PXA688
+#define CLOCK_TICK_RATE 6500000
+#else
#define CLOCK_TICK_RATE 3250000
+#endif
diff --git a/arch/arm/mach-mmp/irq.c b/arch/arm/mach-mmp/irq.c
index 52ff2f0..11b62c5 100644
--- a/arch/arm/mach-mmp/irq.c
+++ b/arch/arm/mach-mmp/irq.c
@@ -20,6 +20,8 @@
#include "common.h"
+#if defined(CONFIG_CPU_PXA168) || defined(CONFIG_CPU_PXA910)
+
#define IRQ_ROUTE_TO_AP (ICU_INT_CONF_AP_INT | ICU_INT_CONF_IRQ)
#define PRIORITY_DEFAULT 0x1
@@ -53,3 +55,226 @@ void __init icu_init_irq(void)
set_irq_flags(irq, IRQF_VALID);
}
}
+#endif /* CONFIG_CPU_PXA168 || CONFIG_CPU_PXA910 */
+
+#if defined(CONFIG_CPU_ARMADA610)
+
+/* mask first-level interrupt */
+#define MASK_FIRST_INT(irq, data) \
+do { \
+ data = __raw_readl(ICU_INT_CONF(irq)); \
+ data &= ~ICU_INT_ROUTE_PJ4_IRQ; \
+ __raw_writel(data, ICU_INT_CONF(irq)); \
+} while (0)
+
+/* unmask first-level interrupt */
+#define UNMASK_FIRST_INT(irq, data) \
+do { \
+ data = __raw_readl(ICU_INT_CONF(irq)); \
+ data |= ICU_INT_ROUTE_PJ4_IRQ; \
+ __raw_writel(data, ICU_INT_CONF(irq)); \
+} while (0)
+
+/* mask second-level interrupt */
+#define MASK_SECOND_INT(irq, data, _base) \
+do { \
+ data = __raw_readl(ARMADA610_ICU_INT##_base##_MASK); \
+ data |= (1 << (irq - ARMADA610_BASE_INT##_base)); \
+ __raw_writel(data, ARMADA610_ICU_INT##_base##_MASK); \
+} while (0)
+
+/* unmask second-level interrupt */
+#define UNMASK_SECOND_INT(irq, data, _base) \
+do { \
+ data = __raw_readl(ARMADA610_ICU_INT##_base##_MASK); \
+ data &= ~(1 << (irq - ARMADA610_BASE_INT##_base)); \
+ __raw_writel(data, ARMADA610_ICU_INT##_base##_MASK); \
+} while (0)
+
+/* disable Sheeva PJ4 IRQ */
+static void armada610_ack_irq(unsigned int irq)
+{
+ unsigned int data;
+
+ if (irq < ARMADA610_BASE_INT4) {
+
+ MASK_FIRST_INT(irq, data);
+ } else if (irq < ARMADA610_BASE_INT5) {
+
+ MASK_FIRST_INT(4, data);
+ MASK_SECOND_INT(irq, data, 4);
+ } else if (irq < ARMADA610_BASE_INT17) {
+
+ MASK_FIRST_INT(5, data);
+ MASK_SECOND_INT(irq, data, 5);
+ } else if (irq < ARMADA610_BASE_INT35) {
+
+ MASK_FIRST_INT(17, data);
+ MASK_SECOND_INT(irq, data, 17);
+ } else if (irq < ARMADA610_BASE_INT51) {
+
+ MASK_FIRST_INT(35, data);
+ MASK_SECOND_INT(irq, data, 35);
+ } else if (irq < ARMADA610_BASE_INT_END) {
+
+ MASK_FIRST_INT(51, data);
+ MASK_SECOND_INT(irq, data, 51);
+ }
+}
+
+/* disable Sheeva PJ4 IRQ */
+static void armada610_mask_irq(unsigned int irq)
+{
+ unsigned int data;
+
+ if (irq < ARMADA610_BASE_INT4) {
+
+ MASK_FIRST_INT(irq, data);
+ } else if (irq < ARMADA610_BASE_INT5) {
+
+ MASK_SECOND_INT(irq, data, 4);
+ } else if (irq < ARMADA610_BASE_INT17) {
+
+ MASK_SECOND_INT(irq, data, 5);
+ } else if (irq < ARMADA610_BASE_INT35) {
+
+ MASK_SECOND_INT(irq, data, 17);
+ } else if (irq < ARMADA610_BASE_INT51) {
+
+ MASK_SECOND_INT(irq, data, 35);
+ } else if (irq < ARMADA610_BASE_INT_END) {
+
+ MASK_SECOND_INT(irq, data, 51);
+ }
+}
+
+/* enable Sheeva PJ4 IRQ */
+static void armada610_unmask_irq(unsigned int irq)
+{
+ unsigned int data;
+
+ if (irq < ARMADA610_BASE_INT4) {
+
+ UNMASK_FIRST_INT(irq, data);
+ } else if (irq < ARMADA610_BASE_INT5) {
+
+ UNMASK_SECOND_INT(irq, data, 4);
+ UNMASK_FIRST_INT(4, data);
+ } else if (irq < ARMADA610_BASE_INT17) {
+
+ UNMASK_SECOND_INT(irq, data, 5);
+ UNMASK_FIRST_INT(5, data);
+ } else if (irq < ARMADA610_BASE_INT35) {
+
+ UNMASK_SECOND_INT(irq, data, 17);
+ UNMASK_FIRST_INT(17, data);
+ } else if (irq < ARMADA610_BASE_INT51) {
+
+ UNMASK_SECOND_INT(irq, data, 35);
+ UNMASK_FIRST_INT(35, data);
+ } else if (irq < ARMADA610_BASE_INT_END) {
+
+ UNMASK_SECOND_INT(irq, data, 51);
+ UNMASK_FIRST_INT(51, data);
+ }
+}
+
+static void armada610_irq_demux_handler(unsigned int irq, struct
irq_desc *desc)
+{
+ DECLARE_BITMAP(irq_status, 32);
+ unsigned int status, mask, irq_nr;
+
+ switch (irq) {
+ case IRQ_ARMADA610_PMIC_BASE:
+ status = __raw_readl(ARMADA610_ICU_INT4_STATUS);
+ mask = __raw_readl(ARMADA610_ICU_INT4_MASK);
+ status &= (~mask & 0x3);
+ break;
+ case IRQ_ARMADA610_RTC_BASE:
+ status = __raw_readl(ARMADA610_ICU_INT5_STATUS);
+ mask = __raw_readl(ARMADA610_ICU_INT5_MASK);
+ status &= (~mask & 0x3);
+ break;
+ case IRQ_ARMADA610_TWSI_BASE:
+ status = __raw_readl(ARMADA610_ICU_INT17_STATUS);
+ mask = __raw_readl(ARMADA610_ICU_INT17_MASK);
+ status &= (~mask & 0x1f);
+ break;
+ case IRQ_ARMADA610_MISC_BASE:
+ status = __raw_readl(ARMADA610_ICU_INT35_STATUS);
+ mask = __raw_readl(ARMADA610_ICU_INT35_MASK);
+ status &= (~mask & 0x7fff);
+ break;
+ case IRQ_ARMADA610_SSP_BASE:
+ status = __raw_readl(ARMADA610_ICU_INT51_STATUS);
+ mask = __raw_readl(ARMADA610_ICU_INT51_MASK);
+ status &= (~mask & 0x3);
+ break;
+ default:
+ return;
+ }
+
+ irq_status[0] = status;
+ while (!bitmap_empty(irq_status, 32)) {
+ irq_nr = find_first_bit(irq_status, 32);
+ clear_bit(irq_nr, irq_status);
+ switch (irq) {
+ case IRQ_ARMADA610_PMIC_BASE:
+ irq_nr += ARMADA610_BASE_INT4;
+ break;
+ case IRQ_ARMADA610_RTC_BASE:
+ irq_nr += ARMADA610_BASE_INT5;
+ break;
+ case IRQ_ARMADA610_TWSI_BASE:
+ irq_nr += ARMADA610_BASE_INT17;
+ break;
+ case IRQ_ARMADA610_MISC_BASE:
+ irq_nr += ARMADA610_BASE_INT35;
+ break;
+ case IRQ_ARMADA610_SSP_BASE:
+ irq_nr += ARMADA610_BASE_INT51;
+ break;
+ }
+ generic_handle_irq(irq_nr);
+ }
+}
+
+static struct irq_chip armada610_irq_chip = {
+ .name = "icu_irq",
+ .ack = armada610_ack_irq,
+ .mask = armada610_mask_irq,
+ .unmask = armada610_unmask_irq,
+};
+
+void __init armada610_init_irq(void)
+{
+ int irq;
+
+ for (irq = 0; irq < ARMADA610_BASE_INT4; irq++) {
+ armada610_mask_irq(irq);
+ set_irq_chip(irq, &armada610_irq_chip);
+ set_irq_flags(irq, IRQF_VALID);
+
+ switch (irq) {
+ case IRQ_ARMADA610_PMIC_BASE:
+ case IRQ_ARMADA610_RTC_BASE:
+ case IRQ_ARMADA610_TWSI_BASE:
+ case IRQ_ARMADA610_MISC_BASE:
+ case IRQ_ARMADA610_SSP_BASE:
+ set_irq_chained_handler(irq, armada610_irq_demux_handler);
+ break;
+ default:
+ set_irq_handler(irq, handle_level_irq);
+ break;
+ }
+ }
+
+ /* add secondary interrupt handler */
+ for (irq = ARMADA610_BASE_INT4; irq < ARMADA610_BASE_INT_END; irq++) {
+ armada610_mask_irq(irq);
+ set_irq_chip(irq, &armada610_irq_chip);
+ set_irq_flags(irq, IRQF_VALID);
+ set_irq_handler(irq, handle_level_irq);
+ }
+}
+#endif /* CONFIG_CPU_ARMADA610 */
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index a8400bb..d5f4874 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -30,7 +30,10 @@
#include <mach/addr-map.h>
#include <mach/regs-timers.h>
+#include <mach/regs-apbc.h>
#include <mach/irqs.h>
+#include <mach/cputype.h>
+#include <asm/mach/time.h>
#include "clock.h"
@@ -158,7 +161,10 @@ static void __init timer_config(void)
__raw_writel(cer & ~0x1, TIMERS_VIRT_BASE + TMR_CER); /* disable */
- ccr &= TMR_CCR_CS_0(0x3);
+ if (cpu_is_armada610())
+ ccr &= TMR_CCR_CS_0(0);
+ else
+ ccr &= TMR_CCR_CS_0(0x3);
__raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR);
/* free-running mode */
@@ -197,3 +203,24 @@ void __init timer_init(int irq)
clocksource_register(&cksrc);
clockevents_register_device(&ckevt);
}
+
+static void __init armada610_timer_init(void)
+{
+ unsigned long clk_rst;
+
+ __raw_writel(APBC_APBCLK | APBC_RST, APBC_ARMADA610_TIMERS);
+
+ /*
+ * enable bus/functional clock, enable 6.5MHz (divider 4),
+ * release reset
+ */
+ clk_rst = APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1);
+ __raw_writel(clk_rst, APBC_ARMADA610_TIMERS);
+
+ timer_init(IRQ_ARMADA610_TIMER1);
+}
+
+struct sys_timer armada610_timer = {
+ .init = armada610_timer_init,
+};
+
--
1.5.6.5
More information about the linux-arm-kernel
mailing list