cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rtc-imx-sc.c (4354B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright 2018 NXP.
      4 */
      5
      6#include <dt-bindings/firmware/imx/rsrc.h>
      7#include <linux/arm-smccc.h>
      8#include <linux/firmware/imx/sci.h>
      9#include <linux/module.h>
     10#include <linux/of.h>
     11#include <linux/platform_device.h>
     12#include <linux/rtc.h>
     13
     14#define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970	9
     15#define IMX_SC_TIMER_FUNC_SET_RTC_ALARM		8
     16#define IMX_SC_TIMER_FUNC_SET_RTC_TIME		6
     17
     18#define IMX_SIP_SRTC			0xC2000002
     19#define IMX_SIP_SRTC_SET_TIME		0x0
     20
     21#define SC_IRQ_GROUP_RTC    2
     22#define SC_IRQ_RTC          1
     23
     24static struct imx_sc_ipc *rtc_ipc_handle;
     25static struct rtc_device *imx_sc_rtc;
     26
     27struct imx_sc_msg_timer_get_rtc_time {
     28	struct imx_sc_rpc_msg hdr;
     29	u32 time;
     30} __packed;
     31
     32struct imx_sc_msg_timer_rtc_set_alarm {
     33	struct imx_sc_rpc_msg hdr;
     34	u16 year;
     35	u8 mon;
     36	u8 day;
     37	u8 hour;
     38	u8 min;
     39	u8 sec;
     40} __packed __aligned(4);
     41
     42static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm)
     43{
     44	struct imx_sc_msg_timer_get_rtc_time msg;
     45	struct imx_sc_rpc_msg *hdr = &msg.hdr;
     46	int ret;
     47
     48	hdr->ver = IMX_SC_RPC_VERSION;
     49	hdr->svc = IMX_SC_RPC_SVC_TIMER;
     50	hdr->func = IMX_SC_TIMER_FUNC_GET_RTC_SEC1970;
     51	hdr->size = 1;
     52
     53	ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true);
     54	if (ret) {
     55		dev_err(dev, "read rtc time failed, ret %d\n", ret);
     56		return ret;
     57	}
     58
     59	rtc_time64_to_tm(msg.time, tm);
     60
     61	return 0;
     62}
     63
     64static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm)
     65{
     66	struct arm_smccc_res res;
     67
     68	/* pack 2 time parameters into 1 register, 16 bits for each */
     69	arm_smccc_smc(IMX_SIP_SRTC, IMX_SIP_SRTC_SET_TIME,
     70		      ((tm->tm_year + 1900) << 16) | (tm->tm_mon + 1),
     71		      (tm->tm_mday << 16) | tm->tm_hour,
     72		      (tm->tm_min << 16) | tm->tm_sec,
     73		      0, 0, 0, &res);
     74
     75	return res.a0;
     76}
     77
     78static int imx_sc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
     79{
     80	return imx_scu_irq_group_enable(SC_IRQ_GROUP_RTC, SC_IRQ_RTC, enable);
     81}
     82
     83static int imx_sc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
     84{
     85	struct imx_sc_msg_timer_rtc_set_alarm msg;
     86	struct imx_sc_rpc_msg *hdr = &msg.hdr;
     87	int ret;
     88	struct rtc_time *alrm_tm = &alrm->time;
     89
     90	hdr->ver = IMX_SC_RPC_VERSION;
     91	hdr->svc = IMX_SC_RPC_SVC_TIMER;
     92	hdr->func = IMX_SC_TIMER_FUNC_SET_RTC_ALARM;
     93	hdr->size = 3;
     94
     95	msg.year = alrm_tm->tm_year + 1900;
     96	msg.mon = alrm_tm->tm_mon + 1;
     97	msg.day = alrm_tm->tm_mday;
     98	msg.hour = alrm_tm->tm_hour;
     99	msg.min = alrm_tm->tm_min;
    100	msg.sec = alrm_tm->tm_sec;
    101
    102	ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true);
    103	if (ret) {
    104		dev_err(dev, "set rtc alarm failed, ret %d\n", ret);
    105		return ret;
    106	}
    107
    108	ret = imx_sc_rtc_alarm_irq_enable(dev, alrm->enabled);
    109	if (ret) {
    110		dev_err(dev, "enable rtc alarm failed, ret %d\n", ret);
    111		return ret;
    112	}
    113
    114	return 0;
    115}
    116
    117static const struct rtc_class_ops imx_sc_rtc_ops = {
    118	.read_time = imx_sc_rtc_read_time,
    119	.set_time = imx_sc_rtc_set_time,
    120	.set_alarm = imx_sc_rtc_set_alarm,
    121	.alarm_irq_enable = imx_sc_rtc_alarm_irq_enable,
    122};
    123
    124static int imx_sc_rtc_alarm_notify(struct notifier_block *nb,
    125					unsigned long event, void *group)
    126{
    127	/* ignore non-rtc irq */
    128	if (!((event & SC_IRQ_RTC) && (*(u8 *)group == SC_IRQ_GROUP_RTC)))
    129		return 0;
    130
    131	rtc_update_irq(imx_sc_rtc, 1, RTC_IRQF | RTC_AF);
    132
    133	return 0;
    134}
    135
    136static struct notifier_block imx_sc_rtc_alarm_sc_notifier = {
    137	.notifier_call = imx_sc_rtc_alarm_notify,
    138};
    139
    140static int imx_sc_rtc_probe(struct platform_device *pdev)
    141{
    142	int ret;
    143
    144	ret = imx_scu_get_handle(&rtc_ipc_handle);
    145	if (ret)
    146		return ret;
    147
    148	device_init_wakeup(&pdev->dev, true);
    149
    150	imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev);
    151	if (IS_ERR(imx_sc_rtc))
    152		return PTR_ERR(imx_sc_rtc);
    153
    154	imx_sc_rtc->ops = &imx_sc_rtc_ops;
    155	imx_sc_rtc->range_min = 0;
    156	imx_sc_rtc->range_max = U32_MAX;
    157
    158	ret = devm_rtc_register_device(imx_sc_rtc);
    159	if (ret)
    160		return ret;
    161
    162	imx_scu_irq_register_notifier(&imx_sc_rtc_alarm_sc_notifier);
    163
    164	return 0;
    165}
    166
    167static const struct of_device_id imx_sc_dt_ids[] = {
    168	{ .compatible = "fsl,imx8qxp-sc-rtc", },
    169	{}
    170};
    171MODULE_DEVICE_TABLE(of, imx_sc_dt_ids);
    172
    173static struct platform_driver imx_sc_rtc_driver = {
    174	.driver = {
    175		.name	= "imx-sc-rtc",
    176		.of_match_table = imx_sc_dt_ids,
    177	},
    178	.probe		= imx_sc_rtc_probe,
    179};
    180module_platform_driver(imx_sc_rtc_driver);
    181
    182MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
    183MODULE_DESCRIPTION("NXP i.MX System Controller RTC Driver");
    184MODULE_LICENSE("GPL");