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