Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] ARM: EXYNOS4: Modify PMU register setting function
From: Jongpill Lee @ 2011-09-19  1:23 UTC (permalink / raw)
  To: linux-arm-kernel

This patch modifies PMU register setting function to support the other Exynos4 series.

Signed-off-by: Jongpill Lee <boyko.lee@samsung.com>
---
 arch/arm/mach-exynos4/include/mach/pmu.h      |    7 +
 arch/arm/mach-exynos4/include/mach/regs-pmu.h |    1 -
 arch/arm/mach-exynos4/pmu.c                   |  239 +++++++++----------------
 3 files changed, 96 insertions(+), 151 deletions(-)

diff --git a/arch/arm/mach-exynos4/include/mach/pmu.h b/arch/arm/mach-exynos4/include/mach/pmu.h
index a952904..632dd56 100644
--- a/arch/arm/mach-exynos4/include/mach/pmu.h
+++ b/arch/arm/mach-exynos4/include/mach/pmu.h
@@ -13,6 +13,8 @@
 #ifndef __ASM_ARCH_PMU_H
 #define __ASM_ARCH_PMU_H __FILE__
 
+#define PMU_TABLE_END	NULL
+
 enum sys_powerdown {
 	SYS_AFTR,
 	SYS_LPA,
@@ -20,6 +22,11 @@ enum sys_powerdown {
 	NUM_SYS_POWERDOWN,
 };
 
+struct exynos4_pmu_conf {
+	void __iomem *reg;
+	unsigned int val[NUM_SYS_POWERDOWN];
+};
+
 extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode);
 
 #endif /* __ASM_ARCH_PMU_H */
diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
index cdf9b47..7fa44b9 100644
--- a/arch/arm/mach-exynos4/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
@@ -27,7 +27,6 @@
 #define S5P_USE_STANDBY_WFI1			(1 << 17)
 #define S5P_USE_STANDBY_WFE0			(1 << 24)
 #define S5P_USE_STANDBY_WFE1			(1 << 25)
-#define S5P_USE_MASK				((0x3 << 16) | (0x3 << 24))
 
 #define S5P_SWRESET				S5P_PMUREG(0x0400)
 
diff --git a/arch/arm/mach-exynos4/pmu.c b/arch/arm/mach-exynos4/pmu.c
index 7ea9eb2..02bfa0d 100644
--- a/arch/arm/mach-exynos4/pmu.c
+++ b/arch/arm/mach-exynos4/pmu.c
@@ -16,160 +16,99 @@
 #include <mach/regs-clock.h>
 #include <mach/pmu.h>
 
-static void __iomem *sys_powerdown_reg[] = {
-	S5P_ARM_CORE0_LOWPWR,
-	S5P_DIS_IRQ_CORE0,
-	S5P_DIS_IRQ_CENTRAL0,
-	S5P_ARM_CORE1_LOWPWR,
-	S5P_DIS_IRQ_CORE1,
-	S5P_DIS_IRQ_CENTRAL1,
-	S5P_ARM_COMMON_LOWPWR,
-	S5P_L2_0_LOWPWR,
-	S5P_L2_1_LOWPWR,
-	S5P_CMU_ACLKSTOP_LOWPWR,
-	S5P_CMU_SCLKSTOP_LOWPWR,
-	S5P_CMU_RESET_LOWPWR,
-	S5P_APLL_SYSCLK_LOWPWR,
-	S5P_MPLL_SYSCLK_LOWPWR,
-	S5P_VPLL_SYSCLK_LOWPWR,
-	S5P_EPLL_SYSCLK_LOWPWR,
-	S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR,
-	S5P_CMU_RESET_GPSALIVE_LOWPWR,
-	S5P_CMU_CLKSTOP_CAM_LOWPWR,
-	S5P_CMU_CLKSTOP_TV_LOWPWR,
-	S5P_CMU_CLKSTOP_MFC_LOWPWR,
-	S5P_CMU_CLKSTOP_G3D_LOWPWR,
-	S5P_CMU_CLKSTOP_LCD0_LOWPWR,
-	S5P_CMU_CLKSTOP_LCD1_LOWPWR,
-	S5P_CMU_CLKSTOP_MAUDIO_LOWPWR,
-	S5P_CMU_CLKSTOP_GPS_LOWPWR,
-	S5P_CMU_RESET_CAM_LOWPWR,
-	S5P_CMU_RESET_TV_LOWPWR,
-	S5P_CMU_RESET_MFC_LOWPWR,
-	S5P_CMU_RESET_G3D_LOWPWR,
-	S5P_CMU_RESET_LCD0_LOWPWR,
-	S5P_CMU_RESET_LCD1_LOWPWR,
-	S5P_CMU_RESET_MAUDIO_LOWPWR,
-	S5P_CMU_RESET_GPS_LOWPWR,
-	S5P_TOP_BUS_LOWPWR,
-	S5P_TOP_RETENTION_LOWPWR,
-	S5P_TOP_PWR_LOWPWR,
-	S5P_LOGIC_RESET_LOWPWR,
-	S5P_ONENAND_MEM_LOWPWR,
-	S5P_MODIMIF_MEM_LOWPWR,
-	S5P_G2D_ACP_MEM_LOWPWR,
-	S5P_USBOTG_MEM_LOWPWR,
-	S5P_HSMMC_MEM_LOWPWR,
-	S5P_CSSYS_MEM_LOWPWR,
-	S5P_SECSS_MEM_LOWPWR,
-	S5P_PCIE_MEM_LOWPWR,
-	S5P_SATA_MEM_LOWPWR,
-	S5P_PAD_RETENTION_DRAM_LOWPWR,
-	S5P_PAD_RETENTION_MAUDIO_LOWPWR,
-	S5P_PAD_RETENTION_GPIO_LOWPWR,
-	S5P_PAD_RETENTION_UART_LOWPWR,
-	S5P_PAD_RETENTION_MMCA_LOWPWR,
-	S5P_PAD_RETENTION_MMCB_LOWPWR,
-	S5P_PAD_RETENTION_EBIA_LOWPWR,
-	S5P_PAD_RETENTION_EBIB_LOWPWR,
-	S5P_PAD_RETENTION_ISOLATION_LOWPWR,
-	S5P_PAD_RETENTION_ALV_SEL_LOWPWR,
-	S5P_XUSBXTI_LOWPWR,
-	S5P_XXTI_LOWPWR,
-	S5P_EXT_REGULATOR_LOWPWR,
-	S5P_GPIO_MODE_LOWPWR,
-	S5P_GPIO_MODE_MAUDIO_LOWPWR,
-	S5P_CAM_LOWPWR,
-	S5P_TV_LOWPWR,
-	S5P_MFC_LOWPWR,
-	S5P_G3D_LOWPWR,
-	S5P_LCD0_LOWPWR,
-	S5P_LCD1_LOWPWR,
-	S5P_MAUDIO_LOWPWR,
-	S5P_GPS_LOWPWR,
-	S5P_GPS_ALIVE_LOWPWR,
-};
+static struct exynos4_pmu_conf *exynos4_pmu_config;
 
-static const unsigned int sys_powerdown_val[][NUM_SYS_POWERDOWN] = {
-	/* { AFTR, LPA, SLEEP }*/
-	{ 0, 0, 2 },	/* ARM_CORE0 */
-	{ 0, 0, 0 },	/* ARM_DIS_IRQ_CORE0 */
-	{ 0, 0, 0 },	/* ARM_DIS_IRQ_CENTRAL0 */
-	{ 0, 0, 2 },	/* ARM_CORE1 */
-	{ 0, 0, 0 },	/* ARM_DIS_IRQ_CORE1 */
-	{ 0, 0, 0 },	/* ARM_DIS_IRQ_CENTRAL1 */
-	{ 0, 0, 2 },	/* ARM_COMMON */
-	{ 2, 2, 3 },	/* ARM_CPU_L2_0 */
-	{ 2, 2, 3 },	/* ARM_CPU_L2_1 */
-	{ 1, 0, 0 },	/* CMU_ACLKSTOP */
-	{ 1, 0, 0 },	/* CMU_SCLKSTOP */
-	{ 1, 1, 0 },	/* CMU_RESET */
-	{ 1, 0, 0 },	/* APLL_SYSCLK */
-	{ 1, 0, 0 },	/* MPLL_SYSCLK */
-	{ 1, 0, 0 },	/* VPLL_SYSCLK */
-	{ 1, 1, 0 },	/* EPLL_SYSCLK */
-	{ 1, 1, 0 },	/* CMU_CLKSTOP_GPS_ALIVE */
-	{ 1, 1, 0 },	/* CMU_RESET_GPS_ALIVE */
-	{ 1, 1, 0 },	/* CMU_CLKSTOP_CAM */
-	{ 1, 1, 0 },	/* CMU_CLKSTOP_TV */
-	{ 1, 1, 0 },	/* CMU_CLKSTOP_MFC */
-	{ 1, 1, 0 },	/* CMU_CLKSTOP_G3D */
-	{ 1, 1, 0 },	/* CMU_CLKSTOP_LCD0 */
-	{ 1, 1, 0 },	/* CMU_CLKSTOP_LCD1 */
-	{ 1, 1, 0 },	/* CMU_CLKSTOP_MAUDIO */
-	{ 1, 1, 0 },	/* CMU_CLKSTOP_GPS */
-	{ 1, 1, 0 },	/* CMU_RESET_CAM */
-	{ 1, 1, 0 },	/* CMU_RESET_TV */
-	{ 1, 1, 0 },	/* CMU_RESET_MFC */
-	{ 1, 1, 0 },	/* CMU_RESET_G3D */
-	{ 1, 1, 0 },	/* CMU_RESET_LCD0 */
-	{ 1, 1, 0 },	/* CMU_RESET_LCD1 */
-	{ 1, 1, 0 },	/* CMU_RESET_MAUDIO */
-	{ 1, 1, 0 },	/* CMU_RESET_GPS */
-	{ 3, 0, 0 },	/* TOP_BUS */
-	{ 1, 0, 1 },	/* TOP_RETENTION */
-	{ 3, 0, 3 },	/* TOP_PWR */
-	{ 1, 1, 0 },	/* LOGIC_RESET */
-	{ 3, 0, 0 },	/* ONENAND_MEM */
-	{ 3, 0, 0 },	/* MODIMIF_MEM */
-	{ 3, 0, 0 },	/* G2D_ACP_MEM */
-	{ 3, 0, 0 },	/* USBOTG_MEM */
-	{ 3, 0, 0 },	/* HSMMC_MEM */
-	{ 3, 0, 0 },	/* CSSYS_MEM */
-	{ 3, 0, 0 },	/* SECSS_MEM */
-	{ 3, 0, 0 },	/* PCIE_MEM */
-	{ 3, 0, 0 },	/* SATA_MEM */
-	{ 1, 0, 0 },	/* PAD_RETENTION_DRAM */
-	{ 1, 1, 0 },	/* PAD_RETENTION_MAUDIO */
-	{ 1, 0, 0 },	/* PAD_RETENTION_GPIO */
-	{ 1, 0, 0 },	/* PAD_RETENTION_UART */
-	{ 1, 0, 0 },	/* PAD_RETENTION_MMCA */
-	{ 1, 0, 0 },	/* PAD_RETENTION_MMCB */
-	{ 1, 0, 0 },	/* PAD_RETENTION_EBIA */
-	{ 1, 0, 0 },	/* PAD_RETENTION_EBIB */
-	{ 1, 0, 0 },	/* PAD_RETENTION_ISOLATION */
-	{ 1, 0, 0 },	/* PAD_RETENTION_ALV_SEL */
-	{ 1, 1, 0 },	/* XUSBXTI */
-	{ 1, 1, 0 },	/* XXTI */
-	{ 1, 1, 0 },	/* EXT_REGULATOR */
-	{ 1, 0, 0 },	/* GPIO_MODE */
-	{ 1, 1, 0 },	/* GPIO_MODE_MAUDIO */
-	{ 7, 0, 0 },	/* CAM */
-	{ 7, 0, 0 },	/* TV */
-	{ 7, 0, 0 },	/* MFC */
-	{ 7, 0, 0 },	/* G3D */
-	{ 7, 0, 0 },	/* LCD0 */
-	{ 7, 0, 0 },	/* LCD1 */
-	{ 7, 7, 0 },	/* MAUDIO */
-	{ 7, 0, 0 },	/* GPS */
-	{ 7, 0, 0 },	/* GPS_ALIVE */
+static struct exynos4_pmu_conf exynos4210_pmu_config[] = {
+	/* { .reg = address, .val = { AFTR, LPA, SLEEP } */
+	{ S5P_ARM_CORE0_LOWPWR,			{ 0x0, 0x0, 0x2 } },
+	{ S5P_DIS_IRQ_CORE0,			{ 0x0, 0x0, 0x0 } },
+	{ S5P_DIS_IRQ_CENTRAL0,			{ 0x0, 0x0, 0x0 } },
+	{ S5P_ARM_CORE1_LOWPWR,			{ 0x0, 0x0, 0x2 } },
+	{ S5P_DIS_IRQ_CORE1,			{ 0x0, 0x0, 0x0 } },
+	{ S5P_DIS_IRQ_CENTRAL1,			{ 0x0, 0x0, 0x0 } },
+	{ S5P_ARM_COMMON_LOWPWR,		{ 0x0, 0x0, 0x2 } },
+	{ S5P_L2_0_LOWPWR,			{ 0x2, 0x2, 0x3 } },
+	{ S5P_L2_1_LOWPWR,			{ 0x2, 0x2, 0x3 } },
+	{ S5P_CMU_ACLKSTOP_LOWPWR,		{ 0x1, 0x0, 0x0 } },
+	{ S5P_CMU_SCLKSTOP_LOWPWR,		{ 0x1, 0x0, 0x0 } },
+	{ S5P_CMU_RESET_LOWPWR,			{ 0x1, 0x1, 0x0 } },
+	{ S5P_APLL_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } },
+	{ S5P_MPLL_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } },
+	{ S5P_VPLL_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } },
+	{ S5P_EPLL_SYSCLK_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR,	{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_RESET_GPSALIVE_LOWPWR,	{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_CLKSTOP_CAM_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_CLKSTOP_TV_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_CLKSTOP_MFC_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_CLKSTOP_G3D_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_CLKSTOP_LCD0_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_CLKSTOP_LCD1_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_CLKSTOP_MAUDIO_LOWPWR,	{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_CLKSTOP_GPS_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_RESET_CAM_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_RESET_TV_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_RESET_MFC_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_RESET_G3D_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_RESET_LCD0_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_RESET_LCD1_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_RESET_MAUDIO_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CMU_RESET_GPS_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_TOP_BUS_LOWPWR,			{ 0x3, 0x0, 0x0 } },
+	{ S5P_TOP_RETENTION_LOWPWR,		{ 0x1, 0x0, 0x1 } },
+	{ S5P_TOP_PWR_LOWPWR,			{ 0x3, 0x0, 0x3 } },
+	{ S5P_LOGIC_RESET_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_ONENAND_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } },
+	{ S5P_MODIMIF_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } },
+	{ S5P_G2D_ACP_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } },
+	{ S5P_USBOTG_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } },
+	{ S5P_HSMMC_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } },
+	{ S5P_CSSYS_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } },
+	{ S5P_SECSS_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } },
+	{ S5P_PCIE_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } },
+	{ S5P_SATA_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } },
+	{ S5P_PAD_RETENTION_DRAM_LOWPWR,	{ 0x1, 0x0, 0x0 } },
+	{ S5P_PAD_RETENTION_MAUDIO_LOWPWR,	{ 0x1, 0x1, 0x0 } },
+	{ S5P_PAD_RETENTION_GPIO_LOWPWR,	{ 0x1, 0x0, 0x0 } },
+	{ S5P_PAD_RETENTION_UART_LOWPWR,	{ 0x1, 0x0, 0x0 } },
+	{ S5P_PAD_RETENTION_MMCA_LOWPWR,	{ 0x1, 0x0, 0x0 } },
+	{ S5P_PAD_RETENTION_MMCB_LOWPWR,	{ 0x1, 0x0, 0x0 } },
+	{ S5P_PAD_RETENTION_EBIA_LOWPWR,	{ 0x1, 0x0, 0x0 } },
+	{ S5P_PAD_RETENTION_EBIB_LOWPWR,	{ 0x1, 0x0, 0x0 } },
+	{ S5P_PAD_RETENTION_ISOLATION_LOWPWR,	{ 0x1, 0x0, 0x0 } },
+	{ S5P_PAD_RETENTION_ALV_SEL_LOWPWR,	{ 0x1, 0x0, 0x0 } },
+	{ S5P_XUSBXTI_LOWPWR,			{ 0x1, 0x1, 0x0 } },
+	{ S5P_XXTI_LOWPWR,			{ 0x1, 0x1, 0x0 } },
+	{ S5P_EXT_REGULATOR_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_GPIO_MODE_LOWPWR,			{ 0x1, 0x0, 0x0 } },
+	{ S5P_GPIO_MODE_MAUDIO_LOWPWR,		{ 0x1, 0x1, 0x0 } },
+	{ S5P_CAM_LOWPWR,			{ 0x7, 0x0, 0x0 } },
+	{ S5P_TV_LOWPWR,			{ 0x7, 0x0, 0x0 } },
+	{ S5P_MFC_LOWPWR,			{ 0x7, 0x0, 0x0 } },
+	{ S5P_G3D_LOWPWR,			{ 0x7, 0x0, 0x0 } },
+	{ S5P_LCD0_LOWPWR,			{ 0x7, 0x0, 0x0 } },
+	{ S5P_LCD1_LOWPWR,			{ 0x7, 0x0, 0x0 } },
+	{ S5P_MAUDIO_LOWPWR,			{ 0x7, 0x7, 0x0 } },
+	{ S5P_GPS_LOWPWR,			{ 0x7, 0x0, 0x0 } },
+	{ S5P_GPS_ALIVE_LOWPWR,			{ 0x7, 0x0, 0x0 } },
+	{ PMU_TABLE_END,},
 };
 
 void exynos4_sys_powerdown_conf(enum sys_powerdown mode)
 {
-	unsigned int count = ARRAY_SIZE(sys_powerdown_reg);
+	unsigned int i;
+
+	for (i = 0; (exynos4_pmu_config[i].reg != PMU_TABLE_END) ; i++)
+		__raw_writel(exynos4_pmu_config[i].val[mode],
+				exynos4_pmu_config[i].reg);
+}
+
+static int __init exynos4_pmu_init(void)
+{
+	exynos4_pmu_config = exynos4210_pmu_config;
+
+	pr_info("EXYNOS4210 PMU Initialize\n");
 
-	for (; count > 0; count--)
-		__raw_writel(sys_powerdown_val[count - 1][mode],
-				sys_powerdown_reg[count - 1]);
+	return 0;
 }
+arch_initcall(exynos4_pmu_init);
-- 
1.7.1

^ permalink raw reply related

* [RFC PATCH 1/3] genirq: add support for per-cpu dev_id interrupts
From: Abhijeet Dharmapurikar @ 2011-09-18 23:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316105551-17505-2-git-send-email-marc.zyngier@arm.com>

On 09/15/2011 09:52 AM, Marc Zyngier wrote:
 > The ARM GIC interrupt controller offers per CPU interrupts (PPIs),
 > which are usually used to connect local timers to each core.
 > Each CPU has its own private interface to the GIC,
 > and only sees the PPIs that are directly connect to it.
 >
 > While these timers are separate devices and have a separate
 > interrupt line to a core, they all use the same IRQ number.
 >
 > For these devices, request_irq() is not the right API as it
 > assumes that an IRQ number is visible by a number of CPUs
 > (through the affinity setting), but makes it very awkward to
 > express that an IRQ number can be handled by all CPUs, and
 > yet be a different interrupt line on each CPU, requiring a
 > different dev_id cookie to be passed back to the handler.
 >
 > The *_percpu_irq() functions is designed to overcome these
 > limitations, by providing a per-cpu dev_id vector:
 >
 > int request_percpu_irq(unsigned int irq, irq_handler_t handler,
 > 		   const char *devname, void __percpu *percpu_dev_id);
 > void free_percpu_irq(unsigned int, void __percpu *);
 > int setup_percpu_irq(unsigned int irq, struct irqaction *new);
 > void remove_percpu_irq(unsigned int irq, struct irqaction *act);
 > void enable_percpu_irq(unsigned int irq);
 > void disable_percpu_irq(unsigned int irq);
 >
 > The API has a number of limitations:
 > - no interrupt sharing
 > - no threading
 > - common handler across all the CPUs
 >
 > Once the interrupt is requested using setup_percpu_irq() or
 > request_percpu_irq(), it must be enabled by each core that wishes
 > its local interrupt to be delivered.
 >
 > Based on an initial patch by Thomas Gleixner.
 >
 > Cc: Thomas Gleixner<tglx@linutronix.de>
 > Signed-off-by: Marc Zyngier<marc.zyngier@arm.com>
 > ---
 >   include/linux/interrupt.h |   40 ++++++---
 >   include/linux/irq.h       |   25 +++++-
 >   include/linux/irqdesc.h   |    3 +
 >   kernel/irq/Kconfig        |    4 +
 >   kernel/irq/chip.c         |   58 +++++++++++++
 >   kernel/irq/internals.h    |    2 +
 >   kernel/irq/manage.c       |  209 
++++++++++++++++++++++++++++++++++++++++++++-
 >   kernel/irq/settings.h     |    7 ++
 >   8 files changed, 332 insertions(+), 16 deletions(-)
 >
 > diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
 > index a103732..f9b7fa3 100644
 > --- a/include/linux/interrupt.h
 > +++ b/include/linux/interrupt.h
 > @@ -95,6 +95,7 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
 >    * @flags:	flags (see IRQF_* above)
 >    * @name:	name of the device
 >    * @dev_id:	cookie to identify the device
 > + * @percpu_dev_id:	cookie to identify the device
 >    * @next:	pointer to the next irqaction for shared interrupts
 >    * @irq:	interrupt number
 >    * @dir:	pointer to the proc/irq/NN/name entry
 > @@ -104,17 +105,20 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
 >    * @thread_mask:	bitmask for keeping track of @thread activity
 >    */
 >   struct irqaction {
 > -	irq_handler_t handler;
 > -	unsigned long flags;
 > -	void *dev_id;
 > -	struct irqaction *next;
 > -	int irq;
 > -	irq_handler_t thread_fn;
 > -	struct task_struct *thread;
 > -	unsigned long thread_flags;
 > -	unsigned long thread_mask;
 > -	const char *name;
 > -	struct proc_dir_entry *dir;
 > +	irq_handler_t		handler;
 > +	unsigned long		flags;
 > +	void			*dev_id;
 > +#ifdef CONFIG_IRQ_PERCPU_DEVID
 > +	void __percpu		*percpu_dev_id;
 > +#endif
 > +	struct irqaction	*next;
 > +	int			irq;
 > +	irq_handler_t		thread_fn;
 > +	struct task_struct	*thread;
 > +	unsigned long		thread_flags;
 > +	unsigned long		thread_mask;
 > +	const char		*name;
 > +	struct proc_dir_entry	*dir;
 >   } ____cacheline_internodealigned_in_smp;
 >
 >   extern irqreturn_t no_action(int cpl, void *dev_id);
 > @@ -136,6 +140,10 @@ extern int __must_check
 >   request_any_context_irq(unsigned int irq, irq_handler_t handler,
 >   			unsigned long flags, const char *name, void *dev_id);
 >
 > +extern int __must_check
 > +request_percpu_irq(unsigned int irq, irq_handler_t handler,
 > +		   const char *devname, void __percpu *percpu_dev_id);
 > +
 >   extern void exit_irq_thread(void);
 >   #else
 >
 > @@ -164,10 +172,18 @@ request_any_context_irq(unsigned int irq, 
irq_handler_t handler,
 >   	return request_irq(irq, handler, flags, name, dev_id);
 >   }
 >
 > +static inline int __must_check
 > +request_percpu_irq(unsigned int irq, irq_handler_t handler,
 > +		   const char *devname, void __percpu *percpu_dev_id)
 > +{
 > +	return request_irq(irq, handler, 0, name, dev_id);

you probably meant devname here instead of name and also percpu_dev_id 
instead of dev_id.

 > +}
 > +
 >   static inline void exit_irq_thread(void) { }
 >   #endif
 >
 >   extern void free_irq(unsigned int, void *);
 > +extern void free_percpu_irq(unsigned int, void __percpu *);
 >
 >   struct device;
 >
 > @@ -207,7 +223,9 @@ extern void devm_free_irq(struct device *dev, 
unsigned int irq, void *dev_id);
 >
 >   extern void disable_irq_nosync(unsigned int irq);
 >   extern void disable_irq(unsigned int irq);
 > +extern void disable_percpu_irq(unsigned int irq);
 >   extern void enable_irq(unsigned int irq);
 > +extern void enable_percpu_irq(unsigned int irq);
 >
 >   /* The following three functions are for the core kernel use only. */
 >   #ifdef CONFIG_GENERIC_HARDIRQS
 > diff --git a/include/linux/irq.h b/include/linux/irq.h
 > index 5951730..1e14fd1 100644
 > --- a/include/linux/irq.h
 > +++ b/include/linux/irq.h
 > @@ -66,6 +66,7 @@ typedef	void (*irq_preflow_handler_t)(struct 
irq_data *data);
 >    * IRQ_NO_BALANCING		- Interrupt cannot be balanced (affinity set)
 >    * IRQ_MOVE_PCNTXT		- Interrupt can be migrated from process context
 >    * IRQ_NESTED_TRHEAD		- Interrupt nests into another thread
 > + * IRQ_PER_CPU_DEVID		- Dev_id is a per-cpu variable
 >    */
 >   enum {
 >   	IRQ_TYPE_NONE		= 0x00000000,
 > @@ -88,12 +89,13 @@ enum {
 >   	IRQ_MOVE_PCNTXT		= (1<<  14),
 >   	IRQ_NESTED_THREAD	= (1<<  15),
 >   	IRQ_NOTHREAD		= (1<<  16),
 > +	IRQ_PER_CPU_DEVID	= (1<<  17),
 >   };
 >
 >   #define IRQF_MODIFY_MASK	\
 >   	(IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
 >   	 IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
 > -	 IRQ_PER_CPU | IRQ_NESTED_THREAD)
 > +	 IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID)
 >
 >   #define IRQ_NO_BALANCING_MASK	(IRQ_PER_CPU | IRQ_NO_BALANCING)
 >
 > @@ -365,6 +367,8 @@ enum {
 >   struct irqaction;
 >   extern int setup_irq(unsigned int irq, struct irqaction *new);
 >   extern void remove_irq(unsigned int irq, struct irqaction *act);
 > +extern int setup_percpu_irq(unsigned int irq, struct irqaction *new);
 > +extern void remove_percpu_irq(unsigned int irq, struct irqaction *act);
 >
 >   extern void irq_cpu_online(void);
 >   extern void irq_cpu_offline(void);
 > @@ -392,6 +396,7 @@ extern void handle_edge_irq(unsigned int irq, 
struct irq_desc *desc);
 >   extern void handle_edge_eoi_irq(unsigned int irq, struct irq_desc 
*desc);
 >   extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc);
 >   extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc);
 > +extern void handle_percpu_devid_irq(unsigned int irq, struct 
irq_desc *desc);
 >   extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
 >   extern void handle_nested_irq(unsigned int irq);
 >
 > @@ -481,6 +486,24 @@ static inline void 
irq_set_nested_thread(unsigned int irq, bool nest)
 >   		irq_clear_status_flags(irq, IRQ_NESTED_THREAD);
 >   }
 >
 > +#ifdef CONFIG_IRQ_PERCPU_DEVID
 > +static inline int irq_set_percpu_devid(unsigned int irq)
 > +{
 > +	struct irq_desc *desc = irq_to_desc(irq);
 > +
 > +	if (!desc)
 > +		return -EINVAL;
 > +
 > +	if (!zalloc_cpumask_var(&desc->percpu_enabled, GFP_KERNEL))
 > +		return -ENOMEM;
 > +
 > +	irq_set_status_flags(irq,
 > +			     IRQ_NOAUTOEN | IRQ_PER_CPU | IRQ_NOTHREAD |
 > +			     IRQ_NOPROBE | IRQ_PER_CPU_DEVID);
 > +	return 0;
 > +}
 > +#endif
 > +
 >   /* Handle dynamic irq creation and destruction */
 >   extern unsigned int create_irq_nr(unsigned int irq_want, int node);
 >   extern int create_irq(void);
 > diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
 > index 150134a..0b4419a 100644
 > --- a/include/linux/irqdesc.h
 > +++ b/include/linux/irqdesc.h
 > @@ -53,6 +53,9 @@ struct irq_desc {
 >   	unsigned long		last_unhandled;	/* Aging timer for unhandled count */
 >   	unsigned int		irqs_unhandled;
 >   	raw_spinlock_t		lock;
 > +#ifdef CONFIG_IRQ_PERCPU_DEVID
 > +	cpumask_var_t		percpu_enabled;
 > +#endif
 >   #ifdef CONFIG_SMP
 >   	const struct cpumask	*affinity_hint;
 >   	struct irq_affinity_notify *affinity_notify;
 > diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
 > index 5a38bf4..75c0631 100644
 > --- a/kernel/irq/Kconfig
 > +++ b/kernel/irq/Kconfig
 > @@ -60,6 +60,10 @@ config IRQ_DOMAIN
 >   config IRQ_FORCED_THREADING
 >          bool
 >
 > +# Support per CPU dev id
 > +config IRQ_PERCPU_DEVID
 > +	bool
 > +
 >   config SPARSE_IRQ
 >   	bool "Support sparse irq numbering"
 >   	depends on HAVE_SPARSE_IRQ
 > diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
 > index d5a3009..d65b23f 100644
 > --- a/kernel/irq/chip.c
 > +++ b/kernel/irq/chip.c
 > @@ -204,6 +204,30 @@ void irq_disable(struct irq_desc *desc)
 >   	}
 >   }
 >
 > +#ifdef CONFIG_IRQ_PERCPU_DEVID
 > +void irq_percpu_enable(struct irq_desc *desc)
 > +{
 > +	unsigned int cpu = get_cpu();
 > +	if (desc->irq_data.chip->irq_enable)
 > +		desc->irq_data.chip->irq_enable(&desc->irq_data);
 > +	else
 > +		desc->irq_data.chip->irq_unmask(&desc->irq_data);
 > +	cpumask_set_cpu(cpu, desc->percpu_enabled);
 > +	put_cpu();
 > +}
 > +
 > +void irq_percpu_disable(struct irq_desc *desc)
 > +{
 > +	unsigned int cpu = get_cpu();
 > +	if (desc->irq_data.chip->irq_disable) {
 > +		desc->irq_data.chip->irq_disable(&desc->irq_data);
 > +		irq_state_set_masked(desc);
 > +	}
 > +	cpumask_clear_cpu(cpu, desc->percpu_enabled);
 > +	put_cpu();
 > +}
 > +#endif
 > +
 >   static inline void mask_ack_irq(struct irq_desc *desc)
 >   {
 >   	if (desc->irq_data.chip->irq_mask_ack)
 > @@ -544,6 +568,40 @@ handle_percpu_irq(unsigned int irq, struct 
irq_desc *desc)
 >   		chip->irq_eoi(&desc->irq_data);
 >   }
 >
 > +#ifdef CONFIG_IRQ_PERCPU_DEVID
 > +/**
 > + * handle_percpu_devid_irq - Per CPU local irq handler with per cpu 
dev ids
 > + * @irq:	the interrupt number
 > + * @desc:	the interrupt description structure for this irq
 > + *
 > + * Per CPU interrupts on SMP machines without locking requirements. 
Same as
 > + * handle_percpu_irq() above but with the following extras:
 > + *
 > + * action->percpu_dev_id is a pointer to percpu variables which
 > + * contain the real device id for the cpu on which this handler is
 > + * called
 > + */
 > +void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc)
 > +{
 > +	struct irq_chip *chip = irq_desc_get_chip(desc);
 > +	struct irqaction *action = desc->action;
 > +	void *dev_id = __this_cpu_ptr(action->percpu_dev_id);
 > +	irqreturn_t res;
 > +
 > +	kstat_incr_irqs_this_cpu(irq, desc);
 > +
 > +	if (chip->irq_ack)
 > +		chip->irq_ack(&desc->irq_data);
 > +
 > +	trace_irq_handler_entry(irq, action);
 > +	res = action->handler(irq, dev_id);
 > +	trace_irq_handler_exit(irq, action, res);
 > +
 > +	if (chip->irq_eoi)
 > +		chip->irq_eoi(&desc->irq_data);
 > +}
 > +#endif
 > +
 >   void
 >   __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int 
is_chained,
 >   		  const char *name)
 > diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
 > index 6546431..a57fd3b 100644
 > --- a/kernel/irq/internals.h
 > +++ b/kernel/irq/internals.h
 > @@ -71,6 +71,8 @@ extern int irq_startup(struct irq_desc *desc);
 >   extern void irq_shutdown(struct irq_desc *desc);
 >   extern void irq_enable(struct irq_desc *desc);
 >   extern void irq_disable(struct irq_desc *desc);
 > +extern void irq_percpu_enable(struct irq_desc *desc);
 > +extern void irq_percpu_disable(struct irq_desc *desc);
 >   extern void mask_irq(struct irq_desc *desc);
 >   extern void unmask_irq(struct irq_desc *desc);
 >
 > diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
 > index 9b956fa..9f10b07 100644
 > --- a/kernel/irq/manage.c
 > +++ b/kernel/irq/manage.c
 > @@ -1118,6 +1118,8 @@ int setup_irq(unsigned int irq, struct 
irqaction *act)
 >   	int retval;
 >   	struct irq_desc *desc = irq_to_desc(irq);
 >
 > +	if (irq_settings_is_per_cpu_devid(desc))
 > +		return -EINVAL;
 >   	chip_bus_lock(desc);
 >   	retval = __setup_irq(irq, desc, act);
 >   	chip_bus_sync_unlock(desc);
 > @@ -1126,7 +1128,7 @@ int setup_irq(unsigned int irq, struct 
irqaction *act)
 >   }
 >   EXPORT_SYMBOL_GPL(setup_irq);
 >
 > - /*
 > +/*
 >    * Internal function to unregister an irqaction - used to free
 >    * regular and special interrupts that are part of the architecture.
 >    */
 > @@ -1224,7 +1226,10 @@ static struct irqaction *__free_irq(unsigned 
int irq, void *dev_id)
 >    */
 >   void remove_irq(unsigned int irq, struct irqaction *act)
 >   {
 > -	__free_irq(irq, act->dev_id);
 > +	struct irq_desc *desc = irq_to_desc(irq);
 > +
 > +	if (desc&&  !irq_settings_is_per_cpu_devid(desc))
 > +	    __free_irq(irq, act->dev_id);
 >   }
 >   EXPORT_SYMBOL_GPL(remove_irq);
 >
 > @@ -1246,7 +1251,7 @@ void free_irq(unsigned int irq, void *dev_id)
 >   {
 >   	struct irq_desc *desc = irq_to_desc(irq);
 >
 > -	if (!desc)
 > +	if (!desc || irq_settings_is_per_cpu_devid(desc))
 >   		return;
 >
 >   #ifdef CONFIG_SMP
 > @@ -1324,7 +1329,8 @@ int request_threaded_irq(unsigned int irq, 
irq_handler_t handler,
 >   	if (!desc)
 >   		return -EINVAL;
 >
 > -	if (!irq_settings_can_request(desc))
 > +	if (!irq_settings_can_request(desc) ||
 > +	    irq_settings_is_per_cpu_devid(desc))
 >   		return -EINVAL;
 >
 >   	if (!handler) {
 > @@ -1409,3 +1415,198 @@ int request_any_context_irq(unsigned int irq, 
irq_handler_t handler,
 >   	return !ret ? IRQC_IS_HARDIRQ : ret;
 >   }
 >   EXPORT_SYMBOL_GPL(request_any_context_irq);
 > +
 > +#ifdef CONFIG_IRQ_PERCPU_DEVID
 > +void enable_percpu_irq(unsigned int irq)
 > +{
 > +	unsigned long flags;
 > +	struct irq_desc *desc = irq_get_desc_buslock(irq,&flags);
 > +
 > +	if (!desc)
 > +		return;
 > +
 > +	irq_percpu_enable(desc);
 > +	irq_put_desc_busunlock(desc, flags);
 > +}
 > +EXPORT_SYMBOL(enable_percpu_irq);
 > +
 > +void disable_percpu_irq(unsigned int irq)
 > +{
 > +	unsigned long flags;
 > +	struct irq_desc *desc = irq_get_desc_buslock(irq,&flags);
 > +
 > +	if (!desc)
 > +		return;
 > +
 > +	irq_percpu_disable(desc);
 > +	irq_put_desc_busunlock(desc, flags);
 > +}
 > +EXPORT_SYMBOL(disable_percpu_irq);
 > +
 > +/*
 > + * Internal function to unregister a percpu irqaction.
 > + */
 > +static struct irqaction *__free_percpu_irq(unsigned int irq, void 
__percpu *dev_id)
 > +{
 > +	struct irq_desc *desc = irq_to_desc(irq);
 > +	struct irqaction *action;
 > +	unsigned long flags;
 > +
 > +	WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
 > +
 > +	if (!desc)
 > +		return NULL;
 > +
 > +	raw_spin_lock_irqsave(&desc->lock, flags);
 > +
 > +	action = desc->action;
 > +	if (!action || action->percpu_dev_id != dev_id) {
 > +		WARN(1, "Trying to free already-free IRQ %d\n", irq);
 > +		raw_spin_unlock_irqrestore(&desc->lock, flags);
 > +		return NULL;
 > +	}
 > +
 > +	/* Found it - now remove it from the list of entries: */
 > +	WARN(!cpumask_empty(desc->percpu_enabled),
 > +	     "percpu IRQ %d still enabled on CPU%d!\n",
 > +	     irq, cpumask_first(desc->percpu_enabled));
 > +	desc->action = NULL;
 > +
 > +#ifdef CONFIG_SMP
 > +	/* make sure affinity_hint is cleaned up */
 > +	if (WARN_ON_ONCE(desc->affinity_hint))
 > +		desc->affinity_hint = NULL;
 > +#endif
 > +
 > +	raw_spin_unlock_irqrestore(&desc->lock, flags);
 > +
 > +	unregister_handler_proc(irq, action);
 > +
 > +	/* Make sure it's not being used on another CPU: */
 > +	synchronize_irq(irq);
 > +
 > +	module_put(desc->owner);

Not sure why is this required. Where is the corresponding try_module_get()?

 > +	return action;
 > +}
 > +
 > +/**
 > + *	remove_percpu_irq - free a per-cpu interrupt
 > + *	@irq: Interrupt line to free
 > + *	@act: irqaction for the interrupt
 > + *
 > + * Used to remove interrupts statically setup by the early boot process.
 > + */
 > +void remove_percpu_irq(unsigned int irq, struct irqaction *act)
 > +{
 > +	struct irq_desc *desc = irq_to_desc(irq);
 > +
 > +	if (desc&&  irq_settings_is_per_cpu_devid(desc))
 > +	    __free_percpu_irq(irq, act->percpu_dev_id);
 > +}
 > +EXPORT_SYMBOL_GPL(remove_percpu_irq);
 > +
 > +/**
 > + *	free_percpu_irq - free an interrupt allocated with request_percpu_irq
 > + *	@irq: Interrupt line to free
 > + *	@dev_id: Device identity to free
 > + *
 > + *	Remove a percpu interrupt handler. The handler is removed, but
 > + *	the interrupt line is not disabled. This must be done on each
 > + *	CPU before calling this function. The function does not return
 > + *	until any executing interrupts for this IRQ have completed.
 > + *
 > + *	This function must not be called from interrupt context.
 > + */
 > +void free_percpu_irq(unsigned int irq, void __percpu *dev_id)
 > +{
 > +	struct irq_desc *desc = irq_to_desc(irq);
 > +
 > +	if (!desc || !irq_settings_is_per_cpu_devid(desc))
 > +		return;
 > +
 > +#ifdef CONFIG_SMP
 > +	if (WARN_ON(desc->affinity_notify))
 > +		desc->affinity_notify = NULL;
 > +#endif
 > +
 > +	chip_bus_lock(desc);
 > +	kfree(__free_percpu_irq(irq, dev_id));
 > +	chip_bus_sync_unlock(desc);
 > +}
 > +EXPORT_SYMBOL(free_percpu_irq);
 > +
 > +/**
 > + *	setup_percpu_irq - setup a per-cpu interrupt
 > + *	@irq: Interrupt line to setup
 > + *	@act: irqaction for the interrupt
 > + *
 > + * Used to statically setup per-cpu interrupts in the early boot 
process.
 > + */
 > +int setup_percpu_irq(unsigned int irq, struct irqaction *act)
 > +{
 > +	int retval;
 > +	struct irq_desc *desc = irq_to_desc(irq);
 > +
 > +	if (!irq_settings_is_per_cpu_devid(desc))
 > +		return -EINVAL;
 > +	chip_bus_lock(desc);
 > +	retval = __setup_irq(irq, desc, act);
 > +	chip_bus_sync_unlock(desc);
 > +
 > +	return retval;
 > +}
 > +EXPORT_SYMBOL_GPL(setup_percpu_irq);
 > +
 > +/**
 > + *	request_percpu_irq - allocate a percpu interrupt line
 > + *	@irq: Interrupt line to allocate
 > + *	@handler: Function to be called when the IRQ occurs.
 > + *		  Primary handler for threaded interrupts
 > + *		  If NULL and thread_fn != NULL the default
 > + *		  primary handler is installed

The patch doesnt support threaded percpu interrupts - please set the 
comment accordingly?

 > + *	@devname: An ascii name for the claiming device
 > + *	@dev_id: A percpu cookie passed back to the handler function
 > + *
 > + *	This call allocates interrupt resources, but doesn't
 > + *	automatically enable the interrupt. It has to be done on each
 > + *	CPU using enable_percpu_irq().
 > + *
 > + *	Dev_id must be globally unique. It is a per-cpu variable, and
 > + *	the handler gets called with the interrupted CPU's instance of
 > + *	that variable.
 > + */
 > +int request_percpu_irq(unsigned int irq, irq_handler_t handler,
 > +		       const char *devname, void __percpu *dev_id)

Can we add irqflags argument. I think it will be useful to pass flags, 
at least the IRQF_TRIGGER_MASK since it ends up calling __setup_irq(). 
The chip could use a set_type callback for ppi's too.

 > +{
 > +	struct irqaction *action;
 > +	struct irq_desc *desc;
 > +	int retval;
 > +
 > +	if (!dev_id)
 > +		return -EINVAL;
 > +
 > +	desc = irq_to_desc(irq);
 > +	if (!desc || !irq_settings_can_request(desc) ||
 > +	    !irq_settings_is_per_cpu_devid(desc))
 > +		return -EINVAL;
 > +
 > +	action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
 > +	if (!action)
 > +		return -ENOMEM;
 > +
 > +	action->handler = handler;
 > +	action->flags = IRQF_PERCPU;

continuing my previous comment this will then be changed to
action->flags = irqflags | IRQF_PERCPU

 > +	action->name = devname;
 > +	action->percpu_dev_id = dev_id;
 > +
 > +	chip_bus_lock(desc);
 > +	retval = __setup_irq(irq, desc, action);
 > +	chip_bus_sync_unlock(desc);
 > +
 > +	if (retval)
 > +		kfree(action);
 > +
 > +	return retval;
 > +}
 > +EXPORT_SYMBOL(request_percpu_irq);
 > +#endif
 > diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h
 > index f166783..1162f10 100644
 > --- a/kernel/irq/settings.h
 > +++ b/kernel/irq/settings.h
 > @@ -13,6 +13,7 @@ enum {
 >   	_IRQ_MOVE_PCNTXT	= IRQ_MOVE_PCNTXT,
 >   	_IRQ_NO_BALANCING	= IRQ_NO_BALANCING,
 >   	_IRQ_NESTED_THREAD	= IRQ_NESTED_THREAD,
 > +	_IRQ_PER_CPU_DEVID	= IRQ_PER_CPU_DEVID,
 >   	_IRQF_MODIFY_MASK	= IRQF_MODIFY_MASK,
 >   };
 >
 > @@ -24,6 +25,7 @@ enum {
 >   #define IRQ_NOTHREAD		GOT_YOU_MORON
 >   #define IRQ_NOAUTOEN		GOT_YOU_MORON
 >   #define IRQ_NESTED_THREAD	GOT_YOU_MORON
 > +#define IRQ_PER_CPU_DEVID	GOT_YOU_MORON
 >   #undef IRQF_MODIFY_MASK
 >   #define IRQF_MODIFY_MASK	GOT_YOU_MORON
 >
 > @@ -39,6 +41,11 @@ static inline bool irq_settings_is_per_cpu(struct 
irq_desc *desc)
 >   	return desc->status_use_accessors&  _IRQ_PER_CPU;
 >   }
 >
 > +static inline bool irq_settings_is_per_cpu_devid(struct irq_desc *desc)
 > +{
 > +	return desc->status_use_accessors&  _IRQ_PER_CPU_DEVID;
 > +}
 > +
 >   static inline void irq_settings_set_per_cpu(struct irq_desc *desc)
 >   {
 >   	desc->status_use_accessors |= _IRQ_PER_CPU;


-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* [PATCH 1/3] at91/gpio: make gpio register base soc independant
From: Ryan Mallon @ 2011-09-18 23:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316285923-12461-1-git-send-email-plagnioj@jcrosoft.com>

On 18/09/11 04:58, Jean-Christophe PLAGNIOL-VILLARD wrote:
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>

Looks good to me. For whole series:

Reviewed-by: Ryan Mallon <rmallon@gmail.com>

> ---
>  arch/arm/mach-at91/at91cap9.c                 |    8 ++++----
>  arch/arm/mach-at91/at91rm9200.c               |    8 ++++----
>  arch/arm/mach-at91/at91sam9260.c              |    6 +++---
>  arch/arm/mach-at91/at91sam9261.c              |    6 +++---
>  arch/arm/mach-at91/at91sam9263.c              |   10 +++++-----
>  arch/arm/mach-at91/at91sam9g45.c              |   10 +++++-----
>  arch/arm/mach-at91/at91sam9rl.c               |    8 ++++----
>  arch/arm/mach-at91/generic.h                  |    2 +-
>  arch/arm/mach-at91/gpio.c                     |    8 ++++++--
>  arch/arm/mach-at91/include/mach/at91cap9.h    |    9 +++++----
>  arch/arm/mach-at91/include/mach/at91rm9200.h  |    9 +++++----
>  arch/arm/mach-at91/include/mach/at91sam9260.h |    7 ++++---
>  arch/arm/mach-at91/include/mach/at91sam9261.h |    7 ++++---
>  arch/arm/mach-at91/include/mach/at91sam9263.h |   11 ++++++-----
>  arch/arm/mach-at91/include/mach/at91sam9g45.h |   11 ++++++-----
>  arch/arm/mach-at91/include/mach/at91sam9rl.h  |    9 +++++----
>  16 files changed, 70 insertions(+), 59 deletions(-)
>
> diff --git a/arch/arm/mach-at91/at91cap9.c b/arch/arm/mach-at91/at91cap9.c
> index ecdd54d..fe00dce 100644
> --- a/arch/arm/mach-at91/at91cap9.c
> +++ b/arch/arm/mach-at91/at91cap9.c
> @@ -296,19 +296,19 @@ void __init at91cap9_set_console_clock(int id)
>  static struct at91_gpio_bank at91cap9_gpio[] = {
>  	{
>  		.id		= AT91CAP9_ID_PIOABCD,
> -		.offset		= AT91_PIOA,
> +		.regbase	= AT91CAP9_BASE_PIOA,
>  		.clock		= &pioABCD_clk,
>  	}, {
>  		.id		= AT91CAP9_ID_PIOABCD,
> -		.offset		= AT91_PIOB,
> +		.regbase	= AT91CAP9_BASE_PIOB,
>  		.clock		= &pioABCD_clk,
>  	}, {
>  		.id		= AT91CAP9_ID_PIOABCD,
> -		.offset		= AT91_PIOC,
> +		.regbase	= AT91CAP9_BASE_PIOC,
>  		.clock		= &pioABCD_clk,
>  	}, {
>  		.id		= AT91CAP9_ID_PIOABCD,
> -		.offset		= AT91_PIOD,
> +		.regbase	= AT91CAP9_BASE_PIOD,
>  		.clock		= &pioABCD_clk,
>  	}
>  };
> diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
> index 713d3bd..8ce8675 100644
> --- a/arch/arm/mach-at91/at91rm9200.c
> +++ b/arch/arm/mach-at91/at91rm9200.c
> @@ -271,19 +271,19 @@ void __init at91rm9200_set_console_clock(int id)
>  static struct at91_gpio_bank at91rm9200_gpio[] = {
>  	{
>  		.id		= AT91RM9200_ID_PIOA,
> -		.offset		= AT91_PIOA,
> +		.regbase	= AT91RM9200_BASE_PIOA,
>  		.clock		= &pioA_clk,
>  	}, {
>  		.id		= AT91RM9200_ID_PIOB,
> -		.offset		= AT91_PIOB,
> +		.regbase	= AT91RM9200_BASE_PIOB,
>  		.clock		= &pioB_clk,
>  	}, {
>  		.id		= AT91RM9200_ID_PIOC,
> -		.offset		= AT91_PIOC,
> +		.regbase	= AT91RM9200_BASE_PIOC,
>  		.clock		= &pioC_clk,
>  	}, {
>  		.id		= AT91RM9200_ID_PIOD,
> -		.offset		= AT91_PIOD,
> +		.regbase	= AT91RM9200_BASE_PIOD,
>  		.clock		= &pioD_clk,
>  	}
>  };
> diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
> index a9be758..d7ad3e0 100644
> --- a/arch/arm/mach-at91/at91sam9260.c
> +++ b/arch/arm/mach-at91/at91sam9260.c
> @@ -265,15 +265,15 @@ void __init at91sam9260_set_console_clock(int id)
>  static struct at91_gpio_bank at91sam9260_gpio[] = {
>  	{
>  		.id		= AT91SAM9260_ID_PIOA,
> -		.offset		= AT91_PIOA,
> +		.regbase	= AT91SAM9260_BASE_PIOA,
>  		.clock		= &pioA_clk,
>  	}, {
>  		.id		= AT91SAM9260_ID_PIOB,
> -		.offset		= AT91_PIOB,
> +		.regbase	= AT91SAM9260_BASE_PIOB,
>  		.clock		= &pioB_clk,
>  	}, {
>  		.id		= AT91SAM9260_ID_PIOC,
> -		.offset		= AT91_PIOC,
> +		.regbase	= AT91SAM9260_BASE_PIOC,
>  		.clock		= &pioC_clk,
>  	}
>  };
> diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
> index 658a518..574aa6b 100644
> --- a/arch/arm/mach-at91/at91sam9261.c
> +++ b/arch/arm/mach-at91/at91sam9261.c
> @@ -254,15 +254,15 @@ void __init at91sam9261_set_console_clock(int id)
>  static struct at91_gpio_bank at91sam9261_gpio[] = {
>  	{
>  		.id		= AT91SAM9261_ID_PIOA,
> -		.offset		= AT91_PIOA,
> +		.regbase	= AT91SAM9261_BASE_PIOA,
>  		.clock		= &pioA_clk,
>  	}, {
>  		.id		= AT91SAM9261_ID_PIOB,
> -		.offset		= AT91_PIOB,
> +		.regbase	= AT91SAM9261_BASE_PIOB,
>  		.clock		= &pioB_clk,
>  	}, {
>  		.id		= AT91SAM9261_ID_PIOC,
> -		.offset		= AT91_PIOC,
> +		.regbase	= AT91SAM9261_BASE_PIOC,
>  		.clock		= &pioC_clk,
>  	}
>  };
> diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
> index f83fbb0..dee0ed7 100644
> --- a/arch/arm/mach-at91/at91sam9263.c
> +++ b/arch/arm/mach-at91/at91sam9263.c
> @@ -266,23 +266,23 @@ void __init at91sam9263_set_console_clock(int id)
>  static struct at91_gpio_bank at91sam9263_gpio[] = {
>  	{
>  		.id		= AT91SAM9263_ID_PIOA,
> -		.offset		= AT91_PIOA,
> +		.regbase	= AT91SAM9263_BASE_PIOA,
>  		.clock		= &pioA_clk,
>  	}, {
>  		.id		= AT91SAM9263_ID_PIOB,
> -		.offset		= AT91_PIOB,
> +		.regbase	= AT91SAM9263_BASE_PIOB,
>  		.clock		= &pioB_clk,
>  	}, {
>  		.id		= AT91SAM9263_ID_PIOCDE,
> -		.offset		= AT91_PIOC,
> +		.regbase	= AT91SAM9263_BASE_PIOC,
>  		.clock		= &pioCDE_clk,
>  	}, {
>  		.id		= AT91SAM9263_ID_PIOCDE,
> -		.offset		= AT91_PIOD,
> +		.regbase	= AT91SAM9263_BASE_PIOD,
>  		.clock		= &pioCDE_clk,
>  	}, {
>  		.id		= AT91SAM9263_ID_PIOCDE,
> -		.offset		= AT91_PIOE,
> +		.regbase	= AT91SAM9263_BASE_PIOE,
>  		.clock		= &pioCDE_clk,
>  	}
>  };
> diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
> index 8f5db7b..753df63 100644
> --- a/arch/arm/mach-at91/at91sam9g45.c
> +++ b/arch/arm/mach-at91/at91sam9g45.c
> @@ -282,23 +282,23 @@ void __init at91sam9g45_set_console_clock(int id)
>  static struct at91_gpio_bank at91sam9g45_gpio[] = {
>  	{
>  		.id		= AT91SAM9G45_ID_PIOA,
> -		.offset		= AT91_PIOA,
> +		.regbase	= AT91SAM9G45_BASE_PIOA,
>  		.clock		= &pioA_clk,
>  	}, {
>  		.id		= AT91SAM9G45_ID_PIOB,
> -		.offset		= AT91_PIOB,
> +		.regbase	= AT91SAM9G45_BASE_PIOB,
>  		.clock		= &pioB_clk,
>  	}, {
>  		.id		= AT91SAM9G45_ID_PIOC,
> -		.offset		= AT91_PIOC,
> +		.regbase	= AT91SAM9G45_BASE_PIOC,
>  		.clock		= &pioC_clk,
>  	}, {
>  		.id		= AT91SAM9G45_ID_PIODE,
> -		.offset		= AT91_PIOD,
> +		.regbase	= AT91SAM9G45_BASE_PIOD,
>  		.clock		= &pioDE_clk,
>  	}, {
>  		.id		= AT91SAM9G45_ID_PIODE,
> -		.offset		= AT91_PIOE,
> +		.regbase	= AT91SAM9G45_BASE_PIOE,
>  		.clock		= &pioDE_clk,
>  	}
>  };
> diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
> index a238105..c4004e2 100644
> --- a/arch/arm/mach-at91/at91sam9rl.c
> +++ b/arch/arm/mach-at91/at91sam9rl.c
> @@ -246,19 +246,19 @@ void __init at91sam9rl_set_console_clock(int id)
>  static struct at91_gpio_bank at91sam9rl_gpio[] = {
>  	{
>  		.id		= AT91SAM9RL_ID_PIOA,
> -		.offset		= AT91_PIOA,
> +		.regbase	= AT91SAM9RL_BASE_PIOA,
>  		.clock		= &pioA_clk,
>  	}, {
>  		.id		= AT91SAM9RL_ID_PIOB,
> -		.offset		= AT91_PIOB,
> +		.regbase	= AT91SAM9RL_BASE_PIOB,
>  		.clock		= &pioB_clk,
>  	}, {
>  		.id		= AT91SAM9RL_ID_PIOC,
> -		.offset		= AT91_PIOC,
> +		.regbase	= AT91SAM9RL_BASE_PIOC,
>  		.clock		= &pioC_clk,
>  	}, {
>  		.id		= AT91SAM9RL_ID_PIOD,
> -		.offset		= AT91_PIOD,
> +		.regbase	= AT91SAM9RL_BASE_PIOD,
>  		.clock		= &pioD_clk,
>  	}
>  };
> diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
> index 938b34f..11d7297 100644
> --- a/arch/arm/mach-at91/generic.h
> +++ b/arch/arm/mach-at91/generic.h
> @@ -65,7 +65,7 @@ extern void at91sam9_alt_reset(void);
>  
>  struct at91_gpio_bank {
>  	unsigned short id;		/* peripheral ID */
> -	unsigned long offset;		/* offset from system peripheral base */
> +	unsigned long regbase;		/* offset from system peripheral base */
>  	struct clk *clock;		/* associated clock */
>  };
>  extern void __init at91_gpio_init(struct at91_gpio_bank *, int nr_banks);
> diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
> index 4615528..04beff1 100644
> --- a/arch/arm/mach-at91/gpio.c
> +++ b/arch/arm/mach-at91/gpio.c
> @@ -616,8 +616,12 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
>  
>  		at91_gpio->bank = &data[i];
>  		at91_gpio->chip.base = PIN_BASE + i * 32;
> -		at91_gpio->regbase = at91_gpio->bank->offset +
> -			(void __iomem *)AT91_VA_BASE_SYS;
> +
> +		at91_gpio->regbase = ioremap(at91_gpio->bank->regbase, 512);
> +		if (!at91_gpio->regbase) {
> +			pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", i);
> +			continue;
> +		}
>  
>  		/* enable PIO controller's clock */
>  		clk_enable(at91_gpio->bank->clock);
> diff --git a/arch/arm/mach-at91/include/mach/at91cap9.h b/arch/arm/mach-at91/include/mach/at91cap9.h
> index c5df1e8..f65d083 100644
> --- a/arch/arm/mach-at91/include/mach/at91cap9.h
> +++ b/arch/arm/mach-at91/include/mach/at91cap9.h
> @@ -88,10 +88,6 @@
>  #define AT91_DMA	(0xffffec00 - AT91_BASE_SYS)
>  #define AT91_DBGU	(0xffffee00 - AT91_BASE_SYS)
>  #define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)
> -#define AT91_PIOA	(0xfffff200 - AT91_BASE_SYS)
> -#define AT91_PIOB	(0xfffff400 - AT91_BASE_SYS)
> -#define AT91_PIOC	(0xfffff600 - AT91_BASE_SYS)
> -#define AT91_PIOD	(0xfffff800 - AT91_BASE_SYS)
>  #define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
>  #define AT91_RSTC	(0xfffffd00 - AT91_BASE_SYS)
>  #define AT91_SHDWC	(0xfffffd10 - AT91_BASE_SYS)
> @@ -102,6 +98,11 @@
>  			(0xfffffd50 - AT91_BASE_SYS) :	\
>  			(0xfffffd60 - AT91_BASE_SYS))
>  
> +#define AT91CAP9_BASE_PIOA	0xfffff200
> +#define AT91CAP9_BASE_PIOB	0xfffff400
> +#define AT91CAP9_BASE_PIOC	0xfffff600
> +#define AT91CAP9_BASE_PIOD	0xfffff800
> +
>  #define AT91_USART0	AT91CAP9_BASE_US0
>  #define AT91_USART1	AT91CAP9_BASE_US1
>  #define AT91_USART2	AT91CAP9_BASE_US2
> diff --git a/arch/arm/mach-at91/include/mach/at91rm9200.h b/arch/arm/mach-at91/include/mach/at91rm9200.h
> index e4037b5..5740954 100644
> --- a/arch/arm/mach-at91/include/mach/at91rm9200.h
> +++ b/arch/arm/mach-at91/include/mach/at91rm9200.h
> @@ -81,15 +81,16 @@
>   */
>  #define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)	/* Advanced Interrupt Controller */
>  #define AT91_DBGU	(0xfffff200 - AT91_BASE_SYS)	/* Debug Unit */
> -#define AT91_PIOA	(0xfffff400 - AT91_BASE_SYS)	/* PIO Controller A */
> -#define AT91_PIOB	(0xfffff600 - AT91_BASE_SYS)	/* PIO Controller B */
> -#define AT91_PIOC	(0xfffff800 - AT91_BASE_SYS)	/* PIO Controller C */
> -#define AT91_PIOD	(0xfffffa00 - AT91_BASE_SYS)	/* PIO Controller D */
>  #define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)	/* Power Management Controller */
>  #define AT91_ST		(0xfffffd00 - AT91_BASE_SYS)	/* System Timer */
>  #define AT91_RTC	(0xfffffe00 - AT91_BASE_SYS)	/* Real-Time Clock */
>  #define AT91_MC		(0xffffff00 - AT91_BASE_SYS)	/* Memory Controllers */
>  
> +#define AT91RM9200_BASE_PIOA	0xfffff400	/* PIO Controller A */
> +#define AT91RM9200_BASE_PIOB	0xfffff600	/* PIO Controller B */
> +#define AT91RM9200_BASE_PIOC	0xfffff800	/* PIO Controller C */
> +#define AT91RM9200_BASE_PIOD	0xfffffa00	/* PIO Controller D */
> +
>  #define AT91_USART0	AT91RM9200_BASE_US0
>  #define AT91_USART1	AT91RM9200_BASE_US1
>  #define AT91_USART2	AT91RM9200_BASE_US2
> diff --git a/arch/arm/mach-at91/include/mach/at91sam9260.h b/arch/arm/mach-at91/include/mach/at91sam9260.h
> index 9a79116..1bea3dc 100644
> --- a/arch/arm/mach-at91/include/mach/at91sam9260.h
> +++ b/arch/arm/mach-at91/include/mach/at91sam9260.h
> @@ -87,9 +87,6 @@
>  #define AT91_CCFG	(0xffffef10 - AT91_BASE_SYS)
>  #define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)
>  #define AT91_DBGU	(0xfffff200 - AT91_BASE_SYS)
> -#define AT91_PIOA	(0xfffff400 - AT91_BASE_SYS)
> -#define AT91_PIOB	(0xfffff600 - AT91_BASE_SYS)
> -#define AT91_PIOC	(0xfffff800 - AT91_BASE_SYS)
>  #define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
>  #define AT91_RSTC	(0xfffffd00 - AT91_BASE_SYS)
>  #define AT91_SHDWC	(0xfffffd10 - AT91_BASE_SYS)
> @@ -98,6 +95,10 @@
>  #define AT91_WDT	(0xfffffd40 - AT91_BASE_SYS)
>  #define AT91_GPBR	(0xfffffd50 - AT91_BASE_SYS)
>  
> +#define AT91SAM9260_BASE_PIOA	0xfffff400
> +#define AT91SAM9260_BASE_PIOB	0xfffff600
> +#define AT91SAM9260_BASE_PIOC	0xfffff800
> +
>  #define AT91_USART0	AT91SAM9260_BASE_US0
>  #define AT91_USART1	AT91SAM9260_BASE_US1
>  #define AT91_USART2	AT91SAM9260_BASE_US2
> diff --git a/arch/arm/mach-at91/include/mach/at91sam9261.h b/arch/arm/mach-at91/include/mach/at91sam9261.h
> index ce59620..17ae9c7 100644
> --- a/arch/arm/mach-at91/include/mach/at91sam9261.h
> +++ b/arch/arm/mach-at91/include/mach/at91sam9261.h
> @@ -70,9 +70,6 @@
>  #define AT91_MATRIX	(0xffffee00 - AT91_BASE_SYS)
>  #define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)
>  #define AT91_DBGU	(0xfffff200 - AT91_BASE_SYS)
> -#define AT91_PIOA	(0xfffff400 - AT91_BASE_SYS)
> -#define AT91_PIOB	(0xfffff600 - AT91_BASE_SYS)
> -#define AT91_PIOC	(0xfffff800 - AT91_BASE_SYS)
>  #define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
>  #define AT91_RSTC	(0xfffffd00 - AT91_BASE_SYS)
>  #define AT91_SHDWC	(0xfffffd10 - AT91_BASE_SYS)
> @@ -81,6 +78,10 @@
>  #define AT91_WDT	(0xfffffd40 - AT91_BASE_SYS)
>  #define AT91_GPBR	(0xfffffd50 - AT91_BASE_SYS)
>  
> +#define AT91SAM9261_BASE_PIOA	0xfffff400
> +#define AT91SAM9261_BASE_PIOB	0xfffff600
> +#define AT91SAM9261_BASE_PIOC	0xfffff800
> +
>  #define AT91_USART0	AT91SAM9261_BASE_US0
>  #define AT91_USART1	AT91SAM9261_BASE_US1
>  #define AT91_USART2	AT91SAM9261_BASE_US2
> diff --git a/arch/arm/mach-at91/include/mach/at91sam9263.h b/arch/arm/mach-at91/include/mach/at91sam9263.h
> index f1b9296..dd54079 100644
> --- a/arch/arm/mach-at91/include/mach/at91sam9263.h
> +++ b/arch/arm/mach-at91/include/mach/at91sam9263.h
> @@ -84,11 +84,6 @@
>  #define AT91_CCFG	(0xffffed10 - AT91_BASE_SYS)
>  #define AT91_DBGU	(0xffffee00 - AT91_BASE_SYS)
>  #define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)
> -#define AT91_PIOA	(0xfffff200 - AT91_BASE_SYS)
> -#define AT91_PIOB	(0xfffff400 - AT91_BASE_SYS)
> -#define AT91_PIOC	(0xfffff600 - AT91_BASE_SYS)
> -#define AT91_PIOD	(0xfffff800 - AT91_BASE_SYS)
> -#define AT91_PIOE	(0xfffffa00 - AT91_BASE_SYS)
>  #define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
>  #define AT91_RSTC	(0xfffffd00 - AT91_BASE_SYS)
>  #define AT91_SHDWC	(0xfffffd10 - AT91_BASE_SYS)
> @@ -98,6 +93,12 @@
>  #define AT91_RTT1	(0xfffffd50 - AT91_BASE_SYS)
>  #define AT91_GPBR	(0xfffffd60 - AT91_BASE_SYS)
>  
> +#define AT91SAM9263_BASE_PIOA	0xfffff200
> +#define AT91SAM9263_BASE_PIOB	0xfffff400
> +#define AT91SAM9263_BASE_PIOC	0xfffff600
> +#define AT91SAM9263_BASE_PIOD	0xfffff800
> +#define AT91SAM9263_BASE_PIOE	0xfffffa00
> +
>  #define AT91_USART0	AT91SAM9263_BASE_US0
>  #define AT91_USART1	AT91SAM9263_BASE_US1
>  #define AT91_USART2	AT91SAM9263_BASE_US2
> diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h
> index 2c611b9..ec370cc 100644
> --- a/arch/arm/mach-at91/include/mach/at91sam9g45.h
> +++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h
> @@ -94,11 +94,6 @@
>  #define AT91_DMA	(0xffffec00 - AT91_BASE_SYS)
>  #define AT91_DBGU	(0xffffee00 - AT91_BASE_SYS)
>  #define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)
> -#define AT91_PIOA	(0xfffff200 - AT91_BASE_SYS)
> -#define AT91_PIOB	(0xfffff400 - AT91_BASE_SYS)
> -#define AT91_PIOC	(0xfffff600 - AT91_BASE_SYS)
> -#define AT91_PIOD	(0xfffff800 - AT91_BASE_SYS)
> -#define AT91_PIOE	(0xfffffa00 - AT91_BASE_SYS)
>  #define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
>  #define AT91_RSTC	(0xfffffd00 - AT91_BASE_SYS)
>  #define AT91_SHDWC	(0xfffffd10 - AT91_BASE_SYS)
> @@ -108,6 +103,12 @@
>  #define AT91_GPBR	(0xfffffd60 - AT91_BASE_SYS)
>  #define AT91_RTC	(0xfffffdb0 - AT91_BASE_SYS)
>  
> +#define AT91SAM9G45_BASE_PIOA	0xfffff200
> +#define AT91SAM9G45_BASE_PIOB	0xfffff400
> +#define AT91SAM9G45_BASE_PIOC	0xfffff600
> +#define AT91SAM9G45_BASE_PIOD	0xfffff800
> +#define AT91SAM9G45_BASE_PIOE	0xfffffa00
> +
>  #define AT91_USART0	AT91SAM9G45_BASE_US0
>  #define AT91_USART1	AT91SAM9G45_BASE_US1
>  #define AT91_USART2	AT91SAM9G45_BASE_US2
> diff --git a/arch/arm/mach-at91/include/mach/at91sam9rl.h b/arch/arm/mach-at91/include/mach/at91sam9rl.h
> index 1aabacd..d3ef11a 100644
> --- a/arch/arm/mach-at91/include/mach/at91sam9rl.h
> +++ b/arch/arm/mach-at91/include/mach/at91sam9rl.h
> @@ -77,10 +77,6 @@
>  #define AT91_CCFG	(0xffffef10 - AT91_BASE_SYS)
>  #define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)
>  #define AT91_DBGU	(0xfffff200 - AT91_BASE_SYS)
> -#define AT91_PIOA	(0xfffff400 - AT91_BASE_SYS)
> -#define AT91_PIOB	(0xfffff600 - AT91_BASE_SYS)
> -#define AT91_PIOC	(0xfffff800 - AT91_BASE_SYS)
> -#define AT91_PIOD	(0xfffffa00 - AT91_BASE_SYS)
>  #define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
>  #define AT91_RSTC	(0xfffffd00 - AT91_BASE_SYS)
>  #define AT91_SHDWC	(0xfffffd10 - AT91_BASE_SYS)
> @@ -91,6 +87,11 @@
>  #define AT91_GPBR	(0xfffffd60 - AT91_BASE_SYS)
>  #define AT91_RTC	(0xfffffe00 - AT91_BASE_SYS)
>  
> +#define AT91SAM9RL_BASE_PIOA	0xfffff400
> +#define AT91SAM9RL_BASE_PIOB	0xfffff600
> +#define AT91SAM9RL_BASE_PIOC	0xfffff800
> +#define AT91SAM9RL_BASE_PIOD	0xfffffa00
> +
>  #define AT91_USART0	AT91SAM9RL_BASE_US0
>  #define AT91_USART1	AT91SAM9RL_BASE_US1
>  #define AT91_USART2	AT91SAM9RL_BASE_US2

^ permalink raw reply

* [PATCH v2] arm: omap3evm: Add support for an MT9M032 based camera board.
From: Laurent Pinchart @ 2011-09-18 21:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316252097-4213-1-git-send-email-martin@neutronstar.dyndns.org>

Hi Martin,

On Saturday 17 September 2011 11:34:57 Martin Hostettler wrote:
> Adds board support for an MT9M032 based camera to omap3evm.
> 
> Sigend-off-by: Martin Hostettler <martin@neutronstar.dyndns.org>
> ---
>  arch/arm/mach-omap2/Makefile                |    1 +
>  arch/arm/mach-omap2/board-omap3evm-camera.c |  183
> +++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 0
> deletions(-)
>  create mode 100644 arch/arm/mach-omap2/board-omap3evm-camera.c
> 
> Changes in V2:
>  * ported to current mainline
>  * Style fixes
>  * Fix error handling
> 
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index f343365..8ae3d25 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -202,6 +202,7 @@ obj-$(CONFIG_MACH_OMAP3_TORPEDO)        +=
> board-omap3logic.o \ obj-$(CONFIG_MACH_OVERO)		+= board-overo.o \
>  					   hsmmc.o
>  obj-$(CONFIG_MACH_OMAP3EVM)		+= board-omap3evm.o \
> +					   board-omap3evm-camera.o \
>  					   hsmmc.o
>  obj-$(CONFIG_MACH_OMAP3_PANDORA)	+= board-omap3pandora.o \
>  					   hsmmc.o
> diff --git a/arch/arm/mach-omap2/board-omap3evm-camera.c
> b/arch/arm/mach-omap2/board-omap3evm-camera.c new file mode 100644
> index 0000000..be987d9
> --- /dev/null
> +++ b/arch/arm/mach-omap2/board-omap3evm-camera.c
> @@ -0,0 +1,183 @@
> +/*
> + * Copyright (C) 2010-2011 Lund Engineering
> + * Contact: Gil Lund <gwlund@lundeng.com>
> + * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
> + *
> + * Board intregration for a MT9M032 camera connected to IMAGE_CONN and I2C
> Bus 2 + *
> + * 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.
> + *
> + * 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., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/gpio.h>
> +#include <plat/mux.h>
> +#include "mux.h"
> +
> +#include "../../../drivers/media/video/omap3isp/isp.h"
> +#include "media/mt9m032.h"
> +
> +#include "devices.h"
> +
> +#define EVM_TWL_GPIO_BASE OMAP_MAX_GPIO_LINES
> +#define GPIO98_VID_DEC_RES	98
> +#define nCAM_VD_SEL		157
> +
> +#define MT9M032_I2C_BUS_NUM	2
> +
> +
> +enum omap3evmdc_mux {
> +	MUX_TVP5146,
> +	MUX_CAMERA_SENSOR,
> +	MUX_EXP_CAMERA_SENSOR,
> +};
> +
> +/**
> + * omap3evm_set_mux - Sets mux to enable signal routing to
> + *                           different peripherals present on new EVM
> board + * @mux_id: enum, mux id to enable
> + *
> + * Returns 0 for success or a negative error code
> + */
> +static int omap3evm_set_mux(enum omap3evmdc_mux mux_id)
> +{
> +	/* Set GPIO6 = 1 */
> +	gpio_set_value_cansleep(EVM_TWL_GPIO_BASE + 6, 1);
> +	gpio_set_value_cansleep(EVM_TWL_GPIO_BASE + 2, 0);
> +
> +	switch (mux_id) {
> +	case MUX_TVP5146:
> +		gpio_set_value_cansleep(EVM_TWL_GPIO_BASE + 2, 0);
> +		gpio_set_value(nCAM_VD_SEL, 1);
> +		break;
> +
> +	case MUX_CAMERA_SENSOR:
> +		gpio_set_value_cansleep(EVM_TWL_GPIO_BASE + 2, 0);
> +		gpio_set_value(nCAM_VD_SEL, 0);
> +		break;
> +
> +	case MUX_EXP_CAMERA_SENSOR:
> +		gpio_set_value_cansleep(EVM_TWL_GPIO_BASE + 2, 1);
> +		break;
> +
> +	default:
> +		pr_err("omap3evm-camera: Invalid mux id #%d\n", mux_id);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct mt9m032_platform_data mt9m032_platform_data = {
> +	.ext_clock = 13500000,
> +	.pll_pre_div = 6,
> +	.pll_mul = 120,
> +	.pll_out_div = 5,
> +	.invert_pixclock = 1,
> +};
> +
> +static struct i2c_board_info camera_i2c_devices[] = {
> +	{
> +		I2C_BOARD_INFO(MT9M032_NAME, MT9M032_I2C_ADDR),
> +		.platform_data = &mt9m032_platform_data,
> +	},
> +};
> +
> +static struct isp_subdev_i2c_board_info camera_i2c_subdevs[] = {
> +	{
> +		.board_info = &camera_i2c_devices[0],
> +		.i2c_adapter_id = MT9M032_I2C_BUS_NUM,
> +	},
> +	{},
> +};
> +
> +static struct isp_v4l2_subdevs_group camera_subdevs[] = {
> +	{
> +		.subdevs = camera_i2c_subdevs,
> +		.interface = ISP_INTERFACE_PARALLEL,
> +		.bus = {
> +			.parallel = {
> +				.data_lane_shift = 1,
> +				.clk_pol = 0,
> +				.bridge = ISPCTRL_PAR_BRIDGE_DISABLE,
> +			}
> +		},
> +	},
> +	{},
> +};
> +
> +static struct isp_platform_data isp_platform_data = {
> +	.subdevs = camera_subdevs,
> +};
> +
> +static int __init camera_init(void)
> +{
> +	int ret = -EINVAL;
> +
> +	omap_mux_init_gpio(nCAM_VD_SEL, OMAP_PIN_OUTPUT);
> +	if (gpio_request(nCAM_VD_SEL, "nCAM_VD_SEL") < 0) {
> +		pr_err("omap3evm-camera: Failed to get GPIO nCAM_VD_SEL(%d)\n",
> +		       nCAM_VD_SEL);
> +		goto err;
> +	}
> +	if (gpio_direction_output(nCAM_VD_SEL, 1) < 0) {
> +		pr_err("omap3evm-camera: Failed to set GPIO nCAM_VD_SEL(%d)
> direction\n", +		       nCAM_VD_SEL);
> +		goto err_vdsel;
> +	}
> +
> +	if (gpio_request(EVM_TWL_GPIO_BASE + 2, "T2_GPIO2") < 0) {
> +		pr_err("omap3evm-camera: Failed to get GPIO T2_GPIO2(%d)\n",
> +		       EVM_TWL_GPIO_BASE + 2);
> +		goto err_vdsel;
> +	}
> +	if (gpio_direction_output(EVM_TWL_GPIO_BASE + 2, 0) < 0) {
> +		pr_err("omap3evm-camera: Failed to set GPIO T2_GPIO2(%d) direction\n",
> +		       EVM_TWL_GPIO_BASE + 2);
> +		goto err_2;
> +	}
> +
> +	if (gpio_request(EVM_TWL_GPIO_BASE + 8, "nCAM_VD_EN") < 0) {
> +		pr_err("omap3evm-camera: Failed to get GPIO nCAM_VD_EN(%d)\n",
> +		       EVM_TWL_GPIO_BASE + 8);
> +		goto err_2;
> +	}
> +	if (gpio_direction_output(EVM_TWL_GPIO_BASE + 8, 0) < 0) {
> +		pr_err("omap3evm-camera: Failed to set GPIO nCAM_VD_EN(%d) direction\n",
> +		       EVM_TWL_GPIO_BASE + 8);
> +		goto err_8;
> +	}
> +
> +	omap3evm_set_mux(MUX_CAMERA_SENSOR);
> +
> +
> +	ret = omap3_init_camera(&isp_platform_data);
> +	if (ret < 0)
> +		goto err_8;
> +	return 0;
> +
> +err_8:
> +	gpio_free(EVM_TWL_GPIO_BASE + 8);
> +err_2:
> +	gpio_free(EVM_TWL_GPIO_BASE + 2);
> +err_vdsel:
> +	gpio_free(nCAM_VD_SEL);
> +err:
> +	return ret;
> +}
> +
> +device_initcall(camera_init);

Please don't use device_initcall(), but call the function directly from the 
OMAP3 EVM init handler. Otherwise camera_init() will be called if OMAP3 EVM 
support is compiled in the kernel, regardless of the board the kernel runs on.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH 5/5] ARM: gic: add OF based initialization
From: Rob Herring @ 2011-09-18 21:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4E722B2D.4050307@gmail.com>

On 09/15/2011 11:43 AM, Rob Herring wrote:
> Benoit,
> 
> On 09/15/2011 08:52 AM, Cousson, Benoit wrote:
>> On 9/15/2011 3:11 PM, Rob Herring wrote:
>>> Benoit,
>>>
>>> On 09/15/2011 05:07 AM, Cousson, Benoit wrote:
>>>> Hi Rob,
>>>>
>>>> On 9/15/2011 9:55 AM, Thomas Abraham wrote:
>>>>> Hi Rob,
>>>>>
>>>>> On 14 September 2011 22:01, Rob Herring<robherring2@gmail.com>   wrote:
>>>>>> From: Rob Herring<rob.herring@calxeda.com>
>>>>>>
>>>>>> This adds gic initialization using device tree data. The
>>>>>> initialization
>>>>>> functions are intended to be called by a generic OF interrupt
>>>>>> controller parsing function once the right pieces are in place.
>>>>>>
>>>>>> PPIs are handled using 3rd cell of interrupts properties to specify
>>>>>> the cpu
>>>>>> mask the PPI is assigned to.
>>>>>>
>>>>>> Signed-off-by: Rob Herring<rob.herring@calxeda.com>
>>>>>> ---
>>>>>>    Documentation/devicetree/bindings/arm/gic.txt |   53
>>>>>> ++++++++++++++++++++++++
>>>>>>    arch/arm/common/gic.c                         |   55
>>>>>> +++++++++++++++++++++++--
>>>>>>    arch/arm/include/asm/hardware/gic.h           |   10 +++++
>>>>>>    3 files changed, 114 insertions(+), 4 deletions(-)
>>>>>>    create mode 100644 Documentation/devicetree/bindings/arm/gic.txt
>>>>>
>>>>> [...]
>>>>>
>>>>>
>>>>>> diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
>>>>>> index d1ccc72..14de380 100644
>>>>>> --- a/arch/arm/common/gic.c
>>>>>> +++ b/arch/arm/common/gic.c
>>>>>
>>>>> [...]
>>>>>
>>>>>> +void __init gic_of_init(struct device_node *node, struct device_node
>>>>>> *parent)
>>>>>> +{
>>>>>> +       void __iomem *cpu_base;
>>>>>> +       void __iomem *dist_base;
>>>>>> +       int irq;
>>>>>> +       struct irq_domain *domain =&gic_data[gic_cnt].domain;
>>>>>> +
>>>>>> +       if (WARN_ON(!node))
>>>>>> +               return;
>>>>>> +
>>>>>> +       dist_base = of_iomap(node, 0);
>>>>>> +       WARN(!dist_base, "unable to map gic dist registers\n");
>>>>>> +
>>>>>> +       cpu_base = of_iomap(node, 1);
>>>>>> +       WARN(!cpu_base, "unable to map gic cpu registers\n");
>>>>>> +
>>>>>> +       domain->nr_irq = gic_irq_count(dist_base);
>>>>>> +       domain->irq_base = irq_alloc_descs(-1, 0, domain->nr_irq,
>>>>>> numa_node_id());
>>>>>
>>>>> For exynos4, all the interrupts originating from GIC are statically
>>>>> mapped to start from 32 in the linux virq space (GIC SPI interrupts
>>>>> start from 64). In the above code, since irq_base would be 0 for
>>>>> exynos4, the interrupt mapping is not working correctly. In your
>>>>> previous version of the patch, you have given a option to the platform
>>>>> code to choose the offset. Could that option be added to this series
>>>>> also. Or a provision to use platform specific translate function
>>>>> instead of the irq_domain_simple translator.
>>>>
>>>> I have another concern on a similar topic.
>>>>
>>>> On OMAP4 the SoC interrupts external to the MPU (SPI) have an offset of
>>>> 32. Only the internal PPI are between 0 and 31.
>>>>
>>>> For the moment we add 32 to every SoC interrupts in the irq.h define,
>>>
>>> Those defines will not be used in the DT case. So the question is
>>> whether to add 32 or not in the DT. Since we have just a single node and
>>> a linear mapping of PPIs and SPIs, the only choice is to have SPIs start
>>> at 32. And from the h/w definition, SPIs always start at 32, so it's in
>>> agreement.
>>
>> This is a agreement inside the MPUSS, but not outside.
>> Both Tegra and OMAP4 must add an offset to the HW irq number to deal
>> with that today.
>>
>>>> but I'm assuming that this offset calculation should be done thanks to a
>>>> dedicated irq domain for the SPI.
>>>> The real HW physical number start at 0, and thus this is that value that
>>>> should be in the irq binding of the device.
>>>>
>>>> So ideally we should have a irq domain for the PPI starting at 0 and
>>>> another one for the SPI starting at 32. Or 32 and 64 for the exynos4
>>>> case, but it looks like the PPI/SPI offset is always 32.
>>>>
>>>
>>> That offset of SPIs is always there. If you have a GIC as a secondary
>>> controller, It will have 32 reserved interrupts and the register layout
>>> is exactly the same as a cpu's GIC.
>>
>> Yep, but that's the GIC view and not the SoC one. My concern is to have
>> to tweak the HW number provided by the HW spec in order to add that offset.
>> If you look at SoC level, the MPUSS is just an IP that can be
>> potentially replaced by other one that will not have a GIC. In that case
>> you will not change the IRQ mapping at SoC level.
>> For example if you replace the Dual-cortexA9 by a single CortexA8, then
>> all the interrupts will have to be shifted by 32 just because the MPU
>> subsystem is different.
>>
> 
> Is that a realistic case? That would be a new chip and new device tree.
> You could argue that the whole peripheral subsystem DT could be reused
> and the numbering needs to be the same. However, there's one thing that
> would prevent that. The number of interrupt cells is defined by the
> controller binding. So you have to change the peripheral nodes anyway.
> 
> It's good that OMAP is trying to standardize the peripheral layout, but
> in my experience that's not something you can rely on.
> 
> At some point the interrupt numbering is going to differ from the h/w
> documentation. If it's not in the DT, then it will be in linux. Right
> now its just offset of 32, but if irqdescs get assigned on demand as PPC
> is doing, then there will be no relationship to the documentation.
> 
>> Since that offset is dependent of the GIC internals and is not exposed
>> outside the MPUSS, it should not be visible by the SoC IPs. And the HW
>> spec is exposing exactly that.
>>
>>> Since the idea of splitting PPIs for each core out to a flattened linux
>>> irq map has been abandoned, I see no reason to have more than 1 domain
>>> with a simple linear translation. Ultimately, domains will do dynamic
>>> irqdesc allocation and the translation within the gic will be completely
>>> dynamic.
>>
>> I think the only reason to do that is to separate internal MPU
>> interrupts with the external ones that should not have a clue about the
>> GIC.
> 
> I see 2 options (besides leaving it as is):
> 
> - Revert back to my previous binding where PPIs are a sub-node and a
> different interrupt parent.
> 
> - Use the current binding, but allow SPIs to start at 0. We can still
> distinguish PPIs and SPIs by the cpu mask cell. A cpu mask of 0 is a
> SPI. If there was ever a reason to have a cpu mask for an SPI, you would
> not be able to with this scheme.
> 
> Either way you will still have the above issue with the cell size changing.
> 

I was headed down the path of implementing the 2nd option above, but had
a dilemma. What would be the numbering base for PPIs in this case?
Should it be 0 in the DT as proposed for SPIs or does it stay at 16?
Numbering PPIs at 0 will just cause confusion as will numbering
differently from SPIs. There is absolutely no mention of SPI0 or SPIx
numbering in the GIC spec. All interrupt number references refer to the
absolute interrupt ID, not a relative number based on the type. The fact
that the Cortex-A9 implementation has interrupt lines numbered equal to
the GIC SPI interrupts is an implementation detail of the A9. Other
cores could have different arrangement including bringing out PPI
interrupts or reserving some SPIs.

As there are many users of the GIC, it makes more sense to align with
the GIC documentation rather than the documentation of 1 SOC. BTW, I
have the exact same issue in our documentation.

Rob

^ permalink raw reply

* [PATCH v2 7/7] s3c-adc: Add support for S3C2416/S3C2450
From: Heiko Stübner @ 2011-09-18 20:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109182241.48858.heiko@sntech.de>

The ADC of the S3C2416/2450 SoC is 10 or 12 bit wide, has its
source selection in the register base+0x18 and its width
selection in bit 03 of the ADCCON register.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
changes since v1:
move setname call
 arch/arm/mach-s3c2416/s3c2416.c |    3 +++
 arch/arm/plat-samsung/adc.c     |   24 +++++++++++++++++++-----
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c
index 494ce91..4261bdc 100644
--- a/arch/arm/mach-s3c2416/s3c2416.c
+++ b/arch/arm/mach-s3c2416/s3c2416.c
@@ -60,6 +60,7 @@
 #include <plat/iic-core.h>
 #include <plat/fb-core.h>
 #include <plat/nand-core.h>
+#include <plat/adc-core.h>
 
 static struct map_desc s3c2416_iodesc[] __initdata = {
 	IODESC_ENT(WATCHDOG),
@@ -97,6 +98,8 @@ int __init s3c2416_init(void)
 
 	s3c_fb_setname("s3c2443-fb");
 
+	s3c_adc_setname("s3c2416-adc");
+
 	register_syscore_ops(&s3c2416_pm_syscore_ops);
 	register_syscore_ops(&s3c24xx_irq_syscore_ops);
 
diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index af16957..c53c509 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -358,6 +358,7 @@ static int s3c_adc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct adc_device *adc;
+	int cpu = platform_get_device_id(pdev)->driver_data;
 	struct resource *regs;
 	int ret;
 	unsigned tmp;
@@ -421,9 +422,12 @@ static int s3c_adc_probe(struct platform_device *pdev)
 	clk_enable(adc->clk);
 
 	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
-	if (platform_get_device_id(pdev)->driver_data & S3C_ADC_QUIRK_12BIT) {
-		/* Enable 12-bit ADC resolution */
-		tmp |= S3C64XX_ADCCON_RESSEL;
+	/* Enable 12-bit ADC resolution */
+	if (cpu & S3C_ADC_QUIRK_12BIT) {
+		if (cpu & S3C_ADC_QUIRK_RESSEL03)
+			tmp |= S3C2416_ADCCON_RESSEL;
+		else
+			tmp |= S3C64XX_ADCCON_RESSEL;
 	}
 	writel(tmp, adc->regs + S3C2410_ADCCON);
 
@@ -491,6 +495,7 @@ static int s3c_adc_resume(struct device *dev)
 	struct platform_device *pdev = container_of(dev,
 			struct platform_device, dev);
 	struct adc_device *adc = platform_get_drvdata(pdev);
+	int cpu = platform_get_device_id(pdev)->driver_data;
 	int ret;
 	unsigned long tmp;
 
@@ -502,8 +507,12 @@ static int s3c_adc_resume(struct device *dev)
 
 	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
 	/* Enable 12-bit ADC resolution */
-	if (platform_get_device_id(pdev)->driver_data & S3C_ADC_QUIRK_12BIT)
-		tmp |= S3C64XX_ADCCON_RESSEL;
+	if (cpu & S3C_ADC_QUIRK_12BIT) {
+		if (cpu & S3C_ADC_QUIRK_RESSEL03)
+			tmp |= S3C2416_ADCCON_RESSEL;
+		else
+			tmp |= S3C64XX_ADCCON_RESSEL;
+	}
 	writel(tmp, adc->regs + S3C2410_ADCCON);
 
 	return 0;
@@ -524,6 +533,11 @@ static struct platform_device_id s3c_adc_driver_ids[] = {
 		.driver_data    = S3C_ADC_QUIRK_10BIT |
 					S3C_ADC_QUIRK_MUX18,
 	}, {
+		.name           = "s3c2416-adc",
+		.driver_data    = S3C_ADC_QUIRK_12BIT |
+					S3C_ADC_QUIRK_MUX18 |
+					S3C_ADC_QUIRK_RESSEL03,
+	}, {
 		.name           = "s3c64xx-adc",
 		.driver_data    = S3C_ADC_QUIRK_12BIT |
 					S3C_ADC_QUIRK_MUXADCCON |
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH v2 6/7] s3c-adc: Add support for S3C2443
From: Heiko Stübner @ 2011-09-18 20:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109182241.48858.heiko@sntech.de>

The S3C2443-adc is 10 bit wide and has its mux-select
in an extra register at base+0x18

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
changes since v1:
 wrap line over 80 chars and move setname call

 arch/arm/mach-s3c2443/s3c2443.c |    3 +++
 arch/arm/plat-samsung/adc.c     |    7 +++++++
 2 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c
index e6a28ba..11dae3e 100644
--- a/arch/arm/mach-s3c2443/s3c2443.c
+++ b/arch/arm/mach-s3c2443/s3c2443.c
@@ -41,6 +41,7 @@
 #include <plat/cpu.h>
 #include <plat/fb-core.h>
 #include <plat/nand-core.h>
+#include <plat/adc-core.h>
 
 static struct map_desc s3c2443_iodesc[] __initdata = {
 	IODESC_ENT(WATCHDOG),
@@ -70,6 +71,8 @@ int __init s3c2443_init(void)
 	s3c_nand_setname("s3c2412-nand");
 	s3c_fb_setname("s3c2443-fb");
 
+	s3c_adc_setname("s3c2443-adc");
+
 	/* change WDT IRQ number */
 	s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT;
 	s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT;
diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index 05030ca..af16957 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -129,6 +129,9 @@ static inline void s3c_adc_select(struct adc_device *adc,
 	if (!client->is_ts) {
 		if (cpu & S3C_ADC_QUIRK_MUX1C)
 			writel(client->channel & 0xf, adc->regs + S5P_ADCMUX);
+		else if (cpu & S3C_ADC_QUIRK_MUX18)
+			writel(client->channel & 0xf,
+				adc->regs + S3C2443_ADCMUX);
 		else
 			con |= S3C2410_ADCCON_SELMUX(client->channel);
 	}
@@ -517,6 +520,10 @@ static struct platform_device_id s3c_adc_driver_ids[] = {
 		.driver_data    = S3C_ADC_QUIRK_10BIT |
 					S3C_ADC_QUIRK_MUXADCCON,
 	}, {
+		.name           = "s3c2443-adc",
+		.driver_data    = S3C_ADC_QUIRK_10BIT |
+					S3C_ADC_QUIRK_MUX18,
+	}, {
 		.name           = "s3c64xx-adc",
 		.driver_data    = S3C_ADC_QUIRK_12BIT |
 					S3C_ADC_QUIRK_MUXADCCON |
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH 5/7] S3C24XX: Allow overriding of adc device name
From: Heiko Stübner @ 2011-09-18 20:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109182241.48858.heiko@sntech.de>

The adc blocks of S3C2443 and S3C2416 contain quirks not present
in the stock S3C24xx adc. Therefore allow them to alter the
device name via s3c_adc_setname.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/plat-samsung/include/plat/adc-core.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/arm/plat-samsung/include/plat/adc-core.h b/arch/arm/plat-samsung/include/plat/adc-core.h
index a281568..a927bee 100644
--- a/arch/arm/plat-samsung/include/plat/adc-core.h
+++ b/arch/arm/plat-samsung/include/plat/adc-core.h
@@ -20,7 +20,7 @@
 /* re-define device name depending on support. */
 static inline void s3c_adc_setname(char *name)
 {
-#ifdef CONFIG_SAMSUNG_DEV_ADC
+#if defined(CONFIG_SAMSUNG_DEV_ADC) || defined(CONFIG_PLAT_S3C24XX)
 	s3c_device_adc.name = name;
 #endif
 }
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH 4/7] s3c-adc: Fix mux bit modification in s3c_adc_select
From: Heiko Stübner @ 2011-09-18 20:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109182241.48858.heiko@sntech.de>

The mux bits in the adccon register should be cleared only
if muxing is really done in ADCCON and not another register.

This patch introduces a conditional for this.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/plat-samsung/adc.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index e3456d6..05030ca 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -121,7 +121,8 @@ static inline void s3c_adc_select(struct adc_device *adc,
 
 	client->select_cb(client, 1);
 
-	con &= ~S3C2410_ADCCON_MUXMASK;
+	if (cpu & S3C_ADC_QUIRK_MUXADCCON)
+		con &= ~S3C2410_ADCCON_MUXMASK;
 	con &= ~S3C2410_ADCCON_STDBM;
 	con &= ~S3C2410_ADCCON_STARTMASK;
 
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH 3/7] s3c-adc: Replace TYPE_ADCVx conditionals with quirks
From: Heiko Stübner @ 2011-09-18 20:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109182241.48858.heiko@sntech.de>

This patch replaces the static TYPE_ADCVs checks with checks for
specific features of an adc block. For this the s3c_cpu_type enum
in driver_data ist int containing containing the bit values
describing the indivial adc block.

This patch contains no functional changes, it merely replaces
the type checks with checks for indidual quirks.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/plat-samsung/adc.c |   33 +++++++++++++++++----------------
 1 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index b209d58..e3456d6 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -39,12 +39,6 @@
  * action is required.
  */
 
-enum s3c_cpu_type {
-	TYPE_ADCV1, /* S3C24XX */
-	TYPE_ADCV2, /* S3C64XX, S5P64X0, S5PC100 */
-	TYPE_ADCV3, /* S5PV210, S5PC110, EXYNOS4210 */
-};
-
 /*
  * Resolution of the ADC - 10 or 12 bit
  */
@@ -123,7 +117,7 @@ static inline void s3c_adc_select(struct adc_device *adc,
 				  struct s3c_adc_client *client)
 {
 	unsigned con = readl(adc->regs + S3C2410_ADCCON);
-	enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
+	int cpu = platform_get_device_id(adc->pdev)->driver_data;
 
 	client->select_cb(client, 1);
 
@@ -132,7 +126,7 @@ static inline void s3c_adc_select(struct adc_device *adc,
 	con &= ~S3C2410_ADCCON_STARTMASK;
 
 	if (!client->is_ts) {
-		if (cpu == TYPE_ADCV3)
+		if (cpu & S3C_ADC_QUIRK_MUX1C)
 			writel(client->channel & 0xf, adc->regs + S5P_ADCMUX);
 		else
 			con |= S3C2410_ADCCON_SELMUX(client->channel);
@@ -308,7 +302,7 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
 {
 	struct adc_device *adc = pw;
 	struct s3c_adc_client *client = adc->cur;
-	enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
+	int cpu = platform_get_device_id(adc->pdev)->driver_data;
 	unsigned data0, data1;
 
 	if (!client) {
@@ -322,7 +316,7 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
 
 	client->nr_samples--;
 
-	if (cpu != TYPE_ADCV1) {
+	if (cpu & S3C_ADC_QUIRK_12BIT) {
 		/* S3C64XX/S5P ADC resolution is 12-bit */
 		data0 &= 0xfff;
 		data1 &= 0xfff;
@@ -349,7 +343,7 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
 	}
 
 exit:
-	if (cpu != TYPE_ADCV1) {
+	if (cpu & S3C_ADC_QUIRK_CLRINT) {
 		/* Clear ADC interrupt */
 		writel(0, adc->regs + S3C64XX_ADCCLRINT);
 	}
@@ -423,7 +417,7 @@ static int s3c_adc_probe(struct platform_device *pdev)
 	clk_enable(adc->clk);
 
 	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
-	if (platform_get_device_id(pdev)->driver_data != TYPE_ADCV1) {
+	if (platform_get_device_id(pdev)->driver_data & S3C_ADC_QUIRK_12BIT) {
 		/* Enable 12-bit ADC resolution */
 		tmp |= S3C64XX_ADCCON_RESSEL;
 	}
@@ -504,7 +498,7 @@ static int s3c_adc_resume(struct device *dev)
 
 	tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
 	/* Enable 12-bit ADC resolution */
-	if (platform_get_device_id(pdev)->driver_data != TYPE_ADCV1)
+	if (platform_get_device_id(pdev)->driver_data & S3C_ADC_QUIRK_12BIT)
 		tmp |= S3C64XX_ADCCON_RESSEL;
 	writel(tmp, adc->regs + S3C2410_ADCCON);
 
@@ -519,13 +513,20 @@ static int s3c_adc_resume(struct device *dev)
 static struct platform_device_id s3c_adc_driver_ids[] = {
 	{
 		.name           = "s3c24xx-adc",
-		.driver_data    = TYPE_ADCV1,
+		.driver_data    = S3C_ADC_QUIRK_10BIT |
+					S3C_ADC_QUIRK_MUXADCCON,
 	}, {
 		.name           = "s3c64xx-adc",
-		.driver_data    = TYPE_ADCV2,
+		.driver_data    = S3C_ADC_QUIRK_12BIT |
+					S3C_ADC_QUIRK_MUXADCCON |
+					S3C_ADC_QUIRK_RESSEL16 |
+					S3C_ADC_QUIRK_CLRINT,
 	}, {
 		.name		= "samsung-adc-v3",
-		.driver_data	= TYPE_ADCV3,
+		.driver_data	= S3C_ADC_QUIRK_12BIT |
+					S3C_ADC_QUIRK_MUX1C |
+					S3C_ADC_QUIRK_RESSEL16 |
+					S3C_ADC_QUIRK_CLRINT,
 	},
 	{ }
 };
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH 2/7] s3c-adc: describe features via quirk constants
From: Heiko Stübner @ 2011-09-18 20:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109182241.48858.heiko@sntech.de>

The adc blocks of S3C2410 through S5P have a multitude of
quirks, i.e. moved bits or whole new registers.

This patch tries to describe these individual features
through constants which can be used to describe an adc.

As SoCs sometimes share only some of these quirks defining
TYPE_ADCVx values for each one wouldn't scale well when
adding more variants.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/plat-samsung/adc.c |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index ee8deef..b209d58 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -45,6 +45,35 @@ enum s3c_cpu_type {
 	TYPE_ADCV3, /* S5PV210, S5PC110, EXYNOS4210 */
 };
 
+/*
+ * Resolution of the ADC - 10 or 12 bit
+ */
+#define S3C_ADC_QUIRK_10BIT		0
+#define S3C_ADC_QUIRK_12BIT		(1<<0)
+
+/*
+ * 12bit ADC can switch resolution between 10 bit and 12 bit
+ * ADCCON bit 03 for S3C2416
+ * ADCCON bit 16 for S3C64XX and up
+ */
+#define S3C_ADC_QUIRK_RESSEL03		(1<<1)
+#define S3C_ADC_QUIRK_RESSEL16		(1<<2)
+
+/*
+ * Input channel select can either be in
+ * - reg ADCCON, bit for S3C24XX and S3C64XX
+ * - reg base+0x18 for 2443/2416/2450
+ * - reg base+0x1C for S5P
+ */
+#define S3C_ADC_QUIRK_MUXADCCON		(1<<3)
+#define S3C_ADC_QUIRK_MUX18		(1<<4)
+#define S3C_ADC_QUIRK_MUX1C		(1<<5)
+
+/*
+ * CLRINT register on S3C64xx
+ */
+#define S3C_ADC_QUIRK_CLRINT		(1<<6)
+
 struct s3c_adc_client {
 	struct platform_device	*pdev;
 	struct list_head	 pend;
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH 1/7] S3C2443/S3C2416: Add adc registers
From: Heiko Stübner @ 2011-09-18 20:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109182241.48858.heiko@sntech.de>

The adc blocks of the S3C2443 and S3C2416 define some
additional registers and bits.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 arch/arm/plat-samsung/include/plat/regs-adc.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-samsung/include/plat/regs-adc.h b/arch/arm/plat-samsung/include/plat/regs-adc.h
index 035e8c3..f42c445 100644
--- a/arch/arm/plat-samsung/include/plat/regs-adc.h
+++ b/arch/arm/plat-samsung/include/plat/regs-adc.h
@@ -20,6 +20,7 @@
 #define S3C2410_ADCDAT0	   S3C2410_ADCREG(0x0C)
 #define S3C2410_ADCDAT1	   S3C2410_ADCREG(0x10)
 #define S3C64XX_ADCUPDN		S3C2410_ADCREG(0x14)
+#define S3C2443_ADCMUX		S3C2410_ADCREG(0x18)
 #define S3C64XX_ADCCLRINT	S3C2410_ADCREG(0x18)
 #define S5P_ADCMUX		S3C2410_ADCREG(0x1C)
 #define S3C64XX_ADCCLRINTPNDNUP	S3C2410_ADCREG(0x20)
@@ -33,6 +34,7 @@
 #define S3C2410_ADCCON_PRSCVLMASK	(0xFF<<6)
 #define S3C2410_ADCCON_SELMUX(x)	(((x)&0x7)<<3)
 #define S3C2410_ADCCON_MUXMASK		(0x7<<3)
+#define S3C2416_ADCCON_RESSEL		(1<<3)
 #define S3C2410_ADCCON_STDBM		(1<<2)
 #define S3C2410_ADCCON_READ_START	(1<<1)
 #define S3C2410_ADCCON_ENABLE_START	(1<<0)
@@ -40,6 +42,7 @@
 
 
 /* ADCTSC Register Bits */
+#define S3C2443_ADCTSC_UD_SEN		(1<<8)
 #define S3C2410_ADCTSC_YM_SEN		(1<<7)
 #define S3C2410_ADCTSC_YP_SEN		(1<<6)
 #define S3C2410_ADCTSC_XM_SEN		(1<<5)
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH v2 0/7] S3C2443/S3C2416: Implement support for ADC
From: Heiko Stübner @ 2011-09-18 20:41 UTC (permalink / raw)
  To: linux-arm-kernel

The adc blocks of S3C2443 and S3C2416/2450 differ in some regards
from previous (S3C2410, etc) and later (S3C64XX, S5P) SoCs.

Defining more TYPE_ADCVx types for these SoCs would complicate the
necessary checks a lot. Therefore I opted for the use of quirk
constants which can describe the features of the respective adc
block and can be tested directly against.

This patch series replaces the type checks with checks for specific
quirks and adds support for S3C2443 and S3C2416/2450 on top of this.

Each patch was compile tested, and I tried to only do "equivalent
transforms" for the stuff on lower levels. But as I have only
access to S3C2416 hardware, real life testing happened only there.

Changes since v1:
added a wrap for a line over 80 and moved the adc_setname call
to the s3c24XX.c files where all the other names are set.

Heiko Stuebner (7):
  S3C2443/S3C2416: Add adc registers
  s3c-adc: describe features via quirk constants
  s3c-adc: Replace TYPE_ADCVx conditionals with quirks
  s3c-adc: Fix mux bit modification in s3c_adc_select
  S3C24XX: Allow overriding of adc device name
  s3c-adc: Add support for S3C2443
  s3c-adc: Add support for S3C2416/S3C2450

 arch/arm/mach-s3c2416/s3c2416.c               |    3 +
 arch/arm/mach-s3c2443/s3c2443.c               |    3 +
 arch/arm/plat-samsung/adc.c                   |   90 +++++++++++++++++++-----
 arch/arm/plat-samsung/include/plat/adc-core.h |    2 +-
 arch/arm/plat-samsung/include/plat/regs-adc.h |    3 +
 5 files changed, 80 insertions(+), 20 deletions(-)

-- 
1.7.2.3

^ permalink raw reply

* [PATCH 0/2] video: s3c-fb: Add window positioning support
From: Laurent Pinchart @ 2011-09-18 20:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4E7646B5.6000000@gmx.de>

Hi Florian,

On Sunday 18 September 2011 21:29:57 Florian Tobias Schandinat wrote:
> On 09/07/2011 03:31 PM, Laurent Pinchart wrote:
> > On Thursday 01 September 2011 18:45:18 Florian Tobias Schandinat wrote:
> >> On 08/25/2011 07:51 PM, Ajay Kumar wrote:
> >>> Just as a note, there are many drivers like mx3fb.c, au1200fb.c and
> >>> OMAP seem to be doing window/plane positioning in their driver code.
> >>> Is it possible to have this window positioning support at a common
> >>> place?
> >> 
> >> Good point. Congratulations for figuring out that I like to standardize
> >> things. But I think your suggestion is far from being enough to be
> >> useful for userspace (which is our goal so that applications can be
> >> reused along drivers and don't need to know about individual drivers).
> > 
> > Beside standardizing things, do you also like to take them one level
> > higher to solve challenging issues ? I know the answer must be yes :-)
> > 
> > The problem at hand here is something we have solved in V4L2
> > (theoretically only for part of it) with the media controller API, the
> > V4L2 subdevs and their pad-level format API.
> > 
> > In a nutshell, the media controller lets drivers model hardware as a
> > graph of buliding blocks connected through their pads and expose that
> > description to userspace applications. In V4L2 most of those blocks are
> > V4L2 subdevs, which are abstract building blocks that implement sets of
> > standard operations. Those operations are exposed to userspace through
> > the V4L2 subdevs pad-level format API, allowing application to configure
> > sizes and selection rectangles at all pads in the graph. Selection
> > rectangles can be used to configure cropping and composing, which is
> > exactly what the window positioning API needs to do.
> > 
> > Instead of creating a new fbdev-specific API to do the same, shouldn't we
> > try to join forces ?
> 
> Okay, thanks for the pointer. After having a look at your API I understand
> that it would solve the problem to discover how many windows (in this
> case) are there and how they can be accessed. It looks fine for this
> purpose, powerful enough and not too complex. So if I get it correct we
> still need at least a way to configure the position of the
> windows/overlays/sink pads similar to what Ajay proposed.

Yes, the media controller API can only expose the topology to userspace, it 
can't be used to configure FB-specific parameters on the pipeline.

> Additionally a way to get and/or set the z-position of the overlays if
> multiple overlays overlap and set/get how the overlays work (overdraw,
> constant alpha, source/destination color keying). Normally I'd consider
> these link properties but I think implementing them as properties of the
> source framebuffer or sink pad would work as well.
> Is this correct or did I miss something?

That's correct.

What bothers me is that both V4L2 and DRM/KMS have the exact same needs. I 
don't think it makes sense to implement three different solutions to the same 
problem in our three video-related APIs. What's your opinion about that ?

I've tried to raise the issue on the dri-devel mailing list ("Proposal for a 
low-level Linux display framework"), but there's still a long way to go before 
convincing everybody. Feel free to help me :-)

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH v2] arm: omap3evm: Add support for an MT9M032 based camera board.
From: martin at neutronstar.dyndns.org @ 2011-09-18 20:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109180008.21254.laurent.pinchart@ideasonboard.com>

On Sun, Sep 18, 2011 at 12:08:20AM +0200, Laurent Pinchart wrote:
> On Sunday 18 September 2011 00:00:16 Sylwester Nawrocki wrote:
> > On 09/17/2011 11:34 AM, Martin Hostettler wrote:
> > > Adds board support for an MT9M032 based camera to omap3evm.
> > 
> > ...
> > 
> > > +
> > > +static int __init camera_init(void)
> > > +{
> > > +	int ret = -EINVAL;
> > > +
> > > +	omap_mux_init_gpio(nCAM_VD_SEL, OMAP_PIN_OUTPUT);
> > > +	if (gpio_request(nCAM_VD_SEL, "nCAM_VD_SEL")<  0) {
> > > +		pr_err("omap3evm-camera: Failed to get GPIO nCAM_VD_SEL(%d)\n",
> > > +		       nCAM_VD_SEL);
> > > +		goto err;
> > > +	}
> > > +	if (gpio_direction_output(nCAM_VD_SEL, 1)<  0) {
> > > +		pr_err("omap3evm-camera: Failed to set GPIO nCAM_VD_SEL(%d)
> > > direction\n", +		       nCAM_VD_SEL);
> > > +		goto err_vdsel;
> > > +	}
> > 
> > How about replacing gpio_request + gpio_direction_output with:
> > 
> > 	gpio_request_one(nCAM_VD_SEL, GPIOF_OUT_INIT_HIGH, "nCAM_VD_SEL");
> 
> I'd even propose gpio_request_array().
> 

Nice interface. Apart from a bit less detailed error reporting it nicely
simplifies the code. I'll make a new patch using that soon.

 - Martin Hostettler

^ permalink raw reply

* [PATCH v2] arm: omap3evm: Add support for an MT9M032 based camera board.
From: martin at neutronstar.dyndns.org @ 2011-09-18 20:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316291069.1610.23.camel@Joe-Laptop>

On Sat, Sep 17, 2011 at 01:24:29PM -0700, Joe Perches wrote:
> On Sat, 2011-09-17 at 11:34 +0200, Martin Hostettler wrote:
> > Adds board support for an MT9M032 based camera to omap3evm.
> 
> All of the logging messages could be
> prefixed by the printk subsystem if you
> add #define pr_fmt before any #include

Ah, i didn't really knew about that feature yet. I really have to keep
that in mind when grepping for error messages in the future.

But i don't think it would help much, as i now reducted the total number
of pr_err calls to 2 in this patch.

Thanks for the idea anyway.

 - Martin Hostettler

> 
> > diff --git a/arch/arm/mach-omap2/board-omap3evm-camera.c b/arch/arm/mach-omap2/board-omap3evm-camera.c
> []
> #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> []
> > +static int omap3evm_set_mux(enum omap3evmdc_mux mux_id)
> []
> > +	switch (mux_id) {
> []
> > +	default:
> > +		pr_err("omap3evm-camera: Invalid mux id #%d\n", mux_id);
> 
> 		pr_err("Invalid mux id #%d\n", mux_id);
> []
> > +static int __init camera_init(void)
> []
> > +	if (gpio_request(nCAM_VD_SEL, "nCAM_VD_SEL") < 0) {
> > +		pr_err("omap3evm-camera: Failed to get GPIO nCAM_VD_SEL(%d)\n",
> > +		       nCAM_VD_SEL);
> 
> 		pr_err("Failed to get GPIO nCAM_VD_SEL(%d)\n",
> 		       nCAM_VD_SEL);
> etc.
> 

^ permalink raw reply

* [PATCH 0/2] video: s3c-fb: Add window positioning support
From: Florian Tobias Schandinat @ 2011-09-18 19:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201109071731.02293.laurent.pinchart@ideasonboard.com>

Hi Laurent,

On 09/07/2011 03:31 PM, Laurent Pinchart wrote:
> Hi Florian,
> 
> On Thursday 01 September 2011 18:45:18 Florian Tobias Schandinat wrote:
>> Hi all,
>>
>> On 08/25/2011 07:51 PM, Ajay Kumar wrote:
>>> Just as a note, there are many drivers like mx3fb.c, au1200fb.c and OMAP
>>> seem to be doing window/plane positioning in their driver code.
>>> Is it possible to have this window positioning support at a common place?
>>
>> Good point. Congratulations for figuring out that I like to standardize
>> things. But I think your suggestion is far from being enough to be useful
>> for userspace (which is our goal so that applications can be reused along
>> drivers and don't need to know about individual drivers).
> 
> Beside standardizing things, do you also like to take them one level higher to 
> solve challenging issues ? I know the answer must be yes :-)
> 
> The problem at hand here is something we have solved in V4L2 (theoretically 
> only for part of it) with the media controller API, the V4L2 subdevs and their 
> pad-level format API.
> 
> In a nutshell, the media controller lets drivers model hardware as a graph of 
> buliding blocks connected through their pads and expose that description to 
> userspace applications. In V4L2 most of those blocks are V4L2 subdevs, which 
> are abstract building blocks that implement sets of standard operations. Those 
> operations are exposed to userspace through the V4L2 subdevs pad-level format 
> API, allowing application to configure sizes and selection rectangles at all 
> pads in the graph. Selection rectangles can be used to configure cropping and 
> composing, which is exactly what the window positioning API needs to do.
> 
> Instead of creating a new fbdev-specific API to do the same, shouldn't we try 
> to join forces ?

Okay, thanks for the pointer. After having a look at your API I understand that
it would solve the problem to discover how many windows (in this case) are there
and how they can be accessed. It looks fine for this purpose, powerful enough
and not too complex. So if I get it correct we still need at least a way to
configure the position of the windows/overlays/sink pads similar to what Ajay
proposed. Additionally a way to get and/or set the z-position of the overlays if
multiple overlays overlap and set/get how the overlays work (overdraw, constant
alpha, source/destination color keying). Normally I'd consider these link
properties but I think implementing them as properties of the source framebuffer
or sink pad would work as well.
Is this correct or did I miss something?


Best regards,

Florian Tobias Schandinat

^ permalink raw reply

* [PATCH 4/4] net/fec: add imx6q enet support
From: Francois Romieu @ 2011-09-18 18:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316346852-17090-5-git-send-email-shawn.guo@linaro.org>

Shawn Guo <shawn.guo@linaro.org> :
[...]
> diff --git a/drivers/net/fec.c b/drivers/net/fec.c
> index 04206e4..849cb0b 100644
> --- a/drivers/net/fec.c
> +++ b/drivers/net/fec.c
> @@ -442,18 +453,23 @@ fec_restart(struct net_device *ndev, int duplex)
>  		/* Enable flow control and length check */
>  		rcntl |= 0x40000000 | 0x00000020;
>  
> -		/* MII or RMII */
> +		/* RGMII, RMII or MII */
> +		if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII)
> +			rcntl |= (1 << 6);
>  		if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
           ^^^^ missing "else"

[...]
> +		/* 1G, 100M or 10M */
> +		if (fep->phy_dev) {
> +			if (fep->phy_dev->speed == SPEED_1000)
> +				ecntl |= (1 << 8);
> +			else if (fep->phy_dev->speed == SPEED_100)
> +				rcntl &= ~(1 << 9);
> +			else
> +				rcntl |= (1 << 9);
> +		}
[...]
> +	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
> +		/* enable ENET endian swap */
> +		ecntl |= (1 << 8);

I do not understand why the endian swap bit of ecntl needs to be
set the same in these two different paths, especially as the latter
handles the old faulty imx28 and the former the newly fixed imx6q.
Typo ?

-- 
Ueimor

^ permalink raw reply

* [PATCH 0/6] mc13783 cleanup
From: Samuel Ortiz @ 2011-09-18 16:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110915160321.GA29357@pengutronix.de>

Hi Uwe,

On Thu, Sep 15, 2011 at 06:03:21PM +0200, Uwe Kleine-K?nig wrote:
> Hi Samuel,
> 
> On Thu, Sep 15, 2011 at 05:12:13PM +0200, Samuel Ortiz wrote:
> > On Thu, Aug 25, 2011 at 09:05:12AM +0200, Philippe R?tornaz wrote:
> > > Le mercredi 24 ao?t 2011 15:27:40, Uwe Kleine-K?nig a ?crit :
> > > > Hello,
> > > > 
> > > > this series removes the long obsolte mc13783 API after fixing all
> > > > remaining users.
> > > 
> > > I posted a patch last month which was touching this MFD too.
> > > We will need to synchronize both patch. 
> > I applied Uwe's patchset now.
> Thanks.
> 
> >                               Could you please sync your code and send me a
> > patchset that applies on top of:
> > 
> > git://git.infradead.org/users/sameo/mfd-2.6.git for-next
> You can fetch the updated series from
> 
> 	git://git.pengutronix.de/git/ukl/linux-2.6.git mc13783
I merged this one on top of my for-next branch. My MFD tree temporary lives on
infradead:

git://git.infradead.org/users/sameo/mfd-2.6.git

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply

* READ THIS: the next mach-types update
From: Arnd Bergmann @ 2011-09-18 15:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110916102754.GA6205@netboy.at.omicron.at>

On Friday 16 September 2011 12:27:54 Richard Cochran wrote:
> On Thu, Sep 15, 2011 at 11:25:28AM +0100, Russell King - ARM Linux wrote:
> > -devixp                  MACH_DEVIXP             DEVIXP                  2885
> > -miccpt                  MACH_MICCPT             MICCPT                  2886
> > -mic256                  MACH_MIC256             MIC256                  2887
> 
> Russell,
> 
> I had posted support for these some time ago, and shortly thereafter
> the whole "clean up the ARM mess" campaign started. I did not follow
> up on posting a second time, for fear of adding more churn.
> 
> So, my question is, what can I do to keep these in the list?
> 
> Can I get plain old board setup files merged (like three of the
> following) ...
> 
>  arch/arm/mach-ixp4xx/Kconfig                   |    8 +
>  arch/arm/mach-ixp4xx/Makefile                  |    2 +
>  arch/arm/mach-ixp4xx/include/mach/uncompress.h |    2 +-
>  arch/arm/mach-ixp4xx/miccpt-pci.c              |   78 +++++++++
>  arch/arm/mach-ixp4xx/miccpt-setup.c            |  219 ++++++++++++++++++++++++
>  5 files changed, 308 insertions(+), 1 deletions(-)
> 
> or would I have to somehow upgrade to DT?

Post them for review again. The rules for new boards are much stricter
now, but we still allow them to get merged if they look good enough.

ixp4xx is not a very active platform, which means that it will take
a while before converting it to device tree probing becomes a priority,
so I would not object adding one board there. It's quite different for
platforms that are still used for new hardware development and have
lots of new boards waiting to get merged.

	Arnd

^ permalink raw reply

* [PATCH 1/3] ARM: EXYNOS4: Modify PMU register setting function
From: Sylwester Nawrocki @ 2011-09-18 15:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316052239-8361-2-git-send-email-boyko.lee@samsung.com>

Hi Jongpill,

On 09/15/2011 04:03 AM, Jongpill Lee wrote:
> This patch modifies PMU register setting function to support the other Exynos4 series.
> 
> Signed-off-by: Jongpill Lee<boyko.lee@samsung.com>
> ---
>   arch/arm/mach-exynos4/include/mach/pmu.h      |    5 +
>   arch/arm/mach-exynos4/include/mach/regs-pmu.h |    1 -
>   arch/arm/mach-exynos4/pmu.c                   |  238 +++++++++---------------
>   3 files changed, 94 insertions(+), 150 deletions(-)
> 
> diff --git a/arch/arm/mach-exynos4/include/mach/pmu.h b/arch/arm/mach-exynos4/include/mach/pmu.h
> index a952904..430e917 100644
> --- a/arch/arm/mach-exynos4/include/mach/pmu.h
> +++ b/arch/arm/mach-exynos4/include/mach/pmu.h
> @@ -20,6 +20,11 @@ enum sys_powerdown {
>   	NUM_SYS_POWERDOWN,
>   };
> 
> +struct exynos4_pmu_conf {
> +	void __iomem *reg;
> +	unsigned long val[NUM_SYS_POWERDOWN];

Why unsigned long? It's for the registers value, wouldn't u32 fit better?

> +};
> +
>   extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode);
> 
>   #endif /* __ASM_ARCH_PMU_H */
> diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
> index cdf9b47..7fa44b9 100644
> --- a/arch/arm/mach-exynos4/include/mach/regs-pmu.h
> +++ b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
> @@ -27,7 +27,6 @@
>   #define S5P_USE_STANDBY_WFI1			(1<<  17)
>   #define S5P_USE_STANDBY_WFE0			(1<<  24)
>   #define S5P_USE_STANDBY_WFE1			(1<<  25)
> -#define S5P_USE_MASK				((0x3<<  16) | (0x3<<  24))
> 
>   #define S5P_SWRESET				S5P_PMUREG(0x0400)
> 
> diff --git a/arch/arm/mach-exynos4/pmu.c b/arch/arm/mach-exynos4/pmu.c
> index 7ea9eb2..0210231 100644
> --- a/arch/arm/mach-exynos4/pmu.c
> +++ b/arch/arm/mach-exynos4/pmu.c
> @@ -16,160 +16,100 @@
>   #include<mach/regs-clock.h>
>   #include<mach/pmu.h>
> 
> -static void __iomem *sys_powerdown_reg[] = {
> -	S5P_ARM_CORE0_LOWPWR,
...
> -	S5P_GPS_ALIVE_LOWPWR,
> -};
> +static struct exynos4_pmu_conf *exynos4_pmu_config;
> +
> +static unsigned int exynos4_pmu_entry_cnt;
> 
> -static const unsigned int sys_powerdown_val[][NUM_SYS_POWERDOWN] = {
> -	/* { AFTR, LPA, SLEEP }*/
> -	{ 0, 0, 2 },	/* ARM_CORE0 */
...
> -	{ 7, 0, 0 },	/* GPS_ALIVE */
> +static struct exynos4_pmu_conf exynos4210_pmu_config[] = {
> +	/* { .reg = address, .val = { AFTR, LPA, SLEEP } */
> +	{ S5P_ARM_CORE0_LOWPWR,			{ 0x0, 0x0, 0x2 } },
...
> +	{ S5P_GPS_ALIVE_LOWPWR,			{ 0x7, 0x0, 0x0 } },
>   };
> 
>   void exynos4_sys_powerdown_conf(enum sys_powerdown mode)
>   {
> -	unsigned int count = ARRAY_SIZE(sys_powerdown_reg);
> +	unsigned int count = exynos4_pmu_entry_cnt;

How about using a sentinel at the array end and getting rid of the global
'exynos4_pmu_entry_cnt' variable? For instance an empty entry { } ?  

> 
>   	for (; count>  0; count--)
> -		__raw_writel(sys_powerdown_val[count - 1][mode],
> -				sys_powerdown_reg[count - 1]);
> +		__raw_writel(exynos4_pmu_config[count - 1].val[mode],
> +				exynos4_pmu_config[count - 1].reg);
> +}
> +
> +static int __init exynos4_pmu_init(void)
> +{
> +	exynos4_pmu_config = exynos4210_pmu_config;
> +	exynos4_pmu_entry_cnt = ARRAY_SIZE(exynos4210_pmu_config);
> +	printk(KERN_INFO "EXYNOS4210 PMU Initialize\n");

	"EXYNOS4210 PMU initialized\n", "EXYNOS4210 PMU initialization completed\n" ?

	Moreover AFAIK pr_info is preferred.

> +
> +	return 0;
>   }
> +arch_initcall(exynos4_pmu_init);

--
Thanks,
Sylwester

^ permalink raw reply

* [PATCH] ARM: OMAP: Add support for dmtimer v2 ip (Re: [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver)
From: DebBarma, Tarun Kanti @ 2011-09-18 12:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110917013531.GB2937@atomide.com>

[...]
> Well here's what I came up with to deal with the different timer
> registers. We can't use the context registers as those are for
> the value naturally..
>
> But we can map the interrupt registers separately and then have
> the rest start from func_base that is different based on the timer
> version. Rebasing the rest of the dmtimer hwmod patches on this
> should be fairly easy, mostly just need to pass timer instead of
> timer->io_base and use __raw_read/write for the interrupt registers.
I went through the patch. It definitely looks much more simplified now.
I will rebase on top of this change.

>
> Also, I ended up checking the timer revision with if (!(tidr >> 16))
> as it seems that those bits are zero for v1 timers? If that works,
> then we don't need patch 02/12 for the revision number.
Right.
--
Tarun
>
> Afzal, care to check if that works for AM335X/TI816X/TI814X?
> It tried it briefly with omap4 gptimer3 as the clockevent and
> CONFIG_LOCAL_TIMER disabled.
>
> The patch is against the current cleanup branch in linux-omap
> tree.
>
> Regards,
>
> Tony
>
>
> From: Tony Lindgren <tony@atomide.com>
> Date: Fri, 16 Sep 2011 15:44:20 -0700
> Subject: [PATCH] ARM: OMAP: Add support for dmtimer v2 ip
>
> The registers are slightly different between v1 and v2 ip that
> is available in omap4 and later for some timers.
>
> Add support for v2 ip by mapping the interrupt related registers
> separately and adding func_base for the functional registers.
>
> Also disable dmtimer driver features on omap4 for now as
> those need the hwmod conversion series to deal with enabling
> the timers properly in omap_dm_timer_init.
>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index cf1de7d..21d34fb 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -78,7 +78,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
> ?{
> ? ? ? ?struct clock_event_device *evt = &clockevent_gpt;
>
> - ? ? ? __omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
> + ? ? ? __omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
>
> ? ? ? ?evt->event_handler(evt);
> ? ? ? ?return IRQ_HANDLED;
> @@ -93,7 +93,7 @@ static struct irqaction omap2_gp_timer_irq = {
> ?static int omap2_gp_timer_set_next_event(unsigned long cycles,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *evt)
> ?{
> - ? ? ? __omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST,
> + ? ? ? __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0xffffffff - cycles, 1);
>
> ? ? ? ?return 0;
> @@ -104,16 +104,16 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
> ?{
> ? ? ? ?u32 period;
>
> - ? ? ? __omap_dm_timer_stop(clkev.io_base, 1, clkev.rate);
> + ? ? ? __omap_dm_timer_stop(&clkev, 1, clkev.rate);
>
> ? ? ? ?switch (mode) {
> ? ? ? ?case CLOCK_EVT_MODE_PERIODIC:
> ? ? ? ? ? ? ? ?period = clkev.rate / HZ;
> ? ? ? ? ? ? ? ?period -= 1;
> ? ? ? ? ? ? ? ?/* Looks like we need to first set the load value separately */
> - ? ? ? ? ? ? ? __omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG,
> + ? ? ? ? ? ? ? __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0xffffffff - period, 1);
> - ? ? ? ? ? ? ? __omap_dm_timer_load_start(clkev.io_base,
> + ? ? ? ? ? ? ? __omap_dm_timer_load_start(&clkev,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0xffffffff - period, 1);
> ? ? ? ? ? ? ? ?break;
> @@ -172,6 +172,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
> ? ? ? ?}
>
> ? ? ? ?omap_hwmod_enable(oh);
> + ? ? ? __omap_dm_timer_init_regs(timer);
>
> ? ? ? ?sys_timer_reserved |= (1 << (gptimer_id - 1));
>
> @@ -189,7 +190,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
> ? ? ? ? ? ? ? ? ? ? ? ?clk_put(src);
> ? ? ? ? ? ? ? ?}
> ? ? ? ?}
> - ? ? ? __omap_dm_timer_reset(timer->io_base, 1, 1);
> + ? ? ? __omap_dm_timer_reset(timer, 1, 1);
> ? ? ? ?timer->posted = 1;
>
> ? ? ? ?timer->rate = clk_get_rate(timer->fclk);
> @@ -210,7 +211,7 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
> ? ? ? ?omap2_gp_timer_irq.dev_id = (void *)&clkev;
> ? ? ? ?setup_irq(clkev.irq, &omap2_gp_timer_irq);
>
> - ? ? ? __omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW);
> + ? ? ? __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
>
> ? ? ? ?clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? clockevent_gpt.shift);
> @@ -251,7 +252,7 @@ static struct omap_dm_timer clksrc;
> ?static DEFINE_CLOCK_DATA(cd);
> ?static cycle_t clocksource_read_cycles(struct clocksource *cs)
> ?{
> - ? ? ? return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1);
> + ? ? ? return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1);
> ?}
>
> ?static struct clocksource clocksource_gpt = {
> @@ -266,7 +267,7 @@ static void notrace dmtimer_update_sched_clock(void)
> ?{
> ? ? ? ?u32 cyc;
>
> - ? ? ? cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
> + ? ? ? cyc = __omap_dm_timer_read_counter(&clksrc, 1);
>
> ? ? ? ?update_sched_clock(&cd, cyc, (u32)~0);
> ?}
> @@ -276,7 +277,7 @@ unsigned long long notrace sched_clock(void)
> ? ? ? ?u32 cyc = 0;
>
> ? ? ? ?if (clksrc.reserved)
> - ? ? ? ? ? ? ? cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
> + ? ? ? ? ? ? ? cyc = __omap_dm_timer_read_counter(&clksrc, 1);
>
> ? ? ? ?return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> ?}
> @@ -293,7 +294,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
> ? ? ? ?pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
> ? ? ? ? ? ? ? ?gptimer_id, clksrc.rate);
>
> - ? ? ? __omap_dm_timer_load_start(clksrc.io_base,
> + ? ? ? __omap_dm_timer_load_start(&clksrc,
> ? ? ? ? ? ? ? ? ? ? ? ?OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
> ? ? ? ?init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
>
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> index 75a847d..e23b7cf 100644
> --- a/arch/arm/plat-omap/dmtimer.c
> +++ b/arch/arm/plat-omap/dmtimer.c
> @@ -170,7 +170,8 @@ static spinlock_t dm_timer_lock;
> ?*/
> ?static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
> ?{
> - ? ? ? return __omap_dm_timer_read(timer->io_base, reg, timer->posted);
> + ? ? ? WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
> + ? ? ? return __omap_dm_timer_read(timer, reg, timer->posted);
> ?}
>
> ?/*
> @@ -182,15 +183,19 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
> ?static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?u32 value)
> ?{
> - ? ? ? __omap_dm_timer_write(timer->io_base, reg, value, timer->posted);
> + ? ? ? WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
> + ? ? ? __omap_dm_timer_write(timer, reg, value, timer->posted);
> ?}
>
> ?static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
> ?{
> ? ? ? ?int c;
>
> + ? ? ? if (!timer->sys_stat)
> + ? ? ? ? ? ? ? return;
> +
> ? ? ? ?c = 0;
> - ? ? ? while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) {
> + ? ? ? while (!(__raw_readl(timer->sys_stat) & 1)) {
> ? ? ? ? ? ? ? ?c++;
> ? ? ? ? ? ? ? ?if (c > 100000) {
> ? ? ? ? ? ? ? ? ? ? ? ?printk(KERN_ERR "Timer failed to reset\n");
> @@ -219,7 +224,7 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
> ? ? ? ?if (cpu_class_is_omap2())
> ? ? ? ? ? ? ? ?wakeup = 1;
>
> - ? ? ? __omap_dm_timer_reset(timer->io_base, autoidle, wakeup);
> + ? ? ? __omap_dm_timer_reset(timer, autoidle, wakeup);
> ? ? ? ?timer->posted = 1;
> ?}
>
> @@ -401,7 +406,7 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
> ? ? ? ?rate = clk_get_rate(timer->fclk);
> ?#endif
>
> - ? ? ? __omap_dm_timer_stop(timer->io_base, timer->posted, rate);
> + ? ? ? __omap_dm_timer_stop(timer, timer->posted, rate);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
>
> @@ -466,7 +471,7 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
> ? ? ? ?}
> ? ? ? ?l |= OMAP_TIMER_CTRL_ST;
>
> - ? ? ? __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted);
> + ? ? ? __omap_dm_timer_load_start(timer, l, load, timer->posted);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
>
> @@ -519,7 +524,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
> ?void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned int value)
> ?{
> - ? ? ? __omap_dm_timer_int_enable(timer->io_base, value);
> + ? ? ? __omap_dm_timer_int_enable(timer, value);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
>
> @@ -527,7 +532,7 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
> ?{
> ? ? ? ?unsigned int l;
>
> - ? ? ? l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
> + ? ? ? l = __raw_readl(timer->irq_stat);
>
> ? ? ? ?return l;
> ?}
> @@ -535,13 +540,13 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
>
> ?void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
> ?{
> - ? ? ? __omap_dm_timer_write_status(timer->io_base, value);
> + ? ? ? __omap_dm_timer_write_status(timer, value);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
>
> ?unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
> ?{
> - ? ? ? return __omap_dm_timer_read_counter(timer->io_base, timer->posted);
> + ? ? ? return __omap_dm_timer_read_counter(timer, timer->posted);
> ?}
> ?EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
>
> @@ -601,6 +606,9 @@ static int __init omap_dm_timer_init(void)
> ? ? ? ? ? ? ? ?dm_timer_count = omap4_dm_timer_count;
> ? ? ? ? ? ? ? ?dm_source_names = omap4_dm_source_names;
> ? ? ? ? ? ? ? ?dm_source_clocks = omap4_dm_source_clocks;
> +
> + ? ? ? ? ? ? ? pr_err("dmtimers disabled for omap4 until hwmod conversion\n");
> + ? ? ? ? ? ? ? return -ENODEV;
> ? ? ? ?}
>
> ? ? ? ?if (cpu_class_is_omap2())
> @@ -630,8 +638,12 @@ static int __init omap_dm_timer_init(void)
> ? ? ? ? ? ? ? ?if (sys_timer_reserved & (1 ?<< i)) {
> ? ? ? ? ? ? ? ? ? ? ? ?timer->reserved = 1;
> ? ? ? ? ? ? ? ? ? ? ? ?timer->posted = 1;
> + ? ? ? ? ? ? ? ? ? ? ? continue;
> ? ? ? ? ? ? ? ?}
> ?#endif
> + ? ? ? ? ? ? ? omap_dm_timer_enable(timer);
> + ? ? ? ? ? ? ? __omap_dm_timer_init_regs(timer);
> + ? ? ? ? ? ? ? omap_dm_timer_disable(timer);
> ? ? ? ?}
>
> ? ? ? ?return 0;
> diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
> index eb5d16c..a11d0c0 100644
> --- a/arch/arm/plat-omap/include/plat/dmtimer.h
> +++ b/arch/arm/plat-omap/include/plat/dmtimer.h
> @@ -98,12 +98,30 @@ int omap_dm_timers_active(void);
> ?* used by dmtimer.c and sys_timer related code.
> ?*/
>
> -/* register offsets */
> -#define _OMAP_TIMER_ID_OFFSET ? ? ? ? ?0x00
> -#define _OMAP_TIMER_OCP_CFG_OFFSET ? ? 0x10
> -#define _OMAP_TIMER_SYS_STAT_OFFSET ? ?0x14
> -#define _OMAP_TIMER_STAT_OFFSET ? ? ? ? ? ? ? ?0x18
> -#define _OMAP_TIMER_INT_EN_OFFSET ? ? ?0x1c
> +/*
> + * The interrupt registers are different between v1 and v2 ip.
> + * These registers are offsets from timer->iobase.
> + */
> +#define OMAP_TIMER_ID_OFFSET ? ? ? ? ? 0x00
> +#define OMAP_TIMER_OCP_CFG_OFFSET ? ? ?0x10
> +
> +#define OMAP_TIMER_V1_SYS_STAT_OFFSET ?0x14
> +#define OMAP_TIMER_V1_STAT_OFFSET ? ? ?0x18
> +#define OMAP_TIMER_V1_INT_EN_OFFSET ? ?0x1c
> +
> +#define OMAP_TIMER_V2_IRQSTATUS_RAW ? ?0x24
> +#define OMAP_TIMER_V2_IRQSTATUS ? ? ? ? ? ? ? ?0x28
> +#define OMAP_TIMER_V2_IRQENABLE_SET ? ?0x2c
> +#define OMAP_TIMER_V2_IRQENABLE_CLR ? ?0x30
> +
> +/*
> + * The functional registers have a different base on v1 and v2 ip.
> + * These registers are offsets from timer->func_base. The func_base
> + * is samae as io_base for v1 and io_base + 0x14 for v2 ip.
> + *
> + */
> +#define OMAP_TIMER_V2_FUNC_OFFSET ? ? ? ? ? ? ?0x14
> +
> ?#define _OMAP_TIMER_WAKEUP_EN_OFFSET ? 0x20
> ?#define _OMAP_TIMER_CTRL_OFFSET ? ? ? ? ? ? ? ?0x24
> ?#define ? ? ? ? ? ? ? ?OMAP_TIMER_CTRL_GPOCFG ? ? ? ? ?(1 << 14)
> @@ -147,21 +165,6 @@ int omap_dm_timers_active(void);
> ?/* register offsets with the write pending bit encoded */
> ?#define ? ? ? ?WPSHIFT ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 16
>
> -#define OMAP_TIMER_ID_REG ? ? ? ? ? ? ? ? ? ? ?(_OMAP_TIMER_ID_OFFSET \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
> -
> -#define OMAP_TIMER_OCP_CFG_REG ? ? ? ? ? ? ? ? (_OMAP_TIMER_OCP_CFG_OFFSET \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
> -
> -#define OMAP_TIMER_SYS_STAT_REG ? ? ? ? ? ? ? ? ? ? ? ?(_OMAP_TIMER_SYS_STAT_OFFSET \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
> -
> -#define OMAP_TIMER_STAT_REG ? ? ? ? ? ? ? ? ? ?(_OMAP_TIMER_STAT_OFFSET \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
> -
> -#define OMAP_TIMER_INT_EN_REG ? ? ? ? ? ? ? ? ?(_OMAP_TIMER_INT_EN_OFFSET \
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | (WP_NONE << WPSHIFT))
> -
> ?#define OMAP_TIMER_WAKEUP_EN_REG ? ? ? ? ? ? ? (_OMAP_TIMER_WAKEUP_EN_OFFSET \
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| (WP_NONE << WPSHIFT))
>
> @@ -213,7 +216,14 @@ struct omap_dm_timer {
> ?#ifdef CONFIG_ARCH_OMAP2PLUS
> ? ? ? ?struct clk *iclk, *fclk;
> ?#endif
> - ? ? ? void __iomem *io_base;
> + ? ? ? void __iomem ? ?*io_base;
> + ? ? ? void __iomem ? ?*sys_stat; ? ? ?/* TISTAT timer status */
> + ? ? ? void __iomem ? ?*irq_stat; ? ? ?/* TISR/IRQSTATUS interrupt status */
> + ? ? ? void __iomem ? ?*irq_ena; ? ? ? /* irq enable */
> + ? ? ? void __iomem ? ?*irq_dis; ? ? ? /* irq disable, only on v2 ip */
> + ? ? ? void __iomem ? ?*pend; ? ? ? ? ?/* write pending */
> + ? ? ? void __iomem ? ?*func_base; ? ? /* function register base */
> +
> ? ? ? ?unsigned long rate;
> ? ? ? ?unsigned reserved:1;
> ? ? ? ?unsigned enabled:1;
> @@ -223,35 +233,57 @@ struct omap_dm_timer {
> ?extern u32 sys_timer_reserved;
> ?void omap_dm_timer_prepare(struct omap_dm_timer *timer);
>
> -static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg,
> +static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int posted)
> ?{
> ? ? ? ?if (posted)
> - ? ? ? ? ? ? ? while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? & (reg >> WPSHIFT))
> + ? ? ? ? ? ? ? while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
> ? ? ? ? ? ? ? ? ? ? ? ?cpu_relax();
>
> - ? ? ? return __raw_readl(base + (reg & 0xff));
> + ? ? ? return __raw_readl(timer->func_base + (reg & 0xff));
> ?}
>
> -static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int posted)
> +static inline void __omap_dm_timer_write(struct omap_dm_timer *timer,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 reg, u32 val, int posted)
> ?{
> ? ? ? ?if (posted)
> - ? ? ? ? ? ? ? while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? & (reg >> WPSHIFT))
> + ? ? ? ? ? ? ? while (__raw_readl(timer->pend) & (reg >> WPSHIFT))
> ? ? ? ? ? ? ? ? ? ? ? ?cpu_relax();
>
> - ? ? ? __raw_writel(val, base + (reg & 0xff));
> + ? ? ? __raw_writel(val, timer->func_base + (reg & 0xff));
> +}
> +
> +static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
> +{
> + ? ? ? u32 tidr;
> +
> + ? ? ? /* Assume v1 ip if bits [31:16] are zero */
> + ? ? ? tidr = __raw_readl(timer->io_base);
> + ? ? ? if (!(tidr >> 16)) {
> + ? ? ? ? ? ? ? timer->sys_stat = timer->io_base + OMAP_TIMER_V1_SYS_STAT_OFFSET;
> + ? ? ? ? ? ? ? timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
> + ? ? ? ? ? ? ? timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
> + ? ? ? ? ? ? ? timer->irq_dis = 0;
> + ? ? ? ? ? ? ? timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
> + ? ? ? ? ? ? ? timer->func_base = timer->io_base;
> + ? ? ? } else {
> + ? ? ? ? ? ? ? timer->sys_stat = 0;
> + ? ? ? ? ? ? ? timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
> + ? ? ? ? ? ? ? timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
> + ? ? ? ? ? ? ? timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
> + ? ? ? ? ? ? ? timer->pend = timer->io_base +
> + ? ? ? ? ? ? ? ? ? ? ? _OMAP_TIMER_WRITE_PEND_OFFSET + OMAP_TIMER_V2_FUNC_OFFSET;
> + ? ? ? ? ? ? ? timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET;
> + ? ? ? }
> ?}
>
> ?/* Assumes the source clock has been set by caller */
> -static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int wakeup)
> +static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int autoidle, int wakeup)
> ?{
> ? ? ? ?u32 l;
>
> - ? ? ? l = __omap_dm_timer_read(base, OMAP_TIMER_OCP_CFG_REG, 0);
> + ? ? ? l = __raw_readl(timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
> ? ? ? ?l |= 0x02 << 3; ?/* Set to smart-idle mode */
> ? ? ? ?l |= 0x2 << 8; ? /* Set clock activity to perserve f-clock on idle */
>
> @@ -261,10 +293,10 @@ static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle,
> ? ? ? ?if (wakeup)
> ? ? ? ? ? ? ? ?l |= 1 << 2;
>
> - ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_OCP_CFG_REG, l, 0);
> + ? ? ? __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
>
> ? ? ? ?/* Match hardware reset default of posted mode */
> - ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_IF_CTRL_REG,
> + ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OMAP_TIMER_CTRL_POSTED, 0);
> ?}
>
> @@ -286,18 +318,18 @@ static inline int __omap_dm_timer_set_source(struct clk *timer_fck,
> ? ? ? ?return ret;
> ?}
>
> -static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long rate)
> +static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int posted, unsigned long rate)
> ?{
> ? ? ? ?u32 l;
>
> - ? ? ? l = __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
> + ? ? ? l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
> ? ? ? ?if (l & OMAP_TIMER_CTRL_ST) {
> ? ? ? ? ? ? ? ?l &= ~0x1;
> - ? ? ? ? ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, l, posted);
> + ? ? ? ? ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted);
> ?#ifdef CONFIG_ARCH_OMAP2PLUS
> ? ? ? ? ? ? ? ?/* Readback to make sure write has completed */
> - ? ? ? ? ? ? ? __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted);
> + ? ? ? ? ? ? ? __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted);
> ? ? ? ? ? ? ? ?/*
> ? ? ? ? ? ? ? ? * Wait for functional clock period x 3.5 to make sure that
> ? ? ? ? ? ? ? ? * timer is stopped
> @@ -307,34 +339,34 @@ static inline void __omap_dm_timer_stop(void __iomem *base, int posted,
> ? ? ? ?}
>
> ? ? ? ?/* Ack possibly pending interrupt */
> - ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OMAP_TIMER_INT_OVERFLOW, 0);
> + ? ? ? __raw_writel(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat);
> ?}
>
> -static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned int load, int posted)
> +static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u32 ctrl, unsigned int load,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int posted)
> ?{
> - ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted);
> - ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, posted);
> + ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted);
> + ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted);
> ?}
>
> -static inline void __omap_dm_timer_int_enable(void __iomem *base,
> +static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned int value)
> ?{
> - ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0);
> - ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
> + ? ? ? __raw_writel(value, timer->irq_ena);
> + ? ? ? __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0);
> ?}
>
> -static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int posted)
> +static inline unsigned int
> +__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted)
> ?{
> - ? ? ? return __omap_dm_timer_read(base, OMAP_TIMER_COUNTER_REG, posted);
> + ? ? ? return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted);
> ?}
>
> -static inline void __omap_dm_timer_write_status(void __iomem *base,
> +static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned int value)
> ?{
> - ? ? ? __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, value, 0);
> + ? ? ? __raw_writel(value, timer->irq_stat);
> ?}
>
> ?#endif /* __ASM_ARCH_DMTIMER_H */
>

^ permalink raw reply

* [PATCH 4/5] ARM: gic: allow irq_start to be 0
From: Russell King - ARM Linux @ 2011-09-18 12:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316017900-19918-5-git-send-email-robherring2@gmail.com>

On Wed, Sep 14, 2011 at 11:31:39AM -0500, Rob Herring wrote:
> From: Rob Herring <rob.herring@calxeda.com>
> 
> There's really no need to set irq_start per platform for the primary gic.
> The SGIs and PPIs are not handled as normal irqs, so how irqs 0-31 are
> setup doesn't really matter. So allow irq_start to be set to 0 to match
> the linux irq numbering.

That's not correct.  The hardware starts numbering SPI IRQs from 32 when
reading the INTACK register.  The number which gets passed through into
asm_do_IRQ() will therefore be from 32 and above.

There's several reasons for this:
1. To avoid IRQ0, which is commonly used to indicate 'no interrupt' to
   drivers.
2. To avoid the ISA IRQ range 1-15 which are hard-coded into various
   drivers (and we want those to fail.)
3. It's wasteful and pointless to manipulate the IRQ number given that we
   have sparse irq support.

Also, bear in mind that gic_irq(SPI0) needs to return 32 to hit the
right registers - so you'd have to set gic->irq_start to -32 to make
SPI0 = IRQ0 work.

Finally, the valid range for irq_start is 16 to 32 + the Linux IRQ base
for the first GIC (SGI) interrupt.  We should probably make gic_init()
BUG() if its passed values less than 16.

^ permalink raw reply

* [PATCH 4/4] net/fec: add imx6q enet support
From: Shawn Guo @ 2011-09-18 11:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316346852-17090-1-git-send-email-shawn.guo@linaro.org>

The imx6q enet is a derivative of imx28 enet controller.  It fixed
the frame endian issue found on imx28, and added 1 Gbps support.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/net/Kconfig |    3 +-
 drivers/net/fec.c   |   59 +++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 8d0314d..fb38962 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1937,8 +1937,7 @@ config DECLANCE
 config FEC
 	bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
 	depends on M523x || M527x || M5272 || M528x || M520x || M532x || \
-		IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC
-	default IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC if ARM
+		ARCH_MXC || ARCH_MXS
 	select PHYLIB
 	help
 	  Say Y here if you want to use the built-in 10/100 Fast ethernet
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 04206e4..849cb0b 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -18,7 +18,7 @@
  * Bug fixes and cleanup by Philippe De Muyter (phdm at macqel.be)
  * Copyright (c) 2004-2006 Macq Electronique SA.
  *
- * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
  */
 
 #include <linux/module.h>
@@ -72,6 +72,10 @@
 #define FEC_QUIRK_SWAP_FRAME		(1 << 1)
 /* Controller uses gasket */
 #define FEC_QUIRK_USE_GASKET		(1 << 2)
+/* Controller has GBIT support */
+#define FEC_QUIRK_HAS_GBIT		(1 << 3)
+/* Controller's phy_speed bit field need to minus one */
+#define FEC_QUIRK_PHY_SPEED_MINUS_ONE	(1 << 4)
 
 static struct platform_device_id fec_devtype[] = {
 	{
@@ -88,6 +92,10 @@ static struct platform_device_id fec_devtype[] = {
 		.name = "imx28-fec",
 		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
 	}, {
+		.name = "imx6q-fec",
+		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+			       FEC_QUIRK_PHY_SPEED_MINUS_ONE,
+	}, {
 		/* sentinel */
 	}
 };
@@ -97,12 +105,14 @@ enum imx_fec_type {
 	IMX25_FEC = 1, 	/* runs on i.mx25/50/53 */
 	IMX27_FEC,	/* runs on i.mx27/35/51 */
 	IMX28_FEC,
+	IMX6Q_FEC,
 };
 
 static const struct of_device_id fec_dt_ids[] = {
 	{ .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },
 	{ .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
 	{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
+	{ .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -373,6 +383,7 @@ fec_restart(struct net_device *ndev, int duplex)
 	int i;
 	u32 temp_mac[2];
 	u32 rcntl = OPT_FRAME_SIZE | 0x04;
+	u32 ecntl = 0x2; /* ETHEREN */
 
 	/* Whack a reset.  We should wait for this. */
 	writel(1, fep->hwp + FEC_ECNTRL);
@@ -442,18 +453,23 @@ fec_restart(struct net_device *ndev, int duplex)
 		/* Enable flow control and length check */
 		rcntl |= 0x40000000 | 0x00000020;
 
-		/* MII or RMII */
+		/* RGMII, RMII or MII */
+		if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII)
+			rcntl |= (1 << 6);
 		if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
 			rcntl |= (1 << 8);
 		else
 			rcntl &= ~(1 << 8);
 
-		/* 10M or 100M */
-		if (fep->phy_dev && fep->phy_dev->speed == SPEED_100)
-			rcntl &= ~(1 << 9);
-		else
-			rcntl |= (1 << 9);
-
+		/* 1G, 100M or 10M */
+		if (fep->phy_dev) {
+			if (fep->phy_dev->speed == SPEED_1000)
+				ecntl |= (1 << 8);
+			else if (fep->phy_dev->speed == SPEED_100)
+				rcntl &= ~(1 << 9);
+			else
+				rcntl |= (1 << 9);
+		}
 	} else {
 #ifdef FEC_MIIGSK_ENR
 		if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
@@ -478,8 +494,15 @@ fec_restart(struct net_device *ndev, int duplex)
 	}
 	writel(rcntl, fep->hwp + FEC_R_CNTRL);
 
+	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+		/* enable ENET endian swap */
+		ecntl |= (1 << 8);
+		/* enable ENET store and forward mode */
+		writel(1 << 8, fep->hwp + FEC_X_WMRK);
+	}
+
 	/* And last, enable the transmit and receive processing */
-	writel(2, fep->hwp + FEC_ECNTRL);
+	writel(ecntl, fep->hwp + FEC_ECNTRL);
 	writel(0, fep->hwp + FEC_R_DES_ACTIVE);
 
 	/* Enable interrupts we wish to service */
@@ -490,6 +513,8 @@ static void
 fec_stop(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	const struct platform_device_id *id_entry =
+				platform_get_device_id(fep->pdev);
 
 	/* We cannot expect a graceful transmit stop without link !!! */
 	if (fep->link) {
@@ -504,6 +529,10 @@ fec_stop(struct net_device *ndev)
 	udelay(10);
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+
+	/* We have to keep ENET enabled to have MII interrupt stay working */
+	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+		writel(2, fep->hwp + FEC_ECNTRL);
 }
 
 
@@ -918,6 +947,8 @@ static int fec_enet_mdio_reset(struct mii_bus *bus)
 static int fec_enet_mii_probe(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	const struct platform_device_id *id_entry =
+				platform_get_device_id(fep->pdev);
 	struct phy_device *phy_dev = NULL;
 	char mdio_bus_id[MII_BUS_ID_SIZE];
 	char phy_name[MII_BUS_ID_SIZE + 3];
@@ -949,14 +980,18 @@ static int fec_enet_mii_probe(struct net_device *ndev)
 
 	snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
 	phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0,
-		PHY_INTERFACE_MODE_MII);
+			      fep->phy_interface);
 	if (IS_ERR(phy_dev)) {
 		printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
 		return PTR_ERR(phy_dev);
 	}
 
 	/* mask with MAC supported features */
-	phy_dev->supported &= PHY_BASIC_FEATURES;
+	if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT)
+		phy_dev->supported &= PHY_GBIT_FEATURES;
+	else
+		phy_dev->supported &= PHY_BASIC_FEATURES;
+
 	phy_dev->advertising = phy_dev->supported;
 
 	fep->phy_dev = phy_dev;
@@ -1008,6 +1043,8 @@ static int fec_enet_mii_init(struct platform_device *pdev)
 	 * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
 	 */
 	fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000);
+	if (id_entry->driver_data & FEC_QUIRK_PHY_SPEED_MINUS_ONE)
+		fep->phy_speed--;
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
 	fep->mii_bus = mdiobus_alloc();
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 3/4] net/fec: set phy_speed to the optimal frequency 2.5 MHz
From: Shawn Guo @ 2011-09-18 11:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316346852-17090-1-git-send-email-shawn.guo@linaro.org>

With the unnecessary 1 bit left-shift on fep->phy_speed during the
calculation, the phy_speed always runs at the half frequency of the
optimal one 2.5 MHz.

The patch removes that 1 bit left-shift to get the optimal phy_speed.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/net/fec.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 5ef0e34..04206e4 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -1007,7 +1007,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
 	/*
 	 * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
 	 */
-	fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1;
+	fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000);
 	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
 	fep->mii_bus = mdiobus_alloc();
-- 
1.7.4.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox