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-goldfish.c (4736B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* drivers/rtc/rtc-goldfish.c
      3 *
      4 * Copyright (C) 2007 Google, Inc.
      5 * Copyright (C) 2017 Imagination Technologies Ltd.
      6 */
      7
      8#include <linux/io.h>
      9#include <linux/module.h>
     10#include <linux/of.h>
     11#include <linux/platform_device.h>
     12#include <linux/rtc.h>
     13#include <linux/goldfish.h>
     14#include <clocksource/timer-goldfish.h>
     15
     16struct goldfish_rtc {
     17	void __iomem *base;
     18	int irq;
     19	struct rtc_device *rtc;
     20};
     21
     22static int goldfish_rtc_read_alarm(struct device *dev,
     23				   struct rtc_wkalrm *alrm)
     24{
     25	u64 rtc_alarm;
     26	u64 rtc_alarm_low;
     27	u64 rtc_alarm_high;
     28	void __iomem *base;
     29	struct goldfish_rtc *rtcdrv;
     30
     31	rtcdrv = dev_get_drvdata(dev);
     32	base = rtcdrv->base;
     33
     34	rtc_alarm_low = gf_ioread32(base + TIMER_ALARM_LOW);
     35	rtc_alarm_high = gf_ioread32(base + TIMER_ALARM_HIGH);
     36	rtc_alarm = (rtc_alarm_high << 32) | rtc_alarm_low;
     37
     38	do_div(rtc_alarm, NSEC_PER_SEC);
     39	memset(alrm, 0, sizeof(struct rtc_wkalrm));
     40
     41	rtc_time64_to_tm(rtc_alarm, &alrm->time);
     42
     43	if (gf_ioread32(base + TIMER_ALARM_STATUS))
     44		alrm->enabled = 1;
     45	else
     46		alrm->enabled = 0;
     47
     48	return 0;
     49}
     50
     51static int goldfish_rtc_set_alarm(struct device *dev,
     52				  struct rtc_wkalrm *alrm)
     53{
     54	struct goldfish_rtc *rtcdrv;
     55	u64 rtc_alarm64;
     56	u64 rtc_status_reg;
     57	void __iomem *base;
     58
     59	rtcdrv = dev_get_drvdata(dev);
     60	base = rtcdrv->base;
     61
     62	if (alrm->enabled) {
     63		rtc_alarm64 = rtc_tm_to_time64(&alrm->time) * NSEC_PER_SEC;
     64		gf_iowrite32((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH);
     65		gf_iowrite32(rtc_alarm64, base + TIMER_ALARM_LOW);
     66		gf_iowrite32(1, base + TIMER_IRQ_ENABLED);
     67	} else {
     68		/*
     69		 * if this function was called with enabled=0
     70		 * then it could mean that the application is
     71		 * trying to cancel an ongoing alarm
     72		 */
     73		rtc_status_reg = gf_ioread32(base + TIMER_ALARM_STATUS);
     74		if (rtc_status_reg)
     75			gf_iowrite32(1, base + TIMER_CLEAR_ALARM);
     76	}
     77
     78	return 0;
     79}
     80
     81static int goldfish_rtc_alarm_irq_enable(struct device *dev,
     82					 unsigned int enabled)
     83{
     84	void __iomem *base;
     85	struct goldfish_rtc *rtcdrv;
     86
     87	rtcdrv = dev_get_drvdata(dev);
     88	base = rtcdrv->base;
     89
     90	if (enabled)
     91		gf_iowrite32(1, base + TIMER_IRQ_ENABLED);
     92	else
     93		gf_iowrite32(0, base + TIMER_IRQ_ENABLED);
     94
     95	return 0;
     96}
     97
     98static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id)
     99{
    100	struct goldfish_rtc *rtcdrv = dev_id;
    101	void __iomem *base = rtcdrv->base;
    102
    103	gf_iowrite32(1, base + TIMER_CLEAR_INTERRUPT);
    104
    105	rtc_update_irq(rtcdrv->rtc, 1, RTC_IRQF | RTC_AF);
    106
    107	return IRQ_HANDLED;
    108}
    109
    110static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm)
    111{
    112	struct goldfish_rtc *rtcdrv;
    113	void __iomem *base;
    114	u64 time_high;
    115	u64 time_low;
    116	u64 time;
    117
    118	rtcdrv = dev_get_drvdata(dev);
    119	base = rtcdrv->base;
    120
    121	time_low = gf_ioread32(base + TIMER_TIME_LOW);
    122	time_high = gf_ioread32(base + TIMER_TIME_HIGH);
    123	time = (time_high << 32) | time_low;
    124
    125	do_div(time, NSEC_PER_SEC);
    126
    127	rtc_time64_to_tm(time, tm);
    128
    129	return 0;
    130}
    131
    132static int goldfish_rtc_set_time(struct device *dev, struct rtc_time *tm)
    133{
    134	struct goldfish_rtc *rtcdrv;
    135	void __iomem *base;
    136	u64 now64;
    137
    138	rtcdrv = dev_get_drvdata(dev);
    139	base = rtcdrv->base;
    140
    141	now64 = rtc_tm_to_time64(tm) * NSEC_PER_SEC;
    142	gf_iowrite32((now64 >> 32), base + TIMER_TIME_HIGH);
    143	gf_iowrite32(now64, base + TIMER_TIME_LOW);
    144
    145	return 0;
    146}
    147
    148static const struct rtc_class_ops goldfish_rtc_ops = {
    149	.read_time	= goldfish_rtc_read_time,
    150	.set_time	= goldfish_rtc_set_time,
    151	.read_alarm	= goldfish_rtc_read_alarm,
    152	.set_alarm	= goldfish_rtc_set_alarm,
    153	.alarm_irq_enable = goldfish_rtc_alarm_irq_enable
    154};
    155
    156static int goldfish_rtc_probe(struct platform_device *pdev)
    157{
    158	struct goldfish_rtc *rtcdrv;
    159	int err;
    160
    161	rtcdrv = devm_kzalloc(&pdev->dev, sizeof(*rtcdrv), GFP_KERNEL);
    162	if (!rtcdrv)
    163		return -ENOMEM;
    164
    165	platform_set_drvdata(pdev, rtcdrv);
    166	rtcdrv->base = devm_platform_ioremap_resource(pdev, 0);
    167	if (IS_ERR(rtcdrv->base))
    168		return PTR_ERR(rtcdrv->base);
    169
    170	rtcdrv->irq = platform_get_irq(pdev, 0);
    171	if (rtcdrv->irq < 0)
    172		return -ENODEV;
    173
    174	rtcdrv->rtc = devm_rtc_allocate_device(&pdev->dev);
    175	if (IS_ERR(rtcdrv->rtc))
    176		return PTR_ERR(rtcdrv->rtc);
    177
    178	rtcdrv->rtc->ops = &goldfish_rtc_ops;
    179	rtcdrv->rtc->range_max = U64_MAX / NSEC_PER_SEC;
    180
    181	err = devm_request_irq(&pdev->dev, rtcdrv->irq,
    182			       goldfish_rtc_interrupt,
    183			       0, pdev->name, rtcdrv);
    184	if (err)
    185		return err;
    186
    187	return devm_rtc_register_device(rtcdrv->rtc);
    188}
    189
    190static const struct of_device_id goldfish_rtc_of_match[] = {
    191	{ .compatible = "google,goldfish-rtc", },
    192	{},
    193};
    194MODULE_DEVICE_TABLE(of, goldfish_rtc_of_match);
    195
    196static struct platform_driver goldfish_rtc = {
    197	.probe = goldfish_rtc_probe,
    198	.driver = {
    199		.name = "goldfish_rtc",
    200		.of_match_table = goldfish_rtc_of_match,
    201	}
    202};
    203
    204module_platform_driver(goldfish_rtc);
    205
    206MODULE_LICENSE("GPL v2");