From patchwork Mon Apr 10 08:41:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 97063 Delivered-To: patch@linaro.org Received: by 10.140.89.233 with SMTP id v96csp1266445qgd; Mon, 10 Apr 2017 01:41:48 -0700 (PDT) X-Received: by 10.28.98.66 with SMTP id w63mr8569307wmb.33.1491813708780; Mon, 10 Apr 2017 01:41:48 -0700 (PDT) Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id u4si11198616wmu.106.2017.04.10.01.41.48; Mon, 10 Apr 2017 01:41:48 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 3F6ADC21DE6; Mon, 10 Apr 2017 08:41:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 37F66C21D85; Mon, 10 Apr 2017 08:41:42 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 3B3A9C21D85; Mon, 10 Apr 2017 08:41:41 +0000 (UTC) Received: from conuserg-11.nifty.com (conuserg-11.nifty.com [210.131.2.78]) by lists.denx.de (Postfix) with ESMTPS id 0A598C21C26 for ; Mon, 10 Apr 2017 08:41:39 +0000 (UTC) Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-11.nifty.com with ESMTP id v3A8fMjZ003025; Mon, 10 Apr 2017 17:41:23 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-11.nifty.com v3A8fMjZ003025 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1491813684; bh=QydReTvd5YIsMZcnNX9xHwSDGst0q1z0M9D8AJXVRLc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JArxfRg4nVzp5tXn10Wa1APcI5KsC7twz1R4wtcFKrSomvBmcnGDekHT3SM0GgxQi qqzfEjqGUuM/g5Q8tx60d1cI4XviemULvNoXi8xoJCN3HUT8HnYEuVPF3H7+krilBV 4emfkCthygFMj8BxUw6KX54OLFBM0LTnxl2fHpUb+NpQuv42oG2bfq7HW0AnEglSyM fmFTdzEK2LYy6jlCvMyyXl9QOH3MY049s5sC8JMa0KwQkvOzHPXEeg3Y4zkD7c413Z yRPoURK8qagzJgjxKNkpxkEnx3+borHsusUsWdxqcB/I3FHcRiKDbRxhSHFov2+/4d YRfNw3N6aQUjg== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Mon, 10 Apr 2017 17:41:18 +0900 Message-Id: <1491813679-22630-2-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1491813679-22630-1-git-send-email-yamada.masahiro@socionext.com> References: <1491813679-22630-1-git-send-email-yamada.masahiro@socionext.com> Cc: Tom Rini Subject: [U-Boot] [PATCH 1/2] ARM: import arm-smccc from Linux 4.11-rc6 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" This imports ARM SMC Calling Convention code from Linux 4.11-rc6. The files have been copied as follows: [Linux] [U-Boot] arch/arm/kernel/smccc-call.S -> arch/arm/cpu/armv7/smccc-call.S arch/arm64/kernel/smccc-call.S -> arch/arm/cpu/armv8/smccc-call.S arch/arm/include/asm/opcodes* -> arch/arm/include/asm/opcodes* include/linux/arm-smccc.h -> include/linux/arm-smccc.h They needed to be adjusted for U-Boot: - Replace the license block with SPDX - Adjust path to asm-offsets.h - define UNWIND() as no-op Signed-off-by: Masahiro Yamada --- arch/arm/Kconfig | 8 ++ arch/arm/cpu/armv7/Makefile | 1 + arch/arm/cpu/armv7/smccc-call.S | 56 +++++++++ arch/arm/cpu/armv8/Makefile | 2 + arch/arm/cpu/armv8/smccc-call.S | 44 +++++++ arch/arm/include/asm/opcodes-sec.h | 17 +++ arch/arm/include/asm/opcodes-virt.h | 27 +++++ arch/arm/include/asm/opcodes.h | 229 ++++++++++++++++++++++++++++++++++++ arch/arm/lib/asm-offsets.c | 8 ++ include/linux/arm-smccc.h | 126 ++++++++++++++++++++ 10 files changed, 518 insertions(+) create mode 100644 arch/arm/cpu/armv7/smccc-call.S create mode 100644 arch/arm/cpu/armv8/smccc-call.S create mode 100644 arch/arm/include/asm/opcodes-sec.h create mode 100644 arch/arm/include/asm/opcodes-virt.h create mode 100644 arch/arm/include/asm/opcodes.h create mode 100644 include/linux/arm-smccc.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7b20750..84744ef 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -174,6 +174,14 @@ config SYS_CACHELINE_SIZE default 64 if SYS_CACHE_SHIFT_6 default 32 if SYS_CACHE_SHIFT_5 +config ARM_SMCCC + bool "Support for ARM SMC Calling Convention (SMCCC)" + depends on CPU_V7 || ARM64 + help + Say Y here if you want to enable ARM SMC Calling Convention. + This should be enabled if U-Boot needs to communicate with system + firmware (for example, PSCI) according to SMCCC. + config SEMIHOSTING bool "support boot from semihosting" help diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile index 02e8778..3a9913a 100644 --- a/arch/arm/cpu/armv7/Makefile +++ b/arch/arm/cpu/armv7/Makefile @@ -18,6 +18,7 @@ obj-y += lowlevel_init.o endif endif +obj-$(CONFIG_ARM_SMCCC) += smccc-call.o obj-$(CONFIG_ARMV7_NONSEC) += nonsec_virt.o virt-v7.o virt-dt.o obj-$(CONFIG_ARMV7_PSCI) += psci.o psci-common.o diff --git a/arch/arm/cpu/armv7/smccc-call.S b/arch/arm/cpu/armv7/smccc-call.S new file mode 100644 index 0000000..c2fdbad --- /dev/null +++ b/arch/arm/cpu/armv7/smccc-call.S @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * SPDX-License-Identifier: GPL-2.0 + */ +#include + +#include +#include + +#define UNWIND(x...) + /* + * Wrap c macros in asm macros to delay expansion until after the + * SMCCC asm macro is expanded. + */ + .macro SMCCC_SMC + __SMC(0) + .endm + + .macro SMCCC_HVC + __HVC(0) + .endm + + .macro SMCCC instr +UNWIND( .fnstart) + mov r12, sp + push {r4-r7} +UNWIND( .save {r4-r7}) + ldm r12, {r4-r7} + \instr + pop {r4-r7} + ldr r12, [sp, #(4 * 4)] + stm r12, {r0-r3} + bx lr +UNWIND( .fnend) + .endm + +/* + * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, + * struct arm_smccc_quirk *quirk) + */ +ENTRY(__arm_smccc_smc) + SMCCC SMCCC_SMC +ENDPROC(__arm_smccc_smc) + +/* + * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, + * struct arm_smccc_quirk *quirk) + */ +ENTRY(__arm_smccc_hvc) + SMCCC SMCCC_HVC +ENDPROC(__arm_smccc_hvc) diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile index 65915ee..c447085 100644 --- a/arch/arm/cpu/armv8/Makefile +++ b/arch/arm/cpu/armv8/Makefile @@ -16,6 +16,8 @@ obj-y += tlb.o obj-y += transition.o obj-y += fwcall.o obj-y += cpu-dt.o +obj-$(CONFIG_ARM_SMCCC) += smccc-call.o + ifndef CONFIG_SPL_BUILD obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o endif diff --git a/arch/arm/cpu/armv8/smccc-call.S b/arch/arm/cpu/armv8/smccc-call.S new file mode 100644 index 0000000..bbb6cba --- /dev/null +++ b/arch/arm/cpu/armv8/smccc-call.S @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * SPDX-License-Identifier: GPL-2.0 + */ +#include +#include +#include + + .macro SMCCC instr + .cfi_startproc + \instr #0 + ldr x4, [sp] + stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS] + stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS] + ldr x4, [sp, #8] + cbz x4, 1f /* no quirk structure */ + ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS] + cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6 + b.ne 1f + str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS] +1: ret + .cfi_endproc + .endm + +/* + * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, + * struct arm_smccc_quirk *quirk) + */ +ENTRY(__arm_smccc_smc) + SMCCC smc +ENDPROC(__arm_smccc_smc) + +/* + * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res, + * struct arm_smccc_quirk *quirk) + */ +ENTRY(__arm_smccc_hvc) + SMCCC hvc +ENDPROC(__arm_smccc_hvc) diff --git a/arch/arm/include/asm/opcodes-sec.h b/arch/arm/include/asm/opcodes-sec.h new file mode 100644 index 0000000..16dee8f --- /dev/null +++ b/arch/arm/include/asm/opcodes-sec.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2012 ARM Limited + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ASM_ARM_OPCODES_SEC_H +#define __ASM_ARM_OPCODES_SEC_H + +#include + +#define __SMC(imm4) __inst_arm_thumb32( \ + 0xE1600070 | (((imm4) & 0xF) << 0), \ + 0xF7F08000 | (((imm4) & 0xF) << 16) \ +) + +#endif /* __ASM_ARM_OPCODES_SEC_H */ diff --git a/arch/arm/include/asm/opcodes-virt.h b/arch/arm/include/asm/opcodes-virt.h new file mode 100644 index 0000000..923f257 --- /dev/null +++ b/arch/arm/include/asm/opcodes-virt.h @@ -0,0 +1,27 @@ +/* + * opcodes-virt.h: Opcode definitions for the ARM virtualization extensions + * Copyright (C) 2012 Linaro Limited + * + * SPDX-License-Identifier: GPL-2.0 + */ +#ifndef __ASM_ARM_OPCODES_VIRT_H +#define __ASM_ARM_OPCODES_VIRT_H + +#include + +#define __HVC(imm16) __inst_arm_thumb32( \ + 0xE1400070 | (((imm16) & 0xFFF0) << 4) | ((imm16) & 0x000F), \ + 0xF7E08000 | (((imm16) & 0xF000) << 4) | ((imm16) & 0x0FFF) \ +) + +#define __ERET __inst_arm_thumb32( \ + 0xE160006E, \ + 0xF3DE8F00 \ +) + +#define __MSR_ELR_HYP(regnum) __inst_arm_thumb32( \ + 0xE12EF300 | regnum, \ + 0xF3808E30 | (regnum << 16) \ +) + +#endif /* ! __ASM_ARM_OPCODES_VIRT_H */ diff --git a/arch/arm/include/asm/opcodes.h b/arch/arm/include/asm/opcodes.h new file mode 100644 index 0000000..199f0ba --- /dev/null +++ b/arch/arm/include/asm/opcodes.h @@ -0,0 +1,229 @@ +/* + * arch/arm/include/asm/opcodes.h + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ASM_ARM_OPCODES_H +#define __ASM_ARM_OPCODES_H + +#ifndef __ASSEMBLY__ +#include +extern asmlinkage unsigned int arm_check_condition(u32 opcode, u32 psr); +#endif + +#define ARM_OPCODE_CONDTEST_FAIL 0 +#define ARM_OPCODE_CONDTEST_PASS 1 +#define ARM_OPCODE_CONDTEST_UNCOND 2 + + +/* + * Assembler opcode byteswap helpers. + * These are only intended for use by this header: don't use them directly, + * because they will be suboptimal in most cases. + */ +#define ___asm_opcode_swab32(x) ( \ + (((x) << 24) & 0xFF000000) \ + | (((x) << 8) & 0x00FF0000) \ + | (((x) >> 8) & 0x0000FF00) \ + | (((x) >> 24) & 0x000000FF) \ +) +#define ___asm_opcode_swab16(x) ( \ + (((x) << 8) & 0xFF00) \ + | (((x) >> 8) & 0x00FF) \ +) +#define ___asm_opcode_swahb32(x) ( \ + (((x) << 8) & 0xFF00FF00) \ + | (((x) >> 8) & 0x00FF00FF) \ +) +#define ___asm_opcode_swahw32(x) ( \ + (((x) << 16) & 0xFFFF0000) \ + | (((x) >> 16) & 0x0000FFFF) \ +) +#define ___asm_opcode_identity32(x) ((x) & 0xFFFFFFFF) +#define ___asm_opcode_identity16(x) ((x) & 0xFFFF) + + +/* + * Opcode byteswap helpers + * + * These macros help with converting instructions between a canonical integer + * format and in-memory representation, in an endianness-agnostic manner. + * + * __mem_to_opcode_*() convert from in-memory representation to canonical form. + * __opcode_to_mem_*() convert from canonical form to in-memory representation. + * + * + * Canonical instruction representation: + * + * ARM: 0xKKLLMMNN + * Thumb 16-bit: 0x0000KKLL, where KK < 0xE8 + * Thumb 32-bit: 0xKKLLMMNN, where KK >= 0xE8 + * + * There is no way to distinguish an ARM instruction in canonical representation + * from a Thumb instruction (just as these cannot be distinguished in memory). + * Where this distinction is important, it needs to be tracked separately. + * + * Note that values in the range 0x0000E800..0xE7FFFFFF intentionally do not + * represent any valid Thumb-2 instruction. For this range, + * __opcode_is_thumb32() and __opcode_is_thumb16() will both be false. + * + * The ___asm variants are intended only for use by this header, in situations + * involving inline assembler. For .S files, the normal __opcode_*() macros + * should do the right thing. + */ +#ifdef __ASSEMBLY__ + +#define ___opcode_swab32(x) ___asm_opcode_swab32(x) +#define ___opcode_swab16(x) ___asm_opcode_swab16(x) +#define ___opcode_swahb32(x) ___asm_opcode_swahb32(x) +#define ___opcode_swahw32(x) ___asm_opcode_swahw32(x) +#define ___opcode_identity32(x) ___asm_opcode_identity32(x) +#define ___opcode_identity16(x) ___asm_opcode_identity16(x) + +#else /* ! __ASSEMBLY__ */ + +#include +#include + +#define ___opcode_swab32(x) swab32(x) +#define ___opcode_swab16(x) swab16(x) +#define ___opcode_swahb32(x) swahb32(x) +#define ___opcode_swahw32(x) swahw32(x) +#define ___opcode_identity32(x) ((u32)(x)) +#define ___opcode_identity16(x) ((u16)(x)) + +#endif /* ! __ASSEMBLY__ */ + + +#ifdef CONFIG_CPU_ENDIAN_BE8 + +#define __opcode_to_mem_arm(x) ___opcode_swab32(x) +#define __opcode_to_mem_thumb16(x) ___opcode_swab16(x) +#define __opcode_to_mem_thumb32(x) ___opcode_swahb32(x) +#define ___asm_opcode_to_mem_arm(x) ___asm_opcode_swab32(x) +#define ___asm_opcode_to_mem_thumb16(x) ___asm_opcode_swab16(x) +#define ___asm_opcode_to_mem_thumb32(x) ___asm_opcode_swahb32(x) + +#else /* ! CONFIG_CPU_ENDIAN_BE8 */ + +#define __opcode_to_mem_arm(x) ___opcode_identity32(x) +#define __opcode_to_mem_thumb16(x) ___opcode_identity16(x) +#define ___asm_opcode_to_mem_arm(x) ___asm_opcode_identity32(x) +#define ___asm_opcode_to_mem_thumb16(x) ___asm_opcode_identity16(x) +#ifndef CONFIG_CPU_ENDIAN_BE32 +/* + * On BE32 systems, using 32-bit accesses to store Thumb instructions will not + * work in all cases, due to alignment constraints. For now, a correct + * version is not provided for BE32. + */ +#define __opcode_to_mem_thumb32(x) ___opcode_swahw32(x) +#define ___asm_opcode_to_mem_thumb32(x) ___asm_opcode_swahw32(x) +#endif + +#endif /* ! CONFIG_CPU_ENDIAN_BE8 */ + +#define __mem_to_opcode_arm(x) __opcode_to_mem_arm(x) +#define __mem_to_opcode_thumb16(x) __opcode_to_mem_thumb16(x) +#ifndef CONFIG_CPU_ENDIAN_BE32 +#define __mem_to_opcode_thumb32(x) __opcode_to_mem_thumb32(x) +#endif + +/* Operations specific to Thumb opcodes */ + +/* Instruction size checks: */ +#define __opcode_is_thumb32(x) ( \ + ((x) & 0xF8000000) == 0xE8000000 \ + || ((x) & 0xF0000000) == 0xF0000000 \ +) +#define __opcode_is_thumb16(x) ( \ + ((x) & 0xFFFF0000) == 0 \ + && !(((x) & 0xF800) == 0xE800 || ((x) & 0xF000) == 0xF000) \ +) + +/* Operations to construct or split 32-bit Thumb instructions: */ +#define __opcode_thumb32_first(x) (___opcode_identity16((x) >> 16)) +#define __opcode_thumb32_second(x) (___opcode_identity16(x)) +#define __opcode_thumb32_compose(first, second) ( \ + (___opcode_identity32(___opcode_identity16(first)) << 16) \ + | ___opcode_identity32(___opcode_identity16(second)) \ +) +#define ___asm_opcode_thumb32_first(x) (___asm_opcode_identity16((x) >> 16)) +#define ___asm_opcode_thumb32_second(x) (___asm_opcode_identity16(x)) +#define ___asm_opcode_thumb32_compose(first, second) ( \ + (___asm_opcode_identity32(___asm_opcode_identity16(first)) << 16) \ + | ___asm_opcode_identity32(___asm_opcode_identity16(second)) \ +) + +/* + * Opcode injection helpers + * + * In rare cases it is necessary to assemble an opcode which the + * assembler does not support directly, or which would normally be + * rejected because of the CFLAGS or AFLAGS used to build the affected + * file. + * + * Before using these macros, consider carefully whether it is feasible + * instead to change the build flags for your file, or whether it really + * makes sense to support old assembler versions when building that + * particular kernel feature. + * + * The macros defined here should only be used where there is no viable + * alternative. + * + * + * __inst_arm(x): emit the specified ARM opcode + * __inst_thumb16(x): emit the specified 16-bit Thumb opcode + * __inst_thumb32(x): emit the specified 32-bit Thumb opcode + * + * __inst_arm_thumb16(arm, thumb): emit either the specified arm or + * 16-bit Thumb opcode, depending on whether an ARM or Thumb-2 + * kernel is being built + * + * __inst_arm_thumb32(arm, thumb): emit either the specified arm or + * 32-bit Thumb opcode, depending on whether an ARM or Thumb-2 + * kernel is being built + * + * + * Note that using these macros directly is poor practice. Instead, you + * should use them to define human-readable wrapper macros to encode the + * instructions that you care about. In code which might run on ARMv7 or + * above, you can usually use the __inst_arm_thumb{16,32} macros to + * specify the ARM and Thumb alternatives at the same time. This ensures + * that the correct opcode gets emitted depending on the instruction set + * used for the kernel build. + * + * Look at opcodes-virt.h for an example of how to use these macros. + */ +#include + +#define __inst_arm(x) ___inst_arm(___asm_opcode_to_mem_arm(x)) +#define __inst_thumb32(x) ___inst_thumb32( \ + ___asm_opcode_to_mem_thumb16(___asm_opcode_thumb32_first(x)), \ + ___asm_opcode_to_mem_thumb16(___asm_opcode_thumb32_second(x)) \ +) +#define __inst_thumb16(x) ___inst_thumb16(___asm_opcode_to_mem_thumb16(x)) + +#ifdef CONFIG_THUMB2_KERNEL +#define __inst_arm_thumb16(arm_opcode, thumb_opcode) \ + __inst_thumb16(thumb_opcode) +#define __inst_arm_thumb32(arm_opcode, thumb_opcode) \ + __inst_thumb32(thumb_opcode) +#else +#define __inst_arm_thumb16(arm_opcode, thumb_opcode) __inst_arm(arm_opcode) +#define __inst_arm_thumb32(arm_opcode, thumb_opcode) __inst_arm(arm_opcode) +#endif + +/* Helpers for the helpers. Don't use these directly. */ +#ifdef __ASSEMBLY__ +#define ___inst_arm(x) .long x +#define ___inst_thumb16(x) .short x +#define ___inst_thumb32(first, second) .short first, second +#else +#define ___inst_arm(x) ".long " __stringify(x) "\n\t" +#define ___inst_thumb16(x) ".short " __stringify(x) "\n\t" +#define ___inst_thumb32(first, second) \ + ".short " __stringify(first) ", " __stringify(second) "\n\t" +#endif + +#endif /* __ASM_ARM_OPCODES_H */ diff --git a/arch/arm/lib/asm-offsets.c b/arch/arm/lib/asm-offsets.c index e5bcaea..d620dc0 100644 --- a/arch/arm/lib/asm-offsets.c +++ b/arch/arm/lib/asm-offsets.c @@ -14,6 +14,7 @@ #include #include +#include #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) \ || defined(CONFIG_MX51) || defined(CONFIG_MX53) @@ -198,5 +199,12 @@ int main(void) DEFINE(PLL_DP_HFS_MFN, offsetof(struct dpll, dp_hfs_mfn)); #endif +#ifdef CONFIG_ARM_SMCCC + DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0)); + DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); + DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); + DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); +#endif + return 0; } diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h new file mode 100644 index 0000000..28e61ce --- /dev/null +++ b/include/linux/arm-smccc.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * SPDX-License-Identifier: GPL-2.0 + */ +#ifndef __LINUX_ARM_SMCCC_H +#define __LINUX_ARM_SMCCC_H + +/* + * This file provides common defines for ARM SMC Calling Convention as + * specified in + * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html + */ + +#define ARM_SMCCC_STD_CALL 0 +#define ARM_SMCCC_FAST_CALL 1 +#define ARM_SMCCC_TYPE_SHIFT 31 + +#define ARM_SMCCC_SMC_32 0 +#define ARM_SMCCC_SMC_64 1 +#define ARM_SMCCC_CALL_CONV_SHIFT 30 + +#define ARM_SMCCC_OWNER_MASK 0x3F +#define ARM_SMCCC_OWNER_SHIFT 24 + +#define ARM_SMCCC_FUNC_MASK 0xFFFF + +#define ARM_SMCCC_IS_FAST_CALL(smc_val) \ + ((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT)) +#define ARM_SMCCC_IS_64(smc_val) \ + ((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT)) +#define ARM_SMCCC_FUNC_NUM(smc_val) ((smc_val) & ARM_SMCCC_FUNC_MASK) +#define ARM_SMCCC_OWNER_NUM(smc_val) \ + (((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK) + +#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \ + (((type) << ARM_SMCCC_TYPE_SHIFT) | \ + ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \ + (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \ + ((func_num) & ARM_SMCCC_FUNC_MASK)) + +#define ARM_SMCCC_OWNER_ARCH 0 +#define ARM_SMCCC_OWNER_CPU 1 +#define ARM_SMCCC_OWNER_SIP 2 +#define ARM_SMCCC_OWNER_OEM 3 +#define ARM_SMCCC_OWNER_STANDARD 4 +#define ARM_SMCCC_OWNER_TRUSTED_APP 48 +#define ARM_SMCCC_OWNER_TRUSTED_APP_END 49 +#define ARM_SMCCC_OWNER_TRUSTED_OS 50 +#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63 + +#define ARM_SMCCC_QUIRK_NONE 0 +#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */ + +#ifndef __ASSEMBLY__ + +#include +#include +/** + * struct arm_smccc_res - Result from SMC/HVC call + * @a0-a3 result values from registers 0 to 3 + */ +struct arm_smccc_res { + unsigned long a0; + unsigned long a1; + unsigned long a2; + unsigned long a3; +}; + +/** + * struct arm_smccc_quirk - Contains quirk information + * @id: quirk identification + * @state: quirk specific information + * @a6: Qualcomm quirk entry for returning post-smc call contents of a6 + */ +struct arm_smccc_quirk { + int id; + union { + unsigned long a6; + } state; +}; + +/** + * __arm_smccc_smc() - make SMC calls + * @a0-a7: arguments passed in registers 0 to 7 + * @res: result values from registers 0 to 3 + * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required. + * + * This function is used to make SMC calls following SMC Calling Convention. + * The content of the supplied param are copied to registers 0 to 7 prior + * to the SMC instruction. The return values are updated with the content + * from register 0 to 3 on return from the SMC instruction. An optional + * quirk structure provides vendor specific behavior. + */ +asmlinkage void __arm_smccc_smc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, unsigned long a6, unsigned long a7, + struct arm_smccc_res *res, struct arm_smccc_quirk *quirk); + +/** + * __arm_smccc_hvc() - make HVC calls + * @a0-a7: arguments passed in registers 0 to 7 + * @res: result values from registers 0 to 3 + * @quirk: points to an arm_smccc_quirk, or NULL when no quirks are required. + * + * This function is used to make HVC calls following SMC Calling + * Convention. The content of the supplied param are copied to registers 0 + * to 7 prior to the HVC instruction. The return values are updated with + * the content from register 0 to 3 on return from the HVC instruction. An + * optional quirk structure provides vendor specific behavior. + */ +asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, unsigned long a6, unsigned long a7, + struct arm_smccc_res *res, struct arm_smccc_quirk *quirk); + +#define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL) + +#define arm_smccc_smc_quirk(...) __arm_smccc_smc(__VA_ARGS__) + +#define arm_smccc_hvc(...) __arm_smccc_hvc(__VA_ARGS__, NULL) + +#define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__) + +#endif /*__ASSEMBLY__*/ +#endif /*__LINUX_ARM_SMCCC_H*/ From patchwork Mon Apr 10 08:41:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 97065 Delivered-To: patch@linaro.org Received: by 10.140.89.233 with SMTP id v96csp1266847qgd; Mon, 10 Apr 2017 01:43:20 -0700 (PDT) X-Received: by 10.223.134.203 with SMTP id 11mr14825245wry.149.1491813800857; Mon, 10 Apr 2017 01:43:20 -0700 (PDT) Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id j18si20431662wra.238.2017.04.10.01.43.20; Mon, 10 Apr 2017 01:43:20 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 681D2C21E25; Mon, 10 Apr 2017 08:42:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id D73E2C21E38; Mon, 10 Apr 2017 08:42:05 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 7B97DC21E24; Mon, 10 Apr 2017 08:42:04 +0000 (UTC) Received: from conuserg-11.nifty.com (conuserg-11.nifty.com [210.131.2.78]) by lists.denx.de (Postfix) with ESMTPS id 4E8F3C21E24 for ; Mon, 10 Apr 2017 08:41:53 +0000 (UTC) Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-11.nifty.com with ESMTP id v3A8fMja003025; Mon, 10 Apr 2017 17:41:24 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-11.nifty.com v3A8fMja003025 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1491813684; bh=u4xAkHjveDQtvPDzNhhVCStXatFvKNXrp33nfz19jbo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=0jpAup8foovL8mCDeTMp6pANbprwun43hAvzZIa29/mYrBnniwzcFMfx7I9v8Y/CB w1Js5Gfa68rER38u9qMIXRXZDJOxROrtUsCARI3McVXu28XF8jFrhmchnPb59rpWK7 jDr89eWclZ6QCsRLs2AW3ay4NxLnMV2XeiOUSlO8/waDytQJSNg3QuZIdddUlTJSgx 0w2D7Lrxt+i9HTrSIbku8a79sgD91xWSmppaHI4+kA9k0EZMiY/2+2lMUnH9uSgWCx fj3qNiKEenGYFIDjvd3Kei60W8aWz2hvsjLi8oIPsP1bzRJUX4YWJg0/91m3bCec8T S/3IWzzzugNDQ== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Mon, 10 Apr 2017 17:41:19 +0900 Message-Id: <1491813679-22630-3-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1491813679-22630-1-git-send-email-yamada.masahiro@socionext.com> References: <1491813679-22630-1-git-send-email-yamada.masahiro@socionext.com> Cc: Tom Rini Subject: [U-Boot] [PATCH 2/2] sysreset: psci: support system reset in a generic way with PSCI X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" If the system is running PSCI firmware, the System Reset function (func ID: 0x80000009) is supposed to be handled by PSCI, that is, the SoC/board specific reset implementation should be moved to PSCI. U-Boot should call the PSCI service according to the arm-smccc manner. The arm-smccc is supported on ARMv7 or later. Especially, ARMv8 generation SoCs are likely to run ARM Trusted Firmware. In this case, U-Boot is a non-secure world boot loader, so it should not be able to reset the system directly. Signed-off-by: Masahiro Yamada --- arch/arm/Kconfig | 1 + drivers/Kconfig | 2 + drivers/Makefile | 5 +- drivers/firmware/Kconfig | 6 +++ drivers/firmware/Makefile | 2 + drivers/firmware/firmware-uclass.c | 11 +++++ drivers/firmware/psci.c | 94 ++++++++++++++++++++++++++++++++++++++ drivers/sysreset/Kconfig | 11 +++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset_psci.c | 41 +++++++++++++++++ include/dm/uclass-id.h | 1 + include/linux/psci.h | 13 ++++++ 12 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 drivers/firmware/Kconfig create mode 100644 drivers/firmware/Makefile create mode 100644 drivers/firmware/firmware-uclass.c create mode 100644 drivers/firmware/psci.c create mode 100644 drivers/sysreset/sysreset_psci.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 84744ef..64984dc 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -177,6 +177,7 @@ config SYS_CACHELINE_SIZE config ARM_SMCCC bool "Support for ARM SMC Calling Convention (SMCCC)" depends on CPU_V7 || ARM64 + select ARM_PSCI_FW help Say Y here if you want to enable ARM SMC Calling Convention. This should be enabled if U-Boot needs to communicate with system diff --git a/drivers/Kconfig b/drivers/Kconfig index 0e5d97d..d0a36ab 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -22,6 +22,8 @@ source "drivers/dfu/Kconfig" source "drivers/dma/Kconfig" +source "drivers/firmware/Kconfig" + source "drivers/fpga/Kconfig" source "drivers/gpio/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 5d8baa5..4a4b237 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_SPL_SERIAL_SUPPORT) += serial/ obj-$(CONFIG_SPL_SPI_SUPPORT) += spi/ obj-$(CONFIG_SPL_POWER_SUPPORT) += power/ power/pmic/ obj-$(CONFIG_SPL_POWER_SUPPORT) += power/regulator/ -obj-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += misc/ sysreset/ +obj-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += misc/ sysreset/ firmware/ obj-$(CONFIG_SPL_MTD_SUPPORT) += mtd/ obj-$(CONFIG_SPL_NAND_SUPPORT) += mtd/nand/ obj-$(CONFIG_SPL_ONENAND_SUPPORT) += mtd/onenand/ @@ -52,7 +52,7 @@ endif ifdef CONFIG_TPL_BUILD obj-$(CONFIG_TPL_I2C_SUPPORT) += i2c/ -obj-$(CONFIG_TPL_DRIVERS_MISC_SUPPORT) += misc/ sysreset/ +obj-$(CONFIG_TPL_DRIVERS_MISC_SUPPORT) += misc/ sysreset/ firmware/ obj-$(CONFIG_TPL_MMC_SUPPORT) += mmc/ obj-$(CONFIG_TPL_MPC8XXX_INIT_DDR_SUPPORT) += ddr/fsl/ obj-$(CONFIG_TPL_NAND_SUPPORT) += mtd/nand/ @@ -71,6 +71,7 @@ obj-y += block/ obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ +obj-y += firmware/ obj-$(CONFIG_FPGA) += fpga/ obj-y += hwmon/ obj-y += misc/ diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig new file mode 100644 index 0000000..4c32426 --- /dev/null +++ b/drivers/firmware/Kconfig @@ -0,0 +1,6 @@ +config FIRMWARE + bool + +config ARM_PSCI_FW + bool + select FIRMWARE diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile new file mode 100644 index 0000000..b208255 --- /dev/null +++ b/drivers/firmware/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_FIRMWARE) += firmware-uclass.o +obj-$(CONFIG_ARM_PSCI_FW) += psci.o diff --git a/drivers/firmware/firmware-uclass.c b/drivers/firmware/firmware-uclass.c new file mode 100644 index 0000000..01b6a44 --- /dev/null +++ b/drivers/firmware/firmware-uclass.c @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +/* Firmware access is platform-dependent. No generic code in uclass */ +UCLASS_DRIVER(firmware) = { + .id = UCLASS_FIRMWARE, + .name = "firmware", +}; diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c new file mode 100644 index 0000000..40fba64 --- /dev/null +++ b/drivers/firmware/psci.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2017 Masahiro Yamada + * + * Based on drivers/firmware/psci.c from Linux: + * Copyright (C) 2015 ARM Limited + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +psci_fn *invoke_psci_fn; + +static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2) +{ + struct arm_smccc_res res; + + arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + return res.a0; +} + +static unsigned long __invoke_psci_fn_smc(unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2) +{ + struct arm_smccc_res res; + + arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + return res.a0; +} + +static int psci_bind(struct udevice *dev) +{ + /* No SYSTEM_RESET support for PSCI 0.1 */ + if (of_device_is_compatible(dev, "arm,psci-0.2") || + of_device_is_compatible(dev, "arm,psci-1.0")) { + int ret; + + /* bind psci-sysreset optionally */ + ret = device_bind_driver(dev, "psci-sysreset", "psci-sysreset", + NULL); + if (ret) + debug("PSCI System Reset was not bound.\n"); + } + + return 0; +} + +static int psci_probe(struct udevice *dev) +{ + DECLARE_GLOBAL_DATA_PTR; + const char *method; + + method = fdt_stringlist_get(gd->fdt_blob, dev->of_offset, "method", 0, + NULL); + if (!method) { + printf("missing \"method\" property\n"); + return -ENXIO; + } + + if (!strcmp("hvc", method)) { + invoke_psci_fn = __invoke_psci_fn_hvc; + } else if (!strcmp("smc", method)) { + invoke_psci_fn = __invoke_psci_fn_smc; + } else { + printf("invalid \"method\" property: %s\n", method); + return -EINVAL; + } + + return 0; +} + +static const struct udevice_id psci_of_match[] = { + { .compatible = "arm,psci" }, + { .compatible = "arm,psci-0.2" }, + { .compatible = "arm,psci-1.0" }, + {}, +}; + +U_BOOT_DRIVER(psci) = { + .name = "psci", + .id = UCLASS_FIRMWARE, + .of_match = psci_of_match, + .bind = psci_bind, + .probe = psci_probe, +}; diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index 05a37b9..1498d37 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -13,4 +13,15 @@ config SYSRESET to effect a reset. The uclass will try all available drivers when reset_walk() is called. +if SYSRESET + +config SYSRESET_PSCI + bool "Enable support for PSCI System Reset" + depends on ARM_PSCI_FW + help + Enable PSCI SYSTEM_RESET function call. To use this, PSCI service + (for example, ARM Trusted Firmware BL31) must be running on your + system. + +endif endmenu diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index 49b8bb6..7bb8406 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -5,6 +5,7 @@ # obj-$(CONFIG_SYSRESET) += sysreset-uclass.o +obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_ROCKCHIP_RK3036) += sysreset_rk3036.o diff --git a/drivers/sysreset/sysreset_psci.c b/drivers/sysreset/sysreset_psci.c new file mode 100644 index 0000000..a4911b7 --- /dev/null +++ b/drivers/sysreset/sysreset_psci.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 Masahiro Yamada + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +static int psci_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + unsigned long function_id; + + switch (type) { + case SYSRESET_WARM: + case SYSRESET_COLD: + function_id = PSCI_0_2_FN_SYSTEM_RESET; + break; + case SYSRESET_POWER: + function_id = PSCI_0_2_FN_SYSTEM_OFF; + break; + default: + return -ENOSYS; + } + + invoke_psci_fn(function_id, 0, 0, 0); + + return -EINPROGRESS; +} + +static struct sysreset_ops psci_sysreset_ops = { + .request = psci_sysreset_request, +}; + +U_BOOT_DRIVER(psci_sysreset) = { + .name = "psci-sysreset", + .id = UCLASS_SYSRESET, + .ops = &psci_sysreset_ops, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 8c92d0b..1b635e4 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -35,6 +35,7 @@ enum uclass_id { UCLASS_DMA, /* Direct Memory Access */ UCLASS_ETH, /* Ethernet device */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ + UCLASS_FIRMWARE, /* Firmware */ UCLASS_I2C, /* I2C bus */ UCLASS_I2C_EEPROM, /* I2C EEPROM device */ UCLASS_I2C_GENERIC, /* Generic I2C device */ diff --git a/include/linux/psci.h b/include/linux/psci.h index 310d83e..8d13bd2 100644 --- a/include/linux/psci.h +++ b/include/linux/psci.h @@ -87,4 +87,17 @@ #define PSCI_RET_NOT_PRESENT -7 #define PSCI_RET_DISABLED -8 +#ifdef CONFIG_ARM_PSCI_FW +typedef unsigned long (psci_fn)(unsigned long, unsigned long, + unsigned long, unsigned long); + +extern psci_fn *invoke_psci_fn; +#else +unsigned long invoke_psci_fn(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3) +{ + return PSCI_RET_DISABLED; +} +#endif + #endif /* _UAPI_LINUX_PSCI_H */