1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2013 Broadcom Corporation
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or
5*4882a593Smuzhiyun * modify it under the terms of the GNU General Public License as
6*4882a593Smuzhiyun * published by the Free Software Foundation version 2.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9*4882a593Smuzhiyun * kind, whether express or implied; without even the implied warranty
10*4882a593Smuzhiyun * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11*4882a593Smuzhiyun * GNU General Public License for more details.
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <stdarg.h>
15*4882a593Smuzhiyun #include <linux/smp.h>
16*4882a593Smuzhiyun #include <linux/io.h>
17*4882a593Smuzhiyun #include <linux/ioport.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <asm/cacheflush.h>
20*4882a593Smuzhiyun #include <linux/of_address.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include "bcm_kona_smc.h"
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun static u32 bcm_smc_buffer_phys; /* physical address */
25*4882a593Smuzhiyun static void __iomem *bcm_smc_buffer; /* virtual address */
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct bcm_kona_smc_data {
28*4882a593Smuzhiyun unsigned service_id;
29*4882a593Smuzhiyun unsigned arg0;
30*4882a593Smuzhiyun unsigned arg1;
31*4882a593Smuzhiyun unsigned arg2;
32*4882a593Smuzhiyun unsigned arg3;
33*4882a593Smuzhiyun unsigned result;
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun static const struct of_device_id bcm_kona_smc_ids[] __initconst = {
37*4882a593Smuzhiyun {.compatible = "brcm,kona-smc"},
38*4882a593Smuzhiyun {.compatible = "bcm,kona-smc"}, /* deprecated name */
39*4882a593Smuzhiyun {},
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /* Map in the args buffer area */
bcm_kona_smc_init(void)43*4882a593Smuzhiyun int __init bcm_kona_smc_init(void)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun struct device_node *node;
46*4882a593Smuzhiyun const __be32 *prop_val;
47*4882a593Smuzhiyun u64 prop_size = 0;
48*4882a593Smuzhiyun unsigned long buffer_size;
49*4882a593Smuzhiyun u32 buffer_phys;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* Read buffer addr and size from the device tree node */
52*4882a593Smuzhiyun node = of_find_matching_node(NULL, bcm_kona_smc_ids);
53*4882a593Smuzhiyun if (!node)
54*4882a593Smuzhiyun return -ENODEV;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun prop_val = of_get_address(node, 0, &prop_size, NULL);
57*4882a593Smuzhiyun of_node_put(node);
58*4882a593Smuzhiyun if (!prop_val)
59*4882a593Smuzhiyun return -EINVAL;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* We assume space for four 32-bit arguments */
62*4882a593Smuzhiyun if (prop_size < 4 * sizeof(u32) || prop_size > (u64)ULONG_MAX)
63*4882a593Smuzhiyun return -EINVAL;
64*4882a593Smuzhiyun buffer_size = (unsigned long)prop_size;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun buffer_phys = be32_to_cpup(prop_val);
67*4882a593Smuzhiyun if (!buffer_phys)
68*4882a593Smuzhiyun return -EINVAL;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun bcm_smc_buffer = ioremap(buffer_phys, buffer_size);
71*4882a593Smuzhiyun if (!bcm_smc_buffer)
72*4882a593Smuzhiyun return -ENOMEM;
73*4882a593Smuzhiyun bcm_smc_buffer_phys = buffer_phys;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun pr_info("Kona Secure API initialized\n");
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun return 0;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /*
81*4882a593Smuzhiyun * int bcm_kona_do_smc(u32 service_id, u32 buffer_addr)
82*4882a593Smuzhiyun *
83*4882a593Smuzhiyun * Only core 0 can run the secure monitor code. If an "smc" request
84*4882a593Smuzhiyun * is initiated on a different core it must be redirected to core 0
85*4882a593Smuzhiyun * for execution. We rely on the caller to handle this.
86*4882a593Smuzhiyun *
87*4882a593Smuzhiyun * Each "smc" request supplies a service id and the address of a
88*4882a593Smuzhiyun * buffer containing parameters related to the service to be
89*4882a593Smuzhiyun * performed. A flags value defines the behavior of the level 2
90*4882a593Smuzhiyun * cache and interrupt handling while the secure monitor executes.
91*4882a593Smuzhiyun *
92*4882a593Smuzhiyun * Parameters to the "smc" request are passed in r4-r6 as follows:
93*4882a593Smuzhiyun * r4 service id
94*4882a593Smuzhiyun * r5 flags (SEC_ROM_*)
95*4882a593Smuzhiyun * r6 physical address of buffer with other parameters
96*4882a593Smuzhiyun *
97*4882a593Smuzhiyun * Execution of an "smc" request produces two distinct results.
98*4882a593Smuzhiyun *
99*4882a593Smuzhiyun * First, the secure monitor call itself (regardless of the specific
100*4882a593Smuzhiyun * service request) can succeed, or can produce an error. When an
101*4882a593Smuzhiyun * "smc" request completes this value is found in r12; it should
102*4882a593Smuzhiyun * always be SEC_EXIT_NORMAL.
103*4882a593Smuzhiyun *
104*4882a593Smuzhiyun * In addition, the particular service performed produces a result.
105*4882a593Smuzhiyun * The values that should be expected depend on the service. We
106*4882a593Smuzhiyun * therefore return this value to the caller, so it can handle the
107*4882a593Smuzhiyun * request result appropriately. This result value is found in r0
108*4882a593Smuzhiyun * when the "smc" request completes.
109*4882a593Smuzhiyun */
bcm_kona_do_smc(u32 service_id,u32 buffer_phys)110*4882a593Smuzhiyun static int bcm_kona_do_smc(u32 service_id, u32 buffer_phys)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun register u32 ip asm("ip"); /* Also called r12 */
113*4882a593Smuzhiyun register u32 r0 asm("r0");
114*4882a593Smuzhiyun register u32 r4 asm("r4");
115*4882a593Smuzhiyun register u32 r5 asm("r5");
116*4882a593Smuzhiyun register u32 r6 asm("r6");
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun r4 = service_id;
119*4882a593Smuzhiyun r5 = 0x3; /* Keep IRQ and FIQ off in SM */
120*4882a593Smuzhiyun r6 = buffer_phys;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun asm volatile (
123*4882a593Smuzhiyun /* Make sure we got the registers we want */
124*4882a593Smuzhiyun __asmeq("%0", "ip")
125*4882a593Smuzhiyun __asmeq("%1", "r0")
126*4882a593Smuzhiyun __asmeq("%2", "r4")
127*4882a593Smuzhiyun __asmeq("%3", "r5")
128*4882a593Smuzhiyun __asmeq("%4", "r6")
129*4882a593Smuzhiyun ".arch_extension sec\n"
130*4882a593Smuzhiyun " smc #0\n"
131*4882a593Smuzhiyun : "=r" (ip), "=r" (r0)
132*4882a593Smuzhiyun : "r" (r4), "r" (r5), "r" (r6)
133*4882a593Smuzhiyun : "r1", "r2", "r3", "r7", "lr");
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun BUG_ON(ip != SEC_EXIT_NORMAL);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun return r0;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /* __bcm_kona_smc() should only run on CPU 0, with pre-emption disabled */
__bcm_kona_smc(void * info)141*4882a593Smuzhiyun static void __bcm_kona_smc(void *info)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun struct bcm_kona_smc_data *data = info;
144*4882a593Smuzhiyun u32 __iomem *args = bcm_smc_buffer;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun BUG_ON(smp_processor_id() != 0);
147*4882a593Smuzhiyun BUG_ON(!args);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* Copy the four 32 bit argument values into the bounce area */
150*4882a593Smuzhiyun writel_relaxed(data->arg0, args++);
151*4882a593Smuzhiyun writel_relaxed(data->arg1, args++);
152*4882a593Smuzhiyun writel_relaxed(data->arg2, args++);
153*4882a593Smuzhiyun writel(data->arg3, args);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /* Flush caches for input data passed to Secure Monitor */
156*4882a593Smuzhiyun flush_cache_all();
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* Trap into Secure Monitor and record the request result */
159*4882a593Smuzhiyun data->result = bcm_kona_do_smc(data->service_id, bcm_smc_buffer_phys);
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
bcm_kona_smc(unsigned service_id,unsigned arg0,unsigned arg1,unsigned arg2,unsigned arg3)162*4882a593Smuzhiyun unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1,
163*4882a593Smuzhiyun unsigned arg2, unsigned arg3)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun struct bcm_kona_smc_data data;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun data.service_id = service_id;
168*4882a593Smuzhiyun data.arg0 = arg0;
169*4882a593Smuzhiyun data.arg1 = arg1;
170*4882a593Smuzhiyun data.arg2 = arg2;
171*4882a593Smuzhiyun data.arg3 = arg3;
172*4882a593Smuzhiyun data.result = 0;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /*
175*4882a593Smuzhiyun * Due to a limitation of the secure monitor, we must use the SMP
176*4882a593Smuzhiyun * infrastructure to forward all secure monitor calls to Core 0.
177*4882a593Smuzhiyun */
178*4882a593Smuzhiyun smp_call_function_single(0, __bcm_kona_smc, &data, 1);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun return data.result;
181*4882a593Smuzhiyun }
182