[ARM] 4184/1: iop: cp6 access handler (undef_hook)
authorDan Williams <dan.j.williams@intel.com>
Tue, 13 Feb 2007 16:12:04 +0000 (17:12 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Wed, 14 Feb 2007 15:21:24 +0000 (15:21 +0000)
Enable svc access to cp6 via an undefined instruction hook.  Do not enable
access for usr code.

This patch also makes iop13xx select PLAT_IOP, this requires a small change
to drivers/i2c/busses/i2c-iop3xx.c.

Per Lennert Buytenhek's note, the cp6 trap routine is moved to arch/arm/plat-iop
Per Nicolas Pitre's note, the cp_wait is skipped since the latency to
return to the faulting function is longer than cp_wait.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/Kconfig
arch/arm/mach-iop13xx/irq.c
arch/arm/mach-iop32x/irq.c
arch/arm/mach-iop33x/irq.c
arch/arm/plat-iop/Makefile
arch/arm/plat-iop/cp6.c [new file with mode: 0644]
drivers/i2c/busses/i2c-iop3xx.c
include/asm-arm/hardware/iop3xx.h

index 6783c2e..3f48e35 100644 (file)
@@ -233,6 +233,8 @@ config ARCH_IOP33X
 
 config ARCH_IOP13XX
        bool "IOP13xx-based"
+       depends on MMU
+       select PLAT_IOP
        select PCI
        help
          Support for Intel's IOP13XX (XScale) family of processors.
index dbbc07c..162b932 100644 (file)
@@ -250,11 +250,14 @@ static struct irq_chip iop13xx_irqchip4 = {
        .unmask = iop13xx_irq_unmask3,
 };
 
+extern void iop_init_cp6_handler(void);
+
 void __init iop13xx_init_irq(void)
 {
        unsigned int i;
 
        u32 cp_flags = iop13xx_cp6_save();
+       iop_init_cp6_handler();
 
        /* disable all interrupts */
        write_intctl_0(0);
index 3ec1cd5..8b0ac55 100644 (file)
@@ -60,6 +60,8 @@ void __init iop32x_init_irq(void)
 {
        int i;
 
+       iop_init_cp6_handler();
+
        intctl_write(0);
        intstr_write(0);
        if (machine_is_glantank() ||
index 00b37f3..effbe6b 100644 (file)
@@ -110,6 +110,8 @@ void __init iop33x_init_irq(void)
 {
        int i;
 
+       iop_init_cp6_handler();
+
        intctl0_write(0);
        intctl1_write(0);
        intstr0_write(0);
index ed91463..3250d73 100644 (file)
@@ -2,7 +2,29 @@
 # Makefile for the linux kernel.
 #
 
-obj-y                  := gpio.o i2c.o pci.o setup.o time.o io.o
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
+obj-y :=
+
+# IOP32X
+obj-$(CONFIG_ARCH_IOP32X) += gpio.o
+obj-$(CONFIG_ARCH_IOP32X) += i2c.o
+obj-$(CONFIG_ARCH_IOP32X) += pci.o
+obj-$(CONFIG_ARCH_IOP32X) += setup.o
+obj-$(CONFIG_ARCH_IOP32X) += time.o
+obj-$(CONFIG_ARCH_IOP32X) += io.o
+obj-$(CONFIG_ARCH_IOP32X) += cp6.o
+
+# IOP33X
+obj-$(CONFIG_ARCH_IOP33X) += gpio.o
+obj-$(CONFIG_ARCH_IOP33X) += i2c.o
+obj-$(CONFIG_ARCH_IOP33X) += pci.o
+obj-$(CONFIG_ARCH_IOP33X) += setup.o
+obj-$(CONFIG_ARCH_IOP33X) += time.o
+obj-$(CONFIG_ARCH_IOP33X) += io.o
+obj-$(CONFIG_ARCH_IOP33X) += cp6.o
+
+# IOP13XX
+obj-$(CONFIG_ARCH_IOP13XX) += cp6.o
+
+obj-m                  :=
+obj-n                  :=
+obj-                   :=
diff --git a/arch/arm/plat-iop/cp6.c b/arch/arm/plat-iop/cp6.c
new file mode 100644 (file)
index 0000000..9612a87
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * IOP Coprocessor-6 access handler
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+#include <linux/init.h>
+#include <asm/traps.h>
+
+static int cp6_trap(struct pt_regs *regs, unsigned int instr)
+{
+       u32 temp;
+
+        /* enable cp6 access */
+        asm volatile (
+               "mrc    p15, 0, %0, c15, c1, 0\n\t"
+               "orr    %0, %0, #(1 << 6)\n\t"
+               "mcr    p15, 0, %0, c15, c1, 0\n\t"
+               : "=r"(temp));
+
+       return 0;
+}
+
+/* permit kernel space cp6 access
+ * deny user space cp6 access
+ */
+static struct undef_hook cp6_hook = {
+       .instr_mask     = 0x0f000ff0,
+       .instr_val      = 0x0e000610,
+       .cpsr_mask      = MODE_MASK,
+       .cpsr_val       = SVC_MODE,
+       .fn             = cp6_trap,
+};
+
+void __init iop_init_cp6_handler(void)
+{
+       register_undef_hook(&cp6_hook);
+}
index d108ab4..b70a7f7 100644 (file)
@@ -84,7 +84,7 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
         * Every time unit enable is asserted, GPOD needs to be cleared
         * on IOP3XX to avoid data corruption on the bus.
         */
-#ifdef CONFIG_PLAT_IOP
+#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
        if (iop3xx_adap->id == 0) {
                gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
                gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
index adb96c7..c91b546 100644 (file)
@@ -278,6 +278,7 @@ extern void gpio_line_set(int line, int value);
 void iop3xx_map_io(void);
 void iop3xx_init_time(unsigned long);
 unsigned long iop3xx_gettimeoffset(void);
+void iop_init_cp6_handler(void);
 
 extern struct platform_device iop3xx_i2c0_device;
 extern struct platform_device iop3xx_i2c1_device;