summaryrefslogtreecommitdiffstats
path: root/arch/blackfin/mach-common
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineering.com>2017-08-23 14:45:25 -0500
committerTimothy Pearson <tpearson@raptorengineering.com>2017-08-23 14:45:25 -0500
commitfcbb27b0ec6dcbc5a5108cb8fb19eae64593d204 (patch)
tree22962a4387943edc841c72a4e636a068c66d58fd /arch/blackfin/mach-common
downloadast2050-linux-kernel-fcbb27b0ec6dcbc5a5108cb8fb19eae64593d204.zip
ast2050-linux-kernel-fcbb27b0ec6dcbc5a5108cb8fb19eae64593d204.tar.gz
Initial import of modified Linux 2.6.28 tree
Original upstream URL: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git | branch linux-2.6.28.y
Diffstat (limited to 'arch/blackfin/mach-common')
-rw-r--r--arch/blackfin/mach-common/Makefile12
-rw-r--r--arch/blackfin/mach-common/arch_checks.c64
-rw-r--r--arch/blackfin/mach-common/cache.S95
-rw-r--r--arch/blackfin/mach-common/cpufreq.c198
-rw-r--r--arch/blackfin/mach-common/dpmc.c137
-rw-r--r--arch/blackfin/mach-common/dpmc_modes.S799
-rw-r--r--arch/blackfin/mach-common/entry.S1552
-rw-r--r--arch/blackfin/mach-common/head.S305
-rw-r--r--arch/blackfin/mach-common/interrupt.S247
-rw-r--r--arch/blackfin/mach-common/ints-priority.c1152
-rw-r--r--arch/blackfin/mach-common/irqpanic.c146
-rw-r--r--arch/blackfin/mach-common/lock.S223
-rw-r--r--arch/blackfin/mach-common/pm.c340
13 files changed, 5270 insertions, 0 deletions
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
new file mode 100644
index 0000000..e6ed57c
--- /dev/null
+++ b/arch/blackfin/mach-common/Makefile
@@ -0,0 +1,12 @@
+#
+# arch/blackfin/mach-common/Makefile
+#
+
+obj-y := \
+ cache.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
diff --git a/arch/blackfin/mach-common/arch_checks.c b/arch/blackfin/mach-common/arch_checks.c
new file mode 100644
index 0000000..98133b9
--- /dev/null
+++ b/arch/blackfin/mach-common/arch_checks.c
@@ -0,0 +1,64 @@
+/*
+ * File: arch/blackfin/mach-common/arch_checks.c
+ * Based on:
+ * Author: Robin Getz <rgetz@blackfin.uclinux.org>
+ *
+ * Created: 25Jul07
+ * Description: Do some checking to make sure things are OK
+ *
+ * Modified:
+ * Copyright 2004-2007 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 <asm/fixed_code.h>
+#include <mach/anomaly.h>
+#include <asm/clocks.h>
+
+#ifdef CONFIG_BFIN_KERNEL_CLOCK
+
+# if (CONFIG_VCO_HZ > CONFIG_MAX_VCO_HZ)
+# error "VCO selected is more than maximum value. Please change the VCO multipler"
+# endif
+
+# if (CONFIG_SCLK_HZ > CONFIG_MAX_SCLK_HZ)
+# error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier"
+# endif
+
+# if (CONFIG_SCLK_HZ < CONFIG_MIN_SCLK_HZ)
+# error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier"
+# endif
+
+# if (ANOMALY_05000273) && (CONFIG_SCLK_HZ * 2 > CONFIG_CCLK_HZ)
+# error "ANOMALY 05000273, please make sure CCLK is at least 2x SCLK"
+# endif
+
+# if (CONFIG_SCLK_HZ > CONFIG_CCLK_HZ) && (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ) && (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ)
+# error "Please select sclk less than cclk"
+# endif
+
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+#if CONFIG_BOOT_LOAD < FIXED_CODE_END
+# error "The kernel load address must be after the fixed code section"
+#endif
+
+#if (CONFIG_BOOT_LOAD & 0x3)
+# error "The kernel load address must be 4 byte aligned"
+#endif
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
new file mode 100644
index 0000000..a028e94
--- /dev/null
+++ b/arch/blackfin/mach-common/cache.S
@@ -0,0 +1,95 @@
+/*
+ * Blackfin cache control code
+ *
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/cache.h>
+#include <asm/page.h>
+
+.text
+
+/* Since all L1 caches work the same way, we use the same method for flushing
+ * them. Only the actual flush instruction differs. We write this in asm as
+ * GCC can be hard to coax into writing nice hardware loops.
+ *
+ * Also, we assume the following register setup:
+ * R0 = start address
+ * R1 = end address
+ */
+.macro do_flush flushins:req optflushins optnopins label
+
+ R2 = -L1_CACHE_BYTES;
+
+ /* start = (start & -L1_CACHE_BYTES) */
+ R0 = R0 & R2;
+
+ /* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */
+ R1 += -1;
+ R1 = R1 & R2;
+ R1 += L1_CACHE_BYTES;
+
+ /* count = (end - start) >> L1_CACHE_SHIFT */
+ R2 = R1 - R0;
+ R2 >>= L1_CACHE_SHIFT;
+ P1 = R2;
+
+.ifnb \label
+\label :
+.endif
+ P0 = R0;
+ LSETUP (1f, 2f) LC1 = P1;
+1:
+.ifnb \optflushins
+ \optflushins [P0];
+.endif
+.ifb \optnopins
+2:
+.endif
+ \flushins [P0++];
+.ifnb \optnopins
+2: \optnopins;
+.endif
+
+ RTS;
+.endm
+
+/* Invalidate all instruction cache lines assocoiated with this memory area */
+ENTRY(_blackfin_icache_flush_range)
+ do_flush IFLUSH, , nop
+ENDPROC(_blackfin_icache_flush_range)
+
+/* Flush all cache lines assocoiated with this area of memory. */
+ENTRY(_blackfin_icache_dcache_flush_range)
+ do_flush FLUSH, IFLUSH
+ENDPROC(_blackfin_icache_dcache_flush_range)
+
+/* Throw away all D-cached data in specified region without any obligation to
+ * write them back. Since the Blackfin ISA does not have an "invalidate"
+ * instruction, we use flush/invalidate. Perhaps as a speed optimization we
+ * could bang on the DTEST MMRs ...
+ */
+ENTRY(_blackfin_dcache_invalidate_range)
+ do_flush FLUSHINV
+ENDPROC(_blackfin_dcache_invalidate_range)
+
+/* Flush all data cache lines assocoiated with this memory area */
+ENTRY(_blackfin_dcache_flush_range)
+ do_flush FLUSH, , , .Ldfr
+ENDPROC(_blackfin_dcache_flush_range)
+
+/* Our headers convert the page structure to an address, so just need to flush
+ * its contents like normal. We know the start address is page aligned (which
+ * greater than our cache alignment), as is the end address. So just jump into
+ * the middle of the dcache flush function.
+ */
+ENTRY(_blackfin_dflush_page)
+ P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT);
+ jump .Ldfr;
+ENDPROC(_blackfin_dflush_page)
diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c
new file mode 100644
index 0000000..dda5443
--- /dev/null
+++ b/arch/blackfin/mach-common/cpufreq.c
@@ -0,0 +1,198 @@
+/*
+ * File: arch/blackfin/mach-common/cpufreq.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: Blackfin core clock scaling
+ *
+ * Modified:
+ * Copyright 2004-2008 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/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/fs.h>
+#include <asm/blackfin.h>
+#include <asm/time.h>
+
+
+/* this is the table of CCLK frequencies, in Hz */
+/* .index is the entry in the auxillary dpm_state_table[] */
+static struct cpufreq_frequency_table bfin_freq_table[] = {
+ {
+ .frequency = CPUFREQ_TABLE_END,
+ .index = 0,
+ },
+ {
+ .frequency = CPUFREQ_TABLE_END,
+ .index = 1,
+ },
+ {
+ .frequency = CPUFREQ_TABLE_END,
+ .index = 2,
+ },
+ {
+ .frequency = CPUFREQ_TABLE_END,
+ .index = 0,
+ },
+};
+
+static struct bfin_dpm_state {
+ unsigned int csel; /* system clock divider */
+ unsigned int tscale; /* change the divider on the core timer interrupt */
+} dpm_state_table[3];
+
+/*
+ normalized to maximum frequncy offset for CYCLES,
+ used in time-ts cycles clock source, but could be used
+ somewhere also.
+ */
+unsigned long long __bfin_cycles_off;
+unsigned int __bfin_cycles_mod;
+
+/**************************************************************************/
+
+static unsigned int bfin_getfreq_khz(unsigned int cpu)
+{
+ /* The driver only support single cpu */
+ if (cpu != 0)
+ return -1;
+
+ return get_cclk() / 1000;
+}
+
+
+static int bfin_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ unsigned int index, plldiv, tscale;
+ unsigned long flags, cclk_hz;
+ struct cpufreq_freqs freqs;
+ cycles_t cycles;
+
+ if (cpufreq_frequency_table_target(policy, bfin_freq_table,
+ target_freq, relation, &index))
+ return -EINVAL;
+
+ cclk_hz = bfin_freq_table[index].frequency;
+
+ freqs.old = bfin_getfreq_khz(0);
+ freqs.new = cclk_hz;
+ freqs.cpu = 0;
+
+ pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
+ cclk_hz, target_freq, freqs.old);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ local_irq_save(flags);
+ plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
+ tscale = dpm_state_table[index].tscale;
+ bfin_write_PLL_DIV(plldiv);
+ /* we have to adjust the core timer, because it is using cclk */
+ bfin_write_TSCALE(tscale);
+ cycles = get_cycles();
+ SSYNC();
+ cycles += 10; /* ~10 cycles we loose after get_cycles() */
+ __bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index);
+ __bfin_cycles_mod = index;
+ local_irq_restore(flags);
+ /* TODO: just test case for cycles clock source, remove later */
+ pr_debug("cpufreq: done\n");
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return 0;
+}
+
+static int bfin_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, bfin_freq_table);
+}
+
+static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
+{
+
+ unsigned long cclk, sclk, csel, min_cclk;
+ int index;
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ cclk = get_cclk() / 1000;
+ sclk = get_sclk() / 1000;
+
+#if ANOMALY_05000273 || (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_DCACHE))
+ min_cclk = sclk * 2;
+#else
+ min_cclk = sclk;
+#endif
+ csel = ((bfin_read_PLL_DIV() & CSEL) >> 4);
+
+ for (index = 0; (cclk >> index) >= min_cclk && csel <= 3; index++, csel++) {
+ bfin_freq_table[index].frequency = cclk >> index;
+ dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */
+ dpm_state_table[index].tscale = (TIME_SCALE / (1 << csel)) - 1;
+
+ pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n",
+ bfin_freq_table[index].frequency,
+ dpm_state_table[index].csel,
+ dpm_state_table[index].tscale);
+ }
+
+ policy->cpuinfo.transition_latency = (bfin_read_PLL_LOCKCNT() / (sclk / 1000000)) * 1000;
+ /*Now ,only support one cpu */
+ policy->cur = cclk;
+ cpufreq_frequency_table_get_attr(bfin_freq_table, policy->cpu);
+ return cpufreq_frequency_table_cpuinfo(policy, bfin_freq_table);
+}
+
+static struct freq_attr *bfin_freq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver bfin_driver = {
+ .verify = bfin_verify_speed,
+ .target = bfin_target,
+ .get = bfin_getfreq_khz,
+ .init = __bfin_cpu_init,
+ .name = "bfin cpufreq",
+ .owner = THIS_MODULE,
+ .attr = bfin_freq_attr,
+};
+
+static int __init bfin_cpu_init(void)
+{
+ return cpufreq_register_driver(&bfin_driver);
+}
+
+static void __exit bfin_cpu_exit(void)
+{
+ cpufreq_unregister_driver(&bfin_driver);
+}
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("cpufreq driver for Blackfin");
+MODULE_LICENSE("GPL");
+
+module_init(bfin_cpu_init);
+module_exit(bfin_cpu_exit);
diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c
new file mode 100644
index 0000000..02c7efd
--- /dev/null
+++ b/arch/blackfin/mach-common/dpmc.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/cpufreq.h>
+
+#include <asm/delay.h>
+#include <asm/dpmc.h>
+
+#define DRIVER_NAME "bfin dpmc"
+
+#define dprintk(msg...) \
+ cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, DRIVER_NAME, msg)
+
+struct bfin_dpmc_platform_data *pdata;
+
+/**
+ * bfin_set_vlev - Update VLEV field in VR_CTL Reg.
+ * Avoid BYPASS sequence
+ */
+static void bfin_set_vlev(unsigned int vlev)
+{
+ unsigned pll_lcnt;
+
+ pll_lcnt = bfin_read_PLL_LOCKCNT();
+
+ bfin_write_PLL_LOCKCNT(1);
+ bfin_write_VR_CTL((bfin_read_VR_CTL() & ~VLEV) | vlev);
+ bfin_write_PLL_LOCKCNT(pll_lcnt);
+}
+
+/**
+ * bfin_get_vlev - Get CPU specific VLEV from platform device data
+ */
+static unsigned int bfin_get_vlev(unsigned int freq)
+{
+ int i;
+
+ if (!pdata)
+ goto err_out;
+
+ freq >>= 16;
+
+ for (i = 0; i < pdata->tabsize; i++)
+ if (freq <= (pdata->tuple_tab[i] & 0xFFFF))
+ return pdata->tuple_tab[i] >> 16;
+
+err_out:
+ printk(KERN_WARNING "DPMC: No suitable CCLK VDDINT voltage pair found\n");
+ return VLEV_120;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int
+vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
+{
+ struct cpufreq_freqs *freq = data;
+
+ if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) {
+ bfin_set_vlev(bfin_get_vlev(freq->new));
+ udelay(pdata->vr_settling_time); /* Wait until Volatge settled */
+
+ } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)
+ bfin_set_vlev(bfin_get_vlev(freq->new));
+
+ return 0;
+}
+
+static struct notifier_block vreg_cpufreq_notifier_block = {
+ .notifier_call = vreg_cpufreq_notifier
+};
+#endif /* CONFIG_CPU_FREQ */
+
+/**
+ * bfin_dpmc_probe -
+ *
+ */
+static int __devinit bfin_dpmc_probe(struct platform_device *pdev)
+{
+ if (pdev->dev.platform_data)
+ pdata = pdev->dev.platform_data;
+ else
+ return -EINVAL;
+
+ return cpufreq_register_notifier(&vreg_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+/**
+ * bfin_dpmc_remove -
+ */
+static int __devexit bfin_dpmc_remove(struct platform_device *pdev)
+{
+ pdata = NULL;
+ return cpufreq_unregister_notifier(&vreg_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+struct platform_driver bfin_dpmc_device_driver = {
+ .probe = bfin_dpmc_probe,
+ .remove = __devexit_p(bfin_dpmc_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+/**
+ * bfin_dpmc_init - Init driver
+ */
+static int __init bfin_dpmc_init(void)
+{
+ return platform_driver_register(&bfin_dpmc_device_driver);
+}
+module_init(bfin_dpmc_init);
+
+/**
+ * bfin_dpmc_exit - break down driver
+ */
+static void __exit bfin_dpmc_exit(void)
+{
+ platform_driver_unregister(&bfin_dpmc_device_driver);
+}
+module_exit(bfin_dpmc_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("cpu power management driver for Blackfin");
+MODULE_LICENSE("GPL");
diff --git a/arch/blackfin/mach-common/dpmc_modes.S b/arch/blackfin/mach-common/dpmc_modes.S
new file mode 100644
index 0000000..ad5431e
--- /dev/null
+++ b/arch/blackfin/mach-common/dpmc_modes.S
@@ -0,0 +1,799 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <mach/irq.h>
+#include <asm/dpmc.h>
+
+.section .l1.text
+
+ENTRY(_sleep_mode)
+ [--SP] = ( R7:0, P5:0 );
+ [--SP] = RETS;
+
+ call _set_sic_iwr;
+
+ R0 = 0xFFFF (Z);
+ call _set_rtc_istat;
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ R1 = W[P0](z);
+ BITSET (R1, 3);
+ W[P0] = R1.L;
+
+ CLI R2;
+ SSYNC;
+ IDLE;
+ STI R2;
+
+ 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);
+ P0.L = lo(PLL_CTL);
+ R7 = w[p0](z);
+ BITCLR (R7, 3);
+ BITCLR (R7, 5);
+ w[p0] = R7.L;
+ IDLE;
+ call _test_pll_locked;
+
+ RETS = [SP++];
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+ENDPROC(_sleep_mode)
+
+ENTRY(_hibernate_mode)
+ [--SP] = ( R7:0, P5:0 );
+ [--SP] = RETS;
+
+ R3 = R0;
+ R0 = IWR_DISABLE_ALL;
+ R1 = IWR_DISABLE_ALL;
+ R2 = IWR_DISABLE_ALL;
+ call _set_sic_iwr;
+ call _set_dram_srfs;
+ SSYNC;
+
+ R0 = 0xFFFF (Z);
+ call _set_rtc_istat;
+
+ P0.H = hi(VR_CTL);
+ P0.L = lo(VR_CTL);
+
+ W[P0] = R3.L;
+ CLI R2;
+ IDLE;
+.Lforever:
+ jump .Lforever;
+ENDPROC(_hibernate_mode)
+
+ENTRY(_sleep_deeper)
+ [--SP] = ( R7:0, P5:0 );
+ [--SP] = RETS;
+
+ 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 */
+
+ /* Clear all the interrupts,bits sticky */
+ R0 = 0xFFFF (Z);
+ 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; /* 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; /* Set Min CLKIN to VCO multiplier */
+
+ SSYNC;
+ IDLE;
+
+ call _test_pll_locked;
+
+ P0.H = hi(VR_CTL);
+ P0.L = lo(VR_CTL);
+ R7 = W[P0](z);
+ R1 = 0x6;
+ R1 <<= 16;
+ R2 = 0x0404(Z);
+ R1 = R1|R2;
+
+ R2 = DEPOSIT(R7, R1);
+ W[P0] = R2; /* Set Min Core Voltage */
+
+ SSYNC;
+ IDLE;
+
+ call _test_pll_locked;
+
+ R0 = P3;
+ R1 = P4;
+ R3 = P5;
+ 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; /* Turn CCLK OFF */
+ SSYNC;
+ IDLE;
+
+ 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);
+ P0.L = lo(VR_CTL);
+ W[P0]= R7;
+
+ SSYNC;
+ IDLE;
+
+ call _test_pll_locked;
+
+ P0.H = hi(PLL_DIV);
+ P0.L = lo(PLL_DIV);
+ W[P0]= R6; /* Restore CCLK and SCLK divider */
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ w[p0] = R5; /* Restore VCO multiplier */
+ IDLE;
+ call _test_pll_locked;
+
+ call _unset_dram_srfs; /* SDRAM Self Refresh Off */
+
+ STI R4;
+
+ RETS = [SP++];
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+ENDPROC(_sleep_deeper)
+
+ENTRY(_set_dram_srfs)
+ /* set the dram to self refresh mode */
+ SSYNC;
+#if defined(EBIU_RSTCTL) /* DDR */
+ P0.H = hi(EBIU_RSTCTL);
+ P0.L = lo(EBIU_RSTCTL);
+ R2 = [P0];
+ BITSET(R2, 3); /* SRREQ enter self-refresh mode */
+ [P0] = R2;
+ SSYNC;
+1:
+ R2 = [P0];
+ CC = BITTST(R2, 4);
+ if !CC JUMP 1b;
+#else /* SDRAM */
+ P0.L = lo(EBIU_SDGCTL);
+ P0.H = hi(EBIU_SDGCTL);
+ R2 = [P0];
+ BITSET(R2, 24); /* SRFS enter self-refresh mode */
+ [P0] = R2;
+ SSYNC;
+
+ P0.L = lo(EBIU_SDSTAT);
+ P0.H = hi(EBIU_SDSTAT);
+1:
+ R2 = w[P0];
+ SSYNC;
+ cc = BITTST(R2, 1); /* SDSRA poll self-refresh status */
+ if !cc jump 1b;
+
+ P0.L = lo(EBIU_SDGCTL);
+ P0.H = hi(EBIU_SDGCTL);
+ R2 = [P0];
+ BITCLR(R2, 0); /* SCTLE disable CLKOUT */
+ [P0] = R2;
+#endif
+ RTS;
+ENDPROC(_set_dram_srfs)
+
+ENTRY(_unset_dram_srfs)
+ /* set the dram out of self refresh mode */
+#if defined(EBIU_RSTCTL) /* DDR */
+ P0.H = hi(EBIU_RSTCTL);
+ P0.L = lo(EBIU_RSTCTL);
+ R2 = [P0];
+ BITCLR(R2, 3); /* clear SRREQ bit */
+ [P0] = R2;
+#elif defined(EBIU_SDGCTL) /* SDRAM */
+
+ P0.L = lo(EBIU_SDGCTL); /* release CLKOUT from self-refresh */
+ P0.H = hi(EBIU_SDGCTL);
+ R2 = [P0];
+ BITSET(R2, 0); /* SCTLE enable CLKOUT */
+ [P0] = R2
+ SSYNC;
+
+ P0.L = lo(EBIU_SDGCTL); /* release SDRAM from self-refresh */
+ P0.H = hi(EBIU_SDGCTL);
+ R2 = [P0];
+ BITCLR(R2, 24); /* clear SRFS bit */
+ [P0] = R2
+#endif
+ SSYNC;
+ RTS;
+ENDPROC(_unset_dram_srfs)
+
+ENTRY(_set_sic_iwr)
+#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;
+ENDPROC(_set_sic_iwr)
+
+ENTRY(_set_rtc_istat)
+#ifndef CONFIG_BF561
+ P0.H = hi(RTC_ISTAT);
+ P0.L = lo(RTC_ISTAT);
+ w[P0] = R0.L;
+ SSYNC;
+#elif (ANOMALY_05000371)
+ nop;
+ nop;
+ nop;
+ nop;
+#endif
+ RTS;
+ENDPROC(_set_rtc_istat)
+
+ENTRY(_test_pll_locked)
+ P0.H = hi(PLL_STAT);
+ P0.L = lo(PLL_STAT);
+1:
+ R0 = W[P0] (Z);
+ CC = BITTST(R0,5);
+ IF !CC JUMP 1b;
+ RTS;
+ENDPROC(_test_pll_locked)
+
+.section .text
+
+ENTRY(_do_hibernate)
+ [--SP] = ( R7:0, P5:0 );
+ [--SP] = RETS;
+ /* Save System MMRs */
+ R2 = R0;
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+
+#ifdef SIC_IMASK0
+ PM_SYS_PUSH(SIC_IMASK0)
+#endif
+#ifdef SIC_IMASK1
+ PM_SYS_PUSH(SIC_IMASK1)
+#endif
+#ifdef SIC_IMASK2
+ PM_SYS_PUSH(SIC_IMASK2)
+#endif
+#ifdef SIC_IMASK
+ PM_SYS_PUSH(SIC_IMASK)
+#endif
+#ifdef SICA_IMASK0
+ PM_SYS_PUSH(SICA_IMASK0)
+#endif
+#ifdef SICA_IMASK1
+ PM_SYS_PUSH(SICA_IMASK1)
+#endif
+#ifdef SIC_IAR2
+ PM_SYS_PUSH(SIC_IAR0)
+ PM_SYS_PUSH(SIC_IAR1)
+ PM_SYS_PUSH(SIC_IAR2)
+#endif
+#ifdef SIC_IAR3
+ PM_SYS_PUSH(SIC_IAR3)
+#endif
+#ifdef SIC_IAR4
+ PM_SYS_PUSH(SIC_IAR4)
+ PM_SYS_PUSH(SIC_IAR5)
+ PM_SYS_PUSH(SIC_IAR6)
+#endif
+#ifdef SIC_IAR7
+ PM_SYS_PUSH(SIC_IAR7)
+#endif
+#ifdef SIC_IAR8
+ PM_SYS_PUSH(SIC_IAR8)
+ PM_SYS_PUSH(SIC_IAR9)
+ PM_SYS_PUSH(SIC_IAR10)
+ PM_SYS_PUSH(SIC_IAR11)
+#endif
+
+#ifdef SICA_IAR0
+ PM_SYS_PUSH(SICA_IAR0)
+ PM_SYS_PUSH(SICA_IAR1)
+ PM_SYS_PUSH(SICA_IAR2)
+ PM_SYS_PUSH(SICA_IAR3)
+ PM_SYS_PUSH(SICA_IAR4)
+ PM_SYS_PUSH(SICA_IAR5)
+ PM_SYS_PUSH(SICA_IAR6)
+ PM_SYS_PUSH(SICA_IAR7)
+#endif
+
+#ifdef SIC_IWR
+ PM_SYS_PUSH(SIC_IWR)
+#endif
+#ifdef SIC_IWR0
+ PM_SYS_PUSH(SIC_IWR0)
+#endif
+#ifdef SIC_IWR1
+ PM_SYS_PUSH(SIC_IWR1)
+#endif
+#ifdef SIC_IWR2
+ PM_SYS_PUSH(SIC_IWR2)
+#endif
+#ifdef SICA_IWR0
+ PM_SYS_PUSH(SICA_IWR0)
+#endif
+#ifdef SICA_IWR1
+ PM_SYS_PUSH(SICA_IWR1)
+#endif
+
+#ifdef PINT0_ASSIGN
+ PM_SYS_PUSH(PINT0_ASSIGN)
+ PM_SYS_PUSH(PINT1_ASSIGN)
+ PM_SYS_PUSH(PINT2_ASSIGN)
+ PM_SYS_PUSH(PINT3_ASSIGN)
+#endif
+
+ PM_SYS_PUSH(EBIU_AMBCTL0)
+ PM_SYS_PUSH(EBIU_AMBCTL1)
+ PM_SYS_PUSH16(EBIU_AMGCTL)
+
+#ifdef EBIU_FCTL
+ PM_SYS_PUSH(EBIU_MBSCTL)
+ PM_SYS_PUSH(EBIU_MODE)
+ PM_SYS_PUSH(EBIU_FCTL)
+#endif
+
+ PM_SYS_PUSH16(SYSCR)
+
+ /* Save Core MMRs */
+ P0.H = hi(SRAM_BASE_ADDRESS);
+ P0.L = lo(SRAM_BASE_ADDRESS);
+
+ PM_PUSH(DMEM_CONTROL)
+ PM_PUSH(DCPLB_ADDR0)
+ PM_PUSH(DCPLB_ADDR1)
+ PM_PUSH(DCPLB_ADDR2)
+ PM_PUSH(DCPLB_ADDR3)
+ PM_PUSH(DCPLB_ADDR4)
+ PM_PUSH(DCPLB_ADDR5)
+ PM_PUSH(DCPLB_ADDR6)
+ PM_PUSH(DCPLB_ADDR7)
+ PM_PUSH(DCPLB_ADDR8)
+ PM_PUSH(DCPLB_ADDR9)
+ PM_PUSH(DCPLB_ADDR10)
+ PM_PUSH(DCPLB_ADDR11)
+ PM_PUSH(DCPLB_ADDR12)
+ PM_PUSH(DCPLB_ADDR13)
+ PM_PUSH(DCPLB_ADDR14)
+ PM_PUSH(DCPLB_ADDR15)
+ PM_PUSH(DCPLB_DATA0)
+ PM_PUSH(DCPLB_DATA1)
+ PM_PUSH(DCPLB_DATA2)
+ PM_PUSH(DCPLB_DATA3)
+ PM_PUSH(DCPLB_DATA4)
+ PM_PUSH(DCPLB_DATA5)
+ PM_PUSH(DCPLB_DATA6)
+ PM_PUSH(DCPLB_DATA7)
+ PM_PUSH(DCPLB_DATA8)
+ PM_PUSH(DCPLB_DATA9)
+ PM_PUSH(DCPLB_DATA10)
+ PM_PUSH(DCPLB_DATA11)
+ PM_PUSH(DCPLB_DATA12)
+ PM_PUSH(DCPLB_DATA13)
+ PM_PUSH(DCPLB_DATA14)
+ PM_PUSH(DCPLB_DATA15)
+ PM_PUSH(IMEM_CONTROL)
+ PM_PUSH(ICPLB_ADDR0)
+ PM_PUSH(ICPLB_ADDR1)
+ PM_PUSH(ICPLB_ADDR2)
+ PM_PUSH(ICPLB_ADDR3)
+ PM_PUSH(ICPLB_ADDR4)
+ PM_PUSH(ICPLB_ADDR5)
+ PM_PUSH(ICPLB_ADDR6)
+ PM_PUSH(ICPLB_ADDR7)
+ PM_PUSH(ICPLB_ADDR8)
+ PM_PUSH(ICPLB_ADDR9)
+ PM_PUSH(ICPLB_ADDR10)
+ PM_PUSH(ICPLB_ADDR11)
+ PM_PUSH(ICPLB_ADDR12)
+ PM_PUSH(ICPLB_ADDR13)
+ PM_PUSH(ICPLB_ADDR14)
+ PM_PUSH(ICPLB_ADDR15)
+ PM_PUSH(ICPLB_DATA0)
+ PM_PUSH(ICPLB_DATA1)
+ PM_PUSH(ICPLB_DATA2)
+ PM_PUSH(ICPLB_DATA3)
+ PM_PUSH(ICPLB_DATA4)
+ PM_PUSH(ICPLB_DATA5)
+ PM_PUSH(ICPLB_DATA6)
+ PM_PUSH(ICPLB_DATA7)
+ PM_PUSH(ICPLB_DATA8)
+ PM_PUSH(ICPLB_DATA9)
+ PM_PUSH(ICPLB_DATA10)
+ PM_PUSH(ICPLB_DATA11)
+ PM_PUSH(ICPLB_DATA12)
+ PM_PUSH(ICPLB_DATA13)
+ PM_PUSH(ICPLB_DATA14)
+ PM_PUSH(ICPLB_DATA15)
+ PM_PUSH(EVT0)
+ PM_PUSH(EVT1)
+ PM_PUSH(EVT2)
+ PM_PUSH(EVT3)
+ PM_PUSH(EVT4)
+ PM_PUSH(EVT5)
+ PM_PUSH(EVT6)
+ PM_PUSH(EVT7)
+ PM_PUSH(EVT8)
+ PM_PUSH(EVT9)
+ PM_PUSH(EVT10)
+ PM_PUSH(EVT11)
+ PM_PUSH(EVT12)
+ PM_PUSH(EVT13)
+ PM_PUSH(EVT14)
+ PM_PUSH(EVT15)
+ PM_PUSH(IMASK)
+ PM_PUSH(ILAT)
+ PM_PUSH(IPRIO)
+ PM_PUSH(TCNTL)
+ PM_PUSH(TPERIOD)
+ PM_PUSH(TSCALE)
+ PM_PUSH(TCOUNT)
+ PM_PUSH(TBUFCTL)
+
+ /* Save Core Registers */
+ [--sp] = SYSCFG;
+ [--sp] = ( R7:0, P5:0 );
+ [--sp] = fp;
+ [--sp] = usp;
+
+ [--sp] = i0;
+ [--sp] = i1;
+ [--sp] = i2;
+ [--sp] = i3;
+
+ [--sp] = m0;
+ [--sp] = m1;
+ [--sp] = m2;
+ [--sp] = m3;
+
+ [--sp] = l0;
+ [--sp] = l1;
+ [--sp] = l2;
+ [--sp] = l3;
+
+ [--sp] = b0;
+ [--sp] = b1;
+ [--sp] = b2;
+ [--sp] = b3;
+ [--sp] = a0.x;
+ [--sp] = a0.w;
+ [--sp] = a1.x;
+ [--sp] = a1.w;
+
+ [--sp] = LC0;
+ [--sp] = LC1;
+ [--sp] = LT0;
+ [--sp] = LT1;
+ [--sp] = LB0;
+ [--sp] = LB1;
+
+ [--sp] = ASTAT;
+ [--sp] = CYCLES;
+ [--sp] = CYCLES2;
+
+ [--sp] = RETS;
+ r0 = RETI;
+ [--sp] = r0;
+ [--sp] = RETX;
+ [--sp] = RETN;
+ [--sp] = RETE;
+ [--sp] = SEQSTAT;
+
+ /* Save Magic, return address and Stack Pointer */
+ P0.H = 0;
+ P0.L = 0;
+ R0.H = 0xDEAD; /* Hibernate Magic */
+ R0.L = 0xBEEF;
+ [P0++] = R0; /* Store Hibernate Magic */
+ R0.H = .Lpm_resume_here;
+ R0.L = .Lpm_resume_here;
+ [P0++] = R0; /* Save Return Address */
+ [P0++] = SP; /* Save Stack Pointer */
+ P0.H = _hibernate_mode;
+ P0.L = _hibernate_mode;
+ R0 = R2;
+ call (P0); /* Goodbye */
+
+.Lpm_resume_here:
+
+ /* Restore Core Registers */
+ SEQSTAT = [sp++];
+ RETE = [sp++];
+ RETN = [sp++];
+ RETX = [sp++];
+ r0 = [sp++];
+ RETI = r0;
+ RETS = [sp++];
+
+ CYCLES2 = [sp++];
+ CYCLES = [sp++];
+ ASTAT = [sp++];
+
+ LB1 = [sp++];
+ LB0 = [sp++];
+ LT1 = [sp++];
+ LT0 = [sp++];
+ LC1 = [sp++];
+ LC0 = [sp++];
+
+ a1.w = [sp++];
+ a1.x = [sp++];
+ a0.w = [sp++];
+ a0.x = [sp++];
+ b3 = [sp++];
+ b2 = [sp++];
+ b1 = [sp++];
+ b0 = [sp++];
+
+ l3 = [sp++];
+ l2 = [sp++];
+ l1 = [sp++];
+ l0 = [sp++];
+
+ m3 = [sp++];
+ m2 = [sp++];
+ m1 = [sp++];
+ m0 = [sp++];
+
+ i3 = [sp++];
+ i2 = [sp++];
+ i1 = [sp++];
+ i0 = [sp++];
+
+ usp = [sp++];
+ fp = [sp++];
+
+ ( R7 : 0, P5 : 0) = [ SP ++ ];
+ SYSCFG = [sp++];
+
+ /* Restore Core MMRs */
+
+ PM_POP(TBUFCTL)
+ PM_POP(TCOUNT)
+ PM_POP(TSCALE)
+ PM_POP(TPERIOD)
+ PM_POP(TCNTL)
+ PM_POP(IPRIO)
+ PM_POP(ILAT)
+ PM_POP(IMASK)
+ PM_POP(EVT15)
+ PM_POP(EVT14)
+ PM_POP(EVT13)
+ PM_POP(EVT12)
+ PM_POP(EVT11)
+ PM_POP(EVT10)
+ PM_POP(EVT9)
+ PM_POP(EVT8)
+ PM_POP(EVT7)
+ PM_POP(EVT6)
+ PM_POP(EVT5)
+ PM_POP(EVT4)
+ PM_POP(EVT3)
+ PM_POP(EVT2)
+ PM_POP(EVT1)
+ PM_POP(EVT0)
+ PM_POP(ICPLB_DATA15)
+ PM_POP(ICPLB_DATA14)
+ PM_POP(ICPLB_DATA13)
+ PM_POP(ICPLB_DATA12)
+ PM_POP(ICPLB_DATA11)
+ PM_POP(ICPLB_DATA10)
+ PM_POP(ICPLB_DATA9)
+ PM_POP(ICPLB_DATA8)
+ PM_POP(ICPLB_DATA7)
+ PM_POP(ICPLB_DATA6)
+ PM_POP(ICPLB_DATA5)
+ PM_POP(ICPLB_DATA4)
+ PM_POP(ICPLB_DATA3)
+ PM_POP(ICPLB_DATA2)
+ PM_POP(ICPLB_DATA1)
+ PM_POP(ICPLB_DATA0)
+ PM_POP(ICPLB_ADDR15)
+ PM_POP(ICPLB_ADDR14)
+ PM_POP(ICPLB_ADDR13)
+ PM_POP(ICPLB_ADDR12)
+ PM_POP(ICPLB_ADDR11)
+ PM_POP(ICPLB_ADDR10)
+ PM_POP(ICPLB_ADDR9)
+ PM_POP(ICPLB_ADDR8)
+ PM_POP(ICPLB_ADDR7)
+ PM_POP(ICPLB_ADDR6)
+ PM_POP(ICPLB_ADDR5)
+ PM_POP(ICPLB_ADDR4)
+ PM_POP(ICPLB_ADDR3)
+ PM_POP(ICPLB_ADDR2)
+ PM_POP(ICPLB_ADDR1)
+ PM_POP(ICPLB_ADDR0)
+ PM_POP(IMEM_CONTROL)
+ PM_POP(DCPLB_DATA15)
+ PM_POP(DCPLB_DATA14)
+ PM_POP(DCPLB_DATA13)
+ PM_POP(DCPLB_DATA12)
+ PM_POP(DCPLB_DATA11)
+ PM_POP(DCPLB_DATA10)
+ PM_POP(DCPLB_DATA9)
+ PM_POP(DCPLB_DATA8)
+ PM_POP(DCPLB_DATA7)
+ PM_POP(DCPLB_DATA6)
+ PM_POP(DCPLB_DATA5)
+ PM_POP(DCPLB_DATA4)
+ PM_POP(DCPLB_DATA3)
+ PM_POP(DCPLB_DATA2)
+ PM_POP(DCPLB_DATA1)
+ PM_POP(DCPLB_DATA0)
+ PM_POP(DCPLB_ADDR15)
+ PM_POP(DCPLB_ADDR14)
+ PM_POP(DCPLB_ADDR13)
+ PM_POP(DCPLB_ADDR12)
+ PM_POP(DCPLB_ADDR11)
+ PM_POP(DCPLB_ADDR10)
+ PM_POP(DCPLB_ADDR9)
+ PM_POP(DCPLB_ADDR8)
+ PM_POP(DCPLB_ADDR7)
+ PM_POP(DCPLB_ADDR6)
+ PM_POP(DCPLB_ADDR5)
+ PM_POP(DCPLB_ADDR4)
+ PM_POP(DCPLB_ADDR3)
+ PM_POP(DCPLB_ADDR2)
+ PM_POP(DCPLB_ADDR1)
+ PM_POP(DCPLB_ADDR0)
+ PM_POP(DMEM_CONTROL)
+
+ /* Restore System MMRs */
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ PM_SYS_POP16(SYSCR)
+
+#ifdef EBIU_FCTL
+ PM_SYS_POP(EBIU_FCTL)
+ PM_SYS_POP(EBIU_MODE)
+ PM_SYS_POP(EBIU_MBSCTL)
+#endif
+ PM_SYS_POP16(EBIU_AMGCTL)
+ PM_SYS_POP(EBIU_AMBCTL1)
+ PM_SYS_POP(EBIU_AMBCTL0)
+
+#ifdef PINT0_ASSIGN
+ PM_SYS_POP(PINT3_ASSIGN)
+ PM_SYS_POP(PINT2_ASSIGN)
+ PM_SYS_POP(PINT1_ASSIGN)
+ PM_SYS_POP(PINT0_ASSIGN)
+#endif
+
+#ifdef SICA_IWR1
+ PM_SYS_POP(SICA_IWR1)
+#endif
+#ifdef SICA_IWR0
+ PM_SYS_POP(SICA_IWR0)
+#endif
+#ifdef SIC_IWR2
+ PM_SYS_POP(SIC_IWR2)
+#endif
+#ifdef SIC_IWR1
+ PM_SYS_POP(SIC_IWR1)
+#endif
+#ifdef SIC_IWR0
+ PM_SYS_POP(SIC_IWR0)
+#endif
+#ifdef SIC_IWR
+ PM_SYS_POP(SIC_IWR)
+#endif
+
+#ifdef SICA_IAR0
+ PM_SYS_POP(SICA_IAR7)
+ PM_SYS_POP(SICA_IAR6)
+ PM_SYS_POP(SICA_IAR5)
+ PM_SYS_POP(SICA_IAR4)
+ PM_SYS_POP(SICA_IAR3)
+ PM_SYS_POP(SICA_IAR2)
+ PM_SYS_POP(SICA_IAR1)
+ PM_SYS_POP(SICA_IAR0)
+#endif
+
+#ifdef SIC_IAR8
+ PM_SYS_POP(SIC_IAR11)
+ PM_SYS_POP(SIC_IAR10)
+ PM_SYS_POP(SIC_IAR9)
+ PM_SYS_POP(SIC_IAR8)
+#endif
+#ifdef SIC_IAR7
+ PM_SYS_POP(SIC_IAR7)
+#endif
+#ifdef SIC_IAR6
+ PM_SYS_POP(SIC_IAR6)
+ PM_SYS_POP(SIC_IAR5)
+ PM_SYS_POP(SIC_IAR4)
+#endif
+#ifdef SIC_IAR3
+ PM_SYS_POP(SIC_IAR3)
+#endif
+#ifdef SIC_IAR2
+ PM_SYS_POP(SIC_IAR2)
+ PM_SYS_POP(SIC_IAR1)
+ PM_SYS_POP(SIC_IAR0)
+#endif
+#ifdef SICA_IMASK1
+ PM_SYS_POP(SICA_IMASK1)
+#endif
+#ifdef SICA_IMASK0
+ PM_SYS_POP(SICA_IMASK0)
+#endif
+#ifdef SIC_IMASK
+ PM_SYS_POP(SIC_IMASK)
+#endif
+#ifdef SIC_IMASK2
+ PM_SYS_POP(SIC_IMASK2)
+#endif
+#ifdef SIC_IMASK1
+ PM_SYS_POP(SIC_IMASK1)
+#endif
+#ifdef SIC_IMASK0
+ PM_SYS_POP(SIC_IMASK0)
+#endif
+
+ [--sp] = RETI; /* Clear Global Interrupt Disable */
+ SP += 4;
+
+ RETS = [SP++];
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+ENDPROC(_do_hibernate)
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
new file mode 100644
index 0000000..bde6dc4
--- /dev/null
+++ b/arch/blackfin/mach-common/entry.S
@@ -0,0 +1,1552 @@
+/*
+ * File: arch/blackfin/mach-common/entry.S
+ * Based on:
+ * Author: Linus Torvalds
+ *
+ * Created: ?
+ * Description: contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all
+ * interrupts and faults that can result in a task-switch.
+ *
+ * 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
+ */
+
+/* NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/unistd.h>
+#include <asm/blackfin.h>
+#include <asm/errno.h>
+#include <asm/fixed_code.h>
+#include <asm/thread_info.h> /* TIF_NEED_RESCHED */
+#include <asm/asm-offsets.h>
+#include <asm/trace.h>
+
+#include <asm/context.S>
+
+#if defined(CONFIG_BFIN_SCRATCH_REG_RETN)
+# define EX_SCRATCH_REG RETN
+#elif defined(CONFIG_BFIN_SCRATCH_REG_RETE)
+# define EX_SCRATCH_REG RETE
+#else
+# define EX_SCRATCH_REG CYCLES
+#endif
+
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
+#endif
+
+/* Slightly simplified and streamlined entry point for CPLB misses.
+ * This one does not lower the level to IRQ5, and thus can be used to
+ * patch up CPLB misses on the kernel stack.
+ */
+#if ANOMALY_05000261
+#define _ex_dviol _ex_workaround_261
+#define _ex_dmiss _ex_workaround_261
+#define _ex_dmult _ex_workaround_261
+
+ENTRY(_ex_workaround_261)
+ /*
+ * Work around an anomaly: if we see a new DCPLB fault, return
+ * without doing anything. Then, if we get the same fault again,
+ * handle it.
+ */
+ P4 = R7; /* Store EXCAUSE */
+ p5.l = _last_cplb_fault_retx;
+ p5.h = _last_cplb_fault_retx;
+ r7 = [p5];
+ r6 = retx;
+ [p5] = r6;
+ cc = r6 == r7;
+ if !cc jump _bfin_return_from_exception;
+ /* fall through */
+ R7 = P4;
+ 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
+ */
+ jump _ex_trap_c;
+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
+ /* 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? */
+ r7 = SEQSTAT; /* reason code is in bit 5:0 */
+ r6.l = lo(SEQSTAT_EXCAUSE);
+ r6.h = hi(SEQSTAT_EXCAUSE);
+ r7 = r7 & r6;
+ r6 = 0x25;
+ CC = R7 == R6;
+ if CC JUMP _double_fault;
+#endif
+
+ DEBUG_HWTRACE_RESTORE(p5, r7)
+ RESTORE_ALL_SYS
+ SP = EX_SCRATCH_REG;
+ rtx;
+ENDPROC(_ex_icplb_miss)
+
+ENTRY(_ex_syscall)
+ raise 15; /* invoked by TRAP #0, for sys call */
+ jump.s _bfin_return_from_exception;
+ENDPROC(_ex_syscall)
+
+ENTRY(_ex_soft_bp)
+ r7 = retx;
+ r7 += -2;
+ retx = r7;
+ jump.s _ex_trap_c;
+ENDPROC(_ex_soft_bp)
+
+ENTRY(_ex_single_step)
+ /* If we just returned from an interrupt, the single step event is
+ for the RTI instruction. */
+ r7 = retx;
+ r6 = reti;
+ cc = r7 == r6;
+ if cc jump _bfin_return_from_exception;
+
+#ifdef CONFIG_KGDB
+ /* Don't do single step in hardware exception handler */
+ p5.l = lo(IPEND);
+ p5.h = hi(IPEND);
+ r6 = [p5];
+ cc = bittst(r6, 4);
+ if cc jump _bfin_return_from_exception;
+ cc = bittst(r6, 5);
+ if cc jump _bfin_return_from_exception;
+
+ /* skip single step if current interrupt priority is higher than
+ * that of the first instruction, from which gdb starts single step */
+ r6 >>= 6;
+ r7 = 10;
+.Lfind_priority_start:
+ cc = bittst(r6, 0);
+ if cc jump .Lfind_priority_done;
+ r6 >>= 1;
+ r7 += -1;
+ cc = r7 == 0;
+ if cc jump .Lfind_priority_done;
+ jump.s .Lfind_priority_start;
+.Lfind_priority_done:
+ p4.l = _kgdb_single_step;
+ p4.h = _kgdb_single_step;
+ r6 = [p4];
+ cc = r6 == 0;
+ if cc jump .Ldo_single_step;
+ r6 += -1;
+ cc = r6 < r7;
+ if cc jump 1f;
+.Ldo_single_step:
+#else
+ /* If we were in user mode, do the single step normally. */
+ p5.l = lo(IPEND);
+ p5.h = hi(IPEND);
+ r6 = [p5];
+ r7 = 0xffe0 (z);
+ r7 = r7 & r6;
+ cc = r7 == 0;
+ if !cc jump 1f;
+#endif
+
+ /* Single stepping only a single instruction, so clear the trace
+ * bit here. */
+ r7 = syscfg;
+ bitclr (r7, 0);
+ syscfg = R7;
+ jump _ex_trap_c;
+
+1:
+ /*
+ * We were in an interrupt handler. By convention, all of them save
+ * SYSCFG with their first instruction, so by checking whether our
+ * RETX points at the entry point, we can determine whether to allow
+ * a single step, or whether to clear SYSCFG.
+ *
+ * First, find out the interrupt level and the event vector for it.
+ */
+ p5.l = lo(EVT0);
+ p5.h = hi(EVT0);
+ p5 += -4;
+2:
+ r7 = rot r7 by -1;
+ p5 += 4;
+ if !cc jump 2b;
+
+ /* What we actually do is test for the _second_ instruction in the
+ * IRQ handler. That way, if there are insns following the restore
+ * of SYSCFG after leaving the handler, we will not turn off SYSCFG
+ * for them. */
+
+ r7 = [p5];
+ r7 += 2;
+ r6 = RETX;
+ cc = R7 == R6;
+ if !cc jump _bfin_return_from_exception;
+
+ r7 = syscfg;
+ bitclr (r7, 0);
+ syscfg = R7;
+
+ /* Fall through to _bfin_return_from_exception. */
+ENDPROC(_ex_single_step)
+
+ENTRY(_bfin_return_from_exception)
+#if ANOMALY_05000257
+ R7=LC0;
+ LC0=R7;
+ R7=LC1;
+ LC1=R7;
+#endif
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ /* While we were processing the current exception,
+ * did we cause another, and double fault?
+ */
+ r7 = SEQSTAT; /* reason code is in bit 5:0 */
+ r6.l = lo(SEQSTAT_EXCAUSE);
+ r6.h = hi(SEQSTAT_EXCAUSE);
+ r7 = r7 & r6;
+ r6 = 0x25;
+ CC = R7 == R6;
+ if CC JUMP _double_fault;
+
+ /* Did we cause a HW error? */
+ p5.l = lo(ILAT);
+ p5.h = hi(ILAT);
+ r6 = [p5];
+ r7 = 0x20; /* Did I just cause anther HW error? */
+ r6 = r7 & r6;
+ CC = R7 == R6;
+ if CC JUMP _double_fault;
+#endif
+
+ (R7:6,P5:4) = [sp++];
+ ASTAT = [sp++];
+ sp = EX_SCRATCH_REG;
+ rtx;
+ENDPROC(_bfin_return_from_exception)
+
+ENTRY(_handle_bad_cplb)
+ DEBUG_HWTRACE_RESTORE(p5, r7)
+ /* To get here, we just tried and failed to change a CPLB
+ * so, handle things in trap_c (C code), by lowering to
+ * IRQ5, just like we normally do. Since this is not a
+ * "normal" return path, we have a do alot of stuff to
+ * 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;
+ [--sp] = (R7:6,P5:4);
+
+ENTRY(_ex_replaceable)
+ nop;
+
+ENTRY(_ex_trap_c)
+ /* Make sure we are not in a double fault */
+ p4.l = lo(IPEND);
+ p4.h = hi(IPEND);
+ r7 = [p4];
+ CC = BITTST (r7, 5);
+ if CC jump _double_fault;
+
+ /* Call C code (trap_c) to handle the exception, which most
+ * likely involves sending a signal to the current process.
+ * To avoid double faults, lower our priority to IRQ5 first.
+ */
+ P5.h = _exception_to_level5;
+ P5.l = _exception_to_level5;
+ p4.l = lo(EVT5);
+ p4.h = hi(EVT5);
+ [p4] = p5;
+ csync;
+
+#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)
+ * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+ * but they are not very interesting, so don't save them
+ */
+
+ 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;
+
+ r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)];
+ p5.h = _saved_icplb_fault_addr;
+ p5.l = _saved_icplb_fault_addr;
+ [p5] = r7;
+
+ r6 = retx;
+ p4.l = _saved_retx;
+ p4.h = _saved_retx;
+ [p4] = r6;
+#endif
+ r6 = SYSCFG;
+ [p4 + 4] = 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;
+
+ p4.l = lo(SAFE_USER_INSTRUCTION);
+ p4.h = hi(SAFE_USER_INSTRUCTION);
+ retx = p4;
+
+ r6 = 0x3f;
+ sti r6;
+
+ raise 5;
+ jump.s _bfin_return_from_exception;
+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
+ */
+ENTRY(_double_fault)
+ /* Turn caches & protection off, to ensure we don't get any more
+ * double exceptions
+ */
+
+ P4.L = LO(IMEM_CONTROL);
+ P4.H = HI(IMEM_CONTROL);
+
+ R5 = [P4]; /* Control Register*/
+ BITCLR(R5,ENICPLB_P);
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+
+ P4.L = LO(DMEM_CONTROL);
+ P4.H = HI(DMEM_CONTROL);
+ R5 = [P4];
+ BITCLR(R5,ENDCPLB_P);
+ SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+
+ /* Fix up the stack */
+ (R7:6,P5:4) = [sp++];
+ ASTAT = [sp++];
+ SP = EX_SCRATCH_REG;
+
+ /* We should be out of the exception stack, and back down into
+ * kernel or user space stack
+ */
+ SAVE_ALL_SYS
+
+ /* The dumping functions expect the return address in the RETI
+ * slot. */
+ r6 = retx;
+ [sp + PT_PC] = r6;
+
+ r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
+ SP += -12;
+ call _double_fault_c;
+ SP += 12;
+.L_double_fault_panic:
+ JUMP .L_double_fault_panic
+
+ENDPROC(_double_fault)
+
+ENTRY(_exception_to_level5)
+ SAVE_ALL_SYS
+
+ p4.l = _saved_retx;
+ p4.h = _saved_retx;
+ r6 = [p4];
+ [sp + PT_PC] = r6;
+
+ r6 = [p4 + 4];
+ [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];
+ sti r6;
+
+ /* Restore the hardware error vector. */
+ P5.h = _evt_ivhw;
+ P5.l = _evt_ivhw;
+ p4.l = lo(EVT5);
+ p4.h = hi(EVT5);
+ [p4] = p5;
+ csync;
+
+ p2.l = lo(IPEND);
+ p2.h = hi(IPEND);
+ csync;
+ r0 = [p2]; /* Read current IPEND */
+ [sp + PT_IPEND] = r0; /* Store IPEND */
+
+ r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
+ SP += -12;
+ call _trap_c;
+ SP += 12;
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ /* Grab ILAT */
+ p2.l = lo(ILAT);
+ p2.h = hi(ILAT);
+ r0 = [p2];
+ r1 = 0x20; /* Did I just cause anther HW error? */
+ r0 = r0 & r1;
+ CC = R0 == R1;
+ if CC JUMP _double_fault;
+#endif
+
+ call _ret_from_exception;
+ RESTORE_ALL_SYS
+ rti;
+ENDPROC(_exception_to_level5)
+
+ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
+ /* Since the kernel stack can be anywhere, it's not guaranteed to be
+ * covered by a CPLB. Switch to an exception stack; use RETN as a
+ * scratch register (for want of a better option).
+ */
+ EX_SCRATCH_REG = sp;
+ sp.l = _exception_stack_top;
+ sp.h = _exception_stack_top;
+ /* Try to deal with syscalls quickly. */
+ [--sp] = ASTAT;
+ [--sp] = (R7:6,P5:4);
+
+#if ANOMALY_05000283 || ANOMALY_05000315
+ cc = r7 == r7;
+ p5.h = HI(CHIPID);
+ p5.l = LO(CHIPID);
+ if cc jump 1f;
+ r7.l = W[p5];
+1:
+#endif
+
+#ifdef 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)
+ * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3,
+ * but they are not very interesting, so don't save them
+ */
+
+ 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;
+
+ r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)];
+ p5.h = _saved_icplb_fault_addr;
+ p5.l = _saved_icplb_fault_addr;
+ [p5] = r7;
+
+ p4.l = _saved_retx;
+ p4.h = _saved_retx;
+ r6 = retx;
+ [p4] = r6;
+
+ r7 = SEQSTAT; /* reason code is in bit 5:0 */
+ p4.l = _saved_seqstat;
+ p4.h = _saved_seqstat;
+ [p4] = r7;
+#else
+ r7 = SEQSTAT; /* reason code is in bit 5:0 */
+#endif
+ r6.l = lo(SEQSTAT_EXCAUSE);
+ r6.h = hi(SEQSTAT_EXCAUSE);
+ r7 = r7 & r6;
+ p5.h = _ex_table;
+ p5.l = _ex_table;
+ p4 = r7;
+ p5 = p5 + (p4 << 2);
+ p4 = [p5];
+ jump (p4);
+
+.Lbadsys:
+ r7 = -ENOSYS; /* signextending enough */
+ [sp + PT_R0] = r7; /* return value from system call */
+ jump .Lsyscall_really_exit;
+ENDPROC(_trap)
+
+ENTRY(_kernel_execve)
+ link SIZEOF_PTREGS;
+ p0 = sp;
+ r3 = SIZEOF_PTREGS / 4;
+ r4 = 0(x);
+0:
+ [p0++] = r4;
+ r3 += -1;
+ cc = r3 == 0;
+ if !cc jump 0b (bp);
+
+ p0 = sp;
+ sp += -16;
+ [sp + 12] = p0;
+ call _do_execve;
+ SP += 16;
+ cc = r0 == 0;
+ if ! cc jump 1f;
+ /* Success. Copy our temporary pt_regs to the top of the kernel
+ * stack and do a normal exception return.
+ */
+ r1 = sp;
+ r0 = (-KERNEL_STACK_SIZE) (x);
+ r1 = r1 & r0;
+ p2 = r1;
+ p3 = [p2];
+ r0 = KERNEL_STACK_SIZE - 4 (z);
+ p1 = r0;
+ p1 = p1 + p2;
+
+ p0 = fp;
+ r4 = [p0--];
+ r3 = SIZEOF_PTREGS / 4;
+0:
+ r4 = [p0--];
+ [p1--] = r4;
+ r3 += -1;
+ cc = r3 == 0;
+ if ! cc jump 0b (bp);
+
+ r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z);
+ p1 = r0;
+ p1 = p1 + p2;
+ sp = p1;
+ r0 = syscfg;
+ [SP + PT_SYSCFG] = r0;
+ [p3 + (TASK_THREAD + THREAD_KSP)] = sp;
+
+ RESTORE_CONTEXT;
+ rti;
+1:
+ unlink;
+ rts;
+ENDPROC(_kernel_execve)
+
+ENTRY(_system_call)
+ /* Store IPEND */
+ p2.l = lo(IPEND);
+ p2.h = hi(IPEND);
+ csync;
+ r0 = [p2];
+ [sp + PT_IPEND] = r0;
+
+ /* Store RETS for now */
+ r0 = rets;
+ [sp + PT_RESERVED] = r0;
+ /* Set the stack for the current process */
+ r7 = sp;
+ r6.l = lo(ALIGN_PAGE_MASK);
+ r6.h = hi(ALIGN_PAGE_MASK);
+ r7 = r7 & r6; /* thread_info */
+ p2 = r7;
+ p2 = [p2];
+
+ [p2+(TASK_THREAD+THREAD_KSP)] = sp;
+
+ /* Check the System Call */
+ r7 = __NR_syscall;
+ /* System call number is passed in P0 */
+ r6 = p0;
+ cc = r6 < r7;
+ if ! cc jump .Lbadsys;
+
+ /* are we tracing syscalls?*/
+ r7 = sp;
+ r6.l = lo(ALIGN_PAGE_MASK);
+ r6.h = hi(ALIGN_PAGE_MASK);
+ r7 = r7 & r6;
+ p2 = r7;
+ r7 = [p2+TI_FLAGS];
+ CC = BITTST(r7,TIF_SYSCALL_TRACE);
+ if CC JUMP _sys_trace;
+
+ /* Execute the appropriate system call */
+
+ p4 = p0;
+ p5.l = _sys_call_table;
+ p5.h = _sys_call_table;
+ p5 = p5 + (p4 << 2);
+ r0 = [sp + PT_R0];
+ r1 = [sp + PT_R1];
+ r2 = [sp + PT_R2];
+ p5 = [p5];
+
+ [--sp] = r5;
+ [--sp] = r4;
+ [--sp] = r3;
+ SP += -12;
+ call (p5);
+ SP += 24;
+ [sp + PT_R0] = r0;
+
+.Lresume_userspace:
+ r7 = sp;
+ r4.l = lo(ALIGN_PAGE_MASK);
+ r4.h = hi(ALIGN_PAGE_MASK);
+ r7 = r7 & r4; /* thread_info->flags */
+ p5 = r7;
+.Lresume_userspace_1:
+ /* Disable interrupts. */
+ [--sp] = reti;
+ reti = [sp++];
+
+ r7 = [p5 + TI_FLAGS];
+ r4.l = lo(_TIF_WORK_MASK);
+ r4.h = hi(_TIF_WORK_MASK);
+ r7 = r7 & r4;
+
+.Lsyscall_resched:
+ cc = BITTST(r7, TIF_NEED_RESCHED);
+ if !cc jump .Lsyscall_sigpending;
+
+ /* Reenable interrupts. */
+ [--sp] = reti;
+ r0 = [sp++];
+
+ SP += -12;
+ call _schedule;
+ SP += 12;
+
+ jump .Lresume_userspace_1;
+
+.Lsyscall_sigpending:
+ cc = BITTST(r7, TIF_RESTORE_SIGMASK);
+ if cc jump .Lsyscall_do_signals;
+ cc = BITTST(r7, TIF_SIGPENDING);
+ if !cc jump .Lsyscall_really_exit;
+.Lsyscall_do_signals:
+ /* Reenable interrupts. */
+ [--sp] = reti;
+ r0 = [sp++];
+
+ r0 = sp;
+ SP += -12;
+ call _do_signal;
+ SP += 12;
+
+.Lsyscall_really_exit:
+ r5 = [sp + PT_RESERVED];
+ rets = r5;
+ rts;
+ENDPROC(_system_call)
+
+/* Do not mark as ENTRY() to avoid error in assembler ...
+ * this symbol need not be global anyways, so ...
+ */
+_sys_trace:
+ call _syscall_trace;
+
+ /* Execute the appropriate system call */
+
+ p4 = [SP + PT_P0];
+ p5.l = _sys_call_table;
+ p5.h = _sys_call_table;
+ p5 = p5 + (p4 << 2);
+ r0 = [sp + PT_R0];
+ r1 = [sp + PT_R1];
+ r2 = [sp + PT_R2];
+ r3 = [sp + PT_R3];
+ r4 = [sp + PT_R4];
+ r5 = [sp + PT_R5];
+ p5 = [p5];
+
+ [--sp] = r5;
+ [--sp] = r4;
+ [--sp] = r3;
+ SP += -12;
+ call (p5);
+ SP += 24;
+ [sp + PT_R0] = r0;
+
+ call _syscall_trace;
+ jump .Lresume_userspace;
+ENDPROC(_sys_trace)
+
+ENTRY(_resume)
+ /*
+ * Beware - when entering resume, prev (the current task) is
+ * in r0, next (the new task) is in r1.
+ */
+ p0 = r0;
+ p1 = r1;
+ [--sp] = rets;
+ [--sp] = fp;
+ [--sp] = (r7:4, p5:3);
+
+ /* save usp */
+ p2 = usp;
+ [p0+(TASK_THREAD+THREAD_USP)] = p2;
+
+ /* save current kernel stack pointer */
+ [p0+(TASK_THREAD+THREAD_KSP)] = sp;
+
+ /* save program counter */
+ r1.l = _new_old_task;
+ r1.h = _new_old_task;
+ [p0+(TASK_THREAD+THREAD_PC)] = r1;
+
+ /* restore the kernel stack pointer */
+ sp = [p1+(TASK_THREAD+THREAD_KSP)];
+
+ /* restore user stack pointer */
+ p0 = [p1+(TASK_THREAD+THREAD_USP)];
+ usp = p0;
+
+ /* restore pc */
+ p0 = [p1+(TASK_THREAD+THREAD_PC)];
+ jump (p0);
+
+ /*
+ * Following code actually lands up in a new (old) task.
+ */
+
+_new_old_task:
+ (r7:4, p5:3) = [sp++];
+ fp = [sp++];
+ rets = [sp++];
+
+ /*
+ * When we come out of resume, r0 carries "old" task, becuase we are
+ * in "new" task.
+ */
+ rts;
+ENDPROC(_resume)
+
+ENTRY(_ret_from_exception)
+ p2.l = lo(IPEND);
+ p2.h = hi(IPEND);
+
+ csync;
+ r0 = [p2];
+ [sp + PT_IPEND] = r0;
+
+1:
+ r2 = LO(~0x37) (Z);
+ r0 = r2 & r0;
+ cc = r0 == 0;
+ if !cc jump 4f; /* if not return to user mode, get out */
+
+ /* Make sure any pending system call or deferred exception
+ * return in ILAT for this process to get executed, otherwise
+ * in case context switch happens, system call of
+ * first process (i.e in ILAT) will be carried
+ * forward to the switched process
+ */
+
+ p2.l = lo(ILAT);
+ p2.h = hi(ILAT);
+ r0 = [p2];
+ r1 = (EVT_IVG14 | EVT_IVG15) (z);
+ r0 = r0 & r1;
+ cc = r0 == 0;
+ if !cc jump 5f;
+
+ /* Set the stack for the current process */
+ r7 = sp;
+ r4.l = lo(ALIGN_PAGE_MASK);
+ r4.h = hi(ALIGN_PAGE_MASK);
+ r7 = r7 & r4; /* thread_info->flags */
+ p5 = r7;
+ r7 = [p5 + TI_FLAGS];
+ r4.l = lo(_TIF_WORK_MASK);
+ r4.h = hi(_TIF_WORK_MASK);
+ r7 = r7 & r4;
+ cc = r7 == 0;
+ if cc jump 4f;
+
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _schedule_and_signal;
+ p1.h = _schedule_and_signal;
+ [p0] = p1;
+ csync;
+ raise 15; /* raise evt14 to do signal or reschedule */
+4:
+ r0 = syscfg;
+ bitclr(r0, 0);
+ syscfg = r0;
+5:
+ rts;
+ENDPROC(_ret_from_exception)
+
+ENTRY(_return_from_int)
+ /* If someone else already raised IRQ 15, do nothing. */
+ csync;
+ p2.l = lo(ILAT);
+ p2.h = hi(ILAT);
+ r0 = [p2];
+ cc = bittst (r0, EVT_IVG15_P);
+ if cc jump 2f;
+
+ /* if not return to user mode, get out */
+ p2.l = lo(IPEND);
+ p2.h = hi(IPEND);
+ r0 = [p2];
+ r1 = 0x17(Z);
+ r2 = ~r1;
+ r2.h = 0;
+ r0 = r2 & r0;
+ r1 = 1;
+ r1 = r0 - r1;
+ r2 = r0 & r1;
+ cc = r2 == 0;
+ if !cc jump 2f;
+
+ /* Lower the interrupt level to 15. */
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _schedule_and_signal_from_int;
+ p1.h = _schedule_and_signal_from_int;
+ [p0] = p1;
+ csync;
+#if ANOMALY_05000281
+ r0.l = lo(SAFE_USER_INSTRUCTION);
+ r0.h = hi(SAFE_USER_INSTRUCTION);
+ reti = r0;
+#endif
+ r0 = 0x801f (z);
+ STI r0;
+ raise 15; /* raise evt15 to do signal or reschedule */
+ rti;
+2:
+ rts;
+ENDPROC(_return_from_int)
+
+ENTRY(_lower_to_irq14)
+#if ANOMALY_05000281
+ r0.l = lo(SAFE_USER_INSTRUCTION);
+ r0.h = hi(SAFE_USER_INSTRUCTION);
+ reti = r0;
+#endif
+ r0 = 0x401f;
+ sti r0;
+ raise 14;
+ rti;
+ENTRY(_evt14_softirq)
+#ifdef CONFIG_DEBUG_HWERR
+ r0 = 0x3f;
+ sti r0;
+#else
+ cli r0;
+#endif
+ [--sp] = RETI;
+ SP += 4;
+ rts;
+
+_schedule_and_signal_from_int:
+ /* To end up here, vector 15 was changed - so we have to change it
+ * back.
+ */
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _evt_system_call;
+ p1.h = _evt_system_call;
+ [p0] = p1;
+ csync;
+
+ /* Set orig_p0 to -1 to indicate this isn't the end of a syscall. */
+ r0 = -1 (x);
+ [sp + PT_ORIG_P0] = r0;
+
+ p1 = rets;
+ [sp + PT_RESERVED] = p1;
+
+ p0.l = _irq_flags;
+ p0.h = _irq_flags;
+ r0 = [p0];
+ sti r0;
+
+ r0 = sp;
+ sp += -12;
+ call _finish_atomic_sections;
+ sp += 12;
+ jump.s .Lresume_userspace;
+
+_schedule_and_signal:
+ SAVE_CONTEXT_SYSCALL
+ /* To end up here, vector 15 was changed - so we have to change it
+ * back.
+ */
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _evt_system_call;
+ p1.h = _evt_system_call;
+ [p0] = p1;
+ csync;
+ p0.l = 1f;
+ p0.h = 1f;
+ [sp + PT_RESERVED] = P0;
+ call .Lresume_userspace;
+1:
+ RESTORE_CONTEXT
+ rti;
+ENDPROC(_lower_to_irq14)
+
+/* We handle this 100% in exception space - to reduce overhead
+ * Only potiential problem is if the software buffer gets swapped out of the
+ * CPLB table - then double fault. - so we don't let this happen in other places
+ */
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
+ENTRY(_ex_trace_buff_full)
+ [--sp] = P3;
+ [--sp] = P2;
+ [--sp] = LC0;
+ [--sp] = LT0;
+ [--sp] = LB0;
+ P5.L = _trace_buff_offset;
+ P5.H = _trace_buff_offset;
+ P3 = [P5]; /* trace_buff_offset */
+ P5.L = lo(TBUFSTAT);
+ P5.H = hi(TBUFSTAT);
+ R7 = [P5];
+ R7 <<= 1; /* double, since we need to read twice */
+ LC0 = R7;
+ R7 <<= 2; /* need to shift over again,
+ * to get the number of bytes */
+ P5.L = lo(TBUF);
+ P5.H = hi(TBUF);
+ R6 = ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*1024) - 1;
+
+ P2 = R7;
+ P3 = P3 + P2;
+ R7 = P3;
+ R7 = R7 & R6;
+ P3 = R7;
+ P2.L = _trace_buff_offset;
+ P2.H = _trace_buff_offset;
+ [P2] = P3;
+
+ P2.L = _software_trace_buff;
+ P2.H = _software_trace_buff;
+
+ LSETUP (.Lstart, .Lend) LC0;
+.Lstart:
+ R7 = [P5]; /* read TBUF */
+ P4 = P3 + P2;
+ [P4] = R7;
+ P3 += -4;
+ R7 = P3;
+ R7 = R7 & R6;
+.Lend:
+ P3 = R7;
+
+ LB0 = [sp++];
+ LT0 = [sp++];
+ LC0 = [sp++];
+ P2 = [sp++];
+ P3 = [sp++];
+ jump _bfin_return_from_exception;
+ENDPROC(_ex_trace_buff_full)
+
+#if CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN == 4
+.data
+#else
+.section .l1.data.B
+#endif /* CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN */
+ENTRY(_trace_buff_offset)
+ .long 0;
+ALIGN
+ENTRY(_software_trace_buff)
+ .rept ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN)*256);
+ .long 0
+ .endr
+#endif /* CONFIG_DEBUG_BFIN_HWTRACE_EXPAND */
+
+#if CONFIG_EARLY_PRINTK
+__INIT
+ENTRY(_early_trap)
+ SAVE_ALL_SYS
+ trace_buffer_stop(p0,r0);
+
+#if ANOMALY_05000283 || ANOMALY_05000315
+ cc = r5 == r5;
+ p4.h = HI(CHIPID);
+ p4.l = LO(CHIPID);
+ if cc jump 1f;
+ r5.l = W[p4];
+1:
+#endif
+
+ /* Turn caches off, to ensure we don't get double exceptions */
+
+ P4.L = LO(IMEM_CONTROL);
+ P4.H = HI(IMEM_CONTROL);
+
+ R5 = [P4]; /* Control Register*/
+ BITCLR(R5,ENICPLB_P);
+ CLI R1;
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+
+ P4.L = LO(DMEM_CONTROL);
+ P4.H = HI(DMEM_CONTROL);
+ R5 = [P4];
+ BITCLR(R5,ENDCPLB_P);
+ SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+ STI R1;
+
+ r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
+ r1 = RETX;
+
+ SP += -12;
+ call _early_trap_c;
+ SP += 12;
+ENDPROC(_early_trap)
+__FINIT
+#endif /* CONFIG_EARLY_PRINTK */
+
+/*
+ * Put these in the kernel data section - that should always be covered by
+ * a CPLB. This is needed to ensure we don't get double fault conditions
+ */
+
+#ifdef CONFIG_SYSCALL_TAB_L1
+.section .l1.data
+#else
+.data
+#endif
+
+ENTRY(_ex_table)
+ /* entry for each EXCAUSE[5:0]
+ * This table must be in sync with the table in ./kernel/traps.c
+ * EXCPT instruction can provide 4 bits of EXCAUSE, allowing 16 to be user defined
+ */
+ .long _ex_syscall /* 0x00 - User Defined - Linux Syscall */
+ .long _ex_soft_bp /* 0x01 - User Defined - Software breakpoint */
+#ifdef CONFIG_KGDB
+ .long _ex_trap_c /* 0x02 - User Defined - KGDB initial connection
+ and break signal trap */
+#else
+ .long _ex_replaceable /* 0x02 - User Defined */
+#endif
+ .long _ex_trap_c /* 0x03 - User Defined - userspace stack overflow */
+ .long _ex_trap_c /* 0x04 - User Defined - dump trace buffer */
+ .long _ex_replaceable /* 0x05 - User Defined */
+ .long _ex_replaceable /* 0x06 - User Defined */
+ .long _ex_replaceable /* 0x07 - User Defined */
+ .long _ex_replaceable /* 0x08 - User Defined */
+ .long _ex_replaceable /* 0x09 - User Defined */
+ .long _ex_replaceable /* 0x0A - User Defined */
+ .long _ex_replaceable /* 0x0B - User Defined */
+ .long _ex_replaceable /* 0x0C - User Defined */
+ .long _ex_replaceable /* 0x0D - User Defined */
+ .long _ex_replaceable /* 0x0E - User Defined */
+ .long _ex_replaceable /* 0x0F - User Defined */
+ .long _ex_single_step /* 0x10 - HW Single step */
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
+ .long _ex_trace_buff_full /* 0x11 - Trace Buffer Full */
+#else
+ .long _ex_trap_c /* 0x11 - Trace Buffer Full */
+#endif
+ .long _ex_trap_c /* 0x12 - Reserved */
+ .long _ex_trap_c /* 0x13 - Reserved */
+ .long _ex_trap_c /* 0x14 - Reserved */
+ .long _ex_trap_c /* 0x15 - Reserved */
+ .long _ex_trap_c /* 0x16 - Reserved */
+ .long _ex_trap_c /* 0x17 - Reserved */
+ .long _ex_trap_c /* 0x18 - Reserved */
+ .long _ex_trap_c /* 0x19 - Reserved */
+ .long _ex_trap_c /* 0x1A - Reserved */
+ .long _ex_trap_c /* 0x1B - Reserved */
+ .long _ex_trap_c /* 0x1C - Reserved */
+ .long _ex_trap_c /* 0x1D - Reserved */
+ .long _ex_trap_c /* 0x1E - Reserved */
+ .long _ex_trap_c /* 0x1F - Reserved */
+ .long _ex_trap_c /* 0x20 - Reserved */
+ .long _ex_trap_c /* 0x21 - Undefined Instruction */
+ .long _ex_trap_c /* 0x22 - Illegal Instruction Combination */
+ .long _ex_dviol /* 0x23 - Data CPLB Protection Violation */
+ .long _ex_trap_c /* 0x24 - Data access misaligned */
+ .long _ex_trap_c /* 0x25 - Unrecoverable Event */
+ .long _ex_dmiss /* 0x26 - Data CPLB Miss */
+ .long _ex_dmult /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero */
+ .long _ex_trap_c /* 0x28 - Emulation Watchpoint */
+ .long _ex_trap_c /* 0x29 - Instruction fetch access error (535 only) */
+ .long _ex_trap_c /* 0x2A - Instruction fetch misaligned */
+ .long _ex_trap_c /* 0x2B - Instruction CPLB protection Violation */
+ .long _ex_icplb_miss /* 0x2C - Instruction CPLB miss */
+ .long _ex_trap_c /* 0x2D - Instruction CPLB Multiple Hits */
+ .long _ex_trap_c /* 0x2E - Illegal use of Supervisor Resource */
+ .long _ex_trap_c /* 0x2E - Illegal use of Supervisor Resource */
+ .long _ex_trap_c /* 0x2F - Reserved */
+ .long _ex_trap_c /* 0x30 - Reserved */
+ .long _ex_trap_c /* 0x31 - Reserved */
+ .long _ex_trap_c /* 0x32 - Reserved */
+ .long _ex_trap_c /* 0x33 - Reserved */
+ .long _ex_trap_c /* 0x34 - Reserved */
+ .long _ex_trap_c /* 0x35 - Reserved */
+ .long _ex_trap_c /* 0x36 - Reserved */
+ .long _ex_trap_c /* 0x37 - Reserved */
+ .long _ex_trap_c /* 0x38 - Reserved */
+ .long _ex_trap_c /* 0x39 - Reserved */
+ .long _ex_trap_c /* 0x3A - Reserved */
+ .long _ex_trap_c /* 0x3B - Reserved */
+ .long _ex_trap_c /* 0x3C - Reserved */
+ .long _ex_trap_c /* 0x3D - Reserved */
+ .long _ex_trap_c /* 0x3E - Reserved */
+ .long _ex_trap_c /* 0x3F - Reserved */
+END(_ex_table)
+
+ENTRY(_sys_call_table)
+ .long _sys_restart_syscall /* 0 */
+ .long _sys_exit
+ .long _sys_fork
+ .long _sys_read
+ .long _sys_write
+ .long _sys_open /* 5 */
+ .long _sys_close
+ .long _sys_ni_syscall /* old waitpid */
+ .long _sys_creat
+ .long _sys_link
+ .long _sys_unlink /* 10 */
+ .long _sys_execve
+ .long _sys_chdir
+ .long _sys_time
+ .long _sys_mknod
+ .long _sys_chmod /* 15 */
+ .long _sys_chown /* chown16 */
+ .long _sys_ni_syscall /* old break syscall holder */
+ .long _sys_ni_syscall /* old stat */
+ .long _sys_lseek
+ .long _sys_getpid /* 20 */
+ .long _sys_mount
+ .long _sys_ni_syscall /* old umount */
+ .long _sys_setuid
+ .long _sys_getuid
+ .long _sys_stime /* 25 */
+ .long _sys_ptrace
+ .long _sys_alarm
+ .long _sys_ni_syscall /* old fstat */
+ .long _sys_pause
+ .long _sys_ni_syscall /* old utime */ /* 30 */
+ .long _sys_ni_syscall /* old stty syscall holder */
+ .long _sys_ni_syscall /* old gtty syscall holder */
+ .long _sys_access
+ .long _sys_nice
+ .long _sys_ni_syscall /* 35 */ /* old ftime syscall holder */
+ .long _sys_sync
+ .long _sys_kill
+ .long _sys_rename
+ .long _sys_mkdir
+ .long _sys_rmdir /* 40 */
+ .long _sys_dup
+ .long _sys_pipe
+ .long _sys_times
+ .long _sys_ni_syscall /* old prof syscall holder */
+ .long _sys_brk /* 45 */
+ .long _sys_setgid
+ .long _sys_getgid
+ .long _sys_ni_syscall /* old sys_signal */
+ .long _sys_geteuid /* geteuid16 */
+ .long _sys_getegid /* getegid16 */ /* 50 */
+ .long _sys_acct
+ .long _sys_umount /* recycled never used phys() */
+ .long _sys_ni_syscall /* old lock syscall holder */
+ .long _sys_ioctl
+ .long _sys_fcntl /* 55 */
+ .long _sys_ni_syscall /* old mpx syscall holder */
+ .long _sys_setpgid
+ .long _sys_ni_syscall /* old ulimit syscall holder */
+ .long _sys_ni_syscall /* old old uname */
+ .long _sys_umask /* 60 */
+ .long _sys_chroot
+ .long _sys_ustat
+ .long _sys_dup2
+ .long _sys_getppid
+ .long _sys_getpgrp /* 65 */
+ .long _sys_setsid
+ .long _sys_ni_syscall /* old sys_sigaction */
+ .long _sys_sgetmask
+ .long _sys_ssetmask
+ .long _sys_setreuid /* setreuid16 */ /* 70 */
+ .long _sys_setregid /* setregid16 */
+ .long _sys_ni_syscall /* old sys_sigsuspend */
+ .long _sys_ni_syscall /* old sys_sigpending */
+ .long _sys_sethostname
+ .long _sys_setrlimit /* 75 */
+ .long _sys_ni_syscall /* old getrlimit */
+ .long _sys_getrusage
+ .long _sys_gettimeofday
+ .long _sys_settimeofday
+ .long _sys_getgroups /* getgroups16 */ /* 80 */
+ .long _sys_setgroups /* setgroups16 */
+ .long _sys_ni_syscall /* old_select */
+ .long _sys_symlink
+ .long _sys_ni_syscall /* old lstat */
+ .long _sys_readlink /* 85 */
+ .long _sys_uselib
+ .long _sys_ni_syscall /* sys_swapon */
+ .long _sys_reboot
+ .long _sys_ni_syscall /* old_readdir */
+ .long _sys_ni_syscall /* sys_mmap */ /* 90 */
+ .long _sys_munmap
+ .long _sys_truncate
+ .long _sys_ftruncate
+ .long _sys_fchmod
+ .long _sys_fchown /* fchown16 */ /* 95 */
+ .long _sys_getpriority
+ .long _sys_setpriority
+ .long _sys_ni_syscall /* old profil syscall holder */
+ .long _sys_statfs
+ .long _sys_fstatfs /* 100 */
+ .long _sys_ni_syscall
+ .long _sys_ni_syscall /* old sys_socketcall */
+ .long _sys_syslog
+ .long _sys_setitimer
+ .long _sys_getitimer /* 105 */
+ .long _sys_newstat
+ .long _sys_newlstat
+ .long _sys_newfstat
+ .long _sys_ni_syscall /* old uname */
+ .long _sys_ni_syscall /* iopl for i386 */ /* 110 */
+ .long _sys_vhangup
+ .long _sys_ni_syscall /* obsolete idle() syscall */
+ .long _sys_ni_syscall /* vm86old for i386 */
+ .long _sys_wait4
+ .long _sys_ni_syscall /* 115 */ /* sys_swapoff */
+ .long _sys_sysinfo
+ .long _sys_ni_syscall /* old sys_ipc */
+ .long _sys_fsync
+ .long _sys_ni_syscall /* old sys_sigreturn */
+ .long _sys_clone /* 120 */
+ .long _sys_setdomainname
+ .long _sys_newuname
+ .long _sys_ni_syscall /* old sys_modify_ldt */
+ .long _sys_adjtimex
+ .long _sys_ni_syscall /* 125 */ /* sys_mprotect */
+ .long _sys_ni_syscall /* old sys_sigprocmask */
+ .long _sys_ni_syscall /* old "creat_module" */
+ .long _sys_init_module
+ .long _sys_delete_module
+ .long _sys_ni_syscall /* 130: old "get_kernel_syms" */
+ .long _sys_quotactl
+ .long _sys_getpgid
+ .long _sys_fchdir
+ .long _sys_bdflush
+ .long _sys_ni_syscall /* 135 */ /* sys_sysfs */
+ .long _sys_personality
+ .long _sys_ni_syscall /* for afs_syscall */
+ .long _sys_setfsuid /* setfsuid16 */
+ .long _sys_setfsgid /* setfsgid16 */
+ .long _sys_llseek /* 140 */
+ .long _sys_getdents
+ .long _sys_ni_syscall /* sys_select */
+ .long _sys_flock
+ .long _sys_ni_syscall /* sys_msync */
+ .long _sys_readv /* 145 */
+ .long _sys_writev
+ .long _sys_getsid
+ .long _sys_fdatasync
+ .long _sys_sysctl
+ .long _sys_ni_syscall /* 150 */ /* sys_mlock */
+ .long _sys_ni_syscall /* sys_munlock */
+ .long _sys_ni_syscall /* sys_mlockall */
+ .long _sys_ni_syscall /* sys_munlockall */
+ .long _sys_sched_setparam
+ .long _sys_sched_getparam /* 155 */
+ .long _sys_sched_setscheduler
+ .long _sys_sched_getscheduler
+ .long _sys_sched_yield
+ .long _sys_sched_get_priority_max
+ .long _sys_sched_get_priority_min /* 160 */
+ .long _sys_sched_rr_get_interval
+ .long _sys_nanosleep
+ .long _sys_mremap
+ .long _sys_setresuid /* setresuid16 */
+ .long _sys_getresuid /* getresuid16 */ /* 165 */
+ .long _sys_ni_syscall /* for vm86 */
+ .long _sys_ni_syscall /* old "query_module" */
+ .long _sys_ni_syscall /* sys_poll */
+ .long _sys_nfsservctl
+ .long _sys_setresgid /* setresgid16 */ /* 170 */
+ .long _sys_getresgid /* getresgid16 */
+ .long _sys_prctl
+ .long _sys_rt_sigreturn
+ .long _sys_rt_sigaction
+ .long _sys_rt_sigprocmask /* 175 */
+ .long _sys_rt_sigpending
+ .long _sys_rt_sigtimedwait
+ .long _sys_rt_sigqueueinfo
+ .long _sys_rt_sigsuspend
+ .long _sys_pread64 /* 180 */
+ .long _sys_pwrite64
+ .long _sys_lchown /* lchown16 */
+ .long _sys_getcwd
+ .long _sys_capget
+ .long _sys_capset /* 185 */
+ .long _sys_sigaltstack
+ .long _sys_sendfile
+ .long _sys_ni_syscall /* streams1 */
+ .long _sys_ni_syscall /* streams2 */
+ .long _sys_vfork /* 190 */
+ .long _sys_getrlimit
+ .long _sys_mmap2
+ .long _sys_truncate64
+ .long _sys_ftruncate64
+ .long _sys_stat64 /* 195 */
+ .long _sys_lstat64
+ .long _sys_fstat64
+ .long _sys_chown
+ .long _sys_getuid
+ .long _sys_getgid /* 200 */
+ .long _sys_geteuid
+ .long _sys_getegid
+ .long _sys_setreuid
+ .long _sys_setregid
+ .long _sys_getgroups /* 205 */
+ .long _sys_setgroups
+ .long _sys_fchown
+ .long _sys_setresuid
+ .long _sys_getresuid
+ .long _sys_setresgid /* 210 */
+ .long _sys_getresgid
+ .long _sys_lchown
+ .long _sys_setuid
+ .long _sys_setgid
+ .long _sys_setfsuid /* 215 */
+ .long _sys_setfsgid
+ .long _sys_pivot_root
+ .long _sys_ni_syscall /* sys_mincore */
+ .long _sys_ni_syscall /* sys_madvise */
+ .long _sys_getdents64 /* 220 */
+ .long _sys_fcntl64
+ .long _sys_ni_syscall /* reserved for TUX */
+ .long _sys_ni_syscall
+ .long _sys_gettid
+ .long _sys_readahead /* 225 */
+ .long _sys_setxattr
+ .long _sys_lsetxattr
+ .long _sys_fsetxattr
+ .long _sys_getxattr
+ .long _sys_lgetxattr /* 230 */
+ .long _sys_fgetxattr
+ .long _sys_listxattr
+ .long _sys_llistxattr
+ .long _sys_flistxattr
+ .long _sys_removexattr /* 235 */
+ .long _sys_lremovexattr
+ .long _sys_fremovexattr
+ .long _sys_tkill
+ .long _sys_sendfile64
+ .long _sys_futex /* 240 */
+ .long _sys_sched_setaffinity
+ .long _sys_sched_getaffinity
+ .long _sys_ni_syscall /* sys_set_thread_area */
+ .long _sys_ni_syscall /* sys_get_thread_area */
+ .long _sys_io_setup /* 245 */
+ .long _sys_io_destroy
+ .long _sys_io_getevents
+ .long _sys_io_submit
+ .long _sys_io_cancel
+ .long _sys_ni_syscall /* 250 */ /* sys_alloc_hugepages */
+ .long _sys_ni_syscall /* sys_freec_hugepages */
+ .long _sys_exit_group
+ .long _sys_lookup_dcookie
+ .long _sys_bfin_spinlock
+ .long _sys_epoll_create /* 255 */
+ .long _sys_epoll_ctl
+ .long _sys_epoll_wait
+ .long _sys_ni_syscall /* remap_file_pages */
+ .long _sys_set_tid_address
+ .long _sys_timer_create /* 260 */
+ .long _sys_timer_settime
+ .long _sys_timer_gettime
+ .long _sys_timer_getoverrun
+ .long _sys_timer_delete
+ .long _sys_clock_settime /* 265 */
+ .long _sys_clock_gettime
+ .long _sys_clock_getres
+ .long _sys_clock_nanosleep
+ .long _sys_statfs64
+ .long _sys_fstatfs64 /* 270 */
+ .long _sys_tgkill
+ .long _sys_utimes
+ .long _sys_fadvise64_64
+ .long _sys_ni_syscall /* vserver */
+ .long _sys_ni_syscall /* 275, mbind */
+ .long _sys_ni_syscall /* get_mempolicy */
+ .long _sys_ni_syscall /* set_mempolicy */
+ .long _sys_mq_open
+ .long _sys_mq_unlink
+ .long _sys_mq_timedsend /* 280 */
+ .long _sys_mq_timedreceive
+ .long _sys_mq_notify
+ .long _sys_mq_getsetattr
+ .long _sys_ni_syscall /* kexec_load */
+ .long _sys_waitid /* 285 */
+ .long _sys_add_key
+ .long _sys_request_key
+ .long _sys_keyctl
+ .long _sys_ioprio_set
+ .long _sys_ioprio_get /* 290 */
+ .long _sys_inotify_init
+ .long _sys_inotify_add_watch
+ .long _sys_inotify_rm_watch
+ .long _sys_ni_syscall /* migrate_pages */
+ .long _sys_openat /* 295 */
+ .long _sys_mkdirat
+ .long _sys_mknodat
+ .long _sys_fchownat
+ .long _sys_futimesat
+ .long _sys_fstatat64 /* 300 */
+ .long _sys_unlinkat
+ .long _sys_renameat
+ .long _sys_linkat
+ .long _sys_symlinkat
+ .long _sys_readlinkat /* 305 */
+ .long _sys_fchmodat
+ .long _sys_faccessat
+ .long _sys_pselect6
+ .long _sys_ppoll
+ .long _sys_unshare /* 310 */
+ .long _sys_sram_alloc
+ .long _sys_sram_free
+ .long _sys_dma_memcpy
+ .long _sys_accept
+ .long _sys_bind /* 315 */
+ .long _sys_connect
+ .long _sys_getpeername
+ .long _sys_getsockname
+ .long _sys_getsockopt
+ .long _sys_listen /* 320 */
+ .long _sys_recv
+ .long _sys_recvfrom
+ .long _sys_recvmsg
+ .long _sys_send
+ .long _sys_sendmsg /* 325 */
+ .long _sys_sendto
+ .long _sys_setsockopt
+ .long _sys_shutdown
+ .long _sys_socket
+ .long _sys_socketpair /* 330 */
+ .long _sys_semctl
+ .long _sys_semget
+ .long _sys_semop
+ .long _sys_msgctl
+ .long _sys_msgget /* 335 */
+ .long _sys_msgrcv
+ .long _sys_msgsnd
+ .long _sys_shmat
+ .long _sys_shmctl
+ .long _sys_shmdt /* 340 */
+ .long _sys_shmget
+ .long _sys_splice
+ .long _sys_sync_file_range
+ .long _sys_tee
+ .long _sys_vmsplice /* 345 */
+ .long _sys_epoll_pwait
+ .long _sys_utimensat
+ .long _sys_signalfd
+ .long _sys_timerfd_create
+ .long _sys_eventfd /* 350 */
+ .long _sys_pread64
+ .long _sys_pwrite64
+ .long _sys_fadvise64
+ .long _sys_set_robust_list
+ .long _sys_get_robust_list /* 355 */
+ .long _sys_fallocate
+ .long _sys_semtimedop
+ .long _sys_timerfd_settime
+ .long _sys_timerfd_gettime
+ .long _sys_signalfd4 /* 360 */
+ .long _sys_eventfd2
+ .long _sys_epoll_create1
+ .long _sys_dup3
+ .long _sys_pipe2
+ .long _sys_inotify_init1 /* 365 */
+
+ .rept NR_syscalls-(.-_sys_call_table)/4
+ .long _sys_ni_syscall
+ .endr
+END(_sys_call_table)
+
+_exception_stack:
+ .rept 1024
+ .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
new file mode 100644
index 0000000..f123a62
--- /dev/null
+++ b/arch/blackfin/mach-common/head.S
@@ -0,0 +1,305 @@
+/*
+ * Common Blackfin startup code
+ *
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/blackfin.h>
+#include <asm/thread_info.h>
+#include <asm/trace.h>
+
+__INIT
+
+#define INITIAL_STACK (L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
+
+ENTRY(__start)
+ /* R0: argument of command line string, passed from uboot, save it */
+ R7 = R0;
+ /* Enable Cycle Counter and Nesting Of Interrupts */
+#ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES
+ R0 = SYSCFG_SNEN;
+#else
+ R0 = SYSCFG_SNEN | SYSCFG_CCEN;
+#endif
+ SYSCFG = R0;
+ R0 = 0;
+
+ /* Clear Out All the data and pointer Registers */
+ R1 = R0;
+ R2 = R0;
+ R3 = R0;
+ R4 = R0;
+ R5 = R0;
+ R6 = R0;
+
+ P0 = R0;
+ P1 = R0;
+ P2 = R0;
+ P3 = R0;
+ P4 = R0;
+ P5 = R0;
+
+ LC0 = r0;
+ LC1 = r0;
+ L0 = r0;
+ L1 = r0;
+ L2 = r0;
+ L3 = r0;
+
+ /* Clear Out All the DAG Registers */
+ B0 = r0;
+ B1 = r0;
+ B2 = r0;
+ B3 = r0;
+
+ I0 = r0;
+ I1 = r0;
+ I2 = r0;
+ I3 = r0;
+
+ M0 = r0;
+ M1 = r0;
+ M2 = r0;
+ M3 = r0;
+
+ /*
+ * Clear ITEST_COMMAND and DTEST_COMMAND registers,
+ * Leaving these as non-zero can confuse the emulator
+ */
+ p0.L = LO(DTEST_COMMAND);
+ p0.H = HI(DTEST_COMMAND);
+ [p0] = R0;
+ [p0 + (ITEST_COMMAND - DTEST_COMMAND)] = R0;
+ CSYNC;
+
+ trace_buffer_init(p0,r0);
+ P0 = R1;
+ R0 = R1;
+
+ /* Turn off the icache */
+ p0.l = LO(IMEM_CONTROL);
+ p0.h = HI(IMEM_CONTROL);
+ R1 = [p0];
+ R0 = ~ENICPLB;
+ R0 = R0 & R1;
+ [p0] = R0;
+ SSYNC;
+
+ /* Turn off the dcache */
+ p0.l = LO(DMEM_CONTROL);
+ p0.h = HI(DMEM_CONTROL);
+ R1 = [p0];
+ R0 = ~ENDCPLB;
+ R0 = R0 & R1;
+ [p0] = R0;
+ SSYNC;
+
+ /* in case of double faults, save a few things */
+ p0.l = _init_retx;
+ p0.h = _init_retx;
+ R0 = RETX;
+ [P0] = R0;
+
+#ifdef CONFIG_DEBUG_DOUBLEFAULT
+ /* Only save these if we are storing them,
+ * This happens here, since L1 gets clobbered
+ * below
+ */
+ p0.l = _saved_retx;
+ p0.h = _saved_retx;
+ p1.l = _init_saved_retx;
+ p1.h = _init_saved_retx;
+ r0 = [p0];
+ [p1] = r0;
+
+ p0.l = _saved_dcplb_fault_addr;
+ p0.h = _saved_dcplb_fault_addr;
+ p1.l = _init_saved_dcplb_fault_addr;
+ p1.h = _init_saved_dcplb_fault_addr;
+ r0 = [p0];
+ [p1] = r0;
+
+ p0.l = _saved_icplb_fault_addr;
+ p0.h = _saved_icplb_fault_addr;
+ p1.l = _init_saved_icplb_fault_addr;
+ p1.h = _init_saved_icplb_fault_addr;
+ r0 = [p0];
+ [p1] = r0;
+
+ p0.l = _saved_seqstat;
+ p0.h = _saved_seqstat;
+ p1.l = _init_saved_seqstat;
+ p1.h = _init_saved_seqstat;
+ r0 = [p0];
+ [p1] = r0;
+#endif
+
+ /* Initialize stack pointer */
+ sp.l = lo(INITIAL_STACK);
+ sp.h = hi(INITIAL_STACK);
+ fp = sp;
+ usp = sp;
+
+#ifdef CONFIG_EARLY_PRINTK
+ call _init_early_exception_vectors;
+#endif
+
+ /* 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;
+#endif
+
+ /* This section keeps the processor in supervisor mode
+ * during kernel boot. Switches to user mode at end of boot.
+ * See page 3-9 of Hardware Reference manual for documentation.
+ */
+
+ /* EVT15 = _real_start */
+
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _real_start;
+ p1.h = _real_start;
+ [p0] = p1;
+ csync;
+
+ p0.l = lo(IMASK);
+ p0.h = hi(IMASK);
+ p1.l = IMASK_IVG15;
+ p1.h = 0x0;
+ [p0] = p1;
+ csync;
+
+ raise 15;
+ p0.l = .LWAIT_HERE;
+ p0.h = .LWAIT_HERE;
+ reti = p0;
+#if ANOMALY_05000281
+ nop; nop; nop;
+#endif
+ rti;
+
+.LWAIT_HERE:
+ jump .LWAIT_HERE;
+ENDPROC(__start)
+
+/* A little BF561 glue ... */
+#ifndef WDOG_CTL
+# define WDOG_CTL WDOGA_CTL
+#endif
+
+ENTRY(_real_start)
+ /* Enable nested interrupts */
+ [--sp] = reti;
+
+ /* watchdog off for now */
+ p0.l = lo(WDOG_CTL);
+ p0.h = hi(WDOG_CTL);
+ r0 = 0xAD6(z);
+ w[p0] = r0;
+ ssync;
+
+#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:
+#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:
+#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:
+#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;
+
+ /* Pass the u-boot arguments to the global value command line */
+ R0 = R7;
+ call _cmdline_init;
+
+ /* Load the current thread pointer and stack */
+ sp.l = _init_thread_union;
+ sp.h = _init_thread_union;
+ p1 = THREAD_SIZE (z);
+ sp = sp + p1;
+ usp = sp;
+ fp = sp;
+ jump.l _start_kernel;
+ENDPROC(_real_start)
+
+__FINIT
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
new file mode 100644
index 0000000..4a2ec7a
--- /dev/null
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -0,0 +1,247 @@
+/*
+ * File: arch/blackfin/mach-common/interrupt.S
+ * Based on:
+ * Author: D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>
+ * Kenneth Albanowski <kjahds@kjahds.com>
+ *
+ * Created: ?
+ * Description: Interrupt Entries
+ *
+ * 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 <asm/blackfin.h>
+#include <mach/irq.h>
+#include <linux/linkage.h>
+#include <asm/entry.h>
+#include <asm/asm-offsets.h>
+#include <asm/trace.h>
+#include <asm/traps.h>
+#include <asm/thread_info.h>
+
+#include <asm/context.S>
+
+.extern _ret_from_exception
+
+#ifdef CONFIG_I_ENTRY_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 4 /* just in case */
+
+/* Common interrupt entry code. First we do CLI, then push
+ * RETI, to keep interrupts disabled, but to allow this state to be changed
+ * by local_bh_enable.
+ * R0 contains the interrupt number, while R1 may contain the value of IPEND,
+ * or garbage if IPEND won't be needed by the ISR. */
+__common_int_entry:
+ [--sp] = fp;
+ [--sp] = usp;
+
+ [--sp] = i0;
+ [--sp] = i1;
+ [--sp] = i2;
+ [--sp] = i3;
+
+ [--sp] = m0;
+ [--sp] = m1;
+ [--sp] = m2;
+ [--sp] = m3;
+
+ [--sp] = l0;
+ [--sp] = l1;
+ [--sp] = l2;
+ [--sp] = l3;
+
+ [--sp] = b0;
+ [--sp] = b1;
+ [--sp] = b2;
+ [--sp] = b3;
+ [--sp] = a0.x;
+ [--sp] = a0.w;
+ [--sp] = a1.x;
+ [--sp] = a1.w;
+
+ [--sp] = LC0;
+ [--sp] = LC1;
+ [--sp] = LT0;
+ [--sp] = LT1;
+ [--sp] = LB0;
+ [--sp] = LB1;
+
+ [--sp] = ASTAT;
+
+ [--sp] = r0; /* Skip reserved */
+ [--sp] = RETS;
+ r2 = RETI;
+ [--sp] = r2;
+ [--sp] = RETX;
+ [--sp] = RETN;
+ [--sp] = RETE;
+ [--sp] = SEQSTAT;
+ [--sp] = r1; /* IPEND - R1 may or may not be set up before jumping here. */
+
+ /* Switch to other method of keeping interrupts disabled. */
+#ifdef CONFIG_DEBUG_HWERR
+ r1 = 0x3f;
+ sti r1;
+#else
+ cli r1;
+#endif
+ [--sp] = RETI; /* orig_pc */
+ /* Clear all L registers. */
+ r1 = 0 (x);
+ l0 = r1;
+ l1 = r1;
+ l2 = r1;
+ l3 = r1;
+#ifdef CONFIG_FRAME_POINTER
+ fp = 0;
+#endif
+
+#if ANOMALY_05000283 || ANOMALY_05000315
+ cc = r7 == r7;
+ p5.h = HI(CHIPID);
+ p5.l = LO(CHIPID);
+ if cc jump 1f;
+ r7.l = W[p5];
+1:
+#endif
+ r1 = sp;
+ SP += -12;
+ call _do_irq;
+ SP += 12;
+ call _return_from_int;
+.Lcommon_restore_context:
+ RESTORE_CONTEXT
+ rti;
+
+/* interrupt routine for ivhw - 5 */
+ENTRY(_evt_ivhw)
+ SAVE_ALL_SYS
+#ifdef CONFIG_FRAME_POINTER
+ fp = 0;
+#endif
+
+#if ANOMALY_05000283 || ANOMALY_05000315
+ cc = r7 == r7;
+ p5.h = HI(CHIPID);
+ p5.l = LO(CHIPID);
+ if cc jump 1f;
+ r7.l = W[p5];
+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);
+ 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 _trap_c;
+ SP += 12;
+
+#ifdef EBIU_ERRMST
+ /* make sure EBIU_ERRMST is clear */
+ p0.l = LO(EBIU_ERRMST);
+ p0.h = HI(EBIU_ERRMST);
+ r0.l = (CORE_ERROR | CORE_MERROR);
+ w[p0] = r0.l;
+#endif
+
+ call _ret_from_exception;
+
+.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).
+ * We don't actually use this, so just return.
+ * For inner circle type details, please see:
+ * http://docs.blackfin.uclinux.org/doku.php?id=linux:nmi
+ */
+ENTRY(_evt_nmi)
+.weak _evt_nmi
+ rtn;
+ENDPROC(_evt_nmi)
+
+/* interrupt routine for core timer - 6 */
+ENTRY(_evt_timer)
+ TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P)
+
+/* interrupt routine for evt7 - 7 */
+ENTRY(_evt_evt7)
+ INTERRUPT_ENTRY(EVT_IVG7_P)
+ENTRY(_evt_evt8)
+ INTERRUPT_ENTRY(EVT_IVG8_P)
+ENTRY(_evt_evt9)
+ INTERRUPT_ENTRY(EVT_IVG9_P)
+ENTRY(_evt_evt10)
+ INTERRUPT_ENTRY(EVT_IVG10_P)
+ENTRY(_evt_evt11)
+ INTERRUPT_ENTRY(EVT_IVG11_P)
+ENTRY(_evt_evt12)
+ INTERRUPT_ENTRY(EVT_IVG12_P)
+ENTRY(_evt_evt13)
+ INTERRUPT_ENTRY(EVT_IVG13_P)
+
+
+ /* interrupt routine for system_call - 15 */
+ENTRY(_evt_system_call)
+ SAVE_CONTEXT_SYSCALL
+#ifdef CONFIG_FRAME_POINTER
+ fp = 0;
+#endif
+ call _system_call;
+ jump .Lcommon_restore_context;
+ENDPROC(_evt_system_call)
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
new file mode 100644
index 0000000..34e8a72
--- /dev/null
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -0,0 +1,1152 @@
+/*
+ * File: arch/blackfin/mach-common/ints-priority.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-2008 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>
+
+#ifdef BF537_FAMILY
+# define BF537_GENERIC_ERROR_INT_DEMUX
+#else
+# undef BF537_GENERIC_ERROR_INT_DEMUX
+#endif
+
+/*
+ * 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;
+
+#ifdef CONFIG_PM
+unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */
+unsigned vr_wakeup;
+#endif
+
+struct ivgx {
+ /* irq number for request_irq, available in mach-bf5xx/irq.h */
+ unsigned int irqno;
+ /* corresponding bit in the SIC_ISR register */
+ unsigned int isrflag;
+} 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];
+
+
+/*
+ * 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 &
+#ifndef CONFIG_BF52x
+ bfin_read32((unsigned long *)SIC_IAR0 +
+ (irqn >> 3)) >> iar_shift)) {
+#else
+ bfin_read32((unsigned long *)SIC_IAR0 +
+ ((irqn%32) >> 3) + ((irqn / 32) * 16)) >> iar_shift)) {
+#endif
+ ivg_table[irq_pos].irqno = IVG7 + irqn;
+ ivg_table[irq_pos].isrflag = 1 << (irqn % 32);
+ ivg7_13[ivg].istop++;
+ irq_pos++;
+ }
+ }
+ }
+}
+
+/*
+ * This is for core internal IRQs
+ */
+
+static void bfin_ack_noop(unsigned int irq)
+{
+ /* Dummy function. */
+}
+
+static void bfin_core_mask_irq(unsigned int irq)
+{
+ irq_flags &= ~(1 << irq);
+ if (!irqs_disabled())
+ local_irq_enable();
+}
+
+static void bfin_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 bfin_internal_mask_irq(unsigned int irq)
+{
+#ifdef CONFIG_BF53x
+ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
+ ~(1 << SIC_SYSIRQ(irq)));
+#else
+ unsigned mask_bank, mask_bit;
+ mask_bank = SIC_SYSIRQ(irq) / 32;
+ mask_bit = SIC_SYSIRQ(irq) % 32;
+ bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
+ ~(1 << mask_bit));
+#endif
+ SSYNC();
+}
+
+static void bfin_internal_unmask_irq(unsigned int irq)
+{
+#ifdef CONFIG_BF53x
+ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
+ (1 << SIC_SYSIRQ(irq)));
+#else
+ unsigned mask_bank, mask_bit;
+ mask_bank = SIC_SYSIRQ(irq) / 32;
+ mask_bit = SIC_SYSIRQ(irq) % 32;
+ bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) |
+ (1 << mask_bit));
+#endif
+ SSYNC();
+}
+
+#ifdef CONFIG_PM
+int bfin_internal_set_wake(unsigned int irq, unsigned int state)
+{
+ unsigned bank, bit, wakeup = 0;
+ unsigned long flags;
+ bank = SIC_SYSIRQ(irq) / 32;
+ bit = SIC_SYSIRQ(irq) % 32;
+
+ switch (irq) {
+#ifdef IRQ_RTC
+ case IRQ_RTC:
+ wakeup |= WAKE;
+ break;
+#endif
+#ifdef IRQ_CAN0_RX
+ case IRQ_CAN0_RX:
+ wakeup |= CANWE;
+ break;
+#endif
+#ifdef IRQ_CAN1_RX
+ case IRQ_CAN1_RX:
+ wakeup |= CANWE;
+ break;
+#endif
+#ifdef IRQ_USB_INT0
+ case IRQ_USB_INT0:
+ wakeup |= USBWE;
+ break;
+#endif
+#ifdef IRQ_KEY
+ case IRQ_KEY:
+ wakeup |= KPADWE;
+ break;
+#endif
+#ifdef CONFIG_BF54x
+ case IRQ_CNT:
+ wakeup |= ROTWE;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ local_irq_save(flags);
+
+ if (state) {
+ bfin_sic_iwr[bank] |= (1 << bit);
+ vr_wakeup |= wakeup;
+
+ } else {
+ bfin_sic_iwr[bank] &= ~(1 << bit);
+ vr_wakeup &= ~wakeup;
+ }
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+#endif
+
+static struct irq_chip bfin_core_irqchip = {
+ .name = "CORE",
+ .ack = bfin_ack_noop,
+ .mask = bfin_core_mask_irq,
+ .unmask = bfin_core_unmask_irq,
+};
+
+static struct irq_chip bfin_internal_irqchip = {
+ .name = "INTN",
+ .ack = bfin_ack_noop,
+ .mask = bfin_internal_mask_irq,
+ .unmask = bfin_internal_unmask_irq,
+ .mask_ack = bfin_internal_mask_irq,
+ .disable = bfin_internal_mask_irq,
+ .enable = bfin_internal_unmask_irq,
+#ifdef CONFIG_PM
+ .set_wake = bfin_internal_set_wake,
+#endif
+};
+
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+static int error_int_mask;
+
+static void bfin_generic_error_mask_irq(unsigned int irq)
+{
+ error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
+
+ if (!error_int_mask)
+ bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
+}
+
+static void bfin_generic_error_unmask_irq(unsigned int irq)
+{
+ bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
+ error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
+}
+
+static struct irq_chip bfin_generic_error_irqchip = {
+ .name = "ERROR",
+ .ack = bfin_ack_noop,
+ .mask_ack = bfin_generic_error_mask_irq,
+ .mask = bfin_generic_error_mask_irq,
+ .unmask = bfin_generic_error_unmask_irq,
+};
+
+static void bfin_demux_error_irq(unsigned int int_err_irq,
+ struct irq_desc *inta_desc)
+{
+ int irq = 0;
+
+ SSYNC();
+
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+ if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
+ irq = IRQ_MAC_ERROR;
+ else
+#endif
+ if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
+ irq = IRQ_SPORT0_ERROR;
+ else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
+ irq = IRQ_SPORT1_ERROR;
+ else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
+ irq = IRQ_PPI_ERROR;
+ else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
+ irq = IRQ_CAN_ERROR;
+ else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
+ irq = IRQ_SPI_ERROR;
+ else if ((bfin_read_UART0_IIR() & UART_ERR_MASK_STAT1) &&
+ (bfin_read_UART0_IIR() & UART_ERR_MASK_STAT0))
+ irq = IRQ_UART0_ERROR;
+ else if ((bfin_read_UART1_IIR() & UART_ERR_MASK_STAT1) &&
+ (bfin_read_UART1_IIR() & UART_ERR_MASK_STAT0))
+ 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 {
+
+ switch (irq) {
+ case IRQ_PPI_ERROR:
+ bfin_write_PPI_STATUS(PPI_ERR_MASK);
+ break;
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+ case IRQ_MAC_ERROR:
+ bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
+ break;
+#endif
+ case IRQ_SPORT0_ERROR:
+ bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
+ break;
+
+ case IRQ_SPORT1_ERROR:
+ bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
+ break;
+
+ case IRQ_CAN_ERROR:
+ bfin_write_CAN_GIS(CAN_ERR_MASK);
+ break;
+
+ case IRQ_SPI_ERROR:
+ bfin_write_SPI_STAT(SPI_ERR_MASK);
+ break;
+
+ default:
+ break;
+ }
+
+ pr_debug("IRQ %d:"
+ " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
+ irq);
+ }
+ } else
+ printk(KERN_ERR
+ "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
+ " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
+ __func__, __FILE__, __LINE__);
+
+}
+#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
+
+static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
+{
+ struct irq_desc *desc = irq_desc + irq;
+ /* May not call generic set_irq_handler() due to spinlock
+ recursion. */
+ desc->handle_irq = handle;
+}
+
+#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)];
+
+extern void bfin_gpio_irq_prepare(unsigned gpio);
+
+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();
+ }
+}
+
+static void bfin_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 bfin_gpio_mask_irq(unsigned int irq)
+{
+ set_gpio_maska(irq - IRQ_PF0, 0);
+ SSYNC();
+}
+
+static void bfin_gpio_unmask_irq(unsigned int irq)
+{
+ set_gpio_maska(irq - IRQ_PF0, 1);
+ SSYNC();
+}
+
+static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+{
+ u16 gpionr = irq - IRQ_PF0;
+
+ if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+ bfin_gpio_irq_prepare(gpionr);
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ bfin_gpio_unmask_irq(irq);
+
+ return 0;
+}
+
+static void bfin_gpio_irq_shutdown(unsigned int irq)
+{
+ bfin_gpio_mask_irq(irq);
+ gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0);
+}
+
+static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+ 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)))
+ bfin_gpio_irq_prepare(gpionr);
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ } else {
+ gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ return 0;
+ }
+
+ set_gpio_inen(gpionr, 0);
+ set_gpio_dir(gpionr, 0);
+
+ 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 */
+
+ 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
+ bfin_set_irq_handler(irq, handle_level_irq);
+
+ 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 = {
+ .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)
+{
+ unsigned int i, gpio, mask, irq, search = 0;
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+ } 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 */
+
+#define NR_PINT_SYS_IRQS 4
+#define NR_PINT_BITS 32
+#define NR_PINTS 160
+#define IRQ_NOT_AVAIL 0xFF
+
+#define PINT_2_BANK(x) ((x) >> 5)
+#define PINT_2_BIT(x) ((x) & 0x1F)
+#define PINT_BIT(x) (1 << (PINT_2_BIT(x)))
+
+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;
+ unsigned int request;
+ unsigned int assign;
+ unsigned int edge_set;
+ unsigned int edge_clear;
+ unsigned int invert_set;
+ unsigned int invert_clear;
+ unsigned int pinstate;
+ unsigned int latch;
+};
+
+static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = {
+ (struct pin_int_t *)PINT0_MASK_SET,
+ (struct pin_int_t *)PINT1_MASK_SET,
+ (struct pin_int_t *)PINT2_MASK_SET,
+ (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)
+{
+
+ u16 irq_base;
+
+ if (bank < 2) { /*PA-PB */
+ irq_base = IRQ_PA0 + bmap * 16;
+ } else { /*PC-PJ */
+ irq_base = IRQ_PC0 + bmap * 16;
+ }
+
+ return irq_base;
+
+}
+
+ /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
+void init_pint_lut(void)
+{
+ u16 bank, bit, irq_base, bit_pos;
+ u32 pint_assign;
+ u8 bmap;
+
+ memset(irq2pint_lut, IRQ_NOT_AVAIL, sizeof(irq2pint_lut));
+
+ for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) {
+
+ pint_assign = pint[bank]->assign;
+
+ for (bit = 0; bit < NR_PINT_BITS; bit++) {
+
+ bmap = (pint_assign >> ((bit / 8) * 8)) & 0xFF;
+
+ irq_base = get_irq_base(bank, bmap);
+
+ irq_base += (bit % 8) + ((bit / 8) & 1 ? 8 : 0);
+ bit_pos = bit + bank * NR_PINT_BITS;
+
+ 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];
+ 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;
+
+ SSYNC();
+}
+
+static void bfin_gpio_mask_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[bank]->mask_clear = pintbit;
+ SSYNC();
+}
+
+static void bfin_gpio_mask_irq(unsigned int irq)
+{
+ u8 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 pintbit = PINT_BIT(pint_val);
+ u8 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];
+
+ if (pint_val == IRQ_NOT_AVAIL) {
+ printk(KERN_ERR
+ "GPIO IRQ %d :Not in PINT Assign table "
+ "Reconfigure Interrupt to Port Assignemt\n", irq);
+ return -ENODEV;
+ }
+
+ if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr)))
+ bfin_gpio_irq_prepare(gpionr);
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ bfin_gpio_unmask_irq(irq);
+
+ return 0;
+}
+
+static void bfin_gpio_irq_shutdown(unsigned int irq)
+{
+ u16 gpionr = irq_to_gpio(irq);
+
+ bfin_gpio_mask_irq(irq);
+ gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(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];
+ u32 pintbit = PINT_BIT(pint_val);
+ u8 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))
+ 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)))
+ bfin_gpio_irq_prepare(gpionr);
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ } else {
+ gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ return 0;
+ }
+
+ 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_clear = pintbit; /* high or rising edge denoted by zero */
+
+ 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)) {
+ pint[bank]->edge_set = pintbit;
+ bfin_set_irq_handler(irq, handle_edge_irq);
+ } else {
+ pint[bank]->edge_clear = pintbit;
+ bfin_set_irq_handler(irq, handle_level_irq);
+ }
+
+ SSYNC();
+
+ 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 = {
+ .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 request, irq;
+
+ switch (inta_irq) {
+ case IRQ_PINT0:
+ bank = 0;
+ break;
+ case IRQ_PINT2:
+ bank = 2;
+ break;
+ case IRQ_PINT3:
+ bank = 3;
+ break;
+ case IRQ_PINT1:
+ bank = 1;
+ break;
+ default:
+ return;
+ }
+
+ pint_val = bank * NR_PINT_BITS;
+
+ request = pint[bank]->request;
+
+ while (request) {
+ if (request & 1) {
+ irq = pint2irq_lut[pint_val] + SYS_IRQS;
+ desc = irq_desc + irq;
+ desc->handle_irq(irq, desc);
+ }
+ pint_val++;
+ request >>= 1;
+ }
+
+}
+#endif
+
+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 */
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
+ 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
+#else
+ bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
+#endif
+
+ local_irq_disable();
+
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+ /* Clear EMAC Interrupt Status bits so we can demux it later */
+ bfin_write_EMAC_SYSTAT(-1);
+#endif
+
+#ifdef CONFIG_BF54x
+# ifdef CONFIG_PINTx_REASSIGN
+ pint[0]->assign = CONFIG_PINT0_ASSIGN;
+ pint[1]->assign = CONFIG_PINT1_ASSIGN;
+ pint[2]->assign = CONFIG_PINT2_ASSIGN;
+ pint[3]->assign = CONFIG_PINT3_ASSIGN;
+# endif
+ /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
+ init_pint_lut();
+#endif
+
+ for (irq = 0; irq <= SYS_IRQS; irq++) {
+ if (irq <= IRQ_CORETMR)
+ set_irq_chip(irq, &bfin_core_irqchip);
+ else
+ set_irq_chip(irq, &bfin_internal_irqchip);
+
+ switch (irq) {
+#if defined(CONFIG_BF53x)
+ case IRQ_PROG_INTA:
+# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
+ case IRQ_MAC_RX:
+# endif
+#elif defined(CONFIG_BF54x)
+ case IRQ_PINT0:
+ case IRQ_PINT1:
+ case IRQ_PINT2:
+ case IRQ_PINT3:
+#elif defined(CONFIG_BF52x)
+ case IRQ_PORTF_INTA:
+ case IRQ_PORTG_INTA:
+ case IRQ_PORTH_INTA:
+#elif defined(CONFIG_BF561)
+ case IRQ_PROG0_INTA:
+ case IRQ_PROG1_INTA:
+ case IRQ_PROG2_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);
+
+ break;
+#endif
+ default:
+ set_irq_handler(irq, handle_simple_irq);
+ break;
+ }
+ }
+
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+ for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
+ set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,
+ handle_level_irq);
+#endif
+
+ /* if configured as edge, then will be changed to do_edge_IRQ */
+ for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)
+ set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,
+ 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;
+
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
+ bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
+#if defined(CONFIG_BF52x)
+ /* 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));
+#else
+ bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
+#endif
+# ifdef CONFIG_BF54x
+ bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
+# endif
+#else
+ bfin_write_SIC_IWR(IWR_DISABLE_ALL);
+#endif
+
+ 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;
+#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;
+ }
+ 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;
+ } else if (sic_status & ivg->isrflag)
+ break;
+ }
+#endif
+ vec = ivg->irqno;
+ }
+ asm_do_IRQ(vec, fp);
+}
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
new file mode 100644
index 0000000..606ded9
--- /dev/null
+++ b/arch/blackfin/mach-common/irqpanic.c
@@ -0,0 +1,146 @@
+/*
+ * File: arch/blackfin/mach-common/irqpanic.c
+ * Based on:
+ * Author:
+ *
+ * Created: ?
+ * Description: panic kernel with dump information
+ *
+ * Modified: rgetz - added cache checking code 14Feb06
+ * 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/sched.h>
+#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
+void irq_panic(int reason, struct pt_regs *regs) __attribute__ ((l1_text));
+#endif
+
+/*
+ * irq_panic - calls panic with string setup
+ */
+asmlinkage void irq_panic(int reason, struct pt_regs *regs)
+{
+#ifdef CONFIG_DEBUG_ICACHE_CHECK
+ unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
+ unsigned short i, j, die;
+ unsigned int bad[10][6];
+
+ /* check entire cache for coherency
+ * Since printk is in cacheable memory,
+ * don't call it until you have checked everything
+ */
+
+ die = 0;
+ i = 0;
+
+ /* check icache */
+
+ for (ca = L1_ICACHE_START; ca <= L1_ICACHE_END && i < 10; ca += 32) {
+
+ /* Grab various address bits for the itest_cmd fields */
+ cmd = (((ca & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */
+ ((ca & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */
+ ((ca & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */
+ 0); /* Access Tag, Read access */
+
+ SSYNC();
+ bfin_write_ITEST_COMMAND(cmd);
+ SSYNC();
+ tag = bfin_read_ITEST_DATA0();
+ SSYNC();
+
+ /* if tag is marked as valid, check it */
+ if (tag & 1) {
+ /* The icache is arranged in 4 groups of 64-bits */
+ for (j = 0; j < 32; j += 8) {
+ cmd = ((((ca + j) & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */
+ (((ca + j) & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */
+ (((ca + j) & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */
+ 4); /* Access Data, Read access */
+
+ SSYNC();
+ bfin_write_ITEST_COMMAND(cmd);
+ SSYNC();
+
+ cache_hi = bfin_read_ITEST_DATA1();
+ cache_lo = bfin_read_ITEST_DATA0();
+
+ pa = ((unsigned int *)((tag & 0xffffcc00) |
+ ((ca + j) & ~(0xffffcc00))));
+
+ /*
+ * Debugging this, enable
+ *
+ * printk("addr: %08x %08x%08x | %08x%08x\n",
+ * ((unsigned int *)((tag & 0xffffcc00) | ((ca+j) & ~(0xffffcc00)))),
+ * cache_hi, cache_lo, *(pa+1), *pa);
+ */
+
+ if (cache_hi != *(pa + 1) || cache_lo != *pa) {
+ /* Since icache is not working, stay out of it, by not printing */
+ die = 1;
+ bad[i][0] = (ca + j);
+ bad[i][1] = cache_hi;
+ bad[i][2] = cache_lo;
+ bad[i][3] = ((tag & 0xffffcc00) |
+ ((ca + j) & ~(0xffffcc00)));
+ bad[i][4] = *(pa + 1);
+ bad[i][5] = *(pa);
+ i++;
+ }
+ }
+ }
+ }
+ if (die) {
+ printk(KERN_EMERG "icache coherency error\n");
+ for (j = 0; j <= i; j++) {
+ printk(KERN_EMERG
+ "cache address : %08x cache value : %08x%08x\n",
+ bad[j][0], bad[j][1], bad[j][2]);
+ printk(KERN_EMERG
+ "physical address: %08x SDRAM value : %08x%08x\n",
+ bad[j][3], bad[j][4], bad[j][5]);
+ }
+ panic("icache coherency error");
+ } else {
+ printk(KERN_EMERG "icache checked, and OK\n");
+ }
+#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
new file mode 100644
index 0000000..9daf012
--- /dev/null
+++ b/arch/blackfin/mach-common/lock.S
@@ -0,0 +1,223 @@
+/*
+ * File: arch/blackfin/mach-common/lock.S
+ * Based on:
+ * Author: LG Soft India
+ *
+ * Created: ?
+ * Description: kernel locks
+ *
+ * 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/blackfin.h>
+
+.text
+
+/* When you come here, it is assumed that
+ * R0 - Which way to be locked
+ */
+
+ENTRY(_cache_grab_lock)
+
+ [--SP]=( R7:0,P5:0 );
+
+ P1.H = HI(IMEM_CONTROL);
+ P1.L = LO(IMEM_CONTROL);
+ P5.H = HI(ICPLB_ADDR0);
+ P5.L = LO(ICPLB_ADDR0);
+ P4.H = HI(ICPLB_DATA0);
+ P4.L = LO(ICPLB_DATA0);
+ R7 = R0;
+
+ /* If the code of interest already resides in the cache
+ * invalidate the entire cache itself.
+ * invalidate_entire_icache;
+ */
+
+ SP += -12;
+ [--SP] = RETS;
+ CALL _invalidate_entire_icache;
+ RETS = [SP++];
+ SP += 12;
+
+ /* Disable the Interrupts*/
+
+ CLI R3;
+
+.LLOCK_WAY:
+
+ /* Way0 - 0xFFA133E0
+ * Way1 - 0xFFA137E0
+ * Way2 - 0xFFA13BE0 Total Way Size = 4K
+ * Way3 - 0xFFA13FE0
+ */
+
+ /* Procedure Ex. -Set the locks for other ways by setting ILOC[3:1]
+ * Only Way0 of the instruction cache can now be
+ * replaced by a new code
+ */
+
+ R5 = R7;
+ CC = BITTST(R7,0);
+ IF CC JUMP .LCLEAR1;
+ R7 = 0;
+ BITSET(R7,0);
+ JUMP .LDONE1;
+
+.LCLEAR1:
+ R7 = 0;
+ BITCLR(R7,0);
+.LDONE1: R4 = R7 << 3;
+ R7 = [P1];
+ R7 = R7 | R4;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+
+ R7 = R5;
+ CC = BITTST(R7,1);
+ IF CC JUMP .LCLEAR2;
+ R7 = 0;
+ BITSET(R7,1);
+ JUMP .LDONE2;
+
+.LCLEAR2:
+ R7 = 0;
+ BITCLR(R7,1);
+.LDONE2: R4 = R7 << 3;
+ R7 = [P1];
+ R7 = R7 | R4;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+
+ R7 = R5;
+ CC = BITTST(R7,2);
+ IF CC JUMP .LCLEAR3;
+ R7 = 0;
+ BITSET(R7,2);
+ JUMP .LDONE3;
+.LCLEAR3:
+ R7 = 0;
+ BITCLR(R7,2);
+.LDONE3: R4 = R7 << 3;
+ R7 = [P1];
+ R7 = R7 | R4;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+
+
+ R7 = R5;
+ CC = BITTST(R7,3);
+ IF CC JUMP .LCLEAR4;
+ R7 = 0;
+ BITSET(R7,3);
+ JUMP .LDONE4;
+.LCLEAR4:
+ R7 = 0;
+ BITCLR(R7,3);
+.LDONE4: R4 = R7 << 3;
+ R7 = [P1];
+ R7 = R7 | R4;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+
+ STI R3;
+
+ ( R7:0,P5:0 ) = [SP++];
+
+ RTS;
+ENDPROC(_cache_grab_lock)
+
+/* After the execution of critical code, the code is now locked into
+ * the cache way. Now we need to set ILOC.
+ *
+ * R0 - Which way to be locked
+ */
+
+ENTRY(_cache_lock)
+
+ [--SP]=( R7:0,P5:0 );
+
+ P1.H = HI(IMEM_CONTROL);
+ P1.L = LO(IMEM_CONTROL);
+
+ /* Disable the Interrupts*/
+ CLI R3;
+
+ R7 = [P1];
+ R2 = ~(0x78) (X); /* mask out ILOC */
+ R7 = R7 & R2;
+ R0 = R0 << 3;
+ R7 = R0 | R7;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+ /* Renable the Interrupts */
+ STI R3;
+
+ ( R7:0,P5:0 ) = [SP++];
+ RTS;
+ENDPROC(_cache_lock)
+
+/* Invalidate the Entire Instruction cache by
+ * disabling IMC bit
+ */
+ENTRY(_invalidate_entire_icache)
+ [--SP] = ( R7:5);
+
+ P0.L = LO(IMEM_CONTROL);
+ P0.H = HI(IMEM_CONTROL);
+ R7 = [P0];
+
+ /* Clear the IMC bit , All valid bits in the instruction
+ * cache are set to the invalid state
+ */
+ BITCLR(R7,IMC_P);
+ CLI R6;
+ SSYNC; /* SSYNC required before invalidating cache. */
+ .align 8;
+ [P0] = R7;
+ SSYNC;
+ STI R6;
+
+ /* Configures the instruction cache agian */
+ R6 = (IMC | ENICPLB);
+ R7 = R7 | R6;
+
+ CLI R6;
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P0] = R7;
+ SSYNC;
+ STI R6;
+
+ ( R7:5) = [SP++];
+ RTS;
+ENDPROC(_invalidate_entire_icache)
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
new file mode 100644
index 0000000..e28c6af
--- /dev/null
+++ b/arch/blackfin/mach-common/pm.c
@@ -0,0 +1,340 @@
+/*
+ * File: arch/blackfin/mach-common/pm.c
+ * Based on: arm/mach-omap/pm.c
+ * Author: Cliff Brake <cbrake@accelent.com> Copyright (c) 2001
+ *
+ * Created: 2001
+ * Description: Blackfin power management
+ *
+ * Modified: Nicolas Pitre - PXA250 support
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ * David Singleton - OMAP1510
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ * Dirk Behme <dirk.behme@de.bosch.com> - OMAP1510/1610
+ * Copyright 2004
+ * Copyright 2004-2008 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/suspend.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/gpio.h>
+#include <asm/dma.h>
+#include <asm/dpmc.h>
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_H
+#define WAKEUP_TYPE PM_WAKE_HIGH
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_L
+#define WAKEUP_TYPE PM_WAKE_LOW
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_F
+#define WAKEUP_TYPE PM_WAKE_FALLING
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_R
+#define WAKEUP_TYPE PM_WAKE_RISING
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_B
+#define WAKEUP_TYPE PM_WAKE_BOTH_EDGES
+#endif
+
+
+void bfin_pm_suspend_standby_enter(void)
+{
+ unsigned long flags;
+
+#ifdef CONFIG_PM_WAKEUP_BY_GPIO
+ gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE);
+#endif
+
+ local_irq_save(flags);
+ bfin_pm_standby_setup();
+
+#ifdef CONFIG_PM_BFIN_SLEEP_DEEPER
+ sleep_deeper(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
+#else
+ sleep_mode(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
+#endif
+
+ bfin_pm_standby_restore();
+
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
+ bfin_write_SIC_IWR0(IWR_DISABLE_ALL);
+#if defined(CONFIG_BF52x)
+ /* 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));
+#else
+ bfin_write_SIC_IWR1(IWR_DISABLE_ALL);
+#endif
+# ifdef CONFIG_BF54x
+ bfin_write_SIC_IWR2(IWR_DISABLE_ALL);
+# endif
+#else
+ bfin_write_SIC_IWR(IWR_DISABLE_ALL);
+#endif
+
+ local_irq_restore(flags);
+}
+
+int bf53x_suspend_l1_mem(unsigned char *memptr)
+{
+ dma_memcpy(memptr, (const void *) L1_CODE_START, L1_CODE_LENGTH);
+ dma_memcpy(memptr + L1_CODE_LENGTH, (const void *) L1_DATA_A_START,
+ L1_DATA_A_LENGTH);
+ dma_memcpy(memptr + L1_CODE_LENGTH + L1_DATA_A_LENGTH,
+ (const void *) L1_DATA_B_START, L1_DATA_B_LENGTH);
+ memcpy(memptr + L1_CODE_LENGTH + L1_DATA_A_LENGTH +
+ L1_DATA_B_LENGTH, (const void *) L1_SCRATCH_START,
+ L1_SCRATCH_LENGTH);
+
+ return 0;
+}
+
+int bf53x_resume_l1_mem(unsigned char *memptr)
+{
+ dma_memcpy((void *) L1_CODE_START, memptr, L1_CODE_LENGTH);
+ dma_memcpy((void *) L1_DATA_A_START, memptr + L1_CODE_LENGTH,
+ L1_DATA_A_LENGTH);
+ dma_memcpy((void *) L1_DATA_B_START, memptr + L1_CODE_LENGTH +
+ L1_DATA_A_LENGTH, L1_DATA_B_LENGTH);
+ memcpy((void *) L1_SCRATCH_START, memptr + L1_CODE_LENGTH +
+ L1_DATA_A_LENGTH + L1_DATA_B_LENGTH, L1_SCRATCH_LENGTH);
+
+ return 0;
+}
+
+#ifdef CONFIG_BFIN_WB
+static void flushinv_all_dcache(void)
+{
+ u32 way, bank, subbank, set;
+ u32 status, addr;
+ u32 dmem_ctl = bfin_read_DMEM_CONTROL();
+
+ for (bank = 0; bank < 2; ++bank) {
+ if (!(dmem_ctl & (1 << (DMC1_P - bank))))
+ continue;
+
+ for (way = 0; way < 2; ++way)
+ for (subbank = 0; subbank < 4; ++subbank)
+ for (set = 0; set < 64; ++set) {
+
+ bfin_write_DTEST_COMMAND(
+ way << 26 |
+ bank << 23 |
+ subbank << 16 |
+ set << 5
+ );
+ CSYNC();
+ status = bfin_read_DTEST_DATA0();
+
+ /* only worry about valid/dirty entries */
+ if ((status & 0x3) != 0x3)
+ continue;
+
+ /* construct the address using the tag */
+ addr = (status & 0xFFFFC800) | (subbank << 12) | (set << 5);
+
+ /* flush it */
+ __asm__ __volatile__("FLUSHINV[%0];" : : "a"(addr));
+ }
+ }
+}
+#endif
+
+static inline void dcache_disable(void)
+{
+#ifdef CONFIG_BFIN_DCACHE
+ unsigned long ctrl;
+
+#ifdef CONFIG_BFIN_WB
+ flushinv_all_dcache();
+#endif
+ SSYNC();
+ ctrl = bfin_read_DMEM_CONTROL();
+ ctrl &= ~ENDCPLB;
+ bfin_write_DMEM_CONTROL(ctrl);
+ SSYNC();
+#endif
+}
+
+static inline void dcache_enable(void)
+{
+#ifdef CONFIG_BFIN_DCACHE
+ unsigned long ctrl;
+ SSYNC();
+ ctrl = bfin_read_DMEM_CONTROL();
+ ctrl |= ENDCPLB;
+ bfin_write_DMEM_CONTROL(ctrl);
+ SSYNC();
+#endif
+}
+
+static inline void icache_disable(void)
+{
+#ifdef CONFIG_BFIN_ICACHE
+ unsigned long ctrl;
+ SSYNC();
+ ctrl = bfin_read_IMEM_CONTROL();
+ ctrl &= ~ENICPLB;
+ bfin_write_IMEM_CONTROL(ctrl);
+ SSYNC();
+#endif
+}
+
+static inline void icache_enable(void)
+{
+#ifdef CONFIG_BFIN_ICACHE
+ unsigned long ctrl;
+ SSYNC();
+ ctrl = bfin_read_IMEM_CONTROL();
+ ctrl |= ENICPLB;
+ bfin_write_IMEM_CONTROL(ctrl);
+ SSYNC();
+#endif
+}
+
+int bfin_pm_suspend_mem_enter(void)
+{
+ unsigned long flags;
+ int wakeup, ret;
+
+ unsigned char *memptr = kmalloc(L1_CODE_LENGTH + L1_DATA_A_LENGTH
+ + L1_DATA_B_LENGTH + L1_SCRATCH_LENGTH,
+ GFP_KERNEL);
+
+ if (memptr == NULL) {
+ panic("bf53x_suspend_l1_mem malloc failed");
+ return -ENOMEM;
+ }
+
+ wakeup = bfin_read_VR_CTL() & ~FREQ;
+ wakeup |= SCKELOW;
+
+#ifdef CONFIG_PM_BFIN_WAKE_PH6
+ wakeup |= PHYWE;
+#endif
+#ifdef CONFIG_PM_BFIN_WAKE_GP
+ wakeup |= GPWE;
+#endif
+
+ local_irq_save(flags);
+
+ ret = blackfin_dma_suspend();
+
+ if (ret) {
+ local_irq_restore(flags);
+ kfree(memptr);
+ return ret;
+ }
+
+ bfin_gpio_pm_hibernate_suspend();
+
+ dcache_disable();
+ icache_disable();
+ bf53x_suspend_l1_mem(memptr);
+
+ do_hibernate(wakeup | vr_wakeup); /* Goodbye */
+
+ bf53x_resume_l1_mem(memptr);
+
+ icache_enable();
+ dcache_enable();
+
+ bfin_gpio_pm_hibernate_restore();
+ blackfin_dma_resume();
+
+ local_irq_restore(flags);
+ kfree(memptr);
+
+ return 0;
+}
+
+/*
+ * bfin_pm_valid - Tell the PM core that we only support the standby sleep
+ * state
+ * @state: suspend state we're checking.
+ *
+ */
+static int bfin_pm_valid(suspend_state_t state)
+{
+ return (state == PM_SUSPEND_STANDBY
+#ifndef BF533_FAMILY
+ /*
+ * On BF533/2/1:
+ * If we enter Hibernate the SCKE Pin is driven Low,
+ * so that the SDRAM enters Self Refresh Mode.
+ * However when the reset sequence that follows hibernate
+ * state is executed, SCKE is driven High, taking the
+ * SDRAM out of Self Refresh.
+ *
+ * If you reconfigure and access the SDRAM "very quickly",
+ * you are likely to avoid errors, otherwise the SDRAM
+ * start losing its contents.
+ * An external HW workaround is possible using logic gates.
+ */
+ || state == PM_SUSPEND_MEM
+#endif
+ );
+}
+
+/*
+ * bfin_pm_enter - Actually enter a sleep state.
+ * @state: State we're entering.
+ *
+ */
+static int bfin_pm_enter(suspend_state_t state)
+{
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ bfin_pm_suspend_standby_enter();
+ break;
+ case PM_SUSPEND_MEM:
+ bfin_pm_suspend_mem_enter();
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct platform_suspend_ops bfin_pm_ops = {
+ .enter = bfin_pm_enter,
+ .valid = bfin_pm_valid,
+};
+
+static int __init bfin_pm_init(void)
+{
+ suspend_set_ops(&bfin_pm_ops);
+ return 0;
+}
+
+__initcall(bfin_pm_init);
OpenPOWER on IntegriCloud