123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /* SPDX-License-Identifier: GPL-2.0+ */
- /*
- * Copyright 2015 Freescale Semiconductor, Inc.
- * Author: Wang Dongsheng <dongsheng.wang@freescale.com>
- */
- #include <config.h>
- #include <linux/linkage.h>
- #include <asm/armv7.h>
- #include <asm/arch-armv7/generictimer.h>
- #include <asm/psci.h>
- #define RCPM_TWAITSR 0x04C
- #define SCFG_CORE0_SFT_RST 0x130
- #define SCFG_CORESRENCR 0x204
- #define DCFG_CCSR_RSTCR 0x0B0
- #define DCFG_CCSR_RSTCR_RESET_REQ 0x2
- #define DCFG_CCSR_BRR 0x0E4
- #define DCFG_CCSR_SCRATCHRW1 0x200
- #define PSCI_FN_PSCI_VERSION_FEATURE_MASK 0x0
- #define PSCI_FN_CPU_SUSPEND_FEATURE_MASK 0x0
- #define PSCI_FN_CPU_OFF_FEATURE_MASK 0x0
- #define PSCI_FN_CPU_ON_FEATURE_MASK 0x0
- #define PSCI_FN_AFFINITY_INFO_FEATURE_MASK 0x0
- #define PSCI_FN_SYSTEM_OFF_FEATURE_MASK 0x0
- #define PSCI_FN_SYSTEM_RESET_FEATURE_MASK 0x0
- #define PSCI_FN_SYSTEM_SUSPEND_FEATURE_MASK 0x0
- .pushsection ._secure.text, "ax"
- .arch_extension sec
- .align 5
- #define ONE_MS (COUNTER_FREQUENCY / 1000)
- #define RESET_WAIT (30 * ONE_MS)
- .globl psci_version
- psci_version:
- movw r0, #0
- movt r0, #1
- bx lr
- _ls102x_psci_supported_table:
- .word ARM_PSCI_0_2_FN_PSCI_VERSION
- .word PSCI_FN_PSCI_VERSION_FEATURE_MASK
- .word ARM_PSCI_0_2_FN_CPU_SUSPEND
- .word PSCI_FN_CPU_SUSPEND_FEATURE_MASK
- .word ARM_PSCI_0_2_FN_CPU_OFF
- .word PSCI_FN_CPU_OFF_FEATURE_MASK
- .word ARM_PSCI_0_2_FN_CPU_ON
- .word PSCI_FN_CPU_ON_FEATURE_MASK
- .word ARM_PSCI_0_2_FN_AFFINITY_INFO
- .word PSCI_FN_AFFINITY_INFO_FEATURE_MASK
- .word ARM_PSCI_0_2_FN_SYSTEM_OFF
- .word PSCI_FN_SYSTEM_OFF_FEATURE_MASK
- .word ARM_PSCI_0_2_FN_SYSTEM_RESET
- .word PSCI_FN_SYSTEM_RESET_FEATURE_MASK
- .word ARM_PSCI_1_0_FN_SYSTEM_SUSPEND
- .word PSCI_FN_SYSTEM_SUSPEND_FEATURE_MASK
- .word 0
- .word ARM_PSCI_RET_NI
- .globl psci_features
- psci_features:
- adr r2, _ls102x_psci_supported_table
- 1: ldr r3, [r2]
- cmp r3, #0
- beq out_psci_features
- cmp r1, r3
- addne r2, r2, #8
- bne 1b
- out_psci_features:
- ldr r0, [r2, #4]
- bx lr
- @ r0: return value ARM_PSCI_RET_SUCCESS or ARM_PSCI_RET_INVAL
- @ r1: input target CPU ID in MPIDR format, original value in r1 may be dropped
- @ r4: output validated CPU ID if ARM_PSCI_RET_SUCCESS returns, meaningless for
- @ ARM_PSCI_RET_INVAL,suppose caller saves r4 before calling
- LENTRY(psci_check_target_cpu_id)
- @ Get the real CPU number
- and r4, r1, #0xff
- mov r0, #ARM_PSCI_RET_INVAL
- @ Bit[31:24], bits must be zero.
- tst r1, #0xff000000
- bxne lr
- @ Affinity level 2 - Cluster: only one cluster in LS1021xa.
- tst r1, #0xff0000
- bxne lr
- @ Affinity level 1 - Processors: should be in 0xf00 format.
- lsr r1, r1, #8
- teq r1, #0xf
- bxne lr
- @ Affinity level 0 - CPU: only 0, 1 are valid in LS1021xa.
- cmp r4, #2
- bxge lr
- mov r0, #ARM_PSCI_RET_SUCCESS
- bx lr
- ENDPROC(psci_check_target_cpu_id)
- @ r1 = target CPU
- @ r2 = target PC
- .globl psci_cpu_on
- psci_cpu_on:
- push {r4, r5, r6, lr}
- @ Clear and Get the correct CPU number
- @ r1 = 0xf01
- bl psci_check_target_cpu_id
- cmp r0, #ARM_PSCI_RET_INVAL
- beq out_psci_cpu_on
- mov r0, r4
- mov r1, r2
- mov r2, r3
- bl psci_save
- mov r1, r4
- @ Get DCFG base address
- movw r4, #(CONFIG_SYS_FSL_GUTS_ADDR & 0xffff)
- movt r4, #(CONFIG_SYS_FSL_GUTS_ADDR >> 16)
- @ Detect target CPU state
- ldr r2, [r4, #DCFG_CCSR_BRR]
- rev r2, r2
- lsr r2, r2, r1
- ands r2, r2, #1
- beq holdoff_release
- @ Reset target CPU
- @ Get SCFG base address
- movw r0, #(CONFIG_SYS_FSL_SCFG_ADDR & 0xffff)
- movt r0, #(CONFIG_SYS_FSL_SCFG_ADDR >> 16)
- @ Enable CORE Soft Reset
- movw r5, #0
- movt r5, #(1 << 15)
- rev r5, r5
- str r5, [r0, #SCFG_CORESRENCR]
- @ Get CPUx offset register
- mov r6, #0x4
- mul r6, r6, r1
- add r2, r0, r6
- @ Do reset on target CPU
- movw r5, #0
- movt r5, #(1 << 15)
- rev r5, r5
- str r5, [r2, #SCFG_CORE0_SFT_RST]
- @ Wait target CPU up
- timer_wait r2, RESET_WAIT
- @ Disable CORE soft reset
- mov r5, #0
- str r5, [r0, #SCFG_CORESRENCR]
- holdoff_release:
- @ Release on target CPU
- ldr r2, [r4, #DCFG_CCSR_BRR]
- mov r6, #1
- lsl r6, r6, r1 @ 32 bytes per CPU
- rev r6, r6
- orr r2, r2, r6
- str r2, [r4, #DCFG_CCSR_BRR]
- @ Set secondary boot entry
- ldr r6, =psci_cpu_entry
- rev r6, r6
- str r6, [r4, #DCFG_CCSR_SCRATCHRW1]
- isb
- dsb
- @ Return
- mov r0, #ARM_PSCI_RET_SUCCESS
- out_psci_cpu_on:
- pop {r4, r5, r6, lr}
- bx lr
- .globl psci_cpu_off
- psci_cpu_off:
- bl psci_cpu_off_common
- 1: wfi
- b 1b
- .globl psci_affinity_info
- psci_affinity_info:
- push {lr}
- mov r0, #ARM_PSCI_RET_INVAL
- @ Verify Affinity level
- cmp r2, #0
- bne out_affinity_info
- bl psci_check_target_cpu_id
- cmp r0, #ARM_PSCI_RET_INVAL
- beq out_affinity_info
- mov r1, r4
- @ Get RCPM base address
- movw r4, #(CONFIG_SYS_FSL_RCPM_ADDR & 0xffff)
- movt r4, #(CONFIG_SYS_FSL_RCPM_ADDR >> 16)
- mov r0, #PSCI_AFFINITY_LEVEL_ON
- @ Detect target CPU state
- ldr r2, [r4, #RCPM_TWAITSR]
- rev r2, r2
- lsr r2, r2, r1
- ands r2, r2, #1
- beq out_affinity_info
- mov r0, #PSCI_AFFINITY_LEVEL_OFF
- out_affinity_info:
- pop {pc}
- .globl psci_system_reset
- psci_system_reset:
- @ Get DCFG base address
- movw r1, #(CONFIG_SYS_FSL_GUTS_ADDR & 0xffff)
- movt r1, #(CONFIG_SYS_FSL_GUTS_ADDR >> 16)
- mov r2, #DCFG_CCSR_RSTCR_RESET_REQ
- rev r2, r2
- str r2, [r1, #DCFG_CCSR_RSTCR]
- 1: wfi
- b 1b
- .globl psci_system_suspend
- psci_system_suspend:
- push {lr}
- bl ls1_system_suspend
- pop {pc}
- .popsection
|