diff options
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.26/1045-introduce-fiq-basis.patch.patch')
-rwxr-xr-x | target/linux/s3c24xx/patches-2.6.26/1045-introduce-fiq-basis.patch.patch | 587 |
1 files changed, 0 insertions, 587 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.26/1045-introduce-fiq-basis.patch.patch b/target/linux/s3c24xx/patches-2.6.26/1045-introduce-fiq-basis.patch.patch deleted file mode 100755 index 7b79d8ef81..0000000000 --- a/target/linux/s3c24xx/patches-2.6.26/1045-introduce-fiq-basis.patch.patch +++ /dev/null @@ -1,587 +0,0 @@ -From 6a2c7de90f47b7eb74f3cb2d181f950ece22b3fb 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-basis.patch - Adds a C-based FIQ ISR which is very convenient (and unusual -- - normally you have to do FIQ ISR in assembler only). - Based on my article: - -http://warmcat.com/_wp/2007/09/17/at91rm9200-fiq-faq-and-simple-example-code-patch/ - -Implemented as a platform device and driver. - -Suspend / resume is tested and works. - -Signed-off-by: Andy Green <andy@warmcat.com> ---- - arch/arm/mach-s3c2440/Kconfig | 7 + - arch/arm/mach-s3c2440/Makefile | 1 + - arch/arm/mach-s3c2440/fiq_c_isr.c | 250 ++++++++++++++++++++++++++ - arch/arm/mach-s3c2440/fiq_c_isr.h | 64 +++++++ - arch/arm/mach-s3c2440/mach-gta02.c | 22 +++ - arch/arm/plat-s3c24xx/irq.c | 32 +++- - include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h | 28 +++ - include/asm-arm/plat-s3c24xx/irq.h | 20 ++ - 8 files changed, 422 insertions(+), 2 deletions(-) - create mode 100644 arch/arm/mach-s3c2440/fiq_c_isr.c - create mode 100644 arch/arm/mach-s3c2440/fiq_c_isr.h - create mode 100644 include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h - -diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig -index 6b317d1..3015aaf 100644 ---- a/arch/arm/mach-s3c2440/Kconfig -+++ b/arch/arm/mach-s3c2440/Kconfig -@@ -22,6 +22,13 @@ config S3C2440_DMA - help - Support for S3C2440 specific DMA code5A - -+config S3C2440_C_FIQ -+ bool "FIQ ISR support in C" -+ depends on ARCH_S3C2410 -+ select FIQ -+ help -+ Support for S3C2440 FIQ support in C -- see -+ ./arch/arm/macs3c2440/fiq_c_isr.c - - menu "S3C2440 Machines" - -diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile -index 1a4defd..4932232 100644 ---- a/arch/arm/mach-s3c2440/Makefile -+++ b/arch/arm/mach-s3c2440/Makefile -@@ -13,6 +13,7 @@ obj-$(CONFIG_CPU_S3C2440) += s3c2440.o dsc.o - obj-$(CONFIG_CPU_S3C2440) += irq.o - obj-$(CONFIG_CPU_S3C2440) += clock.o - obj-$(CONFIG_S3C2440_DMA) += dma.o -+obj-$(CONFIG_S3C2440_C_FIQ) += fiq_c_isr.o - - # Machine support - -diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.c b/arch/arm/mach-s3c2440/fiq_c_isr.c -new file mode 100644 -index 0000000..12f4527 ---- /dev/null -+++ b/arch/arm/mach-s3c2440/fiq_c_isr.c -@@ -0,0 +1,250 @@ -+/* -+ * Copyright 2007 Andy Green <andy@warmcat.com> -+ * S3C modfifications -+ * Copyright 2008 Andy Green <andy@openmoko.com> -+ */ -+ -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <asm/hardware.h> -+#include <asm/fiq.h> -+#include "fiq_c_isr.h" -+#include <linux/sysfs.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+ -+#include <asm/io.h> -+ -+#include <asm/plat-s3c24xx/cpu.h> -+#include <asm/plat-s3c24xx/irq.h> -+ -+/* -+ * Major Caveats for using FIQ -+ * --------------------------- -+ * -+ * 1) it CANNOT touch any vmalloc()'d memory, only memory -+ * that was kmalloc()'d. Static allocations in the monolithic kernel -+ * are kmalloc()'d so they are okay. You can touch memory-mapped IO, but -+ * the pointer for it has to have been stored in kmalloc'd memory. The -+ * reason for this is simple: every now and then Linux turns off interrupts -+ * and reorders the paging tables. If a FIQ happens during this time, the -+ * virtual memory space can be partly or entirely disordered or missing. -+ * -+ * 2) Because vmalloc() is used when a module is inserted, THIS FIQ -+ * ISR HAS TO BE IN THE MONOLITHIC KERNEL, not a module. But the way -+ * it is set up, you can all to enable and disable it from your module -+ * and intercommunicate with it through struct fiq_ipc -+ * fiq_ipc which you can define in -+ * asm/archfiq_ipc_type.h. The reason is the same as above, a -+ * FIQ could happen while even the ISR is not present in virtual memory -+ * space due to pagetables being changed at the time. -+ * -+ * 3) You can't call any Linux API code except simple macros -+ * - understand that FIQ can come in at any time, no matter what -+ * state of undress the kernel may privately be in, thinking it -+ * locked the door by turning off interrupts... FIQ is an -+ * unstoppable monster force (which is its value) -+ * - they are not vmalloc()'d memory safe -+ * - they might do crazy stuff like sleep: FIQ pisses fire and -+ * is not interested in 'sleep' that the weak seem to need -+ * - calling APIs from FIQ can re-enter un-renterable things -+ * - summary: you cannot interoperate with linux APIs directly in the FIQ ISR -+ * -+ * If you follow these rules, it is fantastic, an extremely powerful, solid, -+ * genuine hard realtime feature. -+ * -+ */ -+ -+/* more than enough to cover our jump instruction to the isr */ -+#define SIZEOF_FIQ_JUMP 8 -+/* more than enough to cover s3c2440_fiq_isr() in 4K blocks */ -+#define SIZEOF_FIQ_ISR 0x2000 -+/* increase the size of the stack that is active during FIQ as needed */ -+static u8 u8aFiqStack[4096]; -+ -+/* only one FIQ ISR possible, okay to do these here */ -+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 */ -+ -+/* this function must live in the monolithic kernel somewhere! A module is -+ * NOT good enough! -+ */ -+extern void __attribute__ ((naked)) s3c2440_fiq_isr(void); -+ -+/* this is copied into the hard FIQ vector during init */ -+ -+static void __attribute__ ((naked)) s3c2440_FIQ_Branch(void) -+{ -+ asm __volatile__ ( -+ "mov pc, r8 ; " -+ ); -+} -+ -+/* sysfs */ -+ -+static ssize_t show_count(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ return sprintf(buf, "%ld\n", _fiq_count_fiqs); -+} -+ -+static DEVICE_ATTR(count, 0444, show_count, NULL); -+ -+static struct attribute *s3c2440_fiq_sysfs_entries[] = { -+ &dev_attr_count.attr, -+ NULL -+}; -+ -+static struct attribute_group s3c2440_fiq_attr_group = { -+ .name = "fiq", -+ .attrs = s3c2440_fiq_sysfs_entries, -+}; -+ -+/* -+ * call this from your kernel module to set up the FIQ ISR to service FIQs, -+ * You need to have configured your FIQ input pin before anything will happen -+ * -+ * call it with, eg, IRQ_TIMER3 from asm-arm/arch-s3c2410/irqs.h -+ * -+ * 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) -+{ -+ if (!irq_index_fiq) /* no interrupt */ -+ return; -+ -+ 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); -+ -+ /* 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(); -+} -+ -+ -+/* call this from your kernel module to disable generation of FIQ actions */ -+static void fiq_disable_irq_source(void) -+{ -+ /* nothing makes FIQ any more */ -+ __raw_writel(0, S3C2410_INTMOD); -+ local_fiq_disable(); -+ _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. -+ */ -+void fiq_kick(void) -+{ -+ unsigned long flags; -+ -+ /* we have to take care about FIQ because this modification is -+ * non-atomic, FIQ could come in after the read and before the -+ * writeback and its changes to the register would be lost -+ * (platform INTMSK mod code is taken care of already) -+ */ -+ local_save_flags(flags); -+ local_fiq_disable(); -+ __raw_writel(__raw_readl(S3C2410_INTMSK) & -+ ~(1 << (_fiq_irq - S3C2410_CPUIRQ_OFFSET)), -+ S3C2410_INTMSK); -+ 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); -+ -+ if (!r) -+ return -EIO; -+ /* configure for the interrupt we are meant to use */ -+ fiq_init_irq_source(r->start); -+ -+ return sysfs_create_group(&pdev->dev.kobj, &s3c2440_fiq_attr_group); -+} -+ -+static int sc32440_fiq_remove(struct platform_device *pdev) -+{ -+ fiq_disable_irq_source(); -+ sysfs_remove_group(&pdev->dev.kobj, &s3c2440_fiq_attr_group); -+ return 0; -+} -+ -+static void fiq_set_vector_and_regs(void) -+{ -+ struct pt_regs regs; -+ -+ /* prep the special FIQ mode regs */ -+ memset(®s, 0, sizeof(regs)); -+ regs.ARM_r8 = (unsigned long)s3c2440_fiq_isr; -+ regs.ARM_sp = (unsigned long)u8aFiqStack + sizeof(u8aFiqStack) - 4; -+ /* set up the special FIQ-mode-only registers from our regs */ -+ set_fiq_regs(®s); -+ /* copy our jump to the real ISR into the hard vector address */ -+ set_fiq_handler(s3c2440_FIQ_Branch, SIZEOF_FIQ_JUMP); -+} -+ -+#ifdef CONFIG_PM -+static int sc32440_fiq_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ /* nothing makes FIQ any more */ -+ __raw_writel(0, S3C2410_INTMOD); -+ local_fiq_disable(); -+ -+ return 0; -+} -+ -+static int sc32440_fiq_resume(struct platform_device *pdev) -+{ -+ fiq_set_vector_and_regs(); -+ fiq_init_irq_source(_fiq_irq); -+ return 0; -+} -+#else -+#define sc32440_fiq_suspend NULL -+#define sc32440_fiq_resume NULL -+#endif -+ -+static struct platform_driver sc32440_fiq_driver = { -+ .driver = { -+ .name = "sc32440_fiq", -+ .owner = THIS_MODULE, -+ }, -+ -+ .probe = sc32440_fiq_probe, -+ .remove = __devexit_p(sc32440_fiq_remove), -+ .suspend = sc32440_fiq_suspend, -+ .resume = sc32440_fiq_resume, -+}; -+ -+static int __init sc32440_fiq_init(void) -+{ -+ fiq_set_vector_and_regs(); -+ -+ return platform_driver_register(&sc32440_fiq_driver); -+} -+ -+static void __exit sc32440_fiq_exit(void) -+{ -+ fiq_disable_irq_source(); -+} -+ -+MODULE_AUTHOR("Andy Green <andy@openmoko.com>"); -+MODULE_LICENSE("GPL"); -+ -+module_init(sc32440_fiq_init); -+module_exit(sc32440_fiq_exit); -diff --git a/arch/arm/mach-s3c2440/fiq_c_isr.h b/arch/arm/mach-s3c2440/fiq_c_isr.h -new file mode 100644 -index 0000000..f08740e ---- /dev/null -+++ b/arch/arm/mach-s3c2440/fiq_c_isr.h -@@ -0,0 +1,64 @@ -+#ifndef _LINUX_FIQ_C_ISR_H -+#define _LINUX_FIQ_C_ISR_H -+ -+#include <asm/arch-s3c2410/regs-irq.h> -+ -+extern unsigned long _fiq_count_fiqs; -+extern u32 _fiq_ack_mask; -+ -+/* This CANNOT be implemented in a module -- it has to be used in code -+ * included in the monolithic kernel -+ */ -+ -+#define FIQ_HANDLER_START() \ -+void __attribute__ ((naked)) s3c2440_fiq_isr(void) \ -+{\ -+ /*\ -+ * you can declare local vars here, take care to set the frame size\ -+ * below accordingly if there are more than a few dozen bytes of them\ -+ */\ -+ -+/* stick your locals here :-) -+ * Do NOT initialize them here! define them and initialize them after -+ * FIQ_HANDLER_ENTRY() is done. -+ */ -+ -+#define FIQ_HANDLER_ENTRY(LOCALS, FRAME) \ -+ const int _FIQ_FRAME_SIZE = FRAME; \ -+ /* entry takes care to store registers we will be treading on here */\ -+ asm __volatile__ (\ -+ "mov ip, sp ;"\ -+ /* stash FIQ and r0-r8 normal regs */\ -+ "stmdb sp!, {r0-r12, lr};"\ -+ /* allow SP to get some space */\ -+ "sub sp, sp, %1 ;"\ -+ /* !! THIS SETS THE FRAME, adjust to > sizeof locals */\ -+ "sub fp, sp, %0 ;"\ -+ :\ -+ : "rI" (LOCALS), "rI" (FRAME)\ -+ :"r9"\ -+ ); -+ -+/* stick your ISR code here and then end with... */ -+ -+#define FIQ_HANDLER_END() \ -+ _fiq_count_fiqs++;\ -+ __raw_writel(_fiq_ack_mask, S3C2410_SRCPND);\ -+\ -+ /* exit back to normal mode restoring everything */\ -+ asm __volatile__ (\ -+ /* pop our allocation */\ -+ "add sp, sp, %0 ;"\ -+ /* return FIQ regs back to pristine state\ -+ * and get normal regs back\ -+ */\ -+ "ldmia sp!, {r0-r12, lr};"\ -+\ -+ /* return */\ -+ "subs pc, lr, #4;"\ -+ : \ -+ : "rI" (_FIQ_FRAME_SIZE) \ -+ );\ -+} -+ -+#endif /* _LINUX_FIQ_C_ISR_H */ -diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c -index 46acede..0bdd0e0 100644 ---- a/arch/arm/mach-s3c2440/mach-gta02.c -+++ b/arch/arm/mach-s3c2440/mach-gta02.c -@@ -78,9 +78,31 @@ - - #include <linux/glamofb.h> - -+#include <asm/arch/fiq_ipc_gta02.h> -+#include "fiq_c_isr.h" -+ - /* arbitrates which sensor IRQ owns the shared SPI bus */ - static spinlock_t motion_irq_lock; - -+/* define FIQ IPC struct */ -+/* -+ * contains stuff FIQ ISR modifies and normal kernel code can see and use -+ * this is defined in <asm/arch/fiq_ipc_gta02.h>, you should customize -+ * the definition in there and include the same definition in your kernel -+ * module that wants to interoperate with your FIQ code. -+ */ -+struct fiq_ipc fiq_ipc; -+EXPORT_SYMBOL(fiq_ipc); -+ -+/* define FIQ ISR */ -+ -+FIQ_HANDLER_START() -+/* define your locals here -- no initializers though */ -+FIQ_HANDLER_ENTRY(256, 512) -+/* Your ISR here :-) */ -+FIQ_HANDLER_END() -+ -+ - static struct map_desc gta02_iodesc[] __initdata = { - { - .virtual = 0xe0000000, -diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c -index ae2c5d7..9887db1 100644 ---- a/arch/arm/plat-s3c24xx/irq.c -+++ b/arch/arm/plat-s3c24xx/irq.c -@@ -133,12 +133,20 @@ static void - s3c_irq_mask(unsigned int irqno) - { - unsigned long mask; -- -+#ifdef CONFIG_S3C2440_C_FIQ -+ unsigned long flags; -+#endif - irqno -= IRQ_EINT0; -- -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_save_flags(flags); -+ local_fiq_disable(); -+#endif - mask = __raw_readl(S3C2410_INTMSK); - mask |= 1UL << irqno; - __raw_writel(mask, S3C2410_INTMSK); -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_irq_restore(flags); -+#endif - } - - static inline void -@@ -155,9 +163,19 @@ s3c_irq_maskack(unsigned int irqno) - { - unsigned long bitval = 1UL << (irqno - IRQ_EINT0); - unsigned long mask; -+#ifdef CONFIG_S3C2440_C_FIQ -+ unsigned long flags; -+#endif - -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_save_flags(flags); -+ local_fiq_disable(); -+#endif - mask = __raw_readl(S3C2410_INTMSK); - __raw_writel(mask|bitval, S3C2410_INTMSK); -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_irq_restore(flags); -+#endif - - __raw_writel(bitval, S3C2410_SRCPND); - __raw_writel(bitval, S3C2410_INTPND); -@@ -168,15 +186,25 @@ static void - s3c_irq_unmask(unsigned int irqno) - { - unsigned long mask; -+#ifdef CONFIG_S3C2440_C_FIQ -+ unsigned long flags; -+#endif - - if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23) - irqdbf2("s3c_irq_unmask %d\n", irqno); - - irqno -= IRQ_EINT0; - -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_save_flags(flags); -+ local_fiq_disable(); -+#endif - mask = __raw_readl(S3C2410_INTMSK); - mask &= ~(1UL << irqno); - __raw_writel(mask, S3C2410_INTMSK); -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_irq_restore(flags); -+#endif - } - - struct irq_chip s3c_irq_level_chip = { -diff --git a/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h -new file mode 100644 -index 0000000..341f2bb ---- /dev/null -+++ b/include/asm-arm/arch-s3c2410/fiq_ipc_gta02.h -@@ -0,0 +1,28 @@ -+#ifndef _LINUX_FIQ_IPC_H -+#define _LINUX_FIQ_IPC_H -+ -+/* -+ * this defines the struct which is used to communicate between the FIQ -+ * world and the normal linux kernel world. One of these structs is -+ * statically defined for you in the monolithic kernel so the FIQ ISR code -+ * can safely touch it any any time. -+ * -+ * You also want to include this file in your kernel module that wants to -+ * communicate with your FIQ code. Add any kinds of vars that are used by -+ * the FIQ ISR and the module in here. -+ * -+ * To get you started there is just an int that is incremented every FIQ -+ * you can remove this when you are ready to customize, but it is useful -+ * for testing -+ */ -+ -+struct fiq_ipc { -+ u8 u8a[0]; /* placeholder */ -+}; -+ -+/* actual definition lives in arch/arm/mach-s3c2440/fiq_c_isr.c */ -+extern struct fiq_ipc fiq_ipc; -+ -+extern void fiq_kick(void); /* provoke a FIQ "immediately" */ -+ -+#endif /* _LINUX_FIQ_IPC_H */ -diff --git a/include/asm-arm/plat-s3c24xx/irq.h b/include/asm-arm/plat-s3c24xx/irq.h -index 45746a9..bf15e1c 100644 ---- a/include/asm-arm/plat-s3c24xx/irq.h -+++ b/include/asm-arm/plat-s3c24xx/irq.h -@@ -25,8 +25,15 @@ s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit, - { - unsigned long mask; - unsigned long submask; -+#ifdef CONFIG_S3C2440_C_FIQ -+ unsigned long flags; -+#endif - - submask = __raw_readl(S3C2410_INTSUBMSK); -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_save_flags(flags); -+ local_fiq_disable(); -+#endif - mask = __raw_readl(S3C2410_INTMSK); - - submask |= (1UL << (irqno - IRQ_S3CUART_RX0)); -@@ -39,6 +46,9 @@ s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit, - - /* write back masks */ - __raw_writel(submask, S3C2410_INTSUBMSK); -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_irq_restore(flags); -+#endif - - } - -@@ -47,8 +57,15 @@ s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit) - { - unsigned long mask; - unsigned long submask; -+#ifdef CONFIG_S3C2440_C_FIQ -+ unsigned long flags; -+#endif - - submask = __raw_readl(S3C2410_INTSUBMSK); -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_save_flags(flags); -+ local_fiq_disable(); -+#endif - mask = __raw_readl(S3C2410_INTMSK); - - submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0)); -@@ -57,6 +74,9 @@ s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit) - /* write back masks */ - __raw_writel(submask, S3C2410_INTSUBMSK); - __raw_writel(mask, S3C2410_INTMSK); -+#ifdef CONFIG_S3C2440_C_FIQ -+ local_irq_restore(flags); -+#endif - } - - --- -1.5.6.3 - |