// SPDX-License-Identifier: GPL-2.0/* * Copyright (C) 2022 Microchip. */ #include <linux/device.h>#include <linux/kernel.h>#include <linux/kthread.h>#include <linux/module.h>#include <linux/rtc.h>#include <linux/tee_drv.h> #define RTC_INFO_VERSION 0x1 #define TA_RTC_FEATURE_CORRECTION BIT(0)#define TA_RTC_FEATURE_ALARM BIT(1)#define TA_RTC_FEATURE_WAKEUP_ALARM BIT(2) enum rtc_optee_pta_cmd { /* PTA_CMD_RTC_GET_INFO - Get RTC information * * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_info */ PTA_CMD_RTC_GET_INF = 0x0, /* * PTA_CMD_RTC_GET_TIME - Get time from RTC * * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_time */ PTA_CMD_RTC_GET_TIME = 0x1, /* * PTA_CMD_RTC_SET_TIME - Set time from RTC * * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_time to be * used as RTC time */ PTA_CMD_RTC_SET_TIME = 0x2, /* * PTA_CMD_RTC_GET_OFFSET - Get RTC offset * * [out] value[0].a RTC offset (signed 32bit value) */ PTA_CMD_RTC_GET_OFFSET = 0x3, /* * PTA_CMD_RTC_SET_OFFSET - Set RTC offset * * [in] value[0].a RTC offset to be set (signed 32bit value) */ PTA_CMD_RTC_SET_OFFSET = 0x4, /* * PTA_CMD_RTC_READ_ALARM - Read RTC alarm * * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm */ PTA_CMD_RTC_READ_ALARM = 0x5, /* * PTA_CMD_RTC_SET_ALARM - Set RTC alarm * * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm to be * used as RTC alarm */ PTA_CMD_RTC_SET_ALARM = 0x6, /* * PTA_CMD_RTC_ENABLE_ALARM - Enable Alarm * * [in] value[0].a RTC IRQ flag (uint32_t), 0 to disable the alarm, 1 to enable */ PTA_CMD_RTC_ENABLE_ALARM = 0x7, /* * PTA_CMD_RTC_WAIT_ALARM - Get alarm event * * [out] value[0].a RTC wait alarm return status (uint32_t): * - 0: No alarm event * - 1: Alarm event occurred * - 2: Alarm event canceled */ PTA_CMD_RTC_WAIT_ALARM = 0x8, /* * PTA_CMD_RTC_CANCEL_WAIT - Cancel wait for alarm event */ PTA_CMD_RTC_CANCEL_WAIT = 0x9, /* * PTA_CMD_RTC_SET_WAKE_ALARM_STATUS - Set RTC wake alarm status flag * * [in] value[0].a RTC IRQ wake alarm flag (uint32_t), 0 to disable the wake up * capability, 1 to enable. */ PTA_CMD_RTC_SET_WAKE_ALARM_STATUS = 0xA,}; enum rtc_wait_alarm_status { WAIT_ALARM_RESET = 0x0, WAIT_ALARM_ALARM_OCCURRED = 0x1, WAIT_ALARM_CANCELED = 0x2,}; struct optee_rtc_time { u32 tm_sec; u32 tm_min; u32 tm_hour; u32 tm_mday; u32 tm_mon; u32 tm_year; u32 tm_wday;}; struct optee_rtc_alarm { u8 enabled; u8 pending; struct optee_rtc_time time;}; struct optee_rtc_info { u64 version; u64 features; struct optee_rtc_time range_min; struct optee_rtc_time range_max;}; /** * struct optee_rtc - OP-TEE RTC private data * @dev: OP-TEE based RTC device. * @ctx: OP-TEE context handler. * @session_id: RTC TA session identifier. * @session2_id: RTC wait alarm session identifier. * @shm: Memory pool shared with RTC device. * @features: Bitfield of RTC features * @alarm_task: RTC wait alamr task. * @rtc: RTC device. */struct optee_rtc { struct device *dev; struct tee_context *ctx; u32 session_id; u32 session2_id; struct tee_shm *shm; u64 features; struct task_struct *alarm_task; struct rtc_device *rtc;}; static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct optee_rtc_time *optee_tm; struct tee_param param[4] = {0}; int ret; inv_arg.func = PTA_CMD_RTC_GET_TIME; inv_arg.session = priv->session_id; inv_arg.num_params = 4; /* Fill invoke cmd params */ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; param[0].u.memref.shm = priv->shm; param[0].u.memref.size = sizeof(struct optee_rtc_time); ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; optee_tm = tee_shm_get_va(priv->shm, 0); if (IS_ERR(optee_tm)) return PTR_ERR(optee_tm); if (param[0].u.memref.size != sizeof(*optee_tm)) return -EPROTO; tm->tm_sec = optee_tm->tm_sec; tm->tm_min = optee_tm->tm_min; tm->tm_hour = optee_tm->tm_hour; tm->tm_mday = optee_tm->tm_mday; tm->tm_mon = optee_tm->tm_mon; tm->tm_year = optee_tm->tm_year - 1900; tm->tm_wday = optee_tm->tm_wday; tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); return 0;} static int optee_rtc_settime(struct device *dev, struct rtc_time *tm){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[4] = {0}; struct optee_rtc_time *optee_tm; int ret; inv_arg.func = PTA_CMD_RTC_SET_TIME; inv_arg.session = priv->session_id; inv_arg.num_params = 4; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; param[0].u.memref.shm = priv->shm; param[0].u.memref.size = sizeof(struct optee_rtc_time); optee_tm = tee_shm_get_va(priv->shm, 0); if (IS_ERR(optee_tm)) return PTR_ERR(optee_tm); optee_tm->tm_min = tm->tm_min; optee_tm->tm_sec = tm->tm_sec; optee_tm->tm_hour = tm->tm_hour; optee_tm->tm_mday = tm->tm_mday; optee_tm->tm_mon = tm->tm_mon; optee_tm->tm_year = tm->tm_year + 1900; optee_tm->tm_wday = tm->tm_wday; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0;} static int optee_rtc_readoffset(struct device *dev, long *offset){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[4] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_GET_OFFSET; inv_arg.session = priv->session_id; inv_arg.num_params = 4; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; *offset = param[0].u.value.a; return 0;} static int optee_rtc_setoffset(struct device *dev, long offset){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[4] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_SET_OFFSET; inv_arg.session = priv->session_id; inv_arg.num_params = 4; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = offset; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0;} static int optee_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct optee_rtc_alarm *optee_alarm; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_READ_ALARM; inv_arg.session = priv->session_id; inv_arg.num_params = 1; /* Fill invoke cmd params */ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; param[0].u.memref.shm = priv->shm; param[0].u.memref.size = sizeof(struct optee_rtc_alarm); ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; optee_alarm = tee_shm_get_va(priv->shm, 0); if (IS_ERR(optee_alarm)) return PTR_ERR(optee_alarm); if (param[0].u.memref.size != sizeof(*optee_alarm)) return -EPROTO; alarm->enabled = optee_alarm->enabled; alarm->pending = optee_alarm->pending; alarm->time.tm_sec = optee_alarm->time.tm_sec; alarm->time.tm_min = optee_alarm->time.tm_min; alarm->time.tm_hour = optee_alarm->time.tm_hour; alarm->time.tm_mday = optee_alarm->time.tm_mday; alarm->time.tm_mon = optee_alarm->time.tm_mon; alarm->time.tm_year = optee_alarm->time.tm_year - 1900; alarm->time.tm_wday = optee_alarm->time.tm_wday; alarm->time.tm_yday = rtc_year_days(alarm->time.tm_mday, alarm->time.tm_mon, alarm->time.tm_year); return 0;} static int optee_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct optee_rtc_alarm *optee_alarm; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_SET_ALARM; inv_arg.session = priv->session_id; inv_arg.num_params = 1; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; param[0].u.memref.shm = priv->shm; param[0].u.memref.size = sizeof(struct optee_rtc_alarm); optee_alarm = tee_shm_get_va(priv->shm, 0); if (IS_ERR(optee_alarm)) return PTR_ERR(optee_alarm); optee_alarm->enabled = alarm->enabled; optee_alarm->pending = alarm->pending; optee_alarm->time.tm_sec = alarm->time.tm_sec; optee_alarm->time.tm_min = alarm->time.tm_min; optee_alarm->time.tm_hour = alarm->time.tm_hour; optee_alarm->time.tm_mday = alarm->time.tm_mday; optee_alarm->time.tm_mon = alarm->time.tm_mon; optee_alarm->time.tm_year = alarm->time.tm_year + 1900; optee_alarm->time.tm_wday = alarm->time.tm_wday; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0;} static int optee_rtc_enable_alarm(struct device *dev, unsigned int enabled){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_ENABLE_ALARM; inv_arg.session = priv->session_id; inv_arg.num_params = 1; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = (bool)enabled; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0;} static const struct rtc_class_ops optee_rtc_ops = { .read_time = optee_rtc_readtime, .set_time = optee_rtc_settime, .set_offset = optee_rtc_setoffset, .read_offset = optee_rtc_readoffset, .read_alarm = optee_rtc_read_alarm, .set_alarm = optee_rtc_set_alarm, .alarm_irq_enable = optee_rtc_enable_alarm,}; static int optee_rtc_wait_alarm(struct device *dev, int *return_status){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_WAIT_ALARM; inv_arg.session = priv->session2_id; inv_arg.num_params = 1; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; *return_status = param[0].u.value.a; return 0;} static int optee_rtc_cancel_wait_alarm(struct device *dev){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_CANCEL_WAIT; inv_arg.session = priv->session_id; inv_arg.num_params = 0; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0;} static int optee_rtc_set_alarm_wake_status(struct device *dev, bool status){ struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_SET_WAKE_ALARM_STATUS; inv_arg.session = priv->session_id; inv_arg.num_params = 1; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = status; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0;} static int optee_rtc_handle_alarm_event(void *data){ struct optee_rtc *priv = (struct optee_rtc *)data; int wait_alarm_return_status = 0; int ret; while (!kthread_should_stop()) { ret = optee_rtc_wait_alarm(priv->dev, &wait_alarm_return_status); if (ret) { dev_err(priv->dev, "Failed to wait for alarm: %d\n", ret); return ret; } switch (wait_alarm_return_status) { case WAIT_ALARM_ALARM_OCCURRED: dev_dbg(priv->dev, "Alarm occurred\n"); rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF); break; case WAIT_ALARM_CANCELED: dev_dbg(priv->dev, "Alarm canceled\n"); break; default: dev_warn(priv->dev, "Unknown return status: %d\n", wait_alarm_return_status); break; } } return 0;} static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc, u64 *features){Lines 1–500 of 735. Load more
// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2022 Microchip. */ #include <linux/device.h> #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/module.h> #include <linux/rtc.h> #include <linux/tee_drv.h> #define RTC_INFO_VERSION 0x1 #define TA_RTC_FEATURE_CORRECTION BIT(0) #define TA_RTC_FEATURE_ALARM BIT(1) #define TA_RTC_FEATURE_WAKEUP_ALARM BIT(2) enum rtc_optee_pta_cmd { /* PTA_CMD_RTC_GET_INFO - Get RTC information * * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_info */ PTA_CMD_RTC_GET_INF = 0x0, /* * PTA_CMD_RTC_GET_TIME - Get time from RTC * * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_time */ PTA_CMD_RTC_GET_TIME = 0x1, /* * PTA_CMD_RTC_SET_TIME - Set time from RTC * * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_time to be * used as RTC time */ PTA_CMD_RTC_SET_TIME = 0x2, /* * PTA_CMD_RTC_GET_OFFSET - Get RTC offset * * [out] value[0].a RTC offset (signed 32bit value) */ PTA_CMD_RTC_GET_OFFSET = 0x3, /* * PTA_CMD_RTC_SET_OFFSET - Set RTC offset * * [in] value[0].a RTC offset to be set (signed 32bit value) */ PTA_CMD_RTC_SET_OFFSET = 0x4, /* * PTA_CMD_RTC_READ_ALARM - Read RTC alarm * * [out] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm */ PTA_CMD_RTC_READ_ALARM = 0x5, /* * PTA_CMD_RTC_SET_ALARM - Set RTC alarm * * [in] memref[0] RTC buffer memory reference containing a struct pta_rtc_alarm to be * used as RTC alarm */ PTA_CMD_RTC_SET_ALARM = 0x6, /* * PTA_CMD_RTC_ENABLE_ALARM - Enable Alarm * * [in] value[0].a RTC IRQ flag (uint32_t), 0 to disable the alarm, 1 to enable */ PTA_CMD_RTC_ENABLE_ALARM = 0x7, /* * PTA_CMD_RTC_WAIT_ALARM - Get alarm event * * [out] value[0].a RTC wait alarm return status (uint32_t): * - 0: No alarm event * - 1: Alarm event occurred * - 2: Alarm event canceled */ PTA_CMD_RTC_WAIT_ALARM = 0x8, /* * PTA_CMD_RTC_CANCEL_WAIT - Cancel wait for alarm event */ PTA_CMD_RTC_CANCEL_WAIT = 0x9, /* * PTA_CMD_RTC_SET_WAKE_ALARM_STATUS - Set RTC wake alarm status flag * * [in] value[0].a RTC IRQ wake alarm flag (uint32_t), 0 to disable the wake up * capability, 1 to enable. */ PTA_CMD_RTC_SET_WAKE_ALARM_STATUS = 0xA, }; enum rtc_wait_alarm_status { WAIT_ALARM_RESET = 0x0, WAIT_ALARM_ALARM_OCCURRED = 0x1, WAIT_ALARM_CANCELED = 0x2, }; struct optee_rtc_time { u32 tm_sec; u32 tm_min; u32 tm_hour; u32 tm_mday; u32 tm_mon; u32 tm_year; u32 tm_wday; }; struct optee_rtc_alarm { u8 enabled; u8 pending; struct optee_rtc_time time; }; struct optee_rtc_info { u64 version; u64 features; struct optee_rtc_time range_min; struct optee_rtc_time range_max; }; /** * struct optee_rtc - OP-TEE RTC private data * @dev: OP-TEE based RTC device. * @ctx: OP-TEE context handler. * @session_id: RTC TA session identifier. * @session2_id: RTC wait alarm session identifier. * @shm: Memory pool shared with RTC device. * @features: Bitfield of RTC features * @alarm_task: RTC wait alamr task. * @rtc: RTC device. */ struct optee_rtc { struct device *dev; struct tee_context *ctx; u32 session_id; u32 session2_id; struct tee_shm *shm; u64 features; struct task_struct *alarm_task; struct rtc_device *rtc; }; static int optee_rtc_readtime(struct device *dev, struct rtc_time *tm) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct optee_rtc_time *optee_tm; struct tee_param param[4] = {0}; int ret; inv_arg.func = PTA_CMD_RTC_GET_TIME; inv_arg.session = priv->session_id; inv_arg.num_params = 4; /* Fill invoke cmd params */ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; param[0].u.memref.shm = priv->shm; param[0].u.memref.size = sizeof(struct optee_rtc_time); ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; optee_tm = tee_shm_get_va(priv->shm, 0); if (IS_ERR(optee_tm)) return PTR_ERR(optee_tm); if (param[0].u.memref.size != sizeof(*optee_tm)) return -EPROTO; tm->tm_sec = optee_tm->tm_sec; tm->tm_min = optee_tm->tm_min; tm->tm_hour = optee_tm->tm_hour; tm->tm_mday = optee_tm->tm_mday; tm->tm_mon = optee_tm->tm_mon; tm->tm_year = optee_tm->tm_year - 1900; tm->tm_wday = optee_tm->tm_wday; tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); return 0; } static int optee_rtc_settime(struct device *dev, struct rtc_time *tm) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[4] = {0}; struct optee_rtc_time *optee_tm; int ret; inv_arg.func = PTA_CMD_RTC_SET_TIME; inv_arg.session = priv->session_id; inv_arg.num_params = 4; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; param[0].u.memref.shm = priv->shm; param[0].u.memref.size = sizeof(struct optee_rtc_time); optee_tm = tee_shm_get_va(priv->shm, 0); if (IS_ERR(optee_tm)) return PTR_ERR(optee_tm); optee_tm->tm_min = tm->tm_min; optee_tm->tm_sec = tm->tm_sec; optee_tm->tm_hour = tm->tm_hour; optee_tm->tm_mday = tm->tm_mday; optee_tm->tm_mon = tm->tm_mon; optee_tm->tm_year = tm->tm_year + 1900; optee_tm->tm_wday = tm->tm_wday; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0; } static int optee_rtc_readoffset(struct device *dev, long *offset) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[4] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_GET_OFFSET; inv_arg.session = priv->session_id; inv_arg.num_params = 4; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; *offset = param[0].u.value.a; return 0; } static int optee_rtc_setoffset(struct device *dev, long offset) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[4] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_CORRECTION)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_SET_OFFSET; inv_arg.session = priv->session_id; inv_arg.num_params = 4; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = offset; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0; } static int optee_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct optee_rtc_alarm *optee_alarm; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_READ_ALARM; inv_arg.session = priv->session_id; inv_arg.num_params = 1; /* Fill invoke cmd params */ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; param[0].u.memref.shm = priv->shm; param[0].u.memref.size = sizeof(struct optee_rtc_alarm); ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; optee_alarm = tee_shm_get_va(priv->shm, 0); if (IS_ERR(optee_alarm)) return PTR_ERR(optee_alarm); if (param[0].u.memref.size != sizeof(*optee_alarm)) return -EPROTO; alarm->enabled = optee_alarm->enabled; alarm->pending = optee_alarm->pending; alarm->time.tm_sec = optee_alarm->time.tm_sec; alarm->time.tm_min = optee_alarm->time.tm_min; alarm->time.tm_hour = optee_alarm->time.tm_hour; alarm->time.tm_mday = optee_alarm->time.tm_mday; alarm->time.tm_mon = optee_alarm->time.tm_mon; alarm->time.tm_year = optee_alarm->time.tm_year - 1900; alarm->time.tm_wday = optee_alarm->time.tm_wday; alarm->time.tm_yday = rtc_year_days(alarm->time.tm_mday, alarm->time.tm_mon, alarm->time.tm_year); return 0; } static int optee_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct optee_rtc_alarm *optee_alarm; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_SET_ALARM; inv_arg.session = priv->session_id; inv_arg.num_params = 1; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; param[0].u.memref.shm = priv->shm; param[0].u.memref.size = sizeof(struct optee_rtc_alarm); optee_alarm = tee_shm_get_va(priv->shm, 0); if (IS_ERR(optee_alarm)) return PTR_ERR(optee_alarm); optee_alarm->enabled = alarm->enabled; optee_alarm->pending = alarm->pending; optee_alarm->time.tm_sec = alarm->time.tm_sec; optee_alarm->time.tm_min = alarm->time.tm_min; optee_alarm->time.tm_hour = alarm->time.tm_hour; optee_alarm->time.tm_mday = alarm->time.tm_mday; optee_alarm->time.tm_mon = alarm->time.tm_mon; optee_alarm->time.tm_year = alarm->time.tm_year + 1900; optee_alarm->time.tm_wday = alarm->time.tm_wday; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0; } static int optee_rtc_enable_alarm(struct device *dev, unsigned int enabled) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_ENABLE_ALARM; inv_arg.session = priv->session_id; inv_arg.num_params = 1; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = (bool)enabled; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0; } static const struct rtc_class_ops optee_rtc_ops = { .read_time = optee_rtc_readtime, .set_time = optee_rtc_settime, .set_offset = optee_rtc_setoffset, .read_offset = optee_rtc_readoffset, .read_alarm = optee_rtc_read_alarm, .set_alarm = optee_rtc_set_alarm, .alarm_irq_enable = optee_rtc_enable_alarm, }; static int optee_rtc_wait_alarm(struct device *dev, int *return_status) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_WAIT_ALARM; inv_arg.session = priv->session2_id; inv_arg.num_params = 1; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; *return_status = param[0].u.value.a; return 0; } static int optee_rtc_cancel_wait_alarm(struct device *dev) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_CANCEL_WAIT; inv_arg.session = priv->session_id; inv_arg.num_params = 0; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0; } static int optee_rtc_set_alarm_wake_status(struct device *dev, bool status) { struct optee_rtc *priv = dev_get_drvdata(dev); struct tee_ioctl_invoke_arg inv_arg = {0}; struct tee_param param[1] = {0}; int ret; if (!(priv->features & TA_RTC_FEATURE_ALARM)) return -EOPNOTSUPP; inv_arg.func = PTA_CMD_RTC_SET_WAKE_ALARM_STATUS; inv_arg.session = priv->session_id; inv_arg.num_params = 1; param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; param[0].u.value.a = status; ret = tee_client_invoke_func(priv->ctx, &inv_arg, param); if (ret < 0 || inv_arg.ret != 0) return ret ? ret : -EPROTO; return 0; } static int optee_rtc_handle_alarm_event(void *data) { struct optee_rtc *priv = (struct optee_rtc *)data; int wait_alarm_return_status = 0; int ret; while (!kthread_should_stop()) { ret = optee_rtc_wait_alarm(priv->dev, &wait_alarm_return_status); if (ret) { dev_err(priv->dev, "Failed to wait for alarm: %d\n", ret); return ret; } switch (wait_alarm_return_status) { case WAIT_ALARM_ALARM_OCCURRED: dev_dbg(priv->dev, "Alarm occurred\n"); rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF); break; case WAIT_ALARM_CANCELED: dev_dbg(priv->dev, "Alarm canceled\n"); break; default: dev_warn(priv->dev, "Unknown return status: %d\n", wait_alarm_return_status); break; } } return 0; } static int optee_rtc_read_info(struct device *dev, struct rtc_device *rtc, u64 *features) {