mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-26 05:43:20 +02:00
fc54b9bf15
(stable-branch of Openmoko) git-svn-id: svn://svn.openwrt.org/openwrt/trunk@13613 3c298f89-4303-0410-b956-a3cf2f4a3e73
221 lines
6.7 KiB
Diff
Executable File
221 lines
6.7 KiB
Diff
Executable File
From 26fa0c816d5e1b593128477c7e200fafe3caae18 Mon Sep 17 00:00:00 2001
|
|
From: mokopatches <mokopatches@openmoko.org>
|
|
Date: Fri, 25 Jul 2008 22:21:22 +0100
|
|
Subject: [PATCH] introduce-fiq-use-timer3-as-source.patch
|
|
|
|
This makes the FIQ stuff specific to one of the timers on the
|
|
s3c244x and adds the platform stuff for fiq in the gta02 init
|
|
|
|
Currently one sysfs node is exposed, a count of FIQ events
|
|
|
|
cat /sys/devices/platform/sc32440_fiq.0/fiq/count
|
|
|
|
From: Andy Green <andy@openmoko.com>
|
|
Signed-off-by: Andy Green <andy@openmoko.com>
|
|
---
|
|
arch/arm/mach-s3c2440/fiq_c_isr.c | 56 +++++++++++++++++++++----
|
|
arch/arm/mach-s3c2440/fiq_c_isr.h | 2 +
|
|
arch/arm/mach-s3c2440/mach-gta02.c | 17 ++++++++
|
|
include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h | 2 +-
|
|
4 files changed, 67 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.c b/arch/arm/mach-s3c2440/fiq_c_isr.c
|
|
index 12f4527..a71a234 100644
|
|
--- a/arch/arm/mach-s3c2440/fiq_c_isr.c
|
|
+++ b/arch/arm/mach-s3c2440/fiq_c_isr.c
|
|
@@ -18,6 +18,9 @@
|
|
#include <asm/plat-s3c24xx/cpu.h>
|
|
#include <asm/plat-s3c24xx/irq.h>
|
|
|
|
+#include <asm/arch/pwm.h>
|
|
+#include <asm/plat-s3c/regs-timer.h>
|
|
+
|
|
/*
|
|
* Major Caveats for using FIQ
|
|
* ---------------------------
|
|
@@ -66,6 +69,10 @@ static u8 u8aFiqStack[4096];
|
|
u32 _fiq_ack_mask; /* used by isr exit define */
|
|
unsigned long _fiq_count_fiqs; /* used by isr exit define */
|
|
static int _fiq_irq; /* private ; irq index we were started with, or 0 */
|
|
+struct s3c2410_pwm pwm_timer_fiq;
|
|
+int _fiq_timer_index;
|
|
+u16 _fiq_timer_divisor;
|
|
+
|
|
|
|
/* this function must live in the monolithic kernel somewhere! A module is
|
|
* NOT good enough!
|
|
@@ -110,23 +117,45 @@ static struct attribute_group s3c2440_fiq_attr_group = {
|
|
* you still need to clear the source interrupt in S3C2410_INTMSK to get
|
|
* anything good happening
|
|
*/
|
|
-static void fiq_init_irq_source(int irq_index_fiq)
|
|
+static int fiq_init_irq_source(int irq_index_fiq)
|
|
{
|
|
+ int rc = 0;
|
|
+
|
|
if (!irq_index_fiq) /* no interrupt */
|
|
- return;
|
|
+ goto bail;
|
|
|
|
- printk(KERN_INFO"Enabling FIQ using int idx %d\n",
|
|
- irq_index_fiq - S3C2410_CPUIRQ_OFFSET);
|
|
local_fiq_disable();
|
|
|
|
_fiq_irq = irq_index_fiq;
|
|
_fiq_ack_mask = 1 << (irq_index_fiq - S3C2410_CPUIRQ_OFFSET);
|
|
+ timer_index = (irq_index_fiq - IRQ_TIMER0);
|
|
+
|
|
+ /* set up the timer to operate as a pwm device */
|
|
+
|
|
+ rc = s3c2410_pwm_init(&pwm_timer_fiq);
|
|
+ if (rc)
|
|
+ goto bail;
|
|
+
|
|
+ pwm_timer_fiq.timerid = PWM0 + timer_index;
|
|
+ pwm_timer_fiq.prescaler = (6 - 1) / 2;
|
|
+ pwm_timer_fiq.divider = S3C2410_TCFG1_MUX3_DIV2;
|
|
+ /* default rate == ~32us */
|
|
+ pwm_timer_fiq.counter = pwm_timer_fiq.comparer =
|
|
+ timer_divisor = 64;
|
|
+
|
|
+ rc = s3c2410_pwm_enable(&pwm_timer_fiq);
|
|
+ if (rc)
|
|
+ goto bail;
|
|
+
|
|
+ s3c2410_pwm_start(&pwm_timer_fiq);
|
|
|
|
/* let our selected interrupt be a magic FIQ interrupt */
|
|
__raw_writel(_fiq_ack_mask, S3C2410_INTMOD);
|
|
|
|
/* it's ready to go as soon as we unmask the source in S3C2410_INTMSK */
|
|
local_fiq_enable();
|
|
+bail:
|
|
+ return rc;
|
|
}
|
|
|
|
|
|
@@ -139,15 +168,13 @@ static void fiq_disable_irq_source(void)
|
|
_fiq_irq = 0; /* no active source interrupt now either */
|
|
}
|
|
|
|
-/* this starts FIQ timer events... they continue until the FIQ ISR sees that
|
|
- * its work is done and it turns off the timer. After setting up the fiq_ipc
|
|
- * struct with new work, you call this to start FIQ timer actions up again.
|
|
- * Only the FIQ ISR decides when it is done and controls turning off the
|
|
- * timer events.
|
|
+/*
|
|
+ * fiq_kick() forces a FIQ event to happen shortly after leaving the routine
|
|
*/
|
|
void fiq_kick(void)
|
|
{
|
|
unsigned long flags;
|
|
+ u32 tcon;
|
|
|
|
/* we have to take care about FIQ because this modification is
|
|
* non-atomic, FIQ could come in after the read and before the
|
|
@@ -156,15 +183,24 @@ void fiq_kick(void)
|
|
*/
|
|
local_save_flags(flags);
|
|
local_fiq_disable();
|
|
+ /* allow FIQs to resume */
|
|
__raw_writel(__raw_readl(S3C2410_INTMSK) &
|
|
~(1 << (_fiq_irq - S3C2410_CPUIRQ_OFFSET)),
|
|
S3C2410_INTMSK);
|
|
+ tcon = __raw_readl(S3C2410_TCON) & ~S3C2410_TCON_T3START;
|
|
+ /* fake the timer to a count of 1 */
|
|
+ __raw_writel(1, S3C2410_TCNTB(timer_index));
|
|
+ __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD, S3C2410_TCON);
|
|
+ __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD | S3C2410_TCON_T3START,
|
|
+ S3C2410_TCON);
|
|
+ __raw_writel(tcon | S3C2410_TCON_T3START, S3C2410_TCON);
|
|
local_irq_restore(flags);
|
|
}
|
|
EXPORT_SYMBOL_GPL(fiq_kick);
|
|
|
|
|
|
|
|
+
|
|
static int __init sc32440_fiq_probe(struct platform_device *pdev)
|
|
{
|
|
struct resource *r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
|
@@ -172,6 +208,8 @@ static int __init sc32440_fiq_probe(struct platform_device *pdev)
|
|
if (!r)
|
|
return -EIO;
|
|
/* configure for the interrupt we are meant to use */
|
|
+ printk(KERN_INFO"Enabling FIQ using irq %d\n", r->start);
|
|
+
|
|
fiq_init_irq_source(r->start);
|
|
|
|
return sysfs_create_group(&pdev->dev.kobj, &s3c2440_fiq_attr_group);
|
|
diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.h b/arch/arm/mach-s3c2440/fiq_c_isr.h
|
|
index f08740e..0c45eb7 100644
|
|
--- a/arch/arm/mach-s3c2440/fiq_c_isr.h
|
|
+++ b/arch/arm/mach-s3c2440/fiq_c_isr.h
|
|
@@ -5,6 +5,8 @@
|
|
|
|
extern unsigned long _fiq_count_fiqs;
|
|
extern u32 _fiq_ack_mask;
|
|
+extern int _fiq_timer_index;
|
|
+extern u16 _fiq_timer_divisor;
|
|
|
|
/* This CANNOT be implemented in a module -- it has to be used in code
|
|
* included in the monolithic kernel
|
|
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
|
|
index 0bdd0e0..cb839b2 100644
|
|
--- a/arch/arm/mach-s3c2440/mach-gta02.c
|
|
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
|
|
@@ -57,6 +57,7 @@
|
|
#include <asm/irq.h>
|
|
#include <asm/mach-types.h>
|
|
|
|
+#include <asm/arch-s3c2410/regs-irq.h>
|
|
#include <asm/arch/regs-gpio.h>
|
|
#include <asm/arch/regs-gpioj.h>
|
|
#include <asm/arch/fb.h>
|
|
@@ -336,6 +337,21 @@ struct platform_device gta02_pmu_dev = {
|
|
},
|
|
};
|
|
|
|
+/* FIQ */
|
|
+
|
|
+static struct resource sc32440_fiq_resources[] = {
|
|
+ [0] = {
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ .start = IRQ_TIMER3,
|
|
+ .end = IRQ_TIMER3,
|
|
+ },
|
|
+};
|
|
+
|
|
+struct platform_device sc32440_fiq_device = {
|
|
+ .name = "sc32440_fiq",
|
|
+ .num_resources = 1,
|
|
+ .resource = sc32440_fiq_resources,
|
|
+};
|
|
|
|
/* NOR Flash */
|
|
|
|
@@ -403,6 +419,7 @@ static struct platform_device *gta02_devices[] __initdata = {
|
|
&s3c_device_nand,
|
|
&s3c_device_ts,
|
|
>a02_nor_flash,
|
|
+ &sc32440_fiq_device,
|
|
};
|
|
|
|
static struct s3c2410_nand_set gta02_nand_sets[] = {
|
|
diff --git a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
|
|
index 341f2bb..6cbd8e4 100644
|
|
--- a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
|
|
+++ b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h
|
|
@@ -22,7 +22,7 @@ struct fiq_ipc {
|
|
|
|
/* actual definition lives in arch/arm/mach-s3c2440/fiq_c_isr.c */
|
|
extern struct fiq_ipc fiq_ipc;
|
|
-
|
|
+extern unsigned long _fiq_count_fiqs;
|
|
extern void fiq_kick(void); /* provoke a FIQ "immediately" */
|
|
|
|
#endif /* _LINUX_FIQ_IPC_H */
|
|
--
|
|
1.5.6.3
|
|
|