提交 1205b623 编写于 作者: L 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
  ...
......@@ -28,14 +28,14 @@ config ARM
select ARCH_WANT_IPC_PARSE_VERSION
select BUILDTIME_EXTABLE_SORT if MMU
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 DMA_REMAP if MMU
select EDAC_SUPPORT
select EDAC_ATOMIC_SCRUB
select GENERIC_ALLOCATOR
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_CPU_AUTOPROBE
select GENERIC_EARLY_IOREMAP
......@@ -50,12 +50,12 @@ config ARM
select GENERIC_STRNLEN_USER
select HANDLE_DOMAIN_IRQ
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_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && 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_TRACEHOOK
select HAVE_ARM_SMCCC if CPU_V7
......@@ -64,16 +64,16 @@ config ARM
select HAVE_C_RECORDMCOUNT
select HAVE_DEBUG_KMEMLEAK
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_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU
select HAVE_EXIT_THREAD
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
select HAVE_FUNCTION_GRAPH_TRACER if !THUMB2_KERNEL
select HAVE_FUNCTION_TRACER if !XIP_KERNEL
select HAVE_GCC_PLUGINS
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_IRQ_TIME_ACCOUNTING
select HAVE_KERNEL_GZIP
......@@ -82,15 +82,15 @@ config ARM
select HAVE_KERNEL_LZO
select HAVE_KERNEL_XZ
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_NMI
select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
select HAVE_OPROFILE if HAVE_PERF_EVENTS
select HAVE_OPTPROBES if !THUMB2_KERNEL
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
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_RSEQ
select HAVE_STACKPROTECTOR
......@@ -1738,7 +1738,6 @@ config PARAVIRT
config PARAVIRT_TIME_ACCOUNTING
bool "Paravirtual steal time accounting"
select PARAVIRT
default n
help
Select this option to enable fine granularity task steal time
accounting. Time spent executing other tasks in parallel with
......
......@@ -98,6 +98,24 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_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.
*
......@@ -180,6 +198,11 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)
initrd_start);
setprop_cell(fdt, "/chosen", "linux,initrd-end",
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)
}
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.
*/
......
......@@ -243,13 +243,15 @@
.endm
#endif
#define USER(x...) \
#define USERL(l, x...) \
9999: x; \
.pushsection __ex_table,"a"; \
.align 3; \
.long 9999b,9001f; \
.long 9999b,l; \
.popsection
#define USER(x...) USERL(9001f, x)
#ifdef CONFIG_SMP
#define ALT_SMP(instr...) \
9998: instr
......
......@@ -433,10 +433,6 @@ int sa1111_check_dma_bug(dma_addr_t addr);
int sa1111_driver_register(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 {
int irq_base; /* base for cascaded on-chip IRQs */
unsigned disable_devs;
......
......@@ -349,6 +349,13 @@ do { \
#define __get_user_asm_byte(x, addr, err) \
__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__
#define __get_user_asm_half(x, __gu_addr, err) \
({ \
......@@ -367,6 +374,8 @@ do { \
})
#endif
#endif /* __LINUX_ARM_ARCH__ >= 6 */
#define __get_user_asm_word(x, addr, err) \
__get_user_asm(x, addr, err, ldr)
#endif
......@@ -442,6 +451,13 @@ do { \
#define __put_user_asm_byte(x, __pu_addr, err) \
__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__
#define __put_user_asm_half(x, __pu_addr, err) \
({ \
......@@ -458,6 +474,8 @@ do { \
})
#endif
#endif /* __LINUX_ARM_ARCH__ >= 6 */
#define __put_user_asm_word(x, __pu_addr, err) \
__put_user_asm(x, __pu_addr, err, str)
......
......@@ -398,7 +398,7 @@ ENTRY(secondary_startup)
ldmia r4, {r5, r7, r12} @ address to jump to after
sub lr, r4, r5 @ mmu has been enabled
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 r5, r4, r5) @ it can be done in 3 steps
ARM_BE8(eor r4, r4, r5) @ without using a temp reg.
......
......@@ -724,6 +724,21 @@ void smp_send_stop(void)
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
*/
......
......@@ -34,12 +34,13 @@
* Number of bytes NOT copied.
*/
#ifdef CONFIG_CPU_USE_DOMAINS
#ifndef CONFIG_THUMB2_KERNEL
#define LDR1W_SHIFT 0
#else
#define LDR1W_SHIFT 1
#endif
#define STR1W_SHIFT 0
.macro ldr1w ptr reg abort
ldrusr \reg, \ptr, 4, abort=\abort
......@@ -57,10 +58,30 @@
ldr4w \ptr, \reg5, \reg6, \reg7, \reg8, \abort
.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
ldrusr \reg, \ptr, 1, \cond, abort=\abort
.endm
#define STR1W_SHIFT 0
.macro str1w ptr reg abort
W(str) \reg, [\ptr], #4
.endm
......
......@@ -35,11 +35,6 @@
*/
#define LDR1W_SHIFT 0
#ifndef CONFIG_THUMB2_KERNEL
#define STR1W_SHIFT 0
#else
#define STR1W_SHIFT 1
#endif
.macro ldr1w ptr reg abort
W(ldr) \reg, [\ptr], #4
......@@ -57,6 +52,14 @@
ldr\cond\()b \reg, [\ptr], #1
.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
strusr \reg, \ptr, 4, abort=\abort
.endm
......@@ -72,6 +75,20 @@
str1w \ptr, \reg8, \abort
.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
strusr \reg, \ptr, 1, \cond, abort=\abort
.endm
......
......@@ -42,6 +42,12 @@ _ASM_NOKPROBE(__get_user_1)
ENTRY(__get_user_2)
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
rb .req ip
2: ldrbt r2, [r0], #1
......@@ -56,6 +62,9 @@ rb .req r0
#else
orr r2, rb, r2, lsl #8
#endif
#endif /* __LINUX_ARM_ARCH__ >= 6 */
mov r0, #0
ret lr
ENDPROC(__get_user_2)
......@@ -145,7 +154,9 @@ _ASM_NOKPROBE(__get_user_bad8)
.pushsection __ex_table, "a"
.long 1b, __get_user_bad
.long 2b, __get_user_bad
#if __LINUX_ARM_ARCH__ < 6
.long 3b, __get_user_bad
#endif
.long 4b, __get_user_bad
.long 5b, __get_user_bad8
.long 6b, __get_user_bad8
......
......@@ -41,16 +41,13 @@ ENDPROC(__put_user_1)
ENTRY(__put_user_2)
check_uaccess r0, 2, r1, ip, __put_user_bad
mov ip, r2, lsr #8
#ifdef CONFIG_THUMB2_KERNEL
#ifndef __ARMEB__
2: TUSER(strb) r2, [r0]
3: TUSER(strb) ip, [r0, #1]
#if __LINUX_ARM_ARCH__ >= 6
2: TUSER(strh) r2, [r0]
#else
2: TUSER(strb) ip, [r0]
3: TUSER(strb) r2, [r0, #1]
#endif
#else /* !CONFIG_THUMB2_KERNEL */
mov ip, r2, lsr #8
#ifndef __ARMEB__
2: TUSER(strb) r2, [r0], #1
3: TUSER(strb) ip, [r0]
......@@ -58,7 +55,8 @@ ENTRY(__put_user_2)
2: TUSER(strb) ip, [r0], #1
3: TUSER(strb) r2, [r0]
#endif
#endif /* CONFIG_THUMB2_KERNEL */
#endif /* __LINUX_ARM_ARCH__ >= 6 */
mov r0, #0
ret lr
ENDPROC(__put_user_2)
......@@ -91,7 +89,9 @@ ENDPROC(__put_user_bad)
.pushsection __ex_table, "a"
.long 1b, __put_user_bad
.long 2b, __put_user_bad
#if __LINUX_ARM_ARCH__ < 6
.long 3b, __put_user_bad
#endif
.long 4b, __put_user_bad
.long 5b, __put_user_bad
.long 6b, __put_user_bad
......
......@@ -223,7 +223,6 @@ config MACH_NOKIA_N8X0
config OMAP3_SDRC_AC_TIMING
bool "Enable SDRC AC timing register changes"
depends on ARCH_OMAP3
default n
help
If you know that none of your system initiators will attempt to
access SDRAM during CORE DVFS, select Y here. This should boost
......
......@@ -69,8 +69,6 @@ static const struct omap_smp_config omap5_cfg __initconst = {
.startup_addr = omap5_secondary_startup,
};
static DEFINE_SPINLOCK(boot_lock);
void __iomem *omap4_get_scu_base(void)
{
return cfg.scu_base;
......@@ -173,12 +171,6 @@ static void omap4_secondary_init(unsigned int cpu)
/* Enable ACR to allow for ICUALLU workaround */
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)
......@@ -187,12 +179,6 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle)
static bool booted;
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.
* 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)
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;
}
......
......@@ -46,6 +46,7 @@ config ARCH_LUBBOCK
config MACH_MAINSTONE
bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
select GPIO_REG
select PXA27x
config MACH_ZYLONITE
......@@ -551,7 +552,6 @@ config TOSA_BT
config TOSA_USE_EXT_KEYCODES
bool "Tosa keyboard: use extended keycodes"
depends on MACH_TOSA
default n
help
Say Y here to enable the tosa keyboard driver to generate extended
(>= 127) keycodes. Be aware, that they can't be correctly interpreted
......
......@@ -119,6 +119,10 @@
#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_INPUTS \
(MST_PCMCIA_nIRQ | MST_PCMCIA_nSPKR_BVD2 | MST_PCMCIA_nSTSCHG_BVD1 | \
MST_PCMCIA_nVS2 | MST_PCMCIA_nVS1 | MST_PCMCIA_nCD)
/* board specific IRQs */
#define MAINSTONE_NR_IRQS IRQ_BOARD_START
......
......@@ -136,10 +136,26 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = {
// 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)
{
struct clk *clk;
gpiod_add_lookup_table(&sa1111_pcmcia_gpio_table);
/* Add an alias for the SA1111 PCMCIA clock */
clk = clk_get_sys("pxa2xx-pcmcia", NULL);
if (!IS_ERR(clk)) {
......
......@@ -13,6 +13,7 @@
* published by the Free Software Foundation.
*/
#include <linux/gpio.h>
#include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/platform_device.h>
......@@ -504,12 +505,64 @@ static void __init mainstone_init_keypad(void)
static inline void mainstone_init_keypad(void) {}
#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)
{
int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
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_btuart_info(NULL);
pxa_set_stuart_info(NULL);
......
......@@ -5,4 +5,3 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/arch/arm/plat-versatile/inc
obj-y += realview-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 @@
#include <asm/smp_scu.h>
#include <plat/platsmp.h>
#include "hotplug.h"
#define REALVIEW_SYS_FLAGSSET_OFFSET 0x30
......@@ -79,6 +78,13 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
__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 = {
.smp_prepare_cpus = realview_smp_prepare_cpus,
.smp_secondary_init = versatile_secondary_init,
......
......@@ -6,6 +6,7 @@ config SA1100_ASSABET
bool "Assabet"
select ARM_SA1110_CPUFREQ
select GPIO_REG
select LEDS_GPIO_REGISTER
select REGULATOR
select REGULATOR_FIXED_VOLTAGE
help
......@@ -24,6 +25,7 @@ config ASSABET_NEPONSET
config SA1100_CERF
bool "CerfBoard"
select ARM_SA1110_CPUFREQ
select LEDS_GPIO_REGISTER
help
The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued).
More information is available at:
......
......@@ -15,6 +15,7 @@
#include <linux/errno.h>
#include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h>
#include <linux/gpio_keys.h>
#include <linux/ioport.h>
#include <linux/platform_data/sa11x0-serial.h>
#include <linux/regulator/fixed.h>
......@@ -101,7 +102,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val)
assabet_bcr_gc = gc;
return 0;
return gc->base;
}
/*
......@@ -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)
{
/*
......@@ -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
sa11x0_register_lcd(&lq039q2ds54_info);
#else
......@@ -726,92 +777,9 @@ static void __init assabet_map_io(void)
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)
{
unsigned int assabet_gpio_base;
u32 def_val;
sa1100_init_irq();
......@@ -826,7 +794,10 @@ void __init assabet_init_irq(void)
*
* 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")
......
......@@ -89,18 +89,8 @@ static struct gpio_led_platform_data cerf_gpio_led_info = {
.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 = {
&cerfuart2_device,
&cerf_leds,
};
#ifdef CONFIG_SA1100_CERF_FLASH_32MB
......@@ -176,6 +166,7 @@ static void __init cerf_init(void)
{
sa11x0_ppc_configure_mcp();
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_mcp(&cerf_mcp_data);
sa11x0_register_pcmcia(1, &cerf_cf_gpio_table);
......
......@@ -235,18 +235,11 @@ void sa11x0_register_lcd(struct sa1100fb_mach_info *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)
{
if (table)
gpiod_add_lookup_table(table);
platform_device_register_simple("sa11x0-pcmcia", socket, NULL, 0);
sa11x0pcmcia_legacy = false;
}
static struct platform_device sa11x0mtd_device = {
......@@ -331,9 +324,6 @@ static int __init sa1100_init(void)
{
pm_power_off = sa1100_power_off;
if (sa11x0pcmcia_legacy)
platform_device_register(&sa11x0pcmcia_device);
regulator_has_full_constraints();
return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices));
......
......@@ -126,6 +126,7 @@ static void __init h3100_mach_init(void)
{
h3xxx_mach_init();
sa11x0_register_pcmcia(-1, NULL);
sa11x0_register_lcd(&h3100_lcd_info);
sa11x0_register_irda(&h3100_irda_data);
}
......
......@@ -190,6 +190,17 @@ static struct platform_device s1d13xxxfb_device = {
.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[] = {
[0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
[1] = DEFINE_RES_IRQ(IRQ_GPIO1),
......@@ -265,6 +276,7 @@ static int __init jornada720_init(void)
udelay(20); /* give it some time to restart */
gpiod_add_lookup_table(&jornada_ts_gpiod_table);
gpiod_add_lookup_table(&jornada_pcmcia_gpiod_table);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
......
......@@ -5,6 +5,7 @@
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/irq.h>
......@@ -96,6 +97,19 @@ struct neponset_drvdata {
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;
void neponset_ncr_frob(unsigned int mask, unsigned int val)
......@@ -374,6 +388,8 @@ static int neponset_probe(struct platform_device *dev)
d->base + AUD_CTL, AUD_NGPIO, false,
neponset_aud_names);
gpiod_add_lookup_table(&neponset_pcmcia_table);
/*
* We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
* something on the Neponset activates this IRQ on sleep (eth?)
......@@ -424,6 +440,9 @@ static int neponset_remove(struct platform_device *dev)
platform_device_unregister(d->sa1111);
if (!IS_ERR(d->smc91x))
platform_device_unregister(d->smc91x);
gpiod_remove_lookup_table(&neponset_pcmcia_table);
irq_set_chained_handler(irq, NULL);
irq_free_descs(d->irq_base, NEP_IRQ_NR);
nep = NULL;
......
......@@ -15,6 +15,5 @@ obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o
CFLAGS_tc2_pm.o += -march=armv7-a
CFLAGS_REMOVE_tc2_pm.o = -pg
obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_ARCH_MPS2) += v2m-mps2.o
bool vexpress_smp_init_ops(void);
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)
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 = {
.smp_prepare_cpus = vexpress_smp_dt_prepare_cpus,
.smp_secondary_init = versatile_secondary_init,
......
......@@ -17,26 +17,25 @@
/*
* Faraday optimised copy_user_page
*/
static void __naked
fa_copy_user_page(void *kto, const void *kfrom)
static void fa_copy_user_page(void *kto, const void *kfrom)
{
asm("\
stmfd sp!, {r4, lr} @ 2\n\
mov r2, %0 @ 1\n\
1: ldmia r1!, {r3, r4, ip, lr} @ 4\n\
stmia r0, {r3, r4, ip, lr} @ 4\n\
mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\
add r0, r0, #16 @ 1\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
stmia r0, {r3, r4, ip, lr} @ 4\n\
mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\
add r0, r0, #16 @ 1\n\
subs r2, r2, #1 @ 1\n\
int tmp;
asm volatile ("\
1: ldmia %1!, {r3, r4, ip, lr} @ 4\n\
stmia %0, {r3, r4, ip, lr} @ 4\n\
mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\
add %0, %0, #16 @ 1\n\
ldmia %1!, {r3, r4, ip, lr} @ 4\n\
stmia %0, {r3, r4, ip, lr} @ 4\n\
mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\
add %0, %0, #16 @ 1\n\
subs %2, %2, #1 @ 1\n\
bne 1b @ 1\n\
mcr p15, 0, r2, c7, c10, 4 @ 1 drain WB\n\
ldmfd sp!, {r4, pc} @ 3"
:
: "I" (PAGE_SIZE / 32));
mcr p15, 0, %2, c7, c10, 4 @ 1 drain WB"
: "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
: "2" (PAGE_SIZE / 32)
: "r3", "r4", "ip", "lr");
}
void fa_copy_user_highpage(struct page *to, struct page *from,
......
......@@ -13,58 +13,56 @@
#include <linux/init.h>
#include <linux/highmem.h>
static void __naked
feroceon_copy_user_page(void *kto, const void *kfrom)
static void feroceon_copy_user_page(void *kto, const void *kfrom)
{
asm("\
stmfd sp!, {r4-r9, lr} \n\
mov ip, %2 \n\
1: mov lr, r1 \n\
ldmia r1!, {r2 - r9} \n\
pld [lr, #32] \n\
pld [lr, #64] \n\
pld [lr, #96] \n\
pld [lr, #128] \n\
pld [lr, #160] \n\
pld [lr, #192] \n\
pld [lr, #224] \n\
stmia r0, {r2 - r9} \n\
ldmia r1!, {r2 - r9} \n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
add r0, r0, #32 \n\
stmia r0, {r2 - r9} \n\
ldmia r1!, {r2 - r9} \n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
add r0, r0, #32 \n\
stmia r0, {r2 - r9} \n\
ldmia r1!, {r2 - r9} \n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
add r0, r0, #32 \n\
stmia r0, {r2 - r9} \n\
ldmia r1!, {r2 - r9} \n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
add r0, r0, #32 \n\
stmia r0, {r2 - r9} \n\
ldmia r1!, {r2 - r9} \n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
add r0, r0, #32 \n\
stmia r0, {r2 - r9} \n\
ldmia r1!, {r2 - r9} \n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
add r0, r0, #32 \n\
stmia r0, {r2 - r9} \n\
ldmia r1!, {r2 - r9} \n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
add r0, r0, #32 \n\
stmia r0, {r2 - r9} \n\
subs ip, ip, #(32 * 8) \n\
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line\n\
add r0, r0, #32 \n\
int tmp;
asm volatile ("\
1: ldmia %1!, {r2 - r7, ip, lr} \n\
pld [%1, #0] \n\
pld [%1, #32] \n\
pld [%1, #64] \n\
pld [%1, #96] \n\
pld [%1, #128] \n\
pld [%1, #160] \n\
pld [%1, #192] \n\
stmia %0, {r2 - r7, ip, lr} \n\
ldmia %1!, {r2 - r7, ip, lr} \n\
mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
add %0, %0, #32 \n\
stmia %0, {r2 - r7, ip, lr} \n\
ldmia %1!, {r2 - r7, ip, lr} \n\
mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
add %0, %0, #32 \n\
stmia %0, {r2 - r7, ip, lr} \n\
ldmia %1!, {r2 - r7, ip, lr} \n\
mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
add %0, %0, #32 \n\
stmia %0, {r2 - r7, ip, lr} \n\
ldmia %1!, {r2 - r7, ip, lr} \n\
mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
add %0, %0, #32 \n\
stmia %0, {r2 - r7, ip, lr} \n\
ldmia %1!, {r2 - r7, ip, lr} \n\
mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
add %0, %0, #32 \n\
stmia %0, {r2 - r7, ip, lr} \n\
ldmia %1!, {r2 - r7, ip, lr} \n\
mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
add %0, %0, #32 \n\
stmia %0, {r2 - r7, ip, lr} \n\
ldmia %1!, {r2 - r7, ip, lr} \n\
mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
add %0, %0, #32 \n\
stmia %0, {r2 - r7, ip, lr} \n\
subs %2, %2, #(32 * 8) \n\
mcr p15, 0, %0, c7, c14, 1 @ clean and invalidate D line\n\
add %0, %0, #32 \n\
bne 1b \n\
mcr p15, 0, ip, c7, c10, 4 @ drain WB\n\
ldmfd sp!, {r4-r9, pc}"
:
: "r" (kto), "r" (kfrom), "I" (PAGE_SIZE));
mcr p15, 0, %2, c7, c10, 4 @ drain WB"
: "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
: "2" (PAGE_SIZE)
: "r2", "r3", "r4", "r5", "r6", "r7", "ip", "lr");
}
void feroceon_copy_user_highpage(struct page *to, struct page *from,
......
......@@ -40,12 +40,11 @@ static DEFINE_RAW_SPINLOCK(minicache_lock);
* instruction. If your processor does not supply this, you have to write your
* own copy_user_highpage that does the right thing.
*/
static void __naked
mc_copy_user_page(void *from, void *to)
static void mc_copy_user_page(void *from, void *to)
{
asm volatile(
"stmfd sp!, {r4, lr} @ 2\n\
mov r4, %2 @ 1\n\
int tmp;
asm volatile ("\
ldmia %0!, {r2, r3, ip, lr} @ 4\n\
1: mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\
stmia %1!, {r2, r3, ip, lr} @ 4\n\
......@@ -55,13 +54,13 @@ mc_copy_user_page(void *from, void *to)
mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\
stmia %1!, {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\
ldmneia %0!, {r2, r3, ip, lr} @ 4\n\
bne 1b @ 1\n\
ldmfd sp!, {r4, pc} @ 3"
:
: "r" (from), "r" (to), "I" (PAGE_SIZE / 64));
bne 1b @ "
: "+&r" (from), "+&r" (to), "=&r" (tmp)
: "2" (PAGE_SIZE / 64)
: "r2", "r3", "ip", "lr");
}
void v4_mc_copy_user_highpage(struct page *to, struct page *from,
......
......@@ -22,29 +22,28 @@
* instruction. If your processor does not supply this, you have to write your
* own copy_user_highpage that does the right thing.
*/
static void __naked
v4wb_copy_user_page(void *kto, const void *kfrom)
static void v4wb_copy_user_page(void *kto, const void *kfrom)
{
asm("\
stmfd sp!, {r4, lr} @ 2\n\
mov r2, %2 @ 1\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4+1\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
subs r2, r2, #1 @ 1\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\
ldmneia r1!, {r3, r4, ip, lr} @ 4\n\
int tmp;
asm volatile ("\
ldmia %1!, {r3, r4, ip, lr} @ 4\n\
1: mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia %1!, {r3, r4, ip, lr} @ 4+1\n\
stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia %1!, {r3, r4, ip, lr} @ 4\n\
mcr p15, 0, %0, c7, c6, 1 @ 1 invalidate D line\n\
stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia %1!, {r3, r4, ip, lr} @ 4\n\
subs %2, %2, #1 @ 1\n\
stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmneia %1!, {r3, r4, ip, lr} @ 4\n\
bne 1b @ 1\n\
mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB\n\
ldmfd sp!, {r4, pc} @ 3"
:
: "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64));
mcr p15, 0, %1, c7, c10, 4 @ 1 drain WB"
: "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
: "2" (PAGE_SIZE / 64)
: "r3", "r4", "ip", "lr");
}
void v4wb_copy_user_highpage(struct page *to, struct page *from,
......
......@@ -20,27 +20,26 @@
* dirty data in the cache. However, we do have to ensure that
* subsequent reads are up to date.
*/
static void __naked
v4wt_copy_user_page(void *kto, const void *kfrom)
static void v4wt_copy_user_page(void *kto, const void *kfrom)
{
asm("\
stmfd sp!, {r4, lr} @ 2\n\
mov r2, %2 @ 1\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
1: stmia r0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4+1\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\
ldmia r1!, {r3, r4, ip, lr} @ 4\n\
subs r2, r2, #1 @ 1\n\
stmia r0!, {r3, r4, ip, lr} @ 4\n\
ldmneia r1!, {r3, r4, ip, lr} @ 4\n\
int tmp;
asm volatile ("\
ldmia %1!, {r3, r4, ip, lr} @ 4\n\
1: stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia %1!, {r3, r4, ip, lr} @ 4+1\n\
stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia %1!, {r3, r4, ip, lr} @ 4\n\
stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmia %1!, {r3, r4, ip, lr} @ 4\n\
subs %2, %2, #1 @ 1\n\
stmia %0!, {r3, r4, ip, lr} @ 4\n\
ldmneia %1!, {r3, r4, ip, lr} @ 4\n\
bne 1b @ 1\n\
mcr p15, 0, r2, c7, c7, 0 @ flush ID cache\n\
ldmfd sp!, {r4, pc} @ 3"
:
: "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64));
mcr p15, 0, %2, c7, c7, 0 @ flush ID cache"
: "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
: "2" (PAGE_SIZE / 64)
: "r3", "r4", "ip", "lr");
}
void v4wt_copy_user_highpage(struct page *to, struct page *from,
......
......@@ -21,53 +21,46 @@
/*
* XSC3 optimised copy_user_highpage
* r0 = destination
* r1 = source
*
* 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
* if we eventually end up using our copied page.
*
*/
static void __naked
xsc3_mc_copy_user_page(void *kto, const void *kfrom)
static void xsc3_mc_copy_user_page(void *kto, const void *kfrom)
{
asm("\
stmfd sp!, {r4, r5, lr} \n\
mov lr, %2 \n\
\n\
pld [r1, #0] \n\
pld [r1, #32] \n\
1: pld [r1, #64] \n\
pld [r1, #96] \n\
int tmp;
asm volatile ("\
pld [%1, #0] \n\
pld [%1, #32] \n\
1: pld [%1, #64] \n\
pld [%1, #96] \n\
\n\
2: ldrd r2, [r1], #8 \n\
mov ip, r0 \n\
ldrd r4, [r1], #8 \n\
mcr p15, 0, ip, c7, c6, 1 @ invalidate\n\
strd r2, [r0], #8 \n\
ldrd r2, [r1], #8 \n\
strd r4, [r0], #8 \n\
ldrd r4, [r1], #8 \n\
strd r2, [r0], #8 \n\
strd r4, [r0], #8 \n\
ldrd r2, [r1], #8 \n\
mov ip, r0 \n\
ldrd r4, [r1], #8 \n\
mcr p15, 0, ip, c7, c6, 1 @ invalidate\n\
strd r2, [r0], #8 \n\
ldrd r2, [r1], #8 \n\
subs lr, lr, #1 \n\
strd r4, [r0], #8 \n\
ldrd r4, [r1], #8 \n\
strd r2, [r0], #8 \n\
strd r4, [r0], #8 \n\
2: ldrd r2, r3, [%1], #8 \n\
ldrd r4, r5, [%1], #8 \n\
mcr p15, 0, %0, c7, c6, 1 @ invalidate\n\
strd r2, r3, [%0], #8 \n\
ldrd r2, r3, [%1], #8 \n\
strd r4, r5, [%0], #8 \n\
ldrd r4, r5, [%1], #8 \n\
strd r2, r3, [%0], #8 \n\
strd r4, r5, [%0], #8 \n\
ldrd r2, r3, [%1], #8 \n\
ldrd r4, r5, [%1], #8 \n\
mcr p15, 0, %0, c7, c6, 1 @ invalidate\n\
strd r2, r3, [%0], #8 \n\
ldrd r2, r3, [%1], #8 \n\
subs %2, %2, #1 \n\
strd r4, r5, [%0], #8 \n\
ldrd r4, r5, [%1], #8 \n\
strd r2, r3, [%0], #8 \n\
strd r4, r5, [%0], #8 \n\
bgt 1b \n\
beq 2b \n\
\n\
ldmfd sp!, {r4, r5, pc}"
:
: "r" (kto), "r" (kfrom), "I" (PAGE_SIZE / 64 - 1));
beq 2b "
: "+&r" (kto), "+&r" (kfrom), "=&r" (tmp)
: "2" (PAGE_SIZE / 64 - 1)
: "r2", "r3", "r4", "r5");
}
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
* r0 = destination
* r1 = virtual user address of ultimate destination page
*/
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 r3, #0 \n\
1: mcr p15, 0, %0, c7, c6, 1 @ invalidate line\n\
strd r2, [%0], #8 \n\
strd r2, [%0], #8 \n\
strd r2, [%0], #8 \n\
strd r2, [%0], #8 \n\
strd r2, r3, [%0], #8 \n\
strd r2, r3, [%0], #8 \n\
strd r2, r3, [%0], #8 \n\
strd r2, r3, [%0], #8 \n\
subs r1, r1, #1 \n\
bne 1b"
: "=r" (ptr)
......
......@@ -36,52 +36,51 @@ static DEFINE_RAW_SPINLOCK(minicache_lock);
* Dcache aliasing issue. The writes will be forwarded to the write buffer,
* and merged as appropriate.
*/
static void __naked
mc_copy_user_page(void *from, void *to)
static void mc_copy_user_page(void *from, void *to)
{
int tmp;
/*
* Strangely enough, best performance is achieved
* when prefetching destination as well. (NP)
*/
asm volatile(
"stmfd sp!, {r4, r5, lr} \n\
mov lr, %2 \n\
pld [r0, #0] \n\
pld [r0, #32] \n\
pld [r1, #0] \n\
pld [r1, #32] \n\
1: pld [r0, #64] \n\
pld [r0, #96] \n\
pld [r1, #64] \n\
pld [r1, #96] \n\
2: ldrd r2, [r0], #8 \n\
ldrd r4, [r0], #8 \n\
mov ip, r1 \n\
strd r2, [r1], #8 \n\
ldrd r2, [r0], #8 \n\
strd r4, [r1], #8 \n\
ldrd r4, [r0], #8 \n\
strd r2, [r1], #8 \n\
strd r4, [r1], #8 \n\
asm volatile ("\
pld [%0, #0] \n\
pld [%0, #32] \n\
pld [%1, #0] \n\
pld [%1, #32] \n\
1: pld [%0, #64] \n\
pld [%0, #96] \n\
pld [%1, #64] \n\
pld [%1, #96] \n\
2: ldrd r2, r3, [%0], #8 \n\
ldrd r4, r5, [%0], #8 \n\
mov ip, %1 \n\
strd r2, r3, [%1], #8 \n\
ldrd r2, r3, [%0], #8 \n\
strd r4, r5, [%1], #8 \n\
ldrd r4, r5, [%0], #8 \n\
strd r2, r3, [%1], #8 \n\
strd r4, r5, [%1], #8 \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\
ldrd r4, [r0], #8 \n\
mov ip, r1 \n\
strd r2, [r1], #8 \n\
ldrd r2, [r0], #8 \n\
strd r4, [r1], #8 \n\
ldrd r4, [r0], #8 \n\
strd r2, [r1], #8 \n\
strd r4, [r1], #8 \n\
ldrd r4, r5, [%0], #8 \n\
mov ip, %1 \n\
strd r2, r3, [%1], #8 \n\
ldrd r2, r3, [%0], #8 \n\
strd r4, r5, [%1], #8 \n\
ldrd r4, r5, [%0], #8 \n\
strd r2, r3, [%1], #8 \n\
strd r4, r5, [%1], #8 \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\
bgt 1b \n\
beq 2b \n\
ldmfd sp!, {r4, r5, pc} "
:
: "r" (from), "r" (to), "I" (PAGE_SIZE / 64 - 1));
beq 2b "
: "+&r" (from), "+&r" (to), "=&r" (tmp)
: "2" (PAGE_SIZE / 64 - 1)
: "r2", "r3", "r4", "r5", "ip");
}
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)
mov r2, #0 \n\
mov r3, #0 \n\
1: mov ip, %0 \n\
strd r2, [%0], #8 \n\
strd r2, [%0], #8 \n\
strd r2, [%0], #8 \n\
strd r2, [%0], #8 \n\
strd r2, r3, [%0], #8 \n\
strd r2, r3, [%0], #8 \n\
strd r2, r3, [%0], #8 \n\
strd r2, r3, [%0], #8 \n\
mcr p15, 0, ip, c7, c10, 1 @ clean D line\n\
subs r1, r1, #1 \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,
show_regs(regs);
}
#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.error_code = fsr;
......
......@@ -278,7 +278,7 @@
* If we are building for big.Little with branch predictor hardening,
* 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"
#endif
.type \name\()_processor_functions, #object
......@@ -316,7 +316,7 @@ ENTRY(\name\()_processor_functions)
.endif
.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
#endif
.endm
......
......@@ -33,10 +33,10 @@ ENTRY(lpae_pgtables_remap_asm)
add r7, r2, #0x1000
add r6, r7, r6, lsr #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
adc r5, r5, r1
strd r4, [r7], #1 << L2_ORDER
strd r4, r5, [r7], #1 << L2_ORDER
cmp r7, r6
bls 1b
......@@ -44,22 +44,22 @@ ENTRY(lpae_pgtables_remap_asm)
add r7, r2, #0x1000
add r7, r7, r3, lsr #SECTION_SHIFT - L2_ORDER
bic r7, r7, #(1 << L2_ORDER) - 1
ldrd r4, [r7]
ldrd r4, r5, [r7]
adds r4, r4, r0
adc r5, r5, r1
strd r4, [r7], #1 << L2_ORDER
ldrd r4, [r7]
strd r4, r5, [r7], #1 << L2_ORDER
ldrd r4, r5, [r7]
adds r4, r4, r0
adc r5, r5, r1
strd r4, [r7]
strd r4, r5, [r7]
/* Update level 1 entries */
mov r6, #4
mov r7, r2
2: ldrd r4, [r7]
2: ldrd r4, r5, [r7]
adds r4, r4, r0
adc r5, r5, r1
strd r4, [r7], #1 << L1_ORDER
strd r4, r5, [r7], #1 << L1_ORDER
subs r6, r6, #1
bne 2b
......
......@@ -92,7 +92,6 @@ config OMAP_32K_TIMER
config OMAP3_L2_AUX_SECURE_SAVE_RESTORE
bool "OMAP3 HS/EMU save and restore for L2 AUX control register"
depends on ARCH_OMAP3 && PM
default n
help
Without this option, L2 Auxiliary control register contents are
lost during off-mode entry on HS/EMU devices. This feature
......
......@@ -2,3 +2,4 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
......@@ -37,5 +37,5 @@ pen: ldr r7, [r6]
.align
1: .long .
.long pen_release
.long versatile_cpu_release
ENDPROC(versatile_secondary_startup)
/*
* 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.
*
* 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/errno.h>
......@@ -15,9 +18,9 @@
#include <asm/smp_plat.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;
......@@ -34,11 +37,11 @@ static inline void cpu_enter_lowpower(void)
" bic %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 0\n"
: "=&r" (v)
: "r" (0), "Ir" (CR_C), "Ir" (0x40)
: "r" (0), "Ir" (CR_C), "Ir" (actrl_mask)
: "cc");
}
static inline void cpu_leave_lowpower(void)
static inline void versatile_immitation_leave_lowpower(unsigned int actrl_mask)
{
unsigned int v;
......@@ -50,21 +53,23 @@ static inline void cpu_leave_lowpower(void)
" orr %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 1\n"
: "=&r" (v)
: "Ir" (CR_C), "Ir" (0x40)
: "Ir" (CR_C), "Ir" (actrl_mask)
: "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
* 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 (;;) {
wfi();
if (pen_release == cpu_logical_map(cpu)) {
if (versatile_cpu_release == cpu_logical_map(cpu)) {
/*
* OK, proper wakeup, we're done
*/
......@@ -83,25 +88,17 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
}
/*
* platform-specific code to shutdown a CPU
*
* Called with IRQs disabled
* platform-specific code to shutdown a CPU.
* This code supports immitation-style CPU hotplug for Versatile/Realview/
* 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;
/*
* 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();
versatile_immitation_enter_lowpower(actrl_mask);
versatile_immitation_do_lowpower(cpu, &spurious);
versatile_immitation_leave_lowpower(actrl_mask);
if (spurious)
pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
......
......@@ -8,7 +8,9 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
extern volatile int versatile_cpu_release;
extern void versatile_secondary_startup(void);
extern void versatile_secondary_init(unsigned int cpu);
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 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This 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/errno.h>
......@@ -21,18 +26,32 @@
#include <plat/platsmp.h>
/*
* Write pen_release in a way that is guaranteed to be visible to all
* observers, irrespective of whether they're taking part in coherency
* versatile_cpu_release controls the release of CPUs from the holding
* 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.
*/
static void write_pen_release(int val)
static void versatile_write_cpu_release(int val)
{
pen_release = val;
versatile_cpu_release = val;
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)
{
......@@ -40,13 +59,13 @@ void versatile_secondary_init(unsigned int cpu)
* let the primary processor know we're out of the
* pen, then head off into the C entry point
*/
write_pen_release(-1);
versatile_write_cpu_release(-1);
/*
* Synchronise with the boot thread.
*/
spin_lock(&boot_lock);
spin_unlock(&boot_lock);
raw_spin_lock(&versatile_lock);
raw_spin_unlock(&versatile_lock);
}
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
* and the secondary one
*/
spin_lock(&boot_lock);
raw_spin_lock(&versatile_lock);
/*
* 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)
* since we haven't sent them a soft interrupt, they shouldn't
* 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
......@@ -77,7 +96,7 @@ int versatile_boot_secondary(unsigned int cpu, struct task_struct *idle)
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
smp_rmb();
if (pen_release == -1)
if (versatile_cpu_release == -1)
break;
udelay(10);
......@@ -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
* 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
If unsure, say Y.
config PCMCIA_MAX1600
tristate
comment "PC-card bridges"
config YENTA
......@@ -192,6 +195,8 @@ config PCMCIA_SA1111
select PCMCIA_SOC_COMMON
select PCMCIA_SA11XX_BASE if ARCH_SA1100
select PCMCIA_PXA2XX if ARCH_LUBBOCK && SA1111
select PCMCIA_MAX1600 if ASSABET_NEPONSET
select PCMCIA_MAX1600 if ARCH_LUBBOCK && SA1111
help
Say Y here to include support for SA1111-based PCMCIA or CF
sockets, found on the Jornada 720, Graphicsmaster and other
......@@ -208,6 +213,7 @@ config PCMCIA_PXA2XX
|| MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
|| MACH_COLIBRI320 || MACH_H4700)
select PCMCIA_SOC_COMMON
select PCMCIA_MAX1600 if MACH_MAINSTONE
help
Say Y here to include support for the PXA2xx PCMCIA controller
......
......@@ -35,6 +35,7 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o
obj-$(CONFIG_AT91_CF) += at91_cf.o
obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o
obj-$(CONFIG_PCMCIA_MAX1600) += max1600.o
sa1111_cs-y += sa1111_generic.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 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <pcmcia/ss.h>
#include <asm/mach-types.h>
#include <asm/irq.h>
#include <mach/pxa2xx-regs.h>
#include <mach/mainstone.h>
#include "soc_common.h"
#include "max1600.h"
static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
/*
* Setup default state of GPIO outputs
* before we enable them as outputs.
*/
if (skt->nr == 0) {
skt->socket.pci_irq = MAINSTONE_S0_IRQ;
skt->stat[SOC_STAT_CD].irq = MAINSTONE_S0_CD_IRQ;
skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S0_STSCHG_IRQ;
skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG";
} else {
skt->socket.pci_irq = MAINSTONE_S1_IRQ;
skt->stat[SOC_STAT_CD].irq = MAINSTONE_S1_CD_IRQ;
skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD";
skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S1_STSCHG_IRQ;
skt->stat[SOC_STAT_BVD1].name = "PCMCIA1 STSCHG";
}
return 0;
struct device *dev = skt->socket.dev.parent;
struct max1600 *m;
int ret;
skt->stat[SOC_STAT_CD].name = skt->nr ? "bdetect" : "adetect";
skt->stat[SOC_STAT_BVD1].name = skt->nr ? "bbvd1" : "abvd1";
skt->stat[SOC_STAT_BVD2].name = skt->nr ? "bbvd2" : "abvd2";
skt->stat[SOC_STAT_RDY].name = skt->nr ? "bready" : "aready";
skt->stat[SOC_STAT_VS1].name = skt->nr ? "bvs1" : "avs1";
skt->stat[SOC_STAT_VS2].name = skt->nr ? "bvs2" : "avs2";
skt->gpio_reset = devm_gpiod_get(dev, skt->nr ? "breset" : "areset",
GPIOD_OUT_HIGH);
if (IS_ERR(skt->gpio_reset))
return PTR_ERR(skt->gpio_reset);
ret = max1600_init(dev, &m, skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
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,
struct pcmcia_state *state)
{
unsigned long status, flip;
status = (skt->nr == 0) ? MST_PCMCIA0 : MST_PCMCIA1;
flip = (status ^ mst_pcmcia_status[skt->nr]) & MST_PCMCIA_nSTSCHG_BVD1;
unsigned int flip = mst_pcmcia_bvd1_status[skt->nr] ^ state->bvd1;
/*
* Workaround for STSCHG which can't be deasserted:
......@@ -68,62 +67,18 @@ static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
* as needed to avoid IRQ locks.
*/
if (flip) {
mst_pcmcia_status[skt->nr] = status;
if (status & MST_PCMCIA_nSTSCHG_BVD1)
enable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ
: MAINSTONE_S1_STSCHG_IRQ );
mst_pcmcia_bvd1_status[skt->nr] = state->bvd1;
if (state->bvd1)
enable_irq(skt->stat[SOC_STAT_BVD1].irq);
else
disable_irq( (skt->nr == 0) ? MAINSTONE_S0_STSCHG_IRQ
: MAINSTONE_S1_STSCHG_IRQ );
disable_irq(skt->stat[SOC_STAT_BVD2].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,
const socket_state_t *state)
{
unsigned long power = 0;
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;
return max1600_configure(skt->driver_data, state->Vcc, state->Vpp);
}
static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
......
......@@ -39,8 +39,8 @@ simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
{
long cs3reg = simpad_get_cs3_ro();
state->bvd1 = 1; /* Might be cs3reg & PCMCIA_BVD1 */
state->bvd2 = 1; /* Might be cs3reg & PCMCIA_BVD2 */
/* bvd1 might be cs3reg & PCMCIA_BVD1 */
/* bvd2 might be cs3reg & PCMCIA_BVD2 */
if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) ==
(PCMCIA_VS1|PCMCIA_VS2)) {
......
......@@ -6,29 +6,62 @@
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <asm/hardware/sa1111.h>
#include <asm/mach-types.h>
#include "sa1111_generic.h"
/* Does SOCKET1_3V actually do anything? */
#define SOCKET0_POWER GPIO_GPIO0
#define SOCKET0_3V GPIO_GPIO2
#define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3)
#define SOCKET1_3V GPIO_GPIO3
/*
* Socket 0 power: GPIO A0
* Socket 0 3V: GPIO A2
* Socket 1 power: GPIO A1 & GPIO A3
* 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
jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
{
struct sa1111_pcmcia_socket *s = to_skt(skt);
unsigned int pa_dwr_mask, pa_dwr_set;
struct jornada720_data *j = skt->driver_data;
DECLARE_BITMAP(values, J720_GPIO_MAX) = { 0, };
int ret;
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
switch (skt->nr) {
case 0:
pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
switch (state->Vcc) {
default:
case 0:
pa_dwr_set = 0;
__assign_bit(J720_GPIO_PWR, values, 0);
__assign_bit(J720_GPIO_3V, values, 0);
break;
case 33:
pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;
__assign_bit(J720_GPIO_PWR, values, 1);
__assign_bit(J720_GPIO_3V, values, 1);
break;
case 50:
pa_dwr_set = SOCKET0_POWER;
__assign_bit(J720_GPIO_PWR, values, 1);
__assign_bit(J720_GPIO_3V, values, 0);
break;
}
break;
case 1:
pa_dwr_mask = SOCKET1_POWER;
switch (state->Vcc) {
default:
case 0:
pa_dwr_set = 0;
__assign_bit(J720_GPIO_PWR, values, 0);
__assign_bit(J720_GPIO_3V, values, 0);
break;
case 33:
pa_dwr_set = SOCKET1_POWER;
break;
case 50:
pa_dwr_set = SOCKET1_POWER;
__assign_bit(J720_GPIO_PWR, values, 1);
__assign_bit(J720_GPIO_3V, values, 1);
break;
}
break;
......@@ -81,13 +113,15 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
ret = sa1111_pcmcia_configure_socket(skt, state);
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;
}
static struct pcmcia_low_level jornada720_pcmcia_ops = {
.owner = THIS_MODULE,
.hw_init = jornada720_pcmcia_hw_init,
.configure_socket = jornada720_pcmcia_configure_socket,
.first = 0,
.nr = 2,
......@@ -95,16 +129,9 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = {
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? */
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);
return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops,
sa11xx_drv_pcmcia_add_one);
......
......@@ -24,20 +24,31 @@
#include <mach/hardware.h>
#include <asm/hardware/sa1111.h>
#include <asm/mach-types.h>
#include <mach/lubbock.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
lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
{
struct sa1111_pcmcia_socket *s = to_skt(skt);
unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
struct max1600 *m = skt->driver_data;
int ret = 0;
pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
/* Lubbock uses the Maxim MAX1602, with the following connections:
*
* Socket 0 (PCMCIA):
......@@ -71,74 +82,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
again:
switch (skt->nr) {
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:
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;
default:
......@@ -147,11 +91,8 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
if (ret == 0)
ret = sa1111_pcmcia_configure_socket(skt, state);
if (ret == 0) {
lubbock_set_misc_wr(misc_mask, misc_set);
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
}
if (ret == 0)
ret = max1600_configure(m, state->Vcc, state->Vpp);
#if 1
if (ret == 0 && state->Vcc == 33) {
......@@ -175,8 +116,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
/*
* Switch to 5V, Configure socket with 5V voltage
*/
lubbock_set_misc_wr(misc_mask, 0);
sa1111_set_io(s->dev, pa_dwr_mask, 0);
max1600_configure(m, 0, 0);
/*
* It takes about 100ms to turn off Vcc.
......@@ -201,6 +141,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
static struct pcmcia_low_level lubbock_pcmcia_ops = {
.owner = THIS_MODULE,
.hw_init = lubbock_pcmcia_hw_init,
.configure_socket = lubbock_pcmcia_configure_socket,
.first = 0,
.nr = 2,
......@@ -210,17 +151,6 @@ static struct pcmcia_low_level lubbock_pcmcia_ops = {
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_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops);
return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
......
......@@ -10,12 +10,10 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <mach/neponset.h>
#include <asm/hardware/sa1111.h>
#include "sa1111_generic.h"
#include "max1600.h"
/*
* Neponset uses the Maxim MAX1600, with the following connections:
......@@ -40,70 +38,36 @@
* "Standard Intel code" mode. Refer to the Maxim data sheet for
* the corresponding truth table.
*/
static int
neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
static int neponset_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
struct sa1111_pcmcia_socket *s = to_skt(skt);
unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
struct max1600 *m;
int ret;
switch (skt->nr) {
case 0:
pa_dwr_mask = GPIO_A0 | GPIO_A1;
ncr_mask = NCR_A0VPP | NCR_A1VPP;
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;
ret = max1600_init(skt->socket.dev.parent, &m,
skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
MAX1600_CODE_LOW);
if (ret == 0)
skt->driver_data = m;
case 1:
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;
}
return ret;
}
/*
* pa_dwr_set is the mask for selecting Vcc on both sockets.
* pa_dwr_mask selects which bits (and therefore socket) we change.
*/
switch (state->Vcc) {
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;
}
static int
neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
{
struct max1600 *m = skt->driver_data;
int ret;
ret = sa1111_pcmcia_configure_socket(skt, state);
if (ret == 0) {
neponset_ncr_frob(ncr_mask, ncr_set);
sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
}
if (ret == 0)
ret = max1600_configure(m, state->Vcc, state->Vpp);
return ret;
}
static struct pcmcia_low_level neponset_pcmcia_ops = {
.owner = THIS_MODULE,
.hw_init = neponset_pcmcia_hw_init,
.configure_socket = neponset_pcmcia_configure_socket,
.first = 0,
.nr = 2,
......@@ -111,13 +75,6 @@ static struct pcmcia_low_level neponset_pcmcia_ops = {
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);
return sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
sa11xx_drv_pcmcia_add_one);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册