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 = { 39*aea237bfSChristian Daudt {.compatible = "brcm,kona-smc"}, 40*aea237bfSChristian Daudt {.compatible = "bcm,kona-smc"}, /* deprecated name */ 41b8eb35fdSChristian Daudt {}, 42b8eb35fdSChristian Daudt }; 43b8eb35fdSChristian Daudt 44b8eb35fdSChristian Daudt /* Map in the bounce area */ 45721e0205SArnd Bergmann void __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); 51b8eb35fdSChristian Daudt BUG_ON(!node); 52b8eb35fdSChristian Daudt 53b8eb35fdSChristian Daudt /* Don't care about size or flags of the DT node */ 54b8eb35fdSChristian Daudt bridge_data.buffer_addr = 55b8eb35fdSChristian Daudt be32_to_cpu(*of_get_address(node, 0, NULL, NULL)); 56b8eb35fdSChristian Daudt BUG_ON(!bridge_data.buffer_addr); 57b8eb35fdSChristian Daudt 58b8eb35fdSChristian Daudt bridge_data.bounce = of_iomap(node, 0); 59b8eb35fdSChristian Daudt BUG_ON(!bridge_data.bounce); 60b8eb35fdSChristian Daudt 61b8eb35fdSChristian Daudt bridge_data.initialized = 1; 62b8eb35fdSChristian Daudt 63b8eb35fdSChristian Daudt pr_info("Secure API initialized!\n"); 64b8eb35fdSChristian Daudt } 65b8eb35fdSChristian Daudt 66b8eb35fdSChristian Daudt /* __bcm_kona_smc() should only run on CPU 0, with pre-emption disabled */ 67b8eb35fdSChristian Daudt static void __bcm_kona_smc(void *info) 68b8eb35fdSChristian Daudt { 69b8eb35fdSChristian Daudt struct bcm_kona_smc_data *data = info; 70b8eb35fdSChristian Daudt u32 *args = bridge_data.bounce; 71b8eb35fdSChristian Daudt int rc = 0; 72b8eb35fdSChristian Daudt 73b8eb35fdSChristian Daudt /* Must run on CPU 0 */ 74b8eb35fdSChristian Daudt BUG_ON(smp_processor_id() != 0); 75b8eb35fdSChristian Daudt 76b8eb35fdSChristian Daudt /* Check map in the bounce area */ 77b8eb35fdSChristian Daudt BUG_ON(!bridge_data.initialized); 78b8eb35fdSChristian Daudt 79b8eb35fdSChristian Daudt /* Copy one 32 bit word into the bounce area */ 80b8eb35fdSChristian Daudt args[0] = data->arg0; 81b8eb35fdSChristian Daudt args[1] = data->arg1; 82b8eb35fdSChristian Daudt args[2] = data->arg2; 83b8eb35fdSChristian Daudt args[3] = data->arg3; 84b8eb35fdSChristian Daudt 85b8eb35fdSChristian Daudt /* Flush caches for input data passed to Secure Monitor */ 86b8eb35fdSChristian Daudt if (data->service_id != SSAPI_BRCM_START_VC_CORE) 87b8eb35fdSChristian Daudt flush_cache_all(); 88b8eb35fdSChristian Daudt 89b8eb35fdSChristian Daudt /* Trap into Secure Monitor */ 90b8eb35fdSChristian Daudt rc = bcm_kona_smc_asm(data->service_id, bridge_data.buffer_addr); 91b8eb35fdSChristian Daudt 92b8eb35fdSChristian Daudt if (rc != SEC_ROM_RET_OK) 93b8eb35fdSChristian Daudt pr_err("Secure Monitor call failed (0x%x)!\n", rc); 94b8eb35fdSChristian Daudt } 95b8eb35fdSChristian Daudt 96b8eb35fdSChristian Daudt unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1, 97b8eb35fdSChristian Daudt unsigned arg2, unsigned arg3) 98b8eb35fdSChristian Daudt { 99b8eb35fdSChristian Daudt struct bcm_kona_smc_data data; 100b8eb35fdSChristian Daudt 101b8eb35fdSChristian Daudt data.service_id = service_id; 102b8eb35fdSChristian Daudt data.arg0 = arg0; 103b8eb35fdSChristian Daudt data.arg1 = arg1; 104b8eb35fdSChristian Daudt data.arg2 = arg2; 105b8eb35fdSChristian Daudt data.arg3 = arg3; 106b8eb35fdSChristian Daudt 107b8eb35fdSChristian Daudt /* 108b8eb35fdSChristian Daudt * Due to a limitation of the secure monitor, we must use the SMP 109b8eb35fdSChristian Daudt * infrastructure to forward all secure monitor calls to Core 0. 110b8eb35fdSChristian Daudt */ 111b8eb35fdSChristian Daudt if (get_cpu() != 0) 112b8eb35fdSChristian Daudt smp_call_function_single(0, __bcm_kona_smc, (void *)&data, 1); 113b8eb35fdSChristian Daudt else 114b8eb35fdSChristian Daudt __bcm_kona_smc(&data); 115b8eb35fdSChristian Daudt 116b8eb35fdSChristian Daudt put_cpu(); 117b8eb35fdSChristian Daudt 118b8eb35fdSChristian Daudt return 0; 119b8eb35fdSChristian Daudt } 120