rtc-optee.c (8947B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2022 Microchip. 4 */ 5 6#include <linux/device.h> 7#include <linux/kernel.h> 8#include <linux/module.h> 9#include <linux/rtc.h> 10#include <linux/tee_drv.h> 11 12#define RTC_INFO_VERSION 0x1 13 14#define TA_CMD_RTC_GET_INFO 0x0 15#define TA_CMD_RTC_GET_TIME 0x1 16#define TA_CMD_RTC_SET_TIME 0x2 17#define TA_CMD_RTC_GET_OFFSET 0x3 18#define TA_CMD_RTC_SET_OFFSET 0x4 19 20#define TA_RTC_FEATURE_CORRECTION BIT(0) 21 22struct optee_rtc_time { 23 u32 tm_sec; 24 u32 tm_min; 25 u32 tm_hour; 26 u32 tm_mday; 27 u32 tm_mon; 28 u32 tm_year; 29 u32 tm_wday; 30}; 31 32struct optee_rtc_info { 33 u64 version; 34 u64 features; 35 struct optee_rtc_time range_min; 36 struct optee_rtc_time range_max; 37}; 38 39/** 40 * struct optee_rtc - OP-TEE RTC private data 41 * @dev: OP-TEE based RTC device. 42 * @ctx: OP-TEE context handler. 43 * @session_id: RTC TA session identifier. 44 * @shm: Memory pool shared with RTC device. 45 * @features: Bitfield of RTC features 46 */ 47struct optee_rtc { 48 struct device *dev; 49 struct tee_context *ctx; 50 u32 session_id; 51 struct tee_shm *shm; 52 u64 features; 53}; 54 55static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm) 56{ 57 struct optee_rtc *priv = dev_get_drvdata(dev); 58 struct tee_ioctl_invoke_arg inv_arg = {0}; 59 struct optee_rtc_time *optee_tm; 60 struct tee_param param[4] = {0}; 61 int ret; 62 63 inv_arg.func = TA_CMD_RTC_GET_TIME; 64 inv_arg.session = priv->session_id; 65 inv_arg.num_params = 4; 66 67 /* Fill invoke cmd params */ 68 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; 69 param[0].u.memref.shm = priv->shm; 70 param[0].u.memref.size = sizeof(struct optee_rtc_time); 71 72 ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); 73 if (ret < 0 || inv_arg.ret != 0) 74 return ret ? ret : -EPROTO; 75 76 optee_tm = tee_shm_get_va(priv->shm, 0); 77 if (IS_ERR(optee_tm)) 78 return PTR_ERR(optee_tm); 79 80 if (param[0].u.memref.size != sizeof(*optee_tm)) 81 return -EPROTO; 82 83 tm->tm_sec = optee_tm->tm_sec; 84 tm->tm_min = optee_tm->tm_min; 85 tm->tm_hour = optee_tm->tm_hour; 86 tm->tm_mday = optee_tm->tm_mday; 87 tm->tm_mon = optee_tm->tm_mon; 88 tm->tm_year = optee_tm->tm_year - 1900; 89 tm->tm_wday = optee_tm->tm_wday; 90 tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); 91 92 return 0; 93} 94 95static int optee_rtc_settime(struct device *dev, struct rtc_time *tm) 96{ 97 struct optee_rtc *priv = dev_get_drvdata(dev); 98 struct tee_ioctl_invoke_arg inv_arg = {0}; 99 struct tee_param param[4] = {0}; 100 struct optee_rtc_time optee_tm; 101 void *rtc_data; 102 int ret; 103 104 optee_tm.tm_sec = tm->tm_sec; 105 optee_tm.tm_min = tm->tm_min; 106 optee_tm.tm_hour = tm->tm_hour; 107 optee_tm.tm_mday = tm->tm_mday; 108 optee_tm.tm_mon = tm->tm_mon; 109 optee_tm.tm_year = tm->tm_year + 1900; 110 optee_tm.tm_wday = tm->tm_wday; 111 112 inv_arg.func = TA_CMD_RTC_SET_TIME; 113 inv_arg.session = priv->session_id; 114 inv_arg.num_params = 4; 115 116 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; 117 param[0].u.memref.shm = priv->shm; 118 param[0].u.memref.size = sizeof(struct optee_rtc_time); 119 120 rtc_data = tee_shm_get_va(priv->shm, 0); 121 if (IS_ERR(rtc_data)) 122 return PTR_ERR(rtc_data); 123 124 memcpy(rtc_data, &optee_tm, sizeof(struct optee_rtc_time)); 125 126 ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); 127 if (ret < 0 || inv_arg.ret != 0) 128 return ret ? ret : -EPROTO; 129 130 return 0; 131} 132 133static int optee_rtc_readoffset(struct device *dev, long *offset) 134{ 135 struct optee_rtc *priv = dev_get_drvdata(dev); 136 struct tee_ioctl_invoke_arg inv_arg = {0}; 137 struct tee_param param[4] = {0}; 138 int ret; 139 140 if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) 141 return -EOPNOTSUPP; 142 143 inv_arg.func = TA_CMD_RTC_GET_OFFSET; 144 inv_arg.session = priv->session_id; 145 inv_arg.num_params = 4; 146 147 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; 148 149 ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); 150 if (ret < 0 || inv_arg.ret != 0) 151 return ret ? ret : -EPROTO; 152 153 *offset = param[0].u.value.a; 154 155 return 0; 156} 157 158static int optee_rtc_setoffset(struct device *dev, long offset) 159{ 160 struct optee_rtc *priv = dev_get_drvdata(dev); 161 struct tee_ioctl_invoke_arg inv_arg = {0}; 162 struct tee_param param[4] = {0}; 163 int ret; 164 165 if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) 166 return -EOPNOTSUPP; 167 168 inv_arg.func = TA_CMD_RTC_SET_OFFSET; 169 inv_arg.session = priv->session_id; 170 inv_arg.num_params = 4; 171 172 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; 173 param[0].u.value.a = offset; 174 175 ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); 176 if (ret < 0 || inv_arg.ret != 0) 177 return ret ? ret : -EPROTO; 178 179 return 0; 180} 181 182static const struct rtc_class_ops optee_rtc_ops = { 183 .read_time = optee_rtc_readtime, 184 .set_time = optee_rtc_settime, 185 .set_offset = optee_rtc_setoffset, 186 .read_offset = optee_rtc_readoffset, 187}; 188 189static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc, 190 u64 *features) 191{ 192 struct optee_rtc *priv = dev_get_drvdata(dev); 193 struct tee_ioctl_invoke_arg inv_arg = {0}; 194 struct tee_param param[4] = {0}; 195 struct optee_rtc_info *info; 196 struct optee_rtc_time *tm; 197 int ret; 198 199 inv_arg.func = TA_CMD_RTC_GET_INFO; 200 inv_arg.session = priv->session_id; 201 inv_arg.num_params = 4; 202 203 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; 204 param[0].u.memref.shm = priv->shm; 205 param[0].u.memref.size = sizeof(*info); 206 207 ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); 208 if (ret < 0 || inv_arg.ret != 0) 209 return ret ? ret : -EPROTO; 210 211 info = tee_shm_get_va(priv->shm, 0); 212 if (IS_ERR(info)) 213 return PTR_ERR(info); 214 215 if (param[0].u.memref.size != sizeof(*info)) 216 return -EPROTO; 217 218 if (info->version != RTC_INFO_VERSION) 219 return -EPROTO; 220 221 *features = info->features; 222 223 tm = &info->range_min; 224 rtc->range_min = mktime64(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, 225 tm->tm_sec); 226 tm = &info->range_max; 227 rtc->range_max = mktime64(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, 228 tm->tm_sec); 229 230 return 0; 231} 232 233static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) 234{ 235 if (ver->impl_id == TEE_IMPL_ID_OPTEE) 236 return 1; 237 else 238 return 0; 239} 240 241static int optee_rtc_probe(struct device *dev) 242{ 243 struct tee_client_device *rtc_device = to_tee_client_device(dev); 244 struct tee_ioctl_open_session_arg sess_arg; 245 struct optee_rtc *priv; 246 struct rtc_device *rtc; 247 struct tee_shm *shm; 248 int ret, err; 249 250 memset(&sess_arg, 0, sizeof(sess_arg)); 251 252 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 253 if (!priv) 254 return -ENOMEM; 255 256 rtc = devm_rtc_allocate_device(dev); 257 if (IS_ERR(rtc)) 258 return PTR_ERR(rtc); 259 260 /* Open context with TEE driver */ 261 priv->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); 262 if (IS_ERR(priv->ctx)) 263 return -ENODEV; 264 265 /* Open session with rtc Trusted App */ 266 export_uuid(sess_arg.uuid, &rtc_device->id.uuid); 267 sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL; 268 269 ret = tee_client_open_session(priv->ctx, &sess_arg, NULL); 270 if (ret < 0 || sess_arg.ret != 0) { 271 dev_err(dev, "tee_client_open_session failed, err: %x\n", sess_arg.ret); 272 err = -EINVAL; 273 goto out_ctx; 274 } 275 priv->session_id = sess_arg.session; 276 277 shm = tee_shm_alloc_kernel_buf(priv->ctx, sizeof(struct optee_rtc_info)); 278 if (IS_ERR(shm)) { 279 dev_err(priv->dev, "tee_shm_alloc_kernel_buf failed\n"); 280 err = PTR_ERR(shm); 281 goto out_sess; 282 } 283 284 priv->shm = shm; 285 priv->dev = dev; 286 dev_set_drvdata(dev, priv); 287 288 rtc->ops = &optee_rtc_ops; 289 290 err = optee_rtc_read_info(dev, rtc, &priv->features); 291 if (err) { 292 dev_err(dev, "Failed to get RTC features from OP-TEE\n"); 293 goto out_shm; 294 } 295 296 err = devm_rtc_register_device(rtc); 297 if (err) 298 goto out_shm; 299 300 /* 301 * We must clear this bit after registering because rtc_register_device 302 * will set it if it sees that .set_offset is provided. 303 */ 304 if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) 305 clear_bit(RTC_FEATURE_CORRECTION, rtc->features); 306 307 return 0; 308 309out_shm: 310 tee_shm_free(priv->shm); 311out_sess: 312 tee_client_close_session(priv->ctx, priv->session_id); 313out_ctx: 314 tee_client_close_context(priv->ctx); 315 316 return err; 317} 318 319static int optee_rtc_remove(struct device *dev) 320{ 321 struct optee_rtc *priv = dev_get_drvdata(dev); 322 323 tee_client_close_session(priv->ctx, priv->session_id); 324 tee_client_close_context(priv->ctx); 325 326 return 0; 327} 328 329static const struct tee_client_device_id optee_rtc_id_table[] = { 330 {UUID_INIT(0xf389f8c8, 0x845f, 0x496c, 331 0x8b, 0xbe, 0xd6, 0x4b, 0xd2, 0x4c, 0x92, 0xfd)}, 332 {} 333}; 334 335MODULE_DEVICE_TABLE(tee, optee_rtc_id_table); 336 337static struct tee_client_driver optee_rtc_driver = { 338 .id_table = optee_rtc_id_table, 339 .driver = { 340 .name = "optee_rtc", 341 .bus = &tee_bus_type, 342 .probe = optee_rtc_probe, 343 .remove = optee_rtc_remove, 344 }, 345}; 346 347static int __init optee_rtc_mod_init(void) 348{ 349 return driver_register(&optee_rtc_driver.driver); 350} 351 352static void __exit optee_rtc_mod_exit(void) 353{ 354 driver_unregister(&optee_rtc_driver.driver); 355} 356 357module_init(optee_rtc_mod_init); 358module_exit(optee_rtc_mod_exit); 359 360MODULE_LICENSE("GPL v2"); 361MODULE_AUTHOR("Clément Léger <clement.leger@bootlin.com>"); 362MODULE_DESCRIPTION("OP-TEE based RTC driver");