diff options
Diffstat (limited to 'arch/blackfin/mach-common')
-rw-r--r-- | arch/blackfin/mach-common/Makefile | 4 | ||||
-rw-r--r-- | arch/blackfin/mach-common/dpmc.S | 32 | ||||
-rw-r--r-- | arch/blackfin/mach-common/entry.S | 12 | ||||
-rw-r--r-- | arch/blackfin/mach-common/ints-priority-dc.c | 484 | ||||
-rw-r--r-- | arch/blackfin/mach-common/ints-priority.c (renamed from arch/blackfin/mach-common/ints-priority-sc.c) | 271 | ||||
-rw-r--r-- | arch/blackfin/mach-common/pm.c | 44 |
6 files changed, 279 insertions, 568 deletions
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile index 8636d42..15e33ca 100644 --- a/arch/blackfin/mach-common/Makefile +++ b/arch/blackfin/mach-common/Makefile @@ -4,8 +4,6 @@ obj-y := \ cache.o cacheinit.o entry.o \ - interrupt.o lock.o irqpanic.o arch_checks.o + interrupt.o lock.o irqpanic.o arch_checks.o ints-priority.o -obj-$(CONFIG_BFIN_SINGLE_CORE) += ints-priority-sc.o -obj-$(CONFIG_BFIN_DUAL_CORE) += ints-priority-dc.o obj-$(CONFIG_PM) += pm.o dpmc.o diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S index b82c096e..b80ddd8 100644 --- a/arch/blackfin/mach-common/dpmc.S +++ b/arch/blackfin/mach-common/dpmc.S @@ -191,6 +191,9 @@ ENTRY(_sleep_mode) call _test_pll_locked; R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; P0.H = hi(PLL_CTL); @@ -237,6 +240,10 @@ ENTRY(_deep_sleep) CLI R4; + R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; call _set_dram_srfs; @@ -261,6 +268,9 @@ ENTRY(_deep_sleep) call _test_pll_locked; R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; P0.H = hi(PLL_CTL); @@ -286,7 +296,13 @@ ENTRY(_sleep_deeper) CLI R4; P3 = R0; + P4 = R1; + P5 = R2; + R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; call _set_dram_srfs; /* Set SDRAM Self Refresh */ @@ -327,6 +343,8 @@ ENTRY(_sleep_deeper) call _test_pll_locked; R0 = P3; + R1 = P4; + R3 = P5; call _set_sic_iwr; /* Set Awake from IDLE */ P0.H = hi(PLL_CTL); @@ -340,6 +358,9 @@ ENTRY(_sleep_deeper) call _test_pll_locked; R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; /* Set Awake from IDLE PLL */ P0.H = hi(VR_CTL); @@ -417,14 +438,23 @@ ENTRY(_unset_dram_srfs) RTS; ENTRY(_set_sic_iwr) -#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) +#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) P0.H = hi(SIC_IWR0); P0.L = lo(SIC_IWR0); + P1.H = hi(SIC_IWR1); + P1.L = lo(SIC_IWR1); + [P1] = R1; +#if defined(CONFIG_BF54x) + P1.H = hi(SIC_IWR2); + P1.L = lo(SIC_IWR2); + [P1] = R2; +#endif #else P0.H = hi(SIC_IWR); P0.L = lo(SIC_IWR); #endif [P0] = R0; + SSYNC; RTS; diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index fdd9bf4..2cbb7a0 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -121,6 +121,7 @@ ENTRY(_ex_icplb_miss) (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; SAVE_ALL_SYS + DEBUG_HWTRACE_SAVE(p5, r7) #ifdef CONFIG_MPU R0 = SEQSTAT; R1 = SP; @@ -132,14 +133,13 @@ ENTRY(_ex_icplb_miss) #else call __cplb_hdr; #endif - DEBUG_START_HWTRACE(p5, r7) + DEBUG_HWTRACE_RESTORE(p5, r7) RESTORE_ALL_SYS SP = EX_SCRATCH_REG; rtx; ENDPROC(_ex_icplb_miss) ENTRY(_ex_syscall) - DEBUG_START_HWTRACE(p5, r7) (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; raise 15; /* invoked by TRAP #0, for sys call */ @@ -178,7 +178,6 @@ ENTRY(_ex_single_step) ENDPROC(_ex_single_step) ENTRY(_bfin_return_from_exception) - DEBUG_START_HWTRACE(p5, r7) #if ANOMALY_05000257 R7=LC0; LC0=R7; @@ -200,10 +199,9 @@ ENTRY(_handle_bad_cplb) * need to make a CPLB exception look like a normal exception */ - DEBUG_START_HWTRACE(p5, r7) RESTORE_ALL_SYS [--sp] = ASTAT; - [--sp] = (R7:6, P5:4); + [--sp] = (R7:6,P5:4); ENTRY(_ex_replaceable) nop; @@ -253,7 +251,6 @@ ENTRY(_ex_trap_c) R6 = SEQSTAT; [P5] = R6; - DEBUG_START_HWTRACE(p5, r7) (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; SP = EX_SCRATCH_REG; @@ -382,8 +379,7 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ sp.h = _exception_stack_top; /* Try to deal with syscalls quickly. */ [--sp] = ASTAT; - [--sp] = (R7:6, P5:4); - DEBUG_STOP_HWTRACE(p5, r7) + [--sp] = (R7:6,P5:4); r7 = SEQSTAT; /* reason code is in bit 5:0 */ r6.l = lo(SEQSTAT_EXCAUSE); r6.h = hi(SEQSTAT_EXCAUSE); diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c deleted file mode 100644 index 8d18d6b..0000000 --- a/arch/blackfin/mach-common/ints-priority-dc.c +++ /dev/null @@ -1,484 +0,0 @@ -/* - * File: arch/blackfin/mach-common/ints-priority-dc.c - * Based on: - * Author: - * - * Created: ? - * Description: Set up the interrupt priorities - * - * Modified: - * 1996 Roman Zippel - * 1999 D. Jeff Dionne <jeff@uclinux.org> - * 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca> - * 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> - * 2003 Metrowerks/Motorola - * 2003 Bas Vermeulen <bas@buyways.nl> - * Copyright 2004-2006 Analog Devices Inc. - * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * 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/kernel_stat.h> -#include <linux/seq_file.h> -#include <linux/irq.h> -#ifdef CONFIG_KGDB -#include <linux/kgdb.h> -#endif -#include <asm/traps.h> -#include <asm/blackfin.h> -#include <asm/gpio.h> -#include <asm/irq_handler.h> - -/* - * NOTES: - * - we have separated the physical Hardware interrupt from the - * levels that the LINUX kernel sees (see the description in irq.h) - * - - */ - -/* 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; - -/* The number of spurious interrupts */ -atomic_t num_spurious; - -struct ivgx { - /* irq number for request_irq, available in mach-bf561/irq.h */ - int irqno; - /* corresponding bit in the SICA_ISR0 register */ - int isrflag0; - /* corresponding bit in the SICA_ISR1 register */ - int isrflag1; -} ivg_table[NR_PERI_INTS]; - -struct ivg_slice { - /* position of first irq in ivg_table for given ivg */ - struct ivgx *ifirst; - struct ivgx *istop; -} ivg7_13[IVG13 - IVG7 + 1]; - -static void search_IAR(void); - -/* - * Search SIC_IAR and fill tables with the irqvalues - * and their positions in the SIC_ISR register. - */ -static void __init search_IAR(void) -{ - unsigned ivg, irq_pos = 0; - for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) { - int irqn; - - ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos]; - - for (irqn = 0; irqn < NR_PERI_INTS; irqn++) { - int iar_shift = (irqn & 7) * 4; - if (ivg == - (0xf & - bfin_read32((unsigned long *)SICA_IAR0 + - (irqn >> 3)) >> iar_shift)) { - ivg_table[irq_pos].irqno = IVG7 + irqn; - ivg_table[irq_pos].isrflag0 = - (irqn < 32 ? (1 << irqn) : 0); - ivg_table[irq_pos].isrflag1 = - (irqn < 32 ? 0 : (1 << (irqn - 32))); - ivg7_13[ivg].istop++; - irq_pos++; - } - } - } -} - -/* - * This is for BF561 internal IRQs - */ - -static void ack_noop(unsigned int irq) -{ - /* Dummy function. */ -} - -static void bf561_core_mask_irq(unsigned int irq) -{ - irq_flags &= ~(1 << irq); - if (!irqs_disabled()) - local_irq_enable(); -} - -static void bf561_core_unmask_irq(unsigned int irq) -{ - irq_flags |= 1 << irq; - /* - * If interrupts are enabled, IMASK must contain the same value - * as 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 - * what we need. - */ - if (!irqs_disabled()) - local_irq_enable(); - return; -} - -static void bf561_internal_mask_irq(unsigned int irq) -{ - unsigned long irq_mask; - if ((irq - (IRQ_CORETMR + 1)) < 32) { - irq_mask = (1 << (irq - (IRQ_CORETMR + 1))); - bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() & ~irq_mask); - } else { - irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32)); - bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() & ~irq_mask); - } -} - -static void bf561_internal_unmask_irq(unsigned int irq) -{ - unsigned long irq_mask; - - if ((irq - (IRQ_CORETMR + 1)) < 32) { - irq_mask = (1 << (irq - (IRQ_CORETMR + 1))); - bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() | irq_mask); - } else { - irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32)); - bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() | irq_mask); - } - SSYNC(); -} - -static struct irq_chip bf561_core_irqchip = { - .ack = ack_noop, - .mask = bf561_core_mask_irq, - .unmask = bf561_core_unmask_irq, -}; - -static struct irq_chip bf561_internal_irqchip = { - .ack = ack_noop, - .mask = bf561_internal_mask_irq, - .unmask = bf561_internal_unmask_irq, -}; - -static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)]; -static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)]; - -static void bf561_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(); - } -} - -static void bf561_gpio_mask_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(); - } - - set_gpio_maska(gpionr, 0); - SSYNC(); -} - -static void bf561_gpio_mask_irq(unsigned int irq) -{ - set_gpio_maska(irq - IRQ_PF0, 0); - SSYNC(); -} - -static void bf561_gpio_unmask_irq(unsigned int irq) -{ - set_gpio_maska(irq - IRQ_PF0, 1); - SSYNC(); -} - -static unsigned int bf561_gpio_irq_startup(unsigned int irq) -{ - unsigned int ret; - char buf[8]; - u16 gpionr = irq - IRQ_PF0; - - if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) { - snprintf(buf, sizeof buf, "IRQ %d", irq); - ret = gpio_request(gpionr, buf); - if (ret) - return ret; - - } - - gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr); - bf561_gpio_unmask_irq(irq); - - return ret; - -} - -static void bf561_gpio_irq_shutdown(unsigned int irq) -{ - bf561_gpio_mask_irq(irq); - gpio_free(irq - IRQ_PF0); - gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0); -} - -static int bf561_gpio_irq_type(unsigned int irq, unsigned int type) -{ - - unsigned int ret; - char buf[8]; - u16 gpionr = irq - IRQ_PF0; - - - if (type == IRQ_TYPE_PROBE) { - /* only probe unenabled GPIO interrupt lines */ - if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)) - 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, sizeof buf, "IRQ %d", irq); - ret = gpio_request(gpionr, buf); - if (ret) - return ret; - - } - - gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr); - } else { - gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr); - return 0; - } - - - set_gpio_dir(gpionr, 0); - set_gpio_inen(gpionr, 1); - - - if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { - gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr); - set_gpio_edge(gpionr, 1); - } else { - set_gpio_edge(gpionr, 0); - gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr); - } - - if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) - == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) - set_gpio_both(gpionr, 1); - else - set_gpio_both(gpionr, 0); - - if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))) - set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */ - else - set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */ - - SSYNC(); - - if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) - set_irq_handler(irq, handle_edge_irq); - else - set_irq_handler(irq, handle_level_irq); - - return 0; -} - -static struct irq_chip bf561_gpio_irqchip = { - .ack = bf561_gpio_ack_irq, - .mask = bf561_gpio_mask_irq, - .mask_ack = bf561_gpio_mask_ack_irq, - .unmask = bf561_gpio_unmask_irq, - .set_type = bf561_gpio_irq_type, - .startup = bf561_gpio_irq_startup, - .shutdown = bf561_gpio_irq_shutdown -}; - -static void bf561_demux_gpio_irq(unsigned int inta_irq, - struct irq_desc *intb_desc) -{ - int irq, flag_d, mask; - u16 gpio; - - switch (inta_irq) { - case IRQ_PROG0_INTA: - irq = IRQ_PF0; - break; - case IRQ_PROG1_INTA: - irq = IRQ_PF16; - break; - case IRQ_PROG2_INTA: - irq = IRQ_PF32; - break; - default: - dump_stack(); - return; - } - - gpio = irq - IRQ_PF0; - - flag_d = get_gpiop_data(gpio); - mask = flag_d & (gpio_enabled[gpio_bank(gpio)] & - get_gpiop_maska(gpio)); - - do { - if (mask & 1) { - struct irq_desc *desc = irq_desc + irq; - desc->handle_irq(irq, desc); - } - irq++; - mask >>= 1; - } while (mask); - - -} - -void __init init_exception_vectors(void) -{ - SSYNC(); - - /* cannot program in software: - * evt0 - emulation (jtag) - * evt1 - reset - */ - bfin_write_EVT2(evt_nmi); - bfin_write_EVT3(trap); - bfin_write_EVT5(evt_ivhw); - bfin_write_EVT6(evt_timer); - bfin_write_EVT7(evt_evt7); - bfin_write_EVT8(evt_evt8); - bfin_write_EVT9(evt_evt9); - bfin_write_EVT10(evt_evt10); - bfin_write_EVT11(evt_evt11); - bfin_write_EVT12(evt_evt12); - bfin_write_EVT13(evt_evt13); - bfin_write_EVT14(evt14_softirq); - bfin_write_EVT15(evt_system_call); - CSYNC(); -} - -/* - * 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 */ - bfin_write_SICA_IMASK0(SIC_UNMASK_ALL); - bfin_write_SICA_IMASK1(SIC_UNMASK_ALL); - SSYNC(); - - bfin_write_SICA_IWR0(IWR_ENABLE_ALL); - bfin_write_SICA_IWR1(IWR_ENABLE_ALL); - - local_irq_disable(); - - init_exception_buff(); - - for (irq = 0; irq <= SYS_IRQS; irq++) { - if (irq <= IRQ_CORETMR) - set_irq_chip(irq, &bf561_core_irqchip); - else - set_irq_chip(irq, &bf561_internal_irqchip); - - if ((irq != IRQ_PROG0_INTA) && - (irq != IRQ_PROG1_INTA) && - (irq != IRQ_PROG2_INTA)) - set_irq_handler(irq, handle_simple_irq); - else - set_irq_chained_handler(irq, bf561_demux_gpio_irq); - } - - for (irq = IRQ_PF0; irq <= IRQ_PF47; irq++) { - set_irq_chip(irq, &bf561_gpio_irqchip); - /* if configured as edge, then will be changed to do_edge_IRQ */ - set_irq_handler(irq, handle_level_irq); - } - - bfin_write_IMASK(0); - CSYNC(); - ilat = bfin_read_ILAT(); - CSYNC(); - bfin_write_ILAT(ilat); - CSYNC(); - - printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n"); - /* IMASK=xxx is equivalent to STI xx or irq_flags=xx, - * local_irq_enable() - */ - program_IAR(); - /* Therefore it's better to setup IARs before interrupts enabled */ - search_IAR(); - - /* Enable interrupts IVG7-15 */ - irq_flags = irq_flags | IMASK_IVG15 | - IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | - IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; - - return 0; -} - -#ifdef CONFIG_DO_IRQ_L1 -__attribute__((l1_text)) -#endif -void do_irq(int vec, struct pt_regs *fp) -{ - if (vec == EVT_IVTMR_P) { - vec = IRQ_CORETMR; - } else { - struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst; - struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop; - unsigned long sic_status0, sic_status1; - - SSYNC(); - sic_status0 = bfin_read_SICA_IMASK0() & bfin_read_SICA_ISR0(); - sic_status1 = bfin_read_SICA_IMASK1() & bfin_read_SICA_ISR1(); - - for (;; ivg++) { - if (ivg >= ivg_stop) { - atomic_inc(&num_spurious); - return; - } else if ((sic_status0 & ivg->isrflag0) || - (sic_status1 & ivg->isrflag1)) - break; - } - vec = ivg->irqno; - } - asm_do_IRQ(vec, fp); - -#ifdef CONFIG_KGDB - kgdb_process_breakpoint(); -#endif -} diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority.c index dec42ac..880595a 100644 --- a/arch/blackfin/mach-common/ints-priority-sc.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -1,5 +1,5 @@ /* - * File: arch/blackfin/mach-common/ints-priority-sc.c + * File: arch/blackfin/mach-common/ints-priority.c * Based on: * Author: * @@ -13,7 +13,7 @@ * 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca> * 2003 Metrowerks/Motorola * 2003 Bas Vermeulen <bas@buyways.nl> - * Copyright 2004-2007 Analog Devices Inc. + * Copyright 2004-2008 Analog Devices Inc. * * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -69,6 +69,10 @@ unsigned long irq_flags = 0x1f; /* The number of spurious interrupts */ atomic_t num_spurious; +#ifdef CONFIG_PM +unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */ +#endif + struct ivgx { /* irq number for request_irq, available in mach-bf533/irq.h */ unsigned int irqno; @@ -98,8 +102,7 @@ static void __init search_IAR(void) for (irqn = 0; irqn < NR_PERI_INTS; irqn++) { int iar_shift = (irqn & 7) * 4; - if (ivg == - (0xf & + if (ivg == (0xf & #ifndef CONFIG_BF52x bfin_read32((unsigned long *)SIC_IAR0 + (irqn >> 3)) >> iar_shift)) { @@ -179,6 +182,27 @@ static void bfin_internal_unmask_irq(unsigned int irq) SSYNC(); } +#ifdef CONFIG_PM +int bfin_internal_set_wake(unsigned int irq, unsigned int state) +{ + unsigned bank, bit; + unsigned long flags; + bank = (irq - (IRQ_CORETMR + 1)) / 32; + bit = (irq - (IRQ_CORETMR + 1)) % 32; + + local_irq_save(flags); + + if (state) + bfin_sic_iwr[bank] |= (1 << bit); + else + bfin_sic_iwr[bank] &= ~(1 << bit); + + local_irq_restore(flags); + + return 0; +} +#endif + static struct irq_chip bfin_core_irqchip = { .ack = ack_noop, .mask = bfin_core_mask_irq, @@ -189,6 +213,9 @@ static struct irq_chip bfin_internal_irqchip = { .ack = ack_noop, .mask = bfin_internal_mask_irq, .unmask = bfin_internal_unmask_irq, +#ifdef CONFIG_PM + .set_wake = bfin_internal_set_wake, +#endif }; #ifdef BF537_GENERIC_ERROR_INT_DEMUX @@ -206,8 +233,7 @@ static void bfin_generic_error_mask_irq(unsigned int irq) if (!error_int_mask) { local_irq_disable(); bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() & - ~(1 << - (IRQ_GENERIC_ERROR - + ~(1 << (IRQ_GENERIC_ERROR - (IRQ_CORETMR + 1)))); SSYNC(); local_irq_enable(); @@ -232,7 +258,7 @@ static struct irq_chip bfin_generic_error_irqchip = { }; static void bfin_demux_error_irq(unsigned int int_err_irq, - struct irq_desc *intb_desc) + struct irq_desc *inta_desc) { int irq = 0; @@ -404,16 +430,8 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) return 0; } + set_gpio_inen(gpionr, 0); set_gpio_dir(gpionr, 0); - set_gpio_inen(gpionr, 1); - - if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { - gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr); - set_gpio_edge(gpionr, 1); - } else { - set_gpio_edge(gpionr, 0); - gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr); - } if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) @@ -426,6 +444,18 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) else set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */ + 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)) @@ -436,6 +466,20 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) return 0; } +#ifdef CONFIG_PM +int bfin_gpio_set_wake(unsigned int irq, unsigned int state) +{ + unsigned gpio = irq_to_gpio(irq); + + if (state) + gpio_pm_wakeup_request(gpio, PM_WAKE_IGNORE); + else + gpio_pm_wakeup_free(gpio); + + return 0; +} +#endif + static struct irq_chip bfin_gpio_irqchip = { .ack = bfin_gpio_ack_irq, .mask = bfin_gpio_mask_irq, @@ -443,30 +487,87 @@ static struct irq_chip bfin_gpio_irqchip = { .unmask = bfin_gpio_unmask_irq, .set_type = bfin_gpio_irq_type, .startup = bfin_gpio_irq_startup, - .shutdown = bfin_gpio_irq_shutdown + .shutdown = bfin_gpio_irq_shutdown, +#ifdef CONFIG_PM + .set_wake = bfin_gpio_set_wake, +#endif }; -static void bfin_demux_gpio_irq(unsigned int intb_irq, - struct irq_desc *intb_desc) +static void bfin_demux_gpio_irq(unsigned int inta_irq, + struct irq_desc *desc) { - u16 i; - struct irq_desc *desc; + unsigned int i, gpio, mask, irq, search = 0; - for (i = 0; i < MAX_BLACKFIN_GPIOS; i += 16) { - int irq = IRQ_PF0 + i; - int flag_d = get_gpiop_data(i); - int mask = - flag_d & (gpio_enabled[gpio_bank(i)] & get_gpiop_maska(i)); + switch (inta_irq) { +#if defined(CONFIG_BF53x) + case IRQ_PROG_INTA: + irq = IRQ_PF0; + search = 1; + break; +# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)) + case IRQ_MAC_RX: + irq = IRQ_PH0; + break; +# endif +#elif defined(CONFIG_BF52x) + case IRQ_PORTF_INTA: + irq = IRQ_PF0; + break; + case IRQ_PORTG_INTA: + irq = IRQ_PG0; + break; + case IRQ_PORTH_INTA: + irq = IRQ_PH0; + break; +#elif defined(CONFIG_BF561) + case IRQ_PROG0_INTA: + irq = IRQ_PF0; + break; + case IRQ_PROG1_INTA: + irq = IRQ_PF16; + break; + case IRQ_PROG2_INTA: + irq = IRQ_PF32; + break; +#endif + default: + BUG(); + return; + } - while (mask) { - if (mask & 1) { - desc = irq_desc + irq; - desc->handle_irq(irq, desc); + if (search) { + 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)); + + while (mask) { + if (mask & 1) { + desc = irq_desc + irq; + desc->handle_irq(irq, desc); + } + irq++; + mask >>= 1; } - irq++; - mask >>= 1; } + } else { + gpio = irq_to_gpio(irq); + mask = get_gpiop_data(gpio) & + (gpio_enabled[gpio_bank(gpio)] & + get_gpiop_maska(gpio)); + + do { + if (mask & 1) { + desc = irq_desc + irq; + desc->handle_irq(irq, desc); + } + irq++; + mask >>= 1; + } while (mask); } + } #else /* CONFIG_BF54x */ @@ -711,6 +812,74 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) return 0; } +#ifdef CONFIG_PM +u32 pint_saved_masks[NR_PINT_SYS_IRQS]; +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 bank = PINT_2_BANK(pint_val); + u32 pintbit = PINT_BIT(pint_val); + + switch (bank) { + case 0: + pint_irq = IRQ_PINT0; + break; + case 2: + pint_irq = IRQ_PINT2; + break; + case 3: + pint_irq = IRQ_PINT3; + break; + case 1: + pint_irq = IRQ_PINT1; + break; + default: + return -EINVAL; + } + + bfin_internal_set_wake(pint_irq, state); + + if (state) + pint_wakeup_masks[bank] |= pintbit; + else + pint_wakeup_masks[bank] &= ~pintbit; + + return 0; +} + +u32 bfin_pm_setup(void) +{ + u32 val, i; + + for (i = 0; i < NR_PINT_SYS_IRQS; i++) { + val = pint[i]->mask_clear; + pint_saved_masks[i] = val; + if (val ^ pint_wakeup_masks[i]) { + pint[i]->mask_clear = val; + pint[i]->mask_set = pint_wakeup_masks[i]; + } + } + + return 0; +} + +void bfin_pm_restore(void) +{ + u32 i, val; + + for (i = 0; i < NR_PINT_SYS_IRQS; i++) { + val = pint_saved_masks[i]; + if (val ^ pint_wakeup_masks[i]) { + pint[i]->mask_clear = pint[i]->mask_clear; + pint[i]->mask_set = val; + } + } +} +#endif + static struct irq_chip bfin_gpio_irqchip = { .ack = bfin_gpio_ack_irq, .mask = bfin_gpio_mask_irq, @@ -718,17 +887,19 @@ static struct irq_chip bfin_gpio_irqchip = { .unmask = bfin_gpio_unmask_irq, .set_type = bfin_gpio_irq_type, .startup = bfin_gpio_irq_startup, - .shutdown = bfin_gpio_irq_shutdown + .shutdown = bfin_gpio_irq_shutdown, +#ifdef CONFIG_PM + .set_wake = bfin_gpio_set_wake, +#endif }; -static void bfin_demux_gpio_irq(unsigned int intb_irq, - struct irq_desc *intb_desc) +static void bfin_demux_gpio_irq(unsigned int inta_irq, + struct irq_desc *desc) { u8 bank, pint_val; u32 request, irq; - struct irq_desc *desc; - switch (intb_irq) { + switch (inta_irq) { case IRQ_PINT0: bank = 0; break; @@ -795,7 +966,7 @@ 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) +#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) bfin_write_SIC_IMASK0(SIC_UNMASK_ALL); bfin_write_SIC_IMASK1(SIC_UNMASK_ALL); bfin_write_SIC_IWR0(IWR_ENABLE_ALL); @@ -812,6 +983,8 @@ int __init init_arch_irq(void) local_irq_disable(); + init_exception_buff(); + #ifdef CONFIG_BF54x # ifdef CONFIG_PINTx_REASSIGN pint[0]->assign = CONFIG_PINT0_ASSIGN; @@ -874,6 +1047,19 @@ int __init init_arch_irq(void) set_irq_chained_handler(irq, bfin_demux_gpio_irq); break; +#elif defined(CONFIG_BF561) + case IRQ_PROG0_INTA: + set_irq_chained_handler(irq, + bfin_demux_gpio_irq); + break; + case IRQ_PROG1_INTA: + set_irq_chained_handler(irq, + bfin_demux_gpio_irq); + break; + case IRQ_PROG2_INTA: + set_irq_chained_handler(irq, + bfin_demux_gpio_irq); + break; #endif default: set_irq_handler(irq, handle_simple_irq); @@ -893,11 +1079,8 @@ int __init init_arch_irq(void) } #endif -#ifndef CONFIG_BF54x - for (irq = IRQ_PF0; irq < NR_IRQS; irq++) { -#else - for (irq = IRQ_PA0; irq < NR_IRQS; irq++) { -#endif + for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++) { + set_irq_chip(irq, &bfin_gpio_irqchip); /* if configured as edge, then will be changed to do_edge_IRQ */ set_irq_handler(irq, handle_level_irq); @@ -936,7 +1119,7 @@ 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) +#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) unsigned long sic_status[3]; SSYNC(); diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c index 81930f7..0be805c 100644 --- a/arch/blackfin/mach-common/pm.c +++ b/arch/blackfin/mach-common/pm.c @@ -4,7 +4,7 @@ * Author: Cliff Brake <cbrake@accelent.com> Copyright (c) 2001 * * Created: 2001 - * Description: Power management for the bfin + * Description: Blackfin power management * * Modified: Nicolas Pitre - PXA250 support * Copyright (c) 2002 Monta Vista Software, Inc. @@ -12,7 +12,7 @@ * Copyright (c) 2002 Monta Vista Software, Inc. * Dirk Behme <dirk.behme@de.bosch.com> - OMAP1510/1610 * Copyright 2004 - * Copyright 2004-2006 Analog Devices Inc. + * Copyright 2004-2008 Analog Devices Inc. * * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -67,42 +67,30 @@ void bfin_pm_suspend_standby_enter(void) gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE); #endif -#if defined(CONFIG_PM_WAKEUP_BY_GPIO) || defined(CONFIG_PM_WAKEUP_GPIO_API) - { - u32 flags; + u32 flags; - local_irq_save(flags); + local_irq_save(flags); + bfin_pm_setup(); - sleep_deeper(gpio_pm_setup()); /*Goto Sleep*/ - - gpio_pm_restore(); - -#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) - bfin_write_SIC_IWR0(IWR_ENABLE_ALL); - bfin_write_SIC_IWR1(IWR_ENABLE_ALL); -# ifdef CONFIG_BF54x - bfin_write_SIC_IWR2(IWR_ENABLE_ALL); -# endif +#ifdef CONFIG_PM_BFIN_SLEEP_DEEPER + sleep_deeper(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]); #else - bfin_write_SIC_IWR(IWR_ENABLE_ALL); + sleep_mode(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]); #endif - local_irq_restore(flags); - } -#endif + bfin_pm_restore(); -#if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR) - sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR); -# if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) +#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) bfin_write_SIC_IWR0(IWR_ENABLE_ALL); bfin_write_SIC_IWR1(IWR_ENABLE_ALL); -# ifdef CONFIG_BF54x +# ifdef CONFIG_BF54x bfin_write_SIC_IWR2(IWR_ENABLE_ALL); -# endif -# else - bfin_write_SIC_IWR(IWR_ENABLE_ALL); # endif -#endif /* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */ +#else + bfin_write_SIC_IWR(IWR_ENABLE_ALL); +#endif + + local_irq_restore(flags); } /* |