aboutsummaryrefslogtreecommitdiff
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/Makefile3
-rw-r--r--arch/blackfin/mach-common/cplbhdlr.S130
-rw-r--r--arch/blackfin/mach-common/cplbinfo.c208
-rw-r--r--arch/blackfin/mach-common/cplbmgr.S619
-rw-r--r--arch/blackfin/mach-common/dpmc.S74
-rw-r--r--arch/blackfin/mach-common/entry.S28
-rw-r--r--arch/blackfin/mach-common/interrupt.S48
-rw-r--r--arch/blackfin/mach-common/ints-priority-dc.c10
-rw-r--r--arch/blackfin/mach-common/ints-priority-sc.c84
-rw-r--r--arch/blackfin/mach-common/irqpanic.c50
-rw-r--r--arch/blackfin/mach-common/pm.c16
11 files changed, 190 insertions, 1080 deletions
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
index 4d7733dfd5d..8636d4284bd 100644
--- a/arch/blackfin/mach-common/Makefile
+++ b/arch/blackfin/mach-common/Makefile
@@ -3,10 +3,9 @@
#
obj-y := \
- cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \
+ cache.o cacheinit.o entry.o \
interrupt.o lock.o irqpanic.o arch_checks.o
-obj-$(CONFIG_CPLB_INFO) += cplbinfo.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/cplbhdlr.S b/arch/blackfin/mach-common/cplbhdlr.S
deleted file mode 100644
index 2788532de72..00000000000
--- a/arch/blackfin/mach-common/cplbhdlr.S
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * File: arch/blackfin/mach-common/cplbhdlr.S
- * Based on:
- * Author: LG Soft India
- *
- * Created: ?
- * Description: CPLB exception handler
- *
- * Modified:
- * 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/linkage.h>
-#include <asm/cplb.h>
-#include <asm/entry.h>
-
-#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
-.section .l1.text
-#else
-.text
-#endif
-
-.type _cplb_mgr, STT_FUNC;
-.type _panic_cplb_error, STT_FUNC;
-
-.align 2
-
-ENTRY(__cplb_hdr)
- R2 = SEQSTAT;
-
- /* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */
- R2 <<= 26;
- R2 >>= 26;
-
- R1 = 0x23; /* Data access CPLB protection violation */
- CC = R2 == R1;
- IF !CC JUMP .Lnot_data_write;
- R0 = 2; /* is a write to data space*/
- JUMP .Lis_icplb_miss;
-
-.Lnot_data_write:
- R1 = 0x2C; /* CPLB miss on an instruction fetch */
- CC = R2 == R1;
- R0 = 0; /* is_data_miss == False*/
- IF CC JUMP .Lis_icplb_miss;
-
- R1 = 0x26;
- CC = R2 == R1;
- IF !CC JUMP .Lunknown;
-
- R0 = 1; /* is_data_miss == True*/
-
-.Lis_icplb_miss:
-
-#if defined(CONFIG_BFIN_ICACHE) || defined(CONFIG_BFIN_DCACHE)
-# if defined(CONFIG_BFIN_ICACHE) && !defined(CONFIG_BFIN_DCACHE)
- R1 = CPLB_ENABLE_ICACHE;
-# endif
-# if !defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
- R1 = CPLB_ENABLE_DCACHE;
-# endif
-# if defined(CONFIG_BFIN_ICACHE) && defined(CONFIG_BFIN_DCACHE)
- R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
-# endif
-#else
- R1 = 0;
-#endif
-
- [--SP] = RETS;
- CALL _cplb_mgr;
- RETS = [SP++];
- CC = R0 == 0;
- IF !CC JUMP .Lnot_replaced;
- RTS;
-
-/*
- * Diagnostic exception handlers
- */
-.Lunknown:
- R0 = CPLB_UNKNOWN_ERR;
- JUMP .Lcplb_error;
-
-.Lnot_replaced:
- CC = R0 == CPLB_NO_UNLOCKED;
- IF !CC JUMP .Lnext_check;
- R0 = CPLB_NO_UNLOCKED;
- JUMP .Lcplb_error;
-
-.Lnext_check:
- CC = R0 == CPLB_NO_ADDR_MATCH;
- IF !CC JUMP .Lnext_check2;
- R0 = CPLB_NO_ADDR_MATCH;
- JUMP .Lcplb_error;
-
-.Lnext_check2:
- CC = R0 == CPLB_PROT_VIOL;
- IF !CC JUMP .Lstrange_return_from_cplb_mgr;
- R0 = CPLB_PROT_VIOL;
- JUMP .Lcplb_error;
-
-.Lstrange_return_from_cplb_mgr:
- IDLE;
- CSYNC;
- JUMP .Lstrange_return_from_cplb_mgr;
-
-.Lcplb_error:
- R1 = sp;
- SP += -12;
- call _panic_cplb_error;
- SP += 12;
- JUMP _handle_bad_cplb;
-
-ENDPROC(__cplb_hdr)
diff --git a/arch/blackfin/mach-common/cplbinfo.c b/arch/blackfin/mach-common/cplbinfo.c
deleted file mode 100644
index a4f0b428a34..00000000000
--- a/arch/blackfin/mach-common/cplbinfo.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * File: arch/blackfin/mach-common/cplbinfo.c
- * Based on:
- * Author: Sonic Zhang <sonic.zhang@analog.com>
- *
- * Created: Jan. 2005
- * Description: Display CPLB status
- *
- * Modified:
- * 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.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/uaccess.h>
-
-#include <asm/current.h>
-#include <asm/system.h>
-#include <asm/cplb.h>
-#include <asm/blackfin.h>
-
-#define CPLB_I 1
-#define CPLB_D 2
-
-#define SYNC_SYS SSYNC()
-#define SYNC_CORE CSYNC()
-
-#define CPLB_BIT_PAGESIZE 0x30000
-
-static int page_size_table[4] = {
- 0x00000400, /* 1K */
- 0x00001000, /* 4K */
- 0x00100000, /* 1M */
- 0x00400000 /* 4M */
-};
-
-static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
-
-static int cplb_find_entry(unsigned long *cplb_addr,
- unsigned long *cplb_data, unsigned long addr,
- unsigned long data)
-{
- int ii;
-
- for (ii = 0; ii < 16; ii++)
- if (addr >= cplb_addr[ii] && addr < cplb_addr[ii] +
- page_size_table[(cplb_data[ii] & CPLB_BIT_PAGESIZE) >> 16]
- && (cplb_data[ii] == data))
- return ii;
-
- return -1;
-}
-
-static char *cplb_print_entry(char *buf, int type)
-{
- unsigned long *p_addr = dpdt_table;
- unsigned long *p_data = dpdt_table + 1;
- unsigned long *p_icount = dpdt_swapcount_table;
- unsigned long *p_ocount = dpdt_swapcount_table + 1;
- unsigned long *cplb_addr = (unsigned long *)DCPLB_ADDR0;
- unsigned long *cplb_data = (unsigned long *)DCPLB_DATA0;
- int entry = 0, used_cplb = 0;
-
- if (type == CPLB_I) {
- buf += sprintf(buf, "Instruction CPLB entry:\n");
- p_addr = ipdt_table;
- p_data = ipdt_table + 1;
- p_icount = ipdt_swapcount_table;
- p_ocount = ipdt_swapcount_table + 1;
- cplb_addr = (unsigned long *)ICPLB_ADDR0;
- cplb_data = (unsigned long *)ICPLB_DATA0;
- } else
- buf += sprintf(buf, "Data CPLB entry:\n");
-
- buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\tiCount\toCount\n");
-
- while (*p_addr != 0xffffffff) {
- entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data);
- if (entry >= 0)
- used_cplb |= 1 << entry;
-
- buf +=
- sprintf(buf,
- "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n",
- *p_addr, *p_data,
- page_size_string_table[(*p_data & 0x30000) >> 16],
- (*p_data & CPLB_VALID) ? 'Y' : 'N',
- (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount,
- *p_ocount);
-
- p_addr += 2;
- p_data += 2;
- p_icount += 2;
- p_ocount += 2;
- }
-
- if (used_cplb != 0xffff) {
- buf += sprintf(buf, "Unused/mismatched CPLBs:\n");
-
- for (entry = 0; entry < 16; entry++)
- if (0 == ((1 << entry) & used_cplb)) {
- int flags = cplb_data[entry];
- buf +=
- sprintf(buf,
- "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n",
- entry, cplb_addr[entry], flags,
- page_size_string_table[(flags &
- 0x30000) >>
- 16],
- (flags & CPLB_VALID) ? 'Y' : 'N',
- (flags & CPLB_LOCK) ? 'Y' : 'N');
- }
- }
-
- buf += sprintf(buf, "\n");
-
- return buf;
-}
-
-static int cplbinfo_proc_output(char *buf)
-{
- char *p;
-
- p = buf;
-
- p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
-
- if (bfin_read_IMEM_CONTROL() & ENICPLB)
- p = cplb_print_entry(p, CPLB_I);
- else
- p += sprintf(p, "Instruction CPLB is disabled.\n\n");
-
- if (bfin_read_DMEM_CONTROL() & ENDCPLB)
- p = cplb_print_entry(p, CPLB_D);
- else
- p += sprintf(p, "Data CPLB is disabled.\n");
-
- return p - buf;
-}
-
-static int cplbinfo_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len;
-
- len = cplbinfo_proc_output(page);
- if (len <= off + count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
-}
-
-static int cplbinfo_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- printk(KERN_INFO "Reset the CPLB swap in/out counts.\n");
- memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long));
- memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long));
-
- return count;
-}
-
-static int __init cplbinfo_init(void)
-{
- struct proc_dir_entry *entry;
-
- entry = create_proc_entry("cplbinfo", 0, NULL);
- if (!entry)
- return -ENOMEM;
-
- entry->read_proc = cplbinfo_read_proc;
- entry->write_proc = cplbinfo_write_proc;
- entry->data = NULL;
-
- return 0;
-}
-
-static void __exit cplbinfo_exit(void)
-{
- remove_proc_entry("cplbinfo", NULL);
-}
-
-module_init(cplbinfo_init);
-module_exit(cplbinfo_exit);
diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/mach-common/cplbmgr.S
deleted file mode 100644
index 6f909cbfac7..00000000000
--- a/arch/blackfin/mach-common/cplbmgr.S
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * File: arch/blackfin/mach-common/cplbmgtr.S
- * Based on:
- * Author: LG Soft India
- *
- * Created: ?
- * Description: CPLB replacement routine for CPLB mismatch
- *
- * Modified:
- * 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
- */
-
-/* Usage: int _cplb_mgr(is_data_miss,int enable_cache)
- * is_data_miss==2 => Mark as Dirty, write to the clean data page
- * is_data_miss==1 => Replace a data CPLB.
- * is_data_miss==0 => Replace an instruction CPLB.
- *
- * Returns:
- * CPLB_RELOADED => Successfully updated CPLB table.
- * CPLB_NO_UNLOCKED => All CPLBs are locked, so cannot be evicted.
- * This indicates that the CPLBs in the configuration
- * tablei are badly configured, as this should never
- * occur.
- * CPLB_NO_ADDR_MATCH => The address being accessed, that triggered the
- * exception, is not covered by any of the CPLBs in
- * the configuration table. The application is
- * presumably misbehaving.
- * CPLB_PROT_VIOL => The address being accessed, that triggered the
- * exception, was not a first-write to a clean Write
- * Back Data page, and so presumably is a genuine
- * violation of the page's protection attributes.
- * The application is misbehaving.
- */
-
-#include <linux/linkage.h>
-#include <asm/blackfin.h>
-#include <asm/cplb.h>
-
-#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
-.section .l1.text
-#else
-.text
-#endif
-
-.align 2;
-ENTRY(_cplb_mgr)
-
- [--SP]=( R7:4,P5:3 );
-
- CC = R0 == 2;
- IF CC JUMP .Ldcplb_write;
-
- CC = R0 == 0;
- IF !CC JUMP .Ldcplb_miss_compare;
-
- /* ICPLB Miss Exception. We need to choose one of the
- * currently-installed CPLBs, and replace it with one
- * from the configuration table.
- */
-
- P4.L = LO(ICPLB_FAULT_ADDR);
- P4.H = HI(ICPLB_FAULT_ADDR);
-
- P1 = 16;
- P5.L = _page_size_table;
- P5.H = _page_size_table;
-
- P0.L = LO(ICPLB_DATA0);
- P0.H = HI(ICPLB_DATA0);
- R4 = [P4]; /* Get faulting address*/
- R6 = 64; /* Advance past the fault address, which*/
- R6 = R6 + R4; /* we'll use if we find a match*/
- R3 = ((16 << 8) | 2); /* Extract mask, bits 16 and 17.*/
-
- R5 = 0;
-.Lisearch:
-
- R1 = [P0-0x100]; /* Address for this CPLB */
-
- R0 = [P0++]; /* Info for this CPLB*/
- CC = BITTST(R0,0); /* Is the CPLB valid?*/
- IF !CC JUMP .Lnomatch; /* Skip it, if not.*/
- CC = R4 < R1(IU); /* If fault address less than page start*/
- IF CC JUMP .Lnomatch; /* then skip this one.*/
- R2 = EXTRACT(R0,R3.L) (Z); /* Get page size*/
- P1 = R2;
- P1 = P5 + (P1<<2); /* index into page-size table*/
- R2 = [P1]; /* Get the page size*/
- R1 = R1 + R2; /* and add to page start, to get page end*/
- CC = R4 < R1(IU); /* and see whether fault addr is in page.*/
- IF !CC R4 = R6; /* If so, advance the address and finish loop.*/
- IF !CC JUMP .Lisearch_done;
-.Lnomatch:
- /* Go around again*/
- R5 += 1;
- CC = BITTST(R5, 4); /* i.e CC = R5 >= 16*/
- IF !CC JUMP .Lisearch;
-
-.Lisearch_done:
- I0 = R4; /* Fault address we'll search for*/
-
- /* set up pointers */
- P0.L = LO(ICPLB_DATA0);
- P0.H = HI(ICPLB_DATA0);
-
- /* The replacement procedure for ICPLBs */
-
- P4.L = LO(IMEM_CONTROL);
- P4.H = HI(IMEM_CONTROL);
-
- /* disable cplbs */
- R5 = [P4]; /* Control Register*/
- BITCLR(R5,ENICPLB_P);
- CLI R1;
- SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
- .align 8;
- [P4] = R5;
- SSYNC;
- STI R1;
-
- R1 = -1; /* end point comparison */
- R3 = 16; /* counter */
-
- /* Search through CPLBs for first non-locked entry */
- /* Overwrite it by moving everyone else up by 1 */
-.Licheck_lock:
- R0 = [P0++];
- R3 = R3 + R1;
- CC = R3 == R1;
- IF CC JUMP .Lall_locked;
- CC = BITTST(R0, 0); /* an invalid entry is good */
- IF !CC JUMP .Lifound_victim;
- CC = BITTST(R0,1); /* but a locked entry isn't */
- IF CC JUMP .Licheck_lock;
-
-.Lifound_victim:
-#ifdef CONFIG_CPLB_INFO
- R7 = [P0 - 0x104];
- P2.L = _ipdt_table;
- P2.H = _ipdt_table;
- P3.L = _ipdt_swapcount_table;
- P3.H = _ipdt_swapcount_table;
- P3 += -4;
-.Licount:
- R2 = [P2]; /* address from config table */
- P2 += 8;
- P3 += 8;
- CC = R2==-1;
- IF CC JUMP .Licount_done;
- CC = R7==R2;
- IF !CC JUMP .Licount;
- R7 = [P3];
- R7 += 1;
- [P3] = R7;
- CSYNC;
-.Licount_done:
-#endif
- LC0=R3;
- LSETUP(.Lis_move,.Lie_move) LC0;
-.Lis_move:
- R0 = [P0];
- [P0 - 4] = R0;
- R0 = [P0 - 0x100];
- [P0-0x104] = R0;
-.Lie_move:P0+=4;
-
- /* We've made space in the ICPLB table, so that ICPLB15
- * is now free to be overwritten. Next, we have to determine
- * which CPLB we need to install, from the configuration
- * table. This is a matter of getting the start-of-page
- * addresses and page-lengths from the config table, and
- * determining whether the fault address falls within that
- * range.
- */
-
- P2.L = _ipdt_table;
- P2.H = _ipdt_table;
-#ifdef CONFIG_CPLB_INFO
- P3.L = _ipdt_swapcount_table;
- P3.H = _ipdt_swapcount_table;
- P3 += -8;
-#endif
- P0.L = _page_size_table;
- P0.H = _page_size_table;
-
- /* Retrieve our fault address (which may have been advanced
- * because the faulting instruction crossed a page boundary).
- */
-
- R0 = I0;
-
- /* An extraction pattern, to get the page-size bits from
- * the CPLB data entry. Bits 16-17, so two bits at posn 16.
- */
-
- R1 = ((16<<8)|2);
-.Linext: R4 = [P2++]; /* address from config table */
- R2 = [P2++]; /* data from config table */
-#ifdef CONFIG_CPLB_INFO
- P3 += 8;
-#endif
-
- CC = R4 == -1; /* End of config table*/
- IF CC JUMP .Lno_page_in_table;
-
- /* See if failed address > start address */
- CC = R4 <= R0(IU);
- IF !CC JUMP .Linext;
-
- /* extract page size (17:16)*/
- R3 = EXTRACT(R2, R1.L) (Z);
-
- /* add page size to addr to get range */
-
- P5 = R3;
- P5 = P0 + (P5 << 2); /* scaled, for int access*/
- R3 = [P5];
- R3 = R3 + R4;
-
- /* See if failed address < (start address + page size) */
- CC = R0 < R3(IU);
- IF !CC JUMP .Linext;
-
- /* We've found a CPLB in the config table that covers
- * the faulting address, so install this CPLB into the
- * last entry of the table.
- */
-
- P1.L = LO(ICPLB_DATA15); /* ICPLB_DATA15 */
- P1.H = HI(ICPLB_DATA15);
- [P1] = R2;
- [P1-0x100] = R4;
-#ifdef CONFIG_CPLB_INFO
- R3 = [P3];
- R3 += 1;
- [P3] = R3;
-#endif
-
- /* P4 points to IMEM_CONTROL, and R5 contains its old
- * value, after we disabled ICPLBS. Re-enable them.
- */
-
- BITSET(R5,ENICPLB_P);
- CLI R2;
- SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
- .align 8;
- [P4] = R5;
- SSYNC;
- STI R2;
-
- ( R7:4,P5:3 ) = [SP++];
- R0 = CPLB_RELOADED;
- RTS;
-
-/* FAILED CASES*/
-.Lno_page_in_table:
- R0 = CPLB_NO_ADDR_MATCH;
- JUMP .Lfail_ret;
-
-.Lall_locked:
- R0 = CPLB_NO_UNLOCKED;
- JUMP .Lfail_ret;
-
-.Lprot_violation:
- R0 = CPLB_PROT_VIOL;
-
-.Lfail_ret:
- /* Make sure we turn protection/cache back on, even in the failing case */
- BITSET(R5,ENICPLB_P);
- CLI R2;
- SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
- .align 8;
- [P4] = R5;
- SSYNC;
- STI R2;
-
- ( R7:4,P5:3 ) = [SP++];
- RTS;
-
-.Ldcplb_write:
-
- /* if a DCPLB is marked as write-back (CPLB_WT==0), and
- * it is clean (CPLB_DIRTY==0), then a write to the
- * CPLB's page triggers a protection violation. We have to
- * mark the CPLB as dirty, to indicate that there are
- * pending writes associated with the CPLB.
- */
-
- P4.L = LO(DCPLB_STATUS);
- P4.H = HI(DCPLB_STATUS);
- P3.L = LO(DCPLB_DATA0);
- P3.H = HI(DCPLB_DATA0);
- R5 = [P4];
-
- /* A protection violation can be caused by more than just writes
- * to a clean WB page, so we have to ensure that:
- * - It's a write
- * - to a clean WB page
- * - and is allowed in the mode the access occurred.
- */
-
- CC = BITTST(R5, 16); /* ensure it was a write*/
- IF !CC JUMP .Lprot_violation;
-
- /* to check the rest, we have to retrieve the DCPLB.*/
-
- /* The low half of DCPLB_STATUS is a bit mask*/
-
- R2 = R5.L (Z); /* indicating which CPLB triggered the event.*/
- R3 = 30; /* so we can use this to determine the offset*/
- R2.L = SIGNBITS R2;
- R2 = R2.L (Z); /* into the DCPLB table.*/
- R3 = R3 - R2;
- P4 = R3;
- P3 = P3 + (P4<<2);
- R3 = [P3]; /* Retrieve the CPLB*/
-
- /* Now we can check whether it's a clean WB page*/
-
- CC = BITTST(R3, 14); /* 0==WB, 1==WT*/
- IF CC JUMP .Lprot_violation;
- CC = BITTST(R3, 7); /* 0 == clean, 1 == dirty*/
- IF CC JUMP .Lprot_violation;
-
- /* Check whether the write is allowed in the mode that was active.*/
-
- R2 = 1<<3; /* checking write in user mode*/
- CC = BITTST(R5, 17); /* 0==was user, 1==was super*/
- R5 = CC;
- R2 <<= R5; /* if was super, check write in super mode*/
- R2 = R3 & R2;
- CC = R2 == 0;
- IF CC JUMP .Lprot_violation;
-
- /* It's a genuine write-to-clean-page.*/
-
- BITSET(R3, 7); /* mark as dirty*/
- [P3] = R3; /* and write back.*/
- NOP;
- CSYNC;
- ( R7:4,P5:3 ) = [SP++];
- R0 = CPLB_RELOADED;
- RTS;
-
-.Ldcplb_miss_compare:
-
- /* Data CPLB Miss event. We need to choose a CPLB to
- * evict, and then locate a new CPLB to install from the
- * config table, that covers the faulting address.
- */
-
- P1.L = LO(DCPLB_DATA15);
- P1.H = HI(DCPLB_DATA15);
-
- P4.L = LO(DCPLB_FAULT_ADDR);
- P4.H = HI(DCPLB_FAULT_ADDR);
- R4 = [P4];
- I0 = R4;
-
- /* The replacement procedure for DCPLBs*/
-
- R6 = R1; /* Save for later*/
-
- /* Turn off CPLBs while we work.*/
- P4.L = LO(DMEM_CONTROL);
- P4.H = HI(DMEM_CONTROL);
- R5 = [P4];
- BITCLR(R5,ENDCPLB_P);
- CLI R0;
- SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
- .align 8;
- [P4] = R5;
- SSYNC;
- STI R0;
-
- /* Start looking for a CPLB to evict. Our order of preference
- * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
- * are no good.
- */
-
- I1.L = LO(DCPLB_DATA0);
- I1.H = HI(DCPLB_DATA0);
- P1 = 2;
- P2 = 16;
- I2.L = _dcplb_preference;
- I2.H = _dcplb_preference;
- LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
-.Lsdsearch1:
- R0 = [I2++]; /* Get the bits we're interested in*/
- P0 = I1; /* Go back to start of table*/
- LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
-.Lsdsearch2:
- R1 = [P0++]; /* Fetch each installed CPLB in turn*/
- R2 = R1 & R0; /* and test for interesting bits.*/
- CC = R2 == 0; /* If none are set, it'll do.*/
- IF !CC JUMP .Lskip_stack_check;
-
- R2 = [P0 - 0x104]; /* R2 - PageStart */
- P3.L = _page_size_table; /* retrieve end address */
- P3.H = _page_size_table; /* retrieve end address */
- R3 = 0x1002; /* 16th - position, 2 bits -length */
-#if ANOMALY_05000209
- nop; /* Anomaly 05000209 */
-#endif
- R7 = EXTRACT(R1,R3.l);
- R7 = R7 << 2; /* Page size index offset */
- P5 = R7;
- P3 = P3 + P5;
- R7 = [P3]; /* page size in bytes */
-
- R7 = R2 + R7; /* R7 - PageEnd */
- R4 = SP; /* Test SP is in range */
-
- CC = R7 < R4; /* if PageEnd < SP */
- IF CC JUMP .Ldfound_victim;
- R3 = 0x284; /* stack length from start of trap till
- * the point.
- * 20 stack locations for future modifications
- */
- R4 = R4 + R3;
- CC = R4 < R2; /* if SP + stacklen < PageStart */
- IF CC JUMP .Ldfound_victim;
-.Lskip_stack_check:
-
-.Ledsearch2: NOP;
-.Ledsearch1: NOP;
-
- /* If we got here, we didn't find a DCPLB we considered
- * replacable, which means all of them were locked.
- */
-
- JUMP .Lall_locked;
-.Ldfound_victim:
-
-#ifdef CONFIG_CPLB_INFO
- R7 = [P0 - 0x104];
- P2.L = _dpdt_table;
- P2.H = _dpdt_table;
- P3.L = _dpdt_swapcount_table;
- P3.H = _dpdt_swapcount_table;
- P3 += -4;
-.Ldicount:
- R2 = [P2];
- P2 += 8;
- P3 += 8;
- CC = R2==-1;
- IF CC JUMP .Ldicount_done;
- CC = R7==R2;
- IF !CC JUMP .Ldicount;
- R7 = [P3];
- R7 += 1;
- [P3] = R7;
-.Ldicount_done:
-#endif
-
- /* Clean down the hardware loops*/
- R2 = 0;
- LC1 = R2;
- LC0 = R2;
-
- /* There's a suitable victim in [P0-4] (because we've
- * advanced already).
- */
-
-.LDdoverwrite:
-
- /* [P0-4] is a suitable victim CPLB, so we want to
- * overwrite it by moving all the following CPLBs
- * one space closer to the start.
- */
-
- R1.L = LO(DCPLB_DATA16); /* DCPLB_DATA15 + 4 */
- R1.H = HI(DCPLB_DATA16);
- R0 = P0;
-
- /* If the victim happens to be in DCPLB15,
- * we don't need to move anything.
- */
-
- CC = R1 == R0;
- IF CC JUMP .Lde_moved;
- R1 = R1 - R0;
- R1 >>= 2;
- P1 = R1;
- LSETUP(.Lds_move, .Lde_move) LC0=P1;
-.Lds_move:
- R0 = [P0++]; /* move data */
- [P0 - 8] = R0;
- R0 = [P0-0x104] /* move address */
-.Lde_move: [P0-0x108] = R0;
-
- /* We've now made space in DCPLB15 for the new CPLB to be
- * installed. The next stage is to locate a CPLB in the
- * config table that covers the faulting address.
- */
-
-.Lde_moved:NOP;
- R0 = I0; /* Our faulting address */
-
- P2.L = _dpdt_table;
- P2.H = _dpdt_table;
-#ifdef CONFIG_CPLB_INFO
- P3.L = _dpdt_swapcount_table;
- P3.H = _dpdt_swapcount_table;
- P3 += -8;
-#endif
-
- P1.L = _page_size_table;
- P1.H = _page_size_table;
-
- /* An extraction pattern, to retrieve bits 17:16.*/
-
- R1 = (16<<8)|2;
-.Ldnext: R4 = [P2++]; /* address */
- R2 = [P2++]; /* data */
-#ifdef CONFIG_CPLB_INFO
- P3 += 8;
-#endif
-
- CC = R4 == -1;
- IF CC JUMP .Lno_page_in_table;
-
- /* See if failed address > start address */
- CC = R4 <= R0(IU);
- IF !CC JUMP .Ldnext;
-
- /* extract page size (17:16)*/
- R3 = EXTRACT(R2, R1.L) (Z);
-
- /* add page size to addr to get range */
-
- P5 = R3;
- P5 = P1 + (P5 << 2);
- R3 = [P5];
- R3 = R3 + R4;
-
- /* See if failed address < (start address + page size) */
- CC = R0 < R3(IU);
- IF !CC JUMP .Ldnext;
-
- /* We've found the CPLB that should be installed, so
- * write it into CPLB15, masking off any caching bits
- * if necessary.
- */
-
- P1.L = LO(DCPLB_DATA15);
- P1.H = HI(DCPLB_DATA15);
-
- /* If the DCPLB has cache bits set, but caching hasn't
- * been enabled, then we want to mask off the cache-in-L1
- * bit before installing. Moreover, if caching is off, we
- * also want to ensure that the DCPLB has WT mode set, rather
- * than WB, since WB pages still trigger first-write exceptions
- * even when not caching is off, and the page isn't marked as
- * cachable. Finally, we could mark the page as clean, not dirty,
- * but we choose to leave that decision to the user; if the user
- * chooses to have a CPLB pre-defined as dirty, then they always
- * pay the cost of flushing during eviction, but don't pay the
- * cost of first-write exceptions to mark the page as dirty.
- */
-
-#ifdef CONFIG_BFIN_WT
- BITSET(R6, 14); /* Set WT*/
-#endif
-
- [P1] = R2;
- [P1-0x100] = R4;
-#ifdef CONFIG_CPLB_INFO
- R3 = [P3];
- R3 += 1;
- [P3] = R3;
-#endif
-
- /* We've installed the CPLB, so re-enable CPLBs. P4
- * points to DMEM_CONTROL, and R5 is the value we
- * last wrote to it, when we were disabling CPLBs.
- */
-
- BITSET(R5,ENDCPLB_P);
- CLI R2;
- .align 8;
- [P4] = R5;
- SSYNC;
- STI R2;
-
- ( R7:4,P5:3 ) = [SP++];
- R0 = CPLB_RELOADED;
- RTS;
-ENDPROC(_cplb_mgr)
-
-.data
-.align 4;
-_page_size_table:
-.byte4 0x00000400; /* 1K */
-.byte4 0x00001000; /* 4K */
-.byte4 0x00100000; /* 1M */
-.byte4 0x00400000; /* 4M */
-
-.align 4;
-_dcplb_preference:
-.byte4 0x00000001; /* valid bit */
-.byte4 0x00000002; /* lock bit */
diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S
index 39fbc286110..b82c096e198 100644
--- a/arch/blackfin/mach-common/dpmc.S
+++ b/arch/blackfin/mach-common/dpmc.S
@@ -38,6 +38,9 @@ ENTRY(_unmask_wdog_wakeup_evt)
#if defined(CONFIG_BF561)
P0.H = hi(SICA_IWR1);
P0.L = lo(SICA_IWR1);
+#elif defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
+ P0.h = HI(SIC_IWR0);
+ P0.l = LO(SIC_IWR0);
#else
P0.h = HI(SIC_IWR);
P0.l = LO(SIC_IWR);
@@ -172,7 +175,7 @@ ENTRY(_sleep_mode)
call _set_sic_iwr;
R0 = 0xFFFF (Z);
- call _set_rtc_istat
+ call _set_rtc_istat;
P0.H = hi(PLL_CTL);
P0.L = lo(PLL_CTL);
@@ -210,7 +213,7 @@ ENTRY(_hibernate_mode)
call _set_sic_iwr;
R0 = 0xFFFF (Z);
- call _set_rtc_istat
+ call _set_rtc_istat;
P0.H = hi(VR_CTL);
P0.L = lo(VR_CTL);
@@ -236,7 +239,7 @@ ENTRY(_deep_sleep)
call _set_sic_iwr;
- call _set_sdram_srfs;
+ call _set_dram_srfs;
/* Clear all the interrupts,bits sticky */
R0 = 0xFFFF (Z);
@@ -253,7 +256,7 @@ ENTRY(_deep_sleep)
SSYNC;
IDLE;
- call _unset_sdram_srfs;
+ call _unset_dram_srfs;
call _test_pll_locked;
@@ -285,23 +288,22 @@ ENTRY(_sleep_deeper)
P3 = R0;
R0 = IWR_ENABLE(0);
call _set_sic_iwr;
- call _set_sdram_srfs;
+ call _set_dram_srfs; /* Set SDRAM Self Refresh */
/* Clear all the interrupts,bits sticky */
R0 = 0xFFFF (Z);
- call _set_rtc_istat
-
+ call _set_rtc_istat;
P0.H = hi(PLL_DIV);
P0.L = lo(PLL_DIV);
R6 = W[P0](z);
R0.L = 0xF;
- W[P0] = R0.l;
+ W[P0] = R0.l; /* Set Max VCO to SCLK divider */
P0.H = hi(PLL_CTL);
P0.L = lo(PLL_CTL);
R5 = W[P0](z);
R0.L = (CONFIG_MIN_VCO_HZ/CONFIG_CLKIN_HZ) << 9;
- W[P0] = R0.l;
+ W[P0] = R0.l; /* Set Min CLKIN to VCO multiplier */
SSYNC;
IDLE;
@@ -317,29 +319,28 @@ ENTRY(_sleep_deeper)
R1 = R1|R2;
R2 = DEPOSIT(R7, R1);
- W[P0] = R2;
+ W[P0] = R2; /* Set Min Core Voltage */
SSYNC;
IDLE;
call _test_pll_locked;
+ R0 = P3;
+ call _set_sic_iwr; /* Set Awake from IDLE */
+
P0.H = hi(PLL_CTL);
P0.L = lo(PLL_CTL);
R0 = W[P0](z);
BITSET (R0, 3);
- W[P0] = R0.L;
-
- R0 = P3;
- call _set_sic_iwr;
-
+ W[P0] = R0.L; /* Turn CCLK OFF */
SSYNC;
IDLE;
call _test_pll_locked;
R0 = IWR_ENABLE(0);
- call _set_sic_iwr;
+ call _set_sic_iwr; /* Set Awake from IDLE PLL */
P0.H = hi(VR_CTL);
P0.L = lo(VR_CTL);
@@ -352,15 +353,15 @@ ENTRY(_sleep_deeper)
P0.H = hi(PLL_DIV);
P0.L = lo(PLL_DIV);
- W[P0]= R6;
+ W[P0]= R6; /* Restore CCLK and SCLK divider */
P0.H = hi(PLL_CTL);
P0.L = lo(PLL_CTL);
- w[p0] = R5;
+ w[p0] = R5; /* Restore VCO multiplier */
IDLE;
call _test_pll_locked;
- call _unset_sdram_srfs;
+ call _unset_dram_srfs; /* SDRAM Self Refresh Off */
STI R4;
@@ -368,25 +369,47 @@ ENTRY(_sleep_deeper)
( R7:0, P5:0 ) = [SP++];
RTS;
-ENTRY(_set_sdram_srfs)
- /* set the sdram to self refresh mode */
+ENTRY(_set_dram_srfs)
+ /* set the dram to self refresh mode */
+#if defined(CONFIG_BF54x)
+ P0.H = hi(EBIU_RSTCTL);
+ P0.L = lo(EBIU_RSTCTL);
+ R2 = [P0];
+ R3.H = hi(SRREQ);
+ R3.L = lo(SRREQ);
+#else
P0.H = hi(EBIU_SDGCTL);
P0.L = lo(EBIU_SDGCTL);
R2 = [P0];
R3.H = hi(SRFS);
R3.L = lo(SRFS);
+#endif
R2 = R2|R3;
[P0] = R2;
ssync;
+#if defined(CONFIG_BF54x)
+.LSRR_MODE:
+ R2 = [P0];
+ CC = BITTST(R2, 4);
+ if !CC JUMP .LSRR_MODE;
+#endif
RTS;
-ENTRY(_unset_sdram_srfs)
- /* set the sdram out of self refresh mode */
+ENTRY(_unset_dram_srfs)
+ /* set the dram out of self refresh mode */
+#if defined(CONFIG_BF54x)
+ P0.H = hi(EBIU_RSTCTL);
+ P0.L = lo(EBIU_RSTCTL);
+ R2 = [P0];
+ R3.H = hi(SRREQ);
+ R3.L = lo(SRREQ);
+#else
P0.H = hi(EBIU_SDGCTL);
P0.L = lo(EBIU_SDGCTL);
R2 = [P0];
R3.H = hi(SRFS);
R3.L = lo(SRFS);
+#endif
R3 = ~R3;
R2 = R2&R3;
[P0] = R2;
@@ -394,8 +417,13 @@ ENTRY(_unset_sdram_srfs)
RTS;
ENTRY(_set_sic_iwr)
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x)
+ P0.H = hi(SIC_IWR0);
+ P0.L = lo(SIC_IWR0);
+#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 dc9d3ee2e69..fdd9bf43361 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -95,6 +95,9 @@ ENTRY(_ex_workaround_261)
R6 = 0x26; /* Data CPLB Miss */
cc = R6 == R7;
if cc jump _ex_dcplb_miss (BP);
+ R6 = 0x23; /* Data CPLB Miss */
+ cc = R6 == R7;
+ if cc jump _ex_dcplb_viol (BP);
/* Handle 0x23 Data CPLB Protection Violation
* and Data CPLB Multiple Hits - Linux Trap Zero
*/
@@ -102,17 +105,33 @@ ENTRY(_ex_workaround_261)
ENDPROC(_ex_workaround_261)
#else
+#ifdef CONFIG_MPU
+#define _ex_dviol _ex_dcplb_viol
+#else
#define _ex_dviol _ex_trap_c
+#endif
#define _ex_dmiss _ex_dcplb_miss
#define _ex_dmult _ex_trap_c
#endif
+
+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
+ R0 = SEQSTAT;
+ R1 = SP;
+ sp += -12;
+ call _cplb_hdr;
+ sp += 12;
+ CC = R0 == 0;
+ IF !CC JUMP _handle_bad_cplb;
+#else
call __cplb_hdr;
+#endif
DEBUG_START_HWTRACE(p5, r7)
RESTORE_ALL_SYS
SP = EX_SCRATCH_REG;
@@ -329,7 +348,7 @@ ENTRY(_exception_to_level5)
R7 = R7 + R6;
P5 = R7;
R1 = [P5];
- [SP + 8] = r1;
+ [SP + PT_SEQSTAT] = r1;
r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
SP += -12;
@@ -633,9 +652,7 @@ ENTRY(_ret_from_exception)
[sp + PT_IPEND] = r0;
1:
- r1 = 0x37(Z);
- r2 = ~r1;
- r2.h = 0;
+ r2 = LO(~0x37) (Z);
r0 = r2 & r0;
cc = r0 == 0;
if !cc jump 4f; /* if not return to user mode, get out */
@@ -1356,7 +1373,7 @@ ENTRY(_sys_call_table)
.long _sys_epoll_pwait
.long _sys_utimensat
.long _sys_signalfd
- .long _sys_timerfd
+ .long _sys_ni_syscall
.long _sys_eventfd /* 350 */
.long _sys_pread64
.long _sys_pwrite64
@@ -1364,6 +1381,7 @@ ENTRY(_sys_call_table)
.long _sys_set_robust_list
.long _sys_get_robust_list /* 355 */
.long _sys_fallocate
+ .long _sys_semtimedop
.rept NR_syscalls-(.-_sys_call_table)/4
.long _sys_ni_syscall
.endr
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
index 4de376418a1..7f752c87fe4 100644
--- a/arch/blackfin/mach-common/interrupt.S
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -34,9 +34,13 @@
#include <asm/entry.h>
#include <asm/asm-offsets.h>
#include <asm/trace.h>
+#include <asm/traps.h>
+#include <asm/thread_info.h>
#include <asm/mach-common/context.S>
+.extern _ret_from_exception
+
#ifdef CONFIG_I_ENTRY_L1
.section .l1.text
#else
@@ -117,8 +121,8 @@ __common_int_entry:
#if ANOMALY_05000283 || ANOMALY_05000315
cc = r7 == r7;
- p5.h = 0xffc0;
- p5.l = 0x0014;
+ p5.h = HI(CHIPID);
+ p5.l = LO(CHIPID);
if cc jump 1f;
r7.l = W[p5];
1:
@@ -134,26 +138,22 @@ __common_int_entry:
/* interrupt routine for ivhw - 5 */
ENTRY(_evt_ivhw)
- SAVE_CONTEXT
+ SAVE_ALL_SYS
#ifdef CONFIG_FRAME_POINTER
fp = 0;
#endif
+
#if ANOMALY_05000283
cc = r7 == r7;
- p5.h = 0xffc0;
- p5.l = 0x0014;
+ p5.h = HI(CHIPID);
+ p5.l = LO(CHIPID);
if cc jump 1f;
r7.l = W[p5];
1:
#endif
- trace_buffer_stop(p0, r0);
-
- r0 = IRQ_HWERR;
- r1 = sp;
-
#ifdef CONFIG_HARDWARE_PM
- r7 = SEQSTAT;
+ r7 = [sp + PT_SEQSTAT];
r7 = r7 >>> 0xe;
r6 = 0x1F;
r7 = r7 & r6;
@@ -161,11 +161,29 @@ ENTRY(_evt_ivhw)
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);
+ r0 = [p2];
+ [sp + PT_IPEND] = r0;
+
+ /* set the EXCAUSE to HWERR for trap_c */
+ r0 = [sp + PT_SEQSTAT];
+ R1.L = LO(VEC_HWERR);
+ R1.H = HI(VEC_HWERR);
+ R0 = R0 | R1;
+ [sp + PT_SEQSTAT] = R0;
+
+ r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
SP += -12;
- call _irq_panic;
+ call _trap_c;
SP += 12;
+
+ call _ret_from_exception;
+.Lcommon_restore_all_sys:
+ RESTORE_ALL_SYS
rti;
+
#ifdef CONFIG_HARDWARE_PM
.Lcall_do_ovf:
@@ -173,9 +191,11 @@ ENTRY(_evt_ivhw)
call _pm_overflow;
SP += 12;
- jump .Lcommon_restore_context;
+ jump .Lcommon_restore_all_sys;
#endif
+ENDPROC(_evt_ivhw)
+
/* Interrupt routine for evt2 (NMI).
* We don't actually use this, so just return.
* For inner circle type details, please see:
diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c
index 4882f0e801a..8d18d6b163b 100644
--- a/arch/blackfin/mach-common/ints-priority-dc.c
+++ b/arch/blackfin/mach-common/ints-priority-dc.c
@@ -222,11 +222,12 @@ static void bf561_gpio_unmask_irq(unsigned int irq)
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))) {
-
- ret = gpio_request(gpionr, "IRQ");
+ snprintf(buf, sizeof buf, "IRQ %d", irq);
+ ret = gpio_request(gpionr, buf);
if (ret)
return ret;
@@ -250,6 +251,7 @@ static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
{
unsigned int ret;
+ char buf[8];
u16 gpionr = irq - IRQ_PF0;
@@ -265,8 +267,8 @@ static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
-
- ret = gpio_request(gpionr, "IRQ");
+ snprintf(buf, sizeof buf, "IRQ %d", irq);
+ ret = gpio_request(gpionr, buf);
if (ret)
return ret;
diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c
index 147f0731087..dec42acb5de 100644
--- a/arch/blackfin/mach-common/ints-priority-sc.c
+++ b/arch/blackfin/mach-common/ints-priority-sc.c
@@ -313,6 +313,7 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
static void bfin_gpio_ack_irq(unsigned int irq)
{
u16 gpionr = irq - IRQ_PF0;
@@ -352,9 +353,11 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
{
unsigned int ret;
u16 gpionr = irq - IRQ_PF0;
+ char buf[8];
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
- ret = gpio_request(gpionr, "IRQ");
+ snprintf(buf, sizeof buf, "IRQ %d", irq);
+ ret = gpio_request(gpionr, buf);
if (ret)
return ret;
}
@@ -376,6 +379,7 @@ static int bfin_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) {
@@ -388,7 +392,8 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
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))) {
- ret = gpio_request(gpionr, "IRQ");
+ snprintf(buf, sizeof buf, "IRQ %d", irq);
+ ret = gpio_request(gpionr, buf);
if (ret)
return ret;
}
@@ -478,6 +483,10 @@ static void bfin_demux_gpio_irq(unsigned int intb_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;
@@ -544,13 +553,20 @@ void init_pint_lut(void)
}
-static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
-
static void bfin_gpio_ack_irq(unsigned int irq)
{
u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ u32 pintbit = PINT_BIT(pint_val);
+ u8 bank = PINT_2_BANK(pint_val);
+
+ if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
+ if (pint[bank]->invert_set & pintbit)
+ pint[bank]->invert_clear = pintbit;
+ else
+ pint[bank]->invert_set = pintbit;
+ }
+ pint[bank]->request = pintbit;
- pint[PINT_2_BANK(pint_val)]->request = PINT_BIT(pint_val);
SSYNC();
}
@@ -560,6 +576,13 @@ static void bfin_gpio_mask_ack_irq(unsigned int irq)
u32 pintbit = PINT_BIT(pint_val);
u8 bank = PINT_2_BANK(pint_val);
+ if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
+ if (pint[bank]->invert_set & pintbit)
+ pint[bank]->invert_clear = pintbit;
+ else
+ pint[bank]->invert_set = pintbit;
+ }
+
pint[bank]->request = pintbit;
pint[bank]->mask_clear = pintbit;
SSYNC();
@@ -587,7 +610,8 @@ static void bfin_gpio_unmask_irq(unsigned int irq)
static unsigned int bfin_gpio_irq_startup(unsigned int irq)
{
unsigned int ret;
- u16 gpionr = irq - IRQ_PA0;
+ char buf[8];
+ u16 gpionr = irq_to_gpio(irq);
u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
if (pint_val == IRQ_NOT_AVAIL) {
@@ -598,7 +622,8 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
}
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
- ret = gpio_request(gpionr, "IRQ");
+ snprintf(buf, sizeof buf, "IRQ %d", irq);
+ ret = gpio_request(gpionr, buf);
if (ret)
return ret;
}
@@ -611,16 +636,19 @@ 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);
+
bfin_gpio_mask_irq(irq);
- gpio_free(irq - IRQ_PA0);
- gpio_enabled[gpio_bank(irq - IRQ_PA0)] &= ~gpio_bit(irq - IRQ_PA0);
+ gpio_free(gpionr);
+ gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
}
static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
{
unsigned int ret;
- u16 gpionr = irq - IRQ_PA0;
+ char buf[8];
+ u16 gpionr = irq_to_gpio(irq);
u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
u32 pintbit = PINT_BIT(pint_val);
u8 bank = PINT_2_BANK(pint_val);
@@ -638,7 +666,8 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
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))) {
- ret = gpio_request(gpionr, "IRQ");
+ snprintf(buf, sizeof buf, "IRQ %d", irq);
+ ret = gpio_request(gpionr, buf);
if (ret)
return ret;
}
@@ -651,28 +680,33 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
gpio_direction_input(gpionr);
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
- pint[bank]->edge_set = pintbit;
- } else {
- pint[bank]->edge_clear = pintbit;
- }
-
if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
pint[bank]->invert_set = pintbit; /* low or falling edge denoted by one */
else
- pint[bank]->invert_set = pintbit; /* high or rising edge denoted by zero */
+ pint[bank]->invert_clear = pintbit; /* high or rising edge denoted by zero */
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
- pint[bank]->invert_set = pintbit;
- else
- pint[bank]->invert_set = pintbit;
+ if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
- SSYNC();
+ gpio_both_edge_triggered[bank] |= pintbit;
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ 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)) {
+ pint[bank]->edge_set = pintbit;
set_irq_handler(irq, handle_edge_irq);
- else
+ } else {
+ pint[bank]->edge_clear = pintbit;
set_irq_handler(irq, handle_level_irq);
+ }
+
+ SSYNC();
return 0;
}
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
index b22959b197e..606ded9ff4e 100644
--- a/arch/blackfin/mach-common/irqpanic.c
+++ b/arch/blackfin/mach-common/irqpanic.c
@@ -46,9 +46,6 @@ void irq_panic(int reason, struct pt_regs *regs) __attribute__ ((l1_text));
*/
asmlinkage void irq_panic(int reason, struct pt_regs *regs)
{
- int sig = 0;
- siginfo_t info;
-
#ifdef CONFIG_DEBUG_ICACHE_CHECK
unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
unsigned short i, j, die;
@@ -136,53 +133,6 @@ asmlinkage void irq_panic(int reason, struct pt_regs *regs)
}
#endif
- printk(KERN_EMERG "\n");
- printk(KERN_EMERG "Exception: IRQ 0x%x entered\n", reason);
- printk(KERN_EMERG " code=[0x%08lx], stack frame=0x%08lx, "
- " bad PC=0x%08lx\n",
- (unsigned long)regs->seqstat,
- (unsigned long)regs,
- (unsigned long)regs->pc);
- if (reason == 0x5) {
- printk(KERN_EMERG "----------- HARDWARE ERROR -----------\n");
-
- /* There is only need to check for Hardware Errors, since other
- * EXCEPTIONS are handled in TRAPS.c (MH)
- */
- switch (regs->seqstat & SEQSTAT_HWERRCAUSE) {
- case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): /* System MMR Error */
- info.si_code = BUS_ADRALN;
- sig = SIGBUS;
- printk(KERN_EMERG HWC_x2(KERN_EMERG));
- break;
- case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): /* External Memory Addressing Error */
- info.si_code = BUS_ADRERR;
- sig = SIGBUS;
- printk(KERN_EMERG HWC_x3(KERN_EMERG));
- break;
- case (SEQSTAT_HWERRCAUSE_PERF_FLOW): /* Performance Monitor Overflow */
- printk(KERN_EMERG HWC_x12(KERN_EMERG));
- break;
- case (SEQSTAT_HWERRCAUSE_RAISE_5): /* RAISE 5 instruction */
- printk(KERN_EMERG HWC_x18(KERN_EMERG));
- break;
- default: /* Reserved */
- printk(KERN_EMERG HWC_default(KERN_EMERG));
- break;
- }
- }
-
- regs->ipend = bfin_read_IPEND();
- dump_bfin_process(regs);
- dump_bfin_mem((void *)regs->pc);
- show_regs(regs);
- if (0 == (info.si_signo = sig) || 0 == user_mode(regs)) /* in kernelspace */
- panic("Unhandled IRQ or exceptions!\n");
- else { /* in userspace */
- info.si_errno = 0;
- info.si_addr = (void *)regs->pc;
- force_sig_info(sig, &info, current);
- }
}
#ifdef CONFIG_HARDWARE_PM
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
index dac51fb06f2..81930f7d06f 100644
--- a/arch/blackfin/mach-common/pm.c
+++ b/arch/blackfin/mach-common/pm.c
@@ -77,7 +77,15 @@ void bfin_pm_suspend_standby_enter(void)
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
+#else
bfin_write_SIC_IWR(IWR_ENABLE_ALL);
+#endif
local_irq_restore(flags);
}
@@ -85,7 +93,15 @@ void bfin_pm_suspend_standby_enter(void)
#if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR)
sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR);
+# 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
+# else
bfin_write_SIC_IWR(IWR_ENABLE_ALL);
+# endif
#endif /* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */
}