Commit 1205b623 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-4.21' of git://git.armlinux.org.uk/~rmk/linux-arm

Pull ARM updates from Russell King:
 "Included in this update:

   - Florian Fainelli noticed that userspace segfaults caused by the
     lack of kernel-userspace helpers was hard to diagnose; we now issue
     a warning when userspace tries to use the helpers but the kernel
     has them disabled.

   - Ben Dooks wants compatibility for the old ATAG serial number with
     DT systems.

   - Some cleanup of assembly by Nicolas Pitre.

   - User accessors optimisation from Vincent Whitchurch.

   - More robust kdump on SMP systems from Yufen Wang.

   - Sebastian Andrzej Siewior noticed problems with the SMP "boot_lock"
     on RT kernels, and so we convert the Versatile series of platforms
     to use a raw spinlock instead, consolidating the Versatile
     implementation. We entirely remove the boot_lock on OMAP systems,
     where it's unnecessary. Further patches for other systems will be
     submitted for the following merge window.

   - Start switching old StrongARM-11x0 systems to use gpiolib rather
     than their private GPIO implementation - mostly PCMCIA bits.

   - ARM Kconfig cleanups.

   - Cleanup a mostly harmless mistake in the recent Spectre patch in
     4.20 (which had the effect that data that can be placed into the
     init sections was incorrectly always placed in the rodata section)"

* tag 'for-4.21' of git://git.armlinux.org.uk/~rmk/linux-arm: (25 commits)
  ARM: omap2: remove unnecessary boot_lock
  ARM: versatile: rename and comment SMP implementation
  ARM: versatile: convert boot_lock to raw
  ARM: vexpress/realview: consolidate immitation CPU hotplug
  ARM: fix the cockup in the previous patch
  ARM: sa1100/cerf: switch to using gpio_led_register_device()
  ARM: sa1100/assabet: switch to using gpio leds
  ARM: sa1100/assabet: add gpio keys support for right-hand two buttons
  ARM: sa1111: remove legacy GPIO interfaces
  pcmcia: sa1100*: remove redundant bvd1/bvd2 setting
  ARM: pxa/lubbock: switch PCMCIA to MAX1600 library
  ARM: pxa/mainstone: switch PCMCIA to MAX1600 library and gpiod APIs
  ARM: sa1100/neponset: switch PCMCIA to MAX1600 library and gpiod APIs
  ARM: sa1100/jornada720: switch PCMCIA to gpiod APIs
  pcmcia: add MAX1600 library
  ARM: sa1100: explicitly register sa11x0-pcmcia devices
  ARM: 8813/1: Make aligned 2-byte getuser()/putuser() atomic on ARMv6+
  ARM: 8812/1: Optimise copy_{from/to}_user for !CPU_USE_DOMAINS
  ARM: 8811/1: always list both ldrd/strd registers explicitly
  ARM: 8808/1: kexec:offline panic_smp_self_stop CPU
  ...
parents 9ee3b3f4 6de92920
...@@ -28,14 +28,14 @@ config ARM ...@@ -28,14 +28,14 @@ config ARM
select ARCH_WANT_IPC_PARSE_VERSION select ARCH_WANT_IPC_PARSE_VERSION
select BUILDTIME_EXTABLE_SORT if MMU select BUILDTIME_EXTABLE_SORT if MMU
select CLONE_BACKWARDS select CLONE_BACKWARDS
select CPU_PM if (SUSPEND || CPU_IDLE) select CPU_PM if SUSPEND || CPU_IDLE
select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS
select DMA_REMAP if MMU select DMA_REMAP if MMU
select EDAC_SUPPORT select EDAC_SUPPORT
select EDAC_ATOMIC_SCRUB select EDAC_ATOMIC_SCRUB
select GENERIC_ALLOCATOR select GENERIC_ALLOCATOR
select GENERIC_ARCH_TOPOLOGY if ARM_CPU_TOPOLOGY select GENERIC_ARCH_TOPOLOGY if ARM_CPU_TOPOLOGY
select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI) select GENERIC_ATOMIC64 if CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI
select GENERIC_CLOCKEVENTS_BROADCAST if SMP select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_AUTOPROBE
select GENERIC_EARLY_IOREMAP select GENERIC_EARLY_IOREMAP
...@@ -50,12 +50,12 @@ config ARM ...@@ -50,12 +50,12 @@ config ARM
select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER
select HANDLE_DOMAIN_IRQ select HANDLE_DOMAIN_IRQ
select HARDIRQS_SW_RESEND select HARDIRQS_SW_RESEND
select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_ARCH_MMAP_RND_BITS if MMU
select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) select HAVE_ARCH_SECCOMP_FILTER if AEABI && !OABI_COMPAT
select HAVE_ARCH_THREAD_STRUCT_WHITELIST select HAVE_ARCH_THREAD_STRUCT_WHITELIST
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK
select HAVE_ARM_SMCCC if CPU_V7 select HAVE_ARM_SMCCC if CPU_V7
...@@ -64,16 +64,16 @@ config ARM ...@@ -64,16 +64,16 @@ config ARM
select HAVE_C_RECORDMCOUNT select HAVE_C_RECORDMCOUNT
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_CONTIGUOUS if MMU select HAVE_DMA_CONTIGUOUS if MMU
select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 && MMU select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE
select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU
select HAVE_EXIT_THREAD select HAVE_EXIT_THREAD
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL) select HAVE_FUNCTION_GRAPH_TRACER if !THUMB2_KERNEL
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) select HAVE_FUNCTION_TRACER if !XIP_KERNEL
select HAVE_GCC_PLUGINS select HAVE_GCC_PLUGINS
select HAVE_GENERIC_DMA_COHERENT select HAVE_GENERIC_DMA_COHERENT
select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) select HAVE_HW_BREAKPOINT if PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)
select HAVE_IDE if PCI || ISA || PCMCIA select HAVE_IDE if PCI || ISA || PCMCIA
select HAVE_IRQ_TIME_ACCOUNTING select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_KERNEL_GZIP select HAVE_KERNEL_GZIP
...@@ -82,15 +82,15 @@ config ARM ...@@ -82,15 +82,15 @@ config ARM
select HAVE_KERNEL_LZO select HAVE_KERNEL_LZO
select HAVE_KERNEL_XZ select HAVE_KERNEL_XZ
select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M
select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_KRETPROBES if HAVE_KPROBES
select HAVE_MOD_ARCH_SPECIFIC select HAVE_MOD_ARCH_SPECIFIC
select HAVE_NMI select HAVE_NMI
select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_OPROFILE if HAVE_PERF_EVENTS
select HAVE_OPTPROBES if !THUMB2_KERNEL select HAVE_OPTPROBES if !THUMB2_KERNEL
select HAVE_PERF_EVENTS select HAVE_PERF_EVENTS
select HAVE_PERF_REGS select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP select HAVE_PERF_USER_STACK_DUMP
select HAVE_RCU_TABLE_FREE if (SMP && ARM_LPAE) select HAVE_RCU_TABLE_FREE if SMP && ARM_LPAE
select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RSEQ select HAVE_RSEQ
select HAVE_STACKPROTECTOR select HAVE_STACKPROTECTOR
...@@ -1738,7 +1738,6 @@ config PARAVIRT ...@@ -1738,7 +1738,6 @@ config PARAVIRT
config PARAVIRT_TIME_ACCOUNTING config PARAVIRT_TIME_ACCOUNTING
bool "Paravirtual steal time accounting" bool "Paravirtual steal time accounting"
select PARAVIRT select PARAVIRT
default n
help help
Select this option to enable fine granularity task steal time Select this option to enable fine granularity task steal time
accounting. Time spent executing other tasks in parallel with accounting. Time spent executing other tasks in parallel with
......
...@@ -98,6 +98,24 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) ...@@ -98,6 +98,24 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
setprop_string(fdt, "/chosen", "bootargs", cmdline); setprop_string(fdt, "/chosen", "bootargs", cmdline);
} }
static void hex_str(char *out, uint32_t value)
{
uint32_t digit;
int idx;
for (idx = 7; idx >= 0; idx--) {
digit = value >> 28;
value <<= 4;
digit &= 0xf;
if (digit < 10)
digit += '0';
else
digit += 'A'-10;
*out++ = digit;
}
*out = '\0';
}
/* /*
* Convert and fold provided ATAGs into the provided FDT. * Convert and fold provided ATAGs into the provided FDT.
* *
...@@ -180,6 +198,11 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space) ...@@ -180,6 +198,11 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)
initrd_start); initrd_start);
setprop_cell(fdt, "/chosen", "linux,initrd-end", setprop_cell(fdt, "/chosen", "linux,initrd-end",
initrd_start + initrd_size); initrd_start + initrd_size);
} else if (atag->hdr.tag == ATAG_SERIAL) {
char serno[16+2];
hex_str(serno, atag->u.serialnr.high);
hex_str(serno+8, atag->u.serialnr.low);
setprop_string(fdt, "/", "serial-number", serno);
} }
} }
......
...@@ -1282,65 +1282,6 @@ int sa1111_get_audio_rate(struct sa1111_dev *sadev) ...@@ -1282,65 +1282,6 @@ int sa1111_get_audio_rate(struct sa1111_dev *sadev)
} }
EXPORT_SYMBOL(sa1111_get_audio_rate); EXPORT_SYMBOL(sa1111_get_audio_rate);
void sa1111_set_io_dir(struct sa1111_dev *sadev,
unsigned int bits, unsigned int dir,
unsigned int sleep_dir)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
unsigned long flags;
unsigned int val;
void __iomem *gpio = sachip->base + SA1111_GPIO;
#define MODIFY_BITS(port, mask, dir) \
if (mask) { \
val = readl_relaxed(port); \
val &= ~(mask); \
val |= (dir) & (mask); \
writel_relaxed(val, port); \
}
spin_lock_irqsave(&sachip->lock, flags);
MODIFY_BITS(gpio + SA1111_GPIO_PADDR, bits & 15, dir);
MODIFY_BITS(gpio + SA1111_GPIO_PBDDR, (bits >> 8) & 255, dir >> 8);
MODIFY_BITS(gpio + SA1111_GPIO_PCDDR, (bits >> 16) & 255, dir >> 16);
MODIFY_BITS(gpio + SA1111_GPIO_PASDR, bits & 15, sleep_dir);
MODIFY_BITS(gpio + SA1111_GPIO_PBSDR, (bits >> 8) & 255, sleep_dir >> 8);
MODIFY_BITS(gpio + SA1111_GPIO_PCSDR, (bits >> 16) & 255, sleep_dir >> 16);
spin_unlock_irqrestore(&sachip->lock, flags);
}
EXPORT_SYMBOL(sa1111_set_io_dir);
void sa1111_set_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
unsigned long flags;
unsigned int val;
void __iomem *gpio = sachip->base + SA1111_GPIO;
spin_lock_irqsave(&sachip->lock, flags);
MODIFY_BITS(gpio + SA1111_GPIO_PADWR, bits & 15, v);
MODIFY_BITS(gpio + SA1111_GPIO_PBDWR, (bits >> 8) & 255, v >> 8);
MODIFY_BITS(gpio + SA1111_GPIO_PCDWR, (bits >> 16) & 255, v >> 16);
spin_unlock_irqrestore(&sachip->lock, flags);
}
EXPORT_SYMBOL(sa1111_set_io);
void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
unsigned long flags;
unsigned int val;
void __iomem *gpio = sachip->base + SA1111_GPIO;
spin_lock_irqsave(&sachip->lock, flags);
MODIFY_BITS(gpio + SA1111_GPIO_PASSR, bits & 15, v);
MODIFY_BITS(gpio + SA1111_GPIO_PBSSR, (bits >> 8) & 255, v >> 8);
MODIFY_BITS(gpio + SA1111_GPIO_PCSSR, (bits >> 16) & 255, v >> 16);
spin_unlock_irqrestore(&sachip->lock, flags);
}
EXPORT_SYMBOL(sa1111_set_sleep_io);
/* /*
* Individual device operations. * Individual device operations.
*/ */
......
...@@ -243,13 +243,15 @@ ...@@ -243,13 +243,15 @@
.endm .endm
#endif #endif
#define USER(x...) \ #define USERL(l, x...) \
9999: x; \ 9999: x; \
.pushsection __ex_table,"a"; \ .pushsection __ex_table,"a"; \
.align 3; \ .align 3; \
.long 9999b,9001f; \ .long 9999b,l; \
.popsection .popsection
#define USER(x...) USERL(9001f, x)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#define ALT_SMP(instr...) \ #define ALT_SMP(instr...) \
9998: instr 9998: instr
......
...@@ -433,10 +433,6 @@ int sa1111_check_dma_bug(dma_addr_t addr); ...@@ -433,10 +433,6 @@ int sa1111_check_dma_bug(dma_addr_t addr);
int sa1111_driver_register(struct sa1111_driver *); int sa1111_driver_register(struct sa1111_driver *);
void sa1111_driver_unregister(struct sa1111_driver *); void sa1111_driver_unregister(struct sa1111_driver *);
void sa1111_set_io_dir(struct sa1111_dev *sadev, unsigned int bits, unsigned int dir, unsigned int sleep_dir);
void sa1111_set_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v);
void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned int v);
struct sa1111_platform_data { struct sa1111_platform_data {
int irq_base; /* base for cascaded on-chip IRQs */ int irq_base; /* base for cascaded on-chip IRQs */
unsigned disable_devs; unsigned disable_devs;
......
...@@ -349,6 +349,13 @@ do { \ ...@@ -349,6 +349,13 @@ do { \
#define __get_user_asm_byte(x, addr, err) \ #define __get_user_asm_byte(x, addr, err) \
__get_user_asm(x, addr, err, ldrb) __get_user_asm(x, addr, err, ldrb)
#if __LINUX_ARM_ARCH__ >= 6
#define __get_user_asm_half(x, addr, err) \
__get_user_asm(x, addr, err, ldrh)
#else
#ifndef __ARMEB__ #ifndef __ARMEB__
#define __get_user_asm_half(x, __gu_addr, err) \ #define __get_user_asm_half(x, __gu_addr, err) \
({ \ ({ \
...@@ -367,6 +374,8 @@ do { \ ...@@ -367,6 +374,8 @@ do { \
}) })
#endif #endif
#endif /* __LINUX_ARM_ARCH__ >= 6 */
#define __get_user_asm_word(x, addr, err) \ #define __get_user_asm_word(x, addr, err) \
__get_user_asm(x, addr, err, ldr) __get_user_asm(x, addr, err, ldr)
#endif #endif
...@@ -442,6 +451,13 @@ do { \ ...@@ -442,6 +451,13 @@ do { \
#define __put_user_asm_byte(x, __pu_addr, err) \ #define __put_user_asm_byte(x, __pu_addr, err) \
__put_user_asm(x, __pu_addr, err, strb) __put_user_asm(x, __pu_addr, err, strb)
#if __LINUX_ARM_ARCH__ >= 6
#define __put_user_asm_half(x, __pu_addr, err) \
__put_user_asm(x, __pu_addr, err, strh)
#else
#ifndef __ARMEB__ #ifndef __ARMEB__
#define __put_user_asm_half(x, __pu_addr, err) \ #define __put_user_asm_half(x, __pu_addr, err) \
({ \ ({ \
...@@ -458,6 +474,8 @@ do { \ ...@@ -458,6 +474,8 @@ do { \
}) })
#endif #endif
#endif /* __LINUX_ARM_ARCH__ >= 6 */
#define __put_user_asm_word(x, __pu_addr, err) \ #define __put_user_asm_word(x, __pu_addr, err) \
__put_user_asm(x, __pu_addr, err, str) __put_user_asm(x, __pu_addr, err, str)
......
...@@ -398,7 +398,7 @@ ENTRY(secondary_startup) ...@@ -398,7 +398,7 @@ ENTRY(secondary_startup)
ldmia r4, {r5, r7, r12} @ address to jump to after ldmia r4, {r5, r7, r12} @ address to jump to after
sub lr, r4, r5 @ mmu has been enabled sub lr, r4, r5 @ mmu has been enabled
add r3, r7, lr add r3, r7, lr
ldrd r4, [r3, #0] @ get secondary_data.pgdir ldrd r4, r5, [r3, #0] @ get secondary_data.pgdir
ARM_BE8(eor r4, r4, r5) @ Swap r5 and r4 in BE: ARM_BE8(eor r4, r4, r5) @ Swap r5 and r4 in BE:
ARM_BE8(eor r5, r4, r5) @ it can be done in 3 steps ARM_BE8(eor r5, r4, r5) @ it can be done in 3 steps
ARM_BE8(eor r4, r4, r5) @ without using a temp reg. ARM_BE8(eor r4, r4, r5) @ without using a temp reg.
......
...@@ -724,6 +724,21 @@ void smp_send_stop(void) ...@@ -724,6 +724,21 @@ void smp_send_stop(void)
pr_warn("SMP: failed to stop secondary CPUs\n"); pr_warn("SMP: failed to stop secondary CPUs\n");
} }
/* In case panic() and panic() called at the same time on CPU1 and CPU2,
* and CPU 1 calls panic_smp_self_stop() before crash_smp_send_stop()
* CPU1 can't receive the ipi irqs from CPU2, CPU1 will be always online,
* kdump fails. So split out the panic_smp_self_stop() and add
* set_cpu_online(smp_processor_id(), false).
*/
void panic_smp_self_stop(void)
{
pr_debug("CPU %u will stop doing anything useful since another CPU has paniced\n",
smp_processor_id());
set_cpu_online(smp_processor_id(), false);
while (1)
cpu_relax();
}
/* /*
* not supported here * not supported here
*/ */
......
...@@ -34,12 +34,13 @@ ...@@ -34,12 +34,13 @@
* Number of bytes NOT copied. * Number of bytes NOT copied.
*/ */
#ifdef CONFIG_CPU_USE_DOMAINS
#ifndef CONFIG_THUMB2_KERNEL #ifndef CONFIG_THUMB2_KERNEL
#define LDR1W_SHIFT 0 #define LDR1W_SHIFT 0
#else #else
#define LDR1W_SHIFT 1 #define LDR1W_SHIFT 1
#endif #endif
#define STR1W_SHIFT 0
.macro ldr1w ptr reg abort .macro ldr1w ptr reg abort
ldrusr \reg, \ptr, 4, abort=\abort ldrusr \reg, \ptr, 4, abort=\abort
...@@ -57,10 +58,30 @@ ...@@ -57,10 +58,30 @@
ldr4w \ptr, \reg5, \reg6, \reg7, \reg8, \abort ldr4w \ptr, \reg5, \reg6, \reg7, \reg8, \abort
.endm .endm
#else
#define LDR1W_SHIFT 0
.macro ldr1w ptr reg abort
USERL(\abort, W(ldr) \reg, [\ptr], #4)
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
USERL(\abort, ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4})
.endm
.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
USERL(\abort, ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8})
.endm
#endif /* CONFIG_CPU_USE_DOMAINS */
.macro ldr1b ptr reg cond=al abort .macro ldr1b ptr reg cond=al abort
ldrusr \reg, \ptr, 1, \cond, abort=\abort ldrusr \reg, \ptr, 1, \cond, abort=\abort
.endm .endm
#define STR1W_SHIFT 0
.macro str1w ptr reg abort .macro str1w ptr reg abort
W(str) \reg, [\ptr], #4 W(str) \reg, [\ptr], #4
.endm .endm
......
...@@ -35,11 +35,6 @@ ...@@ -35,11 +35,6 @@
*/ */
#define LDR1W_SHIFT 0 #define LDR1W_SHIFT 0
#ifndef CONFIG_THUMB2_KERNEL
#define STR1W_SHIFT 0
#else
#define STR1W_SHIFT 1
#endif
.macro ldr1w ptr reg abort .macro ldr1w ptr reg abort
W(ldr) \reg, [\ptr], #4 W(ldr) \reg, [\ptr], #4
...@@ -57,6 +52,14 @@ ...@@ -57,6 +52,14 @@
ldr\cond\()b \reg, [\ptr], #1 ldr\cond\()b \reg, [\ptr], #1
.endm .endm
#ifdef CONFIG_CPU_USE_DOMAINS
#ifndef CONFIG_THUMB2_KERNEL
#define STR1W_SHIFT 0
#else
#define STR1W_SHIFT 1
#endif
.macro str1w ptr reg abort .macro str1w ptr reg abort
strusr \reg, \ptr, 4, abort=\abort strusr \reg, \ptr, 4, abort=\abort
.endm .endm
...@@ -72,6 +75,20 @@ ...@@ -72,6 +75,20 @@
str1w \ptr, \reg8, \abort str1w \ptr, \reg8, \abort
.endm .endm
#else
#define STR1W_SHIFT 0
.macro str1w ptr reg abort
USERL(\abort, W(str) \reg, [\ptr], #4)
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
USERL(\abort, stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8})
.endm
#endif /* CONFIG_CPU_USE_DOMAINS */
.macro str1b ptr reg cond=al abort .macro str1b ptr reg cond=al abort
strusr \reg, \ptr, 1, \cond, abort=\abort strusr \reg, \ptr, 1, \cond, abort=\abort
.endm .endm
......
...@@ -42,6 +42,12 @@ _ASM_NOKPROBE(__get_user_1) ...@@ -42,6 +42,12 @@ _ASM_NOKPROBE(__get_user_1)
ENTRY(__get_user_2) ENTRY(__get_user_2)
check_uaccess r0, 2, r1, r2, __get_user_bad check_uaccess r0, 2, r1, r2, __get_user_bad
#if __LINUX_ARM_ARCH__ >= 6
2: TUSER(ldrh) r2, [r0]
#else
#ifdef CONFIG_CPU_USE_DOMAINS #ifdef CONFIG_CPU_USE_DOMAINS
rb .req ip rb .req ip
2: ldrbt r2, [r0], #1 2: ldrbt r2, [r0], #1
...@@ -56,6 +62,9 @@ rb .req r0 ...@@ -56,6 +62,9 @@ rb .req r0
#else #else
orr r2, rb, r2, lsl #8 orr r2, rb, r2, lsl #8
#endif #endif
#endif /* __LINUX_ARM_ARCH__ >= 6 */
mov r0, #0 mov r0, #0
ret lr ret lr
ENDPROC(__get_user_2) ENDPROC(__get_user_2)
...@@ -145,7 +154,9 @@ _ASM_NOKPROBE(__get_user_bad8) ...@@ -145,7 +154,9 @@ _ASM_NOKPROBE(__get_user_bad8)
.pushsection __ex_table, "a" .pushsection __ex_table, "a"
.long 1b, __get_user_bad .long 1b, __get_user_bad
.long 2b, __get_user_bad .long 2b, __get_user_bad
#if __LINUX_ARM_ARCH__ < 6
.long 3b, __get_user_bad .long 3b, __get_user_bad
#endif
.long 4b, __get_user_bad .long 4b, __get_user_bad
.long 5b, __get_user_bad8 .long 5b, __get_user_bad8
.long 6b, __get_user_bad8 .long 6b, __get_user_bad8
......
...@@ -41,16 +41,13 @@ ENDPROC(__put_user_1) ...@@ -41,16 +41,13 @@ ENDPROC(__put_user_1)
ENTRY(__put_user_2) ENTRY(__put_user_2)
check_uaccess r0, 2, r1, ip, __put_user_bad check_uaccess r0, 2, r1, ip, __put_user_bad
mov ip, r2, lsr #8 #if __LINUX_ARM_ARCH__ >= 6
#ifdef CONFIG_THUMB2_KERNEL
#ifndef __ARMEB__ 2: TUSER(strh) r2, [r0]
2: TUSER(strb) r2, [r0]
3: TUSER(strb) ip, [r0, #1]
#else #else
2: TUSER(strb) ip, [r0]
3: TUSER(strb) r2, [r0, #1] mov ip, r2, lsr #8
#endif
#else /* !CONFIG_THUMB2_KERNEL */
#ifndef __ARMEB__ #ifndef __ARMEB__
2: TUSER(strb) r2, [r0], #1 2: TUSER(strb) r2, [r0], #1
3: TUSER(strb) ip, [r0] 3: TUSER(strb) ip, [r0]
...@@ -58,7 +55,8 @@ ENTRY(__put_user_2) ...@@ -58,7 +55,8 @@ ENTRY(__put_user_2)
2: TUSER(strb) ip, [r0], #1 2: TUSER(strb) ip, [r0], #1
3: TUSER(strb) r2, [r0] 3: TUSER(strb) r2, [r0]
#endif #endif
#endif /* CONFIG_THUMB2_KERNEL */
#endif /* __LINUX_ARM_ARCH__ >= 6 */
mov r0, #0 mov r0, #0
ret lr ret lr
ENDPROC(__put_user_2) ENDPROC(__put_user_2)
...@@ -91,7 +89,9 @@ ENDPROC(__put_user_bad) ...@@ -91,7 +89,9 @@ ENDPROC(__put_user_bad)
.pushsection __ex_table, "a" .pushsection __ex_table, "a"
.long 1b, __put_user_bad .long 1b, __put_user_bad
.long 2b, __put_user_bad .long 2b, __put_user_bad
#if __LINUX_ARM_ARCH__ < 6
.long 3b, __put_user_bad .long 3b, __put_user_bad
#endif
.long 4b, __put_user_bad .long 4b, __put_user_bad
.long 5b, __put_user_bad .long 5b, __put_user_bad
.long 6b, __put_user_bad .long 6b, __put_user_bad
......
...@@ -223,7 +223,6 @@ config MACH_NOKIA_N8X0 ...@@ -223,7 +223,6 @@ config MACH_NOKIA_N8X0
config OMAP3_SDRC_AC_TIMING config OMAP3_SDRC_AC_TIMING
bool "Enable SDRC AC timing register changes" bool "Enable SDRC AC timing register changes"
depends on ARCH_OMAP3 depends on ARCH_OMAP3
default n
help help
If you know that none of your system initiators will attempt to If you know that none of your system initiators will attempt to
access SDRAM during CORE DVFS, select Y here. This should boost access SDRAM during CORE DVFS, select Y here. This should boost
......
...@@ -69,8 +69,6 @@ static const struct omap_smp_config omap5_cfg __initconst = { ...@@ -69,8 +69,6 @@ static const struct omap_smp_config omap5_cfg __initconst = {
.startup_addr = omap5_secondary_startup, .startup_addr = omap5_secondary_startup,
}; };
static DEFINE_SPINLOCK(boot_lock);
void __iomem *omap4_get_scu_base(void) void __iomem *omap4_get_scu_base(void)
{ {
return cfg.scu_base; return cfg.scu_base;
...@@ -173,12 +171,6 @@ static void omap4_secondary_init(unsigned int cpu) ...@@ -173,12 +171,6 @@ static void omap4_secondary_init(unsigned int cpu)
/* Enable ACR to allow for ICUALLU workaround */ /* Enable ACR to allow for ICUALLU workaround */
omap5_secondary_harden_predictor(); omap5_secondary_harden_predictor();
} }
/*
* Synchronise with the boot thread.
*/
spin_lock(&boot_lock);
spin_unlock(&boot_lock);
} }
static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle)
...@@ -187,12 +179,6 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) ...@@ -187,12 +179,6 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle)
static bool booted; static bool booted;
static struct powerdomain *cpu1_pwrdm; static struct powerdomain *cpu1_pwrdm;
/*
* Set synchronisation state between this boot processor
* and the secondary one
*/
spin_lock(&boot_lock);
/* /*
* Update the AuxCoreBoot0 with boot state for secondary core. * Update the AuxCoreBoot0 with boot state for secondary core.
* omap4_secondary_startup() routine will hold the secondary core till * omap4_secondary_startup() routine will hold the secondary core till
...@@ -266,12 +252,6 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) ...@@ -266,12 +252,6 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle)
arch_send_wakeup_ipi_mask(cpumask_of(cpu)); arch_send_wakeup_ipi_mask(cpumask_of(cpu));
/*
* Now the secondary core is starting up let it run its
* calibrations, then wait for it to finish
*/
spin_unlock(&boot_lock);
return 0; return 0;
} }
......
...@@ -46,6 +46,7 @@ config ARCH_LUBBOCK ...@@ -46,6 +46,7 @@ config ARCH_LUBBOCK
config MACH_MAINSTONE config MACH_MAINSTONE
bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)" bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
select GPIO_REG
select PXA27x select PXA27x
config MACH_ZYLONITE config MACH_ZYLONITE
...@@ -551,7 +552,6 @@ config TOSA_BT ...@@ -551,7 +552,6 @@ config TOSA_BT
config TOSA_USE_EXT_KEYCODES config TOSA_USE_EXT_KEYCODES
bool "Tosa keyboard: use extended keycodes" bool "Tosa keyboard: use extended keycodes"
depends on MACH_TOSA depends on MACH_TOSA
default n
help help
Say Y here to enable the tosa keyboard driver to generate extended Say Y here to enable the tosa keyboard driver to generate extended
(>= 127) keycodes. Be aware, that they can't be correctly interpreted (>= 127) keycodes. Be aware, that they can't be correctly interpreted
......
...@@ -119,6 +119,10 @@ ...@@ -119,6 +119,10 @@
#define MST_PCMCIA_PWR_VCC_33 0x8 /* voltage VCC = 3.3V */ #define MST_PCMCIA_PWR_VCC_33 0x8 /* voltage VCC = 3.3V */
#define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */ #define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */
#define MST_PCMCIA_INPUTS \
(MST_PCMCIA_nIRQ | MST_PCMCIA_nSPKR_BVD2 | MST_PCMCIA_nSTSCHG_BVD1 | \
MST_PCMCIA_nVS2 | MST_PCMCIA_nVS1 | MST_PCMCIA_nCD)
/* board specific IRQs */ /* board specific IRQs */
#define MAINSTONE_NR_IRQS IRQ_BOARD_START #define MAINSTONE_NR_IRQS IRQ_BOARD_START
......
...@@ -136,10 +136,26 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = { ...@@ -136,10 +136,26 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = {
// no D+ pullup; lubbock can't connect/disconnect in software // no D+ pullup; lubbock can't connect/disconnect in software
}; };
/* GPIOs for SA1111 PCMCIA */
static struct gpiod_lookup_table sa1111_pcmcia_gpio_table = {
.dev_id = "1800",
.table = {
{ "sa1111", 0, "a0vpp", GPIO_ACTIVE_HIGH },
{ "sa1111", 1, "a1vpp", GPIO_ACTIVE_HIGH },
{ "sa1111", 2, "a0vcc", GPIO_ACTIVE_HIGH },
{ "sa1111", 3, "a1vcc", GPIO_ACTIVE_HIGH },
{ "lubbock", 14, "b0vcc", GPIO_ACTIVE_HIGH },
{ "lubbock", 15, "b1vcc", GPIO_ACTIVE_HIGH },
{ },
},
};
static void lubbock_init_pcmcia(void) static void lubbock_init_pcmcia(void)
{ {
struct clk *clk; struct clk *clk;
gpiod_add_lookup_table(&sa1111_pcmcia_gpio_table);
/* Add an alias for the SA1111 PCMCIA clock */ /* Add an alias for the SA1111 PCMCIA clock */
clk = clk_get_sys("pxa2xx-pcmcia", NULL); clk = clk_get_sys("pxa2xx-pcmcia", NULL);
if (!IS_ERR(clk)) { if (!IS_ERR(clk)) {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -504,12 +505,64 @@ static void __init mainstone_init_keypad(void) ...@@ -504,12 +505,64 @@ static void __init mainstone_init_keypad(void)
static inline void mainstone_init_keypad(void) {} static inline void mainstone_init_keypad(void) {}
#endif #endif
static int mst_pcmcia0_irqs[11] = {
[0 ... 10] = -1,
[5] = MAINSTONE_S0_CD_IRQ,
[8] = MAINSTONE_S0_STSCHG_IRQ,
[10] = MAINSTONE_S0_IRQ,
};
static int mst_pcmcia1_irqs[11] = {
[0 ... 10] = -1,
[5] = MAINSTONE_S1_CD_IRQ,
[8] = MAINSTONE_S1_STSCHG_IRQ,
[10] = MAINSTONE_S1_IRQ,
};
static struct gpiod_lookup_table mainstone_pcmcia_gpio_table = {
.dev_id = "pxa2xx-pcmcia",
.table = {
GPIO_LOOKUP("mst-pcmcia0", 0, "a0vpp", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia0", 1, "a1vpp", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia0", 2, "a0vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia0", 3, "a1vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia0", 4, "areset", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia0", 5, "adetect", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("mst-pcmcia0", 6, "avs1", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("mst-pcmcia0", 7, "avs2", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("mst-pcmcia0", 8, "abvd1", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia0", 9, "abvd2", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia0", 10, "aready", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia1", 0, "b0vpp", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia1", 1, "b1vpp", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia1", 2, "b0vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia1", 3, "b1vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia1", 4, "breset", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia1", 5, "bdetect", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("mst-pcmcia1", 6, "bvs1", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("mst-pcmcia1", 7, "bvs2", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("mst-pcmcia1", 8, "bbvd1", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia1", 9, "bbvd2", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("mst-pcmcia1", 10, "bready", GPIO_ACTIVE_HIGH),
{ },
},
};
static void __init mainstone_init(void) static void __init mainstone_init(void)
{ {
int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */ int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
pxa2xx_mfp_config(ARRAY_AND_SIZE(mainstone_pin_config)); pxa2xx_mfp_config(ARRAY_AND_SIZE(mainstone_pin_config));
/* Register board control register(s) as GPIOs */
gpio_reg_init(NULL, (void __iomem *)&MST_PCMCIA0, -1, 11,
"mst-pcmcia0", MST_PCMCIA_INPUTS, 0, NULL,
NULL, mst_pcmcia0_irqs);
gpio_reg_init(NULL, (void __iomem *)&MST_PCMCIA1, -1, 11,
"mst-pcmcia1", MST_PCMCIA_INPUTS, 0, NULL,
NULL, mst_pcmcia1_irqs);
gpiod_add_lookup_table(&mainstone_pcmcia_gpio_table);
pxa_set_ffuart_info(NULL); pxa_set_ffuart_info(NULL);
pxa_set_btuart_info(NULL); pxa_set_btuart_info(NULL);
pxa_set_stuart_info(NULL); pxa_set_stuart_info(NULL);
......
...@@ -5,4 +5,3 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-versatile/inc ...@@ -5,4 +5,3 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-versatile/inc
obj-y += realview-dt.o obj-y += realview-dt.o
obj-$(CONFIG_SMP) += platsmp-dt.o obj-$(CONFIG_SMP) += platsmp-dt.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
/*
* linux/arch/arm/mach-realview/hotplug.c
*
* Copyright (C) 2002 ARM Ltd.
* All Rights Reserved
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/smp.h>
#include <asm/cp15.h>
#include <asm/smp_plat.h>
static inline void cpu_enter_lowpower(void)
{
unsigned int v;
asm volatile(
" mcr p15, 0, %1, c7, c5, 0\n"
" mcr p15, 0, %1, c7, c10, 4\n"
/*
* Turn off coherency
*/
" mrc p15, 0, %0, c1, c0, 1\n"
" bic %0, %0, #0x20\n"
" mcr p15, 0, %0, c1, c0, 1\n"
" mrc p15, 0, %0, c1, c0, 0\n"
" bic %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 0\n"
: "=&r" (v)
: "r" (0), "Ir" (CR_C)
: "cc");
}
static inline void cpu_leave_lowpower(void)
{
unsigned int v;
asm volatile( "mrc p15, 0, %0, c1, c0, 0\n"
" orr %0, %0, %1\n"
" mcr p15, 0, %0, c1, c0, 0\n"
" mrc p15, 0, %0, c1, c0, 1\n"
" orr %0, %0, #0x20\n"
" mcr p15, 0, %0, c1, c0, 1\n"
: "=&r" (v)
: "Ir" (CR_C)
: "cc");
}
static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
{
/*
* there is no power-control hardware on this platform, so all
* we can do is put the core into WFI; this is safe as the calling
* code will have already disabled interrupts
*/
for (;;) {
/*
* here's the WFI
*/
asm(".word 0xe320f003\n"
:
:
: "memory", "cc");
if (pen_release == cpu_logical_map(cpu)) {
/*
* OK, proper wakeup, we're done
*/
break;
}
/*
* Getting here, means that we have come out of WFI without
* having been woken up - this shouldn't happen
*
* Just note it happening - when we're woken, we can report
* its occurrence.
*/
(*spurious)++;
}
}
/*
* platform-specific code to shutdown a CPU
*
* Called with IRQs disabled
*/
void realview_cpu_die(unsigned int cpu)
{
int spurious = 0;
/*
* we're ready for shutdown now, so do it
*/
cpu_enter_lowpower();
platform_do_lowpower(cpu, &spurious);
/*
* bring this CPU back into the world of cache
* coherency, and then restore interrupts
*/
cpu_leave_lowpower();
if (spurious)
pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
}
void realview_cpu_die(unsigned int cpu);
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <asm/smp_scu.h> #include <asm/smp_scu.h>
#include <plat/platsmp.h> #include <plat/platsmp.h>
#include "hotplug.h"
#define REALVIEW_SYS_FLAGSSET_OFFSET 0x30 #define REALVIEW_SYS_FLAGSSET_OFFSET 0x30
...@@ -79,6 +78,13 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus) ...@@ -79,6 +78,13 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
__pa_symbol(versatile_secondary_startup)); __pa_symbol(versatile_secondary_startup));
} }
#ifdef CONFIG_HOTPLUG_CPU
static void realview_cpu_die(unsigned int cpu)
{
return versatile_immitation_cpu_die(cpu, 0x20);
}
#endif
static const struct smp_operations realview_dt_smp_ops __initconst = { static const struct smp_operations realview_dt_smp_ops __initconst = {
.smp_prepare_cpus = realview_smp_prepare_cpus, .smp_prepare_cpus = realview_smp_prepare_cpus,
.smp_secondary_init = versatile_secondary_init, .smp_secondary_init = versatile_secondary_init,
......
...@@ -6,6 +6,7 @@ config SA1100_ASSABET ...@@ -6,6 +6,7 @@ config SA1100_ASSABET
bool "Assabet" bool "Assabet"
select ARM_SA1110_CPUFREQ select ARM_SA1110_CPUFREQ
select GPIO_REG select GPIO_REG
select LEDS_GPIO_REGISTER
select REGULATOR select REGULATOR
select REGULATOR_FIXED_VOLTAGE select REGULATOR_FIXED_VOLTAGE
help help
...@@ -24,6 +25,7 @@ config ASSABET_NEPONSET ...@@ -24,6 +25,7 @@ config ASSABET_NEPONSET
config SA1100_CERF config SA1100_CERF
bool "CerfBoard" bool "CerfBoard"
select ARM_SA1110_CPUFREQ select ARM_SA1110_CPUFREQ
select LEDS_GPIO_REGISTER
help help
The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued). The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued).
More information is available at: More information is available at:
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio/gpio-reg.h> #include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
#include <linux/gpio_keys.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/platform_data/sa11x0-serial.h> #include <linux/platform_data/sa11x0-serial.h>
#include <linux/regulator/fixed.h> #include <linux/regulator/fixed.h>
...@@ -101,7 +102,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val) ...@@ -101,7 +102,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val)
assabet_bcr_gc = gc; assabet_bcr_gc = gc;
return 0; return gc->base;
} }
/* /*
...@@ -479,6 +480,49 @@ static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = { ...@@ -479,6 +480,49 @@ static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = {
}, },
}; };
static struct gpio_led assabet_leds[] __initdata = {
{
.name = "assabet:red",
.default_trigger = "cpu0",
.active_low = 1,
.default_state = LEDS_GPIO_DEFSTATE_KEEP,
}, {
.name = "assabet:green",
.default_trigger = "heartbeat",
.active_low = 1,
.default_state = LEDS_GPIO_DEFSTATE_KEEP,
},
};
static const struct gpio_led_platform_data assabet_leds_pdata __initconst = {
.num_leds = ARRAY_SIZE(assabet_leds),
.leds = assabet_leds,
};
static struct gpio_keys_button assabet_keys_buttons[] = {
{
.gpio = 0,
.irq = IRQ_GPIO0,
.desc = "gpio0",
.wakeup = 1,
.can_disable = 1,
.debounce_interval = 5,
}, {
.gpio = 1,
.irq = IRQ_GPIO1,
.desc = "gpio1",
.wakeup = 1,
.can_disable = 1,
.debounce_interval = 5,
},
};
static const struct gpio_keys_platform_data assabet_keys_pdata = {
.buttons = assabet_keys_buttons,
.nbuttons = ARRAY_SIZE(assabet_keys_buttons),
.rep = 0,
};
static void __init assabet_init(void) static void __init assabet_init(void)
{ {
/* /*
...@@ -533,6 +577,13 @@ static void __init assabet_init(void) ...@@ -533,6 +577,13 @@ static void __init assabet_init(void)
} }
platform_device_register_resndata(NULL, "gpio-keys", 0,
NULL, 0,
&assabet_keys_pdata,
sizeof(assabet_keys_pdata));
gpio_led_register_device(-1, &assabet_leds_pdata);
#ifndef ASSABET_PAL_VIDEO #ifndef ASSABET_PAL_VIDEO
sa11x0_register_lcd(&lq039q2ds54_info); sa11x0_register_lcd(&lq039q2ds54_info);
#else #else
...@@ -726,92 +777,9 @@ static void __init assabet_map_io(void) ...@@ -726,92 +777,9 @@ static void __init assabet_map_io(void)
sa1100_register_uart(2, 3); sa1100_register_uart(2, 3);
} }
/* LEDs */
#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
struct assabet_led {
struct led_classdev cdev;
u32 mask;
};
/*
* The triggers lines up below will only be used if the
* LED triggers are compiled in.
*/
static const struct {
const char *name;
const char *trigger;
} assabet_leds[] = {
{ "assabet:red", "cpu0",},
{ "assabet:green", "heartbeat", },
};
/*
* The LED control in Assabet is reversed:
* - setting bit means turn off LED
* - clearing bit means turn on LED
*/
static void assabet_led_set(struct led_classdev *cdev,
enum led_brightness b)
{
struct assabet_led *led = container_of(cdev,
struct assabet_led, cdev);
if (b != LED_OFF)
ASSABET_BCR_clear(led->mask);
else
ASSABET_BCR_set(led->mask);
}
static enum led_brightness assabet_led_get(struct led_classdev *cdev)
{
struct assabet_led *led = container_of(cdev,
struct assabet_led, cdev);
return (ASSABET_BCR & led->mask) ? LED_OFF : LED_FULL;
}
static int __init assabet_leds_init(void)
{
int i;
if (!machine_is_assabet())
return -ENODEV;
for (i = 0; i < ARRAY_SIZE(assabet_leds); i++) {
struct assabet_led *led;
led = kzalloc(sizeof(*led), GFP_KERNEL);
if (!led)
break;
led->cdev.name = assabet_leds[i].name;
led->cdev.brightness_set = assabet_led_set;
led->cdev.brightness_get = assabet_led_get;
led->cdev.default_trigger = assabet_leds[i].trigger;
if (!i)
led->mask = ASSABET_BCR_LED_RED;
else
led->mask = ASSABET_BCR_LED_GREEN;
if (led_classdev_register(NULL, &led->cdev) < 0) {
kfree(led);
break;
}
}
return 0;
}
/*
* Since we may have triggers on any subsystem, defer registration
* until after subsystem_init.
*/
fs_initcall(assabet_leds_init);
#endif
void __init assabet_init_irq(void) void __init assabet_init_irq(void)
{ {
unsigned int assabet_gpio_base;
u32 def_val; u32 def_val;
sa1100_init_irq(); sa1100_init_irq();
...@@ -826,7 +794,10 @@ void __init assabet_init_irq(void) ...@@ -826,7 +794,10 @@ void __init assabet_init_irq(void)
* *
* This must precede any driver calls to BCR_set() or BCR_clear(). * This must precede any driver calls to BCR_set() or BCR_clear().
*/ */
assabet_init_gpio((void *)&ASSABET_BCR, def_val); assabet_gpio_base = assabet_init_gpio((void *)&ASSABET_BCR, def_val);
assabet_leds[0].gpio = assabet_gpio_base + 13;
assabet_leds[1].gpio = assabet_gpio_base + 14;
} }
MACHINE_START(ASSABET, "Intel-Assabet") MACHINE_START(ASSABET, "Intel-Assabet")
......
...@@ -89,18 +89,8 @@ static struct gpio_led_platform_data cerf_gpio_led_info = { ...@@ -89,18 +89,8 @@ static struct gpio_led_platform_data cerf_gpio_led_info = {
.num_leds = ARRAY_SIZE(cerf_gpio_leds), .num_leds = ARRAY_SIZE(cerf_gpio_leds),
}; };
static struct platform_device cerf_leds = {
.name = "leds-gpio",
.id = -1,
.dev = {
.platform_data = &cerf_gpio_led_info,
}
};
static struct platform_device *cerf_devices[] __initdata = { static struct platform_device *cerf_devices[] __initdata = {
&cerfuart2_device, &cerfuart2_device,
&cerf_leds,
}; };
#ifdef CONFIG_SA1100_CERF_FLASH_32MB #ifdef CONFIG_SA1100_CERF_FLASH_32MB
...@@ -176,6 +166,7 @@ static void __init cerf_init(void) ...@@ -176,6 +166,7 @@ static void __init cerf_init(void)
{ {
sa11x0_ppc_configure_mcp(); sa11x0_ppc_configure_mcp();
platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices)); platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
gpio_led_register_device(-1, &cerf_gpio_led_info);
sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1); sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
sa11x0_register_mcp(&cerf_mcp_data); sa11x0_register_mcp(&cerf_mcp_data);
sa11x0_register_pcmcia(1, &cerf_cf_gpio_table); sa11x0_register_pcmcia(1, &cerf_cf_gpio_table);
......
...@@ -235,18 +235,11 @@ void sa11x0_register_lcd(struct sa1100fb_mach_info *inf) ...@@ -235,18 +235,11 @@ void sa11x0_register_lcd(struct sa1100fb_mach_info *inf)
sa11x0_register_device(&sa11x0fb_device, inf); sa11x0_register_device(&sa11x0fb_device, inf);
} }
static bool sa11x0pcmcia_legacy = true;
static struct platform_device sa11x0pcmcia_device = {
.name = "sa11x0-pcmcia",
.id = -1,
};
void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *table) void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *table)
{ {
if (table) if (table)
gpiod_add_lookup_table(table); gpiod_add_lookup_table(table);
platform_device_register_simple("sa11x0-pcmcia", socket, NULL, 0); platform_device_register_simple("sa11x0-pcmcia", socket, NULL, 0);
sa11x0pcmcia_legacy = false;
} }
static struct platform_device sa11x0mtd_device = { static struct platform_device sa11x0mtd_device = {
...@@ -331,9 +324,6 @@ static int __init sa1100_init(void) ...@@ -331,9 +324,6 @@ static int __init sa1100_init(void)
{ {
pm_power_off = sa1100_power_off; pm_power_off = sa1100_power_off;
if (sa11x0pcmcia_legacy)
platform_device_register(&sa11x0pcmcia_device);
regulator_has_full_constraints(); regulator_has_full_constraints();
return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices)); return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices));
......
...@@ -126,6 +126,7 @@ static void __init h3100_mach_init(void) ...@@ -126,6 +126,7 @@ static void __init h3100_mach_init(void)
{ {
h3xxx_mach_init(); h3xxx_mach_init();
sa11x0_register_pcmcia(-1, NULL);
sa11x0_register_lcd(&h3100_lcd_info); sa11x0_register_lcd(&h3100_lcd_info);
sa11x0_register_irda(&h3100_irda_data); sa11x0_register_irda(&h3100_irda_data);
} }
......
...@@ -190,6 +190,17 @@ static struct platform_device s1d13xxxfb_device = { ...@@ -190,6 +190,17 @@ static struct platform_device s1d13xxxfb_device = {
.resource = s1d13xxxfb_resources, .resource = s1d13xxxfb_resources,
}; };
static struct gpiod_lookup_table jornada_pcmcia_gpiod_table = {
.dev_id = "1800",
.table = {
GPIO_LOOKUP("sa1111", 0, "s0-power", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 1, "s1-power", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 2, "s0-3v", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 3, "s1-3v", GPIO_ACTIVE_HIGH),
{ },
},
};
static struct resource sa1111_resources[] = { static struct resource sa1111_resources[] = {
[0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN), [0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
[1] = DEFINE_RES_IRQ(IRQ_GPIO1), [1] = DEFINE_RES_IRQ(IRQ_GPIO1),
...@@ -265,6 +276,7 @@ static int __init jornada720_init(void) ...@@ -265,6 +276,7 @@ static int __init jornada720_init(void)
udelay(20); /* give it some time to restart */ udelay(20); /* give it some time to restart */
gpiod_add_lookup_table(&jornada_ts_gpiod_table); gpiod_add_lookup_table(&jornada_ts_gpiod_table);
gpiod_add_lookup_table(&jornada_pcmcia_gpiod_table);
ret = platform_add_devices(devices, ARRAY_SIZE(devices)); ret = platform_add_devices(devices, ARRAY_SIZE(devices));
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/gpio/gpio-reg.h> #include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -96,6 +97,19 @@ struct neponset_drvdata { ...@@ -96,6 +97,19 @@ struct neponset_drvdata {
struct gpio_chip *gpio[4]; struct gpio_chip *gpio[4];
}; };
static struct gpiod_lookup_table neponset_pcmcia_table = {
.dev_id = "1800",
.table = {
GPIO_LOOKUP("sa1111", 1, "a0vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 0, "a1vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("neponset-ncr", 5, "a0vpp", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("neponset-ncr", 6, "a1vpp", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 2, "b0vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 3, "b1vcc", GPIO_ACTIVE_HIGH),
{ },
},
};
static struct neponset_drvdata *nep; static struct neponset_drvdata *nep;
void neponset_ncr_frob(unsigned int mask, unsigned int val) void neponset_ncr_frob(unsigned int mask, unsigned int val)
...@@ -374,6 +388,8 @@ static int neponset_probe(struct platform_device *dev) ...@@ -374,6 +388,8 @@ static int neponset_probe(struct platform_device *dev)
d->base + AUD_CTL, AUD_NGPIO, false, d->base + AUD_CTL, AUD_NGPIO, false,
neponset_aud_names); neponset_aud_names);
gpiod_add_lookup_table(&neponset_pcmcia_table);
/* /*
* We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
* something on the Neponset activates this IRQ on sleep (eth?) * something on the Neponset activates this IRQ on sleep (eth?)
...@@ -424,6 +440,9 @@ static int neponset_remove(struct platform_device *dev) ...@@ -424,6 +440,9 @@ static int neponset_remove(struct platform_device *dev)
platform_device_unregister(d->sa1111); platform_device_unregister(d->sa1111);
if (!IS_ERR(d->smc91x)) if (!IS_ERR(d->smc91x))
platform_device_unregister(d->smc91x); platform_device_unregister(d->smc91x);
gpiod_remove_lookup_table(&neponset_pcmcia_table);
irq_set_chained_handler(irq, NULL); irq_set_chained_handler(irq, NULL);
irq_free_descs(d->irq_base, NEP_IRQ_NR); irq_free_descs(d->irq_base, NEP_IRQ_NR);
nep = NULL; nep = NULL;
......
...@@ -15,6 +15,5 @@ obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o ...@@ -15,6 +15,5 @@ obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o
CFLAGS_tc2_pm.o += -march=armv7-a CFLAGS_tc2_pm.o += -march=armv7-a
CFLAGS_REMOVE_tc2_pm.o = -pg CFLAGS_REMOVE_tc2_pm.o = -pg
obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_ARCH_MPS2) += v2m-mps2.o obj-$(CONFIG_ARCH_MPS2) += v2m-mps2.o
bool vexpress_smp_init_ops(void); bool vexpress_smp_init_ops(void);
extern const struct smp_operations vexpress_smp_dt_ops; extern const struct smp_operations vexpress_smp_dt_ops;
extern void vexpress_cpu_die(unsigned int cpu);
...@@ -82,6 +82,13 @@ static void __init vexpress_smp_dt_prepare_cpus(unsigned int max_cpus) ...@@ -82,6 +82,13 @@ static void __init vexpress_smp_dt_prepare_cpus(unsigned int max_cpus)
vexpress_flags_set(__pa_symbol(versatile_secondary_startup)); vexpress_flags_set(__pa_symbol(versatile_secondary_startup));
} }
#ifdef CONFIG_HOTPLUG_CPU
static void vexpress_cpu_die(unsigned int cpu)
{
versatile_immitation_cpu_die(cpu, 0x40);
}
#endif
const struct smp_operations vexpress_smp_dt_ops __initconst = { const struct smp_operations vexpress_smp_dt_ops __initconst = {
.smp_prepare_cpus = vexpress_smp_dt_prepare_cpus, .smp_prepare_cpus = vexpress_smp_dt_prepare_cpus,
.smp_secondary_init = versatile_secondary_init, .smp_secondary_init = versatile_secondary_init,
......
...@@ -17,26 +17,25 @@ ...@@ -17,26 +17,25 @@
/* /*
* Faraday optimised copy_user_page * Faraday optimised copy_user_page
*/ */
static void __naked static void fa_copy_user_page(void *kto, const void *kfrom)
fa_copy_user_page(void *kto, const void *kfrom)
{ {
asm("\ int tmp;
stmfd sp!, {r4, lr} @ 2\n\
mov r2, %0 @ 1\n\ asm volatile ("\
1: ldmia r1!, {r3, r4, ip, lr} @ 4\n\ 1: ldmia %1!, {r3, r4, ip, lr} @ 4\n\
stmia r0, {r3, r4, ip, lr} @ 4\n\ stmia %0, {r3, r4, ip, lr} @ 4\n\
mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\ mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\
add r0, r0, #16 @ 1\n\ add %0, %0, #16 @ 1\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\ ldmia %1!, {r3, r4, ip, lr} @ 4\n\
stmia r0, {r3, r4, ip, lr} @ 4\n\ stmia %0, {r3, r4, ip, lr} @ 4\n\
mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\ mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\
add r0, r0, #16 @ 1\n\ add %0, %0, #16 @ 1\n\
subs r2, r2, #1 @ 1\n\ subs %2, %2, #1 @ 1\n\
bne 1b @ 1\n\ bne 1b @ 1\n\
mcr p15, 0, r2, c7, c10, 4 @ 1 drain WB\n\ mcr p15, 0, %2, c7, c10, 4 @ 1 drain WB"
ldmfd sp!, {r4, pc} @ 3" : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
: : "2" (PAGE_SIZE / 32)
: "I" (PAGE_SIZE / 32)); : "r3", "r4", "ip", "lr");
} }
void fa_copy_user_highpage(struct page *to, struct page *from, void fa_copy_user_highpage(struct page *to, struct page *from,
......
...@@ -13,58 +13,56 @@ ...@@ -13,58 +13,56 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/highmem.h> #include <linux/highmem.h>
static void __naked static void feroceon_copy_user_page(void *kto, const void *kfrom)
feroceon_copy_user_page(void *kto, const void *kfrom)
{ {
asm("\ int tmp;
stmfd sp!, {r4-r9, lr} \n\
mov ip, %2 \n\ asm volatile ("\
1: mov lr, r1 \n\ 1: ldmia %1!, {r2 - r7, ip, lr} \n\
ldmia r1!, {r2 - r9} \n\ pld [%1, #0] \n\
pld [lr, #32] \n\ pld [%1, #32] \n\
pld [lr, #64] \n\ pld [%1, #64] \n\
pld [lr, #96] \n\ pld [%1, #96] \n\
pld [lr, #128] \n\ pld [%1, #128] \n\
pld [lr, #160] \n\ pld [%1, #160] \n\
pld [lr, #192] \n\ pld [%1, #192] \n\
pld [lr, #224] \n\ stmia %0, {r2 - r7, ip, lr} \n\
stmia r0, {r2 - r9} \n\ ldmia %1!, {r2 - r7, ip, lr} \n\
ldmia r1!, {r2 - r9} \n\ mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ add %0, %0, #32 \n\
add r0, r0, #32 \n\ stmia %0, {r2 - r7, ip, lr} \n\
stmia r0, {r2 - r9} \n\ ldmia %1!, {r2 - r7, ip, lr} \n\
ldmia r1!, {r2 - r9} \n\ mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ add %0, %0, #32 \n\
add r0, r0, #32 \n\ stmia %0, {r2 - r7, ip, lr} \n\
stmia r0, {r2 - r9} \n\ ldmia %1!, {r2 - r7, ip, lr} \n\
ldmia r1!, {r2 - r9} \n\ mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ add %0, %0, #32 \n\
add r0, r0, #32 \n\ stmia %0, {r2 - r7, ip, lr} \n\
stmia r0, {r2 - r9} \n\ ldmia %1!, {r2 - r7, ip, lr} \n\
ldmia r1!, {r2 - r9} \n\ mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ add %0, %0, #32 \n\
add r0, r0, #32 \n\ stmia %0, {r2 - r7, ip, lr} \n\
stmia r0, {r2 - r9} \n\ ldmia %1!, {r2 - r7, ip, lr} \n\
ldmia r1!, {r2 - r9} \n\ mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ add %0, %0, #32 \n\
add r0, r0, #32 \n\ stmia %0, {r2 - r7, ip, lr} \n\
stmia r0, {r2 - r9} \n\ ldmia %1!, {r2 - r7, ip, lr} \n\
ldmia r1!, {r2 - r9} \n\ mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ add %0, %0, #32 \n\
add r0, r0, #32 \n\ stmia %0, {r2 - r7, ip, lr} \n\
stmia r0, {r2 - r9} \n\ ldmia %1!, {r2 - r7, ip, lr} \n\
ldmia r1!, {r2 - r9} \n\ mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ add %0, %0, #32 \n\
add r0, r0, #32 \n\ stmia %0, {r2 - r7, ip, lr} \n\
stmia r0, {r2 - r9} \n\ subs %2, %2, #(32 * 8) \n\
subs ip, ip, #(32 * 8) \n\ mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\ add %0, %0, #32 \n\
add r0, r0, #32 \n\
bne 1b \n\ bne 1b \n\
mcr p15, 0, ip, c7, c10, 4 @ drain WB\n\ mcr p15, 0, %2, c7, c10, 4 @ drain WB"
ldmfd sp!, {r4-r9, pc}" : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
: : "2" (PAGE_SIZE)
: "r" (kto), "r" (kfrom), "I" (PAGE_SIZE)); : "r2", "r3", "r4", "r5", "r6", "r7", "ip", "lr");
} }
void feroceon_copy_user_highpage(struct page *to, struct page *from, void feroceon_copy_user_highpage(struct page *to, struct page *from,
......
...@@ -40,12 +40,11 @@ static DEFINE_RAW_SPINLOCK(minicache_lock); ...@@ -40,12 +40,11 @@ static DEFINE_RAW_SPINLOCK(minicache_lock);
* instruction. If your processor does not supply this, you have to write your * instruction. If your processor does not supply this, you have to write your
* own copy_user_highpage that does the right thing. * own copy_user_highpage that does the right thing.
*/ */
static void __naked static void mc_copy_user_page(void *from, void *to)
mc_copy_user_page(void *from, void *to)
{ {
asm volatile( int tmp;
"stmfd sp!, {r4, lr} @ 2\n\
mov r4, %2 @ 1\n\ asm volatile ("\
ldmia %0!, {r2, r3, ip, lr} @ 4\n\ ldmia %0!, {r2, r3, ip, lr} @ 4\n\
1: mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ 1: mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\
stmia %1!, {r2, r3, ip, lr} @ 4\n\ stmia %1!, {r2, r3, ip, lr} @ 4\n\
...@@ -55,13 +54,13 @@ mc_copy_user_page(void *from, void *to) ...@@ -55,13 +54,13 @@ mc_copy_user_page(void *from, void *to)
mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\
stmia %1!, {r2, r3, ip, lr} @ 4\n\ stmia %1!, {r2, r3, ip, lr} @ 4\n\
ldmia %0!, {r2, r3, ip, lr} @ 4\n\ ldmia %0!, {r2, r3, ip, lr} @ 4\n\
subs r4, r4, #1 @ 1\n\ subs %2, %2, #1 @ 1\n\
stmia %1!, {r2, r3, ip, lr} @ 4\n\ stmia %1!, {r2, r3, ip, lr} @ 4\n\
ldmneia %0!, {r2, r3, ip, lr} @ 4\n\ ldmneia %0!, {r2, r3, ip, lr} @ 4\n\
bne 1b @ 1\n\ bne 1b @ "
ldmfd sp!, {r4, pc} @ 3" : "+&r" (from), "+&r" (to), "=&r" (tmp)
: : "2" (PAGE_SIZE / 64)
: "r" (from), "r" (to), "I" (PAGE_SIZE / 64)); : "r2", "r3", "ip", "lr");
} }
void v4_mc_copy_user_highpage(struct page *to, struct page *from, void v4_mc_copy_user_highpage(struct page *to, struct page *from,
......
...@@ -22,29 +22,28 @@ ...@@ -22,29 +22,28 @@
* instruction. If your processor does not supply this, you have to write your * instruction. If your processor does not supply this, you have to write your
* own copy_user_highpage that does the right thing. * own copy_user_highpage that does the right thing.
*/ */
static void __naked static void v4wb_copy_user_page(void *kto, const void *kfrom)
v4wb_copy_user_page(void *kto, const void *kfrom)
{ {
asm("\ int tmp;
stmfd sp!, {r4, lr} @ 2\n\
mov r2, %2 @ 1\n\ asm volatile ("\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\ ldmia %1!, {r3, r4, ip, lr} @ 4\n\
1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\ 1: mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\ stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4+1\n\ ldmia %1!, {r3, r4, ip, lr} @ 4+1\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\ stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\ ldmia %1!, {r3, r4, ip, lr} @ 4\n\
mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\ mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\ stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\ ldmia %1!, {r3, r4, ip, lr} @ 4\n\
subs r2, r2, #1 @ 1\n\ subs %2, %2, #1 @ 1\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\ stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmneia r1!, {r3, r4, ip, lr} @ 4\n\ ldmneia %1!, {r3, r4, ip, lr} @ 4\n\
bne 1b @ 1\n\ bne 1b @ 1\n\
mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB\n\ mcr p15, 0, %1, c7, c10, 4 @ 1 drain WB"
ldmfd sp!, {r4, pc} @ 3" : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
: : "2" (PAGE_SIZE / 64)
: "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64)); : "r3", "r4", "ip", "lr");
} }
void v4wb_copy_user_highpage(struct page *to, struct page *from, void v4wb_copy_user_highpage(struct page *to, struct page *from,
......
...@@ -20,27 +20,26 @@ ...@@ -20,27 +20,26 @@
* dirty data in the cache. However, we do have to ensure that * dirty data in the cache. However, we do have to ensure that
* subsequent reads are up to date. * subsequent reads are up to date.
*/ */
static void __naked static void v4wt_copy_user_page(void *kto, const void *kfrom)
v4wt_copy_user_page(void *kto, const void *kfrom)
{ {
asm("\ int tmp;
stmfd sp!, {r4, lr} @ 2\n\
mov r2, %2 @ 1\n\ asm volatile ("\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\ ldmia %1!, {r3, r4, ip, lr} @ 4\n\
1: stmia r0!, {r3, r4, ip, lr} @ 4\n\ 1: stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4+1\n\ ldmia %1!, {r3, r4, ip, lr} @ 4+1\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\ stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\ ldmia %1!, {r3, r4, ip, lr} @ 4\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\ stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\ ldmia %1!, {r3, r4, ip, lr} @ 4\n\
subs r2, r2, #1 @ 1\n\ subs %2, %2, #1 @ 1\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\ stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmneia r1!, {r3, r4, ip, lr} @ 4\n\ ldmneia %1!, {r3, r4, ip, lr} @ 4\n\
bne 1b @ 1\n\ bne 1b @ 1\n\
mcr p15, 0, r2, c7, c7, 0 @ flush ID cache\n\ mcr p15, 0, %2, c7, c7, 0 @ flush ID cache"
ldmfd sp!, {r4, pc} @ 3" : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
: : "2" (PAGE_SIZE / 64)
: "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64)); : "r3", "r4", "ip", "lr");
} }
void v4wt_copy_user_highpage(struct page *to, struct page *from, void v4wt_copy_user_highpage(struct page *to, struct page *from,
......
...@@ -21,53 +21,46 @@ ...@@ -21,53 +21,46 @@
/* /*
* XSC3 optimised copy_user_highpage * XSC3 optimised copy_user_highpage
* r0 = destination
* r1 = source
* *
* The source page may have some clean entries in the cache already, but we * The source page may have some clean entries in the cache already, but we
* can safely ignore them - break_cow() will flush them out of the cache * can safely ignore them - break_cow() will flush them out of the cache
* if we eventually end up using our copied page. * if we eventually end up using our copied page.
* *
*/ */
static void __naked static void xsc3_mc_copy_user_page(void *kto, const void *kfrom)
xsc3_mc_copy_user_page(void *kto, const void *kfrom)
{ {
asm("\ int tmp;
stmfd sp!, {r4, r5, lr} \n\
mov lr, %2 \n\ asm volatile ("\
\n\ pld [%1, #0] \n\
pld [r1, #0] \n\ pld [%1, #32] \n\
pld [r1, #32] \n\ 1: pld [%1, #64] \n\
1: pld [r1, #64] \n\ pld [%1, #96] \n\
pld [r1, #96] \n\
\n\ \n\
2: ldrd r2, [r1], #8 \n\ 2: ldrd r2, r3, [%1], #8 \n\
mov ip, r0 \n\ ldrd r4, r5, [%1], #8 \n\
ldrd r4, [r1], #8 \n\ mcr p15, 0, %0, c7, c6, 1 @ invalidate\n\
mcr p15, 0, ip, c7, c6, 1 @ invalidate\n\ strd r2, r3, [%0], #8 \n\
strd r2, [r0], #8 \n\ ldrd r2, r3, [%1], #8 \n\
ldrd r2, [r1], #8 \n\ strd r4, r5, [%0], #8 \n\
strd r4, [r0], #8 \n\ ldrd r4, r5, [%1], #8 \n\
ldrd r4, [r1], #8 \n\ strd r2, r3, [%0], #8 \n\
strd r2, [r0], #8 \n\ strd r4, r5, [%0], #8 \n\
strd r4, [r0], #8 \n\ ldrd r2, r3, [%1], #8 \n\
ldrd r2, [r1], #8 \n\ ldrd r4, r5, [%1], #8 \n\
mov ip, r0 \n\ mcr p15, 0, %0, c7, c6, 1 @ invalidate\n\
ldrd r4, [r1], #8 \n\ strd r2, r3, [%0], #8 \n\
mcr p15, 0, ip, c7, c6, 1 @ invalidate\n\ ldrd r2, r3, [%1], #8 \n\
strd r2, [r0], #8 \n\ subs %2, %2, #1 \n\
ldrd r2, [r1], #8 \n\ strd r4, r5, [%0], #8 \n\
subs lr, lr, #1 \n\ ldrd r4, r5, [%1], #8 \n\
strd r4, [r0], #8 \n\ strd r2, r3, [%0], #8 \n\
ldrd r4, [r1], #8 \n\ strd r4, r5, [%0], #8 \n\
strd r2, [r0], #8 \n\
strd r4, [r0], #8 \n\
bgt 1b \n\ bgt 1b \n\
beq 2b \n\ beq 2b "
\n\ : "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
ldmfd sp!, {r4, r5, pc}" : "2" (PAGE_SIZE / 64 - 1)
: : "r2", "r3", "r4", "r5");
: "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64 - 1));
} }
void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, void xsc3_mc_copy_user_highpage(struct page *to, struct page *from,
...@@ -85,8 +78,6 @@ void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, ...@@ -85,8 +78,6 @@ void xsc3_mc_copy_user_highpage(struct page *to, struct page *from,
/* /*
* XScale optimised clear_user_page * XScale optimised clear_user_page
* r0 = destination
* r1 = virtual user address of ultimate destination page
*/ */
void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr) void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
{ {
...@@ -96,10 +87,10 @@ void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr) ...@@ -96,10 +87,10 @@ void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
mov r2, #0 \n\ mov r2, #0 \n\
mov r3, #0 \n\ mov r3, #0 \n\
1: mcr p15, 0, %0, c7, c6, 1 @ invalidate line\n\ 1: mcr p15, 0, %0, c7, c6, 1 @ invalidate line\n\
strd r2, [%0], #8 \n\ strd r2, r3, [%0], #8 \n\
strd r2, [%0], #8 \n\ strd r2, r3, [%0], #8 \n\
strd r2, [%0], #8 \n\ strd r2, r3, [%0], #8 \n\
strd r2, [%0], #8 \n\ strd r2, r3, [%0], #8 \n\
subs r1, r1, #1 \n\ subs r1, r1, #1 \n\
bne 1b" bne 1b"
: "=r" (ptr) : "=r" (ptr)
......
...@@ -36,52 +36,51 @@ static DEFINE_RAW_SPINLOCK(minicache_lock); ...@@ -36,52 +36,51 @@ static DEFINE_RAW_SPINLOCK(minicache_lock);
* Dcache aliasing issue. The writes will be forwarded to the write buffer, * Dcache aliasing issue. The writes will be forwarded to the write buffer,
* and merged as appropriate. * and merged as appropriate.
*/ */
static void __naked static void mc_copy_user_page(void *from, void *to)
mc_copy_user_page(void *from, void *to)
{ {
int tmp;
/* /*
* Strangely enough, best performance is achieved * Strangely enough, best performance is achieved
* when prefetching destination as well. (NP) * when prefetching destination as well. (NP)
*/ */
asm volatile( asm volatile ("\
"stmfd sp!, {r4, r5, lr} \n\ pld [%0, #0] \n\
mov lr, %2 \n\ pld [%0, #32] \n\
pld [r0, #0] \n\ pld [%1, #0] \n\
pld [r0, #32] \n\ pld [%1, #32] \n\
pld [r1, #0] \n\ 1: pld [%0, #64] \n\
pld [r1, #32] \n\ pld [%0, #96] \n\
1: pld [r0, #64] \n\ pld [%1, #64] \n\
pld [r0, #96] \n\ pld [%1, #96] \n\
pld [r1, #64] \n\ 2: ldrd r2, r3, [%0], #8 \n\
pld [r1, #96] \n\ ldrd r4, r5, [%0], #8 \n\
2: ldrd r2, [r0], #8 \n\ mov ip, %1 \n\
ldrd r4, [r0], #8 \n\ strd r2, r3, [%1], #8 \n\
mov ip, r1 \n\ ldrd r2, r3, [%0], #8 \n\
strd r2, [r1], #8 \n\ strd r4, r5, [%1], #8 \n\
ldrd r2, [r0], #8 \n\ ldrd r4, r5, [%0], #8 \n\
strd r4, [r1], #8 \n\ strd r2, r3, [%1], #8 \n\
ldrd r4, [r0], #8 \n\ strd r4, r5, [%1], #8 \n\
strd r2, [r1], #8 \n\
strd r4, [r1], #8 \n\
mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\
ldrd r2, [r0], #8 \n\ ldrd r2, r3, [%0], #8 \n\
mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\
ldrd r4, [r0], #8 \n\ ldrd r4, r5, [%0], #8 \n\
mov ip, r1 \n\ mov ip, %1 \n\
strd r2, [r1], #8 \n\ strd r2, r3, [%1], #8 \n\
ldrd r2, [r0], #8 \n\ ldrd r2, r3, [%0], #8 \n\
strd r4, [r1], #8 \n\ strd r4, r5, [%1], #8 \n\
ldrd r4, [r0], #8 \n\ ldrd r4, r5, [%0], #8 \n\
strd r2, [r1], #8 \n\ strd r2, r3, [%1], #8 \n\
strd r4, [r1], #8 \n\ strd r4, r5, [%1], #8 \n\
mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\
subs lr, lr, #1 \n\ subs %2, %2, #1 \n\
mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\
bgt 1b \n\ bgt 1b \n\
beq 2b \n\ beq 2b "
ldmfd sp!, {r4, r5, pc} " : "+&r" (from), "+&r" (to), "=&r" (tmp)
: : "2" (PAGE_SIZE / 64 - 1)
: "r" (from), "r" (to), "I" (PAGE_SIZE / 64 - 1)); : "r2", "r3", "r4", "r5", "ip");
} }
void xscale_mc_copy_user_highpage(struct page *to, struct page *from, void xscale_mc_copy_user_highpage(struct page *to, struct page *from,
...@@ -115,10 +114,10 @@ xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr) ...@@ -115,10 +114,10 @@ xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
mov r2, #0 \n\ mov r2, #0 \n\
mov r3, #0 \n\ mov r3, #0 \n\
1: mov ip, %0 \n\ 1: mov ip, %0 \n\
strd r2, [%0], #8 \n\ strd r2, r3, [%0], #8 \n\
strd r2, [%0], #8 \n\ strd r2, r3, [%0], #8 \n\
strd r2, [%0], #8 \n\ strd r2, r3, [%0], #8 \n\
strd r2, [%0], #8 \n\ strd r2, r3, [%0], #8 \n\
mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\ mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\
subs r1, r1, #1 \n\ subs r1, r1, #1 \n\
mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\ mcr p15, 0, ip, c7, c6, 1 @ invalidate D line\n\
......
...@@ -173,6 +173,12 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr, ...@@ -173,6 +173,12 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
show_regs(regs); show_regs(regs);
} }
#endif #endif
#ifndef CONFIG_KUSER_HELPERS
if ((sig == SIGSEGV) && ((addr & PAGE_MASK) == 0xffff0000))
printk_ratelimited(KERN_DEBUG
"%s: CONFIG_KUSER_HELPERS disabled at 0x%08lx\n",
tsk->comm, addr);
#endif
tsk->thread.address = addr; tsk->thread.address = addr;
tsk->thread.error_code = fsr; tsk->thread.error_code = fsr;
......
...@@ -278,7 +278,7 @@ ...@@ -278,7 +278,7 @@
* If we are building for big.Little with branch predictor hardening, * If we are building for big.Little with branch predictor hardening,
* we need the processor function tables to remain available after boot. * we need the processor function tables to remain available after boot.
*/ */
#if 1 // defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR) #if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
.section ".rodata" .section ".rodata"
#endif #endif
.type \name\()_processor_functions, #object .type \name\()_processor_functions, #object
...@@ -316,7 +316,7 @@ ENTRY(\name\()_processor_functions) ...@@ -316,7 +316,7 @@ ENTRY(\name\()_processor_functions)
.endif .endif
.size \name\()_processor_functions, . - \name\()_processor_functions .size \name\()_processor_functions, . - \name\()_processor_functions
#if 1 // defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR) #if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
.previous .previous
#endif #endif
.endm .endm
......
...@@ -33,10 +33,10 @@ ENTRY(lpae_pgtables_remap_asm) ...@@ -33,10 +33,10 @@ ENTRY(lpae_pgtables_remap_asm)
add r7, r2, #0x1000 add r7, r2, #0x1000
add r6, r7, r6, lsr #SECTION_SHIFT - L2_ORDER add r6, r7, r6, lsr #SECTION_SHIFT - L2_ORDER
add r7, r7, #PAGE_OFFSET >> (SECTION_SHIFT - L2_ORDER) add r7, r7, #PAGE_OFFSET >> (SECTION_SHIFT - L2_ORDER)
1: ldrd r4, [r7] 1: ldrd r4, r5, [r7]
adds r4, r4, r0 adds r4, r4, r0
adc r5, r5, r1 adc r5, r5, r1
strd r4, [r7], #1 << L2_ORDER strd r4, r5, [r7], #1 << L2_ORDER
cmp r7, r6 cmp r7, r6
bls 1b bls 1b
...@@ -44,22 +44,22 @@ ENTRY(lpae_pgtables_remap_asm) ...@@ -44,22 +44,22 @@ ENTRY(lpae_pgtables_remap_asm)
add r7, r2, #0x1000 add r7, r2, #0x1000
add r7, r7, r3, lsr #SECTION_SHIFT - L2_ORDER add r7, r7, r3, lsr #SECTION_SHIFT - L2_ORDER
bic r7, r7, #(1 << L2_ORDER) - 1 bic r7, r7, #(1 << L2_ORDER) - 1
ldrd r4, [r7] ldrd r4, r5, [r7]
adds r4, r4, r0 adds r4, r4, r0
adc r5, r5, r1 adc r5, r5, r1
strd r4, [r7], #1 << L2_ORDER strd r4, r5, [r7], #1 << L2_ORDER
ldrd r4, [r7] ldrd r4, r5, [r7]
adds r4, r4, r0 adds r4, r4, r0
adc r5, r5, r1 adc r5, r5, r1
strd r4, [r7] strd r4, r5, [r7]
/* Update level 1 entries */ /* Update level 1 entries */
mov r6, #4 mov r6, #4
mov r7, r2 mov r7, r2
2: ldrd r4, [r7] 2: ldrd r4, r5, [r7]
adds r4, r4, r0 adds r4, r4, r0
adc r5, r5, r1 adc r5, r5, r1
strd r4, [r7], #1 << L1_ORDER strd r4, r5, [r7], #1 << L1_ORDER
subs r6, r6, #1 subs r6, r6, #1
bne 2b bne 2b
......
...@@ -92,7 +92,6 @@ config OMAP_32K_TIMER ...@@ -92,7 +92,6 @@ config OMAP_32K_TIMER
config OMAP3_L2_AUX_SECURE_SAVE_RESTORE config OMAP3_L2_AUX_SECURE_SAVE_RESTORE
bool "OMAP3 HS/EMU save and restore for L2 AUX control register" bool "OMAP3 HS/EMU save and restore for L2 AUX control register"
depends on ARCH_OMAP3 && PM depends on ARCH_OMAP3 && PM
default n
help help
Without this option, L2 Auxiliary control register contents are Without this option, L2 Auxiliary control register contents are
lost during off-mode entry on HS/EMU devices. This feature lost during off-mode entry on HS/EMU devices. This feature
......
...@@ -2,3 +2,4 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include ...@@ -2,3 +2,4 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o
obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_SMP) += headsmp.o platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
...@@ -37,5 +37,5 @@ pen: ldr r7, [r6] ...@@ -37,5 +37,5 @@ pen: ldr r7, [r6]
.align .align
1: .long . 1: .long .
.long pen_release .long versatile_cpu_release
ENDPROC(versatile_secondary_startup) ENDPROC(versatile_secondary_startup)
/* /*
* linux/arch/arm/mach-realview/hotplug.c
*
* Copyright (C) 2002 ARM Ltd. * Copyright (C) 2002 ARM Ltd.
* All Rights Reserved * All Rights Reserved
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*
* This hotplug implementation is _specific_ to the situation found on
* ARM development platforms where there is _no_ possibility of actually
* taking a CPU offline, resetting it, or otherwise. Real platforms must
* NOT copy this code.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -15,9 +18,9 @@ ...@@ -15,9 +18,9 @@
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include <asm/cp15.h> #include <asm/cp15.h>
#include "core.h" #include <plat/platsmp.h>
static inline void cpu_enter_lowpower(void) static inline void versatile_immitation_enter_lowpower(unsigned int actrl_mask)
{ {
unsigned int v; unsigned int v;
...@@ -34,11 +37,11 @@ static inline void cpu_enter_lowpower(void) ...@@ -34,11 +37,11 @@ static inline void cpu_enter_lowpower(void)
" bic %0, %0, %2\n" " bic %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 0\n" " mcr p15, 0, %0, c1, c0, 0\n"
: "=&r" (v) : "=&r" (v)
: "r" (0), "Ir" (CR_C), "Ir" (0x40) : "r" (0), "Ir" (CR_C), "Ir" (actrl_mask)
: "cc"); : "cc");
} }
static inline void cpu_leave_lowpower(void) static inline void versatile_immitation_leave_lowpower(unsigned int actrl_mask)
{ {
unsigned int v; unsigned int v;
...@@ -50,21 +53,23 @@ static inline void cpu_leave_lowpower(void) ...@@ -50,21 +53,23 @@ static inline void cpu_leave_lowpower(void)
" orr %0, %0, %2\n" " orr %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 1\n" " mcr p15, 0, %0, c1, c0, 1\n"
: "=&r" (v) : "=&r" (v)
: "Ir" (CR_C), "Ir" (0x40) : "Ir" (CR_C), "Ir" (actrl_mask)
: "cc"); : "cc");
} }
static inline void platform_do_lowpower(unsigned int cpu, int *spurious) static inline void versatile_immitation_do_lowpower(unsigned int cpu, int *spurious)
{ {
/* /*
* there is no power-control hardware on this platform, so all * there is no power-control hardware on this platform, so all
* we can do is put the core into WFI; this is safe as the calling * we can do is put the core into WFI; this is safe as the calling
* code will have already disabled interrupts * code will have already disabled interrupts.
*
* This code should not be used outside Versatile platforms.
*/ */
for (;;) { for (;;) {
wfi(); wfi();
if (pen_release == cpu_logical_map(cpu)) { if (versatile_cpu_release == cpu_logical_map(cpu)) {
/* /*
* OK, proper wakeup, we're done * OK, proper wakeup, we're done
*/ */
...@@ -83,25 +88,17 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) ...@@ -83,25 +88,17 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
} }
/* /*
* platform-specific code to shutdown a CPU * platform-specific code to shutdown a CPU.
* * This code supports immitation-style CPU hotplug for Versatile/Realview/
* Called with IRQs disabled * Versatile Express platforms that are unable to do real CPU hotplug.
*/ */
void vexpress_cpu_die(unsigned int cpu) void versatile_immitation_cpu_die(unsigned int cpu, unsigned int actrl_mask)
{ {
int spurious = 0; int spurious = 0;
/* versatile_immitation_enter_lowpower(actrl_mask);
* we're ready for shutdown now, so do it versatile_immitation_do_lowpower(cpu, &spurious);
*/ versatile_immitation_leave_lowpower(actrl_mask);
cpu_enter_lowpower();
platform_do_lowpower(cpu, &spurious);
/*
* bring this CPU back into the world of cache
* coherency, and then restore interrupts
*/
cpu_leave_lowpower();
if (spurious) if (spurious)
pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
......
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
extern volatile int versatile_cpu_release;
extern void versatile_secondary_startup(void); extern void versatile_secondary_startup(void);
extern void versatile_secondary_init(unsigned int cpu); extern void versatile_secondary_init(unsigned int cpu);
extern int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle); extern int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle);
void versatile_immitation_cpu_die(unsigned int cpu, unsigned int actrl_mask);
...@@ -7,6 +7,11 @@ ...@@ -7,6 +7,11 @@
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*
* This code is specific to the hardware found on ARM Realview and
* Versatile Express platforms where the CPUs are unable to be individually
* woken, and where there is no way to hot-unplug CPUs. Real platforms
* should not copy this code.
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -21,18 +26,32 @@ ...@@ -21,18 +26,32 @@
#include <plat/platsmp.h> #include <plat/platsmp.h>
/* /*
* Write pen_release in a way that is guaranteed to be visible to all * versatile_cpu_release controls the release of CPUs from the holding
* observers, irrespective of whether they're taking part in coherency * pen in headsmp.S, which exists because we are not always able to
* control the release of individual CPUs from the board firmware.
* Production platforms do not need this.
*/
volatile int versatile_cpu_release = -1;
/*
* Write versatile_cpu_release in a way that is guaranteed to be visible to
* all observers, irrespective of whether they're taking part in coherency
* or not. This is necessary for the hotplug code to work reliably. * or not. This is necessary for the hotplug code to work reliably.
*/ */
static void write_pen_release(int val) static void versatile_write_cpu_release(int val)
{ {
pen_release = val; versatile_cpu_release = val;
smp_wmb(); smp_wmb();
sync_cache_w(&pen_release); sync_cache_w(&versatile_cpu_release);
} }
static DEFINE_SPINLOCK(boot_lock); /*
* versatile_lock exists to avoid running the loops_per_jiffy delay loop
* calibrations on the secondary CPU while the requesting CPU is using
* the limited-bandwidth bus - which affects the calibration value.
* Production platforms do not need this.
*/
static DEFINE_RAW_SPINLOCK(versatile_lock);
void versatile_secondary_init(unsigned int cpu) void versatile_secondary_init(unsigned int cpu)
{ {
...@@ -40,13 +59,13 @@ void versatile_secondary_init(unsigned int cpu) ...@@ -40,13 +59,13 @@ void versatile_secondary_init(unsigned int cpu)
* let the primary processor know we're out of the * let the primary processor know we're out of the
* pen, then head off into the C entry point * pen, then head off into the C entry point
*/ */
write_pen_release(-1); versatile_write_cpu_release(-1);
/* /*
* Synchronise with the boot thread. * Synchronise with the boot thread.
*/ */
spin_lock(&boot_lock); raw_spin_lock(&versatile_lock);
spin_unlock(&boot_lock); raw_spin_unlock(&versatile_lock);
} }
int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle)
...@@ -57,7 +76,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) ...@@ -57,7 +76,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle)
* Set synchronisation state between this boot processor * Set synchronisation state between this boot processor
* and the secondary one * and the secondary one
*/ */
spin_lock(&boot_lock); raw_spin_lock(&versatile_lock);
/* /*
* This is really belt and braces; we hold unintended secondary * This is really belt and braces; we hold unintended secondary
...@@ -65,7 +84,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) ...@@ -65,7 +84,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle)
* since we haven't sent them a soft interrupt, they shouldn't * since we haven't sent them a soft interrupt, they shouldn't
* be there. * be there.
*/ */
write_pen_release(cpu_logical_map(cpu)); versatile_write_cpu_release(cpu_logical_map(cpu));
/* /*
* Send the secondary CPU a soft interrupt, thereby causing * Send the secondary CPU a soft interrupt, thereby causing
...@@ -77,7 +96,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) ...@@ -77,7 +96,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle)
timeout = jiffies + (1 * HZ); timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) { while (time_before(jiffies, timeout)) {
smp_rmb(); smp_rmb();
if (pen_release == -1) if (versatile_cpu_release == -1)
break; break;
udelay(10); udelay(10);
...@@ -87,7 +106,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle) ...@@ -87,7 +106,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle)
* now the secondary core is starting up let it run its * now the secondary core is starting up let it run its
* calibrations, then wait for it to finish * calibrations, then wait for it to finish
*/ */
spin_unlock(&boot_lock); raw_spin_unlock(&versatile_lock);
return pen_release != -1 ? -ENOSYS : 0; return versatile_cpu_release != -1 ? -ENOSYS : 0;
} }
...@@ -64,6 +64,9 @@ config CARDBUS ...@@ -64,6 +64,9 @@ config CARDBUS
If unsure, say Y. If unsure, say Y.
config PCMCIA_MAX1600
tristate
comment "PC-card bridges" comment "PC-card bridges"
config YENTA config YENTA
...@@ -192,6 +195,8 @@ config PCMCIA_SA1111 ...@@ -192,6 +195,8 @@ config PCMCIA_SA1111
select PCMCIA_SOC_COMMON select PCMCIA_SOC_COMMON
select PCMCIA_SA11XX_BASE if ARCH_SA1100 select PCMCIA_SA11XX_BASE if ARCH_SA1100
select PCMCIA_PXA2XX if ARCH_LUBBOCK && SA1111 select PCMCIA_PXA2XX if ARCH_LUBBOCK && SA1111
select PCMCIA_MAX1600 if ASSABET_NEPONSET
select PCMCIA_MAX1600 if ARCH_LUBBOCK && SA1111
help help
Say Y here to include support for SA1111-based PCMCIA or CF Say Y here to include support for SA1111-based PCMCIA or CF
sockets, found on the Jornada 720, Graphicsmaster and other sockets, found on the Jornada 720, Graphicsmaster and other
...@@ -208,6 +213,7 @@ config PCMCIA_PXA2XX ...@@ -208,6 +213,7 @@ config PCMCIA_PXA2XX
|| MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \ || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
|| MACH_COLIBRI320 || MACH_H4700) || MACH_COLIBRI320 || MACH_H4700)
select PCMCIA_SOC_COMMON select PCMCIA_SOC_COMMON
select PCMCIA_MAX1600 if MACH_MAINSTONE
help help
Say Y here to include support for the PXA2xx PCMCIA controller Say Y here to include support for the PXA2xx PCMCIA controller
......
...@@ -35,6 +35,7 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o ...@@ -35,6 +35,7 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o
obj-$(CONFIG_AT91_CF) += at91_cf.o obj-$(CONFIG_AT91_CF) += at91_cf.o
obj-$(CONFIG_ELECTRA_CF) += electra_cf.o obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o
obj-$(CONFIG_PCMCIA_MAX1600) += max1600.o
sa1111_cs-y += sa1111_generic.o sa1111_cs-y += sa1111_generic.o
sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1111_neponset.o sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1111_neponset.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* MAX1600 PCMCIA power switch library
*
* Copyright (C) 2016 Russell King
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include "max1600.h"
static const char *max1600_gpio_name[2][MAX1600_GPIO_MAX] = {
{ "a0vcc", "a1vcc", "a0vpp", "a1vpp" },
{ "b0vcc", "b1vcc", "b0vpp", "b1vpp" },
};
int max1600_init(struct device *dev, struct max1600 **ptr,
unsigned int channel, unsigned int code)
{
struct max1600 *m;
int chan;
int i;
switch (channel) {
case MAX1600_CHAN_A:
chan = 0;
break;
case MAX1600_CHAN_B:
chan = 1;
break;
default:
return -EINVAL;
}
if (code != MAX1600_CODE_LOW && code != MAX1600_CODE_HIGH)
return -EINVAL;
m = devm_kzalloc(dev, sizeof(*m), GFP_KERNEL);
if (!m)
return -ENOMEM;
m->dev = dev;
m->code = code;
for (i = 0; i < MAX1600_GPIO_MAX; i++) {
const char *name;
name = max1600_gpio_name[chan][i];
if (i != MAX1600_GPIO_0VPP) {
m->gpio[i] = devm_gpiod_get(dev, name, GPIOD_OUT_LOW);
} else {
m->gpio[i] = devm_gpiod_get_optional(dev, name,
GPIOD_OUT_LOW);
if (!m->gpio[i])
break;
}
if (IS_ERR(m->gpio[i]))
return PTR_ERR(m->gpio[i]);
}
*ptr = m;
return 0;
}
EXPORT_SYMBOL_GPL(max1600_init);
int max1600_configure(struct max1600 *m, unsigned int vcc, unsigned int vpp)
{
DECLARE_BITMAP(values, MAX1600_GPIO_MAX) = { 0, };
int n = MAX1600_GPIO_0VPP;
if (m->gpio[MAX1600_GPIO_0VPP]) {
if (vpp == 0) {
__assign_bit(MAX1600_GPIO_0VPP, values, 0);
__assign_bit(MAX1600_GPIO_1VPP, values, 0);
} else if (vpp == 120) {
__assign_bit(MAX1600_GPIO_0VPP, values, 0);
__assign_bit(MAX1600_GPIO_1VPP, values, 1);
} else if (vpp == vcc) {
__assign_bit(MAX1600_GPIO_0VPP, values, 1);
__assign_bit(MAX1600_GPIO_1VPP, values, 0);
} else {
dev_err(m->dev, "unrecognised Vpp %u.%uV\n",
vpp / 10, vpp % 10);
return -EINVAL;
}
n = MAX1600_GPIO_MAX;
} else if (vpp != vcc && vpp != 0) {
dev_err(m->dev, "no VPP control\n");
return -EINVAL;
}
if (vcc == 0) {
__assign_bit(MAX1600_GPIO_0VCC, values, 0);
__assign_bit(MAX1600_GPIO_1VCC, values, 0);
} else if (vcc == 33) { /* VY */
__assign_bit(MAX1600_GPIO_0VCC, values, 1);
__assign_bit(MAX1600_GPIO_1VCC, values, 0);
} else if (vcc == 50) { /* VX */
__assign_bit(MAX1600_GPIO_0VCC, values, 0);
__assign_bit(MAX1600_GPIO_1VCC, values, 1);
} else {
dev_err(m->dev, "unrecognised Vcc %u.%uV\n",
vcc / 10, vcc % 10);
return -EINVAL;
}
if (m->code == MAX1600_CODE_HIGH) {
/*
* Cirrus mode appears to be the same as Intel mode,
* except the VCC pins are inverted.
*/
__change_bit(MAX1600_GPIO_0VCC, values);
__change_bit(MAX1600_GPIO_1VCC, values);
}
return gpiod_set_array_value_cansleep(n, m->gpio, NULL, values);
}
EXPORT_SYMBOL_GPL(max1600_configure);
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef MAX1600_H
#define MAX1600_H
struct gpio_desc;
enum {
MAX1600_GPIO_0VCC = 0,
MAX1600_GPIO_1VCC,
MAX1600_GPIO_0VPP,
MAX1600_GPIO_1VPP,
MAX1600_GPIO_MAX,
MAX1600_CHAN_A,
MAX1600_CHAN_B,
MAX1600_CODE_LOW,
MAX1600_CODE_HIGH,
};
struct max1600 {
struct gpio_desc *gpio[MAX1600_GPIO_MAX];
struct device *dev;
unsigned int code;
};
int max1600_init(struct device *dev, struct max1600 **ptr,
unsigned int channel, unsigned int code);
int max1600_configure(struct max1600 *, unsigned int vcc, unsigned int vpp);
#endif
...@@ -11,56 +11,55 @@ ...@@ -11,56 +11,55 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/gpio/consumer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <pcmcia/ss.h> #include <pcmcia/ss.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/irq.h>
#include <mach/pxa2xx-regs.h>
#include <mach/mainstone.h>
#include "soc_common.h" #include "soc_common.h"
#include "max1600.h"
static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{ {
/* struct device *dev = skt->socket.dev.parent;
* Setup default state of GPIO outputs struct max1600 *m;
* before we enable them as outputs. int ret;
*/
if (skt->nr == 0) { skt->stat[SOC_STAT_CD].name = skt->nr ? "bdetect" : "adetect";
skt->socket.pci_irq = MAINSTONE_S0_IRQ; skt->stat[SOC_STAT_BVD1].name = skt->nr ? "bbvd1" : "abvd1";
skt->stat[SOC_STAT_CD].irq = MAINSTONE_S0_CD_IRQ; skt->stat[SOC_STAT_BVD2].name = skt->nr ? "bbvd2" : "abvd2";
skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD"; skt->stat[SOC_STAT_RDY].name = skt->nr ? "bready" : "aready";
skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S0_STSCHG_IRQ; skt->stat[SOC_STAT_VS1].name = skt->nr ? "bvs1" : "avs1";
skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG"; skt->stat[SOC_STAT_VS2].name = skt->nr ? "bvs2" : "avs2";
} else {
skt->socket.pci_irq = MAINSTONE_S1_IRQ; skt->gpio_reset = devm_gpiod_get(dev, skt->nr ? "breset" : "areset",
skt->stat[SOC_STAT_CD].irq = MAINSTONE_S1_CD_IRQ; GPIOD_OUT_HIGH);
skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD"; if (IS_ERR(skt->gpio_reset))
skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S1_STSCHG_IRQ; return PTR_ERR(skt->gpio_reset);
skt->stat[SOC_STAT_BVD1].name = "PCMCIA1 STSCHG";
} ret = max1600_init(dev, &m, skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
return 0; MAX1600_CODE_HIGH);
if (ret)
return ret;
skt->driver_data = m;
return soc_pcmcia_request_gpiods(skt);
} }
static unsigned long mst_pcmcia_status[2]; static unsigned int mst_pcmcia_bvd1_status[2];
static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt, static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
struct pcmcia_state *state) struct pcmcia_state *state)
{ {
unsigned long status, flip; unsigned int flip = mst_pcmcia_bvd1_status[skt->nr] ^ state->bvd1;
status = (skt->nr == 0) ? MST_PCMCIA0 : MST_PCMCIA1;
flip = (status ^ mst_pcmcia_status[skt->nr]) & MST_PCMCIA_nSTSCHG_BVD1;
/* /*
* Workaround for STSCHG which can't be deasserted: * Workaround for STSCHG which can't be deasserted:
...@@ -68,62 +67,18 @@ static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt, ...@@ -68,62 +67,18 @@ static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
* as needed to avoid IRQ locks. * as needed to avoid IRQ locks.
*/ */
if (flip) { if (flip) {
mst_pcmcia_status[skt->nr] = status; mst_pcmcia_bvd1_status[skt->nr] = state->bvd1;
if (status & MST_PCMCIA_nSTSCHG_BVD1) if (state->bvd1)
enable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ enable_irq(skt->stat[SOC_STAT_BVD1].irq);
: MAINSTONE_S1_STSCHG_IRQ );
else else
disable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ disable_irq(skt->stat[SOC_STAT_BVD2].irq);
: MAINSTONE_S1_STSCHG_IRQ );
} }
state->detect = (status & MST_PCMCIA_nCD) ? 0 : 1;
state->ready = (status & MST_PCMCIA_nIRQ) ? 1 : 0;
state->bvd1 = (status & MST_PCMCIA_nSTSCHG_BVD1) ? 1 : 0;
state->bvd2 = (status & MST_PCMCIA_nSPKR_BVD2) ? 1 : 0;
state->vs_3v = (status & MST_PCMCIA_nVS1) ? 0 : 1;
state->vs_Xv = (status & MST_PCMCIA_nVS2) ? 0 : 1;
} }
static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state) const socket_state_t *state)
{ {
unsigned long power = 0; return max1600_configure(skt->driver_data, state->Vcc, state->Vpp);
int ret = 0;
switch (state->Vcc) {
case 0: power |= MST_PCMCIA_PWR_VCC_0; break;
case 33: power |= MST_PCMCIA_PWR_VCC_33; break;
case 50: power |= MST_PCMCIA_PWR_VCC_50; break;
default:
printk(KERN_ERR "%s(): bad Vcc %u\n",
__func__, state->Vcc);
ret = -1;
}
switch (state->Vpp) {
case 0: power |= MST_PCMCIA_PWR_VPP_0; break;
case 120: power |= MST_PCMCIA_PWR_VPP_120; break;
default:
if(state->Vpp == state->Vcc) {
power |= MST_PCMCIA_PWR_VPP_VCC;
} else {
printk(KERN_ERR "%s(): bad Vpp %u\n",
__func__, state->Vpp);
ret = -1;
}
}
if (state->flags & SS_RESET)
power |= MST_PCMCIA_RESET;
switch (skt->nr) {
case 0: MST_PCMCIA0 = power; break;
case 1: MST_PCMCIA1 = power; break;
default: ret = -1;
}
return ret;
} }
static struct pcmcia_low_level mst_pcmcia_ops __initdata = { static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
......
...@@ -39,8 +39,8 @@ simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt, ...@@ -39,8 +39,8 @@ simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
{ {
long cs3reg = simpad_get_cs3_ro(); long cs3reg = simpad_get_cs3_ro();
state->bvd1 = 1; /* Might be cs3reg & PCMCIA_BVD1 */ /* bvd1 might be cs3reg & PCMCIA_BVD1 */
state->bvd2 = 1; /* Might be cs3reg & PCMCIA_BVD2 */ /* bvd2 might be cs3reg & PCMCIA_BVD2 */
if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) == if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) ==
(PCMCIA_VS1|PCMCIA_VS2)) { (PCMCIA_VS1|PCMCIA_VS2)) {
......
...@@ -6,29 +6,62 @@ ...@@ -6,29 +6,62 @@
* *
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/hardware/sa1111.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include "sa1111_generic.h" #include "sa1111_generic.h"
/* Does SOCKET1_3V actually do anything? */ /*
#define SOCKET0_POWER GPIO_GPIO0 * Socket 0 power: GPIO A0
#define SOCKET0_3V GPIO_GPIO2 * Socket 0 3V: GPIO A2
#define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3) * Socket 1 power: GPIO A1 & GPIO A3
#define SOCKET1_3V GPIO_GPIO3 * Socket 1 3V: GPIO A3
* Does Socket 1 3V actually do anything?
*/
enum {
J720_GPIO_PWR,
J720_GPIO_3V,
J720_GPIO_MAX,
};
struct jornada720_data {
struct gpio_desc *gpio[J720_GPIO_MAX];
};
static int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
struct device *dev = skt->socket.dev.parent;
struct jornada720_data *j;
j = devm_kzalloc(dev, sizeof(*j), GFP_KERNEL);
if (!j)
return -ENOMEM;
j->gpio[J720_GPIO_PWR] = devm_gpiod_get(dev, skt->nr ? "s1-power" :
"s0-power", GPIOD_OUT_LOW);
if (IS_ERR(j->gpio[J720_GPIO_PWR]))
return PTR_ERR(j->gpio[J720_GPIO_PWR]);
j->gpio[J720_GPIO_3V] = devm_gpiod_get(dev, skt->nr ? "s1-3v" :
"s0-3v", GPIOD_OUT_LOW);
if (IS_ERR(j->gpio[J720_GPIO_3V]))
return PTR_ERR(j->gpio[J720_GPIO_3V]);
skt->driver_data = j;
return 0;
}
static int static int
jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
{ {
struct sa1111_pcmcia_socket *s = to_skt(skt); struct jornada720_data *j = skt->driver_data;
unsigned int pa_dwr_mask, pa_dwr_set; DECLARE_BITMAP(values, J720_GPIO_MAX) = { 0, };
int ret; int ret;
printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__, printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
...@@ -36,35 +69,34 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s ...@@ -36,35 +69,34 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
switch (skt->nr) { switch (skt->nr) {
case 0: case 0:
pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
switch (state->Vcc) { switch (state->Vcc) {
default: default:
case 0: case 0:
pa_dwr_set = 0; __assign_bit(J720_GPIO_PWR, values, 0);
__assign_bit(J720_GPIO_3V, values, 0);
break; break;
case 33: case 33:
pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; __assign_bit(J720_GPIO_PWR, values, 1);
__assign_bit(J720_GPIO_3V, values, 1);
break; break;
case 50: case 50:
pa_dwr_set = SOCKET0_POWER; __assign_bit(J720_GPIO_PWR, values, 1);
__assign_bit(J720_GPIO_3V, values, 0);
break; break;
} }
break; break;
case 1: case 1:
pa_dwr_mask = SOCKET1_POWER;
switch (state->Vcc) { switch (state->Vcc) {
default: default:
case 0: case 0:
pa_dwr_set = 0; __assign_bit(J720_GPIO_PWR, values, 0);
__assign_bit(J720_GPIO_3V, values, 0);
break; break;
case 33: case 33:
pa_dwr_set = SOCKET1_POWER;
break;
case 50: case 50:
pa_dwr_set = SOCKET1_POWER; __assign_bit(J720_GPIO_PWR, values, 1);
__assign_bit(J720_GPIO_3V, values, 1);
break; break;
} }
break; break;
...@@ -81,13 +113,15 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s ...@@ -81,13 +113,15 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
ret = sa1111_pcmcia_configure_socket(skt, state); ret = sa1111_pcmcia_configure_socket(skt, state);
if (ret == 0) if (ret == 0)
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); ret = gpiod_set_array_value_cansleep(J720_GPIO_MAX, j->gpio,
NULL, values);
return ret; return ret;
} }
static struct pcmcia_low_level jornada720_pcmcia_ops = { static struct pcmcia_low_level jornada720_pcmcia_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hw_init = jornada720_pcmcia_hw_init,
.configure_socket = jornada720_pcmcia_configure_socket, .configure_socket = jornada720_pcmcia_configure_socket,
.first = 0, .first = 0,
.nr = 2, .nr = 2,
...@@ -95,16 +129,9 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = { ...@@ -95,16 +129,9 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = {
int pcmcia_jornada720_init(struct sa1111_dev *sadev) int pcmcia_jornada720_init(struct sa1111_dev *sadev)
{ {
unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
/* Fixme: why messing around with SA11x0's GPIO1? */ /* Fixme: why messing around with SA11x0's GPIO1? */
GRER |= 0x00000002; GRER |= 0x00000002;
/* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
sa1111_set_io_dir(sadev, pin, 0, 0);
sa1111_set_io(sadev, pin, 0);
sa1111_set_sleep_io(sadev, pin, 0);
sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops); sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops, return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops,
sa11xx_drv_pcmcia_add_one); sa11xx_drv_pcmcia_add_one);
......
...@@ -24,20 +24,31 @@ ...@@ -24,20 +24,31 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <mach/lubbock.h>
#include "sa1111_generic.h" #include "sa1111_generic.h"
#include "max1600.h"
static int lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
struct max1600 *m;
int ret;
ret = max1600_init(skt->socket.dev.parent, &m,
skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
MAX1600_CODE_HIGH);
if (ret == 0)
skt->driver_data = m;
return ret;
}
static int static int
lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state) const socket_state_t *state)
{ {
struct sa1111_pcmcia_socket *s = to_skt(skt); struct max1600 *m = skt->driver_data;
unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
int ret = 0; int ret = 0;
pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
/* Lubbock uses the Maxim MAX1602, with the following connections: /* Lubbock uses the Maxim MAX1602, with the following connections:
* *
* Socket 0 (PCMCIA): * Socket 0 (PCMCIA):
...@@ -71,74 +82,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ...@@ -71,74 +82,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
again: again:
switch (skt->nr) { switch (skt->nr) {
case 0: case 0:
pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
switch (state->Vcc) {
case 0: /* Hi-Z */
break;
case 33: /* VY */
pa_dwr_set |= GPIO_A3;
break;
case 50: /* VX */
pa_dwr_set |= GPIO_A2;
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
__func__, state->Vcc);
ret = -1;
}
switch (state->Vpp) {
case 0: /* Hi-Z */
break;
case 120: /* 12IN */
pa_dwr_set |= GPIO_A1;
break;
default: /* VCC */
if (state->Vpp == state->Vcc)
pa_dwr_set |= GPIO_A0;
else {
printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
__func__, state->Vpp);
ret = -1;
break;
}
}
break;
case 1: case 1:
misc_mask = (1 << 15) | (1 << 14);
switch (state->Vcc) {
case 0: /* Hi-Z */
break;
case 33: /* VY */
misc_set |= 1 << 15;
break;
case 50: /* VX */
misc_set |= 1 << 14;
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
__func__, state->Vcc);
ret = -1;
break;
}
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
__func__, state->Vpp);
ret = -1;
break;
}
break; break;
default: default:
...@@ -147,11 +91,8 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ...@@ -147,11 +91,8 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
if (ret == 0) if (ret == 0)
ret = sa1111_pcmcia_configure_socket(skt, state); ret = sa1111_pcmcia_configure_socket(skt, state);
if (ret == 0)
if (ret == 0) { ret = max1600_configure(m, state->Vcc, state->Vpp);
lubbock_set_misc_wr(misc_mask, misc_set);
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
}
#if 1 #if 1
if (ret == 0 && state->Vcc == 33) { if (ret == 0 && state->Vcc == 33) {
...@@ -175,8 +116,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ...@@ -175,8 +116,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
/* /*
* Switch to 5V, Configure socket with 5V voltage * Switch to 5V, Configure socket with 5V voltage
*/ */
lubbock_set_misc_wr(misc_mask, 0); max1600_configure(m, 0, 0);
sa1111_set_io(s->dev, pa_dwr_mask, 0);
/* /*
* It takes about 100ms to turn off Vcc. * It takes about 100ms to turn off Vcc.
...@@ -201,6 +141,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ...@@ -201,6 +141,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
static struct pcmcia_low_level lubbock_pcmcia_ops = { static struct pcmcia_low_level lubbock_pcmcia_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hw_init = lubbock_pcmcia_hw_init,
.configure_socket = lubbock_pcmcia_configure_socket, .configure_socket = lubbock_pcmcia_configure_socket,
.first = 0, .first = 0,
.nr = 2, .nr = 2,
...@@ -210,17 +151,6 @@ static struct pcmcia_low_level lubbock_pcmcia_ops = { ...@@ -210,17 +151,6 @@ static struct pcmcia_low_level lubbock_pcmcia_ops = {
int pcmcia_lubbock_init(struct sa1111_dev *sadev) int pcmcia_lubbock_init(struct sa1111_dev *sadev)
{ {
/*
* Set GPIO_A<3:0> to be outputs for the MAX1600,
* and switch to standby mode.
*/
sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
/* Set CF Socket 1 power to standby mode. */
lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops); pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
pxa2xx_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops); pxa2xx_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops);
return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops, return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
......
...@@ -10,12 +10,10 @@ ...@@ -10,12 +10,10 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <mach/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <mach/neponset.h>
#include <asm/hardware/sa1111.h>
#include "sa1111_generic.h" #include "sa1111_generic.h"
#include "max1600.h"
/* /*
* Neponset uses the Maxim MAX1600, with the following connections: * Neponset uses the Maxim MAX1600, with the following connections:
...@@ -40,70 +38,36 @@ ...@@ -40,70 +38,36 @@
* "Standard Intel code" mode. Refer to the Maxim data sheet for * "Standard Intel code" mode. Refer to the Maxim data sheet for
* the corresponding truth table. * the corresponding truth table.
*/ */
static int neponset_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
static int
neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
{ {
struct sa1111_pcmcia_socket *s = to_skt(skt); struct max1600 *m;
unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
int ret; int ret;
switch (skt->nr) { ret = max1600_init(skt->socket.dev.parent, &m,
case 0: skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
pa_dwr_mask = GPIO_A0 | GPIO_A1; MAX1600_CODE_LOW);
ncr_mask = NCR_A0VPP | NCR_A1VPP; if (ret == 0)
skt->driver_data = m;
if (state->Vpp == 0)
ncr_set = 0;
else if (state->Vpp == 120)
ncr_set = NCR_A1VPP;
else if (state->Vpp == state->Vcc)
ncr_set = NCR_A0VPP;
else {
printk(KERN_ERR "%s(): unrecognized VPP %u\n",
__func__, state->Vpp);
return -1;
}
break;
case 1: return ret;
pa_dwr_mask = GPIO_A2 | GPIO_A3; }
ncr_mask = 0;
ncr_set = 0;
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
__func__, state->Vpp);
return -1;
}
break;
default:
return -1;
}
/* static int
* pa_dwr_set is the mask for selecting Vcc on both sockets. neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
* pa_dwr_mask selects which bits (and therefore socket) we change. {
*/ struct max1600 *m = skt->driver_data;
switch (state->Vcc) { int ret;
default:
case 0: pa_dwr_set = 0; break;
case 33: pa_dwr_set = GPIO_A1|GPIO_A2; break;
case 50: pa_dwr_set = GPIO_A0|GPIO_A3; break;
}
ret = sa1111_pcmcia_configure_socket(skt, state); ret = sa1111_pcmcia_configure_socket(skt, state);
if (ret == 0) { if (ret == 0)
neponset_ncr_frob(ncr_mask, ncr_set); ret = max1600_configure(m, state->Vcc, state->Vpp);
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
}
return ret; return ret;
} }
static struct pcmcia_low_level neponset_pcmcia_ops = { static struct pcmcia_low_level neponset_pcmcia_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.hw_init = neponset_pcmcia_hw_init,
.configure_socket = neponset_pcmcia_configure_socket, .configure_socket = neponset_pcmcia_configure_socket,
.first = 0, .first = 0,
.nr = 2, .nr = 2,
...@@ -111,13 +75,6 @@ static struct pcmcia_low_level neponset_pcmcia_ops = { ...@@ -111,13 +75,6 @@ static struct pcmcia_low_level neponset_pcmcia_ops = {
int pcmcia_neponset_init(struct sa1111_dev *sadev) int pcmcia_neponset_init(struct sa1111_dev *sadev)
{ {
/*
* Set GPIO_A<3:0> to be outputs for the MAX1600,
* and switch to standby mode.
*/
sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops); sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops);
return sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops, return sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
sa11xx_drv_pcmcia_add_one); sa11xx_drv_pcmcia_add_one);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment