Merge branches 'at91', 'dcache', 'ftrace', 'hwbpt', 'misc', 'mmci', 's3c', 'st-ux...
authorRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 18 Oct 2010 21:34:25 +0000 (22:34 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 18 Oct 2010 21:34:25 +0000 (22:34 +0100)
78 files changed:
Makefile
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/configs/u300_defconfig
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/cachetype.h
arch/arm/include/asm/ftrace.h
arch/arm/include/asm/hw_breakpoint.h [new file with mode: 0644]
arch/arm/include/asm/module.h
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/processor.h
arch/arm/include/asm/ptrace.h
arch/arm/include/asm/smp_plat.h
arch/arm/include/asm/system.h
arch/arm/include/asm/tlbflush.h
arch/arm/kernel/Makefile
arch/arm/kernel/armksyms.c
arch/arm/kernel/entry-common.S
arch/arm/kernel/ftrace.c
arch/arm/kernel/hw_breakpoint.c [new file with mode: 0644]
arch/arm/kernel/module.c
arch/arm/kernel/process.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/setup.c
arch/arm/kernel/unwind.c
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/board-flexibity.c [new file with mode: 0644]
arch/arm/mach-realview/core.c
arch/arm/mach-s3c64xx/mach-smartq.c
arch/arm/mach-s3c64xx/mach-smartq5.c
arch/arm/mach-s3c64xx/mach-smartq7.c
arch/arm/mach-ux500/Kconfig
arch/arm/mach-ux500/Makefile
arch/arm/mach-ux500/board-mop500-regulators.c [new file with mode: 0644]
arch/arm/mach-ux500/board-mop500-sdi.c [new file with mode: 0644]
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/board-mop500.h [new file with mode: 0644]
arch/arm/mach-ux500/cpu-db5500.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/devices-db8500.c
arch/arm/mach-ux500/hotplug.c [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/db5500-regs.h
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/include/mach/devices.h
arch/arm/mach-ux500/include/mach/hardware.h
arch/arm/mach-ux500/include/mach/irqs-db5500.h
arch/arm/mach-ux500/include/mach/irqs.h
arch/arm/mach-ux500/include/mach/mbox.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/prcmu-regs.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/prcmu.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/setup.h
arch/arm/mach-ux500/mbox.c [new file with mode: 0644]
arch/arm/mach-ux500/modem_irq.c [new file with mode: 0644]
arch/arm/mach-ux500/pins-db5500.h [new file with mode: 0644]
arch/arm/mach-ux500/pins-db8500.h
arch/arm/mach-ux500/platsmp.c
arch/arm/mach-ux500/prcmu.c [new file with mode: 0644]
arch/arm/mach-ux500/ste-dma40-db5500.h [new file with mode: 0644]
arch/arm/mach-ux500/ste-dma40-db8500.h
arch/arm/mm/copypage-v4mc.c
arch/arm/mm/copypage-v6.c
arch/arm/mm/copypage-xscale.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault-armv.c
arch/arm/mm/fault.c
arch/arm/mm/flush.c
arch/arm/plat-nomadik/gpio.c
arch/arm/plat-nomadik/include/plat/gpio.h
arch/arm/plat-nomadik/include/plat/pincfg.h
drivers/gpio/tc35892-gpio.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
include/linux/amba/mmci.h
include/linux/mfd/tc35892.h
kernel/trace/Kconfig
scripts/Makefile.build
scripts/recordmcount.pl

index 471c49f..cf7fcb3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -554,8 +554,15 @@ endif
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS  += -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
+# Some targets (ARM with Thumb2, for example), can't be built with frame
+# pointers.  For those, we don't have FUNCTION_TRACER automatically
+# select FRAME_POINTER.  However, FUNCTION_TRACER adds -pg, and this is
+# incompatible with -fomit-frame-pointer with current GCC, so we don't use
+# -fomit-frame-pointer with FUNCTION_TRACER.
+ifndef CONFIG_FUNCTION_TRACER
 KBUILD_CFLAGS  += -fomit-frame-pointer
 endif
+endif
 
 ifdef CONFIG_DEBUG_INFO
 KBUILD_CFLAGS  += -g
index 94360e7..b404e5e 100644 (file)
@@ -19,6 +19,8 @@ config ARM
        select HAVE_KPROBES if (!XIP_KERNEL)
        select HAVE_KRETPROBES if (HAVE_KPROBES)
        select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
+       select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
+       select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL)
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZO
@@ -26,6 +28,7 @@ config ARM
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
        select HAVE_REGS_AND_STACK_ACCESS_API
+       select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V7))
        help
          The ARM series is a line of low-power-consumption RISC chip designs
          licensed by ARM Ltd and targeted at embedded applications and
index 91344af..4dbce53 100644 (file)
@@ -27,6 +27,11 @@ config ARM_UNWIND
          the performance is not affected. Currently, this feature
          only works with EABI compilers. If unsure say Y.
 
+config OLD_MCOUNT
+       bool
+       depends on FUNCTION_TRACER && FRAME_POINTER
+       default y
+
 config DEBUG_USER
        bool "Verbose user fault messages"
        help
index 46e5e07..c1c252c 100644 (file)
@@ -28,26 +28,9 @@ CONFIG_CPU_IDLE=y
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
 # CONFIG_SUSPEND is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MISC_DEVICES is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
@@ -58,7 +41,6 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
-CONFIG_POWER_SUPPLY=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_REGULATOR=y
@@ -66,24 +48,10 @@ CONFIG_FB=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_VERBOSE_PROCFS is not set
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-# CONFIG_SND_SPI is not set
-CONFIG_SND_SOC=y
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
 CONFIG_MMC_ARMMMCI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_BACKLIGHT=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_HCTOSYS is not set
 CONFIG_RTC_DRV_COH901331=y
@@ -93,12 +61,11 @@ CONFIG_COH901318=y
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DETECT_SOFTLOCKUP is not set
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
index a3db768..3acd8fa 100644 (file)
 #endif
 
 /*
- * This flag is used to indicate that the page pointed to by a pte
- * is dirty and requires cleaning before returning it to the user.
+ * This flag is used to indicate that the page pointed to by a pte is clean
+ * and does not require cleaning before returning it to the user.
  */
-#define PG_dcache_dirty PG_arch_1
+#define PG_dcache_clean PG_arch_1
 
 /*
  *     MM Cache Management
@@ -431,9 +431,6 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
 #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
 static inline void flush_kernel_dcache_page(struct page *page)
 {
-       /* highmem pages are always flushed upon kunmap already */
-       if ((cache_is_vivt() || cache_is_vipt_aliasing()) && !PageHighMem(page))
-               __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
 }
 
 #define flush_dcache_mmap_lock(mapping) \
index d3a4c2c..c023db0 100644 (file)
@@ -6,6 +6,7 @@
 #define CACHEID_VIPT_ALIASING          (1 << 2)
 #define CACHEID_VIPT                   (CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING)
 #define CACHEID_ASID_TAGGED            (1 << 3)
+#define CACHEID_VIPT_I_ALIASING                (1 << 4)
 
 extern unsigned int cacheid;
 
@@ -14,15 +15,18 @@ extern unsigned int cacheid;
 #define cache_is_vipt_nonaliasing()    cacheid_is(CACHEID_VIPT_NONALIASING)
 #define cache_is_vipt_aliasing()       cacheid_is(CACHEID_VIPT_ALIASING)
 #define icache_is_vivt_asid_tagged()   cacheid_is(CACHEID_ASID_TAGGED)
+#define icache_is_vipt_aliasing()      cacheid_is(CACHEID_VIPT_I_ALIASING)
 
 /*
  * __LINUX_ARM_ARCH__ is the minimum supported CPU architecture
  * Mask out support which will never be present on newer CPUs.
  * - v6+ is never VIVT
- * - v7+ VIPT never aliases
+ * - v7+ VIPT never aliases on D-side
  */
 #if __LINUX_ARM_ARCH__ >= 7
-#define __CACHEID_ARCH_MIN     (CACHEID_VIPT_NONALIASING | CACHEID_ASID_TAGGED)
+#define __CACHEID_ARCH_MIN     (CACHEID_VIPT_NONALIASING |\
+                                CACHEID_ASID_TAGGED |\
+                                CACHEID_VIPT_I_ALIASING)
 #elif __LINUX_ARM_ARCH__ >= 6
 #define        __CACHEID_ARCH_MIN      (~CACHEID_VIVT)
 #else
index 103f7ee..f89515a 100644 (file)
@@ -2,12 +2,30 @@
 #define _ASM_ARM_FTRACE
 
 #ifdef CONFIG_FUNCTION_TRACER
-#define MCOUNT_ADDR            ((long)(mcount))
+#define MCOUNT_ADDR            ((unsigned long)(__gnu_mcount_nc))
 #define MCOUNT_INSN_SIZE       4 /* sizeof mcount call */
 
 #ifndef __ASSEMBLY__
 extern void mcount(void);
 extern void __gnu_mcount_nc(void);
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+struct dyn_arch_ftrace {
+#ifdef CONFIG_OLD_MCOUNT
+       bool    old_mcount;
+#endif
+};
+
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       /* With Thumb-2, the recorded addresses have the lsb set */
+       return addr & ~1;
+}
+
+extern void ftrace_caller_old(void);
+extern void ftrace_call_old(void);
+#endif
+
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/hw_breakpoint.h b/arch/arm/include/asm/hw_breakpoint.h
new file mode 100644 (file)
index 0000000..4d8ae9d
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef _ARM_HW_BREAKPOINT_H
+#define _ARM_HW_BREAKPOINT_H
+
+#ifdef __KERNEL__
+
+struct task_struct;
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+
+struct arch_hw_breakpoint_ctrl {
+               u32 __reserved  : 9,
+               mismatch        : 1,
+                               : 9,
+               len             : 8,
+               type            : 2,
+               privilege       : 2,
+               enabled         : 1;
+};
+
+struct arch_hw_breakpoint {
+       u32     address;
+       u32     trigger;
+       struct perf_event *suspended_wp;
+       struct arch_hw_breakpoint_ctrl ctrl;
+};
+
+static inline u32 encode_ctrl_reg(struct arch_hw_breakpoint_ctrl ctrl)
+{
+       return (ctrl.mismatch << 22) | (ctrl.len << 5) | (ctrl.type << 3) |
+               (ctrl.privilege << 1) | ctrl.enabled;
+}
+
+static inline void decode_ctrl_reg(u32 reg,
+                                  struct arch_hw_breakpoint_ctrl *ctrl)
+{
+       ctrl->enabled   = reg & 0x1;
+       reg >>= 1;
+       ctrl->privilege = reg & 0x3;
+       reg >>= 2;
+       ctrl->type      = reg & 0x3;
+       reg >>= 2;
+       ctrl->len       = reg & 0xff;
+       reg >>= 17;
+       ctrl->mismatch  = reg & 0x1;
+}
+
+/* Debug architecture numbers. */
+#define ARM_DEBUG_ARCH_RESERVED        0       /* In case of ptrace ABI updates. */
+#define ARM_DEBUG_ARCH_V6      1
+#define ARM_DEBUG_ARCH_V6_1    2
+#define ARM_DEBUG_ARCH_V7_ECP14        3
+#define ARM_DEBUG_ARCH_V7_MM   4
+
+/* Breakpoint */
+#define ARM_BREAKPOINT_EXECUTE 0
+
+/* Watchpoints */
+#define ARM_BREAKPOINT_LOAD    1
+#define ARM_BREAKPOINT_STORE   2
+
+/* Privilege Levels */
+#define ARM_BREAKPOINT_PRIV    1
+#define ARM_BREAKPOINT_USER    2
+
+/* Lengths */
+#define ARM_BREAKPOINT_LEN_1   0x1
+#define ARM_BREAKPOINT_LEN_2   0x3
+#define ARM_BREAKPOINT_LEN_4   0xf
+#define ARM_BREAKPOINT_LEN_8   0xff
+
+/* Limits */
+#define ARM_MAX_BRP            16
+#define ARM_MAX_WRP            16
+#define ARM_MAX_HBP_SLOTS      (ARM_MAX_BRP + ARM_MAX_WRP)
+
+/* DSCR method of entry bits. */
+#define ARM_DSCR_MOE(x)                        ((x >> 2) & 0xf)
+#define ARM_ENTRY_BREAKPOINT           0x1
+#define ARM_ENTRY_ASYNC_WATCHPOINT     0x2
+#define ARM_ENTRY_SYNC_WATCHPOINT      0xa
+
+/* DSCR monitor/halting bits. */
+#define ARM_DSCR_HDBGEN                (1 << 14)
+#define ARM_DSCR_MDBGEN                (1 << 15)
+
+/* opcode2 numbers for the co-processor instructions. */
+#define ARM_OP2_BVR            4
+#define ARM_OP2_BCR            5
+#define ARM_OP2_WVR            6
+#define ARM_OP2_WCR            7
+
+/* Base register numbers for the debug registers. */
+#define ARM_BASE_BVR           64
+#define ARM_BASE_BCR           80
+#define ARM_BASE_WVR           96
+#define ARM_BASE_WCR           112
+
+/* Accessor macros for the debug registers. */
+#define ARM_DBG_READ(M, OP2, VAL) do {\
+       asm volatile("mrc p14, 0, %0, c0," #M ", " #OP2 : "=r" (VAL));\
+} while (0)
+
+#define ARM_DBG_WRITE(M, OP2, VAL) do {\
+       asm volatile("mcr p14, 0, %0, c0," #M ", " #OP2 : : "r" (VAL));\
+} while (0)
+
+struct notifier_block;
+struct perf_event;
+struct pmu;
+
+extern struct pmu perf_ops_bp;
+extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
+                                 int *gen_len, int *gen_type);
+extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
+extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+                                          unsigned long val, void *data);
+
+extern u8 arch_get_debug_arch(void);
+extern u8 arch_get_max_wp_len(void);
+extern void clear_ptrace_hw_breakpoint(struct task_struct *tsk);
+
+int arch_install_hw_breakpoint(struct perf_event *bp);
+void arch_uninstall_hw_breakpoint(struct perf_event *bp);
+void hw_breakpoint_pmu_read(struct perf_event *bp);
+int hw_breakpoint_slots(int type);
+
+#else
+static inline void clear_ptrace_hw_breakpoint(struct task_struct *tsk) {}
+
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+#endif /* __KERNEL__ */
+#endif /* _ARM_HW_BREAKPOINT_H */
index e4dfa69..cbb0bc2 100644 (file)
@@ -7,20 +7,27 @@
 
 struct unwind_table;
 
-struct mod_arch_specific
-{
 #ifdef CONFIG_ARM_UNWIND
-       Elf_Shdr *unw_sec_init;
-       Elf_Shdr *unw_sec_devinit;
-       Elf_Shdr *unw_sec_core;
-       Elf_Shdr *sec_init_text;
-       Elf_Shdr *sec_devinit_text;
-       Elf_Shdr *sec_core_text;
-       struct unwind_table *unwind_init;
-       struct unwind_table *unwind_devinit;
-       struct unwind_table *unwind_core;
-#endif
+struct arm_unwind_mapping {
+       Elf_Shdr *unw_sec;
+       Elf_Shdr *sec_text;
+       struct unwind_table *unwind;
+};
+enum {
+       ARM_SEC_INIT,
+       ARM_SEC_DEVINIT,
+       ARM_SEC_CORE,
+       ARM_SEC_EXIT,
+       ARM_SEC_DEVEXIT,
+       ARM_SEC_MAX,
+};
+struct mod_arch_specific {
+       struct arm_unwind_mapping map[ARM_SEC_MAX];
 };
+#else
+struct mod_arch_specific {
+};
+#endif
 
 /*
  * Include the ARM architecture version.
index e90b167..a9672e8 100644 (file)
@@ -278,9 +278,24 @@ extern struct page *empty_zero_page;
 
 #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
 
-#define set_pte_at(mm,addr,ptep,pteval) do { \
-       set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \
- } while (0)
+#if __LINUX_ARM_ARCH__ < 6
+static inline void __sync_icache_dcache(pte_t pteval)
+{
+}
+#else
+extern void __sync_icache_dcache(pte_t pteval);
+#endif
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t pteval)
+{
+       if (addr >= TASK_SIZE)
+               set_pte_ext(ptep, pteval, 0);
+       else {
+               __sync_icache_dcache(pteval);
+               set_pte_ext(ptep, pteval, PTE_EXT_NG);
+       }
+}
 
 /*
  * The following only work if pte_present() is true.
@@ -290,8 +305,13 @@ extern struct page *empty_zero_page;
 #define pte_write(pte)         (pte_val(pte) & L_PTE_WRITE)
 #define pte_dirty(pte)         (pte_val(pte) & L_PTE_DIRTY)
 #define pte_young(pte)         (pte_val(pte) & L_PTE_YOUNG)
+#define pte_exec(pte)          (pte_val(pte) & L_PTE_EXEC)
 #define pte_special(pte)       (0)
 
+#define pte_present_user(pte) \
+       ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
+        (L_PTE_PRESENT | L_PTE_USER))
+
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
 
index 7bed3da..67357ba 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifdef __KERNEL__
 
+#include <asm/hw_breakpoint.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
 
@@ -41,6 +42,9 @@ struct debug_entry {
 struct debug_info {
        int                     nsaved;
        struct debug_entry      bp[2];
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+       struct perf_event       *hbp[ARM_MAX_HBP_SLOTS];
+#endif
 };
 
 struct thread_struct {
index 7ce15eb..783d50f 100644 (file)
@@ -29,6 +29,8 @@
 #define PTRACE_SETCRUNCHREGS   26
 #define PTRACE_GETVFPREGS      27
 #define PTRACE_SETVFPREGS      28
+#define PTRACE_GETHBPREGS      29
+#define PTRACE_SETHBPREGS      30
 
 /*
  * PSR bits
index 7f4e663..f24c1b9 100644 (file)
@@ -31,6 +31,9 @@ static inline int tlb_ops_need_broadcast(void)
        return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
 }
 
+#if !defined(CONFIG_SMP) || __LINUX_ARM_ARCH__ >= 7
+#define cache_ops_need_broadcast()     0
+#else
 static inline int cache_ops_need_broadcast(void)
 {
        if (!is_smp())
@@ -38,5 +41,6 @@ static inline int cache_ops_need_broadcast(void)
 
        return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 1;
 }
+#endif
 
 #endif
index 48e360c..1120f18 100644 (file)
@@ -85,6 +85,10 @@ void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
                                       struct pt_regs *),
                     int sig, int code, const char *name);
 
+void hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int,
+                                      struct pt_regs *),
+                    int sig, int code, const char *name);
+
 #define xchg(ptr,x) \
        ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
index cf2f018..ce7378e 100644 (file)
@@ -570,12 +570,20 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 #endif
 
 /*
- * if PG_dcache_dirty is set for the page, we need to ensure that any
+ * If PG_dcache_clean is not set for the page, we need to ensure that any
  * cache entries for the kernels virtual memory range are written
- * back to the page.
+ * back to the page. On ARMv6 and later, the cache coherency is handled via
+ * the set_pte_at() function.
  */
+#if __LINUX_ARM_ARCH__ < 6
 extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
        pte_t *ptep);
+#else
+static inline void update_mmu_cache(struct vm_area_struct *vma,
+                                   unsigned long addr, pte_t *ptep)
+{
+}
+#endif
 
 #endif
 
index 980b78e..5b9b268 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_KGDB)            += kgdb.o
 obj-$(CONFIG_ARM_UNWIND)       += unwind.o
 obj-$(CONFIG_HAVE_TCM)         += tcm.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
+obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
 
 obj-$(CONFIG_CRUNCH)           += crunch.o crunch-bits.o
 AFLAGS_crunch-bits.o           := -Wa,-mcpu=ep9312
index 8214bfe..e5e1e53 100644 (file)
@@ -165,6 +165,8 @@ EXPORT_SYMBOL(_find_next_bit_be);
 #endif
 
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CONFIG_OLD_MCOUNT
 EXPORT_SYMBOL(mcount);
+#endif
 EXPORT_SYMBOL(__gnu_mcount_nc);
 #endif
index 7885722..2d23ad9 100644 (file)
@@ -129,30 +129,58 @@ ENDPROC(ret_from_fork)
  * clobber the ip register.  This is OK because the ARM calling convention
  * allows it to be clobbered in subroutines and doesn't use it to hold
  * parameters.)
+ *
+ * When using dynamic ftrace, we patch out the mcount call by a "mov r0, r0"
+ * for the mcount case, and a "pop {lr}" for the __gnu_mcount_nc case (see
+ * arch/arm/kernel/ftrace.c).
  */
+
+#ifndef CONFIG_OLD_MCOUNT
+#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
+#error Ftrace requires CONFIG_FRAME_POINTER=y with GCC older than 4.4.0.
+#endif
+#endif
+
 #ifdef CONFIG_DYNAMIC_FTRACE
-ENTRY(mcount)
+ENTRY(__gnu_mcount_nc)
+       mov     ip, lr
+       ldmia   sp!, {lr}
+       mov     pc, ip
+ENDPROC(__gnu_mcount_nc)
+
+ENTRY(ftrace_caller)
        stmdb   sp!, {r0-r3, lr}
        mov     r0, lr
        sub     r0, r0, #MCOUNT_INSN_SIZE
+       ldr     r1, [sp, #20]
 
-       .globl mcount_call
-mcount_call:
+       .global ftrace_call
+ftrace_call:
        bl      ftrace_stub
-       ldr     lr, [fp, #-4]                   @ restore lr
-       ldmia   sp!, {r0-r3, pc}
+       ldmia   sp!, {r0-r3, ip, lr}
+       mov     pc, ip
+ENDPROC(ftrace_caller)
 
-ENTRY(ftrace_caller)
+#ifdef CONFIG_OLD_MCOUNT
+ENTRY(mcount)
+       stmdb   sp!, {lr}
+       ldr     lr, [fp, #-4]
+       ldmia   sp!, {pc}
+ENDPROC(mcount)
+
+ENTRY(ftrace_caller_old)
        stmdb   sp!, {r0-r3, lr}
        ldr     r1, [fp, #-4]
        mov     r0, lr
        sub     r0, r0, #MCOUNT_INSN_SIZE
 
-       .globl ftrace_call
-ftrace_call:
+       .globl ftrace_call_old
+ftrace_call_old:
        bl      ftrace_stub
        ldr     lr, [fp, #-4]                   @ restore lr
        ldmia   sp!, {r0-r3, pc}
+ENDPROC(ftrace_caller_old)
+#endif
 
 #else
 
@@ -160,7 +188,7 @@ ENTRY(__gnu_mcount_nc)
        stmdb   sp!, {r0-r3, lr}
        ldr     r0, =ftrace_trace_function
        ldr     r2, [r0]
-       adr     r0, ftrace_stub
+       adr     r0, .Lftrace_stub
        cmp     r0, r2
        bne     gnu_trace
        ldmia   sp!, {r0-r3, ip, lr}
@@ -170,11 +198,19 @@ gnu_trace:
        ldr     r1, [sp, #20]                   @ lr of instrumented routine
        mov     r0, lr
        sub     r0, r0, #MCOUNT_INSN_SIZE
-       mov     lr, pc
+       adr     lr, BSYM(1f)
        mov     pc, r2
+1:
        ldmia   sp!, {r0-r3, ip, lr}
        mov     pc, ip
+ENDPROC(__gnu_mcount_nc)
 
+#ifdef CONFIG_OLD_MCOUNT
+/*
+ * This is under an ifdef in order to force link-time errors for people trying
+ * to build with !FRAME_POINTER with a GCC which doesn't use the new-style
+ * mcount.
+ */
 ENTRY(mcount)
        stmdb   sp!, {r0-r3, lr}
        ldr     r0, =ftrace_trace_function
@@ -193,12 +229,15 @@ trace:
        mov     pc, r2
        ldr     lr, [fp, #-4]                   @ restore lr
        ldmia   sp!, {r0-r3, pc}
+ENDPROC(mcount)
+#endif
 
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
-       .globl ftrace_stub
-ftrace_stub:
+ENTRY(ftrace_stub)
+.Lftrace_stub:
        mov     pc, lr
+ENDPROC(ftrace_stub)
 
 #endif /* CONFIG_FUNCTION_TRACER */
 
index 0298286..971ac8c 100644 (file)
  * Dynamic function tracing support.
  *
  * Copyright (C) 2008 Abhishek Sagar <sagar.abhishek@gmail.com>
+ * Copyright (C) 2010 Rabin Vincent <rabin@rab.in>
  *
  * For licencing details, see COPYING.
  *
  * Defines low-level handling of mcount calls when the kernel
  * is compiled with the -pg flag. When using dynamic ftrace, the
- * mcount call-sites get patched lazily with NOP till they are
- * enabled. All code mutation routines here take effect atomically.
+ * mcount call-sites get patched with NOP till they are enabled.
+ * All code mutation routines here are called under stop_machine().
  */
 
 #include <linux/ftrace.h>
+#include <linux/uaccess.h>
 
 #include <asm/cacheflush.h>
 #include <asm/ftrace.h>
 
-#define PC_OFFSET      8
-#define BL_OPCODE      0xeb000000
-#define BL_OFFSET_MASK 0x00ffffff
+#ifdef CONFIG_THUMB2_KERNEL
+#define        NOP             0xeb04f85d      /* pop.w {lr} */
+#else
+#define        NOP             0xe8bd4000      /* pop {lr} */
+#endif
 
-static unsigned long bl_insn;
-static const unsigned long NOP = 0xe1a00000; /* mov r0, r0 */
+#ifdef CONFIG_OLD_MCOUNT
+#define OLD_MCOUNT_ADDR        ((unsigned long) mcount)
+#define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old)
 
-unsigned char *ftrace_nop_replace(void)
+#define        OLD_NOP         0xe1a00000      /* mov r0, r0 */
+
+static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
 {
-       return (char *)&NOP;
+       return rec->arch.old_mcount ? OLD_NOP : NOP;
 }
 
+static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
+{
+       if (!rec->arch.old_mcount)
+               return addr;
+
+       if (addr == MCOUNT_ADDR)
+               addr = OLD_MCOUNT_ADDR;
+       else if (addr == FTRACE_ADDR)
+               addr = OLD_FTRACE_ADDR;
+
+       return addr;
+}
+#else
+static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
+{
+       return NOP;
+}
+
+static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
+{
+       return addr;
+}
+#endif
+
 /* construct a branch (BL) instruction to addr */
-unsigned char *ftrace_call_replace(unsigned long pc, unsigned long addr)
+#ifdef CONFIG_THUMB2_KERNEL
+static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 {
+       unsigned long s, j1, j2, i1, i2, imm10, imm11;
+       unsigned long first, second;
        long offset;
 
-       offset = (long)addr - (long)(pc + PC_OFFSET);
+       offset = (long)addr - (long)(pc + 4);
+       if (offset < -16777216 || offset > 16777214) {
+               WARN_ON_ONCE(1);
+               return 0;
+       }
+
+       s       = (offset >> 24) & 0x1;
+       i1      = (offset >> 23) & 0x1;
+       i2      = (offset >> 22) & 0x1;
+       imm10   = (offset >> 12) & 0x3ff;
+       imm11   = (offset >>  1) & 0x7ff;
+
+       j1 = (!i1) ^ s;
+       j2 = (!i2) ^ s;
+
+       first = 0xf000 | (s << 10) | imm10;
+       second = 0xd000 | (j1 << 13) | (j2 << 11) | imm11;
+
+       return (second << 16) | first;
+}
+#else
+static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
+{
+       long offset;
+
+       offset = (long)addr - (long)(pc + 8);
        if (unlikely(offset < -33554432 || offset > 33554428)) {
                /* Can't generate branches that far (from ARM ARM). Ftrace
                 * doesn't generate branches outside of kernel text.
                 */
                WARN_ON_ONCE(1);
-               return NULL;
+               return 0;
        }
-       offset = (offset >> 2) & BL_OFFSET_MASK;
-       bl_insn = BL_OPCODE | offset;
-       return (unsigned char *)&bl_insn;
-}
 
-int ftrace_modify_code(unsigned long pc, unsigned char *old_code,
-                      unsigned char *new_code)
-{
-       unsigned long err = 0, replaced = 0, old, new;
+       offset = (offset >> 2) & 0x00ffffff;
 
-       old = *(unsigned long *)old_code;
-       new = *(unsigned long *)new_code;
+       return 0xeb000000 | offset;
+}
+#endif
 
-       __asm__ __volatile__ (
-               "1:  ldr    %1, [%2]  \n"
-               "    cmp    %1, %4    \n"
-               "2:  streq  %3, [%2]  \n"
-               "    cmpne  %1, %3    \n"
-               "    movne  %0, #2    \n"
-               "3:\n"
+static int ftrace_modify_code(unsigned long pc, unsigned long old,
+                             unsigned long new)
+{
+       unsigned long replaced;
 
-               ".pushsection .fixup, \"ax\"\n"
-               "4:  mov  %0, #1  \n"
-               "    b    3b      \n"
-               ".popsection\n"
+       if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
+               return -EFAULT;
 
-               ".pushsection __ex_table, \"a\"\n"
-               "    .long 1b, 4b \n"
-               "    .long 2b, 4b \n"
-               ".popsection\n"
+       if (replaced != old)
+               return -EINVAL;
 
-               : "=r"(err), "=r"(replaced)
-               : "r"(pc), "r"(new), "r"(old), "0"(err), "1"(replaced)
-               : "memory");
+       if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE))
+               return -EPERM;
 
-       if (!err && (replaced == old))
-               flush_icache_range(pc, pc + MCOUNT_INSN_SIZE);
+       flush_icache_range(pc, pc + MCOUNT_INSN_SIZE);
 
-       return err;
+       return 0;
 }
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
-       int ret;
        unsigned long pc, old;
-       unsigned char *new;
+       unsigned long new;
+       int ret;
 
        pc = (unsigned long)&ftrace_call;
        memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE);
        new = ftrace_call_replace(pc, (unsigned long)func);
-       ret = ftrace_modify_code(pc, (unsigned char *)&old, new);
+
+       ret = ftrace_modify_code(pc, old, new);
+
+#ifdef CONFIG_OLD_MCOUNT
+       if (!ret) {
+               pc = (unsigned long)&ftrace_call_old;
+               memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE);
+               new = ftrace_call_replace(pc, (unsigned long)func);
+
+               ret = ftrace_modify_code(pc, old, new);
+       }
+#endif
+
+       return ret;
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+       unsigned long new, old;
+       unsigned long ip = rec->ip;
+
+       old = ftrace_nop_replace(rec);
+       new = ftrace_call_replace(ip, adjust_address(rec, addr));
+
+       return ftrace_modify_code(rec->ip, old, new);
+}
+
+int ftrace_make_nop(struct module *mod,
+                   struct dyn_ftrace *rec, unsigned long addr)
+{
+       unsigned long ip = rec->ip;
+       unsigned long old;
+       unsigned long new;
+       int ret;
+
+       old = ftrace_call_replace(ip, adjust_address(rec, addr));
+       new = ftrace_nop_replace(rec);
+       ret = ftrace_modify_code(ip, old, new);
+
+#ifdef CONFIG_OLD_MCOUNT
+       if (ret == -EINVAL && addr == MCOUNT_ADDR) {
+               rec->arch.old_mcount = true;
+
+               old = ftrace_call_replace(ip, adjust_address(rec, addr));
+               new = ftrace_nop_replace(rec);
+               ret = ftrace_modify_code(ip, old, new);
+       }
+#endif
+
        return ret;
 }
 
-/* run from ftrace_init with irqs disabled */
 int __init ftrace_dyn_arch_init(void *data)
 {
-       ftrace_mcount_set(data);
+       *(unsigned long *)data = 0;
+
        return 0;
 }
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
new file mode 100644 (file)
index 0000000..54593b0
--- /dev/null
@@ -0,0 +1,849 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2009, 2010 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+/*
+ * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
+ * using the CPU's debug registers.
+ */
+#define pr_fmt(fmt) "hw-breakpoint: " fmt
+
+#include <linux/errno.h>
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <asm/current.h>
+#include <asm/hw_breakpoint.h>
+#include <asm/kdebug.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+
+/* Breakpoint currently in use for each BRP. */
+static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
+
+/* Watchpoint currently in use for each WRP. */
+static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]);
+
+/* Number of BRP/WRP registers on this CPU. */
+static int core_num_brps;
+static int core_num_wrps;
+
+/* Debug architecture version. */
+static u8 debug_arch;
+
+/* Maximum supported watchpoint length. */
+static u8 max_watchpoint_len;
+
+/* Determine number of BRP registers available. */
+static int get_num_brps(void)
+{
+       u32 didr;
+       ARM_DBG_READ(c0, 0, didr);
+       return ((didr >> 24) & 0xf) + 1;
+}
+
+/* Determine number of WRP registers available. */
+static int get_num_wrps(void)
+{
+       /*
+        * FIXME: When a watchpoint fires, the only way to work out which
+        * watchpoint it was is by disassembling the faulting instruction
+        * and working out the address of the memory access.
+        *
+        * Furthermore, we can only do this if the watchpoint was precise
+        * since imprecise watchpoints prevent us from calculating register
+        * based addresses.
+        *
+        * For the time being, we only report 1 watchpoint register so we
+        * always know which watchpoint fired. In the future we can either
+        * add a disassembler and address generation emulator, or we can
+        * insert a check to see if the DFAR is set on watchpoint exception
+        * entry [the ARM ARM states that the DFAR is UNKNOWN, but
+        * experience shows that it is set on some implementations].
+        */
+
+#if 0
+       u32 didr, wrps;
+       ARM_DBG_READ(c0, 0, didr);
+       return ((didr >> 28) & 0xf) + 1;
+#endif
+
+       return 1;
+}
+
+int hw_breakpoint_slots(int type)
+{
+       /*
+        * We can be called early, so don't rely on
+        * our static variables being initialised.
+        */
+       switch (type) {
+       case TYPE_INST:
+               return get_num_brps();
+       case TYPE_DATA:
+               return get_num_wrps();
+       default:
+               pr_warning("unknown slot type: %d\n", type);
+               return 0;
+       }
+}
+
+/* Determine debug architecture. */
+static u8 get_debug_arch(void)
+{
+       u32 didr;
+
+       /* Do we implement the extended CPUID interface? */
+       if (((read_cpuid_id() >> 16) & 0xf) != 0xf) {
+               pr_warning("CPUID feature registers not supported. "
+                               "Assuming v6 debug is present.\n");
+               return ARM_DEBUG_ARCH_V6;
+       }
+
+       ARM_DBG_READ(c0, 0, didr);
+       return (didr >> 16) & 0xf;
+}
+
+/* Does this core support mismatch breakpoints? */
+static int core_has_mismatch_bps(void)
+{
+       return debug_arch >= ARM_DEBUG_ARCH_V7_ECP14 && core_num_brps > 1;
+}
+
+u8 arch_get_debug_arch(void)
+{
+       return debug_arch;
+}
+
+#define READ_WB_REG_CASE(OP2, M, VAL)          \
+       case ((OP2 << 4) + M):                  \
+               ARM_DBG_READ(c ## M, OP2, VAL); \
+               break
+
+#define WRITE_WB_REG_CASE(OP2, M, VAL)         \
+       case ((OP2 << 4) + M):                  \
+               ARM_DBG_WRITE(c ## M, OP2, VAL);\
+               break
+
+#define GEN_READ_WB_REG_CASES(OP2, VAL)                \
+       READ_WB_REG_CASE(OP2, 0, VAL);          \
+       READ_WB_REG_CASE(OP2, 1, VAL);          \
+       READ_WB_REG_CASE(OP2, 2, VAL);          \
+       READ_WB_REG_CASE(OP2, 3, VAL);          \
+       READ_WB_REG_CASE(OP2, 4, VAL);          \
+       READ_WB_REG_CASE(OP2, 5, VAL);          \
+       READ_WB_REG_CASE(OP2, 6, VAL);          \
+       READ_WB_REG_CASE(OP2, 7, VAL);          \
+       READ_WB_REG_CASE(OP2, 8, VAL);          \
+       READ_WB_REG_CASE(OP2, 9, VAL);          \
+       READ_WB_REG_CASE(OP2, 10, VAL);         \
+       READ_WB_REG_CASE(OP2, 11, VAL);         \
+       READ_WB_REG_CASE(OP2, 12, VAL);         \
+       READ_WB_REG_CASE(OP2, 13, VAL);         \
+       READ_WB_REG_CASE(OP2, 14, VAL);         \
+       READ_WB_REG_CASE(OP2, 15, VAL)
+
+#define GEN_WRITE_WB_REG_CASES(OP2, VAL)       \
+       WRITE_WB_REG_CASE(OP2, 0, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 1, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 2, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 3, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 4, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 5, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 6, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 7, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 8, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 9, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 10, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 11, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 12, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 13, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 14, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 15, VAL)
+
+static u32 read_wb_reg(int n)
+{
+       u32 val = 0;
+
+       switch (n) {
+       GEN_READ_WB_REG_CASES(ARM_OP2_BVR, val);
+       GEN_READ_WB_REG_CASES(ARM_OP2_BCR, val);
+       GEN_READ_WB_REG_CASES(ARM_OP2_WVR, val);
+       GEN_READ_WB_REG_CASES(ARM_OP2_WCR, val);
+       default:
+               pr_warning("attempt to read from unknown breakpoint "
+                               "register %d\n", n);
+       }
+
+       return val;
+}
+
+static void write_wb_reg(int n, u32 val)
+{
+       switch (n) {
+       GEN_WRITE_WB_REG_CASES(ARM_OP2_BVR, val);
+       GEN_WRITE_WB_REG_CASES(ARM_OP2_BCR, val);
+       GEN_WRITE_WB_REG_CASES(ARM_OP2_WVR, val);
+       GEN_WRITE_WB_REG_CASES(ARM_OP2_WCR, val);
+       default:
+               pr_warning("attempt to write to unknown breakpoint "
+                               "register %d\n", n);
+       }
+       isb();
+}
+
+/*
+ * In order to access the breakpoint/watchpoint control registers,
+ * we must be running in debug monitor mode. Unfortunately, we can
+ * be put into halting debug mode at any time by an external debugger
+ * but there is nothing we can do to prevent that.
+ */
+static int enable_monitor_mode(void)
+{
+       u32 dscr;
+       int ret = 0;
+
+       ARM_DBG_READ(c1, 0, dscr);
+
+       /* Ensure that halting mode is disabled. */
+       if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN, "halting debug mode enabled."
+                               "Unable to access hardware resources.")) {
+               ret = -EPERM;
+               goto out;
+       }
+
+       /* Write to the corresponding DSCR. */
+       switch (debug_arch) {
+       case ARM_DEBUG_ARCH_V6:
+       case ARM_DEBUG_ARCH_V6_1:
+               ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN));
+               break;
+       case ARM_DEBUG_ARCH_V7_ECP14:
+               ARM_DBG_WRITE(c2, 2, (dscr | ARM_DSCR_MDBGEN));
+               break;
+       default:
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /* Check that the write made it through. */
+       ARM_DBG_READ(c1, 0, dscr);
+       if (WARN_ONCE(!(dscr & ARM_DSCR_MDBGEN),
+                               "failed to enable monitor mode.")) {
+               ret = -EPERM;
+       }
+
+out:
+       return ret;
+}
+
+/*
+ * Check if 8-bit byte-address select is available.
+ * This clobbers WRP 0.
+ */
+static u8 get_max_wp_len(void)
+{
+       u32 ctrl_reg;
+       struct arch_hw_breakpoint_ctrl ctrl;
+       u8 size = 4;
+
+       if (debug_arch < ARM_DEBUG_ARCH_V7_ECP14)
+               goto out;
+
+       if (enable_monitor_mode())
+               goto out;
+
+       memset(&ctrl, 0, sizeof(ctrl));
+       ctrl.len = ARM_BREAKPOINT_LEN_8;
+       ctrl_reg = encode_ctrl_reg(ctrl);
+
+       write_wb_reg(ARM_BASE_WVR, 0);
+       write_wb_reg(ARM_BASE_WCR, ctrl_reg);
+       if ((read_wb_reg(ARM_BASE_WCR) & ctrl_reg) == ctrl_reg)
+               size = 8;
+
+out:
+       return size;
+}
+
+u8 arch_get_max_wp_len(void)
+{
+       return max_watchpoint_len;
+}
+
+/*
+ * Handler for reactivating a suspended watchpoint when the single
+ * step `mismatch' breakpoint is triggered.
+ */
+static void wp_single_step_handler(struct perf_event *bp, int unused,
+                                  struct perf_sample_data *data,
+                                  struct pt_regs *regs)
+{
+       perf_event_enable(counter_arch_bp(bp)->suspended_wp);
+       unregister_hw_breakpoint(bp);
+}
+
+static int bp_is_single_step(struct perf_event *bp)
+{
+       return bp->overflow_handler == wp_single_step_handler;
+}
+
+/*
+ * Install a perf counter breakpoint.
+ */
+int arch_install_hw_breakpoint(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       struct perf_event **slot, **slots;
+       int i, max_slots, ctrl_base, val_base, ret = 0;
+
+       /* Ensure that we are in monitor mode and halting mode is disabled. */
+       ret = enable_monitor_mode();
+       if (ret)
+               goto out;
+
+       if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+               /* Breakpoint */
+               ctrl_base = ARM_BASE_BCR;
+               val_base = ARM_BASE_BVR;
+               slots = __get_cpu_var(bp_on_reg);
+               max_slots = core_num_brps - 1;
+
+               if (bp_is_single_step(bp)) {
+                       info->ctrl.mismatch = 1;
+                       i = max_slots;
+                       slots[i] = bp;
+                       goto setup;
+               }
+       } else {
+               /* Watchpoint */
+               ctrl_base = ARM_BASE_WCR;
+               val_base = ARM_BASE_WVR;
+               slots = __get_cpu_var(wp_on_reg);
+               max_slots = core_num_wrps;
+       }
+
+       for (i = 0; i < max_slots; ++i) {
+               slot = &slots[i];
+
+               if (!*slot) {
+                       *slot = bp;
+                       break;
+               }
+       }
+
+       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+setup:
+       /* Setup the address register. */
+       write_wb_reg(val_base + i, info->address);
+
+       /* Setup the control register. */
+       write_wb_reg(ctrl_base + i, encode_ctrl_reg(info->ctrl) | 0x1);
+
+out:
+       return ret;
+}
+
+void arch_uninstall_hw_breakpoint(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       struct perf_event **slot, **slots;
+       int i, max_slots, base;
+
+       if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+               /* Breakpoint */
+               base = ARM_BASE_BCR;
+               slots = __get_cpu_var(bp_on_reg);
+               max_slots = core_num_brps - 1;
+
+               if (bp_is_single_step(bp)) {
+                       i = max_slots;
+                       slots[i] = NULL;
+                       goto reset;
+               }
+       } else {
+               /* Watchpoint */
+               base = ARM_BASE_WCR;
+               slots = __get_cpu_var(wp_on_reg);
+               max_slots = core_num_wrps;
+       }
+
+       /* Remove the breakpoint. */
+       for (i = 0; i < max_slots; ++i) {
+               slot = &slots[i];
+
+               if (*slot == bp) {
+                       *slot = NULL;
+                       break;
+               }
+       }
+
+       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot"))
+               return;
+
+reset:
+       /* Reset the control register. */
+       write_wb_reg(base + i, 0);
+}
+
+static int get_hbp_len(u8 hbp_len)
+{
+       unsigned int len_in_bytes = 0;
+
+       switch (hbp_len) {
+       case ARM_BREAKPOINT_LEN_1:
+               len_in_bytes = 1;
+               break;
+       case ARM_BREAKPOINT_LEN_2:
+               len_in_bytes = 2;
+               break;
+       case ARM_BREAKPOINT_LEN_4:
+               len_in_bytes = 4;
+               break;
+       case ARM_BREAKPOINT_LEN_8:
+               len_in_bytes = 8;
+               break;
+       }
+
+       return len_in_bytes;
+}
+
+/*
+ * Check whether bp virtual address is in kernel space.
+ */
+int arch_check_bp_in_kernelspace(struct perf_event *bp)
+{
+       unsigned int len;
+       unsigned long va;
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+       va = info->address;
+       len = get_hbp_len(info->ctrl.len);
+
+       return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
+}
+
+/*
+ * Extract generic type and length encodings from an arch_hw_breakpoint_ctrl.
+ * Hopefully this will disappear when ptrace can bypass the conversion
+ * to generic breakpoint descriptions.
+ */
+int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
+                          int *gen_len, int *gen_type)
+{
+       /* Type */
+       switch (ctrl.type) {
+       case ARM_BREAKPOINT_EXECUTE:
+               *gen_type = HW_BREAKPOINT_X;
+               break;
+       case ARM_BREAKPOINT_LOAD:
+               *gen_type = HW_BREAKPOINT_R;
+               break;
+       case ARM_BREAKPOINT_STORE:
+               *gen_type = HW_BREAKPOINT_W;
+               break;
+       case ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE:
+               *gen_type = HW_BREAKPOINT_RW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Len */
+       switch (ctrl.len) {
+       case ARM_BREAKPOINT_LEN_1:
+               *gen_len = HW_BREAKPOINT_LEN_1;
+               break;
+       case ARM_BREAKPOINT_LEN_2:
+               *gen_len = HW_BREAKPOINT_LEN_2;
+               break;
+       case ARM_BREAKPOINT_LEN_4:
+               *gen_len = HW_BREAKPOINT_LEN_4;
+               break;
+       case ARM_BREAKPOINT_LEN_8:
+               *gen_len = HW_BREAKPOINT_LEN_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Construct an arch_hw_breakpoint from a perf_event.
+ */
+static int arch_build_bp_info(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+       /* Type */
+       switch (bp->attr.bp_type) {
+       case HW_BREAKPOINT_X:
+               info->ctrl.type = ARM_BREAKPOINT_EXECUTE;
+               break;
+       case HW_BREAKPOINT_R:
+               info->ctrl.type = ARM_BREAKPOINT_LOAD;
+               break;
+       case HW_BREAKPOINT_W:
+               info->ctrl.type = ARM_BREAKPOINT_STORE;
+               break;
+       case HW_BREAKPOINT_RW:
+               info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Len */
+       switch (bp->attr.bp_len) {
+       case HW_BREAKPOINT_LEN_1:
+               info->ctrl.len = ARM_BREAKPOINT_LEN_1;
+               break;
+       case HW_BREAKPOINT_LEN_2:
+               info->ctrl.len = ARM_BREAKPOINT_LEN_2;
+               break;
+       case HW_BREAKPOINT_LEN_4:
+               info->ctrl.len = ARM_BREAKPOINT_LEN_4;
+               break;
+       case HW_BREAKPOINT_LEN_8:
+               info->ctrl.len = ARM_BREAKPOINT_LEN_8;
+               if ((info->ctrl.type != ARM_BREAKPOINT_EXECUTE)
+                       && max_watchpoint_len >= 8)
+                       break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Address */
+       info->address = bp->attr.bp_addr;
+
+       /* Privilege */
+       info->ctrl.privilege = ARM_BREAKPOINT_USER;
+       if (arch_check_bp_in_kernelspace(bp) && !bp_is_single_step(bp))
+               info->ctrl.privilege |= ARM_BREAKPOINT_PRIV;
+
+       /* Enabled? */
+       info->ctrl.enabled = !bp->attr.disabled;
+
+       /* Mismatch */
+       info->ctrl.mismatch = 0;
+
+       return 0;
+}
+
+/*
+ * Validate the arch-specific HW Breakpoint register settings.
+ */
+int arch_validate_hwbkpt_settings(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       int ret = 0;
+       u32 bytelen, max_len, offset, alignment_mask = 0x3;
+
+       /* Build the arch_hw_breakpoint. */
+       ret = arch_build_bp_info(bp);
+       if (ret)
+               goto out;
+
+       /* Check address alignment. */
+       if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
+               alignment_mask = 0x7;
+       if (info->address & alignment_mask) {
+               /*
+                * Try to fix the alignment. This may result in a length
+                * that is too large, so we must check for that.
+                */
+               bytelen = get_hbp_len(info->ctrl.len);
+               max_len = info->ctrl.type == ARM_BREAKPOINT_EXECUTE ? 4 :
+                               max_watchpoint_len;
+
+               if (max_len >= 8)
+                       offset = info->address & 0x7;
+               else
+                       offset = info->address & 0x3;
+
+               if (bytelen > (1 << ((max_len - (offset + 1)) >> 1))) {
+                       ret = -EFBIG;
+                       goto out;
+               }
+
+               info->ctrl.len <<= offset;
+               info->address &= ~offset;
+
+               pr_debug("breakpoint alignment fixup: length = 0x%x, "
+                       "address = 0x%x\n", info->ctrl.len, info->address);
+       }
+
+       /*
+        * Currently we rely on an overflow handler to take
+        * care of single-stepping the breakpoint when it fires.
+        * In the case of userspace breakpoints on a core with V7 debug,
+        * we can use the mismatch feature as a poor-man's hardware single-step.
+        */
+       if (WARN_ONCE(!bp->overflow_handler &&
+               (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_bps()),
+                       "overflow handler required but none found")) {
+               ret = -EINVAL;
+               goto out;
+       }
+out:
+       return ret;
+}
+
+static void update_mismatch_flag(int idx, int flag)
+{
+       struct perf_event *bp = __get_cpu_var(bp_on_reg[idx]);
+       struct arch_hw_breakpoint *info;
+
+       if (bp == NULL)
+               return;
+
+       info = counter_arch_bp(bp);
+
+       /* Update the mismatch field to enter/exit `single-step' mode */
+       if (!bp->overflow_handler && info->ctrl.mismatch != flag) {
+               info->ctrl.mismatch = flag;
+               write_wb_reg(ARM_BASE_BCR + idx, encode_ctrl_reg(info->ctrl) | 0x1);
+       }
+}
+
+static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
+{
+       int i;
+       struct perf_event *bp, **slots = __get_cpu_var(wp_on_reg);
+       struct arch_hw_breakpoint *info;
+       struct perf_event_attr attr;
+
+       /* Without a disassembler, we can only handle 1 watchpoint. */
+       BUG_ON(core_num_wrps > 1);
+
+       hw_breakpoint_init(&attr);
+       attr.bp_addr    = regs->ARM_pc & ~0x3;
+       attr.bp_len     = HW_BREAKPOINT_LEN_4;
+       attr.bp_type    = HW_BREAKPOINT_X;
+
+       for (i = 0; i < core_num_wrps; ++i) {
+               rcu_read_lock();
+
+               if (slots[i] == NULL) {
+                       rcu_read_unlock();
+                       continue;
+               }
+
+               /*
+                * The DFAR is an unknown value. Since we only allow a
+                * single watchpoint, we can set the trigger to the lowest
+                * possible faulting address.
+                */
+               info = counter_arch_bp(slots[i]);
+               info->trigger = slots[i]->attr.bp_addr;
+               pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
+               perf_bp_event(slots[i], regs);
+
+               /*
+                * If no overflow handler is present, insert a temporary
+                * mismatch breakpoint so we can single-step over the
+                * watchpoint trigger.
+                */
+               if (!slots[i]->overflow_handler) {
+                       bp = register_user_hw_breakpoint(&attr,
+                                                        wp_single_step_handler,
+                                                        current);
+                       counter_arch_bp(bp)->suspended_wp = slots[i];
+                       perf_event_disable(slots[i]);
+               }
+
+               rcu_read_unlock();
+       }
+}
+
+static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)
+{
+       int i;
+       int mismatch;
+       u32 ctrl_reg, val, addr;
+       struct perf_event *bp, **slots = __get_cpu_var(bp_on_reg);
+       struct arch_hw_breakpoint *info;
+       struct arch_hw_breakpoint_ctrl ctrl;
+
+       /* The exception entry code places the amended lr in the PC. */
+       addr = regs->ARM_pc;
+
+       for (i = 0; i < core_num_brps; ++i) {
+               rcu_read_lock();
+
+               bp = slots[i];
+
+               if (bp == NULL) {
+                       rcu_read_unlock();
+                       continue;
+               }
+
+               mismatch = 0;
+
+               /* Check if the breakpoint value matches. */
+               val = read_wb_reg(ARM_BASE_BVR + i);
+               if (val != (addr & ~0x3))
+                       goto unlock;
+
+               /* Possible match, check the byte address select to confirm. */
+               ctrl_reg = read_wb_reg(ARM_BASE_BCR + i);
+               decode_ctrl_reg(ctrl_reg, &ctrl);
+               if ((1 << (addr & 0x3)) & ctrl.len) {
+                       mismatch = 1;
+                       info = counter_arch_bp(bp);
+                       info->trigger = addr;
+               }
+
+unlock:
+               if ((mismatch && !info->ctrl.mismatch) || bp_is_single_step(bp)) {
+                       pr_debug("breakpoint fired: address = 0x%x\n", addr);
+                       perf_bp_event(bp, regs);
+               }
+
+               update_mismatch_flag(i, mismatch);
+               rcu_read_unlock();
+       }
+}
+
+/*
+ * Called from either the Data Abort Handler [watchpoint] or the
+ * Prefetch Abort Handler [breakpoint].
+ */
+static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
+                                struct pt_regs *regs)
+{
+       int ret = 1; /* Unhandled fault. */
+       u32 dscr;
+
+       /* We only handle watchpoints and hardware breakpoints. */
+       ARM_DBG_READ(c1, 0, dscr);
+
+       /* Perform perf callbacks. */
+       switch (ARM_DSCR_MOE(dscr)) {
+       case ARM_ENTRY_BREAKPOINT:
+               breakpoint_handler(addr, regs);
+               break;
+       case ARM_ENTRY_ASYNC_WATCHPOINT:
+               WARN_ON("Asynchronous watchpoint exception taken. "
+                       "Debugging results may be unreliable");
+       case ARM_ENTRY_SYNC_WATCHPOINT:
+               watchpoint_handler(addr, regs);
+               break;
+       default:
+               goto out;
+       }
+
+       ret = 0;
+out:
+       return ret;
+}
+
+/*
+ * One-time initialisation.
+ */
+static void __init reset_ctrl_regs(void *unused)
+{
+       int i;
+
+       if (enable_monitor_mode())
+               return;
+
+       for (i = 0; i < core_num_brps; ++i) {
+               write_wb_reg(ARM_BASE_BCR + i, 0UL);
+               write_wb_reg(ARM_BASE_BVR + i, 0UL);
+       }
+
+       for (i = 0; i < core_num_wrps; ++i) {
+               write_wb_reg(ARM_BASE_WCR + i, 0UL);
+               write_wb_reg(ARM_BASE_WVR + i, 0UL);
+       }
+}
+
+static int __init arch_hw_breakpoint_init(void)
+{
+       int ret = 0;
+       u32 dscr;
+
+       debug_arch = get_debug_arch();
+
+       if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) {
+               pr_info("debug architecture 0x%x unsupported.\n", debug_arch);
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /* Determine how many BRPs/WRPs are available. */
+       core_num_brps = get_num_brps();
+       core_num_wrps = get_num_wrps();
+
+       pr_info("found %d breakpoint and %d watchpoint registers.\n",
+                       core_num_brps, core_num_wrps);
+
+       if (core_has_mismatch_bps())
+               pr_info("1 breakpoint reserved for watchpoint single-step.\n");
+
+       ARM_DBG_READ(c1, 0, dscr);
+       if (dscr & ARM_DSCR_HDBGEN) {
+               pr_warning("halting debug mode enabled. Assuming maximum "
+                               "watchpoint size of 4 bytes.");
+       } else {
+               /* Work out the maximum supported watchpoint length. */
+               max_watchpoint_len = get_max_wp_len();
+               pr_info("maximum watchpoint size is %u bytes.\n",
+                               max_watchpoint_len);
+
+               /*
+                * Reset the breakpoint resources. We assume that a halting
+                * debugger will leave the world in a nice state for us.
+                */
+               smp_call_function(reset_ctrl_regs, NULL, 1);
+               reset_ctrl_regs(NULL);
+       }
+
+       /* Register debug fault handler. */
+       hook_fault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT,
+                       "watchpoint debug exception");
+       hook_ifault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT,
+                       "breakpoint debug exception");
+
+out:
+       return ret;
+}
+arch_initcall(arch_hw_breakpoint_init);
+
+void hw_breakpoint_pmu_read(struct perf_event *bp)
+{
+}
+
+/*
+ * Dummy function to register with die_notifier.
+ */
+int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+                                       unsigned long val, void *data)
+{
+       return NOTIFY_DONE;
+}
index 6b46058..d9bd786 100644 (file)
@@ -69,20 +69,31 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
 {
 #ifdef CONFIG_ARM_UNWIND
        Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+       struct arm_unwind_mapping *maps = mod->arch.map;
 
        for (s = sechdrs; s < sechdrs_end; s++) {
-               if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0)
-                       mod->arch.unw_sec_init = s;
-               else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0)
-                       mod->arch.unw_sec_devinit = s;
-               else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0)
-                       mod->arch.unw_sec_core = s;
-               else if (strcmp(".init.text", secstrings + s->sh_name) == 0)
-                       mod->arch.sec_init_text = s;
-               else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0)
-                       mod->arch.sec_devinit_text = s;
-               else if (strcmp(".text", secstrings + s->sh_name) == 0)
-                       mod->arch.sec_core_text = s;
+               char const *secname = secstrings + s->sh_name;
+
+               if (strcmp(".ARM.exidx.init.text", secname) == 0)
+                       maps[ARM_SEC_INIT].unw_sec = s;
+               else if (strcmp(".ARM.exidx.devinit.text", secname) == 0)
+                       maps[ARM_SEC_DEVINIT].unw_sec = s;
+               else if (strcmp(".ARM.exidx", secname) == 0)
+                       maps[ARM_SEC_CORE].unw_sec = s;
+               else if (strcmp(".ARM.exidx.exit.text", secname) == 0)
+                       maps[ARM_SEC_EXIT].unw_sec = s;
+               else if (strcmp(".ARM.exidx.devexit.text", secname) == 0)
+                       maps[ARM_SEC_DEVEXIT].unw_sec = s;
+               else if (strcmp(".init.text", secname) == 0)
+                       maps[ARM_SEC_INIT].sec_text = s;
+               else if (strcmp(".devinit.text", secname) == 0)
+                       maps[ARM_SEC_DEVINIT].sec_text = s;
+               else if (strcmp(".text", secname) == 0)
+                       maps[ARM_SEC_CORE].sec_text = s;
+               else if (strcmp(".exit.text", secname) == 0)
+                       maps[ARM_SEC_EXIT].sec_text = s;
+               else if (strcmp(".devexit.text", secname) == 0)
+                       maps[ARM_SEC_DEVEXIT].sec_text = s;
        }
 #endif
        return 0;
@@ -292,31 +303,22 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
 #ifdef CONFIG_ARM_UNWIND
 static void register_unwind_tables(struct module *mod)
 {
-       if (mod->arch.unw_sec_init && mod->arch.sec_init_text)
-               mod->arch.unwind_init =
-                       unwind_table_add(mod->arch.unw_sec_init->sh_addr,
-                                        mod->arch.unw_sec_init->sh_size,
-                                        mod->arch.sec_init_text->sh_addr,
-                                        mod->arch.sec_init_text->sh_size);
-       if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text)
-               mod->arch.unwind_devinit =
-                       unwind_table_add(mod->arch.unw_sec_devinit->sh_addr,
-                                        mod->arch.unw_sec_devinit->sh_size,
-                                        mod->arch.sec_devinit_text->sh_addr,
-                                        mod->arch.sec_devinit_text->sh_size);
-       if (mod->arch.unw_sec_core && mod->arch.sec_core_text)
-               mod->arch.unwind_core =
-                       unwind_table_add(mod->arch.unw_sec_core->sh_addr,
-                                        mod->arch.unw_sec_core->sh_size,
-                                        mod->arch.sec_core_text->sh_addr,
-                                        mod->arch.sec_core_text->sh_size);
+       int i;
+       for (i = 0; i < ARM_SEC_MAX; ++i) {
+               struct arm_unwind_mapping *map = &mod->arch.map[i];
+               if (map->unw_sec && map->sec_text)
+                       map->unwind = unwind_table_add(map->unw_sec->sh_addr,
+                                                      map->unw_sec->sh_size,
+                                                      map->sec_text->sh_addr,
+                                                      map->sec_text->sh_size);
+       }
 }
 
 static void unregister_unwind_tables(struct module *mod)
 {
-       unwind_table_del(mod->arch.unwind_init);
-       unwind_table_del(mod->arch.unwind_devinit);
-       unwind_table_del(mod->arch.unwind_core);
+       int i = ARM_SEC_MAX;
+       while (--i >= 0)
+               unwind_table_del(mod->arch.map[i].unwind);
 }
 #else
 static inline void register_unwind_tables(struct module *mod) { }
index 23def52..3af34bf 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/utsname.h>
 #include <linux/uaccess.h>
 #include <linux/random.h>
+#include <linux/hw_breakpoint.h>
 
 #include <asm/cacheflush.h>
 #include <asm/leds.h>
@@ -336,6 +337,8 @@ void flush_thread(void)
        struct thread_info *thread = current_thread_info();
        struct task_struct *tsk = current;
 
+       flush_ptrace_hw_breakpoint(tsk);
+
        memset(thread->used_cp, 0, sizeof(thread->used_cp));
        memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
        memset(&thread->fpstate, 0, sizeof(union fp_state));
@@ -364,6 +367,8 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
        thread->cpu_context.sp = (unsigned long)childregs;
        thread->cpu_context.pc = (unsigned long)ret_from_fork;
 
+       clear_ptrace_hw_breakpoint(p);
+
        if (clone_flags & CLONE_SETTLS)
                thread->tp_value = regs->ARM_r3;
 
index f99d489..e0cb637 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/init.h>
 #include <linux/signal.h>
 #include <linux/uaccess.h>
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -847,6 +849,232 @@ static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
 }
 #endif
 
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+/*
+ * Convert a virtual register number into an index for a thread_info
+ * breakpoint array. Breakpoints are identified using positive numbers
+ * whilst watchpoints are negative. The registers are laid out as pairs
+ * of (address, control), each pair mapping to a unique hw_breakpoint struct.
+ * Register 0 is reserved for describing resource information.
+ */
+static int ptrace_hbp_num_to_idx(long num)
+{
+       if (num < 0)
+               num = (ARM_MAX_BRP << 1) - num;
+       return (num - 1) >> 1;
+}
+
+/*
+ * Returns the virtual register number for the address of the
+ * breakpoint at index idx.
+ */
+static long ptrace_hbp_idx_to_num(int idx)
+{
+       long mid = ARM_MAX_BRP << 1;
+       long num = (idx << 1) + 1;
+       return num > mid ? mid - num : num;
+}
+
+/*
+ * Handle hitting a HW-breakpoint.
+ */
+static void ptrace_hbptriggered(struct perf_event *bp, int unused,
+                                    struct perf_sample_data *data,
+                                    struct pt_regs *regs)
+{
+       struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
+       long num;
+       int i;
+       siginfo_t info;
+
+       for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i)
+               if (current->thread.debug.hbp[i] == bp)
+                       break;
+
+       num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i);
+
+       info.si_signo   = SIGTRAP;
+       info.si_errno   = (int)num;
+       info.si_code    = TRAP_HWBKPT;
+       info.si_addr    = (void __user *)(bkpt->trigger);
+
+       force_sig_info(SIGTRAP, &info, current);
+}
+
+/*
+ * Set ptrace breakpoint pointers to zero for this task.
+ * This is required in order to prevent child processes from unregistering
+ * breakpoints held by their parent.
+ */
+void clear_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+       memset(tsk->thread.debug.hbp, 0, sizeof(tsk->thread.debug.hbp));
+}
+
+/*
+ * Unregister breakpoints from this task and reset the pointers in
+ * the thread_struct.
+ */
+void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+       int i;
+       struct thread_struct *t = &tsk->thread;
+
+       for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) {
+               if (t->debug.hbp[i]) {
+                       unregister_hw_breakpoint(t->debug.hbp[i]);
+                       t->debug.hbp[i] = NULL;
+               }
+       }
+}
+
+static u32 ptrace_get_hbp_resource_info(void)
+{
+       u8 num_brps, num_wrps, debug_arch, wp_len;
+       u32 reg = 0;
+
+       num_brps        = hw_breakpoint_slots(TYPE_INST);
+       num_wrps        = hw_breakpoint_slots(TYPE_DATA);
+       debug_arch      = arch_get_debug_arch();
+       wp_len          = arch_get_max_wp_len();
+
+       reg             |= debug_arch;
+       reg             <<= 8;
+       reg             |= wp_len;
+       reg             <<= 8;
+       reg             |= num_wrps;
+       reg             <<= 8;
+       reg             |= num_brps;
+
+       return reg;
+}
+
+static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type)
+{
+       struct perf_event_attr attr;
+
+       ptrace_breakpoint_init(&attr);
+
+       /* Initialise fields to sane defaults. */
+       attr.bp_addr    = 0;
+       attr.bp_len     = HW_BREAKPOINT_LEN_4;
+       attr.bp_type    = type;
+       attr.disabled   = 1;
+
+       return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, tsk);
+}
+
+static int ptrace_gethbpregs(struct task_struct *tsk, long num,
+                            unsigned long  __user *data)
+{
+       u32 reg;
+       int idx, ret = 0;
+       struct perf_event *bp;
+       struct arch_hw_breakpoint_ctrl arch_ctrl;
+
+       if (num == 0) {
+               reg = ptrace_get_hbp_resource_info();
+       } else {
+               idx = ptrace_hbp_num_to_idx(num);
+               if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               bp = tsk->thread.debug.hbp[idx];
+               if (!bp) {
+                       reg = 0;
+                       goto put;
+               }
+
+               arch_ctrl = counter_arch_bp(bp)->ctrl;
+
+               /*
+                * Fix up the len because we may have adjusted it
+                * to compensate for an unaligned address.
+                */
+               while (!(arch_ctrl.len & 0x1))
+                       arch_ctrl.len >>= 1;
+
+               if (idx & 0x1)
+                       reg = encode_ctrl_reg(arch_ctrl);
+               else
+                       reg = bp->attr.bp_addr;
+       }
+
+put:
+       if (put_user(reg, data))
+               ret = -EFAULT;
+
+out:
+       return ret;
+}
+
+static int ptrace_sethbpregs(struct task_struct *tsk, long num,
+                            unsigned long __user *data)
+{
+       int idx, gen_len, gen_type, implied_type, ret = 0;
+       u32 user_val;
+       struct perf_event *bp;
+       struct arch_hw_breakpoint_ctrl ctrl;
+       struct perf_event_attr attr;
+
+       if (num == 0)
+               goto out;
+       else if (num < 0)
+               implied_type = HW_BREAKPOINT_RW;
+       else
+               implied_type = HW_BREAKPOINT_X;
+
+       idx = ptrace_hbp_num_to_idx(num);
+       if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (get_user(user_val, data)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       bp = tsk->thread.debug.hbp[idx];
+       if (!bp) {
+               bp = ptrace_hbp_create(tsk, implied_type);
+               if (IS_ERR(bp)) {
+                       ret = PTR_ERR(bp);
+                       goto out;
+               }
+               tsk->thread.debug.hbp[idx] = bp;
+       }
+
+       attr = bp->attr;
+
+       if (num & 0x1) {
+               /* Address */
+               attr.bp_addr    = user_val;
+       } else {
+               /* Control */
+               decode_ctrl_reg(user_val, &ctrl);
+               ret = arch_bp_generic_fields(ctrl, &gen_len, &gen_type);
+               if (ret)
+                       goto out;
+
+               if ((gen_type & implied_type) != gen_type) {
+                               ret = -EINVAL;
+                               goto out;
+               }
+
+               attr.bp_len     = gen_len;
+               attr.bp_type    = gen_type;
+               attr.disabled   = !ctrl.enabled;
+       }
+
+       ret = modify_user_hw_breakpoint(bp, &attr);
+out:
+       return ret;
+}
+#endif
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
        int ret;
@@ -916,6 +1144,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        break;
 #endif
 
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+               case PTRACE_GETHBPREGS:
+                       ret = ptrace_gethbpregs(child, addr,
+                                               (unsigned long __user *)data);
+                       break;
+               case PTRACE_SETHBPREGS:
+                       ret = ptrace_sethbpregs(child, addr,
+                                               (unsigned long __user *)data);
+                       break;
+#endif
+
                default:
                        ret = ptrace_request(child, request, addr, data);
                        break;
index f389171..336f14e 100644 (file)
@@ -239,6 +239,35 @@ int cpu_architecture(void)
        return cpu_arch;
 }
 
+static int cpu_has_aliasing_icache(unsigned int arch)
+{
+       int aliasing_icache;
+       unsigned int id_reg, num_sets, line_size;
+
+       /* arch specifies the register format */
+       switch (arch) {
+       case CPU_ARCH_ARMv7:
+               asm("mcr        p15, 2, %0, c0, c0, 0 @ set CSSELR"
+                   : /* No output operands */
+                   : "r" (1));
+               isb();
+               asm("mrc        p15, 1, %0, c0, c0, 0 @ read CCSIDR"
+                   : "=r" (id_reg));
+               line_size = 4 << ((id_reg & 0x7) + 2);
+               num_sets = ((id_reg >> 13) & 0x7fff) + 1;
+               aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
+               break;
+       case CPU_ARCH_ARMv6:
+               aliasing_icache = read_cpuid_cachetype() & (1 << 11);
+               break;
+       default:
+               /* I-cache aliases will be handled by D-cache aliasing code */
+               aliasing_icache = 0;
+       }
+
+       return aliasing_icache;
+}
+
 static void __init cacheid_init(void)
 {
        unsigned int cachetype = read_cpuid_cachetype();
@@ -250,10 +279,15 @@ static void __init cacheid_init(void)
                        cacheid = CACHEID_VIPT_NONALIASING;
                        if ((cachetype & (3 << 14)) == 1 << 14)
                                cacheid |= CACHEID_ASID_TAGGED;
-               } else if (cachetype & (1 << 23))
+                       else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
+                               cacheid |= CACHEID_VIPT_I_ALIASING;
+               } else if (cachetype & (1 << 23)) {
                        cacheid = CACHEID_VIPT_ALIASING;
-               else
+               } else {
                        cacheid = CACHEID_VIPT_NONALIASING;
+                       if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6))
+                               cacheid |= CACHEID_VIPT_I_ALIASING;
+               }
        } else {
                cacheid = CACHEID_VIVT;
        }
@@ -264,7 +298,7 @@ static void __init cacheid_init(void)
                cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
                cache_is_vivt() ? "VIVT" :
                icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
-               cache_is_vipt_aliasing() ? "VIPT aliasing" :
+               icache_is_vipt_aliasing() ? "VIPT aliasing" :
                cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
 }
 
index dd81a91..2a16176 100644 (file)
@@ -146,6 +146,8 @@ static struct unwind_idx *unwind_find_idx(unsigned long addr)
                            addr < table->end_addr) {
                                idx = search_index(addr, table->start,
                                                   table->stop - 1);
+                               /* Move-to-front to exploit common traces */
+                               list_move(&table->list, &unwind_tables);
                                break;
                        }
                }
index 939bccd..ca33862 100644 (file)
@@ -248,6 +248,12 @@ config MACH_CPU9260
          Select this if you are using a Eukrea Electromatique's
          CPU9260 Board <http://www.eukrea.com/>
 
+config MACH_FLEXIBITY
+       bool "Flexibity Connect board"
+       help
+         Select this if you are using Flexibity Connect board
+         <http://www.flexibity.com>
+
 endif
 
 # ----------------------------------------------------------
index ca2ac00..7cbe06d 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_MACH_USB_A9260)  += board-usb-a9260.o
 obj-$(CONFIG_MACH_QIL_A9260)   += board-qil-a9260.o
 obj-$(CONFIG_MACH_AFEB9260)    += board-afeb-9260v1.o
 obj-$(CONFIG_MACH_CPU9260)     += board-cpu9krea.o
+obj-$(CONFIG_MACH_FLEXIBITY)   += board-flexibity.o
 
 # AT91SAM9261 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o
diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
new file mode 100644 (file)
index 0000000..216c8ca
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * linux/arch/arm/mach-at91/board-flexibity.c
+ *
+ *  Copyright (C) 2010 Flexibity
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2006 Atmel
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+
+#include "generic.h"
+
+static void __init flexibity_map_io(void)
+{
+       /* Initialize processor: 18.432 MHz crystal */
+       at91sam9260_initialize(18432000);
+
+       /* DBGU on ttyS0. (Rx & Tx only) */
+       at91_register_uart(0, 0, 0);
+
+       /* set serial console to ttyS0 (ie, DBGU) */
+       at91_set_serial_console(0);
+}
+
+static void __init flexibity_init_irq(void)
+{
+       at91sam9260_init_interrupts(NULL);
+}
+
+/* USB Host port */
+static struct at91_usbh_data __initdata flexibity_usbh_data = {
+       .ports          = 2,
+};
+
+/* USB Device port */
+static struct at91_udc_data __initdata flexibity_udc_data = {
+       .vbus_pin       = AT91_PIN_PC5,
+       .pullup_pin     = 0,            /* pull-up driven by UDC */
+};
+
+/* SPI devices */
+static struct spi_board_info flexibity_spi_devices[] = {
+       {       /* DataFlash chip */
+               .modalias       = "mtd_dataflash",
+               .chip_select    = 1,
+               .max_speed_hz   = 15 * 1000 * 1000,
+               .bus_num        = 0,
+       },
+};
+
+/* MCI (SD/MMC) */
+static struct at91_mmc_data __initdata flexibity_mmc_data = {
+       .slot_b         = 0,
+       .wire4          = 1,
+       .det_pin        = AT91_PIN_PC9,
+       .wp_pin         = AT91_PIN_PC4,
+};
+
+/* LEDs */
+static struct gpio_led flexibity_leds[] = {
+       {
+               .name                   = "usb1:green",
+               .gpio                   = AT91_PIN_PA12,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb1:red",
+               .gpio                   = AT91_PIN_PA13,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb2:green",
+               .gpio                   = AT91_PIN_PB26,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb2:red",
+               .gpio                   = AT91_PIN_PB27,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb3:green",
+               .gpio                   = AT91_PIN_PC8,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb3:red",
+               .gpio                   = AT91_PIN_PC6,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb4:green",
+               .gpio                   = AT91_PIN_PB4,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb4:red",
+               .gpio                   = AT91_PIN_PB5,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       }
+};
+
+static void __init flexibity_board_init(void)
+{
+       /* Serial */
+       at91_add_device_serial();
+       /* USB Host */
+       at91_add_device_usbh(&flexibity_usbh_data);
+       /* USB Device */
+       at91_add_device_udc(&flexibity_udc_data);
+       /* SPI */
+       at91_add_device_spi(flexibity_spi_devices,
+               ARRAY_SIZE(flexibity_spi_devices));
+       /* MMC */
+       at91_add_device_mmc(0, &flexibity_mmc_data);
+       /* LEDs */
+       at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds));
+}
+
+MACHINE_START(FLEXIBITY, "Flexibity Connect")
+       /* Maintainer: Maxim Osipov */
+       .phys_io        = AT91_BASE_SYS,
+       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+       .boot_params    = AT91_SDRAM_BASE + 0x100,
+       .timer          = &at91sam926x_timer,
+       .map_io         = flexibity_map_io,
+       .init_irq       = flexibity_init_irq,
+       .init_machine   = flexibity_board_init,
+MACHINE_END
index 2fa38df..07c0815 100644 (file)
@@ -259,6 +259,7 @@ struct mmci_platform_data realview_mmc0_plat_data = {
        .status         = realview_mmc_status,
        .gpio_wp        = 17,
        .gpio_cd        = 16,
+       .cd_invert      = true,
 };
 
 struct mmci_platform_data realview_mmc1_plat_data = {
@@ -266,6 +267,7 @@ struct mmci_platform_data realview_mmc1_plat_data = {
        .status         = realview_mmc_status,
        .gpio_wp        = 19,
        .gpio_cd        = 18,
+       .cd_invert      = true,
 };
 
 /*
index 3a9639b..cb1ebeb 100644 (file)
@@ -136,7 +136,7 @@ static struct platform_device smartq_usb_otg_vbus_dev = {
        .dev.platform_data      = &smartq_usb_otg_vbus_pdata,
 };
 
-static int __init smartq_bl_init(struct device *dev)
+static int smartq_bl_init(struct device *dev)
 {
     s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2));
 
index a4d59b0..235e439 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "mach-smartq.h"
 
-static struct gpio_led smartq5_leds[] __initdata = {
+static struct gpio_led smartq5_leds[] = {
        {
                .name                   = "smartq5:green",
                .active_low             = 1,
index e50a7d7..78a58c3 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "mach-smartq.h"
 
-static struct gpio_led smartq7_leds[] __initdata = {
+static struct gpio_led smartq7_leds[] = {
        {
                .name                   = "smartq7:red",
                .active_low             = 1,
index 6625e5b..2dd44a0 100644 (file)
@@ -21,9 +21,7 @@ config MACH_U8500_MOP
        bool "U8500 Development platform"
        select UX500_SOC_DB8500
        help
-         Include support for mop500 development platform
-         based on U8500 architecture. The platform is based
-         on early drop silicon version of 8500.
+         Include support for the mop500 development platform.
 
 config MACH_U5500
        bool "U5500 Development platform"
@@ -39,4 +37,18 @@ config UX500_DEBUG_UART
          Choose the UART on which kernel low-level debug messages should be
          output.
 
+config U5500_MODEM_IRQ
+       bool "Modem IRQ support"
+       depends on MACH_U5500
+       default y
+       help
+         Add support for handling IRQ:s from modem side
+
+config U5500_MBOX
+       bool "Mailbox support"
+       depends on MACH_U5500 && U5500_MODEM_IRQ
+       default y
+       help
+         Add support for U5500 mailbox communication with modem side
+
 endif
index 4556aea..9e27a84 100644 (file)
@@ -4,8 +4,12 @@
 
 obj-y                          := clock.o cpu.o devices.o
 obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o
-obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
-obj-$(CONFIG_MACH_U8500_MOP)   += board-mop500.o
+obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
+obj-$(CONFIG_MACH_U8500_MOP)   += board-mop500.o board-mop500-sdi.o
 obj-$(CONFIG_MACH_U5500)       += board-u5500.o
 obj-$(CONFIG_SMP)              += platsmp.o headsmp.o
+obj-$(CONFIG_HOTPLUG_CPU)      += hotplug.o
 obj-$(CONFIG_LOCAL_TIMERS)     += localtimer.o
+obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o
+obj-$(CONFIG_U5500_MODEM_IRQ)  += modem_irq.o
+obj-$(CONFIG_U5500_MBOX)       += mbox.o
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c
new file mode 100644 (file)
index 0000000..1187f1f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ * MOP500 board specific initialization for regulators
+ */
+#include <linux/kernel.h>
+#include <linux/regulator/machine.h>
+
+/* supplies to the display/camera */
+static struct regulator_init_data ab8500_vaux1_regulator = {
+       .constraints = {
+               .name = "V-DISPLAY",
+               .min_uV = 2500000,
+               .max_uV = 2900000,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+                                       REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supplies to the on-board eMMC */
+static struct regulator_init_data ab8500_vaux2_regulator = {
+       .constraints = {
+               .name = "V-eMMC1",
+               .min_uV = 1100000,
+               .max_uV = 3300000,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+                                       REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for VAUX3, supplies to SDcard slots */
+static struct regulator_init_data ab8500_vaux3_regulator = {
+       .constraints = {
+               .name = "V-MMC-SD",
+               .min_uV = 1100000,
+               .max_uV = 3300000,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+                                       REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for tvout, gpadc, TVOUT LDO */
+static struct regulator_init_data ab8500_vtvout_init = {
+       .constraints = {
+               .name = "V-TVOUT",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for ab8500-vaudio, VAUDIO LDO */
+static struct regulator_init_data ab8500_vaudio_init = {
+       .constraints = {
+               .name = "V-AUD",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for v-anamic1 VAMic1-LDO */
+static struct regulator_init_data ab8500_vamic1_init = {
+       .constraints = {
+               .name = "V-AMIC1",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
+static struct regulator_init_data ab8500_vamic2_init = {
+       .constraints = {
+               .name = "V-AMIC2",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for v-dmic, VDMIC LDO */
+static struct regulator_init_data ab8500_vdmic_init = {
+       .constraints = {
+               .name = "V-DMIC",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for v-intcore12, VINTCORE12 LDO */
+static struct regulator_init_data ab8500_vintcore_init = {
+       .constraints = {
+               .name = "V-INTCORE",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for U8500 CSI/DSI, VANA LDO */
+static struct regulator_init_data ab8500_vana_init = {
+       .constraints = {
+               .name = "V-CSI/DSI",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c
new file mode 100644 (file)
index 0000000..bac9956
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Hanumath Prasad <hanumath.prasad@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/mmci.h>
+#include <linux/mmc/host.h>
+#include <linux/platform_device.h>
+
+#include <plat/pincfg.h>
+#include <mach/devices.h>
+#include <mach/hardware.h>
+
+#include "pins-db8500.h"
+#include "board-mop500.h"
+
+static pin_cfg_t mop500_sdi_pins[] = {
+       /* SDI4 (on-board eMMC) */
+       GPIO197_MC4_DAT3,
+       GPIO198_MC4_DAT2,
+       GPIO199_MC4_DAT1,
+       GPIO200_MC4_DAT0,
+       GPIO201_MC4_CMD,
+       GPIO202_MC4_FBCLK,
+       GPIO203_MC4_CLK,
+       GPIO204_MC4_DAT7,
+       GPIO205_MC4_DAT6,
+       GPIO206_MC4_DAT5,
+       GPIO207_MC4_DAT4,
+};
+
+static pin_cfg_t mop500_sdi2_pins[] = {
+       /* SDI2 (POP eMMC) */
+       GPIO128_MC2_CLK,
+       GPIO129_MC2_CMD,
+       GPIO130_MC2_FBCLK,
+       GPIO131_MC2_DAT0,
+       GPIO132_MC2_DAT1,
+       GPIO133_MC2_DAT2,
+       GPIO134_MC2_DAT3,
+       GPIO135_MC2_DAT4,
+       GPIO136_MC2_DAT5,
+       GPIO137_MC2_DAT6,
+       GPIO138_MC2_DAT7,
+};
+
+/*
+ * SDI 2 (POP eMMC, not on DB8500ed)
+ */
+
+static struct mmci_platform_data mop500_sdi2_data = {
+       .ocr_mask       = MMC_VDD_165_195,
+       .f_max          = 100000000,
+       .capabilities   = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+       .gpio_cd        = -1,
+       .gpio_wp        = -1,
+};
+
+/*
+ * SDI 4 (on-board eMMC)
+ */
+
+static struct mmci_platform_data mop500_sdi4_data = {
+       .ocr_mask       = MMC_VDD_29_30,
+       .f_max          = 100000000,
+       .capabilities   = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA |
+                         MMC_CAP_MMC_HIGHSPEED,
+       .gpio_cd        = -1,
+       .gpio_wp        = -1,
+};
+
+void mop500_sdi_init(void)
+{
+       nmk_config_pins(mop500_sdi_pins, ARRAY_SIZE(mop500_sdi_pins));
+
+       u8500_sdi2_device.dev.platform_data = &mop500_sdi2_data;
+       u8500_sdi4_device.dev.platform_data = &mop500_sdi4_data;
+
+       if (!cpu_is_u8500ed()) {
+               nmk_config_pins(mop500_sdi2_pins, ARRAY_SIZE(mop500_sdi2_pins));
+               amba_device_register(&u8500_sdi2_device, &iomem_resource);
+       }
+
+       /* On-board eMMC */
+       amba_device_register(&u8500_sdi4_device, &iomem_resource);
+}
index 0e8fd13..642b8e6 100644 (file)
 #include <mach/hardware.h>
 #include <mach/setup.h>
 #include <mach/devices.h>
+#include <mach/irqs.h>
 
 #include "pins-db8500.h"
+#include "board-mop500.h"
 
 static pin_cfg_t mop500_pins[] = {
        /* SSP0 */
@@ -75,9 +77,27 @@ static struct ab8500_platform_data ab8500_platdata = {
        .irq_base       = MOP500_AB8500_IRQ_BASE,
 };
 
-static struct spi_board_info u8500_spi_devices[] = {
+static struct resource ab8500_resources[] = {
+       [0] = {
+               .start = IRQ_AB8500,
+               .end = IRQ_AB8500,
+               .flags = IORESOURCE_IRQ
+       }
+};
+
+struct platform_device ab8500_device = {
+       .name = "ab8500-i2c",
+       .id = 0,
+       .dev = {
+               .platform_data = &ab8500_platdata,
+       },
+       .num_resources = 1,
+       .resource = ab8500_resources,
+};
+
+static struct spi_board_info ab8500_spi_devices[] = {
        {
-               .modalias = "ab8500",
+               .modalias = "ab8500-spi",
                .controller_data = &ab4500_chip_info,
                .platform_data = &ab8500_platdata,
                .max_speed_hz = 12000000,
@@ -163,8 +183,14 @@ static void __init u8500_init_machine(void)
 
        platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
 
-       spi_register_board_info(u8500_spi_devices,
-                       ARRAY_SIZE(u8500_spi_devices));
+       mop500_sdi_init();
+
+       /* If HW is early drop (ED) or V1.0 then use SPI to access AB8500 */
+       if (cpu_is_u8500ed() || cpu_is_u8500v10())
+               spi_register_board_info(ab8500_spi_devices,
+                       ARRAY_SIZE(ab8500_spi_devices));
+       else /* If HW is v.1.1 or later use I2C to access AB8500 */
+               platform_device_register(&ab8500_device);
 }
 
 MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h
new file mode 100644 (file)
index 0000000..2d24032
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __BOARD_MOP500_H
+#define __BOARD_MOP500_H
+
+extern void mop500_sdi_init(void);
+
+#endif
index e9278f6..2f87075 100644 (file)
@@ -14,6 +14,7 @@
 #include <mach/hardware.h>
 #include <mach/devices.h>
 #include <mach/setup.h>
+#include <mach/irqs.h>
 
 static struct map_desc u5500_io_desc[] __initdata = {
        __IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K),
@@ -24,6 +25,90 @@ static struct map_desc u5500_io_desc[] __initdata = {
        __IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K),
 };
 
+static struct resource mbox0_resources[] = {
+       {
+               .name = "mbox_peer",
+               .start = U5500_MBOX0_PEER_START,
+               .end = U5500_MBOX0_PEER_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_local",
+               .start = U5500_MBOX0_LOCAL_START,
+               .end = U5500_MBOX0_LOCAL_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_irq",
+               .start = MBOX_PAIR0_VIRT_IRQ,
+               .end = MBOX_PAIR0_VIRT_IRQ,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static struct resource mbox1_resources[] = {
+       {
+               .name = "mbox_peer",
+               .start = U5500_MBOX1_PEER_START,
+               .end = U5500_MBOX1_PEER_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_local",
+               .start = U5500_MBOX1_LOCAL_START,
+               .end = U5500_MBOX1_LOCAL_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_irq",
+               .start = MBOX_PAIR1_VIRT_IRQ,
+               .end = MBOX_PAIR1_VIRT_IRQ,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static struct resource mbox2_resources[] = {
+       {
+               .name = "mbox_peer",
+               .start = U5500_MBOX2_PEER_START,
+               .end = U5500_MBOX2_PEER_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_local",
+               .start = U5500_MBOX2_LOCAL_START,
+               .end = U5500_MBOX2_LOCAL_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_irq",
+               .start = MBOX_PAIR2_VIRT_IRQ,
+               .end = MBOX_PAIR2_VIRT_IRQ,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static struct platform_device mbox0_device = {
+       .id = 0,
+       .name = "mbox",
+       .resource = mbox0_resources,
+       .num_resources = ARRAY_SIZE(mbox0_resources),
+};
+
+static struct platform_device mbox1_device = {
+       .id = 1,
+       .name = "mbox",
+       .resource = mbox1_resources,
+       .num_resources = ARRAY_SIZE(mbox1_resources),
+};
+
+static struct platform_device mbox2_device = {
+       .id = 2,
+       .name = "mbox",
+       .resource = mbox2_resources,
+       .num_resources = ARRAY_SIZE(mbox2_resources),
+};
+
 static struct platform_device *u5500_platform_devs[] __initdata = {
        &u5500_gpio_devs[0],
        &u5500_gpio_devs[1],
@@ -33,6 +118,9 @@ static struct platform_device *u5500_platform_devs[] __initdata = {
        &u5500_gpio_devs[5],
        &u5500_gpio_devs[6],
        &u5500_gpio_devs[7],
+       &mbox0_device,
+       &mbox1_device,
+       &mbox2_device,
 };
 
 void __init u5500_map_io(void)
index f21c444..4acab75 100644 (file)
@@ -38,10 +38,12 @@ static struct platform_device *platform_devs[] __initdata = {
 /* minimum static i/o mapping required to boot U8500 platforms */
 static struct map_desc u8500_io_desc[] __initdata = {
        __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
+       __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K),
+       __MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M),
 };
 
 static struct map_desc u8500ed_io_desc[] __initdata = {
@@ -53,6 +55,69 @@ static struct map_desc u8500v1_io_desc[] __initdata = {
        __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K),
 };
 
+/*
+ * Functions to differentiate between later ASICs
+ * We look into the end of the ROM to locate the hardcoded ASIC ID.
+ * This is only needed to differentiate between minor revisions and
+ * process variants of an ASIC, the major revisions are encoded in
+ * the cpuid.
+ */
+#define U8500_ASIC_ID_LOC_ED_V1        (U8500_BOOT_ROM_BASE + 0x1FFF4)
+#define U8500_ASIC_ID_LOC_V2   (U8500_BOOT_ROM_BASE + 0x1DBF4)
+#define U8500_ASIC_REV_ED      0x01
+#define U8500_ASIC_REV_V10     0xA0
+#define U8500_ASIC_REV_V11     0xA1
+#define U8500_ASIC_REV_V20     0xB0
+
+/**
+ * struct db8500_asic_id - fields of the ASIC ID
+ * @process: the manufacturing process, 0x40 is 40 nm
+ *  0x00 is "standard"
+ * @partnumber: hithereto 0x8500 for DB8500
+ * @revision: version code in the series
+ * This field definion is not formally defined but makes
+ * sense.
+ */
+struct db8500_asic_id {
+       u8 process;
+       u16 partnumber;
+       u8 revision;
+};
+
+/* This isn't going to change at runtime */
+static struct db8500_asic_id db8500_id;
+
+static void __init get_db8500_asic_id(void)
+{
+       u32 asicid;
+
+       if (cpu_is_u8500v1() || cpu_is_u8500ed())
+               asicid = readl(__io_address(U8500_ASIC_ID_LOC_ED_V1));
+       else if (cpu_is_u8500v2())
+               asicid = readl(__io_address(U8500_ASIC_ID_LOC_V2));
+       else
+               BUG();
+
+       db8500_id.process = (asicid >> 24);
+       db8500_id.partnumber = (asicid >> 16) & 0xFFFFU;
+       db8500_id.revision = asicid & 0xFFU;
+}
+
+bool cpu_is_u8500v10(void)
+{
+       return (db8500_id.revision == U8500_ASIC_REV_V10);
+}
+
+bool cpu_is_u8500v11(void)
+{
+       return (db8500_id.revision == U8500_ASIC_REV_V11);
+}
+
+bool cpu_is_u8500v20(void)
+{
+       return (db8500_id.revision == U8500_ASIC_REV_V20);
+}
+
 void __init u8500_map_io(void)
 {
        ux500_map_io();
@@ -63,6 +128,9 @@ void __init u8500_map_io(void)
                iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc));
        else
                iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc));
+
+       /* Read out the ASIC ID as early as we can */
+       get_db8500_asic_id();
 }
 
 /*
@@ -70,6 +138,20 @@ void __init u8500_map_io(void)
  */
 void __init u8500_init_devices(void)
 {
+       /* Display some ASIC boilerplate */
+       pr_info("DB8500: process: %02x, revision ID: 0x%02x\n",
+               db8500_id.process, db8500_id.revision);
+       if (cpu_is_u8500ed())
+               pr_info("DB8500: Early Drop (ED)\n");
+       else if (cpu_is_u8500v10())
+               pr_info("DB8500: version 1.0\n");
+       else if (cpu_is_u8500v11())
+               pr_info("DB8500: version 1.1\n");
+       else if (cpu_is_u8500v20())
+               pr_info("DB8500: version 2.0\n");
+       else
+               pr_warning("ASIC: UNKNOWN SILICON VERSION!\n");
+
        ux500_init_devices();
 
        if (cpu_is_u8500ed())
index 9280d25..40032fe 100644 (file)
@@ -110,6 +110,82 @@ struct platform_device u8500_i2c4_device = {
        .num_resources  = ARRAY_SIZE(u8500_i2c4_resources),
 };
 
+/*
+ * SD/MMC
+ */
+
+struct amba_device u8500_sdi0_device = {
+       .dev            = {
+               .init_name = "sdi0",
+       },
+       .res            = {
+               .start  = U8500_SDI0_BASE,
+               .end    = U8500_SDI0_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC0, NO_IRQ},
+};
+
+struct amba_device u8500_sdi1_device = {
+       .dev            = {
+               .init_name = "sdi1",
+       },
+       .res            = {
+               .start  = U8500_SDI1_BASE,
+               .end    = U8500_SDI1_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC1, NO_IRQ},
+};
+
+struct amba_device u8500_sdi2_device = {
+       .dev            = {
+               .init_name = "sdi2",
+       },
+       .res            = {
+               .start  = U8500_SDI2_BASE,
+               .end    = U8500_SDI2_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC2, NO_IRQ},
+};
+
+struct amba_device u8500_sdi3_device = {
+       .dev            = {
+               .init_name = "sdi3",
+       },
+       .res            = {
+               .start  = U8500_SDI3_BASE,
+               .end    = U8500_SDI3_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC3, NO_IRQ},
+};
+
+struct amba_device u8500_sdi4_device = {
+       .dev            = {
+               .init_name = "sdi4",
+       },
+       .res            = {
+               .start  = U8500_SDI4_BASE,
+               .end    = U8500_SDI4_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC4, NO_IRQ},
+};
+
+struct amba_device u8500_sdi5_device = {
+       .dev            = {
+               .init_name = "sdi5",
+       },
+       .res            = {
+               .start  = U8500_SDI5_BASE,
+               .end    = U8500_SDI5_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC5, NO_IRQ},
+};
+
 static struct resource dma40_resources[] = {
        [0] = {
                .start = U8500_DMA_BASE,
@@ -170,23 +246,23 @@ struct stedma40_chan_cfg dma40_memcpy_conf_log = {
  * Mapping between destination event lines and physical device address.
  * The event line is tied to a device and therefor the address is constant.
  */
-static const dma_addr_t dma40_tx_map[STEDMA40_NR_DEV];
+static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV];
 
 /* Mapping between source event lines and physical device address */
-static const dma_addr_t dma40_rx_map[STEDMA40_NR_DEV];
+static const dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV];
 
 /* Reserved event lines for memcpy only */
 static int dma40_memcpy_event[] = {
-       STEDMA40_MEMCPY_TX_0,
-       STEDMA40_MEMCPY_TX_1,
-       STEDMA40_MEMCPY_TX_2,
-       STEDMA40_MEMCPY_TX_3,
-       STEDMA40_MEMCPY_TX_4,
-       STEDMA40_MEMCPY_TX_5,
+       DB8500_DMA_MEMCPY_TX_0,
+       DB8500_DMA_MEMCPY_TX_1,
+       DB8500_DMA_MEMCPY_TX_2,
+       DB8500_DMA_MEMCPY_TX_3,
+       DB8500_DMA_MEMCPY_TX_4,
+       DB8500_DMA_MEMCPY_TX_5,
 };
 
 static struct stedma40_platform_data dma40_plat_data = {
-       .dev_len = STEDMA40_NR_DEV,
+       .dev_len = DB8500_DMA_NR_DEV,
        .dev_rx = dma40_rx_map,
        .dev_tx = dma40_tx_map,
        .memcpy = dma40_memcpy_event,
diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c
new file mode 100644 (file)
index 0000000..b782a03
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *     Based on ARM realview platform
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/completion.h>
+
+#include <asm/cacheflush.h>
+
+extern volatile int pen_release;
+
+static DECLARE_COMPLETION(cpu_killed);
+
+static inline void platform_do_lowpower(unsigned int cpu)
+{
+       flush_cache_all();
+
+       /* we put the platform to just WFI */
+       for (;;) {
+               __asm__ __volatile__("dsb\n\t" "wfi\n\t"
+                               : : : "memory");
+               if (pen_release == cpu) {
+                       /*
+                        * OK, proper wakeup, we're done
+                        */
+                       break;
+               }
+       }
+}
+
+int platform_cpu_kill(unsigned int cpu)
+{
+       return wait_for_completion_timeout(&cpu_killed, 5000);
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void platform_cpu_die(unsigned int cpu)
+{
+#ifdef DEBUG
+       unsigned int this_cpu = hard_smp_processor_id();
+
+       if (cpu != this_cpu) {
+               printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n",
+                          this_cpu, cpu);
+               BUG();
+       }
+#endif
+
+       printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+       complete(&cpu_killed);
+
+       /* directly enter low power state, skipping secure registers */
+       platform_do_lowpower(cpu);
+}
+
+int platform_cpu_disable(unsigned int cpu)
+{
+       /*
+        * we don't allow CPU 0 to be shutdown (it is still too special
+        * e.g. clock tick interrupts)
+        */
+       return cpu == 0 ? -EPERM : 0;
+}
index 545c80f..3eafc0e 100644 (file)
 #define U5500_GPIOBANK6_BASE   (U5500_GPIO4_BASE + 0x80)
 #define U5500_GPIOBANK7_BASE   (U5500_GPIO4_BASE + 0x100)
 
+#define U5500_MBOX_BASE                (U5500_MODEM_BASE + 0xFFD1000)
+#define U5500_MBOX0_PEER_START (U5500_MBOX_BASE + 0x40)
+#define U5500_MBOX0_PEER_END   (U5500_MBOX_BASE + 0x5F)
+#define U5500_MBOX0_LOCAL_START        (U5500_MBOX_BASE + 0x60)
+#define U5500_MBOX0_LOCAL_END  (U5500_MBOX_BASE + 0x7F)
+#define U5500_MBOX1_PEER_START (U5500_MBOX_BASE + 0x80)
+#define U5500_MBOX1_PEER_END   (U5500_MBOX_BASE + 0x9F)
+#define U5500_MBOX1_LOCAL_START        (U5500_MBOX_BASE + 0xA0)
+#define U5500_MBOX1_LOCAL_END  (U5500_MBOX_BASE + 0xBF)
+#define U5500_MBOX2_PEER_START (U5500_MBOX_BASE + 0x00)
+#define U5500_MBOX2_PEER_END   (U5500_MBOX_BASE + 0x1F)
+#define U5500_MBOX2_LOCAL_START        (U5500_MBOX_BASE + 0x20)
+#define U5500_MBOX2_LOCAL_END  (U5500_MBOX_BASE + 0x3F)
+
 #endif
index f000218..f07d098 100644 (file)
@@ -30,8 +30,6 @@
 #define U8500_ICN_BASE         0x81000000
 
 #define U8500_BOOT_ROM_BASE    0x90000000
-/* ASIC ID is at 0xff4 offset within this region */
-#define U8500_ASIC_ID_BASE     0x9001F000
 
 #define U8500_PER6_BASE                0xa03c0000
 #define U8500_PER5_BASE                0xa03e0000
index c2b2f25..33a120c 100644 (file)
@@ -27,6 +27,13 @@ extern struct platform_device u8500_i2c0_device;
 extern struct platform_device u8500_i2c4_device;
 extern struct platform_device u8500_dma40_device;
 
+extern struct amba_device u8500_sdi0_device;
+extern struct amba_device u8500_sdi1_device;
+extern struct amba_device u8500_sdi2_device;
+extern struct amba_device u8500_sdi3_device;
+extern struct amba_device u8500_sdi4_device;
+extern struct amba_device u8500_sdi5_device;
+
 void dma40_u8500ed_fixup(void);
 
 #endif
index 8656379..32e883a 100644 (file)
@@ -104,16 +104,35 @@ static inline bool cpu_is_u8500(void)
 #endif
 }
 
+#define CPUID_DB8500ED 0x410fc090
+#define CPUID_DB8500V1 0x411fc091
+#define CPUID_DB8500V2 0x412fc091
+
 static inline bool cpu_is_u8500ed(void)
 {
-       return cpu_is_u8500() && (read_cpuid_id() & 15) == 0;
+       return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500ED);
 }
 
 static inline bool cpu_is_u8500v1(void)
 {
-       return cpu_is_u8500() && (read_cpuid_id() & 15) == 1;
+       return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V1);
+}
+
+static inline bool cpu_is_u8500v2(void)
+{
+       return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V2);
 }
 
+#ifdef CONFIG_UX500_SOC_DB8500
+bool cpu_is_u8500v10(void);
+bool cpu_is_u8500v11(void);
+bool cpu_is_u8500v20(void);
+#else
+static inline bool cpu_is_u8500v10(void) { return false; }
+static inline bool cpu_is_u8500v11(void) { return false; }
+static inline bool cpu_is_u8500v20(void) { return false; }
+#endif
+
 static inline bool cpu_is_u5500(void)
 {
 #ifdef CONFIG_UX500_SOC_DB5500
index 6fbfe5e..bfa123d 100644 (file)
@@ -61,6 +61,7 @@
 #define IRQ_DB5500_SDMMC0              (IRQ_SHPI_START + 60)
 #define IRQ_DB5500_HSEM                        (IRQ_SHPI_START + 61)
 #define IRQ_DB5500_SBAG                        (IRQ_SHPI_START + 63)
+#define IRQ_DB5500_MODEM               (IRQ_SHPI_START + 65)
 #define IRQ_DB5500_SPI1                        (IRQ_SHPI_START + 96)
 #define IRQ_DB5500_MSP2                        (IRQ_SHPI_START + 98)
 #define IRQ_DB5500_SRPTIMER            (IRQ_SHPI_START + 101)
index 10385bd..693aa57 100644 (file)
@@ -40,7 +40,8 @@
 #define IRQ_HSIR_CH1_OVRRUN    (IRQ_SHPI_START + 33)
 #define IRQ_HSIR_CH2_OVRRUN    (IRQ_SHPI_START + 34)
 #define IRQ_HSIR_CH3_OVRRUN    (IRQ_SHPI_START + 35)
-#define IRQ_AB4500             (IRQ_SHPI_START + 40)
+#define IRQ_AB8500             (IRQ_SHPI_START + 40)
+#define IRQ_PRCMU               (IRQ_SHPI_START + 47)
 #define IRQ_DISP               (IRQ_SHPI_START + 48)
 #define IRQ_SiPI3              (IRQ_SHPI_START + 49)
 #define IRQ_I2C4               (IRQ_SHPI_START + 51)
 #include <mach/irqs-board-mop500.h>
 #endif
 
-#define NR_IRQS                                IRQ_BOARD_END
+/*
+ * After the board specific IRQ:s we reserve a range of IRQ:s in which virtual
+ * IRQ:s representing modem IRQ:s can be allocated
+ */
+#define IRQ_MODEM_EVENTS_BASE (IRQ_BOARD_END + 1)
+#define IRQ_MODEM_EVENTS_NBR 72
+#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
+
+/* List of virtual IRQ:s that are allocated from the range above */
+#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
+#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
+#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
+
+#define NR_IRQS                                IRQ_MODEM_EVENTS_END
 
 #endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-ux500/include/mach/mbox.h b/arch/arm/mach-ux500/include/mach/mbox.h
new file mode 100644 (file)
index 0000000..7f9da4d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __INC_STE_MBOX_H
+#define __INC_STE_MBOX_H
+
+#define MBOX_BUF_SIZE 16
+#define MBOX_NAME_SIZE 8
+
+/**
+  * mbox_recv_cb_t - Definition of the mailbox callback.
+  * @mbox_msg: The mailbox message.
+  * @priv:     The clients private data as specified in the call to mbox_setup.
+  *
+  * This function will be called upon reception of new mailbox messages.
+  */
+typedef void mbox_recv_cb_t (u32 mbox_msg, void *priv);
+
+/**
+  * struct mbox - Mailbox instance struct
+  * @list:             Linked list head.
+  * @pdev:             Pointer to device struct.
+  * @cb:               Callback function. Will be called
+  *                    when new data is received.
+  * @client_data:      Clients private data. Will be sent back
+  *                    in the callback function.
+  * @virtbase_peer:    Virtual address for outgoing mailbox.
+  * @virtbase_local:   Virtual address for incoming mailbox.
+  * @buffer:           Then internal queue for outgoing messages.
+  * @name:             Name of this mailbox.
+  * @buffer_available: Completion variable to achieve "blocking send".
+  *                    This variable will be signaled when there is
+  *                    internal buffer space available.
+  * @client_blocked:   To keep track if any client is currently
+  *                    blocked.
+  * @lock:             Spinlock to protect this mailbox instance.
+  * @write_index:      Index in internal buffer to write to.
+  * @read_index:       Index in internal buffer to read from.
+  * @allocated:                Indicates whether this particular mailbox
+  *                    id has been allocated by someone.
+  */
+struct mbox {
+       struct list_head list;
+       struct platform_device *pdev;
+       mbox_recv_cb_t *cb;
+       void *client_data;
+       void __iomem *virtbase_peer;
+       void __iomem *virtbase_local;
+       u32 buffer[MBOX_BUF_SIZE];
+       char name[MBOX_NAME_SIZE];
+       struct completion buffer_available;
+       u8 client_blocked;
+       spinlock_t lock;
+       u8 write_index;
+       u8 read_index;
+       bool allocated;
+};
+
+/**
+  * mbox_setup - Set up a mailbox and return its instance.
+  * @mbox_id:  The ID number of the mailbox. 0 or 1 for modem CPU,
+  *            2 for modem DSP.
+  * @mbox_cb:  Pointer to the callback function to be called when a new message
+  *            is received.
+  * @priv:     Client user data which will be returned in the callback.
+  *
+  * Returns a mailbox instance to be specified in subsequent calls to mbox_send.
+  */
+struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv);
+
+/**
+  * mbox_send - Send a mailbox message.
+  * @mbox:     Mailbox instance (returned by mbox_setup)
+  * @mbox_msg: The mailbox message to send.
+  * @block:    Specifies whether this call will block until send is possible,
+  *            or return an error if the mailbox buffer is full.
+  *
+  * Returns 0 on success or a negative error code on error. -ENOMEM indicates
+  * that the internal buffer is full and you have to try again later (or
+  * specify "block" in order to block until send is possible).
+  */
+int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block);
+
+#endif /*INC_STE_MBOX_H*/
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-regs.h b/arch/arm/mach-ux500/include/mach/prcmu-regs.h
new file mode 100644 (file)
index 0000000..8885f39
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+#ifndef __MACH_PRCMU_REGS_H
+#define __MACH_PRCMU_REGS_H
+
+#include <mach/hardware.h>
+
+#define _PRCMU_BASE            IO_ADDRESS(U8500_PRCMU_BASE)
+
+#define PRCM_ARM_PLLDIVPS      (_PRCMU_BASE + 0x118)
+#define PRCM_ARM_CHGCLKREQ     (_PRCMU_BASE + 0x114)
+#define PRCM_PLLARM_ENABLE     (_PRCMU_BASE + 0x98)
+#define PRCM_ARMCLKFIX_MGT     (_PRCMU_BASE + 0x0)
+#define PRCM_A9_RESETN_CLR     (_PRCMU_BASE + 0x1f4)
+#define PRCM_A9_RESETN_SET     (_PRCMU_BASE + 0x1f0)
+#define PRCM_ARM_LS_CLAMP      (_PRCMU_BASE + 0x30c)
+#define PRCM_SRAM_A9           (_PRCMU_BASE + 0x308)
+
+/* ARM WFI Standby signal register */
+#define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
+#define PRCMU_IOCR              (_PRCMU_BASE + 0x310)
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL      (_PRCMU_BASE + 0x0fc)
+#define PRCM_MBOX_CPU_SET      (_PRCMU_BASE + 0x100)
+#define PRCM_MBOX_CPU_CLR      (_PRCMU_BASE + 0x104)
+
+/* Dual A9 core interrupt management unit registers */
+#define PRCM_A9_MASK_REQ       (_PRCMU_BASE + 0x328)
+#define PRCM_A9_MASK_ACK       (_PRCMU_BASE + 0x32c)
+#define PRCM_ARMITMSK31TO0     (_PRCMU_BASE + 0x11c)
+#define PRCM_ARMITMSK63TO32    (_PRCMU_BASE + 0x120)
+#define PRCM_ARMITMSK95TO64    (_PRCMU_BASE + 0x124)
+#define PRCM_ARMITMSK127TO96   (_PRCMU_BASE + 0x128)
+#define PRCM_POWER_STATE_VAL   (_PRCMU_BASE + 0x25C)
+#define PRCM_ARMITVAL31TO0     (_PRCMU_BASE + 0x260)
+#define PRCM_ARMITVAL63TO32    (_PRCMU_BASE + 0x264)
+#define PRCM_ARMITVAL95TO64    (_PRCMU_BASE + 0x268)
+#define PRCM_ARMITVAL127TO96   (_PRCMU_BASE + 0x26C)
+
+#define PRCM_HOSTACCESS_REQ    (_PRCMU_BASE + 0x334)
+#define ARM_WAKEUP_MODEM       0x1
+
+#define PRCM_ARM_IT1_CLEAR     (_PRCMU_BASE + 0x48C)
+#define PRCM_ARM_IT1_VAL       (_PRCMU_BASE + 0x494)
+#define PRCM_HOLD_EVT          (_PRCMU_BASE + 0x174)
+
+#define PRCM_ITSTATUS0         (_PRCMU_BASE + 0x148)
+#define PRCM_ITSTATUS1         (_PRCMU_BASE + 0x150)
+#define PRCM_ITSTATUS2         (_PRCMU_BASE + 0x158)
+#define PRCM_ITSTATUS3         (_PRCMU_BASE + 0x160)
+#define PRCM_ITSTATUS4         (_PRCMU_BASE + 0x168)
+#define PRCM_ITSTATUS5         (_PRCMU_BASE + 0x484)
+#define PRCM_ITCLEAR5          (_PRCMU_BASE + 0x488)
+#define PRCM_ARMIT_MASKXP70_IT (_PRCMU_BASE + 0x1018)
+
+/* System reset register */
+#define PRCM_APE_SOFTRST       (_PRCMU_BASE + 0x228)
+
+/* Level shifter and clamp control registers */
+#define PRCM_MMIP_LS_CLAMP_SET     (_PRCMU_BASE + 0x420)
+#define PRCM_MMIP_LS_CLAMP_CLR     (_PRCMU_BASE + 0x424)
+
+/* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
+#define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
+#define PRCM_LCDCLK_MGT            (_PRCMU_BASE + 0x044)
+#define PRCM_MCDECLK_MGT           (_PRCMU_BASE + 0x064)
+#define PRCM_HDMICLK_MGT           (_PRCMU_BASE + 0x058)
+#define PRCM_TVCLK_MGT             (_PRCMU_BASE + 0x07c)
+#define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
+#define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
+#define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
+#define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
+
+/* ePOD and memory power signal control registers */
+#define PRCM_EPOD_C_SET            (_PRCMU_BASE + 0x410)
+#define PRCM_SRAM_LS_SLEEP         (_PRCMU_BASE + 0x304)
+
+/* Debug power control unit registers */
+#define PRCM_POWER_STATE_SET       (_PRCMU_BASE + 0x254)
+
+/* Miscellaneous unit registers */
+#define PRCM_DSI_SW_RESET          (_PRCMU_BASE + 0x324)
+
+#endif /* __MACH_PRCMU__REGS_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h
new file mode 100644 (file)
index 0000000..549843f
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * PRCMU f/w APIs
+ */
+#ifndef __MACH_PRCMU_H
+#define __MACH_PRCMU_H
+
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+
+#endif /* __MACH_PRCMU_H */
index e978dbd..54bbe64 100644 (file)
@@ -38,4 +38,11 @@ extern struct sys_timer ux500_timer;
        .type           = MT_DEVICE,            \
 }
 
+#define __MEM_DEV_DESC(x, sz)  {               \
+       .virtual        = IO_ADDRESS(x),        \
+       .pfn            = __phys_to_pfn(x),     \
+       .length         = sz,                   \
+       .type           = MT_MEMORY,            \
+}
+
 #endif /*  __ASM_ARCH_SETUP_H */
diff --git a/arch/arm/mach-ux500/mbox.c b/arch/arm/mach-ux500/mbox.c
new file mode 100644 (file)
index 0000000..6343538
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+/*
+ * Mailbox nomenclature:
+ *
+ *       APE           MODEM
+ *           mbox pairX
+ *   ..........................
+ *   .                       .
+ *   .           peer        .
+ *   .     send  ----        .
+ *   .      -->  |  |        .
+ *   .           |  |        .
+ *   .           ----        .
+ *   .                       .
+ *   .           local       .
+ *   .     rec   ----        .
+ *   .           |  | <--    .
+ *   .           |  |        .
+ *   .           ----        .
+ *   .........................
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/completion.h>
+#include <mach/mbox.h>
+
+#define MBOX_NAME "mbox"
+
+#define MBOX_FIFO_DATA        0x000
+#define MBOX_FIFO_ADD         0x004
+#define MBOX_FIFO_REMOVE      0x008
+#define MBOX_FIFO_THRES_FREE  0x00C
+#define MBOX_FIFO_THRES_OCCUP 0x010
+#define MBOX_FIFO_STATUS      0x014
+
+#define MBOX_DISABLE_IRQ 0x4
+#define MBOX_ENABLE_IRQ  0x0
+#define MBOX_LATCH 1
+
+/* Global list of all mailboxes */
+static struct list_head mboxs = LIST_HEAD_INIT(mboxs);
+
+static struct mbox *get_mbox_with_id(u8 id)
+{
+       u8 i;
+       struct list_head *pos = &mboxs;
+       for (i = 0; i <= id; i++)
+               pos = pos->next;
+
+       return (struct mbox *) list_entry(pos, struct mbox, list);
+}
+
+int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block)
+{
+       int res = 0;
+
+       spin_lock(&mbox->lock);
+
+       dev_dbg(&(mbox->pdev->dev),
+               "About to buffer 0x%X to mailbox 0x%X."
+               " ri = %d, wi = %d\n",
+               mbox_msg, (u32)mbox, mbox->read_index,
+               mbox->write_index);
+
+       /* Check if write buffer is full */
+       while (((mbox->write_index + 1) % MBOX_BUF_SIZE) == mbox->read_index) {
+               if (!block) {
+                       dev_dbg(&(mbox->pdev->dev),
+                       "Buffer full in non-blocking call! "
+                       "Returning -ENOMEM!\n");
+                       res = -ENOMEM;
+                       goto exit;
+               }
+               spin_unlock(&mbox->lock);
+               dev_dbg(&(mbox->pdev->dev),
+                       "Buffer full in blocking call! Sleeping...\n");
+               mbox->client_blocked = 1;
+               wait_for_completion(&mbox->buffer_available);
+               dev_dbg(&(mbox->pdev->dev),
+                       "Blocking send was woken up! Trying again...\n");
+               spin_lock(&mbox->lock);
+       }
+
+       mbox->buffer[mbox->write_index] = mbox_msg;
+       mbox->write_index = (mbox->write_index + 1) % MBOX_BUF_SIZE;
+
+       /*
+        * Indicate that we want an IRQ as soon as there is a slot
+        * in the FIFO
+        */
+       writel(MBOX_ENABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+
+exit:
+       spin_unlock(&mbox->lock);
+       return res;
+}
+EXPORT_SYMBOL(mbox_send);
+
+#if defined(CONFIG_DEBUG_FS)
+/*
+ * Expected input: <value> <nbr sends>
+ * Example: "echo 0xdeadbeef 4 > mbox-node" sends 0xdeadbeef 4 times
+ */
+static ssize_t mbox_write_fifo(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf,
+                              size_t count)
+{
+       unsigned long mbox_mess;
+       unsigned long nbr_sends;
+       unsigned long i;
+       char int_buf[16];
+       char *token;
+       char *val;
+
+       struct mbox *mbox = (struct mbox *) dev->platform_data;
+
+       strncpy((char *) &int_buf, buf, sizeof(int_buf));
+       token = (char *) &int_buf;
+
+       /* Parse message */
+       val = strsep(&token, " ");
+       if ((val == NULL) || (strict_strtoul(val, 16, &mbox_mess) != 0))
+               mbox_mess = 0xDEADBEEF;
+
+       val = strsep(&token, " ");
+       if ((val == NULL) || (strict_strtoul(val, 10, &nbr_sends) != 0))
+               nbr_sends = 1;
+
+       dev_dbg(dev, "Will write 0x%lX %ld times using data struct at 0x%X\n",
+               mbox_mess, nbr_sends, (u32) mbox);
+
+       for (i = 0; i < nbr_sends; i++)
+               mbox_send(mbox, mbox_mess, true);
+
+       return count;
+}
+
+static ssize_t mbox_read_fifo(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       int mbox_value;
+       struct mbox *mbox = (struct mbox *) dev->platform_data;
+
+       if ((readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7) <= 0)
+               return sprintf(buf, "Mailbox is empty\n");
+
+       mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
+       writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
+
+       return sprintf(buf, "0x%X\n", mbox_value);
+}
+
+static DEVICE_ATTR(fifo, S_IWUGO | S_IRUGO, mbox_read_fifo, mbox_write_fifo);
+
+static int mbox_show(struct seq_file *s, void *data)
+{
+       struct list_head *pos;
+       u8 mbox_index = 0;
+
+       list_for_each(pos, &mboxs) {
+               struct mbox *m =
+                       (struct mbox *) list_entry(pos, struct mbox, list);
+               if (m == NULL) {
+                       seq_printf(s,
+                                  "Unable to retrieve mailbox %d\n",
+                                  mbox_index);
+                       continue;
+               }
+
+               spin_lock(&m->lock);
+               if ((m->virtbase_peer == NULL) || (m->virtbase_local == NULL)) {
+                       seq_printf(s, "MAILBOX %d not setup or corrupt\n",
+                                  mbox_index);
+                       spin_unlock(&m->lock);
+                       continue;
+               }
+
+               seq_printf(s,
+               "===========================\n"
+               " MAILBOX %d\n"
+               " PEER MAILBOX DUMP\n"
+               "---------------------------\n"
+               "FIFO:                 0x%X (%d)\n"
+               "Free     Threshold:   0x%.2X (%d)\n"
+               "Occupied Threshold:   0x%.2X (%d)\n"
+               "Status:               0x%.2X (%d)\n"
+               "   Free spaces  (ot):    %d (%d)\n"
+               "   Occup spaces (ot):    %d (%d)\n"
+               "===========================\n"
+               " LOCAL MAILBOX DUMP\n"
+               "---------------------------\n"
+               "FIFO:                 0x%.X (%d)\n"
+               "Free     Threshold:   0x%.2X (%d)\n"
+               "Occupied Threshold:   0x%.2X (%d)\n"
+               "Status:               0x%.2X (%d)\n"
+               "   Free spaces  (ot):    %d (%d)\n"
+               "   Occup spaces (ot):    %d (%d)\n"
+               "===========================\n"
+               "write_index: %d\n"
+               "read_index : %d\n"
+               "===========================\n"
+               "\n",
+               mbox_index,
+               readl(m->virtbase_peer + MBOX_FIFO_DATA),
+               readl(m->virtbase_peer + MBOX_FIFO_DATA),
+               readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
+               readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
+               readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
+               readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
+               readl(m->virtbase_peer + MBOX_FIFO_STATUS),
+               readl(m->virtbase_peer + MBOX_FIFO_STATUS),
+               (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 4) & 0x7,
+               (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 7) & 0x1,
+               (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 0) & 0x7,
+               (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 3) & 0x1,
+               readl(m->virtbase_local + MBOX_FIFO_DATA),
+               readl(m->virtbase_local + MBOX_FIFO_DATA),
+               readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
+               readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
+               readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
+               readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
+               readl(m->virtbase_local + MBOX_FIFO_STATUS),
+               readl(m->virtbase_local + MBOX_FIFO_STATUS),
+               (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 4) & 0x7,
+               (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 7) & 0x1,
+               (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 0) & 0x7,
+               (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 3) & 0x1,
+               m->write_index, m->read_index);
+               mbox_index++;
+               spin_unlock(&m->lock);
+       }
+
+       return 0;
+}
+
+static int mbox_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mbox_show, NULL);
+}
+
+static const struct file_operations mbox_operations = {
+       .owner = THIS_MODULE,
+       .open = mbox_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+#endif
+
+static irqreturn_t mbox_irq(int irq, void *arg)
+{
+       u32 mbox_value;
+       int nbr_occup;
+       int nbr_free;
+       struct mbox *mbox = (struct mbox *) arg;
+
+       spin_lock(&mbox->lock);
+
+       dev_dbg(&(mbox->pdev->dev),
+               "mbox IRQ [%d] received. ri = %d, wi = %d\n",
+               irq, mbox->read_index, mbox->write_index);
+
+       /*
+        * Check if we have any outgoing messages, and if there is space for
+        * them in the FIFO.
+        */
+       if (mbox->read_index != mbox->write_index) {
+               /*
+                * Check by reading FREE for LOCAL since that indicates
+                * OCCUP for PEER
+                */
+               nbr_free = (readl(mbox->virtbase_local + MBOX_FIFO_STATUS)
+                           >> 4) & 0x7;
+               dev_dbg(&(mbox->pdev->dev),
+                       "Status indicates %d empty spaces in the FIFO!\n",
+                       nbr_free);
+
+               while ((nbr_free > 0) &&
+                      (mbox->read_index != mbox->write_index)) {
+                       /* Write the message and latch it into the FIFO */
+                       writel(mbox->buffer[mbox->read_index],
+                              (mbox->virtbase_peer + MBOX_FIFO_DATA));
+                       writel(MBOX_LATCH,
+                              (mbox->virtbase_peer + MBOX_FIFO_ADD));
+                       dev_dbg(&(mbox->pdev->dev),
+                               "Wrote message 0x%X to addr 0x%X\n",
+                               mbox->buffer[mbox->read_index],
+                               (u32) (mbox->virtbase_peer + MBOX_FIFO_DATA));
+
+                       nbr_free--;
+                       mbox->read_index =
+                               (mbox->read_index + 1) % MBOX_BUF_SIZE;
+               }
+
+               /*
+                * Check if we still want IRQ:s when there is free
+                * space to send
+                */
+               if (mbox->read_index != mbox->write_index) {
+                       dev_dbg(&(mbox->pdev->dev),
+                               "Still have messages to send, but FIFO full. "
+                               "Request IRQ again!\n");
+                       writel(MBOX_ENABLE_IRQ,
+                              mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+               } else {
+                       dev_dbg(&(mbox->pdev->dev),
+                               "No more messages to send. "
+                               "Do not request IRQ again!\n");
+                       writel(MBOX_DISABLE_IRQ,
+                              mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+               }
+
+               /*
+                * Check if we can signal any blocked clients that it is OK to
+                * start buffering again
+                */
+               if (mbox->client_blocked &&
+                   (((mbox->write_index + 1) % MBOX_BUF_SIZE)
+                    != mbox->read_index)) {
+                       dev_dbg(&(mbox->pdev->dev),
+                               "Waking up blocked client\n");
+                       complete(&mbox->buffer_available);
+                       mbox->client_blocked = 0;
+               }
+       }
+
+       /* Check if we have any incoming messages */
+       nbr_occup = readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7;
+       if (nbr_occup == 0)
+               goto exit;
+
+       if (mbox->cb == NULL) {
+               dev_dbg(&(mbox->pdev->dev), "No receive callback registered, "
+                       "leaving %d incoming messages in fifo!\n", nbr_occup);
+               goto exit;
+       }
+
+       /* Read and acknowledge the message */
+       mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
+       writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
+
+       /* Notify consumer of new mailbox message */
+       dev_dbg(&(mbox->pdev->dev), "Calling callback for message 0x%X!\n",
+               mbox_value);
+       mbox->cb(mbox_value, mbox->client_data);
+
+exit:
+       dev_dbg(&(mbox->pdev->dev), "Exit mbox IRQ. ri = %d, wi = %d\n",
+               mbox->read_index, mbox->write_index);
+       spin_unlock(&mbox->lock);
+
+       return IRQ_HANDLED;
+}
+
+/* Setup is executed once for each mbox pair */
+struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
+{
+       struct resource *resource;
+       int irq;
+       int res;
+       struct mbox *mbox;
+
+       mbox = get_mbox_with_id(mbox_id);
+       if (mbox == NULL) {
+               dev_err(&(mbox->pdev->dev), "Incorrect mailbox id: %d!\n",
+                       mbox_id);
+               goto exit;
+       }
+
+       /*
+        * Check if mailbox has been allocated to someone else,
+        * otherwise allocate it
+        */
+       if (mbox->allocated) {
+               dev_err(&(mbox->pdev->dev), "Mailbox number %d is busy!\n",
+                       mbox_id);
+               mbox = NULL;
+               goto exit;
+       }
+       mbox->allocated = true;
+
+       dev_dbg(&(mbox->pdev->dev), "Initiating mailbox number %d: 0x%X...\n",
+               mbox_id, (u32)mbox);
+
+       mbox->client_data = priv;
+       mbox->cb = mbox_cb;
+
+       /* Get addr for peer mailbox and ioremap it */
+       resource = platform_get_resource_byname(mbox->pdev,
+                                               IORESOURCE_MEM,
+                                               "mbox_peer");
+       if (resource == NULL) {
+               dev_err(&(mbox->pdev->dev),
+                       "Unable to retrieve mbox peer resource\n");
+               mbox = NULL;
+               goto exit;
+       }
+       dev_dbg(&(mbox->pdev->dev),
+               "Resource name: %s start: 0x%X, end: 0x%X\n",
+               resource->name, resource->start, resource->end);
+       mbox->virtbase_peer =
+               ioremap(resource->start, resource->end - resource->start);
+       if (!mbox->virtbase_peer) {
+               dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n");
+               mbox = NULL;
+               goto exit;
+       }
+       dev_dbg(&(mbox->pdev->dev),
+               "ioremapped peer physical: (0x%X-0x%X) to virtual: 0x%X\n",
+               resource->start, resource->end, (u32) mbox->virtbase_peer);
+
+       /* Get addr for local mailbox and ioremap it */
+       resource = platform_get_resource_byname(mbox->pdev,
+                                               IORESOURCE_MEM,
+                                               "mbox_local");
+       if (resource == NULL) {
+               dev_err(&(mbox->pdev->dev),
+                       "Unable to retrieve mbox local resource\n");
+               mbox = NULL;
+               goto exit;
+       }
+       dev_dbg(&(mbox->pdev->dev),
+               "Resource name: %s start: 0x%X, end: 0x%X\n",
+               resource->name, resource->start, resource->end);
+       mbox->virtbase_local =
+               ioremap(resource->start, resource->end - resource->start);
+       if (!mbox->virtbase_local) {
+               dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n");
+               mbox = NULL;
+               goto exit;
+       }
+       dev_dbg(&(mbox->pdev->dev),
+               "ioremapped local physical: (0x%X-0x%X) to virtual: 0x%X\n",
+               resource->start, resource->end, (u32) mbox->virtbase_peer);
+
+       init_completion(&mbox->buffer_available);
+       mbox->client_blocked = 0;
+
+       /* Get IRQ for mailbox and allocate it */
+       irq = platform_get_irq_byname(mbox->pdev, "mbox_irq");
+       if (irq < 0) {
+               dev_err(&(mbox->pdev->dev),
+                       "Unable to retrieve mbox irq resource\n");
+               mbox = NULL;
+               goto exit;
+       }
+
+       dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", irq);
+       res = request_irq(irq, mbox_irq, 0, mbox->name, (void *) mbox);
+       if (res < 0) {
+               dev_err(&(mbox->pdev->dev),
+                       "Unable to allocate mbox irq %d\n", irq);
+               mbox = NULL;
+               goto exit;
+       }
+
+       /* Set up mailbox to not launch IRQ on free space in mailbox */
+       writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+
+       /*
+        * Set up mailbox to launch IRQ on new message if we have
+        * a callback set. If not, do not raise IRQ, but keep message
+        * in FIFO for manual retrieval
+        */
+       if (mbox_cb != NULL)
+               writel(MBOX_ENABLE_IRQ,
+                      mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
+       else
+               writel(MBOX_DISABLE_IRQ,
+                      mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
+
+#if defined(CONFIG_DEBUG_FS)
+       res = device_create_file(&(mbox->pdev->dev), &dev_attr_fifo);
+       if (res != 0)
+               dev_warn(&(mbox->pdev->dev),
+                        "Unable to create mbox sysfs entry");
+
+       (void) debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL,
+                                  NULL, &mbox_operations);
+#endif
+
+       dev_info(&(mbox->pdev->dev),
+                "Mailbox driver with index %d initated!\n", mbox_id);
+
+exit:
+       return mbox;
+}
+EXPORT_SYMBOL(mbox_setup);
+
+
+int __init mbox_probe(struct platform_device *pdev)
+{
+       struct mbox local_mbox;
+       struct mbox *mbox;
+       int res = 0;
+       dev_dbg(&(pdev->dev), "Probing mailbox (pdev = 0x%X)...\n", (u32) pdev);
+
+       memset(&local_mbox, 0x0, sizeof(struct mbox));
+
+       /* Associate our mbox data with the platform device */
+       res = platform_device_add_data(pdev,
+                                      (void *) &local_mbox,
+                                      sizeof(struct mbox));
+       if (res != 0) {
+               dev_err(&(pdev->dev),
+                       "Unable to allocate driver platform data!\n");
+               goto exit;
+       }
+
+       mbox = (struct mbox *) pdev->dev.platform_data;
+       mbox->pdev = pdev;
+       mbox->write_index = 0;
+       mbox->read_index = 0;
+
+       INIT_LIST_HEAD(&(mbox->list));
+       list_add_tail(&(mbox->list), &mboxs);
+
+       sprintf(mbox->name, "%s", MBOX_NAME);
+       spin_lock_init(&mbox->lock);
+
+       dev_info(&(pdev->dev), "Mailbox driver loaded\n");
+
+exit:
+       return res;
+}
+
+static struct platform_driver mbox_driver = {
+       .driver = {
+               .name = MBOX_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init mbox_init(void)
+{
+       return platform_driver_probe(&mbox_driver, mbox_probe);
+}
+
+module_init(mbox_init);
+
+void __exit mbox_exit(void)
+{
+       platform_driver_unregister(&mbox_driver);
+}
+
+module_exit(mbox_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MBOX driver");
diff --git a/arch/arm/mach-ux500/modem_irq.c b/arch/arm/mach-ux500/modem_irq.c
new file mode 100644 (file)
index 0000000..3187f88
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define MODEM_INTCON_BASE_ADDR 0xBFFD3000
+#define MODEM_INTCON_SIZE 0xFFF
+
+#define DEST_IRQ41_OFFSET 0x2A4
+#define DEST_IRQ43_OFFSET 0x2AC
+#define DEST_IRQ45_OFFSET 0x2B4
+
+#define PRIO_IRQ41_OFFSET 0x6A4
+#define PRIO_IRQ43_OFFSET 0x6AC
+#define PRIO_IRQ45_OFFSET 0x6B4
+
+#define ALLOW_IRQ_OFFSET 0x104
+
+#define MODEM_INTCON_CPU_NBR 0x1
+#define MODEM_INTCON_PRIO_HIGH 0x0
+
+#define MODEM_INTCON_ALLOW_IRQ41 0x0200
+#define MODEM_INTCON_ALLOW_IRQ43 0x0800
+#define MODEM_INTCON_ALLOW_IRQ45 0x2000
+
+#define MODEM_IRQ_REG_OFFSET 0x4
+
+struct modem_irq {
+       void __iomem *modem_intcon_base;
+};
+
+
+static void setup_modem_intcon(void __iomem *modem_intcon_base)
+{
+       /* IC_DESTINATION_BASE_ARRAY - Which CPU to receive the IRQ */
+       writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ41_OFFSET);
+       writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ43_OFFSET);
+       writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ45_OFFSET);
+
+       /* IC_PRIORITY_BASE_ARRAY - IRQ priority in modem IRQ controller */
+       writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ41_OFFSET);
+       writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ43_OFFSET);
+       writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ45_OFFSET);
+
+       /* IC_ALLOW_ARRAY - IRQ enable */
+       writel(MODEM_INTCON_ALLOW_IRQ41 |
+                  MODEM_INTCON_ALLOW_IRQ43 |
+                  MODEM_INTCON_ALLOW_IRQ45,
+                  modem_intcon_base + ALLOW_IRQ_OFFSET);
+}
+
+static irqreturn_t modem_cpu_irq_handler(int irq, void *data)
+{
+       int real_irq;
+       int virt_irq;
+       struct modem_irq *mi = (struct modem_irq *)data;
+
+       /* Read modem side IRQ number from modem IRQ controller */
+       real_irq = readl(mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET) & 0xFF;
+       virt_irq = IRQ_MODEM_EVENTS_BASE + real_irq;
+
+       pr_debug("modem_irq: Worker read addr 0x%X and got value 0x%X "
+                "which will be 0x%X (%d) which translates to "
+                "virtual IRQ 0x%X (%d)!\n",
+                  (u32)mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET,
+                  real_irq,
+                  real_irq & 0xFF,
+                  real_irq & 0xFF,
+                  virt_irq,
+                  virt_irq);
+
+       if (virt_irq != 0)
+               generic_handle_irq(virt_irq);
+
+       pr_debug("modem_irq: Done handling virtual IRQ %d!\n", virt_irq);
+
+       return IRQ_HANDLED;
+}
+
+static void create_virtual_irq(int irq, struct irq_chip *modem_irq_chip)
+{
+       set_irq_chip(irq, modem_irq_chip);
+       set_irq_handler(irq, handle_simple_irq);
+       set_irq_flags(irq, IRQF_VALID);
+
+       pr_debug("modem_irq: Created virtual IRQ %d\n", irq);
+}
+
+static int modem_irq_init(void)
+{
+       int err;
+       static struct irq_chip  modem_irq_chip;
+       struct modem_irq *mi;
+
+       pr_info("modem_irq: Set up IRQ handler for incoming modem IRQ %d\n",
+                  IRQ_DB5500_MODEM);
+
+       mi = kmalloc(sizeof(struct modem_irq), GFP_KERNEL);
+       if (!mi) {
+               pr_err("modem_irq: Could not allocate device\n");
+               return -ENOMEM;
+       }
+
+       mi->modem_intcon_base =
+               ioremap(MODEM_INTCON_BASE_ADDR, MODEM_INTCON_SIZE);
+       pr_debug("modem_irq: ioremapped modem_intcon_base from "
+                "phy 0x%x to virt 0x%x\n", MODEM_INTCON_BASE_ADDR,
+                (u32)mi->modem_intcon_base);
+
+       setup_modem_intcon(mi->modem_intcon_base);
+
+       modem_irq_chip = dummy_irq_chip;
+       modem_irq_chip.name = "modem_irq";
+
+       /* Create the virtual IRQ:s needed */
+       create_virtual_irq(MBOX_PAIR0_VIRT_IRQ, &modem_irq_chip);
+       create_virtual_irq(MBOX_PAIR1_VIRT_IRQ, &modem_irq_chip);
+       create_virtual_irq(MBOX_PAIR2_VIRT_IRQ, &modem_irq_chip);
+
+       err = request_threaded_irq(IRQ_DB5500_MODEM, NULL,
+                                  modem_cpu_irq_handler, IRQF_ONESHOT,
+                                  "modem_irq", mi);
+       if (err)
+               pr_err("modem_irq: Could not register IRQ %d\n",
+                      IRQ_DB5500_MODEM);
+
+       return 0;
+}
+
+arch_initcall(modem_irq_init);
diff --git a/arch/arm/mach-ux500/pins-db5500.h b/arch/arm/mach-ux500/pins-db5500.h
new file mode 100644 (file)
index 0000000..bf50c21
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ */
+
+#ifndef __MACH_DB5500_PINS_H
+#define __MACH_DB5500_PINS_H
+
+#define GPIO0_GPIO             PIN_CFG(0, GPIO)
+#define GPIO0_SM_CS3n          PIN_CFG(0, ALT_A)
+
+#define GPIO1_GPIO             PIN_CFG(1, GPIO)
+#define GPIO1_SM_A3            PIN_CFG(1, ALT_A)
+
+#define GPIO2_GPIO             PIN_CFG(2, GPIO)
+#define GPIO2_SM_A4            PIN_CFG(2, ALT_A)
+#define GPIO2_SM_AVD           PIN_CFG(2, ALT_B)
+
+#define GPIO3_GPIO             PIN_CFG(3, GPIO)
+#define GPIO3_I2C1_SCL         PIN_CFG(3, ALT_A)
+
+#define GPIO4_GPIO             PIN_CFG(4, GPIO)
+#define GPIO4_I2C1_SDA         PIN_CFG(4, ALT_A)
+
+#define GPIO5_GPIO             PIN_CFG(5, GPIO)
+#define GPIO5_MC0_DAT0         PIN_CFG(5, ALT_A)
+#define GPIO5_SM_ADQ8          PIN_CFG(5, ALT_B)
+
+#define GPIO6_GPIO             PIN_CFG(6, GPIO)
+#define GPIO6_MC0_DAT1         PIN_CFG(6, ALT_A)
+#define GPIO6_SM_ADQ0          PIN_CFG(6, ALT_B)
+
+#define GPIO7_GPIO             PIN_CFG(7, GPIO)
+#define GPIO7_MC0_DAT2         PIN_CFG(7, ALT_A)
+#define GPIO7_SM_ADQ9          PIN_CFG(7, ALT_B)
+
+#define GPIO8_GPIO             PIN_CFG(8, GPIO)
+#define GPIO8_MC0_DAT3         PIN_CFG(8, ALT_A)
+#define GPIO8_SM_ADQ1          PIN_CFG(8, ALT_B)
+
+#define GPIO9_GPIO             PIN_CFG(9, GPIO)
+#define GPIO9_MC0_DAT4         PIN_CFG(9, ALT_A)
+#define GPIO9_SM_ADQ10         PIN_CFG(9, ALT_B)
+
+#define GPIO10_GPIO            PIN_CFG(10, GPIO)
+#define GPIO10_MC0_DAT5                PIN_CFG(10, ALT_A)
+#define GPIO10_SM_ADQ2         PIN_CFG(10, ALT_B)
+
+#define GPIO11_GPIO            PIN_CFG(11, GPIO)
+#define GPIO11_MC0_DAT6                PIN_CFG(11, ALT_A)
+#define GPIO11_SM_ADQ11                PIN_CFG(11, ALT_B)
+
+#define GPIO12_GPIO            PIN_CFG(12, GPIO)
+#define GPIO12_MC0_DAT7                PIN_CFG(12, ALT_A)
+#define GPIO12_SM_ADQ3         PIN_CFG(12, ALT_B)
+
+#define GPIO13_GPIO            PIN_CFG(13, GPIO)
+#define GPIO13_MC0_CMD         PIN_CFG(13, ALT_A)
+#define GPIO13_SM_BUSY0n       PIN_CFG(13, ALT_B)
+#define GPIO13_SM_WAIT0n       PIN_CFG(13, ALT_C)
+
+#define GPIO14_GPIO            PIN_CFG(14, GPIO)
+#define GPIO14_MC0_CLK         PIN_CFG(14, ALT_A)
+#define GPIO14_SM_CS1n         PIN_CFG(14, ALT_B)
+#define GPIO14_SM_CKO          PIN_CFG(14, ALT_C)
+
+#define GPIO15_GPIO            PIN_CFG(15, GPIO)
+#define GPIO15_SM_A5           PIN_CFG(15, ALT_A)
+#define GPIO15_SM_CLE          PIN_CFG(15, ALT_B)
+
+#define GPIO16_GPIO            PIN_CFG(16, GPIO)
+#define GPIO16_MC2_CMD         PIN_CFG(16, ALT_A)
+#define GPIO16_SM_OEn          PIN_CFG(16, ALT_B)
+
+#define GPIO17_GPIO            PIN_CFG(17, GPIO)
+#define GPIO17_MC2_CLK         PIN_CFG(17, ALT_A)
+#define GPIO17_SM_WEn          PIN_CFG(17, ALT_B)
+
+#define GPIO18_GPIO            PIN_CFG(18, GPIO)
+#define GPIO18_SM_A6           PIN_CFG(18, ALT_A)
+#define GPIO18_SM_ALE          PIN_CFG(18, ALT_B)
+#define GPIO18_SM_AVDn         PIN_CFG(18, ALT_C)
+
+#define GPIO19_GPIO            PIN_CFG(19, GPIO)
+#define GPIO19_MC2_DAT1                PIN_CFG(19, ALT_A)
+#define GPIO19_SM_ADQ4         PIN_CFG(19, ALT_B)
+
+#define GPIO20_GPIO            PIN_CFG(20, GPIO)
+#define GPIO20_MC2_DAT3                PIN_CFG(20, ALT_A)
+#define GPIO20_SM_ADQ5         PIN_CFG(20, ALT_B)
+
+#define GPIO21_GPIO            PIN_CFG(21, GPIO)
+#define GPIO21_MC2_DAT5                PIN_CFG(21, ALT_A)
+#define GPIO21_SM_ADQ6         PIN_CFG(21, ALT_B)
+
+#define GPIO22_GPIO            PIN_CFG(22, GPIO)
+#define GPIO22_MC2_DAT7                PIN_CFG(22, ALT_A)
+#define GPIO22_SM_ADQ7         PIN_CFG(22, ALT_B)
+
+#define GPIO23_GPIO            PIN_CFG(23, GPIO)
+#define GPIO23_MC2_DAT0                PIN_CFG(23, ALT_A)
+#define GPIO23_SM_ADQ12                PIN_CFG(23, ALT_B)
+#define GPIO23_MC0_DAT1                PIN_CFG(23, ALT_C)
+
+#define GPIO24_GPIO            PIN_CFG(24, GPIO)
+#define GPIO24_MC2_DAT2                PIN_CFG(24, ALT_A)
+#define GPIO24_SM_ADQ13                PIN_CFG(24, ALT_B)
+#define GPIO24_MC0_DAT3                PIN_CFG(24, ALT_C)
+
+#define GPIO25_GPIO            PIN_CFG(25, GPIO)
+#define GPIO25_MC2_DAT4                PIN_CFG(25, ALT_A)
+#define GPIO25_SM_ADQ14                PIN_CFG(25, ALT_B)
+#define GPIO25_MC0_CMD         PIN_CFG(25, ALT_C)
+
+#define GPIO26_GPIO            PIN_CFG(26, GPIO)
+#define GPIO26_MC2_DAT6                PIN_CFG(26, ALT_A)
+#define GPIO26_SM_ADQ15                PIN_CFG(26, ALT_B)
+
+#define GPIO27_GPIO            PIN_CFG(27, GPIO)
+#define GPIO27_SM_CS0n         PIN_CFG(27, ALT_A)
+#define GPIO27_SM_PS0n         PIN_CFG(27, ALT_B)
+
+#define GPIO28_GPIO            PIN_CFG(28, GPIO)
+#define GPIO28_U0_TXD          PIN_CFG(28, ALT_A)
+#define GPIO28_SM_A0           PIN_CFG(28, ALT_B)
+
+#define GPIO29_GPIO            PIN_CFG(29, GPIO)
+#define GPIO29_U0_RXD          PIN_CFG(29, ALT_A)
+#define GPIO29_SM_A1           PIN_CFG(29, ALT_B)
+#define GPIO29_PWM_0           PIN_CFG(29, ALT_C)
+
+#define GPIO30_GPIO            PIN_CFG(30, GPIO)
+#define GPIO30_MC0_DAT5                PIN_CFG(30, ALT_A)
+#define GPIO30_SM_A2           PIN_CFG(30, ALT_B)
+#define GPIO30_PWM_1           PIN_CFG(30, ALT_C)
+
+#define GPIO31_GPIO            PIN_CFG(31, GPIO)
+#define GPIO31_MC0_DAT7                PIN_CFG(31, ALT_A)
+#define GPIO31_SM_CS2n         PIN_CFG(31, ALT_B)
+#define GPIO31_PWM_2           PIN_CFG(31, ALT_C)
+
+#define GPIO32_GPIO            PIN_CFG(32, GPIO)
+#define GPIO32_MSP0_TCK                PIN_CFG(32, ALT_A)
+#define GPIO32_ACCI2S0_SCK     PIN_CFG(32, ALT_B)
+
+#define GPIO33_GPIO            PIN_CFG(33, GPIO)
+#define GPIO33_MSP0_TFS                PIN_CFG(33, ALT_A)
+#define GPIO33_ACCI2S0_WS      PIN_CFG(33, ALT_B)
+
+#define GPIO34_GPIO            PIN_CFG(34, GPIO)
+#define GPIO34_MSP0_TXD                PIN_CFG(34, ALT_A)
+#define GPIO34_ACCI2S0_DLD     PIN_CFG(34, ALT_B)
+
+#define GPIO35_GPIO            PIN_CFG(35, GPIO)
+#define GPIO35_MSP0_RXD                PIN_CFG(35, ALT_A)
+#define GPIO35_ACCI2S0_ULD     PIN_CFG(35, ALT_B)
+
+#define GPIO64_GPIO            PIN_CFG(64, GPIO)
+#define GPIO64_USB_DAT0                PIN_CFG(64, ALT_A)
+#define GPIO64_U0_TXD          PIN_CFG(64, ALT_B)
+
+#define GPIO65_GPIO            PIN_CFG(65, GPIO)
+#define GPIO65_USB_DAT1                PIN_CFG(65, ALT_A)
+#define GPIO65_U0_RXD          PIN_CFG(65, ALT_B)
+
+#define GPIO66_GPIO            PIN_CFG(66, GPIO)
+#define GPIO66_USB_DAT2                PIN_CFG(66, ALT_A)
+
+#define GPIO67_GPIO            PIN_CFG(67, GPIO)
+#define GPIO67_USB_DAT3                PIN_CFG(67, ALT_A)
+
+#define GPIO68_GPIO            PIN_CFG(68, GPIO)
+#define GPIO68_USB_DAT4                PIN_CFG(68, ALT_A)
+
+#define GPIO69_GPIO            PIN_CFG(69, GPIO)
+#define GPIO69_USB_DAT5                PIN_CFG(69, ALT_A)
+
+#define GPIO70_GPIO            PIN_CFG(70, GPIO)
+#define GPIO70_USB_DAT6                PIN_CFG(70, ALT_A)
+
+#define GPIO71_GPIO            PIN_CFG(71, GPIO)
+#define GPIO71_USB_DAT7                PIN_CFG(71, ALT_A)
+
+#define GPIO72_GPIO            PIN_CFG(72, GPIO)
+#define GPIO72_USB_STP         PIN_CFG(72, ALT_A)
+
+#define GPIO73_GPIO            PIN_CFG(73, GPIO)
+#define GPIO73_USB_DIR         PIN_CFG(73, ALT_A)
+
+#define GPIO74_GPIO            PIN_CFG(74, GPIO)
+#define GPIO74_USB_NXT         PIN_CFG(74, ALT_A)
+
+#define GPIO75_GPIO            PIN_CFG(75, GPIO)
+#define GPIO75_USB_XCLK                PIN_CFG(75, ALT_A)
+
+#define GPIO76_GPIO            PIN_CFG(76, GPIO)
+
+#define GPIO77_GPIO            PIN_CFG(77, GPIO)
+#define GPIO77_ACCTX_ON                PIN_CFG(77, ALT_A)
+
+#define GPIO78_GPIO            PIN_CFG(78, GPIO)
+#define GPIO78_IRQn            PIN_CFG(78, ALT_A)
+
+#define GPIO79_GPIO            PIN_CFG(79, GPIO)
+#define GPIO79_ACCSIM_Clk      PIN_CFG(79, ALT_A)
+
+#define GPIO80_GPIO            PIN_CFG(80, GPIO)
+#define GPIO80_ACCSIM_Da       PIN_CFG(80, ALT_A)
+
+#define GPIO81_GPIO            PIN_CFG(81, GPIO)
+#define GPIO81_ACCSIM_Reset    PIN_CFG(81, ALT_A)
+
+#define GPIO82_GPIO            PIN_CFG(82, GPIO)
+#define GPIO82_ACCSIM_DDir     PIN_CFG(82, ALT_A)
+
+#define GPIO96_GPIO            PIN_CFG(96, GPIO)
+#define GPIO96_MSP1_TCK                PIN_CFG(96, ALT_A)
+#define GPIO96_PRCMU_DEBUG3    PIN_CFG(96, ALT_B)
+#define GPIO96_PRCMU_DEBUG7    PIN_CFG(96, ALT_C)
+
+#define GPIO97_GPIO            PIN_CFG(97, GPIO)
+#define GPIO97_MSP1_TFS                PIN_CFG(97, ALT_A)
+#define GPIO97_PRCMU_DEBUG2    PIN_CFG(97, ALT_B)
+#define GPIO97_PRCMU_DEBUG6    PIN_CFG(97, ALT_C)
+
+#define GPIO98_GPIO            PIN_CFG(98, GPIO)
+#define GPIO98_MSP1_TXD                PIN_CFG(98, ALT_A)
+#define GPIO98_PRCMU_DEBUG1    PIN_CFG(98, ALT_B)
+#define GPIO98_PRCMU_DEBUG5    PIN_CFG(98, ALT_C)
+
+#define GPIO99_GPIO            PIN_CFG(99, GPIO)
+#define GPIO99_MSP1_RXD                PIN_CFG(99, ALT_A)
+#define GPIO99_PRCMU_DEBUG0    PIN_CFG(99, ALT_B)
+#define GPIO99_PRCMU_DEBUG4    PIN_CFG(99, ALT_C)
+
+#define GPIO100_GPIO           PIN_CFG(100, GPIO)
+#define GPIO100_I2C0_SCL       PIN_CFG(100, ALT_A)
+
+#define GPIO101_GPIO           PIN_CFG(101, GPIO)
+#define GPIO101_I2C0_SDA       PIN_CFG(101, ALT_A)
+
+#define GPIO128_GPIO           PIN_CFG(128, GPIO)
+#define GPIO128_KP_I0          PIN_CFG(128, ALT_A)
+#define GPIO128_BUSMON_D0      PIN_CFG(128, ALT_B)
+
+#define GPIO129_GPIO           PIN_CFG(129, GPIO)
+#define GPIO129_KP_O0          PIN_CFG(129, ALT_A)
+#define GPIO129_BUSMON_D1      PIN_CFG(129, ALT_B)
+
+#define GPIO130_GPIO           PIN_CFG(130, GPIO)
+#define GPIO130_KP_I1          PIN_CFG(130, ALT_A)
+#define GPIO130_BUSMON_D2      PIN_CFG(130, ALT_B)
+
+#define GPIO131_GPIO           PIN_CFG(131, GPIO)
+#define GPIO131_KP_O1          PIN_CFG(131, ALT_A)
+#define GPIO131_BUSMON_D3      PIN_CFG(131, ALT_B)
+
+#define GPIO132_GPIO           PIN_CFG(132, GPIO)
+#define GPIO132_KP_I2          PIN_CFG(132, ALT_A)
+#define GPIO132_ETM_D15                PIN_CFG(132, ALT_B)
+#define GPIO132_STMAPE_CLK     PIN_CFG(132, ALT_C)
+
+#define GPIO133_GPIO           PIN_CFG(133, GPIO)
+#define GPIO133_KP_O2          PIN_CFG(133, ALT_A)
+#define GPIO133_ETM_D14                PIN_CFG(133, ALT_B)
+#define GPIO133_U0_RXD         PIN_CFG(133, ALT_C)
+
+#define GPIO134_GPIO           PIN_CFG(134, GPIO)
+#define GPIO134_KP_I3          PIN_CFG(134, ALT_A)
+#define GPIO134_ETM_D13                PIN_CFG(134, ALT_B)
+#define GPIO134_STMAPE_DAT0    PIN_CFG(134, ALT_C)
+
+#define GPIO135_GPIO           PIN_CFG(135, GPIO)
+#define GPIO135_KP_O3          PIN_CFG(135, ALT_A)
+#define GPIO135_ETM_D12                PIN_CFG(135, ALT_B)
+#define GPIO135_STMAPE_DAT1    PIN_CFG(135, ALT_C)
+
+#define GPIO136_GPIO           PIN_CFG(136, GPIO)
+#define GPIO136_KP_I4          PIN_CFG(136, ALT_A)
+#define GPIO136_ETM_D11                PIN_CFG(136, ALT_B)
+#define GPIO136_STMAPE_DAT2    PIN_CFG(136, ALT_C)
+
+#define GPIO137_GPIO           PIN_CFG(137, GPIO)
+#define GPIO137_KP_O4          PIN_CFG(137, ALT_A)
+#define GPIO137_ETM_D10                PIN_CFG(137, ALT_B)
+#define GPIO137_STMAPE_DAT3    PIN_CFG(137, ALT_C)
+
+#define GPIO138_GPIO           PIN_CFG(138, GPIO)
+#define GPIO138_KP_I5          PIN_CFG(138, ALT_A)
+#define GPIO138_ETM_D9         PIN_CFG(138, ALT_B)
+#define GPIO138_U0_TXD         PIN_CFG(138, ALT_C)
+
+#define GPIO139_GPIO           PIN_CFG(139, GPIO)
+#define GPIO139_KP_O5          PIN_CFG(139, ALT_A)
+#define GPIO139_ETM_D8         PIN_CFG(139, ALT_B)
+#define GPIO139_BUSMON_D11     PIN_CFG(139, ALT_C)
+
+#define GPIO140_GPIO           PIN_CFG(140, GPIO)
+#define GPIO140_KP_I6          PIN_CFG(140, ALT_A)
+#define GPIO140_ETM_D7         PIN_CFG(140, ALT_B)
+#define GPIO140_STMAPE_CLK     PIN_CFG(140, ALT_C)
+
+#define GPIO141_GPIO           PIN_CFG(141, GPIO)
+#define GPIO141_KP_O6          PIN_CFG(141, ALT_A)
+#define GPIO141_ETM_D6         PIN_CFG(141, ALT_B)
+#define GPIO141_U0_RXD         PIN_CFG(141, ALT_C)
+
+#define GPIO142_GPIO           PIN_CFG(142, GPIO)
+#define GPIO142_KP_I7          PIN_CFG(142, ALT_A)
+#define GPIO142_ETM_D5         PIN_CFG(142, ALT_B)
+#define GPIO142_STMAPE_DAT0    PIN_CFG(142, ALT_C)
+
+#define GPIO143_GPIO           PIN_CFG(143, GPIO)
+#define GPIO143_KP_O7          PIN_CFG(143, ALT_A)
+#define GPIO143_ETM_D4         PIN_CFG(143, ALT_B)
+#define GPIO143_STMAPE_DAT1    PIN_CFG(143, ALT_C)
+
+#define GPIO144_GPIO           PIN_CFG(144, GPIO)
+#define GPIO144_I2C3_SCL       PIN_CFG(144, ALT_A)
+#define GPIO144_ETM_D3         PIN_CFG(144, ALT_B)
+#define GPIO144_STMAPE_DAT2    PIN_CFG(144, ALT_C)
+
+#define GPIO145_GPIO           PIN_CFG(145, GPIO)
+#define GPIO145_I2C3_SDA       PIN_CFG(145, ALT_A)
+#define GPIO145_ETM_D2         PIN_CFG(145, ALT_B)
+#define GPIO145_STMAPE_DAT3    PIN_CFG(145, ALT_C)
+
+#define GPIO146_GPIO           PIN_CFG(146, GPIO)
+#define GPIO146_PWM_0          PIN_CFG(146, ALT_A)
+#define GPIO146_ETM_D1         PIN_CFG(146, ALT_B)
+
+#define GPIO147_GPIO           PIN_CFG(147, GPIO)
+#define GPIO147_PWM_1          PIN_CFG(147, ALT_A)
+#define GPIO147_ETM_D0         PIN_CFG(147, ALT_B)
+
+#define GPIO148_GPIO           PIN_CFG(148, GPIO)
+#define GPIO148_PWM_2          PIN_CFG(148, ALT_A)
+#define GPIO148_ETM_CLK                PIN_CFG(148, ALT_B)
+
+#define GPIO160_GPIO           PIN_CFG(160, GPIO)
+#define GPIO160_CLKOUT_REQn    PIN_CFG(160, ALT_A)
+
+#define GPIO161_GPIO           PIN_CFG(161, GPIO)
+#define GPIO161_CLKOUT_0       PIN_CFG(161, ALT_A)
+
+#define GPIO162_GPIO           PIN_CFG(162, GPIO)
+#define GPIO162_CLKOUT_1       PIN_CFG(162, ALT_A)
+
+#define GPIO163_GPIO           PIN_CFG(163, GPIO)
+
+#define GPIO164_GPIO           PIN_CFG(164, GPIO)
+#define GPIO164_GPS_START      PIN_CFG(164, ALT_A)
+
+#define GPIO165_GPIO           PIN_CFG(165, GPIO)
+#define GPIO165_SPI1_CS2n      PIN_CFG(165, ALT_A)
+#define GPIO165_U3_RXD         PIN_CFG(165, ALT_B)
+#define GPIO165_BUSMON_D20     PIN_CFG(165, ALT_C)
+
+#define GPIO166_GPIO           PIN_CFG(166, GPIO)
+#define GPIO166_SPI1_CS1n      PIN_CFG(166, ALT_A)
+#define GPIO166_U3_TXD         PIN_CFG(166, ALT_B)
+#define GPIO166_BUSMON_D21     PIN_CFG(166, ALT_C)
+
+#define GPIO167_GPIO           PIN_CFG(167, GPIO)
+#define GPIO167_SPI1_CS0n      PIN_CFG(167, ALT_A)
+#define GPIO167_U3_RTSn                PIN_CFG(167, ALT_B)
+#define GPIO167_BUSMON_D22     PIN_CFG(167, ALT_C)
+
+#define GPIO168_GPIO           PIN_CFG(168, GPIO)
+#define GPIO168_SPI1_RXD       PIN_CFG(168, ALT_A)
+#define GPIO168_U3_CTSn                PIN_CFG(168, ALT_B)
+#define GPIO168_BUSMON_D23     PIN_CFG(168, ALT_C)
+
+#define GPIO169_GPIO           PIN_CFG(169, GPIO)
+#define GPIO169_SPI1_TXD       PIN_CFG(169, ALT_A)
+#define GPIO169_DDR_RC         PIN_CFG(169, ALT_B)
+#define GPIO169_BUSMON_D24     PIN_CFG(169, ALT_C)
+
+#define GPIO170_GPIO           PIN_CFG(170, GPIO)
+#define GPIO170_SPI1_CLK       PIN_CFG(170, ALT_A)
+
+#define GPIO171_GPIO           PIN_CFG(171, GPIO)
+#define GPIO171_MC3_DAT0       PIN_CFG(171, ALT_A)
+#define GPIO171_SPI3_RXD       PIN_CFG(171, ALT_B)
+#define GPIO171_BUSMON_D25     PIN_CFG(171, ALT_C)
+
+#define GPIO172_GPIO           PIN_CFG(172, GPIO)
+#define GPIO172_MC3_DAT1       PIN_CFG(172, ALT_A)
+#define GPIO172_SPI3_CS1n      PIN_CFG(172, ALT_B)
+#define GPIO172_BUSMON_D26     PIN_CFG(172, ALT_C)
+
+#define GPIO173_GPIO           PIN_CFG(173, GPIO)
+#define GPIO173_MC3_DAT2       PIN_CFG(173, ALT_A)
+#define GPIO173_SPI3_CS2n      PIN_CFG(173, ALT_B)
+#define GPIO173_BUSMON_D27     PIN_CFG(173, ALT_C)
+
+#define GPIO174_GPIO           PIN_CFG(174, GPIO)
+#define GPIO174_MC3_DAT3       PIN_CFG(174, ALT_A)
+#define GPIO174_SPI3_CS0n      PIN_CFG(174, ALT_B)
+#define GPIO174_BUSMON_D28     PIN_CFG(174, ALT_C)
+
+#define GPIO175_GPIO           PIN_CFG(175, GPIO)
+#define GPIO175_MC3_CMD                PIN_CFG(175, ALT_A)
+#define GPIO175_SPI3_TXD       PIN_CFG(175, ALT_B)
+#define GPIO175_BUSMON_D29     PIN_CFG(175, ALT_C)
+
+#define GPIO176_GPIO           PIN_CFG(176, GPIO)
+#define GPIO176_MC3_CLK                PIN_CFG(176, ALT_A)
+#define GPIO176_SPI3_CLK       PIN_CFG(176, ALT_B)
+
+#define GPIO177_GPIO           PIN_CFG(177, GPIO)
+#define GPIO177_U2_RXD         PIN_CFG(177, ALT_A)
+#define GPIO177_I2C3_SCL       PIN_CFG(177, ALT_B)
+#define GPIO177_BUSMON_D30     PIN_CFG(177, ALT_C)
+
+#define GPIO178_GPIO           PIN_CFG(178, GPIO)
+#define GPIO178_U2_TXD         PIN_CFG(178, ALT_A)
+#define GPIO178_I2C3_SDA       PIN_CFG(178, ALT_B)
+#define GPIO178_BUSMON_D31     PIN_CFG(178, ALT_C)
+
+#define GPIO179_GPIO           PIN_CFG(179, GPIO)
+#define GPIO179_U2_CTSn                PIN_CFG(179, ALT_A)
+#define GPIO179_U3_RXD         PIN_CFG(179, ALT_B)
+#define GPIO179_BUSMON_D32     PIN_CFG(179, ALT_C)
+
+#define GPIO180_GPIO           PIN_CFG(180, GPIO)
+#define GPIO180_U2_RTSn                PIN_CFG(180, ALT_A)
+#define GPIO180_U3_TXD         PIN_CFG(180, ALT_B)
+#define GPIO180_BUSMON_D33     PIN_CFG(180, ALT_C)
+
+#define GPIO185_GPIO           PIN_CFG(185, GPIO)
+#define GPIO185_SPI3_CS2n      PIN_CFG(185, ALT_A)
+#define GPIO185_MC4_DAT0       PIN_CFG(185, ALT_B)
+
+#define GPIO186_GPIO           PIN_CFG(186, GPIO)
+#define GPIO186_SPI3_CS1n      PIN_CFG(186, ALT_A)
+#define GPIO186_MC4_DAT1       PIN_CFG(186, ALT_B)
+
+#define GPIO187_GPIO           PIN_CFG(187, GPIO)
+#define GPIO187_SPI3_CS0n      PIN_CFG(187, ALT_A)
+#define GPIO187_MC4_DAT2       PIN_CFG(187, ALT_B)
+
+#define GPIO188_GPIO           PIN_CFG(188, GPIO)
+#define GPIO188_SPI3_RXD       PIN_CFG(188, ALT_A)
+#define GPIO188_MC4_DAT3       PIN_CFG(188, ALT_B)
+
+#define GPIO189_GPIO           PIN_CFG(189, GPIO)
+#define GPIO189_SPI3_TXD       PIN_CFG(189, ALT_A)
+#define GPIO189_MC4_CMD                PIN_CFG(189, ALT_B)
+
+#define GPIO190_GPIO           PIN_CFG(190, GPIO)
+#define GPIO190_SPI3_CLK       PIN_CFG(190, ALT_A)
+#define GPIO190_MC4_CLK                PIN_CFG(190, ALT_B)
+
+#define GPIO191_GPIO           PIN_CFG(191, GPIO)
+#define GPIO191_MC1_DAT0       PIN_CFG(191, ALT_A)
+#define GPIO191_MC4_DAT4       PIN_CFG(191, ALT_B)
+#define GPIO191_STMAPE_DAT0    PIN_CFG(191, ALT_C)
+
+#define GPIO192_GPIO           PIN_CFG(192, GPIO)
+#define GPIO192_MC1_DAT1       PIN_CFG(192, ALT_A)
+#define GPIO192_MC4_DAT5       PIN_CFG(192, ALT_B)
+#define GPIO192_STMAPE_DAT1    PIN_CFG(192, ALT_C)
+
+#define GPIO193_GPIO           PIN_CFG(193, GPIO)
+#define GPIO193_MC1_DAT2       PIN_CFG(193, ALT_A)
+#define GPIO193_MC4_DAT6       PIN_CFG(193, ALT_B)
+#define GPIO193_STMAPE_DAT2    PIN_CFG(193, ALT_C)
+
+#define GPIO194_GPIO           PIN_CFG(194, GPIO)
+#define GPIO194_MC1_DAT3       PIN_CFG(194, ALT_A)
+#define GPIO194_MC4_DAT7       PIN_CFG(194, ALT_B)
+#define GPIO194_STMAPE_DAT3    PIN_CFG(194, ALT_C)
+
+#define GPIO195_GPIO           PIN_CFG(195, GPIO)
+#define GPIO195_MC1_CLK                PIN_CFG(195, ALT_A)
+#define GPIO195_STMAPE_CLK     PIN_CFG(195, ALT_B)
+#define GPIO195_BUSMON_CLK     PIN_CFG(195, ALT_C)
+
+#define GPIO196_GPIO           PIN_CFG(196, GPIO)
+#define GPIO196_MC1_CMD                PIN_CFG(196, ALT_A)
+#define GPIO196_U0_RXD         PIN_CFG(196, ALT_B)
+#define GPIO196_BUSMON_D38     PIN_CFG(196, ALT_C)
+
+#define GPIO197_GPIO           PIN_CFG(197, GPIO)
+#define GPIO197_MC1_CMDDIR     PIN_CFG(197, ALT_A)
+#define GPIO197_BUSMON_D39     PIN_CFG(197, ALT_B)
+
+#define GPIO198_GPIO           PIN_CFG(198, GPIO)
+#define GPIO198_MC1_FBCLK      PIN_CFG(198, ALT_A)
+
+#define GPIO199_GPIO           PIN_CFG(199, GPIO)
+#define GPIO199_MC1_DAT0DIR    PIN_CFG(199, ALT_A)
+#define GPIO199_BUSMON_D40     PIN_CFG(199, ALT_B)
+
+#define GPIO200_GPIO           PIN_CFG(200, GPIO)
+#define GPIO200_U1_TXD         PIN_CFG(200, ALT_A)
+#define GPIO200_ACCU0_RTSn     PIN_CFG(200, ALT_B)
+
+#define GPIO201_GPIO           PIN_CFG(201, GPIO)
+#define GPIO201_U1_RXD         PIN_CFG(201, ALT_A)
+#define GPIO201_ACCU0_CTSn     PIN_CFG(201, ALT_B)
+
+#define GPIO202_GPIO           PIN_CFG(202, GPIO)
+#define GPIO202_U1_CTSn                PIN_CFG(202, ALT_A)
+#define GPIO202_ACCU0_RXD      PIN_CFG(202, ALT_B)
+
+#define GPIO203_GPIO           PIN_CFG(203, GPIO)
+#define GPIO203_U1_RTSn                PIN_CFG(203, ALT_A)
+#define GPIO203_ACCU0_TXD      PIN_CFG(203, ALT_B)
+
+#define GPIO204_GPIO           PIN_CFG(204, GPIO)
+#define GPIO204_SPI0_CS2n      PIN_CFG(204, ALT_A)
+#define GPIO204_ACCGPIO_000    PIN_CFG(204, ALT_B)
+#define GPIO204_LCD_VSI1       PIN_CFG(204, ALT_C)
+
+#define GPIO205_GPIO           PIN_CFG(205, GPIO)
+#define GPIO205_SPI0_CS1n      PIN_CFG(205, ALT_A)
+#define GPIO205_ACCGPIO_001    PIN_CFG(205, ALT_B)
+#define GPIO205_LCD_D3         PIN_CFG(205, ALT_C)
+
+#define GPIO206_GPIO           PIN_CFG(206, GPIO)
+#define GPIO206_SPI0_CS0n      PIN_CFG(206, ALT_A)
+#define GPIO206_ACCGPIO_002    PIN_CFG(206, ALT_B)
+#define GPIO206_LCD_D2         PIN_CFG(206, ALT_C)
+
+#define GPIO207_GPIO           PIN_CFG(207, GPIO)
+#define GPIO207_SPI0_RXD       PIN_CFG(207, ALT_A)
+#define GPIO207_ACCGPIO_003    PIN_CFG(207, ALT_B)
+#define GPIO207_LCD_D1         PIN_CFG(207, ALT_C)
+
+#define GPIO208_GPIO           PIN_CFG(208, GPIO)
+#define GPIO208_SPI0_TXD       PIN_CFG(208, ALT_A)
+#define GPIO208_ACCGPIO_004    PIN_CFG(208, ALT_B)
+#define GPIO208_LCD_D0         PIN_CFG(208, ALT_C)
+
+#define GPIO209_GPIO           PIN_CFG(209, GPIO)
+#define GPIO209_SPI0_CLK       PIN_CFG(209, ALT_A)
+#define GPIO209_ACCGPIO_005    PIN_CFG(209, ALT_B)
+#define GPIO209_LCD_CLK                PIN_CFG(209, ALT_C)
+
+#define GPIO210_GPIO           PIN_CFG(210, GPIO)
+#define GPIO210_LCD_VSO                PIN_CFG(210, ALT_A)
+#define GPIO210_PRCMU_PWRCTRL1 PIN_CFG(210, ALT_B)
+
+#define GPIO211_GPIO           PIN_CFG(211, GPIO)
+#define GPIO211_LCD_VSI0       PIN_CFG(211, ALT_A)
+#define GPIO211_PRCMU_PWRCTRL2 PIN_CFG(211, ALT_B)
+
+#define GPIO212_GPIO           PIN_CFG(212, GPIO)
+#define GPIO212_SPI2_CS2n      PIN_CFG(212, ALT_A)
+#define GPIO212_LCD_HSO                PIN_CFG(212, ALT_B)
+
+#define GPIO213_GPIO           PIN_CFG(213, GPIO)
+#define GPIO213_SPI2_CS1n      PIN_CFG(213, ALT_A)
+#define GPIO213_LCD_DE         PIN_CFG(213, ALT_B)
+#define GPIO213_BUSMON_D16     PIN_CFG(213, ALT_C)
+
+#define GPIO214_GPIO           PIN_CFG(214, GPIO)
+#define GPIO214_SPI2_CS0n      PIN_CFG(214, ALT_A)
+#define GPIO214_LCD_D7         PIN_CFG(214, ALT_B)
+#define GPIO214_BUSMON_D17     PIN_CFG(214, ALT_C)
+
+#define GPIO215_GPIO           PIN_CFG(215, GPIO)
+#define GPIO215_SPI2_RXD       PIN_CFG(215, ALT_A)
+#define GPIO215_LCD_D6         PIN_CFG(215, ALT_B)
+#define GPIO215_BUSMON_D18     PIN_CFG(215, ALT_C)
+
+#define GPIO216_GPIO           PIN_CFG(216, GPIO)
+#define GPIO216_SPI2_CLK       PIN_CFG(216, ALT_A)
+#define GPIO216_LCD_D5         PIN_CFG(216, ALT_B)
+
+#define GPIO217_GPIO           PIN_CFG(217, GPIO)
+#define GPIO217_SPI2_TXD       PIN_CFG(217, ALT_A)
+#define GPIO217_LCD_D4         PIN_CFG(217, ALT_B)
+#define GPIO217_BUSMON_D19     PIN_CFG(217, ALT_C)
+
+#define GPIO218_GPIO           PIN_CFG(218, GPIO)
+#define GPIO218_I2C2_SCL       PIN_CFG(218, ALT_A)
+#define GPIO218_LCD_VSO                PIN_CFG(218, ALT_B)
+
+#define GPIO219_GPIO           PIN_CFG(219, GPIO)
+#define GPIO219_I2C2_SDA       PIN_CFG(219, ALT_A)
+#define GPIO219_LCD_D3         PIN_CFG(219, ALT_B)
+
+#define GPIO220_GPIO           PIN_CFG(220, GPIO)
+#define GPIO220_MSP2_TCK       PIN_CFG(220, ALT_A)
+#define GPIO220_LCD_D2         PIN_CFG(220, ALT_B)
+
+#define GPIO221_GPIO           PIN_CFG(221, GPIO)
+#define GPIO221_MSP2_TFS       PIN_CFG(221, ALT_A)
+#define GPIO221_LCD_D1         PIN_CFG(221, ALT_B)
+
+#define GPIO222_GPIO           PIN_CFG(222, GPIO)
+#define GPIO222_MSP2_TXD       PIN_CFG(222, ALT_A)
+#define GPIO222_LCD_D0         PIN_CFG(222, ALT_B)
+
+#define GPIO223_GPIO           PIN_CFG(223, GPIO)
+#define GPIO223_MSP2_RXD       PIN_CFG(223, ALT_A)
+#define GPIO223_LCD_CLK                PIN_CFG(223, ALT_B)
+
+#define GPIO224_GPIO           PIN_CFG(224, GPIO)
+#define GPIO224_PRCMU_PWRCTRL0 PIN_CFG(224, ALT_A)
+#define GPIO224_LCD_VSI1       PIN_CFG(224, ALT_B)
+
+#define GPIO225_GPIO           PIN_CFG(225, GPIO)
+#define GPIO225_PRCMU_PWRCTRL1 PIN_CFG(225, ALT_A)
+#define GPIO225_IRDA_RXD       PIN_CFG(225, ALT_B)
+
+#define GPIO226_GPIO           PIN_CFG(226, GPIO)
+#define GPIO226_PRCMU_PWRCTRL2 PIN_CFG(226, ALT_A)
+#define GPIO226_IRRC_DAT       PIN_CFG(226, ALT_B)
+
+#define GPIO227_GPIO           PIN_CFG(227, GPIO)
+#define GPIO227_IRRC_DAT       PIN_CFG(227, ALT_A)
+#define GPIO227_IRDA_TXD       PIN_CFG(227, ALT_B)
+
+#endif
index 9055d5d..66f8761 100644 (file)
 #define GPIO17_SLIM0_CLK       PIN_CFG(17, ALT_C)
 
 #define GPIO18_GPIO            PIN_CFG(18, GPIO)
-#define GPIO18_MC0_CMDDIR      PIN_CFG(18, ALT_A)
+#define GPIO18_MC0_CMDDIR      PIN_CFG_PULL(18, ALT_A, UP)
 #define GPIO18_U2_RXD          PIN_CFG(18, ALT_B)
 #define GPIO18_MS_IEP          PIN_CFG(18, ALT_C)
 
 #define GPIO19_GPIO            PIN_CFG(19, GPIO)
-#define GPIO19_MC0_DAT0DIR     PIN_CFG(19, ALT_A)
+#define GPIO19_MC0_DAT0DIR     PIN_CFG_PULL(19, ALT_A, UP)
 #define GPIO19_U2_TXD          PIN_CFG(19, ALT_B)
 #define GPIO19_MS_DAT0DIR      PIN_CFG(19, ALT_C)
 
 #define GPIO20_GPIO            PIN_CFG(20, GPIO)
-#define GPIO20_MC0_DAT2DIR     PIN_CFG(20, ALT_A)
+#define GPIO20_MC0_DAT2DIR     PIN_CFG_PULL(20, ALT_A, UP)
 #define GPIO20_UARTMOD_TXD     PIN_CFG(20, ALT_B)
 #define GPIO20_IP_TRIGOUT      PIN_CFG(20, ALT_C)
 
 #define GPIO21_GPIO            PIN_CFG(21, GPIO)
-#define GPIO21_MC0_DAT31DIR    PIN_CFG(21, ALT_A)
+#define GPIO21_MC0_DAT31DIR    PIN_CFG_PULL(21, ALT_A, UP)
 #define GPIO21_MSP0_SCK                PIN_CFG(21, ALT_B)
 #define GPIO21_MS_DAT31DIR     PIN_CFG(21, ALT_C)
 
 #define GPIO22_GPIO            PIN_CFG(22, GPIO)
-#define GPIO22_MC0_FBCLK       PIN_CFG(22, ALT_A)
+#define GPIO22_MC0_FBCLK       PIN_CFG_PULL(22, ALT_A, UP)
 #define GPIO22_UARTMOD_RXD     PIN_CFG(22, ALT_B)
 #define GPIO22_MS_FBCLK                PIN_CFG(22, ALT_C)
 
 #define GPIO23_GPIO            PIN_CFG(23, GPIO)
-#define GPIO23_MC0_CLK         PIN_CFG(23, ALT_A)
+#define GPIO23_MC0_CLK         PIN_CFG_PULL(23, ALT_A, UP)
 #define GPIO23_STMMOD_CLK      PIN_CFG(23, ALT_B)
 #define GPIO23_MS_CLK          PIN_CFG(23, ALT_C)
 
 #define GPIO24_GPIO            PIN_CFG(24, GPIO)
-#define GPIO24_MC0_CMD         PIN_CFG(24, ALT_A)
+#define GPIO24_MC0_CMD         PIN_CFG_PULL(24, ALT_A, UP)
 #define GPIO24_UARTMOD_RXD     PIN_CFG(24, ALT_B)
 #define GPIO24_MS_BS           PIN_CFG(24, ALT_C)
 
 #define GPIO25_GPIO            PIN_CFG(25, GPIO)
-#define GPIO25_MC0_DAT0                PIN_CFG(25, ALT_A)
+#define GPIO25_MC0_DAT0                PIN_CFG_PULL(25, ALT_A, UP)
 #define GPIO25_STMMOD_DAT0     PIN_CFG(25, ALT_B)
 #define GPIO25_MS_DAT0         PIN_CFG(25, ALT_C)
 
 #define GPIO26_GPIO            PIN_CFG(26, GPIO)
-#define GPIO26_MC0_DAT1                PIN_CFG(26, ALT_A)
+#define GPIO26_MC0_DAT1                PIN_CFG_PULL(26, ALT_A, UP)
 #define GPIO26_STMMOD_DAT1     PIN_CFG(26, ALT_B)
 #define GPIO26_MS_DAT1         PIN_CFG(26, ALT_C)
 
 #define GPIO27_GPIO            PIN_CFG(27, GPIO)
-#define GPIO27_MC0_DAT2                PIN_CFG(27, ALT_A)
+#define GPIO27_MC0_DAT2                PIN_CFG_PULL(27, ALT_A, UP)
 #define GPIO27_STMMOD_DAT2     PIN_CFG(27, ALT_B)
 #define GPIO27_MS_DAT2         PIN_CFG(27, ALT_C)
 
 #define GPIO28_GPIO            PIN_CFG(28, GPIO)
-#define GPIO28_MC0_DAT3                PIN_CFG(28, ALT_A)
+#define GPIO28_MC0_DAT3                PIN_CFG_PULL(28, ALT_A, UP)
 #define GPIO28_STMMOD_DAT3     PIN_CFG(28, ALT_B)
 #define GPIO28_MS_DAT3         PIN_CFG(28, ALT_C)
 
 #define GPIO97_MC5_DAT7                PIN_CFG(97, ALT_C)
 
 #define GPIO128_GPIO           PIN_CFG(128, GPIO)
-#define GPIO128_MC2_CLK                PIN_CFG(128, ALT_A)
+#define GPIO128_MC2_CLK                PIN_CFG_PULL(128, ALT_A, UP)
 #define GPIO128_SM_CKO         PIN_CFG(128, ALT_B)
 
 #define GPIO129_GPIO           PIN_CFG(129, GPIO)
-#define GPIO129_MC2_CMD                PIN_CFG(129, ALT_A)
+#define GPIO129_MC2_CMD                PIN_CFG_PULL(129, ALT_A, UP)
 #define GPIO129_SM_WAIT0n      PIN_CFG(129, ALT_B)
 
 #define GPIO130_GPIO           PIN_CFG(130, GPIO)
-#define GPIO130_MC2_FBCLK      PIN_CFG(130, ALT_A)
+#define GPIO130_MC2_FBCLK      PIN_CFG_PULL(130, ALT_A, UP)
 #define GPIO130_SM_FBCLK       PIN_CFG(130, ALT_B)
 #define GPIO130_MC2_RSTN       PIN_CFG(130, ALT_C)
 
 #define GPIO131_GPIO           PIN_CFG(131, GPIO)
-#define GPIO131_MC2_DAT0       PIN_CFG(131, ALT_A)
+#define GPIO131_MC2_DAT0       PIN_CFG_PULL(131, ALT_A, UP)
 #define GPIO131_SM_ADQ8                PIN_CFG(131, ALT_B)
 
 #define GPIO132_GPIO           PIN_CFG(132, GPIO)
-#define GPIO132_MC2_DAT1       PIN_CFG(132, ALT_A)
+#define GPIO132_MC2_DAT1       PIN_CFG_PULL(132, ALT_A, UP)
 #define GPIO132_SM_ADQ9                PIN_CFG(132, ALT_B)
 
 #define GPIO133_GPIO           PIN_CFG(133, GPIO)
-#define GPIO133_MC2_DAT2       PIN_CFG(133, ALT_A)
+#define GPIO133_MC2_DAT2       PIN_CFG_PULL(133, ALT_A, UP)
 #define GPIO133_SM_ADQ10       PIN_CFG(133, ALT_B)
 
 #define GPIO134_GPIO           PIN_CFG(134, GPIO)
-#define GPIO134_MC2_DAT3       PIN_CFG(134, ALT_A)
+#define GPIO134_MC2_DAT3       PIN_CFG_PULL(134, ALT_A, UP)
 #define GPIO134_SM_ADQ11       PIN_CFG(134, ALT_B)
 
 #define GPIO135_GPIO           PIN_CFG(135, GPIO)
-#define GPIO135_MC2_DAT4       PIN_CFG(135, ALT_A)
+#define GPIO135_MC2_DAT4       PIN_CFG_PULL(135, ALT_A, UP)
 #define GPIO135_SM_ADQ12       PIN_CFG(135, ALT_B)
 
 #define GPIO136_GPIO           PIN_CFG(136, GPIO)
-#define GPIO136_MC2_DAT5       PIN_CFG(136, ALT_A)
+#define GPIO136_MC2_DAT5       PIN_CFG_PULL(136, ALT_A, UP)
 #define GPIO136_SM_ADQ13       PIN_CFG(136, ALT_B)
 
 #define GPIO137_GPIO           PIN_CFG(137, GPIO)
-#define GPIO137_MC2_DAT6       PIN_CFG(137, ALT_A)
+#define GPIO137_MC2_DAT6       PIN_CFG_PULL(137, ALT_A, UP)
 #define GPIO137_SM_ADQ14       PIN_CFG(137, ALT_B)
 
 #define GPIO138_GPIO           PIN_CFG(138, GPIO)
-#define GPIO138_MC2_DAT7       PIN_CFG(138, ALT_A)
+#define GPIO138_MC2_DAT7       PIN_CFG_PULL(138, ALT_A, UP)
 #define GPIO138_SM_ADQ15       PIN_CFG(138, ALT_B)
 
 #define GPIO139_GPIO           PIN_CFG(139, GPIO)
 #define GPIO196_MSP2_RXD       PIN_CFG(196, ALT_A)
 
 #define GPIO197_GPIO           PIN_CFG(197, GPIO)
-#define GPIO197_MC4_DAT3       PIN_CFG(197, ALT_A)
+#define GPIO197_MC4_DAT3       PIN_CFG_PULL(197, ALT_A, UP)
 
 #define GPIO198_GPIO           PIN_CFG(198, GPIO)
-#define GPIO198_MC4_DAT2       PIN_CFG(198, ALT_A)
+#define GPIO198_MC4_DAT2       PIN_CFG_PULL(198, ALT_A, UP)
 
 #define GPIO199_GPIO           PIN_CFG(199, GPIO)
-#define GPIO199_MC4_DAT1       PIN_CFG(199, ALT_A)
+#define GPIO199_MC4_DAT1       PIN_CFG_PULL(199, ALT_A, UP)
 
 #define GPIO200_GPIO           PIN_CFG(200, GPIO)
-#define GPIO200_MC4_DAT0       PIN_CFG(200, ALT_A)
+#define GPIO200_MC4_DAT0       PIN_CFG_PULL(200, ALT_A, UP)
 
 #define GPIO201_GPIO           PIN_CFG(201, GPIO)
-#define GPIO201_MC4_CMD                PIN_CFG(201, ALT_A)
+#define GPIO201_MC4_CMD                PIN_CFG_PULL(201, ALT_A, UP)
 
 #define GPIO202_GPIO           PIN_CFG(202, GPIO)
-#define GPIO202_MC4_FBCLK      PIN_CFG(202, ALT_A)
+#define GPIO202_MC4_FBCLK      PIN_CFG_PULL(202, ALT_A, UP)
 #define GPIO202_PWL            PIN_CFG(202, ALT_B)
 #define GPIO202_MC4_RSTN       PIN_CFG(202, ALT_C)
 
 #define GPIO203_GPIO           PIN_CFG(203, GPIO)
-#define GPIO203_MC4_CLK                PIN_CFG(203, ALT_A)
+#define GPIO203_MC4_CLK                PIN_CFG_PULL(203, ALT_A, UP)
 
 #define GPIO204_GPIO           PIN_CFG(204, GPIO)
-#define GPIO204_MC4_DAT7       PIN_CFG(204, ALT_A)
+#define GPIO204_MC4_DAT7       PIN_CFG_PULL(204, ALT_A, UP)
 
 #define GPIO205_GPIO           PIN_CFG(205, GPIO)
-#define GPIO205_MC4_DAT6       PIN_CFG(205, ALT_A)
+#define GPIO205_MC4_DAT6       PIN_CFG_PULL(205, ALT_A, UP)
 
 #define GPIO206_GPIO           PIN_CFG(206, GPIO)
-#define GPIO206_MC4_DAT5       PIN_CFG(206, ALT_A)
+#define GPIO206_MC4_DAT5       PIN_CFG_PULL(206, ALT_A, UP)
 
 #define GPIO207_GPIO           PIN_CFG(207, GPIO)
-#define GPIO207_MC4_DAT4       PIN_CFG(207, ALT_A)
+#define GPIO207_MC4_DAT4       PIN_CFG_PULL(207, ALT_A, UP)
 
 #define GPIO208_GPIO           PIN_CFG(208, GPIO)
 #define GPIO208_MC1_CLK                PIN_CFG(208, ALT_A)
index 438ef16..9e4c678 100644 (file)
@@ -78,6 +78,8 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
        __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
        outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1);
 
+       smp_cross_call(cpumask_of(cpu));
+
        timeout = jiffies + (1 * HZ);
        while (time_before(jiffies, timeout)) {
                if (pen_release == -1)
diff --git a/arch/arm/mach-ux500/prcmu.c b/arch/arm/mach-ux500/prcmu.c
new file mode 100644 (file)
index 0000000..293274d
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) ST Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U8500 PRCMU driver.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+
+#include <mach/hardware.h>
+#include <mach/prcmu-regs.h>
+
+#define PRCMU_TCDM_BASE __io_address(U8500_PRCMU_TCDM_BASE)
+
+#define REQ_MB5 (PRCMU_TCDM_BASE + 0xE44)
+#define ACK_MB5 (PRCMU_TCDM_BASE + 0xDF4)
+
+#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
+#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
+#define REQ_MB5_I2C_REG (REQ_MB5 + 2)
+#define REQ_MB5_I2C_VAL (REQ_MB5 + 3)
+
+#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
+#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
+
+#define I2C_WRITE(slave) ((slave) << 1)
+#define I2C_READ(slave) (((slave) << 1) | BIT(0))
+#define I2C_STOP_EN BIT(3)
+
+enum ack_mb5_status {
+       I2C_WR_OK = 0x01,
+       I2C_RD_OK = 0x02,
+};
+
+#define MBOX_BIT BIT
+#define NUM_MBOX 8
+
+static struct {
+       struct mutex lock;
+       struct completion work;
+       bool failed;
+       struct {
+               u8 status;
+               u8 value;
+       } ack;
+} mb5_transfer;
+
+/**
+ * prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The read out value(s).
+ * @size:      The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if (size != 1)
+               return -EINVAL;
+
+       r = mutex_lock_interruptible(&mb5_transfer.lock);
+       if (r)
+               return r;
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+
+       writeb(I2C_READ(slave), REQ_MB5_I2C_SLAVE_OP);
+       writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
+       writeb(reg, REQ_MB5_I2C_REG);
+
+       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+       if (!wait_for_completion_timeout(&mb5_transfer.work,
+                       msecs_to_jiffies(500))) {
+               pr_err("prcmu: prcmu_abb_read timed out.\n");
+               r = -EIO;
+               goto unlock_and_return;
+       }
+       r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
+       if (!r)
+               *value = mb5_transfer.ack.value;
+
+unlock_and_return:
+       mutex_unlock(&mb5_transfer.lock);
+       return r;
+}
+EXPORT_SYMBOL(prcmu_abb_read);
+
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The value(s) to write.
+ * @size:      The number of registers to write.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if (size != 1)
+               return -EINVAL;
+
+       r = mutex_lock_interruptible(&mb5_transfer.lock);
+       if (r)
+               return r;
+
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+
+       writeb(I2C_WRITE(slave), REQ_MB5_I2C_SLAVE_OP);
+       writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
+       writeb(reg, REQ_MB5_I2C_REG);
+       writeb(*value, REQ_MB5_I2C_VAL);
+
+       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+       if (!wait_for_completion_timeout(&mb5_transfer.work,
+                       msecs_to_jiffies(500))) {
+               pr_err("prcmu: prcmu_abb_write timed out.\n");
+               r = -EIO;
+               goto unlock_and_return;
+       }
+       r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
+
+unlock_and_return:
+       mutex_unlock(&mb5_transfer.lock);
+       return r;
+}
+EXPORT_SYMBOL(prcmu_abb_write);
+
+static void read_mailbox_0(void)
+{
+       writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_1(void)
+{
+       writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_2(void)
+{
+       writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_3(void)
+{
+       writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_4(void)
+{
+       writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_5(void)
+{
+       mb5_transfer.ack.status = readb(ACK_MB5_I2C_STATUS);
+       mb5_transfer.ack.value = readb(ACK_MB5_I2C_VAL);
+       complete(&mb5_transfer.work);
+       writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_6(void)
+{
+       writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_7(void)
+{
+       writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
+}
+
+static void (* const read_mailbox[NUM_MBOX])(void) = {
+       read_mailbox_0,
+       read_mailbox_1,
+       read_mailbox_2,
+       read_mailbox_3,
+       read_mailbox_4,
+       read_mailbox_5,
+       read_mailbox_6,
+       read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+       u32 bits;
+       u8 n;
+
+       bits = (readl(PRCM_ARM_IT1_VAL) & (MBOX_BIT(NUM_MBOX) - 1));
+       if (unlikely(!bits))
+               return IRQ_NONE;
+
+       for (n = 0; bits; n++) {
+               if (bits & MBOX_BIT(n)) {
+                       bits -= MBOX_BIT(n);
+                       read_mailbox[n]();
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+static int __init prcmu_init(void)
+{
+       mutex_init(&mb5_transfer.lock);
+       init_completion(&mb5_transfer.work);
+
+       /* Clean up the mailbox interrupts after pre-kernel code. */
+       writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR);
+
+       return request_irq(IRQ_PRCMU, prcmu_irq_handler, 0, "prcmu", NULL);
+}
+
+arch_initcall(prcmu_init);
diff --git a/arch/arm/mach-ux500/ste-dma40-db5500.h b/arch/arm/mach-ux500/ste-dma40-db5500.h
new file mode 100644 (file)
index 0000000..cb2110c
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * DB5500-SoC-specific configuration for DMA40
+ */
+
+#ifndef STE_DMA40_DB5500_H
+#define STE_DMA40_DB5500_H
+
+#define DB5500_DMA_NR_DEV 64
+
+enum dma_src_dev_type {
+       DB5500_DMA_DEV0_SPI0_RX = 0,
+       DB5500_DMA_DEV1_SPI1_RX = 1,
+       DB5500_DMA_DEV2_SPI2_RX = 2,
+       DB5500_DMA_DEV3_SPI3_RX = 3,
+       DB5500_DMA_DEV4_USB_OTG_IEP_1_9 = 4,
+       DB5500_DMA_DEV5_USB_OTG_IEP_2_10 = 5,
+       DB5500_DMA_DEV6_USB_OTG_IEP_3_11 = 6,
+       DB5500_DMA_DEV7_IRDA_RFS = 7,
+       DB5500_DMA_DEV8_IRDA_FIFO_RX = 8,
+       DB5500_DMA_DEV9_MSP0_RX = 9,
+       DB5500_DMA_DEV10_MSP1_RX = 10,
+       DB5500_DMA_DEV11_MSP2_RX = 11,
+       DB5500_DMA_DEV12_UART0_RX = 12,
+       DB5500_DMA_DEV13_UART1_RX = 13,
+       DB5500_DMA_DEV14_UART2_RX = 14,
+       DB5500_DMA_DEV15_UART3_RX = 15,
+       DB5500_DMA_DEV16_USB_OTG_IEP_8 = 16,
+       DB5500_DMA_DEV17_USB_OTG_IEP_1_9 = 17,
+       DB5500_DMA_DEV18_USB_OTG_IEP_2_10 = 18,
+       DB5500_DMA_DEV19_USB_OTG_IEP_3_11 = 19,
+       DB5500_DMA_DEV20_USB_OTG_IEP_4_12 = 20,
+       DB5500_DMA_DEV21_USB_OTG_IEP_5_13 = 21,
+       DB5500_DMA_DEV22_USB_OTG_IEP_6_14 = 22,
+       DB5500_DMA_DEV23_USB_OTG_IEP_7_15 = 23,
+       DB5500_DMA_DEV24_SDMMC0_RX = 24,
+       DB5500_DMA_DEV25_SDMMC1_RX = 25,
+       DB5500_DMA_DEV26_SDMMC2_RX = 26,
+       DB5500_DMA_DEV27_SDMMC3_RX = 27,
+       DB5500_DMA_DEV28_SDMMC4_RX = 28,
+       /* 29 - 32 not used */
+       DB5500_DMA_DEV33_SDMMC0_RX = 33,
+       DB5500_DMA_DEV34_SDMMC1_RX = 34,
+       DB5500_DMA_DEV35_SDMMC2_RX = 35,
+       DB5500_DMA_DEV36_SDMMC3_RX = 36,
+       DB5500_DMA_DEV37_SDMMC4_RX = 37,
+       DB5500_DMA_DEV38_USB_OTG_IEP_8 = 38,
+       DB5500_DMA_DEV39_USB_OTG_IEP_1_9 = 39,
+       DB5500_DMA_DEV40_USB_OTG_IEP_2_10 = 40,
+       DB5500_DMA_DEV41_USB_OTG_IEP_3_11 = 41,
+       DB5500_DMA_DEV42_USB_OTG_IEP_4_12 = 42,
+       DB5500_DMA_DEV43_USB_OTG_IEP_5_13 = 43,
+       DB5500_DMA_DEV44_USB_OTG_IEP_6_14 = 44,
+       DB5500_DMA_DEV45_USB_OTG_IEP_7_15 = 45,
+       /* 46 not used */
+       DB5500_DMA_DEV47_MCDE_RX = 47,
+       DB5500_DMA_DEV48_CRYPTO1_RX = 48,
+       /* 49, 50 not used */
+       DB5500_DMA_DEV49_I2C1_RX = 51,
+       DB5500_DMA_DEV50_I2C3_RX = 52,
+       DB5500_DMA_DEV51_I2C2_RX = 53,
+       /* 54 - 60 not used */
+       DB5500_DMA_DEV61_CRYPTO0_RX = 61,
+       /* 62, 63 not used */
+};
+
+enum dma_dest_dev_type {
+       DB5500_DMA_DEV0_SPI0_TX = 0,
+       DB5500_DMA_DEV1_SPI1_TX = 1,
+       DB5500_DMA_DEV2_SPI2_TX = 2,
+       DB5500_DMA_DEV3_SPI3_TX = 3,
+       DB5500_DMA_DEV4_USB_OTG_OEP_1_9 = 4,
+       DB5500_DMA_DEV5_USB_OTG_OEP_2_10 = 5,
+       DB5500_DMA_DEV6_USB_OTG_OEP_3_11 = 6,
+       DB5500_DMA_DEV7_IRRC_TX = 7,
+       DB5500_DMA_DEV8_IRDA_FIFO_TX = 8,
+       DB5500_DMA_DEV9_MSP0_TX = 9,
+       DB5500_DMA_DEV10_MSP1_TX = 10,
+       DB5500_DMA_DEV11_MSP2_TX = 11,
+       DB5500_DMA_DEV12_UART0_TX = 12,
+       DB5500_DMA_DEV13_UART1_TX = 13,
+       DB5500_DMA_DEV14_UART2_TX = 14,
+       DB5500_DMA_DEV15_UART3_TX = 15,
+       DB5500_DMA_DEV16_USB_OTG_OEP_8 = 16,
+       DB5500_DMA_DEV17_USB_OTG_OEP_1_9 = 17,
+       DB5500_DMA_DEV18_USB_OTG_OEP_2_10 = 18,
+       DB5500_DMA_DEV19_USB_OTG_OEP_3_11 = 19,
+       DB5500_DMA_DEV20_USB_OTG_OEP_4_12 = 20,
+       DB5500_DMA_DEV21_USB_OTG_OEP_5_13 = 21,
+       DB5500_DMA_DEV22_USB_OTG_OEP_6_14 = 22,
+       DB5500_DMA_DEV23_USB_OTG_OEP_7_15 = 23,
+       DB5500_DMA_DEV24_SDMMC0_TX = 24,
+       DB5500_DMA_DEV25_SDMMC1_TX = 25,
+       DB5500_DMA_DEV26_SDMMC2_TX = 26,
+       DB5500_DMA_DEV27_SDMMC3_TX = 27,
+       DB5500_DMA_DEV28_SDMMC4_TX = 28,
+       /* 29 - 31 not used */
+       DB5500_DMA_DEV32_FSMC_TX = 32,
+       DB5500_DMA_DEV33_SDMMC0_TX = 33,
+       DB5500_DMA_DEV34_SDMMC1_TX = 34,
+       DB5500_DMA_DEV35_SDMMC2_TX = 35,
+       DB5500_DMA_DEV36_SDMMC3_TX = 36,
+       DB5500_DMA_DEV37_SDMMC4_TX = 37,
+       DB5500_DMA_DEV38_USB_OTG_OEP_8 = 38,
+       DB5500_DMA_DEV39_USB_OTG_OEP_1_9 = 39,
+       DB5500_DMA_DEV40_USB_OTG_OEP_2_10 = 40,
+       DB5500_DMA_DEV41_USB_OTG_OEP_3_11 = 41,
+       DB5500_DMA_DEV42_USB_OTG_OEP_4_12 = 42,
+       DB5500_DMA_DEV43_USB_OTG_OEP_5_13 = 43,
+       DB5500_DMA_DEV44_USB_OTG_OEP_6_14 = 44,
+       DB5500_DMA_DEV45_USB_OTG_OEP_7_15 = 45,
+       /* 46 not used */
+       DB5500_DMA_DEV47_STM_TX = 47,
+       DB5500_DMA_DEV48_CRYPTO1_TX = 48,
+       DB5500_DMA_DEV49_CRYPTO1_TX_HASH1_TX = 49,
+       DB5500_DMA_DEV50_HASH1_TX = 50,
+       DB5500_DMA_DEV51_I2C1_TX = 51,
+       DB5500_DMA_DEV52_I2C3_TX = 52,
+       DB5500_DMA_DEV53_I2C2_TX = 53,
+       /* 54, 55 not used */
+       DB5500_DMA_MEMCPY_TX_1 = 56,
+       DB5500_DMA_MEMCPY_TX_2 = 57,
+       DB5500_DMA_MEMCPY_TX_3 = 58,
+       DB5500_DMA_MEMCPY_TX_4 = 59,
+       DB5500_DMA_MEMCPY_TX_5 = 60,
+       DB5500_DMA_DEV61_CRYPTO0_TX = 61,
+       DB5500_DMA_DEV62_CRYPTO0_TX_HASH0_TX = 62,
+       DB5500_DMA_DEV63_HASH0_TX = 63,
+};
+
+#endif
index 9d9d379..a616419 100644 (file)
 #ifndef STE_DMA40_DB8500_H
 #define STE_DMA40_DB8500_H
 
-#define STEDMA40_NR_DEV 64
+#define DB8500_DMA_NR_DEV 64
 
 enum dma_src_dev_type {
-       STEDMA40_DEV_SPI0_RX = 0,
-       STEDMA40_DEV_SD_MMC0_RX = 1,
-       STEDMA40_DEV_SD_MMC1_RX = 2,
-       STEDMA40_DEV_SD_MMC2_RX = 3,
-       STEDMA40_DEV_I2C1_RX = 4,
-       STEDMA40_DEV_I2C3_RX = 5,
-       STEDMA40_DEV_I2C2_RX = 6,
-       STEDMA40_DEV_I2C4_RX = 7, /* Only on V1 */
-       STEDMA40_DEV_SSP0_RX = 8,
-       STEDMA40_DEV_SSP1_RX = 9,
-       STEDMA40_DEV_MCDE_RX = 10,
-       STEDMA40_DEV_UART2_RX = 11,
-       STEDMA40_DEV_UART1_RX = 12,
-       STEDMA40_DEV_UART0_RX = 13,
-       STEDMA40_DEV_MSP2_RX = 14,
-       STEDMA40_DEV_I2C0_RX = 15,
-       STEDMA40_DEV_USB_OTG_IEP_8 = 16,
-       STEDMA40_DEV_USB_OTG_IEP_1_9 = 17,
-       STEDMA40_DEV_USB_OTG_IEP_2_10 = 18,
-       STEDMA40_DEV_USB_OTG_IEP_3_11 = 19,
-       STEDMA40_DEV_SLIM0_CH0_RX_HSI_RX_CH0 = 20,
-       STEDMA40_DEV_SLIM0_CH1_RX_HSI_RX_CH1 = 21,
-       STEDMA40_DEV_SLIM0_CH2_RX_HSI_RX_CH2 = 22,
-       STEDMA40_DEV_SLIM0_CH3_RX_HSI_RX_CH3 = 23,
-       STEDMA40_DEV_SRC_SXA0_RX_TX = 24,
-       STEDMA40_DEV_SRC_SXA1_RX_TX = 25,
-       STEDMA40_DEV_SRC_SXA2_RX_TX = 26,
-       STEDMA40_DEV_SRC_SXA3_RX_TX = 27,
-       STEDMA40_DEV_SD_MM2_RX = 28,
-       STEDMA40_DEV_SD_MM0_RX = 29,
-       STEDMA40_DEV_MSP1_RX = 30,
-       /*
-        * This channel is either SlimBus or MSP,
-        * never both at the same time.
-        */
-       STEDMA40_SLIM0_CH0_RX = 31,
-       STEDMA40_DEV_MSP0_RX = 31,
-       STEDMA40_DEV_SD_MM1_RX = 32,
-       STEDMA40_DEV_SPI2_RX = 33,
-       STEDMA40_DEV_I2C3_RX2 = 34,
-       STEDMA40_DEV_SPI1_RX = 35,
-       STEDMA40_DEV_USB_OTG_IEP_4_12 = 36,
-       STEDMA40_DEV_USB_OTG_IEP_5_13 = 37,
-       STEDMA40_DEV_USB_OTG_IEP_6_14 = 38,
-       STEDMA40_DEV_USB_OTG_IEP_7_15 = 39,
-       STEDMA40_DEV_SPI3_RX = 40,
-       STEDMA40_DEV_SD_MM3_RX = 41,
-       STEDMA40_DEV_SD_MM4_RX = 42,
-       STEDMA40_DEV_SD_MM5_RX = 43,
-       STEDMA40_DEV_SRC_SXA4_RX_TX = 44,
-       STEDMA40_DEV_SRC_SXA5_RX_TX = 45,
-       STEDMA40_DEV_SRC_SXA6_RX_TX = 46,
-       STEDMA40_DEV_SRC_SXA7_RX_TX = 47,
-       STEDMA40_DEV_CAC1_RX = 48,
-       /* RX channels 49 and 50 are unused */
-       STEDMA40_DEV_MSHC_RX = 51,
-       STEDMA40_DEV_SLIM1_CH0_RX_HSI_RX_CH4 = 52,
-       STEDMA40_DEV_SLIM1_CH1_RX_HSI_RX_CH5 = 53,
-       STEDMA40_DEV_SLIM1_CH2_RX_HSI_RX_CH6 = 54,
-       STEDMA40_DEV_SLIM1_CH3_RX_HSI_RX_CH7 = 55,
-       /* RX channels 56 thru 60 are unused */
-       STEDMA40_DEV_CAC0_RX = 61,
-       /* RX channels 62 and 63 are unused */
+       DB8500_DMA_DEV0_SPI0_RX = 0,
+       DB8500_DMA_DEV1_SD_MMC0_RX = 1,
+       DB8500_DMA_DEV2_SD_MMC1_RX = 2,
+       DB8500_DMA_DEV3_SD_MMC2_RX = 3,
+       DB8500_DMA_DEV4_I2C1_RX = 4,
+       DB8500_DMA_DEV5_I2C3_RX = 5,
+       DB8500_DMA_DEV6_I2C2_RX = 6,
+       DB8500_DMA_DEV7_I2C4_RX = 7, /* Only on V1 and later */
+       DB8500_DMA_DEV8_SSP0_RX = 8,
+       DB8500_DMA_DEV9_SSP1_RX = 9,
+       DB8500_DMA_DEV10_MCDE_RX = 10,
+       DB8500_DMA_DEV11_UART2_RX = 11,
+       DB8500_DMA_DEV12_UART1_RX = 12,
+       DB8500_DMA_DEV13_UART0_RX = 13,
+       DB8500_DMA_DEV14_MSP2_RX = 14,
+       DB8500_DMA_DEV15_I2C0_RX = 15,
+       DB8500_DMA_DEV16_USB_OTG_IEP_7_15 = 16,
+       DB8500_DMA_DEV17_USB_OTG_IEP_6_14 = 17,
+       DB8500_DMA_DEV18_USB_OTG_IEP_5_13 = 18,
+       DB8500_DMA_DEV19_USB_OTG_IEP_4_12 = 19,
+       DB8500_DMA_DEV20_SLIM0_CH0_RX_HSI_RX_CH0 = 20,
+       DB8500_DMA_DEV21_SLIM0_CH1_RX_HSI_RX_CH1 = 21,
+       DB8500_DMA_DEV22_SLIM0_CH2_RX_HSI_RX_CH2 = 22,
+       DB8500_DMA_DEV23_SLIM0_CH3_RX_HSI_RX_CH3 = 23,
+       DB8500_DMA_DEV24_SRC_SXA0_RX_TX = 24,
+       DB8500_DMA_DEV25_SRC_SXA1_RX_TX = 25,
+       DB8500_DMA_DEV26_SRC_SXA2_RX_TX = 26,
+       DB8500_DMA_DEV27_SRC_SXA3_RX_TX = 27,
+       DB8500_DMA_DEV28_SD_MM2_RX = 28,
+       DB8500_DMA_DEV29_SD_MM0_RX = 29,
+       DB8500_DMA_DEV30_MSP1_RX = 30,
+       /* On DB8500v2, MSP3 RX replaces MSP1 RX */
+       DB8500_DMA_DEV30_MSP3_RX = 30,
+       DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX = 31,
+       DB8500_DMA_DEV32_SD_MM1_RX = 32,
+       DB8500_DMA_DEV33_SPI2_RX = 33,
+       DB8500_DMA_DEV34_I2C3_RX2 = 34,
+       DB8500_DMA_DEV35_SPI1_RX = 35,
+       DB8500_DMA_DEV36_USB_OTG_IEP_3_11 = 36,
+       DB8500_DMA_DEV37_USB_OTG_IEP_2_10 = 37,
+       DB8500_DMA_DEV38_USB_OTG_IEP_1_9 = 38,
+       DB8500_DMA_DEV39_USB_OTG_IEP_8 = 39,
+       DB8500_DMA_DEV40_SPI3_RX = 40,
+       DB8500_DMA_DEV41_SD_MM3_RX = 41,
+       DB8500_DMA_DEV42_SD_MM4_RX = 42,
+       DB8500_DMA_DEV43_SD_MM5_RX = 43,
+       DB8500_DMA_DEV44_SRC_SXA4_RX_TX = 44,
+       DB8500_DMA_DEV45_SRC_SXA5_RX_TX = 45,
+       DB8500_DMA_DEV46_SLIM0_CH8_RX_SRC_SXA6_RX_TX = 46,
+       DB8500_DMA_DEV47_SLIM0_CH9_RX_SRC_SXA7_RX_TX = 47,
+       DB8500_DMA_DEV48_CAC1_RX = 48,
+       /* 49, 50 and 51 are not used */
+       DB8500_DMA_DEV52_SLIM0_CH4_RX_HSI_RX_CH4 = 52,
+       DB8500_DMA_DEV53_SLIM0_CH5_RX_HSI_RX_CH5 = 53,
+       DB8500_DMA_DEV54_SLIM0_CH6_RX_HSI_RX_CH6 = 54,
+       DB8500_DMA_DEV55_SLIM0_CH7_RX_HSI_RX_CH7 = 55,
+       /* 56, 57, 58, 59 and 60 are not used */
+       DB8500_DMA_DEV61_CAC0_RX = 61,
+       /* 62 and 63 are not used */
 };
 
 enum dma_dest_dev_type {
-       STEDMA40_DEV_SPI0_TX = 0,
-       STEDMA40_DEV_SD_MMC0_TX = 1,
-       STEDMA40_DEV_SD_MMC1_TX = 2,
-       STEDMA40_DEV_SD_MMC2_TX = 3,
-       STEDMA40_DEV_I2C1_TX = 4,
-       STEDMA40_DEV_I2C3_TX = 5,
-       STEDMA40_DEV_I2C2_TX = 6,
-       STEDMA50_DEV_I2C4_TX = 7, /* Only on V1 */
-       STEDMA40_DEV_SSP0_TX = 8,
-       STEDMA40_DEV_SSP1_TX = 9,
-       /* TX channel 10 is unused */
-       STEDMA40_DEV_UART2_TX = 11,
-       STEDMA40_DEV_UART1_TX = 12,
-       STEDMA40_DEV_UART0_TX= 13,
-       STEDMA40_DEV_MSP2_TX = 14,
-       STEDMA40_DEV_I2C0_TX = 15,
-       STEDMA40_DEV_USB_OTG_OEP_8 = 16,
-       STEDMA40_DEV_USB_OTG_OEP_1_9 = 17,
-       STEDMA40_DEV_USB_OTG_OEP_2_10= 18,
-       STEDMA40_DEV_USB_OTG_OEP_3_11 = 19,
-       STEDMA40_DEV_SLIM0_CH0_TX_HSI_TX_CH0 = 20,
-       STEDMA40_DEV_SLIM0_CH1_TX_HSI_TX_CH1 = 21,
-       STEDMA40_DEV_SLIM0_CH2_TX_HSI_TX_CH2 = 22,
-       STEDMA40_DEV_SLIM0_CH3_TX_HSI_TX_CH3 = 23,
-       STEDMA40_DEV_DST_SXA0_RX_TX = 24,
-       STEDMA40_DEV_DST_SXA1_RX_TX = 25,
-       STEDMA40_DEV_DST_SXA2_RX_TX = 26,
-       STEDMA40_DEV_DST_SXA3_RX_TX = 27,
-       STEDMA40_DEV_SD_MM2_TX = 28,
-       STEDMA40_DEV_SD_MM0_TX = 29,
-       STEDMA40_DEV_MSP1_TX = 30,
-       /*
-        * This channel is either SlimBus or MSP,
-        * never both at the same time.
-        */
-       STEDMA40_SLIM0_CH0_TX = 31,
-       STEDMA40_DEV_MSP0_TX = 31,
-       STEDMA40_DEV_SD_MM1_TX = 32,
-       STEDMA40_DEV_SPI2_TX = 33,
-       /* Secondary I2C3 channel */
-       STEDMA40_DEV_I2C3_TX2 = 34,
-       STEDMA40_DEV_SPI1_TX = 35,
-       STEDMA40_DEV_USB_OTG_OEP_4_12 = 36,
-       STEDMA40_DEV_USB_OTG_OEP_5_13 = 37,
-       STEDMA40_DEV_USB_OTG_OEP_6_14 = 38,
-       STEDMA40_DEV_USB_OTG_OEP_7_15 = 39,
-       STEDMA40_DEV_SPI3_TX = 40,
-       STEDMA40_DEV_SD_MM3_TX = 41,
-       STEDMA40_DEV_SD_MM4_TX = 42,
-       STEDMA40_DEV_SD_MM5_TX = 43,
-       STEDMA40_DEV_DST_SXA4_RX_TX = 44,
-       STEDMA40_DEV_DST_SXA5_RX_TX = 45,
-       STEDMA40_DEV_DST_SXA6_RX_TX = 46,
-       STEDMA40_DEV_DST_SXA7_RX_TX = 47,
-       STEDMA40_DEV_CAC1_TX = 48,
-       STEDMA40_DEV_CAC1_TX_HAC1_TX = 49,
-       STEDMA40_DEV_HAC1_TX = 50,
-       STEDMA40_MEMCPY_TX_0 = 51,
-       STEDMA40_DEV_SLIM1_CH0_TX_HSI_TX_CH4 = 52,
-       STEDMA40_DEV_SLIM1_CH1_TX_HSI_TX_CH5 = 53,
-       STEDMA40_DEV_SLIM1_CH2_TX_HSI_TX_CH6 = 54,
-       STEDMA40_DEV_SLIM1_CH3_TX_HSI_TX_CH7 = 55,
-       STEDMA40_MEMCPY_TX_1 = 56,
-       STEDMA40_MEMCPY_TX_2 = 57,
-       STEDMA40_MEMCPY_TX_3 = 58,
-       STEDMA40_MEMCPY_TX_4 = 59,
-       STEDMA40_MEMCPY_TX_5 = 60,
-       STEDMA40_DEV_CAC0_TX = 61,
-       STEDMA40_DEV_CAC0_TX_HAC0_TX = 62,
-       STEDMA40_DEV_HAC0_TX = 63,
+       DB8500_DMA_DEV0_SPI0_TX = 0,
+       DB8500_DMA_DEV1_SD_MMC0_TX = 1,
+       DB8500_DMA_DEV2_SD_MMC1_TX = 2,
+       DB8500_DMA_DEV3_SD_MMC2_TX = 3,
+       DB8500_DMA_DEV4_I2C1_TX = 4,
+       DB8500_DMA_DEV5_I2C3_TX = 5,
+       DB8500_DMA_DEV6_I2C2_TX = 6,
+       DB8500_DMA_DEV7_I2C4_TX = 7, /* Only on V1 and later */
+       DB8500_DMA_DEV8_SSP0_TX = 8,
+       DB8500_DMA_DEV9_SSP1_TX = 9,
+       /* 10 is not used*/
+       DB8500_DMA_DEV11_UART2_TX = 11,
+       DB8500_DMA_DEV12_UART1_TX = 12,
+       DB8500_DMA_DEV13_UART0_TX = 13,
+       DB8500_DMA_DEV14_MSP2_TX = 14,
+       DB8500_DMA_DEV15_I2C0_TX = 15,
+       DB8500_DMA_DEV16_USB_OTG_OEP_7_15 = 16,
+       DB8500_DMA_DEV17_USB_OTG_OEP_6_14 = 17,
+       DB8500_DMA_DEV18_USB_OTG_OEP_5_13 = 18,
+       DB8500_DMA_DEV19_USB_OTG_OEP_4_12 = 19,
+       DB8500_DMA_DEV20_SLIM0_CH0_TX_HSI_TX_CH0 = 20,
+       DB8500_DMA_DEV21_SLIM0_CH1_TX_HSI_TX_CH1 = 21,
+       DB8500_DMA_DEV22_SLIM0_CH2_TX_HSI_TX_CH2 = 22,
+       DB8500_DMA_DEV23_SLIM0_CH3_TX_HSI_TX_CH3 = 23,
+       DB8500_DMA_DEV24_DST_SXA0_RX_TX = 24,
+       DB8500_DMA_DEV25_DST_SXA1_RX_TX = 25,
+       DB8500_DMA_DEV26_DST_SXA2_RX_TX = 26,
+       DB8500_DMA_DEV27_DST_SXA3_RX_TX = 27,
+       DB8500_DMA_DEV28_SD_MM2_TX = 28,
+       DB8500_DMA_DEV29_SD_MM0_TX = 29,
+       DB8500_DMA_DEV30_MSP1_TX = 30,
+       DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX = 31,
+       DB8500_DMA_DEV32_SD_MM1_TX = 32,
+       DB8500_DMA_DEV33_SPI2_TX = 33,
+       DB8500_DMA_DEV34_I2C3_TX2 = 34,
+       DB8500_DMA_DEV35_SPI1_TX = 35,
+       DB8500_DMA_DEV36_USB_OTG_OEP_3_11 = 36,
+       DB8500_DMA_DEV37_USB_OTG_OEP_2_10 = 37,
+       DB8500_DMA_DEV38_USB_OTG_OEP_1_9 = 38,
+       DB8500_DMA_DEV39_USB_OTG_OEP_8 = 39,
+       DB8500_DMA_DEV40_SPI3_TX = 40,
+       DB8500_DMA_DEV41_SD_MM3_TX = 41,
+       DB8500_DMA_DEV42_SD_MM4_TX = 42,
+       DB8500_DMA_DEV43_SD_MM5_TX = 43,
+       DB8500_DMA_DEV44_DST_SXA4_RX_TX = 44,
+       DB8500_DMA_DEV45_DST_SXA5_RX_TX = 45,
+       DB8500_DMA_DEV46_SLIM0_CH8_TX_DST_SXA6_RX_TX = 46,
+       DB8500_DMA_DEV47_SLIM0_CH9_TX_DST_SXA7_RX_TX = 47,
+       DB8500_DMA_DEV48_CAC1_TX  = 48,
+       DB8500_DMA_DEV49_CAC1_TX_HAC1_TX = 49,
+       DB8500_DMA_DEV50_HAC1_TX = 50,
+       DB8500_DMA_MEMCPY_TX_0 = 51,
+       DB8500_DMA_DEV52_SLIM1_CH4_TX_HSI_TX_CH4 = 52,
+       DB8500_DMA_DEV53_SLIM1_CH5_TX_HSI_TX_CH5 = 53,
+       DB8500_DMA_DEV54_SLIM1_CH6_TX_HSI_TX_CH6 = 54,
+       DB8500_DMA_DEV55_SLIM1_CH7_TX_HSI_TX_CH7 = 55,
+       DB8500_DMA_MEMCPY_TX_1 = 56,
+       DB8500_DMA_MEMCPY_TX_2 = 57,
+       DB8500_DMA_MEMCPY_TX_3 = 58,
+       DB8500_DMA_MEMCPY_TX_4 = 59,
+       DB8500_DMA_MEMCPY_TX_5 = 60,
+       DB8500_DMA_DEV61_CAC0_TX = 61,
+       DB8500_DMA_DEV62_CAC0_TX_HAC0_TX = 62,
+       DB8500_DMA_DEV63_HAC0_TX = 63,
 };
 
 #endif
index 598c51a..b806151 100644 (file)
@@ -73,7 +73,7 @@ void v4_mc_copy_user_highpage(struct page *to, struct page *from,
 {
        void *kto = kmap_atomic(to, KM_USER1);
 
-       if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+       if (!test_and_set_bit(PG_dcache_clean, &from->flags))
                __flush_dcache_page(page_mapping(from), from);
 
        spin_lock(&minicache_lock);
index f55fa10..bdba6c6 100644 (file)
@@ -79,7 +79,7 @@ static void v6_copy_user_highpage_aliasing(struct page *to,
        unsigned int offset = CACHE_COLOUR(vaddr);
        unsigned long kfrom, kto;
 
-       if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+       if (!test_and_set_bit(PG_dcache_clean, &from->flags))
                __flush_dcache_page(page_mapping(from), from);
 
        /* FIXME: not highmem safe */
index 9920c0a..649bbcd 100644 (file)
@@ -95,7 +95,7 @@ void xscale_mc_copy_user_highpage(struct page *to, struct page *from,
 {
        void *kto = kmap_atomic(to, KM_USER1);
 
-       if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+       if (!test_and_set_bit(PG_dcache_clean, &from->flags))
                __flush_dcache_page(page_mapping(from), from);
 
        spin_lock(&minicache_lock);
index 4bc43e5..e4dd064 100644 (file)
@@ -523,6 +523,12 @@ void ___dma_page_dev_to_cpu(struct page *page, unsigned long off,
                outer_inv_range(paddr, paddr + size);
 
        dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
+
+       /*
+        * Mark the D-cache clean for this page to avoid extra flushing.
+        */
+       if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
+               set_bit(PG_dcache_clean, &page->flags);
 }
 EXPORT_SYMBOL(___dma_page_dev_to_cpu);
 
index 9b906de..8440d95 100644 (file)
@@ -28,6 +28,7 @@
 
 static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE;
 
+#if __LINUX_ARM_ARCH__ < 6
 /*
  * We take the easy way out of this problem - we make the
  * PTE uncacheable.  However, we leave the write buffer on.
@@ -141,7 +142,7 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma,
  * a page table, or changing an existing PTE.  Basically, there are two
  * things that we need to take care of:
  *
- *  1. If PG_dcache_dirty is set for the page, we need to ensure
+ *  1. If PG_dcache_clean is not set for the page, we need to ensure
  *     that any cache entries for the kernels virtual memory
  *     range are written back to the page.
  *  2. If we have multiple shared mappings of the same space in
@@ -168,10 +169,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
                return;
 
        mapping = page_mapping(page);
-#ifndef CONFIG_SMP
-       if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
+       if (!test_and_set_bit(PG_dcache_clean, &page->flags))
                __flush_dcache_page(mapping, page);
-#endif
        if (mapping) {
                if (cache_is_vivt())
                        make_coherent(mapping, vma, addr, ptep, pfn);
@@ -179,6 +178,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
                        __flush_icache_all();
        }
 }
+#endif /* __LINUX_ARM_ARCH__ < 6 */
 
 /*
  * Check whether the write buffer has physical address aliasing
index 23b0b03..1e21e12 100644 (file)
@@ -581,6 +581,19 @@ static struct fsr_info ifsr_info[] = {
        { do_bad,               SIGBUS,  0,             "unknown 31"                       },
 };
 
+void __init
+hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
+                int sig, int code, const char *name)
+{
+       if (nr < 0 || nr >= ARRAY_SIZE(ifsr_info))
+               BUG();
+
+       ifsr_info[nr].fn   = fn;
+       ifsr_info[nr].sig  = sig;
+       ifsr_info[nr].code = code;
+       ifsr_info[nr].name = name;
+}
+
 asmlinkage void __exception
 do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
 {
index c6844cb..391ffae 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/smp_plat.h>
 #include <asm/system.h>
 #include <asm/tlbflush.h>
+#include <asm/smp_plat.h>
 
 #include "mm.h"
 
@@ -39,6 +40,18 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
            : "cc");
 }
 
+static void flush_icache_alias(unsigned long pfn, unsigned long vaddr, unsigned long len)
+{
+       unsigned long colour = CACHE_COLOUR(vaddr);
+       unsigned long offset = vaddr & (PAGE_SIZE - 1);
+       unsigned long to;
+
+       set_pte_ext(TOP_PTE(ALIAS_FLUSH_START) + colour, pfn_pte(pfn, PAGE_KERNEL), 0);
+       to = ALIAS_FLUSH_START + (colour << PAGE_SHIFT) + offset;
+       flush_tlb_kernel_page(to);
+       flush_icache_range(to, to + len);
+}
+
 void flush_cache_mm(struct mm_struct *mm)
 {
        if (cache_is_vivt()) {
@@ -89,16 +102,16 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig
        if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged())
                __flush_icache_all();
 }
+
 #else
-#define flush_pfn_alias(pfn,vaddr)     do { } while (0)
+#define flush_pfn_alias(pfn,vaddr)             do { } while (0)
+#define flush_icache_alias(pfn,vaddr,len)      do { } while (0)
 #endif
 
-#ifdef CONFIG_SMP
 static void flush_ptrace_access_other(void *args)
 {
        __flush_icache_all();
 }
-#endif
 
 static
 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
@@ -118,15 +131,16 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
                return;
        }
 
-       /* VIPT non-aliasing cache */
+       /* VIPT non-aliasing D-cache */
        if (vma->vm_flags & VM_EXEC) {
                unsigned long addr = (unsigned long)kaddr;
-               __cpuc_coherent_kern_range(addr, addr + len);
-#ifdef CONFIG_SMP
+               if (icache_is_vipt_aliasing())
+                       flush_icache_alias(page_to_pfn(page), uaddr, len);
+               else
+                       __cpuc_coherent_kern_range(addr, addr + len);
                if (cache_ops_need_broadcast())
                        smp_call_function(flush_ptrace_access_other,
                                          NULL, 1);
-#endif
        }
 }
 
@@ -215,6 +229,36 @@ static void __flush_dcache_aliases(struct address_space *mapping, struct page *p
        flush_dcache_mmap_unlock(mapping);
 }
 
+#if __LINUX_ARM_ARCH__ >= 6
+void __sync_icache_dcache(pte_t pteval)
+{
+       unsigned long pfn;
+       struct page *page;
+       struct address_space *mapping;
+
+       if (!pte_present_user(pteval))
+               return;
+       if (cache_is_vipt_nonaliasing() && !pte_exec(pteval))
+               /* only flush non-aliasing VIPT caches for exec mappings */
+               return;
+       pfn = pte_pfn(pteval);
+       if (!pfn_valid(pfn))
+               return;
+
+       page = pfn_to_page(pfn);
+       if (cache_is_vipt_aliasing())
+               mapping = page_mapping(page);
+       else
+               mapping = NULL;
+
+       if (!test_and_set_bit(PG_dcache_clean, &page->flags))
+               __flush_dcache_page(mapping, page);
+       /* pte_exec() already checked above for non-aliasing VIPT cache */
+       if (cache_is_vipt_nonaliasing() || pte_exec(pteval))
+               __flush_icache_all();
+}
+#endif
+
 /*
  * Ensure cache coherency between kernel mapping and userspace mapping
  * of this page.
@@ -246,17 +290,16 @@ void flush_dcache_page(struct page *page)
 
        mapping = page_mapping(page);
 
-#ifndef CONFIG_SMP
-       if (!PageHighMem(page) && mapping && !mapping_mapped(mapping))
-               set_bit(PG_dcache_dirty, &page->flags);
-       else
-#endif
-       {
+       if (!cache_ops_need_broadcast() &&
+           mapping && !mapping_mapped(mapping))
+               clear_bit(PG_dcache_clean, &page->flags);
+       else {
                __flush_dcache_page(mapping, page);
                if (mapping && cache_is_vivt())
                        __flush_dcache_aliases(mapping, page);
                else if (mapping)
                        __flush_icache_all();
+               set_bit(PG_dcache_clean, &page->flags);
        }
 }
 EXPORT_SYMBOL(flush_dcache_page);
index 977c8f9..85e6fd2 100644 (file)
@@ -102,6 +102,22 @@ static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
        writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
 }
 
+static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip,
+                                 unsigned offset, int val)
+{
+       if (val)
+               writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS);
+       else
+               writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC);
+}
+
+static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
+                                 unsigned offset, int val)
+{
+       writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
+       __nmk_gpio_set_output(nmk_chip, offset, val);
+}
+
 static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
                             pin_cfg_t cfg)
 {
@@ -118,20 +134,29 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
                [3] /* illegal */       = "??"
        };
        static const char *slpmnames[] = {
-               [NMK_GPIO_SLPM_INPUT]           = "input",
-               [NMK_GPIO_SLPM_NOCHANGE]        = "no-change",
+               [NMK_GPIO_SLPM_INPUT]           = "input/wakeup",
+               [NMK_GPIO_SLPM_NOCHANGE]        = "no-change/no-wakeup",
        };
 
        int pin = PIN_NUM(cfg);
        int pull = PIN_PULL(cfg);
        int af = PIN_ALT(cfg);
        int slpm = PIN_SLPM(cfg);
+       int output = PIN_DIR(cfg);
+       int val = PIN_VAL(cfg);
 
-       dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s\n",
-               pin, afnames[af], pullnames[pull], slpmnames[slpm]);
+       dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s (%s%s)\n",
+               pin, afnames[af], pullnames[pull], slpmnames[slpm],
+               output ? "output " : "input",
+               output ? (val ? "high" : "low") : "");
+
+       if (output)
+               __nmk_gpio_make_output(nmk_chip, offset, val);
+       else {
+               __nmk_gpio_make_input(nmk_chip, offset);
+               __nmk_gpio_set_pull(nmk_chip, offset, pull);
+       }
 
-       __nmk_gpio_make_input(nmk_chip, offset);
-       __nmk_gpio_set_pull(nmk_chip, offset, pull);
        __nmk_gpio_set_slpm(nmk_chip, offset, slpm);
        __nmk_gpio_set_mode(nmk_chip, offset, af);
 }
@@ -200,6 +225,10 @@ EXPORT_SYMBOL(nmk_config_pins);
  * changed to an input (with pullup/down enabled) in sleep and deep sleep.  If
  * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was
  * configured even when in sleep and deep sleep.
+ *
+ * On DB8500v2 onwards, this setting loses the previous meaning and instead
+ * indicates if wakeup detection is enabled on the pin.  Note that
+ * enable_irq_wake() will automatically enable wakeup detection.
  */
 int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
 {
@@ -367,7 +396,27 @@ static void nmk_gpio_irq_unmask(unsigned int irq)
 
 static int nmk_gpio_irq_set_wake(unsigned int irq, unsigned int on)
 {
-       return nmk_gpio_irq_modify(irq, WAKE, on);
+       struct nmk_gpio_chip *nmk_chip;
+       unsigned long flags;
+       int gpio;
+
+       gpio = NOMADIK_IRQ_TO_GPIO(irq);
+       nmk_chip = get_irq_chip_data(irq);
+       if (!nmk_chip)
+               return -EINVAL;
+
+       spin_lock_irqsave(&nmk_chip->lock, flags);
+#ifdef CONFIG_ARCH_U8500
+       if (cpu_is_u8500v2()) {
+               __nmk_gpio_set_slpm(nmk_chip, gpio,
+                                   on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
+                                      : NMK_GPIO_SLPM_WAKEUP_DISABLE);
+       }
+#endif
+       __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
+       spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+       return 0;
 }
 
 static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
@@ -495,12 +544,8 @@ static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
 {
        struct nmk_gpio_chip *nmk_chip =
                container_of(chip, struct nmk_gpio_chip, chip);
-       u32 bit = 1 << offset;
 
-       if (val)
-               writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
-       else
-               writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
+       __nmk_gpio_set_output(nmk_chip, offset, val);
 }
 
 static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
@@ -509,8 +554,7 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
        struct nmk_gpio_chip *nmk_chip =
                container_of(chip, struct nmk_gpio_chip, chip);
 
-       writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
-       nmk_gpio_set_output(chip, offset, val);
+       __nmk_gpio_make_output(nmk_chip, offset, val);
 
        return 0;
 }
@@ -534,7 +578,7 @@ static struct gpio_chip nmk_gpio_template = {
        .can_sleep              = 0,
 };
 
-static int __init nmk_gpio_probe(struct platform_device *dev)
+static int __devinit nmk_gpio_probe(struct platform_device *dev)
 {
        struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
        struct nmk_gpio_chip *nmk_chip;
index aba3551..67b113d 100644 (file)
@@ -65,7 +65,9 @@ enum nmk_gpio_pull {
 /* Sleep mode */
 enum nmk_gpio_slpm {
        NMK_GPIO_SLPM_INPUT,
+       NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT,
        NMK_GPIO_SLPM_NOCHANGE,
+       NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
 };
 
 extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
index 7eed11c..8c5ae3f 100644 (file)
  *     bit  9..10 - Alternate Function Selection
  *     bit 11..12 - Pull up/down state
  *     bit     13 - Sleep mode behaviour
+ *     bit     14 - (sleep mode) Direction
+ *     bit     15 - (sleep mode) Value (if output)
  *
  * to facilitate the definition, the following macros are provided
  *
  * PIN_CFG_DEFAULT - default config (0):
  *                  pull up/down = disabled
- *                  sleep mode = input
+ *                  sleep mode = input/wakeup
+ *                  (sleep mode) direction = input
+ *                  (sleep mode) value = low
  *
  * PIN_CFG        - default config with alternate function
  * PIN_CFG_PULL           - default config with alternate function and pull up/down
@@ -53,8 +57,36 @@ typedef unsigned long pin_cfg_t;
 #define PIN_SLPM_SHIFT         13
 #define PIN_SLPM_MASK          (0x1 << PIN_SLPM_SHIFT)
 #define PIN_SLPM(x)            (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT)
-#define PIN_SLPM_INPUT         (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT)
+#define PIN_SLPM_MAKE_INPUT    (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT)
 #define PIN_SLPM_NOCHANGE      (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT)
+/* These two replace the above in DB8500v2+ */
+#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT)
+#define PIN_SLPM_WAKEUP_DISABLE        (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT)
+
+#define PIN_DIR_SHIFT          14
+#define PIN_DIR_MASK           (0x1 << PIN_DIR_SHIFT)
+#define PIN_DIR(x)             (((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT)
+#define PIN_DIR_INPUT          (0 << PIN_DIR_SHIFT)
+#define PIN_DIR_OUTPUT         (1 << PIN_DIR_SHIFT)
+
+#define PIN_VAL_SHIFT          15
+#define PIN_VAL_MASK           (0x1 << PIN_VAL_SHIFT)
+#define PIN_VAL(x)             (((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT)
+#define PIN_VAL_LOW            (0 << PIN_VAL_SHIFT)
+#define PIN_VAL_HIGH           (1 << PIN_VAL_SHIFT)
+
+/* Shortcuts.  Use these instead of separate DIR and VAL.  */
+#define PIN_INPUT              PIN_DIR_INPUT
+#define PIN_OUTPUT_LOW         (PIN_DIR_OUTPUT | PIN_VAL_LOW)
+#define PIN_OUTPUT_HIGH                (PIN_DIR_OUTPUT | PIN_VAL_HIGH)
+
+/*
+ * These are the same as the ones above, but should make more sense to the
+ * reader when seen along with a setting a pin to AF mode.
+ */
+#define PIN_SLPM_INPUT         PIN_INPUT
+#define PIN_SLPM_OUTPUT_LOW    PIN_OUTPUT_LOW
+#define PIN_SLPM_OUTPUT_HIGH   PIN_OUTPUT_HIGH
 
 #define PIN_CFG_DEFAULT                (PIN_PULL_NONE | PIN_SLPM_INPUT)
 
index 1be6288..7e10c93 100644 (file)
@@ -322,6 +322,9 @@ static int __devinit tc35892_gpio_probe(struct platform_device *pdev)
                goto out_freeirq;
        }
 
+       if (pdata->setup)
+               pdata->setup(tc35892, tc35892_gpio->chip.base);
+
        platform_set_drvdata(pdev, tc35892_gpio);
 
        return 0;
@@ -338,9 +341,14 @@ out_free:
 static int __devexit tc35892_gpio_remove(struct platform_device *pdev)
 {
        struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev);
+       struct tc35892 *tc35892 = tc35892_gpio->tc35892;
+       struct tc35892_gpio_platform_data *pdata = tc35892->pdata->gpio;
        int irq = platform_get_irq(pdev, 0);
        int ret;
 
+       if (pdata->remove)
+               pdata->remove(tc35892, tc35892_gpio->chip.base);
+
        ret = gpiochip_remove(&tc35892_gpio->chip);
        if (ret < 0) {
                dev_err(tc35892_gpio->dev,
index 840b301..f2e02d7 100644 (file)
@@ -41,23 +41,35 @@ static unsigned int fmax = 515633;
  * @clkreg: default value for MCICLOCK register
  * @clkreg_enable: enable value for MMCICLOCK register
  * @datalength_bits: number of bits in the MMCIDATALENGTH register
+ * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
+ *           is asserted (likewise for RX)
+ * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
+ *               is asserted (likewise for RX)
  */
 struct variant_data {
        unsigned int            clkreg;
        unsigned int            clkreg_enable;
        unsigned int            datalength_bits;
+       unsigned int            fifosize;
+       unsigned int            fifohalfsize;
 };
 
 static struct variant_data variant_arm = {
+       .fifosize               = 16 * 4,
+       .fifohalfsize           = 8 * 4,
        .datalength_bits        = 16,
 };
 
 static struct variant_data variant_u300 = {
+       .fifosize               = 16 * 4,
+       .fifohalfsize           = 8 * 4,
        .clkreg_enable          = 1 << 13, /* HWFCEN */
        .datalength_bits        = 16,
 };
 
 static struct variant_data variant_ux500 = {
+       .fifosize               = 30 * 4,
+       .fifohalfsize           = 8 * 4,
        .clkreg                 = MCI_CLK_ENABLE,
        .clkreg_enable          = 1 << 14, /* HWFCEN */
        .datalength_bits        = 24,
@@ -138,6 +150,7 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
 
 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 {
+       struct variant_data *variant = host->variant;
        unsigned int datactrl, timeout, irqmask;
        unsigned long long clks;
        void __iomem *base;
@@ -173,7 +186,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
                 * If we have less than a FIFOSIZE of bytes to transfer,
                 * trigger a PIO interrupt as soon as any data is available.
                 */
-               if (host->size < MCI_FIFOSIZE)
+               if (host->size < variant->fifosize)
                        irqmask |= MCI_RXDATAAVLBLMASK;
        } else {
                /*
@@ -332,13 +345,15 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
 
 static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
 {
+       struct variant_data *variant = host->variant;
        void __iomem *base = host->base;
        char *ptr = buffer;
 
        do {
                unsigned int count, maxcnt;
 
-               maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
+               maxcnt = status & MCI_TXFIFOEMPTY ?
+                        variant->fifosize : variant->fifohalfsize;
                count = min(remain, maxcnt);
 
                writesl(base + MMCIFIFO, ptr, count >> 2);
@@ -362,6 +377,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
 {
        struct mmci_host *host = dev_id;
        struct sg_mapping_iter *sg_miter = &host->sg_miter;
+       struct variant_data *variant = host->variant;
        void __iomem *base = host->base;
        unsigned long flags;
        u32 status;
@@ -420,7 +436,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
         * If we're nearing the end of the read, switch to
         * "any data available" mode.
         */
-       if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE)
+       if (status & MCI_RXACTIVE && host->size < variant->fifosize)
                writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
 
        /*
@@ -564,18 +580,23 @@ static int mmci_get_ro(struct mmc_host *mmc)
        if (host->gpio_wp == -ENOSYS)
                return -ENOSYS;
 
-       return gpio_get_value(host->gpio_wp);
+       return gpio_get_value_cansleep(host->gpio_wp);
 }
 
 static int mmci_get_cd(struct mmc_host *mmc)
 {
        struct mmci_host *host = mmc_priv(mmc);
+       struct mmci_platform_data *plat = host->plat;
        unsigned int status;
 
-       if (host->gpio_cd == -ENOSYS)
-               status = host->plat->status(mmc_dev(host->mmc));
-       else
-               status = !gpio_get_value(host->gpio_cd);
+       if (host->gpio_cd == -ENOSYS) {
+               if (!plat->status)
+                       return 1; /* Assume always present */
+
+               status = plat->status(mmc_dev(host->mmc));
+       } else
+               status = !!gpio_get_value_cansleep(host->gpio_cd)
+                       ^ plat->cd_invert;
 
        /*
         * Use positive logic throughout - status is zero for no card,
@@ -584,6 +605,15 @@ static int mmci_get_cd(struct mmc_host *mmc)
        return status;
 }
 
+static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
+{
+       struct mmci_host *host = dev_id;
+
+       mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+
+       return IRQ_HANDLED;
+}
+
 static const struct mmc_host_ops mmci_ops = {
        .request        = mmci_request,
        .set_ios        = mmci_set_ios,
@@ -620,6 +650,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 
        host->gpio_wp = -ENOSYS;
        host->gpio_cd = -ENOSYS;
+       host->gpio_cd_irq = -1;
 
        host->hw_designer = amba_manf(dev);
        host->hw_revision = amba_rev(dev);
@@ -699,7 +730,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        if (host->vcc == NULL)
                mmc->ocr_avail = plat->ocr_mask;
        mmc->caps = plat->capabilities;
-       mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        /*
         * We can do SGIO
@@ -744,6 +774,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                        host->gpio_cd = plat->gpio_cd;
                else if (ret != -ENOSYS)
                        goto err_gpio_cd;
+
+               ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd),
+                                             mmci_cd_irq, 0,
+                                             DRIVER_NAME " (cd)", host);
+               if (ret >= 0)
+                       host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd);
        }
        if (gpio_is_valid(plat->gpio_wp)) {
                ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");
@@ -755,6 +791,10 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                        goto err_gpio_wp;
        }
 
+       if ((host->plat->status || host->gpio_cd != -ENOSYS)
+           && host->gpio_cd_irq < 0)
+               mmc->caps |= MMC_CAP_NEEDS_POLL;
+
        ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
        if (ret)
                goto unmap;
@@ -781,6 +821,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        if (host->gpio_wp != -ENOSYS)
                gpio_free(host->gpio_wp);
  err_gpio_wp:
+       if (host->gpio_cd_irq >= 0)
+               free_irq(host->gpio_cd_irq, host);
        if (host->gpio_cd != -ENOSYS)
                gpio_free(host->gpio_cd);
  err_gpio_cd:
@@ -819,6 +861,8 @@ static int __devexit mmci_remove(struct amba_device *dev)
 
                if (host->gpio_wp != -ENOSYS)
                        gpio_free(host->gpio_wp);
+               if (host->gpio_cd_irq >= 0)
+                       free_irq(host->gpio_cd_irq, host);
                if (host->gpio_cd != -ENOSYS)
                        gpio_free(host->gpio_cd);
 
index 68970cf..4ae887f 100644 (file)
 #define MCI_DPSM_MODE          (1 << 2)
 #define MCI_DPSM_DMAENABLE     (1 << 3)
 #define MCI_DPSM_BLOCKSIZE     (1 << 4)
-#define MCI_DPSM_RWSTART       (1 << 8)
-#define MCI_DPSM_RWSTOP                (1 << 9)
-#define MCI_DPSM_RWMOD         (1 << 10)
-#define MCI_DPSM_SDIOEN                (1 << 11)
+/* Control register extensions in the ST Micro U300 and Ux500 versions */
+#define MCI_ST_DPSM_RWSTART    (1 << 8)
+#define MCI_ST_DPSM_RWSTOP     (1 << 9)
+#define MCI_ST_DPSM_RWMOD      (1 << 10)
+#define MCI_ST_DPSM_SDIOEN     (1 << 11)
+/* Control register extensions in the ST Micro Ux500 versions */
+#define MCI_ST_DPSM_DMAREQCTL  (1 << 12)
+#define MCI_ST_DPSM_DBOOTMODEEN        (1 << 13)
+#define MCI_ST_DPSM_BUSYMODE   (1 << 14)
+#define MCI_ST_DPSM_DDRMODE    (1 << 15)
 
 #define MMCIDATACNT            0x030
 #define MMCISTATUS             0x034
        MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|       \
        MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
 
-/*
- * The size of the FIFO in bytes.
- */
-#define MCI_FIFOSIZE   (16*4)
-       
-#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
-
 #define NR_SG          16
 
 struct clk;
@@ -154,6 +153,7 @@ struct mmci_host {
        struct clk              *clk;
        int                     gpio_cd;
        int                     gpio_wp;
+       int                     gpio_cd_irq;
 
        unsigned int            data_xfered;
 
index ca84ce7..f4ee9ac 100644 (file)
@@ -24,6 +24,7 @@
  * whether a card is present in the MMC slot or not
  * @gpio_wp: read this GPIO pin to see if the card is write protected
  * @gpio_cd: read this GPIO pin to detect card insertion
+ * @cd_invert: true if the gpio_cd pin value is active low
  * @capabilities: the capabilities of the block as implemented in
  * this platform, signify anything MMC_CAP_* from mmc/host.h
  */
@@ -35,6 +36,7 @@ struct mmci_platform_data {
        unsigned int (*status)(struct device *);
        int     gpio_wp;
        int     gpio_cd;
+       bool    cd_invert;
        unsigned long capabilities;
 };
 
index e47f770..eff3094 100644 (file)
@@ -111,9 +111,13 @@ extern int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val);
  * struct tc35892_gpio_platform_data - TC35892 GPIO platform data
  * @gpio_base: first gpio number assigned to TC35892.  A maximum of
  *            %TC35892_NR_GPIOS GPIOs will be allocated.
+ * @setup: callback for board-specific initialization
+ * @remove: callback for board-specific teardown
  */
 struct tc35892_gpio_platform_data {
        int gpio_base;
+       void (*setup)(struct tc35892 *tc35892, unsigned gpio_base);
+       void (*remove)(struct tc35892 *tc35892, unsigned gpio_base);
 };
 
 /**
index 538501c..6329d06 100644 (file)
@@ -121,7 +121,7 @@ if FTRACE
 config FUNCTION_TRACER
        bool "Kernel Function Tracer"
        depends on HAVE_FUNCTION_TRACER
-       select FRAME_POINTER
+       select FRAME_POINTER if (!ARM_UNWIND)
        select KALLSYMS
        select GENERIC_TRACER
        select CONTEXT_SWITCH_TRACER
index a1a5cf9..108eeb9 100644 (file)
@@ -212,7 +212,8 @@ ifdef CONFIG_FTRACE_MCOUNT_RECORD
 cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
        "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
        "$(if $(CONFIG_64BIT),64,32)" \
-       "$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" "$(NM)" "$(RM)" "$(MV)" \
+       "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \
+       "$(LD)" "$(NM)" "$(RM)" "$(MV)" \
        "$(if $(part-of-module),1,0)" "$(@)";
 endif
 
index e67f054..1d7963f 100755 (executable)
@@ -270,6 +270,8 @@ if ($arch eq "x86_64") {
 } elsif ($arch eq "arm") {
     $alignment = 2;
     $section_type = '%progbits';
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_ARM_(CALL|PC24|THM_CALL)" .
+                       "\\s+(__gnu_mcount_nc|mcount)\$";
 
 } elsif ($arch eq "ia64") {
     $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";