mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	As documented in GCC naked functions should only use basic ASM
syntax. The extended ASM or mixture of basic ASM and "C" code is
not guaranteed. Currently this works because it was hard coded
to follow and check GCC behavior for arguments and register
placement.
Furthermore with clang using parameters in Extended asm in a
naked function is not supported:
  arch/arm/firmware/trusted_foundations.c:47:10: error: parameter
          references not allowed in naked functions
                : "r" (type), "r" (arg1), "r" (arg2)
                       ^
Use a regular function to be more portable. This aligns also with
the other SMC call implementations e.g. in qcom_scm-32.c and
bcm_kona_smc.c.
Cc: Dmitry Osipenko <digetx@gmail.com>
Cc: Stephen Warren <swarren@nvidia.com>
Cc: Thierry Reding <treding@nvidia.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Thierry Reding <treding@nvidia.com>
		
	
			
		
			
				
	
	
		
			103 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Trusted Foundations support for ARM CPUs
 | 
						|
 *
 | 
						|
 * Copyright (c) 2013, NVIDIA Corporation.
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU General Public License as published by
 | 
						|
 * the Free Software Foundation; either version 2 of the License, or
 | 
						|
 * (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful, but WITHOUT
 | 
						|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | 
						|
 * more details.
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/kernel.h>
 | 
						|
#include <linux/init.h>
 | 
						|
#include <linux/of.h>
 | 
						|
#include <asm/firmware.h>
 | 
						|
#include <asm/trusted_foundations.h>
 | 
						|
 | 
						|
#define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200
 | 
						|
 | 
						|
#define TF_CPU_PM		0xfffffffc
 | 
						|
#define TF_CPU_PM_S3		0xffffffe3
 | 
						|
#define TF_CPU_PM_S2		0xffffffe6
 | 
						|
#define TF_CPU_PM_S2_NO_MC_CLK	0xffffffe5
 | 
						|
#define TF_CPU_PM_S1		0xffffffe4
 | 
						|
#define TF_CPU_PM_S1_NOFLUSH_L2	0xffffffe7
 | 
						|
 | 
						|
static unsigned long cpu_boot_addr;
 | 
						|
 | 
						|
static void tf_generic_smc(u32 type, u32 arg1, u32 arg2)
 | 
						|
{
 | 
						|
	register u32 r0 asm("r0") = type;
 | 
						|
	register u32 r1 asm("r1") = arg1;
 | 
						|
	register u32 r2 asm("r2") = arg2;
 | 
						|
 | 
						|
	asm volatile(
 | 
						|
		".arch_extension	sec\n\t"
 | 
						|
		"stmfd	sp!, {r4 - r11}\n\t"
 | 
						|
		__asmeq("%0", "r0")
 | 
						|
		__asmeq("%1", "r1")
 | 
						|
		__asmeq("%2", "r2")
 | 
						|
		"mov	r3, #0\n\t"
 | 
						|
		"mov	r4, #0\n\t"
 | 
						|
		"smc	#0\n\t"
 | 
						|
		"ldmfd	sp!, {r4 - r11}\n\t"
 | 
						|
		:
 | 
						|
		: "r" (r0), "r" (r1), "r" (r2)
 | 
						|
		: "memory", "r3", "r12", "lr");
 | 
						|
}
 | 
						|
 | 
						|
static int tf_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
 | 
						|
{
 | 
						|
	cpu_boot_addr = boot_addr;
 | 
						|
	tf_generic_smc(TF_SET_CPU_BOOT_ADDR_SMC, cpu_boot_addr, 0);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int tf_prepare_idle(void)
 | 
						|
{
 | 
						|
	tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2, cpu_boot_addr);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static const struct firmware_ops trusted_foundations_ops = {
 | 
						|
	.set_cpu_boot_addr = tf_set_cpu_boot_addr,
 | 
						|
	.prepare_idle = tf_prepare_idle,
 | 
						|
};
 | 
						|
 | 
						|
void register_trusted_foundations(struct trusted_foundations_platform_data *pd)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	 * we are not using version information for now since currently
 | 
						|
	 * supported SMCs are compatible with all TF releases
 | 
						|
	 */
 | 
						|
	register_firmware_ops(&trusted_foundations_ops);
 | 
						|
}
 | 
						|
 | 
						|
void of_register_trusted_foundations(void)
 | 
						|
{
 | 
						|
	struct device_node *node;
 | 
						|
	struct trusted_foundations_platform_data pdata;
 | 
						|
	int err;
 | 
						|
 | 
						|
	node = of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations");
 | 
						|
	if (!node)
 | 
						|
		return;
 | 
						|
 | 
						|
	err = of_property_read_u32(node, "tlm,version-major",
 | 
						|
				   &pdata.version_major);
 | 
						|
	if (err != 0)
 | 
						|
		panic("Trusted Foundation: missing version-major property\n");
 | 
						|
	err = of_property_read_u32(node, "tlm,version-minor",
 | 
						|
				   &pdata.version_minor);
 | 
						|
	if (err != 0)
 | 
						|
		panic("Trusted Foundation: missing version-minor property\n");
 | 
						|
	register_trusted_foundations(&pdata);
 | 
						|
}
 |