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-cadence.c (10635B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3/*
      4 * Copyright 2019 Cadence
      5 *
      6 * Authors:
      7 *  Jan Kotas <jank@cadence.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/platform_device.h>
     12#include <linux/of.h>
     13#include <linux/io.h>
     14#include <linux/rtc.h>
     15#include <linux/clk.h>
     16#include <linux/bcd.h>
     17#include <linux/bitfield.h>
     18#include <linux/interrupt.h>
     19#include <linux/pm_wakeirq.h>
     20
     21/* Registers */
     22#define CDNS_RTC_CTLR		0x00
     23#define CDNS_RTC_HMR		0x04
     24#define CDNS_RTC_TIMR		0x08
     25#define CDNS_RTC_CALR		0x0C
     26#define CDNS_RTC_TIMAR		0x10
     27#define CDNS_RTC_CALAR		0x14
     28#define CDNS_RTC_AENR		0x18
     29#define CDNS_RTC_EFLR		0x1C
     30#define CDNS_RTC_IENR		0x20
     31#define CDNS_RTC_IDISR		0x24
     32#define CDNS_RTC_IMSKR		0x28
     33#define CDNS_RTC_STSR		0x2C
     34#define CDNS_RTC_KRTCR		0x30
     35
     36/* Control */
     37#define CDNS_RTC_CTLR_TIME	BIT(0)
     38#define CDNS_RTC_CTLR_CAL	BIT(1)
     39#define CDNS_RTC_CTLR_TIME_CAL	(CDNS_RTC_CTLR_TIME | CDNS_RTC_CTLR_CAL)
     40
     41/* Status */
     42#define CDNS_RTC_STSR_VT	BIT(0)
     43#define CDNS_RTC_STSR_VC	BIT(1)
     44#define CDNS_RTC_STSR_VTA	BIT(2)
     45#define CDNS_RTC_STSR_VCA	BIT(3)
     46#define CDNS_RTC_STSR_VT_VC	(CDNS_RTC_STSR_VT | CDNS_RTC_STSR_VC)
     47#define CDNS_RTC_STSR_VTA_VCA	(CDNS_RTC_STSR_VTA | CDNS_RTC_STSR_VCA)
     48
     49/* Keep RTC */
     50#define CDNS_RTC_KRTCR_KRTC	BIT(0)
     51
     52/* Alarm, Event, Interrupt */
     53#define CDNS_RTC_AEI_HOS	BIT(0)
     54#define CDNS_RTC_AEI_SEC	BIT(1)
     55#define CDNS_RTC_AEI_MIN	BIT(2)
     56#define CDNS_RTC_AEI_HOUR	BIT(3)
     57#define CDNS_RTC_AEI_DATE	BIT(4)
     58#define CDNS_RTC_AEI_MNTH	BIT(5)
     59#define CDNS_RTC_AEI_ALRM	BIT(6)
     60
     61/* Time */
     62#define CDNS_RTC_TIME_H		GENMASK(7, 0)
     63#define CDNS_RTC_TIME_S		GENMASK(14, 8)
     64#define CDNS_RTC_TIME_M		GENMASK(22, 16)
     65#define CDNS_RTC_TIME_HR	GENMASK(29, 24)
     66#define CDNS_RTC_TIME_PM	BIT(30)
     67#define CDNS_RTC_TIME_CH	BIT(31)
     68
     69/* Calendar */
     70#define CDNS_RTC_CAL_DAY	GENMASK(2, 0)
     71#define CDNS_RTC_CAL_M		GENMASK(7, 3)
     72#define CDNS_RTC_CAL_D		GENMASK(13, 8)
     73#define CDNS_RTC_CAL_Y		GENMASK(23, 16)
     74#define CDNS_RTC_CAL_C		GENMASK(29, 24)
     75#define CDNS_RTC_CAL_CH		BIT(31)
     76
     77#define CDNS_RTC_MAX_REGS_TRIES	3
     78
     79struct cdns_rtc {
     80	struct rtc_device *rtc_dev;
     81	struct clk *pclk;
     82	struct clk *ref_clk;
     83	void __iomem *regs;
     84	int irq;
     85};
     86
     87static void cdns_rtc_set_enabled(struct cdns_rtc *crtc, bool enabled)
     88{
     89	u32 reg = enabled ? 0x0 : CDNS_RTC_CTLR_TIME_CAL;
     90
     91	writel(reg, crtc->regs + CDNS_RTC_CTLR);
     92}
     93
     94static bool cdns_rtc_get_enabled(struct cdns_rtc *crtc)
     95{
     96	return !(readl(crtc->regs + CDNS_RTC_CTLR) & CDNS_RTC_CTLR_TIME_CAL);
     97}
     98
     99static irqreturn_t cdns_rtc_irq_handler(int irq, void *id)
    100{
    101	struct device *dev = id;
    102	struct cdns_rtc *crtc = dev_get_drvdata(dev);
    103
    104	/* Reading the register clears it */
    105	if (!(readl(crtc->regs + CDNS_RTC_EFLR) & CDNS_RTC_AEI_ALRM))
    106		return IRQ_NONE;
    107
    108	rtc_update_irq(crtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
    109	return IRQ_HANDLED;
    110}
    111
    112static u32 cdns_rtc_time2reg(struct rtc_time *tm)
    113{
    114	return FIELD_PREP(CDNS_RTC_TIME_S,  bin2bcd(tm->tm_sec))
    115	     | FIELD_PREP(CDNS_RTC_TIME_M,  bin2bcd(tm->tm_min))
    116	     | FIELD_PREP(CDNS_RTC_TIME_HR, bin2bcd(tm->tm_hour));
    117}
    118
    119static void cdns_rtc_reg2time(u32 reg, struct rtc_time *tm)
    120{
    121	tm->tm_sec  = bcd2bin(FIELD_GET(CDNS_RTC_TIME_S, reg));
    122	tm->tm_min  = bcd2bin(FIELD_GET(CDNS_RTC_TIME_M, reg));
    123	tm->tm_hour = bcd2bin(FIELD_GET(CDNS_RTC_TIME_HR, reg));
    124}
    125
    126static int cdns_rtc_read_time(struct device *dev, struct rtc_time *tm)
    127{
    128	struct cdns_rtc *crtc = dev_get_drvdata(dev);
    129	u32 reg;
    130
    131	/* If the RTC is disabled, assume the values are invalid */
    132	if (!cdns_rtc_get_enabled(crtc))
    133		return -EINVAL;
    134
    135	cdns_rtc_set_enabled(crtc, false);
    136
    137	reg = readl(crtc->regs + CDNS_RTC_TIMR);
    138	cdns_rtc_reg2time(reg, tm);
    139
    140	reg = readl(crtc->regs + CDNS_RTC_CALR);
    141	tm->tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));
    142	tm->tm_mon  = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;
    143	tm->tm_year = bcd2bin(FIELD_GET(CDNS_RTC_CAL_Y, reg))
    144		    + bcd2bin(FIELD_GET(CDNS_RTC_CAL_C, reg)) * 100 - 1900;
    145	tm->tm_wday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_DAY, reg)) - 1;
    146
    147	cdns_rtc_set_enabled(crtc, true);
    148	return 0;
    149}
    150
    151static int cdns_rtc_set_time(struct device *dev, struct rtc_time *tm)
    152{
    153	struct cdns_rtc *crtc = dev_get_drvdata(dev);
    154	u32 timr, calr, stsr;
    155	int ret = -EIO;
    156	int year = tm->tm_year + 1900;
    157	int tries;
    158
    159	cdns_rtc_set_enabled(crtc, false);
    160
    161	timr = cdns_rtc_time2reg(tm);
    162
    163	calr = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(tm->tm_mday))
    164	     | FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(tm->tm_mon + 1))
    165	     | FIELD_PREP(CDNS_RTC_CAL_Y, bin2bcd(year % 100))
    166	     | FIELD_PREP(CDNS_RTC_CAL_C, bin2bcd(year / 100))
    167	     | FIELD_PREP(CDNS_RTC_CAL_DAY, tm->tm_wday + 1);
    168
    169	/* Update registers, check valid flags */
    170	for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {
    171		writel(timr, crtc->regs + CDNS_RTC_TIMR);
    172		writel(calr, crtc->regs + CDNS_RTC_CALR);
    173		stsr = readl(crtc->regs + CDNS_RTC_STSR);
    174
    175		if ((stsr & CDNS_RTC_STSR_VT_VC) == CDNS_RTC_STSR_VT_VC) {
    176			ret = 0;
    177			break;
    178		}
    179	}
    180
    181	cdns_rtc_set_enabled(crtc, true);
    182	return ret;
    183}
    184
    185static int cdns_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
    186{
    187	struct cdns_rtc *crtc = dev_get_drvdata(dev);
    188
    189	if (enabled) {
    190		writel((CDNS_RTC_AEI_SEC | CDNS_RTC_AEI_MIN | CDNS_RTC_AEI_HOUR
    191			| CDNS_RTC_AEI_DATE | CDNS_RTC_AEI_MNTH),
    192		       crtc->regs + CDNS_RTC_AENR);
    193		writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IENR);
    194	} else {
    195		writel(0, crtc->regs + CDNS_RTC_AENR);
    196		writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IDISR);
    197	}
    198
    199	return 0;
    200}
    201
    202static int cdns_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
    203{
    204	struct cdns_rtc *crtc = dev_get_drvdata(dev);
    205	u32 reg;
    206
    207	reg = readl(crtc->regs + CDNS_RTC_TIMAR);
    208	cdns_rtc_reg2time(reg, &alarm->time);
    209
    210	reg = readl(crtc->regs + CDNS_RTC_CALAR);
    211	alarm->time.tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));
    212	alarm->time.tm_mon  = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;
    213
    214	return 0;
    215}
    216
    217static int cdns_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
    218{
    219	struct cdns_rtc *crtc = dev_get_drvdata(dev);
    220	int ret = -EIO;
    221	int tries;
    222	u32 timar, calar, stsr;
    223
    224	cdns_rtc_alarm_irq_enable(dev, 0);
    225
    226	timar = cdns_rtc_time2reg(&alarm->time);
    227	calar = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(alarm->time.tm_mday))
    228	      | FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(alarm->time.tm_mon + 1));
    229
    230	/* Update registers, check valid alarm flags */
    231	for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {
    232		writel(timar, crtc->regs + CDNS_RTC_TIMAR);
    233		writel(calar, crtc->regs + CDNS_RTC_CALAR);
    234		stsr = readl(crtc->regs + CDNS_RTC_STSR);
    235
    236		if ((stsr & CDNS_RTC_STSR_VTA_VCA) == CDNS_RTC_STSR_VTA_VCA) {
    237			ret = 0;
    238			break;
    239		}
    240	}
    241
    242	if (!ret)
    243		cdns_rtc_alarm_irq_enable(dev, alarm->enabled);
    244	return ret;
    245}
    246
    247static const struct rtc_class_ops cdns_rtc_ops = {
    248	.read_time	= cdns_rtc_read_time,
    249	.set_time	= cdns_rtc_set_time,
    250	.read_alarm	= cdns_rtc_read_alarm,
    251	.set_alarm	= cdns_rtc_set_alarm,
    252	.alarm_irq_enable = cdns_rtc_alarm_irq_enable,
    253};
    254
    255static int cdns_rtc_probe(struct platform_device *pdev)
    256{
    257	struct cdns_rtc *crtc;
    258	int ret;
    259	unsigned long ref_clk_freq;
    260
    261	crtc = devm_kzalloc(&pdev->dev, sizeof(*crtc), GFP_KERNEL);
    262	if (!crtc)
    263		return -ENOMEM;
    264
    265	crtc->regs = devm_platform_ioremap_resource(pdev, 0);
    266	if (IS_ERR(crtc->regs))
    267		return PTR_ERR(crtc->regs);
    268
    269	crtc->irq = platform_get_irq(pdev, 0);
    270	if (crtc->irq < 0)
    271		return -EINVAL;
    272
    273	crtc->pclk = devm_clk_get(&pdev->dev, "pclk");
    274	if (IS_ERR(crtc->pclk)) {
    275		ret = PTR_ERR(crtc->pclk);
    276		dev_err(&pdev->dev,
    277			"Failed to retrieve the peripheral clock, %d\n", ret);
    278		return ret;
    279	}
    280
    281	crtc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
    282	if (IS_ERR(crtc->ref_clk)) {
    283		ret = PTR_ERR(crtc->ref_clk);
    284		dev_err(&pdev->dev,
    285			"Failed to retrieve the reference clock, %d\n", ret);
    286		return ret;
    287	}
    288
    289	crtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
    290	if (IS_ERR(crtc->rtc_dev))
    291		return PTR_ERR(crtc->rtc_dev);
    292
    293	platform_set_drvdata(pdev, crtc);
    294
    295	ret = clk_prepare_enable(crtc->pclk);
    296	if (ret) {
    297		dev_err(&pdev->dev,
    298			"Failed to enable the peripheral clock, %d\n", ret);
    299		return ret;
    300	}
    301
    302	ret = clk_prepare_enable(crtc->ref_clk);
    303	if (ret) {
    304		dev_err(&pdev->dev,
    305			"Failed to enable the reference clock, %d\n", ret);
    306		goto err_disable_pclk;
    307	}
    308
    309	ref_clk_freq = clk_get_rate(crtc->ref_clk);
    310	if ((ref_clk_freq != 1) && (ref_clk_freq != 100)) {
    311		dev_err(&pdev->dev,
    312			"Invalid reference clock frequency %lu Hz.\n",
    313			ref_clk_freq);
    314		ret = -EINVAL;
    315		goto err_disable_ref_clk;
    316	}
    317
    318	ret = devm_request_irq(&pdev->dev, crtc->irq,
    319			       cdns_rtc_irq_handler, 0,
    320			       dev_name(&pdev->dev), &pdev->dev);
    321	if (ret) {
    322		dev_err(&pdev->dev,
    323			"Failed to request interrupt for the device, %d\n",
    324			ret);
    325		goto err_disable_ref_clk;
    326	}
    327
    328	/* The RTC supports 01.01.1900 - 31.12.2999 */
    329	crtc->rtc_dev->range_min = mktime64(1900,  1,  1,  0,  0,  0);
    330	crtc->rtc_dev->range_max = mktime64(2999, 12, 31, 23, 59, 59);
    331
    332	crtc->rtc_dev->ops = &cdns_rtc_ops;
    333	device_init_wakeup(&pdev->dev, true);
    334
    335	/* Always use 24-hour mode and keep the RTC values */
    336	writel(0, crtc->regs + CDNS_RTC_HMR);
    337	writel(CDNS_RTC_KRTCR_KRTC, crtc->regs + CDNS_RTC_KRTCR);
    338
    339	ret = devm_rtc_register_device(crtc->rtc_dev);
    340	if (ret)
    341		goto err_disable_wakeup;
    342
    343	return 0;
    344
    345err_disable_wakeup:
    346	device_init_wakeup(&pdev->dev, false);
    347
    348err_disable_ref_clk:
    349	clk_disable_unprepare(crtc->ref_clk);
    350
    351err_disable_pclk:
    352	clk_disable_unprepare(crtc->pclk);
    353
    354	return ret;
    355}
    356
    357static int cdns_rtc_remove(struct platform_device *pdev)
    358{
    359	struct cdns_rtc *crtc = platform_get_drvdata(pdev);
    360
    361	cdns_rtc_alarm_irq_enable(&pdev->dev, 0);
    362	device_init_wakeup(&pdev->dev, 0);
    363
    364	clk_disable_unprepare(crtc->pclk);
    365	clk_disable_unprepare(crtc->ref_clk);
    366
    367	return 0;
    368}
    369
    370#ifdef CONFIG_PM_SLEEP
    371static int cdns_rtc_suspend(struct device *dev)
    372{
    373	struct cdns_rtc *crtc = dev_get_drvdata(dev);
    374
    375	if (device_may_wakeup(dev))
    376		enable_irq_wake(crtc->irq);
    377
    378	return 0;
    379}
    380
    381static int cdns_rtc_resume(struct device *dev)
    382{
    383	struct cdns_rtc *crtc = dev_get_drvdata(dev);
    384
    385	if (device_may_wakeup(dev))
    386		disable_irq_wake(crtc->irq);
    387
    388	return 0;
    389}
    390#endif
    391
    392static SIMPLE_DEV_PM_OPS(cdns_rtc_pm_ops, cdns_rtc_suspend, cdns_rtc_resume);
    393
    394static const struct of_device_id cdns_rtc_of_match[] = {
    395	{ .compatible = "cdns,rtc-r109v3" },
    396	{ },
    397};
    398MODULE_DEVICE_TABLE(of, cdns_rtc_of_match);
    399
    400static struct platform_driver cdns_rtc_driver = {
    401	.driver = {
    402		.name = "cdns-rtc",
    403		.of_match_table = cdns_rtc_of_match,
    404		.pm = &cdns_rtc_pm_ops,
    405	},
    406	.probe = cdns_rtc_probe,
    407	.remove = cdns_rtc_remove,
    408};
    409module_platform_driver(cdns_rtc_driver);
    410
    411MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
    412MODULE_DESCRIPTION("Cadence RTC driver");
    413MODULE_LICENSE("GPL v2");
    414MODULE_ALIAS("platform:cdns-rtc");