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 24c64756ccSAlex Elder static u32 bcm_smc_buffer_phys; /* physical address */ 25c64756ccSAlex Elder static void __iomem *bcm_smc_buffer; /* virtual address */ 26b8eb35fdSChristian Daudt 27b8eb35fdSChristian Daudt struct bcm_kona_smc_data { 28b8eb35fdSChristian Daudt unsigned service_id; 29b8eb35fdSChristian Daudt unsigned arg0; 30b8eb35fdSChristian Daudt unsigned arg1; 31b8eb35fdSChristian Daudt unsigned arg2; 32b8eb35fdSChristian Daudt unsigned arg3; 336c90f108SAlex Elder unsigned result; 34b8eb35fdSChristian Daudt }; 35b8eb35fdSChristian Daudt 360527873bSArnd Bergmann static const struct of_device_id bcm_kona_smc_ids[] __initconst = { 37aea237bfSChristian Daudt {.compatible = "brcm,kona-smc"}, 38aea237bfSChristian Daudt {.compatible = "bcm,kona-smc"}, /* deprecated name */ 39b8eb35fdSChristian Daudt {}, 40b8eb35fdSChristian Daudt }; 41b8eb35fdSChristian Daudt 42c64756ccSAlex Elder /* Map in the args buffer area */ 433a76b351SChristian Daudt int __init bcm_kona_smc_init(void) 44b8eb35fdSChristian Daudt { 45b8eb35fdSChristian Daudt struct device_node *node; 465c4cee2fSAlex Elder const __be32 *prop_val; 47c64756ccSAlex Elder u64 prop_size = 0; 48c64756ccSAlex Elder unsigned long buffer_size; 49c64756ccSAlex Elder u32 buffer_phys; 50b8eb35fdSChristian Daudt 51b8eb35fdSChristian Daudt /* Read buffer addr and size from the device tree node */ 52b8eb35fdSChristian Daudt node = of_find_matching_node(NULL, bcm_kona_smc_ids); 533a76b351SChristian Daudt if (!node) 543a76b351SChristian Daudt return -ENODEV; 55b8eb35fdSChristian Daudt 56c64756ccSAlex Elder prop_val = of_get_address(node, 0, &prop_size, NULL); 575c4cee2fSAlex Elder if (!prop_val) 585c4cee2fSAlex Elder return -EINVAL; 595c4cee2fSAlex Elder 60c64756ccSAlex Elder /* We assume space for four 32-bit arguments */ 61c64756ccSAlex Elder if (prop_size < 4 * sizeof(u32) || prop_size > (u64)ULONG_MAX) 62c64756ccSAlex Elder return -EINVAL; 63c64756ccSAlex Elder buffer_size = (unsigned long)prop_size; 64c64756ccSAlex Elder 65c64756ccSAlex Elder buffer_phys = be32_to_cpup(prop_val); 66c64756ccSAlex Elder if (!buffer_phys) 675c4cee2fSAlex Elder return -EINVAL; 68b8eb35fdSChristian Daudt 69c64756ccSAlex Elder bcm_smc_buffer = ioremap(buffer_phys, buffer_size); 70c64756ccSAlex Elder if (!bcm_smc_buffer) 715c4cee2fSAlex Elder return -ENOMEM; 72c64756ccSAlex Elder bcm_smc_buffer_phys = buffer_phys; 73b8eb35fdSChristian Daudt 743a76b351SChristian Daudt pr_info("Kona Secure API initialized\n"); 753a76b351SChristian Daudt 763a76b351SChristian Daudt return 0; 77b8eb35fdSChristian Daudt } 78b8eb35fdSChristian Daudt 798b9c550eSAlex Elder /* 80ed24f446SAlex Elder * int bcm_kona_do_smc(u32 service_id, u32 buffer_addr) 81ed24f446SAlex Elder * 82ed24f446SAlex Elder * Only core 0 can run the secure monitor code. If an "smc" request 83ed24f446SAlex Elder * is initiated on a different core it must be redirected to core 0 84ed24f446SAlex Elder * for execution. We rely on the caller to handle this. 85ed24f446SAlex Elder * 86ed24f446SAlex Elder * Each "smc" request supplies a service id and the address of a 87ed24f446SAlex Elder * buffer containing parameters related to the service to be 88ed24f446SAlex Elder * performed. A flags value defines the behavior of the level 2 89ed24f446SAlex Elder * cache and interrupt handling while the secure monitor executes. 90ed24f446SAlex Elder * 91ed24f446SAlex Elder * Parameters to the "smc" request are passed in r4-r6 as follows: 92ed24f446SAlex Elder * r4 service id 93ed24f446SAlex Elder * r5 flags (SEC_ROM_*) 94ed24f446SAlex Elder * r6 physical address of buffer with other parameters 95ed24f446SAlex Elder * 96ed24f446SAlex Elder * Execution of an "smc" request produces two distinct results. 97ed24f446SAlex Elder * 98ed24f446SAlex Elder * First, the secure monitor call itself (regardless of the specific 99ed24f446SAlex Elder * service request) can succeed, or can produce an error. When an 100ed24f446SAlex Elder * "smc" request completes this value is found in r12; it should 101ed24f446SAlex Elder * always be SEC_EXIT_NORMAL. 102ed24f446SAlex Elder * 103ed24f446SAlex Elder * In addition, the particular service performed produces a result. 104ed24f446SAlex Elder * The values that should be expected depend on the service. We 105ed24f446SAlex Elder * therefore return this value to the caller, so it can handle the 106ed24f446SAlex Elder * request result appropriately. This result value is found in r0 107ed24f446SAlex Elder * when the "smc" request completes. 1088b9c550eSAlex Elder */ 1098b9c550eSAlex Elder static int bcm_kona_do_smc(u32 service_id, u32 buffer_phys) 1108b9c550eSAlex Elder { 1118b9c550eSAlex Elder register u32 ip asm("ip"); /* Also called r12 */ 1128b9c550eSAlex Elder register u32 r0 asm("r0"); 1138b9c550eSAlex Elder register u32 r4 asm("r4"); 1148b9c550eSAlex Elder register u32 r5 asm("r5"); 1158b9c550eSAlex Elder register u32 r6 asm("r6"); 1168b9c550eSAlex Elder 1178b9c550eSAlex Elder r4 = service_id; 1188b9c550eSAlex Elder r5 = 0x3; /* Keep IRQ and FIQ off in SM */ 1198b9c550eSAlex Elder r6 = buffer_phys; 1208b9c550eSAlex Elder 1218b9c550eSAlex Elder asm volatile ( 1228b9c550eSAlex Elder /* Make sure we got the registers we want */ 1238b9c550eSAlex Elder __asmeq("%0", "ip") 1248b9c550eSAlex Elder __asmeq("%1", "r0") 1258b9c550eSAlex Elder __asmeq("%2", "r4") 1268b9c550eSAlex Elder __asmeq("%3", "r5") 1278b9c550eSAlex Elder __asmeq("%4", "r6") 1288b9c550eSAlex Elder ".arch_extension sec\n" 1298b9c550eSAlex Elder " smc #0\n" 1308b9c550eSAlex Elder : "=r" (ip), "=r" (r0) 1318b9c550eSAlex Elder : "r" (r4), "r" (r5), "r" (r6) 1328b9c550eSAlex Elder : "r1", "r2", "r3", "r7", "lr"); 1338b9c550eSAlex Elder 1348b9c550eSAlex Elder BUG_ON(ip != SEC_EXIT_NORMAL); 1358b9c550eSAlex Elder 1368b9c550eSAlex Elder return r0; 1378b9c550eSAlex Elder } 1388b9c550eSAlex Elder 139b8eb35fdSChristian Daudt /* __bcm_kona_smc() should only run on CPU 0, with pre-emption disabled */ 140b8eb35fdSChristian Daudt static void __bcm_kona_smc(void *info) 141b8eb35fdSChristian Daudt { 142b8eb35fdSChristian Daudt struct bcm_kona_smc_data *data = info; 143*b47879aaSBen Dooks u32 __iomem *args = bcm_smc_buffer; 144b8eb35fdSChristian Daudt 145b8eb35fdSChristian Daudt BUG_ON(smp_processor_id() != 0); 146c64756ccSAlex Elder BUG_ON(!args); 147b8eb35fdSChristian Daudt 148e80eef33SAlex Elder /* Copy the four 32 bit argument values into the bounce area */ 149e80eef33SAlex Elder writel_relaxed(data->arg0, args++); 150e80eef33SAlex Elder writel_relaxed(data->arg1, args++); 151e80eef33SAlex Elder writel_relaxed(data->arg2, args++); 152e80eef33SAlex Elder writel(data->arg3, args); 153b8eb35fdSChristian Daudt 154b8eb35fdSChristian Daudt /* Flush caches for input data passed to Secure Monitor */ 155b8eb35fdSChristian Daudt flush_cache_all(); 156b8eb35fdSChristian Daudt 1576c90f108SAlex Elder /* Trap into Secure Monitor and record the request result */ 1588b9c550eSAlex Elder data->result = bcm_kona_do_smc(data->service_id, bcm_smc_buffer_phys); 159b8eb35fdSChristian Daudt } 160b8eb35fdSChristian Daudt 161b8eb35fdSChristian Daudt unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1, 162b8eb35fdSChristian Daudt unsigned arg2, unsigned arg3) 163b8eb35fdSChristian Daudt { 164b8eb35fdSChristian Daudt struct bcm_kona_smc_data data; 165b8eb35fdSChristian Daudt 166b8eb35fdSChristian Daudt data.service_id = service_id; 167b8eb35fdSChristian Daudt data.arg0 = arg0; 168b8eb35fdSChristian Daudt data.arg1 = arg1; 169b8eb35fdSChristian Daudt data.arg2 = arg2; 170b8eb35fdSChristian Daudt data.arg3 = arg3; 1716c90f108SAlex Elder data.result = 0; 172b8eb35fdSChristian Daudt 173b8eb35fdSChristian Daudt /* 174b8eb35fdSChristian Daudt * Due to a limitation of the secure monitor, we must use the SMP 175b8eb35fdSChristian Daudt * infrastructure to forward all secure monitor calls to Core 0. 176b8eb35fdSChristian Daudt */ 17735138d52SAlex Elder smp_call_function_single(0, __bcm_kona_smc, &data, 1); 178b8eb35fdSChristian Daudt 1796c90f108SAlex Elder return data.result; 180b8eb35fdSChristian Daudt } 181