summaryrefslogtreecommitdiff
path: root/arch/blackfin/mach-common
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/mach-common')
-rw-r--r--arch/blackfin/mach-common/Makefile4
-rw-r--r--arch/blackfin/mach-common/cache-c.c24
-rw-r--r--arch/blackfin/mach-common/cache.S6
-rw-r--r--arch/blackfin/mach-common/clocks-init.c93
-rw-r--r--arch/blackfin/mach-common/cpufreq.c6
-rw-r--r--arch/blackfin/mach-common/dpmc_modes.S3
-rw-r--r--arch/blackfin/mach-common/entry.S132
-rw-r--r--arch/blackfin/mach-common/head.S117
-rw-r--r--arch/blackfin/mach-common/interrupt.S80
-rw-r--r--arch/blackfin/mach-common/ints-priority.c541
-rw-r--r--arch/blackfin/mach-common/irqpanic.c12
-rw-r--r--arch/blackfin/mach-common/lock.S4
-rw-r--r--arch/blackfin/mach-common/pm.c20
-rw-r--r--arch/blackfin/mach-common/smp.c476
14 files changed, 1149 insertions, 369 deletions
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
index e6ed57c56d4b..1f3228ed713f 100644
--- a/arch/blackfin/mach-common/Makefile
+++ b/arch/blackfin/mach-common/Makefile
@@ -3,10 +3,12 @@
#
obj-y := \
- cache.o entry.o head.o \
+ cache.o cache-c.o entry.o head.o \
interrupt.o irqpanic.o arch_checks.o ints-priority.o
obj-$(CONFIG_BFIN_ICACHE_LOCK) += lock.o
obj-$(CONFIG_PM) += pm.o dpmc_modes.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_BFIN_KERNEL_CLOCK) += clocks-init.o
diff --git a/arch/blackfin/mach-common/cache-c.c b/arch/blackfin/mach-common/cache-c.c
new file mode 100644
index 000000000000..e6ab1f815123
--- /dev/null
+++ b/arch/blackfin/mach-common/cache-c.c
@@ -0,0 +1,24 @@
+/*
+ * Blackfin cache control code (simpler control-style functions)
+ *
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <asm/blackfin.h>
+
+/* Invalidate the Entire Data cache by
+ * clearing DMC[1:0] bits
+ */
+void blackfin_invalidate_entire_dcache(void)
+{
+ u32 dmem = bfin_read_DMEM_CONTROL();
+ SSYNC();
+ bfin_write_DMEM_CONTROL(dmem & ~0xc);
+ SSYNC();
+ bfin_write_DMEM_CONTROL(dmem);
+ SSYNC();
+}
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
index a028e9450419..3c98dacbf289 100644
--- a/arch/blackfin/mach-common/cache.S
+++ b/arch/blackfin/mach-common/cache.S
@@ -49,13 +49,17 @@
.ifnb \optflushins
\optflushins [P0];
.endif
+#if ANOMALY_05000443
.ifb \optnopins
2:
.endif
\flushins [P0++];
.ifnb \optnopins
-2: \optnopins;
+2: \optnopins;
.endif
+#else
+2: \flushins [P0++];
+#endif
RTS;
.endm
diff --git a/arch/blackfin/mach-common/clocks-init.c b/arch/blackfin/mach-common/clocks-init.c
new file mode 100644
index 000000000000..5d182abefc7b
--- /dev/null
+++ b/arch/blackfin/mach-common/clocks-init.c
@@ -0,0 +1,93 @@
+/*
+ * arch/blackfin/mach-common/clocks-init.c - reprogram clocks / memory
+ *
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/blackfin.h>
+
+#include <asm/dma.h>
+#include <asm/clocks.h>
+#include <asm/mem_init.h>
+
+#define PLL_CTL_VAL \
+ (((CONFIG_VCO_MULT & 63) << 9) | CLKIN_HALF | \
+ (PLL_BYPASS << 8) | (ANOMALY_05000265 ? 0x8000 : 0))
+
+__attribute__((l1_text))
+static void do_sync(void)
+{
+ __builtin_bfin_ssync();
+}
+
+__attribute__((l1_text))
+void init_clocks(void)
+{
+ /* Kill any active DMAs as they may trigger external memory accesses
+ * in the middle of reprogramming things, and that'll screw us up.
+ * For example, any automatic DMAs left by U-Boot for splash screens.
+ */
+ size_t i;
+ for (i = 0; i < MAX_DMA_CHANNELS; ++i) {
+ struct dma_register *dma = dma_io_base_addr[i];
+ dma->cfg = 0;
+ }
+
+ do_sync();
+
+#ifdef SIC_IWR0
+ bfin_write_SIC_IWR0(IWR_ENABLE(0));
+# ifdef SIC_IWR1
+ /* BF52x system reset does not properly reset SIC_IWR1 which
+ * will screw up the bootrom as it relies on MDMA0/1 waking it
+ * up from IDLE instructions. See this report for more info:
+ * http://blackfin.uclinux.org/gf/tracker/4323
+ */
+ if (ANOMALY_05000435)
+ bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
+ else
+ bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
+# endif
+# ifdef SIC_IWR2
+ bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
+# endif
+#else
+ bfin_write_SIC_IWR(IWR_ENABLE(0));
+#endif
+ do_sync();
+#ifdef EBIU_SDGCTL
+ bfin_write_EBIU_SDGCTL(bfin_read_EBIU_SDGCTL() | SRFS);
+ do_sync();
+#endif
+
+#ifdef CLKBUFOE
+ bfin_write16(VR_CTL, bfin_read_VR_CTL() | CLKBUFOE);
+ do_sync();
+ __asm__ __volatile__("IDLE;");
+#endif
+ bfin_write_PLL_LOCKCNT(0x300);
+ do_sync();
+ bfin_write16(PLL_CTL, PLL_CTL_VAL);
+ __asm__ __volatile__("IDLE;");
+ bfin_write_PLL_DIV(CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+#ifdef EBIU_SDGCTL
+ bfin_write_EBIU_SDRRC(mem_SDRRC);
+ bfin_write_EBIU_SDGCTL(mem_SDGCTL);
+#else
+ bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() & ~(SRREQ));
+ do_sync();
+ bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() | 0x1);
+ bfin_write_EBIU_DDRCTL0(mem_DDRCTL0);
+ bfin_write_EBIU_DDRCTL1(mem_DDRCTL1);
+ bfin_write_EBIU_DDRCTL2(mem_DDRCTL2);
+#ifdef CONFIG_MEM_EBIU_DDRQUE
+ bfin_write_EBIU_DDRQUE(CONFIG_MEM_EBIU_DDRQUE);
+#endif
+#endif
+ do_sync();
+ bfin_read16(0);
+}
diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c
index dda5443b37ed..72e16605ca09 100644
--- a/arch/blackfin/mach-common/cpufreq.c
+++ b/arch/blackfin/mach-common/cpufreq.c
@@ -104,7 +104,7 @@ static int bfin_target(struct cpufreq_policy *policy,
cclk_hz, target_freq, freqs.old);
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- local_irq_save(flags);
+ local_irq_save_hw(flags);
plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
tscale = dpm_state_table[index].tscale;
bfin_write_PLL_DIV(plldiv);
@@ -112,10 +112,10 @@ static int bfin_target(struct cpufreq_policy *policy,
bfin_write_TSCALE(tscale);
cycles = get_cycles();
SSYNC();
- cycles += 10; /* ~10 cycles we loose after get_cycles() */
+ cycles += 10; /* ~10 cycles we lose after get_cycles() */
__bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index);
__bfin_cycles_mod = index;
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
/* TODO: just test case for cycles clock source, remove later */
pr_debug("cpufreq: done\n");
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
diff --git a/arch/blackfin/mach-common/dpmc_modes.S b/arch/blackfin/mach-common/dpmc_modes.S
index ad5431e2cd05..4da50bcd9300 100644
--- a/arch/blackfin/mach-common/dpmc_modes.S
+++ b/arch/blackfin/mach-common/dpmc_modes.S
@@ -247,7 +247,8 @@ ENTRY(_unset_dram_srfs)
ENDPROC(_unset_dram_srfs)
ENTRY(_set_sic_iwr)
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) || \
+ defined(CONFIG_BF538) || defined(CONFIG_BF539) || defined(CONFIG_BF51x)
P0.H = hi(SIC_IWR0);
P0.L = lo(SIC_IWR0);
P1.H = hi(SIC_IWR1);
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index bde6dc4e2614..fae774651374 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -36,6 +36,7 @@
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/unistd.h>
+#include <linux/threads.h>
#include <asm/blackfin.h>
#include <asm/errno.h>
#include <asm/fixed_code.h>
@@ -75,11 +76,11 @@ ENTRY(_ex_workaround_261)
* handle it.
*/
P4 = R7; /* Store EXCAUSE */
- p5.l = _last_cplb_fault_retx;
- p5.h = _last_cplb_fault_retx;
- r7 = [p5];
+
+ GET_PDA(p5, r7);
+ r7 = [p5 + PDA_LFRETX];
r6 = retx;
- [p5] = r6;
+ [p5 + PDA_LFRETX] = r6;
cc = r6 == r7;
if !cc jump _bfin_return_from_exception;
/* fall through */
@@ -111,24 +112,21 @@ ENTRY(_ex_dcplb_viol)
ENTRY(_ex_dcplb_miss)
ENTRY(_ex_icplb_miss)
(R7:6,P5:4) = [sp++];
- ASTAT = [sp++];
- SAVE_ALL_SYS
-#ifdef CONFIG_MPU
+ /* We leave the previously pushed ASTAT on the stack. */
+ SAVE_CONTEXT_CPLB
+
/* We must load R1 here, _before_ DEBUG_HWTRACE_SAVE, since that
* will change the stack pointer. */
R0 = SEQSTAT;
R1 = SP;
-#endif
+
DEBUG_HWTRACE_SAVE(p5, r7)
-#ifdef CONFIG_MPU
+
sp += -12;
call _cplb_hdr;
sp += 12;
CC = R0 == 0;
IF !CC JUMP _handle_bad_cplb;
-#else
- call __cplb_hdr;
-#endif
#ifdef CONFIG_DEBUG_DOUBLEFAULT
/* While we were processing this, did we double fault? */
@@ -142,7 +140,8 @@ ENTRY(_ex_icplb_miss)
#endif
DEBUG_HWTRACE_RESTORE(p5, r7)
- RESTORE_ALL_SYS
+ RESTORE_CONTEXT_CPLB
+ ASTAT = [SP++];
SP = EX_SCRATCH_REG;
rtx;
ENDPROC(_ex_icplb_miss)
@@ -297,9 +296,8 @@ ENTRY(_handle_bad_cplb)
* the stack to get ready so, we can fall through - we
* need to make a CPLB exception look like a normal exception
*/
-
- RESTORE_ALL_SYS
- [--sp] = ASTAT;
+ RESTORE_CONTEXT_CPLB
+ /* ASTAT is still on the stack, where it is needed. */
[--sp] = (R7:6,P5:4);
ENTRY(_ex_replaceable)
@@ -324,7 +322,9 @@ ENTRY(_ex_trap_c)
[p4] = p5;
csync;
+ GET_PDA(p5, r6);
#ifndef CONFIG_DEBUG_DOUBLEFAULT
+
/*
* Save these registers, as they are only valid in exception context
* (where we are now - as soon as we defer to IRQ5, they can change)
@@ -335,29 +335,25 @@ ENTRY(_ex_trap_c)
p4.l = lo(DCPLB_FAULT_ADDR);
p4.h = hi(DCPLB_FAULT_ADDR);
r7 = [p4];
- p5.h = _saved_dcplb_fault_addr;
- p5.l = _saved_dcplb_fault_addr;
- [p5] = r7;
+ [p5 + PDA_DCPLB] = r7;
- r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)];
- p5.h = _saved_icplb_fault_addr;
- p5.l = _saved_icplb_fault_addr;
- [p5] = r7;
+ p4.l = lo(ICPLB_FAULT_ADDR);
+ p4.h = hi(ICPLB_FAULT_ADDR);
+ r6 = [p4];
+ [p5 + PDA_ICPLB] = r6;
r6 = retx;
- p4.l = _saved_retx;
- p4.h = _saved_retx;
- [p4] = r6;
+ [p5 + PDA_RETX] = r6;
#endif
r6 = SYSCFG;
- [p4 + 4] = r6;
+ [p5 + PDA_SYSCFG] = r6;
BITCLR(r6, 0);
SYSCFG = r6;
/* Disable all interrupts, but make sure level 5 is enabled so
* we can switch to that level. Save the old mask. */
cli r6;
- [p4 + 8] = r6;
+ [p5 + PDA_EXIMASK] = r6;
p4.l = lo(SAFE_USER_INSTRUCTION);
p4.h = hi(SAFE_USER_INSTRUCTION);
@@ -371,9 +367,10 @@ ENTRY(_ex_trap_c)
ENDPROC(_ex_trap_c)
/* We just realized we got an exception, while we were processing a different
- * exception. This is a unrecoverable event, so crash
+ * exception. This is a unrecoverable event, so crash.
+ * Note: this cannot be ENTRY() as we jump here with "if cc jump" ...
*/
-ENTRY(_double_fault)
+_double_fault:
/* Turn caches & protection off, to ensure we don't get any more
* double exceptions
*/
@@ -424,17 +421,16 @@ ENDPROC(_double_fault)
ENTRY(_exception_to_level5)
SAVE_ALL_SYS
- p4.l = _saved_retx;
- p4.h = _saved_retx;
- r6 = [p4];
+ GET_PDA(p4, r7); /* Fetch current PDA */
+ r6 = [p4 + PDA_RETX];
[sp + PT_PC] = r6;
- r6 = [p4 + 4];
+ r6 = [p4 + PDA_SYSCFG];
[sp + PT_SYSCFG] = r6;
/* Restore interrupt mask. We haven't pushed RETI, so this
* doesn't enable interrupts until we return from this handler. */
- r6 = [p4 + 8];
+ r6 = [p4 + PDA_EXIMASK];
sti r6;
/* Restore the hardware error vector. */
@@ -478,8 +474,8 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
* scratch register (for want of a better option).
*/
EX_SCRATCH_REG = sp;
- sp.l = _exception_stack_top;
- sp.h = _exception_stack_top;
+ GET_PDA_SAFE(sp);
+ sp = [sp + PDA_EXSTACK]
/* Try to deal with syscalls quickly. */
[--sp] = ASTAT;
[--sp] = (R7:6,P5:4);
@@ -501,27 +497,22 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
* but they are not very interesting, so don't save them
*/
+ GET_PDA(p5, r7);
p4.l = lo(DCPLB_FAULT_ADDR);
p4.h = hi(DCPLB_FAULT_ADDR);
r7 = [p4];
- p5.h = _saved_dcplb_fault_addr;
- p5.l = _saved_dcplb_fault_addr;
- [p5] = r7;
+ [p5 + PDA_DCPLB] = r7;
- r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)];
- p5.h = _saved_icplb_fault_addr;
- p5.l = _saved_icplb_fault_addr;
- [p5] = r7;
+ p4.l = lo(ICPLB_FAULT_ADDR);
+ p4.h = hi(ICPLB_FAULT_ADDR);
+ r7 = [p4];
+ [p5 + PDA_ICPLB] = r7;
- p4.l = _saved_retx;
- p4.h = _saved_retx;
r6 = retx;
- [p4] = r6;
+ [p5 + PDA_RETX] = r6;
r7 = SEQSTAT; /* reason code is in bit 5:0 */
- p4.l = _saved_seqstat;
- p4.h = _saved_seqstat;
- [p4] = r7;
+ [p5 + PDA_SEQSTAT] = r7;
#else
r7 = SEQSTAT; /* reason code is in bit 5:0 */
#endif
@@ -546,11 +537,11 @@ ENTRY(_kernel_execve)
p0 = sp;
r3 = SIZEOF_PTREGS / 4;
r4 = 0(x);
-0:
+.Lclear_regs:
[p0++] = r4;
r3 += -1;
cc = r3 == 0;
- if !cc jump 0b (bp);
+ if !cc jump .Lclear_regs (bp);
p0 = sp;
sp += -16;
@@ -558,7 +549,7 @@ ENTRY(_kernel_execve)
call _do_execve;
SP += 16;
cc = r0 == 0;
- if ! cc jump 1f;
+ if ! cc jump .Lexecve_failed;
/* Success. Copy our temporary pt_regs to the top of the kernel
* stack and do a normal exception return.
*/
@@ -574,12 +565,12 @@ ENTRY(_kernel_execve)
p0 = fp;
r4 = [p0--];
r3 = SIZEOF_PTREGS / 4;
-0:
+.Lcopy_regs:
r4 = [p0--];
[p1--] = r4;
r3 += -1;
cc = r3 == 0;
- if ! cc jump 0b (bp);
+ if ! cc jump .Lcopy_regs (bp);
r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z);
p1 = r0;
@@ -591,7 +582,7 @@ ENTRY(_kernel_execve)
RESTORE_CONTEXT;
rti;
-1:
+.Lexecve_failed:
unlink;
rts;
ENDPROC(_kernel_execve)
@@ -925,9 +916,14 @@ _schedule_and_signal_from_int:
p1 = rets;
[sp + PT_RESERVED] = p1;
- p0.l = _irq_flags;
- p0.h = _irq_flags;
+#ifdef CONFIG_SMP
+ GET_PDA(p0, r0); /* Fetch current PDA (can't migrate to other CPU here) */
+ r0 = [p0 + PDA_IRQFLAGS];
+#else
+ p0.l = _bfin_irq_flags;
+ p0.h = _bfin_irq_flags;
r0 = [p0];
+#endif
sti r0;
r0 = sp;
@@ -1539,14 +1535,18 @@ ENTRY(_sys_call_table)
.endr
END(_sys_call_table)
-_exception_stack:
- .rept 1024
- .long 0;
+#ifdef CONFIG_EXCEPTION_L1_SCRATCH
+/* .section .l1.bss.scratch */
+.set _exception_stack_top, L1_SCRATCH_START + L1_SCRATCH_LENGTH
+#else
+#ifdef CONFIG_SYSCALL_TAB_L1
+.section .l1.bss
+#else
+.bss
+#endif
+ENTRY(_exception_stack)
+ .rept 1024 * NR_CPUS
+ .long 0
.endr
_exception_stack_top:
-
-#if ANOMALY_05000261
-/* Used by the assembly entry point to work around an anomaly. */
-_last_cplb_fault_retx:
- .long 0;
#endif
diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S
index f123a62e2451..e1e42c029e15 100644
--- a/arch/blackfin/mach-common/head.S
+++ b/arch/blackfin/mach-common/head.S
@@ -13,6 +13,7 @@
#include <asm/blackfin.h>
#include <asm/thread_info.h>
#include <asm/trace.h>
+#include <asm/asm-offsets.h>
__INIT
@@ -111,33 +112,26 @@ ENTRY(__start)
* This happens here, since L1 gets clobbered
* below
*/
- p0.l = _saved_retx;
- p0.h = _saved_retx;
+ GET_PDA(p0, r0);
+ r7 = [p0 + PDA_RETX];
p1.l = _init_saved_retx;
p1.h = _init_saved_retx;
- r0 = [p0];
- [p1] = r0;
+ [p1] = r7;
- p0.l = _saved_dcplb_fault_addr;
- p0.h = _saved_dcplb_fault_addr;
+ r7 = [p0 + PDA_DCPLB];
p1.l = _init_saved_dcplb_fault_addr;
p1.h = _init_saved_dcplb_fault_addr;
- r0 = [p0];
- [p1] = r0;
+ [p1] = r7;
- p0.l = _saved_icplb_fault_addr;
- p0.h = _saved_icplb_fault_addr;
+ r7 = [p0 + PDA_ICPLB];
p1.l = _init_saved_icplb_fault_addr;
p1.h = _init_saved_icplb_fault_addr;
- r0 = [p0];
- [p1] = r0;
+ [p1] = r7;
- p0.l = _saved_seqstat;
- p0.h = _saved_seqstat;
+ r7 = [p0 + PDA_SEQSTAT];
p1.l = _init_saved_seqstat;
p1.h = _init_saved_seqstat;
- r0 = [p0];
- [p1] = r0;
+ [p1] = r7;
#endif
/* Initialize stack pointer */
@@ -153,7 +147,7 @@ ENTRY(__start)
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
call _bfin_relocate_l1_mem;
#ifdef CONFIG_BFIN_KERNEL_CLOCK
- call _start_dma_code;
+ call _init_clocks;
#endif
/* This section keeps the processor in supervisor mode
@@ -170,12 +164,8 @@ ENTRY(__start)
[p0] = p1;
csync;
- p0.l = lo(IMASK);
- p0.h = hi(IMASK);
- p1.l = IMASK_IVG15;
- p1.h = 0x0;
- [p0] = p1;
- csync;
+ r0 = EVT_IVG15 (z);
+ sti r0;
raise 15;
p0.l = .LWAIT_HERE;
@@ -195,6 +185,19 @@ ENDPROC(__start)
# define WDOG_CTL WDOGA_CTL
#endif
+ENTRY(__init_clear_bss)
+ r2 = r2 - r1;
+ cc = r2 == 0;
+ if cc jump .L_bss_done;
+ r2 >>= 2;
+ p1 = r1;
+ p2 = r2;
+ lsetup (1f, 1f) lc0 = p2;
+1: [p1++] = r0;
+.L_bss_done:
+ rts;
+ENDPROC(__init_clear_bss)
+
ENTRY(_real_start)
/* Enable nested interrupts */
[--sp] = reti;
@@ -206,87 +209,34 @@ ENTRY(_real_start)
w[p0] = r0;
ssync;
+ r0 = 0 (x);
+ /* Zero out all of the fun bss regions */
#if L1_DATA_A_LENGTH > 0
r1.l = __sbss_l1;
r1.h = __sbss_l1;
r2.l = __ebss_l1;
r2.h = __ebss_l1;
- r0 = 0 (z);
- r2 = r2 - r1;
- cc = r2 == 0;
- if cc jump .L_a_l1_done;
- r2 >>= 2;
- p1 = r1;
- p2 = r2;
- lsetup (.L_clear_a_l1, .L_clear_a_l1 ) lc0 = p2;
-.L_clear_a_l1:
- [p1++] = r0;
-.L_a_l1_done:
+ call __init_clear_bss
#endif
-
#if L1_DATA_B_LENGTH > 0
r1.l = __sbss_b_l1;
r1.h = __sbss_b_l1;
r2.l = __ebss_b_l1;
r2.h = __ebss_b_l1;
- r0 = 0 (z);
- r2 = r2 - r1;
- cc = r2 == 0;
- if cc jump .L_b_l1_done;
- r2 >>= 2;
- p1 = r1;
- p2 = r2;
- lsetup (.L_clear_b_l1, .L_clear_b_l1 ) lc0 = p2;
-.L_clear_b_l1:
- [p1++] = r0;
-.L_b_l1_done:
+ call __init_clear_bss
#endif
-
#if L2_LENGTH > 0
r1.l = __sbss_l2;
r1.h = __sbss_l2;
r2.l = __ebss_l2;
r2.h = __ebss_l2;
- r0 = 0 (z);
- r2 = r2 - r1;
- cc = r2 == 0;
- if cc jump .L_l2_done;
- r2 >>= 2;
- p1 = r1;
- p2 = r2;
- lsetup (.L_clear_l2, .L_clear_l2 ) lc0 = p2;
-.L_clear_l2:
- [p1++] = r0;
-.L_l2_done:
+ call __init_clear_bss
#endif
-
- /* Zero out the bss region
- * Note: this will fail if bss is 0 bytes ...
- */
- r0 = 0 (z);
r1.l = ___bss_start;
r1.h = ___bss_start;
r2.l = ___bss_stop;
r2.h = ___bss_stop;
- r2 = r2 - r1;
- r2 >>= 2;
- p1 = r1;
- p2 = r2;
- lsetup (.L_clear_bss, .L_clear_bss) lc0 = p2;
-.L_clear_bss:
- [p1++] = r0;
-
- /* In case there is a NULL pointer reference,
- * zero out region before stext
- */
- p1 = r0;
- r2.l = __stext;
- r2.h = __stext;
- r2 >>= 2;
- p2 = r2;
- lsetup (.L_clear_zero, .L_clear_zero) lc0 = p2;
-.L_clear_zero:
- [p1++] = r0;
+ call __init_clear_bss
/* Pass the u-boot arguments to the global value command line */
R0 = R7;
@@ -299,6 +249,9 @@ ENTRY(_real_start)
sp = sp + p1;
usp = sp;
fp = sp;
+ sp += -12;
+ call _init_pda
+ sp += 12;
jump.l _start_kernel;
ENDPROC(_real_start)
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
index 4a2ec7a9675a..473df0f7fa78 100644
--- a/arch/blackfin/mach-common/interrupt.S
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -129,8 +129,15 @@ __common_int_entry:
#endif
r1 = sp;
SP += -12;
+#ifdef CONFIG_IPIPE
+ call ___ipipe_grab_irq
+ SP += 12;
+ cc = r0 == 0;
+ if cc jump .Lcommon_restore_context;
+#else /* CONFIG_IPIPE */
call _do_irq;
SP += 12;
+#endif /* CONFIG_IPIPE */
call _return_from_int;
.Lcommon_restore_context:
RESTORE_CONTEXT
@@ -152,15 +159,6 @@ ENTRY(_evt_ivhw)
1:
#endif
-#ifdef CONFIG_HARDWARE_PM
- r7 = [sp + PT_SEQSTAT];
- r7 = r7 >>> 0xe;
- r6 = 0x1F;
- r7 = r7 & r6;
- r5 = 0x12;
- cc = r7 == r5;
- if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */
-#endif
# We are going to dump something out, so make sure we print IPEND properly
p2.l = lo(IPEND);
p2.h = hi(IPEND);
@@ -192,17 +190,6 @@ ENTRY(_evt_ivhw)
.Lcommon_restore_all_sys:
RESTORE_ALL_SYS
rti;
-
-#ifdef CONFIG_HARDWARE_PM
-.Lcall_do_ovf:
-
- SP += -12;
- call _pm_overflow;
- SP += 12;
-
- jump .Lcommon_restore_all_sys;
-#endif
-
ENDPROC(_evt_ivhw)
/* Interrupt routine for evt2 (NMI).
@@ -245,3 +232,56 @@ ENTRY(_evt_system_call)
call _system_call;
jump .Lcommon_restore_context;
ENDPROC(_evt_system_call)
+
+#ifdef CONFIG_IPIPE
+ENTRY(___ipipe_call_irqtail)
+ r0.l = 1f;
+ r0.h = 1f;
+ reti = r0;
+ rti;
+1:
+ [--sp] = rets;
+ [--sp] = ( r7:4, p5:3 );
+ p0.l = ___ipipe_irq_tail_hook;
+ p0.h = ___ipipe_irq_tail_hook;
+ p0 = [p0];
+ sp += -12;
+ call (p0);
+ sp += 12;
+ ( r7:4, p5:3 ) = [sp++];
+ rets = [sp++];
+
+ [--sp] = reti;
+ reti = [sp++]; /* IRQs are off. */
+ r0.h = 3f;
+ r0.l = 3f;
+ p0.l = lo(EVT14);
+ p0.h = hi(EVT14);
+ [p0] = r0;
+ csync;
+ r0 = 0x401f;
+ sti r0;
+ raise 14;
+ [--sp] = reti; /* IRQs on. */
+2:
+ jump 2b; /* Likely paranoid. */
+3:
+ sp += 4; /* Discard saved RETI */
+ r0.h = _evt14_softirq;
+ r0.l = _evt14_softirq;
+ p0.l = lo(EVT14);
+ p0.h = hi(EVT14);
+ [p0] = r0;
+ csync;
+ p0.l = _bfin_irq_flags;
+ p0.h = _bfin_irq_flags;
+ r0 = [p0];
+ sti r0;
+#if 0 /* FIXME: this actually raises scheduling latencies */
+ /* Reenable interrupts */
+ [--sp] = reti;
+ r0 = [sp++];
+#endif
+ rts;
+ENDPROC(___ipipe_call_irqtail)
+#endif /* CONFIG_IPIPE */
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index 34e8a726ffda..1bba6030dce9 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -1,9 +1,6 @@
/*
* File: arch/blackfin/mach-common/ints-priority.c
- * Based on:
- * Author:
*
- * Created: ?
* Description: Set up the interrupt priorities
*
* Modified:
@@ -37,6 +34,9 @@
#include <linux/kernel_stat.h>
#include <linux/seq_file.h>
#include <linux/irq.h>
+#ifdef CONFIG_IPIPE
+#include <linux/ipipe.h>
+#endif
#ifdef CONFIG_KGDB
#include <linux/kgdb.h>
#endif
@@ -45,6 +45,8 @@
#include <asm/gpio.h>
#include <asm/irq_handler.h>
+#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
+
#ifdef BF537_FAMILY
# define BF537_GENERIC_ERROR_INT_DEMUX
#else
@@ -58,13 +60,16 @@
* -
*/
+#ifndef CONFIG_SMP
/* Initialize this to an actual value to force it into the .data
* section so that we know it is properly initialized at entry into
* the kernel but before bss is initialized to zero (which is where
* it would live otherwise). The 0x1f magic represents the IRQs we
* cannot actually mask out in hardware.
*/
-unsigned long irq_flags = 0x1f;
+unsigned long bfin_irq_flags = 0x1f;
+EXPORT_SYMBOL(bfin_irq_flags);
+#endif
/* The number of spurious interrupts */
atomic_t num_spurious;
@@ -103,12 +108,14 @@ static void __init search_IAR(void)
for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
int iar_shift = (irqn & 7) * 4;
if (ivg == (0xf &
-#ifndef CONFIG_BF52x
+#if defined(CONFIG_BF52x) || defined(CONFIG_BF538) \
+ || defined(CONFIG_BF539) || defined(CONFIG_BF51x)
bfin_read32((unsigned long *)SIC_IAR0 +
- (irqn >> 3)) >> iar_shift)) {
+ ((irqn % 32) >> 3) + ((irqn / 32) *
+ ((SIC_IAR4 - SIC_IAR0) / 4))) >> iar_shift)) {
#else
bfin_read32((unsigned long *)SIC_IAR0 +
- ((irqn%32) >> 3) + ((irqn / 32) * 16)) >> iar_shift)) {
+ (irqn >> 3)) >> iar_shift)) {
#endif
ivg_table[irq_pos].irqno = IVG7 + irqn;
ivg_table[irq_pos].isrflag = 1 << (irqn % 32);
@@ -130,25 +137,25 @@ static void bfin_ack_noop(unsigned int irq)
static void bfin_core_mask_irq(unsigned int irq)
{
- irq_flags &= ~(1 << irq);
- if (!irqs_disabled())
- local_irq_enable();
+ bfin_irq_flags &= ~(1 << irq);
+ if (!irqs_disabled_hw())
+ local_irq_enable_hw();
}
static void bfin_core_unmask_irq(unsigned int irq)
{
- irq_flags |= 1 << irq;
+ bfin_irq_flags |= 1 << irq;
/*
* If interrupts are enabled, IMASK must contain the same value
- * as irq_flags. Make sure that invariant holds. If interrupts
+ * as bfin_irq_flags. Make sure that invariant holds. If interrupts
* are currently disabled we need not do anything; one of the
* callers will take care of setting IMASK to the proper value
* when reenabling interrupts.
- * local_irq_enable just does "STI irq_flags", so it's exactly
+ * local_irq_enable just does "STI bfin_irq_flags", so it's exactly
* what we need.
*/
- if (!irqs_disabled())
- local_irq_enable();
+ if (!irqs_disabled_hw())
+ local_irq_enable_hw();
return;
}
@@ -163,8 +170,11 @@ static void bfin_internal_mask_irq(unsigned int irq)
mask_bit = SIC_SYSIRQ(irq) % 32;
bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
~(1 << mask_bit));
+#ifdef CONFIG_SMP
+ bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) &
+ ~(1 << mask_bit));
+#endif
#endif
- SSYNC();
}
static void bfin_internal_unmask_irq(unsigned int irq)
@@ -178,14 +188,17 @@ static void bfin_internal_unmask_irq(unsigned int irq)
mask_bit = SIC_SYSIRQ(irq) % 32;
bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) |
(1 << mask_bit));
+#ifdef CONFIG_SMP
+ bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) |
+ (1 << mask_bit));
+#endif
#endif
- SSYNC();
}
#ifdef CONFIG_PM
int bfin_internal_set_wake(unsigned int irq, unsigned int state)
{
- unsigned bank, bit, wakeup = 0;
+ u32 bank, bit, wakeup = 0;
unsigned long flags;
bank = SIC_SYSIRQ(irq) / 32;
bit = SIC_SYSIRQ(irq) % 32;
@@ -225,7 +238,7 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state)
break;
}
- local_irq_save(flags);
+ local_irq_save_hw(flags);
if (state) {
bfin_sic_iwr[bank] |= (1 << bit);
@@ -236,7 +249,7 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state)
vr_wakeup &= ~wakeup;
}
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
return 0;
}
@@ -262,6 +275,19 @@ static struct irq_chip bfin_internal_irqchip = {
#endif
};
+static void bfin_handle_irq(unsigned irq)
+{
+#ifdef CONFIG_IPIPE
+ struct pt_regs regs; /* Contents not used. */
+ ipipe_trace_irq_entry(irq);
+ __ipipe_handle_irq(irq, &regs);
+ ipipe_trace_irq_exit(irq);
+#else /* !CONFIG_IPIPE */
+ struct irq_desc *desc = irq_desc + irq;
+ desc->handle_irq(irq, desc);
+#endif /* !CONFIG_IPIPE */
+}
+
#ifdef BF537_GENERIC_ERROR_INT_DEMUX
static int error_int_mask;
@@ -292,8 +318,6 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
{
int irq = 0;
- SSYNC();
-
#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
irq = IRQ_MAC_ERROR;
@@ -317,10 +341,9 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
irq = IRQ_UART1_ERROR;
if (irq) {
- if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR))) {
- struct irq_desc *desc = irq_desc + irq;
- desc->handle_irq(irq, desc);
- } else {
+ if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
+ bfin_handle_irq(irq);
+ else {
switch (irq) {
case IRQ_PPI_ERROR:
@@ -366,62 +389,57 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
{
+#ifdef CONFIG_IPIPE
+ _set_irq_handler(irq, handle_edge_irq);
+#else
struct irq_desc *desc = irq_desc + irq;
/* May not call generic set_irq_handler() due to spinlock
recursion. */
desc->handle_irq = handle;
+#endif
}
-#if !defined(CONFIG_BF54x)
-
-static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
-static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
-
+static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS);
extern void bfin_gpio_irq_prepare(unsigned gpio);
+#if !defined(CONFIG_BF54x)
+
static void bfin_gpio_ack_irq(unsigned int irq)
{
- u16 gpionr = irq - IRQ_PF0;
-
- if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
- set_gpio_data(gpionr, 0);
- SSYNC();
- }
+ /* AFAIK ack_irq in case mask_ack is provided
+ * get's only called for edge sense irqs
+ */
+ set_gpio_data(irq_to_gpio(irq), 0);
}
static void bfin_gpio_mask_ack_irq(unsigned int irq)
{
- u16 gpionr = irq - IRQ_PF0;
+ struct irq_desc *desc = irq_desc + irq;
+ u32 gpionr = irq_to_gpio(irq);
- if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+ if (desc->handle_irq == handle_edge_irq)
set_gpio_data(gpionr, 0);
- SSYNC();
- }
set_gpio_maska(gpionr, 0);
- SSYNC();
}
static void bfin_gpio_mask_irq(unsigned int irq)
{
- set_gpio_maska(irq - IRQ_PF0, 0);
- SSYNC();
+ set_gpio_maska(irq_to_gpio(irq), 0);
}
static void bfin_gpio_unmask_irq(unsigned int irq)
{
- set_gpio_maska(irq - IRQ_PF0, 1);
- SSYNC();
+ set_gpio_maska(irq_to_gpio(irq), 1);
}
static unsigned int bfin_gpio_irq_startup(unsigned int irq)
{
- u16 gpionr = irq - IRQ_PF0;
+ u32 gpionr = irq_to_gpio(irq);
- if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+ if (__test_and_set_bit(gpionr, gpio_enabled))
bfin_gpio_irq_prepare(gpionr);
- gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
bfin_gpio_unmask_irq(irq);
return 0;
@@ -429,29 +447,39 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
static void bfin_gpio_irq_shutdown(unsigned int irq)
{
+ u32 gpionr = irq_to_gpio(irq);
+
bfin_gpio_mask_irq(irq);
- gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0);
+ __clear_bit(gpionr, gpio_enabled);
+ bfin_gpio_irq_free(gpionr);
}
static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
{
- u16 gpionr = irq - IRQ_PF0;
+ int ret;
+ char buf[16];
+ u32 gpionr = irq_to_gpio(irq);
if (type == IRQ_TYPE_PROBE) {
/* only probe unenabled GPIO interrupt lines */
- if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))
+ if (__test_bit(gpionr, gpio_enabled))
return 0;
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
}
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+
+ snprintf(buf, 16, "gpio-irq%d", irq);
+ ret = bfin_gpio_irq_request(gpionr, buf);
+ if (ret)
+ return ret;
+
+ if (__test_and_set_bit(gpionr, gpio_enabled))
bfin_gpio_irq_prepare(gpionr);
- gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
} else {
- gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ __clear_bit(gpionr, gpio_enabled);
return 0;
}
@@ -472,17 +500,13 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
set_gpio_edge(gpionr, 1);
set_gpio_inen(gpionr, 1);
- gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr);
set_gpio_data(gpionr, 0);
} else {
set_gpio_edge(gpionr, 0);
- gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
set_gpio_inen(gpionr, 1);
}
- SSYNC();
-
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
bfin_set_irq_handler(irq, handle_edge_irq);
else
@@ -505,22 +529,6 @@ int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
}
#endif
-static struct irq_chip bfin_gpio_irqchip = {
- .name = "GPIO",
- .ack = bfin_gpio_ack_irq,
- .mask = bfin_gpio_mask_irq,
- .mask_ack = bfin_gpio_mask_ack_irq,
- .unmask = bfin_gpio_unmask_irq,
- .disable = bfin_gpio_mask_irq,
- .enable = bfin_gpio_unmask_irq,
- .set_type = bfin_gpio_irq_type,
- .startup = bfin_gpio_irq_startup,
- .shutdown = bfin_gpio_irq_shutdown,
-#ifdef CONFIG_PM
- .set_wake = bfin_gpio_set_wake,
-#endif
-};
-
static void bfin_demux_gpio_irq(unsigned int inta_irq,
struct irq_desc *desc)
{
@@ -537,7 +545,11 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
irq = IRQ_PH0;
break;
# endif
-#elif defined(CONFIG_BF52x)
+#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
+ case IRQ_PORTF_INTA:
+ irq = IRQ_PF0;
+ break;
+#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
case IRQ_PORTF_INTA:
irq = IRQ_PF0;
break;
@@ -567,30 +579,22 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
irq += i;
- mask = get_gpiop_data(i) &
- (gpio_enabled[gpio_bank(i)] &
- get_gpiop_maska(i));
+ mask = get_gpiop_data(i) & get_gpiop_maska(i);
while (mask) {
- if (mask & 1) {
- desc = irq_desc + irq;
- desc->handle_irq(irq, desc);
- }
+ if (mask & 1)
+ bfin_handle_irq(irq);
irq++;
mask >>= 1;
}
}
} else {
gpio = irq_to_gpio(irq);
- mask = get_gpiop_data(gpio) &
- (gpio_enabled[gpio_bank(gpio)] &
- get_gpiop_maska(gpio));
+ mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
do {
- if (mask & 1) {
- desc = irq_desc + irq;
- desc->handle_irq(irq, desc);
- }
+ if (mask & 1)
+ bfin_handle_irq(irq);
irq++;
mask >>= 1;
} while (mask);
@@ -612,10 +616,6 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
static unsigned char irq2pint_lut[NR_PINTS];
static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
-static unsigned int gpio_both_edge_triggered[NR_PINT_SYS_IRQS];
-static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
-
-
struct pin_int_t {
unsigned int mask_set;
unsigned int mask_clear;
@@ -636,12 +636,9 @@ static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = {
(struct pin_int_t *)PINT3_MASK_SET,
};
-extern void bfin_gpio_irq_prepare(unsigned gpio);
-
-inline unsigned short get_irq_base(u8 bank, u8 bmap)
+inline unsigned int get_irq_base(u32 bank, u8 bmap)
{
-
- u16 irq_base;
+ unsigned int irq_base;
if (bank < 2) { /*PA-PB */
irq_base = IRQ_PA0 + bmap * 16;
@@ -650,7 +647,6 @@ inline unsigned short get_irq_base(u8 bank, u8 bmap)
}
return irq_base;
-
}
/* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
@@ -677,20 +673,18 @@ void init_pint_lut(void)
pint2irq_lut[bit_pos] = irq_base - SYS_IRQS;
irq2pint_lut[irq_base - SYS_IRQS] = bit_pos;
-
}
-
}
-
}
static void bfin_gpio_ack_irq(unsigned int irq)
{
- u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ struct irq_desc *desc = irq_desc + irq;
+ u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
u32 pintbit = PINT_BIT(pint_val);
- u8 bank = PINT_2_BANK(pint_val);
+ u32 bank = PINT_2_BANK(pint_val);
- if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
+ if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
if (pint[bank]->invert_set & pintbit)
pint[bank]->invert_clear = pintbit;
else
@@ -698,16 +692,16 @@ static void bfin_gpio_ack_irq(unsigned int irq)
}
pint[bank]->request = pintbit;
- SSYNC();
}
static void bfin_gpio_mask_ack_irq(unsigned int irq)
{
- u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ struct irq_desc *desc = irq_desc + irq;
+ u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
u32 pintbit = PINT_BIT(pint_val);
- u8 bank = PINT_2_BANK(pint_val);
+ u32 bank = PINT_2_BANK(pint_val);
- if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
+ if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
if (pint[bank]->invert_set & pintbit)
pint[bank]->invert_clear = pintbit;
else
@@ -716,32 +710,29 @@ static void bfin_gpio_mask_ack_irq(unsigned int irq)
pint[bank]->request = pintbit;
pint[bank]->mask_clear = pintbit;
- SSYNC();
}
static void bfin_gpio_mask_irq(unsigned int irq)
{
- u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val);
- SSYNC();
}
static void bfin_gpio_unmask_irq(unsigned int irq)
{
- u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
u32 pintbit = PINT_BIT(pint_val);
- u8 bank = PINT_2_BANK(pint_val);
+ u32 bank = PINT_2_BANK(pint_val);
pint[bank]->request = pintbit;
pint[bank]->mask_set = pintbit;
- SSYNC();
}
static unsigned int bfin_gpio_irq_startup(unsigned int irq)
{
- u16 gpionr = irq_to_gpio(irq);
- u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ u32 gpionr = irq_to_gpio(irq);
+ u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
if (pint_val == IRQ_NOT_AVAIL) {
printk(KERN_ERR
@@ -750,10 +741,9 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
return -ENODEV;
}
- if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+ if (__test_and_set_bit(gpionr, gpio_enabled))
bfin_gpio_irq_prepare(gpionr);
- gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
bfin_gpio_unmask_irq(irq);
return 0;
@@ -761,38 +751,45 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
static void bfin_gpio_irq_shutdown(unsigned int irq)
{
- u16 gpionr = irq_to_gpio(irq);
+ u32 gpionr = irq_to_gpio(irq);
bfin_gpio_mask_irq(irq);
- gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ __clear_bit(gpionr, gpio_enabled);
+ bfin_gpio_irq_free(gpionr);
}
static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
{
-
- u16 gpionr = irq_to_gpio(irq);
- u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ int ret;
+ char buf[16];
+ u32 gpionr = irq_to_gpio(irq);
+ u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
u32 pintbit = PINT_BIT(pint_val);
- u8 bank = PINT_2_BANK(pint_val);
+ u32 bank = PINT_2_BANK(pint_val);
if (pint_val == IRQ_NOT_AVAIL)
return -ENODEV;
if (type == IRQ_TYPE_PROBE) {
/* only probe unenabled GPIO interrupt lines */
- if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))
+ if (__test_bit(gpionr, gpio_enabled))
return 0;
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
}
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+
+ snprintf(buf, 16, "gpio-irq%d", irq);
+ ret = bfin_gpio_irq_request(gpionr, buf);
+ if (ret)
+ return ret;
+
+ if (__test_and_set_bit(gpionr, gpio_enabled))
bfin_gpio_irq_prepare(gpionr);
- gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
} else {
- gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ __clear_bit(gpionr, gpio_enabled);
return 0;
}
@@ -803,15 +800,10 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
== (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
-
- gpio_both_edge_triggered[bank] |= pintbit;
-
if (gpio_get_value(gpionr))
pint[bank]->invert_set = pintbit;
else
pint[bank]->invert_clear = pintbit;
- } else {
- gpio_both_edge_triggered[bank] &= ~pintbit;
}
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
@@ -822,8 +814,6 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
bfin_set_irq_handler(irq, handle_level_irq);
}
- SSYNC();
-
return 0;
}
@@ -834,7 +824,7 @@ u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
{
u32 pint_irq;
- u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
u32 bank = PINT_2_BANK(pint_val);
u32 pintbit = PINT_BIT(pint_val);
@@ -895,26 +885,10 @@ void bfin_pm_restore(void)
}
#endif
-static struct irq_chip bfin_gpio_irqchip = {
- .name = "GPIO",
- .ack = bfin_gpio_ack_irq,
- .mask = bfin_gpio_mask_irq,
- .mask_ack = bfin_gpio_mask_ack_irq,
- .unmask = bfin_gpio_unmask_irq,
- .disable = bfin_gpio_mask_irq,
- .enable = bfin_gpio_unmask_irq,
- .set_type = bfin_gpio_irq_type,
- .startup = bfin_gpio_irq_startup,
- .shutdown = bfin_gpio_irq_shutdown,
-#ifdef CONFIG_PM
- .set_wake = bfin_gpio_set_wake,
-#endif
-};
-
static void bfin_demux_gpio_irq(unsigned int inta_irq,
struct irq_desc *desc)
{
- u8 bank, pint_val;
+ u32 bank, pint_val;
u32 request, irq;
switch (inta_irq) {
@@ -941,8 +915,7 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
while (request) {
if (request & 1) {
irq = pint2irq_lut[pint_val] + SYS_IRQS;
- desc = irq_desc + irq;
- desc->handle_irq(irq, desc);
+ bfin_handle_irq(irq);
}
pint_val++;
request >>= 1;
@@ -951,10 +924,24 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
}
#endif
-void __init init_exception_vectors(void)
-{
- SSYNC();
+static struct irq_chip bfin_gpio_irqchip = {
+ .name = "GPIO",
+ .ack = bfin_gpio_ack_irq,
+ .mask = bfin_gpio_mask_irq,
+ .mask_ack = bfin_gpio_mask_ack_irq,
+ .unmask = bfin_gpio_unmask_irq,
+ .disable = bfin_gpio_mask_irq,
+ .enable = bfin_gpio_unmask_irq,
+ .set_type = bfin_gpio_irq_type,
+ .startup = bfin_gpio_irq_startup,
+ .shutdown = bfin_gpio_irq_shutdown,
+#ifdef CONFIG_PM
+ .set_wake = bfin_gpio_set_wake,
+#endif
+};
+void __cpuinit init_exception_vectors(void)
+{
/* cannot program in software:
* evt0 - emulation (jtag)
* evt1 - reset
@@ -979,17 +966,23 @@ void __init init_exception_vectors(void)
* This function should be called during kernel startup to initialize
* the BFin IRQ handling routines.
*/
+
int __init init_arch_irq(void)
{
int irq;
unsigned long ilat = 0;
/* Disable all the peripheral intrs - page 4-29 HW Ref manual */
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
+ || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
# ifdef CONFIG_BF54x
bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
# endif
+# ifdef CONFIG_SMP
+ bfin_write_SICB_IMASK0(SIC_UNMASK_ALL);
+ bfin_write_SICB_IMASK1(SIC_UNMASK_ALL);
+# endif
#else
bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
#endif
@@ -1029,7 +1022,7 @@ int __init init_arch_irq(void)
case IRQ_PINT1:
case IRQ_PINT2:
case IRQ_PINT3:
-#elif defined(CONFIG_BF52x)
+#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
case IRQ_PORTF_INTA:
case IRQ_PORTG_INTA:
case IRQ_PORTH_INTA:
@@ -1037,18 +1030,41 @@ int __init init_arch_irq(void)
case IRQ_PROG0_INTA:
case IRQ_PROG1_INTA:
case IRQ_PROG2_INTA:
+#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
+ case IRQ_PORTF_INTA:
#endif
+
set_irq_chained_handler(irq,
bfin_demux_gpio_irq);
break;
#ifdef BF537_GENERIC_ERROR_INT_DEMUX
case IRQ_GENERIC_ERROR:
- set_irq_handler(irq, bfin_demux_error_irq);
-
+ set_irq_chained_handler(irq, bfin_demux_error_irq);
+ break;
+#endif
+#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+ case IRQ_TIMER0:
+ set_irq_handler(irq, handle_percpu_irq);
+ break;
+#endif
+#ifdef CONFIG_SMP
+ case IRQ_SUPPLE_0:
+ case IRQ_SUPPLE_1:
+ set_irq_handler(irq, handle_percpu_irq);
break;
#endif
default:
+#ifdef CONFIG_IPIPE
+ /*
+ * We want internal interrupt sources to be masked, because
+ * ISRs may trigger interrupts recursively (e.g. DMA), but
+ * interrupts are _not_ masked at CPU level. So let's handle
+ * them as level interrupts.
+ */
+ set_irq_handler(irq, handle_level_irq);
+#else /* !CONFIG_IPIPE */
set_irq_handler(irq, handle_simple_irq);
+#endif /* !CONFIG_IPIPE */
break;
}
}
@@ -1073,7 +1089,7 @@ int __init init_arch_irq(void)
CSYNC();
printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
- /* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
+ /* IMASK=xxx is equivalent to STI xx or bfin_irq_flags=xx,
* local_irq_enable()
*/
program_IAR();
@@ -1081,19 +1097,23 @@ int __init init_arch_irq(void)
search_IAR();
/* Enable interrupts IVG7-15 */
- irq_flags = irq_flags | IMASK_IVG15 |
+ bfin_irq_flags |= IMASK_IVG15 |
IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
+ || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
-#if defined(CONFIG_BF52x)
- /* BF52x system reset does not properly reset SIC_IWR1 which
+#if defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
+ /* BF52x/BF51x system reset does not properly reset SIC_IWR1 which
* will screw up the bootrom as it relies on MDMA0/1 waking it
* up from IDLE instructions. See this report for more info:
* http://blackfin.uclinux.org/gf/tracker/4323
*/
- bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
+ if (ANOMALY_05000435)
+ bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
+ else
+ bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
#else
bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
#endif
@@ -1104,6 +1124,14 @@ int __init init_arch_irq(void)
bfin_write_SIC_IWR(IWR_DISABLE_ALL);
#endif
+#ifdef CONFIG_IPIPE
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ struct irq_desc *desc = irq_desc + irq;
+ desc->ic_prio = __ipipe_get_irq_priority(irq);
+ desc->thr_prio = __ipipe_get_irqthread_priority(irq);
+ }
+#endif /* CONFIG_IPIPE */
+
return 0;
}
@@ -1117,11 +1145,20 @@ void do_irq(int vec, struct pt_regs *fp)
} else {
struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
+ || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
unsigned long sic_status[3];
- sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
- sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
+ if (smp_processor_id()) {
+#ifdef CONFIG_SMP
+ /* This will be optimized out in UP mode. */
+ sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
+ sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
+#endif
+ } else {
+ sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
+ sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
+ }
#ifdef CONFIG_BF54x
sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
#endif
@@ -1150,3 +1187,161 @@ void do_irq(int vec, struct pt_regs *fp)
}
asm_do_IRQ(vec, fp);
}
+
+#ifdef CONFIG_IPIPE
+
+int __ipipe_get_irq_priority(unsigned irq)
+{
+ int ient, prio;
+
+ if (irq <= IRQ_CORETMR)
+ return irq;
+
+ for (ient = 0; ient < NR_PERI_INTS; ient++) {
+ struct ivgx *ivg = ivg_table + ient;
+ if (ivg->irqno == irq) {
+ for (prio = 0; prio <= IVG13-IVG7; prio++) {
+ if (ivg7_13[prio].ifirst <= ivg &&
+ ivg7_13[prio].istop > ivg)
+ return IVG7 + prio;
+ }
+ }
+ }
+
+ return IVG15;
+}
+
+int __ipipe_get_irqthread_priority(unsigned irq)
+{
+ int ient, prio;
+ int demux_irq;
+
+ /* The returned priority value is rescaled to [0..IVG13+1]
+ * with 0 being the lowest effective priority level. */
+
+ if (irq <= IRQ_CORETMR)
+ return IVG13 - irq + 1;
+
+ /* GPIO IRQs are given the priority of the demux
+ * interrupt. */
+ if (IS_GPIOIRQ(irq)) {
+#if defined(CONFIG_BF54x)
+ u32 bank = PINT_2_BANK(irq2pint_lut[irq - SYS_IRQS]);
+ demux_irq = (bank == 0 ? IRQ_PINT0 :
+ bank == 1 ? IRQ_PINT1 :
+ bank == 2 ? IRQ_PINT2 :
+ IRQ_PINT3);
+#elif defined(CONFIG_BF561)
+ demux_irq = (irq >= IRQ_PF32 ? IRQ_PROG2_INTA :
+ irq >= IRQ_PF16 ? IRQ_PROG1_INTA :
+ IRQ_PROG0_INTA);
+#elif defined(CONFIG_BF52x)
+ demux_irq = (irq >= IRQ_PH0 ? IRQ_PORTH_INTA :
+ irq >= IRQ_PG0 ? IRQ_PORTG_INTA :
+ IRQ_PORTF_INTA);
+#else
+ demux_irq = irq;
+#endif
+ return IVG13 - PRIO_GPIODEMUX(demux_irq) + 1;
+ }
+
+ /* The GPIO demux interrupt is given a lower priority
+ * than the GPIO IRQs, so that its threaded handler
+ * unmasks the interrupt line after the decoded IRQs
+ * have been processed. */
+ prio = PRIO_GPIODEMUX(irq);
+ /* demux irq? */
+ if (prio != -1)
+ return IVG13 - prio;
+
+ for (ient = 0; ient < NR_PERI_INTS; ient++) {
+ struct ivgx *ivg = ivg_table + ient;
+ if (ivg->irqno == irq) {
+ for (prio = 0; prio <= IVG13-IVG7; prio++) {
+ if (ivg7_13[prio].ifirst <= ivg &&
+ ivg7_13[prio].istop > ivg)
+ return IVG7 - prio;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Hw interrupts are disabled on entry (check SAVE_CONTEXT). */
+#ifdef CONFIG_DO_IRQ_L1
+__attribute__((l1_text))
+#endif
+asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
+{
+ struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop;
+ struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
+ int irq;
+
+ if (likely(vec == EVT_IVTMR_P)) {
+ irq = IRQ_CORETMR;
+ goto handle_irq;
+ }
+
+ SSYNC();
+
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
+ {
+ unsigned long sic_status[3];
+
+ sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
+ sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
+#ifdef CONFIG_BF54x
+ sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
+#endif
+ for (;; ivg++) {
+ if (ivg >= ivg_stop) {
+ atomic_inc(&num_spurious);
+ return 0;
+ }
+ if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
+ break;
+ }
+ }
+#else
+ {
+ unsigned long sic_status;
+
+ sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
+
+ for (;; ivg++) {
+ if (ivg >= ivg_stop) {
+ atomic_inc(&num_spurious);
+ return 0;
+ } else if (sic_status & ivg->isrflag)
+ break;
+ }
+ }
+#endif
+
+ irq = ivg->irqno;
+
+ if (irq == IRQ_SYSTMR) {
+ bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */
+ /* This is basically what we need from the register frame. */
+ __raw_get_cpu_var(__ipipe_tick_regs).ipend = regs->ipend;
+ __raw_get_cpu_var(__ipipe_tick_regs).pc = regs->pc;
+ if (!ipipe_root_domain_p)
+ __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
+ else
+ __raw_get_cpu_var(__ipipe_tick_regs).ipend &= ~0x10;
+ }
+
+handle_irq:
+
+ ipipe_trace_irq_entry(irq);
+ __ipipe_handle_irq(irq, regs);
+ ipipe_trace_irq_exit(irq);
+
+ if (ipipe_root_domain_p)
+ return !test_bit(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status));
+
+ return 0;
+}
+
+#endif /* CONFIG_IPIPE */
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
index 606ded9ff4e1..05004df0f78b 100644
--- a/arch/blackfin/mach-common/irqpanic.c
+++ b/arch/blackfin/mach-common/irqpanic.c
@@ -33,8 +33,6 @@
#include <asm/traps.h>
#include <asm/blackfin.h>
-#include "../oprofile/op_blackfin.h"
-
#ifdef CONFIG_DEBUG_ICACHE_CHECK
#define L1_ICACHE_START 0xffa10000
#define L1_ICACHE_END 0xffa13fff
@@ -134,13 +132,3 @@ asmlinkage void irq_panic(int reason, struct pt_regs *regs)
#endif
}
-
-#ifdef CONFIG_HARDWARE_PM
-/*
- * call the handler of Performance overflow
- */
-asmlinkage void pm_overflow(int irq, struct pt_regs *regs)
-{
- pm_overflow_handler(irq, regs);
-}
-#endif
diff --git a/arch/blackfin/mach-common/lock.S b/arch/blackfin/mach-common/lock.S
index 9daf01201e9f..6c5f5f0ea7fe 100644
--- a/arch/blackfin/mach-common/lock.S
+++ b/arch/blackfin/mach-common/lock.S
@@ -160,7 +160,7 @@ ENDPROC(_cache_grab_lock)
* R0 - Which way to be locked
*/
-ENTRY(_cache_lock)
+ENTRY(_bfin_cache_lock)
[--SP]=( R7:0,P5:0 );
@@ -184,7 +184,7 @@ ENTRY(_cache_lock)
( R7:0,P5:0 ) = [SP++];
RTS;
-ENDPROC(_cache_lock)
+ENDPROC(_bfin_cache_lock)
/* Invalidate the Entire Instruction cache by
* disabling IMC bit
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
index e28c6af1f415..d3d70fd67c16 100644
--- a/arch/blackfin/mach-common/pm.c
+++ b/arch/blackfin/mach-common/pm.c
@@ -71,7 +71,7 @@ void bfin_pm_suspend_standby_enter(void)
gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE);
#endif
- local_irq_save(flags);
+ local_irq_save_hw(flags);
bfin_pm_standby_setup();
#ifdef CONFIG_PM_BFIN_SLEEP_DEEPER
@@ -82,15 +82,19 @@ void bfin_pm_suspend_standby_enter(void)
bfin_pm_standby_restore();
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) || \
+ defined(CONFIG_BF538) || defined(CONFIG_BF539) || defined(CONFIG_BF51x)
bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
-#if defined(CONFIG_BF52x)
+#if defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
/* BF52x system reset does not properly reset SIC_IWR1 which
* will screw up the bootrom as it relies on MDMA0/1 waking it
* up from IDLE instructions. See this report for more info:
* http://blackfin.uclinux.org/gf/tracker/4323
*/
- bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
+ if (ANOMALY_05000435)
+ bfin_write_SIC_IWR1(IWR_ENABLE(10) | IWR_ENABLE(11));
+ else
+ bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
#else
bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
#endif
@@ -101,7 +105,7 @@ void bfin_pm_suspend_standby_enter(void)
bfin_write_SIC_IWR(IWR_DISABLE_ALL);
#endif
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
}
int bf53x_suspend_l1_mem(unsigned char *memptr)
@@ -245,12 +249,12 @@ int bfin_pm_suspend_mem_enter(void)
wakeup |= GPWE;
#endif
- local_irq_save(flags);
+ local_irq_save_hw(flags);
ret = blackfin_dma_suspend();
if (ret) {
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
kfree(memptr);
return ret;
}
@@ -271,7 +275,7 @@ int bfin_pm_suspend_mem_enter(void)
bfin_gpio_pm_hibernate_restore();
blackfin_dma_resume();
- local_irq_restore(flags);
+ local_irq_restore_hw(flags);
kfree(memptr);
return 0;
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
new file mode 100644
index 000000000000..77c992847094
--- /dev/null
+++ b/arch/blackfin/mach-common/smp.c
@@ -0,0 +1,476 @@
+/*
+ * File: arch/blackfin/kernel/smp.c
+ * Author: Philippe Gerum <rpm@xenomai.org>
+ * IPI management based on arch/arm/kernel/smp.c.
+ *
+ * Copyright 2007 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/cache.h>
+#include <linux/profile.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <asm/atomic.h>
+#include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/cpu.h>
+#include <linux/err.h>
+
+struct corelock_slot corelock __attribute__ ((__section__(".l2.bss")));
+
+void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb,
+ *init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb,
+ *init_saved_dcplb_fault_addr_coreb;
+
+cpumask_t cpu_possible_map;
+EXPORT_SYMBOL(cpu_possible_map);
+
+cpumask_t cpu_online_map;
+EXPORT_SYMBOL(cpu_online_map);
+
+#define BFIN_IPI_RESCHEDULE 0
+#define BFIN_IPI_CALL_FUNC 1
+#define BFIN_IPI_CPU_STOP 2
+
+struct blackfin_flush_data {
+ unsigned long start;
+ unsigned long end;
+};
+
+void *secondary_stack;
+
+
+struct smp_call_struct {
+ void (*func)(void *info);
+ void *info;
+ int wait;
+ cpumask_t pending;
+ cpumask_t waitmask;
+};
+
+static struct blackfin_flush_data smp_flush_data;
+
+static DEFINE_SPINLOCK(stop_lock);
+
+struct ipi_message {
+ struct list_head list;
+ unsigned long type;
+ struct smp_call_struct call_struct;
+};
+
+struct ipi_message_queue {
+ struct list_head head;
+ spinlock_t lock;
+ unsigned long count;
+};
+
+static DEFINE_PER_CPU(struct ipi_message_queue, ipi_msg_queue);
+
+static void ipi_cpu_stop(unsigned int cpu)
+{
+ spin_lock(&stop_lock);
+ printk(KERN_CRIT "CPU%u: stopping\n", cpu);
+ dump_stack();
+ spin_unlock(&stop_lock);
+
+ cpu_clear(cpu, cpu_online_map);
+
+ local_irq_disable();
+
+ while (1)
+ SSYNC();
+}
+
+static void ipi_flush_icache(void *info)
+{
+ struct blackfin_flush_data *fdata = info;
+
+ /* Invalidate the memory holding the bounds of the flushed region. */
+ blackfin_dcache_invalidate_range((unsigned long)fdata,
+ (unsigned long)fdata + sizeof(*fdata));
+
+ blackfin_icache_flush_range(fdata->start, fdata->end);
+}
+
+static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
+{
+ int wait;
+ void (*func)(void *info);
+ void *info;
+ func = msg->call_struct.func;
+ info = msg->call_struct.info;
+ wait = msg->call_struct.wait;
+ cpu_clear(cpu, msg->call_struct.pending);
+ func(info);
+ if (wait)
+ cpu_clear(cpu, msg->call_struct.waitmask);
+ else
+ kfree(msg);
+}
+
+static irqreturn_t ipi_handler(int irq, void *dev_instance)
+{
+ struct ipi_message *msg, *mg;
+ struct ipi_message_queue *msg_queue;
+ unsigned int cpu = smp_processor_id();
+
+ platform_clear_ipi(cpu);
+
+ msg_queue = &__get_cpu_var(ipi_msg_queue);
+ msg_queue->count++;
+
+ spin_lock(&msg_queue->lock);
+ list_for_each_entry_safe(msg, mg, &msg_queue->head, list) {
+ list_del(&msg->list);
+ switch (msg->type) {
+ case BFIN_IPI_RESCHEDULE:
+ /* That's the easiest one; leave it to
+ * return_from_int. */
+ kfree(msg);
+ break;
+ case BFIN_IPI_CALL_FUNC:
+ ipi_call_function(cpu, msg);
+ break;
+ case BFIN_IPI_CPU_STOP:
+ ipi_cpu_stop(cpu);
+ kfree(msg);
+ break;
+ default:
+ printk(KERN_CRIT "CPU%u: Unknown IPI message \
+ 0x%lx\n", cpu, msg->type);
+ kfree(msg);
+ break;
+ }
+ }
+ spin_unlock(&msg_queue->lock);
+ return IRQ_HANDLED;
+}
+
+static void ipi_queue_init(void)
+{
+ unsigned int cpu;
+ struct ipi_message_queue *msg_queue;
+ for_each_possible_cpu(cpu) {
+ msg_queue = &per_cpu(ipi_msg_queue, cpu);
+ INIT_LIST_HEAD(&msg_queue->head);
+ spin_lock_init(&msg_queue->lock);
+ msg_queue->count = 0;
+ }
+}
+
+int smp_call_function(void (*func)(void *info), void *info, int wait)
+{
+ unsigned int cpu;
+ cpumask_t callmap;
+ unsigned long flags;
+ struct ipi_message_queue *msg_queue;
+ struct ipi_message *msg;
+
+ callmap = cpu_online_map;
+ cpu_clear(smp_processor_id(), callmap);
+ if (cpus_empty(callmap))
+ return 0;
+
+ msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
+ INIT_LIST_HEAD(&msg->list);
+ msg->call_struct.func = func;
+ msg->call_struct.info = info;
+ msg->call_struct.wait = wait;
+ msg->call_struct.pending = callmap;
+ msg->call_struct.waitmask = callmap;
+ msg->type = BFIN_IPI_CALL_FUNC;
+
+ for_each_cpu_mask(cpu, callmap) {
+ msg_queue = &per_cpu(ipi_msg_queue, cpu);
+ spin_lock_irqsave(&msg_queue->lock, flags);
+ list_add(&msg->list, &msg_queue->head);
+ spin_unlock_irqrestore(&msg_queue->lock, flags);
+ platform_send_ipi_cpu(cpu);
+ }
+ if (wait) {
+ while (!cpus_empty(msg->call_struct.waitmask))
+ blackfin_dcache_invalidate_range(
+ (unsigned long)(&msg->call_struct.waitmask),
+ (unsigned long)(&msg->call_struct.waitmask));
+ kfree(msg);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(smp_call_function);
+
+int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
+ int wait)
+{
+ unsigned int cpu = cpuid;
+ cpumask_t callmap;
+ unsigned long flags;
+ struct ipi_message_queue *msg_queue;
+ struct ipi_message *msg;
+
+ if (cpu_is_offline(cpu))
+ return 0;
+ cpus_clear(callmap);
+ cpu_set(cpu, callmap);
+
+ msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
+ INIT_LIST_HEAD(&msg->list);
+ msg->call_struct.func = func;
+ msg->call_struct.info = info;
+ msg->call_struct.wait = wait;
+ msg->call_struct.pending = callmap;
+ msg->call_struct.waitmask = callmap;
+ msg->type = BFIN_IPI_CALL_FUNC;
+
+ msg_queue = &per_cpu(ipi_msg_queue, cpu);
+ spin_lock_irqsave(&msg_queue->lock, flags);
+ list_add(&msg->list, &msg_queue->head);
+ spin_unlock_irqrestore(&msg_queue->lock, flags);
+ platform_send_ipi_cpu(cpu);
+
+ if (wait) {
+ while (!cpus_empty(msg->call_struct.waitmask))
+ blackfin_dcache_invalidate_range(
+ (unsigned long)(&msg->call_struct.waitmask),
+ (unsigned long)(&msg->call_struct.waitmask));
+ kfree(msg);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(smp_call_function_single);
+
+void smp_send_reschedule(int cpu)
+{
+ unsigned long flags;
+ struct ipi_message_queue *msg_queue;
+ struct ipi_message *msg;
+
+ if (cpu_is_offline(cpu))
+ return;
+
+ msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
+ memset(msg, 0, sizeof(msg));
+ INIT_LIST_HEAD(&msg->list);
+ msg->type = BFIN_IPI_RESCHEDULE;
+
+ msg_queue = &per_cpu(ipi_msg_queue, cpu);
+ spin_lock_irqsave(&msg_queue->lock, flags);
+ list_add(&msg->list, &msg_queue->head);
+ spin_unlock_irqrestore(&msg_queue->lock, flags);
+ platform_send_ipi_cpu(cpu);
+
+ return;
+}
+
+void smp_send_stop(void)
+{
+ unsigned int cpu;
+ cpumask_t callmap;
+ unsigned long flags;
+ struct ipi_message_queue *msg_queue;
+ struct ipi_message *msg;
+
+ callmap = cpu_online_map;
+ cpu_clear(smp_processor_id(), callmap);
+ if (cpus_empty(callmap))
+ return;
+
+ msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
+ memset(msg, 0, sizeof(msg));
+ INIT_LIST_HEAD(&msg->list);
+ msg->type = BFIN_IPI_CPU_STOP;
+
+ for_each_cpu_mask(cpu, callmap) {
+ msg_queue = &per_cpu(ipi_msg_queue, cpu);
+ spin_lock_irqsave(&msg_queue->lock, flags);
+ list_add(&msg->list, &msg_queue->head);
+ spin_unlock_irqrestore(&msg_queue->lock, flags);
+ platform_send_ipi_cpu(cpu);
+ }
+ return;
+}
+
+int __cpuinit __cpu_up(unsigned int cpu)
+{
+ struct task_struct *idle;
+ int ret;
+
+ idle = fork_idle(cpu);
+ if (IS_ERR(idle)) {
+ printk(KERN_ERR "CPU%u: fork() failed\n", cpu);
+ return PTR_ERR(idle);
+ }
+
+ secondary_stack = task_stack_page(idle) + THREAD_SIZE;
+ smp_wmb();
+
+ ret = platform_boot_secondary(cpu, idle);
+
+ if (ret) {
+ cpu_clear(cpu, cpu_present_map);
+ printk(KERN_CRIT "CPU%u: processor failed to boot (%d)\n", cpu, ret);
+ free_task(idle);
+ } else
+ cpu_set(cpu, cpu_online_map);
+
+ secondary_stack = NULL;
+
+ return ret;
+}
+
+static void __cpuinit setup_secondary(unsigned int cpu)
+{
+#if !(defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE))
+ struct irq_desc *timer_desc;
+#endif
+ unsigned long ilat;
+
+ bfin_write_IMASK(0);
+ CSYNC();
+ ilat = bfin_read_ILAT();
+ CSYNC();
+ bfin_write_ILAT(ilat);
+ CSYNC();
+
+ /* Reserve the PDA space for the secondary CPU. */
+ reserve_pda();
+
+ /* Enable interrupt levels IVG7-15. IARs have been already
+ * programmed by the boot CPU. */
+ bfin_irq_flags |= IMASK_IVG15 |
+ IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
+ IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
+
+#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)
+ /* Power down the core timer, just to play safe. */
+ bfin_write_TCNTL(0);
+
+ /* system timer0 has been setup by CoreA. */
+#else
+ timer_desc = irq_desc + IRQ_CORETMR;
+ setup_core_timer();
+ timer_desc->chip->enable(IRQ_CORETMR);
+#endif
+}
+
+void __cpuinit secondary_start_kernel(void)
+{
+ unsigned int cpu = smp_processor_id();
+ struct mm_struct *mm = &init_mm;
+
+ if (_bfin_swrst & SWRST_DBL_FAULT_B) {
+ printk(KERN_EMERG "CoreB Recovering from DOUBLE FAULT event\n");
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n",
+ (int)init_saved_seqstat_coreb & SEQSTAT_EXCAUSE, init_saved_retx_coreb);
+ printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr_coreb);
+ printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr_coreb);
+#endif
+ printk(KERN_NOTICE " The instruction at %pF caused a double exception\n",
+ init_retx_coreb);
+ }
+
+ /*
+ * We want the D-cache to be enabled early, in case the atomic
+ * support code emulates cache coherence (see
+ * __ARCH_SYNC_CORE_DCACHE).
+ */
+ init_exception_vectors();
+
+ bfin_setup_caches(cpu);
+
+ local_irq_disable();
+
+ /* Attach the new idle task to the global mm. */
+ atomic_inc(&mm->mm_users);
+ atomic_inc(&mm->mm_count);
+ current->active_mm = mm;
+ BUG_ON(current->mm); /* Can't be, but better be safe than sorry. */
+
+ preempt_disable();
+
+ setup_secondary(cpu);
+
+ local_irq_enable();
+
+ platform_secondary_init(cpu);
+
+ cpu_idle();
+}
+
+void __init smp_prepare_boot_cpu(void)
+{
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+ platform_prepare_cpus(max_cpus);
+ ipi_queue_init();
+ platform_request_ipi(&ipi_handler);
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+ unsigned long bogosum = 0;
+ unsigned int cpu;
+
+ for_each_online_cpu(cpu)
+ bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy;
+
+ printk(KERN_INFO "SMP: Total of %d processors activated "
+ "(%lu.%02lu BogoMIPS).\n",
+ num_online_cpus(),
+ bogosum / (500000/HZ),
+ (bogosum / (5000/HZ)) % 100);
+}
+
+void smp_icache_flush_range_others(unsigned long start, unsigned long end)
+{
+ smp_flush_data.start = start;
+ smp_flush_data.end = end;
+
+ if (smp_call_function(&ipi_flush_icache, &smp_flush_data, 1))
+ printk(KERN_WARNING "SMP: failed to run I-cache flush request on other CPUs\n");
+}
+EXPORT_SYMBOL_GPL(smp_icache_flush_range_others);
+
+#ifdef __ARCH_SYNC_CORE_DCACHE
+unsigned long barrier_mask __attribute__ ((__section__(".l2.bss")));
+
+void resync_core_dcache(void)
+{
+ unsigned int cpu = get_cpu();
+ blackfin_invalidate_entire_dcache();
+ ++per_cpu(cpu_data, cpu).dcache_invld_count;
+ put_cpu();
+}
+EXPORT_SYMBOL(resync_core_dcache);
+#endif