blob: 33538dfd7ac6e43c8771b332f47b05858b095c16 [file] [log] [blame]
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001/*
2 * Header file of MobiCore Driver Kernel Module.
3 *
4 * MobiCore Fast Call interface
5 *
6 * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
Oana Medvesaneedd9e92013-02-21 19:39:04 +01007 * <-- Copyright Trustonic Limited 2013 -->
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#ifndef _MC_FASTCALL_H_
15#define _MC_FASTCALL_H_
16
17#include "debug.h"
18
Oana Medvesan9f099cf2013-02-08 09:50:46 +010019/* Use the arch_extension sec pseudo op before switching to secure world */
20#if defined(__GNUC__) && \
21 defined(__GNUC_MINOR__) && \
22 defined(__GNUC_PATCHLEVEL__) && \
23 ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)) \
24 >= 40502
25#define MC_ARCH_EXTENSION_SEC
26#endif
27
Lukas Hänel28a9ffd2012-11-07 13:17:39 +090028/*
29 * MobiCore SMCs
30 */
31#define MC_SMC_N_YIELD 0x3 /* Yield to switch from NWd to SWd. */
32#define MC_SMC_N_SIQ 0x4 /* SIQ to switch from NWd to SWd. */
33
34/*
35 * MobiCore fast calls. See MCI documentation
36 */
37#define MC_FC_INIT -1
38#define MC_FC_INFO -2
Lukas Hänel28a9ffd2012-11-07 13:17:39 +090039#define MC_FC_NWD_TRACE -31 /* Mem trace setup fastcall */
Oana Medvesana0361802013-12-20 13:52:46 +010040#ifdef TBASE_CORE_SWITCHER
41#define MC_FC_SWITCH_CORE 0x84000005
42#endif
Lukas Hänel28a9ffd2012-11-07 13:17:39 +090043
44
45/*
46 * return code for fast calls
47 */
48#define MC_FC_RET_OK 0
49#define MC_FC_RET_ERR_INVALID 1
50#define MC_FC_RET_ERR_ALREADY_INITIALIZED 5
51
52
53/* structure wrappers for specific fastcalls */
54
55/* generic fast call parameters */
56union fc_generic {
57 struct {
58 uint32_t cmd;
59 uint32_t param[3];
60 } as_in;
61 struct {
62 uint32_t resp;
63 uint32_t ret;
64 uint32_t param[2];
65 } as_out;
66};
67
68/* fast call init */
69union mc_fc_init {
70 union fc_generic as_generic;
71 struct {
72 uint32_t cmd;
73 uint32_t base;
74 uint32_t nq_info;
75 uint32_t mcp_info;
76 } as_in;
77 struct {
78 uint32_t resp;
79 uint32_t ret;
80 uint32_t rfu[2];
81 } as_out;
82};
83
84/* fast call info parameters */
85union mc_fc_info {
86 union fc_generic as_generic;
87 struct {
88 uint32_t cmd;
89 uint32_t ext_info_id;
90 uint32_t rfu[2];
91 } as_in;
92 struct {
93 uint32_t resp;
94 uint32_t ret;
95 uint32_t state;
96 uint32_t ext_info;
97 } as_out;
98};
99
Oana Medvesana0361802013-12-20 13:52:46 +0100100#ifdef TBASE_CORE_SWITCHER
101/* fast call switch Core parameters */
102union mc_fc_swich_core {
103 union fc_generic as_generic;
104 struct {
105 uint32_t cmd;
106 uint32_t core_id;
107 uint32_t rfu[2];
108 } as_in;
109 struct {
110 uint32_t resp;
111 uint32_t ret;
112 uint32_t state;
113 uint32_t ext_info;
114 } as_out;
115};
116#endif
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900117/*
118 * _smc() - fast call to MobiCore
119 *
120 * @data: pointer to fast call data
121 */
122static inline long _smc(void *data)
123{
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100124 int ret = 0;
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100125
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900126 if (data == NULL)
127 return -EPERM;
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100128
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900129#ifdef MC_SMC_FASTCALL
130 {
Oana Medvesana0361802013-12-20 13:52:46 +0100131 ret = smc_fastcall(data, sizeof(union fc_generic));
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900132 }
133#else
134 {
Oana Medvesana0361802013-12-20 13:52:46 +0100135 union fc_generic *fc_generic = data;
136 /* SMC expect values in r0-r3 */
137 register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd;
138 register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0];
139 register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1];
140 register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2];
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900141
142 __asm__ volatile (
143#ifdef MC_ARCH_EXTENSION_SEC
144 /* This pseudo op is supported and required from
145 * binutils 2.21 on */
146 ".arch_extension sec\n"
147#endif
148 "smc 0\n"
149 : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
150 );
Oana Medvesana0361802013-12-20 13:52:46 +0100151#ifdef __ARM_VE_A9X4_QEMU__
152 /* Qemu does not return to the address following the SMC
153 instruction so we have to insert several nop instructions to
154 workaround this Qemu bug. */
155 __asm__ volatile (
156 "nop\n"
157 "nop\n"
158 "nop\n"
159 "nop"
160 );
161#endif
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900162
163 /* set response */
Oana Medvesana0361802013-12-20 13:52:46 +0100164 fc_generic->as_out.resp = reg0;
165 fc_generic->as_out.ret = reg1;
166 fc_generic->as_out.param[0] = reg2;
167 fc_generic->as_out.param[1] = reg3;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900168 }
169#endif
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100170 return ret;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900171}
172
173/*
174 * convert fast call return code to linux driver module error code
175 */
176static inline int convert_fc_ret(uint32_t sret)
177{
178 int ret = -EFAULT;
179
180 switch (sret) {
181 case MC_FC_RET_OK:
182 ret = 0;
183 break;
184 case MC_FC_RET_ERR_INVALID:
185 ret = -EINVAL;
186 break;
187 case MC_FC_RET_ERR_ALREADY_INITIALIZED:
188 ret = -EBUSY;
189 break;
190 default:
191 break;
192 }
193 return ret;
194}
195
196#endif /* _MC_FASTCALL_H_ */