ARM: mvebu: fix cpuidle implementation to work on big-endian systems
On Marvell Armada XP, when a CPU comes back from deep idle state of
cpuidle, it restarts its execution at armada_370_xp_cpu_resume(),
which puts back the CPU into the coherency, and then calls the generic
cpu_resume() function.
While this works on little-endian configurations, it doesn't work on
big-endian configurations because the CPU restarts in little-endian,
and therefore must be switched back to big-endian to operate
properly. To achieve this, a 'setend be' instruction must be executed
in big-endian configurations. However, the ARM_BE8() macro that is
used to implement nice compile-time conditional for ARM LE vs. ARM BE8
is not easily usable in inline assembly.
Therefore, this patch moves the armada_370_xp_cpu_resume() C function,
which was anyway just a block of inline assembly, into a proper
pmsu_ll.S file, and adds the appropriate ARM_BE8(setend be)
instruction.
Without this patch, an Armada XP big endian configuration with cpuidle
enabled fails to boot, as it hangs as soon as one of the CPU hits the
deep idle state.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Link: https://lkml.kernel.org/r/1404130165-3593-1-git-send-email-thomas.petazzoni@free-electrons.com
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
2014-06-30 20:09:25 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 Marvell
|
|
|
|
*
|
|
|
|
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
|
|
|
* Gregory Clement <gregory.clement@free-electrons.com>
|
|
|
|
*
|
|
|
|
* This file is licensed under the terms of the GNU General Public
|
|
|
|
* License version 2. This program is licensed "as is" without any
|
|
|
|
* warranty of any kind, whether express or implied.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/linkage.h>
|
|
|
|
#include <asm/assembler.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the entry point through which CPUs exiting cpuidle deep
|
|
|
|
* idle state are going.
|
|
|
|
*/
|
|
|
|
ENTRY(armada_370_xp_cpu_resume)
|
|
|
|
ARM_BE8(setend be ) @ go BE8 if entered LE
|
|
|
|
bl ll_add_cpu_to_smp_group
|
|
|
|
bl ll_enable_coherency
|
|
|
|
b cpu_resume
|
|
|
|
ENDPROC(armada_370_xp_cpu_resume)
|
|
|
|
|
2014-07-23 21:00:52 +08:00
|
|
|
ENTRY(armada_38x_cpu_resume)
|
|
|
|
/* do we need it for Armada 38x*/
|
|
|
|
ARM_BE8(setend be ) @ go BE8 if entered LE
|
|
|
|
bl v7_invalidate_l1
|
|
|
|
mrc p15, 4, r1, c15, c0 @ get SCU base address
|
|
|
|
orr r1, r1, #0x8 @ SCU CPU Power Status Register
|
|
|
|
mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID
|
|
|
|
and r0, r0, #15
|
|
|
|
add r1, r1, r0
|
|
|
|
mov r0, #0x0
|
|
|
|
strb r0, [r1] @ switch SCU power state to Normal mode
|
|
|
|
b cpu_resume
|
|
|
|
ENDPROC(armada_38x_cpu_resume)
|
|
|
|
|
2014-07-23 21:00:40 +08:00
|
|
|
.global mvebu_boot_wa_start
|
|
|
|
.global mvebu_boot_wa_end
|
|
|
|
|
|
|
|
/* The following code will be executed from SRAM */
|
|
|
|
ENTRY(mvebu_boot_wa_start)
|
|
|
|
mvebu_boot_wa_start:
|
|
|
|
ARM_BE8(setend be)
|
|
|
|
adr r0, 1f
|
|
|
|
ldr r0, [r0] @ load the address of the
|
|
|
|
@ resume register
|
|
|
|
ldr r0, [r0] @ load the value in the
|
|
|
|
@ resume register
|
|
|
|
ARM_BE8(rev r0, r0) @ the value is stored LE
|
|
|
|
mov pc, r0 @ jump to this value
|
|
|
|
/*
|
|
|
|
* the last word of this piece of code will be filled by the physical
|
|
|
|
* address of the boot address register just after being copied in SRAM
|
|
|
|
*/
|
|
|
|
1:
|
|
|
|
.long .
|
|
|
|
mvebu_boot_wa_end:
|
|
|
|
ENDPROC(mvebu_boot_wa_end)
|