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 24*c64756ccSAlex Elder static u32 bcm_smc_buffer_phys; /* physical address */ 25*c64756ccSAlex 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; 33b8eb35fdSChristian Daudt }; 34b8eb35fdSChristian Daudt 35b8eb35fdSChristian Daudt static const struct of_device_id bcm_kona_smc_ids[] __initconst = { 36aea237bfSChristian Daudt {.compatible = "brcm,kona-smc"}, 37aea237bfSChristian Daudt {.compatible = "bcm,kona-smc"}, /* deprecated name */ 38b8eb35fdSChristian Daudt {}, 39b8eb35fdSChristian Daudt }; 40b8eb35fdSChristian Daudt 41*c64756ccSAlex Elder /* Map in the args buffer area */ 423a76b351SChristian Daudt int __init bcm_kona_smc_init(void) 43b8eb35fdSChristian Daudt { 44b8eb35fdSChristian Daudt struct device_node *node; 455c4cee2fSAlex Elder const __be32 *prop_val; 46*c64756ccSAlex Elder u64 prop_size = 0; 47*c64756ccSAlex Elder unsigned long buffer_size; 48*c64756ccSAlex Elder u32 buffer_phys; 49b8eb35fdSChristian Daudt 50b8eb35fdSChristian Daudt /* Read buffer addr and size from the device tree node */ 51b8eb35fdSChristian Daudt node = of_find_matching_node(NULL, bcm_kona_smc_ids); 523a76b351SChristian Daudt if (!node) 533a76b351SChristian Daudt return -ENODEV; 54b8eb35fdSChristian Daudt 55*c64756ccSAlex Elder prop_val = of_get_address(node, 0, &prop_size, NULL); 565c4cee2fSAlex Elder if (!prop_val) 575c4cee2fSAlex Elder return -EINVAL; 585c4cee2fSAlex Elder 59*c64756ccSAlex Elder /* We assume space for four 32-bit arguments */ 60*c64756ccSAlex Elder if (prop_size < 4 * sizeof(u32) || prop_size > (u64)ULONG_MAX) 61*c64756ccSAlex Elder return -EINVAL; 62*c64756ccSAlex Elder buffer_size = (unsigned long)prop_size; 63*c64756ccSAlex Elder 64*c64756ccSAlex Elder buffer_phys = be32_to_cpup(prop_val); 65*c64756ccSAlex Elder if (!buffer_phys) 665c4cee2fSAlex Elder return -EINVAL; 67b8eb35fdSChristian Daudt 68*c64756ccSAlex Elder bcm_smc_buffer = ioremap(buffer_phys, buffer_size); 69*c64756ccSAlex Elder if (!bcm_smc_buffer) 705c4cee2fSAlex Elder return -ENOMEM; 71*c64756ccSAlex Elder bcm_smc_buffer_phys = buffer_phys; 72b8eb35fdSChristian Daudt 733a76b351SChristian Daudt pr_info("Kona Secure API initialized\n"); 743a76b351SChristian Daudt 753a76b351SChristian Daudt return 0; 76b8eb35fdSChristian Daudt } 77b8eb35fdSChristian Daudt 78b8eb35fdSChristian Daudt /* __bcm_kona_smc() should only run on CPU 0, with pre-emption disabled */ 79b8eb35fdSChristian Daudt static void __bcm_kona_smc(void *info) 80b8eb35fdSChristian Daudt { 81b8eb35fdSChristian Daudt struct bcm_kona_smc_data *data = info; 82*c64756ccSAlex Elder u32 *args = bcm_smc_buffer; 83*c64756ccSAlex Elder int rc; 84b8eb35fdSChristian Daudt 85b8eb35fdSChristian Daudt BUG_ON(smp_processor_id() != 0); 86*c64756ccSAlex Elder BUG_ON(!args); 87b8eb35fdSChristian Daudt 88e80eef33SAlex Elder /* Copy the four 32 bit argument values into the bounce area */ 89e80eef33SAlex Elder writel_relaxed(data->arg0, args++); 90e80eef33SAlex Elder writel_relaxed(data->arg1, args++); 91e80eef33SAlex Elder writel_relaxed(data->arg2, args++); 92e80eef33SAlex Elder writel(data->arg3, args); 93b8eb35fdSChristian Daudt 94b8eb35fdSChristian Daudt /* Flush caches for input data passed to Secure Monitor */ 95b8eb35fdSChristian Daudt flush_cache_all(); 96b8eb35fdSChristian Daudt 97b8eb35fdSChristian Daudt /* Trap into Secure Monitor */ 98*c64756ccSAlex Elder rc = bcm_kona_smc_asm(data->service_id, bcm_smc_buffer_phys); 99b8eb35fdSChristian Daudt 100b8eb35fdSChristian Daudt if (rc != SEC_ROM_RET_OK) 101b8eb35fdSChristian Daudt pr_err("Secure Monitor call failed (0x%x)!\n", rc); 102b8eb35fdSChristian Daudt } 103b8eb35fdSChristian Daudt 104b8eb35fdSChristian Daudt unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1, 105b8eb35fdSChristian Daudt unsigned arg2, unsigned arg3) 106b8eb35fdSChristian Daudt { 107b8eb35fdSChristian Daudt struct bcm_kona_smc_data data; 108b8eb35fdSChristian Daudt 109b8eb35fdSChristian Daudt data.service_id = service_id; 110b8eb35fdSChristian Daudt data.arg0 = arg0; 111b8eb35fdSChristian Daudt data.arg1 = arg1; 112b8eb35fdSChristian Daudt data.arg2 = arg2; 113b8eb35fdSChristian Daudt data.arg3 = arg3; 114b8eb35fdSChristian Daudt 115b8eb35fdSChristian Daudt /* 116b8eb35fdSChristian Daudt * Due to a limitation of the secure monitor, we must use the SMP 117b8eb35fdSChristian Daudt * infrastructure to forward all secure monitor calls to Core 0. 118b8eb35fdSChristian Daudt */ 119b8eb35fdSChristian Daudt if (get_cpu() != 0) 120b8eb35fdSChristian Daudt smp_call_function_single(0, __bcm_kona_smc, (void *)&data, 1); 121b8eb35fdSChristian Daudt else 122b8eb35fdSChristian Daudt __bcm_kona_smc(&data); 123b8eb35fdSChristian Daudt 124b8eb35fdSChristian Daudt put_cpu(); 125b8eb35fdSChristian Daudt 126b8eb35fdSChristian Daudt return 0; 127b8eb35fdSChristian Daudt } 128