18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * OMAP Secure API infrastructure.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc.
68c2ecf20Sopenharmony_ci *	Santosh Shilimkar <santosh.shilimkar@ti.com>
78c2ecf20Sopenharmony_ci * Copyright (C) 2012 Ivaylo Dimitrov <freemangordon@abv.bg>
88c2ecf20Sopenharmony_ci * Copyright (C) 2013 Pali Rohár <pali@kernel.org>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/arm-smccc.h>
128c2ecf20Sopenharmony_ci#include <linux/cpu_pm.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/io.h>
168c2ecf20Sopenharmony_ci#include <linux/memblock.h>
178c2ecf20Sopenharmony_ci#include <linux/of.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <asm/cacheflush.h>
208c2ecf20Sopenharmony_ci#include <asm/memblock.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "common.h"
238c2ecf20Sopenharmony_ci#include "omap-secure.h"
248c2ecf20Sopenharmony_ci#include "soc.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic phys_addr_t omap_secure_memblock_base;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cibool optee_available;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define OMAP_SIP_SMC_STD_CALL_VAL(func_num) \
318c2ecf20Sopenharmony_ci	ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_32, \
328c2ecf20Sopenharmony_ci	ARM_SMCCC_OWNER_SIP, (func_num))
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void __init omap_optee_init_check(void)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct device_node *np;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	/*
398c2ecf20Sopenharmony_ci	 * We only check that the OP-TEE node is present and available. The
408c2ecf20Sopenharmony_ci	 * OP-TEE kernel driver is not needed for the type of interaction made
418c2ecf20Sopenharmony_ci	 * with OP-TEE here so the driver's status is not checked.
428c2ecf20Sopenharmony_ci	 */
438c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/firmware/optee");
448c2ecf20Sopenharmony_ci	if (np && of_device_is_available(np))
458c2ecf20Sopenharmony_ci		optee_available = true;
468c2ecf20Sopenharmony_ci	of_node_put(np);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/**
508c2ecf20Sopenharmony_ci * omap_sec_dispatcher: Routine to dispatch low power secure
518c2ecf20Sopenharmony_ci * service routines
528c2ecf20Sopenharmony_ci * @idx: The HAL API index
538c2ecf20Sopenharmony_ci * @flag: The flag indicating criticality of operation
548c2ecf20Sopenharmony_ci * @nargs: Number of valid arguments out of four.
558c2ecf20Sopenharmony_ci * @arg1, arg2, arg3 args4: Parameters passed to secure API
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * Return the non-zero error value on failure.
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_ciu32 omap_secure_dispatcher(u32 idx, u32 flag, u32 nargs, u32 arg1, u32 arg2,
608c2ecf20Sopenharmony_ci							 u32 arg3, u32 arg4)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	u32 ret;
638c2ecf20Sopenharmony_ci	u32 param[5];
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	param[0] = nargs;
668c2ecf20Sopenharmony_ci	param[1] = arg1;
678c2ecf20Sopenharmony_ci	param[2] = arg2;
688c2ecf20Sopenharmony_ci	param[3] = arg3;
698c2ecf20Sopenharmony_ci	param[4] = arg4;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/*
728c2ecf20Sopenharmony_ci	 * Secure API needs physical address
738c2ecf20Sopenharmony_ci	 * pointer for the parameters
748c2ecf20Sopenharmony_ci	 */
758c2ecf20Sopenharmony_ci	flush_cache_all();
768c2ecf20Sopenharmony_ci	outer_clean_range(__pa(param), __pa(param + 5));
778c2ecf20Sopenharmony_ci	ret = omap_smc2(idx, flag, __pa(param));
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return ret;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_civoid omap_smccc_smc(u32 fn, u32 arg)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	struct arm_smccc_res res;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	arm_smccc_smc(OMAP_SIP_SMC_STD_CALL_VAL(fn), arg,
878c2ecf20Sopenharmony_ci		      0, 0, 0, 0, 0, 0, &res);
888c2ecf20Sopenharmony_ci	WARN(res.a0, "Secure function call 0x%08x failed\n", fn);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_civoid omap_smc1(u32 fn, u32 arg)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	/*
948c2ecf20Sopenharmony_ci	 * If this platform has OP-TEE installed we use ARM SMC calls
958c2ecf20Sopenharmony_ci	 * otherwise fall back to the OMAP ROM style calls.
968c2ecf20Sopenharmony_ci	 */
978c2ecf20Sopenharmony_ci	if (optee_available)
988c2ecf20Sopenharmony_ci		omap_smccc_smc(fn, arg);
998c2ecf20Sopenharmony_ci	else
1008c2ecf20Sopenharmony_ci		_omap_smc1(fn, arg);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/* Allocate the memory to save secure ram */
1048c2ecf20Sopenharmony_ciint __init omap_secure_ram_reserve_memblock(void)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	u32 size = OMAP_SECURE_RAM_STORAGE;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	size = ALIGN(size, SECTION_SIZE);
1098c2ecf20Sopenharmony_ci	omap_secure_memblock_base = arm_memblock_steal(size, SECTION_SIZE);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return 0;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ciphys_addr_t omap_secure_ram_mempool_base(void)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	return omap_secure_memblock_base;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
1208c2ecf20Sopenharmony_ciu32 omap3_save_secure_ram(void __iomem *addr, int size)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	u32 ret;
1238c2ecf20Sopenharmony_ci	u32 param[5];
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (size != OMAP3_SAVE_SECURE_RAM_SZ)
1268c2ecf20Sopenharmony_ci		return OMAP3_SAVE_SECURE_RAM_SZ;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	param[0] = 4;		/* Number of arguments */
1298c2ecf20Sopenharmony_ci	param[1] = __pa(addr);	/* Physical address for saving */
1308c2ecf20Sopenharmony_ci	param[2] = 0;
1318c2ecf20Sopenharmony_ci	param[3] = 1;
1328c2ecf20Sopenharmony_ci	param[4] = 1;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	ret = save_secure_ram_context(__pa(param));
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return ret;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci#endif
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/**
1418c2ecf20Sopenharmony_ci * rx51_secure_dispatcher: Routine to dispatch secure PPA API calls
1428c2ecf20Sopenharmony_ci * @idx: The PPA API index
1438c2ecf20Sopenharmony_ci * @process: Process ID
1448c2ecf20Sopenharmony_ci * @flag: The flag indicating criticality of operation
1458c2ecf20Sopenharmony_ci * @nargs: Number of valid arguments out of four.
1468c2ecf20Sopenharmony_ci * @arg1, arg2, arg3 args4: Parameters passed to secure API
1478c2ecf20Sopenharmony_ci *
1488c2ecf20Sopenharmony_ci * Return the non-zero error value on failure.
1498c2ecf20Sopenharmony_ci *
1508c2ecf20Sopenharmony_ci * NOTE: rx51_secure_dispatcher differs from omap_secure_dispatcher because
1518c2ecf20Sopenharmony_ci *       it calling omap_smc3() instead omap_smc2() and param[0] is nargs+1
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_ciu32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs,
1548c2ecf20Sopenharmony_ci			   u32 arg1, u32 arg2, u32 arg3, u32 arg4)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	u32 ret;
1578c2ecf20Sopenharmony_ci	u32 param[5];
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	param[0] = nargs+1; /* RX-51 needs number of arguments + 1 */
1608c2ecf20Sopenharmony_ci	param[1] = arg1;
1618c2ecf20Sopenharmony_ci	param[2] = arg2;
1628c2ecf20Sopenharmony_ci	param[3] = arg3;
1638c2ecf20Sopenharmony_ci	param[4] = arg4;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/*
1668c2ecf20Sopenharmony_ci	 * Secure API needs physical address
1678c2ecf20Sopenharmony_ci	 * pointer for the parameters
1688c2ecf20Sopenharmony_ci	 */
1698c2ecf20Sopenharmony_ci	local_irq_disable();
1708c2ecf20Sopenharmony_ci	local_fiq_disable();
1718c2ecf20Sopenharmony_ci	flush_cache_all();
1728c2ecf20Sopenharmony_ci	outer_clean_range(__pa(param), __pa(param + 5));
1738c2ecf20Sopenharmony_ci	ret = omap_smc3(idx, process, flag, __pa(param));
1748c2ecf20Sopenharmony_ci	flush_cache_all();
1758c2ecf20Sopenharmony_ci	local_fiq_enable();
1768c2ecf20Sopenharmony_ci	local_irq_enable();
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return ret;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci/**
1828c2ecf20Sopenharmony_ci * rx51_secure_update_aux_cr: Routine to modify the contents of Auxiliary Control Register
1838c2ecf20Sopenharmony_ci *  @set_bits: bits to set in ACR
1848c2ecf20Sopenharmony_ci *  @clr_bits: bits to clear in ACR
1858c2ecf20Sopenharmony_ci *
1868c2ecf20Sopenharmony_ci * Return the non-zero error value on failure.
1878c2ecf20Sopenharmony_ci*/
1888c2ecf20Sopenharmony_ciu32 rx51_secure_update_aux_cr(u32 set_bits, u32 clear_bits)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	u32 acr;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/* Read ACR */
1938c2ecf20Sopenharmony_ci	asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (acr));
1948c2ecf20Sopenharmony_ci	acr &= ~clear_bits;
1958c2ecf20Sopenharmony_ci	acr |= set_bits;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return rx51_secure_dispatcher(RX51_PPA_WRITE_ACR,
1988c2ecf20Sopenharmony_ci				      0,
1998c2ecf20Sopenharmony_ci				      FLAG_START_CRITICAL,
2008c2ecf20Sopenharmony_ci				      1, acr, 0, 0, 0);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci/**
2048c2ecf20Sopenharmony_ci * rx51_secure_rng_call: Routine for HW random generator
2058c2ecf20Sopenharmony_ci */
2068c2ecf20Sopenharmony_ciu32 rx51_secure_rng_call(u32 ptr, u32 count, u32 flag)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	return rx51_secure_dispatcher(RX51_PPA_HWRNG,
2098c2ecf20Sopenharmony_ci				      0,
2108c2ecf20Sopenharmony_ci				      NO_FLAG,
2118c2ecf20Sopenharmony_ci				      3, ptr, count, flag, 0);
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_civoid __init omap_secure_init(void)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	omap_optee_init_check();
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci/*
2208c2ecf20Sopenharmony_ci * Dummy dispatcher call after core OSWR and MPU off. Updates the ROM return
2218c2ecf20Sopenharmony_ci * address after MMU has been re-enabled after CPU1 has been woken up again.
2228c2ecf20Sopenharmony_ci * Otherwise the ROM code will attempt to use the earlier physical return
2238c2ecf20Sopenharmony_ci * address that got set with MMU off when waking up CPU1. Only used on secure
2248c2ecf20Sopenharmony_ci * devices.
2258c2ecf20Sopenharmony_ci */
2268c2ecf20Sopenharmony_cistatic int cpu_notifier(struct notifier_block *nb, unsigned long cmd, void *v)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	switch (cmd) {
2298c2ecf20Sopenharmony_ci	case CPU_CLUSTER_PM_EXIT:
2308c2ecf20Sopenharmony_ci		omap_secure_dispatcher(OMAP4_PPA_SERVICE_0,
2318c2ecf20Sopenharmony_ci				       FLAG_START_CRITICAL,
2328c2ecf20Sopenharmony_ci				       0, 0, 0, 0, 0);
2338c2ecf20Sopenharmony_ci		break;
2348c2ecf20Sopenharmony_ci	default:
2358c2ecf20Sopenharmony_ci		break;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return NOTIFY_OK;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic struct notifier_block secure_notifier_block = {
2428c2ecf20Sopenharmony_ci	.notifier_call = cpu_notifier,
2438c2ecf20Sopenharmony_ci};
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int __init secure_pm_init(void)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	if (omap_type() == OMAP2_DEVICE_TYPE_GP || !soc_is_omap44xx())
2488c2ecf20Sopenharmony_ci		return 0;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	cpu_pm_register_notifier(&secure_notifier_block);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ciomap_arch_initcall(secure_pm_init);
255