#include <linux/smp.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <asm/cacheflush.h>
#include <linux/of_address.h>
#include "bcm_kona_smc.h"
static u32 bcm_smc_buffer_phys;
static void __iomem *bcm_smc_buffer;
struct bcm_kona_smc_data {
unsigned service_id;
unsigned arg0;
unsigned arg1;
unsigned arg2;
unsigned arg3;
unsigned result;
};
static const struct of_device_id bcm_kona_smc_ids[] __initconst = {
{.compatible = "brcm,kona-smc"},
{.compatible = "bcm,kona-smc"},
{},
};
int __init bcm_kona_smc_init(void)
{
struct device_node *node;
struct resource res;
int ret;
node = of_find_matching_node(NULL, bcm_kona_smc_ids);
if (!node)
return -ENODEV;
ret = of_address_to_resource(node, 0, &res);
of_node_put(node);
if (ret)
return -EINVAL;
bcm_smc_buffer = ioremap(res.start, resource_size(&res));
if (!bcm_smc_buffer)
return -ENOMEM;
bcm_smc_buffer_phys = res.start;
pr_info("Kona Secure API initialized\n");
return 0;
}
static int bcm_kona_do_smc(u32 service_id, u32 buffer_phys)
{
register u32 ip asm("ip");
register u32 r0 asm("r0");
register u32 r4 asm("r4");
register u32 r5 asm("r5");
register u32 r6 asm("r6");
r4 = service_id;
r5 = 0x3;
r6 = buffer_phys;
asm volatile (
__asmeq("%0", "ip")
__asmeq("%1", "r0")
__asmeq("%2", "r4")
__asmeq("%3", "r5")
__asmeq("%4", "r6")
".arch_extension sec\n"
" smc #0\n"
: "=r" (ip), "=r" (r0)
: "r" (r4), "r" (r5), "r" (r6)
: "r1", "r2", "r3", "r7", "lr");
BUG_ON(ip != SEC_EXIT_NORMAL);
return r0;
}
static void __bcm_kona_smc(void *info)
{
struct bcm_kona_smc_data *data = info;
u32 __iomem *args = bcm_smc_buffer;
BUG_ON(smp_processor_id() != 0);
BUG_ON(!args);
writel_relaxed(data->arg0, args++);
writel_relaxed(data->arg1, args++);
writel_relaxed(data->arg2, args++);
writel(data->arg3, args);
flush_cache_all();
data->result = bcm_kona_do_smc(data->service_id, bcm_smc_buffer_phys);
}
unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1,
unsigned arg2, unsigned arg3)
{
struct bcm_kona_smc_data data;
data.service_id = service_id;
data.arg0 = arg0;
data.arg1 = arg1;
data.arg2 = arg2;
data.arg3 = arg3;
data.result = 0;
smp_call_function_single(0, __bcm_kona_smc, &data, 1);
return data.result;
}