blob: 2fea065b3b5009680ef15e7ec9524c2fc2cb6322 [file] [log] [blame]
/**
* Header file of MobiCore Driver Kernel Module.
*
* @addtogroup MobiCore_Driver_Kernel_Module
* @{
* Internal structures of the McDrvModule
* @file
*
* MobiCore Fast Call interface
*
* <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _MC_FASTCALL_H_
#define _MC_FASTCALL_H_
#include "debug.h"
/**
* MobiCore SMCs
*/
#define MC_SMC_N_YIELD 0x3 /**< Yield to switch from NWd to SWd. */
#define MC_SMC_N_SIQ 0x4 /**< SIQ to switch from NWd to SWd. */
/**
* MobiCore fast calls. See MCI documentation
*/
#define MC_FC_INIT -1
#define MC_FC_INFO -2
#define MC_FC_POWER -3
#define MC_FC_DUMP -4
#define MC_FC_NWD_TRACE -31 /**< Mem trace setup fastcall */
/**
* return code for fast calls
*/
#define MC_FC_RET_OK 0
#define MC_FC_RET_ERR_INVALID 1
#define MC_FC_RET_ERR_ALREADY_INITIALIZED 5
/* structure wrappers for specific fastcalls */
/** generic fast call parameters */
union fc_generic {
struct {
uint32_t cmd;
uint32_t param[3];
} as_in;
struct {
uint32_t resp;
uint32_t ret;
uint32_t param[2];
} as_out;
};
/** fast call init */
union mc_fc_init {
union fc_generic as_generic;
struct {
uint32_t cmd;
uint32_t base;
uint32_t nq_info;
uint32_t mcp_info;
} as_in;
struct {
uint32_t resp;
uint32_t ret;
uint32_t rfu[2];
} as_out;
};
/** fast call info parameters */
union mc_fc_info {
union fc_generic as_generic;
struct {
uint32_t cmd;
uint32_t ext_info_id;
uint32_t rfu[2];
} as_in;
struct {
uint32_t resp;
uint32_t ret;
uint32_t state;
uint32_t ext_info;
} as_out;
};
/**
* fast call to MobiCore
*
* @param fc_generic pointer to fast call data
*/
static inline long _smc(void *data)
{
union fc_generic *fc_generic = data;
MCDRV_ASSERT(fc_generic != NULL);
/* We only expect to make smc calls on CPU0 otherwise something wrong
* will happen */
MCDRV_ASSERT(raw_smp_processor_id() == 0);
#ifdef MC_SMC_FASTCALL
{
int ret = 0;
ret = smc_fastcall((void *)fc_generic, sizeof(*fc_generic));
}
#else
{
/* SVC expect values in r0-r3 */
register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd;
register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0];
register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1];
register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2];
/* one of the famous preprocessor hacks to stringify things.*/
#define __STR2(x) #x
#define __STR(x) __STR2(x)
/* compiler does not support certain instructions
* "SMC": secure monitor call.*/
#define ASM_ARM_SMC 0xE1600070
/* "BPKT": debugging breakpoint.
* We keep this, as is comes quite handy for debugging. */
#define ASM_ARM_BPKT 0xE1200070
#define ASM_THUMB_BPKT 0xBE00
__asm__ volatile (
#ifdef CONFIG_ARM_ERRATA_766421
"dmb\n"
#endif
".word " __STR(ASM_ARM_SMC) "\n"
#ifdef CONFIG_ARM_ERRATA_766421
"dmb\n"
#endif
: "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
);
/* set response */
fc_generic->as_out.resp = reg0;
fc_generic->as_out.ret = reg1;
fc_generic->as_out.param[0] = reg2;
fc_generic->as_out.param[1] = reg3;
}
#endif
return 0;
}
/**
* convert fast call return code to linux driver module error code
*
*/
static inline int convert_fc_ret(uint32_t sret)
{
int ret = -EFAULT;
switch (sret) {
case MC_FC_RET_OK:
ret = 0;
break;
case MC_FC_RET_ERR_INVALID:
ret = -EINVAL;
break;
case MC_FC_RET_ERR_ALREADY_INITIALIZED:
ret = -EBUSY;
break;
}
return ret;
}
#endif /* _MC_FASTCALL_H_ */
/** @} */