xref: /openbmc/linux/arch/arm/mach-bcm/bcm_kona_smc.c (revision e80eef33f4596a247fdcf7d67d54d95d9dfaf7d3)
1b8eb35fdSChristian Daudt /*
2b8eb35fdSChristian Daudt  * Copyright (C) 2013 Broadcom Corporation
3b8eb35fdSChristian Daudt  *
4b8eb35fdSChristian Daudt  * This program is free software; you can redistribute it and/or
5b8eb35fdSChristian Daudt  * modify it under the terms of the GNU General Public License as
6b8eb35fdSChristian Daudt  * published by the Free Software Foundation version 2.
7b8eb35fdSChristian Daudt  *
8b8eb35fdSChristian Daudt  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9b8eb35fdSChristian Daudt  * kind, whether express or implied; without even the implied warranty
10b8eb35fdSChristian Daudt  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11b8eb35fdSChristian Daudt  * GNU General Public License for more details.
12b8eb35fdSChristian Daudt  */
13b8eb35fdSChristian Daudt 
14b8eb35fdSChristian Daudt #include <stdarg.h>
15b8eb35fdSChristian Daudt #include <linux/smp.h>
16b8eb35fdSChristian Daudt #include <linux/io.h>
17b8eb35fdSChristian Daudt #include <linux/ioport.h>
18b8eb35fdSChristian Daudt 
19b8eb35fdSChristian Daudt #include <asm/cacheflush.h>
20b8eb35fdSChristian Daudt #include <linux/of_address.h>
21b8eb35fdSChristian Daudt 
22b8eb35fdSChristian Daudt #include "bcm_kona_smc.h"
23b8eb35fdSChristian Daudt 
24b8eb35fdSChristian Daudt struct secure_bridge_data {
25b8eb35fdSChristian Daudt 	void __iomem *bounce;		/* virtual address */
26b8eb35fdSChristian Daudt 	u32 __iomem buffer_addr;	/* physical address */
27b8eb35fdSChristian Daudt 	int initialized;
28b8eb35fdSChristian Daudt } bridge_data;
29b8eb35fdSChristian Daudt 
30b8eb35fdSChristian Daudt struct bcm_kona_smc_data {
31b8eb35fdSChristian Daudt 	unsigned service_id;
32b8eb35fdSChristian Daudt 	unsigned arg0;
33b8eb35fdSChristian Daudt 	unsigned arg1;
34b8eb35fdSChristian Daudt 	unsigned arg2;
35b8eb35fdSChristian Daudt 	unsigned arg3;
36b8eb35fdSChristian Daudt };
37b8eb35fdSChristian Daudt 
38b8eb35fdSChristian Daudt static const struct of_device_id bcm_kona_smc_ids[] __initconst = {
39aea237bfSChristian Daudt 	{.compatible = "brcm,kona-smc"},
40aea237bfSChristian Daudt 	{.compatible = "bcm,kona-smc"}, /* deprecated name */
41b8eb35fdSChristian Daudt 	{},
42b8eb35fdSChristian Daudt };
43b8eb35fdSChristian Daudt 
44b8eb35fdSChristian Daudt /* Map in the bounce area */
453a76b351SChristian Daudt int __init bcm_kona_smc_init(void)
46b8eb35fdSChristian Daudt {
47b8eb35fdSChristian Daudt 	struct device_node *node;
48b8eb35fdSChristian Daudt 
49b8eb35fdSChristian Daudt 	/* Read buffer addr and size from the device tree node */
50b8eb35fdSChristian Daudt 	node = of_find_matching_node(NULL, bcm_kona_smc_ids);
513a76b351SChristian Daudt 	if (!node)
523a76b351SChristian Daudt 		return -ENODEV;
53b8eb35fdSChristian Daudt 
54b8eb35fdSChristian Daudt 	/* Don't care about size or flags of the DT node */
55b8eb35fdSChristian Daudt 	bridge_data.buffer_addr =
56b8eb35fdSChristian Daudt 		be32_to_cpu(*of_get_address(node, 0, NULL, NULL));
57b8eb35fdSChristian Daudt 	BUG_ON(!bridge_data.buffer_addr);
58b8eb35fdSChristian Daudt 
59b8eb35fdSChristian Daudt 	bridge_data.bounce = of_iomap(node, 0);
60b8eb35fdSChristian Daudt 	BUG_ON(!bridge_data.bounce);
61b8eb35fdSChristian Daudt 
62b8eb35fdSChristian Daudt 	bridge_data.initialized = 1;
63b8eb35fdSChristian Daudt 
643a76b351SChristian Daudt 	pr_info("Kona Secure API initialized\n");
653a76b351SChristian Daudt 
663a76b351SChristian Daudt 	return 0;
67b8eb35fdSChristian Daudt }
68b8eb35fdSChristian Daudt 
69b8eb35fdSChristian Daudt /* __bcm_kona_smc() should only run on CPU 0, with pre-emption disabled */
70b8eb35fdSChristian Daudt static void __bcm_kona_smc(void *info)
71b8eb35fdSChristian Daudt {
72b8eb35fdSChristian Daudt 	struct bcm_kona_smc_data *data = info;
73b8eb35fdSChristian Daudt 	u32 *args = bridge_data.bounce;
74b8eb35fdSChristian Daudt 	int rc = 0;
75b8eb35fdSChristian Daudt 
76b8eb35fdSChristian Daudt 	/* Must run on CPU 0 */
77b8eb35fdSChristian Daudt 	BUG_ON(smp_processor_id() != 0);
78b8eb35fdSChristian Daudt 
79b8eb35fdSChristian Daudt 	/* Check map in the bounce area */
80b8eb35fdSChristian Daudt 	BUG_ON(!bridge_data.initialized);
81b8eb35fdSChristian Daudt 
82*e80eef33SAlex Elder 	/* Copy the four 32 bit argument values into the bounce area */
83*e80eef33SAlex Elder 	writel_relaxed(data->arg0, args++);
84*e80eef33SAlex Elder 	writel_relaxed(data->arg1, args++);
85*e80eef33SAlex Elder 	writel_relaxed(data->arg2, args++);
86*e80eef33SAlex Elder 	writel(data->arg3, args);
87b8eb35fdSChristian Daudt 
88b8eb35fdSChristian Daudt 	/* Flush caches for input data passed to Secure Monitor */
89b8eb35fdSChristian Daudt 	if (data->service_id != SSAPI_BRCM_START_VC_CORE)
90b8eb35fdSChristian Daudt 		flush_cache_all();
91b8eb35fdSChristian Daudt 
92b8eb35fdSChristian Daudt 	/* Trap into Secure Monitor */
93b8eb35fdSChristian Daudt 	rc = bcm_kona_smc_asm(data->service_id, bridge_data.buffer_addr);
94b8eb35fdSChristian Daudt 
95b8eb35fdSChristian Daudt 	if (rc != SEC_ROM_RET_OK)
96b8eb35fdSChristian Daudt 		pr_err("Secure Monitor call failed (0x%x)!\n", rc);
97b8eb35fdSChristian Daudt }
98b8eb35fdSChristian Daudt 
99b8eb35fdSChristian Daudt unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1,
100b8eb35fdSChristian Daudt 		  unsigned arg2, unsigned arg3)
101b8eb35fdSChristian Daudt {
102b8eb35fdSChristian Daudt 	struct bcm_kona_smc_data data;
103b8eb35fdSChristian Daudt 
104b8eb35fdSChristian Daudt 	data.service_id = service_id;
105b8eb35fdSChristian Daudt 	data.arg0 = arg0;
106b8eb35fdSChristian Daudt 	data.arg1 = arg1;
107b8eb35fdSChristian Daudt 	data.arg2 = arg2;
108b8eb35fdSChristian Daudt 	data.arg3 = arg3;
109b8eb35fdSChristian Daudt 
110b8eb35fdSChristian Daudt 	/*
111b8eb35fdSChristian Daudt 	 * Due to a limitation of the secure monitor, we must use the SMP
112b8eb35fdSChristian Daudt 	 * infrastructure to forward all secure monitor calls to Core 0.
113b8eb35fdSChristian Daudt 	 */
114b8eb35fdSChristian Daudt 	if (get_cpu() != 0)
115b8eb35fdSChristian Daudt 		smp_call_function_single(0, __bcm_kona_smc, (void *)&data, 1);
116b8eb35fdSChristian Daudt 	else
117b8eb35fdSChristian Daudt 		__bcm_kona_smc(&data);
118b8eb35fdSChristian Daudt 
119b8eb35fdSChristian Daudt 	put_cpu();
120b8eb35fdSChristian Daudt 
121b8eb35fdSChristian Daudt 	return 0;
122b8eb35fdSChristian Daudt }
123