From d05d698bb4110d91050a5f448885d662eb3595b9 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 4 Dec 2009 09:41:28 -0500 Subject: [PATCH] mmp: support marvell MMP2 Marvell MMP2 is a SoC based on PJ4 core. It's ARMv6 compatible. Support basic interrupt handler and timer. Signed-off-by: Haojian Zhuang --- arch/arm/Kconfig | 4 +- arch/arm/mach-mmp/Kconfig | 19 ++- 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 | 31 ++++- arch/arm/mach-mmp/include/mach/timex.h | 4 + arch/arm/mach-mmp/irq-mmp2.c | 240 ++++++++++++++++++++++++++ arch/arm/mach-mmp/time.c | 26 +++- 11 files changed, 509 insertions(+), 16 deletions(-) create mode 100644 arch/arm/mach-mmp/irq-mmp2.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 233a222..de816e6 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -495,7 +495,7 @@ config ARCH_ORION5X Orion-2 (5281), Orion-1-90 (6183). config ARCH_MMP - bool "Marvell PXA168/910" + bool "Marvell MMP/MMP2" depends on MMU select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB @@ -506,7 +506,7 @@ config ARCH_MMP select TICK_ONESHOT select PLAT_PXA help - Support for Marvell's PXA168/910 processor line. + Support for Marvell's MMP/MMP2 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..8c20fe3 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 MMP/MMP2 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_MMP2 + help + Say 'Y' here if you want to support the Marvell MMP2-based + Flint Development Platform. + MMP2-based board can't be co-existed with PXA168-based & + PXA910-based development board. Since MMP2 is compatible to + ARMv6 architecture. + endmenu config CPU_PXA168 @@ -44,4 +54,11 @@ config CPU_PXA910 help Select code specific to PXA910 +config CPU_MMP2 + bool + select CPU_V6 + select CPU_32v6K + select PLAT_PXA + help + Select code specific to MMP2. MMP2 is ARMv6 compatible. endif diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h index c33fbbc..85bf124 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 mmp2_timer; extern void __init pxa168_init_irq(void); extern void __init pxa910_init_irq(void); +extern void __init mmp2_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..242ec18 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 + * MMP2 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_MMP2 +#define __cpu_is_mmp2(id) \ + ({ unsigned int _id = ((id) >> 4) & 0xfff; _id == 0x581; }) +#else +#define __cpu_is_mmp2(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_mmp2() ({ __cpu_is_mmp2(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..98869bb 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 (MMP) + 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 (MMP2) + 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..364d117 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 MMP2 + */ +#define IRQ_MMP2_NONE (-1) +#define IRQ_MMP2_SSP1 0 +#define IRQ_MMP2_SSP2 1 +#define IRQ_MMP2_SSPA1 2 +#define IRQ_MMP2_SSPA2 3 +#define IRQ_MMP2_PMIC_BASE 4 /* PMIC & Charger */ +#define IRQ_MMP2_RTC_BASE 5 +#define IRQ_MMP2_TWSI1 7 +#define IRQ_MMP2_GPU 8 +#define IRQ_MMP2_KEYPAD 9 +#define IRQ_MMP2_ROTARY 10 +#define IRQ_MMP2_TRACKBALL 11 +#define IRQ_MMP2_ONEWIRE 12 +#define IRQ_MMP2_TIMER1 13 +#define IRQ_MMP2_TIMER2 14 +#define IRQ_MMP2_TIMER3 15 +#define IRQ_MMP2_RIPC 16 +#define IRQ_MMP2_TWSI_BASE 17 /* TWSI2 ~ TWSI6 */ +#define IRQ_MMP2_HDMI 19 +#define IRQ_MMP2_SSP3 20 +#define IRQ_MMP2_SSP4 21 +#define IRQ_MMP2_USB_HS1 22 +#define IRQ_MMP2_USB_HS2 23 +#define IRQ_MMP2_UART3 24 +#define IRQ_MMP2_UART1 27 +#define IRQ_MMP2_UART2 28 +#define IRQ_MMP2_MIPI_DSI 29 +#define IRQ_MMP2_CI2 30 +#define IRQ_MMP2_PMU_TIMER1 31 +#define IRQ_MMP2_PMU_TIMER2 32 +#define IRQ_MMP2_PMU_TIMER3 33 +#define IRQ_MMP2_USB_FS 34 +#define IRQ_MMP2_MISC_BASE 35 +#define IRQ_MMP2_WDT1 36 +#define IRQ_MMP2_NAND_DMA 37 +#define IRQ_MMP2_USIM 38 +#define IRQ_MMP2_MMC 39 +#define IRQ_MMP2_WTM 40 +#define IRQ_MMP2_LCD 41 +#define IRQ_MMP2_CI 42 +#define IRQ_MMP2_IRE 43 +#define IRQ_MMP2_USB_OTG 44 +#define IRQ_MMP2_NAND 45 +#define IRQ_MMP2_UART4 46 +#define IRQ_MMP2_DMA_FIQ 47 +#define IRQ_MMP2_DMA_RIQ 48 +#define IRQ_MMP2_GPIO 49 +#define IRQ_MMP2_SSP_BASE 51 +#define IRQ_MMP2_MMC2 52 +#define IRQ_MMP2_MMC3 53 +#define IRQ_MMP2_MMC4 54 +#define IRQ_MMP2_MIPI_HSI 55 +#define IRQ_MMP2_MSP 58 +#define IRQ_MMP2_MIPI_SLIM_DMA 59 +#define IRQ_MMP2_PJ4_FREQ_CHG 60 +#define IRQ_MMP2_MIPI_SLIM 62 +#define IRQ_MMP2_SM 63 + +/* secondary interrupt of INT #4 */ +#define MMP2_BASE_INT4 64 +#define IRQ_MMP2_CHARGER (MMP2_BASE_INT4) +#define IRQ_MMP2_PMIC (MMP2_BASE_INT4 + 1) + +/* secondary interrupt of INT #5 */ +#define MMP2_BASE_INT5 66 +#define IRQ_MMP2_RTC_ALARM (MMP2_BASE_INT5) +#define IRQ_MMP2_RTC (MMP2_BASE_INT5 + 1) + +/* secondary interrupt of INT #17 */ +#define MMP2_BASE_INT17 68 +#define IRQ_MMP2_TWSI2 (MMP2_BASE_INT17) +#define IRQ_MMP2_TWSI3 (MMP2_BASE_INT17 + 1) +#define IRQ_MMP2_TWSI4 (MMP2_BASE_INT17 + 2) +#define IRQ_MMP2_TWSI5 (MMP2_BASE_INT17 + 3) +#define IRQ_MMP2_TWSI6 (MMP2_BASE_INT17 + 4) + +/* secondary interrupt of INT #35 */ +#define MMP2_BASE_INT35 73 +#define IRQ_MMP2_PERF (MMP2_BASE_INT35) +#define IRQ_MMP2_L2_PA_ECC (MMP2_BASE_INT35 + 1) +#define IRQ_MMP2_L2_ECC (MMP2_BASE_INT35 + 2) +#define IRQ_MMP2_L2_UECC (MMP2_BASE_INT35 + 3) +#define IRQ_MMP2_DDR (MMP2_BASE_INT35 + 4) +#define IRQ_MMP2_FAB0_TIMEOUT (MMP2_BASE_INT35 + 5) +#define IRQ_MMP2_FAB1_TIMEOUT (MMP2_BASE_INT35 + 6) +#define IRQ_MMP2_FAB2_TIMEOUT (MMP2_BASE_INT35 + 7) +#define IRQ_MMP2_THERMAL (MMP2_BASE_INT35 + 9) +#define IRQ_MMP2_MAIN_PMU (MMP2_BASE_INT35 + 10) +#define IRQ_MMP2_WDT2 (MMP2_BASE_INT35 + 11) +#define IRQ_MMP2_CORESIGHT (MMP2_BASE_INT35 + 12) +#define IRQ_MMP2_COMMTX (MMP2_BASE_INT35 + 13) +#define IRQ_MMP2_COMMRX (MMP2_BASE_INT35 + 14) + +/* secondary interrupt of INT #51 */ +#define MMP2_BASE_INT51 88 +#define IRQ_MMP2_SSP1_SRDY (MMP2_BASE_INT51) +#define IRQ_MMP2_SSP3_SRDY (MMP2_BASE_INT51 + 1) + +#define MMP2_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..712af03 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 MMP2 + */ +#define APBC_MMP2_RTC APBC_REG(0x000) +#define APBC_MMP2_TWSI1 APBC_REG(0x004) +#define APBC_MMP2_TWSI2 APBC_REG(0x008) +#define APBC_MMP2_TWSI3 APBC_REG(0x00c) +#define APBC_MMP2_TWSI4 APBC_REG(0x010) +#define APBC_MMP2_ONEWIRE APBC_REG(0x014) +#define APBC_MMP2_KPC APBC_REG(0x018) +#define APBC_MMP2_TB_ROTARY APBC_REG(0x01c) +#define APBC_MMP2_SW_JTAG APBC_REG(0x020) +#define APBC_MMP2_TIMERS APBC_REG(0x024) +#define APBC_MMP2_UART1 APBC_REG(0x02c) +#define APBC_MMP2_UART2 APBC_REG(0x030) +#define APBC_MMP2_UART3 APBC_REG(0x034) +#define APBC_MMP2_GPIO APBC_REG(0x038) +#define APBC_MMP2_PWM0 APBC_REG(0x03c) +#define APBC_MMP2_PWM1 APBC_REG(0x040) +#define APBC_MMP2_PWM2 APBC_REG(0x044) +#define APBC_MMP2_PWM3 APBC_REG(0x048) +#define APBC_MMP2_SSP0 APBC_REG(0x04c) +#define APBC_MMP2_SSP1 APBC_REG(0x050) +#define APBC_MMP2_SSP2 APBC_REG(0x054) +#define APBC_MMP2_SSP3 APBC_REG(0x058) +#define APBC_MMP2_SSP4 APBC_REG(0x05c) +#define APBC_MMP2_SSP5 APBC_REG(0x060) +#define APBC_MMP2_AIB APBC_REG(0x064) +#define APBC_MMP2_ASFAR APBC_REG(0x068) +#define APBC_MMP2_ASSAR APBC_REG(0x06c) +#define APBC_MMP2_USIM APBC_REG(0x070) +#define APBC_MMP2_MPMU APBC_REG(0x074) +#define APBC_MMP2_IPC APBC_REG(0x078) +#define APBC_MMP2_TWSI5 APBC_REG(0x07c) +#define APBC_MMP2_TWSI6 APBC_REG(0x080) +#define APBC_MMP2_TWSI_INTSTS APBC_REG(0x084) +#define APBC_MMP2_UART4 APBC_REG(0x088) +#define APBC_MMP2_RIPC APBC_REG(0x08c) +#define APBC_MMP2_THSENS1 APBC_REG(0x090) /* Thermal Sensor */ +#define APBC_MMP2_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..1d3c2a7 100644 --- a/arch/arm/mach-mmp/include/mach/regs-icu.h +++ b/arch/arm/mach-mmp/include/mach/regs-icu.h @@ -17,15 +17,44 @@ #define ICU_REG(x) (ICU_VIRT_BASE + (x)) #define ICU_INT_CONF(n) ICU_REG((n) << 2) +#define ICU_INT_CONF_MASK (0xf) + +/************ PXA168/PXA910 (MMP) *********************/ #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 */ +/************ PXA168/PXA910 (MMP) *********************/ + +/************************** MMP2 ***********************/ +/* + * 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 MMP2_ICU_INT4_STATUS ICU_REG(0x150) +#define MMP2_ICU_INT5_STATUS ICU_REG(0x154) +#define MMP2_ICU_INT17_STATUS ICU_REG(0x158) +#define MMP2_ICU_INT35_STATUS ICU_REG(0x15c) +#define MMP2_ICU_INT51_STATUS ICU_REG(0x160) + +#define MMP2_ICU_INT4_MASK ICU_REG(0x168) +#define MMP2_ICU_INT5_MASK ICU_REG(0x16C) +#define MMP2_ICU_INT17_MASK ICU_REG(0x170) +#define MMP2_ICU_INT35_MASK ICU_REG(0x174) +#define MMP2_ICU_INT51_MASK ICU_REG(0x178) + +#define MMP2_ICU_SP_IRQ_SEL ICU_REG(0x100) +#define MMP2_ICU_PJ4_IRQ_SEL ICU_REG(0x104) +#define MMP2_ICU_PJ4_FIQ_SEL ICU_REG(0x108) +/************************** MMP2 ***********************/ #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..70c9f1d 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_MMP2 +#define CLOCK_TICK_RATE 6500000 +#else #define CLOCK_TICK_RATE 3250000 +#endif diff --git a/arch/arm/mach-mmp/irq-mmp2.c b/arch/arm/mach-mmp/irq-mmp2.c new file mode 100644 index 0000000..ea4a95b --- /dev/null +++ b/arch/arm/mach-mmp/irq-mmp2.c @@ -0,0 +1,240 @@ +/* + * linux/arch/arm/mach-mmp/irq-mmp2.c + * + * Generic IRQ handling, GPIO IRQ demultiplexing, etc. + * + * Author: Haojian Zhuang + * Copyright: Marvell International Ltd. + * + * 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 +#include +#include + +#include + +#include "common.h" + + +/* 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(MMP2_ICU_INT##_base##_MASK); \ + data |= (1 << (irq - MMP2_BASE_INT##_base)); \ + __raw_writel(data, MMP2_ICU_INT##_base##_MASK); \ +} while (0) + +/* unmask second-level interrupt */ +#define UNMASK_SECOND_INT(irq, data, _base) \ +do { \ + data = __raw_readl(MMP2_ICU_INT##_base##_MASK); \ + data &= ~(1 << (irq - MMP2_BASE_INT##_base)); \ + __raw_writel(data, MMP2_ICU_INT##_base##_MASK); \ +} while (0) + +/* disable Sheeva PJ4 IRQ */ +static void mmp2_ack_irq(unsigned int irq) +{ + unsigned int data; + + if (irq < MMP2_BASE_INT4) { + + MASK_FIRST_INT(irq, data); + } else if (irq < MMP2_BASE_INT5) { + + MASK_FIRST_INT(4, data); + MASK_SECOND_INT(irq, data, 4); + } else if (irq < MMP2_BASE_INT17) { + + MASK_FIRST_INT(5, data); + MASK_SECOND_INT(irq, data, 5); + } else if (irq < MMP2_BASE_INT35) { + + MASK_FIRST_INT(17, data); + MASK_SECOND_INT(irq, data, 17); + } else if (irq < MMP2_BASE_INT51) { + + MASK_FIRST_INT(35, data); + MASK_SECOND_INT(irq, data, 35); + } else if (irq < MMP2_BASE_INT_END) { + + MASK_FIRST_INT(51, data); + MASK_SECOND_INT(irq, data, 51); + } +} + +/* disable Sheeva PJ4 IRQ */ +static void mmp2_mask_irq(unsigned int irq) +{ + unsigned int data; + + if (irq < MMP2_BASE_INT4) { + + MASK_FIRST_INT(irq, data); + } else if (irq < MMP2_BASE_INT5) { + + MASK_SECOND_INT(irq, data, 4); + } else if (irq < MMP2_BASE_INT17) { + + MASK_SECOND_INT(irq, data, 5); + } else if (irq < MMP2_BASE_INT35) { + + MASK_SECOND_INT(irq, data, 17); + } else if (irq < MMP2_BASE_INT51) { + + MASK_SECOND_INT(irq, data, 35); + } else if (irq < MMP2_BASE_INT_END) { + + MASK_SECOND_INT(irq, data, 51); + } +} + +/* enable Sheeva PJ4 IRQ */ +static void mmp2_unmask_irq(unsigned int irq) +{ + unsigned int data; + + if (irq < MMP2_BASE_INT4) { + + UNMASK_FIRST_INT(irq, data); + } else if (irq < MMP2_BASE_INT5) { + + UNMASK_SECOND_INT(irq, data, 4); + UNMASK_FIRST_INT(4, data); + } else if (irq < MMP2_BASE_INT17) { + + UNMASK_SECOND_INT(irq, data, 5); + UNMASK_FIRST_INT(5, data); + } else if (irq < MMP2_BASE_INT35) { + + UNMASK_SECOND_INT(irq, data, 17); + UNMASK_FIRST_INT(17, data); + } else if (irq < MMP2_BASE_INT51) { + + UNMASK_SECOND_INT(irq, data, 35); + UNMASK_FIRST_INT(35, data); + } else if (irq < MMP2_BASE_INT_END) { + + UNMASK_SECOND_INT(irq, data, 51); + UNMASK_FIRST_INT(51, data); + } +} + +static void mmp2_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_MMP2_PMIC_BASE: + status = __raw_readl(MMP2_ICU_INT4_STATUS); + mask = __raw_readl(MMP2_ICU_INT4_MASK); + status &= (~mask & 0x3); + break; + case IRQ_MMP2_RTC_BASE: + status = __raw_readl(MMP2_ICU_INT5_STATUS); + mask = __raw_readl(MMP2_ICU_INT5_MASK); + status &= (~mask & 0x3); + break; + case IRQ_MMP2_TWSI_BASE: + status = __raw_readl(MMP2_ICU_INT17_STATUS); + mask = __raw_readl(MMP2_ICU_INT17_MASK); + status &= (~mask & 0x1f); + break; + case IRQ_MMP2_MISC_BASE: + status = __raw_readl(MMP2_ICU_INT35_STATUS); + mask = __raw_readl(MMP2_ICU_INT35_MASK); + status &= (~mask & 0x7fff); + break; + case IRQ_MMP2_SSP_BASE: + status = __raw_readl(MMP2_ICU_INT51_STATUS); + mask = __raw_readl(MMP2_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_MMP2_PMIC_BASE: + irq_nr += MMP2_BASE_INT4; + break; + case IRQ_MMP2_RTC_BASE: + irq_nr += MMP2_BASE_INT5; + break; + case IRQ_MMP2_TWSI_BASE: + irq_nr += MMP2_BASE_INT17; + break; + case IRQ_MMP2_MISC_BASE: + irq_nr += MMP2_BASE_INT35; + break; + case IRQ_MMP2_SSP_BASE: + irq_nr += MMP2_BASE_INT51; + break; + } + generic_handle_irq(irq_nr); + } +} + +static struct irq_chip mmp2_irq_chip = { + .name = "icu_irq", + .ack = mmp2_ack_irq, + .mask = mmp2_mask_irq, + .unmask = mmp2_unmask_irq, +}; + +void __init mmp2_init_irq(void) +{ + int irq; + + for (irq = 0; irq < MMP2_BASE_INT4; irq++) { + mmp2_mask_irq(irq); + set_irq_chip(irq, &mmp2_irq_chip); + set_irq_flags(irq, IRQF_VALID); + + switch (irq) { + case IRQ_MMP2_PMIC_BASE: + case IRQ_MMP2_RTC_BASE: + case IRQ_MMP2_TWSI_BASE: + case IRQ_MMP2_MISC_BASE: + case IRQ_MMP2_SSP_BASE: + set_irq_chained_handler(irq, mmp2_irq_demux_handler); + break; + default: + set_irq_handler(irq, handle_level_irq); + break; + } + } + + /* add secondary interrupt handler */ + for (irq = MMP2_BASE_INT4; irq < MMP2_BASE_INT_END; irq++) { + mmp2_mask_irq(irq); + set_irq_chip(irq, &mmp2_irq_chip); + set_irq_flags(irq, IRQF_VALID); + set_irq_handler(irq, handle_level_irq); + } +} diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c index a8400bb..cf75694 100644 --- a/arch/arm/mach-mmp/time.c +++ b/arch/arm/mach-mmp/time.c @@ -30,7 +30,10 @@ #include #include +#include #include +#include +#include #include "clock.h" @@ -158,7 +161,7 @@ static void __init timer_config(void) __raw_writel(cer & ~0x1, TIMERS_VIRT_BASE + TMR_CER); /* disable */ - ccr &= TMR_CCR_CS_0(0x3); + ccr &= (cpu_is_mmp2()) ? TMR_CCR_CS_0(0) : TMR_CCR_CS_0(3); __raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR); /* free-running mode */ @@ -197,3 +200,24 @@ void __init timer_init(int irq) clocksource_register(&cksrc); clockevents_register_device(&ckevt); } + +static void __init mmp2_timer_init(void) +{ + unsigned long clk_rst; + + __raw_writel(APBC_APBCLK | APBC_RST, APBC_MMP2_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_MMP2_TIMERS); + + timer_init(IRQ_MMP2_TIMER1); +} + +struct sys_timer mmp2_timer = { + .init = mmp2_timer_init, +}; + -- 1.5.6.5